文章总结: 本文深入探讨了Go二进制文件的逆向分析与病毒分析技术。首先介绍了如何通过IDAPro和Go官方命令查询Go语言版本,接着详细解析了pclntab(程序计数器线性表)的结构,包括pcHeader和moduledata结构体,并指导如何通过magic值定位关键数据。随后,文章提供了一份IDAPro的Python脚本,用于自动修复并重命名代码中的函数,以还原其原始符号信息。最后,以一个Go编写的恶意样本为例,分析了其具备的心跳包、进程注入、文件传输、凭证窃取等功能,并给出了相关的IOC(指标)。 综合评分: 85 文章分类: 二进制安全,逆向分析,恶意软件,安全工具,实战经验
过卡巴佬的【go二进制逆向反射符号&病毒分析】
Kei sec
2026年3月20日 00:17 上海
编者荐语:
推荐一下某佬(逆向过卡巴dump内存)的go二进制逆向反射符号文章
以下文章来源于ThreatSafe Lab ,作者cooper
ThreatSafe Lab .
聚焦恶意情报与病毒分析
查询版本
Go 二进制文件中,还会把构建本文件的 Go 语言版本号打包进去。查看方式有以下 2 种:
- 通过 IDAPro 中的 strings 检索:
- 通过 Go 语言官方命令
$ go version [FILE],该命令不指定文件则打印本地安装的 Go 语言版本,指定文件则打印目标文件对应的 Go 语言版本:
Pclntab
- 查询对应版本的pcHeader,以及获取 moduledata 结构 源代码 https://github.com/golang/go/blob/go1.23.1/src/runtime/symtab.go
// pcHeader holds data used by the pclntab lookups.
type pcHeader struct {
magic uint32// 0xFFFFFFF1
pad1, pad2 uint8 // 0,0
minLC uint8 // min instruction size
ptrSize uint8 // size of a ptr in bytes
nfunc int // number of functions in the module
nfiles uint // number of entries in the file tab
textStart uintptr// base for function entry PC offsets in this module, equal to moduledata.text
funcnameOffset uintptr// offset to the funcnametab variable from pcHeader
cuOffset uintptr// offset to the cutab variable from pcHeader
filetabOffset uintptr// offset to the filetab variable from pcHeader
pctabOffset uintptr// offset to the pctab variable from pcHeader
pclnOffset uintptr// offset to the pclntab variable from pcHeader
}
// moduledata records information about the layout of the executable
// image. It is written by the linker. Any changes here must be
// matched changes to the code in cmd/link/internal/ld/symtab.go:symtab.
// moduledata is stored in statically allocated non-pointer memory;
// none of the pointers here are visible to the garbage collector.
type moduledata struct {
sys.NotInHeap // Only in static data
pcHeader *pcHeader
funcnametab []byte
cutab []uint32
filetab []byte
pctab []byte
pclntable []byte
ftab []functab
findfunctab uintptr
minpc, maxpc uintptr
text, etext uintptr
noptrdata, enoptrdata uintptr
data, edata uintptr
bss, ebss uintptr
noptrbss, enoptrbss uintptr
covctrs, ecovctrs uintptr
end, gcdata, gcbss uintptr
types, etypes uintptr
rodata uintptr
gofunc uintptr// go.func.*
textsectmap []textsect
typelinks []int32// offsets from types
itablinks []*itab
ptab []ptabEntry
pluginpath string
pkghashes []modulehash
// This slice records the initializing tasks that need to be
// done to start up the program. It is built by the linker.
inittasks []*initTask
modulename string
modulehashes []modulehash
hasmain uint8// 1 if module contains the main function, 0 otherwise
bad bool// module failed to load and should be ignored
gcdatamask, gcbssmask bitvector
typemap map[typeOff]*_type // offset to *_rtype in previous module
next *moduledata
}
- 通过
magic uint32 // 0xFFFFFFF1定位到pcHeader之后交叉引用找到moduledata
- 通过
pclnOffset(偏移与pcHeader) 定位 0x11F2DE0
- pcln对应的结构体如下
//src\runtime\symtab.go
type functab struct {
entryoff uint32 // relative to runtime.text
funcoff uint32
}
type funcInfo struct {
*_func
datap *moduledata
}
//src\runtime\runtime2.go
type _func struct {
entry uintptr // start pc
nameoff int32 // function name
args int32 // in/out args size
deferreturn uint32 // offset of start of a deferreturn call instruction from entry, if any.
pcsp uint32
pcfile uint32
pcln uint32
npcdata uint32
cuOffset uint32 // runtime.cutab offset of this function's CU
funcID funcID // set for certain special runtime functions
_ [2]byte // pad
nfuncdata uint8 // must be last
}
对应着一个 funcInfo 结构体, 里面包含一个 _func 类型,该类型中有我们想要的信息。 意思就是: func 的 _func = pclntable + funcOff 通过上图的信息计算:
0x11F2DE0+ 0x0D5B0 = 0x1200390 对应_func
- 函数结构名称偏移与对应
IDA 代码修复patch代码
import idc
from idc import *
import ida_nalt
moduledata_addr = addr
pcHeader_addr = idc.get_qword(moduledata_addr)
if idc.get_wide_dword(pcHeader_addr) != 0x0FFFFFFF0:
print(idc.get_wide_dword(pcHeader_addr))
print("错误,并不是一个正确的go文件")
funcnametable_addr = idc.get_qword(moduledata_addr + 8)
filetab_addr = idc.get_qword(moduledata_addr + 8 + ((8*3) * 2))
pclntable_addr = idc.get_qword(moduledata_addr + 8 + ((8*3) * 4))
pclntable_size = idc.get_qword(moduledata_addr + 8 + ((8*3) * 4) + (8 * 4))
set_name(moduledata_addr, "firstmoduledata")
set_name(funcnametable_addr, "funcnametable")
set_name(filetab_addr, "filetab")
set_name(pclntable_addr, "pclntable")
print(pclntable_size)
def readString(addr):
ea = addr
res = ''
cur_ea_db = get_db_byte(ea)
while cur_ea_db != 0and cur_ea_db != 0xff:
res += chr(cur_ea_db)
ea += 1
cur_ea_db = get_db_byte(ea)
return res
def relaxName(name):
# 将函数名称改成ida 支持的字符串
#print(name)
if type(name) != str:
name = name.decode()
name = name.replace('.', '_').replace("<-", '_chan_left_').replace('*', '_ptr_').replace('-', '_').replace(';','').replace('"', '').replace('\\', '')
name = name.replace('(', '').replace(')', '').replace('/', '_').replace(' ', '_').replace(',', 'comma').replace('{','').replace('}', '').replace('[', '').replace(']', '')
return name
cur_addr = 0
for i in range(pclntable_size):
# 获取函数信息表
cur_addr = pclntable_addr + (i * 8)
# 获取函数入口偏移
funcentryOff = get_wide_dword(cur_addr)
funcoff = get_wide_dword(cur_addr + 4)
funcInfo_addr = pclntable_addr + funcoff
funcentry_addr = get_wide_dword(funcInfo_addr)
funnameoff = get_wide_dword(funcInfo_addr + 4)
funname_addr = funcnametable_addr + funnameoff
funname = readString(funname_addr)
# 真实函数地址
truefuncname = relaxName(funname)
truefuncentry = ida_nalt.get_imagebase() + 0x1000 + funcentryOff
print(hex(truefuncentry), hex(funcoff), hex(funcInfo_addr),hex(funcentry_addr), hex(funnameoff),hex(funname_addr) ,funname)
# 改名
set_name(truefuncentry, truefuncname)
样本分析
最新的ida 9.0以上已经支持解析go反射符号,以该go木马为例
分析其功能如下
- 心跳包
- cmd_spaw_inject
- 文件上传下载
- 凭证窃取&进程kill
- cmd&powershell
- Assembly&端口扫描
IOC
- C&C: 149.104.104.244
- sha1:f1c494f8e6f6c4461bd2d5142137b5effe2b757a
好久没发文章了,等我最近有空挤一篇“
加解密签名对抗
”文章
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:Kei sec 《过卡巴佬的【go二进制逆向反射符号&病毒分析】》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。








评论