本节摘要:图形界面精读好用,批量无力。本节把 1.1 与 1.2 节的动作变成脚本。第一部分给三个必须无头的场景:样本批量、CI 流水线、无人值守。第二部分上手 analyzeHeadless:一条命令完成导入、分析、跑脚本、清理工程,参数逐个拆解。第三部分写第一个 Ghidra 脚本 export_functions.py,遍历函数管理器,把函数名、入口、大小导出成 JSON——这就是后续所有 AI 工具流的「备料」格式。第四部分换 PyGhidra:在普通 Python 里 start 后 open_program,把 Ghidra 当库用,适合与 pandas、模型调用同进程组合。最后划定边界:哪些事仍该回 GUI 做。
| 场景 | 痛点 | 无头方案 |
|---|---|---|
| 样本批量初筛:一百个待分析二进制 | 逐个双击导入要一天 | analyzeHeadless 循环跑目录 |
| 流水线集成:新样本入库即自动出函数清单 | 人工触发不可持续 | CI 任务定时执行脚本 |
| 无人值守:服务器上没有图形界面 | GUI 根本起不来 | 命令行 + 脚本 |
无头模式复用的是同一套分析引擎与脚本接口——GUI 里能拿到的程序对象,脚本里一样拿得到。
analyzeHeadless 是 Ghidra 自带的命令行入口,位于发行包 support 目录。最小可用命令:
# bash —— analyzeHeadless 单文件分析并导出(写法示意,以官方文档为准) GHIDRA=/opt/ghidra_12.1.4_PUBLIC "$GHIDRA/support/analyzeHeadless" /path/to/re-lab/ghidra_proj ReLab \ -import bin/demo_stripped \ -scriptPath scripts \ -postScript export_functions.py \ -deleteProject
| 参数 | 作用 |
|---|---|
| ghidra_proj ReLab | 工程目录与工程名 |
| -import 文件 | 导入并自动分析该二进制 |
| -scriptPath 目录 | 脚本搜索路径 |
| -postScript 脚本 | 分析完成后执行(脚本里可带参数) |
| -deleteProject | 用后即焚,不留工程残骸(需要留工程复看时去掉) |
一个容易忽略的点:-import 每次都新建程序,重跑会重名冲突;批处理常用「先 -import 初次建库、再 -process 复用已有库」的两段式,参数细节以官方文档为准。
Ghidra 脚本运行在有上下文的环境里:currentProgram 直接就是当前程序对象。新建 scripts/export_functions.py:
# export_functions.py —— Ghidra 脚本:导出函数清单 JSON(API 以官方文档为准) import json OUT = "out/functions.json" rows = [] fm = currentProgram.getFunctionManager() for func in fm.getFunctions(True): rows.append({ "name": func.getName(), "entry": str(func.getEntryPoint()), "size": func.getBody().getNumAddresses(), }) with open(OUT, "w", encoding="utf-8") as fh: json.dump({"program": str(currentProgram.getName()), "functions": rows}, fh, ensure_ascii=False, indent=2) print("exported %d functions -> %s" % (len(rows), OUT))
对 demo_stripped 跑完后,out/functions.json 形如:
# out/functions.json —— 导出结果示例(节选,示意) { "program": "demo_stripped", "functions": [ {"name": "FUN_00401160", "entry": "00401160", "size": 83}, {"name": "FUN_00401189", "entry": "00401189", "size": 76} ] }
这份 JSON 是全书的「通用货币」:第 02 章 r2pipe 导出同构数据,第 03 章模型列函数走同一条路,第 04 章的 RAG 索引以它为输入。把结构定稳定(name、entry、size),后面每章都省事。
analyzeHeadless 的脚本是「分析完成后被动执行」;PyGhidra(Ghidra 官方 Python 支持,随发行版提供,安装方式以官方文档为准)则让你在普通 Python 里主动驱动:
# bash —— PyGhidra 环境准备(写法示意,以官方文档为准) cd /opt/ghidra_12.1.4_PUBLIC ./support/pyghidraRun # 带界面的 Python 控制台 # 库模式使用:按官方文档安装附带的 pyghidra 包后,在任意虚拟环境 import
# pyghidra_demo.py —— 库模式:Python 主动打开并遍历函数(API 以官方文档为准) import pyghidra pyghidra.start() with pyghidra.open_program("bin/demo_stripped", analyze=True) as api: program = api.getCurrentProgram() fm = program.getFunctionManager() funcs = list(fm.getFunctions(True)) print("program:", program.getName()) print("functions:", len(funcs)) for func in funcs[:5]: print(func.getName(), func.getEntryPoint())
库模式的价值在于「同进程组合」:函数清单可以直接进 pandas 统计、直接喂模型、直接写数据库,没有中间文件。第 03 章 GhidraMCP 的 headless 支持正是建立在 PyGhidra 上(要求 Python 3.10~3.13)。
两种方式的关系:analyzeHeadless 适合「一条命令跑完就退」的批处理;PyGhidra 适合「分析只是长流程中的一步」的编排。底层是同一套 API,脚本可平滑迁移。
| 任务 | 推荐方式 | 原因 |
|---|---|---|
| 单个程序精读、手工重命名 | GUI | 交互反馈快,理解需要眼睛 |
| 批量导清单、批量初筛 | analyzeHeadless | 无人值守,循环友好 |
| 与模型 / 数据处理同流程 | PyGhidra | 同进程无中间态 |
| 大样本分析卡死 | headless 分段 | 可控超时与重试 |
三个常见坑:其一,脚本里的路径是「Ghidra 进程的当前目录」,批处理前先统一工作目录;其二,-deleteProject 与「想保留重命名成果」冲突——要落库就不要删工程;其三,Python 版本:PyGhidra 相关链路对 Python 3.10~3.13 有要求,虚拟环境里先核对版本。
至此,Ghidra 地基完工:能装、能读、能脚本化导出。下一章换一件更轻的武器——radare2,看命令行哲学如何把同样的活儿干出「管道」的味道。