def runCode(self, fileName, parameters=None, stackSize=2048): message = LedgerWalletProxyRequest() f = open(fileName, 'rb') elffile = ELFFile(f) for section in elffile.iter_sections(): if section.name == '.ledger': message.startCode.signature = section.data()[0:ord(section.data()[1]) + 2] break if len(message.startCode.signature) == 0: raise Exception("Missing code signature") message.startCode.stackSize = stackSize message.startCode.entryPoint = elffile.header['e_entry'] message.startCode.parameters = parameters for segment in elffile.iter_segments(): if segment['p_type'] == 'PT_LOAD': codeRange = message.startCode.code.add() flags = 0 if ((segment['p_flags'] & P_FLAGS.PF_W) == 0): flags = flags | 0x01 codeRange.flags = flags codeRange.start = segment['p_vaddr'] codeRange.end = segment['p_vaddr'] + segment['p_memsz'] codeRange.dataLength = segment['p_filesz'] codeRange.data = segment.data() response = self.transport.exchange(message) while response.HasField('logAck'): print response.logAck.message message = LedgerWalletProxyRequest() message.resumeCode.CopyFrom(ResumeCode()) response = self.transport.exchange(message) if response.HasField('startCodeResponseAck'): return response.startCodeResponseAck.response else: raise ProxyException("Unexpected response", response)
def analyze(self, pkginfo, tar): exec_stacks = [] for entry in tar: tmpname = _test_elf_and_extract(tar, entry) if not tmpname: continue try: fp = open(tmpname, 'rb') elffile = ELFFile(fp) for segment in elffile.iter_segments(): if segment['p_type'] != 'PT_GNU_STACK': continue mode = segment['p_flags'] if mode & 1: exec_stacks.append(entry.name) fp.close() finally: os.unlink(tmpname) if exec_stacks: self.warnings = [("elffile-with-execstack %s", i) for i in exec_stacks]
def test_core_prpsinfo(self): with open(os.path.join('test', 'testfiles_for_unittests', 'core_linux64.elf'), 'rb') as f: elf = ELFFile(f) for segment in elf.iter_segments(): if not isinstance(segment, NoteSegment): continue notes = list(segment.iter_notes()) for note in segment.iter_notes(): if note['n_type'] != 'NT_PRPSINFO': continue desc = note['n_desc'] self.assertEquals(desc['pr_state'], 0) self.assertEquals(desc['pr_sname'], b'R') self.assertEquals(desc['pr_zomb'], 0) self.assertEquals(desc['pr_nice'], 0) self.assertEquals(desc['pr_flag'], 0x400600) self.assertEquals(desc['pr_uid'], 1000) self.assertEquals(desc['pr_gid'], 1000) self.assertEquals(desc['pr_pid'], 23395) self.assertEquals(desc['pr_ppid'], 23187) self.assertEquals(desc['pr_pgrp'], 23395) self.assertEquals(desc['pr_sid'], 23187) self.assertEquals( desc['pr_fname'], b'coredump_self\x00\x00\x00') self.assertEquals( desc['pr_psargs'], b'./coredump_self foo bar 42 ' + b'\x00' * (80 - 27))
def test_core_prpsinfo(self): elf = ELFFile(self._core_file) for segment in elf.iter_segments(): if not isinstance(segment, NoteSegment): continue notes = list(segment.iter_notes()) for note in segment.iter_notes(): if note['n_type'] != 'NT_PRPSINFO': continue desc = note['n_desc'] self.assertEqual(desc['pr_state'], 0) self.assertEqual(desc['pr_sname'], b'R') self.assertEqual(desc['pr_zomb'], 0) self.assertEqual(desc['pr_nice'], 0) self.assertEqual(desc['pr_flag'], 0x400600) self.assertEqual(desc['pr_uid'], 1000) self.assertEqual(desc['pr_gid'], 1000) self.assertEqual(desc['pr_pid'], 23395) self.assertEqual(desc['pr_ppid'], 23187) self.assertEqual(desc['pr_pgrp'], 23395) self.assertEqual(desc['pr_sid'], 23187) self.assertEqual( desc['pr_fname'], b'coredump_self\x00\x00\x00') self.assertEqual( desc['pr_psargs'], b'./coredump_self foo bar 42 ' + b'\x00' * (80 - 27))
def load_file(self, filename=None): if filename is None: raise FormatError("Filename not specified.") try: elffile = ELFFile(open(filename, 'rb')) except: raise FormatError("Could not open ELF file \"%s\"." % filename) section_lma_map = dict() for section in elffile.iter_sections(): if section["sh_type"] != "SHT_PROGBITS": continue if section["sh_flags"] & SH_FLAGS.SHF_ALLOC: for segment in elffile.iter_segments(): if segment.section_in_segment(section): if not segment in section_lma_map: section_lma_map[segment] = segment["p_paddr"] segment_offset = section_lma_map[segment] section_lma_map[segment] += section["sh_size"] break new_section = FormatELF_Section(section, segment_offset) section_name = section.name[1 : ] self.sections[section_name] = new_section if len(self.sections) == 0: raise FormatError("ELF file \"%s\" contains no data." % filename)
def get_elf_info(filepath): """ Parse and return ELFInfo. Adds various calculated properties to the ELF header, segments and sections. Such added properties are those with prefix 'x_' in the returned dicts. """ local_path = pwndbg.file.get_file(filepath) with open(local_path, 'rb') as f: elffile = ELFFile(f) header = dict(elffile.header) segments = [] for seg in elffile.iter_segments(): s = dict(seg.header) s['x_perms'] = [ mnemonic for mask, mnemonic in [(PF_R, 'read'), (PF_W, 'write'), (PF_X, 'execute')] if s['p_flags'] & mask != 0 ] # end of memory backing s['x_vaddr_mem_end'] = s['p_vaddr'] + s['p_memsz'] # end of file backing s['x_vaddr_file_end'] = s['p_vaddr'] + s['p_filesz'] segments.append(s) sections = [] for sec in elffile.iter_sections(): s = dict(sec.header) s['x_name'] = sec.name s['x_addr_mem_end'] = s['x_addr_file_end'] = s['sh_addr'] + s['sh_size'] sections.append(s) return ELFInfo(header, sections, segments)
class Elf(Binary): def __init__(self, filename): super(Elf, self).__init__(filename) self.elf = ELFFile(file(filename)) self.arch = {'x86':'i386','x64':'amd64'}[self.elf.get_machine_arch()] assert self.elf.header.e_type in ['ET_DYN', 'ET_EXEC', 'ET_CORE'] #Get interpreter elf self.interpreter = None for elf_segment in self.elf.iter_segments(): if elf_segment.header.p_type != 'PT_INTERP': continue self.interpreter = Elf(elf_segment.data()[:-1]) break if not self.interpreter is None: assert self.interpreter.arch == self.arch assert self.interpreter.elf.header.e_type in ['ET_DYN', 'ET_EXEC'] def maps(self): for elf_segment in self.elf.iter_segments(): if elf_segment.header.p_type != 'PT_LOAD' or elf_segment.header.p_memsz == 0: continue flags = elf_segment.header.p_flags #PF_X 0x1 Execute - PF_W 0x2 Write - PF_R 0x4 Read perms = [' ', ' x', ' w ', ' wx', 'r ', 'r x', 'rw ', 'rwx'][flags&7] if 'r' not in perms: raise Exception("Not readable map from cgc elf not supported") #CGCMAP-- assert elf_segment.header.p_filesz != 0 or elf_segment.header.p_memsz != 0 yield((elf_segment.header.p_vaddr, elf_segment.header.p_memsz, perms, elf_segment.stream.name, elf_segment.header.p_offset, elf_segment.header.p_filesz)) def getInterpreter(self): return self.interpreter def threads(self): yield(('Running', {'EIP': self.elf.header.e_entry}))
def test_dynamic_segment(self): """Verify that we can process relocations on the PT_DYNAMIC segment without section headers""" test_dir = os.path.join('test', 'testfiles_for_unittests') with open(os.path.join(test_dir, 'x64_bad_sections.elf'), 'rb') as f: elff = ELFFile(f) for seg in elff.iter_segments(): if isinstance(seg, DynamicSegment): relos = seg.get_relocation_tables() self.assertEqual(set(relos), {'JMPREL', 'RELA'})
def is_dynamic_executable(path): """Is `path` a dynamic executable?""" from elftools.elf.elffile import ELFFile from elftools.common.exceptions import ELFError # This way of answering the question is perhaps a bit OTT. But it works. try: e = ELFFile(open(path, 'rb')) return 'PT_DYNAMIC' in [s.header.p_type for s in e.iter_segments()] except ELFError as e: print("ELFFile({}) failed {}".format(path, e)) return False
def test_reading_symbols(self): """Verify we can read symbol table without SymbolTableSection""" with open(os.path.join("test", "testfiles_for_unittests", "aarch64_super_stripped.elf"), "rb") as f: elf = ELFFile(f) for segment in elf.iter_segments(): if segment.header.p_type != "PT_DYNAMIC": continue symbol_names = [x.name for x in segment.iter_symbols()] exp = [b"", b"__libc_start_main", b"__gmon_start__", b"abort"] self.assertEqual(symbol_names, exp)
def test_disasm_against_objdump(objdump_path, binary_path): # TODO: code repetition from test_disasm_standalone, encapsulate inner functionality. start_time = time.time() total_inst = 0 match_inst = 0 print(('Processing file:', binary_path)) elf_file = ELFFile(open(binary_path, 'rb')) if elf_file.num_segments() == 0: print('There are no program headers in this file.') return objdump = ObjdumpWrapper(objdump_path) disasm = HexagonDisassembler(objdump_compatible=True) for segment in elf_file.iter_segments(): if segment['p_flags'] & P_FLAGS.PF_X: print("Offset: {:x}".format(segment['p_offset'])) print("VirtAddr: {:x}".format(segment['p_vaddr'])) print("FileSiz: {:x}".format(segment['p_filesz'])) segment_data = segment.data() data_pos = 0 while data_pos + INST_SIZE <= len(segment_data): addr = segment['p_vaddr'] + data_pos inst_as_int = struct.unpack('<I', segment_data[data_pos: data_pos + 4])[0] disasm_output = disasm.disasm_one_inst(inst_as_int, addr).text.strip() objdump_output = objdump.disasm_packet_raw( segment_data[data_pos: min(data_pos + 4 * 4, segment_data)], addr).strip() if (objdump_output != disasm_output): print("[{:08x}] {:s}".format(addr, objdump_output)) print("[{:08x}] {:s}".format(addr, disasm_output)) print() else: match_inst += 1 data_pos += 4 total_inst += 1 elapsed_time = time.time() - start_time print("Elapsed time: {0:.2f}".format(elapsed_time)) print('Match: {0:.2f}%'.format(match_inst / total_inst * 100))
def test_reading_symbols(self): """Verify we can read symbol table without SymbolTableSection""" with open(os.path.join('test', 'testfiles_for_unittests', 'aarch64_super_stripped.elf'), 'rb') as f: elf = ELFFile(f) for segment in elf.iter_segments(): if segment.header.p_type != 'PT_DYNAMIC': continue symbol_names = [x.name for x in segment.iter_symbols()] exp = [b'', b'__libc_start_main', b'__gmon_start__', b'abort'] self.assertEqual(symbol_names, exp)
def loadELF(self, filename): try: elf = ELFFile(open(filename, 'rb')) except: raise Exception("[-] This file is not an ELF file: %s" % filename) self.arch = elf.get_machine_arch() self.entry = elf.header.e_entry self.memory = self.load_code_segments(elf.iter_segments(), filename) self.symtab, self.thumbtab, self.code_addrs = self.load_section_info(elf.iter_sections()) self.thumbtab.sort(key=lambda tup: tup[0]) self.code_addrs = sorted(self.code_addrs, key=lambda k: k['address'])
def test_disasm_standalone(binary_path, timeout = None): profile = cProfile.Profile() profile.enable() start_time = time.time() print(('Processing file:', binary_path)) elf_file = ELFFile(open(binary_path, 'rb')) if elf_file.num_segments() == 0: print('There are no program headers in this file.') return disasm = HexagonDisassembler() total_inst = 0 for segment in elf_file.iter_segments(): if segment['p_flags'] & P_FLAGS.PF_X: print("Offset: {:x}".format(segment['p_offset'])) print("VirtAddr: {:x}".format(segment['p_vaddr'])) print("FileSiz: {:x}".format(segment['p_filesz'])) segment_data = segment.data() data_pos = 0 while data_pos + INST_SIZE <= len(segment_data): addr = segment['p_vaddr'] + data_pos inst_as_int = struct.unpack('<I', segment_data[data_pos: data_pos + 4])[0] dis = disasm.disasm_one_inst(inst_as_int, addr) print("[{:08x}] {:s}".format(addr, dis.text)) data_pos += 4 total_inst += 1 if timeout and (time.time() - start_time) > timeout: break profile.disable() prof_stats = pstats.Stats(profile) prof_stats.strip_dirs().sort_stats('cumulative').print_stats(20) print("Total instructions: " + str(total_inst)) elapsed_time = time.time() - start_time print("Elapsed time: " + str(elapsed_time))
def test_get_number_of_syms(self): """ Verify we can get get the number of symbols from a GNU hash section. """ with open(os.path.join('test', 'testfiles_for_unittests', 'lib_versioned64.so.1.elf'), 'rb') as f: elf = ELFFile(f) for segment in elf.iter_segments(): if segment.header.p_type != 'PT_DYNAMIC': continue _, hash_offset = segment.get_table_offset('DT_GNU_HASH') hash_section = GNUHashSection(elf.stream, hash_offset, elf) self.assertEqual(hash_section.get_number_of_symbols(), 24)
def _load_binary_elf(self, filename): logger.info("Loading ELF image into memory") f = open(filename, 'rb') elffile = ELFFile(f) for index, segment in enumerate(elffile.iter_segments()): logger.info("Loading segment #{} ({:#x}-{:#x})".format(index, segment.header.p_vaddr, segment.header.p_vaddr + segment.header.p_filesz)) for i, b in enumerate(bytearray(segment.data())): self.ir_emulator.write_memory(segment.header.p_vaddr + i, 1, b) f.close()
class SharedObjectInfo(): def __init__(self, path, baddr): self.path = path self._set_elf_file() self.low_addr = baddr self.high_addr = baddr + self._get_mem_size() # Check whether the ELF file is position independent code self.is_pic = self.elf_file.header['e_type'] == 'ET_DYN' # Don't set the so info's dwarf_info initially, only when # symbol lookup is first required self._dwarf_info = None @property def dwarf_info(self): if self._dwarf_info is None: self._set_dwarf_info() return self._dwarf_info def _set_elf_file(self): try: binary_file = open(self.path, 'rb') self.elf_file = ELFFile(binary_file) except IOError: print('Failed to open ' + self.path, file=sys.stderr) sys.exit(-1) def _set_dwarf_info(self): if not self.elf_file.has_dwarf_info(): print('Binary ' + self.path + ' has no DWARF info', file=sys.stderr) sys.exit(-1) self._dwarf_info = self.elf_file.get_dwarf_info() def _get_mem_size(self): mem_size = 0 for segment in self.elf_file.iter_segments(): if segment['p_type'] == 'PT_LOAD': alignment = segment['p_align'] segment_size = segment['p_memsz'] aligned_size = math.ceil(segment_size / alignment) * alignment mem_size += aligned_size return mem_size
def test_missing_sections(self): """Verify we can get dynamic strings w/out section headers""" libs = [] with open(os.path.join("test", "testfiles_for_unittests", "aarch64_super_stripped.elf"), "rb") as f: elf = ELFFile(f) 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_NEEDED": libs.append(t.needed.decode("utf-8")) exp = ["libc.so.6"] self.assertEqual(libs, exp)
def _load_binary_elf(self, filename): logger.info("Loading ELF image into memory") f = open(filename, 'rb') elffile = ELFFile(f) for index, segment in enumerate(elffile.iter_segments()): logger.info("Loading segment #{} ({:#x}-{:#x})".format( index, segment.header.p_vaddr, segment.header.p_vaddr + segment.header.p_filesz)) for i, b in enumerate(bytearray(segment.data())): self.ir_emulator.write_memory(segment.header.p_vaddr + i, 1, b) f.close()
def load_elf_and_run(f): elffile = ELFFile(f) for segment in elffile.iter_segments(): t = describe_p_type(segment['p_type']) print("Program Header: Size: %d, Virtual Address: 0x%x, Type: %s" % (segment['p_filesz'], segment['p_vaddr'], t)) if not (segment['p_vaddr'] & 0x80000000): continue if segment['p_filesz'] == 0 or segment['p_vaddr'] == 0: print("Skipped") continue write_ram(segment['p_vaddr'], segment.data(), True) print("Entry: 0x%x" % elffile['e_entry']) go_ram(elffile['e_entry'])
class CGCElf(Binary): @staticmethod def _cgc2elf(filename): # hack begin so we can use upstream Elftool with open(filename, 'rb') as fd: stream = io.BytesIO(fd.read()) stream.write(b'\x7fELF') stream.name = fd.name return stream def __init__(self, filename): super().__init__(filename) stream = self._cgc2elf(filename) self.elf = ELFFile(stream) self.arch = { 'x86': 'i386', 'x64': 'amd64' }[self.elf.get_machine_arch()] assert 'i386' == self.arch assert self.elf.header.e_type in ['ET_EXEC'] def maps(self): for elf_segment in self.elf.iter_segments(): if elf_segment.header.p_type not in [ 'PT_LOAD', 'PT_NULL', 'PT_PHDR', 'PT_CGCPOV2' ]: raise Exception("Not Supported Section") if elf_segment.header.p_type != 'PT_LOAD' or elf_segment.header.p_memsz == 0: continue flags = elf_segment.header.p_flags # PF_X 0x1 Execute - PF_W 0x2 Write - PF_R 0x4 Read perms = [' ', ' x', ' w ', ' wx', 'r ', 'r x', 'rw ', 'rwx'][flags & 7] if 'r' not in perms: raise Exception("Not readable map from cgc elf not supported") # CGCMAP-- assert elf_segment.header.p_filesz != 0 or elf_segment.header.p_memsz != 0 yield ((elf_segment.header.p_vaddr, elf_segment.header.p_memsz, perms, elf_segment.stream.name, elf_segment.header.p_offset, elf_segment.header.p_filesz)) def threads(self): yield (('Running', {'EIP': self.elf.header.e_entry}))
def test_missing_sections(self): """Verify we can get dynamic strings w/out section headers""" libs = [] with open(os.path.join('test', 'testfiles_for_unittests', 'aarch64_super_stripped.elf'), 'rb') as f: elf = ELFFile(f) 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_NEEDED': libs.append(t.needed.decode('utf-8')) exp = ['libc.so.6'] self.assertEqual(libs, exp)
def _program_elf(self, file_obj: IO[bytes], **kwargs: Any) -> None: assert self._loader elf = ELFFile(file_obj) for segment in elf.iter_segments(): addr = segment['p_paddr'] if segment.header.p_type == 'PT_LOAD' and segment.header.p_filesz != 0: data = bytearray(segment.data()) LOG.debug("Writing segment LMA:0x%08x, VMA:0x%08x, size %d", addr, segment['p_vaddr'], segment.header.p_filesz) try: self._loader.add_data(addr, data) except ValueError as e: LOG.warning("Failed to add data chunk: %s", e) else: LOG.debug("Skipping segment LMA:0x%08x, VMA:0x%08x, size %d", addr, segment['p_vaddr'], segment.header.p_filesz)
def __init__(self, elf=None): self.segments = [] if elf != None: callback, path = elf.split(':') self.callback = int(callback) with open(path, 'rb') as file: elffile = ELFFile(file) self.entry = elffile['e_entry'] for segment in elffile.iter_segments(): if segment['p_type'] == 'PT_LOAD': self.segments.append( BinarySegment(segment['p_paddr'], segment.data()))
def GetElfSegments(self): if self.isOpen() == False: return b"" ret = [] elffile = ELFFile(self.__file_handler) for segment in elffile.iter_segments(): if segment['p_type'] == 'PT_LOAD': addr = segment['p_paddr'] if addr == 0 and elffile["e_entry"] != 0: addr = elffile["e_entry"] ret.append( ElfSegments(addr, segment.data()[addr:len(segment.data())])) else: ret.append(ElfSegments(addr, segment.data())) self.__file_handler.seek(0) return ret
def __parse_binaries(self, width): self.mem = {} for binary in self.binaries: with open(binary, 'rb') as file: elffile = ELFFile(file) for segment in elffile.iter_segments(): if segment['p_type'] == 'PT_LOAD': data = segment.data() addr = segment['p_paddr'] size = len(data) load = True if len(self.areas) != 0: load = False for area in self.areas: if addr >= area[0] and addr + size <= area[1]: load = True break if load: self.dump( ' Handling section (base: 0x%x, size: 0x%x)' % (addr, size)) self.__add_mem(addr, size, data, width) if segment['p_filesz'] < segment['p_memsz']: addr = segment['p_paddr'] + segment['p_filesz'] size = segment['p_memsz'] - segment['p_filesz'] self.dump( ' Init section to 0 (base: 0x%x, size: 0x%x)' % (addr, size)) self.__add_mem(addr, size, [0] * size, width) else: self.dump( ' Bypassing section (base: 0x%x, size: 0x%x)' % (addr, size))
def write_elf(path: str) -> None: with open(path, 'rb') as f: elffile = ELFFile(f) if elffile['e_machine'] != 189: logger.error('incompatible elf file, not for microblaze') for segment in elffile.iter_segments(): offset = segment['p_vaddr'] data = segment.data() logger.debug('writing 0x%X bytes at 0x%X', len(data), offset) # hack to write to the correct memory space if offset < mem_i.mmio.length: mem_i.write(offset, data) else: offset -= mem_i.mmio.length mem_d.write(offset, data)
def __init__(self, blockSize = 0, elf = None, encrypt = False, aesKey = None, aesIv = None): self.blockSize = blockSize self.encrypt = encrypt self.aesKey = aesKey self.aesIv = aesIv self.bin = BlockBuffer(blockSize) self.elf = elf self.segments = [] if elf: elffile = ELFFile(elf) self.entry = elffile['e_entry'] for segment in elffile.iter_segments(): if segment['p_type'] == 'PT_LOAD': self.segments.append(BinarySegment(segment['p_paddr'], segment.data()))
def readelf_interp(binary_path): """ This reads the program interpreter (INTERP), usually ld-linux.so from the given binary. It will return None if it can't find it. """ # Use pyelftools to extract the program header elffile = ELFFile(open(binary_path)) # Go through the segments until we INTERP segment interp = None for segment in elffile.iter_segments(): if isinstance(segment, InterpSegment): interp = segment.get_interp_name() return interp
def __init__(self, elf=None): self.segments = [] if elf != None: with open(elf, 'rb') as file: print("Reading ELF file") elffile = ELFFile(file) self.entry = elffile['e_entry'] for segment in elffile.iter_segments(): if segment['p_type'] == 'PT_LOAD': print(" Segment : %x %x" % (segment['p_paddr'], len(segment.data()))) self.segments.append( BinarySegment(segment['p_paddr'], segment.data()))
def load_elf(self, binary): if self.verbose: print('Loading %s' % binary) with open(binary, 'rb') as file: elffile = ELFFile(file) for segment in elffile.iter_segments(): if segment['p_type'] == 'PT_LOAD': data = segment.data() addr = segment['p_paddr'] size = len(data) if self.verbose: print('Loading section (base: 0x%x, size: 0x%x)' % (addr, size)) self.write(addr, size, data) if segment['p_filesz'] < segment['p_memsz']: addr = segment['p_paddr'] + segment['p_filesz'] size = segment['p_memsz'] - segment['p_filesz'] print('Init section to 0 (base: 0x%x, size: 0x%x)' % (addr, size)) self.write(addr, size, [0] * size) set_pc_addr_config = self.config.get('**/debug_bridge/set_pc_addr') if set_pc_addr_config is not None: set_pc_offset_config = self.config.get( '**/debug_bridge/set_pc_offset') entry = elffile.header['e_entry'] if set_pc_offset_config is not None: entry += set_pc_offset_config.get_int() if self.verbose: print('Setting PC (base: 0x%x, value: 0x%x)' % (set_pc_addr_config.get_int(), entry)) return self.write_32(set_pc_addr_config.get_int(), entry) return 0
def get_binary_info(prog): """Look for the loader requested by the program, and record existing mappings required by program itself.""" interp = None binary_mappings = [] with open(prog, 'rb') as f: e = ELFFile(f) for seg in e.iter_segments(): if isinstance(seg, InterpSegment): interp = seg.get_interp_name() if seg['p_type'] == 'PT_LOAD': binary_mappings.append((seg['p_vaddr'], seg['p_memsz'])) if interp is None: raise Exception("Could not find interp in binary") return interp, binary_mappings
def test_get_number_of_syms(self): """ Verify we can get get the number of symbols from an ELF hash section. """ with open(os.path.join('test', 'testfiles_for_unittests', 'aarch64_super_stripped.elf'), 'rb') as f: elf = ELFFile(f) dynamic_segment = None for segment in elf.iter_segments(): if segment.header.p_type == 'PT_DYNAMIC': dynamic_segment = segment break _, hash_offset = dynamic_segment.get_table_offset('DT_HASH') hash_section = ELFHashTable(elf, hash_offset, dynamic_segment) self.assertIsNotNone(hash_section) self.assertEqual(hash_section.get_number_of_symbols(), 4)
def _extract_elf_mmap (self, fobj): try: _mle_elf = ELFFile (fobj) _tmp_file = tempfile.TemporaryFile () for segment in _mle_elf.iter_segments (): if segment ['p_type'] is 'PT_LOAD': _p_offset = segment ['p_offset'] _p_filesz = segment ['p_filesz'] _p_memsz = segment ['p_memsz'] _elf_end = _p_offset + _p_filesz # copy segment _tmp_file.write (fobj [_p_offset : _elf_end]) # 0 fill remaining area for a in range (_p_memsz - _p_filesz): _tmp_file.write ('\x00') return mmap.mmap (_tmp_file.fileno (), 0, access=mmap.ACCESS_WRITE) except IOError as e: raise MLEError ('error decompressing ELF file {0}: {1}'.format (e.filename, e.strerror))
class ELF: # TODO: check valid def __init__(self, filename): self.valid = False with open(filename, 'rb') as f: try: self.elf = ELFFile(f) self.base_addr = 0 self.seg_raw_offsets = {} self.seg_va_offsets = {} for seg in self.elf.iter_segments(): if seg["p_type"] == "PT_LOAD": if self.base_addr == 0 or seg[ "p_vaddr"] < self.base_addr: self.base_addr = seg["p_vaddr"] self.seg_raw_offsets[seg["p_offset"]] = { "va": seg["p_vaddr"], "raw_size": seg["p_filesz"] } self.seg_va_offsets[seg["p_vaddr"]] = { "raw": seg["p_offset"], "v_size": seg["p_memsz"] } self.valid = True except ELFError as ex: sys.stderr.write("Error: not ELF file") def raw2va(self, raw): for raw_start, seg in self.seg_raw_offsets.items(): if raw >= raw_start and raw < raw_start + seg["raw_size"]: return raw - raw_start + seg["va"] sys.stderr.write("Error: could not calculate virtual address for " + hex(raw) + "\n") return -1 def va2raw(self, va): for va_start, seg in self.seg_va_offsets.items(): if va >= va_start and va < va_start + seg["v_size"]: return va - va_start + seg["raw"] sys.stderr.write("Error: could not calculate raw offset for " + hex(va) + "\n") return -1
def analyze(self, pkginfo, tar): missing_relro = [] for entry in tar: if not entry.isfile(): continue fp = tar.extractfile(entry) if not is_elf(fp): continue elffile = ELFFile(fp) if any(seg['p_type'] == 'PT_GNU_RELRO' for seg in elffile.iter_segments()): if self.has_bind_now(elffile): continue missing_relro.append(entry.name) if missing_relro: self.warnings = [("elffile-without-relro %s", i) for i in missing_relro]
class CGCElf(Binary): @staticmethod def _cgc2elf(filename): #hack begin so we can use upstream Elftool with open(filename, 'rb') as fd: stream = StringIO.StringIO(fd.read()) stream.write('\x7fELF') stream.name = fd.name return stream def __init__(self, filename): super(CGCElf, self).__init__(filename) stream = self._cgc2elf(filename) self.elf = ELFFile(stream) self.arch = {'x86':'i386','x64':'amd64'}[self.elf.get_machine_arch()] assert 'i386' == self.arch assert self.elf.header.e_type in ['ET_EXEC'] def maps(self): for elf_segment in self.elf.iter_segments(): if elf_segment.header.p_type not in ['PT_LOAD', 'PT_NULL', 'PT_PHDR', 'PT_CGCPOV2']: raise Exception("Not Supported Section") if elf_segment.header.p_type != 'PT_LOAD' or elf_segment.header.p_memsz == 0: continue flags = elf_segment.header.p_flags #PF_X 0x1 Execute - PF_W 0x2 Write - PF_R 0x4 Read perms = [' ', ' x', ' w ', ' wx', 'r ', 'r x', 'rw ', 'rwx'][flags&7] if 'r' not in perms: raise Exception("Not readable map from cgc elf not supported") #CGCMAP-- assert elf_segment.header.p_filesz != 0 or elf_segment.header.p_memsz != 0 yield((elf_segment.header.p_vaddr, elf_segment.header.p_memsz, perms, elf_segment.stream.name, elf_segment.header.p_offset, elf_segment.header.p_filesz)) def threads(self): yield(('Running', {'EIP': self.elf.header.e_entry}))
def test_dynamic_segment(self): """ Test that the degenerate case for the dynamic segment does not crash """ with open( os.path.join('test', 'testfiles_for_unittests', 'debug_info.elf'), 'rb') as f: elf = ELFFile(f) seen_dynamic_segment = False for segment in elf.iter_segments(): if segment.header.p_type == 'PT_DYNAMIC': self.assertEqual( segment.num_tags(), 0, "The dynamic segment in this file should be empty") seen_dynamic_segment = True break self.assertTrue(seen_dynamic_segment, "There should be a dynamic segment in this file")
def read_sections(config: Config, ef: ELFFile) -> SectionDF: """Read a section table from an ELFFile.""" columns = ['section', 'type', 'address', 'size', 'flags', 'segment'] index = [] rows = [] for i, section in enumerate(ef.iter_sections()): index.append(i) segment_number = -1 for j, segment in enumerate(ef.iter_segments()): if segment.section_in_segment(section): segment_number = j break rows.append([ section.name, elftools.elf.descriptions.describe_sh_type(section['sh_type']), section['sh_addr'], section['sh_size'], section['sh_flags'], segment_number ]) return SectionDF(rows, index=index, columns=columns)
def load(self): binaries = self.get_config().get('load-binary_eval') if binaries is not None: binaries = [eval(binaries)] else: binaries = self.get_config().get('binaries') elffile = None if binaries is not None: for binary in binaries: with open(binary, 'rb') as file: elffile = ELFFile(file) for segment in elffile.iter_segments(): if segment['p_type'] == 'PT_LOAD': self.get_impl().module.loader_io_req( self.get_impl().instance, segment['p_paddr'], segment['p_filesz'], True, segment.data()) if segment['p_filesz'] < segment['p_memsz']: self.get_impl().module.loader_memset( self.get_impl().instance, segment['p_paddr'] + segment['p_filesz'], segment['p_memsz'] - segment['p_filesz'], 0) set_pc_addr = self.get_json().get_child_int('set_pc_addr') set_pc_offset = self.get_json().get_child_int('set_pc_offset') start_addr = self.get_json().get_child_int('start_addr') start_value = self.get_json().get_child_int('start_value') if set_pc_addr is not None and elffile is not None: entry = elffile.header['e_entry'] if set_pc_offset is not None: entry += set_pc_offset self.get_impl().module.loader_io_req( self.get_impl().instance, set_pc_addr, 4, True, (entry).to_bytes(4, byteorder='little')) if start_addr is not None: self.get_impl().module.loader_io_req( self.get_impl().instance, start_addr, 4, True, (start_value).to_bytes(4, byteorder='little'))
def load(self, binary): print('Loading ELF file (path: %s)' % binary) self.jtag_set_dbg_mode_soc() with open(binary, 'rb') as file: elffile = ELFFile(file) for segment in elffile.iter_segments(): if segment['p_type'] == 'PT_LOAD': data = segment.data() addr = segment['p_paddr'] size = len(data) print('Loading section (base: 0x%x, size: 0x%x)' % (addr, size)) self.jtag_write(addr, size, data)
def read_elf_bin_file_segments(target_file): """Will ingest a simple statically linked ELF binary and return its relevant segments in a tuple for use by emulator. """ if not target_file: return False # At least check if file exists in some matter at all at some point. if not os.path.isfile(target_file) and os.access(target_file, os.R_OK): raise IOError("Error obtaining file") elf_segments = [] with open(target_file, "rb") as bin_file: elf_bin = ELFFile(bin_file) # Will store section name, offset, and size as a 3-tuple for seg in elf_bin.iter_segments(): elf_segments.append((seg.header['p_type'], seg.header['p_vaddr'], seg.header['p_memsz'], seg.data())) return elf_segments
def parse_elf(elffile): '''Parses an ELF executable and return the image base, list of sections, the symbol table Args: elfffile (str): path to an ELF file Returns: imgbase: image base segs: binary segments list funcs: binary functions list from symbol table ''' funcs = [] segs = [] #imgbase not needed here, function's virtual address is calculated based on segments(address, offset, size) imgbase = 0 try: with open(elffile, 'rb') as f: elffile = ELFFile(f) sec = elffile.get_section_by_name('.symtab') if not sec: sys.stderr.write("No symbol table found bin binary\n") '''if isinstance(sec, SymbolTableSection): for i in range(1, sec.num_symbols() + 1): if sec.get_symbol(i)["st_info"]["type"] == "STT_FUNC": fcn = BinaryFunction() fcn.name = sec.get_symbol(i).name fcn.offset = sec.get_symbol(i)["st_value"] fcn.size = sec.get_symbol(i)["st_size"] funcs.append(fcn) ''' f.seek(0) for segment in elffile.iter_segments(): if segment['p_type'] == 'PT_LOAD': seg = BinarySegment() seg.addr = segment['p_vaddr'] seg.size = segment['p_filesz'] seg.offset = segment['p_offset'] segs.append(seg) except ELFError: sys.stderr.write('Unable to parse ELF file') sys.exit(1) return imgbase, segs, funcs
def process_file(filename): print('Processing file:', filename) functions = {} with open(filename, 'rb') as f: p_vaddr = [] p_offset = [] elffile = ELFFile(f) for seg in elffile.iter_segments(): __printSectionInfo(seg) if seg.header.p_type == 'PT_LOAD': p_vaddr.append(seg.header.p_vaddr) p_offset.append(seg.header.p_offset) print(p_offset) print(p_vaddr) section = elffile.get_section_by_name('.symtab') if not section: print('No symbol table found. Perhaps this ELF has been stripped?') return min_address_find = [] for symb in section.iter_symbols(): if symb.entry.st_info.type == 'STT_FUNC': if symb.entry.st_shndx == 'SHN_UNDEF': continue if symb.entry.st_size == 0: continue st_value = symb.entry.st_value for i in range(len(p_vaddr) - 1, -1, -1): if (symb.entry.st_value >= p_vaddr[i]): print(symb.entry.st_value,p_vaddr[i],p_offset[i]) st_value = symb.entry.st_value - p_vaddr[i] + p_offset[i] # print(symb.name, st_value, symb.entry.st_size) #, symb.entry.st_shndx) functions[symb.name] = {'value': st_value, 'size': symb.entry.st_size} min_address_find.append(st_value) print(hex(min(min_address_find))) # print(functions) return functions
def test_reading_symbols_elf_hash(self): """ Verify we can read symbol table without SymbolTableSection but with a SYSV-style symbol hash table""" with open(os.path.join('test', 'testfiles_for_unittests', 'aarch64_super_stripped.elf'), 'rb') as f: elf = ELFFile(f) for segment in elf.iter_segments(): if segment.header.p_type != 'PT_DYNAMIC': continue num_symbols = segment.num_symbols() symbol_names = [x.name for x in segment.iter_symbols()] symbol_at_index_3 = segment.get_symbol(3) symbols_abort = segment.get_symbol_by_name('abort') self.assertEqual(num_symbols, 4) exp = ['', '__libc_start_main', '__gmon_start__', 'abort'] self.assertEqual(symbol_names, exp) self.assertEqual(symbol_at_index_3.name, 'abort') self.assertIsNotNone(symbols_abort) self.assertEqual(symbols_abort[0], symbol_at_index_3)
def buildLoadMap(elfFileName, memConf): memMapConf = {} with open(elfFileName, 'rb') as f: elfFileObj = ELFFile(f) for segment in elfFileObj.iter_segments(): if ( 'PT_LOAD' == segment.header['p_type'] and segment.header['p_vaddr'] != segment.header['p_paddr']): for section in elfFileObj.iter_sections(): if ( not section.is_null() and not ((section['sh_flags'] & SH_FLAGS.SHF_TLS) != 0 and section['sh_type'] == 'SHT_NOBITS' and segment['p_type'] != 'PT_TLS') and segment.section_in_segment(section)): loadAddr = 0 if ( (section['sh_flags'] & SH_FLAGS.SHF_ALLOC) != 0 and section['sh_type'] != 'SHT_NOBITS') : loadAddr = segment.header['p_paddr'] + section['sh_addr'] - segment.header['p_vaddr'] else : loadAddr = segment.header['p_paddr'] + section['sh_offset'] - segment.header['p_offset'] memMapConf[section.name] = (addr2region(segment.header['p_paddr'], memConf), loadAddr) return memMapConf
def test_reading_symbols_elf_hash(self): """ Verify we can read symbol table without SymbolTableSection but with a SYSV-style symbol hash table""" with open( os.path.join('test', 'testfiles_for_unittests', 'aarch64_super_stripped.elf'), 'rb') as f: elf = ELFFile(f) for segment in elf.iter_segments(): if segment.header.p_type != 'PT_DYNAMIC': continue num_symbols = segment.num_symbols() symbol_names = [x.name for x in segment.iter_symbols()] symbol_at_index_3 = segment.get_symbol(3) symbols_abort = segment.get_symbol_by_name('abort') self.assertEqual(num_symbols, 4) exp = ['', '__libc_start_main', '__gmon_start__', 'abort'] self.assertEqual(symbol_names, exp) self.assertEqual(symbol_at_index_3.name, 'abort') self.assertIsNotNone(symbols_abort)
def analyze(self, pkginfo, tar): exec_stacks = [] for entry in tar: if not entry.isfile(): continue fp = tar.extractfile(entry) if not is_elf(fp): continue elffile = ELFFile(fp) for segment in elffile.iter_segments(): if segment['p_type'] != 'PT_GNU_STACK': continue mode = segment['p_flags'] if mode & 1: exec_stacks.append(entry.name) if exec_stacks: self.warnings = [("elffile-with-execstack %s", i) for i in exec_stacks]
def create_binary(header, elf, boot=False): elf_data = load(elf) with open(elf,'rb') as f: elffile = ELFFile(f) data = [] for segment in elffile.iter_segments(): offset = segment['p_offset'] v_addr = segment['p_vaddr'] filesz = segment['p_filesz'] memsz = segment['p_memsz'] if segment['p_type'] != 'PT_LOAD': continue print offset,v_addr,filesz,memsz data.append(elf_data[offset:offset + filesz] + '\x00'*(memsz-filesz)) data = ''.join(data) entry_point = elffile.header['e_entry'] symbols = [c for c in get_symbols(elffile)] if boot: with open('build/boot.o','rb') as f: elf = ELFFile(f) boot_symbols = [c for c in get_symbols(elf)] symbols = boot_symbols + symbols symbols.sort( lambda x,y: cmp(x[0], y[0]) ) #get rid of any "bx lr"s data = data.replace(struct.pack('<I',0xe12fff1e),struct.pack('<I',0xe1a0f00e)) #We'll stick the symbols on the end symbols = ''.join(struct.pack('>I',value) + name + '\00' for (value,name) in symbols) if boot: header = load(header) header = header.replace(struct.pack('<I',0xcafebabe),struct.pack('<I',entry_point)) assert len(header) < 0x1000 header = header + '\x00'*(0x1000 - len(header)) entry_point = None else: header = '' return to_synapse_format(header+data, symbols, entry_point)
def _procelf(self): rf = cStringIO.StringIO(self.elfcontents) f = ELFFile(rf) filemap = [] floor = SLCell.FLASH_BASE for segment in f.iter_segments(): if len(segment.data()) == 0: continue binaddr = segment["p_paddr"] - floor if binaddr < 0: raise InvalidCellFileException("File contains addresses before payload area") end = binaddr + len(segment.data()) if end >= SLCell.PAYLOAD_LENGTH: raise InvalidCellFileException("File contains addresses after payload area: \nend = 0x%08x" % end) if end >= len(filemap): filemap += ["\xFF"]*(end-len(filemap) + 1) for d in segment.data(): filemap[binaddr] = d binaddr += 1 self._rawimage = "".join(filemap) #Here we would check for variants self._cellobj["variant_consts"] = []
def main(): if(len(sys.argv)!=3): print "Usage: %s <ELF filename> <output filename>" % sys.argv[0] return print "Opening ELF file: %s" % sys.argv[1] elffile = ELFFile(open(sys.argv[1],'r')) print "Entry point: 0x%x" % elffile.header['e_entry'] loadsegments = list() for segment in elffile.iter_segments(): segtype = describe_p_type(segment['p_type']) if(segtype=="LOAD"): loadsegments.append(segment) imgsize = 0 for segment in loadsegments: if(elffile.elfclass == 32): print "Load offset " + str(describe_p_flags(segment['p_flags'])) + \ " 0x%08x at 0x%08x, align 0x%0x" % \ (segment['p_offset'], segment['p_vaddr'], segment['p_align']) else: print "Load offset " + str(describe_p_flags(segment['p_flags'])) + \ " 0x%016x at 0x%016x, align 0x%0x" % \ (segment['p_offset'], segment['p_vaddr'], segment['p_align']) print "\tFile size: 0x%x\tMem size: 0x%x" % (segment['p_filesz'], segment['p_memsz']) imgsize = max(imgsize,segment['p_vaddr']+segment['p_memsz']) print "Image size: 0x%x" % imgsize buf = ctypes.create_string_buffer(imgsize) for segment in loadsegments: offset = segment['p_vaddr'] data = segment.data() for i in range(len(segment.data())): buf[offset+i] = data[i] outfile = file(sys.argv[2],'w') for char in buf: outfile.write(char)
def verify_firmware(firmware): """Verify a firmware image. Validate that the header is well formed and the checksums for the ELF segments are correct. Throw an AssertionError on validation failure. """ assert len(firmware) > ctypes.sizeof(ElfHeader), "Invalid header" header = ElfHeader.from_buffer_copy(firmware) elfdata = firmware[ctypes.sizeof(ElfHeader):] # verify the header assert header.magic == 0x05b1adba, "Invalid header" assert header.version == 1, "Invalid header" assert header.num_cksums == 1, "Invalid header" # verify the header checksums and offsets are consistent and fall within # the right segments elf = ELFFile(io.BytesIO(elfdata)) load_segments = [seg for seg in elf.iter_segments() if seg.header.p_type == "PT_LOAD"] assert len(load_segments) == 2, "Image corrupted" # verify that both checksums are in the first (text) segment seg = load_segments[0] assert seg.header.p_flags == (P_FLAGS.PF_R | P_FLAGS.PF_X), "Invalid header" assert header.c1_offset >= seg.header.p_offset, "Invalid header" assert header.c1_offset < seg.header.p_offset + seg.header.p_filesz, "Invalid header" # verify the header checksums match the embedded checksums c1_embedded = elfdata[header.c1_offset:header.c1_offset+4] assert header.c1_cksum == struct.unpack("<I", c1_embedded)[0], "Invalid header or image corrupted" # recalculate and verify the checksums segdata = load_segments[0].data() c1_idx = header.c1_offset - load_segments[0].header.p_offset crc32 = crcmod.predefined.Crc("crc-32") crc32.update(segdata[:c1_idx]) crc32.update(segdata[c1_idx + 4:]) assert crc32.crcValue == header.c1_cksum, "Image corrupted"
def getCodeSegment(binary_file): """Get executable segments area from binary file. Parameters: binary_file (str): binary file including path. Returns: [(int, int)] """ result = [] if binary_file: with open(binary_file, 'rb') as f: elffile = ELFFile(f) for segment in elffile.iter_segments(): if (segment['p_flags'] & 0b1): start = segment['p_vaddr'] end = start + segment['p_memsz'] result.append((start, end)) return result else: return result
def prelink_libs(libs, outdir, existing_mappings, baseaddr=0xf0ffffff): """For every library we calculate its size and alignment, find a space in our new compact addr space and create a copy of the library that is prelinked to the addr. Start mapping these from the *end* of the addr space down, but leaving a bit of space at the top for stuff like the stack.""" for lib in libs: with open(lib, 'rb') as f: # Determine the alignment and size required for all LOAD segments # combined align, size = 0, 0 e = ELFFile(f) for seg in e.iter_segments(): if seg['p_type'] != 'PT_LOAD': continue if seg['p_align'] > align: align = seg['p_align'] size = seg['p_vaddr'] + seg['p_memsz'] baseaddr -= size # Search for a slot that is not overlapping with anything else and # aligned properly found = False while not found: if baseaddr % align: baseaddr -= baseaddr % align overlap = get_overlap((baseaddr, size), existing_mappings) if overlap: baseaddr = overlap[0] - size else: found = True print "Found %08x - %08x for %s" % (baseaddr, baseaddr + size, lib) newlib = os.path.join(outdir, os.path.basename(lib)) shutil.copy(lib, newlib) ex("prelink -r 0x%x \"%s\"" % (baseaddr, newlib))
def test_reading_symbols_gnu_hash(self): """ Verify we can read symbol table without SymbolTableSection but with a GNU symbol hash table""" with open(os.path.join('test', 'testfiles_for_unittests', 'android_dyntags.elf'), 'rb') as f: elf = ELFFile(f) for segment in elf.iter_segments(): if segment.header.p_type != 'PT_DYNAMIC': continue num_symbols = segment.num_symbols() symbol_names = [x.name for x in segment.iter_symbols()] symbol_at_index_3 = segment.get_symbol(3) symbols_atfork = segment.get_symbol_by_name('__register_atfork') self.assertEqual(num_symbols, 212) exp = ['', '__cxa_finalize' , '__cxa_atexit', '__register_atfork', '__stack_chk_fail', '_ZNK7android7RefBase9decStrongEPKv', '_ZN7android7RefBaseD2Ev', '_ZdlPv', 'pthread_mutex_lock'] self.assertEqual(symbol_names[:9], exp) self.assertEqual(symbol_at_index_3.name, '__register_atfork') self.assertIsNotNone(symbols_atfork) self.assertEqual(symbols_atfork[0], symbol_at_index_3)
from elftools.elf.elffile import ELFFile from elftools.elf.segments import InterpSegment installdir = sys.argv[1] # generate shell wrappers for dynamically linked ELF to run them with embedded dynamic linker for root, dirs, files in os.walk(installdir): for file in files: filepath = os.path.join(root, file) try: with open(filepath, 'rb') as filed: try: e = ELFFile(filed) if e.header.e_type == 'ET_EXEC': is_dynamic_elf = False for s in e.iter_segments(): if isinstance(s, InterpSegment): # This ELF is a dynamically linked one dynamic_linker_path = s.get_interp_name() is_dynamic_elf = True break if is_dynamic_elf: del e filed.close() wrapped_path = os.path.join(root, file + '_wrapped') os.rename(filepath, wrapped_path) target_path = wrapped_path.replace(installdir, '') filed = open(filepath, 'w+') filed.write("""#!/bin/sh export ROOTFS_RO=$SNAP export ROOTFS_RW=$SNAP_DATA export LD_LIBRARY_PATH=$SNAP/usr/lib:$SNAP/lib:$LD_LIBRARY_PATH
start, end = map(lambda x: int(x, 16), m.groups()[:2]) mappings.append((start, end, m.group(3), mapping)) hooks = dict() deps = list() soname = '?' base = int(argv[2], 16) with open(argv[1], 'rb') as inp: try: elf = ELFFile(inp, loadbase = base) except ELFError: exit(1) for seg in elf.iter_segments(): if not isinstance(seg, DynamicSegment): continue try: soname = seg['DT_SONAME'].soname print >>stderr, seg['DT_SONAME'] except KeyError: soname = 'main' for tag in seg.iter_tags(): if tag.entry.d_tag == 'DT_NEEDED': print >> stderr, tag deps.append(tag.needed) try: