def create_load_seg(li, start, end, modificationType, name, segmentType="CODE"): # add_segm(0, start, end, name, "") seg = idaapi.segment_t() seg.start_ea = start seg.end_ea = end seg.bitness = 1 # 32-bit idaapi.add_segm_ex(seg, name, "", 0) # AddSeg(start, end, 0, 1, idaapi.saAbs, idaapi.scPub) offset = li.tell() # li.file2base(offset, start, end, 0) data = li.read(end - start) # put_dword if modificationType == 2: byteswapped = bytearray([0]) * len(data) byteswapped[0::2] = data[1::2] byteswapped[1::2] = data[0::2] # idaapi.mem2base(str(byteswapped), start, end) for i in range(0, end - start): idaapi.put_byte(start + i, byteswapped[i]) else: idaapi.mem2base(data, start, end)
def load_file(li, neflags, format): # Select the PC processor module idaapi.set_processor_type("BPF", SETPROC_ALL|SETPROC_FATAL) buf = read_whole_file(li, 8) if not buf: return 0 start = 0x0 seg = idaapi.segment_t() size = len(buf) end = start + size # Create the segment seg.startEA = start seg.endEA = end seg.bitness = 1 # 32-bit idaapi.add_segm_ex(seg, "bpf_c", "CODE", 0) # Copy the bytes idaapi.mem2base(buf, start, end) # add entry point idaapi.add_entry(start, start, "start", 1) # add comment to beginning of disassembly idaapi.describe(start, True, "BPF bytecode disassembly") # Mark for analysis AutoMark(start, AU_CODE) setup_enums() return 1
def load_file(li, neflags, format): if format != "NeoGeo 68k loader": return 0 idaapi.set_processor_type("68000", SETPROC_ALL | SETPROC_FATAL) idaapi.add_segm(0, 0x000000, 0x0FFFFF, "ROM", "CODE") idaapi.add_segm(0, 0x100000, 0x10F2FF, "WRAM", "DATA") idaapi.add_segm(0, 0x10F300, 0x10FFFF, "BIOSRAM", "DATA") idaapi.add_segm(0, 0x200000, 0x2FFFFF, "PORT", "DATA") idaapi.add_segm(0, 0x300000, 0x3FFFFF, "IO", "DATA") idaapi.add_segm(0, 0x400000, 0x401FFF, "PALETTES", "DATA") idaapi.add_segm(0, 0x800000, 0xBFFFFF, "MEMCARD", "DATA") idaapi.add_segm(0, 0xC00000, 0xC1FFFF, "SYSROM", "DATA") idaapi.add_segm(0, 0xD00000, 0xD0FFFF, "BRAM", "DATA") li.seek(0, 2) size = li.tell() li.seek(0) file_data = li.read(size) idaapi.mem2base(file_data, 0, 0x100000) name_long(0x000000, "InitSP") name_long(0x000004, "InitPC") idaapi.do_unknown(0x3C0000, 1) idaapi.doByte(0x3C0000, 1) idaapi.set_name(0x3C0000, "REG_VRAMADDR") #idaapi.set_cmt(0x3C0000, "Pouet.", 1) return 1
def load_file(li, neflags, format): idaapi.set_processor_type("n2t-hack", idaapi.SETPROC_ALL|idaapi.SETPROC_FATAL) li.seek(0) hack_data = li.read(li.size()) hack_instructions = [int(instruction, 2) for instruction in hack_data.splitlines()] hack_instructions_bin = ''.join(struct.pack("!H", instruction) for instruction in hack_instructions) print "Found %d hack instructions" % len(hack_instructions) seg = idaapi.segment_t() seg.startEA= 0 seg.endEA = len(hack_instructions) seg.align = idaapi.saAbs seg.comb = idaapi.scPriv seg.bitness = 0 # 16-bit idaapi.add_segm_ex(seg, "Hack-ROM", "CODE", idaapi.ADDSEG_OR_DIE) # This method seems to change in next versions. #idaapi.mem2base(hack_instructions_bin, 0, -1) idaapi.mem2base(hack_instructions_bin, 0) return 1
def load_file(li, neflags, format): # Select the PC processor module idaapi.set_processor_type("EVM", SETPROC_ALL | SETPROC_FATAL) # TODO: detect and emulate contract creation code li.seek(0) buf = li.read(li.size()) if not buf: return 0 if buf[0:2] == '0x': print "Detected hex" new_buf = buf[2:].strip().rstrip() buf_set = set() for c in new_buf: buf_set.update(c) hex_set = set(list('0123456789abcdef')) if buf_set <= hex_set: # subset print "Replacing original buffer with hex decoded version" buf = new_buf.decode('hex') # Load all shellcode into different segments start = 0x0 seg = idaapi.segment_t() size = len(buf) end = start + size # Create the segment seg.startEA = start seg.endEA = end seg.bitness = 1 # 32-bit idaapi.add_segm_ex(seg, "evm", "CODE", 0) # TODO: make segments for stack, memory, storage # Copy the bytes idaapi.mem2base(buf, start, end) # check for swarm hash and make it data instead of code swarm_hash_address = buf.find('ebzzr0') if swarm_hash_address != -1: print "Swarm hash detected, making it data" for i in range(swarm_hash_address - 1, swarm_hash_address + 42): MakeByte(i) ida_bytes.set_cmt(swarm_hash_address - 1, "swarm hash", True) # add entry point idaapi.add_entry(start, start, "start", 1) # add comment to beginning of disassembly idaapi.describe(start, True, "EVM bytecode disassembly") # Mark for analysis AutoMark(start, AU_CODE) #setup_enums() return 1
def create_segments(self, li): li.seek(0x800) code = li.read(self.rom_size) idaapi.add_segm(0, 0x80000000, self.rom_addr, 'RAM', 'DATA') idc.set_default_sreg_value(0x80000000, 'ds', 0) seg = idaapi.getseg(0x80000000) seg.perm = idaapi.SEGPERM_EXEC | idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE idaapi.mem2base(code, self.rom_addr, 0x800) idaapi.add_segm(0, self.rom_addr, self.rom_addr + self.rom_size, 'CODE', 'CODE') idc.set_default_sreg_value(self.rom_addr, 'ds', 0) seg = idaapi.getseg(self.rom_addr) seg.perm = idaapi.SEGPERM_EXEC | idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE if self.data_addr != 0: idaapi.add_segm(0, self.data_addr, self.data_addr + self.data_size, '.data', 'DATA') idc.set_default_sreg_value(self.data_addr, 'ds', 0) seg = idaapi.getseg(self.data_addr) seg.perm = idaapi.SEGPERM_EXEC | idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE if self.bss_addr != 0: idaapi.add_segm(0, self.bss_addr, self.bss_addr + self.bss_size, '.bss', 'BSS') idc.set_default_sreg_value(self.bss_addr, 'ds', 0) seg = idaapi.getseg(self.bss_addr) seg.perm = idaapi.SEGPERM_EXEC | idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE idaapi.add_segm(0, self.rom_addr + self.rom_size, 0x80200000, 'RAM', 'DATA') idc.set_default_sreg_value(self.rom_addr + self.rom_size, 'ds', 0) seg = idaapi.getseg(self.rom_addr + self.rom_size) seg.perm = idaapi.SEGPERM_EXEC | idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE idaapi.add_segm(0, 0x1F800000, 0x1F800400, 'CACHE', 'DATA') idaapi.add_segm(0, 0x1F800400, 0x1F801000, 'UNK1', 'XTRN') self.add_mem_ctrl1() self.add_mem_ctrl2() self.add_periph_io() self.add_int_ctrl() self.add_dma() self.add_timers() self.add_cdrom_regs() self.add_gpu_regs() self.add_mdec_regs() self.add_spu_voices() self.add_spu_ctrl_regs() self.create_got_fix() idaapi.cvar.inf.start_ss = idaapi.cvar.inf.start_cs = 0 idaapi.cvar.inf.start_ip = idaapi.cvar.inf.start_ea = self.init_pc idaapi.cvar.inf.start_sp = self.sp_base + self.sp_offset
def _AddSegment(self, name, base_address, data=None): """Add a segment to the IDB with some basic options set for convenience.""" s = idaapi.segment_t() s.startEA = base_address s.endEA = base_address + len(data) s.bitness = 1 # 32-bit s.align = idaapi.saRelByte s.comb = idaapi.scPub s.sel = idaapi.setup_selector(0) # We mark the segments as code, as we know these are loops in memory idaapi.add_segm_ex(s, name, "CODE", idaapi.ADDSEG_NOSREG | idaapi.ADDSEG_OR_DIE) idaapi.mem2base(data, base_address)
def map(ea, size, newea, **kwds): """Map `size` bytes of data from `ea` into a new segment at `newea`. The keyword `name` can be used to name the segment. """ # grab the file offset and the data we want fpos, data = idaapi.get_fileregion_offset(ea), database.read(ea, size) if len(data) != size: raise E.ReadOrWriteError( u"{:s}.map({:#x}, {:+#x}, {:#x}{:s}) : Unable to read {:#x} bytes from {:#x}." .format( __name__, ea, size, newea, u", {:s}".format(utils.string.kwargs(kwds)) if kwds else '', size, ea)) # rebase the data to the new address res = idaapi.mem2base(data, newea, fpos) if not res: raise E.DisassemblerError( u"{:s}.map({:#x}, {:+#x}, {:#x}{:s}) : Unable to remap {:#x}:{:+#x} to {:#x}." .format( __name__, ea, size, newea, u", {:s}".format(utils.string.kwargs(kwds)) if kwds else '', ea, size, newea)) # now we can create the new segment return new(newea, size, kwds.get("name", "map_{:x}".format(ea)))
def AddSegment(name, base_address, data): """Add a segment to the IDB with some basic options set for convenience.""" s = idaapi.segment_t() s.startEA = base_address s.endEA = base_address + len(data) s.bitness = 1 # 32-bit s.align = idaapi.saRelByte s.comb = idaapi.scPub s.sel = idaapi.setup_selector(0) idaapi.add_segm_ex(s, name, None, idaapi.ADDSEG_NOSREG | idaapi.ADDSEG_OR_DIE) idaapi.mem2base(data, base_address)
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 """ # Select the PC processor module idaapi.set_processor_type("metapc", ida_idp.SETPROC_LOADER) # read MBR into buffer li.seek(0, os.SEEK_SET) buf = li.read(li.size()) seg = idaapi.segment_t() start = 0x7C00 size = len(buf) end = start + size # Create the segment seg.start_ea = start seg.end_ea = end seg.bitness = 0 # 16-bit idaapi.add_segm_ex(seg, "seg0", "CODE", 0) # Copy the bytes idaapi.mem2base(buf, start, end) # add entry point idaapi.add_entry(start, start, "start", 1) strid = add_struct_def() idaapi.set_name(start + 0x1BE, "MBR_PARTITION_TABLE", idaapi.SN_CHECK) str_size = idaapi.get_struc_size(strid) idaapi.create_struct(start + 0x1BE, str_size, strid) idaapi.set_name(510, "MBR_SIGN", idaapi.SN_CHECK) # Mark for analysis AutoMark(start, AU_CODE) load_debugger("bochs", 0) return 1
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 """ # Select the PC processor module idaapi.set_processor_type("metapc", SETPROC_ALL|SETPROC_FATAL) buf = read_whole_file(li) r = extract_pdf_shellcode(buf) if not r: return 0 # Load all shellcode into different segments start = 0x10000 seg = idaapi.segment_t() for id, ver, n, sc in r: size = len(sc) end = start + size # Create the segment seg.startEA = start seg.endEA = end seg.bitness = 1 # 32-bit idaapi.add_segm_ex(seg, "obj_%d_%d_%d" % (id, ver, n), "CODE", 0) # Copy the bytes idaapi.mem2base(sc, start, end) # Mark for analysis AutoMark(start, AU_CODE) # Compute next loading address start = ((end / 0x1000) + 1) * 0x1000 # Select the bochs debugger LoadDebugger("bochs", 0) return 1
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 """ # Select the PC processor module idaapi.set_processor_type("metapc", SETPROC_LOADER) buf = read_whole_file(li) r = extract_pdf_shellcode(buf) if not r: return 0 # Load all shellcode into different segments start = 0x10000 seg = idaapi.segment_t() for id, ver, n, sc in r: size = len(sc) end = start + size # Create the segment seg.start_ea = start seg.end_ea = end seg.bitness = 1 # 32-bit idaapi.add_segm_ex(seg, "obj_%d_%d_%d" % (id, ver, n), "CODE", 0) # Copy the bytes idaapi.mem2base(sc, start, end) # Mark for analysis AutoMark(start, AU_CODE) # Compute next loading address start = ((end / 0x1000) + 1) * 0x1000 # Select the bochs debugger load_debugger("bochs", 0) return 1
def load_file(li, neflags, format): """Load the file into database Args: li: a file-like object which can be used to access the input data neflags: options selected by the user, see loader.hpp Returns: 0-failure 1-ok """ idaapi.set_processor_type("sh4", SETPROC_ALL | SETPROC_FATAL) li.seek(0, idaapi.SEEK_END) size = li.tell() li.seek(0) rom_data = li.read(size) s = idaapi.segment_t() s.startEA = 0 s.endEA = size s.bitness = 1 # 32-bit s.align = idaapi.saRelByte s.comb = idaapi.scPub s.sel = idaapi.setup_selector(0) idaapi.add_segm_ex(s, "ROM", "DATA", idaapi.ADDSEG_NOSREG | idaapi.ADDSEG_OR_DIE) idaapi.mem2base(rom_data, 0) headr = JasperThe2kCat() headr.AnotateHeader(binary_file=li) headr.MakeStrings(binary_file=li) gentries = gameEntries() gentries.readGameLoops(binary_file=li) gentries.CreateSegments(binary_file=li) gentries.makeDWordTables() gentries.makeDWordTables(start_address=0x2a0, end_address=0x1000) gentries.addIDA_entry() print("load ok") return 1
def map(ea, size, newea, **kwds): """Map ``size`` bytes of data from ``ea`` into a new segment at ``newea``. ``name`` can be used to name the segment. """ fpos,data = idaapi.get_fileregion_offset(ea),database.read(ea, size) if len(data) != size: raise ValueError("{:s}.map({:x}, {:#x}, {:x}) : Unable to read {:#x} bytes from {:#x}".format(__name__, ea, size, newea, size, ea)) res = idaapi.mem2base(data, newea, fpos) if not res: raise ValueError("{:s}.map({:x}, {:#x}, {:x}) : Unable to remap {:#x}:{:+#x} to {:#x}".format(__name__, ea, size, newea, ea, size, newea)) return create(newea, size, kwds.get("name', 'map_{:x}".format(ea)))
def map(ea, size, newea, **kwds): '''Map /size/ bytes of data from /ea/ into a new segment at /newea/ /name/ can be used to name the segment. ''' fpos, data = idaapi.get_fileregion_offset(ea), database.read(ea, size) if len(data) != size: raise Exception, "Unable to read %x bytes from %x" % (size, ea) res = idaapi.mem2base(data, newea, fpos) if not res: raise Exception, "Unable to remap %x:+%x to %x" % (ea, size, newea) return create(newea, size, kwds.get('name', 'map_%x' % ea))
def map(ea, size, newea, **kwds): '''Map /size/ bytes of data from /ea/ into a new segment at /newea/ /name/ can be used to name the segment. ''' fpos,data = idaapi.get_fileregion_offset(ea),database.read(ea, size) if len(data) != size: raise Exception, "Unable to read %x bytes from %x"% (size, ea) res = idaapi.mem2base(data, newea, fpos) if not res: raise Exception, "Unable to remap %x:+%x to %x"% (ea, size, newea) return create(newea, size, kwds.get('name', 'map_%x'% ea))
def map(ea, size, newea, **kwds): """Map `size` bytes of data from `ea` into a new segment at `newea`. The keyword `name` can be used to name the segment. """ fpos, data = idaapi.get_fileregion_offset(ea), database.read(ea, size) if len(data) != size: raise E.ReadOrWriteError( "{:s}.map({:#x}, {:+#x}, {:#x}) : Unable to read {:#x} bytes from {:#x}." .format(__name__, ea, size, newea, size, ea)) res = idaapi.mem2base(data, newea, fpos) if not res: raise E.DisassemblerError( "{:s}.map({:#x}, {:+#x}, {:#x}) : Unable to remap {:#x}:{:+#x} to {:#x}." .format(__name__, ea, size, newea, ea, size, newea)) return new(newea, size, kwds.get("name', 'map_{:x}".format(ea)))
def map(ea, size, newea, **kwds): """Map `size` bytes of data from `ea` into a new segment at `newea`. The keyword `name` can be used to name the segment. """ # grab the file offset and the data we want fpos, data = idaapi.get_fileregion_offset(ea), database.read(ea, size) if len(data) != size: raise E.ReadOrWriteError(u"{:s}.map({:#x}, {:+#x}, {:#x}{:s}) : Unable to read {:#x} bytes from {:#x}.".format(__name__, ea, size, newea, u", {:s}".format(utils.string.kwargs(kwds)) if kwds else '', size, ea)) # rebase the data to the new address res = idaapi.mem2base(data, newea, fpos) if not res: raise E.DisassemblerError(u"{:s}.map({:#x}, {:+#x}, {:#x}{:s}) : Unable to remap {:#x}:{:+#x} to {:#x}.".format(__name__, ea, size, newea, u", {:s}".format(utils.string.kwargs(kwds)) if kwds else '', ea, size, newea)) # now we can create the new segment return new(newea, size, kwds.get("name", "map_{:x}".format(ea)))
def load_one_file(li, options, idx, basename=None): bypass_plt = OPT_BYPASS_PLT in options f = load_nxo(li) if idx == 0: if f.armv7: idc.SetShortPrm(idc.INF_LFLAGS, idc.GetShortPrm(idc.INF_LFLAGS) | idc.LFLG_PC_FLAT) else: idc.SetShortPrm(idc.INF_LFLAGS, idc.GetShortPrm(idc.INF_LFLAGS) | idc.LFLG_64BIT) idc.SetCharPrm(idc.INF_DEMNAMES, idaapi.DEMNAM_GCC3) idaapi.set_compiler_id(idaapi.COMP_GNU) idaapi.add_til2('gnulnx_arm' if f.armv7 else 'gnulnx_arm64', 1) # don't create tails idc.set_inf_attr(idc.INF_AF, idc.get_inf_attr(idc.INF_AF) & ~idc.AF_FTAIL) if OPT_LOAD_31_BIT in options: loadbase = 0x8000000 step = 0x1000000 elif f.armv7: loadbase = 0x60000000 step = 0x10000000 else: loadbase = 0x7100000000 step = 0x100000000 loadbase += idx * step f.binfile.seek(0) as_string = f.binfile.read(f.bssoff) idaapi.mem2base(as_string, loadbase) seg_prefix = basename if basename is not None else '' for start, end, name, kind in f.sections: if name.startswith('.got'): kind = 'CONST' idaapi.add_segm(0, loadbase+start, loadbase+end, seg_prefix+name, kind) segm = idaapi.get_segm_by_name(seg_prefix+name) if kind == 'CONST': segm.perm = idaapi.SEGPERM_READ elif kind == 'CODE': segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_EXEC elif kind == 'DATA': segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE elif kind == 'BSS': segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE idaapi.update_segm(segm) idaapi.set_segm_addressing(segm, 1 if f.armv7 else 2) # do imports # TODO: can we make imports show up in "Imports" window? undef_count = 0 for s in f.symbols: if not s.shndx and s.name: undef_count += 1 last_ea = max(loadbase + end for start, end, name, kind in f.sections) undef_entry_size = 8 undef_ea = ((last_ea + 0xFFF) & ~0xFFF) + undef_entry_size # plus 8 so we don't end up on the "end" symbol undef_seg = basename + '.UNDEF' if basename is not None else 'UNDEF' idaapi.add_segm(0, undef_ea, undef_ea+undef_count*undef_entry_size, undef_seg, 'XTRN') segm = idaapi.get_segm_by_name(undef_seg) segm.type = idaapi.SEG_XTRN idaapi.update_segm(segm) for i,s in enumerate(f.symbols): if not s.shndx and s.name: idc.MakeQword(undef_ea) idaapi.do_name_anyway(undef_ea, s.name) s.resolved = undef_ea undef_ea += undef_entry_size elif i != 0: assert s.shndx s.resolved = loadbase + s.value if s.name: if s.type == STT_FUNC: idaapi.add_entry(s.resolved, s.resolved, s.name, 0) else: idaapi.do_name_anyway(s.resolved, s.name) else: # NULL symbol s.resolved = 0 funcs = set() for s in f.symbols: if s.name and s.shndx and s.value: if s.type == STT_FUNC: funcs.add(loadbase+s.value) symend = loadbase+s.value+s.size if Dword(symend) != 0: funcs.add(symend) got_name_lookup = {} for offset, r_type, sym, addend in f.relocations: target = offset + loadbase if r_type in (R_ARM_GLOB_DAT, R_ARM_JUMP_SLOT, R_ARM_ABS32): if not sym: print 'error: relocation at %X failed' % target else: idaapi.put_long(target, sym.resolved) elif r_type == R_ARM_RELATIVE: idaapi.put_long(target, idaapi.get_long(target) + loadbase) elif r_type in (R_AARCH64_GLOB_DAT, R_AARCH64_JUMP_SLOT, R_AARCH64_ABS64): idaapi.put_qword(target, sym.resolved + addend) if addend == 0: got_name_lookup[offset] = sym.name elif r_type == R_AARCH64_RELATIVE: idaapi.put_qword(target, loadbase + addend) if addend < f.textsize: funcs.add(loadbase + addend) else: print 'TODO r_type %d' % (r_type,) ida_make_offset(f, target) for func, target in f.plt_entries: if target in got_name_lookup: addr = loadbase + func funcs.add(addr) idaapi.do_name_anyway(addr, got_name_lookup[target]) if not f.armv7: funcs |= find_bl_targets(loadbase, loadbase+f.textsize) if bypass_plt: plt_lookup = f.plt_lookup for pco in xrange(0, f.textsize, 4): pc = loadbase + pco d = Dword(pc) if (d & 0x7c000000) == (0x94000000 & 0x7c000000): imm = d & 0x3ffffff if imm & 0x2000000: imm |= ~0x1ffffff if 0 <= imm <= 2: continue target = (pc + imm * 4) - loadbase if target in plt_lookup: new_target = plt_lookup[target] + loadbase new_instr = (d & ~0x3ffffff) | (((new_target - pc) / 4) & 0x3ffffff) idaapi.put_long(pc, new_instr) for pco in xrange(0, f.textsize, 4): pc = loadbase + pco d = Dword(pc) if d == 0x14000001: funcs.add(pc + 4) for pc, _ in f.eh_table: funcs.add(loadbase + pc) for addr in sorted(funcs, reverse=True): idaapi.auto_make_proc(addr) return 1
def load_file(li, neflags, fmt): 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) # Get the meta offset meta_ofs = find_kernel_meta(li) assert meta_ofs != -1 # Read important offsets. li.seek(meta_ofs + 0x40) text_base, init_base, init_base2, kernel_end = struct.unpack( '<QQQQ', li.read(0x20)) # Load the init segment. li.seek(0) init_data = li.read(KERNEL_INIT_SIZE) idaapi.mem2base(init_data, init_base) # Emulate the kernel init segment to determine interesting extents emu = Emulator() emu.run_emulator(init_base, init_data) builder = SegmentBuilder() builder.add_segment(init_base, KERNEL_INIT_SIZE, '.init', 'RWX') text_phys = 0 text_size = 0 ro_size = 0 rw_size = 0 core_dram_mappings = [] for (virt_addr, size, phys_addr, attr) in emu.mappings: print('%x, %x, %x, %x' % (virt_addr, size, phys_addr, attr)) assert attr in [ 0x4000000000078B, 0x78B, 0x6000000000078B, 0x6000000000070B, 0x60000000000607, 0x60000000000709 ] if attr == 0x78B or attr == 0x4000000000078B: # .text assert virt_addr == text_base builder.add_segment(virt_addr, size, '.text', 'CODE') li.seek(phys_addr - init_base) idaapi.mem2base(li.read(size), virt_addr) text_phys = phys_addr text_size = size elif attr == 0x6000000000078B: # .rodata assert text_size != 0 assert virt_addr == text_base + text_size builder.add_segment(virt_addr, size, '.rodata', 'CONST') li.seek(phys_addr - init_base) idaapi.mem2base(li.read(size), virt_addr) ro_size = size elif attr == 0x6000000000070B and virt_addr == text_base + text_size + ro_size: assert text_size != 0 assert ro_size != 0 # .rwdata builder.add_segment(virt_addr, size, '.rwdata', 'DATA') li.seek(phys_addr - init_base) idaapi.mem2base(li.read(size), virt_addr) rw_size = size elif attr == 0x60000000000607: # IO DEVICES = { (0x40000000, 0x40000): '.iram', (0x50041000, 0x01000): '.gicd', (0x50042000, 0x01000): '.gicc', (0x60001000, 0x01000): '.semaphore', (0x60004000, 0x01000): '.primary_ictlr', (0x60006000, 0x01000): '.clkrst', (0x60007000, 0x01000): '.flow_ctlr', (0x6000F000, 0x01000): '.evp', (0x70006000, 0x01000): '.uart', (0x7000E000, 0x01000): '.rtc_pmc', (0x70016000, 0x02000): '.atomics', (0x70019000, 0x01000): '.mc', (0x7001C000, 0x01000): '.mc0', (0x7001D000, 0x01000): '.mc1', } assert (phys_addr, size) in DEVICES.keys() name = DEVICES[(phys_addr, size)] builder.add_segment(virt_addr, size, name, 'IO') elif attr == 0x6000000000070B: # Kernel DRAM if phys_addr == (emu.ttbr & ~0xFFF) and size == 0x1000: builder.add_segment(virt_addr, size, '.ttbr1', 'DATA') else: core_dram_mappings.append( (virt_addr, size, phys_addr, attr)) else: # Linear DRAM assert attr == 0x60000000000709 idaapi.add_segm(0, virt_addr, virt_addr + size, '.linear_dram', 'DATA', idaapi.ADDSEG_SPARSE) segm = idaapi.get_segm_by_name('.linear_dram') segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE idaapi.update_segm(segm) idaapi.set_segm_addressing(segm, 2) assert len(core_dram_mappings) % 5 == 0 if len(core_dram_mappings) // 5 == 3: # 1.0.0-style core local mappings assert core_dram_mappings[ 0 + 0][2] == core_dram_mappings[0 + 3][2] - 0x2000 assert core_dram_mappings[ 0 + 3][2] == core_dram_mappings[0 + 6][2] - 0x2000 assert core_dram_mappings[ 0 + 6][2] == core_dram_mappings[0 + 9][2] - 0x2000 assert core_dram_mappings[0 + 0][2] == core_dram_mappings[0 + 12][2] assert core_dram_mappings[ 1 + 0][2] == core_dram_mappings[1 + 3][2] - 0x2000 assert core_dram_mappings[ 1 + 3][2] == core_dram_mappings[1 + 6][2] - 0x2000 assert core_dram_mappings[ 1 + 6][2] == core_dram_mappings[1 + 9][2] - 0x2000 assert core_dram_mappings[1 + 0][2] == core_dram_mappings[1 + 12][2] assert core_dram_mappings[ 2 + 0][2] == core_dram_mappings[2 + 3][2] - 0x1000 assert core_dram_mappings[ 2 + 3][2] == core_dram_mappings[2 + 6][2] - 0x1000 assert core_dram_mappings[ 2 + 6][2] == core_dram_mappings[2 + 9][2] - 0x1000 assert core_dram_mappings[2 + 0][2] == core_dram_mappings[2 + 12][2] builder.add_segment(core_dram_mappings[0][0], 0xA000 * 4, '.core_local_regions', 'DATA') builder.add_segment(core_dram_mappings[3 * 4 + 0][0], core_dram_mappings[3 * 4 + 0][1], '.current_common_stack', 'DATA') builder.add_segment(core_dram_mappings[3 * 4 + 1][0], core_dram_mappings[3 * 4 + 1][1], '.current_main_stack', 'DATA') builder.add_segment(core_dram_mappings[3 * 4 + 2][0], core_dram_mappings[3 * 4 + 2][1], '.current_context', 'DATA') elif len(core_dram_mappings) // 5 == 4: # 3.0.0-style core local mappings assert core_dram_mappings[ 0 + 0][2] == core_dram_mappings[0 + 4][2] - 0x2000 assert core_dram_mappings[ 0 + 4][2] == core_dram_mappings[0 + 8][2] - 0x2000 assert core_dram_mappings[ 0 + 8][2] == core_dram_mappings[0 + 12][2] - 0x2000 assert core_dram_mappings[0 + 0][2] == core_dram_mappings[0 + 16][2] assert core_dram_mappings[ 1 + 0][2] == core_dram_mappings[1 + 4][2] - 0x2000 assert core_dram_mappings[ 1 + 4][2] == core_dram_mappings[1 + 8][2] - 0x2000 assert core_dram_mappings[ 1 + 8][2] == core_dram_mappings[1 + 12][2] - 0x2000 assert core_dram_mappings[1 + 0][2] == core_dram_mappings[1 + 16][2] assert core_dram_mappings[ 2 + 0][2] == core_dram_mappings[2 + 4][2] - 0x2000 assert core_dram_mappings[ 2 + 4][2] == core_dram_mappings[2 + 8][2] - 0x2000 assert core_dram_mappings[ 2 + 8][2] == core_dram_mappings[2 + 12][2] - 0x2000 assert core_dram_mappings[2 + 0][2] == core_dram_mappings[2 + 16][2] assert core_dram_mappings[ 3 + 0][2] == core_dram_mappings[3 + 4][2] - 0x1000 assert core_dram_mappings[ 3 + 4][2] == core_dram_mappings[3 + 8][2] - 0x1000 assert core_dram_mappings[ 3 + 8][2] == core_dram_mappings[3 + 12][2] - 0x1000 assert core_dram_mappings[3 + 0][2] == core_dram_mappings[3 + 16][2] builder.add_segment(core_dram_mappings[0][0], 0xE000 * 4, '.core_local_regions', 'DATA') builder.add_segment(core_dram_mappings[4 * 4 + 0][0], core_dram_mappings[4 * 4 + 0][1], '.current_common_stack', 'DATA') builder.add_segment(core_dram_mappings[4 * 4 + 1][0], core_dram_mappings[4 * 4 + 1][1], '.current_main_stack', 'DATA') builder.add_segment(core_dram_mappings[4 * 4 + 2][0], core_dram_mappings[4 * 4 + 2][1], '.current_idle_stack', 'DATA') builder.add_segment(core_dram_mappings[4 * 4 + 3][0], core_dram_mappings[4 * 4 + 3][1], '.current_context', 'DATA') seg_prefix = '' for start, end, name, kind in builder.flatten(): idaapi.add_segm(0, start, end, seg_prefix + name, kind) segm = idaapi.get_segm_by_name(seg_prefix + name) if kind == 'CONST': segm.perm = idaapi.SEGPERM_READ elif kind == 'CODE': segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_EXEC elif kind == 'DATA': segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE elif kind == 'BSS': segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE elif kind == 'RWX': segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE | idaapi.SEGPERM_EXEC elif kind == 'IO': segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE idaapi.update_segm(segm) idaapi.set_segm_addressing(segm, 2) # 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' % (kind, ctx) idc.create_insn(addr) idc.set_name(addr, name) # Set .init as code. idc.create_insn(init_base) idc.set_name(init_base, 'crt0') # Set text start as code. idc.create_insn(text_base) idc.set_name(text_base, 'HorizonKernelMain') # Patch movk instructions to be better understandable by ida. li.seek(text_phys - init_base) text = li.read(text_size) ro_rw = li.read(ro_size + rw_size) patch_movk_to_adrp(text_base, text, ro_rw, emu.mappings) return 1
def readToSegment(li, src, size, target, name): li.seek(src) data = li.read(size) idaapi.mem2base(data, target) AddSeg(target,target + size,0,1,idaapi.saRelWord, idaapi.scPub) RenameSeg(target, name)
def load_file(li, neflags, format): if format != "NeoGeo 68k loader": return 0 idaapi.set_processor_type("68000", SETPROC_ALL | SETPROC_FATAL) idaapi.add_segm(0, 0x000000, 0x0FFFFF, "ROM", "CODE") idaapi.add_segm(0, 0x100000, 0x10F2FF, "WRAM", "DATA") idaapi.add_segm(0, 0x10F300, 0x10FFFF, "BIOSRAM", "DATA") idaapi.add_segm(0, 0x200000, 0x2FFFFF, "PORT", "DATA") idaapi.add_segm(0, 0x300000, 0x3FFFFF, "IO", "DATA") idaapi.add_segm(0, 0x400000, 0x401FFF, "PALETTES", "DATA") idaapi.add_segm(0, 0x800000, 0xBFFFFF, "MEMCARD", "DATA") idaapi.add_segm(0, 0xC00000, 0xC1FFFF, "SYSROM", "DATA") idaapi.add_segm(0, 0xD00000, 0xD0FFFF, "BRAM", "DATA") map_io_registers() li.seek(0, 2) file_size = li.tell() li.seek(0) # read p1 rom file_data = li.read(0x100000) file_remain = file_size - 0x100000 idaapi.mem2base(file_data, 0, 0x100000) # read p2 rom bank2_seg_offset = 0x01000000 bank2_seg_index = 0 while file_remain > 0: bank2_seg_start = bank2_seg_offset + 0x200000 bank2_seg_end = bank2_seg_start + 0x2FFFFF idaapi.add_segm(0, bank2_seg_start, bank2_seg_end, "BANK2_%d" % bank2_seg_index, "DATA") bytes_to_read = file_remain if bytes_to_read > 0x100000: bytes_to_read = 0x100000 file_data = li.read(bytes_to_read) idaapi.mem2base(file_data, bank2_seg_start, bank2_seg_start + len(file_data)) bank2_seg_offset += 0x01000000 bank2_seg_index += 1 file_remain -= bytes_to_read # http://ajworld.net/neogeodev/beginner/ name_long(0x000000, "InitSP") name_long(0x000004, "InitPC") name_long(0x000008, "BusError") name_long(0x00000C, "AddressError") name_long(0x000010, "IllegalInstruction") name_long(0x000014, "DivByZero") name_long(0x000018, "CHK") name_long(0x00001C, "TRAPV") name_long(0x000020, "PrivilegeViolation") name_long(0x000024, "Trace") name_long(0x000028, "Line1010Emu") name_long(0x00002C, "Line1111Emu") name_array(0x000030, "Reserved0", 0xC) name_long(0x000003C, "UnintializedInterruptVec") name_array(0x000040, "Reserved1", 0x20) name_long(0x000060, "VirtualInterrupt") name_long(0x000064, "Interrupt1") name_long(0x000068, "Interrupt2") name_long(0x00006C, "Interrupt3") name_long(0x000070, "Interrupt4") name_long(0x000074, "Interrupt5") name_long(0x000078, "Interrupt6") name_long(0x00007C, "Interrupt7") name_dword_array(0x000080, "Traps", 0x10) name_array(0x0000C0, "Reserved2", 0x40) # Neo-Geo header # https://wiki.neogeodev.org/index.php?title=68k_program_header idc.create_strlit(0x000100, 0x000107) idaapi.set_name(0x000100, "Magic") name_byte(0x000107, "SysVersion") name_word(0x000108, "GameID") name_long(0x00010A, "ProgramSize") name_long(0x00010E, "BackupRAMPtr") name_word(0x000112, "BackupRAMSize") name_byte(0x000114, "EyecatchFlag") name_byte(0x000115, "EyecatchSpriteBank") name_long(0x000116, "MenuJP") name_long(0x00011A, "MenuUS") name_long(0x00011E, "MenuEU") name_code(0x000122, "Routine_USER", 6) name_code(0x000128, "Routine_PLAYER_START", 6) name_code(0x00012E, "Routine_DEMO_END", 6) name_code(0x000134, "Routine_COIN_SOUND", 6) name_array(0x00013A, "Unknown0", 0x48) name_long(0x000182, "CartridgeRecognitionCodePtr") name_long(0x000186, "Unknown1") name_long(0x00018A, "Unknown2") name_long(0x00018E, "MenuES") # Spanish # BIOS RAM set_name_with_comment(0x10FD80, "BIOS_SYSTEM_MODE", "0x00 : System" "0x80 : Game") set_name_with_comment(0x10FD82, "BIOS_MVS_FLAG", "0 : HOME/AES\n" "1 : MVS") set_name_with_comment( 0x10FDAE, "BIOS_USER_REQUEST", "0 : Startup initialization\n" "1 : Eye-catcher\n" "2 : Demo Game / Game\n" "3 : Title Display") set_name_with_comment( 0x10FDAF, "BIOS_USER_MODE", "Current game status.\n" "0 : init/boot\n" "1 : title/demo\n" "2 : game") set_name_with_comment( 0x10FEC5, "BIOS_TITLE_MODE", "Newer games set this to 1 in their command 3 USER subroutine.\n" "It prevents the system ROM from calling command 3 twice after game over if credits are already in the system.\n" ) #idaapi.del_items(0x3C0000) # VRAM set_name_with_comment( 0x3C0000, "REG_VRAMADDR", "sets the VRAM address for the next read/write operation.") set_name_with_comment(0x3C0002, "REG_VRAMRW", "the data read or to write.") set_name_with_comment( 0x3C0004, "REG_VRAMMOD", "the signed value automatically added to the VRAM address after a write." ) set_name_with_comment( 0x3C000C, "LSPC_IRQ_ACK", "IRQ acknowledgement register.\nbit2 : Ack.VBlank | bit 1 : Ack.HBlank | bit 0 : IRQ3" ) idaapi.set_name(0xC00444, "SYSTEM_RETURN") idaapi.set_name(0xC0044A, "SYSTEM_IO") idaapi.set_name(0xD00100, "BOARD_CORRUPTED") #idaapi.set_cmt(0x3C0000, "Pouet.", 1) return 1
def _AddData(self, name, base_address, data=None): idaapi.mem2base(data, base_address)
def load_file(li, neflags, format): # Check the format we've been asked to load if format != FORMAT_NAME: return 0 # Datatrak 68K - set processor type idaapi.set_processor_type("68000", SETPROC_ALL | SETPROC_FATAL) # Add segments idaapi.add_segm(0, 0x000000, 0x03FFFF, "ROM", "CODE") # TODO validate ROM area idaapi.add_segm(0, 0x200000, 0x21FFFF, "RAM", "DATA") # TODO validate RAM area idaapi.add_segm(0, 0x220000, 0x23FFFF, "RAM2", "DATA") # TODO validate this, it's here just to fill space idaapi.add_segm(0, 0x240000, 0x2400FF, "IO_ADC", "DATA") # A/D converter idaapi.add_segm(0, 0x240100, 0x2401FF, "IO_UNK_01", "DATA") # idaapi.add_segm(0, 0x240200, 0x2402FF, "IO_RFPHA", "DATA") # RF phase detector idaapi.add_segm(0, 0x240300, 0x2403FF, "IO_UART", "DATA") # Dual UART idaapi.add_segm(0, 0x240400, 0x2404FF, "IO_UNK_04", "DATA") # idaapi.add_segm(0, 0x240500, 0x2405FF, "IO_UNK_05", "DATA") # idaapi.add_segm(0, 0x240600, 0x2406FF, "IO_UNK_06", "DATA") # idaapi.add_segm(0, 0x240700, 0x2407FF, "IO_UNK_07", "DATA") # idaapi.add_segm(0, 0x240800, 0x2408FF, "IO_UNK_08", "DATA") # idaapi.add_segm(0, 0x240900, 0x24FFFF, "IO_UNKNOWN", "DATA") # # Seek to EOF and get filesize li.seek(0, 2) size = li.tell() # Seek back to start of file, read the file into memory li.seek(0) file_data = li.read(size) idaapi.mem2base(file_data, 0, size) # data,start,end do_68k_vectors() # Get the initial program counter initPC = struct.unpack('>L', bytearray(file_data[4:8]))[0] # Hunt down the DATA segment initialiser, starting at the reset vector pattern = [ 0x41, 0xF9, 0x00, 0x20, 0x00, 0x00, # LEA (0x200000).L, A0 ; start of dseg in RAM 0x20, 0x3C, 0x00, None, None, None, # MOVE.L #EndOfDataSeg, D0 ; end of dseg in RAM 0x90, 0x88, # SUB.L A0, D0 ; D0 = D0 - A0 0x43, 0xF9, 0x00, None, None, None, # LEA (StartOfData), A1 ; start of dseg initialisation data 0x53, 0x80, # SUBQ.L #1, D0 ; D0 -- 0x10, 0xD9, # MOVE.B (A1)+, (A0)+ ; *a0++ = *a1++ 0x51, 0xC8, 0xFF, 0xFC # DBF D0, $-2 ; decrement d0, branch if >= 0 ] sh_reg = [0x00] * len(pattern) # TODO: Refactor this to use IDA's internal buffer instead of the file_data array? for addr in range(initPC, initPC + 0x100): # shift in next byte sh_reg = sh_reg[1:] sh_reg.append(ord(file_data[addr])) # check if we've found a match match = True for i in range(len(pattern)): if pattern[i] is not None and pattern[i] != sh_reg[i]: match = False break # exit the search loop if we found a match if match: break if match: # If we've exited the loop and have a match, fish the DSEG addresses # out of the instruction parameters. dsegRamStart = struct.unpack(">L", bytearray(sh_reg[2:6]))[0] dsegRamEnd = struct.unpack(">L", bytearray(sh_reg[8:12]))[0] dsegRomStart = struct.unpack(">L", bytearray(sh_reg[16:20]))[0] print("DSEG RAM Start %08X" % dsegRamStart) print("DSEG RAM End %08X" % dsegRamEnd) print("DSEG ROM Start %08X" % dsegRomStart) # Calculate initialised data segment end and end of the idata in ROM dsegLen = dsegRamEnd - dsegRamStart dsegRomEnd = dsegRomStart + dsegLen # Load the idata into RAM from the appropriate part of the ROM file idaapi.mem2base(file_data[dsegRomStart:dsegRomEnd], dsegRamStart, dsegRamEnd) # TODO: Designate the source idata as ROM DATA idaapi.add_segm(0, dsegRomStart, dsegRomEnd, "DATAINIT", "DATA") else: print("No Match") # TODO: Try to identify the boundary between CODE and ROMDATA and move that into a segment # Wait for autoanalysis to finish autoWait() # Convert all MOVEA source parameters into address references doMoveaAddrRefs() # TODO: Search for switch-case jump tables oper_re = re.compile(r'\(pc,([ad][0-9]).([bwl])\)') insnStack = [] for ea in Heads(0x33B0, 0x33D0): # Decode the instruction and operands insn = { 'ea': ea, 'disasm': GetDisasm(ea), 'mnem': GetMnem(ea), } opnds = [] for i in range(3): opnd = { 'type': get_operand_type(ea, i), 'opnd': GetOpnd(ea, i), 'value': GetOperandValue(ea, i) } # store non-empty operands only if opnd['type'] != 0: # FIXME use operand type constants opnds.append(opnd) insn['operands'] = opnds # push the instruction onto the stack, limiting the stack size insnStack.append(insn) insnStack = insnStack[-10:] # Look for this sequence at the end of the stack: # ADD.W d0,d0 # MOVE.W <table>(pc,d0.w) # JMP <table>(pc,d0.w) # if insnStack[-1]['mnem'] == 'jmp' and insnStack[-2]['mnem'].startswith( 'move.') and insnStack[-3]['mnem'].startswith('add.'): print("*** Potential jumptable sequence found at EOS") pprint(insnStack[-3]) pprint(insnStack[-2]) pprint(insnStack[-1]) # Check the argtypes # Jump and move should have identical first argument types if insnStack[-1]['operands'][0]['type'] != 4 or insnStack[-2][ 'operands'][0]['type'] != 4: continue # Add should be rigged to double the value of a register if insnStack[-3]['operands'][0]['type'] != 1 or insnStack[-3][ 'operands'][1]['type'] != 1: continue if insnStack[-3]['operands'][0]['opnd'] != insnStack[-3][ 'operands'][1]['opnd']: continue # Jumptable address is the offset in the jump instruction's first operand jumptableAddr = insnStack[-1]['operands'][0]['value'] # Jump instruction EA jumpinstrAddr = insnStack[-1]['ea'] # Jump register jumpReg = insnStack[-3]['operands'][0]['opnd'] # Is there a subtract instruction above the 'add R,R'? if insnStack[-4]['mnem'].startswith('subi.'): jumpOffset = insnStack[-4]['operands'][0]['value'] else: jumpOffset = 0 print( "Jumptable Debug: TADDR %08X, JADDR %08X, OFFSET %d, REGISTER '%s'" % (jumptableAddr, jumpinstrAddr, jumpOffset, jumpReg)) jtLowerBound = None jtUpperBound = None # Hunt backwards for the compare operations (to get the JT bounds) for i in reversed(range(3, 8)): # 10 - 2 curi = insnStack[-i] previ = insnStack[-(i + 1)] if previ['mnem'].startswith('cmpi.'): print("COMPARE value %d" % previ['operands'][0]['value']) if curi['mnem'].startswith('blt.'): jtLowerBound = previ['operands'][0]['value'] elif curi['mnem'].startswith('bgt.'): jtUpperBound = previ['operands'][0]['value'] print("Jumptable Debug: upperbound %s lowerbound %s" % (jtUpperBound, jtLowerBound)) # TODO: figure out the register size # Set jumptable data swInf = switch_info_t() swInf.set_jtable_element_size # TODO: use AddCodeXref(?) to link calls where a function address has been copied into an address register # TODO: Search for the task table? """ # ??? idaapi.do_unknown(0x3C0000, 1) idaapi.doByte(0x3C0000, 1) idaapi.set_name(0x3C0000, "REG_VRAMADDR") #idaapi.set_cmt(0x3C0000, "Pouet.", 1) """ return 1
def load_mapping(emu, mapping): vaddr, _, size, _ = mapping idaapi.mem2base(emu.read_mem(vaddr, size), vaddr)
def load_file(li, neflags, format): idaapi.set_processor_type("arm", idaapi.SETPROC_ALL | idaapi.SETPROC_FATAL) f = load_nxo(li) if f.armv7: SetShortPrm(INF_LFLAGS, GetShortPrm(INF_LFLAGS) | LFLG_PC_FLAT) else: SetShortPrm(INF_LFLAGS, GetShortPrm(INF_LFLAGS) | LFLG_64BIT) SetCharPrm(INF_DEMNAMES, idaapi.DEMNAM_GCC3) idaapi.set_compiler_id(idaapi.COMP_GNU) idaapi.add_til2('gnulnx_arm' if f.armv7 else 'gnulnx_arm64', 1) loadbase = 0x60000000 if f.armv7 else 0x7100000000 f.binfile.seek(0) as_string = f.binfile.read(f.bssoff) idaapi.mem2base(as_string, loadbase) if f.text[1] != None: li.file2base(f.text[1], loadbase + f.text[2], loadbase + f.text[2] + f.text[3], True) if f.ro[1] != None: li.file2base(f.ro[1], loadbase + f.ro[2], loadbase + f.ro[2] + f.ro[3], True) if f.data[1] != None: li.file2base(f.data[1], loadbase + f.data[2], loadbase + f.data[2] + f.data[3], True) for start, end, name, kind in f.sections: if name.startswith('.got'): kind = 'CONST' idaapi.add_segm(0, loadbase + start, loadbase + end, name, kind) segm = idaapi.get_segm_by_name(name) if kind == 'CONST': segm.perm = idaapi.SEGPERM_READ elif kind == 'CODE': segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_EXEC elif kind == 'DATA': segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE elif kind == 'BSS': segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE idaapi.update_segm(segm) idaapi.set_segm_addressing(segm, 1 if f.armv7 else 2) # do imports # TODO: can we make imports show up in "Imports" window? undef_count = 0 for s in f.symbols: if not s.shndx and s.name: undef_count += 1 last_ea = max(loadbase + end for start, end, name, kind in f.sections) undef_entry_size = 8 undef_ea = ( (last_ea + 0xFFF) & ~0xFFF ) + undef_entry_size # plus 8 so we don't end up on the "end" symbol idaapi.add_segm(0, undef_ea, undef_ea + undef_count * undef_entry_size, "UNDEF", "XTRN") segm = idaapi.get_segm_by_name("UNDEF") segm.type = idaapi.SEG_XTRN idaapi.update_segm(segm) for i, s in enumerate(f.symbols): if not s.shndx and s.name: MakeQword(undef_ea) idaapi.do_name_anyway(undef_ea, s.name) s.resolved = undef_ea undef_ea += undef_entry_size elif i != 0: assert s.shndx s.resolved = loadbase + s.value if s.name: if s.type == STT_FUNC: print hex(s.resolved), s.name idaapi.add_entry(s.resolved, s.resolved, s.name, 0) else: idaapi.do_name_anyway(s.resolved, s.name) else: # NULL symbol s.resolved = 0 funcs = set() for s in f.symbols: if s.name and s.shndx and s.value: if s.type == STT_FUNC: funcs.add(loadbase + s.value) got_name_lookup = {} for offset, r_type, sym, addend in f.relocations: target = offset + loadbase if r_type in (R_ARM_GLOB_DAT, R_ARM_JUMP_SLOT, R_ARM_ABS32): if not sym: print 'error: relocation at %X failed' % target else: idaapi.put_long(target, sym.resolved) elif r_type == R_ARM_RELATIVE: idaapi.put_long(target, idaapi.get_long(target) + loadbase) elif r_type in (R_AARCH64_GLOB_DAT, R_AARCH64_JUMP_SLOT, R_AARCH64_ABS64): idaapi.put_qword(target, sym.resolved + addend) if addend == 0: got_name_lookup[offset] = sym.name elif r_type == R_AARCH64_RELATIVE: idaapi.put_qword(target, loadbase + addend) if addend < f.textsize: funcs.add(loadbase + addend) else: print 'TODO r_type %d' % (r_type, ) ida_make_offset(f, target) for func, target in f.plt_entries: if target in got_name_lookup: addr = loadbase + func funcs.add(addr) idaapi.do_name_anyway(addr, got_name_lookup[target]) funcs |= find_bl_targets(loadbase, loadbase + f.textsize) for addr in sorted(funcs, reverse=True): AutoMark(addr, AU_CODE) AutoMark(addr, AU_PROC) return 1
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
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 ''' idaapi.set_processor_type('cLEMENCy', idaapi.SETPROC_USER | idaapi.SETPROC_FATAL) li.seek(0) data = convert(li.read(li.size())) if len(data) > 0x4000000: # program too large return 0 idaapi.mem2base(data, 0, len(data)) seg = idaapi.segment_t() seg.startEA = 0 seg.endEA = 0x4000000 # seg.bitness = 1 idaapi.add_segm_ex(seg, "PROGRAM", "CODE", idaapi.ADDSEG_SPARSE) seg = idaapi.segment_t() seg.startEA = 0x4000000 seg.endEA = 0x400001e idaapi.add_segm_ex(seg, "CLOCKIO", "RAM", idaapi.ADDSEG_SPARSE) seg = idaapi.segment_t() seg.startEA = 0x4010000 seg.endEA = 0x4011000 idaapi.add_segm_ex(seg, "FLAGIO", "RAM", idaapi.ADDSEG_SPARSE) seg = idaapi.segment_t() seg.startEA = 0x5000000 seg.endEA = 0x5002000 idaapi.add_segm_ex(seg, "RDATA", "RAM", idaapi.ADDSEG_SPARSE) seg = idaapi.segment_t() seg.startEA = 0x5002000 seg.endEA = 0x5002003 idaapi.add_segm_ex(seg, "RDATASZ", "RAM", idaapi.ADDSEG_SPARSE) seg = idaapi.segment_t() seg.startEA = 0x5010000 seg.endEA = 0x5012000 idaapi.add_segm_ex(seg, "SDATA", "RAM", idaapi.ADDSEG_SPARSE) seg = idaapi.segment_t() seg.startEA = 0x5012000 seg.endEA = 0x5012003 idaapi.add_segm_ex(seg, "SDATASZ", "RAM", idaapi.ADDSEG_SPARSE) seg = idaapi.segment_t() seg.startEA = 0x6000000 seg.endEA = 0x6800000 idaapi.add_segm_ex(seg, "SHMEM", "RAM", idaapi.ADDSEG_SPARSE) seg = idaapi.segment_t() seg.startEA = 0x6800000 seg.endEA = 0x7000000 idaapi.add_segm_ex(seg, "NVRAM", "RAM", idaapi.ADDSEG_SPARSE) seg = idaapi.segment_t() seg.startEA = 0x7FFFF00 seg.endEA = 0x7FFFF1C idaapi.add_segm_ex(seg, "IVEC", "RAM", idaapi.ADDSEG_SPARSE) seg = idaapi.segment_t() seg.startEA = 0x7FFFF80 seg.endEA = 0x8000000 idaapi.add_segm_ex(seg, "PROCID", "RAM", idaapi.ADDSEG_SPARSE) idaapi.add_entry(0, 0, "_start", True) # idc.AutoMark( 0, AU_CODE ) return 1
def load_file(li, netflags, format): nsis = nsisfile.NSIS.from_path(idaapi.get_input_file_path()) # Create NSIS netnode. nsis_netnode = idaapi.netnode("$ NSIS", 0, True) nsis_netnode.hashset("VERSION_MAJOR", nsis.version_major) nsis_netnode.hashset("VERSION_MINOR", nsis.version_minor) # Create blocks segments. for name, n, sclass in BLOCKS: offset = nsis.header.blocks[n].offset if offset == 0: continue content = nsis.block(n) # Create block segment seg = idaapi.segment_t() seg.startEA = offset seg.endEA = offset + len(content) idaapi.add_segm_ex(seg, name, sclass, 0) idaapi.mem2base(content, offset) # Add one virtual segment to hold variables. var_seg = idaapi.segment_t() var_start = align(nsis.size()) var_seg.startEA = var_start var_seg.endEA = var_start + 0x1000 # Size chosen arbitrarily, should be enough. idaapi.add_segm_ex(var_seg, "VARS", "BSS", 0) # Create standard vars. for i, v in enumerate(nrs.strings.SYSVAR_NAMES.values()): idaapi.do_name_anyway(var_seg.startEA + i + 20, "$" + v) code_base = nsis.header.blocks[fileform.NB_ENTRIES].offset # Create sections functions. for i, section in enumerate(nsis.sections): if section.code == PTR_NONE: continue name = nsis.get_string(section.name_ptr) if not name: name = "_section" + str(i) ea = code_base + nrs.entry_to_offset(section.code) cname = canonize_name(name) AddEntryPoint(ea, ea, cname, 1) # Mark pages handlers. for i, page in enumerate(nsis.pages): for fn in ["prefunc", "showfunc", "leavefunc"]: addr = getattr(page, fn) if addr != PTR_NONE: name = "_page_{}_{}".format(i, fn) ea = code_base + nrs.entry_to_offset(addr) AddEntryPoint(ea, ea, name, 1) # Mark installer handlers. for event in [ "Init", "InstSuccess", "InstFailed", "UserAbort", "GUIInit", "GUIEnd", "MouseOverSection", "VerifyInstDir", "SelChange", "RebootFailed", ]: addr = getattr(nsis.header, "code_on" + event) if addr != PTR_NONE: name = "_on" + event ea = code_base + nrs.entry_to_offset(addr) AddEntryPoint(ea, ea, name, 1) # Create strings. """ strings_data = nsis.block(fileform.NB_STRINGS) strings_off = nsis.header.blocks[fileform.NB_STRINGS].offset i = 0 while i < len(strings_data): decoded_string, length = \ nrs.strings.decode(strings_data, i, nsis.version_major) decoded_string = str(decoded_string) string_name = canonize_name(decoded_string) idaapi.make_ascii_string(strings_off + i, length, ASCSTR_C) idaapi.set_cmt(strings_off + i, decoded_string, True) idaapi.do_name_anyway(strings_off + i, string_name) i += length #""" # Set processor to nsis script. SetProcessorType("nsis", SETPROC_ALL | SETPROC_FATAL) return 1