2

I'm using IDAPython on IDA 6.5 and I'm trying to get all the switch jump tables in a DLL. Mainly I'm interested in jump tables that are jumped indirectly:

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

Basically, what interests me is:

  • The address from where the jmp happens
  • The list of the possible locations, for example - loc_65018723, loc_65018736...

I already know how to get all the jmp addresses using IDAPython, but I don't know if it's a jmp to a jump table or just a normal jmp.

In most cases, IDA knows to identify those jump tables, so is there a way to get that info from the API?

Thanks a lot!

2
  • Unfortunately I don't have IDA 6.5 installed, but as far as I remember idaapi.get_switch_info_ex(ea) already was there. The simplest way to see reference usage of this function is searching python code with call to this function on github.
    – w s
    Aug 25, 2016 at 9:12
  • Thanks a lot! It was exactly what I needed. If you post it as an answer, I will mark it as answered :)
    – Alex
    Aug 26, 2016 at 11:42

2 Answers 2

2

Decided to add a small code snippet to show how to iterate through the .text segment, obtaining all the switch table locations and storing the jump targets in a dictionary.

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)

Update: To build upon this for newer versions of 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)

This resolves the offsets to the with respect to elbase of the switch_info_t structure which IDA provides if get_switch_info is succesful. See: https://hex-rays.com/products/ida/support/idapython_docs/ida_nalt.html#ida_nalt.switch_info_t.elbase for more information, and cross reference this to the c++ support if need-be at https://hex-rays.com/products/ida/support/sdkdoc/structswitch__info__t.html

3
  • getnseg receives a segment number, while SegByName returns a segment selector, these are not the same thing. Your first line is erroneous.
    – NirIzr
    Sep 9, 2016 at 10:38
  • Additionally, using idc.Dword feels insecure and assumes the switch code is indeed structured the way OP described, which isn't always the case.
    – NirIzr
    Sep 9, 2016 at 10:48
  • Thanks Nirlzr, the above snippet comes from my old script I used on ARM32 binaries to extract out jumptables in order to rewrite them. I've updated it to fix the mistakes you've pointed out.
    – chuazl
    Sep 10, 2016 at 9:32
0

To safely get all references from a certain EA, there's idc.XrefsFrom(ea, flags). You'll get an iterator for cross references from a certain EA (the switch-case's branch/jump instruction). switch-cases are easy to identify as they're always with more than two cross references targets.

According to this the flags parameter is one of the following:

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

The object you'll get from each iteration is an ida_xref object, exposing the following attributes:

  1. frm - The source of the cross reference, the code that performs the jump in our case.
  2. to - The target of the cross reference, the code that will be executed according to the jump table selector in our case.
  3. iscode - Boolean, True if cross reference is a code cross reference, must be True in our case.
  4. type - One of the available type values, see below. You could use idautils.XrefTypeName(typecode) to translate the integer you get here to a readable string.
  5. user - Boolean, True if this cross reference was created by the user, opposed to being automatically created by IDA.

The valid cross reference types are, according to this:

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_Near_Call',
18 : 'Code_Far_Jump',
19 : 'Code_Near_Jump',
20 : 'Code_User',
21 : 'Ordinary_Flow'
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.