mandiant/GoReSym

GitHub: mandiant/GoReSym

GoReSym 是一款专为逆向分析设计的 Go 语言二进制符号恢复工具,能够从剥离符号或异常打包的 Go 程序中提取函数、类型和元数据信息。

Stars: 938 | Forks: 97

# GoReSym ![GoReSym Logo](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/a0d24baa94123532.png) GoReSym 是一个 Go 符号解析器,用于提取程序元数据(例如 CPU 架构、操作系统、字节序、编译器版本等)、函数元数据(起始和结束地址、名称、源码)、文件名和行号元数据,以及嵌入的结构和类型。该跨平台程序直接基于[开源 Go 编译器](https://github.com/golang/go/tree/master/src/debug/gosym)和运行时代码。 上游 Go 运行时代码经过扩展以处理: * 剥离符号的二进制文件 * 畸形的未打包二进制文件,例如来自 UPX 的文件 * 将单个数据范围分割跨多个节的二进制文件 * `moduledata` 结构的位置 # 用法 请参阅 https://www.mandiant.com/resources/blog/golang-internals-symbol-recovery 了解逆向工程详细信息和示例用法。 你可以从 [Releases 标签页](https://github.com/mandiant/GoReSym/releases/) 下载预构建的 `linux`、`macos` 和 `windows` GoReSym 二进制文件。 要使用最新的 Go 编译器从源代码构建,请调用 Go 编译器: ``` go build ``` 构建完成后,像这样调用 GoReSym: ``` GoReSym.exe -t -d -p /path/to/input.exe ``` 在这个例子中,我们要求 GoReSym 恢复嵌入在文件 `/path/to/input.exe` 中的类型名称(`-t`)、用户包名称、标准 Go 包名称(`-d`)和输入文件路径(`-p`)。输出如下所示: ``` { "Version": "1.14.15", "BuildId": "Zb9QmokKTiOUgHKmaIwz/wd2rtE3W9PN-um1Ocdzh/qTdqcTY_jVajHy_-TtYv/Z_kJu9M77OjfijEiHMcF", "Arch": "amd64", "TabMeta": { "VA": 5174784, "Version": "1.2", "Endianess": "LittleEndian", "CpuQuantum": 1, "CpuQuantumStr": "x86/x64", "PointerSize": 8 }, "ModuleMeta": { "VA": 5678816, "Types": 4845568, "ETypes": 5171904, "Typelinks": { "Data": 5171904, "Len": 695, "Capacity": 695 }, "ITablinks": { "Data": 5174688, "Len": 11, "Capacity": 11 }, "LegacyTypes": { "Data": 0, "Len": 0, "Capacity": 0 } }, "Types": [ ... ], "Files": [ ... ], "Strings": [ ... ], "UserFunctions": [ ... ], "StdFunctions": [ ... ] } ``` 以下是所有可用的标志: * `-d` ("default",可选) 标志将打印标准 Go 包以及用户包。 * `-p` ("paths",可选) 标志将打印嵌入在 `pclntab` 中的任何文件路径。 * `-t` ("types",可选) 标志将打印 Go 类型名称。 * `-strings` (可选) 标志将通过分析字符串驻留表从二进制文件中提取嵌入的 Go 字符串。 * `-m ` ("manual",可选) 标志将在给定的虚拟地址递归转储 `RTYPE` 结构 * `-v ` ("version",可选) 标志将覆盖自动版本检测并使用提供的版本。某些剥离符号的二进制文件需要此标志。如果版本不准确,类型解析将失败。 * `-human` (可选) 标志将打印平面文本列表而不是 JSON。在打印结构和接口类型时特别有用。 * `-about` (可选) 标志将打印许可证信息 要将此信息导入 IDA Pro,你可以运行 [https://github.com/mandiant/GoReSym/blob/master/IDAPython/goresym_rename.py](IDAPython/goresym_rename.py) 中的脚本。它将读取 GoReSym 生成的 json 文件并在 IDA 中设置符号/标签。 # 版本支持 随着 Go 编译器和运行时的变化,嵌入的元数据结构也发生了变化。GoReSym 支持以下 Go 版本和元数据的组合: * ARM64 𝒙 Intel x86/x64 𝒙 MACH-O/ELF/PE 𝒙 大/小端序的所有组合 * `pclntab` 解析:>= Go 1.2 * `moduledata` 位置:>= Go 1.2 * `moduledata` 类型解析:>= Go 1.5 用于提取类型的 `moduledata` 表在 Go 1.5 之前不存在,因此该库将永远不支持从非常旧的 Go 版本中提取类型。 该库目前处理 1.2 之前、1.2、1.16、1.18 和 1.20 的 `pclntab` 布局。请注意,pclntab 版本始终 <= Go 运行时版本(例如:Go 运行时 1.19 使用 1.18 pclntab 布局),我们的目标是 _始终支持最新的运行时版本_。 # 贡献 GoReSym 的大部分源代码复制自上游 Go 编译器源目录 `/internal`。为了使其工作,我们必须对源代码进行一些调整。如果你想为 GoReSym 做贡献,请继续阅读,以便我们解释此导入过程。 由于 Go 包的工作方式,我们需要从源文件树中删除 `/internal` 路径。这导致复制了大量内部 Go 文件,其中目录树基本保持不变,但许多文件的导入进行了小改动:对 `/internal` 路径的引用替换为 `github.com/mandiant/GoReSym/`。 我们还修改了许多内部结构以导出字段和方法。Go 上游没有导出这些内容是因为用户不应依赖它们。但是,此工具的目的是提取内部信息,因此我们承担了维护这些结构的任务。这不是一个理想的情况,但也不容易避免。如果你更新此仓库,必须注意保持这些修改完好无损。手动合并上游的提交可能比整体复制上游文件更好。 我愿意接受关于如何更好地构建此项目以避免这些问题,同时仍能使用典型的 `go build` 进行编译的建议。之前有一段涉及 Go 维护者的讨论在[这里](https://github.com/golang/go/issues/46792)。 忽略一些微不足道的更改,大多数新逻辑存在于 `/objfile` 中。例如,文件 `objfile/internals` 定义了 GoReSym 解析的反向内部 Go 结构。 # 参考 * `pclntab` 规范:[golang.org/s/go12symtab](https://docs.google.com/document/d/1lyPIbmsYbXnpNj57a261hgOYVpNRcgydurVQIyZOz_o/pub) * `pclntab` 魔数:[pclntab.go#L169](https://github.com/golang/go/blob/89f687d6dbc11613f715d1644b4983905293dd33/src/debug/gosym/pclntab.go#L169) * `objfile` 错误: * [golang/go#42954](https://github.com/golang/go/issues/42954) * [golang/go#47981](https://github.com/golang/go/issues/47981) * [golang/go#47852](https://github.com/golang/go/issues/47852) * `buildID` 旧版错误:[golang/go#50809](https://github.com/golang/go/issues/50809) # 变更 * 添加了对 Go 1.24 二进制文件的解析支持,同时保持与旧版 1.2 布局的兼容性。 * GoReSym 现在还将尝试根据 `runtime_modulesinit` 初始化方法的签名查找 pclntab,并尝试修复 pclntab 魔数(在 pclntab 魔数已被修改的情况下)。 * 扩展了 `objfile/` 中的 `pcln()` 函数,以支持对 `pclntab` 魔数进行字节扫描 * 添加了诸如 `DataAfterSection` 的例程,以支持 `/debug/` 中文件格式解析器的签名扫描 * 向 `debug/gosym/symtab.go` 的 `walksymtab` 添加了检查,以便在可选的 `symtab` 节为空时提前退出 * 导出了许多成员和内部结构(更改太多无法一一列举) * 移除了 `objfile/objfile.go` 的 `PCLineTable()` 中的 `goobj` liner 支持 * 在 `loadPeTable`(及其他格式变体)周围添加了额外的健全性检查,以避免在符号存在但被恶意修改为无效时发生 panic(参考:[golang/go#47981](https://github.com/golang/go/issues/47981)) * 修改了一些内部函数的签名,以提供对节地址和偏移量等信息的低级访问 * 为支持的文件格式实现了 `read_memory` 例程,以便按虚拟地址读取文件数据 * 引入了 `moduledata` 扫描例程以帮助定位 moduledata,从而支持扫描类型和接口(通过 typelinks) * 为无效的符号表向 `readStringTable` 添加了大小保护。解析失败也会被忽略。 # 许可证 MIT
标签:Assetfinder, DAST, EVTX分析, EVTX分析, Golang Internals, Go语言, Mandiant, SecList, Strip二进制, 二进制分析, 云安全运维, 云资产清单, 元数据提取, 内存取证, 函数签名, 恶意软件分析, 日志审计, 程序破解, 符号恢复, 类型恢复, 脱壳, 进程保护, 逆向工程