def processfile(args, filetypehint, fh): class DummyIDB: def __init__(idb, args): if args.i64: idb.magic = 'IDA2' elif args.i32: idb.magic = 'IDA1' else: idb.magic = None try: magic = fh.read(64) fh.seek(-64, 1) if magic.startswith(b"Va") or magic.startswith(b"VA"): idb = DummyIDB(args) if filetypehint == 'id1': processid1(args, idblib.ID1File(idb, fh)) elif filetypehint == 'nam': processnam(args, idblib.NAMFile(idb, fh)) elif filetypehint == 'seg': processseg(args, idblib.SEGFile(idb, fh)) else: print("unknown VA type file: %s" % hexdump(magic)) elif magic.startswith(b"IDAS"): processid2(args, idblib.ID2File(DummyIDB(args), fh)) elif magic.startswith(b"IDATIL"): processtil(args, idblib.ID2File(DummyIDB(args), fh)) elif magic.startswith(b"IDA"): processidb(args, idblib.IDBFile(fh)) elif magic.find(b'B-tree v') > 0: processid0(args, idblib.ID0File(DummyIDB(args), fh)) except Exception as e: print("ERROR %s" % e) if args.debug: raise
def _parseIDB(self, filename): import logging import carbonara_idb as idb import idblib logging.basicConfig() printout(RED + "[ ]" + NC + " Getting linked libraries") libs_list = self._cmd_j('ilj') self.data['libs'] = [] for lib in libs_list: self.data['libs'].append({"name": lib}) printout("\r" + GREEN + "[x]" + NC + " Getting linked libraries\n") printout(RED + "[ ]" + NC + " Getting imported functions") #get imported functions imports = self._cmd_j('iij') self.data["imports"] = [] self.imports_dict = {} for imp in imports: if len(imp["name"]) == 0: continue i = { "name": imp["name"], "addr": imp["plt"] #??? for PE binaries? } for lib in libs_list: if len(imp["name"]) > len(lib) and imp["name"][:len(lib )] == lib: self.imports_dict[imp["name"][len(lib):]] = imp["plt"] break self.data["imports"].append(i) printout("\r" + GREEN + "[x]" + NC + " Getting imported functions\n") printout(RED + "[ ]" + NC + " Getting exported symbols") #get exported symbols exports = self._cmd_j('iEj') self.data["exports"] = [] for exp in exports: e = { "name": exp["name"], "offset": exp["paddr"], "size": exp["size"] } self.data["exports"].append(e) printout("\r" + GREEN + "[x]" + NC + " Getting exported symbols\n") #analyze all printout(RED + "[ ]" + NC + " Analyzing all") self.r2.cmd("aaa") printout(GREEN + "[x]" + NC + " Analyzing all\n") def strz(b, o): return b[o:b.find(b'\x00', o)].decode('utf-8', 'ignore') fhandle = open(filename, 'rb') idbfile = idblib.IDBFile(fhandle) id0 = idblib.ID0File(idbfile, idbfile.getpart(0)) root = id0.nodeByName('Root Node') if root: params = id0.bytes(root, 'S', 0x41b994) #whooooo if params: magic, version, cpu, idpflags, demnames, filetype, coresize, corestart, ostype, apptype = struct.unpack_from( "<3sH8sBBH" + (id0.fmt * 2) + "HH", params, 0) #maaagic cpu = strz(cpu, 0)[1:] #print(magic, version, cpu, idpflags, demnames, filetype, coresize, corestart, ostype, apptype) try: self.arch = matching.archFromIda(cpu, self.data["info"]["bits"], self.data["info"]["endian"]) except: raise ArchNotSupported("arch %s (%d bits) not supported" % (cpu, self.data["info"]["bits"])) self.data["info"]["arch"] = self.arch.name self.procs = [] with idb.from_file(filename) as db: api = idb.IDAPython(db) ida_funcs = api.idautils.Functions() sym_imp_l = len("sym.imp") printout(RED + "[ ]" + NC + " Getting procedures (0/%d)" % len(ida_funcs)) i = 1 #iterate for each function for func in ida_funcs: printout("\r" + RED + "[ ]" + NC + " Getting procedures (%d/%d)" % (i, len(ida_funcs))) try: fcn_name = api.idc.GetFunctionName(func) start = api.idc.GetFunctionAttr(func, api.idc.FUNCATTR_START) end = api.idc.GetFunctionAttr(func, api.idc.FUNCATTR_END) cur_addr = start flow_insns = [] asm = '' insns_list = [] self.r2.cmd('s ' + hex(start)) temp_d = self._cmd_j('pdj') if temp_d == None: raise RuntimeError("radare ignored %s" % fcn_name) temp_ins = {} fcn_instructions = [] for ins in temp_d: if "offset" in ins: temp_ins[ins["offset"]] = ins #get assembly from function while cur_addr <= end: next_instr = api.idc.NextHead(cur_addr) #get size instr if next_instr > end: size = end - cur_addr else: size = next_instr - cur_addr #print cur_addr flags = api.idc.GetFlags(cur_addr) if api.ida_bytes.isCode(flags): instr = None if cur_addr in temp_ins: instr = temp_ins[cur_addr] else: self.r2.cmd('s ' + hex(cur_addr)) temp_d = self._cmd_j('pdj') if temp_d == None: break for ins in temp_d: if "offset" in ins: temp_ins[ins["offset"]] = ins if ins["offset"] == cur_addr: instr = ins if instr == None: break #print instr["opcode"] if instr["type"] == "invalid": cur_addr = next_instr continue #get comment if possible try: cmt = api.ida_bytes.get_cmt(cur_addr, True).replace( '\n', ' ') instr["comment"] = cmt except: pass fcn_instructions.append(instr) cur_addr = next_instr #get raw bytes from function try: fcn_bytes = api.idc.GetManyBytes(start, end - start) except: self.r2.cmd('s ' + hex(start)) #r2 cmd p6e : get bytes of a function in base64 fcn_bytes = base64.b64decode( self.r2.cmd('p6e ' + str(end - start)).rstrip()) #get callconv => NOT WORKING #flags = api.idc.GetFunctionAttr(func, api.idc.FUNCATTR_FLAGS) #callconv = api.idc.get_optype_flags1(flags) fcn_call_conv = None self.procs.append({ "offset": start, "name": fcn_name, "size": end - start, "calltype": fcn_call_conv, "instructions": fcn_instructions, "bytes": fcn_bytes }) except Exception: if _DEBUG: import traceback traceback.print_exc() printerr(" >> " + RED + "Error" + NC + " on function %s, skipped" % fcn_name) i += 1 printout("\r" + GREEN + "[x]" + NC + " Getting procedures\n")