Example #1
0
 def nextimmref(self, ea, ui=True):
     """
     Finds the next occurrance of an immediate value being a reference, like
     ldr r2, [r2,#(dword_809EEF4+0x1F8 - 0x809f0e4)]
     :param ea: ea to start searching from
     :param ui: if True, jump to address automatically
     :return: hex formatted ea of next name
     """
     # don't count this item
     ea = Data.Data(ea).ea + Data.Data(ea).getSize()
     output = idaapi.BADADDR
     while ea < self.end_ea:
         d = Data.Data(ea)
         if d.isCode() and '#' in d.getOrigDisasm():
             disasm = d.getOrigDisasm()
             # check out the xrefs from the data, see if it references to them
             xrefs = d.getXRefsFrom()
             for xref in xrefs[0]:
                 if Data.Data(xref).getName() in disasm:
                     output = ea
                     break
             for xref in xrefs[1]:
                 if Data.Data(xref).getName() in disasm:
                     output = ea
                     break
             if output != idaapi.BADADDR:
                 break
         ea += d.getSize()
     if ui: idaapi.jumpto(ea)
     return '%07X' % output
    def rngExterns(start_ea, end_ea, toStr=True):
        """
        creates .equs for all external symbols used in the range
        :param start_ea: start ea of the range, inclusive
        :param end_ea: end ea of the range, exclusive
        :return: a string containing all the external symbol .equs, or just the refs if not disp
        """
        ea = start_ea
        xrefs = []

        # if there's a function at end_ea, include all of its refs
        if Function.isFunction(end_ea):
            f = Function.Function(end_ea)
            end_ea = f.func_ea + f.getSize(withPool=True)

        # obtain xrefs of every data item, filtering out internal ones and duplicates
        while ea < end_ea:
            d = Data.Data(ea)
            # append crefs ands xrefs

            for xref in d.getXRefsFrom()[0]:
                # all code refs shouldn't have a +1 in them. The thumb switch isn't involved with the symbol itself
                if (idc.isCode(idc.GetFlags(xref)) or idc.isCode(
                        idc.GetFlags(xref - 1))) and xref & 1 == 1:
                    xref = xref - 1

                if ((xref < start_ea or xref >= end_ea
                     )  # filter internal (not external; within range)
                        and xref not in xrefs):  # filter duplicate
                    xrefs.append(xref)
            for xref in d.getXRefsFrom()[1]:
                # all code refs shouldn't have a +1 in them. The thumb switch isn't involved with the symbol itself
                if (idc.isCode(idc.GetFlags(xref)) or idc.isCode(
                        idc.GetFlags(xref - 1))) and xref & 1 == 1:
                    xref = xref - 1

                if ((xref < start_ea or xref >= end_ea
                     )  # filter internal (not external; within range)
                        and xref not in xrefs  # filter duplicate
                        and d.isPointer(xref)
                    ):  # filter non-pointer symbols, like byte_50
                    xrefs.append(xref)
            # advance to next item
            ea = ea + d.getSize()

        xrefs.sort()

        if not toStr:
            return xrefs

        output = ''
        # output file formats to include symbols into linking process
        for xref in xrefs:
            d = Data.Data(xref)
            name = d.getName()
            xref = d.ea
            output += '.equ %s, 0x%07X\n' % (name, xref)

        return output
Example #3
0
def unkTillName(ea):
    d = Data.Data(ea)
    while True:
        size = d.getSize()
        idc.del_items(d.ea, d.getSize())
        d = Data.Data(d.ea + size)
        if d.getName(): break
    return d.ea
Example #4
0
def tillName(ea, f):
    d = Data.Data(ea)
    while True:
        size = d.getSize()
        f(d.ea)
        d = Data.Data(d.ea + size)
        if d.getName(): break
    return d.ea
Example #5
0
def arrTillRef(ea):
    # TODO [BUG]: sometimes swallows names?
    if not Data.Data(ea).isPointer(ea):
        return False
    ref_ea = next.byDataElement(
        ea, lambda ea: idc.Name(ea) or Data.Data(ea).hasPointer(), ui=False)
    delRange(ea, ref_ea)
    idc.make_array(ea, ref_ea - ea)
    return True
Example #6
0
def actionP():
    """
    Profiling Action. Time Profiling and other analyses go here.
    """
    # tp.runTimeTests()
    n = 10
    x = lambda ea: Data.Data(ea).__str__()
    t, output = tp.avgTime_us(n, x, here())
    print('[%03d us] %s' % (t, Data.Data(here()).getDisasm()))
def runTimeTests(n=10):
    """
    Performs time profiling tests for optimization purposes
    :param n: number of times to sample the time. Result is the average of all samples
    """
    x = lambda: Data.Data(idc.here())._lowerCode(idc.GetDisasm(idc.here()))
    y = lambda: Data.Data(idc.here())._lowerCodeOLD(idc.GetDisasm(idc.here()))
    print(x())
    runTimeTest(n, 'new _lowerCode', x)
    print(y())
    runTimeTest(n, 'old _lowerCode', y)
Example #8
0
def unk2ArrRng(start_ea, end_ea):
    """
    converts all completely unknowns to byte arrays
    """
    d = Data.Data(start_ea)
    while d.ea < end_ea:
        if d.getName() and idc.isUnknown(idc.GetFlags(d.ea)):
            name = d.getName()
            if unk2Arr(d.ea): print('%s -> %s' % (name, d.getName()))
            d = Data.Data(d.ea)
        d = Data.Data(d.ea + d.getSize())
Example #9
0
def delShiftedContent(ea):
    d = Data.Data(ea)
    content = d.getContent()
    if type(content) == list or not d.getXRefsFrom(
    )[1] or content < 0x8000000 or not d.isPointer(content):
        return False
    dContent = Data.Data(content)
    if content == dContent.ea or dContent.isCode():
        return False
    if not idc.del_items(dContent.ea, dContent.getSize()):
        for i in range(dContent.ea, dContent.ea + dContent.getSize()):
            idc.del_items(i, 1)
    return True
Example #10
0
    def nextbin(self, ea, ui=True):
        """
        Finds the next big blob of data. The heuristic is it has to be at least sizeLimitHeuristic in size
        UI jumps to start_ea automatically.
        :param ea: ea to search from
        :param ui: if True, jump to address automatically
        :return: tuple hex format of the bin range and the size: (%07X, %07X, 0x$X)
        """
        sizeLimitHeuristic = 0x1000

        # don't count this item
        ea = Data.Data(ea).ea + Data.Data(ea).getSize()

        # range params
        start_ea = idaapi.BADADDR
        end_ea = idaapi.BADADDR
        size = 0

        # state machine of finding range
        st_start = 0
        st_traverse = 1
        st_end = 2
        state = st_start

        while ea < self.end_ea:
            d = Data.Data(ea)

            if not d.isCode():
                if state == st_start:
                    start_ea = ea
                    size = 0
                    state = st_traverse
                if state == st_traverse:
                    size += d.getSize()
                if state == st_end:
                    raise(Exception('entered invalid state'))

            if d.isCode():
                # only end if valid size
                if state == st_traverse:
                    if size >= sizeLimitHeuristic:
                        state = st_end
                    else:
                        state = st_start
                if state == st_end:
                    end_ea = ea
                    break

            ea += d.getSize()
        idaapi.jumpto(start_ea)
        return '0x%07X, 0x%07X, 0x%X' % (start_ea, end_ea, size)
Example #11
0
    def nextOneWordArr():
        d = Data.Data(ea)
        while (d.ea < pointerRange[1]):
            content = d.getContent()

            # case: byte array that's 4 elements. Likely a word
            if type(content) == list and len(content) == 4 and (d.getSize() / len(content) == 1):
                break
            d = Data.Data(d.ea + d.getSize())

        if d.ea >= pointerRange[1]:
            print(False)
        else:
            print('%07X' % d.ea)
            idc.jumpto(d.ea)
Example #12
0
def findMostUsedLabels(start_ea, end_ea, count, notModified=False, disp=True):
    # type: (int, int, int, bool, bool) -> list[int]
    """
    Scans through all labels in the given range and counts the ones with the highest amount of references
    :param start_ea: start of the range
    :param end_ea: end of the range
    :param count:
    :param notModified:
    :param disp:
    :return:
    """
    xrefs = []

    if count <= 0: count = 1
    for i in range(count):
        xrefs.append((0, 0))

    ea = start_ea
    while ea < end_ea:
        if not idc.get_name(ea):
            ea += idc.get_item_size(ea)
            continue
        if notModified:
            name = Data.Data(ea).getName()
            if not ('_' in name and name[name.rindex('_'):] == ('_%X' % ea)):
                continue

        currXrefs = Data.Data(ea).getXRefsTo()
        numXrefs = len(currXrefs[0]) + len(currXrefs[1])

        # add if more than least in the list and sort
        if numXrefs > xrefs[0][1]:
            xrefs[0] = (ea, numXrefs)
            xrefs = sorted(xrefs, key=lambda tup: tup[1])

        ea += idc.get_item_size(ea)

    # reverse to display most common first
    xrefs = sorted(xrefs, key=lambda tup: tup[1], reverse=True)

    if disp:
        for ea, xrefCount in xrefs:
            print('%07x <%s>: %d' % (ea, Data.Data(ea).getName(), xrefCount))

    output = []
    for ea, xrefCount in xrefs:
        output.append(ea)
    return output
 def checkExtractedCode(self):
     """
     Checks if any gameFile that is not disassembled has any code in it
     All code must be disassembled, and data should be extracted
     If code is contained within extracted binaries, they are reported back
     :return: [] if no code in extracted ranged. list[gameFile] otherwise.
     """
     # grab necessary variables from the environment and assert that they were given
     gameFiles = self.get('gameFiles')
     if not gameFiles:
         print('ERROR: environmental variables for gameFiles' +
               ' must be provided.')
         return
     markedFiles = []
     keys = gameFiles.keys()
     keys.sort()
     for file in keys:
         if not '.s' in file:
             # traverse the range, make sure it has no code
             ea = gameFiles[file][0]
             while ea < gameFiles[file][1]:
                 d = Data.Data(ea)
                 if (d.isCode()):
                     markedFiles.append(file)
                     break
                 ea += d.getSize()
     return markedFiles
Example #14
0
def markRedundantInsts(start_ea, end_ea):
    """
    Some instructions, like add r0, r0, #0 can be optimized to add r0, #0 by assemblers.
    This gets in the way of disassembly. This attempts to fix that by replacing all such occurrances with
    purely their data format, and it also adds a comment on that line specifying the original inst.

    To specify that a data item has to be forced to data, this puts <mkdata> in its comment.
    :param start_ea: start address of the marking
    :param end_ea: end address of the marking
    """
    ea = start_ea
    while ea < end_ea:
        d = Data.Data(ea)
        if d.isCode() and '<mkdata>' not in d.getComment():
            redundant = True
            # MOVS R3, R3
            content = d.getContent()
            if d.getContent() in srchTools.nextTools.next._getFakeInstructions(
            ):
                print("%07X: <mkdata>" % (ea))
            else:
                redundant = False

            if redundant:
                cmt = d.getComment()
                if cmt:
                    cmt = '<mkdata> ' + cmt
                else:
                    cmt = '<mkdata>'
                d.setComment(cmt)
        ea += d.getSize()
Example #15
0
def sync_identified_units_names(source_units, addr_space):
    def test_matching_name(unit, ea, verbose=False):
        if idc.get_name(ea) != unit['name']:
            err_msg = '0x{:X}: found differing unit name: unit {} != ida {}'.format(ea, unit['name'], idc.get_name(ea))
            if verbose:
                return err_msg
            return False
        return True

    print(os.getcwd())
    log_file = open('../a.log.ign', 'w')

    synced_function_addrs, synced_data_addrs, synced_unk_addrs = cache_find_synced_units(source_units, addr_space,
                                                                                                 recache=True)

    for ea in synced_function_addrs:
        unit = source_unit.get_physical_unit(source_units, ea)

        func = Function.Function(ea)
        out = test_matching_name(unit, func.func_ea, verbose=True)
        if type(out) is str:
            print(out)
            log_file.write(out + '\n')

    for ea in synced_data_addrs:
        unit = source_unit.get_physical_unit(source_units, ea)

        data = Data.Data(ea)
        out = test_matching_name(unit, data.ea, verbose=True)
        if type(out) is str:
            print(out)
            log_file.write(out + '\n')

    log_file.close()
    def testContent(self):
        """
        ensures that the content of the data object is identical to that in the database
        """
        for key in self.testData.keys():
            td = self.testData[key]
            d = Data.Data(td['ea'])
            Test.assertEquals(d.getContent(), td['content'],
                              "%s: Invalid Content. Expected='%s', Actual='%s'" % (key, td['content'], d.getContent()))

            if key == "array":
                print("IDA")
                print(self.hexArr(d.getContent()))
                romData = self.readROM(td['ea'], td['size'])
                print("NO LOADER")
                print(self.hexArr([4, 255, 3, 42, 0, 255, 34, 9, 3, 3, 81, 78, 1, 3, 4, 54, 131, 4,
                                   20, 32, 3, 4, 12, 38, 4, 4, 11, 1, 4, 4, 14, 0, 4, 4, 27, 80, 4,
                                   4, 17, 36, 0, 4, 33, 8, 4, 4, 24, 3, 4, 4, 82, 22, 1, 4, 1, 11,
                                   1, 4, 19, 37, 1, 4, 32, 62, 1, 4, 31, 19, 1, 4, 13, 20, 1, 4, 0,
                                   10, 1, 4, 80, 67, 1, 4, 16, 72, 1, 4, 10, 75, 1, 4, 25, 35, 1, 4,
                                   28, 18, 2, 4, 69, 79, 2, 4, 45, 26, 2, 4, 43, 21, 2, 4, 47, 29, 2,
                                   4, 61, 64, 2, 4, 49, 31, 2, 4, 65, 70, 2, 4, 64, 69, 2, 4, 40, 14]))
                print("ROM")
                print(self.hexArr(Data.Data._combineBytes(romData, 4)))
            Test.assertEquals(d.getContent(bin=True), self.readROM(td['ea'], td['size']),
                              "%s: Invalid Bin Content. Expected='%s', Actual='%s'"
                              % (key, self.readROM(td['ea'], td['size']), d.getContent(bin=True)))
Example #17
0
def find_synced_units(source_units, addr_space):
    """
    :returns: units which are synced in type, size, and starting address. This only applies to Function or Data. All else is treated as Unknown
              it returns a list of synced function addresses, synced data addresses, and synced unknown addresses
    """
    synced_functions = []
    synced_data = []
    synced_unk = []
    for i, ea in enumerate(addr_space):
        unit = source_unit.get_physical_unit(source_units, ea)
        unit_size = source_unit.compute_unit_size_from_index(addr_space, i)

        if unit['unit']['id'] is AsmFile.UNIT_IDS.FUNCTION:
            if Function.isFunction(ea):
                func = Function.Function(ea)
                if func.func_ea == ea and func.getSize(withPool=True) == unit_size:
                    synced_functions.append(ea)
        else:
            data = Data.Data(ea)
            if data.ea == ea:
                if data.getSize() == unit_size:
                    if unit['unit']['id'] == AsmFile.UNIT_IDS.DATA:
                        synced_data.append(ea)
                    else:
                        synced_unk.append(ea)
                else:
                    # get size until another label is defined
                    till_label_size = _next.name(ea, ui=False, hexOut=False) - ea
                    if till_label_size == unit_size:
                        if unit['unit']['id'] == AsmFile.UNIT_IDS.DATA:
                            synced_data.append(ea)
                        else:
                            synced_unk.append(ea)

    return synced_functions, synced_data, synced_unk
Example #18
0
    def rng(start_ea, end_ea, debug=False):
        # type: (int, int) -> str
        """
        disassembles all data elements within a range
        if a function is detected within the range, the function itself is disassembled
        as a whole item. (meaning it could surpass end_ea, but it would be the last item)
        :param start_ea: the start ea of the range
        :param end_ea: the end ea, not included
        :return: the disassembly of the range, in optimal format
        """
        ea = start_ea
        disasm = ''

        # disassemble the range
        ea = start_ea
        while ea < end_ea:
            if  Function.isFunction(ea):
                f = Function.Function(ea)
                if debug: print("%07X: disass function %s @ %07X" % (ea, f.getName(), f.func_ea))
                disasm += f.getFormattedDisasm(start_ea, end_ea) + "\n\n"
                ea = ea + f.getSize(withPool=True)
            else:
                d = Data.Data(ea)
                if debug: print("%07X: disass data %s @ %07X" % (ea, d.getName(), d.ea))
                disasm += d.getFormattedDisasm(start_ea, end_ea) + "\n"
                ea = ea + d.getSize()

        # add comment for debugging purposes
        # disasm += "/*For debugging purposes, connect comment at any range!*/\n"

        return disasm
    def read(self, accesses_path):
        # type: (str) -> None
        """
        Reads in the memory accesses defined by the MemAccessScanner protocol
        :param accesses_path: path to a file containing the accesses
        :return:
        """
        f = open(accesses_path, "r")
        s = f.read()
        items = s.split(' ')
        self.accesses = []
        for i in range(len(items)):
            if '::' in items[i]:
                access_ea = int(items[i][items[i].index('::') + 2:], 16)
                access = items[i + 1][:-1]
                self.accesses.append((access_ea, access))
        self.accesses.sort(key=lambda tup: tup[0])

        for access_ea, access in self.accesses:
            if Function.isFunction(access_ea):
                func_ea = Function.Function(access_ea).func_ea
                if func_ea not in self.funcs:
                    self.funcs.append(func_ea)
            else:
                data_ea = Data.Data(access_ea).ea
                if data_ea not in self.data:
                    self.data.append(data_ea)
        self.funcs.sort()
        self.data.sort()

        f.close()
Example #20
0
def registerUncompFile(ea, force=True):
    # type: (int) -> bool
    d = Data.Data(ea)
    compPtr = d.getContent()
    if not idc.is_dword(d.getFlags()) or type(compPtr) == list:
        if not force: return False
        print('[%07X] -> dword' % (ea))
        forceItemOp(ea, idc.create_dword, ea)
        d = Data.Data(ea)
        compPtr = d.getContent()

    # compressed pointers have the 31th bit set
    if not compPtr & (1 << 31):
        return False

    compPtr = compPtr - (1 << 31)

    #  make its content an array, and set a name for it, and a size
    compData = Data.Data(compPtr)
    if compData.ea != compPtr:
        idc.del_items(compData.ea)
        compData = Data.Data(compPtr)
    compSize = getLZ77CompressedSize(compPtr)
    # size must have been identified
    if compSize == -1:
        return False
    if compSize % 4 != 0:
        compSize += 4 - (compSize % 4)  # must be word aligned

    if compData.getSize() != compSize:
        if not idc.del_items(compPtr, compSize):
            for i in range(compPtr, compPtr + compSize):
                idc.del_items(i, 1)
        idc.make_array(compPtr, compSize)

    if not compData.getName():
        compData.setName('comp_%07X' % compData.ea)

    idc.op_man(ea, 0, '%s + 1<<31' % compData.getName())

    # now register the compressed data as its own file
    filename = 'data/compressed/%s.lz77' % compData.getName()
    print('[%07X] addFile %s' % (ea, filename))
    dis = Terminal.DisTerminal()
    dis.addFile(filename, compPtr, compPtr + compSize)

    return True
    def testBasic(self):
        # type: () -> None
        """
        Tests that InvalidDataException is raised if instantiated with invalid EA.
        And tests that valid data give valid behavior: ea, name, size, and comments
        :testParams: encapsulated object showing manually computed function parameters
        """
        for key in self.testData.keys():
            td = self.testData[key]
            d = Data.Data(td['ea'])
            # valid EA
            Test.assertEquals(d.ea, td['ea'],
                              "%s: Data EA mistmatch: Expected=0x%08X, Actual=0x%08X" % (key, td['ea'], d.ea))
            # getName
            Test.assertEquals(d.getName(), td['name'], "%s: Data name mismatch: Expected='%s', Actual='%s'"
                              % (key, td['name'], d.getName()))
            # setName
            d.setName("t__" + td['name'])
            Test.assertEquals(d.getName(), "t__" + td['name'], "%s: setName() not working" % key)
            d.setName(td['name'])
            Test.assertEquals(d.getName(), td['name'], "%s: could not set name back to normal" % key)
            # getSize
            Test.assertEquals(d.getSize(), td['size'], "%s: invalid size. Expected=%d, Actual=%d"
                              % (key, td['size'], d.getSize()))
            # getComment
            Test.assertEquals(d.getComment(), td['cmt'],
                              "%s: Comment mismatch: Expected='%s', Actual='%s'" % (key, td['cmt'], d.getComment()))
            # setComment
            d.setComment("t__" + td['cmt'])
            Test.assertEquals(d.getComment(), "t__" + td['cmt'], "%s: setComment() not working" % key)
            d.setComment(td['cmt'])
            Test.assertEquals(d.getComment(), td['cmt'], "%s: could not set comment back to normal" % key)
            # xrefs
            Test.assertEquals(d.getXRefsTo(), td['xrefsTo'],
                              "%s: Invalid XrefsTo. Expected=%s, Actual=%s"
                              % (key, self.xrefs2str(td['xrefsTo']), self.xrefs2str(d.getXRefsTo())))
            Test.assertEquals(d.getXRefsFrom(), td['xrefsFrom'],
                              "%s: Invalid XrefsFrom. Expected=%s, Actual=%s"
                              % (key, self.xrefs2str(td['xrefsFrom']), self.xrefs2str(d.getXRefsFrom())))

        # test that when addressing in the middle of an array, the EA returned is its beginning
        td = self.testData['array']
        d = Data.Data(td['ea'] + td['size']/2)
        Test.assertEquals(td['ea'], d.ea,
                          "array: EA not fixed to beginning of array. Expected=0x%08X, Actual=0x%08X"
                          % (td['ea'], d.ea))
Example #22
0
    def rngInc(start_ea, end_ea):
        """
        Reports back the exposed (or public) symbols of the range
        The symbols are .global forwarded, and represent the symbols defined within the range
        :param start_ea: linear address of the start of the range
        :param end_ea: linear address of the end of the range, exclusive
        :return: a series of .equ's representing the public (and private) interface of the range
        """
        ea = start_ea
        pubrefs = []
        # fwdrefs = []
        while ea < end_ea:
                d = Data.Data(ea)
                if d.getName():
                    # check xrefs to the item, if any is outside the range, it's a public reference
                    isPublic = False
                    xrefsTo = d.getXRefsTo()
                    for cref in xrefsTo[0]:
                        if cref < start_ea or cref >= end_ea:
                            isPublic = True
                    for dref in xrefsTo[1]:
                        if dref < start_ea or dref >= end_ea:
                            isPublic = True
                    if isPublic:
                        pubrefs.append((d.getName(), d.ea))
                     # For debugging purposes
                    # else:
                    #     fwdrefs.append((d.getName(), d.ea))
                ea = ea + d.getSize()

        # string build includes
        inc = '/* Public Symbols */\n'
        for name, ea in pubrefs:
            d = Data.Data(ea)
            if d.isFunctionStart():
                cmt = idc.get_func_cmt(ea, repeatable=1)
                if cmt: cmt = ' // ' + cmt.replace('\n', '\n// ')
            else:
                cmt = ''
            inc += '.global %s%s\n' % (name, cmt)
        # For debugging purposes, defining forward references could be useful in include files
        # inc += "\n// Forward Reference\n"
        # for name, ea in fwdrefs:
        #     inc += ".equ %s, 0x%07X\n" % (name, ea)
        inc += "\n"
        return inc
    def getFormattedDisasm(self, start_ea=False, end_ea=False):
        # type: () -> str
        """
        Gets the disassembly of the function by creating data elements of all
        its items, including its pool.
        :param start_ea: file range start, enables formatting to use a global/local macro
        :param end_ea: file range end, enables formatting to use a global/local macro
        :return:
        """
        ea = self.func_ea
        disasm = ''

        # spefiy function comment, if available
        # put // for function comment in each line
        comment = ''
        if self.getComment(repeatable=True):
            comment += '// ' + self.getComment(repeatable=True).replace(
                '\n', '\n// ') + '\n'
        if self.getComment():
            comment += '// ' + self.getComment().replace('\n', '\n// ') + '\n'
        disasm += comment

        # specify start of function
        # file range supplied, inform if thumb or arm function, local/global thumb via macros
        isThumb = self.isThumb()
        if end_ea:
            if isThumb:
                if self.isGlobal(start_ea, end_ea):
                    disasm += '\tthumb_func_start %s\n' % (self.getName())
                else:
                    disasm += '\tthumb_local_start\n'
            else:
                disasm += "\tarm_func_start %s\n" % (self.getName())
        # no macros approach, give sufficient type to symbols
        else:
            disasm = '.func\n'
            # specify  whether this is an arm or thumb function
            if isThumb:
                disasm += ".thumb_func\n"
            else:
                disasm += ".arm\n"

        # disassemble all items within the function
        while ea < self.func_ea + self.getSize(withPool=True):
            d = Data.Data(ea)
            disasm += d.getFormattedDisasm(start_ea, end_ea) + "\n"
            # advance to next item
            ea = ea + d.getSize()

        if end_ea:
            if isThumb:
                disasm += "\tthumb_func_end %s" % self.getName()
            else:
                disasm += "\tarm_func_end %s" % self.getName()
        else:
            disasm += ".endfunc // %s" % self.getName()

        return disasm
Example #24
0
def deadfunc(ea, end_ea=None, ui=True, hexOut=True):
    """
    This finds the next occurrance of a dead function not recognized as a function (ie, red code or data)
    This can only find functions ranges it can guarantee, ie, only PUSH {..., LR} POP {..., PC} patterns.
    :param ea: ea to start searching from
    :param end_ea: the last address of the search range
    :param ui: if True, jump to address automatically
    :param hexOut: output hex formatted ea range instead
    :return: range of ea of next dead function
    """
    # don't count this item
    ea = Data.Data(ea).ea + Data.Data(ea).getSize()
    foundPush = False
    push_ea = idaapi.BADADDR
    pop_ea = idaapi.BADADDR
    push_regs = None
    if not end_ea: end_ea = end_ea
    while ea < end_ea:
        # the current item must not belong to a function, or have any data xrefs
        if not Function.isFunction(ea) and not Data.Data(ea).getXRefsTo()[1]:
            try:
                inst = InstDecoder.Inst(ea).fields
            except ValueError:
                ea += 2
                continue
            # if PUSH {..., LR}
            if inst and inst['magic'] == InstDecoder.INST_PUSHPOP and not inst[
                    'pop'] and inst['lr']:
                foundPush = True
                push_ea = ea
                push_regs = inst['Rlist']
            # detected a POP {..., PC} after the PUSH {..., LR}, and the registers match
            if (foundPush and inst
                    and inst['magic'] == InstDecoder.INST_PUSHPOP
                    and inst['pop'] and inst['lr']
                    and inst['Rlist'] == push_regs):
                pop_ea = ea
                break
        else:
            foundPush = False
        ea += 2

    if ui: idc.jumpto(push_ea)
    if hexOut: return '(%07X, %07X)' % (push_ea, pop_ea)
    return (push_ea, pop_ea)
    def getStackVarDisasm(self):
        """
        if the function uses stack variables with SP, their symbols should be defined
        :return:
        """
        disasm = ''
        id = idc.GetFrame(self.func_ea)
        firstMember = idc.GetFirstMember(id)
        if hasStackVars(self.func_ea):
            # first, obtain the base by finding an instruction that uses one of the stack variables
            stackVars = getStackVars(self.func_ea)
            ea = self.func_ea
            base = -1

            # TODO: maybe use get_min_spd_ea(func_ea) to get the base pointer? this stands for stack pointer delta!

            # search function instructions to find base (TODO: hacky, but i dunno how else to find base yet)
            while ea < self.func_ea + self.getSize():
                d = Data.Data(ea)
                origDisasm = d.getOrigDisasm()
                # case where the stack frame is referenced
                for var, offset in stackVars:
                    if var in origDisasm and '#' in origDisasm:
                        # cases like LDR SP, [base+var_xx]
                        if '[' in origDisasm:
                            # grab the base
                            if '+' in origDisasm:
                                base = int(
                                    origDisasm[origDisasm.index('#') +
                                               1:origDisasm.index('+')], 16)
                            else:
                                base = 0
                            # obtained base! no need to continue looping
                            break
                        # some cases like ADD SP, base+var_xx don't have '['
                        elif '+' in origDisasm:
                            base = int(
                                origDisasm[origDisasm.index('#') +
                                           1:origDisasm.index('+')], 16)
                            # obtained base! no need to continue looping
                            break
                if base != -1:
                    break
                ea += d.getSize()
            # if base couldn't be found still, it's likely no SP access is done with variables
            if base == -1:
                base = 0

            # build up disasm based on stack vars using base-relative offsets
            for name, off in stackVars:
                relOff = base - off
                if relOff > 0:
                    disasm += ".equ %s, -0x%X\n" % (name, abs(relOff))
                else:
                    disasm += ".equ %s, 0x%X\n" % (name, abs(relOff))

        return disasm
Example #26
0
 def nextred(self, ea, ui=True):
     """
     Looks for code items outside function items. The first detected is returned
     :param ea: ea to start searching from
     :param ui: if True, jump to address automatically
     :return: hex formatted ea of next name
     """
     # don't count this item
     ea = Data.Data(ea).ea + Data.Data(ea).getSize()
     output = idaapi.BADADDR
     while ea < self.end_ea:
         d = Data.Data(ea)
         if d.isCode() and not Function.isFunction(d.ea):
             output = ea
             break
         ea += d.getSize()
     if ui: idaapi.jumpto(ea)
     return '%07X' % output
Example #27
0
 def nextknown(self, ea, ui=True):
     """
     Finds the next ea with which a name exists
     :param ea: ea to start searching from
     :param ui: if True, jump to address automatically
     :return: hex formatted ea of next name
     """
     # don't count this item
     ea = Data.Data(ea).ea + Data.Data(ea).getSize()
     output = idaapi.BADADDR
     while ea < self.end_ea:
         d = Data.Data(ea)
         if not idc.isUnknown(d._getFlags()):
             output = ea
             break
         ea += d.getSize()
     if ui: idaapi.jumpto(ea)
     return '%07X' % output
Example #28
0
 def nextarm(self, ea, ui=True):
     # type: (int) -> str
     """
     Finds the next ARM item, which has a Segment register value 'T' of 0
     :param ea: address to start searching from
     :param ui: if True, jump to address automatically
     :return: the address (in str) of the next ARM instruction
     """
     # don't count this item
     ea += Data.Data(ea).getSize()
     output = idaapi.BADADDR
     while ea < self.end_ea:
         d = Data.Data(ea)
         # detect next code32
         if idc.GetReg(ea, 'T') == 0:
             output = ea
             break
         ea += d.getSize()
     return '%07X' % output
Example #29
0
def removeRedCode(start_ea, end_ea):
    """
    unconditionally removes all red code within a specified region
    :param start_ea: start of the region
    :param end_ea: end of the region
    :return:
    """
    srchNext = next
    redStart_ea = redEnd_ea = srchNext.red(start_ea, end_ea, ui=False)
    while redEnd_ea < end_ea:
        d = Data.Data(redEnd_ea)
        while d.isCode() and not Function.isFunction(d.ea):
            redEnd_ea += 2
            d = Data.Data(redEnd_ea)
        # change to bytes
        print("%07X: del red code (%07X, %07X)" %
              (redStart_ea, redStart_ea, redEnd_ea))
        idc.del_items(redStart_ea, 0, redEnd_ea - redStart_ea)
        redStart_ea = redEnd_ea = srchNext.red(redEnd_ea, end_ea, ui=False)
Example #30
0
 def nextascii(self, ea, ui=True):
     # type: (int) -> str
     """
     returns the next data item containing ascii characters (seems valid for utf too)
     :param ea: the address to start searching from
     :param ui: if True, jump to address automatically
     :return: hex formatted str of the address of the next ascii item
     """
     # don't count this item
     ea = Data.Data(ea).ea + Data.Data(ea).getSize()
     output = idaapi.BADADDR
     while ea < self.end_ea:
         d = Data.Data(ea)
         # ARM, unless it's a branch
         if idc.isASCII(d._getFlags()):
             output = ea
             break
         ea += d.getSize()
     if ui: idaapi.jumpto(output)
     return '%07X' % output