4、Ghidra脚本入门:Python脚本插件安装、Headless模式、基础API调用、脚本调试

说实话,Ghidra 最让我着迷的地方,就是它的脚本系统。你想想看,一个逆向工具再强大,如果只能点点鼠标,那跟用计算器做微积分有什么区别?真正的高手,都是用脚本把重复劳动自动化,把复杂逻辑封装起来。这一章,我就带你走一遍 Ghidra 脚本的入门之路。

4.1 Python脚本插件安装

Ghidra 默认支持 Java 和 Python 两种脚本语言。Java 是亲儿子,性能好,API 最全。但 Python 呢?上手快,生态好,我个人的主力语言就是 Python。所以咱们先从 Python 说起。

Ghidra 的 Python 支持,靠的是一个叫 Jython 的东西。Jython 是 Java 平台上的 Python 实现,说白了,就是用 Java 写了一个 Python 解释器。所以你的 Python 脚本,本质上还是在 JVM 里跑,能直接调用 Ghidra 的 Java API。

注意:Ghidra 内置的是 Jython 2.7,不是 Python 3。所以写脚本时别用 Python 3 的语法,比如 print 要加括号,但 range 返回的是列表不是迭代器。我曾经有个同事,上来就写 f-string,结果跑不动,排查了半天。

安装步骤其实很简单:

  1. 打开 Ghidra,进入 File → Configure → Experimental
  2. 勾选 Python 插件(如果没看到,可能需要手动下载 jython-standalone.jar)
  3. 重启 Ghidra
  4. 点击 Window → Script Manager,就能看到 Python 脚本了

我个人习惯,装好之后先跑一个 Hello World 试试:

# hello.py
print("Hello from Ghidra Python!")
print("Current program: ", getCurrentProgram().getName())

点一下运行,如果控制台输出了信息,那就成了。

4.2 Headless模式:让脚本飞起来

GUI 模式虽然方便,但你要批量分析几百个二进制文件呢?一个个打开、运行脚本、关闭?那不得累死。这时候就需要 Headless 模式了。

Headless 模式,就是不带界面的 Ghidra。它可以在命令行里运行,适合自动化、服务器部署、CI/CD 流程。

启动命令长这样:

./analyzeHeadless /path/to/project TempProject \
  -import /path/to/binary \
  -postScript /path/to/script.py \
  -deleteProject

参数解释一下:

  • /path/to/project:Ghidra 项目存放目录
  • TempProject:临时项目名,用完就删
  • -import:要分析的二进制文件
  • -postScript:分析完成后运行的脚本
  • -deleteProject:跑完就删项目,省空间
小技巧:我经常用 -preScript-postScript 组合。preScript 做初始化,postScript 做分析。比如 preScript 里设置分析选项,postScript 里导出结果。

Headless 模式还有一个好处:可以并行跑。我曾在一次项目中,用 8 个进程同时分析 200 个固件,一晚上全搞定。要是手动操作,估计得一周。

4.3 基础API调用:你得知道这些

Ghidra 的 API 非常庞大,但常用的其实就那么几个。我帮你梳理一下最核心的:

API 类别 常用函数/类 作用
程序信息 getCurrentProgram() 获取当前分析的程序对象
函数操作 getFunctionManager() 获取函数管理器,遍历所有函数
指令遍历 getListing() 获取指令列表,逐条分析
内存访问 getMemory() 读取/写入内存数据
符号/引用 getReferenceManager() 查找交叉引用、字符串引用

举个例子,我想遍历所有函数,打印函数名和地址:

from ghidra.program.model.listing import Function

fm = getCurrentProgram().getFunctionManager()
functions = fm.getFunctions(True)

for func in functions:
    name = func.getName()
    addr = func.getEntryPoint()
    print(f"Function: {name} @ {addr}")

嗯,这里要注意:getFunctions(True) 里的 True 表示正向遍历。如果你传 False,那就是反向遍历,从地址高的往低的走。

再比如,我想找所有对某个字符串的引用:

from ghidra.program.model.symbol import RefType

target_str = "password"
data_mgr = getCurrentProgram().getListing()
data = data_mgr.getDefinedData(True)

for d in data:
    if d.isString() and str(d.getValue()) == target_str:
        refs = getCurrentProgram().getReferenceManager().getReferencesTo(d.getAddress())
        for ref in refs:
            print(f"Reference from: {ref.getFromAddress()}")

这段代码我实际用过。当时分析一个恶意软件,它把 C2 服务器地址藏在字符串表里,我就是用这个脚本把所有引用点找出来的。

4.4 脚本调试:别怕,有办法

写脚本哪有不 debug 的?Ghidra 的脚本调试,说实话,没有 IDE 那么方便。但有几个技巧能帮你省不少时间。

第一招:print 大法

最简单也最有效。在关键位置加 print(),看变量值、看执行流程。Ghidra 的控制台会输出所有 print 内容。

print("DEBUG: current address = ", addr)
print("DEBUG: function count = ", len(list(functions)))

第二招:使用 monitor 对象

Ghidra 的脚本 API 里有一个 monitor 对象,可以用来检查用户是否取消了操作,也可以输出进度。

from ghidra.util.task import TaskMonitor

# 检查是否被取消
if monitor.isCancelled():
    print("User cancelled!")
    return

# 更新进度
monitor.setMessage("Processing function " + str(i))
monitor.setProgress(i)

第三招:异常捕获

脚本跑着跑着崩了,最烦人。我习惯在关键代码段加 try-except:

try:
    # 你的分析逻辑
    result = do_something()
except Exception as e:
    print("Error at address", addr, ":", str(e))
    # 记录错误,继续执行
    pass
避坑指南:我曾经写过一个脚本,遍历所有指令,结果遇到一个畸形指令,直接抛异常把整个脚本搞崩了。加了 try-except 之后,至少能跑完,把错误信息记录下来,回头再修。

第四招:分段测试

别一次性写几百行。写一个小功能,跑一下,确认没问题,再往下写。我一般把脚本拆成几个函数,每个函数单独测试。

4.5 知识体系总览

说了这么多,我画了一张图,帮你把这一章的核心逻辑串起来:

Ghidra 脚本入门知识体系 Ghidra 脚本 Python 插件安装 Jython 2.7 环境 Headless 模式 批量分析 / 自动化 / CI/CD 基础 API 调用 函数 / 指令 / 内存 / 引用 脚本调试技巧 print / monitor / try-except 目标:自动化逆向分析,提升效率

这张图把四个核心模块串起来了。你从安装 Python 插件开始,学会在 GUI 里写脚本。然后掌握 Headless 模式,让脚本脱离界面运行。接着熟悉基础 API,知道怎么操作函数、指令、内存。最后学会调试技巧,遇到问题不慌。

说白了,脚本就是你的武器。用得好了,别人还在手动翻汇编,你已经把结果导出成 CSV 了。我见过太多人,花大量时间做重复劳动,其实写个脚本十分钟就能搞定。嗯,这一章的内容就这些,去试试吧。


专注资料整理