4

I want to identify the jump statements due to switch/case in an IDA Pro disassembled binary. My ultimate goal is to read the jump table entries. I am also interested in function table/vtables. For switch/case, I see the jump statements as:

  1. jmp ds:off_20B280CC[ebx*4]

  2. jmp dword ptr ds:loc_6B2A825C[ecx*4] [Q: Is it due to switch/jump?]

The operand types of these jumps, as I see from GetOperandValue(inst.ea, 0), are "Memory Reference" (type value 2). The jump statements like jb short loc_6B2A8154 has operand type "Immediate Near Address" (type value 7). However, the jump statements like jmp ds:__imp_memset in the thunk functions to call imported functions also have the operand type "Memory Reference".

Is there any way I can distinguish between jump statements for switch/case and thunk functions?

2 Answers 2

3

In many cases, IDA already knows that a jump is part of a jump-table and probably the result of a switch. When this is true, you can access it using IDAPython.

The relevant functions are get_switch_info_ex(ea) and get_switch_info_ex(ea). Looking in IDAPython's documentation, we find:

calc_switch_cases(insn_ea, py_swi)

Get information about a switch's cases.

The returned information can be used as follows:

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]

@param insn_ea: address of the 'indirect jump' instruction @param si: switch information

@return: a structure with 2 members: 'cases', and 'targets'.

Returns: cases_and_targets_t

To get the results variable from the example, we use the following code:

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)

So to check if an instruction is a switch or not, you can use the following function:

def is_switch(ea):
    si = idaapi.get_switch_info_ex(ea)
    results = idaapi.calc_switch_cases(ea, si)
    return bool(results)

If you wish to use it, I've written a basic wrapper class for IDA's switch in Sark. See here.

0

On the x86 architecture, jump statements due to switch/case statements often follow the pattern:

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

where <index-register> contains the value being switched on and the "4" is the scaling factor. Depending on your compiler may have good results searching for jump instructions with indexed memory operands.

However the compiler is free to compile switch statements into cascades of cmp and jnz statements if it determines that doing so would produce more efficient code. For instance:

switch (foo) {
case 1: do_something(); break;
case 10000: do_something_else(); break;
case 1000000: do_final_thing(); break;
}

would be terribly inefficient implemented as a table lookup. Therefore, just looking for indexed memory operands won't necessarily find all switch/cases in your program.

You need also take into account that the compiler may write the switch differently. It is fully possible that it might determine that it is better to emit the sequence

mov eax,table_offset[eax*4]
jmp eax

or, as in old hand-rolled binaries adapted from hand-written assembler written for 8086 or 80286 real mode:

shl eax,4
jmp table_offset[eax]

To cover all bases, you will be forced to use other techniques like backward slicing to determine the destinations of a compiled switch/case statement.

2
  • Thanks for explaining other switch/case scenarios. I'll have to take care of those. However, I am taking figuring out the indexed memory operands for switch/case jumps as a first step. I am using IDA Python scripting to get the instruction types, operand types and values, etc. Using IDA Python, I still cannot distinguish between switch/case jumps to indexed memory references and other memory references due to thunk functions. Any pointer would be appreciated.
    – ssultana
    Apr 1, 2016 at 18:38
  • I'm not familiar with IDA but could you, after identifying the indirect jmp, then compare that its opcode startis with FF 24 85 / 8D / 95 / 9D etc. I.e mask out the i part of the sib byte of the indirect jump? Apr 1, 2016 at 18:50

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.