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)
def main(): print("[*] loading crypto constants") for const in non_sparse_consts: const["byte_array"] = convert_to_byte_array(const) for start in idautils.Segments(): print("[*] searching for crypto constants in %s" % idc.get_segm_name(start)) ea = start while ea < idc.get_segm_end(start): bbbb = list(struct.unpack("BBBB", idc.get_bytes(ea, 4))) for const in non_sparse_consts: if bbbb != const["byte_array"][:4]: continue if map(lambda x:ord(x), idc.get_bytes(ea, len(const["byte_array"]))) == const["byte_array"]: print(("0x%0" + str(digits) + "X: found const array %s (used in %s)") % (ea, const["name"], const["algorithm"])) idc.set_name(ea, const["name"]) if const["size"] == "B": idc.create_byte(ea) elif const["size"] == "L": idc.create_dword(ea) elif const["size"] == "Q": idc.create_qword(ea) idc.make_array(ea, len(const["array"])) ea += len(const["byte_array"]) - 4 break ea += 4 ea = start if idc.get_segm_attr(ea, idc.SEGATTR_TYPE) == 2: while ea < idc.get_segm_end(start): d = ida_bytes.get_dword(ea) for const in sparse_consts: if d != const["array"][0]: continue tmp = ea + 4 for val in const["array"][1:]: for i in range(8): if ida_bytes.get_dword(tmp + i) == val: tmp = tmp + i + 4 break else: break else: print(("0x%0" + str(digits) + "X: found sparse constants for %s") % (ea, const["algorithm"])) cmt = idc.get_cmt(idc.prev_head(ea), 0) if cmt: idc.set_cmt(idc.prev_head(ea), cmt + ' ' + const["name"], 0) else: idc.set_cmt(idc.prev_head(ea), const["name"], 0) ea = tmp break ea += 1 print("[*] finished")
def main(): print("[*] loading crypto constants") for const in non_sparse_consts: const["byte_array"] = convert_to_byte_array(const) for start in Segments(): print("[*] searching for crypto constants in %s" % get_segm_name(start)) ea = start while ea < get_segm_end(start): bbbb = list(struct.unpack("BBBB", get_bytes(ea, 4))) for const in non_sparse_consts: if bbbb != const["byte_array"][:4]: continue if map(lambda x: ord(x), get_bytes(ea, len( const["byte_array"]))) == const["byte_array"]: print("0x%08X: found const array %s (used in %s)" % (ea, const["name"], const["algorithm"])) set_name(ea, const["name"]) if const["size"] == "B": idc.create_byte(ea) elif const["size"] == "L": idc.create_dword(ea) elif const["size"] == "Q": idc.create_qword(ea) make_array(ea, len(const["array"])) ea += len(const["byte_array"]) - 4 break ea += 4 ea = start if get_segm_attr(ea, SEGATTR_TYPE) == 2: while ea < get_segm_end(start): d = ida_bytes.get_dword(ea) for const in sparse_consts: if d != const["array"][0]: continue tmp = ea + 4 for val in const["array"][1:]: for i in range(8): if ida_bytes.get_dword(tmp + i) == val: tmp = tmp + i + 4 break else: break else: print("0x%08X: found sparse constants for %s" % (ea, const["algorithm"])) ea = tmp break ea += 1 print("[*] finished")
def main(): print("[*] loading crypto constants") for const in non_sparse_consts: const["byte_array"] = convert_to_byte_array(const) for start in idautils.Segments(): print("[*] searching for crypto constants in %s" % idc.get_segm_name(start)) ea = start while ea < idc.get_segm_end(start): bbbb = list(struct.unpack("BBBB", idc.get_bytes(ea, 4))) for const in non_sparse_consts: if bbbb != const["byte_array"][:4]: continue if list( map(lambda x: x if type(x) == int else ord(x), idc.get_bytes(ea, len( const["byte_array"])))) == const["byte_array"]: print(("0x%0" + str(digits) + "X: found const array %s (used in %s)") % (ea, const["name"], const["algorithm"])) idc.set_name(ea, const["name"], ida_name.SN_FORCE) if const["size"] == "B": idc.create_byte(ea) elif const["size"] == "L": idc.create_dword(ea) elif const["size"] == "Q": idc.create_qword(ea) idc.make_array(ea, len(const["array"])) ea += len(const["byte_array"]) - 4 break ea += 4 ea = start if idc.get_segm_attr(ea, idc.SEGATTR_TYPE) == idc.SEG_CODE: while ea < idc.get_segm_end(start): d = ida_bytes.get_dword(ea) for const in sparse_consts: if d != const["array"][0]: continue tmp = ea + 4 for val in const["array"][1:]: for i in range(8): if ida_bytes.get_dword(tmp + i) == val: tmp = tmp + i + 4 break else: break else: print(("0x%0" + str(digits) + "X: found sparse constants for %s") % (ea, const["algorithm"])) cmt = idc.get_cmt(idc.prev_head(ea), 0) if cmt: idc.set_cmt(idc.prev_head(ea), cmt + ' ' + const["name"], 0) else: idc.set_cmt(idc.prev_head(ea), const["name"], 0) ea = tmp break ea += 1 print("[*] searching for crypto constants in immediate operand") funcs = idautils.Functions() for f in funcs: flags = idc.get_func_flags(f) if (not flags & (idc.FUNC_LIB | idc.FUNC_THUNK)): ea = f f_end = idc.get_func_attr(f, idc.FUNCATTR_END) while (ea < f_end): imm_operands = [] insn = ida_ua.insn_t() ida_ua.decode_insn(insn, ea) for i in range(len(insn.ops)): if insn.ops[i].type == ida_ua.o_void: break if insn.ops[i].type == ida_ua.o_imm: imm_operands.append(insn.ops[i].value) if len(imm_operands) == 0: ea = idc.find_code(ea, idc.SEARCH_DOWN) continue for const in operand_consts: if const["value"] in imm_operands: print(("0x%0" + str(digits) + "X: found immediate operand constants for %s") % (ea, const["algorithm"])) cmt = idc.get_cmt(ea, 0) if cmt: idc.set_cmt(ea, cmt + ' ' + const["name"], 0) else: idc.set_cmt(ea, const["name"], 0) break ea = idc.find_code(ea, idc.SEARCH_DOWN) print("[*] finished")
def sync_data_definitions_in(source_units, address_space, ea): from edit_source.include.definitions import DATA_TYPES def create_array_of(ea, count, size, op, error=False, verbose=False): ops.delete_items(ea, size) status = op(ea) if count != 1: status = idc.make_array(ea, count) if verbose: if status is False: print('error: {:07X}: failed to perform operation'.format(ea)) if error: if status is False: raise Exception('{:07X}: failed to perform operation'.format(ea)) return status unit = source_unit.get_physical_unit(source_units, ea) UNIT_IDS = asm_file.AsmFile.UNIT_IDS if unit['unit']['id'] is UNIT_IDS.DATA: print('{:07X} <{}>'.format(unit['ea'], unit['name'])) cur_ea = ea for t in unit['types']: idc.jumpto(cur_ea) data_type = t[0] count = t[1] print('{} {:07X} {}'.format(DATA_TYPES.STR[data_type], cur_ea, count)) if data_type is DATA_TYPES.BYTE: size = count create_array_of(cur_ea, count, size, idc.create_byte, error=True) cur_ea += size elif data_type is DATA_TYPES.WORD: size = count * 4 create_array_of(cur_ea, count, size, idc.create_dword, error=True) cur_ea += size elif data_type is DATA_TYPES.HWORD: size = count * 2 create_array_of(cur_ea, count, size, idc.create_word, error=True) cur_ea += size elif data_type is DATA_TYPES.OFF: xrefs = unit['xrefs_from'] first_label_ea = xrefs[0][0] size = count * 4 if not (gba_address.is_ewram_address(first_label_ea) or gba_address.is_iwram_address( first_label_ea) or gba_address.is_rom_address(first_label_ea)): # a constant, don't point. # TODO: actually include the constant in IDA create_array_status = create_array_of(cur_ea, count, size, idc.create_dword, error=True) idc.set_array_params(ea, 0, 1, 0) pass else: ops.delete_items(cur_ea, size) idc.create_dword(cur_ea) idc.op_plain_offset(cur_ea, 0, 0) create_array_status = True if count != 1: create_array_status = idc.make_array(cur_ea, count) idc.set_array_params(cur_ea, 0, 1, 0) if create_array_status is False: raise Exception('could not create array at {:07X} with count {}'.format(cur_ea, count)) # TODO: check if it has an offset and fix that cur_ea += size elif data_type is DATA_TYPES.ALIGN: pass elif data_type is DATA_TYPES.SPACE: pass elif data_type is DATA_TYPES.INCBIN: pass idc.jumpto(cur_ea)
def load_file(li, neflags, format): """ Load the file into database @param li: a file-like object which can be used to access the input data @param neflags: options selected by the user, see loader.hpp @return: 0-failure, 1-ok """ if format == AtariSTTOSImageName: idaapi.set_processor_type('68K', ida_idp.SETPROC_LOADER) li.seek(0) header = read_struct(li, tos_image_header) li.seek(0, idaapi.SEEK_END) filesize = li.tell() idc.add_segm_ex(header.os_beg, header.os_beg + filesize, 0, 1, idaapi.saRelPara, idaapi.scPub, idc.ADDSEG_NOSREG) idc.set_segm_name(header.os_beg, 'TOS') li.seek(0) li.file2base(0, header.os_beg, header.os_beg + filesize, 0) idaapi.add_entry(header.os_beg, header.os_beg, "ostext", 1) idc.set_cmt(header.os_beg, 'branch to reset handler', 0) idc.set_name(header.os_beg + 2, 'os_version') idc.create_word(header.os_beg + 2) idc.set_cmt(header.os_beg + 2, 'OS version number', 0) idc.set_cmt(header.os_beg + 4, '-> system reset handler', 0) reseth = ida_bytes.get_dword(header.os_beg + 4) idc.set_name(reseth, 'reseth') idc.set_name(header.os_beg + 8, 'os_beg') idc.set_cmt(header.os_beg + 8, '-> base of OS', 0) idc.set_name(header.os_beg + 12, 'os_end') idc.set_cmt(header.os_beg + 12, '-> end of OS memory usage', 0) os_end = ida_bytes.get_dword(header.os_beg + 12) idc.add_segm_ex(0x0, os_end, 0, 1, idaapi.saRelPara, idaapi.scPub, idc.ADDSEG_NOSREG) idc.set_segm_name(0x0, 'DOSRAM') idc.set_name(os_end, 'endos') idc.set_name(header.os_beg + 16, 'os_exec') idc.set_cmt(header.os_beg + 16, '-> default shell', 0) idc.set_name(header.os_beg + 20, 'os_magic') idc.set_cmt(header.os_beg + 20, '-> GEM magic (or NULL)', 0) idc.set_name(header.os_beg + 24, 'os_date') idc.create_dword(header.os_beg + 24) idc.set_cmt(header.os_beg + 24, 'date the system was built', 0) idc.set_name(header.os_beg + 28, 'os_conf') idc.create_word(header.os_beg + 28) idc.set_cmt(header.os_beg + 28, 'configuration bits', 0) idc.set_name(header.os_beg + 30, 'os_dosdate') idc.create_word(header.os_beg + 30) idc.set_cmt(header.os_beg + 30, 'DOS-format date the system was built', 0) addr = header.os_beg + 32 while addr < reseth: if addr == header.os_beg + 0x20: idc.set_cmt(addr, 'base of GEMDOS pool', 0) idc.set_name(ida_bytes.get_dword(addr), '_root') elif addr == header.os_beg + 0x24: idc.set_cmt(addr, '-> keyboard shift-state byte', 0) idc.set_name(ida_bytes.get_dword(addr), 'kbshift') elif addr == header.os_beg + 0x28: idc.set_cmt(addr, '-> current process', 0) idc.set_name(ida_bytes.get_dword(addr), '_run') elif addr == header.os_beg + 0x2c: idc.set_cmt(addr, 'reserved for future use', 0) idc.create_dword(addr) addr += 4 the_magic = ida_bytes.get_dword(header.os_beg + 20) gem_end = ida_bytes.get_dword(the_magic + 4) aes_init = ida_bytes.get_dword(the_magic + 8) idc.add_segm_ex(os_end, gem_end + 1, 0, 1, idaapi.saRelPara, idaapi.scPub, idc.ADDSEG_NOSREG) idc.set_segm_name(os_end, 'GEMRAM') idc.set_name(the_magic, 'the_magic') idc.create_dword(the_magic) idc.set_cmt(the_magic, '$87654321 if GEM present', 0) idc.create_dword(the_magic + 4) idc.set_cmt(the_magic + 4, 'End address of OS RAM usage', 0) idc.create_dword(the_magic + 8) idc.set_cmt(the_magic + 8, 'Execution address of GEM', 0) idaapi.add_entry(aes_init, aes_init, "gem_entry", 1) idc.set_name(gem_end, 'gem_end') idaapi.auto_wait() return 1 elif format == AtariSTProgramName: idaapi.set_processor_type('68K', ida_idp.SETPROC_LOADER) li.seek(0) header = read_struct(li, gemdos_executable_header) base_addr = AtariSTBaseAddress text_addr = base_addr data_addr = text_addr + header.PRG_tsize bss_addr = data_addr + header.PRG_dsize idc.add_segm_ex(text_addr, text_addr + header.PRG_tsize, 0, 1, idaapi.saRelPara, idaapi.scPub, idc.ADDSEG_NOSREG) idc.set_segm_name(text_addr, 'tseg') idc.add_segm_ex(data_addr, data_addr + header.PRG_dsize, 0, 1, idaapi.saRelPara, idaapi.scPub, idc.ADDSEG_NOSREG) idc.set_segm_name(data_addr, 'dseg') idc.add_segm_ex(bss_addr, bss_addr + header.PRG_bsize, 0, 1, idaapi.saRelPara, idaapi.scPub, idc.ADDSEG_SPARSE) idc.set_segm_name(bss_addr, 'bseg') li.file2base(ctypes.sizeof(gemdos_executable_header), text_addr, text_addr + header.PRG_tsize + header.PRG_dsize, 0) # relocate the application li.seek(0, idaapi.SEEK_END) filesize = li.tell() li.seek(0, idaapi.SEEK_SET) relocDataOffset = ctypes.sizeof( gemdos_executable_header ) + header.PRG_tsize + header.PRG_dsize + header.PRG_ssize li.seek(relocDataOffset) relocData = li.read(filesize - relocDataOffset) roffset = 4 rea = struct.unpack('>I', relocData[:roffset])[0] if rea != 0: rea = rea + base_addr idc.patch_dword(rea, ida_bytes.get_dword(rea) + base_addr) if rea >= data_addr: # in the DATA segment, make sure it is an actual pointer idc.create_dword(rea) while True: offset = ord(relocData[roffset]) roffset += 1 if offset == 0: # end of the relocation table break if offset == 1: # odd numbers are not valid, 1 is a special case to skip 254 bytes without relocating rea += 254 continue rea += offset idc.patch_dword(rea, ida_bytes.get_dword(rea) + base_addr) if rea >= data_addr: # in the DATA segment, make sure it is an actual pointer idc.create_dword(rea) # apply a symbol table, if part of the file if header.PRG_ssize: symboltableDataOffset = ctypes.sizeof( gemdos_executable_header) + header.PRG_tsize + header.PRG_dsize li.seek(symboltableDataOffset) symboltableData = li.read(header.PRG_ssize) soffset = 0 while soffset < header.PRG_ssize: entry = symboltableData[soffset:soffset + 14] soffset += 14 name = entry[:8] flags, value = struct.unpack('>HL', entry[8:]) if ( flags & 0x0048 ) and soffset + 14 < header.PRG_ssize: # GST extended DRI symbol format? entry = symboltableData[soffset:soffset + 14] soffset += 14 name += entry[:8] if ( flags & 0xf000 ) == 0xa000: # global defined symbol? (registers, etc are not supported) value += text_addr # relocate the value if (flags & 0xf00) == 0x0100: # BSS idc.set_name(value, name) elif (flags & 0xf00) == 0x0200: # TEXT idaapi.add_entry(value, value, name, 1) elif (flags & 0xf00) == 0x0400: # DATA idc.set_name(value, name) idaapi.add_entry(text_addr, text_addr, "start", 1) idaapi.plan_and_wait(text_addr, text_addr + header.PRG_tsize) idaapi.auto_wait() return 1 return 0
def load_file(li, neflags, format): # ensure we are not wrongly called if not format.startswith("Accessory Firmware Update"): return 0 li.seek(0) data = li.read(0x14) (magic, xxx1, fw_type, fw_ver, fw_len, unk1, product_id, hw_rev_id) = struct.unpack("<HHHHIIHH", data) li.seek(0x20) AFU_signature_header_data = li.read(24) (sig_magic, unknown1, unknown2, digest_type, digest_len, digest_offset, sig_type, sig_len, sig_offset) = struct.unpack("<IHHHHIHHI", AFU_signature_header_data) idaapi.set_processor_type("ARM:ARMv7-M", ida_idp.SETPROC_ALL) if product_id == 0x312: # Apple Pencil fw_base = 0x8006080 msp_base = fw_base elif product_id == 0x14c: # Apple Pencil 2 if fw_type == 1: fw_base = 0x08000980 msp_base = fw_base + 0x180 if fw_type == 0x20: fw_base = 0x0 msp_base = fw_base if fw_type == 0x30: fw_base = 0x0 msp_base = fw_base if fw_type == 0x50: fw_base = 0x08000000 msp_base = fw_base elif product_id == 0x26d: # Siri Remote 2 if fw_type == 1: fw_base = 0x8008080 msp_base = fw_base + 0x180 if fw_type == 0xb0: fw_base = 0x280 msp_base = fw_base + 0x180 elif product_id == 0x268: # Smart Keyboard 12.9" fw_base = 0x08002600 msp_base = fw_base elif product_id == 0x26A: # Smart Keyboard 9.7" fw_base = 0x08002600 msp_base = fw_base elif product_id == 0x26B: # Smart Keyboard 10.5" fw_base = 0x08002600 # don't really know, haven't seen an OTA so far msp_base = fw_base elif product_id == 0x292: # Smart Keyboard Folio 11" fw_base = 0x08000980 # seems to work msp_base = fw_base + 0x180 elif product_id == 0x293: # Smart Keyboard Folio 12.9" fw_base = 0x08000980 # seems to work msp_base = fw_base + 0x180 else: return 0 # for now a heuristic show_header = True if fw_type != 1 or fw_base == 0: show_header = False if show_header: li.file2base(0, fw_base - 0x80, fw_base, 1) li.file2base(0x80, fw_base, fw_base + fw_len, 1) if show_header: idaapi.add_segm(0, fw_base - 0x80, fw_base, "HEADER", "DATA") idaapi.add_segm(0, fw_base, fw_base + fw_len, "__TEXT", "CODE") idaapi.add_segm(0, 0xE000E000, 0xE000F000, "__SYSREG", "DATA") idaapi.add_segm(0, SRAM_BASE, SRAM_BASE + SRAM_SIZE, "__SRAM", "DATA") if show_header: idc.split_sreg_range(fw_base - 0x80, "T", 1) idc.split_sreg_range(fw_base, "T", 1) # register the structures register_structs() # apply the structure if show_header: idc.set_name(fw_base - 0x80, "AFU_HEADER") idc.create_struct(fw_base - 0x80, -1, "afu_full_header") ida_nalt.unhide_item(fw_base - 0x80 + 1) # handle the digest and signature if sig_magic == 0x61E34724: # apply the structure if show_header: idc.set_name(fw_base - 0x80 + 0x20, "AFU_SIG_HEADER") #idc.create_struct(fw_base - 0x80 + 0x20, -1, "afu_sig_header") #ida_nalt.unhide_item(fw_base - 0x80 + 0x20 + 1) # first handle the digest base = fw_base + fw_len li.file2base(digest_offset, base, base + digest_len, 1) idaapi.add_segm(0, base, base + digest_len, "__DIGEST", "DATA") idc.create_byte(base) idc.make_array(base, digest_len) idc.set_name(base, "AFU_DIGEST") # now handle the signature base += digest_len li.file2base(sig_offset, base, base + sig_len, 1) idaapi.add_segm(0, base, base + sig_len, "__SIGNATURE", "DATA") idc.create_byte(base) idc.make_array(base, sig_len) idc.set_name(base, "AFU_SIGNATURE") # check if __TEXT starts with an SRAM address # this is the initial MSP that is followed by exception vectors initMSP = idc.Dword(msp_base) print "initMSP 0x%x" % initMSP if (initMSP >= SRAM_BASE) and initMSP <= (SRAM_BASE + SRAM_SIZE): idc.set_name(msp_base, "init_MSP") idc.create_dword(msp_base) idc.op_plain_offset(msp_base, -1, 0) idc.set_cmt(msp_base, "Initial MSP value", 0) # these are now the exception vectors # determine how many exception vectors there are cnt = 0 handlers = {} last_multi = None multi = False while cnt < 255: ptr = idc.Dword(msp_base + 4 + 4 * cnt) if ptr != 0: # must be inside __TEXT if (ptr < fw_base) or (ptr > fw_base + fw_len): break if (ptr & 1) == 0: # must be thumb mode break # convert into a dword + offset idc.create_dword(msp_base + 4 + 4 * cnt) if ptr != 0: idc.op_offset(msp_base + 4 + 4 * cnt, 0, idc.REF_OFF32, -1, 0, 0) idc.set_cmt( msp_base + 4 + 4 * cnt, "exception %d: %s" % (cnt + 1, exception_table[cnt + 1]), 0) # should only RESET vector be our entrypoint? idc.add_entry(ptr & ~1, ptr & ~1, "", 1) # remember how often we see each handler if ptr != 0: if handlers.has_key(ptr): handlers[ptr] += 1 if last_multi != None: if last_multi != ptr: multi = True last_multi = ptr else: handlers[ptr] = 1 cnt += 1 print "cnt: %d" % cnt if cnt > 0: i = 1 while i <= cnt: ptr = idc.Dword(msp_base + 4 * i) if ptr != 0: # ensure this is if handlers[ptr] == 1: idc.set_name( ptr & ~1, "%s_%s" % (EXCEPTION_PREFIX, exception_table[i])) elif not multi: idc.set_name(ptr & ~1, "%s_%s" % (EXCEPTION_PREFIX, "UNIMPL")) i += 1 return 1