2. 遍历加载命令
任务说明
本案例目标是在Ghidra中编写Java脚本,遍历当前程序中所有Mach-O加载命令(Load Command),输出每条命令的类型、在文件中的偏移量以及命令大小。脚本需兼容Ghidra对Mach-O文件的解析接口,可直接在Ghidra脚本管理器中运行。
实现原理
Ghidra通过MachoHeader和LoadCommand接口暴露Mach-O解析结果。每个LoadCommand对象提供getCommandType()获取命令类型枚举、getCommandOffset()获取命令起始偏移、getCommandLength()获取命令总长度(含cmd和cmdsize字段)。脚本只需遍历header返回的命令列表即可完成目标。
完整代码
import ghidra.app.script.GhidraScript;
import ghidra.app.util.bin.format.macho.MachoHeader;
import ghidra.app.util.bin.format.macho.commands.LoadCommand;
import ghidra.program.model.listing.Program;
public class ListLoadCommands extends GhidraScript {
@Override
public void run() throws Exception {
Program program = getCurrentProgram();
if (program == null) {
println("请先打开一个Mach-O二进制文件");
return;
}
// 获取Mach-O头信息(Ghidra解析后缓存于program中)
MachoHeader header = MachoHeader.getMachoHeader(program);
if (header == null) {
println("当前程序不是有效的Mach-O文件,或Ghidra未能解析其头部");
return;
}
LoadCommand[] commands = header.getLoadCommands();
if (commands == null || commands.length == 0) {
println("未找到任何加载命令");
return;
}
println("=== Mach-O加载命令列表 ===");
println(String.format("%-30s %-12s %-10s", "命令类型", "偏移(hex)", "大小"));
println("------------------------------------------------------");
for (LoadCommand cmd : commands) {
String typeName = cmd.getCommandType().toString();
long offset = cmd.getCommandOffset();
int length = cmd.getCommandLength();
println(String.format("%-30s 0x%08x %d", typeName, offset, length));
}
}
}
运行方式
- 在Ghidra中打开一个Mach-O格式的二进制文件(如iOS应用的可执行文件或macOS命令行工具),等待自动分析完成。
- 点击 Window → Script Manager,在脚本目录中新建Java脚本,将上述代码粘贴保存为
ListLoadCommands.java。 - 在脚本管理器中选中该脚本,点击Run执行。
验证方法
脚本执行后,控制台输出应满足以下条件即判定通过:
- 输出以
=== Mach-O加载命令列表 ===开头,且包含表头行。 - 每一行对应一条加载命令,包含命令类型名称、十六进制偏移和十进制大小。
- 命令类型名称与Ghidra中
LoadCommandType枚举一致(如LC_SEGMENT_64、LC_LOAD_DYLIB等)。 - 偏移值递增,且每条命令的偏移+大小等于下一条命令的偏移(或等于文件末尾),验证遍历完整性。
若使用系统自带的/bin/ls(Mach-O格式)作为测试对象,预期输出中应包含LC_SEGMENT_64、LC_LOAD_DYLIB、LC_MAIN等常见命令类型,且首条命令偏移通常为0x0(对应LC_SEGMENT_64)。
常见问题
- 脚本报错
MachoHeader.getMachoHeader返回null:确认当前程序确为Mach-O格式,且Ghidra已完成解析(可查看Program Properties中的格式信息)。若仍失败,尝试重新分析文件(Analyze → Auto Analyze)。 - 输出为空:部分瘦二进制(FAT)包含多个架构,Ghidra默认解析当前选中的架构。若需查看其他架构,需在导入时选择具体架构切片。