2

I want to know using IDAPython if an instruction at the end of a basic block is a jump/branch instruction (like B or JNZ) and also determine if it's conditional or not. I need it in a CPU agnostic way, without relying on mnemonics.

I cannot find how to do so by grepping in the $IDA_DIR/python directory.

  • I'm not sure I understood the phrasing, did you mean to ask if a branch is conditional or not? (i.e. the difference between JMP and Jcc instructions?) – NirIzr Nov 29 '17 at 20:53
  • I want to determine if the instructions is a branch/jump (like B or JNZ) and then also determine if it's conditional or not. But in a CPU agnostic way, without relaying on mnemonics. – joxeankoret Dec 1 '17 at 9:02
3

You can try this function that I wrote which worked just fine in some quick tests I did. You might need to implement more code to handle edge cases, but in general it should work.

The function was written with the following generic assumptions (which isn't always true):

  • A Branch\Jump instruction has at least one local reference
  • A Conditional Branch would have the flow continued to the next instruction in True/False cases.

And here's the code which is commented where I think it'd be helpful:

from idaapi import *
from idc import *

def check_conditional(func_ea, addr):
    # Get: function's base address, suspicious branch/jmp address
    # Returns: a strings which says whether the address is a Conditional Branch, Unconditional Branch or neither

    f_start = get_func(func_ea).startEA
    f_end = FindFuncEnd(f_start)

    # Get local function's references made from the instruction
    refs = CodeRefsFrom(addr, 0)
    refs = set(filter(lambda x: x>=f_start and x<=f_end, refs)) 
    if refs:
        # Add a reference to the next instruction if the flow continues to it
        next_head = NextHead(addr, f_end)
        if isFlow(GetFlags(next_head)):
            # refs holds the referenced address so you can use them later
            refs.add(next_head)
            return "Conditional Branch"
        else:
            return "Unconditional Branch"           
    else:
        return "Not JMP/Branch at all"
  • I was thinking about something similar but wanted to get a cleaner solution – NirIzr Dec 2 '17 at 9:02
1

This solution isn't 100% architecture agnostic but it is a little simpler and shouldn't be too difficult to add support for architectures with delay slots. If you are just interested whether the flow is conditional or not then you can ignore the Rfirst0 part.

def conditional_branches_for(ea):
    func = idaapi.get_func(ea)

    for basicblock in idaapi.FlowChart(func):
        # Insert logic here for getting branch for archs with delay slots
        last_ea = PrevHead(basicblock.endEA)

        # Get any Xrefs that are not part of the regular flow
        if Rfirst0(last_ea) == idaapi.BADADDR:
            print('Skipping {:#x} because it is not a branch'.format(last_ea))
            continue

        successors = len(tuple(basicblock.succs()))
        if successors == 0:
            branch_type = 'does not branch'
        elif successors == 1:
            branch_type = 'has an unconditional branch'
        else:
            branch_type = 'has a conditional branch'

        print('BasicBlock at {:#x} {}'.format(last_ea, branch_type))

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.