You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求推荐识别二进制中调用约定汇编、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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 06:53:23