def main(): idaapi.auto_wait() base = idaapi.get_imagebase() tif = idaapi.tinfo_t() f = open(os.environ.get("DESTPATH", "functype_"), 'w') for ea in Segments(): # only code segment if idaapi.segtype(ea) != idaapi.SEG_CODE: continue for fva in Functions(get_segm_start(ea), get_segm_end(ea)): func_name = get_func_name(fva) has_type = idaapi.get_tinfo(tif, fva) or idaapi.guess_tinfo( tif, fva) if not has_type: continue info = serialize(tif) if info is None: continue print( hex(fva - base)[:-1], "|", func_name, "|", tif, "|", len(info['args'])) f.write("0x%x|%s|%s\n" % (fva - base, func_name, json.dumps(info))) f.close() idaapi.qexit(0)
def output_segments(out): """Dump binary segmentation.""" info = idaapi.get_inf_structure() size = "r32" if info.is_32bit else "r64" out.writelines(('(', info.get_proc_name()[1], ' ', size, ' (')) for seg in idautils.Segments(): out.write("\n({} {} {:d} ({:#x} {:d}))".format( get_segm_name(seg), "code" if idaapi.segtype(seg) == idaapi.SEG_CODE else "data", idaapi.get_fileregion_offset(seg), seg, idaapi.getseg(seg).size())) out.write("))\n")
def output_segments(out): """Dump binary segmentation.""" info = idaapi.get_inf_structure() size = "r32" if info.is_32bit else "r64" out.writelines(('(', info.get_proc_name()[1], ' ', size, ' (')) for seg in idautils.Segments(): out.write("\n({} {} {:d} ({:#x} {:d}))".format( idaapi.get_segm_name(seg), "code" if idaapi.segtype(seg) == idaapi.SEG_CODE else "data", idaapi.get_fileregion_offset(seg), seg, idaapi.getseg(seg).size())) out.write("))\n")
def dump_loader_info(output_filename): """Dump information for BAP's loader into output_filename.""" from idautils import Segments import idc idaapi.autoWait() with open(output_filename, 'w+') as out: info = idaapi.get_inf_structure() size = "r32" if info.is_32bit else "r64" out.write("(%s %s (" % (info.get_proc_name()[1], size)) for seg in Segments(): out.write("\n(%s %s %d (0x%X %d))" % ( idaapi.get_segm_name(seg), "code" if idaapi.segtype(seg) == idaapi.SEG_CODE else "data", idaapi.get_fileregion_offset(seg), seg, idaapi.getseg(seg).size())) out.write("))\n")
def type(self): return idaapi.segtype(self.ea)
def scan_for_stacks(): def preceeding_call(ea): p = idautils.DecodePreviousInstruction(ea) if p and "BL" in idc.GetMnem(p.ea): return str(idc.GetOpnd(p.ea, 0)) else: return "" def jumps_to(f, t): f_ea = idc.LocByName(f) t_ea = idc.LocByName(t) for start, end in idautils.Chunks(f_ea): ea = start while (ea < end): i = idautils.DecodeInstruction(ea) #Functions have data chunks in them, these are offsets and dwords. skipping 4 ahead seems like a safe choice. if type(i) == type(None): ea += 4 continue #detect if instruction is a jump to t_ea m = idc.GetMnem(ea) if idc.GetMnem(ea) == "LDR" and idc.GetOpnd( ea, 0) == "PC" and t in idc.GetOpnd(ea, 1): return True elif idc.GetMnem(ea) == "BX" and idc.GetOpnd(ea, 0) == t: return True try: ea += i.size except: print "0x%08x" % ea print "DecodeInstruction failed!" print i.size return False #return True if the function at ea has an indirect jump, like BX Reg # (This is not so simple, e.g. we don't want to include jumptables etc... for now it is just this simple implementation.) def jumps_to_reg(ea): return False stack_addrs = [] for s in idautils.Segments(): if idaapi.segtype(s) != idaapi.SEG_CODE: print "starting scanning segment at 0x%08x" % s addrs = find_ret_addrs(s) print "found %d return addresses in segment" % len(addrs) stack_addrs += addrs log_stack_addrs(stack_addrs) print "okay, stored all occurences. let's find viable call chains." chain = [] chains = [] for i in range(len(stack_addrs)): #if this is the last one, just add to chain if had to and finish. if (i == (len(stack_addrs) - 1)): if len(chain) > 0: chain.append(addr) chains.append(chain) continue addr = stack_addrs[i] ret_addr = Dword(addr) & 0xFFFFFFFE #adjust Thumb addresses to_f = str(idc.GetFunctionName(ret_addr)) next_ret_addr = Dword( stack_addrs[i + 1]) & 0xFFFFFFFE #adjust Thumb addresses pre_f = preceeding_call(next_ret_addr) if pre_f == to_f: chain.append(addr) elif jumps_to(pre_f, to_f): chain.append("direct jump") chain.append(addr) elif jumps_to_reg(pre_f): chain.append("indirect_jump?") chain.append(addr) #no bonus, need to start a new chain at next_ret_addr else: # if there is an existing chain, that means this addr was connected to the previous, so can be added into the chain. if len(chain) > 0: chain.append(addr) chains.append(chain) chain = [] print "found all chains, logging..." log_stack_chains(chains) print "... and done!"
f = idaapi.get_func(s_addr) if (type(f) == type(None)): print "Failed to create function! Undefined instructions?" s_addr += 2 else: num_added_functions += 1 ea = -1 for c in idautils.Chunks(s_addr): if c[1] > ea: ea = c[1] if ea != -1: s_addr = ea #failed? else: s_addr += 2 else: s_addr += 2 print "finished segment" return num_added_functions num_total_added_functions = 0 for s in idautils.Segments(): s_start = s if idaapi.segtype(s_start) == idaapi.SEG_CODE: print "starting segment at 0x%08x" % s_start num_total_added_functions += def_functions(s) print "Added %d functions in total" % num_total_added_functions
def scan_for_stacks(): def preceeding_call(ea): p = idautils.DecodePreviousInstruction(ea) if p and "BL" in idc.GetMnem(p.ea): return str(idc.GetOpnd(p.ea, 0)) else: return "" def jumps_to(f, t): f_ea = idc.LocByName(f) t_ea = idc.LocByName(t) for start,end in idautils.Chunks(f_ea): ea = start while (ea < end): i = idautils.DecodeInstruction(ea) #Functions have data chunks in them, these are offsets and dwords. skipping 4 ahead seems like a safe choice. if type(i) == type(None): ea += 4 continue #detect if instruction is a jump to t_ea m = idc.GetMnem(ea) if idc.GetMnem(ea) == "LDR" and idc.GetOpnd(ea, 0) == "PC" and t in idc.GetOpnd(ea, 1): return True elif idc.GetMnem(ea) == "BX" and idc.GetOpnd(ea, 0) == t: return True try: ea += i.size except: print "0x%08x" % ea print "DecodeInstruction failed!" print i.size return False #return True if the function at ea has an indirect jump, like BX Reg # (This is not so simple, e.g. we don't want to include jumptables etc... for now it is just this simple implementation.) def jumps_to_reg(ea): return False stack_addrs = [] for s in idautils.Segments(): if idaapi.segtype(s) != idaapi.SEG_CODE: print "starting scanning segment at 0x%08x" % s addrs = find_ret_addrs(s) print "found %d return addresses in segment" % len(addrs) stack_addrs += addrs log_stack_addrs(stack_addrs) print "okay, stored all occurences. let's find viable call chains." chain = [] chains = [] for i in range(len(stack_addrs)): #if this is the last one, just add to chain if had to and finish. if (i == (len(stack_addrs) - 1) ): if len(chain) > 0: chain.append(addr) chains.append(chain) continue addr = stack_addrs[i] ret_addr = Dword(addr) & 0xFFFFFFFE #adjust Thumb addresses to_f = str(idc.GetFunctionName(ret_addr)) next_ret_addr = Dword(stack_addrs[i+1]) & 0xFFFFFFFE #adjust Thumb addresses pre_f = preceeding_call(next_ret_addr) if pre_f == to_f: chain.append(addr) elif jumps_to(pre_f, to_f): chain.append("direct jump") chain.append(addr) elif jumps_to_reg(pre_f): chain.append("indirect_jump?") chain.append(addr) #no bonus, need to start a new chain at next_ret_addr else: # if there is an existing chain, that means this addr was connected to the previous, so can be added into the chain. if len(chain) > 0: chain.append(addr) chains.append(chain) chain = [] print "found all chains, logging..." log_stack_chains(chains) print "... and done!"
def load_cro(li, is_crs): if is_crs: base = 0 else: base = 0x00100000 # arbitrary li.seek(0x80) (Magic, NameOffset, NextCRO, PreviousCRO, FileSize, BssSize, FixedSize, UnknownZero, UnkSegmentTag, OnLoadSegmentTag, OnExitSegmentTag, OnUnresolvedSegmentTag, CodeOffset, CodeSize, DataOffset, DataSize, ModuleNameOffset, ModuleNameSize, SegmentTableOffset, SegmentNum, ExportNamedSymbolTableOffset, ExportNamedSymbolNum, ExportIndexedSymbolTableOffset, ExportIndexedSymbolNum, ExportStringsOffset, ExportStringsSize, ExportTreeTableOffset, ExportTreeNum, ImportModuleTableOffset, ImportModuleNum, ExternalPatchTableOffset, ExternalPatchNum, ImportNamedSymbolTableOffset, ImportNamedSymbolNum, ImportIndexedSymbolTableOffset, ImportIndexedSymbolNum, ImportAnonymousSymbolTableOffset, ImportAnonymousSymbolNum, ImportStringsOffset, ImportStringsSize, StaticAnonymousSymbolTableOffset, StaticAnonymousSymbolNum, InternalPatchTableOffset, InternalPatchNum, StaticPatchTableOffset, StaticPatchNum) = struct.unpack( "<IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII", li.read(0x138 - 0x80)) if not is_crs: li.file2base(0, base, base + FileSize, 0) idaapi.add_segm(0, base, base + 0x80, "header", "RODATA") idaapi.add_segm(0, base + SegmentTableOffset, base + DataOffset, "tables", "RODATA") # set segments li.seek(SegmentTableOffset) segmentDic = [("CODE", ".text"), ("DATA", ".rodata"), ("DATA", ".data"), ("BSS", ".bss")] segmentAddress = [] for i in range(SegmentNum): SegmentOffset, SegmentSize, SegmentType = struct.unpack( "<III", li.read(12)) if SegmentType == 3: SegmentOffset = 0x08000000 idaapi.enable_flags(base + SegmentOffset, base + SegmentOffset + SegmentSize, idaapi.STT_VA) segmentAddress.append(base + SegmentOffset) if SegmentSize: idaapi.add_segm(0, segmentAddress[i], segmentAddress[i] + SegmentSize, segmentDic[SegmentType][1], segmentDic[SegmentType][0]) # do internal relocations li.seek(InternalPatchTableOffset) for i in range(InternalPatchNum): target, patch_type, source, _, _, shift = struct.unpack( "<IBBBBI", li.read(12)) target_offset = DecodeTag(segmentAddress, target) source_offset = segmentAddress[source] + shift if patch_type == 2: value = source_offset elif patch_type == 3: rel = source_offset - target_offset if rel < 0: rel += 0x100000000 value = rel idaapi.patch_long(target_offset, value) f = idaapi.fixup_data_t() f.type = idaapi.FIXUP_OFF32 f.off = value idaapi.set_fixup(target_offset, f) # import li.seek(ImportNamedSymbolTableOffset) importNamedSymbolTable = [] for i in range(ImportNamedSymbolNum): importNamedSymbolTable.append(struct.unpack('<II', li.read(8))) for importNamedSymbol in importNamedSymbolTable: nameOffset, batchOffset = importNamedSymbol li.seek(nameOffset) name = "" while True: c = li.read(1) if c == '\0': break name += c do_import_batch(li, segmentAddress, batchOffset, name) li.seek(ImportModuleTableOffset) module = [] for i in range(ImportModuleNum): module.append(struct.unpack('<IIIII', li.read(20))) for m in module: moduleNameOffset, indexed, indexedNum, anonymous, anonymousNum = m li.seek(moduleNameOffset) mname = "" while True: c = li.read(1) if c == '\0': break mname += c indexeds = [] li.seek(indexed) for i in range(indexedNum): indexeds.append(struct.unpack('<II', li.read(8))) anonymouses = [] li.seek(anonymous) for i in range(anonymousNum): anonymouses.append(struct.unpack('<II', li.read(8))) for i in indexeds: index, batchOffset = i do_import_batch(li, segmentAddress, batchOffset, "%s_%d" % (mname, index)) for i in anonymouses: tag, batchOffset = i do_import_batch(li, segmentAddress, batchOffset, "%s_%08X" % (mname, tag)) # export li.seek(ExportNamedSymbolTableOffset) exportNamedSymbolTable = [] for i in range(ExportNamedSymbolNum): exportNamedSymbolTable.append(struct.unpack('<II', li.read(8))) for exportNamedSymbol in exportNamedSymbolTable: nameOffset, target = exportNamedSymbol target_offset = DecodeTag(segmentAddress, target) li.seek(nameOffset) name = "" while True: c = li.read(1) if c == '\0': break name += c if idaapi.segtype(target_offset) == idaapi.SEG_CODE: target_offset &= ~1 idaapi.add_entry(target_offset, target_offset, name, idaapi.segtype(target_offset) == idaapi.SEG_CODE) idaapi.make_name_public(target_offset) li.seek(ExportIndexedSymbolTableOffset) for i in range(ExportIndexedSymbolNum): target, = struct.unpack('<I', li.read(4)) target_offset = DecodeTag(segmentAddress, target) if idaapi.segtype(target_offset) == idaapi.SEG_CODE: target_offset &= ~1 idaapi.add_entry(i, target_offset, "indexedExport_%d" % i, idaapi.segtype(target_offset) == idaapi.SEG_CODE) idaapi.make_name_public(target_offset)
def load_cro(li, is_crs): if is_crs: base = 0 else: base = 0x00100000 # arbitrary li.seek(0x80) (Magic, NameOffset, NextCRO, PreviousCRO, FileSize, BssSize, FixedSize, UnknownZero, UnkSegmentTag, OnLoadSegmentTag, OnExitSegmentTag, OnUnresolvedSegmentTag, CodeOffset, CodeSize, DataOffset, DataSize, ModuleNameOffset, ModuleNameSize, SegmentTableOffset, SegmentNum, ExportNamedSymbolTableOffset, ExportNamedSymbolNum, ExportIndexedSymbolTableOffset, ExportIndexedSymbolNum, ExportStringsOffset, ExportStringsSize, ExportTreeTableOffset, ExportTreeNum, ImportModuleTableOffset, ImportModuleNum, ExternalPatchTableOffset, ExternalPatchNum, ImportNamedSymbolTableOffset, ImportNamedSymbolNum, ImportIndexedSymbolTableOffset, ImportIndexedSymbolNum, ImportAnonymousSymbolTableOffset, ImportAnonymousSymbolNum, ImportStringsOffset, ImportStringsSize, StaticAnonymousSymbolTableOffset, StaticAnonymousSymbolNum, InternalPatchTableOffset, InternalPatchNum, StaticPatchTableOffset, StaticPatchNum) = struct.unpack("<IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII", li.read(0x138 - 0x80)) if not is_crs: li.file2base(0, base, base + FileSize, 0) # set segments li.seek(SegmentTableOffset) segmentDic = [ ("CODE", ".text"), ("DATA", ".rodata"), ("DATA", ".data"), ("BSS", ".bss") ] segmentAddress = [] for i in range(SegmentNum): SegmentOffset, SegmentSize, SegmentType = struct.unpack("<III", li.read(12)) if SegmentType == 3: SegmentOffset = 0x08000000 idaapi.enable_flags(base + SegmentOffset, base + SegmentOffset + SegmentSize, idaapi.STT_VA) segmentAddress.append(base + SegmentOffset) if SegmentSize : idaapi.add_segm(0, segmentAddress[i], segmentAddress[i] + SegmentSize, segmentDic[SegmentType][1], segmentDic[SegmentType][0]) # do internal relocations li.seek(InternalPatchTableOffset) for i in range(InternalPatchNum): target, patch_type, source, _, _, shift = struct.unpack("<IBBBBI", li.read(12)) target_offset = DecodeTag(segmentAddress, target) source_offset = segmentAddress[source] + shift if patch_type == 2: value = source_offset elif patch_type == 3: rel = source_offset - target_offset if rel < 0: rel += 0x100000000 value = rel idaapi.patch_long(target_offset, value) f = idaapi.fixup_data_t() f.type = idaapi.FIXUP_OFF32 f.off = value idaapi.set_fixup(target_offset, f) # import li.seek(ImportNamedSymbolTableOffset) importNamedSymbolTable = [] for i in range(ImportNamedSymbolNum): importNamedSymbolTable.append(struct.unpack('<II', li.read(8))) for importNamedSymbol in importNamedSymbolTable: nameOffset, batchOffset = importNamedSymbol li.seek(nameOffset) name = "" while True: c = li.read(1) if c == '\0': break name += c do_import_batch(li, segmentAddress, batchOffset, name) li.seek(ImportModuleTableOffset) module = [] for i in range(ImportModuleNum): module.append(struct.unpack('<IIIII', li.read(20))) for m in module: moduleNameOffset, indexed, indexedNum, anonymous, anonymousNum = m li.seek(moduleNameOffset) mname = "" while True: c = li.read(1) if c == '\0': break mname += c indexeds = [] li.seek(indexed) for i in range(indexedNum): indexeds.append(struct.unpack('<II', li.read(8))) anonymouses = [] li.seek(anonymous) for i in range(anonymousNum): anonymouses.append(struct.unpack('<II', li.read(8))) for i in indexeds: index, batchOffset = i do_import_batch(li, segmentAddress, batchOffset, "%s_%d"%(mname, index)) for i in anonymouses: tag, batchOffset = i do_import_batch(li, segmentAddress, batchOffset, "%s_%08X"%(mname, tag)) # export li.seek(ExportNamedSymbolTableOffset) exportNamedSymbolTable = [] for i in range(ExportNamedSymbolNum): exportNamedSymbolTable.append(struct.unpack('<II', li.read(8))) for exportNamedSymbol in exportNamedSymbolTable: nameOffset, target = exportNamedSymbol target_offset = DecodeTag(segmentAddress, target) li.seek(nameOffset) name = "" while True: c = li.read(1) if c == '\0': break name += c idaapi.add_entry(target_offset, target_offset, name, idaapi.segtype(target_offset) == idaapi.SEG_CODE) idaapi.make_name_public(target_offset) li.seek(ExportIndexedSymbolTableOffset) for i in range(ExportIndexedSymbolNum): target, = struct.unpack('<I', li.read(4)) target_offset = DecodeTag(segmentAddress, target) idaapi.add_entry(i, target_offset, "indexedExport_%d" % i, idaapi.segtype(target_offset) == idaapi.SEG_CODE) idaapi.make_name_public(target_offset)