mcpField
A
analyzing-go-binaries

analyzing-go-binaries

github.com/trilwu安全17750 次安装12 周前更新
代码仓库

关于 analyzing-go-binaries

用于分析已编译 Go 程序(包括已剥离符号的二进制文件)的逆向工程技能。它面向安全分析师和逆向工程人员,利用 Go 特有方法恢复符号、类型、依赖项并理解程序行为。

主要功能

  1. 01识别 Go 二进制文件及版本
  2. 02恢复符号和函数名称
  3. 03提取类型元数据与结构标签
  4. 04检查依赖项和构建设置
  5. 05审查 Go 特有安全风险
  6. 06分析 Go 恶意软件痕迹

适用场景

  1. 01初步分析陌生的 Go 可执行文件
  2. 02恢复服务的 API 结构
  3. 03检查 Go 恶意软件样本
  4. 04在二进制文件中查找安全问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/trilwu/secskills --skill analyzing-go-binaries

安装后在 Claude Code 中输入/analyzing-go-binaries确认已加载。

详细介绍

分析 Go 二进制文件

Go 二进制文件看起来令人望而生畏:静态链接,体积达数十 MB,没有熟悉的导入项,而且经过“剥离”,导致工具显示数千个 sub_ 函数。其实并非如此。Go 自带用于运行时反射和 panic 跟踪的符号表,strip 不会将其移除。恢复符号后,这类二进制文件就成了最容易分析的目标之一。

适用场景

  • strings 显示 runtime.main、go:buildid、go.buildinfo 或 runtime.gopanic
  • “已剥离”的二进制文件有 5–50 MB,且几乎没有动态导入项
  • 反汇编工具显示数千个未命名函数和难以辨认的字符串
  • 分析 Go 恶意软件、Go 命令行工具或编译后的 Go 服务

不适用场景

  • Rust 二进制文件——请使用 analyzing-rust-binaries;其符号恢复方式完全不同
  • .NET 程序集——请使用 analyzing-dotnet-assemblies
  • 尚未隔离的疑似恶意软件——先使用 analyzing-malware 处理环境,再回到这里
  • 通用原生逆向工程——请使用 analyzing-binaries

确认是否为 Go,以及 Go 版本

strings -n 6 target | rg -m5 'go1\.[0-9]+|go:buildid|runtime\.main|GOROOT'
go version target                     # works on unstripped and many stripped builds
go version -m target                  # module list and build settings — free SBOM

go version -m 是价值最高的首条命令。它会打印带版本号的模块依赖关系图,让你在反汇编之前就能了解所用的第三方库——通常可以直接解答问题(使用了哪个 HTTP 库、哪种加密方式、哪个 C2 框架)。

Go 版本很重要,因为 pclntab 的布局在 1.2、1.16、1.18 和 1.20 版本发生过变化。工具失效通常是版本不匹配导致的,而不是二进制文件经过了强化。

恢复符号

# GoReSym — extracts pclntab, moduledata, types, and build info
GoReSym -t -d -p target > syms.json
#   -t  user type metadata
#   -d  include standard library
#   -p  paths

# redress — Go-aware analysis, works well when GoReSym struggles
redress info target
redress symbols target
redress types target

# Load into the disassembler
#   IDA:    AlphaGolang, golang_loader_assist, or the GoReSym IDA script
#   Ghidra: GolangAnalyzerExtension, or gotools
#   Binja:  the Golang loader plugin

应用符号后,函数会显示其真实名称—— main.processRequest、crypto/tls.(*Conn).Handshake、 github.com/vendor/pkg.Function。筛选 main.* 和第三方模块路径。runtime.、internal/ 和标准库下的所有内容都是原生代码,占函数总数的 90% 以上。

jq -r '.UserFunctions[].FunctionName' syms.json | rg -v '^(runtime|internal|reflect|sync)\.' | head -40

在反汇编工具中阅读 Go 代码

了解以下四点后,Go 反汇编列表就不再难以理解:

**字符串没有终止符。**Go 字符串由指针和长度构成,因此 strings 的输出会把相邻字面量连在一起,而反汇编工具会显示指针加载操作,后跟一个长度常量。找到这对值——指针旁边的常量就是长度,可以据此从数据块中截取出正确的子字符串。

**调用约定。**在 Go 1.17 之前,所有参数和返回值都通过栈传递,而不是通过寄存器。从 1.17 开始,amd64/arm64 使用寄存器 ABI。按 C 调用约定配置的反编译器会显示错误的参数;支持 Go 的插件可以修正这一点,这也是反编译器输出看起来毫无意义的主要原因。

**接口分派。**通过接口发起的调用会经过 itab——一个包含具体类型及其方法指针的表。要解析调用目标,先找到正在加载的 itab,再读取具体类型。类型恢复工具可以为这些类型命名,从而将间接调用转换为易读的形式。

Goroutine 和 defer。go f() 会编译为以 f 为参数的 runtime.newproc,因此并发逻辑不会以直接调用的形式出现。defer 会变成 runtime.deferproc/deferreturn,使清理代码分散到与源代码不同的位置。跟踪控制流时,请检查 newproc 调用点,以免完全漏掉相关工作。

类型恢复

Go 会嵌入完整的类型描述符,以支持反射。这意味着可以恢复结构体字段名称和布局——包括可直接映射到线上协议的 JSON 标签。

redress types target | rg -A10 'type main\.'
# Struct tags like `json:"api_key"` recover the exact protocol field names

这是了解 Go 服务 API 接口或 Go 植入程序 C2 消息格式的最快途径:恢复请求和响应结构体,就能获得协议内容,无需阅读任何指令。

Go 特定安全审查

如果任务是查找漏洞,而不是理解行为,值得重点检查以下 Go 特定类别:

  • 忽略错误。 对返回错误的函数使用 _ =,尤其是在认证、加密和文件操作中。
  • 使用 math/rand 生成安全相关值。 使用非加密随机数生成器生成令牌、会话 ID 或随机数。
  • 在 tls.Config 中设置 InsecureSkipVerify: true。
  • 使用 fmt.Sprintf 构造 SQL、shell 命令或 URL。
  • 共享 map 和结构体上的数据竞争——这通常是高负载下授权漏洞的根源。
  • 使用 shell 调用 os/exec,或使用由输入构造的参数调用它。

如果有源代码,请使用 auditing-code-for-vulnerabilities 和 govulncheck;以上内容适用于只有二进制文件的情况。

Go 恶意软件注意事项

Go 常用于跨平台植入程序,并会留下有用的痕迹:

  • 通过 go version -m 获取的模块列表可以识别所用框架——网络库、加密库,有时还能识别 C2 项目本身。
  • 构建路径会在符号表中泄露开发者用户名、项目名称和目录结构。
  • main. 包的函数名称通常会保留下来,因为剥离符号不会移除 pclntab,因此可以直接获得一份能力列表。
  • 有些样本会刻意剥离 pclntab,或使用会破坏 moduledata 的工具。如果 GoReSym 和 redress 都无法处理一个明显是 Go 编写的样本,请将其视为值得报告的规避迹象,并改为直接扫描类型描述符。

将 IOC 和检测结果交给 analyzing-malware 和 engineering-detections。

应拒绝的自我安慰

  • “它已剥离符号,所以没有符号。” strip 不会移除 pclntab。下结论前先运行 GoReSym。
  • “反编译器的输出一团糟。” 它使用了错误的调用约定。请应用支持 Go 的插件。
  • “有几千个函数,这得花上好几周。” 几乎全是运行时和标准库函数。筛选 main.* 和供应商模块。
  • “所有字符串都挤在一起了。” Go 字符串由指针和长度组成。按长度常量切分。
  • “工具失败了,这个二进制文件受到了保护。” 先检查 Go 版本是否在工具支持的 pclntab 版本范围内。
  • “我需要追踪每个 goroutine。” 找出 runtime.newproc 的调用位置,并查看传给它的函数。

参考资料

  • analyzing-binaries — 有关此主题的一般分类和动态分析
  • analyzing-malware — Go 样本的遏制和 IOC 提取
  • auditing-code-for-vulnerabilities — 存在源代码时的 Go 漏洞类别检查清单
  • GoReSym、redress、AlphaGolang、GolangAnalyzerExtension、go version -m

评论

支持 Markdown