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 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 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 cmd_make_array(self, a, count): return str(idc.make_array(int(a, 0), int(count, 0)))
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): # 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
def load(infos): for info in infos: idc.make_array(info['start'], info['length'])
def make_arr(self, addr, arr_size, struc_size, type): res = idc.make_array(addr, arr_size) if res == False: ida_bytes.del_items(addr, arr_size * struc_size, ida_bytes.DELIT_SIMPLE) idc.SetType(addr, type) idc.make_array(addr, arr_size)
def arrTillName(ea): if not Data.Data(ea).isPointer(ea): return False name_ea = unkTillName(ea) idc.make_array(ea, name_ea - ea) return True
def name_array(ea, name, nitems): idaapi.set_name(ea, name) idc.make_array(ea, nitems) idaapi.set_offset(ea, 0, 0)