def __register_dyn(self, seg_readelf): """ Parse the dynamic section for dynamically linked objects. """ runpath, rpath = "", "" for tag in seg_readelf.iter_tags(): # Create a dictionary, self._dynamic, mapping DT_* strings to their values tagstr = self.arch.translate_dynamic_tag(tag.entry.d_tag) self._dynamic[tagstr] = tag.entry.d_val # For tags that may appear more than once, handle them here if tagstr == 'DT_NEEDED': self.deps.append(maybedecode(tag.needed)) elif tagstr == 'DT_SONAME': self.provides = maybedecode(tag.soname) elif tagstr == 'DT_RUNPATH': runpath = maybedecode(tag.runpath) elif tagstr == 'DT_RPATH': rpath = maybedecode(tag.rpath) self.extra_load_path = self.__parse_rpath(runpath, rpath) self.strtab = seg_readelf._get_stringtable() # To extract symbols from binaries without section headers, we need to hack into pyelftools. # None of the following things make sense without a string table or a symbol table if 'DT_STRTAB' in self._dynamic and 'DT_SYMTAB' in self._dynamic and 'DT_SYMENT' in self._dynamic: # Construct our own symbol table to hack around pyreadelf assuming section headers are around fakesymtabheader = { 'sh_offset': AT.from_lva(self._dynamic['DT_SYMTAB'], self).to_rva(), 'sh_entsize': self._dynamic['DT_SYMENT'], 'sh_size': 0, # bogus size: no iteration allowed 'sh_flags': 0, 'sh_addralign': 0, } self.dynsym = elffile.SymbolTableSection(fakesymtabheader, 'symtab_cle', self.reader, self.strtab) self.dynsym.stream = self.memory # set up the hash table, prefering the gnu hash section to the old hash section # the hash table lets you get any symbol given its name if 'DT_GNU_HASH' in self._dynamic: self.hashtable = GNUHashTable( self.dynsym, self.memory, AT.from_lva(self._dynamic['DT_GNU_HASH'], self).to_rva(), self.arch) elif 'DT_HASH' in self._dynamic: self.hashtable = ELFHashTable( self.dynsym, self.memory, AT.from_lva(self._dynamic['DT_HASH'], self).to_rva(), self.arch) else: l.warning("No hash table available in %s", self.binary) # mips' relocations are absolutely screwed up, handle some of them here. self.__relocate_mips() # perform a lot of checks to figure out what kind of relocation tables are around self.rela_type = None if 'DT_PLTREL' in self._dynamic: if self._dynamic['DT_PLTREL'] == 7: self.rela_type = 'RELA' relentsz = self.reader.structs.Elf_Rela.sizeof() elif self._dynamic['DT_PLTREL'] == 17: self.rela_type = 'REL' relentsz = self.reader.structs.Elf_Rel.sizeof() else: raise CLEInvalidBinaryError( 'DT_PLTREL is not REL or RELA?') else: if 'DT_RELA' in self._dynamic: self.rela_type = 'RELA' relentsz = self.reader.structs.Elf_Rela.sizeof() elif 'DT_REL' in self._dynamic: self.rela_type = 'REL' relentsz = self.reader.structs.Elf_Rel.sizeof() else: return # try to parse relocations out of a table of type DT_REL{,A} rela_tag = 'DT_' + self.rela_type relsz_tag = rela_tag + 'SZ' if rela_tag in self._dynamic: reloffset = AT.from_lva(self._dynamic[rela_tag], self).to_rva() if relsz_tag not in self._dynamic: raise CLEInvalidBinaryError( 'Dynamic section contains %s but not %s' % (rela_tag, relsz_tag)) relsz = self._dynamic[relsz_tag] fakerelheader = { 'sh_offset': reloffset, 'sh_type': 'SHT_' + self.rela_type, 'sh_entsize': relentsz, 'sh_size': relsz, 'sh_flags': 0, 'sh_addralign': 0, } readelf_relocsec = elffile.RelocationSection( fakerelheader, 'reloc_cle', self.reader) readelf_relocsec.stream = self.memory self.__register_relocs(readelf_relocsec) # try to parse relocations out of a table of type DT_JMPREL if 'DT_JMPREL' in self._dynamic: jmpreloffset = AT.from_lva(self._dynamic['DT_JMPREL'], self).to_rva() if 'DT_PLTRELSZ' not in self._dynamic: raise CLEInvalidBinaryError( 'Dynamic section contains DT_JMPREL but not DT_PLTRELSZ' ) jmprelsz = self._dynamic['DT_PLTRELSZ'] fakejmprelheader = { 'sh_offset': jmpreloffset, 'sh_type': 'SHT_' + self.rela_type, 'sh_entsize': relentsz, 'sh_size': jmprelsz, 'sh_flags': 0, 'sh_addralign': 0, } readelf_jmprelsec = elffile.RelocationSection( fakejmprelheader, 'jmprel_cle', self.reader) readelf_jmprelsec.stream = self.memory self.__register_relocs(readelf_jmprelsec, force_jmprel=True)
def __register_dyn(self, seg_readelf): """ Parse the dynamic section for dynamically linked objects. """ for tag in seg_readelf.iter_tags(): # Create a dictionary, self._dynamic, mapping DT_* strings to their values tagstr = self.arch.translate_dynamic_tag(tag.entry.d_tag) self._dynamic[tagstr] = tag.entry.d_val # For tags that may appear more than once, handle them here if tagstr == 'DT_NEEDED': self.deps.append(tag.entry.d_val) # None of the following things make sense without a string table if 'DT_STRTAB' in self._dynamic: # To handle binaries without section headers, we need to hack around pyreadelf's assumptions # make our own string table fakestrtabheader = { 'sh_offset': AT.from_lva(self._dynamic['DT_STRTAB'], self).to_rva() } self.strtab = elffile.StringTableSection(fakestrtabheader, 'strtab_cle', self.memory) # get the list of strings that are the required shared libraries self.deps = map(self.strtab.get_string, self.deps) # get the string for the "shared object name" that this binary provides if 'DT_SONAME' in self._dynamic: self.provides = self.strtab.get_string( self._dynamic['DT_SONAME']) # None of the following structures can be used without a symbol table if 'DT_SYMTAB' in self._dynamic and 'DT_SYMENT' in self._dynamic: # Construct our own symbol table to hack around pyreadelf assuming section headers are around fakesymtabheader = { 'sh_offset': AT.from_lva(self._dynamic['DT_SYMTAB'], self).to_rva(), 'sh_entsize': self._dynamic['DT_SYMENT'], 'sh_size': 0 } # bogus size: no iteration allowed self.dynsym = elffile.SymbolTableSection( fakesymtabheader, 'symtab_cle', self.memory, self.reader, self.strtab) # set up the hash table, prefering the gnu hash section to the old hash section # the hash table lets you get any symbol given its name if 'DT_GNU_HASH' in self._dynamic: self.hashtable = GNUHashTable( self.dynsym, self.memory, AT.from_lva(self._dynamic['DT_GNU_HASH'], self).to_rva(), self.arch) elif 'DT_HASH' in self._dynamic: self.hashtable = ELFHashTable( self.dynsym, self.memory, AT.from_lva(self._dynamic['DT_HASH'], self).to_rva(), self.arch) else: l.warning("No hash table available in %s", self.binary) # mips' relocations are absolutely screwed up, handle some of them here. self.__relocate_mips() # perform a lot of checks to figure out what kind of relocation tables are around self.rela_type = None if 'DT_PLTREL' in self._dynamic: if self._dynamic['DT_PLTREL'] == 7: self.rela_type = 'RELA' relentsz = self.reader.structs.Elf_Rela.sizeof() elif self._dynamic['DT_PLTREL'] == 17: self.rela_type = 'REL' relentsz = self.reader.structs.Elf_Rel.sizeof() else: raise CLEInvalidBinaryError( 'DT_PLTREL is not REL or RELA?') else: if 'DT_RELA' in self._dynamic: self.rela_type = 'RELA' relentsz = self.reader.structs.Elf_Rela.sizeof() elif 'DT_REL' in self._dynamic: self.rela_type = 'REL' relentsz = self.reader.structs.Elf_Rel.sizeof() else: return # try to parse relocations out of a table of type DT_REL{,A} if 'DT_' + self.rela_type in self._dynamic: reloffset = self._dynamic['DT_' + self.rela_type] and \ AT.from_lva(self._dynamic['DT_' + self.rela_type], self).to_rva() if 'DT_' + self.rela_type + 'SZ' not in self._dynamic: raise CLEInvalidBinaryError( 'Dynamic section contains DT_' + self.rela_type + ', but DT_' + self.rela_type + 'SZ is not present') relsz = self._dynamic['DT_' + self.rela_type + 'SZ'] fakerelheader = { 'sh_offset': reloffset, 'sh_type': 'SHT_' + self.rela_type, 'sh_entsize': relentsz, 'sh_size': relsz } readelf_relocsec = elffile.RelocationSection( fakerelheader, 'reloc_cle', self.memory, self.reader) self.__register_relocs(readelf_relocsec) # try to parse relocations out of a table of type DT_JMPREL if 'DT_JMPREL' in self._dynamic: jmpreloffset = self._dynamic['DT_JMPREL'] and AT.from_lva( self._dynamic['DT_JMPREL'], self).to_rva() if 'DT_PLTRELSZ' not in self._dynamic: raise CLEInvalidBinaryError( 'Dynamic section contains DT_JMPREL, but DT_PLTRELSZ is not present' ) jmprelsz = self._dynamic['DT_PLTRELSZ'] fakejmprelheader = { 'sh_offset': jmpreloffset, 'sh_type': 'SHT_' + self.rela_type, 'sh_entsize': relentsz, 'sh_size': jmprelsz } readelf_jmprelsec = elffile.RelocationSection( fakejmprelheader, 'jmprel_cle', self.memory, self.reader) self.jmprel = OrderedDict( (reloc.symbol.name, reloc) for reloc in self.__register_relocs(readelf_jmprelsec) if reloc.symbol.name != '')