Ejemplo n.º 1
0
def DecodeElf(data, location):
    """Decode an ELF file and return information about it

    Args:
        data: Data from ELF file
        location: Start address of data to return

    Returns:
        ElfInfo object containing information about the decoded ELF file
    """
    file_size = len(data)
    with io.BytesIO(data) as fd:
        elf = ELFFile(fd)
        data_start = 0xffffffff
        data_end = 0
        mem_end = 0
        virt_to_phys = 0

        for i in range(elf.num_segments()):
            segment = elf.get_segment(i)
            if segment['p_type'] != 'PT_LOAD' or not segment['p_memsz']:
                skipped = 1  # To make code-coverage see this line
                continue
            start = segment['p_paddr']
            mend = start + segment['p_memsz']
            rend = start + segment['p_filesz']
            data_start = min(data_start, start)
            data_end = max(data_end, rend)
            mem_end = max(mem_end, mend)
            if not virt_to_phys:
                virt_to_phys = segment['p_paddr'] - segment['p_vaddr']

        output = bytearray(data_end - data_start)
        for i in range(elf.num_segments()):
            segment = elf.get_segment(i)
            if segment['p_type'] != 'PT_LOAD' or not segment['p_memsz']:
                skipped = 1  # To make code-coverage see this line
                continue
            start = segment['p_paddr']
            offset = 0
            if start < location:
                offset = location - start
                start = location
            # A legal ELF file can have a program header with non-zero length
            # but zero-length file size and a non-zero offset which, added
            # together, are greater than input->size (i.e. the total file size).
            #  So we need to not even test in the case that p_filesz is zero.
            # Note: All of this code is commented out since we don't have a test
            # case for it.
            size = segment['p_filesz']
            #if not size:
            #continue
            #end = segment['p_offset'] + segment['p_filesz']
            #if end > file_size:
            #raise ValueError('Underflow copying out the segment. File has %#x bytes left, segment end is %#x\n',
            #file_size, end)
            output[start - data_start:start - data_start +
                   size] = (segment.data()[offset:])
    return ElfInfo(output, data_start, elf.header['e_entry'] + virt_to_phys,
                   mem_end - data_start)
Ejemplo n.º 2
0
def openCoreDump(filename):
    f = open(filename, "rb")
    elf = ELFFile(f)
    try:
        # assert that we can process the file
        assert elf.elfclass == 64, "elfclass == {}; only elfclass 64 is supported".format(
            elf.elfclass)
        assert elf.header[
            "e_machine"] == "EM_X86_64", "e_machine == {}; only e_machine EM_X86_64 is supported".format(
                elf.header["e_machine"])
        assert elf.header[
            "e_type"] == "ET_CORE", "e_type == {}; only e_type ET_CORE is supported".format(
                elf.header['e_type'])
        assert elf.header["e_ident"][
            "EI_OSABI"] == "ELFOSABI_FREEBSD", "ei_osabi == {}; only ei_osabi ELFOSABI_FREEBSD is supported".format(
                elf.header["e_ident"]["EI_OSABI"])
    except Exception as e:
        # in case of exception, skip to the next file
        print("Exception for {}".format(elf.stream.name))
        print(e)
        f.close()
        return None
    else:
        # get elf segments
        # check that we have a note segment
        elf.notes = None
        if isinstance(elf.get_segment(0), NoteSegment):
            elf.notes = elf.get_segment(0)
        return elf
Ejemplo n.º 3
0
def read_segments(filename):
    elffile = ELFFile(open(filename, 'rb'))
    segments = list()
    for segment_idx in range(elffile.num_segments()):
        segments.insert(segment_idx, dict())
        segments[segment_idx]['segment'] = elffile.get_segment(segment_idx)
    return segments
Ejemplo n.º 4
0
def read_segments(data):
    """Read segments from an ELF file

    Args:
        data (bytes): Contents of file

    Returns:
        tuple:
            list of segments, each:
                int: Segment number (0 = first)
                int: Start address of segment in memory
                bytes: Contents of segment
            int: entry address for image

    Raises:
        ValueError: elftools is not available
    """
    if not ELF_TOOLS:
        raise ValueError('Python elftools package is not available')
    with io.BytesIO(data) as inf:
        try:
            elf = ELFFile(inf)
        except ELFError as err:
            raise ValueError(err)
        entry = elf.header['e_entry']
        segments = []
        for i in range(elf.num_segments()):
            segment = elf.get_segment(i)
            if segment['p_type'] != 'PT_LOAD' or not segment['p_memsz']:
                skipped = 1  # To make code-coverage see this line
                continue
            start = segment['p_offset']
            rend = start + segment['p_filesz']
            segments.append((i, segment['p_paddr'], data[start:rend]))
    return segments, entry
Ejemplo n.º 5
0
def elfheader():
    """
    Prints the section mappings contained in the ELF header.
    """
    local_path = pwndbg.file.get_file(pwndbg.proc.exe)
    if not local_path:
        print('No file is selected')
        return

    with open(local_path, 'rb') as f:
        elffile = ELFFile(f)
        load_segment = elffile.get_segment(3)
        segment_base = load_segment['p_vaddr']
        sections = []
        for section in elffile.iter_sections():
            start = section['sh_addr']

            # Don't print sections that aren't mapped into memory
            if start == 0:
                continue

            size = section['sh_size']
            sections.append((start, start + size, section.name))

        sections.sort()
        for start, end, name in sections:
            print('%#x - %#x ' % (start, end), name)
Ejemplo n.º 6
0
 def dump_segments(self):
     with open(self.filename, "rb") as f:
         elf = ELFFile(f)
         self.structs = elf.structs
         segments = []
         for i in range(elf.num_segments()):
             seg = elf.get_segment(i)
             segments.append(seg.header)
     return segments
Ejemplo n.º 7
0
def generate_atf_binary(bl31_file_name):
    with open(bl31_file_name) as bl31_file:
        bl31 = ELFFile(bl31_file)
        num = bl31.num_segments()
        for i in range(num):
            seg = bl31.get_segment(i)
            if ('PT_LOAD' == seg.__getitem__(ELF_SEG_P_TYPE)):
                paddr = seg.__getitem__(ELF_SEG_P_PADDR)
                file_name = 'bl31_0x%08x.bin' % paddr
                with open(file_name, "wb") as atf:
                    atf.write(seg.data())
Ejemplo n.º 8
0
def get_elf_entry_point_offset(path):
    physical_ep = None
    try:
        with open(path, "rb") as f:
            elf = ELFFile(f)
            physical_ep = elf._parse_elf_header().e_entry
            physical_ep -= elf.get_segment(0).header.p_vaddr
    except Exception as e:
        logger.error(e.__str__())
        physical_ep = None
    return physical_ep
def generate_atf_fit_dts(fit_file_name, bl31_file_name, uboot_file_name,
                         dtbs_file_name):
    """
    Generate FIT script for ATF image.
    """
    if fit_file_name != sys.stdout:
        fit_file = open(fit_file_name, "wb")
    else:
        fit_file = sys.stdout

    num_load_seg = 0
    p_paddr = 0xFFFFFFFF
    with open(uboot_file_name, 'rb') as uboot_file:
        uboot = ELFFile(uboot_file)
        for i in range(uboot.num_segments()):
            seg = uboot.get_segment(i)
            if ('PT_LOAD' == seg.__getitem__(ELF_SEG_P_TYPE)):
                p_paddr = seg.__getitem__(ELF_SEG_P_PADDR)
                num_load_seg = num_load_seg + 1

    assert (p_paddr != 0xFFFFFFFF and num_load_seg == 1)

    fit_file.write(DT_HEADER % p_paddr)

    with open(bl31_file_name, 'rb') as bl31_file:
        bl31 = ELFFile(bl31_file)
        elf_entry = bl31.header['e_entry']
        for i in range(bl31.num_segments()):
            seg = bl31.get_segment(i)
            if ('PT_LOAD' == seg.__getitem__(ELF_SEG_P_TYPE)):
                paddr = seg.__getitem__(ELF_SEG_P_PADDR)
                p = seg.__getitem__(ELF_SEG_P_PADDR)
                append_atf_node(fit_file, i + 1, paddr, elf_entry)
    atf_cnt = i + 1
    append_fdt_node(fit_file, dtbs_file_name)
    fit_file.write('%s\n' % DT_IMAGES_NODE_END)
    append_conf_node(fit_file, dtbs_file_name, atf_cnt)
    fit_file.write('%s\n' % DT_END)

    if fit_file_name != sys.stdout:
        fit_file.close()
Ejemplo n.º 10
0
def generate_atf_binary(bl31_file_name):
    with open(bl31_file_name) as bl31_file:
        bl31 = ELFFile(bl31_file)

        num = bl31.num_segments()
        for i in range(num):
            seg = bl31.get_segment(i)
            if ('PT_LOAD' == seg.__getitem__(ELF_SEG_P_TYPE)):
                paddr = seg.__getitem__(ELF_SEG_P_PADDR)
                file_name = 'bl31_0x%08x.bin' % paddr
                with open(file_name, "wb") as atf:
                    atf.write(seg.data());
Ejemplo n.º 11
0
def generate_atf_fit_dts(fit_file_name, bl31_file_name, uboot_file_name, dtbs_file_name):
    """
    Generate FIT script for ATF image.
    """
    if fit_file_name != sys.stdout:
        fit_file = open(fit_file_name, "wb")
    else:
        fit_file = sys.stdout

    num_load_seg = 0
    p_paddr = 0xFFFFFFFF
    with open(uboot_file_name, 'rb') as uboot_file:
        uboot = ELFFile(uboot_file)
        for i in range(uboot.num_segments()):
            seg = uboot.get_segment(i)
            if ('PT_LOAD' == seg.__getitem__(ELF_SEG_P_TYPE)):
                p_paddr = seg.__getitem__(ELF_SEG_P_PADDR)
                num_load_seg = num_load_seg + 1

    assert (p_paddr != 0xFFFFFFFF and num_load_seg == 1)

    fit_file.write(DT_HEADER % p_paddr)

    with open(bl31_file_name, 'rb') as bl31_file:
        bl31 = ELFFile(bl31_file)
        elf_entry = bl31.header['e_entry']
        for i in range(bl31.num_segments()):
            seg = bl31.get_segment(i)
            if ('PT_LOAD' == seg.__getitem__(ELF_SEG_P_TYPE)):
                paddr = seg.__getitem__(ELF_SEG_P_PADDR)
                p= seg.__getitem__(ELF_SEG_P_PADDR)
                append_atf_node(fit_file, i+1, paddr, elf_entry)
    atf_cnt = i+1
    append_fdt_node(fit_file, dtbs_file_name)
    fit_file.write('%s\n' % DT_IMAGES_NODE_END)
    append_conf_node(fit_file, dtbs_file_name, atf_cnt)
    fit_file.write('%s\n' % DT_END)

    if fit_file_name != sys.stdout:
        fit_file.close()
Ejemplo n.º 12
0
def generate_atf_fit_dts_bl31(fit_file, bl31_file_name, dtbs_file_name):
    with open(bl31_file_name, 'rb') as bl31_file:
        bl31 = ELFFile(bl31_file)
        elf_entry = bl31.header['e_entry']
        segments = bl31.num_segments()
        for i in range(segments):
            seg = bl31.get_segment(i)
            if seg.__getitem__(ELF_SEG_P_TYPE) == 'PT_LOAD':
                paddr = seg.__getitem__(ELF_SEG_P_PADDR)
                append_bl31_node(fit_file, i + 1, paddr, elf_entry)
    append_fdt_node(fit_file, dtbs_file_name)
    fit_file.write(DT_IMAGES_NODE_END)
    append_conf_node(fit_file, dtbs_file_name, segments)
Ejemplo n.º 13
0
def generate_atf_fit_dts_bl31(fit_file, bl31_file_name, dtbs_file_name):
    with open(bl31_file_name, 'rb') as bl31_file:
        bl31 = ELFFile(bl31_file)
        elf_entry = bl31.header['e_entry']
        segments = bl31.num_segments()
        for i in range(segments):
            seg = bl31.get_segment(i)
            if seg.__getitem__(ELF_SEG_P_TYPE) == 'PT_LOAD':
                paddr = seg.__getitem__(ELF_SEG_P_PADDR)
                append_bl31_node(fit_file, i + 1, paddr, elf_entry)
    append_fdt_node(fit_file, dtbs_file_name)
    fit_file.write(DT_IMAGES_NODE_END)
    append_conf_node(fit_file, dtbs_file_name, segments)
Ejemplo n.º 14
0
def elf_to_dol(elf_path, dol_path):
	from elftools.elf.elffile import ELFFile

	with open(elf_path, 'rb') as elf_file, open(dol_path, 'wb') as dol_file:
		elf = ELFFile(elf_file)
		num_segments = elf.num_segments()

		dol_file.write(bytes([0x00] * 0x100))

		idx = 0
		for i in range(num_segments):
			segment = elf.get_segment(i)
			if not segment_is_text(segment):
				continue
			write_segment_to_dol(idx, segment, dol_file)
			idx += 1

		idx = 7
		for i in range(num_segments):
			segment = elf.get_segment(i)
			if not segment_is_data(segment):
				continue
			write_segment_to_dol(idx, segment, dol_file)
			idx += 1

		bss_start = 0
		bss_end = 0
		for i in range(num_segments):
			segment = elf.get_segment(i)
			if not segment_is_bss(segment):
				continue
			if bss_start == 0:
				bss_start = segment["p_vaddr"]
			bss_end = segment["p_vaddr"] + segment["p_memsz"]
		write_to_dol_header(dol_file, 0xd8, bss_start)
		bss_size = bss_end - bss_start
		write_to_dol_header(dol_file, 0xdc, bss_size)

		write_to_dol_header(dol_file, 0xe0, elf["e_entry"])
Ejemplo n.º 15
0
def generate_atf_fit_dts_uboot(fit_file, uboot_file_name):
    num_load_seg = 0
    p_paddr = 0xFFFFFFFF
    with open(uboot_file_name, 'rb') as uboot_file:
        uboot = ELFFile(uboot_file)
        for i in range(uboot.num_segments()):
            seg = uboot.get_segment(i)
            if seg.__getitem__(ELF_SEG_P_TYPE) == 'PT_LOAD':
                p_paddr = seg.__getitem__(ELF_SEG_P_PADDR)
                num_load_seg = num_load_seg + 1

    assert (p_paddr != 0xFFFFFFFF and num_load_seg == 1)

    fit_file.write(DT_UBOOT % p_paddr)
Ejemplo n.º 16
0
def generate_atf_fit_dts_uboot(fit_file, uboot_file_name):
    num_load_seg = 0
    p_paddr = 0xFFFFFFFF
    with open(uboot_file_name, 'rb') as uboot_file:
        uboot = ELFFile(uboot_file)
        for i in range(uboot.num_segments()):
            seg = uboot.get_segment(i)
            if seg.__getitem__(ELF_SEG_P_TYPE) == 'PT_LOAD':
                p_paddr = seg.__getitem__(ELF_SEG_P_PADDR)
                num_load_seg = num_load_seg + 1

    assert (p_paddr != 0xFFFFFFFF and num_load_seg == 1)

    fit_file.write(DT_UBOOT % p_paddr)
Ejemplo n.º 17
0
def get_bl31_segments_info(bl31_file_name):
    """
    Get load offset, physical offset, file size
    from bl31 elf file program headers.
    """
    with open(bl31_file_name) as bl31_file:
        bl31 = ELFFile(bl31_file)

        num = bl31.num_segments()
        print 'Number of Segments : %d' % bl31.num_segments()
        for i in range(num):
            print 'Segment %d' % i
            seg = bl31.get_segment(i)
            ptype = seg[ELF_SEG_P_TYPE]
            poffset = seg[ELF_SEG_P_OFFSET]
            pmemsz = seg[ELF_SEG_P_MEMSZ]
            pfilesz = seg[ELF_SEG_P_FILESZ]
            print 'type: %s\nfilesz: %08x\nmemsz: %08x\noffset: %08x' % (ptype, pfilesz, pmemsz, poffset)
            paddr = seg[ELF_SEG_P_PADDR]
            print 'paddr: %08x' % paddr
def get_bl31_segments_info(bl31_file_name):
    """
    Get load offset, physical offset, file size
    from bl31 elf file program headers.
    """
    with open(bl31_file_name) as bl31_file:
        bl31 = ELFFile(bl31_file)

        num = bl31.num_segments()
        print('Number of Segments : %d' % bl31.num_segments())
        for i in range(num):
            print('Segment %d' % i)
            seg = bl31.get_segment(i)
            ptype = seg[ELF_SEG_P_TYPE]
            poffset = seg[ELF_SEG_P_OFFSET]
            pmemsz = seg[ELF_SEG_P_MEMSZ]
            pfilesz = seg[ELF_SEG_P_FILESZ]
            print('type: %s\nfilesz: %08x\nmemsz: %08x\noffset: %08x' %
                  (ptype, pfilesz, pmemsz, poffset))
            paddr = seg[ELF_SEG_P_PADDR]
            print('paddr: %08x' % paddr)
Ejemplo n.º 19
0
Archivo: elf.py Proyecto: StalkR/pwndbg
def elfheader():
    """
    Prints the section mappings contained in the ELF header.
    """
    local_path = pwndbg.file.get_file(pwndbg.proc.exe)
    with open(local_path, 'rb') as f:
        elffile = ELFFile(f)
        load_segment = elffile.get_segment(3)
        segment_base = load_segment['p_vaddr']
        sections = []
        for section in elffile.iter_sections():
            start = section['sh_addr']

            # Don't print sections that aren't mapped into memory
            if start == 0:
                continue

            size = section['sh_size']
            sections.append((start, start + size, section.name.decode('ascii')))

        sections.sort()
        for start, end, name in sections:
            print('%#x - %#x %s' % (start, end, name))
Ejemplo n.º 20
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
Ejemplo n.º 21
0
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
Ejemplo n.º 22
0
if __name__ == '__main__':

    if len(sys.argv) < 2:
        print(
            "You must provide this script with an elf binary file you want to examine"
        )
        exit(1)

    print(f"Mapping between segments and sections in the file {sys.argv[1]}")

    elffile = ELFFile(open(sys.argv[1], 'rb'))

    segments = list()
    for segment_idx in range(elffile.num_segments()):
        segments.insert(segment_idx, dict())
        segments[segment_idx]['segment'] = elffile.get_segment(segment_idx)
        segments[segment_idx]['sections'] = list()

    for section_idx in range(elffile.num_sections()):
        section = elffile.get_section(section_idx)
        for segment in segments:
            if segment['segment'].section_in_segment(section):
                segment['sections'].append(section)

    for segment in segments:
        seg_head = segment['segment'].header
        print("Segment:")
        print(
            f"Type: {seg_head.p_type}\nOffset: {hex(seg_head.p_offset)}\nVirtual address: {hex(seg_head.p_vaddr)}\nPhysical address: {(seg_head.p_paddr)}\nSize in file: {hex(seg_head.p_filesz)}\nSize in memory: {hex(seg_head.p_memsz)}\n"
        )
Ejemplo n.º 23
0
#!/usr/bin/env python3
import sys
from elftools.elf.elffile import ELFFile
from hexdump import hexdump
import struct
import binascii

e = ELFFile(open("devcfg.mbn" if len(sys.argv) == 1 else sys.argv[1], "rb"))

# segment 0 = ELF header
# segment 1 = cert
# segment 2 = cert

ss = e.get_segment(2)
print(dir(ss))

la = ss.header['p_vaddr']
print(hex(la))

d = ss.data()
#hexdump(d)

#for i in range(0, len(d), 4):
for i in range(0, 0x100, 4):
    aa = struct.unpack("I", d[i:i + 4])[0] - la
    if aa >= 0 and aa < len(d):
        ss = d[aa:aa + 0x100].split(b"\x00")[0]
        print(hex(i), hex(aa), ss)


def g32(i):
Ejemplo n.º 24
0
def process_file(filename):
    print('Processing file:', filename)
    with open(filename, 'rb') as f:
        elffile = ELFFile(f)

        # The provided linkerscript sorts the sections in the appropriate order
        assert (elffile.num_segments() == 1)
        segment = elffile.get_segment(0)

        symtab = elffile.get_section_by_name('.symtab')

        # A table of exported callbacks where each entry is made of two u32
        # values, the first is the event ID and the second is the address of the
        # callback function
        exports_sym = symtab.get_symbol_by_name('Exports')[0]

        exports_addr = exports_sym['st_value']
        exports_size = exports_sym['st_size']
        assert ((exports_addr & 3) == 0)
        assert ((exports_size & 7) == 0)

        # The text and data sections are merged together, the bss is allocated
        # and zeroed by the loader. The 4 takes into account the extra pointer
        # to the application class that's inserted by the loader.
        code_size = segment['p_filesz'] - 4
        bss_size = segment['p_memsz'] - code_size

        # Address of the funalizer function
        finish_sym = symtab.get_symbol_by_name('_finish')[0]
        finish_addr = finish_sym['st_value']

        asset0 = struct.pack(
            '<16I',
            0x1000,  # Fixed?
            1,  # Version
            code_size,  # Code + Data size
            0,  # Same but for libs
            4,  # Space for the Klass pointer
            bss_size,  # Size of the zeroed area
            code_size,  # Offset for the Klass pointer
            exports_addr,  # Offset for the exports array
            0xffffffff,  # Same but for libs
            0xffffffff,  # Init array start
            0xffffffff,  # Fini array start
            0,  # Init array len (in words)
            0,  # Fini array len (in words)
            elffile['e_entry'],  # Entry point
            finish_addr,  # Exit point
            0x2B0B3ED5)  # Used to check if the .sig file is valid

        # Make it writable, we may perform some modification later
        asset1 = bytearray(segment.data())

        reloc_offsets = []
        reloc_sections = [
            sect for sect in elffile.iter_sections()
            if isinstance(sect, RelocationSection)
        ]

        # The only relocation performed by the loader is adding the address
        # where the app is loaded to a whole u32
        for rel_section in reloc_sections:
            for reloc in rel_section.iter_relocations():
                ty = reloc['r_info_type']
                # Make sure it's not STN_UNDEF
                assert (reloc['r_info_sym'] != 0)

                if ty == ENUM_RELOC_TYPE_ARM['R_ARM_ABS32']:
                    reloc_offsets.append(reloc['r_offset'])
                elif ty == ENUM_RELOC_TYPE_ARM['R_ARM_REL32'] or \
                        ty == ENUM_RELOC_TYPE_ARM['R_ARM_CALL']:
                    # Already PC-independent
                    pass
                else:
                    raise RuntimeError('Unknown relocation type!')

        # Terminates the list
        reloc_offsets.append(0xffffffff)

        asset2 = struct.pack('<IIII', 1,
                             len(reloc_offsets) - 1,
                             16 + len(reloc_offsets) * 4, 0xf0123456)
        for off in reloc_offsets:
            asset2 += struct.pack('<I', off)

        # The key file is simply chopped, shuffled and hashed with SHA1 together
        # with the "magic" word at 0x3c in the asset0.
        with open(filename + '.sig', 'w+b') as out:
            header = struct.pack(
                '<II',
                0x1000,  # Fixed ?
                8)  # Key slot
            out.write(header)
            out.write(
                b'\x63\x9a\x83\xa1\x99\x4b\xfb\x42\x56\xd4\x5e\x44\x2a\x90\x2a\x35'
            )
            out.write(
                b'\xf5\xd5\xdc\xef\xb9\x80\x90\x3d\x80\x33\x94\x5f\x54\x6c\xcc\x9a'
            )
            out.write(
                b'\xe8\xa7\xad\xf7\xe0\x22\x3d\x1e\x59\x30\x38\x3a\x4d\x30\x39\x3a'
            )
            out.write(
                b'\x44\x30\x31\x3a\x54\x30\x39\x3a\x30\x30\xe3\xd1\xa5\xca\xbc\x94'
            )
            out.write(
                b'\x75\xd1\x0c\x79\x70\x03\x1b\x10\x33\x50\x31\xad\x79\xbc')

        with open(filename + '.aab', 'w+b') as out:
            out.write(b'ABHS')
            header = struct.pack(
                '<3I',
                0x1000,  # Fixed ?
                0x10,  # Application type
                3)  # Number of assets
            out.write(header)

            off = 16 + 3 * 12
            for i, asset in enumerate([asset0, asset1, asset2]):
                entry = struct.pack('<3I', i, len(asset), off)
                off += len(asset)
                out.write(entry)

            out.write(asset0)
            out.write(asset1)
            out.write(asset2)
Ejemplo n.º 25
0
    def load(cls, fo):
        ef = ELFFile(fo)

        if ef.header['e_type'] != 'ET_EXEC':
            raise RuntimeError(
                'not an ELF executable file (type {})'.format(ef.header['e_type']))
        if ef.header['e_machine'] != 'EM_68K':
            raise RuntimeError('not an M68K ELF file')
        if ef.num_segments() != 2:
            raise RuntimeError('wrong number of segments in ELF file')

        # Look at segments for text and data; note that we
        # expect to see exactly two segments, one RX, one RW,
        # for text and data respectively, with data immediately
        # following text in memory.

        textSegment = ef.get_segment(0)
        textAddress = textSegment['p_vaddr']
        textSize = textSegment['p_filesz']

        dataSegment = ef.get_segment(1)
        dataAddress = dataSegment['p_vaddr']
        dataSize = dataSegment['p_filesz']

        # Look for BSS sections
        bssAddress = None
        bssLimit = None
        for section in ef.iter_sections():
            if (section['sh_type'] == 'SHT_NOBITS') and (section['sh_flags'] & SH_FLAGS.SHF_ALLOC):

                secStart = section['sh_addr']
                secLimit = section['sh_addr'] + section['sh_size']

                # track low BSS address
                if bssAddress is None:
                    bssAddress = secStart
                elif secStart < bssAddress:
                    bssAddress = secStart

                # track BSS limit
                if bssLimit is None:
                    bssLimit = secLimit
                elif secLimit > bssLimit:
                    bssLimit = secLimit

        if bssAddress is None:
            bssAddress = dataAddress + dataSize
            bssSize = 0
        else:
            bssSize = bssLimit - bssAddress

        # extend text to cover the gap created by data segment alignment
        dataGap = dataAddress - (textAddress + textSize)
        if dataGap < 0:
            raise RuntimeError('data segment before text')
        textSize += dataGap

        # extend data to cover the gap created by BSS alignment
        bssGap = bssAddress - (dataAddress + dataSize)
        if bssGap < 0:
            raise RuntimeError('BSS before data segment (0x{:x} inside/before 0x{:x}/0x{:x}'.format(
                bssAddress, dataAddress, dataSize))
        dataSize += bssGap

        # sanity-check the text and data segments
        if (textSegment['p_type'] != 'PT_LOAD') or (dataSegment['p_type'] != 'PT_LOAD'):
            raise RuntimeError('expected two PT_LOAD segments')

        if (textSegment['p_flags'] & cls.P_FLAGS_MASK) != cls.P_FLAGS_RX:
            raise RuntimeError('text segment is not RX')
        if textAddress != 0:
            raise RuntimeError('text segment is not at 0')

        if (dataSegment['p_flags'] & cls.P_FLAGS_MASK) != cls.P_FLAGS_RW:
            raise RuntimeError('data segment is not RW')
        if dataAddress != textAddress + textSize:
            raise RuntimeError('data segment @ 0x{:x} does not follow text 0x{:x}/0x{:x}'.format(
                dataAddress, textAddress, textSize))

        text = textSegment.data().ljust(textSize, '\0')
        data = dataSegment.data().ljust(dataSize, '\0')

        if len(text) != textSize:
            raise RuntimeError('text size mismatch')
        if len(data) != dataSize:
            raise RuntimeError('data size mismatch')

        print('text 0x{:x} data 0x{:x} bss 0x{:x}'.format(textSize, dataSize, bssSize))

        # look for relocations
        relocs = dict()
        for section in ef.iter_sections():
            if isinstance(section, RelocationSection):

                # what section do these relocations affect?
                relocSection = ef.get_section(section['sh_info'])
                if not (relocSection['sh_flags'] & SH_FLAGS.SHF_ALLOC):
                    #print('Not relocating {}'.format(relocSection.name))
                    continue

                #print('Relocate: {} using {}'.format(relocSection.name, section.name))
                symtab = ef.get_section(section['sh_link'])

                for reloc in section.iter_relocations():
                    relAddress = reloc['r_offset']
                    if relAddress >= (len(text) + len(data)):
                        raise RuntimeError('relocation outside known space')

                    if not reloc.is_RELA():
                        raise RuntimeError('unexpected REL reloc')

                    relType = reloc['r_info_type']

                    # get the symbol table entry the reloc refers to
                    if reloc['r_info_sym'] >= symtab.num_symbols():
                        raise RuntimeError(
                            'symbol reference in relocation out of bounds')
                    relTarget = symtab.get_symbol(reloc['r_info_sym'])['st_value']

                    # It looks like we can ignore the addend, as it's already
                    # present in the object file...
                    relAddend = reloc['r_addend']

                    # Sort out what we're going to do with this relocation...
                    if relType == R_68K_32:
                        pass
                    elif relType == R_68K_NONE:
                        #print('ignoring none-reloc @ 0x{:x}'.format(relAddress))
                        continue
                    elif relType == R_68K_PC32:
                        #print('ignoring PC32 reloc @ 0x{:x} -> 0x{:x}+{:x}'.format(relAddress, relTarget, relAddend))
                        continue
                    elif relType == R_68K_PC16:
                        #print('ignoring PC16 reloc @ 0x{:x} -> 0x{:x}+{:x}'.format(relAddress, relTarget, relAddend))
                        continue
                    elif relType == R_68K_PC8:
                        #print('ignoring PC8 reloc @ 0x{:x} -> 0x{:x}+{:x}'.format(relAddress, relTarget, relAddend))
                        continue
                    else:
                        raise RuntimeError('unexpected relocation type {} @ 0x{:x} -> 0x{:x}+x'.format(relType, relAddress, relTarget, relAddend))

                    #print('RELA address 0x{:08x} target 0x{:x} type {} addend 0x{:x}'.format(relAddress, relTarget, relType, relAddend))

                    if relTarget < len(text):
                        relType |= R_TEXT
                        if relAddend > len(text):
                            raise RuntimeError('addend outside of text section')
                    elif relTarget < (len(text) + len(data)):
                        relType |= R_DATA
                        if relAddend > len(data):
                            raise RuntimeError('addend outside of data section')
                    elif relTarget <= (len(text) + len(data) + bssSize):
                        # note, <= to allow pointer to _end, which is immediately *after* the BSS
                        relType |= R_BSS
                        if relAddend > bssSize:
                            raise RuntimeError('addend outside of bss section')
                    else:
                        raise RuntimeError(
                            'relocation target not in known space')

                    #print('    -> type 0x{:03x}'.format(relType))

                    if relAddress < len(text):
                        inSeg = text
                        segOffset = relAddress
                    elif relAddress < (len(text) + len(data)):
                        inSeg = data
                        segOffset = relAddress - len(text)
                    else:
                        raise RuntimeError('relocation not in known space')

                    unRelocated = struct.unpack('>L', inSeg[segOffset:segOffset+4])[0]
                    #print('    unrelocated: 0x{:x}'.format(unRelocated))

                    if unRelocated != (relTarget + relAddend):
                        raise RuntimeError("unrelocated field 0x{:x} != target 0x{:x} + addend 0x{:x}".format(unRelocated, relTarget, relAddend))

                    relocs[relAddress] = relType

        return cls(text=text,
                   data=data,
                   bssSize=bssSize,
                   relocs=relocs)