def read_program(filename): ''' Identifies the program header (ELF/PE) and returns an ELF, PE or DataIO instance. Args: filename (str): the program to read. Returns: an instance of currently supported program format (ELF, PE) ''' try: data = open(filename, 'rb') except (TypeError, IOError): data = bytes(filename) f = DataIO(data) try: # open file as a ELF object: p = elf.Elf(f) logger.info("ELF format detected") return p except elf.ElfError: f.seek(0) logger.debug('ElfError raised for %s' % f.name) try: # open file as a PE object: p = pe.PE(f) logger.info("PE format detected") return p except pe.PEError: f.seek(0) logger.debug('PEError raised for %s' % f.name) try: # open file as a HEX object: p = utils.HEX(f) logger.info("HEX format detected") return p except utils.FormatError: f.seek(0) logger.debug(' HEX FormatError raised for %s' % f.name) try: # open file as a SREC object: p = utils.SREC(f) logger.info("SREC format detected") return p except utils.FormatError: f.seek(0) logger.debug(' SREC FormatError raised for %s' % f.name) logger.warning('unknown format') return f
def __init__(self, romfile, cpu): try: f = open(romfile, "rb") except (ValueError, TypeError, IOError): print("romfile '%s' not found" % romfile) else: rom = DataIO(f) super().__init__(shellcode(rom), cpu) # setup memory space: # ------------------- # [0x0000-0x00FF] zero page: self.state.mmap.write(0, b'\0' * 0x100) # [0x0100-0x01FF] stack: self.state.mmap.write(0x100, b'\0' * 0x100) # [0x0200-0x02FF] input buffer (keyboard/floppy): self.state.mmap.write(0x200, b'\0' * 0x100) # [0x0300-0x03FF] program space & system API: self.state.mmap.write(0x300, b'\0' * 0x100) # [0x0400-0x07FF] video page1: self.state.mmap.write(0x400, b'\0' * 0x400) # [0x0800-0x0BFF] video page2: self.state.mmap.write(0x800, b'\0' * 0x400) # [0x0C00-0x1FFF] is free... # [0x2000-0x3FFF] high-res video page1: self.state.mmap.write(0x2000, b'\0' * 0x2000) # [0x4000-0x5FFF] high-res video page2: self.state.mmap.write(0x4000, b'\0' * 0x2000) # [0x6000-0xBFFF] is free... # [0xC000-0xC0FF] memory-mapped I/O: for io, addr in IOMAP: xf = cpu.ext(io, size=8) xf.stub = Apple2c.stub(xf.ref) self.state.mmap.write(addr, xf) # [0xC100-0xFFFF] ROM memory: self.setup_rom()
def read_program(filename): ''' Identifies the program header (ELF/PE) and returns an ELF, PE or DataIO instance. Args: filename (str): the program to read. Returns: an instance of currently supported program format (ELF, PE) ''' obj = None try: # open file as a ELF object: p = elf.Elf(filename) logger.info("ELF format detected") return p except elf.ElfError: pass try: # open file as a PE object: p = pe.PE(filename) logger.info("PE format detected") return p except pe.PEError: pass logger.warning('unknown format') try: data = open(filename, 'rb') except (TypeError, IOError): data = filename return DataIO(data)
def __init__(self,filename): try: f = open(filename,'rb') except (TypeError,IOError): f = str(filename) data = DataIO(f) self.data = data # parse DOS header: self.DOS = DOSHdr(data) # parse PE header: self.NT = COFFHdr(data,self.DOS.e_lfanew) # parse Optional Header: self.Opt = OptionalHdr(data,self.DOS.e_lfanew+len(self.NT)) self.basemap = self.Opt.ImageBase if self.NT.SizeOfOptionalHeader != len(self.Opt): logger.warning('Optional header size mismatch') # read Sections: self.sections = [] offset = self.DOS.e_lfanew + len(self.NT) + self.NT.SizeOfOptionalHeader for i in range(self.NT.NumberOfSections): s = SectionHdr(data,offset) self.sections.append(s) offset += len(s) self.functions = self.__functions() self.variables = self.__variables() self.tls = self.__tls()
def test_parser_elf32(samples): for filename in samples: if filename[-4:] == '.elf': with open(filename, 'rb') as f: p = Elf(DataIO(f)) assert p.Ehdr.e_ident.ELFMAG == b'ELF' assert p.Ehdr.e_ident.EI_CLASS == 1
def test_parser_hex(samples): for filename in samples: if filename[-4:] == '.hex': with open(filename, 'rb') as f: p = HEX(DataIO(f)) assert len(p.L) == 163 assert isinstance(p.L[0], HEXline) assert p.L[-1].HEXcode == EndOfFile
def decode(self): mem = [] for l in self.L: if l.SRECtype in (Data16, Data24, Data32): mem.append((l.address, l.data)) m = MemoryMap() for (k, v) in mem: m.write(k, v) if len(m._zones) == 1: self.__dataio = DataIO(m._zones[None].dump())
def __init__(self, filename): from amoco.system.loader import read_program self.rom = read_program(filename) self.ivt = IVT(self.rom, offset=self.IVT_offset) assert self.ivt.self != 0 ILR = DataIO(self.rom[0:4096]) RawExec.__init__(self, ILR, cpu=cpu_armv7) start = self.ivt.self - self.IVT_offset self.relocate(start) if self.ivt.boot_data: self.boot_data = BootData(self.mmap, self.ivt.boot_data) off = self.boot_data.start - start data = self.rom[off:off + self.boot_data.size] self.mmap.write(self.boot_data.start, data) assert self.ivt.csf self.csf = CSF(self.mmap, self.ivt.csf)
def decode(self): seg = 0 ela = 0 lines = [] for l in self.L: if l.HEXcode == ExtendedSegmentAddress: seg = l.base elif l.HEXcode == ExtendedLinearAddress: ela = l.ela elif l.HEXcode == Data: if ela: address = (ela << 16) + l.address elif seg: address = (seg * 16) + l.address else: address = l.address lines.append((address, l.data)) m = MemoryMap() self.__lines = lines for k, v in lines: m.write(k, v) if len(m._zones) == 1: self.__dataio = DataIO(m._zones[None].dump())
def read_program(filename): obj = None try: # open file as a ELF object: p = elf.Elf(filename) logger.info("ELF format detected") return p except elf.ElfError: pass try: # open file as a PE object: p = pe.PE(filename) logger.info("PE format detected") return p except pe.PEError: pass logger.warning('unknown format') try: data = file(filename,'rb') except (TypeError,IOError): data = filename return DataIO(data)
def test_raw_002(sc1): p = RawExec(DataIO(sc1))
def __init__(self, filename): try: f = open(filename, 'rb') except (TypeError, IOError): from amoco.system.core import DataIO f = DataIO(bytes(filename)) self.__file = f data = self.__file.read(52) if len(data) < 52: data = data.ljust(52, b'\x00') self.Ehdr = Elf32_Ehdr(data) self.dynamic = False # read program header table: should not raise any errors self.Phdr = [] if self.Ehdr.e_phoff: self.__file.seek(self.Ehdr.e_phoff) n, l = self.Ehdr.e_phnum, self.Ehdr.e_phentsize data = self.__file.read(n * l) for pht in range(n): logger.progress(pht, n, u'parsing Phdrs ') self.Phdr.append(Elf32_Phdr(data[pht * l:])) if self.Phdr[-1].p_type == PT_LOAD: if not self.basemap: self.basemap = self.Phdr[-1].p_vaddr elif self.Phdr[-1].p_type == PT_DYNAMIC: self.dynamic = True elif not self.Phdr[-1].p_type in ELF_CONSTS['p_type'].keys(): logger.verbose(u'invalid segment detected (removed)') self.Phdr.pop() # read section header table: unused by loader, can raise error self.Shdr = [] if self.Ehdr.e_shoff: try: self.__file.seek(self.Ehdr.e_shoff) n, l = self.Ehdr.e_shnum, self.Ehdr.e_shentsize data = self.__file.read(n * l) for sht in range(n): logger.progress(sht, n, 'parsing Shdrs ') S = Elf32_Shdr(data[sht * l:]) if S.sh_type in ELF_CONSTS['sh_type'].keys(): self.Shdr.append(S) else: raise StandardError except: logger.verbose('invalid section detected (all Shdr removed)') self.Shdr = [] # read section's name string table: n = self.Ehdr.e_shstrndx if n != SHN_UNDEF and n in range(len(self.Shdr)): S = self.Shdr[self.Ehdr.e_shstrndx] self.__file.seek(S.sh_offset) data = self.__file.read(S.sh_size) if S.sh_type != SHT_STRTAB: logger.verbose('section names not a string table') for s in self.Shdr: s.name = '' else: for s in self.Shdr: name = data[s.sh_name:].split(b'\0')[0] s.name = codecs.decode(name) self.functions = self.__functions() self.variables = self.__variables()
def test_raw_002(sc1): p = RawExec(shellcode(DataIO(sc1)))
def __init__(self): self.data = DataIO(b'')
def test_parser_srec(samples): for filename in samples: if filename[-4:] == '.srec': with open(filename, 'rb') as f: p = SREC(DataIO(f))
def test_raw_001(samples): for f in samples: if f[-4:] == '.raw': p = RawExec(DataIO(open(f, 'rb')))
def __init__(self): self.__file = DataIO(b'')
def test_raw_001(samples): for filename in samples: if filename[-4:] == '.raw': with open(filename, 'rb') as f: p = RawExec(DataIO(f))
def test_parser_elf64(samples): for filename in samples: if filename[-4:] == '.elf64': with open(filename, 'rb') as f: p = Elf64(DataIO(f)) assert p.Ehdr.e_ident['ELFMAG'] == b'ELF'
class Elf32(object): basemap = None symtab = None strtab = None reltab = None functions = None variables = None @property def entrypoints(self): return [self.Ehdr.e_entry] @property def filename(self): return self.__file.name def __init__(self, filename): try: self.__file = file(filename, 'rb') except (TypeError, IOError): from amoco.system.core import DataIO self.__file = DataIO(filename) data = self.__file.read(52) if len(data) < 52: data = data.ljust(52, '\x00') self.Ehdr = Elf32_Ehdr(data) self.dynamic = False # read program header table: should not raise any errors self.Phdr = [] if self.Ehdr.e_phoff: self.__file.seek(self.Ehdr.e_phoff) n, l = self.Ehdr.e_phnum, self.Ehdr.e_phentsize data = self.__file.read(n * l) for pht in range(n): logger.progress(pht, n, 'parsing Phdrs ') self.Phdr.append(Elf32_Phdr(data[pht * l:])) if self.Phdr[-1].p_type == PT_LOAD: if not self.basemap: self.basemap = self.Phdr[-1].p_vaddr elif self.Phdr[-1].p_type == PT_DYNAMIC: self.dynamic = True elif not self.Phdr[-1].p_type in ELF_CONSTS['p_type'].keys(): logger.verbose('invalid segment detected (removed)') self.Phdr.pop() # read section header table: unused by loader, can raise error self.Shdr = [] if self.Ehdr.e_shoff: try: self.__file.seek(self.Ehdr.e_shoff) n, l = self.Ehdr.e_shnum, self.Ehdr.e_shentsize data = self.__file.read(n * l) for sht in range(n): logger.progress(sht, n, 'parsing Shdrs ') S = Elf32_Shdr(data[sht * l:]) if S.sh_type in ELF_CONSTS['sh_type'].keys(): self.Shdr.append(S) else: raise StandardError except: logger.verbose('invalid section detected (all Shdr removed)') self.Shdr = [] # read section's name string table: n = self.Ehdr.e_shstrndx if n != SHN_UNDEF and n in range(len(self.Shdr)): S = self.Shdr[self.Ehdr.e_shstrndx] self.__file.seek(S.sh_offset) data = self.__file.read(S.sh_size) if S.sh_type != SHT_STRTAB: logger.verbose('section names not a string table') for s in self.Shdr: s.name = '' else: for s in self.Shdr: s.name = data[s.sh_name:].split('\0')[0] self.functions = self.__functions() self.variables = self.__variables() ## def getsize(self): total = sum([s.p_filesz for s in self.Phdr]) return total # allows to get info about target : # - section index (0 is error, -1 is a dynamic call) # - offset into section (idem) # - base virtual address (0 for dynamic calls) # target can be a virtual address in hex string format or integer, # or a symbol string searched in the functions dictionary. def getinfo(self, target): addr = None if isinstance(target, str): try: addr = int(target, 16) except ValueError: for a, f in self.functions.iteritems(): if f[0] == target: addr = int(a, 16) break elif type(target) in [int, long]: addr = target if addr is None: # target is propably a symbol not found in functions return None, 0, 0 # now we have addr so we can see in which section/segment it is... # sections are smaller than segments so we try first with Shdr # but this may lead to errors because what really matters are segments # loaded by the kernel binfmt_elf.c loader. if self.Shdr: for s in self.Shdr[::-1]: if s.sh_type == SHT_NULL: continue if s.sh_addr <= addr < s.sh_addr + s.sh_size: return s, addr - s.sh_addr, s.sh_addr ## elif self.Phdr: for s in self.Phdr[::-1]: if s.p_type != PT_LOAD: continue if s.p_vaddr <= addr < s.p_vaddr + s.p_filesz: return s, addr - s.p_vaddr, s.p_vaddr return None, 0, 0 ## def data(self, target, size): return self.readcode(target, size)[0] def readcode(self, target, size=None): s, offset, base = self.getinfo(target) data = '' if s: if isinstance(s, Elf32_Phdr): c = self.readsegment(s) else: c = self.readsection(s) if c: if size != None: if isinstance(c, Elf32_Str): c = c.data data = c[offset:offset + size] else: data = c[offset:] return data, 0, base + offset def readsegment(self, S): if S: if S.p_type == PT_LOAD: self.__file.seek(S.p_offset) return self.__file.read(S.p_filesz).ljust(S.p_memsz, '\x00') return None ## def loadsegment(self, S, pagesize=None): if S: if S.p_type == PT_LOAD: self.__file.seek(S.p_offset) if S.p_offset != (S.p_vaddr % S.p_align): logger.verbose('wrong p_vaddr/p_align [%08x/%0d]' % (S.p_vaddr, S.p_align)) base = S.p_vaddr bytes = self.__file.read(S.p_filesz).ljust(S.p_memsz, '\x00') if pagesize: # note: bytes are not truncated, only extended if needed... bytes = bytes.ljust(pagesize, '\x00') return {base: bytes} return None ## def readsection(self, sect): S = None if type(sect) == str: for st in self.Shdr: if st.name == sect: S = st break elif type(sect) in [int, long]: S = self.Shdr[sect] else: S = sect if S: if S.sh_type in (SHT_SYMTAB, SHT_DYNSYM): return self.__read_symtab(S) elif S.sh_type == SHT_STRTAB: return self.__read_strtab(S) elif S.sh_type in (SHT_REL, SHT_RELA): return self.__read_relocs(S) elif S.sh_type == SHT_DYNAMIC: return self.__read_dynamic(S) elif S.sh_type == SHT_PROGBITS: self.__file.seek(S.sh_offset) return self.__file.read(S.sh_size) return None ## def __read_symtab(self, section): if section.sh_type not in (SHT_SYMTAB, SHT_DYNSYM): logger.warning('not a symbol table section') return None # read the section: self.__file.seek(section.sh_offset) data = self.__file.read(section.sh_size) # and parse it into Elf32_Sym objects: l = section.sh_entsize if (section.sh_size % l) != 0: raise ElfError('symbol table size mismatch') else: n = section.sh_size / l symtab = [] for i in range(n): symtab.append(Elf32_Sym(data[i * l:])) self.symtab = symtab return symtab ## def __read_strtab(self, section): if section.sh_type != SHT_STRTAB: raise ElfError('not a string table section') self.__file.seek(section.sh_offset) data = self.__file.read(section.sh_size) strtab = Elf32_Str(data) self.strtab = strtab return strtab ## def __read_relocs(self, section): if section.sh_type not in (SHT_REL, SHT_RELA): logger.warning('not a relocation table section') return None self.__file.seek(section.sh_offset) data = self.__file.read(section.sh_size) l = section.sh_entsize if (section.sh_size % l) != 0: raise ElfError('relocation table size mismatch') else: n = section.sh_size / l reltab = [] if section.sh_type == SHT_REL: for i in range(n): reltab.append(Elf32_Rel(data[i * l:])) elif section.sh_type == SHT_RELA: for i in range(n): reltab.append(Elf32_Rela(data[i * l:])) self.reltab = reltab return reltab def __read_dynamic(self, section): if section.sh_type != SHT_DYNAMIC: logger.warning('not a dynamic linking section') return None # read the section: self.__file.seek(section.sh_offset) data = self.__file.read(section.sh_size) # and parse it into Elf32_Dyn objects: l = section.sh_entsize if (section.sh_size % l) != 0: raise ElfError('dynamic linking size mismatch') else: n = section.sh_size / l dyntab = [] for i in range(n): dyntab.append(Elf32_Dyn(data[i * l:])) self.dyntab = dyntab return dyntab ## def __read_note(self, section): if section.sh_type != SHT_NOTE: logger.warning('not a note section') return None self.__file.seek(section.sh_offset) data = self.__file.read(section.sh_size) note = Elf32_Note(data) self.note = note return note ## def __functions(self, fltr=None): D = self.__symbols(STT_FUNC) # fltr applies to section name only : if fltr: for k, v in D.iteritems(): if self.Shdr[v[2]].name != fltr: D.pop(k) if self.dynamic: D.update(self.__dynamic(STT_FUNC)) return D def __variables(self, fltr=None): D = self.__symbols(STT_OBJECT) # fltr applies also to section name : if fltr: for k, v in D.iteritems(): if self.Shdr[v[2]].name != fltr: D.pop(k) return D def __symbols(self, t): if not self.readsection('.symtab'): return {} D = {} if self.readsection('.strtab'): for sym in self.symtab: if sym.st_type == t and sym.st_value: D[sym.st_value] = (self.strtab[sym.st_name], sym.st_size, sym.st_info, sym.st_shndx) else: # need to build a fake strtab with our own symbol names: pass #TODO return D def __dynamic(self, type=STT_FUNC): if not self.readsection('.dynsym'): return {} D = {} if self.readsection('.dynstr'): for i, s in enumerate(self.Shdr): if s.sh_type in (SHT_REL, SHT_RELA): if self.readsection(i): for r in self.reltab: if r.r_offset: sym = self.symtab[r.r_sym] D[r.r_offset] = self.strtab[sym.st_name] else: # need to build a fake strtab with our own symbol names: pass #TODO return D def __str__(self): ss = ['ELF header:'] tmp = self.Ehdr.pfx self.Ehdr.pfx = '\t' ss.append(self.Ehdr.__str__()) self.Ehdr.pfx = tmp ss += ['\nSections:'] for s in self.Shdr: tmp = s.pfx s.pfx = '\t' ss.append(s.__str__()) ss.append('---') s.pfx = tmp ss += ['\nSegments:'] for s in self.Phdr: tmp = s.pfx s.pfx = '\t' ss.append(s.__str__()) ss.append('---') s.pfx = tmp return '\n'.join(ss)