def read_phdrs(self, at_phdr=None, at_phnum=None): ''' Using the auxv array information, read and populate the phdrs list. @type at_phdr: Integer @param at_phdr: Location of the program headers @type at_phnum: Integer @param at_phnum: Number of program headers ''' if at_phdr == None: print "Location (AT_PHDR) could not be read, exiting" self.doexit() if at_phnum == None: print "Number (AT_PHNUM) could not be read, exiting" self.doexit() location = at_phdr for count in xrange(at_phnum): if CPU_WORD_SIZE == 4: length = len(Elf.Elf32Pheader()) self.phdrs.append(\ Elf.Elf32Pheader(self.read_memory_libc(location,length))) elif CPU_WORD_SIZE == 8: length = len(Elf.Elf64Pheader()) self.phdrs.append(\ Elf.Elf64Pheader(self.read_memory_libc(location,length))) location = location + length
def test_minimal(self): for path in (('linux','amd64','static64.llvm.elf'), ('linux','i386','static32.llvm.elf')): logger.warn("======== %r ========", path) fn = helpers.getTestPath(*path) e = Elf.Elf(file(fn)) vw = viv_cli.VivCli() vw.loadFromFile(fn)
def parseBinary(self): typemap = { Elf.STT_FUNC: vtrace.SYM_FUNCTION, Elf.STT_SECTION: vtrace.SYM_SECTION, Elf.STT_OBJECT: vtrace.SYM_GLOBAL } elf = Elf.Elf(self.filename) base = self.loadbase # Quick pass to see if we need to assume prelink for sec in elf.sections: if sec.name != ".text": continue # Try to detect prelinked if sec.sh_addr != sec.sh_offset: base = 0 break for sec in elf.sections: self.addSymbol(sec.name, sec.sh_addr + base, sec.sh_size, vtrace.SYM_SECTION) for sym in elf.symbols: self.addSymbol(sym.name, sym.st_value + base, sym.st_size, typemap.get((sym.st_info & 0xf), vtrace.SYM_MISC)) for sym in elf.dynamic_symbols: self.addSymbol(sym.name, sym.st_value + base, sym.st_size, typemap.get((sym.st_info & 0xf), vtrace.SYM_MISC))
def test_files(self): results = [] for name, test_data, path in self.data: logger.warning("======== %r ========", name) fn = helpers.getTestPath(*path) e = Elf.Elf(open(fn, 'rb')) vw = viv_cli.VivCli() vw.loadFromFile(fn) do_analyze(vw) logger.debug("testing %r (%r)...", name, fn) retval = self.do_file(vw, test_data, name) results.append(retval) failed = 0 for fidx, tres in enumerate(results): for testname, testdata in tres.items(): if testdata != (0, 0): failed += testdata[0] + testdata[1] fname = self.data[fidx][0] failed_old, failed_new = testdata logger.error('%s: %s: missing: %r new: %r (%r)', fname, testname, failed_old, failed_new, fname) self.assertEqual(failed, 0, msg="ELF Tests Failed (see error log)")
def platformParseBinary(self, filename, baseaddr, normname): typemap = { Elf.STT_FUNC: e_resolv.FunctionSymbol, Elf.STT_SECTION: e_resolv.SectionSymbol, } fd = file(filename, 'rb') elf = Elf.Elf(fd) addbase = 0 if not elf.isPreLinked() and elf.isSharedObject(): addbase = baseaddr for sec in elf.sections: sym = e_resolv.SectionSymbol(sec.name, sec.sh_addr + addbase, sec.sh_size, normname) self.addSymbol(sym) for sym in elf.symbols: symclass = typemap.get((sym.st_info & 0xf), e_resolv.Symbol) sym = symclass(sym.name, sym.st_value + addbase, sym.st_size, normname) self.addSymbol(sym) for sym in elf.dynamic_symbols: symclass = typemap.get((sym.st_info & 0xf), e_resolv.Symbol) sym = symclass(sym.name, sym.st_value + addbase, sym.st_size, normname) self.addSymbol(sym)
def dynamic_array_entry_generator(self, offset): ''' Iterate over the dynamic array entries. It will automatically seek() via the reads. We do an infinite loop since we don't know where DT_NULL will be found. @type offset: Integer @param offset: Offset to where the dynamic array can be found ''' while 1: self.elf.seek(offset, 0) offset = offset + CPU_WORD_SIZE * 2 if CPU_WORD_SIZE == 4: yield Elf.Elf32Dynamic(self.elf.read(CPU_WORD_SIZE * 2)) elif CPU_WORD_SIZE == 8: yield Elf.Elf64Dynamic(self.elf.read(CPU_WORD_SIZE * 2))
def DISABLEtest_minimal(self): ''' Until we've got soe decent tests for this, all this does is prolong the test time ''' for path in (('linux','amd64','static64.llvm.elf'), ('linux','i386','static32.llvm.elf')): logger.warning("======== %r ========", path) fn = helpers.getTestPath(*path) e = Elf.Elf(open(fn, 'rb')) vw = viv_cli.VivCli() vw.loadFromFile(fn)
def makeRelocTable(vw, va, maxva, addbase, baseaddr, addend=False): if addend: sname = 'elf.Elf%dReloca' % (vw.getPointerSize() * 8) else: sname = 'elf.Elf%dReloc' % (vw.getPointerSize() * 8) while va < maxva: s = vw.makeStructure(va, sname) tname = Elf.r_types_386.get(Elf.getRelocType(s.r_info), "Unknown Type") vw.setComment(va, tname) va += len(s)
def platformParseBinary(self, filename, baseaddr, normname): typemap = { Elf.STT_FUNC: e_resolv.FunctionSymbol, Elf.STT_SECTION: e_resolv.SectionSymbol, } try: fd = self.platformOpenFile(filename) elf = Elf.Elf(fd) except IOError: try: # it's possible we hit vdso or something similar elf = Elf.elfFromMemoryObject(self, baseaddr) except: raise # elf = Elf.Elf(fd) addbase = 0 if not elf.isPreLinked() and elf.isSharedObject(): addbase = baseaddr for sec in elf.sections: sym = e_resolv.SectionSymbol(sec.name, sec.sh_addr + addbase, sec.sh_size, normname) self.addSymbol(sym) for sym in elf.symbols: symclass = typemap.get((sym.st_info & 0xf), e_resolv.Symbol) sym = symclass(sym.name, sym.st_value + addbase, sym.st_size, normname) self.addSymbol(sym) for sym in elf.dynamic_symbols: symclass = typemap.get((sym.st_info & 0xf), e_resolv.Symbol) sym = symclass(sym.name, sym.st_value + addbase, sym.st_size, normname) self.addSymbol(sym) if elf.isExecutable(): sym = e_resolv.Symbol('__entry', elf.e_entry, 0, normname) self.addSymbol(sym)
def update_elfDict(game, my_elves): global elfDict if my_elves: # add new and delete old elves from the dictionary for elf in my_elves: # add new if elf.unique_id not in elfDict.keys(): elfDict[elf.unique_id] = Elf(game, elf) for uid in elfDict.keys(): # delete old if uid not in [elf.unique_id for elf in my_elves]: del elfDict[uid] else: # if we have no elves just clear the dictionary elfDict.clear() for elf in elfDict.values(): # update game for all elf objects elf.game = game
def parse_dt_symtab(self, dyn): ''' Callback responsible for parsing the DT_SYMTAB dynamic array entry. Currently this just locates where the .symtab section is. Override this function to perform your own analysis on DT_SYMTAB. @type dyn: ElfXXDynamic @param dyn: Dynamic array entry ''' if CPU_WORD_SIZE == 4: self.elf_header.sections.append(Elf.Elf32Section()) elif CPU_WORD_SIZE == 8: self.elf_header.sections.append(Elf.Elf64Section()) symtab = self.elf_header.sections[-1] symtab.setName(".symtab") if self.elf_header.e_type == Elf.ET_EXEC: symtab.sh_offset = dyn.d_value #XXX: symtab.sh_offset = dyn.d_value - BASEADDR elif self.elf_header.e_type == Elf.ET_DYN: symtab.sh_offset = dyn.d_value
def find_elf_header(self): ''' Find and populate an ELF header structure. Will also clear all section header information since it is invalid. ''' self.elf.seek(0, 0) self.elf_header = Elf.Elf(self.elf.read(64)) self.elf_header.myname = "rebuilt elf header" self.elf_header.e_shoff = 0 self.elf_header.e_shentsize = 0 self.elf_header.e_shnum = 0 self.elf_header.e_shstrndx = 0 self.elf.seek(0, 0) self.elf.write(self.elf_header.serialize())
def createUnitToBuy(self): self.uniteToBuy = [ Amazon(), Dwarf(), Elf(), Giant(), Hobbit(), Humans(), Mago(), Orc(), Rats(), Skeletton(), Triton(), Troll(), Wizzard(), Zombie() ] shuffle(self.uniteToBuy)
def setUpClass(cls): super(ELFTests, cls).setUpClass() cls.tests = [] for test in data: name, test_data, path = test logger.warn("======== %r ========", name) fn = helpers.getTestPath(*path) e = Elf.Elf(file(fn)) vw = viv_cli.VivCli() vw.loadFromFile(fn) #vw.analyze() vae.analyze(vw) vagr.analyze(vw) vaeep.analyze(vw) vagp.analyze(vw) cls.tests.append((name, test_data, fn, e, vw)) cls.maxDiff = None
def platformParseBinary(self, filename, baseaddr, normname): typemap = { Elf.STT_FUNC: e_resolv.FunctionSymbol, Elf.STT_SECTION: e_resolv.SectionSymbol, } try: fd = self.platformOpenFile(filename) elf = Elf.Elf(fd) except IOError: try: # it's possible we hit vdso or something similar elf = Elf.elfFromMemoryObject(self, baseaddr) except: raise # elf = Elf.Elf(fd) addbase = 0 if not elf.isPreLinked() and elf.isSharedObject(): addbase = baseaddr for sec in elf.sections: sym = e_resolv.SectionSymbol(sec.name, sec.sh_addr+addbase, sec.sh_size, normname) self.addSymbol(sym) for sym in elf.symbols: symclass = typemap.get((sym.st_info & 0xf), e_resolv.Symbol) sym = symclass(sym.name, sym.st_value+addbase, sym.st_size, normname) self.addSymbol(sym) for sym in elf.dynamic_symbols: symclass = typemap.get((sym.st_info & 0xf), e_resolv.Symbol) sym = symclass(sym.name, sym.st_value+addbase, sym.st_size, normname) self.addSymbol(sym) if elf.isExecutable(): sym = e_resolv.Symbol('__entry', elf.e_entry, 0, normname) self.addSymbol(sym)
def __init__(self, name, trace=None, verbose=False): self.binexe = name.split(os.sep)[-1] self.verbose = verbose self.locsec = None self.bin = None self.startaddress = None self.eip = 0 self.lastcall = (0, 0) # last target and last source address if os.name == 'posix': self.bin = Elf(argv[1]) self.startaddress = self.bin.e_entry elif os.name == 'nt': self.bin = PE(argv[1]) self.startaddress = self.bin.OPTIONAL_HEADER.AddressOfEntryPoint + self.bin.OPTIONAL_HEADER.ImageBase self.me = getTrace() self.me.registerNotifier(NOTIFY_EXIT, VerboseNotifier()) self.me.registerNotifier(NOTIFY_BREAK, VerboseNotifier()) self.me.registerNotifier(NOTIFY_LOAD_LIBRARY, LibraryNotifier()) self.me.addBreakpoint( Breakpoint(self.startaddress) ) # This should get us past the loader code into the actual start of the binary self.me.metadata['RUN'] = True self.me.execute(argv[1])
def parseFd(vw, fd, filename=None, baseaddr=None): fd.seek(0) elf = Elf.Elf(fd) return loadElfIntoWorkspace(vw, elf, filename=filename, baseaddr=baseaddr)
def parseBytes(vw, bytes, baseaddr=None): fd = StringIO(bytes) elf = Elf.Elf(fd) return loadElfIntoWorkspace(vw, elf, baseaddr=baseaddr)
def parseFile(vw, filename, baseaddr=None): fd = open(filename, 'rb') elf = Elf.Elf(fd) return loadElfIntoWorkspace(vw, elf, filename=filename, baseaddr=baseaddr)
def loadElfIntoWorkspace(vw, elf, filename=None): arch = arch_names.get(elf.e_machine) if arch == None: raise Exception("Unsupported Architecture: %d\n", elf.e_machine) platform = elf.getPlatform() # setup needed platform/format vw.setMeta('Architecture', arch) vw.setMeta('Platform', platform) vw.setMeta('Format', 'elf') vw.setMeta('DefaultCall', archcalls.get(arch, 'unknown')) vw.addNoReturnApi("*.exit") # Base addr is earliest section address rounded to pagesize # NOTE: This is only for prelink'd so's and exe's. Make something for old style so. addbase = False if not elf.isPreLinked() and elf.isSharedObject(): addbase = True baseaddr = elf.getBaseAddress() #FIXME make filename come from dynamic's if present for shared object if filename == None: filename = "elf_%.8x" % baseaddr fhash = "unknown hash" if os.path.exists(filename): fhash = v_parsers.md5File(filename) fname = vw.addFile(filename.lower(), baseaddr, fhash) strtabs = {} secnames = [] for sec in elf.getSections(): secnames.append(sec.getName()) pgms = elf.getPheaders() secs = elf.getSections() for pgm in pgms: if pgm.p_type == Elf.PT_LOAD: if vw.verbose: vw.vprint('Loading: %s' % (repr(pgm))) bytez = elf.readAtOffset(pgm.p_offset, pgm.p_filesz) bytez += "\x00" * (pgm.p_memsz - pgm.p_filesz) pva = pgm.p_vaddr if addbase: pva += baseaddr vw.addMemoryMap(pva, pgm.p_flags & 0x7, fname, bytez) #FIXME perms else: if vw.verbose: vw.vprint('Skipping: %s' % repr(pgm)) if len(pgms) == 0: # fall back to loading sections as best we can... if vw.verbose: vw.vprint('elf: no program headers found!') maps = [[s.sh_offset, s.sh_size] for s in secs if s.sh_offset and s.sh_size] maps.sort() merged = [] for i in xrange(len(maps)): if merged and maps[i][0] == (merged[-1][0] + merged[-1][1]): merged[-1][1] += maps[i][1] continue merged.append(maps[i]) baseaddr = 0x05000000 for offset, size in merged: bytez = elf.readAtOffset(offset, size) vw.addMemoryMap(baseaddr + offset, 0x7, fname, bytez) for sec in secs: if sec.sh_offset and sec.sh_size: sec.sh_addr = baseaddr + sec.sh_offset # First add all section definitions so we have them for sec in secs: sname = sec.getName() size = sec.sh_size if sec.sh_addr == 0: continue # Skip non-memory mapped sections sva = sec.sh_addr if addbase: sva += baseaddr vw.addSegment(sva, size, sname, fname) # Now trigger section specific analysis for sec in secs: #FIXME dup code here... sname = sec.getName() size = sec.sh_size if sec.sh_addr == 0: continue # Skip non-memory mapped sections sva = sec.sh_addr if addbase: sva += baseaddr if sname == ".interp": vw.makeString(sva) elif sname == ".init": vw.makeName(sva, "init_function", filelocal=True) vw.addEntryPoint(sva) elif sname == ".fini": vw.makeName(sva, "fini_function", filelocal=True) vw.addEntryPoint(sva) elif sname == ".dynamic": # Imports makeDynamicTable(vw, sva, sva + size) # FIXME section names are optional, use dynamic info from .dynamic elif sname == ".dynstr": # String table for dynamics makeStringTable(vw, sva, sva + size) elif sname == ".dynsym": #print "LINK",sec.sh_link for s in makeSymbolTable(vw, sva, sva + size): pass #print "########################.dynsym",s # If the section is really a string table, do it if sec.sh_type == Elf.SHT_STRTAB: makeStringTable(vw, sva, sva + size) elif sec.sh_type == Elf.SHT_SYMTAB: makeSymbolTable(vw, sva, sva + size) elif sec.sh_type == Elf.SHT_REL: makeRelocTable(vw, sva, sva + size, addbase, baseaddr) if sec.sh_flags & Elf.SHF_STRINGS: print "FIXME HANDLE SHF STRINGS" # Let pyelf do all the stupid string parsing... for r in elf.getRelocs(): rtype = Elf.getRelocType(r.r_info) rlva = r.r_offset if addbase: rlva += baseaddr try: # If it has a name, it's an externally # resolved "import" entry, otherwise, just a regular reloc if arch in ('i386', 'amd64'): name = r.getName() if name: if rtype == Elf.R_386_JMP_SLOT: vw.makeImport(rlva, "*", name) # FIXME elf has conflicting names for 2 relocs? #elif rtype == Elf.R_386_GLOB_DAT: #vw.makeImport(rlva, "*", name) elif rtype == Elf.R_386_32: pass else: vw.verbprint('unknown reloc type: %d %s (at %s)' % (rtype, name, hex(rlva))) if arch == 'arm': name = r.getName() if name: if rtype == Elf.R_ARM_JUMP_SLOT: vw.makeImport(rlva, "*", name) else: vw.verbprint('unknown reloc type: %d %s (at %s)' % (rtype, name, hex(rlva))) except vivisect.InvalidLocation, e: print "NOTE", e
def makeRelocTable(vw, va, maxva, addbase, baseaddr): while va < maxva: s = vw.makeStructure(va, "elf.Elf32Reloc") tname = Elf.r_types_386.get(Elf.getRelocType(s.r_info), "Unknown Type") vw.setComment(va, tname) va += len(s)
def loadElfIntoWorkspace(vw, elf, filename=None): arch = arch_names.get(elf.e_machine) if arch == None: raise Exception("Unsupported Architecture: %d\n", elf.e_machine) # setup needed platform/format vw.setMeta('Architecture', arch) vw.setMeta('Platform', 'unknown') vw.setMeta('Format', 'elf') # FIXME try to determine *which* Elf system... if arch == 'i386': vw.setMeta("DefaultCall", "cdecl") elif arch == 'amd64': vw.setMeta("DefaultCall", "sysvamd64call") vw.addNoReturnApi("*.exit") # Base addr is earliest section address rounded to pagesize # NOTE: This is only for prelink'd so's and exe's. Make something for old style so. addbase = False if not elf.isPreLinked() and elf.isSharedObject(): addbase = True baseaddr = elf.getBaseAddress() #FIXME make filename come from dynamic's if present for shared object if filename == None: filename = "elf_%.8x" % baseaddr fname = vw.addFile(filename, baseaddr, v_parsers.md5File(filename)) strtabs = {} secnames = [] for sec in elf.getSections(): secnames.append(sec.getName()) for pgm in elf.getPheaders(): if pgm.p_type == Elf.PT_LOAD: if vw.verbose: vw.vprint('Loading: %s' % (repr(pgm))) bytes = elf.readAtOffset(pgm.p_offset, pgm.p_filesz) bytes += "\x00" * (pgm.p_memsz - pgm.p_filesz) pva = pgm.p_vaddr if addbase: pva += baseaddr vw.addMemoryMap(pva, pgm.p_flags & 0x7, fname, bytes) #FIXME perms else: if vw.verbose: vw.vprint('Skipping: %s' % repr(pgm)) # First add all section definitions so we have them for sec in elf.getSections(): sname = sec.getName() size = sec.sh_size if sec.sh_addr == 0: continue # Skip non-memory mapped sections sva = sec.sh_addr if addbase: sva += baseaddr vw.addSegment(sva, size, sname, fname) # Now trigger section specific analysis for sec in elf.getSections(): #FIXME dup code here... sname = sec.getName() size = sec.sh_size if sec.sh_addr == 0: continue # Skip non-memory mapped sections sva = sec.sh_addr if addbase: sva += baseaddr if sname == ".interp": vw.makeString(sva) elif sname == ".init": vw.makeName(sva, "init_function", filelocal=True) vw.addEntryPoint(sva) elif sname == ".fini": vw.makeName(sva, "fini_function", filelocal=True) vw.addEntryPoint(sva) elif sname == ".dynamic": # Imports makeDynamicTable(vw, sva, sva+size) # FIXME section names are optional, use dynamic info from .dynamic elif sname == ".dynstr": # String table for dynamics makeStringTable(vw, sva, sva+size) elif sname == ".dynsym": #print "LINK",sec.sh_link for s in makeSymbolTable(vw, sva, sva+size): pass #print "########################.dynsym",s # If the section is really a string table, do it if sec.sh_type == Elf.SHT_STRTAB: makeStringTable(vw, sva, sva+size) elif sec.sh_type == Elf.SHT_SYMTAB: # FIXME 32 bit specific! #print "FOUND A SYMBOL TABLE!" makeSymbolTable(vw, sva, sva+size) elif sec.sh_type == Elf.SHT_REL: makeRelocTable(vw, sva, sva+size, addbase, baseaddr) if sec.sh_flags & Elf.SHF_STRINGS: print "FIXME HANDLE SHF STRINGS" # Let pyelf do all the stupid string parsing... for r in elf.getRelocs(): rtype = Elf.getRelocType(r.r_info) rlva = r.r_offset if addbase: rlva += baseaddr try: # If it has a name, it's an externally # resolved "import" entry, otherwise, just a regular reloc if arch in ('i386','amd64'): name = r.getName() if name: if rtype == Elf.R_386_JMP_SLOT: vw.makeImport(rlva, "*", name) # FIXME elf has conflicting names for 2 relocs? #elif rtype == Elf.R_386_GLOB_DAT: #vw.makeImport(rlva, "*", name) elif rtype == Elf.R_386_32: pass else: vw.verbprint('unknown reloc type: %d %s (at %s)' % (rtype, name, hex(rlva))) if arch == 'arm': name = r.getName() if name: if rtype == Elf.R_ARM_JUMP_SLOT: vw.makeImport(rlva, "*", name) else: vw.verbprint('unknown reloc type: %d %s (at %s)' % (rtype, name, hex(rlva))) except vivisect.InvalidLocation, e: print "NOTE",e
def applyRelocs(elf, vw, addbase=False, baseaddr=0): # process relocations / strings (relocs use Dynamic Symbols) arch = arch_names.get(elf.e_machine) relocs = elf.getRelocs() logger.debug("reloc len: %d", len(relocs)) for r in relocs: rtype = Elf.getRelocType(r.r_info) rlva = r.r_offset if addbase: rlva += baseaddr try: # If it has a name, it's an externally resolved "import" entry, # otherwise, just a regular reloc name = r.getName() dmglname = demangle(name) logger.debug('relocs: 0x%x: %r (%r)', rlva, dmglname, name) if arch in ('i386', 'amd64'): if name: if rtype == Elf.R_X86_64_IRELATIVE: # before making import, let's fix up the pointer as a BASEPTR Relocation ptr = r.r_addend vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr) logger.info('Reloc: R_X86_64_IRELATIVE 0x%x', rlva) if rtype in (Elf.R_386_JMP_SLOT, Elf.R_X86_64_GLOB_DAT, Elf.R_X86_64_IRELATIVE): logger.info('Reloc: making Import 0x%x (name: %s/%s) ', rlva, name, dmglname) vw.makeImport(rlva, "*", dmglname) vw.setComment(rlva, name) elif rtype in (Elf.R_386_32, Elf.R_386_COPY): pass else: logger.warn('unknown reloc type: %d %s (at %s)', rtype, name, hex(rlva)) logger.info(r.tree()) else: if rtype == Elf.R_386_RELATIVE: # R_X86_64_RELATIVE is the same number ptr = vw.readMemoryPtr(rlva) logger.info( 'R_386_RELATIVE: adding Relocation 0x%x -> 0x%x (name: %s) ', rlva, ptr, dmglname) vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr) elif rtype == Elf.R_X86_64_IRELATIVE: # first make it a relocation that is based on the imagebase ptr = r.r_addend logger.info( 'R_X86_64_IRELATIVE: adding Relocation 0x%x -> 0x%x (name: %r %r) ', rlva, ptr, name, dmglname) vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr) # next get the target and find a name, since the reloc itself doesn't have one tgt = vw.readMemoryPtr(rlva) tgtname = vw.getName(tgt) if tgtname is not None: logger.info(' name(0x%x): %r', tgt, tgtname) fn, symname = tgtname.split('.', 1) logger.info( 'Reloc: making Import 0x%x (name: %s.%s) ', rlva, fn, symname) vw.makeImport(rlva, fn, symname) else: logger.warn('unknown reloc type: %d %s (at %s)', rtype, name, hex(rlva)) logger.info(r.tree()) if arch in ('arm', 'thumb', 'thumb16'): if rtype == Elf.R_ARM_JUMP_SLOT: symidx = r.getSymTabIndex() sym = elf.getDynSymbol(symidx) ptr = sym.st_value #quick check to make sure we don't provide this symbol if ptr: logger.info( 'R_ARM_JUMP_SLOT: adding Relocation 0x%x -> 0x%x (%s) ', rlva, ptr, dmglname) if addbase: vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr) else: vw.addRelocation(rlva, vivisect.RTYPE_BASERELOC, ptr) pname = "ptr_%s_%.8x" % (name, rlva) if vw.vaByName(pname) is None: vw.makeName(rlva, pname) if addbase: ptr += baseaddr vw.makeName(ptr, name) vw.setComment(ptr, dmglname) else: logger.info( 'R_ARM_JUMP_SLOT: adding Import 0x%x (%s) ', rlva, dmglname) vw.makeImport(rlva, "*", dmglname) vw.setComment(rlva, name) elif rtype == Elf.R_ARM_GLOB_DAT: symidx = r.getSymTabIndex() sym = elf.getDynSymbol(symidx) ptr = sym.st_value #quick check to make sure we don't provide this symbol if ptr: logger.info( 'R_ARM_GLOB_DAT: adding Relocation 0x%x -> 0x%x (%s) ', rlva, ptr, dmglname) vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr) pname = "ptr_%s" % name if vw.vaByName(pname) is None: vw.makeName(rlva, pname) if addbase: ptr += baseaddr vw.makeImport(ptr, "*", dmglname) vw.setComment(ptr, name) else: logger.info('R_ARM_GLOB_DAT: adding Import 0x%x (%s) ', rlva, dmglname) vw.makeImport(rlva, "*", dmglname) vw.setComment(rlva, name) elif rtype == Elf.R_ARM_ABS32: symidx = r.getSymTabIndex() sym = elf.getDynSymbol(symidx) ptr = sym.st_value if ptr: logger.info( 'R_ARM_ABS32: adding Relocation 0x%x -> 0x%x (%s) ', rlva, ptr, dmglname) vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr) pname = "ptr_%s" % name if vw.vaByName(pname) is None and len(name): vw.makeName(rlva, pname) else: logger.info('R_ARM_ABS32: adding Import 0x%x (%s) ', rlva, dmglname) vw.makeImport(rlva, "*", dmglname) vw.setComment(rlva, name) vw.setComment(rlva, dmglname) elif rtype == Elf.R_ARM_RELATIVE: # Adjust locations for the rebasing ptr = vw.readMemoryPtr(rlva) logger.info( 'R_ARM_RELATIVE: adding Relocation 0x%x -> 0x%x (name: %s) ', rlva, ptr, dmglname) vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr) if len(name): vw.makeName(rlva, dmglname, makeuniq=True) vw.setComment(rlva, name) else: logger.warn('unknown reloc type: %d %s (at %s)', rtype, name, hex(rlva)) logger.info(r.tree()) except vivisect.InvalidLocation as e: logger.warn("NOTE\t%r", e)
def applyRelocs(elf, vw, addbase=False, baseaddr=0): ''' process relocations / strings (relocs use Dynamic Symbols) ''' arch = arch_names.get(elf.e_machine) relocs = elf.getRelocs() logger.debug("reloc len: %d", len(relocs)) for r in relocs: rtype = Elf.getRelocType(r.r_info) rlva = r.r_offset if addbase: rlva += baseaddr try: # If it has a name, it's an externally resolved "import" entry, # otherwise, just a regular reloc name = r.getName() dmglname = demangle(name) logger.debug('relocs: 0x%x: %s (%s)', rlva, dmglname, name) if arch in ('i386', 'amd64'): if name: if rtype == Elf.R_X86_64_IRELATIVE: # before making import, let's fix up the pointer as a BASEPTR Relocation ptr = r.r_addend vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr) logger.info('Reloc: R_X86_64_IRELATIVE 0x%x', rlva) if rtype in (Elf.R_386_JMP_SLOT, Elf.R_X86_64_GLOB_DAT, Elf.R_X86_64_IRELATIVE): logger.info('Reloc: making Import 0x%x (name: %s/%s) ', rlva, name, dmglname) vw.makeImport(rlva, "*", dmglname) vw.setComment(rlva, name) elif rtype in (Elf.R_386_32, Elf.R_386_COPY, Elf.R_X86_64_TPOFF64): pass else: logger.warning('unknown reloc type: %d %s (at %s)', rtype, name, hex(rlva)) logger.info(r.tree()) else: if rtype == Elf.R_386_RELATIVE: # R_X86_64_RELATIVE is the same number ptr = vw.readMemoryPtr(rlva) logger.info( 'R_386_RELATIVE: adding Relocation 0x%x -> 0x%x (name: %s) ', rlva, ptr, dmglname) vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr) elif rtype == Elf.R_X86_64_IRELATIVE: # first make it a relocation that is based on the imagebase ptr = r.r_addend logger.info( 'R_X86_64_IRELATIVE: adding Relocation 0x%x -> 0x%x (name: %r %r) ', rlva, ptr, name, dmglname) vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr) # next get the target and find a name, since the reloc itself doesn't have one tgt = vw.readMemoryPtr(rlva) tgtname = vw.getName(tgt) if tgtname is not None: logger.info(' name(0x%x): %r', tgt, tgtname) fn, symname = tgtname.split('.', 1) logger.info( 'Reloc: making Import 0x%x (name: %s.%s) ', rlva, fn, symname) vw.makeImport(rlva, fn, symname) else: logger.warning('unknown reloc type: %d %s (at %s)', rtype, name, hex(rlva)) logger.info(r.tree()) if arch in ('arm', 'thumb', 'thumb16'): # ARM REL entries require an addend that could be stored as a # number or an instruction! import envi.archs.arm.const as eaac if r.vsHasField('addend'): # this is a RELA object, bringing its own addend field! addend = r.addend else: # otherwise, we have to check the stored value for number or instruction # if it's an instruction, we have to use the immediate value and then # figure out if it's negative based on the instruction! try: temp = vw.readMemoryPtr(rlva) if rtype in Elf.r_armclasses[ Elf. R_ARMCLASS_DATA] or rtype in Elf.r_armclasses[ Elf.R_ARMCLASS_MISC]: # relocation points to a DATA or MISCELLANEOUS location addend = temp else: # relocation points to a CODE location (ARM, THUMB16, THUMB32) op = vw.parseOpcode(rlva) for oper in op.opers: if hasattr(oper, 'val'): addend = oper.val break elif hasattr(oper, 'offset'): addend = oper.offset break lastoper = op.opers[-1] if op.mnem.startswith('sub') or \ op.mnem in ('ldr', 'str') and \ hasattr(lastoper, 'pubwl') and \ not (lastoper.pubwl & eaac.PUxWL_ADD): addend = -addend except Exception as e: logger.exception("ELF: Reloc Addend determination: %s", e) addend = temp logger.debug('addend: 0x%x', addend) if rtype == Elf.R_ARM_JUMP_SLOT: symidx = r.getSymTabIndex() sym = elf.getDynSymbol(symidx) ptr = sym.st_value # quick check to make sure we don't provide this symbol # some toolchains like to point the GOT back at it's PLT entry # that does *not* mean it's not an IMPORT if ptr and not isPLT(vw, ptr): logger.info( 'R_ARM_JUMP_SLOT: adding Relocation 0x%x -> 0x%x (%s) ', rlva, ptr, dmglname) if addbase: vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr) else: vw.addRelocation(rlva, vivisect.RTYPE_BASERELOC, ptr) pname = "ptr_%s_%.8x" % (name, rlva) if vw.vaByName(pname) is None: vw.makeName(rlva, pname) # name the target as well if addbase: ptr += baseaddr # normalize thumb addresses ptr &= -2 vw.makeName(ptr, name) vw.setComment(ptr, dmglname) else: logger.info( 'R_ARM_JUMP_SLOT: adding Import 0x%x (%s) ', rlva, dmglname) vw.makeImport(rlva, "*", dmglname) vw.setComment(rlva, name) elif rtype == Elf.R_ARM_GLOB_DAT: symidx = r.getSymTabIndex() sym = elf.getDynSymbol(symidx) ptr = sym.st_value if ptr: logger.info( 'R_ARM_GLOB_DAT: adding Relocation 0x%x -> 0x%x (%s) ', rlva, ptr, dmglname) if addbase: vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr) else: vw.addRelocation(rlva, vivisect.RTYPE_BASERELOC, ptr) pname = "ptr_%s" % name if vw.vaByName(pname) is None: vw.makeName(rlva, pname) if addbase: ptr += baseaddr vw.makeImport(ptr, "*", dmglname) vw.setComment(ptr, name) else: logger.info('R_ARM_GLOB_DAT: adding Import 0x%x (%s) ', rlva, dmglname) vw.makeImport(rlva, "*", dmglname) vw.setComment(rlva, name) elif rtype == Elf.R_ARM_ABS32: symidx = r.getSymTabIndex() sym = elf.getDynSymbol(symidx) ptr = sym.st_value if ptr: logger.info( 'R_ARM_ABS32: adding Relocation 0x%x -> 0x%x (%s) ', rlva, ptr, dmglname) vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr) pname = "ptr_%s" % name if vw.vaByName(pname) is None and len(name): vw.makeName(rlva, pname) else: logger.info('R_ARM_ABS32: adding Import 0x%x (%s) ', rlva, dmglname) vw.makeImport(rlva, "*", dmglname) vw.setComment(rlva, name) vw.setComment(rlva, dmglname) elif rtype == Elf.R_ARM_RELATIVE: # Adjust locations for the rebasing ptr = vw.readMemoryPtr(rlva) logger.info( 'R_ARM_RELATIVE: adding Relocation 0x%x -> 0x%x (name: %s) ', rlva, ptr, dmglname) vw.addRelocation(rlva, vivisect.RTYPE_BASEPTR, ptr) if len(name): vw.makeName(rlva, dmglname, makeuniq=True) vw.setComment(rlva, name) elif rtype == Elf.R_ARM_COPY: pass else: logger.warning('unknown reloc type: %d %s (at %s)', rtype, name, hex(rlva)) logger.info(r.tree()) except vivisect.InvalidLocation as e: logger.warning("NOTE\t%r", e)
def loadElfIntoWorkspace(vw, elf, filename=None): arch = arch_names.get(elf.e_machine) if arch == None: raise Exception("Unsupported Architecture: %d\n", elf.e_machine) # setup needed platform/format vw.setMeta('Architecture', arch) vw.setMeta('Platform', 'unknown') vw.setMeta('Format', 'elf') # FIXME try to determine *which* Elf system... if arch == 'i386': vw.setMeta("DefaultCall", "cdecl") elif arch == 'amd64': vw.setMeta("DefaultCall", "sysvamd64call") vw.addNoReturnApi("*.exit") # Base addr is earliest section address rounded to pagesize # NOTE: This is only for prelink'd so's and exe's. Make something for old style so. addbase = False if not elf.isPreLinked() and elf.isSharedObject(): addbase = True baseaddr = elf.getBaseAddress() #FIXME make filename come from dynamic's if present for shared object if filename == None: filename = "elf_%.8x" % baseaddr fname = vw.addFile(filename, baseaddr, v_parsers.md5File(filename)) strtabs = {} secnames = [] for sec in elf.getSections(): secnames.append(sec.getName()) for pgm in elf.getPheaders(): if pgm.p_type == Elf.PT_LOAD: if vw.verbose: vw.vprint('Loading: %s' % (repr(pgm))) bytes = elf.readAtOffset(pgm.p_offset, pgm.p_filesz) bytes += "\x00" * (pgm.p_memsz - pgm.p_filesz) pva = pgm.p_vaddr if addbase: pva += baseaddr vw.addMemoryMap(pva, pgm.p_flags & 0x7, fname, bytes) #FIXME perms else: if vw.verbose: vw.vprint('Skipping: %s' % repr(pgm)) # First add all section definitions so we have them for sec in elf.getSections(): sname = sec.getName() size = sec.sh_size if sec.sh_addr == 0: continue # Skip non-memory mapped sections sva = sec.sh_addr if addbase: sva += baseaddr vw.addSegment(sva, size, sname, fname) # Now trigger section specific analysis for sec in elf.getSections(): #FIXME dup code here... sname = sec.getName() size = sec.sh_size if sec.sh_addr == 0: continue # Skip non-memory mapped sections sva = sec.sh_addr if addbase: sva += baseaddr if sname == ".interp": vw.makeString(sva) elif sname == ".init": vw.makeName(sva, "init_function", filelocal=True) vw.addEntryPoint(sva) elif sname == ".fini": vw.makeName(sva, "fini_function", filelocal=True) vw.addEntryPoint(sva) elif sname == ".dynamic": # Imports makeDynamicTable(vw, sva, sva + size) # FIXME section names are optional, use dynamic info from .dynamic elif sname == ".dynstr": # String table for dynamics makeStringTable(vw, sva, sva + size) elif sname == ".dynsym": #print "LINK",sec.sh_link for s in makeSymbolTable(vw, sva, sva + size): pass #print "########################.dynsym",s # If the section is really a string table, do it if sec.sh_type == Elf.SHT_STRTAB: makeStringTable(vw, sva, sva + size) elif sec.sh_type == Elf.SHT_SYMTAB: # FIXME 32 bit specific! #print "FOUND A SYMBOL TABLE!" makeSymbolTable(vw, sva, sva + size) elif sec.sh_type == Elf.SHT_REL: makeRelocTable(vw, sva, sva + size, addbase, baseaddr) if sec.sh_flags & Elf.SHF_STRINGS: print "FIXME HANDLE SHF STRINGS" # Let pyelf do all the stupid string parsing... for r in elf.getRelocs(): rtype = Elf.getRelocType(r.r_info) rlva = r.r_offset if addbase: rlva += baseaddr try: # If it has a name, it's an externally # resolved "import" entry, otherwise, just a regular reloc if arch in ('i386', 'amd64'): name = r.getName() if name: if rtype == Elf.R_386_JMP_SLOT: vw.makeImport(rlva, "*", name) # FIXME elf has conflicting names for 2 relocs? #elif rtype == Elf.R_386_GLOB_DAT: #vw.makeImport(rlva, "*", name) elif rtype == Elf.R_386_32: pass else: vw.verbprint('unknown reloc type: %d %s (at %s)' % (rtype, name, hex(rlva))) if arch == 'arm': name = r.getName() if name: if rtype == Elf.R_ARM_JUMP_SLOT: vw.makeImport(rlva, "*", name) else: vw.verbprint('unknown reloc type: %d %s (at %s)' % (rtype, name, hex(rlva))) except vivisect.InvalidLocation, e: print "NOTE", e
def loadElfIntoWorkspace(vw, elf, filename=None): arch = arch_names.get(elf.e_machine) if arch == None: raise Exception("Unsupported Architecture: %d\n", elf.e_machine) platform = elf.getPlatform() # setup needed platform/format vw.setMeta('Architecture', arch) vw.setMeta('Platform', platform) vw.setMeta('Format', 'elf') vw.setMeta('DefaultCall', archcalls.get(arch,'unknown')) vw.addNoReturnApi("*.exit") # Base addr is earliest section address rounded to pagesize # NOTE: This is only for prelink'd so's and exe's. Make something for old style so. addbase = False if not elf.isPreLinked() and elf.isSharedObject(): addbase = True baseaddr = elf.getBaseAddress() #FIXME make filename come from dynamic's if present for shared object if filename == None: filename = "elf_%.8x" % baseaddr fhash = "unknown hash" if os.path.exists(filename): fhash = v_parsers.md5File(filename) fname = vw.addFile(filename.lower(), baseaddr, fhash) strtabs = {} secnames = [] for sec in elf.getSections(): secnames.append(sec.getName()) pgms = elf.getPheaders() secs = elf.getSections() for pgm in pgms: if pgm.p_type == Elf.PT_LOAD: if vw.verbose: vw.vprint('Loading: %s' % (repr(pgm))) bytez = elf.readAtOffset(pgm.p_offset, pgm.p_filesz) bytez += "\x00" * (pgm.p_memsz - pgm.p_filesz) pva = pgm.p_vaddr if addbase: pva += baseaddr vw.addMemoryMap(pva, pgm.p_flags & 0x7, fname, bytez) #FIXME perms else: if vw.verbose: vw.vprint('Skipping: %s' % repr(pgm)) if len(pgms) == 0: # fall back to loading sections as best we can... if vw.verbose: vw.vprint('elf: no program headers found!') maps = [ [s.sh_offset,s.sh_size] for s in secs if s.sh_offset and s.sh_size ] maps.sort() merged = [] for i in xrange(len(maps)): if merged and maps[i][0] == (merged[-1][0] + merged[-1][1]): merged[-1][1] += maps[i][1] continue merged.append( maps[i] ) baseaddr = 0x05000000 for offset,size in merged: bytez = elf.readAtOffset(offset,size) vw.addMemoryMap(baseaddr + offset, 0x7, fname, bytez) for sec in secs: if sec.sh_offset and sec.sh_size: sec.sh_addr = baseaddr + sec.sh_offset # First add all section definitions so we have them for sec in secs: sname = sec.getName() size = sec.sh_size if sec.sh_addr == 0: continue # Skip non-memory mapped sections sva = sec.sh_addr if addbase: sva += baseaddr vw.addSegment(sva, size, sname, fname) # Now trigger section specific analysis for sec in secs: #FIXME dup code here... sname = sec.getName() size = sec.sh_size if sec.sh_addr == 0: continue # Skip non-memory mapped sections sva = sec.sh_addr if addbase: sva += baseaddr if sname == ".interp": vw.makeString(sva) elif sname == ".init": vw.makeName(sva, "init_function", filelocal=True) vw.addEntryPoint(sva) elif sname == ".fini": vw.makeName(sva, "fini_function", filelocal=True) vw.addEntryPoint(sva) elif sname == ".dynamic": # Imports makeDynamicTable(vw, sva, sva+size) # FIXME section names are optional, use dynamic info from .dynamic elif sname == ".dynstr": # String table for dynamics makeStringTable(vw, sva, sva+size) elif sname == ".dynsym": #print "LINK",sec.sh_link for s in makeSymbolTable(vw, sva, sva+size): pass #print "########################.dynsym",s # If the section is really a string table, do it if sec.sh_type == Elf.SHT_STRTAB: makeStringTable(vw, sva, sva+size) elif sec.sh_type == Elf.SHT_SYMTAB: makeSymbolTable(vw, sva, sva+size) elif sec.sh_type == Elf.SHT_REL: makeRelocTable(vw, sva, sva+size, addbase, baseaddr) if sec.sh_flags & Elf.SHF_STRINGS: print "FIXME HANDLE SHF STRINGS" # Let pyelf do all the stupid string parsing... for r in elf.getRelocs(): rtype = Elf.getRelocType(r.r_info) rlva = r.r_offset if addbase: rlva += baseaddr try: # If it has a name, it's an externally # resolved "import" entry, otherwise, just a regular reloc if arch in ('i386','amd64'): name = r.getName() if name: if rtype == Elf.R_386_JMP_SLOT: vw.makeImport(rlva, "*", name) # FIXME elf has conflicting names for 2 relocs? #elif rtype == Elf.R_386_GLOB_DAT: #vw.makeImport(rlva, "*", name) elif rtype == Elf.R_386_32: pass else: vw.verbprint('unknown reloc type: %d %s (at %s)' % (rtype, name, hex(rlva))) if arch == 'arm': name = r.getName() if name: if rtype == Elf.R_ARM_JUMP_SLOT: vw.makeImport(rlva, "*", name) else: vw.verbprint('unknown reloc type: %d %s (at %s)' % (rtype, name, hex(rlva))) except vivisect.InvalidLocation, e: print "NOTE",e
def parseFile(vw, filename): fd = file(filename, 'rb') elf = Elf.Elf(fd) return loadElfIntoWorkspace(vw, elf, filename=filename)
def parseBytes(vw, bytes): fd = StringIO(bytes) elf = Elf.Elf(fd) return loadElfIntoWorkspace(vw, elf)
def load_level(): global book global player global timer global elements global elfs values = {} file_name = "./Assets/Levels/level1.dat" if not os.path.isfile(file_name): return False else: file = open(file_name, "r") for line in file.readlines(): v_n = "" v = "" s = 0 for c in line: if c == '=': s = 1 continue elif c == ' ': continue if s == 0: v_n = v_n + c elif s == 1: v = v + c values[v_n] = v.replace('\n', '') file.close() if not os.path.isfile(values["board"]): return False else: player = Player(int(values["start_x"]), int(values["start_y"])) elements = [] elfs = [] file = open(values["board"], "r") i = 0 for value in file.readlines(): nu = "" co = "" ro = "" s = 0 for c in value: if c == '-': s = s + 1 continue if s == 0: nu = nu + c elif s == 1: co = co + c elif s == 2: ro = ro + c sprite = titles[int(nu)] sprite = pygame.transform.rotate(sprite, 90 * int(ro)) elements.append( Element(i % int(values["size_x"]), int(i / int(values["size_x"])), sprite, int(co))) i = i + 1 file.close() book = Book(elements) for i in range(3): elfs.append(Elf(elements, player)) timer = threading.Thread(target=timer_loop) timer.start()