IDA:确定指令是从内存读取还是写入内存的通用方法?

逆向工程 艾达 拆卸 部件 蟒蛇 idapro-sdk
2021-07-10 03:47:48

我想确定指令 a) 是从内存地址读取还是 b) 写入内存地址。我目前可以想到 IDA 中的两种方法:

  1. 寻找助记符列表(更好:特定操作码?),例如对于 x86,请参见此处并手动将它们中的每一个映射到read, write

    这对我来说似乎不是很优雅。

  2. 使用该idc.GetOpType(ea, n)函数并检查相关o_*常量(请参阅此处),即:

    o_mem      = idaapi.o_mem       # Direct Memory Reference  (DATA)      addr
    o_phrase   = idaapi.o_phrase    # Memory Ref [Base Reg + Index Reg]    phrase
    o_displ    = idaapi.o_displ     # Memory Reg [Base Reg + Index Reg + Displacement] phrase+addr
    

    然而,这些并没有告诉我指令是从内存读取还是写入内存。

有没有更好的方法来找出我想要的东西?理想的方式适用于多个 CPU 架构?

3个回答

虽然 API 可能很麻烦,但在静态分析期间,您要查找的大部分信息都可以从 IDA“轻松”获得。其中一些有点通用,而其他部分需要根据处理器类型进行不同的处理。

要检查操作数是否对内存执行读或写访问,您可以使用以下命令:

import idaapi
import idautils
import idc

OPND_WRITE_FLAGS = {
    0: idaapi.CF_CHG1,
    1: idaapi.CF_CHG2,
    2: idaapi.CF_CHG3,
    3: idaapi.CF_CHG4,
    4: idaapi.CF_CHG5,
    5: idaapi.CF_CHG6,
}

OPND_READ_FLAGS = {
    0: idaapi.CF_USE1,
    1: idaapi.CF_USE2,
    2: idaapi.CF_USE3,
    3: idaapi.CF_USE4,
    4: idaapi.CF_USE5,
    5: idaapi.CF_USE6,
}

def print_insn_mem_interaction(ea):
    insn = idautils.DecodeInstruction(ea)

    # The features are needed for operand flags.
    feature = insn.get_canon_feature()

    for op in insn.Operands:
        # You always get 6 operands. Some of them are set to `o_void` to indicate
        # that they are not used.
        if op.type == idaapi.o_void:
            break

        # There are 3 types of memory references in IDA. We want all 3.
        is_mem = op.type in (idaapi.o_mem, idaapi.o_phrase, idaapi.o_displ)

        # Extract per-operand read/write status from the feature.
        is_write = feature & OPND_WRITE_FLAGS[op.n]
        is_read = feature & OPND_READ_FLAGS[op.n]

        if not is_mem:
            # Operand does not access memory.
            continue

        # Ugly line for the display. Sorry.
        action = 'memory {}'.format('/'.join(filter(bool, ('read' if is_read else None, 'write' if is_write else None))))

        print 'Operand[{}]<{}> : {}'.format(op.n, idc.GetOpnd(ea, op.n), action)

但是,告诉访问的地址是另一回事。

o_displo_phrase操作数的解析特定于处理器类型,并且完全没有记录(实际上,文档说随心所欲)。如果您对适用于 x86 和 x64 的解析器感兴趣,可以在此处查看我的代码

如果您需要使用任何其他架构,我建议您使用更脚本友好的反汇编程序。在这方面,Capstone可能是一个不错的选择。

最后,如果您需要实际地址,您可能不得不求助于动态分析。

除了动态分析(如评论中建议的那样)之外,无法从 IDA 获取该信息。

IDA 不维护完整的中间表示(也称为中间语言),并且 IDA 无法获得此类信息,主要是因为它不需要反汇编程序的实现。然而,反编译器需要它,因此 hex-rays 反编译器可能实现了更完整的 IR,但不能让用户访问它。

通常使用IL将每条汇编指令翻译成多条中间语言指令,共同达到与原始指令相同的目的。这将指令转化为不那么复杂且更易于操作/处理的操作。

有提供或实现 IL 的开源工具,例如OpenREIL,您可以在 IDA 之外使用它们(特别是它有STMLDM说明)。

如果您有 IDA Pro 6.x,那么解决方案非常简单:https : //www.hex-rays.com/products/ida/support/tutorials/tracing.pdf