Exemplo n.º 1
0
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
Exemplo n.º 2
0
    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")