如何用Ghidra Python脚本获取带符号的格式化反汇编代码?
Ghidra 68000二进制反汇编脚本优化:恢复符号与无符号值格式化
问题场景
正在用Ghidra分析68000架构二进制,自带的“另存为”输出格式不满足需求,自己写Python脚本遍历代码单元后得到的结果是:
move.w #-0x5d56,(0xffffa602).w bsr.b 0x000002c2
但Ghidra列表窗口显示的是带符号和无符号值的规整格式:
move.w #0xA2AA ,(ptr_to_last_updatable_bg_area).w bsr.b set_reg_values_2e2
需要实现至少恢复地址对应符号,最好同时把带符号值转为无符号十六进制的效果。
解决方案
核心技巧:复用Ghidra内置格式化逻辑
最省心的方式是直接调用Ghidra API里已经实现的指令格式化方法,它会自动处理符号替换和无符号值转换,和列表窗口输出完全一致。
完整脚本示例
from ghidra.program.model.listing import Listing from ghidra.util.task import TaskMonitor # 获取当前程序和列表对象 program = getCurrentProgram() listing = program.getListing() monitor = TaskMonitor.DUMMY # 确定要遍历的地址范围:优先选中区域,否则取已加载内存 addr_set = currentSelection if addr_set.isEmpty(): addr_set = program.getMemory().getLoadedAndInitializedAddressSet() # 遍历每个地址的指令并输出格式化结果 for addr in addr_set.getAddresses(True): instr = listing.getInstructionAt(addr) if not instr: continue # 直接调用toString()得到和Ghidra列表一致的格式 print(instr.toString())
手动定制格式(按需使用)
如果需要自定义输出样式,可以手动解析每个操作数:
from ghidra.program.model.listing import Listing from ghidra.program.model.symbol import SymbolTable from ghidra.util.task import TaskMonitor program = getCurrentProgram() listing = program.getListing() symbol_table = program.getSymbolTable() monitor = TaskMonitor.DUMMY addr_set = currentSelection if not currentSelection.isEmpty() else program.getMemory().getLoadedAndInitializedAddressSet() for addr in addr_set.getAddresses(True): instr = listing.getInstructionAt(addr) if not instr: continue mnemonic = instr.getMnemonicString() operands = [] for i in range(instr.getNumOperands()): op = instr.getOperand(i) # 处理立即数:转无符号十六进制 if op.isImmediate(): val = op.getValue() size = instr.getOperandSize(i) if size == 2: # 16位立即数 unsigned_val = val & 0xFFFF operands.append(f"#{hex(unsigned_val).upper()}") elif size == 4: # 32位立即数 unsigned_val = val & 0xFFFFFFFF operands.append(f"#{hex(unsigned_val).upper()}") else: operands.append(op.toString()) # 处理地址操作数:替换为符号 elif op.isAddress(): op_addr = op.getAddress() symbol = symbol_table.getPrimarySymbol(op_addr) if symbol and symbol.getName(): # 根据操作数类型调整格式(比如内存操作加.w后缀) operands.append(f"({symbol.getName()}).w") else: operands.append(f"({hex(op_addr.getOffset()).upper()}).w") # 其他操作数直接用默认格式 else: operands.append(op.toString()) # 拼接成最终指令字符串 full_instr = f"{mnemonic} {' ,'.join(operands)}" print(full_instr)
关键API说明
instr.toString(): 直接复用Ghidra的内置格式化逻辑,一键得到符号化、无符号值的规整输出symbol_table.getPrimarySymbol(op_addr): 根据地址查询对应的主符号,用于手动替换地址为符号名- 位运算
val & 0xFFFF/0xFFFFFFFF: 将带符号立即数转为无符号,适配68000的16/32位数据宽度
内容的提问来源于stack exchange,提问作者T. Tournesol
相关产品推荐
相关产品推荐

