コード例 #1
0
def test_files(fns, quiet=False, profile=False, runtime=False):
    for fn in fns:
        short_fn = fn.split("/")[-1] if "/" in fn else fn
        if os.path.isdir(fn):
            if not quiet:
                print "{} {}: skipping directory".format(notice, short_fn)
            continue
        try:
            elf = ELFFile(open(fn))
        except ELFError:
            if not quiet:
                print "{} {}: skipping non-ELF file".format(notice, short_fn)
            continue

        engine_functions = {}
        for engine in ENGINES:
            try:
                this_engine = Static(fn, debug=0,
                                     static_engine=engine)  #no debug output
                if args.profile:
                    #needs pycallgraph
                    from pycallgraph import PyCallGraph
                    from pycallgraph.output import GraphvizOutput
                    graphviz = GraphvizOutput()
                    graphviz.output_file = 'prof.png'
                    with PyCallGraph(output=graphviz):
                        this_engine.process()
                else:
                    this_engine.process()
                engine_functions[engine] = {
                    x.start
                    for x in this_engine['functions']
                }
            except KeyboardInterrupt:
                print "{} User stopped processing test cases.".format(notice)
                sys.exit()
            except MemoryError:
                #print "{} {}: bap encountered a memory error.".format(fail, short_fn, engine)
                continue
            except Exception as e:
                print "{} {}: {} engine failed to process file with `{}'".format(
                    fail, short_fn, engine, e)
                continue
        if runtime:
            if not quiet:
                print "{} {}: {} ran without exceptions".format(
                    ok_green, short_fn, engine)
            continue

        if elf.has_dwarf_info():
            dwarfinfo = elf.get_dwarf_info()
            dwarf_functions = get_functions(dwarfinfo)
            for engine, functions in engine_functions.iteritems():
                missed = dwarf_functions - functions
                total_fxns = len(dwarf_functions)
                if len(missed) == 0:
                    print "{} {}: {} engine found all {} function(s)".format(
                        ok_green, short_fn, engine, total_fxns)
                else:
                    status = fail if len(missed) == total_fxns else warn
                    if args.verbose:
                        fmt = "{} {}: {} engine missed {}/{} function(s): {}"
                        missed_s = ", ".join(hex(fxn) for fxn in missed)
                        print fmt.format(status, short_fn, engine, len(missed),
                                         total_fxns, missed_s)
                    else:
                        fmt = "{} {}: {} engine missed {}/{} function(s)"
                        print fmt.format(status, short_fn, engine, len(missed),
                                         total_fxns)
        else:
            for engine, functions in engine_functions.iteritems():
                status = fail if len(functions) == 0 else ok_blue
                print "{} {}: {} engine found {} function(s). (dwarf info unavailable)".format(
                    status, short_fn, engine, len(functions))
コード例 #2
0
    def load_module(self, filename, do_init=True):
        m = self.find_module_by_name(filename)
        if (m != None):
            return m
        #
        logger.debug("Loading module '%s'." % filename)
        #do sth like linker
        with open(filename, 'rb') as fstream:
            #TODO: load elf without Section Header,pyelftools do not support.
            elf = ELFFile(fstream)

            dynamic = elf.header.e_type == 'ET_DYN'

            if not dynamic:
                raise NotImplementedError(
                    "Only ET_DYN is supported at the moment.")

            # Parse program header (Execution view).

            # - LOAD (determinate what parts of the ELF file get mapped into memory)
            load_segments = [
                x for x in elf.iter_segments() if x.header.p_type == 'PT_LOAD'
            ]

            # Find bounds of the load segments.
            bound_low = 0
            bound_high = 0

            for segment in load_segments:
                if segment.header.p_memsz == 0:
                    continue

                if bound_low > segment.header.p_vaddr:
                    bound_low = segment.header.p_vaddr

                high = segment.header.p_vaddr + segment.header.p_memsz

                if bound_high < high:
                    bound_high = high
            '''
            // Segment addresses in memory.
            Elf32_Addr seg_start = phdr->p_vaddr + load_bias_;
            Elf32_Addr seg_end   = seg_start + phdr->p_memsz;

            Elf32_Addr seg_page_start = PAGE_START(seg_start);
            Elf32_Addr seg_page_end   = PAGE_END(seg_end);

            // File offsets.
            Elf32_Addr file_start = phdr->p_offset;
            Elf32_Addr file_end   = file_start + phdr->p_filesz;

            Elf32_Addr seg_file_end   = seg_start + phdr->p_filesz;
            Elf32_Addr file_page_start = PAGE_START(file_start);
            Elf32_Addr file_length = file_end - file_page_start;

            if (file_length != 0) {
            void* seg_addr = mmap((void*)seg_page_start,
                                    file_length,
                                    PFLAGS_TO_PROT(phdr->p_flags),
                                    MAP_FIXED|MAP_PRIVATE,
                                    fd_,
                                    file_page_start);
            '''
            # Retrieve a base address for this module.
            load_base = self.mem_reserve(bound_low, bound_high)

            vf = VirtualFile(
                misc_utils.system_path_to_vfs_path(self.__vfs_root, filename),
                misc_utils.my_open(filename, os.O_RDONLY), filename)
            for segment in load_segments:
                prot = get_segment_protection(segment.header.p_flags)
                prot = prot if prot is not 0 else UC_PROT_ALL

                #self.emu.memory.map(load_base + segment.header.p_vaddr, segment.header.p_memsz, prot)
                #self.emu.mu.mem_write(load_base + segment.header.p_vaddr, segment.data())

                seg_start = load_base + segment.header.p_vaddr
                seg_page_start = page_start(seg_start)
                file_start = segment.header.p_offset
                file_end = file_start + segment.header.p_filesz
                file_page_start = page_start(file_start)
                file_length = file_end - file_page_start
                assert (file_length > 0)
                if (file_length > 0):
                    self.emu.memory.map(seg_page_start, file_length, prot, vf,
                                        file_page_start)
                #

                seg_end = seg_start + segment.header.p_memsz
                seg_page_end = page_end(seg_end)

                seg_file_end = seg_start + segment.header.p_filesz

                seg_file_end = page_end(seg_file_end)
                '''
                      void* zeromap = mmap((void*)seg_file_end,
                           seg_page_end - seg_file_end,
                           PFLAGS_TO_PROT(phdr->p_flags),
                           MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE,
                           -1,
                           0);
                '''
                self.emu.memory.map(seg_file_end, seg_page_end - seg_file_end,
                                    prot)
            #

            # Find init array.
            init_array_size = 0
            init_array_offset = 0
            init_array = []
            init_addr = 0
            dynstr_addr = 0
            dt_needed = []
            for x in elf.iter_segments():
                if x.header.p_type == "PT_DYNAMIC":
                    for tag in x.iter_tags():
                        if tag.entry.d_tag == "DT_INIT_ARRAYSZ":
                            init_array_size = tag.entry.d_val
                        elif tag.entry.d_tag == "DT_INIT_ARRAY":
                            init_array_offset = tag.entry.d_val
                        elif tag.entry.d_tag == "DT_INIT":
                            init_addr = tag.entry.d_val + load_base
                        elif tag.entry.d_tag == "DT_STRTAB":
                            dynstr_addr = tag.entry.d_val + load_base
                        elif tag.entry.d_tag == "DT_NEEDED":
                            dt_needed.append(tag.entry.d_val)
                        #
                    #
                    break
                #
            #
            so_needed = []
            for str_off in dt_needed:
                str_addr = dynstr_addr + str_off
                so_name = memory_helpers.read_utf8(self.emu.mu, str_addr)
                so_needed.append(so_name)
            #
            for so_name in so_needed:
                path = misc_utils.vfs_path_to_system_path(
                    self.__vfs_root, so_name)
                if (not os.path.exists(path)):
                    logger.warn("%s needed by %s do not exist in vfs %s" %
                                (so_name, filename, self.__vfs_root))
                    continue
                #
                libmod = self.load_module(path)
            #

            rel_section = None
            for section in elf.iter_sections():
                if not isinstance(section, RelocationSection):
                    continue
                rel_section = section
                break
            #
            # Parse section header (Linking view).
            dynsym = elf.get_section_by_name(".dynsym")
            for _ in range(int(init_array_size / 4)):
                b = self.emu.mu.mem_read(load_base + init_array_offset, 4)
                fun_ptr = int.from_bytes(b, byteorder='little', signed=False)
                if fun_ptr != 0:
                    # fun_ptr += load_base
                    init_array.append(fun_ptr + load_base)
                    # print ("find init array for :%s %x" % (filename, fun_ptr))
                else:
                    # search in reloc
                    for rel in rel_section.iter_relocations():
                        rel_info_type = rel['r_info_type']
                        rel_addr = rel['r_offset']
                        if rel_info_type == arm.R_ARM_ABS32 and rel_addr == init_array_offset:
                            sym = dynsym.get_symbol(rel['r_info_sym'])
                            sym_value = sym['st_value']
                            init_array.append(load_base + sym_value)
                            # print ("find init array for :%s %x" % (filename, sym_value))
                            break
                        #
                    #
                init_array_offset += 4

            # Resolve all symbols.
            symbols_resolved = dict()

            for section in elf.iter_sections():
                if not isinstance(section, SymbolTableSection):
                    continue

                itersymbols = section.iter_symbols()
                next(itersymbols)  # Skip first symbol which is always NULL.
                for symbol in itersymbols:
                    symbol_address = self._elf_get_symval(
                        elf, load_base, symbol)
                    if symbol_address is not None:
                        symbols_resolved[symbol.name] = SymbolResolved(
                            symbol_address, symbol)

            # Relocate.
            for section in elf.iter_sections():
                if not isinstance(section, RelocationSection):
                    continue

                for rel in section.iter_relocations():
                    sym = dynsym.get_symbol(rel['r_info_sym'])
                    sym_value = sym['st_value']

                    rel_addr = load_base + rel[
                        'r_offset']  # Location where relocation should happen
                    rel_info_type = rel['r_info_type']

                    #print(filename)
                    #print("%x"%rel_addr)
                    # Relocation table for ARM
                    if rel_info_type == arm.R_ARM_ABS32:
                        if sym.name in symbols_resolved:
                            sym_addr = symbols_resolved[sym.name].address

                            value_orig_bytes = self.emu.mu.mem_read(
                                rel_addr, 4)
                            value_orig = int.from_bytes(value_orig_bytes,
                                                        byteorder='little')

                            #R_ARM_ABS32 重定位方式参见 android linker源码
                            #*reinterpret_cast<Elf32_Addr*>(reloc) += sym_addr;
                            value = sym_addr + value_orig
                            # Write the new value
                            #print(value)
                            self.emu.mu.mem_write(
                                rel_addr, value.to_bytes(4,
                                                         byteorder='little'))
                        #
                    #
                    elif rel_info_type in (arm.R_ARM_GLOB_DAT,
                                           arm.R_ARM_JUMP_SLOT,
                                           arm.R_AARCH64_GLOB_DAT,
                                           arm.R_AARCH64_JUMP_SLOT):
                        # Resolve the symbol.
                        #R_ARM_GLOB_DAT,R_ARM_JUMP_SLOT修复方式见linker源码
                        #*reinterpret_cast<Elf32_Addr*>(reloc) = sym_addr;
                        if sym.name in symbols_resolved:
                            value = symbols_resolved[sym.name].address

                            # Write the new value
                            #print(value)
                            self.emu.mu.mem_write(
                                rel_addr, value.to_bytes(4,
                                                         byteorder='little'))
                        #
                    #
                    elif rel_info_type in (arm.R_ARM_RELATIVE,
                                           arm.R_AARCH64_RELATIVE):
                        if sym_value == 0:
                            # Load address at which it was linked originally.
                            value_orig_bytes = self.emu.mu.mem_read(
                                rel_addr, 4)
                            value_orig = int.from_bytes(value_orig_bytes,
                                                        byteorder='little')

                            # Create the new value
                            value = load_base + value_orig

                            #print(value)
                            # Write the new value
                            self.emu.mu.mem_write(
                                rel_addr, value.to_bytes(4,
                                                         byteorder='little'))
                        else:
                            raise NotImplementedError()
                    else:
                        logger.error("Unhandled relocation type %i." %
                                     rel_info_type)
                    #

            # Store information about loaded module.
            module = Module(filename, load_base, bound_high - bound_low,
                            symbols_resolved, init_addr, init_array)
            self.modules.append(module)
            #TODO init tls like linker
            '''
            void __libc_init_tls(KernelArgumentBlock& args) {
                __libc_auxv = args.auxv;
                unsigned stack_top = (__get_sp() & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
                unsigned stack_size = 128 * 1024;
                unsigned stack_bottom = stack_top - stack_size;
                static void* tls[BIONIC_TLS_SLOTS];
                static pthread_internal_t thread;
                thread.tid = gettid();
                thread.tls = tls;
                pthread_attr_init(&thread.attr);
                pthread_attr_setstack(&thread.attr, (void*) stack_bottom, stack_size);
                _init_thread(&thread, false);
                __init_tls(&thread);
                tls[TLS_SLOT_BIONIC_PREINIT] = &args;
            }
            '''
            if do_init:
                '''
                for r in self.emu.mu.mem_regions():
                    print("region begin :0x%08X end:0x%08X, prot:%d"%(r[0], r[1], r[2]))
                #
                '''
                module.call_init(self.emu)
            #
            logger.info("finish load lib %s" % filename)
            return module
コード例 #3
0
def return_parsed_section(filename, secname):
    with open(filename, 'rb') as f:
        elffile = ELFFile(f)

        #ll=elffile.iter_sections()
        #for x in ll:
        #    print x.name

        section = elffile.get_section_by_name(str2bytes(secname))

        if section is None:
            print 'ERROR! Section ' + secname + ' does not exist in the file!'

        #print 'Name of section is: '+bytes2str(section.name)

        ##assuming no relocation section for now
        #self._note_relocs_for_section(section)
        addr = section['sh_addr']
        data = section.data()
        dataptr = 0

        setStartAddress('  %s ' % _format_hex(addr, elffile, fieldsize=8))

        toreturn = []
        while dataptr < len(data):
            bytesleft = len(data) - dataptr
            # chunks of 16 bytes per line
            linebytes = 16 if bytesleft > 16 else bytesleft

            #not adding addresses in beginning of 4 * 4 bytes
            #toreturn+='  %s ' % _format_hex(addr, elffile, fieldsize=8 )
            for i in range(16):
                if i < linebytes:
                    toreturn.append('%2.2x' % byte2int(data[dataptr + i]))
                else:
                    pass
                    #not doing anything
                    #toreturn+='  '
                if i % 4 == 3:
                    pass
                    #not doing anything
                    #toreturn+=' '

            for i in range(linebytes):
                c = data[dataptr + i:dataptr + i + 1]
                if byte2int(c[0]) >= 32 and byte2int(c[0]) < 0x7f:
                    pass
                    #removing not used info
                    #toreturn+=bytes2str(c)
                else:
                    pass
                    #removing not used info
                    #toreturn+=(bytes2str(b'.'))

            #again not adding string or newline
            #toreturn+='\n'
            addr += linebytes
            dataptr += linebytes

        for x in range(len(toreturn) % 4):
            toreturn.append('')

        if toreturn == []:
            print 'No data to display in ' + secname + ' section'
            return
        global little
        little = isLittleEndian(elffile)
        finalreturn = arrangeData(toreturn, isLittleEndian(elffile))
        setNumOfInst(len(finalreturn))
        return finalreturn
コード例 #4
0
ファイル: elf_parser.py プロジェクト: woachk/bin2llvm
def do_elf(path_to_elf, out_dir='/tmp'):
    """This function reads information from elf file and translates it to
    appropiate config structure.
    """

    ret = {}
    elf = ELFFile(open(path_to_elf, 'rb'))
    if 'ARM' != elf.get_machine_arch():
        raise Exception("Architecture not supported")

    ret['architecture'] = 'arm'
    ret['cpu_model'] = 'arm926'
    ret['endianness'] = 'little' if elf.little_endian else 'big'
    ret['entry_address'] = [elf.header.e_entry]

    thumb_targets = []
    targets = []
    for sec in elf.iter_sections():
        if sec.name.startswith(b'.symtab'):
            log.info("[Translator] binary contains symbols! Using those instead of the single entry")
            ret['entry_address'] = []
            # nm can run on any type of elf binary
            p = subprocess.Popen(['nm', path_to_elf], stdout=subprocess.PIPE)
            out, _ = p.communicate()
            for l in out.split('\n'):
                try:
                    addr, t, name = l.split(' ')
                except:
                    continue
                if (t == 't' or t == 'T') and not name.startswith('$'):
                    targets.append(int(addr, 16))

            # call readelf -s for getting the thumb bit
            # somehow, the $a and $t are not always generated?
            p = subprocess.Popen(['readelf', '-s', path_to_elf], \
                    stdout=subprocess.PIPE)
            out, _ = p.communicate()
            for l in out.split('\n'):
                try:
                    _, addr, _, t, _, _, _, name = l.split()
                except:
                    #print("QQ: %s: %d" % (l, len(l.split(' '))))
                    #print(str(l.split(None)))
                    continue
                if t != 'FUNC':
                    continue
                jumpPC = int(addr, 16)
                if jumpPC & 1 == 0x1:
                    thumb_targets.append(jumpPC & -2)

    segments = []
    cnt = 0
    mapped_targets = []
    mapped_thumb_targets = []

    for i in range(elf.num_segments()):
        seg = elf.get_segment(i)
        if seg.header.p_type != 'PT_LOAD':
            continue

        #print(dir(seg.header))
        assert(seg.header.p_paddr == seg.header.p_vaddr)
        padding = seg.header.p_paddr % 4096
        #assert(seg.header.p_paddr % 4096 == 0)

        new_section = {}
        s = max(seg.header.p_memsz, seg.header.p_filesz)

        # round up to 4k
        if s % 4096 != 0:
            s = 4096*int((s+4096)/4096)

        s += padding

        # round up to 4k
        if s % 4096 != 0:
            s = 4096*int((s+4096)/4096)

        # build segment info
        segm_name = 'seg-'+str(cnt)+'.bin'
        segm_file = os.path.join(out_dir, segm_name)
        offset = seg.header.p_offset-padding
        assert(offset >= 0)

        segm_desc = {}
        segm_desc['file'] = segm_file
        segm_desc['size'] = s
        segm_desc['address'] = seg.header.p_paddr - padding
        segm_desc['name'] = segm_name

        # save chunk
        save_chunk(segm_file, path_to_elf, offset, s)
        cnt += 1
        segments.append(segm_desc)

        log.debug("[Translator] loaded %s%08x@%08x" % \
                (seg.header.p_type, seg.header.p_paddr, \
            seg.header.p_offset))

        def inside_segment(e):
            return e >= segm_desc['address'] and \
                e < (segm_desc['address'] + \
                    segm_desc['size'])
        # filter data
        map(mapped_targets.append, filter(inside_segment, \
                targets))
        map(mapped_thumb_targets.append, filter(inside_segment, \
                thumb_targets))

    ret['segments'] = segments

    # unique
    mapped_thumb_targets = sorted(list(set(mapped_thumb_targets)))
    mapped_targets = sorted(list(set(mapped_targets)))
    log.debug("[Translator] elf: %d entries and %d thumb bits" % \
            (len(mapped_targets), len(mapped_thumb_targets)))

    if len(mapped_thumb_targets) > 0:
        fout = os.path.join(out_dir, "is-thumb-initial.json")
        with open(fout, 'wt') as f:
            f.write(json.dumps(mapped_thumb_targets))
    else:
        fout = None

    map(ret['entry_address'].append, mapped_targets)
    return ret, fout
コード例 #5
0
def process_file(filename, modulename, language, outputname):
    functions = []

    with open(filename, "rb") as f:
        elffile = ELFFile(f)

        if not elffile.has_dwarf_info():
            print("File has no DWARF info. Compile with -g.")
            sys.exit(1)

        dwarfinfo = elffile.get_dwarf_info()

        funcs_addr = 0
        funcs_size = 0
        vars_addr = 0
        vars_size = 0
        for section in elffile.iter_sections():
            if section.name == ".lf.funcs":
                funcs_addr = section["sh_addr"]
                funcs_size = section["sh_size"]
            if section.name == ".lf.vars":
                vars_addr = section["sh_addr"]
                vars_size = section["sh_size"]

        if funcs_addr == 0:
            outc = open(outputname, "w")
            sys.exit(0)

        # This iterates through all CUs, even the ones without .lf.funcs section
        i = 0
        for cu in dwarfinfo.iter_CUs():
            top = cu.get_top_DIE()
            for child in top.iter_children():
                if child.tag == "DW_TAG_subprogram" and "DW_AT_low_pc" in child.attributes:
                    address = child.attributes["DW_AT_low_pc"].value
                    if address in range(funcs_addr, funcs_addr + funcs_size):
                        name = child.attributes["DW_AT_name"].value
                        # print "n: " + name
                        if "DW_AT_type" in child.attributes.keys():
                            tdie = get_die_at_offset(
                                cu, child.attributes["DW_AT_type"].value)
                            if tdie == None:
                                print(
                                    "Failed to get die at offset: " +
                                    hex(child.attributes["DW_AT_type"].value))
                                return 1
                            while tdie.tag == "DW_TAG_typedef":
                                tdie = get_die_at_offset(
                                    cu, tdie.attributes["DW_AT_type"].value)
                            if "DW_AT_name" in tdie.attributes:
                                type = tdie.attributes["DW_AT_name"].value
                                ret = tdie.attributes["DW_AT_byte_size"].value
                            elif "DW_AT_byte_size" in tdie.attributes:
                                type = "void *"
                                ret = tdie.attributes["DW_AT_byte_size"].value
                            else:
                                type = "void"
                                ret = 0x2
                        params = get_parameters_from_die(cu, child)
                        functions.append(Function(type, name, ret, params))

        if language.lower() == "c":
            generate_c(modulename, outputname, functions)
        elif language.lower() == "python":
            generate_py(modulename, outputname, functions)
        else:
            print("Invalid language: " + language)
            sys.exit(1)
コード例 #6
0
def __main():
    # Get the LD parameters
    if len(sys.argv) < 7:
        raise ValueError(
            'Command line:\n\tappname hexpath stacklen ldexe ldscript ldoself ldmap ldobjelf ldobj*\nGiven:\n\t'
            + str(sys.argv))
    appname = sys.argv[1].strip()[:MAX_NAME_LENGTH]
    hexpath = sys.argv[2]
    stacklen = int(sys.argv[3][3:],
                   16) if sys.argv[3].strip().lower()[0:2] == '0x' else int(
                       sys.argv[3])
    ldexe = sys.argv[4]
    ldscript = sys.argv[5]
    ldoself = sys.argv[6]
    ldmap = sys.argv[7]
    ldobjelf = sys.argv[8]
    ldobjs = sys.argv[9:]

    # Get the length of each section
    pgmlen, bsslen, datalen = 0, 0, 0
    with open(ldobjelf, 'rb') as f:
        elffile = ELFFile(f)
        for section in elffile.iter_sections():
            if section.name == '.text': pgmlen = int(section['sh_size'])
            elif section.name == '.bss': bsslen = int(section['sh_size'])
            elif section.name == '.data': datalen = int(section['sh_size'])

    # Open the serial port
    ser = serial.Serial(SERIAL_PORT, SERIAL_BAUD)
    sio = io.TextIOWrapper(buffer=io.BufferedRWPair(ser, ser, 1),
                           newline='\r\n',
                           line_buffering=True,
                           encoding='ascii')
    try:
        sio.write(unicode('\n\n'))
        time.sleep(0.1)
        while ser.inWaiting():
            ser.flushInput()
            time.sleep(0.1)
        sio.write(unicode('app_install\n'))
        print '"' + sio.readline() + '"'

        # Send the section sizes and app name
        sizestr = '%0.8X,%0.8X,%0.8X,%0.8X,%0.2X%s' % (
            pgmlen, bsslen, datalen, stacklen, len(appname), appname)
        print sizestr
        sio.write(unicode(sizestr + '\n'))

        # Receive the allocated addresses
        addrs = sio.readline().split(',')
        pgmadr = int(addrs[0].strip(), 16)
        bssadr = int(addrs[1].strip(), 16)
        dataadr = int(addrs[2].strip(), 16)
        datapgmadr = int(addrs[3].strip(), 16)

        # Link to the OS symbols
        sectopt = [
            '--section-start',
            '.text=0x%0.8X' % pgmadr, '--section-start',
            '.bss=0x%0.8X' % bssadr, '--section-start',
            '.data=0x%0.8X' % dataadr
        ]
        args = [
            ldexe, '--script', ldscript, '--just-symbols', ldoself, '-Map',
            ldmap, '-o', ldobjelf
        ] + sectopt + ldobjs
        print args
        subprocess.call(args)
        subprocess.call(['make'])

        with open(ldobjelf, 'rb') as f:
            elffile = ELFFile(f)
            threadadr = __find_address(elffile, ENTRY_THREAD_NAME)
            print 'app_thread = 0x%0.8X' % threadadr

        # Read the generated IHEX file and remove unused records
        with open(hexpath, 'r') as f:
            hexdata = f.readlines()
        hexdata = [
            line.strip() for line in hexdata
            if not line[7:9] in ['05', '03'] and len(line) >= 11
        ]
        hexdata = [line for line in hexdata if len(line) > 0]
        if len([None for line in hexdata if line[7:9] == '01'
                ]) != 1 and hexdata[-1][7:9] != '01':
            raise RuntimeError(
                'The IHEX must contain a single EOF record, as last record')

        # Insert the entry point thread record
        chks = threadadr & 0xFFFFFFFF
        chks = (chks >> 24) + (chks >> 16) + (chks >> 8) + (chks & 0xFF)
        chks = 0x100 - (0x04 + 0x00 + 0x00 + 0x05 + chks) & 0xFF
        hexdata[0:0] = [':04000005%0.8X%0.2X' % (threadadr, chks)]

        # Send IHEX records
        for i in range(len(hexdata)):
            line = sio.readline().strip()
            print line
            if line != ',':
                raise RuntimeError(
                    'Error while loading line %d ("%s", received "%s")' %
                    (i, hexdata[i], line))
            sio.write(unicode(hexdata[i] + '\n'))
            print hexdata[i]

        line = sio.readline().strip()
        print line
        if line != '$':
            raise RuntimeError(
                'Error while terminating programming (received "%s")' % line)
        ser.close()

    except:
        ser.close()
        raise
コード例 #7
0
ファイル: patch.py プロジェクト: zoutaov/FBUnpinner
if __name__ == "__main__":
    # Validate command line args
    try:
        libcoldstart_path = sys.argv[1]
    except IndexError:
        libcoldstart_path = os.path.join(os.getcwd(), "libcoldstart.so")
    try:
        new_path = sys.argv[2]
    except IndexError:
        new_path = os.path.join(os.path.dirname(libcoldstart_path),
                                "libcoldstart-patched.so")

    f = open(libcoldstart_path, "rb")
    # Validate input file
    elf = ELFFile(f)
    arch = elf.get_machine_arch()
    if arch != "ARM" and arch != "x86":
        print(
            "[!] ERROR: Unknown architecture in libcoldstart.so, this script only supports ARM and x86!"
        )

    shutil.copyfile(libcoldstart_path, new_path)

    patched = False
    patcher13 = TLS13Patcher(f, elf, arch, new_path)
    if patcher13.find_error_strings():
        print("[+] Patching TLS1.3 stack!")
        patcher13.patch()
        patched = True
    else:
コード例 #8
0
def ParseELF(path,
             root='/',
             prefix='',
             ldpaths={
                 'conf': [],
                 'env': [],
                 'interp': []
             },
             display=None,
             debug=False,
             _first=True,
             _all_libs={}):
    """Parse the ELF dependency tree of the specified file

  Args:
    path: The ELF to scan
    root: The root tree to prepend to paths; this applies to interp and rpaths
          only as |path| and |ldpaths| are expected to be prefixed already
    prefix: The path under |root| to search
    ldpaths: dict containing library paths to search; should have the keys:
             conf, env, interp
    display: The path to show rather than |path|
    debug: Enable debug output
    _first: Recursive use only; is this the first ELF ?
    _all_libs: Recursive use only; dict of all libs we've seen

  Returns:
    a dict containing information about all the ELFs; e.g.
    {
      'interp': '/lib64/ld-linux.so.2',
      'needed': ['libc.so.6', 'libcurl.so.4',],
      'libs': {
        'libc.so.6': {
          'path': '/lib64/libc.so.6',
          'needed': [],
        },
        'libcurl.so.4': {
          'path': '/usr/lib64/libcurl.so.4',
          'needed': ['libc.so.6', 'librt.so.1',],
        },
      },
    }
  """
    if _first:
        _all_libs = {}
        ldpaths = ldpaths.copy()
    ret = {
        'interp': None,
        'path': path if display is None else display,
        'realpath': path,
        'needed': [],
        'rpath': [],
        'runpath': [],
        'libs': _all_libs,
    }

    dbg(debug, 'ParseELF(%s)' % path)

    with open(path, 'rb') as f:
        elf = ELFFile(f)

        # If this is the first ELF, extract the interpreter.
        if _first:
            for segment in elf.iter_segments():
                if segment.header.p_type != 'PT_INTERP':
                    continue

                interp = bstr(segment.get_interp_name())
                dbg(debug, '  interp           =', interp)
                ret['interp'] = normpath(root + interp)
                real_interp = readlink(ret['interp'], root, prefixed=True)
                ret['libs'][os.path.basename(interp)] = {
                    'path': ret['interp'],
                    'realpath': real_interp,
                    'needed': [],
                }
                # XXX: Could read it and scan for /lib paths.
                # If the interp is a symlink, lets follow it on the assumption that it
                # is in this path purely for ABI reasons, and the distro is using a
                # different (probably more correct) path.  This can come up in some
                # multilib situations like s390x where /lib64/ contains all the native
                # libraries, but /lib/ld64.so.1 is the interp hardcoded in gcc, so the
                # ld64.so.1 is really a symlink to ../lib64/ld64.so.1.  In the multiarch
                # setup, it'll be /lib/ld64.so.1 -> /lib/s390x-linux-gnu/ld64.so.1.
                # That is why we use |real_interp| here instead of |interp|.
                ldpaths['interp'] = [
                    os.path.dirname(real_interp),
                    normpath(root + prefix + '/usr/' +
                             os.path.dirname(real_interp)[len(root) +
                                                          len(prefix):]),
                ]
                dbg(debug, '  ldpaths[interp]  =', ldpaths['interp'])
                break

        # Parse the ELF's dynamic tags.
        libs = []
        rpaths = []
        runpaths = []
        for segment in elf.iter_segments():
            if segment.header.p_type != 'PT_DYNAMIC':
                continue

            for t in segment.iter_tags():
                if t.entry.d_tag == 'DT_RPATH':
                    rpaths = ParseLdPaths(bstr(t.rpath), root=root, path=path)
                elif t.entry.d_tag == 'DT_RUNPATH':
                    runpaths = ParseLdPaths(bstr(t.runpath),
                                            root=root,
                                            path=path)
                elif t.entry.d_tag == 'DT_NEEDED':
                    libs.append(bstr(t.needed))
            if runpaths:
                # If both RPATH and RUNPATH are set, only the latter is used.
                rpaths = []

            # XXX: We assume there is only one PT_DYNAMIC.  This is
            # probably fine since the runtime ldso does the same.
            break
        if _first:
            # Propagate the rpaths used by the main ELF since those will be
            # used at runtime to locate things.
            ldpaths['rpath'] = rpaths
            ldpaths['runpath'] = runpaths
            dbg(debug, '  ldpaths[rpath]   =', rpaths)
            dbg(debug, '  ldpaths[runpath] =', runpaths)
        ret['rpath'] = rpaths
        ret['runpath'] = runpaths
        ret['needed'] = libs

        # Search for the libs this ELF uses.
        all_ldpaths = None
        for lib in libs:
            if lib in _all_libs:
                continue
            if all_ldpaths is None:
                all_ldpaths = rpaths + ldpaths['rpath'] + ldpaths[
                    'env'] + runpaths + ldpaths['runpath'] + ldpaths[
                        'conf'] + ldpaths['interp']
            realpath, fullpath = FindLib(elf,
                                         lib,
                                         all_ldpaths,
                                         root,
                                         debug=debug)
            _all_libs[lib] = {
                'realpath': realpath,
                'path': fullpath,
                'needed': [],
            }
            if fullpath:
                try:
                    lret = ParseELF(realpath,
                                    root,
                                    prefix,
                                    ldpaths,
                                    display=fullpath,
                                    debug=debug,
                                    _first=False,
                                    _all_libs=_all_libs)
                except exceptions.ELFError as e:
                    warn('%s: %s' % (realpath, e))
                _all_libs[lib]['needed'] = lret['needed']

        del elf

    return ret
コード例 #9
0
def main():
    parse_args()

    with open(args.kernel, "rb") as fp:
        kernel = ELFFile(fp)
        syms = get_symbols(kernel)

    if "CONFIG_MULTI_LEVEL_INTERRUPTS" in syms:
        max_irq_per = syms["CONFIG_MAX_IRQ_PER_AGGREGATOR"]

        if "CONFIG_2ND_LEVEL_INTERRUPTS" in syms:
            num_aggregators = syms["CONFIG_NUM_2ND_LEVEL_AGGREGATORS"]
            irq2_baseoffset = syms["CONFIG_2ND_LVL_ISR_TBL_OFFSET"]
            list_2nd_lvl_offsets = [
                syms['CONFIG_2ND_LVL_INTR_{}_OFFSET'.format(str(i).zfill(2))]
                for i in range(num_aggregators)
            ]

            debug('2nd level offsets: {}'.format(list_2nd_lvl_offsets))

            if "CONFIG_3RD_LEVEL_INTERRUPTS" in syms:
                num_aggregators = syms["CONFIG_NUM_3RD_LEVEL_AGGREGATORS"]
                irq3_baseoffset = syms["CONFIG_3RD_LVL_ISR_TBL_OFFSET"]
                list_3rd_lvl_offsets = [
                    syms['CONFIG_3RD_LVL_INTR_{}_OFFSET'.format(
                        str(i).zfill(2))] for i in range(num_aggregators)
                ]

                debug('3rd level offsets: {}'.format(list_3rd_lvl_offsets))

    intlist = read_intlist(args.intlist, syms)
    nvec = intlist["num_vectors"]
    offset = intlist["offset"]

    if nvec > pow(2, 15):
        raise ValueError('nvec is too large, check endianness.')

    swt_spurious_handler = "((uintptr_t)&z_irq_spurious)"
    vt_spurious_handler = "z_irq_spurious"
    vt_irq_handler = "_isr_wrapper"

    debug('offset is ' + str(offset))
    debug('num_vectors is ' + str(nvec))

    # Set default entries in both tables
    if args.sw_isr_table:
        # All vectors just jump to the common vt_irq_handler. If some entries
        # are used for direct interrupts, they will be replaced later.
        if args.vector_table:
            vt = [vt_irq_handler for i in range(nvec)]
        else:
            vt = None
        # Default to spurious interrupt handler. Configured interrupts
        # will replace these entries.
        swt = [(0, swt_spurious_handler) for i in range(nvec)]
    else:
        if args.vector_table:
            vt = [vt_spurious_handler for i in range(nvec)]
        else:
            error(
                "one or both of -s or -V needs to be specified on command line"
            )
        swt = None

    for irq, flags, func, param in intlist["interrupts"]:
        if flags & ISR_FLAG_DIRECT:
            if param != 0:
                error("Direct irq %d declared, but has non-NULL parameter" %
                      irq)
            if not 0 <= irq - offset < len(vt):
                error("IRQ %d (offset=%d) exceeds the maximum of %d" %
                      (irq - offset, offset, len(vt) - 1))
            vt[irq - offset] = func
        else:
            # Regular interrupt
            if not swt:
                error("Regular Interrupt %d declared with parameter 0x%x "
                      "but no SW ISR_TABLE in use" % (irq, param))

            if not "CONFIG_MULTI_LEVEL_INTERRUPTS" in syms:
                table_index = irq - offset
            else:
                # Figure out third level interrupt position
                debug('IRQ = ' + hex(irq))
                irq3 = (irq & THIRD_LVL_INTERRUPTS) >> 16
                irq2 = (irq & SECND_LVL_INTERRUPTS) >> 8
                irq1 = (irq & FIRST_LVL_INTERRUPTS)

                if irq3:
                    irq_parent = irq2
                    list_index = getindex(irq_parent, list_3rd_lvl_offsets)
                    irq3_pos = irq3_baseoffset + max_irq_per * list_index + irq3 - 1
                    debug('IRQ_level = 3')
                    debug('IRQ_Indx = ' + str(irq3))
                    debug('IRQ_Pos  = ' + str(irq3_pos))
                    table_index = irq3_pos - offset

                # Figure out second level interrupt position
                elif irq2:
                    irq_parent = irq1
                    list_index = getindex(irq_parent, list_2nd_lvl_offsets)
                    irq2_pos = irq2_baseoffset + max_irq_per * list_index + irq2 - 1
                    debug('IRQ_level = 2')
                    debug('IRQ_Indx = ' + str(irq2))
                    debug('IRQ_Pos  = ' + str(irq2_pos))
                    table_index = irq2_pos - offset

                # Figure out first level interrupt position
                else:
                    debug('IRQ_level = 1')
                    debug('IRQ_Indx = ' + str(irq1))
                    debug('IRQ_Pos  = ' + str(irq1))
                    table_index = irq1 - offset

            if not 0 <= table_index < len(swt):
                error("IRQ %d (offset=%d) exceeds the maximum of %d" %
                      (table_index, offset, len(swt) - 1))
            if swt[table_index] != (0, swt_spurious_handler):
                error(
                    f"multiple registrations at table_index {table_index} for irq {irq} (0x{irq:x})"
                    +
                    f"\nExisting handler 0x{swt[table_index][1]:x}, new handler 0x{func:x}"
                    +
                    "\nHas IRQ_CONNECT or IRQ_DIRECT_CONNECT accidentally been invoked on the same irq multiple times?"
                )

            swt[table_index] = (param, func)

    with open(args.output_source, "w") as fp:
        write_source_file(fp, vt, swt, intlist, syms)
コード例 #10
0
ファイル: gen_mmu.py プロジェクト: snellnxp/zephyr
def main():
    """Main program"""
    global syms
    parse_args()

    with open(args.kernel, "rb") as elf_fp:
        kernel = ELFFile(elf_fp)
        syms = get_symbols(kernel)

    if isdef("CONFIG_X86_64"):
        pclass = PtablesIA32e
    elif isdef("CONFIG_X86_PAE"):
        pclass = PtablesPAE
    else:
        pclass = Ptables32bit

    debug("building %s" % pclass.__name__)

    vm_base = syms["CONFIG_KERNEL_VM_BASE"]
    vm_size = syms["CONFIG_KERNEL_VM_SIZE"]
    vm_offset = syms["CONFIG_KERNEL_VM_OFFSET"]

    sram_base = syms["CONFIG_SRAM_BASE_ADDRESS"]
    sram_size = syms["CONFIG_SRAM_SIZE"] * 1024

    mapped_kernel_base = syms["z_mapped_start"]
    mapped_kernel_size = syms["z_mapped_size"]

    if isdef("CONFIG_SRAM_OFFSET"):
        sram_offset = syms["CONFIG_SRAM_OFFSET"]
    else:
        sram_offset = 0

    # Figure out if there is any need to do virtual-to-physical
    # address translation
    virt_to_phys_offset = (sram_base + sram_offset) - (vm_base + vm_offset)

    if isdef("CONFIG_ARCH_MAPS_ALL_RAM"):
        image_base = sram_base
        image_size = sram_size
    else:
        image_base = mapped_kernel_base
        image_size = mapped_kernel_size

    image_base_phys = image_base + virt_to_phys_offset

    ptables_phys = syms["z_x86_pagetables_start"] + virt_to_phys_offset

    debug("Address space: 0x%x - 0x%x size 0x%x" %
          (vm_base, vm_base + vm_size - 1, vm_size))

    debug("Zephyr image: 0x%x - 0x%x size 0x%x" %
          (image_base, image_base + image_size - 1, image_size))

    is_perm_regions = isdef("CONFIG_SRAM_REGION_PERMISSIONS")

    if image_size >= vm_size:
        error("VM size is too small (have 0x%x need more than 0x%x)" %
              (vm_size, image_size))

    if is_perm_regions:
        # Don't allow execution by default for any pages. We'll adjust this
        # in later calls to pt.set_region_perms()
        map_flags = FLAG_P | ENTRY_XD
    else:
        map_flags = FLAG_P

    pt = pclass(ptables_phys)
    # Instantiate all the paging structures for the address space
    pt.reserve(vm_base, vm_size)
    # Map the zephyr image
    pt.map(image_base_phys, image_base, image_size, map_flags | ENTRY_RW)

    if isdef("CONFIG_X86_64"):
        # 64-bit has a special region in the first 64K to bootstrap other CPUs
        # from real mode
        locore_base = syms["_locore_start"]
        locore_size = syms["_lodata_end"] - locore_base
        debug("Base addresses: physical 0x%x size 0x%x" %
              (locore_base, locore_size))
        pt.map(locore_base, None, locore_size, map_flags | ENTRY_RW)

    if isdef("CONFIG_XIP"):
        # Additionally identity-map all ROM as read-only
        pt.map(syms["CONFIG_FLASH_BASE_ADDRESS"], None,
               syms["CONFIG_FLASH_SIZE"] * 1024, map_flags)

    # Adjust mapped region permissions if configured
    if is_perm_regions:
        # Need to accomplish the following things:
        # - Text regions need the XD flag cleared and RW flag removed
        #   if not built with gdbstub support
        # - Rodata regions need the RW flag cleared
        # - User mode needs access as we currently do not separate application
        #   text/rodata from kernel text/rodata
        if isdef("CONFIG_GDBSTUB"):
            flags = FLAG_P | ENTRY_US | ENTRY_RW
            pt.set_region_perms("_image_text", flags)
        else:
            flags = FLAG_P | ENTRY_US
            pt.set_region_perms("_image_text", flags)

        flags = FLAG_P | ENTRY_US | ENTRY_XD
        pt.set_region_perms("_image_rodata", flags)

        if isdef("CONFIG_COVERAGE_GCOV") and isdef("CONFIG_USERSPACE"):
            # If GCOV is enabled, user mode must be able to write to its
            # common data area
            pt.set_region_perms("__gcov_bss",
                                FLAG_P | ENTRY_RW | ENTRY_US | ENTRY_XD)

        if isdef("CONFIG_X86_64"):
            # Set appropriate permissions for locore areas much like we did
            # with the main text/rodata regions

            if isdef("CONFIG_X86_KPTI"):
                # Set the User bit for the read-only locore/lorodata areas.
                # This ensures they get mapped into the User page tables if
                # KPTI is turned on. There is no sensitive data in them, and
                # they contain text/data needed to take an exception or
                # interrupt.
                flag_user = ENTRY_US
            else:
                flag_user = 0

            pt.set_region_perms("_locore", FLAG_P | flag_user)
            pt.set_region_perms("_lorodata", FLAG_P | ENTRY_XD | flag_user)

    pt.write_output(args.output)
コード例 #11
0
def main(input, output, format='nro'):
	format = format.lower()
	assert format in ('nro', 'nso')

	with open(input, 'rb') as f:
		elffile = ELFFile(f)
		elffile.iter_sections_by_type = lambda type: (x for x in elffile.iter_sections() if isinstance(x, type))

		symbols = {}
		symbolList = []
		for x in elffile.iter_sections_by_type(SymbolTableSection):
			for i, sym in enumerate(x.iter_symbols()):
				sectaddr = elffile.get_section(sym['st_shndx'])['sh_addr'] if isinstance(sym['st_shndx'], int) else 0
				symbols[sym.name] = sectaddr + sym['st_value']
				symbolList.append(sym.name)

		textCont, rodataCont, relaDynCont, dataCont, dynamicCont, dynstrCont, dynsymCont = [elffile.get_section_by_name(x).data() for x in (
		        '.text', '.rodata', '.rela.dyn', '.data', '.dynamic', '.dynstr', '.dynsym')]
		csec = dict(text=textCont, rodata=rodataCont, relaDyn=relaDynCont, data=dataCont, dynamic=dynamicCont, dynstr=dynstrCont, dynsym=dynsymCont)

		def replace(tgt, offset, data):
			orig = csec[tgt]
			csec[tgt] = orig[:offset] + data + orig[offset + len(data):]

		for x in elffile.iter_sections_by_type(RelocationSection):
			tgtsect = elffile.get_section(x['sh_info'])
			tgt = tgtsect.name[1:]
			if tgt not in csec:
				continue
			for iter in x.iter_relocations():
				symname = symbolList[iter['r_info_sym']]
				if not symname.startswith('NORELOC_'):
					continue

				reloc_type = iter['r_info_type']
				if reloc_type == R_AARCH64_PREL32:
					replace(tgt, iter['r_offset'], struct.pack('<i', symbols[symname] + iter['r_addend'] - (
							tgtsect['sh_addr'] + iter['r_offset'])))
				elif reloc_type == R_AARCH64_ABS32:
					replace(tgt, iter['r_offset'], struct.pack('<I', symbols[symname] + iter['r_addend']))
				else:
					print('Unknown relocation type!', reloc_type)
					assert False

		text, rodata, data = csec['text'], csec['rodata'], csec['data']

		if len(rodata) & 0x7:
			rodata += '\0'.encode() * (0x8 - (len(rodata) & 0x7))

		rodata += csec['relaDyn']

		if len(data) & 0x7:
			data += '\0'.encode() * (0x8 - (len(data) & 0x7))

		if len(text) & 0xFFF:
			text += '\0'.encode() * (0x1000 - (len(text) & 0xFFF))
		if len(rodata) & 0xFFF:
			rodata += '\0'.encode() * (0x1000 - (len(rodata) & 0xFFF))

		data += csec['dynamic']
		if len(data) & 0xFFF:
			data += '\0'.encode() * (0x1000 - (len(data) & 0xFFF))
		data += csec['dynsym']
		if len(data) & 0x7:
			data += '\0'.encode() * (0x8 - (len(data) & 0x7))
		data += csec['dynstr']

		if len(data) & 0xFFF:
			data += '\0'.encode() * (0x1000 - (len(data) & 0xFFF))
		
		bssSize = elffile.get_section_by_name('.bss')['sh_size']
		if bssSize & 0xFFF:
			bssSize += 0x1000 - (bssSize & 0xFFF)

		if format == 'nro':
			# text = text[0x80:]
			with open(output, 'wb') as fp:
				fp.write(text[:0x4]) # first branch instruction
				fp.write(struct.pack('<III', len(text) + len(rodata) + 8, 0, 0))
				fp.write('NRO0'.encode())
				fp.write(struct.pack('<III', 0, len(text) + len(rodata) + len(data), 0))
				fp.write(struct.pack('<II', 0, len(text)))	# exec segment
				fp.write(struct.pack('<II', len(text), len(rodata))) # read only segment
				fp.write(struct.pack('<II', len(text) + len(rodata), len(data))) # rw segment
				fp.write(struct.pack('<II', bssSize, 0))
				fp.write('\0'.encode() * 0x40)
				fp.write(text[0x80:])
				fp.write(rodata)
				fp.write(data)
		else:
			with open(output, 'wb') as fp:
				ctext, crodata, cdata = [lz4.block.compress(x, store_size=False) for x in (text, rodata, data)]

				fp.write('NSO0'.encode())
				fp.write('\0'.encode() * 0xC)

				off = 0x101
				fp.write(struct.pack('<IIII', off, 0, len(text), 0))
				off += len(ctext)
				fp.write(struct.pack('<IIII', off, len(text), len(rodata), 0))
				off += len(crodata)
				fp.write(struct.pack('<IIII', off, len(text) + len(rodata), len(data),
									 symbols['NORELOC_BSS_END_'] - symbols['NORELOC_BSS_START_']))
				fp.write('\0'.encode() * 0x20)
				fp.write(struct.pack('<IIII', len(ctext), len(crodata), len(cdata), 0))
				fp.write('\0'.encode() * 0x91)

				fp.write(ctext)
				fp.write(crodata)
				fp.write(cdata)
コード例 #12
0
    def parse_elf(file, elf, starting_function, start_addr, size, section_name,
                  ret, caller, call_dic):
        i = 0
        current_func = Function(starting_function, ret, file)
        ret.add_function(current_func)
        section = elf.get_section_by_name(section_name)
        sh_addr = section['sh_addr']
        sh_size = section['sh_size']
        if (size == 0):  # sometime the size is 0
            size = sh_size
        offset = start_addr - sh_addr
        stop_offset = offset + size
        code = section.data()[offset:stop_offset]
        opcode = ""
        for b in code:
            opcode += "%02x" % b

        address = start_addr
        callers = set()
        caller = list()

        while (i < len(opcode)):
            op_list = opcode.split()
            abs_instr = AbstractInstruction(current_func)
            instr_string, length, arguments, clock, register, index, immediate, indirect, dst_register, dst_index = abs_instr.parse(
                op_list[0][i:])
            if (instr_string == ""
                ):  # --------- this will be changed later (sancus instruction)
                return ret
            instr = InstructionFactory.get_instruction(instr_string,
                                                       function=current_func)
            instr.get_info(length, address, arguments, clock, op_list[0][i:],
                           register, index, immediate, indirect, dst_register,
                           dst_index, file)
            current_func.add_instruction(instr)

            if (instr_string == 'call' and op_list[0][i + 1] == '0'):
                hex_addr = op_list[0][i + 6] + op_list[0][i + 7] + op_list[0][
                    i + 4] + op_list[0][i + 5]
                call_target = int(hex_addr, 16)

                elf = ELFFile(open(file, 'rb'))
                sym_table_name, sym_table_size, section_name = SyntaxConverter.find_symbol_by_addr(
                    elf, call_target)
                callee_function_name = sym_table_name
                callee_function_size = sym_table_size

                # Check for recursionn -------------------------
                callers.clear()
                if caller is not None:
                    caller.clear()

                if (call_target == start_addr):
                    return ret
                else:
                    count = 0
                    call_dic.setdefault(call_target, []).append(start_addr)
                    callers = {start_addr}
                    tmp = call_dic.get(start_addr)
                    if tmp is not None:
                        caller.extend(tmp)
                    while len(caller) > 0:
                        first_caller = caller.pop(0)
                        if (len(callers) == count):
                            return ret
                        if (call_target in callers):
                            return ret
                        count = len(callers)
                        callers.add(first_caller)
                        temp = call_dic.get(first_caller)
                        if temp is not None:
                            caller.extend(temp)

                SyntaxConverter.parse_elf(file, elf, callee_function_name,
                                          call_target, callee_function_size,
                                          section_name, ret, current_func,
                                          call_dic)

            i = i + (length * 4)
            address = address + (length * 2)
        return ret
コード例 #13
0
def process_file(filename):
    # print('Processing file:', filename)

    debug_paths = []
    with open(filename, 'rb') as f:
        elffile = ELFFile(f)

        if not elffile.has_dwarf_info():
            for section in elffile.iter_sections():
                name = bytes2str(section.name)
                # print(name)

                # first try to find ".note.gnu.build-id" in ELF itself
                # uint32 name_size; /* size of the name */
                # uint32 hash_size; /* size of the hash */
                # uint32 identifier; /* NT_GNU_BUILD_ID == 0x3 */
                # char   name[name_size]; /* the name "GNU" */
                # char   hash[hash_size]; /* the hash */
                #
                # objdump -s -j .note.gnu.build-id /usr/bin/openssl
                if name == ".note.gnu.build-id":
                    data = section.data()
                    hash = data[16:]
                    value = binascii.hexlify(hash).decode("ascii")
                    # print(value)
                    # a value of "0834ce567a2d57deed6706e28fa29225cf043e16"
                    # implies that we will have a path which looks like,
                    # /usr/lib/debug/.build-id/08/34ce5...25cf043e16.debug
                    path = os.path.join(value[0:2], value[2:] + ".debug")
                    # print(path)
                    debug_paths.append(path)
                # A filename, with any leading directory components removed,
                # followed by a zero byte, zero to three bytes of padding, as
                # needed to reach the next four-byte boundary within the
                # section, and a four-byte CRC checksum, stored in the same
                # endianness used for the executable file itself.
                #
                # objdump -s -j .gnu_debuglink /usr/bin/openssl
                if name == ".gnu_debuglink":
                    data = section.data()
                    fdata = data[0:data.find(b"\x00")]
                    debug_paths.append(fdata.decode("utf-8"))
        else:
            # this file itself has the DWARF information, must be my lucky day!
            get_producer(filename)

        # get_dwarf_info returns a DWARFInfo context object, which is the
        # starting point for all DWARF-based processing in pyelftools.
        for path in debug_paths:
            # So, for example, suppose you ask gdb to debug /usr/bin/ls, which
            # has a debug link that specifies the file ls.debug, and a build ID
            # whose value in hex is abcdef1234. If the list of the global debug
            # directories includes /usr/lib/debug, then gdb will look for the
            # following debug information files, in the indicated order:
            #
            # /usr/lib/debug/.build-id/ab/cdef1234.debug
            # /usr/bin/ls.debug
            # /usr/bin/.debug/ls.debug
            # /usr/lib/debug/usr/bin/ls.debug.

            rpath = os.path.join("/usr/lib/debug/.build-id", path)
            if os.path.isfile(rpath):
                producer = get_producer(rpath)  # got producer, is one enough?
                if producer:
                    print(producer)
                    continue

            # `cwd` + "/usr/lib/debug/.build-id" is our hack ;)
            debug_prefixes = ["/usr/lib/debug/.build-id/", "/usr/bin/",
                              "/usr/lib/debug/usr/bin/"]

            for prefix in debug_prefixes:
                rpath = os.path.join(prefix, path)
                if os.path.isfile(rpath):
                    get_producer(rpath)
コード例 #14
0
ファイル: relocations.py プロジェクト: fujidori/codebox
import sys
from elftools.elf.elffile import ELFFile
from elftools.elf.relocation import RelocationSection

with open('./chall.elf', 'rb') as f:
    e = ELFFile(f)
    for section in e.iter_sections():
        if isinstance(section, RelocationSection):
            print(f'{section.name}:')
            symbol_table = e.get_section(section['sh_link'])
            for relocation in section.iter_relocations():
                symbol = symbol_table.get_symbol(relocation['r_info_sym'])
                addr = hex(relocation['r_offset'])
                print(f'{symbol.name} {addr}')
コード例 #15
0
#!/usr/bin/env python3

import capstone as cs
from elftools.elf.elffile import ELFFile
import diff_settings
from pathlib import Path
from typing import Any, Dict, Set
import utils

config: Dict[str, Any] = {}
diff_settings.apply(config, {})

base_elf = ELFFile((Path(__file__).parent.parent / config["baseimg"]).open("rb"))
my_elf = ELFFile((Path(__file__).parent.parent / config["myimg"]).open("rb"))
my_symtab = my_elf.get_section_by_name(".symtab")
if not my_symtab:
    utils.fail(f'{config["myimg"]} has no symbol table')


def get_file_offset(elf, addr: int) -> int:
    for seg in elf.iter_segments():
        if seg.header["p_type"] != "PT_LOAD":
            continue
        if seg["p_vaddr"] <= addr < seg["p_vaddr"] + seg["p_filesz"]:
            return addr - seg["p_vaddr"] + seg["p_offset"]
    assert False


def get_symbol_file_offset(elf, table, name: str) -> int:
    syms = table.get_symbol_by_name(name)
    if not syms or len(syms) != 1:
コード例 #16
0
def process_file(dwarf_name, typedes_name):

    try:
        dwarf_file = open(dwarf_name, 'rb')

        if typedes_name:
            typedes_file = open(typedes_name, 'w')
        else:
            typedes_file = sys.stdout
    except IOError:
        print("Error: can't open file.")

    elffile = ELFFile(dwarf_file)

    if not elffile.has_dwarf_info():
        print('Error: File has no DWARF info')
        return 1

    # get_dwarf_info returns a DWARFInfo context object, which is the
    # starting point for all DWARF-based processing in pyelftools.
    dwarfinfo = elffile.get_dwarf_info()

    for CU in dwarfinfo.iter_CUs():
        # DWARFInfo allows to iterate over the compile units contained in
        # the .debug_info section. CU is a CompileUnit object, with some
        # computed attributes (such as its offset in the section) and
        # a header which conforms to the DWARF standard. The access to
        # header elements is, as usual, via item-lookup.
        # print('// Found a compile unit at offset %s, length %s' % (
        # CU.cu_offset, CU['unit_length']))

        # Start with the top DIE, the root for this CU's DIE tree
        top_DIE = CU.get_top_DIE()
        # print('// Top DIE with tag=%s' % top_DIE.tag)

        # Each DIE holds an OrderedDict of attributes, mapping names to
        # values. Values are represented by AttributeValue objects in
        # elftools/dwarf/die.py
        # We're interested in the DW_AT_name attribute. Note that its value
        # is usually a string taken from the .debug_string section. This
        # is done transparently by the library, and such a value will be
        # simply given as a string.
        name_attr = top_DIE.attributes['DW_AT_name']

        # Only C supported! C++ is more complex and currently not supported
        if die_get_attr_val(top_DIE,
                            'DW_AT_language') not in [DW_LANG_C, DW_LANG_C89]:

            continue

        typedes_file.write('file %s\n' % bytes2str(name_attr.value))

        # if name_attr != 'sbo/com_so/elf.c':
        #     continue

        die_build_refs(top_DIE, {})

        # die_order_children(top_DIE)

        # Display DIEs recursively starting with top_DIE
        die_info_rec(dwarfinfo,
                     typedes_file,
                     top_DIE,
                     False,
                     print_pointers=False)

        die_del_dict_rec(top_DIE)

    return 0
コード例 #17
0
 def __init__(self, filename):
     self.filename = filename
     with open(self.filename, 'rb') as f:
         self.elffile = ELFFile(f)
コード例 #18
0
    def config_from_elf(self, path):
        """Load all the necessary information about the program parsing the ELF
        headers. Furthermore, check some pre-requisites for the exploit to be
        successful."""
        executable_file = open(path, "r")
        elf = ELFFile(executable_file)
        get_section = lambda name: first_or_none(
            filter(lambda section: section.name == name, elf.iter_sections()))
        get_section_address = lambda section: None if (get_section(
            section) is None) else get_section(section).header.sh_addr

        # Checks
        if elf.header.e_type == ENUM_E_TYPE["ET_EXEC"]:
            raise Exception("Only non-PIE executables are supported")

        # Binary type
        self.arch = elf.header.e_machine
        self.little = elf.little_endian
        self.pointer_size = elf.elfclass / 8
        self.pointer_format = ("0x%." + str(self.pointer_size * 2) + "x")
        self.structs = elftools.elf.structs.ELFStructs(self.little,
                                                       self.pointer_size * 8)

        # Useful sections
        self.sections = {
            section.name: (section.header.sh_addr,
                           section.header.sh_addr + section.header.sh_size)
            for section in elf.iter_sections()
        }
        self.plt = get_section_address(".plt")
        self.got = get_section_address(".got")
        self.gotplt = get_section_address(".got.plt")

        # Dynamic section
        dynamic_section = get_section(".dynamic")
        self.writable_dynamic = dynamic_section.header.sh_flags & SH_FLAGS.SHF_WRITE
        self.dynamic = dynamic_section.header.sh_addr
        dynamic_entries = [
            self.structs.Elf_Dyn.parse(dynamic_entry)
            for dynamic_entry in chunks(dynamic_section.data(),
                                        self.structs.Elf_Dyn.sizeof())
        ]

        # Dynamic symbols
        # TODO: we're relying on section names here
        symbol_table = elf.get_section_by_name(".dynsym")
        has_name = lambda name: lambda symbol: symbol.name == name
        attribute_or_default = lambda default, attribute, x: getattr(
            x, attribute) if x is not None else default
        memcpy_symbol = first_or_none(
            filter(has_name("memcpy"), symbol_table.iter_symbols()))
        self.memcpy_plt = 0 if memcpy_symbol is None else memcpy_symbol.entry.st_value

        # We try not to rely on section names
        get_dynamic = lambda name: first_or_none(
            map(lambda entry: entry.d_val,
                filter(lambda entry: entry.d_tag == name, dynamic_entries)))
        get_dynamic_index = lambda name: filter(
            lambda entry: entry[1].d_tag == name, enumerate(dynamic_entries))[
                0][0]
        self.dynstr = get_dynamic("DT_STRTAB")
        self.dynsym = get_dynamic("DT_SYMTAB")
        self.versym = get_dynamic("DT_VERSYM")
        self.verneed = get_dynamic("DT_VERNEED")
        self.relplt = get_dynamic("DT_JMPREL")
        self.addend = get_dynamic("DT_RELA") is not None
        self.dt_debug = self.dynamic + get_dynamic_index(
            "DT_DEBUG") * self.structs.Elf_Dyn.sizeof() + self.pointer_size
        self.full_relro = (get_dynamic("DT_FLAGS") is not None) and \
                          ((get_dynamic("DT_FLAGS") & DF_BIND_NOW) != 0)
        self.full_relro = self.full_relro or ((get_dynamic("DT_FLAGS_1") is not None) and \
                          ((get_dynamic("DT_FLAGS_1") & DF_1_NOW) != 0))

        # Choose between Elf_Rel and Elf_Rela depending on the architecture
        self.rel_struct = self.structs.Elf_Rela if self.addend else self.structs.Elf_Rel

        # Looks like 64-bit and 32-bit have different alignment for the call to _dl_fixup
        self.reloc_alignment = 1 if self.pointer_size == 4 else self.rel_struct.sizeof(
        )
        self.reloc_index_multiplier = self.rel_struct.sizeof(
        ) if self.pointer_size == 4 else 1

        #
        # Find candidate writeable areas
        #

        # Collect PT_LOAD segments (what gets mapped)
        loaded_segments = filter(
            lambda segment: segment.header.p_type == "PT_LOAD",
            elf.iter_segments())
        # Collect the segments which are writeable
        writeable_segments = filter(
            lambda segment: segment.header.p_flags & P_FLAGS.PF_W,
            loaded_segments)
        # Get their memory ranges (start, end)
        writeable_ranges = RangeSet.mutual_union(*map(
            lambda segment: (segment.header.p_vaddr, segment.header.p_vaddr +
                             segment.header.p_memsz), writeable_segments))

        # List of sections we don't want to write to
        dont_overwrite_sections = filter_none([
            self.dynstr, self.dynsym, self.versym, self.relplt, self.dynamic,
            self.got, self.gotplt
        ])
        # Memory ranges of the sections we don't want to write to
        dont_overwrite_ranges = RangeSet.mutual_union(*[
            self.sections[self.section_from_address(start)]
            for start in dont_overwrite_sections
        ])

        # Handle RELRO segment, we don't want to write there
        relro_segment = first_or_none(
            filter(lambda segment: segment.header.p_type == "PT_GNU_RELRO",
                   elf.iter_segments()))
        if relro_segment is not None:
            dont_overwrite_ranges = dont_overwrite_ranges | RangeSet(
                relro_segment.header.p_vaddr,
                relro_segment.header.p_vaddr + relro_segment.header.p_memsz)

        # Compute the set of candidate memory ranges
        self.writeable_ranges = writeable_ranges - dont_overwrite_ranges

        # Save the index of the DT_FINI entry
        fini = filter(lambda (i, entry): entry.d_tag == "DT_FINI",
                      enumerate(dynamic_entries))
        if len(fini) > 0:
            self.fini = self.dynamic + self.structs.Elf_Dyn.sizeof(
            ) * fini[0][0]

        # Gadgets
        if self.gadgets.has_key(self.arch):
            executable_segments = filter(
                lambda segment: segment.header.p_flags & P_FLAGS.PF_X,
                elf.iter_segments())

            for name, (info, gadget) in self.gadgets[self.arch].iteritems():
                locations = find_all_strings(executable_segments,
                                             hex_bytes(gadget))
                locations = map(self.ptr2str, locations)
                location = first_or_none(
                    filter(
                        lambda address: not reduce(
                            lambda accumulate, badchar: badchar in address or
                            accumulate, self.badchars, False), locations))
                if location is None:
                    self.gadgets[self.arch][name] = None
                else:
                    self.gadgets[self.arch][name] = (info, gadget, location)

        # Find all '\x00\x00' in non-writeable segments
        self.non_writeable_segments = filter(
            lambda segment: not (segment.header.p_flags & P_FLAGS.PF_W),
            loaded_segments)
        self.zero_or_one_addresses = find_all_strings(self.non_writeable_segments, "\x00\x00") + \
                                     find_all_strings(self.non_writeable_segments, "\x01\x00" if self.little else "\x00\x01")

        self.filler = self.ptr2str(
            reduce(lambda x, y: (x << 32) | 0xdeadb00b,
                   xrange(1 + (self.pointer_size % 4)), 0))
        self.relocation_type = relocation_types[self.arch]

        #
        # Find the reloc pointing to the symbol whose name is the earliest in .dynstr
        #

        relplt_section = elf.get_section_by_name(
            self.section_from_address(self.relplt))
        dynsym_section = elf.get_section_by_name(
            self.section_from_address(self.dynsym))

        if not (isinstance(relplt_section, RelocationSection) and \
                isinstance(dynsym_section, SymbolTableSection)):
            raise Exception("Unexpect type for dynamic sections: " +
                            str(relplt_section) + " " + str(dynsym_section))

        # Grab .got.plt relocs symbol indexes
        symbol_indexes = [
            reloc.entry.r_info_sym
            if reloc.entry.r_info_type == self.relocation_type else None
            for reloc in relplt_section.iter_relocations()
        ]
        # Get offsets in .dynstr
        names_offsets = [
            dynsym_section.get_symbol(index).entry.st_name
            if index is not None else None for index in symbol_indexes
        ]
        # Filter out unamed offsets
        names_offsets = [
            offset if offset > 0 else None for offset in names_offsets
        ]
        # Get the minimum value
        self.min_reloc_index, self.min_string_offset = min(
            enumerate(names_offsets), key=operator.itemgetter(1))
        self.min_symbol_index = symbol_indexes[self.min_reloc_index]

        log(self.dump())
コード例 #19
0
 def __init__(self, file, verbose=False):
     self.elffile = ELFFile(file)
     self._versioninfo = None
     self.data = {}
     self.data["arch"] = self.elffile.elfclass
     self._verbose = verbose
コード例 #20
0
 def open(self):
     self.fd = open(self.elffile, "rb")
     self.elf = ELFFile(self.fd)
コード例 #21
0
 def loadElf(self,
             elfStream,
             parameters="",
             stackSize=100000,
             maxResponseSize=4096,
             continuation=None,
             signature=None):
     if parameters == None:
         parameters = ""
     elffile = ELFFile(elfStream)
     # Locate signature if not passed
     if signature == None:
         for section in elffile.iter_sections():
             if section.name == '.ledger':
                 signature = section.data()[0:ord(section.data()[1]) + 2]
                 break
     if signature == None:
         raise Exception("Missing code signature")
     # Allocate session
     allocateSize = stackSize
     for segment in elffile.iter_segments():
         if segment['p_type'] == 'PT_LOAD':
             allocateSize = allocateSize + segment['p_memsz']
     cmd = struct.pack(">H", self.CMD_CODE_INIT)
     cmd = cmd + struct.pack(">I", allocateSize)
     response = self.link.exchange(cmd)
     if response[0] != self.STATUS_CODE_EXEC_OK:
         raise Exception("Unexpected status on CODE_INIT %.2x" %
                         response[0])
     # Load each component
     for segment in elffile.iter_segments():
         if segment['p_type'] == 'PT_LOAD':
             flags = 0
             if ((segment['p_flags'] & P_FLAGS.PF_W) == 0):
                 flags = flags | self.MSG_LOAD_SECTION_FLAG_READ_ONLY
             cmd = struct.pack(">H", self.CMD_CODE_LOAD_SECTION)
             cmd = cmd + chr(flags)
             cmd = cmd + struct.pack(">I", segment['p_vaddr'])
             cmd = cmd + struct.pack(
                 ">I", segment['p_vaddr'] + segment['p_memsz'])
             cmd = cmd + struct.pack(">I", segment['p_filesz'])
             cmd = cmd + segment.data()
             response = self.link.exchange(cmd)
             if response[0] != self.STATUS_CODE_EXEC_OK:
                 raise Exception(
                     "Unexpected status on CODE_LOAD_SECTION %.2x" %
                     response[0])
     # Run or resume
     if continuation == None:
         cmd = struct.pack(">H", self.CMD_CODE_RUN)
         cmd = cmd + struct.pack(">I", elffile.header['e_entry'])
         cmd = cmd + struct.pack(">I", stackSize)
         cmd = cmd + struct.pack(">I", 0)
         cmd = cmd + struct.pack(">I", len(parameters))
         cmd = cmd + struct.pack(">I", len(signature))
         cmd = cmd + str(parameters)
         cmd = cmd + signature
     else:
         cmd = struct.pack(">H", self.CMD_CODE_RESUME)
         cmd = cmd + struct.pack(">I", continuation['slot'])
         cmd = cmd + struct.pack(">I", len(continuation['blob']))
         cmd = cmd + struct.pack(">I", 0)
         cmd = cmd + struct.pack(">I", len(parameters))
         cmd = cmd + str(continuation['blob'])
         cmd = cmd + str(parameters)
     response = self.link.exchange(cmd, maxResponseSize)
     result = {}
     if response[0] == self.STATUS_CODE_EXEC_OK:
         result['suspended'] = False
         result['response'] = response[1:]
     elif response[0] == self.STATUS_CODE_EXEC_SUSPENDED:
         result['suspended'] = True
         slot, blobSize, appDataSize = struct.unpack(
             ">III", str(response[1:1 + 12]))
         result['slot'] = slot
         result['blob'] = response[1 + 12:1 + 12 + blobSize]
         result['response'] = response[1 + 12 + blobSize:1 + 12 + blobSize +
                                       appDataSize]
     else:
         raise Exception("Application error reported %.2x" % response[0])
     return result
コード例 #22
0
def ParseElfFile(elfFileArg):
    FileName = elfFileArg
    with open(FileName, 'rb') as f:
        e = ELFFile(f)
        TextPhysicalAddress = 0
        APPSize = 0
        EntryPoint = e['e_entry']
        DataPhysicalAddress = 0
        DataSize = 0

        print('Entry point = ' + hex(e['e_entry']))

        for i in range(int(e.num_segments())):
            segment = e.get_segment(i)
            physicalAddress = hex(segment.header['p_paddr'])
            offest = hex(segment.header['p_offset'])
            size = hex(segment.header['p_filesz'])
            APPSize += segment.header['p_filesz']

            name = ''
            if i == 0:
                name = '.text'
                TextPhysicalAddress = segment.header['p_paddr']
            elif i == 1:
                name = '.data'
                DataPhysicalAddress = segment.header['p_paddr']
                DataSize = segment.header['p_filesz']
            elif i == 2:
                name = '.bss'

            print('Section name = ' + name)
            print('Section physical address = ' + physicalAddress)
            print('Section offest = ' + offest)
            print('Section size = ' + size + '\n')

        # the text section
        #textSec = e.get_section_by_name('.text')
        textSec = e.get_segment(0)
        textval = textSec.data()

        #data section
        datasec = e.get_segment(1)
        dataval = datasec.data()

        file = open('TEXT_FILE.txt', 'wb')
        file.write(textval)
        file.close

        file = open('DATA_FILE.txt', 'wb')
        file.write(dataval)
        file.close

        print("EntryPoint = " + hex(EntryPoint))
        print("APPSize = " + hex(APPSize))
        print("TextPhysicalAddress = " + hex(TextPhysicalAddress))
        print("DataPhysicalAddress = " + hex(DataPhysicalAddress))
        print("DataSize = " + hex(DataSize))

        file = open('INFO_FILE.txt', 'wb')
        file.write(int_to_bytes(TextPhysicalAddress))
        file.write(int_to_bytes(APPSize))
        file.write(int_to_bytes(EntryPoint))
        file.write(int_to_bytes(DataPhysicalAddress))
        file.write(int_to_bytes(DataSize))
        file.close
コード例 #23
0
from elftools.elf.sections import SymbolTableSection
from pandare import Panda, blocking, ffi

# Single arg of arch, defaults to i386
arch = "i386" if len(argv) <= 1 else argv[1]
panda = Panda(generic=arch)

bin_dir = "taint"
bin_name = "taint"

out = []
mappings = {}

# Read symbols from bin into mappings
with open(path.join(bin_dir, bin_name), 'rb') as f:
    our_elf = ELFFile(f)
    for section in our_elf.iter_sections():
        if not isinstance(section, SymbolTableSection): continue
        for symbol in section.iter_symbols():
            if len(symbol.name):  # Sometimes empty
                mappings[symbol['st_value']] = symbol.name

tainted = False
g_phys_addrs = []


@panda.cb_before_block_exec_invalidate_opt(procname=bin_name)
def taint_it(cpu, tb):
    if tb.pc in mappings and mappings[tb.pc] == "apply_taint":
        global tainted
        if not tainted:
コード例 #24
0
 def set_elf(self, filename):
     self.elf_file = ELFFile(open(filename))
コード例 #25
0
from elftools.elf.constants import P_FLAGS
from elftools.elf.elffile import ELFFile
from elftools.elf.sections import SymbolTableSection
from unicorn import Uc, UC_ARCH_ARM, UC_MODE_LITTLE_ENDIAN, UC_PROT_WRITE, UC_PROT_READ, UC_PROT_EXEC, UC_HOOK_CODE, \
    UC_HOOK_MEM_READ, UC_HOOK_MEM_WRITE, UC_MEM_WRITE, UC_MEM_READ
from unicorn.arm_const import *
from capstone import Cs, CS_ARCH_ARM, CS_MODE_THUMB, CsInsn
from keystone import Ks, KS_MODE_THUMB, KS_ARCH_ARM, KS_MODE_ARM
import struct
import json

# 加载so文件
filename = "./libnative-lib.so"
fd = open(filename, 'r+b')
elf = ELFFile(fd)


def align(addr, size, align):
    fr_addr = addr // align * align
    to_addr = (addr + size + align - 1) // align * align
    return fr_addr, to_addr - fr_addr


def pflags2prot(p_flags):
    ret = 0
    if p_flags & P_FLAGS.PF_R != 0:
        ret |= UC_PROT_READ
    if p_flags & P_FLAGS.PF_W != 0:
        ret |= UC_PROT_WRITE
    if p_flags & P_FLAGS.PF_X != 0:
        ret |= UC_PROT_EXEC
コード例 #26
0
    def parseImage(self):

        # basic stats
        self._SizeBytes = os.path.getsize(self._Path)

        # open
        self._Handle = open(self._Path, 'rb')
        self._Elf = ELFFile(self._Handle)

        # executable
        if self._Elf['e_type'] == 'ET_EXEC':
            self._IsExecutable = True

        # header string table
        hdstrtbl = None
        cnt = 0
        for sec in self._Elf.iter_sections():
            if (sec['sh_type'] == 'SHT_STRTAB') and (self._Elf['e_shstrndx']
                                                     == cnt):
                hdstrtbl = sec
                break
            cnt += 1
        if hdstrtbl is None:
            raise Exception("[ERROR] Could not find header string table!")

        # register segments
        for seg in self._Elf.iter_segments():
            self._Segments.append(seg)

        # register sections
        for sec in self._Elf.iter_sections():
            curname = hdstrtbl.get_string(sec['sh_name'])
            if (sec['sh_addr'] != 0):
                cursec = SectionInfo()
                cursec._Name = curname
                cursec._Addr = sec['sh_addr']
                cursec._Size = sec['sh_size']
                cursec._Obj = sec
                self._Sections[cursec._Addr] = cursec

        # special sections
        secnames = []
        for sec in self._Elf.iter_sections():
            if sec['sh_size'] > 0:
                secnames.append(hdstrtbl.get_string(sec['sh_name']))
        if ('.text' not in secnames):
            raise Exception("[ERROR] No text section found!")
        if (('.symtab' not in secnames) and ('.dynsym' not in secnames)):
            raise Exception("[ERROR] No symbol table found!")
        if (('.strtab' not in secnames) and ('.dynstr' not in secnames)):
            raise Exception("[ERROR] No string table found!")
        usedebugtables = (('.symtab' in secnames) and ('.strtab' in secnames))

        # register special sections
        for sec in self._Elf.iter_sections():
            if sec['sh_size'] > 0:
                cursec = SectionInfo()
                cursec._Name = hdstrtbl.get_string(sec['sh_name'])
                cursec._Addr = sec['sh_addr']
                cursec._Size = sec['sh_size']
                cursec._Obj = sec
                if cursec._Name == '.text':
                    self._TextSection = cursec
                elif cursec._Name == '.plt':
                    self._PLTSection = cursec
                elif (cursec._Name == '.symtab') and usedebugtables:
                    self._SymbolTable = cursec
                elif (cursec._Name == '.strtab') and usedebugtables:
                    self._StringTable = cursec
                elif (cursec._Name == '.dynsym') and not usedebugtables:
                    self._SymbolTable = cursec
                elif (cursec._Name == '.dynstr') and not usedebugtables:
                    self._StringTable = cursec

        # sanity check
        if (self._TextSection is None):
            raise Exception("[ERROR] Could not assign text section!")
        if (self._PLTSection is None):
            raise Exception("[ERROR] Could not assign plt section!")
        if (self._SymbolTable is None):
            raise Exception("[ERROR] Could not assign symbol table!")
        if (self._StringTable is None):
            raise Exception("[ERROR] Could not assign string table!")

        # parse strings
        binstr = self._StringTable._Obj.data()
        binstrdec = binstr.decode()
        curstart = 0
        for cmatch in re.finditer('\x00', binstrdec):
            curstr = binstr[curstart:cmatch.start()].decode("utf-8")
            if curstr != "":
                self._Strings[curstart] = curstr
            curstart = cmatch.start() + 1
        self._Strings[0] = ''

        # register symbols
        for symb in self._SymbolTable._Obj.iter_symbols():
            if (symb['st_value'] != 0) and \
               (symb['st_info']['type'] != 'STT_SECTION') and \
               (symb['st_info']['type'] != 'STT_FILE') and \
               (symb['st_info']['type'] != 'STT_NOTYPE') and \
               (symb['st_info']['bind'] != 'STB_LOCAL'):

                # new symbol
                cursymb = SymbolInfo()
                cursymb._Name = symb.name
                cursymb._Addr = symb['st_value']
                cursymb._Size = symb['st_size']
                cursymb._Type = symb['st_info']['type']
                cursymb._Obj = symb

                # fix name
                if cursymb._Name == '':
                    cursymb._Name = '0x%08x' % cursymb._Addr

                # safe add
                if cursymb._Addr in self._Symbols.keys():
                    if sys.stdout.isatty():
                        print ("[INFO] Symbols with same start addr: new=%s and old=%s" \
                               % (cursymb._Name, self._Symbols[cursymb._Addr]._Name))
                    if cursymb._Size == self._Symbols[cursymb._Addr]._Size:
                        self._Symbols[cursymb._Addr]._Name += ("+%s" %
                                                               cursymb._Name)
                    elif cursymb._Size > self._Symbols[cursymb._Addr]._Size:
                        cursymb._Name += ("+%s(len=%d)" % \
                                          (self._Symbols[cursymb._Addr]._Name, \
                                           self._Symbols[cursymb._Addr]._Size))
                        self._Symbols[cursymb._Addr] = cursymb
                    elif cursymb._Size < self._Symbols[cursymb._Addr]._Size:
                        self._Symbols[cursymb._Addr]._Name += ("+%s(len=%d)" % \
                                                               (cursymb._Name, \
                                                                cursymb._Size))
                else:
                    self._Symbols[cursymb._Addr] = cursymb

        # prune overlay functions
        ksort = sorted(self._Symbols.keys())
        krem = []
        for i in range(0, len(ksort) - 1):
            if ((self._Symbols[ksort[i]]._Addr + self._Symbols[ksort[i]]._Size) > \
                self._Symbols[ksort[i+1]]._Addr) and \
               ((self._Symbols[ksort[i]]._Addr + self._Symbols[ksort[i]]._Size) == \
                (self._Symbols[ksort[i+1]]._Addr + self._Symbols[ksort[i+1]]._Size)):
                krem.append((ksort[i], ksort[i + 1]))
        for k in krem:
            if sys.stdout.isatty():
                print("[INFO] Pruning overlay function %s." %
                      self._Symbols[k[1]]._Name)
            self._Symbols[k[0]]._Name += ("+%s(%d)" % \
                                          (self._Symbols[k[1]]._Name, k[1]-k[0]))
            self._Symbols.pop(k[1])

        # fast access
        self._SectionsFast = numpy.zeros(len(self._Sections), \
                                         dtype=numpy.dtype([('Start', numpy.uintp, 1), \
                                                            ('Size', numpy.uintp, 1)]))
        ksort = sorted(self._Sections.keys())
        for i in range(0, len(self._Sections)):
            self._SectionsFast[i]['Start'] = self._Sections[ksort[i]]._Addr
            self._SectionsFast[i]['Size'] = self._Sections[ksort[i]]._Size
        self._SymbolsFast = numpy.zeros(len(self._Symbols), \
                                        dtype=numpy.dtype([('Start', numpy.uintp, 1), \
                                                           ('Size', numpy.uintp, 1)]))
        ksort = sorted(self._Symbols.keys())
        for i in range(0, len(self._Symbols)):
            self._SymbolsFast[i]['Start'] = self._Symbols[ksort[i]]._Addr
            self._SymbolsFast[i]['Size'] = self._Symbols[ksort[i]]._Size

        # consistency check
        for i in range(0, len(self._SectionsFast) - 1):
            if self._SectionsFast[i]['Start'] + self._SectionsFast[i]['Size'] > \
               self._SectionsFast[i+1]['Start']:
                raise Exception('[ERROR] Inconsistent section placement!')
        for i in range(0, len(self._SymbolsFast) - 1):
            if self._SymbolsFast[i]['Start'] + self._SymbolsFast[i]['Size'] > \
               self._SymbolsFast[i+1]['Start']:
                raise Exception('[ERROR] Inconsistent symbol placement: %s -> %s!' % \
                                (self._Symbols[self._SymbolsFast[i]['Start']]._Name, \
                                 self._Symbols[self._SymbolsFast[i+1]['Start']]._Name))

        # set up disassembler
        if 'x64' in self._Elf.get_machine_arch().lower():
            md = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_64)
        elif 'x86' in self._Elf.get_machine_arch().lower():
            md = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_32)
        elif 'arm' in self._Elf.get_machine_arch().lower():
            md = capstone.Cs(capstone.CS_ARCH_ARM, capstone.CS_MODE_ARM)
        elif 'aarch64' in self._Elf.get_machine_arch().lower():
            md = capstone.Cs(capstone.CS_ARCH_ARM64, capstone.CS_MODE_ARM + \
                             capstone.CS_MODE_V8)
        else:
            raise Exception(
                "[ERROR] Image architecture currently not supported!")
        md.skipdata = True

        # parse .text section
        instructions = md.disasm_lite(self._TextSection._Obj.data(), \
                                      self._TextSection._Addr)
        for (address, size, mnemonic, op_str) in instructions:
            self._TextInstructions[address] = (size,
                                               "%s\t%s" % (mnemonic, op_str))

        # parse .plt instructions
        instructions = md.disasm_lite(self._PLTSection._Obj.data(), \
                                      self._PLTSection._Addr)
        for (address, size, mnemonic, op_str) in instructions:
            self._PLTInstructions[address] = (size,
                                              "%s\t%s" % (mnemonic, op_str))
コード例 #27
0
 def __init__(self, ql: Qiling, elf_stream):
     self.ql = ql
     self.elffile = ELFFile(elf_stream)
     self._versioninfo = None
コード例 #28
0
def main():
    """Main function of database generator"""
    args = parse_args()

    # Setup logging
    logging.basicConfig(format=LOGGER_FORMAT, level=logging.WARNING)
    if args.debug:
        logger.setLevel(logging.DEBUG)
    elif args.verbose:
        logger.setLevel(logging.INFO)

    elffile = open(args.elffile, "rb")
    if not elffile:
        logger.error("ERROR: Cannot open ELF file: %s, exiting...",
                     args.elffile)
        sys.exit(1)

    logger.info("ELF file %s", args.elffile)

    if args.json:
        logger.info("JSON Database file %s", args.json)
        section_extraction = True

    if args.syst:
        logger.info("MIPI Sys-T Collateral file %s", args.syst)
        section_extraction = False

    elf = ELFFile(elffile)

    database = LogDatabase()

    if args.build_header:
        with open(args.build_header) as f:
            for l in f:
                match = re.match(r'\s*#define\s+BUILD_VERSION\s+(.*)', l)
                if match:
                    database.set_build_id(match.group(1))
                    break

    if args.build:
        database.set_build_id(args.build)
        logger.info("Build ID: %s", args.build)

    extract_elf_information(elf, database)

    process_kconfigs(elf, database)

    logger.info("Target: %s, %d-bit", database.get_arch(),
                database.get_tgt_bits())
    if database.is_tgt_little_endian():
        logger.info("Endianness: Little")
    else:
        logger.info("Endianness: Big")

    if database.is_tgt_64bit():
        global PTR_FMT
        PTR_FMT = '0x%016x'

    # Extract strings from ELF files
    string_mappings = extract_static_strings(elf, database, section_extraction)
    if len(string_mappings) > 0:
        database.set_string_mappings(string_mappings)
        logger.info("Found %d strings", len(string_mappings))

    # Extract information related to logging subsystem
    if not section_extraction:
        # The logging subsys information (e.g. log module names)
        # may require additional strings outside of those extracted
        # via ELF DWARF variables. So generate a new string mappings
        # with strings in various ELF sections.
        string_mappings = extract_static_strings(elf,
                                                 database,
                                                 section_extraction=True)

    extract_logging_subsys_information(elf, database, string_mappings)

    # Write database file
    if args.json:
        if not LogDatabase.write_json_database(args.json, database):
            logger.error(
                "ERROR: Cannot open database file for write: %s, exiting...",
                args.json)
            sys.exit(1)

    if args.syst:
        if not LogDatabase.write_syst_database(args.syst, database):
            logger.error(
                "ERROR: Cannot open database file for write: %s, exiting...",
                args.syst)
            sys.exit(1)

    elffile.close()
コード例 #29
0
def main():
    """Main function"""
    global args
    parse_args()

    if not os.path.exists(args.kernel):
        error("{0} does not exist.".format(args.kernel))

    elf_fd = open(args.kernel, "rb")

    # Create a modifiable byte stream
    raw_elf = elf_fd.read()
    output = create_string_buffer(raw_elf)

    elf = ELFFile(elf_fd)

    if not elf.has_dwarf_info():
        error("ELF file has no DWARF information")

    if elf.num_segments() == 0:
        error("ELF file has no program header table")

    syms = extract_all_symbols_from_elf(elf)

    vm_base = syms["CONFIG_KERNEL_VM_BASE"]
    vm_size = syms["CONFIG_KERNEL_VM_SIZE"]

    sram_base = syms["CONFIG_SRAM_BASE_ADDRESS"]
    sram_size = syms["CONFIG_SRAM_SIZE"] * 1024

    vm_offset = syms["CONFIG_KERNEL_VM_OFFSET"]
    sram_offset = syms.get("CONFIG_SRAM_OFFSET", 0)

    #
    # Calculate virtual-to-physical address translation
    #
    virt_to_phys_offset = (sram_base + sram_offset) - (vm_base + vm_offset)

    log("Virtual address space: 0x%x - 0x%x size 0x%x (offset 0x%x)" %
        (vm_base, vm_base + vm_size, vm_size, vm_offset))
    log("Physical address space: 0x%x - 0x%x size 0x%x (offset 0x%x)" %
        (sram_base, sram_base + sram_size, sram_size, sram_offset))

    #
    # Update the entry address in header
    #
    if elf.elfclass == 32:
        load_entry_type = "I"
    else:
        load_entry_type = "Q"

    entry_virt = struct.unpack_from(load_entry_type, output,
                                    ELF_HDR_ENTRY_OFFSET)[0]
    entry_phys = entry_virt + virt_to_phys_offset
    struct.pack_into(load_entry_type, output, ELF_HDR_ENTRY_OFFSET, entry_phys)

    log("Entry Address: 0x%x -> 0x%x" % (entry_virt, entry_phys))

    #
    # Update load address in program header segments
    #

    # Program header segment offset from beginning of file
    ph_off = elf.header['e_phoff']

    # ph_seg_type: segment type and other fields before virtual address
    # ph_seg_addr: virtual and phyiscal addresses
    # ph_seg_whole: whole segment
    if elf.elfclass == 32:
        ph_seg_type = "II"
        ph_seg_addr = "II"
        ph_seg_whole = "IIIIIIII"
    else:
        ph_seg_type = "IIQ"
        ph_seg_addr = "QQ"
        ph_seg_whole = "IIQQQQQQ"

    # Go through all segments
    for ph_idx in range(elf.num_segments()):
        seg_off = ph_off + struct.calcsize(ph_seg_whole) * ph_idx

        seg_type, _ = struct.unpack_from(ph_seg_type, output, seg_off)

        # Only process LOAD segments
        if seg_type != 0x01:
            continue

        # Add offset to get to the addresses
        addr_off = seg_off + struct.calcsize(ph_seg_type)

        # Grab virtual and physical addresses
        seg_vaddr, seg_paddr = struct.unpack_from(ph_seg_addr, output,
                                                  addr_off)

        # Apply virt-to-phys offset so it will load into
        # physical address
        seg_paddr_new = seg_vaddr + virt_to_phys_offset

        log("Segment %d: physical address 0x%x -> 0x%x" %
            (ph_idx, seg_paddr, seg_paddr_new))

        # Put the addresses back
        struct.pack_into(ph_seg_addr, output, addr_off, seg_vaddr,
                         seg_paddr_new)

    out_fd = open(args.output, "wb")
    out_fd.write(output)
    out_fd.close()

    elf_fd.close()
コード例 #30
0
#!/usr/bin/env python

import usb.core
import usb.util
import time, struct

from hidapi import hidapi
import ctypes

from elftools.elf.elffile import ELFFile

pid_runtime = 0x6080
pid_bootloader = 0x6084

e = ELFFile(open('arcin.elf'))

firmware = ''

for segment in sorted(e.iter_segments(), key=lambda x: x.header.p_paddr):
    if segment.header.p_type != 'PT_LOAD':
        continue

    data = segment.data()
    lma = segment.header.p_paddr

    # Workaround for LD aligning segments to a larger boundary than 8k.
    if lma == 0x8000000:
        lma += 0x2000
        data = data[0x2000:]

    # Add padding if necessary.