注意:该功能已直接集成到 radare2 核心中,作为 gopc analysis plugin
一个基于 radare2 的 Go gopclntab 解析器,用于从 Go 二进制文件中恢复函数符号,包括完全剥离符号的二进制文件。支持 ELF、Mach-O 和 PE 二进制文件,涵盖 Go 1.2、1.16、1.18 及 1.20+ 版本。
每个 Go 1.2+ 二进制文件都嵌入了一个名为 gopclntab(程序计数器行表)的数据区域,Go 运行时利用它进行堆栈跟踪、恐慌消息、垃圾回收和调试器支持。它是 Go 二进制文件中最有价值的符号信息源之一。
r2gopclntabParser 通过 radare2 读取该区域,解析版本特定的结构,然后打印恢复的函数列表(包含地址、源文件和行号),或将恢复的函数名称作为函数定义、标志和注释应用回打开的 radare2 会话中。
| 依赖项 | 最低版本 |
|---|---|
| Python 3 | 3.8+ |
| radare2 | 5.0+(已在 6.0.9 上测试) |
| r2pipe | 任意 |
不需要其他 Python 包。脚本仅使用标准库(struct、json、argparse、os、sys)加上 r2pipe。
python3 r2_gopclntab.py -f ./mybinary -l
python3 r2_gopclntab.py -f ./mybinary -n main.main
python3 r2_gopclntab.py -f ./mybinary -v -l
python3 r2_gopclntab.py -f ./mybinary --apply
python3 r2_gopclntab.py -f ./mybinary --json
#!pipe python3 r2_gopclntab.py --r2pipe --apply -v
---
## CLI参考```
usage: r2_gopclntab.py [-h] [-f FILE] [-n FUNCNAME] [-v] [-l]
[--apply] [--json] [--files] [--r2pipe]
| 标志 | 描述 |
|---|---|
-f FILE, --file FILE | 要分析的Go二进制文件路径。脚本会启动自己的r2实例。 |
--r2pipe | 连接到已在运行的r2会话(用于r2控制台内部)。 |
| 标志 | 描述 |
|---|---|
-l, --list | 打印每个恢复的函数及其地址。 |
-n NAME, --funcname NAME | 仅打印名称包含NAME(子字符串匹配)的函数。如果存在完全匹配,则单独打印其地址。 |
-v, --verbose | 打印进度信息、解析的头部字段和内部偏移量。 |
--apply | 将恢复的函数名称写入radare2会话,包括函数定义(af+)、go.标志空间中的标志,以及带有原始Go名称和源代码位置的注释。 |
--json | 将头部和完整函数列表以JSON格式输出到stdout。 |
--files | 打印从文件表中提取的源文件路径列表。 |
-h, --help | 显示帮助信息。 |
标志可以自由组合。当没有给出输出标志时,默认行为是打印头部和完整函数列表。
以下所有示例均针对一个剥离后的Go 1.26 Mach-O arm64二进制文件运行(使用-ldflags="-s -w"构建)。测试程序定义了main.main、main.fibonacci、main.helloWorld和main.addNumbers。编译器内联了helloWorld和addNumbers,因此它们不会出现在gopclntab中。
运行时不带任何标志(或仅使用-f)会打印解析后的头部,后跟完整的函数表:```
$ python3 r2_gopclntab.py -f ./gotest_stripped
在开始之前,您只需要设置一个配置文件。最快和最简单的方法是运行并按照设置向导的提示进行操作,使用以下命令:
```console
$ tools-for-github setup
您将被询问一系列问题,配置文件将生成在 ~/.tools-for-github.toml。
如果您想手动创建并配置文件,请创建 ~/.tools-for-github.toml 并填入以下内容:
# [github] 部分是可选的,如果省略,将使用默认值。
[github]
base_url = "https://api.github.com" # 如果您使用的是 GitHub Enterprise Server,请更改此设置。
api_token = "" # 默认值是 GITHUB_TOKEN 环境变量的值。
此配置文件位于 $HOME/.tools-for-github.toml。
还有其他可用的选项,但这些是必需的。有关所有配置选项的完整参考,请参阅文档。
接下来,您还需要一个 GitHub 令牌,可以设置为 GITHUB_TOKEN 环境变量,或在 ~/.tools-for-github.toml 中配置。创建令牌的文档可在此处找到。还要记得在需要时为您的令牌启用 SSO。
现在,您可以像这样使用任何脚本:
$ tools-for-github <script> <arguments>
例如,要使用 sync-github-all 脚本,可以运行以下命令:
$ tools-for-github sync-github-all --help
要列出所有可用脚本,请运行以下命令:
$ tools-for-github
初始设置后,使用 update 脚本将 tools-for-github 更新到最新版本:
$ tools-for-github update
github-tools 或早期版本的 tools-for-github 升级如果您之前使用过 github-tools 或 v3.0.0 之前的 tools-for-github 版本,配置文件已发生变更。配置文件的位置已从 ~/.github-tools.toml 移至 ~/.tools-for-github.toml,并且格式也发生了变化。幸运的是,设置向导可以帮助您迁移现有的配置。只需运行:
$ tools-for-github setup
向导将检测您现有的配置,并询问是否要迁移到新格式。
旧的配置格式如下所示:
github_api_token = ""
github_base_url = "https://api.github.com"
而新的配置格式如下所示:
[github]
base_url = "https://api.github.com"
api_token = ""
0x100001000 go:buildid 0x100001070 internal/abi.BoundsDecode (/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/bounds.go:86) 0x100001150 internal/abi.NoEscape (/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/escape.go:19) 0x100001160 internal/abi.Kind.String (/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/type.go:143) 0x1000011E0 internal/abi.TypeOf (/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/type.go:181) 0x1000011F0 internal/abi.(*Type).ExportedMethods (/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/type.go:453) ... 0x1000A0BB0 main.fibonacci (/tmp/gotest/main.go:13) 0x1000A0C20 main.main (/tmp/gotest/main.go:20) 0x1000A0D20 go:textfipsstart 0x1000A0D30 go:textfipsend
[+] 2030 function(s) shown
### 详细模式 (-v)
添加了部分扫描进度、textStart解析详情和内部偏移信息:```
$ python3 r2_gopclntab.py -f ./gotest_stripped -v
.``` [] Running radare2 analysis... [] Binary format: mach0, endian: little, arch: arm, bits: 64 [] Scanning binary for gopclntab magic bytes... [] Scanning section '0.__TEXT.__text' (0x100001000, 0x9FD44)... [] Scanning section '1.__TEXT.__symbol_stub1' (0x1000A0D60, 0x2B8)... [] Scanning section '2.__TEXT.__rodata' (0x1000A1020, 0xACC2)... [] Scanning section '3.__TEXT.__gopclntab' (0x1000ABCE8, 0xA48AE)... [] Found magic at vaddr=0x1000ABCE8 [] Parsed header: PcHeader(magic=0xFFFFFFF1, version=1.20+, ptrSize=8, minLC=4, nfunc=2030, nfiles=261, textStart=0x0) [] textStart is 0, using .text section vaddr: 0x100001000 [*] Parsed 2030 functions
Magic: 0xFFFFFFF1 Go version: 1.20+ ...
### 搜索模式 (-n)
按子串匹配过滤函数列表。如果存在精确匹配,则会单独打印其地址。
搜索所有包含 `main.` 的子串函数:```
$ python3 r2_gopclntab.py -f ./gotest_stripped -n "main."
0x100041920 runtime.main.func2 (/opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/proc.go:207) 0x10006CE30 runtime.main.func1 (/opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/proc.go:174) 0x1000A0BB0 main.fibonacci (/tmp/gotest/main.go:13) 0x1000A0C20 main.main (/tmp/gotest/main.go:20)