由于IDA Pro反汇编二进制文件中的switch / case,我想标识跳转语句。我的最终目标是读取跳转表条目。我也对函数表/ vtables感兴趣。对于switch / case,我将跳转语句视为:


jmp ds:off_20B280CC[ebx*4]
jmp dword ptr ds:loc_6B2A825C[ecx*4] [Q:是由于switch / jump吗?]从GetOperandValue(inst.ea, 0)可以看到,这些跳转的操作数类型是“内存引用”(类型值2)。像jb short loc_6B2A8154这样的跳转语句的操作数类型为“立即临近地址”(类型值7)。但是,thunk函数中的诸如jmp ds:__imp_memset之类的跳转语句用于调用导入的函数,其操作数类型也为“内存引用”。

有什么办法可以区分switch / case和thunk函数的跳转语句?

#1 楼

在许多情况下,IDA已经知道跳转是跳转表的一部分,并且很可能是切换的结果。如果是这样,则可以使用IDAPython访问它。

相关的功能是get_switch_info_ex(ea)get_switch_info_ex(ea)
通过查看IDAPython文档,我们发现: /> calc_switch_cases(insn_ea,py_swi)

获取有关交换机的案例的信息。

返回的信息可以按如下方式使用: br />
@param insn_ea:“间接跳转”指令的地址@param si:
切换信息

@return:具有2个成员的结构:“ cases”,和'targets'。

返回值:case_and_targets_t


要从示例中获取results变量,我们使用以下代码:

for idx in xrange(len(results.cases)):
    cur_case = results.cases[idx]
    for cidx in xrange(len(cur_case)):
        print "case: %d" % cur_case[cidx]
    print "  goto 0x%x" % results.targets[idx]


因此,要检查指令是否为开关,可以使用以下功能:

si = idaapi.get_switch_info_ex(ea)
results = idaapi.calc_switch_cases(ea, si)
if not results:
    print "No switch related jump at 0x{:X}".format(ea)


如果您希望使用它,我为Sark中的IDA交换机编写了一个基本包装器类。见这里。

#2 楼

在x86体系结构上,由于switch / case语句而产生的跳转语句通常遵循以下模式:

比例因子。取决于您的编译器,搜索带有索引的内存操作数的跳转指令可能会有好的结果。高效的代码。例如:

jmp <offset> [<index-register> * 4]   ;; pointers are 4 bytes


将效率非常低地实现为表查找。因此,仅查找索引的内存操作数并不一定会在程序中找到所有开关/大小写。完全有可能确定发出序列更好
switch (foo) {
case 1: do_something(); break;
case 10000: do_something_else(); break;
case 1000000: do_final_thing(); break;
}


mov eax,table_offset[eax*4]
jmp eax


要覆盖所有基础,您将被迫使用其他技术(例如向后切片)来确定已编译的switch / case语句的目标。 。

评论


感谢您解释其他开关/案例方案。我得照顾那些。但是,作为第一步,我要弄清楚索引的内存操作数用于开关/大小写跳转。我正在使用IDA Python脚本来获取指令类型,操作数类型和值等。使用IDA Python,由于thunk函数的缘故,我仍然无法区分对索引内存引用和其他内存引用的切换/案例跳转。任何指针将不胜感激。

–苏丹娜
16-4-1在18:38



我不熟悉IDA,但是在识别了间接jmp之后,您能否将其操作码开始与FF 24 85 / 8D / 95 / 9D等进行比较。

– JohnKällén
16年4月1日在18:50