Esempio n. 1
0
    def _btn_trace_color_clicked(self):
        col = 0xccffcc
        col2 = 0xbbeebb

        if False:
            for ea, basic_block in self.infoparser.basic_blocks.iteritems():
                while ea != idaapi.BADADDR:
                    idc.set_color(ea, idc.CIC_ITEM, col)
                    ea = idc.next_head(ea, basic_block['end'])

            for target_pc, flow in self.infoparser.flows.iteritems():
                refs = []
                for xref in idautils.XrefsTo(target_pc):
                    refs.append(xref.frm)

                for jump_from_pc, flowtype in flow.iteritems():

                    if jump_from_pc in refs:
                        continue

                    if ida_ua.ua_mnem(jump_from_pc) == 'call':
                        flowtype = idaapi.fl_CN
                    else:
                        flowtype = idaapi.fl_JN

                    idc.set_color(jump_from_pc, idc.CIC_ITEM, col2)
                    idc.AddCodeXref(jump_from_pc, target_pc, flowtype)
Esempio n. 2
0
def add_call_xref(frm, to):
    """
    Add XREF to a call function
    @param frm: EA of From address (The CALL instruction address)
    @param to: EA of To Address (The called funciton address)
    @return: True if XREF was added successfully, otherwise False
    """
    return idc.AddCodeXref(frm, to, 0x31)
    def objc_msgsend_xref(self,
                          call_ea,
                          objc_self,
                          objc_selector,
                          create_xref=True):
        '''
        This function will create a code xref to an objc method
        
        call_ea : location of call/jmp objc_msgsend (regardless of direct/indirect)
        objc_self: ea where RDI is set to static value (or that we find it's from a previous call or the RDI of the current function)
        objc_selector: ea where RSI is set to static value
        
        This ignores the RDI register, which is the `self` argument to objc_msgsend()
        id objc_msgSend(id self, SEL op, ...);
        So far, this seems to be fine as far as the cross-references are concerned.

        '''

        # get instruction mnemonic at address - I guess to check and make sure
        # it's mov rsi, blah
        instruction = idc.GetDisasm(objc_selector)
        if self.debugflag:
            print ">>> objc_msgsend_xref 0x%08x %s" % (objc_selector,
                                                       instruction)

        # get outbound references in the appropriate segment
        # implicit assumption is there is exacltly one
        target_selref = None
        for _ref in idautils.DataRefsFrom(objc_selector):
            if idc.SegName(_ref) == "__objc_selrefs":
                target_selref = _ref

        if not target_selref:
            return False

        # get outbound references in the appropriate segment
        # implicit assumption is there is exacltly one
        target_methname = None
        for _ref in idautils.DataRefsFrom(target_selref):
            if idc.SegName(_ref) == "__objc_methname":
                target_methname = _ref

        if not target_methname:
            return False

        # get inbound references
        # __objc_const
        # must be a __objc2_meth
        # I hope this method is correct to find __objc2_meth structs
        # BUG: when the binary has mutiple objc methods by the same name, this logic fails
        # Track RDI register. have to figure out what instance/class is referenced
        objc2_meth_struct_id = ida_struct.get_struc_id("__objc2_meth")
        meth_struct_found = False
        target_method = None
        for _ref in idautils.DataRefsTo(target_methname):
            # multiple may match
            # we care about the __obj2_meth struct found in references
            if idc.SegName(_ref) == "__objc_const":
                # check the outbound references
                for _meth_ref in idautils.DataRefsFrom(_ref):
                    if _meth_ref == objc2_meth_struct_id:
                        meth_struct_found = True

                if meth_struct_found:
                    # only do this once
                    # TODO: check against RDI here to make sure it's the proper class
                    # meth_struct_found = False

                    for _meth_ref in idautils.DataRefsFrom(_ref):
                        # assumption made on function always being in text segment
                        if idc.SegName(_meth_ref) == "__text":
                            # save the method implementation -- this is the function ptr
                            if self.debugflag:
                                print "0x%08x checking for the proper method -- %s" % (
                                    _meth_ref,
                                    idc.get_name(
                                        idc.get_func_attr(
                                            _meth_ref, idc.FUNCATTR_START)))
                            target_method = _meth_ref

        if not target_method:
            return False

        # After dereferencing across the IDB file, we finally have a target function.
        # In other words, if there isn't a method **in this binary** no xref is made (IDA only loads one binary?)
        # that is referenced from the mov rsi, <selector> instruction
        if self.debugflag: print "Found target method 0x%08x" % target_method
        if create_xref:
            idc.AddCodeXref(objc_selector, target_method, idc.fl_CF)

        return True
Esempio n. 4
0
def import_branches(data_json, resolver):
    image_functions = set(idautils.Functions())
    image_base = idaapi.get_imagebase()

    n_new_functions = 0
    n_new_xrefs = 0

    for element in data_json["indirect_branches"]:
        # Rebase all the addresses.
        call_addr = resolver.rebase(element["from"], image_base)
        refs = map(lambda x: resolver.rebase(x, image_base), element["to"])

        # If not present in ida's function list, add it.
        if not call_addr in image_functions:
            # assert idc.MakeCode(call_addr) != 0
            # assert idc.MakeFunction(call_addr) != 0
            # image_functions.add(call_addr)
            # print "Creating function @ %.16x" % call_addr
            n_new_functions += 1

        # Get the references
        function_xrefs = [x.frm for x in idautils.XrefsTo(call_addr, 0)]

        # Add the references if missing.
        for ref in refs:
            if not ref in function_xrefs:
                print "Creating XREF from %.16x to %.16x" % (call_addr, ref)

                # Make code just in case.
                idc.MakeCode(call_addr)
                idc.MakeCode(ref)

                idc.AddCodeXref(call_addr, ref, idc.XREF_USER | idc.fl_CN)
                n_new_xrefs += 1

    for element in data_json["direct_branches"]:
        # Rebase all the addresses.
        func_addr = resolver.rebase(element["function"], image_base)
        refs = map(lambda x: resolver.rebase(x, image_base),
                   element["references"])

        # If not present in ida's function list, add it.
        if not func_addr in image_functions:
            # assert idc.MakeCode(func_addr) != 0
            # assert idc.MakeFunction(func_addr) != 0
            # image_functions.add(func_addr)
            print "Creating function @ %.16x" % func_addr
            n_new_functions += 1

        # Get the references
        function_xrefs = [x.frm for x in idautils.XrefsTo(func_addr, 0)]

        # Add the references if missing.
        for ref in refs:
            if not ref in function_xrefs:
                print "Creating XREF from %.16x to %.16x" % (ref, func_addr)
                # idc.AddCodeXref(ref, func_addr, idc.XREF_USER | idc.fl_CN)
                n_new_xrefs += 1

    print "Created %d new functions" % n_new_functions
    print "Created %d new xrefs" % n_new_xrefs
Esempio n. 5
0
    def NasmAssemble(self, function_ea, write_ea):
        dir = self.opty_dir

        nasm = "C:\\Program Files\\nasm\\nasm.exe"
        arg1 = "f_%08x.asm" % function_ea
        arg2 = "-o f_%08x.o" % function_ea
        arg3 = "-l f_%08x.lst" % function_ea
        arg4 = "-Ox"

        orig_dir = os.getcwd()
        os.chdir(dir)

        idc.Batch(0)
        while 1:
            try:
                p = subprocess.Popen([nasm, arg1, arg2, arg3, arg4],
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE,
                                     stdin=subprocess.PIPE)
                o, e = p.communicate()

                if o != "": print o
                if e != "": print e

                fop = open("f_%08x.o" % function_ea, "rb")

                ans = idaapi.askyn_c(
                    0,
                    "HIDECANCEL\nDo you want to manually edit function before writing to IDA?"
                )
                if ans == 1:
                    os.startfile(arg1, "open")
                    idaapi.warning(
                        "Press OK button when you're done editing file.")
                    fop.close()
                    continue
                else:
                    idc.Batch(1)
                    break

            except:
                error_msg = '\n'.join(e.split("\n")[:15])

                os.startfile(arg1, "open")
                ans = idaapi.askyn_c(
                    1, """HIDECANCEL\nNASM failed to assemble [f_%08x.o] file.
You can manually edit and NASM this file [f_%08x.asm] and click Yes when you're done.
File is located in directory where your IDB is located.
If you want to skip this function press No.

Nasm output:
%s""" % (function_ea, function_ea, error_msg))

                if ans == 1:
                    continue
                else:
                    os.chdir(orig_dir)
                    idc.Batch(1)
                    return None

        os.chdir(orig_dir)

        print ">>>Writing function [%08x] @ [%08x]" % (function_ea, write_ea)

        data = fop.read()
        data_len = len(data)
        for offset in xrange(0, data_len):
            idc.PatchByte(write_ea + offset, ord(data[offset]))
        fop.close()

        idc.MakeCode(write_ea)

        fp = open("%s\\f_%08x.lst" % (dir, function_ea), "r")
        asm_lst = fp.read()

        base_addr = re.search(r"ORG ([\dABCDEF]+)H", asm_lst).group(1)
        base_addr = int(base_addr, 16)

        for jt in self.jmp_table_refs:
            m = re.search(r"\s*\d+\s+([\dABCDEF]{8}).*?%s" % re.escape(jt),
                          asm_lst, re.IGNORECASE)
            if m != None:
                jt_ea = int(m.group(1), 16)
                jt_str = re.search(r"SJ_.{8}", jt, re.IGNORECASE).group()
                for m in re.findall(
                        r"(?i)\n\s*\d+\s+[\dABCDEF]{8}\s+.*?\s+%s" %
                        re.escape(jt_str), asm_lst):
                    r = re.search(r"\d+\s([\dABCDEF]{8})", m.strip(),
                                  re.IGNORECASE).group(1)

                    #print "AddCodeXref(0x%08x, 0x%08x, idc.XREF_USER)" % (jt_ea+base_addr, idc.Dword(int(r, 16)+base_addr))
                    idc.AddCodeXref(jt_ea + base_addr,
                                    idc.Dword(int(r, 16) + base_addr),
                                    idc.XREF_USER)
            else:
                raise MiscError

        for line in asm_lst.split("\n"):
            comment = re.search(r"###(.*?)###", line)
            if comment != None:
                data = re.search(r"\s*\d+\s([\dABCDEF]+)\s([\dABCDEF\(\)]+)",
                                 line)
                if data != None:
                    offset = int(data.group(1), 16)
                    idc.MakeComm(write_ea + offset, comment.group(1))

        fp.close()

        return write_ea + data_len + 10
Esempio n. 6
0
def scanDataForRelocs(M, D, start, end, new_eas, seg_offset):
    i = start
    while i < end:
        more_dref = [d for d in idautils.DataRefsFrom(i)]
        dref_size = idc.ItemSize(i) or 1
        if len(more_dref) == 0 and dref_size == 1:
            dword = readDword(i)
            DEBUG("Testing address: {0:x}... ".format(i))
            # check for unmakred references
            if isInData(dword, dword+1):
                idc.MakeDword(i)
                idc.add_dref(i, dword, idc.XREF_USER|idc.dr_O)
                DEBUG("making New Data Reference at: {0:x} => {1:x}\n".format(i, dword))
                dref_size = 4
            elif isInternalCode(dword):
                idc.MakeDword(i)
                idc.AddCodeXref(i, dword, idc.XREF_USER|idc.fl_F)
                DEBUG("making New Code Reference at: {0:x} => {1:x}\n".format(i, dword))
                dref_size = 4
            else:
                DEBUG("not code or data ref\n")

        i += dref_size

    def insertReference(M, D, ea, pointsto, seg_offset, new_eas):
        # do not make code references for mid-function code accessed via a JMP -- 
        # they will be found via the jumptable code. This prevents the insertion
        # of lots of extra code, but could be wrong for some cases
        if ea in ACCESSED_VIA_JMP and not isStartOfFunction(pointsto):
            # bail only if we are access via JMP and not the start
            # of a function
            DEBUG("\t\tNOT ADDING REF: {:08x} -> {:08x}\n".format(ea, pointsto))
            return

        DEBUG("\t\tFound a probable ref from: {0:x} => {1:x}\n".format(ea, pointsto))
        real_size = idc.ItemSize(pointsto)
        DEBUG("\t\tReal Ref: {0:x}, size: {1}\n".format(pointsto, real_size))
        insertRelocatedSymbol(M, D, pointsto, ea, seg_offset, new_eas, real_size)

    def checkIfJumpData(ea, size):
        """
        Loop through ea to ea+size, and if 
        every dword there points to code, this is a jump data section

        returns true or false and list of recovered ea => destination mappings
        """
        table_map = {}
        for jea in xrange(ea, ea+size, 4):
            dword = readDword(jea)
            if not isInternalCode(dword):
                DEBUG("Dword {:x} does not point to code, not a table\n".format(dword))
                return False, table_map

            table_map[jea] = dword

        return True, table_map

    i = start
    while i < end:
        DEBUG("Checking address: {:x}\n".format(i))
        dref_size = idc.ItemSize(i) or 1
        if dref_size > 4 and dref_size % 4 == 0:
            DEBUG("Possible table data at {:x}; size: {:x}\n".format(i, dref_size))
            (is_table, addrs) = checkIfJumpData(i, dref_size)
            if is_table:
                DEBUG("Its a table, adding {} references\n".format(len(addrs)));
                for ta in sorted(addrs.keys()):
                    insertReference(M, D, ta, addrs[ta], seg_offset, new_eas)
            else:
                DEBUG("Its not a table\n");

        elif dref_size == 4:
            more_cref = [c for c in idautils.CodeRefsFrom(i,0)]
            more_dref = [d for d in idautils.DataRefsFrom(i)]
            more_dref.extend(more_cref)
            if len(more_dref) > 0:
                DEBUG("\t\tFound a probable ref from: {0:x} => {1:x}\n".format(i, more_dref[0]))
                if len(more_dref) == 1:
                    insertReference(M, D, i, more_dref[0], seg_offset, new_eas)
                else: 
                    DEBUG("\t\tWARNING: Possible data ref problem\n");
                    insertReference(M, D, i, more_dref[0], seg_offset, new_eas)

        i += dref_size
Esempio n. 7
0
def addxref(x, y, z, i, k):
    idc.AddCodeXref(x, y, idc.XREF_USER | idc.fl_F)
    idc.AddCodeXref(y, z, idc.XREF_USER | idc.fl_F)
    print 'add xref for', k