基础知识
执行顺序
执行 runtime_init()
启动GC gcenable()
执行 main_init() (init是由Golang的编译器为每个包生成的,用于初始化该报所依赖的其他包以及该包的全局变量)
fn := main_init
fn()
执行main函数,此时程序进入用户的代码
fn = main_main
fn()
符号恢复
基础知识
runtime
runtime.schedinit():引用 Go 的构建版本。了解确切的版本可以调查可能的脚本解析失败(因为某些内部结构可能会根据 Go 的版本而改变)。
runtime.GOROOT():引用编译期间使用的 Go 的安装文件夹。这可能对恶意软件跟踪有用。
pclntab( Program Counter Line Table)( 程序计数器行数映射表)
从1.2版本开始,Golang可执行文件潜入了一个名为PC行表得结构,也称为pclntab。这个结构是从Plan9继承而来的。其最初的目的是将程序计数器值(pc)与另一个值关联起来。
该结构已经发展,现在包含一个函数符号表,它特别存储了二进制文件中定义的所有例程得如何点和名称。pclntab不能轻易从二进制文件中剥离出来,并为我们提供一种可靠的方法来改进反汇编得控制流。
moduledata 记录了有关可执行映像布局的信息。它由链接器写入。此处的任何更改都必须与 cmd/link/internal/ld/symtab.go:symtab.moduledata 中代码的更改相匹配,该模块存储在静态分配的非指针内存中;垃圾收集器看不到此处的任何指针。
Version | pclntab | |
1.4-1.15 | None | |
1.16-1.17 | // pcHeader holds data used by the pclntab lookups.
type pcHeader struct { magic uint32 // 0xFFFFFFFA } |
|
1.18-1.19 | type pcHeader struct {
magic uint32 // 0xFFFFFFF0 pad1, pad2 uint8 // 0,0 } |
|
1.20 | // pcHeader holds data used by the pclntab lookups.
type pcHeader struct { magic uint32 // 0xFFFFFFF1 } |
|
1.21 | // pcHeader holds data used by the pclntab lookups.
type pcHeader struct { magic uint32 // 0xFFFFFFF1 } |
|
1.22 | // pcHeader holds data used by the pclntab lookups.
type pcHeader struct { magic uint32 // 0xFFFFFFF1 } |
|
1.23 | // pcHeader holds data used by the pclntab lookups.type
pcHeader struct { magic uint32 // 0xFFFFFFF1 } |
– magic:一个固定的魔数,用于验证 `pcHeader` 的有效性。值为 `0xFFFFFFF1`。 – pad1, pad2:填充字节,保持结构体对齐。值为 `0`。 – minLC:最小指令大小。 – ptrSize:指针大小,以字节为单位。 – nfunc:模块中的函数数量。 – nfiles:文件表中的条目数量。 – textStart:函数入口的 PC 偏移的基地址,与 `moduledata.text` 相等。 – funcnameOffset:从 `pcHeader` 开始到 `funcnametab` 的偏移量。 – cuOffset:从 `pcHeader` 开始到 `cutab` 的偏移量。 – filetabOffset:从 `pcHeader` 开始到 `filetab` 的偏移量。 – pctabOffset:从 `pcHeader` 开始到 `pctab` 的偏移量。 – pclnOffset:从 `pcHeader` 开始到 `pclntab` 的偏移量。 |
ModuleData
moduleData结构块是记录有关可执行文件布局得信息。
Version | moduleData | |
1.4-1.6 | None | |
1.7 |
type moduledata struct {
pclntable []byte
ftab []functab
filetab []uint32
findfunctab uintptr
minpc, maxpc uintptr
text, etext uintptr
noptrdata, enoptrdata uintptr
data, edata uintptr
bss, ebss uintptr
noptrbss, enoptrbss uintptr
end, gcdata, gcbss uintptr
types, etypes uintptr
typelinks []int32 // offsets from types
itablinks []*itab
modulename string
modulehashes []modulehash
gcdatamask, gcbssmask bitvector
typemap map[typeOff]*_type // offset to *_rtype in previous module
next *moduledata
}
|
|
1.8-1.9 |
// 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/internal/ld/symtab.go:symtab.
// moduledata is stored in read-only memory; none of the pointers here
// are visible to the garbage collector.
type moduledata struct {
pclntable []byte
ftab []functab
filetab []uint32
findfunctab uintptr
minpc, maxpc uintptr
text, etext uintptr
noptrdata, enoptrdata uintptr
data, edata uintptr
bss, ebss uintptr
noptrbss, enoptrbss uintptr
end, gcdata, gcbss uintptr
types, etypes uintptr
textsectmap []textsect
typelinks []int32 // offsets from types
itablinks []*itab
ptab []ptabEntry
pluginpath string
pkghashes []modulehash
modulename string
modulehashes []modulehash
gcdatamask, gcbssmask bitvector
typemap map[typeOff]*_type // offset to *_rtype in previous module
next *moduledata
}
|
|
1.10 |
type moduledata struct {
pclntable []byte
ftab []functab
filetab []uint32
findfunctab uintptr
minpc, maxpc uintptr
text, etext uintptr
noptrdata, enoptrdata uintptr
data, edata uintptr
bss, ebss uintptr
noptrbss, enoptrbss uintptr
end, gcdata, gcbss uintptr
types, etypes uintptr
textsectmap []textsect
typelinks []int32 // offsets from types
itablinks []*itab
ptab []ptabEntry
pluginpath string
pkghashes []modulehash
modulename string
modulehashes []modulehash
hasmain uint8 // 1 if module contains the main function, 0 otherwise
gcdatamask, gcbssmask bitvector
typemap map[typeOff]*_type // offset to *_rtype in previous module
bad bool // module failed to load and should be ignored
next *moduledata
}
|
|
1.23 |
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
}
|
– pcHeader:指向 `pcHeader` 结构体的指针。 – funcnametab:函数名称表,以字节数组形式存储。 – cutab:编译单元表,以 `uint32` 数组形式存储。 – filetab:文件表,以字节数组形式存储。 – pctab:PC 表,以字节数组形式存储。 – pclntable:PC 行号表,以字节数组形式存储。 – ftab:函数表,存储函数的入口和偏移信息。 – findfunctab:用于查找函数表的指针。 – minpc, maxpc:模块中最小和最大的 PC 值。 – text, etext:文本段的起始和结束地址。 – noptrdata, enoptrdata:无指针数据段的起始和结束地址。 – data, edata:数据段的起始和结束地址。 – bss, ebss:BSS 段的起始和结束地址。 – noptrbss, enoptrbss:无指针 BSS 段的起始和结束地址。 – covctrs, ecovctrs:覆盖计数器段的起始和结束地址。 – end, gcdata, gcbss:结束地址、GC 数据和 GC BSS 的地址。 – types, etypes:类型信息的起始和结束地址。 – rodata:只读数据段的地址。 – gofunc:Go 函数的地址。 – textsectmap:文本段映射。 – typelinks:类型的偏移数组。 – itablinks:接口表数组。 – ptab:ptab 表。 – pluginpath:插件路径。 – pkghashes:包哈希数组。 – inittasks:初始化任务数组。 – modulename:模块名称。 – modulehashes:模块哈希数组。 – hasmain:模块是否包含 main 函数。 – bad:模块是否加载失败。 – gcdatamask, gcbssmask:GC 数据和 BSS 的位向量。 – typemap:类型映射,偏移到 `_type` 的映射。 – next:指向下一个 `moduledata` 结构体的指针。 |
functab
存储了函数的入口和偏移信息
Version | functab | |
1.7-1.10 | type functab struct {
entry uintptr } |
|
开源工具
AlphaGolang:https://github.com/SentineLabs/AlphaGolang
go_parser:https://github.com/0xjiayu/go_parser
IDAGolangHelper: https://github.com/sibears/IDAGolangHelper
参考链接
分析 Golang 可执行文件
https://www.pnfsoftware.com/blog/analyzing-golang-executables/
分析用例:StealthWorker
SHA1: 42ec52678aeac0ddf583ca36277c0cf8ee1fc680
- runtime.schedinit的代码中引用了样本的版本
- runtime.GOROOT的代码中引用了开发者根路径