安全与风控
分析 Go 语言恶意软件时如何用 Ghidra 解析…
当需要逆向分析 Go 编译的恶意样本、去混淆 garble 打包的 Go 二进制、或从被剥离符号的 Go 可执行文件中恢复函数名与第三方依赖时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 49/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
分析 Go 语言恶意软件时如何用 Ghi通用
解决思路
- 确认环境:安装 Ghidra 11.0+ 与 JDK 17+、GoResolver 插件、Go Reverse Engineering Tool Kit(go-re.tk)、Python 3.9+,并熟悉 Go 运行时内部机制(goroutine、channel、interface)与 Go 二进制结构(pclntab、moduledata、itab)。
- 理解 Go 二进制结构:pclntab(PC Line Table)将程序计数器映射到函数名、源文件与行号,即使被 strip 仍保留;moduledata 含类型信息、itab 与 pclntab 指针;Go 字符串是「指针+长度」对而非 C 风格 null 结尾。
- 理解函数恢复原理:strip 后函数名仍在 pclntab 中,但 garble 等混淆工具会把函数重命名为随机字符串;GoResolver 通过计算被混淆函数的控制流图签名并与已知 Go 标准库/第三方包函数数据库匹配来恢复名称。
- 理解依赖提取原理:Go 的依赖管理会把模块路径与版本字符串嵌入二进制,提取这些可揭示恶意软件的第三方依赖(HTTP 库、加密包、C2 框架),无需完整逆向即可推断能力。
- 步骤 1 初始二进制分析:编写 Python 脚本读取文件,用 magic `\xff Go buildinf:` 定位 Go build info 偏移,并在附近用正则 `go\d+\.\d+(?:\.\d+)?` 提取 Go 版本。
- 步骤 1 定位 pclntab:按版本匹配 magic 字节——`\xfb\xff\xff\xff\x00\x00`(Go 1.2-1.15)、`\xfa\xff\xff\xff\x00\x00`(Go 1.16-1.17)、`\xf1\xff\xff\xff\x00\x00`(Go 1.18-1.19)、`\xf0\xff\xff\xff\x00\x00`(Go 1.20+),记录偏移与版本。
- 步骤 1 提取函数名:用正则匹配 `main|runtime|fmt|net|os|crypto|encoding|io|sync|syscall|reflect|strings|bytes|path|time|math|sort|github\.com|golang\.org` 等前缀的 `[/\.][\w/.]+` 模式,过滤长度 4-200 的字符串并去重排序。
- 步骤 1 提取 Go 字符串:用正则 `[\x20-\x7e]{10,}` 抓取可读序列,并按关键词过滤(http、https、tcp、udp、dns、cmd、shell、exec、upload、download、encrypt、decrypt、key、token、password、c2、beacon、agent、implant、bot、mutex、persist、registry、scheduled)。
- 步骤 1 提取依赖:用正则匹配 `(github\.com|gitlab\.com|golang\.org|gopkg\.in|go\.etcd\.io|google\.golang\.org)/[^\x00\s]{5,80}`,去重排序得到模块路径。
- 步骤 1 汇总输出:打印文件大小、build info、pclntab 偏移与版本、恢复的函数名数量,并按 network、crypto、os_exec、file_io、main、third_party 分类展示(每类前 10 个),再列出依赖(前 20)与可疑字符串(前 20)。
- 步骤 2 Ghidra 脚本分析:在 Ghidra Script Manager 中运行 `AnalyzeGoBinary.py`(category 为 MalwareAnalysis),获取当前 program、memory、listing。
- 步骤 2 在 Ghidra 中定位 pclntab:依次用 magic 字节 `[0xf0,0xff,0xff,0xff]`(Go 1.20+)、`[0xf1,0xff,0xff,0xff]`(Go 1.18-1.19)、`[0xfa,0xff,0xff,0xff]`(Go 1.16-1.17)、`[0xfb,0xff,0xff,0xff]`(Go 1.2-1.15)调用 `memory.findBytes`,找到后用 `program.getSymbolTable().createLabel(addr, "go_pclntab", None, SourceType.ANALYSIS)` 打标签。
- 步骤 2 修复 Go 字符串定义:注意 Go 字符串是 ptr+len 而非 null 结尾,需在 Ghidra 中相应修正字符串引用。
- 步骤 2 统计 Go 函数符号:遍历 `symbol_table.getAllSymbols(True)`,统计名称含 `.` 且包含 `main.`、`runtime.`、`net.`、`crypto.`、`os.` 等包前缀的符号数量。
- 验证结果:确认已提取 Go 版本与 build 信息、已定位并解析 pclntab 恢复函数名、已识别揭示能力的第三方依赖、已枚举 main 包函数用于定向分析、已分类 network/crypto/os_exec 函数、Ghidra 已正确标注 Go 运行时结构。
适用边界 · 注意事项
- 样本不是 Go 编译的二进制(无 Go buildinfo 或 pclntab magic)时不适用。
- 没有安装 Ghidra、GoResolver 或相关工具链时无法按此流程执行。
- 仅需快速静态字符串扫描、无需恢复函数名或依赖关系时,完整流程过重。