如何在 IDAPython 中查找所有开关跳转表

逆向工程 艾达 蟒蛇 idapro插件 反汇编者 idapro-sdk
2021-06-14 00:50:05

我在 IDA 6.5 上使用 IDAPython,我试图在 DLL 中获取所有开关跳转表。我主要对间接跳转的跳转表感兴趣:

jmp     ds:off_65018790[ecx*4] ; switch jump

基本上,我感兴趣的是:

  • jmp 发生的地址
  • 可能的位置列表,例如 - loc_65018723、loc_65018736...

我已经知道如何使用 IDAPython 获取所有 jmp 地址,但我不知道它是跳转表的 jmp 还是普通的 jmp。

在大多数情况下,IDA 知道识别那些跳转表,那么有没有办法从 API 中获取这些信息?

非常感谢!

2个回答

决定添加一个小代码片段来展示如何遍历 .text 段,获取所有开关表位置并将跳转目标存储在字典中。

text_seg = idaapi.get_segm_by_name('.text')
jump_table = dict()

# iterate through all items within the segment
for head_ea in idautils.Heads(text_seg.startEA, text_seg.endEA):
    if idc.isCode(idc.GetFlags(head_ea)):
        switch_info = idaapi.get_switch_info_ex(head_ea)
        if (switch_info and switch_info.jumps != 0):
            loc = switch_info.jumps
            jump_table[loc] = list()
            element_num = switch_info.get_jtable_size()
            element_size = switch_info.get_jtable_element_size()
            for num in range(0, element_num):
                table_entry = loc+num*element_size
                jump_table[loc].append(idc.GetManyBytes(table_entry), element_size)

更新:在此基础上为新版本的 IDA 构建

def find_jumps(si: ida_nalt.switch_info_t) -> list:
    jtable = []
    e_size = si.get_jtable_element_size()

    for num in range(0, si.get_jtable_size()):
        jtable.append(int.from_bytes(ida_bytes.get_bytes(si.jumps + (num * e_size), e_size), 'little') + si.elbase)

    return jtable

ea = 0x0000000000000000 # some ea
si = ida_nalt.switch_info_t()
if (ida_nalt.get_switch_info(si, ea) is not None): # jump table
    jtable = find_jumps(si)

如果成功,这将解决IDA 提供elbaseswitch_info_t结构的偏移量get_switch_info请参阅:https : //hex-rays.com/products/ida/support/idapython_docs/ida_nalt.html#ida_nalt.switch_info_t.elbase了解更多信息,c++如果需要,请在https://hex交叉参考支持-rays.com/products/ida/support/sdkdoc/structswitch__info__t.html

为了安全地从某个 获取所有引用EA,有idc.XrefsFrom(ea, flags). 您将获得一个迭代器,用于来自某个EA(开关案例的分支/跳转指令)的交叉引用切换案例很容易识别,因为它们总是有两个以上的交叉引用目标。

根据这个flags参数是以下情况之一:

XREF_USER = 32
XREF_TAIL = 64
XREF_BASE = 128
XREF_MASK = 31
XREF_PASTEND = 256
XREF_ALL = 0
XREF_FAR = 1
XREF_DATA = 2

您将从每次迭代中获得的ida_xref对象是一个对象,公开以下属性:

  1. frm - 交叉引用的来源,在我们的例子中执行跳转的代码。
  2. to - 交叉引用的目标,在我们的例子中将根据跳转表选择器执行的代码。
  3. iscode- 布尔值,True如果交叉引用是代码交叉引用,True在我们的例子中必须是
  4. type- 可用的类型值之一,见下文。您可以使用idautils.XrefTypeName(typecode)将您在此处获得的整数转换为可读字符串。
  5. user - Boolean,如果此交叉引用是由用户创建的,则为 True,而不是由 IDA 自动创建。

有效交叉引用类型是,根据

ref_types = {
0:'Data_Unknown',
1:'Data_Offset',
2:'Data_Write',
3:'Data_Read',
4:'Data_Text',
5:'Data_Informational',
16:'Code_Far_Call',
17'Code_Call' ,
18 : 'Code_Far_Jump',
19 : 'Code_Near_Jump',
20 : 'Code_User',
21 : 'Ordinary_Flow'
}