• 我们在哪一颗星上见过 ,以至如此相互思念 ;我们在哪一颗星上相互思念过,以至如此相互深爱
  • 我们在哪一颗星上分别 ,以至如此相互辉映 ;我们在哪一颗星上入睡 ,以至如此唤醒黎明
  • 认识世界 克服困难 洞悉所有 贴近生活 寻找珍爱 感受彼此

恶意代码技术理论:GoLang恶意代码分析

基于语言 云涯 4年前 (2020-07-09) 2604次浏览

基础知识

执行顺序

执行         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
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.
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 varible from pcHeader
pclnOffset uintptr // offset to the pclntab variable from pcHeader

}

1.18-1.19 type pcHeader struct {

magic uint32 // 0xFFFFFFF0

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

}

1.20 // 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

}

1.21 // 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

}

1.22 // 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

}

1.23 // 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

}

– 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
funcoff uintptr

}

开源工具

AlphaGolang:https://github.com/SentineLabs/AlphaGolang

go_parser:https://github.com/0xjiayu/go_parser

IDAGolangHelperhttps://github.com/sibears/IDAGolangHelper

 

参考链接

分析 Golang 可执行文件

https://www.pnfsoftware.com/blog/analyzing-golang-executables/

分析用例:StealthWorker

SHA1: 42ec52678aeac0ddf583ca36277c0cf8ee1fc680

  • runtime.schedinit的代码中引用了样本的版本
  • runtime.GOROOT的代码中引用了开发者根路径

 

 

 

 


云涯历险记 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:恶意代码技术理论:GoLang恶意代码分析
喜欢 (0)