求推荐识别二进制中调用约定汇编、VEX IR及函数首尾的工具方法
调用约定相关二进制分析的工具与实现方案
一、检测调用约定相关汇编指令
工具推荐
- IDA Pro/Ghidra/Binary Ninja:这类成熟的逆向工程工具内置了调用约定识别逻辑,能自动标记函数的调用约定类型(如cdecl、stdcall、fastcall等),并可直接提取函数序言、尾声及调用前后的栈操作指令。
- Capstone:轻量级汇编反汇编库,可程序化遍历二进制指令,筛选栈指针(RSP/RBP)操作、
call/ret等与调用约定强相关的指令。
实现示例(Ghidra Python脚本)
from ghidra.program.model.listing import Function currentProgram = getCurrentProgram() listing = currentProgram.getListing() # 遍历所有函数,提取调用约定相关指令 for func in currentProgram.getFunctionManager().getFunctions(True): print(f"\n=== 函数: {func.getName()} | 调用约定: {func.getCallingConventionName()} ===") # 提取序言指令 prologue_range = func.getPrologue() if prologue_range: print("序言指令:") for insn in listing.getInstructions(prologue_range, True): print(f" 0x{insn.getAddress().getOffset():x}: {insn.getMnemonicString()} {insn.getDefaultOperandRepresentation(0)}") # 提取调用后的栈清理指令(调用者负责清理的场景) for block in func.getBlocks(): for insn in listing.getInstructions(block, True): if insn.getMnemonicString() == "add" and "rsp" in insn.getDefaultOperandRepresentation(0): print(f"调用者栈清理指令: 0x{insn.getAddress().getOffset():x}: {insn}") elif insn.getMnemonicString() == "ret" and insn.getDefaultOperandRepresentation(0) != "": print(f"被调用者栈清理ret指令: 0x{insn.getAddress().getOffset():x}: {insn}")
二、筛选与调用约定相关的VEX IR语句
Angr/Valgrind的VEX IR与原始汇编指令存在地址映射关系,可通过该关联筛选目标IR:
Angr实现示例
import angr proj = angr.Project("目标二进制路径", auto_load_libs=False) cc_analysis = proj.analyses.CompleteCallingConventions() for func in proj.kb.functions.values(): if func.is_simprocedure: continue print(f"\n=== 函数: {func.name} | 地址: 0x{func.addr:x} ===") # 遍历函数基本块,关联VEX IR与汇编指令 for block in func.blocks: vex_block = block.vex # 遍历每个VEX语句,获取对应的原始汇编地址 for stmt_idx, stmt in enumerate(vex_block.statements): insn_addr = vex_block.addr + vex_block.stmt_offsets[stmt_idx] # 找到对应汇编指令 insn = next((i for i in block.capstone.insns if i.address == insn_addr), None) if insn: # 筛选栈操作、call/ret相关的IR if insn.mnemonic in ["push", "pop", "mov", "sub", "add", "call", "ret"] and \ ("rsp" in insn.op_str or "rbp" in insn.op_str or insn.mnemonic in ["call", "ret"]): print(f"汇编指令: 0x{insn_addr:x} | {insn.mnemonic} {insn.op_str}") print(f"对应VEX IR: {stmt}\n")
PyVEX直接分析示例
import pyvex # 传入二进制指令字节流转换为VEX IR insn_bytes = b'\x55\x48\x89\xe5\x48\x83\xec\x20' # x86_64序言:push rbp; mov rbp, rsp; sub rsp, 0x20 irsb = pyvex.block.IRSB(insn_bytes, 0x1000, arch='x86_64') for stmt in irsb.statements: # 筛选涉及RSP/RBP的IR语句 if isinstance(stmt, pyvex.stmt.WrTmp): # 检查是否读取或修改RSP/RBP if isinstance(stmt.data, pyvex.expr.Get): reg_name = pyvex.arch.x86_64.registers[stmt.data.offset][1] if reg_name in ["rsp", "rbp"]: print(f"IR读取{reg_name}: {stmt}") elif isinstance(stmt.data, pyvex.expr.Binop): for arg in stmt.data.args: if isinstance(arg, pyvex.expr.Get): reg_name = pyvex.arch.x86_64.registers[arg.offset][1] if reg_name in ["rsp", "rbp"]: print(f"IR运算涉及{reg_name}: {stmt}")
三、定位函数序言与尾声
工具原生方法
- Ghidra:直接调用
Function.getPrologue()和Function.getEpilogues()获取地址范围,再提取指令。 - IDA Pro:使用
get_func_attr(func, FUNCATTR_PROLOGUE_END)获取序言结束地址,get_func_attr(func, FUNCATTR_EPILOGUE_START)获取尾声起始地址。
Angr手动识别示例
import angr proj = angr.Project("目标二进制路径", auto_load_libs=False) for func in proj.kb.functions.values(): if func.is_simprocedure: continue print(f"\n=== 函数: {func.name} 序言/尾声 ===") prologue_found = False # 遍历函数前几条指令识别序言 for insn in func.capstone.insns[:10]: if insn.mnemonic == "push" and insn.op_str == "rbp": print(f"序言指令: 0x{insn.address:x}: {insn}") prologue_found = True elif prologue_found and insn.mnemonic == "mov" and insn.op_str == "rbp, rsp": print(f"序言指令: 0x{insn.address:x}: {insn}") elif prologue_found and insn.mnemonic == "sub" and "rsp" in insn.op_str: print(f"序言栈分配指令: 0x{insn.address:x}: {insn}") break # 遍历函数末尾指令识别尾声 for insn in reversed(list(func.capstone.insns[-10:])): if insn.mnemonic == "mov" and insn.op_str == "rsp, rbp": print(f"尾声指令: 0x{insn.address:x}: {insn}") elif insn.mnemonic == "pop" and insn.op_str == "rbp": print(f"尾声指令: 0x{insn.address:x}: {insn}") elif insn.mnemonic == "ret": print(f"尾声返回指令: 0x{insn.address:x}: {insn}") break
关键提示
Angr的complete_calling_conventions分析返回的是调用约定的抽象规则(如参数传递寄存器、栈清理责任方),若要获取具体指令,必须结合函数的反汇编指令流,通过地址映射关联VEX IR与原始汇编,再筛选栈操作、call/ret等关键指令。
内容的提问来源于stack exchange,提问作者Duan Chenfeng
相关产品推荐
相关产品推荐

