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()方法。
知识体系一览
为了让你更直观地理解本章内容,我画了张图:
这张图把本章的核心内容串起来了。你写脚本时,无非就是在这三个分支里打转:选语言、调API、写入口。
写在最后
脚本基础这块,说白了就是「先跑起来,再谈优化」。我见过太多人一开始就想写一个完美的插件,结果卡在环境配置上。我的建议是:先用Python写个Hello World,确认环境没问题,再慢慢深入。
你想想看,Ghidra脚本能做的事情远不止重命名。后面我们会一步步深入,但今天先把地基打牢。
课后小练习:修改上面的Hello World脚本,让它输出当前程序的所有节区(Section)名称和起始地址。提示:用currentProgram.getMemory().getBlocks()。