用于通过 P-Code 分析恢复 Go 二进制文件中字符串定义的脚本。 已在 x86、x86-64、ARM 和 ARM64 上测试。
这些可以在脚本管理器(Script Manager)的 Golang 类别中找到。
GoDynamicStrings.java
GoFuncCallStrings.java
GoStaticStrings.java
GoKnownStrings.java
data/known_strings.json 加载。GoStringFiller.java
go.string.* 中的空白。还有一些动态字符串分析脚本的特殊变体:
GoDynamicStringsSingle.java
GoDynamicStrings.java 相同的分析,但使用单个反编译器进程。如果在分析二进制文件时并行反编译器进程耗尽系统内存,请使用此脚本。GoDynamicStringsHigh.java
这可以在脚本管理器(Script Manager)的 PCode 类别中找到。
PrintHighPCode.java
以下是使用这些脚本恢复 Go 二进制文件中字符串定义的一般流程:
.rodata、.rdata 或 __rodata 中的所有字符串。然后在代码列表中右键单击并选择“清除代码字节”(Clear Code Bytes)。GoKnownStrings.java 以检测一些标准字符串。GoStaticStrings.java。GoFuncCallStrings.java (如果 Ghidra 的内置 Golang 功能支持该 Golang 二进制版本)。GoDynamicStrings.java。GoStringFiller.java。
go.string.*。go.string.* 中剩余的空白,并定义任何具有明显起点和终点的字符串。
GoStringFiller.java,请确定未定义字符串数据中字符串长度发生变化的位置,并定义最接近该边界的字符串。然后重新运行 ,以自动填充它能够正确确定剩余未定义字符串长度的位置。在 Ghidra 中:
对于带有 GhidraDev 插件的 Eclipse:
使用 Eclipse 构建:
直接使用 Gradle 构建:
$ cd Ghostrings
$ gradle -PGHIDRA_INSTALL_DIR=<ghidra_install_dir>
逆向工程 Go 程序时一个众所周知的问题是,Go 字符串缺少空终止符,这使得从编译后的二进制文件恢复字符串定义变得困难。Go 程序的许多常量字符串值在编译构建中会全部存储在一个巨大的数据块中,字符串数据中没有任何终止符来标记一个字符串在哪里结束、另一个字符串从哪里开始。即使是一个只打印 “Hello world!” 的简单程序,也有超过 1,500 个与 Go 运行时系统和其他标准库相关的字符串。这可能导致典型的 ASCII 字符串发现实现(例如 Ghidra 提供的实现)产生长达数万个字符的误报字符串定义。
Go 使用的不是以空字符结尾的字符串,而是一种由指针和长度值组成的字符串结构。许多这类字符串结构在运行时创建于程序栈上,因此恢复单个字符串的起始位置和长度值需要分析编译后的机器码。有一些现有脚本通过检查某些 x86-64 指令模式来执行此分析,但它们会漏掉那些最终对栈产生相同效果但指令变体未处理的字符串结构,而且它们也仅限于特定的 ISA。
Ghostrings 通过使用 Ghidra 反编译器分析生成的、与架构无关的简化 P-Code 操作来避免这两个问题。
版权所有 2022 NCC Group。根据 GPLv3 许可证发布(见 LICENSE)。
项目主要作者:James Chambers [email protected]
GoStringFiller.java