第 36 章 Ghidra 深度使用(免费 IDA 的完全体)
Ghidra 是 NSA 开源的免费逆向平台,能力与 IDA 对标:多架构反汇编、反编译(Decompiler)、脚本化(Jython/Python 3)、插件生态、无头模式(headless)。预算有限或想自动化时,Ghidra 是第一选择。
📍 知识点地图 | 主题:Ghidra深度 | 前置:第4章 | 后续:— | 核心概念:headless、脚本、结构体恢复、插件
36.1 Ghidra 能力全景(vs IDA 对比)
| 能力 | Ghidra | IDA | 说明 |
|---|---|---|---|
| 反编译器 | Decompiler(C 风格) | Hex-Rays | 质量接近,免费 |
| 多架构 | 极广(含 DSP/小众) | 广 | 小众架构 Ghidra 更强 |
| 脚本语言 | Jython / Python 3 | IDAPython | 都强 |
| 自动化 | headless 一流 | -A + idalib | Ghidra 更方便 |
| 协作 | 团队服务器(免费) | 收费 | 团队项目 Ghidra 完胜 |
| 价格 | 免费开源 | 商业 | — |
| 调试器 | 内置(较弱) | 内置(较强) | 调试还是 IDA/x64dbg |
| 插件生态 | 丰富 | 更丰富 | D-810 等去混淆工具 IDA 多 |
36.2 Ghidra 核心操作速览
启动: analyzeHeadless(命令行)或 ghidraRun(GUI)
GUI 主窗口布局:
Program Tree 文件/段结构
Listing 反汇编视图(主工作区)
Decompile 反编译窗口(选中函数按 F5 快捷键/右键 Decompile)
Symbol Tree 符号/函数列表
Script Manager 脚本管理器(Window → Script Manager)
常用快捷键:
F5 或右键 → Decompile 反编译
X 交叉引用
L 改标签(重命名)
Ctrl+L 标签对话框
Ctrl+Shift+G 去地址
G 导航到地址/符号
F2 断点(调试器模式)
36.3 反编译与类型恢复(核心能力)
反编译基础
选中函数 → Decompile 窗口显示伪 C
伪代码操作:
右键变量 → Set Type(设类型)
右键变量 → Retype Variable
右键 → Label(重命名变量)
右键 → 加注释(Inline comment)
选中数组 → 右键 → Array…(设维度)
结构体恢复(Ghidra 特色:拖拽式)
1. Data Type Manager(数据类型管理器)
2. 右键 → New → Structure
3. 从 Listing 拖拽字段到结构体编辑器
4. 应用到函数/全局 → 伪代码自动展开字段
调用约定识别
右键函数 → Edit Function Signature
常见约定: __cdecl / __stdcall / __fastcall / __thiscall
ARM: AAPCS;64 位: Windows x64 / SysV
类型恢复错误 → 手动改约定 → 反编译输出立刻变清晰
36.4 脚本化(Ghidra Python)
基础
# Ghidra 脚本上下文: 全局变量 currentProgram / state
from ghidra.program.model.symbol import SymbolType
# 列函数
fm = currentProgram.getFunctionManager()
for f in fm.getFunctions(True):
print(f.getName(), hex(f.getEntryPoint().getOffset()))
# 反编译
from ghidra.app.decompiler import DecompInterface
decomp = DecompInterface()
decomp.openProgram(currentProgram)
func = fm.getFunctionAt(toAddr(0x401000))
res = decomp.decompileFunction(func, 60, monitor)
print(res.getDecompiledFunction().getC())
实用脚本模式
# 1. 提取所有字符串
listing = currentProgram.getListing()
for d in listing.getDefinedData(True):
if d.getDataType().getName() == "string":
print(hex(d.getAddress().getOffset()), d.getDefaultValueRepresentation())
# 2. 批量导出反编译(喂 LLM)
# 3. 提取 XREF(谁引用某地址)
from ghidra.program.model.symbol import ReferenceManager
refs = currentProgram.getReferenceManager().getReferencesTo(toAddr(0x405000))
for r in refs:
print(hex(r.getFromAddress().getOffset()))
运行
GUI: Window → Script Manager → 选中脚本 → Run
命令行: analyzeHeadless 项目目录 项目名 -process target.exe -postScript script.py
36.5 无头模式(headless)——自动化主力
# 基本用法
analyzeHeadless /tmp/proj MyProj -import target.exe -postScript analyze.py -scriptPath /tmp/scripts
# 批量分析目录
analyzeHeadless /tmp/proj MyProj -import /tmp/samples/ -recursive -postScript batch.py
# 关键参数
-import <file/dir> 导入目标
-recursive 递归目录
-postScript <script> 导入后执行脚本
-scriptPath <dir> 脚本路径
-overwrite 覆盖已分析
-process <file> 重跑已导入的文件(不重新导入)
headless 的价值:可以放进 CI/CD 管道、批量恶意软件分析、CTF 自动化。
36.6 批量恶意软件分析管道(Ghidra 实战)
1. analyzeHeadless 批量导入样本目录
2. postScript: 提取(函数数/字符串/导入/可疑模式)
3. 输出 JSON/CSV 报告
4. LLM 批量分类(第 29 章)
5. 可疑样本 → GUI 深挖
36.7 Ghidra 插件与扩展(补强能力)
| 插件/扩展 | 用途 |
|---|---|
| GOOMBA | OLLVM 去平坦化(Ghidra 版) |
| ghidra-rust | Rust 符号辅助 |
| ghidra-golang | Go 符号恢复 |
| Diaphora (Ghidra 版) | 二进制对比 |
| ghidriff | 命令行 diff(CI 友好) |
| Sleigh 处理器模块 | 新增架构支持 |
| LLM 插件(社区) | AI 辅助注释/命名 |
# 安装: 插件 jar 放入 extensions/ 目录 → 重启 Ghidra
36.8 Ghidra 深度工作流
目标: 无头批量分析 + 深挖一个目标
1. analyzeHeadless 导入 → postScript 提取特征
2. 报告驱动: 先看统计数据(可疑字符串/危险导入/高复杂度函数)
3. GUI 打开重点文件 → 反编译 → 类型恢复 → 重命名
4. 去混淆(GOOMBA/D-810 类)→ 再看
5. 动态验证(配合 GDB/Frida,第 5-6 章)
6. 输出 C 代码/报告
动手练习
- 用 analyzeHeadless 批量导入 3 个样本,postScript 提取函数数和字符串到 JSON。
- 在 Ghidra 中给一个含结构体的函数做结构体恢复(拖拽法),对比前后伪代码。
- 写一个 Ghidra 脚本:提取所有引用了某个字符串的函数名。
- 用 ghidriff 对比两个版本的二进制,找出变更函数。
深入阅读
- 仓库:
skills/reverse-engineering/tools.md(Ghidra headless 用法) - 仓库:
skills/reverse-engineering/tools-advanced.md(Ghidra 脚本/去混淆框架) - 仓库:
skills/reverse-engineering/references/ollvm-deobfuscation.md(GOOMBA 等) - 仓库:
skills/reverse-engineering/languages-compiled.md(Rust/Ghidra 脚本) - 仓库:
skills/patch-diff-exploit/references/diff-tools-comparison.md(ghidriff)