Example #1
0
    def markSwitchTables(self, sc, aggressive=True):
        """Help IDA by marking all of the needed information from the observed switch tables.

        Args:
            sc (segment): (sark) code segment in which we are interested right now
            aggressive (bool, optional): True iff the marking operation should be aggressive, see notes. (True by default)

        Notes
        -----
            1. Make sure the switch case jump instruction is indeed a code line
            2. Make sure the jump instruction has a code reference to all of the switch cases
            3. (Aggressive) Make sure each switch table entry is a proper code pointer to it's matching case
            4. (Aggressive) Enforce the correct code type over the entire gap between the minimal and maximal case
        """
        for switch_instr, table_start, table_end in [
                x for x in self._switch_case_entries
                if sc.start_ea <= x[0] and x[1] < sc.end_ea
        ]:
            cases = []
            if not sark.Line(switch_instr).is_code:
                ida_bytes.del_items(switch_instr, 0,
                                    self._analyzer.addressSize())
                idc.create_insn(switch_instr)
            for ea in range(table_start, table_end,
                            self._analyzer.addressSize()):
                entry = self._analyzer.parseAdderss(ea)
                if aggressive:
                    self._analyzer.markCodePtr(ea, entry)
                fixed_entry = self._analyzer.cleanPtr(entry)
                cases.append(fixed_entry)
                idc.add_cref(switch_instr, fixed_entry,
                             idc.XREF_USER | idc.dr_O)
            if aggressive:
                self._analyzer.setCodeType(min(cases), max(cases),
                                           self._analyzer.ptrCodeType(entry))
Example #2
0
 def add_stub_func(va, sc, nm):
     idaapi.patch_bytes(va, binascii.unhexlify(sc))
     idc.create_insn(va)
     idc.add_func(va)
     mykutils.makename_safe(va, self._stubname(nm))
     cmt = ('%s implementation generated by FLARE Code Grafter' % (nm))
     idc.set_cmt(va, cmt, 1)
Example #3
0
def ida_main():
    import idc

    filepath = ida_kernwin.ask_file(0, "*.map", "Load a Dolphin emulator symbol map")
    if filepath is None:
        return
    symbol_map = load_dolphin_map(filepath)

    for symbol in symbol_map:
        addr = int(symbol.vaddr, 16)
        size = int(symbol.size, 16)
        ida_bytes.del_items(addr, size, 0)
        if symbol.section in [".init", ".text"]:
            idc.create_insn(addr)
            success = ida_funcs.add_func(
                addr,
                idc.BADADDR if not size else (addr+size)
            )
        else:
            success = ida_bytes.create_data(addr, idc.FF_BYTE, size, 0)

        if not success:
            ida_kernwin.msg("Can't apply properties for symbol:"
                        " {0.vaddr} - {0.name}\n".format(symbol))

        flags = idc.SN_NOCHECK | idc.SN_PUBLIC
        if symbol.name.startswith("zz_"):
            flags |= idc.SN_AUTO | idc.SN_WEAK
        else:
            flags |= idc.SN_NON_AUTO
        idc.set_name(addr, symbol.name, flags)
Example #4
0
def resolve_loops():

    PATTERNS = ["81 FB ?? ?? ?? ?? 75"]

    count_patched = 0
    count_not_patched = 0

    for pattern in PATTERNS:

        ea = 0

        while ea != BADADDR:
            '''
             pattern: 81 FB ?? ?? ?? ?? 75
            .text:00406AA0 01 C7                add     edi, eax
            .text:00406AA2 66 41                inc     cx
            .text:00406AA4 43                   inc     ebx
            .text:00406AA5 81 FB A6 01 00 00    cmp     ebx, 1A6h
            .text:00406AAB 75 F3                jnz     short loc_406AA0

            patched:
            .text:00406AA0 01 C7                add     edi, eax
            .text:00406AA2 66 41                inc     cx
            .text:00406AA4 43                   inc     ebx
            .text:00406AA5 90                   nop
            .text:00406AA6 90                   nop
            .text:00406AA7 90                   nop
            .text:00406AA8 90                   nop
            .text:00406AA9 90                   nop
            .text:00406AAA 90                   nop
            .text:00406AAB 90                   nop
            .text:00406AAC 90                   nop
            '''

            ea = ida_search.find_binary(
                ea, BADADDR, pattern, 16,
                SEARCH_NEXT | SEARCH_DOWN | SEARCH_CASE)

            if ea_in_bounds(ea):

                # Patch CMP and conditional jmp instructions in order to remove the loop
                ida_bytes.patch_byte(ea + 0, 0x90)
                ida_bytes.patch_byte(ea + 1, 0x90)
                ida_bytes.patch_byte(ea + 2, 0x90)
                ida_bytes.patch_byte(ea + 3, 0x90)
                ida_bytes.patch_byte(ea + 4, 0x90)
                ida_bytes.patch_byte(ea + 5, 0x90)
                ida_bytes.patch_byte(ea + 6, 0x90)
                ida_bytes.patch_byte(ea + 7, 0x90)

                idc.create_insn(ea)

                count_patched += 1

    print("\tPatched resolve_loops: {0}".format(count_patched))
    print("\tNot Patched resolve_loops: {0}".format(count_not_patched))
def deobfuscate_rets(ea):
    if idc.get_wide_byte(ea) == 0x83:
        fill_with_nops(ea, ea + 7)
    else:
        fill_with_nops(ea, ea + 8)

    idc.patch_byte(ea, 0xC3)
    idc.create_insn(ea)

    return True
Example #6
0
            def format_vfunc_name(self, ea, current_func_name,
                                  proposed_func_name, class_name,
                                  parent_class_names):
                if current_func_name.startswith("j_"):  # jump
                    current_func_name = current_func_name.lstrip("j_")

                if current_func_name.startswith("qword_"):
                    idc.auto_mark_range(ea, ea + 1, idc.AU_CODE)
                    idc.create_insn(ea)
                    idc.add_func(ea)
                    current_func_name = api.get_addr_name(ea)
                    print(
                        "Info: qword in vtbl of {1} at 0x{0:X}, it may be an offset to undefined code"
                        .format(ea, class_name))

                # Previously renamed as a vfunc
                if current_func_name.startswith(class_name):
                    # return the proposed func name in case it was updated since last run
                    current_class_name = current_func_name.rsplit(".", 1)[0]
                    return "{0}.{1}".format(current_class_name,
                                            proposed_func_name)

                # This should have been handled in the parent class
                if any(
                        current_func_name.startswith(name)
                        for name in parent_class_names):
                    return ""

                if current_func_name.startswith("sub_"):
                    return "{0}.{1}".format(class_name, proposed_func_name)

                if current_func_name.startswith("nullsub_"):
                    return "{0}.{1}_nullsub".format(class_name,
                                                    proposed_func_name)

                if current_func_name.startswith("loc_"):
                    return "{0}.{1}_loc".format(class_name, proposed_func_name)

                if current_func_name.startswith("locret_"):
                    return "{0}.{1}_locret".format(class_name,
                                                   proposed_func_name)

                # Name it later in a child class when it gets overridden
                if current_func_name == "_purecall":
                    return ""

                # Mangled func names, thanks IDA
                if current_func_name.startswith(
                        "?") or current_func_name.startswith("_"):
                    return "{0}.{1}".format(class_name, proposed_func_name)

                return None
def _convert_address_to_function(func):
    """Convert an address that IDA has classified incorrectly into a proper function."""
    # If everything goes wrong, we'll try to restore this function.
    orig = idc.first_func_chunk(func)
    # If the address is not code, let's undefine whatever it is.
    if not ida_bytes.is_code(ida_bytes.get_full_flags(func)):
        if not is_mapped(func):
            # Well, that's awkward.
            return False
        item = ida_bytes.get_item_head(func)
        itemend = ida_bytes.get_item_end(func)
        if item != idc.BADADDR:
            _log(1, 'Undefining item {:#x} - {:#x}', item, itemend)
            ida_bytes.del_items(item, ida_bytes.DELIT_EXPAND)
            idc.create_insn(func)
            # Give IDA a chance to analyze the new code or else we won't be able to create a
            # function.
            #ida_auto.auto_wait()
            autoanalyze()
            idc.plan_and_wait(item, itemend)
    else:
        # Just try removing the chunk from its current function. IDA can add it to another function
        # automatically, so make sure it's removed from all functions by doing it in loop until it
        # fails.
        for i in range(1024):
            if not idc.remove_fchunk(func, func):
                break
    # Now try making a function.
    if ida_funcs.add_func(func) != 0:
        return True
    # This is a stubborn chunk. Try recording the list of chunks, deleting the original function,
    # creating the new function, then re-creating the original function.
    if orig != idc.BADADDR:
        chunks = list(idautils.Chunks(orig))
        if ida_funcs.del_func(orig) != 0:
            # Ok, now let's create the new function, and recreate the original.
            if ida_funcs.add_func(func) != 0:
                if ida_funcs.add_func(orig) != 0:
                    # Ok, so we created the functions! Now, if any of the original chunks are not
                    # contained in a function, we'll abort and undo.
                    if all(idaapi.get_func(start) for start, end in chunks):
                        return True
            # Try to undo the damage.
            for start, _ in chunks:
                ida_funcs.del_func(start)
    # Everything we've tried so far has failed. If there was originally a function, try to restore
    # it.
    if orig != idc.BADADDR:
        _log(0, 'Trying to restore original function {:#x}', orig)
        ida_funcs.add_func(orig)
    return False
def simplify_jumps(ea):
    # If we got long first conditional jump
    if idc.get_wide_byte(ea) == 0x0F:
        alternative_jmp_cmd = idc.get_wide_byte(ea + 1) ^ 1
        interm_jmp_offt = 6
    else:
        alternative_jmp_cmd = idc.get_wide_byte(ea) ^ 0xF1
        interm_jmp_offt = 2

    # Get intermediate jump's value
    if idc.get_wide_byte(ea + interm_jmp_offt) == 0x0F:
        interm_jmp_param = idc.get_wide_dword(ea + interm_jmp_offt + 2)
        final_jmp_addr = ea + interm_jmp_param + interm_jmp_offt + 6
    else:
        interm_jmp_param = idc.get_wide_byte(ea + interm_jmp_offt + 1)
        final_jmp_addr = ea + interm_jmp_param + interm_jmp_offt + 2

    # Check the last conditional jump

    # 75 ?? ... 0F 85 ?? ?? ?? ??
    if idc.get_wide_byte(final_jmp_addr) == 0x0F and \
       idc.get_wide_byte(final_jmp_addr + 1) == alternative_jmp_cmd:
        final_jmp_param = idc.get_wide_dword(final_jmp_addr + 2)
        final_jmp_target = (final_jmp_addr + final_jmp_param + 6) & 0xFFFFFFFF

    # 75 ?? ... 75 ??
    elif idc.get_wide_byte(final_jmp_addr) ^ 0xF0 == alternative_jmp_cmd:
        final_jmp_param = idc.get_wide_byte(final_jmp_addr + 1)
        final_jmp_target = (final_jmp_addr + final_jmp_param + 2) & 0xFFFFFFFF

    # Make a little cleanup: remove garbage code
    elif interm_jmp_param < 0x10:
        fill_with_nops(ea + interm_jmp_offt, final_jmp_addr)
        return True

    else:
        return

    if final_jmp_target - ea < 0xFF:
        fill_with_nops(ea + interm_jmp_offt, final_jmp_target)
    else:
        fill_with_nops(ea + interm_jmp_offt, final_jmp_addr + 6)

    # Restore seconds jump
    idc.patch_byte(ea + interm_jmp_offt, 0x0F)
    idc.patch_byte(ea + interm_jmp_offt + 1, alternative_jmp_cmd)
    idc.patch_dword(ea + interm_jmp_offt + 2, final_jmp_target - (ea + interm_jmp_offt) - 6)
    idc.create_insn(ea + interm_jmp_offt)

    return True
Example #9
0
	def get_func_end(self, start):

		if (idc.add_func(start)):
			return idc.find_func_end(start)

		ea = start
		while (idc.get_wide_byte(ea) != 0xCC):
			idc.create_insn(ea)
			ea += idc.get_item_size(ea)

			if (ea - start > self.jit_max_size):
				return 0

		return ea
Example #10
0
    def markCodePtr(self, src, dest, aggressive=True):
        """Mark a code pointer from src to dest.

        Args:
            src (int): effective address for the pointer's location
            dest (int): effective address for the pointed code address
            aggressive (bool, optional): True iff should redefine the src & dest (True by default)
        """
        clean_dest = self.cleanPtr(dest)
        if aggressive:
            ida_bytes.del_items(src, 0, self.addressSize())
        if self.makeAddress(src):
            idc.add_dref(src, clean_dest, idc.XREF_USER | idc.dr_O)
            idc.add_cref(src, clean_dest, idc.XREF_USER | idc.dr_O)
            ida_offset.op_offset(src, 0, idc.REF_OFF32)
            if aggressive:
                ida_bytes.del_items(dest, 0, self.addressSize())
                idc.create_insn(self.cleanPtr(dest))
Example #11
0
def convert_code_data_region_to_code(start_ea, end_ea):
    size = end_ea - start_ea
    score, count = code_score(start_ea, end_ea)
    if score >= 0.75:
        #print '{:016x}  {:8x}  {}'.format(start_ea, size, score)
        idc.del_items(start_ea, idc.DELIT_SIMPLE, size)
        for ea in range(start_ea, end_ea, 4):
            ilen = idc.create_insn(ea)
            if ilen == 0:
                idc.create_dword(ea)
Example #12
0
def resolve_opaque_push_retn():

    PATTERNS = ["68 ?? ?? ?? ?? C3"]

    count_patched = 0

    for pattern in PATTERNS:

        ea = 0

        while ea != BADADDR:
            ea = ida_search.find_binary(
                ea, BADADDR, pattern, 16,
                SEARCH_NEXT | SEARCH_DOWN | SEARCH_CASE)
            ''' 
            pattern: 68 ?? ?? ?? ?? C3
            .text:00406922 68 B2 6A 00 10       push    0x10006ab2
            .text:00406927 C3                   retn
            
            patched:
            .text:00406922 E9 B2 6A 00 10       jmp     0x10006ab2
            .text:00406927 90                   nop
            '''

            if ea_in_bounds(ea):
                j_pos = ea
                pos_jmp = idc.get_wide_dword(j_pos + 1)  # absolute address

                offset = pos_jmp - 5 - j_pos

                # Patch the push and retn instructions with NOPs (6 bytes)
                for i in range(0, 6):
                    ida_bytes.patch_byte(j_pos + i, 0x90)

                ida_bytes.patch_byte(j_pos, 0xE9)
                ida_bytes.patch_dword(j_pos + 0x1, offset)

                idc.create_insn(ea)

                count_patched += 1

    print("\tPatched resolve_opaque_push_retn: {0}".format(count_patched))
def resolve_obf_calls(ea):
    next_instr_addr = idc.get_wide_dword(ea + 1)

    first_jmp_target = (ea + idc.get_wide_dword(ea + 0x7) + 0xB) & 0xFFFFFFFF
    second_jmp_target = (ea + idc.get_wide_dword(ea + 0xD) + 0x11) & 0xFFFFFFFF

    if first_jmp_target != second_jmp_target:
        return

    call_param = (first_jmp_target - ea - 5) & 0xFFFFFFFF

    # Now we can replace all code till next instruction's address with NOPs
    fill_with_nops(ea, next_instr_addr)

    # Insert CALL
    ida_bytes.patch_byte(ea, 0xE8)                      # CALL
    ida_bytes.patch_dword(ea + 1, call_param)
    idc.create_insn(ea)

    return True
def resolve_calls_through_register(ea):
    next_instr_addr = idc.get_wide_dword(ea + 1)

    # Check if that's just a parameter passing through stack
    if ea & 0xFFFF0000 != next_instr_addr & 0xFFFF0000:
        return

    if next_instr_addr - ea > 0x100:
        return

    if idc.get_wide_byte(ea + 6) & 0xF0 in [0x20, 0xE0]:
        call_param = 0x9000 + idc.get_wide_byte(ea + 6) ^ 0x30
    else:
        call_param = idc.get_wide_word(ea + 6) ^ 0x30

    fill_with_nops(ea, next_instr_addr)
    idc.patch_byte(ea, 0xFF)
    idc.patch_word(ea + 1, call_param)
    idc.create_insn(ea)

    return True
Example #15
0
def check_previous_inst_is_call(return_addr, is_64bit):
    list_of_call_inst_lengths = [2, 3, 5, 6, 7]
    if is_64bit:
        list_of_call_inst_lengths.append(9)

    for call_length in list_of_call_inst_lengths:
        call_addr = return_addr - call_length

        try:
            if idaapi.is_call_insn(call_addr) and idc.create_insn(
                    call_addr) and print_insn_mnem(call_addr) == "call":
                return (True, call_addr)
        except ValueError:
            continue

    return (False, None)
def cleanup_resolveapi_calls(ea):
    delta = 0 if idc.get_wide_byte(ea) == 0x6A else 3

    intermediate_call_target = idc.get_wide_dword(ea + 8 + delta)
    if intermediate_call_target > 0x40:
        return

    # Check if we got library name
    if idc.get_wide_dword(ea + intermediate_call_target + 8 + delta) != 0x006c6c64:   # "dll\x00"
        return

    # Check if we got enough space for patching
    if idc.get_wide_dword(ea + intermediate_call_target + 0x11 + delta) != 0x90909090 or \
    idc.get_wide_byte(ea + intermediate_call_target + 0x15 + delta) != 0x90:
        return

    idc.patch_byte(ea + 7 + delta, 0xEB)
    idc.patch_byte(ea + 8 + delta, intermediate_call_target + 3)
    fill_with_nops(ea + 9 + delta, ea + 0xC + delta)
    idc.create_insn(ea + 7 + delta)

    # Now we need to pass module name parameter through stack
    resolve_api_call_param = idc.get_wide_dword(ea + intermediate_call_target + 0xD + delta)
    resolve_api_call_param = resolve_api_call_param - 5     # offset due to inserted PUSH command

    # Insert new PUSH command
    idc.patch_byte(ea + intermediate_call_target + 0xC + delta, 0x68)
    idc.patch_dword(ea + intermediate_call_target + 0xD + delta, ea + 0xC + delta)
    idc.create_insn(ea + intermediate_call_target + 0xC + delta)

    # Restore call ResolveApi
    idc.patch_byte(ea + intermediate_call_target + 0x11 + delta, 0xE8)
    idc.patch_dword(ea + intermediate_call_target + 0x12 + delta, resolve_api_call_param)
    idc.create_insn(ea + intermediate_call_target + 0x11 + delta)
    
    return True
Example #17
0
 def makeInsn(self, addr):
     if idc.create_insn(addr) == 0:
         idc.del_items(addr, idc.DELIT_EXPAND)
         idc.create_insn(addr)
     idc.auto_wait()
Example #18
0
def dataScan(analyzer, scs):
    """Scan the code segments for orphan data blobs that represent analysis errors.

    Args:
        analyzer (instance): analyzer instance to be used
        scs (list): list of (sark) code segments
    """
    # First Scan - unreffed data chunks inside functions ==> should be converted to code
    for sc in scs:
        first_line = None
        end_line = None
        for line in sc.lines:
            # After the first, the rest of the lines should have 0 crefs
            if first_line is not None and ((not line.is_data)
                                           or len(list(line.drefs_to)) > 0
                                           or len(list(line.crefs_to)) > 0):
                end_line = line
            # we only care about data lines with a single cref from the previous line
            elif first_line is None and (
                (not line.is_data) or len(list(line.drefs_to)) > 0
                    or len(list(line.crefs_to)) != 1
                    or sark.Line(list(line.crefs_to)[0]).next != line):
                end_line = line
            # don't mark switch entries
            elif analyzer.switch_identifier.isSwitchEntry(line.start_ea):
                end_line = line
            # Finally, check if it could be a function of some type
            elif first_line is None:
                first_line = line
                continue
            # Found an adjacent suitable line
            else:
                continue
            # Now check if we found something (end_line is always != None at this point)
            if first_line is not None and end_line is not None:
                chunk_start = first_line.start_ea
                chunk_end = end_line.start_ea
                # check that we can deduce anything on this current code type
                if not analyzer.supportedCodeType(
                        analyzer.codeType(chunk_start)):
                    continue
                # check that the chunk before us is not the end of a function
                if analyzer.func_classifier.predictFunctionEnd(chunk_start):
                    # shouldn't really happen, do nothing in this case
                    pass
                # data chunk in the middle of a function, and not at it's end - convert it to code
                else:
                    analyzer.logger.debug(
                        "In-Function data chunk at: 0x%x - 0x%x (%d)",
                        chunk_start, chunk_end, chunk_end - chunk_start)
                    ida_bytes.del_items(chunk_start, 0,
                                        chunk_end - chunk_start)
                    idc.create_insn(chunk_start)
                # reset the vars
                first_line = None
                end_line = None

    # Second scan - unreffed data chunks outside of functions ==> new functions, possibly of different code type
    size_limit = analyzer.func_classifier.functionStartSize()
    analyzer.logger.debug("Size limit for data scan is: %d", size_limit)
    conversion_candidates = []
    # recon pass
    for sc in scs:
        first_line = None
        end_line = None
        for line in sc.lines:
            # we only care about data lines without xrefs
            if (not line.is_data) or len(list(line.crefs_to)) > 0 or len(
                    list(line.drefs_to)) > 0:
                end_line = line
            # check if it's big enough for the classifier
            elif line.size < size_limit:
                end_line = line
            # check if it looks like a string
            elif analyzer.str_identifier.isLocalAsciiString(line.start_ea,
                                                            check_refs=False):
                analyzer.str_identifier.defineAsciiString(line.start_ea)
                end_line = line
            # make sure it isn't a switch entry
            elif analyzer.switch_identifier.isSwitchEntry(line.start_ea):
                end_line = line
            # Finally, check if it could be a function of some type
            elif first_line is None:
                first_line = line
                continue
            # Found an adjacent suitable line
            else:
                continue
            # Now check if we found something (end_line is always != None at this point)
            if first_line is not None and end_line is not None:
                chunk_start = first_line.start_ea
                chunk_end = end_line.start_ea
                guess_code_type = analyzer.func_classifier.predictFunctionStartType(
                    chunk_start)
                original_code_type = analyzer.codeType(chunk_start)
                analyzer.logger.debug(
                    "Found a data chunk at: 0x%x - 0x%x (%d), (Type %d, Local type %d)",
                    chunk_start, chunk_end, chunk_end - chunk_start,
                    guess_code_type, original_code_type)
                # Check if this is the beginning of a function
                if analyzer.func_classifier.predictFunctionStart(
                        chunk_start, guess_code_type):
                    conversion_candidates.append(
                        (chunk_start, chunk_end, guess_code_type,
                         original_code_type))
                # reset the vars
                first_line = None
                end_line = None
    # conversion pass
    for chunk_start, chunk_end, guess_code_type, original_code_type in conversion_candidates:
        analyzer.logger.info(
            "Found an isolated data chunk at: 0x%x - 0x%x (%d), (Type %d, Local type %d)",
            chunk_start, chunk_end, chunk_end - chunk_start, guess_code_type,
            original_code_type)
        ida_bytes.del_items(chunk_start, 0, chunk_end - chunk_start)
        if original_code_type != guess_code_type:
            analyzer.setCodeType(chunk_start, chunk_end, guess_code_type)
        idc.plan_and_wait(chunk_start, chunk_end)
        ida_funcs.add_func(chunk_start)
Example #19
0
 def __call__(self):
     idc.create_insn(self.ea)
Example #20
0
def try_mark_as_code(ea):
    if is_code(ea) and not is_code_by_flags(ea):
        idc.create_insn(ea)
        idaapi.auto_wait()
        return True
    return False
Example #21
0
 def apply(self):
     if self.data_at_address:
         ida_bytes.del_items(self.address, ida_bytes.DELIT_SIMPLE)
     idc.create_insn(self.address)
     return True
Example #22
0
 def cmd_make_code(self, a):
     return str(idc.create_insn(int(a, 0)))
Example #23
0
def get_all_calls():
    is_64bit = set_version_and_platform_specific_elements()

    call_list = []
    call_addr_list = []

    #check if stack segment is None. It's a problem
    if is_64bit:
        sp = cpu.Rsp
        ip = cpu.Rip
    else:
        sp = cpu.Esp
        ip = cpu.Eip

    if idaapi.getseg(cpu.Rsp) is None:
        warning("Stack segment is None")
        return False

    #information about current fun
    is_current_fun = True
    call_list.append(get_info_about_call(ip, "", sp, is_current_fun))
    call_addr_list.append(ip)

    #iterate by stack
    if is_64bit:
        #at the begging return address is set as a current ip
        return_addr = cpu.Rip
        curr_sp = cpu.Rsp
        curr_bp = cpu.Rbp

        for i in range(0, MAX_NUMBER_FUNCTION_TO_SHOW):
            return_addr, curr_sp, curr_bp = calculate_caller_function_frame_info_x64(
                return_addr, curr_sp, curr_bp)
            if return_addr == idaapi.BADADDR or return_addr == 0:
                break

            curr_segment = idaapi.getseg(return_addr)

            #segmenst must exists and be executable
            if not curr_segment or (curr_segment.perm
                                    & idaapi.SEGPERM_EXEC) == 0:
                continue

            is_call, curr_call_addr = check_previous_inst_is_call(
                return_addr, is_64bit)
            if not is_call:
                continue

            #if bytes are not disassembled, then do it
            flags = ida_bytes.get_full_flags(curr_call_addr)
            if not ida_bytes.is_code(flags):
                idc.create_insn(curr_call_addr)

            #save a call argument
            call_list.append(
                get_info_about_call(curr_call_addr,
                                    print_operand(curr_call_addr, 0),
                                    return_addr))
            call_addr_list.append(curr_call_addr)
    else:
        curr_ebp = cpu.Ebp
        ptr_size = 4
        pfn_get_ptr = idc.get_wide_dword

        for i in range(0, MAX_NUMBER_FUNCTION_TO_SHOW):
            return_addr = pfn_get_ptr(curr_ebp + ptr_size)
            debug('ret: {:08X}'.format(return_addr))
            curr_ebp = pfn_get_ptr(curr_ebp)
            debug('ebp: {:08X}'.format(curr_ebp))

            if return_addr == idaapi.BADADDR or return_addr == 0:
                break

            curr_segment = idaapi.getseg(return_addr)

            #segmenst must exists and be executable
            if not curr_segment or (curr_segment.perm
                                    & idaapi.SEGPERM_EXEC) == 0:
                continue

            is_call, curr_call_addr = check_previous_inst_is_call(
                return_addr, is_64bit)
            if not is_call:
                continue

            #if bytes are not disassembled, then do it
            flags = ida_bytes.get_full_flags(curr_call_addr)
            if not ida_bytes.is_code(flags):
                idc.create_insn(curr_call_addr)

            #save a call argument
            call_list.append(
                get_info_about_call(curr_call_addr,
                                    print_operand(curr_call_addr, 0),
                                    curr_ebp))
            call_addr_list.append(curr_call_addr)

    return True, call_list, call_addr_list
Example #24
0
    def locateDataPtrs(self, scs, sds):
        """Locate all data / code fptrs in the given set of segments.

        Args:
            scs (list): list of (sark) code segments
            sds (list): list of (sark) data segments
        """
        local_ref_ptrs = defaultdict(set)
        seen_list = []
        approved_ptrs = []
        approved_eas = set()
        ptrs_mappings = defaultdict(set)
        marked_artifacts = []
        for sd in sds:
            cur_ea = pad(sd.start_ea, self._analyzer.data_fptr_alignment)
            while cur_ea < sd.end_ea:
                line = sark.Line(cur_ea)
                if line.is_string:
                    cur_ea += pad(line.size,
                                  self._analyzer.data_fptr_alignment)
                    continue
                # check for a function ptr
                value = self._analyzer.parseAdderss(cur_ea)
                # make sure it is valid (enforces that the code_type is active)
                if self.isValidCodePtr(value, scs):
                    func_value = self._analyzer.cleanPtr(value)
                    code_type = self._analyzer.ptrCodeType(value)
                    # is seen
                    if func_value in local_ref_ptrs:
                        local_ref_ptrs[func_value].add(code_type)
                        ptrs_mappings[func_value].add(cur_ea)
                        self._analyzer.logger.debug(
                            "Located a fptr from 0x%x to 0x%x (type: %d) - Undeclared function",
                            cur_ea, func_value, code_type)
                        if self.isPrintableAddress(value):
                            self._analyzer.logger.debug(
                                "Looks like a printable FP: 0x%x", value)
                        approved_ptrs.append((cur_ea, value))
                        approved_eas.add(cur_ea)
                        seen_list.append((cur_ea, True))
                        marked_artifacts.append((cur_ea, True))
                    # is start of real function, from the correct type
                    elif self._analyzer.codeType(
                            func_value
                    ) == code_type and self._analyzer.func_classifier.isFuncStart(
                            func_value):
                        local_ref_ptrs[func_value].add(code_type)
                        ptrs_mappings[func_value].add(cur_ea)
                        self._analyzer.logger.debug(
                            "Located a fptr from 0x%x to 0x%x (type: %d) - Existing function",
                            cur_ea, func_value, code_type)
                        approved_ptrs.append((cur_ea, value))
                        approved_eas.add(cur_ea)
                        seen_list.append((cur_ea, True))
                        marked_artifacts.append((cur_ea, True))
                    # is start of function
                    elif self._analyzer.func_classifier.predictFunctionStartMixed(
                            func_value, known_type=code_type):
                        local_ref_ptrs[func_value].add(code_type)
                        ptrs_mappings[func_value].add(cur_ea)
                        self._analyzer.logger.debug(
                            "Located a fptr from 0x%x to 0x%x (type: %d) - Undeclared function",
                            cur_ea, func_value, code_type)
                        if self.isPrintableAddress(value):
                            self._analyzer.logger.debug(
                                "Looks like a printable FP: 0x%x", value)
                        approved_ptrs.append((cur_ea, value))
                        approved_eas.add(cur_ea)
                        seen_list.append((cur_ea, True))
                        marked_artifacts.append((cur_ea, True))
                    # only a candidate - may be will be approved later
                    else:
                        seen_list.append((cur_ea, False))
                        # check for an analysis problem
                        if len(list(line.drefs_from)) > 0:
                            idc.del_dref(cur_ea, value)
                            idc.del_dref(cur_ea, func_value)
                # Check for a valid data pointer
                elif self.isValidDataPtr(value, sds):
                    # make it a data pointer
                    self._analyzer.markDataPtr(cur_ea, value)
                    self._analyzer.logger.debug(
                        "Located a data ptr from 0x%x to 0x%x", cur_ea, value)
                    marked_artifacts.append((cur_ea, False))
                    marked_artifacts.append((value, False))
                # continue forward
                cur_ea += pad(self._analyzer.addressSize(),
                              self._analyzer.data_fptr_alignment)

        # check if there is some pattern we can use to find more fptrs
        chosen_threshold = 7
        cur_window = []
        window_index = 0
        # NOTE: this step is too risky if there are Read-Only data constants inside the text section
        while window_index < len(
                seen_list) and not self._analyzer.isCodeMixedWithData():
            # If we didn't reach the end, and
            # 1. The window doesn't have enough "True" pointers
            # 2. The windows contains only "True" pointers
            # Slide the window onward
            while window_index < len(seen_list) and (
                    len(list(filter(lambda x: x[1],
                                    cur_window))) < chosen_threshold
                    or len(list(filter(lambda x: not x[1], cur_window))) == 0):
                # If we are above the threshold (meaning that cond #2 applies), kick out the first ptr (which is a "True" ptr)
                if chosen_threshold < len(
                        list(filter(lambda x: x[1], cur_window))):
                    cur_window = cur_window[1:]
                # Add a new pointer at the end of our window
                cur_window.append(seen_list[window_index])
                window_index += 1
            # Sanity check: check if we have a candidate
            if window_index == len(seen_list) and len(
                    list(filter(lambda x: not x[1], cur_window))) == 0:
                break
            # measure the deltas
            chosen_window = list(filter(lambda x: x[1], cur_window))
            # deltas between the "True" pointers
            chosen_deltas = set()
            for i in range(len(chosen_window) - 1):
                chosen_deltas.add(chosen_window[i + 1][0] -
                                  chosen_window[i][0])
            # All possible deltas between adjacent pointers
            seen_deltas = set()
            for i in range(len(cur_window) - 1):
                seen_deltas.add(cur_window[i + 1][0] - cur_window[i][0])
            new_chosen = None
            # check for a pattern
            if len(seen_deltas) <= len(chosen_deltas):
                new_chosen = list(filter(lambda x: not x[1], cur_window))[0]
            # check if the window starts with a candidate, that is right near a "True" pointer
            elif not cur_window[0][1]:
                first_seen = cur_window[0]
                seen_addr = first_seen[0]
                for candidate in [
                        seen_addr - self._analyzer.data_fptr_alignment,
                        seen_addr + self._analyzer.data_fptr_alignment
                ]:
                    if candidate in approved_eas:
                        new_chosen = first_seen
                        break
            # check if found a match
            if new_chosen is not None:
                # re-insert ourselves with our new values
                our_index = cur_window.index(new_chosen)
                cur_window = cur_window[:our_index] + [
                    (new_chosen[0], True)
                ] + cur_window[our_index + 1:]
                # mark the pointer
                cur_ea = new_chosen[0]
                value = self._analyzer.parseAdderss(cur_ea)
                func_value = self._analyzer.cleanPtr(value)
                code_type = self._analyzer.ptrCodeType(value)
                local_ref_ptrs[func_value].add(code_type)
                ptrs_mappings[func_value].add(cur_ea)
                approved_ptrs.append((cur_ea, value))
                marked_artifacts.append((cur_ea, True))
                approved_eas.add(cur_ea)
                self._analyzer.logger.debug(
                    "Located new fptr from 0x%x to 0x%x (type: %d)", cur_ea,
                    func_value, code_type)
            # advance the window
            cur_window = cur_window[1:]

        # filter the pointers (we could have false positives)
        disqualified_addresses = set()
        for cur_ea, raw_address in approved_ptrs:
            fixed_address = self._analyzer.cleanPtr(raw_address)
            disqualified = False
            # check if already disqualified
            if fixed_address not in ptrs_mappings:
                continue
            # Several code types for the same address, we take no chances and remove them all
            if len(local_ref_ptrs[fixed_address]) != 1:
                disqualified = True
            # Check if the code type is even legal for that address
            else:
                wanted_code_type = list(local_ref_ptrs[fixed_address])[0]
                orig_code_type = self._analyzer.codeType(fixed_address)
                idc.ida_bytes.del_items(fixed_address, 0,
                                        self._analyzer.addressSize())
                if orig_code_type != wanted_code_type:
                    self._analyzer.setCodeType(fixed_address,
                                               fixed_address + 4,
                                               wanted_code_type)
                if idc.create_insn(fixed_address) == 0:
                    disqualified = True
                # Always clean after ourselves
                ida_bytes.del_items(fixed_address, 0,
                                    self._analyzer.addressSize())
                if orig_code_type != wanted_code_type:
                    self._analyzer.setCodeType(
                        fixed_address,
                        fixed_address + self._analyzer.addressSize(),
                        orig_code_type)
            # We are OK, can continue
            if not disqualified:
                continue
            # Found a false function pointer
            # Be cautious with the removals, we could have duplicates
            if fixed_address in self._ptrs_mappings:
                self._ptrs_mappings.pop(fixed_address)
            disqualified_addresses.add(raw_address)
            marked_artifacts.remove((cur_ea, True))
            # no need to remove from local_ref_ptrs, as the global variable only gets the approved values
            # no need to remove from approved_eas, as this data set isn't used anymore
            self._analyzer.logger.debug(
                "Disqualified (code) pointer 0x%08x from 0x%08x (type %d, seen types %s)",
                fixed_address, cur_ea, wanted_code_type,
                local_ref_ptrs[fixed_address])

        # Now filter them based on scoped range from other artifacts
        marked_artifacts.sort(key=lambda x: x[0])
        cur_index = 0
        prev_artifact = None
        while cur_index < len(marked_artifacts) - 1:
            cur_ea, is_fptr = marked_artifacts[cur_index]
            next_ea, _ = marked_artifacts[cur_index + 1]
            # Only check ourselves against the next in line
            if cur_ea + FPTR_LOCALITY_RANGE < next_ea:
                if prev_artifact is None and is_fptr:
                    # we should be disqualified
                    raw_address = self._analyzer.parseAdderss(cur_ea)
                    wanted_code_type = self._analyzer.ptrCodeType(raw_address)
                    fixed_address = self._analyzer.cleanPtr(raw_address)
                    # Be cautious with the removals, we could have duplicates
                    if fixed_address in self._ptrs_mappings:
                        self._ptrs_mappings.pop(fixed_address)
                    disqualified_addresses.add(raw_address)
                    self._analyzer.logger.debug(
                        "Disqualified (scope) pointer 0x%08x from 0x%08x (type %d))",
                        fixed_address, cur_ea, wanted_code_type)
                # set the prev artifact
                prev_artifact = None
                # check the next element
                cur_index += 1
            # We are linking to the next element, so he is legit too
            else:
                prev_artifact = next_ea
                cur_index += 1

        # mark the pointers
        for cur_ea, raw_address in filter(
                lambda x: x[1] not in disqualified_addresses, approved_ptrs):
            self._ref_ptrs[self._analyzer.cleanPtr(
                raw_address)] = self._analyzer.ptrCodeType(raw_address)
            self._analyzer.markCodePtr(cur_ea, raw_address)

        # print some results
        self._analyzer.logger.info(
            "Found %d different potential function pointer destinations",
            len(self._ref_ptrs))
Example #25
0
    def create_function(
        fnc,
        overwrite_names,
        offset,
        add_names=True,
    ):
        def set_name(addr, name):
            if not add_names:
                return
            try:
                numericName = int(name, 16)
                return
            except ValueError:
                pass
            ok = False
            if not IDAtools.is_dummy_name(name):
                ok = idc.set_name(addr, name, idc.SN_CHECK)
            if not ok:
                data = (name, size, addr)

        name = fnc.get("name")
        addr = int(fnc.get("addr"))
        addr = addr + int(offset)
        size = int(fnc.get("size"))

        if type(addr) == int:
            idc.create_insn(addr)

            code = IDAtools.is_code(addr)
            fnc = IDAtools.is_func(addr)
            fnc_chnk = IDAtools.is_func_chunk(addr)
            start = IDAtools.get_func_start(addr)
            generic = fnc and IDAtools.func_is_generic(addr)

            if size >= 2 and size % 2 == 0:
                end = addr + size
            else:
                end = idaapi.BADADDR

            if (fnc or fnc_chnk):
                ok = idc.set_func_end(addr, addr)
                if not ok:
                    pass
                    #print("{0:#x}: cannot add fnc, there still exists code, {1}, {2:#x}".format(addr, size, end))
            if IDAtools.is_dummy_name_by_addr(addr) and (
                    not name.startswith("sub_") and overwrite_names):
                set_name(addr, name)
            elif start == addr and overwrite_names:
                set_name(addr, name)

            elif start != addr:
                if fnc_chnk:
                    idc.remove_fchunk(addr, addr)
                elif fnc:
                    idc.set_func_end(
                        addr, addr)  # force previous function to end here.
                ok = idaapi.add_func(addr, end)
                if ok and add_names and overwrite_names:
                    set_name(addr, name)
                if not ok:
                    print("{0:#x}: cannot add fnc, {1}, {2:#x}".format(
                        addr, size, end))
            else:
                print(
                    "{0:#x}: unknown problem - code: {1}, fnc: {2}, start {3:#x}, size {4}, end {5}"
                    .format(addr, code, fnc, start, size, end))

        IDAtools.ida_wait()
Example #26
0
def load_file(li, neflags, format):
    # Set flags
    idaapi.set_processor_type(
        "arm", idaapi.SETPROC_LOADER_NON_FATAL | idaapi.SETPROC_LOADER)
    idc.set_inf_attr(idc.INF_LFLAGS,
                     idc.get_inf_attr(idc.INF_LFLAGS) | idc.LFLG_64BIT)
    idc.set_inf_attr(idc.INF_DEMNAMES, idaapi.DEMNAM_GCC3)
    idaapi.set_compiler_id(idaapi.COMP_GNU)
    idaapi.add_til('gnulnx_arm64', 1)

    # Load IRAM memory
    li.seek(0)
    pk11 = li.read(PK1L_SIZE)
    idaapi.mem2base(pk11, PK1L_ADDRESS)

    # Add identity mappings
    add_segment(PK1L_ADDRESS, PK1L_SIZE, '.pk1_identity', 'RWX')
    add_segment(TZRAM_BASE, TZRAM_SIZE, '.tz_identity', 'RWX')

    # Emulate package1 to determine interesting extents
    emu = Emulator()
    emu.run_emulator(pk11)

    # Refresh IRAM contents to reflect any decompression that may have occurred.
    idaapi.mem2base(emu.read_mem(PK1L_ADDRESS, PK1L_SIZE), PK1L_ADDRESS)

    if not emu.found_smc_evp:
        # Set coldboot crt0
        idc.create_insn(emu.entrypoint)
        idc.set_name(emu.entrypoint, 'coldboot_crt0')
        return 1

    iram_mappings = []
    dram_mappings = []
    tzram_mappings = []
    mmio_mappings = []

    for m in emu.mappings:
        if is_tzram(m):
            tzram_mappings.append(m)
        elif is_dram(m):
            dram_mappings.append(m)
        elif is_iram(m):
            iram_mappings.append(m)
        else:
            assert is_mmio(m)
            mmio_mappings.append(m)

    for m in mmio_mappings:
        add_mmio_mapping(m)

    # Process IRAM mappings
    if len(iram_mappings) == 3:
        sorted_irams = sorted(iram_mappings, key=lambda m: m[2])
        if [m[2] for m in sorted_irams] == [0x1000, 0x1000, 0x10000]:
            assert len(set([m[3] for m in sorted_irams])) == 2
            if sorted_irams[1][3] == sorted_irams[2][3]:
                add_segment(sorted_irams[0][0], sorted_irams[0][2], '.bl_sync',
                            'IO')
                add_segment(sorted_irams[1][0], sorted_irams[1][2], '.sc7_fw',
                            'DATA')
                add_segment(sorted_irams[2][0], sorted_irams[2][2],
                            '.sc7_tmp_save', 'DATA')
            else:
                assert sorted_irams[0][3] == sorted_irams[2][3]
                add_segment(sorted_irams[1][0], sorted_irams[1][2], '.bl_sync',
                            'IO')
                add_segment(sorted_irams[0][0], sorted_irams[0][2], '.sc7_fw',
                            'DATA')
                add_segment(sorted_irams[2][0], sorted_irams[2][2],
                            '.sc7_tmp_save', 'DATA')
        else:
            print iram_mappings
            raise ValueError('Unknown IRAM mapping set')
    elif len(iram_mappings) == 2:
        sorted_irams = sorted(iram_mappings, key=lambda m: m[2])
        if [m[2] for m in sorted_irams] == [0x1000, 0x10000]:
            assert len(set([m[3] for m in sorted_irams])) == 2
            add_segment(sorted_irams[0][0], sorted_irams[0][2], '.bl_sync',
                        'IO')
            add_segment(sorted_irams[1][0], sorted_irams[1][2],
                        '.sc7_tmp_save', 'DATA')
        else:
            print iram_mappings
            raise ValueError('Unknown IRAM mapping set')
    else:
        print iram_mappings
        raise ValueError('Unknown IRAM mapping set')

    # Process DRAM mappings
    if len(dram_mappings) == 2:
        sorted_drams = sorted(dram_mappings, key=lambda m: m[2])
        if [m[2] for m in sorted_drams] == [0x1000, 0x10000]:
            add_segment(sorted_drams[0][0], sorted_drams[0][2], '.sc7_se_ctx',
                        'DATA')
            add_segment(sorted_drams[1][0], sorted_drams[1][2], '.sc7_sm_ctz',
                        'DATA')
        else:
            print dram_mappings
            raise ValueError('Unknown DRAM mapping set')
    else:
        print dram_mappings
        raise ValueError('Unknown DRAM mapping set')

    # Process TZRAM segments
    tzram_groups = []
    for (vaddr, paddr, size, attr) in sorted(tzram_mappings,
                                             key=lambda m: m[0]):
        inserted = False
        for i in xrange(len(tzram_groups)):
            if vaddr == tzram_groups[i][-1][0] + tzram_groups[i][-1][
                    2] and tzram_groups[i][-1][2] != 0x40000:
                tzram_groups[i].append((vaddr, paddr, size, attr))
                inserted = True
                break
        if not inserted:
            tzram_groups.append([(vaddr, paddr, size, attr)])

    for group in tzram_groups:
        print 'Group'
        for m in group:
            print '    %x %x %x %x' % m

    # Process groups
    for group in tzram_groups:
        if len(group) > 1:
            if is_executable(group[0]):
                # .text/.rodata/.rwdata :)
                if len(group) == 2:
                    add_segment(group[0][0], group[0][2], '.text_rodata',
                                'CODE')
                    add_segment(group[1][0], group[1][2], '.rwdata', 'DATA')
                    load_mapping(emu, group[0])
                    load_mapping(emu, group[1])
                else:
                    assert len(group) == 3
                    add_segment(group[0][0], group[0][2], '.text', 'CODE')
                    add_segment(group[1][0], group[1][2], '.rodata', 'CONST')
                    add_segment(group[2][0], group[2][2], '.rwdata', 'DATA')
                    load_mapping(emu, group[0])
                    load_mapping(emu, group[1])
                    load_mapping(emu, group[2])
        elif is_executable(group[0]):
            assert len(group) == 1
            vaddr, paddr, size, attr = group[0]
            if size > 0x8000:
                assert len(
                    filter(lambda g: is_executable(g[0]) and g[0][2] > 0x8000,
                           tzram_groups)) == 1
                assert is_writable(group[0])
                add_segment(vaddr, size, '.code', 'RWX')
                load_mapping(emu, group[0])
            elif size == 0x2000:
                assert len(
                    filter(lambda g: is_executable(g[0]) and g[0][2] == 0x2000,
                           tzram_groups)) == 1
                add_segment(vaddr, size, '.pk2ldr', 'RWX')
                load_mapping(emu, group[0])
            else:
                assert size == 0x1000
                assert len(
                    filter(lambda g: is_executable(g[0]) and g[0][2] == 0x1000,
                           tzram_groups)) == 1
                add_segment(vaddr, size, '.vectors', 'CODE')
                load_mapping(emu, group[0])
        elif len(group) == 1 and (group[0][2] == 0x10000
                                  or group[0][2] == 0x40000):
            assert len(
                filter(
                    lambda g: len(g) == 1 and not is_executable(g[0]) and
                    (g[0][2] == 0x10000 or g[0][2] == 0x40000),
                    tzram_groups)) == 1
            assert not is_writable(group[0])
            vaddr, paddr, size, attr = group[0]
            add_segment(vaddr, size, '.tzram_ro_view', 'CONST')
        elif len(group) == 1 and group[0][2] == 0x1000:
            vaddr, paddr, size, attr = group[0]
            pk2ldr_group = filter(
                lambda g: is_executable(g[0]) and g[0][2] == 0x2000,
                tzram_groups)
            assert len(pk2ldr_group) == 1
            pk2ldr_group = pk2ldr_group[0][0]
            if paddr == emu.l3_table:
                add_segment(vaddr, size, '.l3_table', 'DATA')
            elif paddr == (emu.l3_table - 0x1000):
                add_segment(vaddr, size, '.l2_table', 'DATA')
            elif paddr == pk2ldr_group[1]:
                add_segment(vaddr, size, '.reused_stack0', 'DATA')
            elif paddr == (pk2ldr_group[1] + 0x1000):
                add_segment(vaddr, size, '.reused_stack1', 'DATA')
            elif vaddr == emu.phys_to_virt[
                    emu.ttbr & ~0xFFF][0] or vaddr == emu.core0_stack_page:
                add_segment(vaddr, size, '.shared_data', 'DATA')
            else:
                print 'Unknown Group'
                for m in group:
                    print '    %x %x %x %x' % m
                assert False
        else:
            print 'Unknown Group'
            for m in group:
                print '    %x %x %x %x' % m
            assert False

    # Set vector types as code.
    for i, ctx in enumerate(['sp0', 'spx', 'a64', 'a32']):
        for j, kind in enumerate(['synch', 'irq', 'fiq', 'serror']):
            addr = emu.vbar + 0x200 * i + 0x80 * j
            name = '%s_%s_exception' % (ctx, kind)
            idc.create_insn(addr)
            idc.set_name(addr, name)

    # Set coldboot crt0
    idc.create_insn(emu.entrypoint)
    idc.set_name(emu.entrypoint, 'coldboot_crt0')

    # Add SMC list entries
    assert len(emu.smc_lists) == 2
    idc.set_name(emu.smc_lists_addr, 'g_smc_lists')
    for i, name in enumerate(['user', 'priv']):
        addr, num_entries, pad = emu.smc_lists[i]
        idc.set_name(addr, 'g_smc_list_%s' % name)
        for n in xrange(num_entries):
            id, access, func = up('<IIQ', emu.read_mem(addr + 0x10 * n, 0x10))
            if func == 0:
                continue
            smc_name = get_smc_name(name == 'user', id)
            process_smc(func, smc_name)

    # We're done
    return 1
Example #27
0
def import_functions(fncs, add_names=True, always_thumb=True):

    name_counter = defaultdict(int)
    imported_functions = defaultdict(set)
    cfg_conflicts = defaultdict(set)
    symbol_defects = list()
    failed_fncs = list()

    countername_Fail = 0
    counterfct_fail = 0

    def set_name(addr, name):
        # FIXME creates unnamed_178 etc. instead of proper function name in IDA 7.2 on CYW20735
        name = name.replace("sub_", "unnamed_")
        cmt = idc.get_cmt(addr, 0)
        name_cmt = "fcn.%s" % name
        if cmt:
            name_cmt = cmt + ", " + name_cmt
        idc.set_cmt(addr, name_cmt, 0)
        if not add_names:
            return
        if name.isupper():
            try:
                # hackish way to stop warning about hex import
                # FIXME leave 'sub_' intact if it already exists
                # FIXME do not set the name to the hex prologue because it has duplicates, set it to
                #       'pp_{position}' instead
                a = int(name, 16)
                """continue"""
            except ValueError:
                pass
        ok = idc.set_name(addr, name, idc.SN_CHECK)
        if not ok:
            data = (name, size, addr)
            failed_fncs.append((data, "name"))
            print("{0:#x}: cannot add name, {1}".format(addr, name))
            countername_Fail = countername_Fail + 1
        else:
            imported_functions[addr].add(name)

    for name, size, addr, thumb in fncs:
        name_counter[name] += 1

        if not always_thumb:
            idc.split_sreg_range(addr, "T", int(thumb), idc.SR_user)
        idc.create_insn(addr)

        code = is_code(addr)
        fnc = is_func(addr)
        fnc_chnk = is_func_chunk(addr)
        data = (name, size, addr)
        start = get_func_start(addr)
        generic = fnc and func_is_generic(addr)

        # BADADDR automatically finds end of fnc.
        if size >= 2 and size % 2 == 0:
            end = addr + size
        else:
            end = idaapi.BADADDR

        if not code and not (fnc or fnc_chnk):
            symbol_defects.append(data)
        elif (fnc or fnc_chnk) and not code:
            cfg_conflicts[idc.get_func_name(addr)] = (data, start)
        elif start == addr and not generic:
            set_name(addr, name)  # duplicate symbol
        elif start == addr and generic:
            set_name(addr, name)
        elif start != addr:
            if fnc_chnk:
                idc.remove_fchunk(addr, addr)
            elif fnc:
                idc.set_func_end(addr,
                                 addr)  # force previous function to end here.
            ok = idaapi.add_func(addr, end)
            if not ok:
                failed_fncs.append((data, "fnc"))
                print("{0:#x}: cannot add fnc, {1}, {2:#x}".format(
                    addr, size, end))
                counterfct_fail = counterfct_fail + 1
            else:
                set_name(addr, name)
        else:
            failed_fncs.append((data, "unknown"))
            print(
                "{0:#x}: unknown problem - code: {1}, fnc: {2}, start {3:#x}, size {4}, end {5}"
                .format(addr, code, fnc, start, size, end))

    ida_auto.auto_wait()
    print("not added functions: {1} , not added names: {0}".format(
        countername_Fail, counterfct_fail))
    return name_counter, imported_functions, failed_fncs, cfg_conflicts, symbol_defects
Example #28
0
def process_smc(func, smc_name):
    idc.create_insn(func)
    idc.set_name(func, 'smc_%s' % smc_name)
    disasm = get_disasm(func)
    if disasm[:2] == ['adrp', 'x1']:
        d = [
            get_disasm(ea)
            for ea in [func, func + 4, func + 8, func + 12, func + 16]
        ]
        if not d[1][:2] == ['adrp', 'x2']:
            return
        if not d[2][:3] == ['add', 'x1', 'x1']:
            return
        if not d[3][:3] == ['add', 'x2', 'x2']:
            return
        if not d[4][0] == 'b':
            return
        func_impl = parse_adr_op(d[0][2]) + parse_adr_op(d[2][3])
        gr_impl = parse_adr_op(d[1][2]) + parse_adr_op(d[3][3])
        gr_name = '%s_get_result' % smc_name
        if smc_name == 'unwrap_titlekey':
            gr_name += '_data'
        idc.create_insn(func_impl)
        idc.set_name(func_impl, smc_name)
        idc.create_insn(gr_impl)
        idc.set_name(gr_impl, gr_name)
        if d[4][1].startswith('unk_'):
            async_smc = parse_adr_op(d[4][1])
            idc.create_insn(async_smc)
            idc.set_name(async_smc, 'handle_asynchronous_smc')
    elif disasm[:2] == ['adrl', 'x1']:
        branch_d = get_disasm(func + 8)
        if branch_d[0] == 'b':
            func_impl = parse_adr_op(disasm[2])
            idc.create_insn(func_impl)
            idc.set_name(func_impl, smc_name)
            if branch_d[1].startswith('unk_'):
                sync_smc = parse_adr_op(branch_d[1])
                idc.create_insn(sync_smc)
                idc.set_name(sync_smc, 'handle_synchronous_smc')
Example #29
0
def make_code(addresses):
    for ea in addresses:
        idc.create_insn(ea)
    return addresses
Example #30
0
    def activate(self, ctx):
        if self.action in ACTION_MENU_CONVERT:
            sel, start, end = lazy_read_selection()
            if not sel:
                idc.msg("[LazyIDA] Nothing to convert.")
                return False

            size = end - start
            data = idc.get_bytes(start, size)
            if isinstance(data, str):  # python2 compatibility
                data = bytearray(data)
            assert size == len(data)

            name = idc.get_name(start, idc.GN_VISIBLE)
            if not name:
                name = "data"
            if data:
                output = None
                plg_print("Dump from 0x%X to 0x%X (%u bytes):" % (start, end - 1, size))
                if self.action == ACTION_MENU_CONVERT[0]:
                    # escaped string
                    output = '"%s"' % "".join("\\x%02X" % b for b in data)

                elif self.action == ACTION_MENU_CONVERT[1]:
                    # hex string, space
                    output = " ".join("%02X" % b for b in data)

                elif self.action == ACTION_MENU_CONVERT[2]:
                    # C array
                    output = "unsigned char %s[%d] = {" % (name, size)
                    for i in range(size):
                        if i % 16 == 0:
                            output += "\n    "
                        output += "0x%02X, " % data[i]
                    output = output[:-2] + "\n};"

                elif self.action == ACTION_MENU_CONVERT[3]:
                    # C array word
                    data += b"\x00"
                    array_size = (size + 1) // 2
                    output = "unsigned short %s[%d] = {" % (name, array_size)
                    for i in range(0, size, 2):
                        if i % 16 == 0:
                            output += "\n    "
                        output += "0x%04X, " % u16(data[i:i+2])
                    output = output[:-2] + "\n};"

                elif self.action == ACTION_MENU_CONVERT[4]:
                    # C array dword
                    data += b"\x00" * 3
                    array_size = (size + 3) // 4
                    output = "unsigned int %s[%d] = {" % (name, array_size)
                    for i in range(0, size, 4):
                        if i % 32 == 0:
                            output += "\n    "
                        output += "0x%08X, " % u32(data[i:i+4])
                    output = output[:-2] + "\n};"

                elif self.action == ACTION_MENU_CONVERT[5]:
                    # C array qword
                    data += b"\x00" * 7
                    array_size = (size + 7) // 8
                    output = "unsigned long %s[%d] = {" % (name, array_size)
                    for i in range(0, size, 8):
                        if i % 32 == 0:
                            output += "\n    "
                        output += "%#018X, " % u64(data[i:i+8])
                    output = output[:-2] + "\n};"
                    output = output.replace("0X", "0x")

                elif self.action == ACTION_MENU_CONVERT[6]:
                    # python list
                    output = "[%s]" % ", ".join("0x%02X" % b for b in data)

                elif self.action == ACTION_MENU_CONVERT[7]:
                    # python list word
                    data += b"\x00"
                    output = "[%s]" % ", ".join("0x%04X" % u16(data[i:i+2]) for i in range(0, size, 2))

                elif self.action == ACTION_MENU_CONVERT[8]:
                    # python list dword
                    data += b"\x00" * 3
                    output = "[%s]" % ", ".join("0x%08X" % u32(data[i:i+4]) for i in range(0, size, 4))

                elif self.action == ACTION_MENU_CONVERT[9]:
                    # python list qword
                    data += b"\x00" * 7
                    output = "[%s]" %  ", ".join("%#018X" % u64(data[i:i+8]) for i in range(0, size, 8)).replace("0X", "0x")

                elif self.action == ACTION_MENU_CONVERT[10]:
                    # MASM byte array
                    header = "%s db " % name
                    output = header
                    for i in range(size):
                        if i and i % 16 == 0:
                            output += "\n"
                            output += " " * len(header)
                        output += "0%02Xh, " % data[i]
                    output = output[:-2]

                elif self.action == ACTION_MENU_CONVERT[11]:
                    # GNU ASM byte array
                    header = "%s: .byte " % name
                    output = header
                    for i in range(size):
                        if i and i % 16 == 0:
                            output += "\n"
                            output += " " * len(header)
                        output += "0x%02X, " % data[i]
                    output = output[:-2]

                if output:
                    print(output)
                    copy_to_clip(output)
                    output = None

        elif self.action == ACTION_MENU_COPY_DATA:
            # added by merc, modified by HTC
            sel, start, end = lazy_read_selection()
            if not sel:
                return 0

            data = idaapi.get_bytes(start, end - start)
            if isinstance(data, str):
                data = bytearray(data)
            output = "".join("%02X" % b for b in data)
            copy_to_clip(output)
            plg_print("Hex string '%s' copied" % output)

        elif self.action == ACTION_MENU_DUMP_DATA:
            # add by HTC
            sel, start, end = lazy_read_selection()
            if not sel:
                return 0

            size = end - start
            data = idaapi.get_bytes(start, size)
            assert len(data) == size
            if data and len(data) == size:
                dump_data_to_file("Dump_At_%X_Size_%d.dump" % (start, size), data)
            else:
                plg_print("0x%X: unable to get %d bytes" % (start, size))

        elif self.action == ACTION_MENU_XOR_DATA:
            sel, start, end = lazy_read_selection()
            if not sel:
                return 0

            size = end - start

            key = idaapi.ask_str("AA BB CC DD", 0, "Xor with hex values (or a string begin and end with\" or ')...")
            if not key:
                return 0

            bytes_key = bytearray()
            if is_str(key):
                bytes_key = str_to_bytes(key)
            else:
                bytes_key = hex_to_bytes(key)

            if not bytes_key:
                return 0

            data = idc.get_bytes(start, end - start)
            if isinstance(data, str):  # python2 compatibility
                data = bytearray(data)

            output = xor_data(data, bytes_key)
            if not output:
                plg_print("Sorry, error occurred. My bug :( Please report.")
                return 0

            assert size == len(output)

            plg_print("Xor result from 0x%X to 0x%X (%d bytes) with %s:" % (start, end, end - start, key))
            process_data_result(start, output)

        elif self.action == ACTION_MENU_FILL_NOP:
            sel, start, end = lazy_read_selection()
            if not sel:
                return 0

            idaapi.patch_bytes(start, b"\x90" * (end - start))
            idc.create_insn(start)
            plg_print("Fill 0x%X to 0x%X (%u bytes) with NOPs" % (start, end, end - start))

        elif self.action == ACTION_MENU_B64STD:
            base64_decode(True)

        elif self.action == ACTION_MENU_B64URL:
            base64_decode(False)

        elif self.action == ACTION_MENU_SCAN_VUL:
            plg_print("Finding Format String Vulnerability...")
            found = []
            for addr in idautils.Functions():
                name = idc.get_func_name(addr)
                if "printf" in name and "v" not in name and idc.get_segm_name(addr) in (".text", ".plt", ".idata"):
                    xrefs = idautils.CodeRefsTo(addr, False)
                    for xref in xrefs:
                        vul = self.check_fmt_function(name, xref)
                        if vul:
                            found.append(vul)
            if found:
                plg_print("Done! %d possible vulnerabilities found." % len(found))
                ch = VulnChoose("Vulnerability", found, None, False)
                ch.Show()
            else:
                plg_print("No format string vulnerabilities found.")

        else:
            return 0

        return 1