Ghidra脚本基础:Python vs Java,API入门与Hello World

说实话,我刚接触Ghidra脚本时,第一反应是——这玩意儿到底该用Python还是Java?

我当时在逆向一个嵌入式固件,函数命名全靠手动,几千个函数看得我眼冒金星。后来发现Ghidra支持脚本自动化,才算是找到了救星。今天我就把这块基础给你捋清楚。

脚本类型:Python vs Java,怎么选?

Ghidra支持两种脚本语言:Python(Jython)Java。很多人纠结选哪个,我直接说结论:

对比维度 Python(Jython) Java
上手难度 低,语法简洁 中等,需要编译
执行效率 较慢(解释执行) 快(编译执行)
API访问 完整,但部分高级功能受限 完整,无限制
调试体验 交互式,即时反馈 需要IDE支持
典型场景 快速原型、数据分析、小工具 复杂插件、性能敏感任务

我个人习惯:日常分析用Python,写插件用Java。为什么?Python改起来快,跑个脚本几秒钟就能看到结果。Java适合做那种需要反复调用的工具,比如我写过一个批量重命名插件,用Java编译一次,后面直接拖进去用。

核心要点:Ghidra的Python其实是Jython——它跑在JVM上,不是原生CPython。所以别指望能用numpy、pandas这些库。但好处是,它能直接调用Ghidra的Java API,功能上不打折扣。

API入门:你只需要记住这几个核心类

Ghidra的API很大,但常用的其实就那几个。我刚开始也被一堆类名搞晕过,后来发现抓住主线就行。

说白了,你写脚本无非就是做三件事:获取当前程序、操作函数、处理数据。对应的核心类就三个:

  • currentProgram:当前分析的程序对象,一切操作的入口
  • FunctionManager:管理所有函数,增删改查都靠它
  • Listing:程序的反汇编列表,可以遍历指令、数据

举个例子,你想拿到当前程序里所有函数的名字:

# Python脚本示例
from ghidra.program.model.listing import Function

# 获取函数管理器
fm = currentProgram.getFunctionManager()

# 遍历所有函数
for func in fm.getFunctions(True):
    print(func.getName())

这段代码我写过不下五十次。每次拿到一个新固件,第一件事就是跑一遍,看看有多少函数、命名规律是什么。

小技巧:在Ghidra脚本编辑器中,按Ctrl+Space可以触发API自动补全。我当年不知道这个,硬是一个一个类名手敲,走了不少弯路。

第一个Hello World脚本

光说不练假把式。咱们直接写一个能跑的脚本。

打开Ghidra,点击 Window → Script Manager,然后点 Create New Script。选Python,名字就叫 HelloWorld.py

把下面代码贴进去:

# HelloWorld.py
# 我的第一个Ghidra脚本

def run():
    # 获取当前程序信息
    program_name = currentProgram.getName()
    program_language = currentProgram.getLanguageID()
    
    # 输出到控制台
    print("Hello from Ghidra!")
    print("当前程序: " + program_name)
    print("语言架构: " + str(program_language))
    
    # 统计函数数量
    fm = currentProgram.getFunctionManager()
    func_count = len(list(fm.getFunctions(True)))
    print("函数总数: " + str(func_count))
    
    # 弹个对话框
    from ghidra.util import Msg
    Msg.showInfo(getClass(), "Hello World", 
                 "分析完成!\n程序: " + program_name + 
                 "\n函数数: " + str(func_count))

# 脚本入口
if __name__ == "__main__":
    run()

保存后,双击运行。你会看到控制台输出了程序信息,还弹了个对话框。

这段代码干了什么?

  • 获取了当前程序的名字和架构
  • 统计了函数总数
  • 用两种方式输出结果——控制台和对话框

嗯,这里要注意:run()函数是Ghidra脚本的约定入口。你写Python脚本时,必须定义一个run函数,否则脚本管理器找不到执行点。

我曾经踩过的坑:第一次写脚本时,我把代码直接写在文件最外层,没包在run()里。结果脚本管理器报错说找不到入口。后来才明白,Ghidra的Python脚本必须有一个run()函数作为入口点。Java脚本则是实现run()方法。

知识体系一览

为了让你更直观地理解本章内容,我画了张图:

Ghidra脚本基础核心知识体系 Ghidra脚本 脚本类型 Python (Jython) Java API核心类 currentProgram FunctionManager Listing Hello World run()入口 控制台输出 对话框输出 Python适合快速原型,Java适合复杂插件 核心API三件套:currentProgram + FunctionManager + Listing

这张图把本章的核心内容串起来了。你写脚本时,无非就是在这三个分支里打转:选语言、调API、写入口。

写在最后

脚本基础这块,说白了就是「先跑起来,再谈优化」。我见过太多人一开始就想写一个完美的插件,结果卡在环境配置上。我的建议是:先用Python写个Hello World,确认环境没问题,再慢慢深入。

你想想看,Ghidra脚本能做的事情远不止重命名。后面我们会一步步深入,但今天先把地基打牢。

课后小练习:修改上面的Hello World脚本,让它输出当前程序的所有节区(Section)名称和起始地址。提示:用currentProgram.getMemory().getBlocks()

专注资料整理