def _find_dt(self, tag): """ Find an entry in the DYNAMIC array. Arguments: tag(int): Single tag to find Returns: Pointer to the data described by the specified entry. """ leak = self.leak base = self.libbase dynamic = self.dynamic name = next(k for k, v in ENUM_D_TAG.items() if v == tag) Dyn = {32: elf.Elf32_Dyn, 64: elf.Elf64_Dyn}[self.elfclass] # Found the _DYNAMIC program header, now find PLTGOT entry in it # An entry with a DT_NULL tag marks the end of the DYNAMIC array. while not leak.field_compare(dynamic, Dyn.d_tag, constants.DT_NULL): if leak.field_compare(dynamic, Dyn.d_tag, tag): break dynamic += sizeof(Dyn) else: self.failure("Could not find tag %s" % name) return None self.status("Found %s at %#x" % (name, dynamic)) ptr = leak.field(dynamic, Dyn.d_ptr) ptr = self._make_absolute_ptr(ptr) return ptr
def _lookup(self, symb): """Performs the actual symbol lookup within one ELF file.""" leak = self.leak Dyn = {32: elf.Elf32_Dyn, 64: elf.Elf64_Dyn}[self.elfclass] name = lambda tag: next(k for k,v in ENUM_D_TAG.items() if v == tag) self.status('.gnu.hash/.hash, .strtab and .symtab offsets') # # We need all three of the hash, string table, and symbol table. # hshtab = self._find_dt(constants.DT_GNU_HASH) strtab = self._find_dt(constants.DT_STRTAB) symtab = self._find_dt(constants.DT_SYMTAB) # Assume GNU hash will hit, since it is the default for GCC. if hshtab: hshtype = 'gnu' else: hshtab = self._find_dt(constants.DT_HASH) hshtype = 'sysv' if not all([strtab, symtab, hshtab]): self.failure("Could not find all tables") strtab = self._make_absolute_ptr(strtab) symtab = self._make_absolute_ptr(symtab) hshtab = self._make_absolute_ptr(hshtab) # # Perform the hash lookup # routine = {'sysv': self._resolve_symbol_sysv, 'gnu': self._resolve_symbol_gnu}[hshtype] return routine(self.libbase, symb, hshtab, strtab, symtab)
def _find_dt(self, tag): """ Find an entry in the DYNAMIC array. Arguments: tag(int): Single tag to find Returns: Pointer to the data described by the specified entry. """ leak = self.leak base = self.libbase dynamic = self.dynamic name = next(k for k,v in ENUM_D_TAG.items() if v == tag) Dyn = {32: elf.Elf32_Dyn, 64: elf.Elf64_Dyn} [self.elfclass] # Found the _DYNAMIC program header, now find PLTGOT entry in it # An entry with a DT_NULL tag marks the end of the DYNAMIC array. while not leak.field_compare(dynamic, Dyn.d_tag, constants.DT_NULL): if leak.field_compare(dynamic, Dyn.d_tag, tag): break dynamic += sizeof(Dyn) else: self.failure("Could not find tag %s" % name) return None self.status("Found %s at %#x" % (name, dynamic)) ptr = leak.field(dynamic, Dyn.d_ptr) # Sometimes this is an offset rather than an actual pointer. if 0 < ptr < 0x400000: ptr += self.libbase return ptr
def _get_dynamic_tags(self): dynamic_tags = [] for section in self.elf.iter_sections(): if not isinstance(section, DynamicSection): continue for tag in section.iter_tags(): dynamic_tags.append({ "tag": self._print_addr( ENUM_D_TAG.get(tag.entry.d_tag, tag.entry.d_tag) ), "type": tag.entry.d_tag[3:], "value": self._parse_tag(tag), }) return dynamic_tags
def _get_dynamic_tags(self) -> List[Dict[str, str]]: dynamic_tags = [] for section in self.elf.iter_sections(): if not isinstance(section, DynamicSection): continue dynamic_tags.extend( { "tag": self._print_addr(ENUM_D_TAG.get(tag.entry.d_tag, tag.entry.d_tag)), "type": str(tag.entry.d_tag)[3:], "value": self._parse_tag(tag), } for tag in section.iter_tags() ) return dynamic_tags
def display_dynamic_tags(self): """ Display the dynamic tags contained in the file """ has_dynamic_sections = False for section in self.elffile.iter_sections(): if not isinstance(section, DynamicSection): continue has_dynamic_sections = True self._emitline("\nDynamic section at offset %s contains %s entries:" % ( self._format_hex(section['sh_offset']), section.num_tags())) self._emitline(" Tag Type Name/Value") padding = 20 + (8 if self.elffile.elfclass == 32 else 0) for tag in section.iter_tags(): if tag.entry.d_tag == 'DT_NEEDED': parsed = 'Shared library: [%s]' % bytes2str(tag.needed) elif tag.entry.d_tag == 'DT_RPATH': parsed = 'Library rpath: [%s]' % bytes2str(tag.rpath) elif tag.entry.d_tag == 'DT_RUNPATH': parsed = 'Library runpath: [%s]' % bytes2str(tag.runpath) elif tag.entry.d_tag == 'DT_SONAME': parsed = 'Library soname: [%s]' % bytes2str(tag.soname) elif (tag.entry.d_tag.endswith('SZ') or tag.entry.d_tag.endswith('ENT')): parsed = '%i (bytes)' % tag['d_val'] elif (tag.entry.d_tag.endswith('NUM') or tag.entry.d_tag.endswith('COUNT')): parsed = '%i' % tag['d_val'] elif tag.entry.d_tag == 'DT_PLTREL': s = describe_dyn_tag(tag.entry.d_val) if s.startswith('DT_'): s = s[3:] parsed = '%s' % s else: parsed = '%#x' % tag['d_val'] self._emitline(" %s %-*s %s" % ( self._format_hex(ENUM_D_TAG.get(tag.entry.d_tag, tag.entry.d_tag), fullhex=True, lead0x=True), padding, '(%s)' % (tag.entry.d_tag[3:],), parsed)) if not has_dynamic_sections: # readelf only prints this if there is at least one segment if self.elffile.num_segments(): self._emitline("\nThere is no dynamic section in this file.")
def _get_dynamic_tags(self): dynamic_tags = [] for section in self.elf.iter_sections(): if not isinstance(section, DynamicSection): continue for tag in section.iter_tags(): dynamic_tags.append({ "tag": self._print_addr( ENUM_D_TAG.get(tag.entry.d_tag, tag.entry.d_tag)), "type": tag.entry.d_tag[3:], "value": self._parse_tag(tag), }) return dynamic_tags
def _find_dt(self, tags): """ Find an entry in the DYNAMIC array. Arguments: tags(int, tuple): Single tag, or list of tags to search for Returns: Pointer to the data described by the specified entry. """ if not isinstance(tags, (list, tuple)): tags = [tags] leak = self.leak base = self.libbase dynamic = self.dynamic name = lambda tag: next(k for k,v in ENUM_D_TAG.items() if v == tag) Dyn = {32: elf.Elf32_Dyn, 64: elf.Elf64_Dyn} [self.elfclass] # Found the _DYNAMIC program header, now find PLTGOT entry in it # An entry with a DT_NULL tag marks the end of the DYNAMIC array. while True: d_tag = leak.field(dynamic, Dyn.d_tag) if d_tag == constants.DT_NULL: return None elif d_tag in tags: break #Skip to next dynamic += sizeof(Dyn) else: self.failure("Could not find any of: " % map(name, tags)) return None self.status("Found %s at %#x" % (name(d_tag), dynamic)) ptr = leak.field(dynamic, Dyn.d_ptr) # Sometimes this is an offset rather than an actual pointer. if 0 < ptr < 0x400000: ptr += self.libbase return ptr
def _find_dt(self, tags): """ Find an entry in the DYNAMIC array. Arguments: tags(int, tuple): Single tag, or list of tags to search for Returns: Pointer to the data described by the specified entry. """ if not isinstance(tags, (list, tuple)): tags = [tags] leak = self.leak base = self.libbase dynamic = self.dynamic name = lambda tag: next(k for k, v in ENUM_D_TAG.items() if v == tag) Dyn = {32: elf.Elf32_Dyn, 64: elf.Elf64_Dyn}[self.elfclass] # Found the _DYNAMIC program header, now find PLTGOT entry in it # An entry with a DT_NULL tag marks the end of the DYNAMIC array. while True: d_tag = leak.field(dynamic, Dyn.d_tag) if d_tag == constants.DT_NULL: return None elif d_tag in tags: break #Skip to next dynamic += sizeof(Dyn) else: self.failure("Could not find any of: " % map(name, tags)) return None self.status("Found %s at %#x" % (name(d_tag), dynamic)) ptr = leak.field(dynamic, Dyn.d_ptr) # Sometimes this is an offset rather than an actual pointer. if 0 < ptr < 0x400000: ptr += self.libbase return ptr
def _lookup(self, symb): """Performs the actual symbol lookup within one ELF file.""" leak = self.leak Dyn = {32: elf.Elf32_Dyn, 64: elf.Elf64_Dyn}[self.elfclass] name = lambda tag: next(k for k, v in ENUM_D_TAG.items() if v == tag) self.status(".gnu.hash/.hash, .strtab and .symtab offsets") # # We need all three of the hash, string table, and symbol table. # hshtab = self._find_dt(constants.DT_GNU_HASH) strtab = self._find_dt(constants.DT_STRTAB) symtab = self._find_dt(constants.DT_SYMTAB) # Assume GNU hash will hit, since it is the default for GCC. if hshtab: hshtype = "gnu" else: hshtab = self._find_dt(constants.DT_HASH) hshtype = "sysv" if not all([strtab, symtab, hshtab]): self.failure("Could not find all tables") # glibc pointers are relocated but uclibc are not if 0 < strtab < 0x400000: strtab += self.libbase symtab += self.libbase hshtab += self.libbase # # Perform the hash lookup # routine = {"sysv": self._resolve_symbol_sysv, "gnu": self._resolve_symbol_gnu}[hshtype] return routine(self.libbase, symb, hshtab, strtab, symtab)
def get_sections(self): sections = [] for nsec, section in enumerate(self._elf.iter_sections()): result = {} result['nsec'] = nsec result['name'] = section.name result['sh_type'] = describe_sh_type(section['sh_type']) if self._elf.elfclass == 32: result['sh_addr'] = section['sh_addr'] result['shoffset'] = section['sh_offset'] result['sh_size'] = section['sh_size'] result['sh_entsize'] = section['sh_entsize'] result['sh_flags'] = describe_sh_flags(section['sh_flags']) result['sh_link'] = section['sh_link'] result['sh_info'] = section['sh_info'] result['sh_addralign'] = section['sh_addralign'] else: # 64 result['sh_addr'] = section['sh_addr'] result['sh_offset'] = section['sh_offset'] result['sh_size'] = section['sh_size'] result['sh_entsize'] = section['sh_entsize'] result['sh_flags'] = describe_sh_flags(section['sh_flags']) result['sh_link'] = section['sh_link'], section['sh_info'] result['sh_addralign'] = section['sh_addralign'] # Dynamic Section if isinstance(section, DynamicSection): result['special_type'] = 'dynamic' result['dynamic'] = [] has_dynamic_sections = True for tag in section.iter_tags(): dynamic = {} if tag.entry.d_tag == 'DT_NEEDED': parsed = 'Shared library: [%s]' % tag.needed elif tag.entry.d_tag == 'DT_RPATH': parsed = 'Library rpath: [%s]' % tag.rpath elif tag.entry.d_tag == 'DT_RUNPATH': parsed = 'Library runpath: [%s]' % tag.runpath elif tag.entry.d_tag == 'DT_SONAME': parsed = 'Library soname: [%s]' % tag.soname elif tag.entry.d_tag.endswith(('SZ', 'ENT')): parsed = '%i (bytes)' % tag['d_val'] elif tag.entry.d_tag.endswith(('NUM', 'COUNT')): parsed = '%i' % tag['d_val'] elif tag.entry.d_tag == 'DT_PLTREL': s = describe_dyn_tag(tag.entry.d_val) if s.startswith('DT_'): s = s[3:] parsed = '%s' % s else: parsed = '%#x' % tag['d_val'] dynamic['tag'] = ENUM_D_TAG.get( tag.entry.d_tag, tag.entry.d_tag) dynamic['tag_type'] = tag.entry.d_tag[3:] dynamic['tag_value'] = parsed result['dynamic'].append(dynamic) #Relocation Section if isinstance(section, RelocationSection): result['special_type'] = 'relocation' result['relocation'] = [] has_relocation_sections = True # The symbol table section pointed to in sh_link symtable = self._elf.get_section(section['sh_link']) for rel in section.iter_relocations(): relocation = {} relocation['r_offset'] = rel['r_offset'] relocation['r_info'] = rel['r_info'] relocation['r_info_type'] = describe_reloc_type( rel['r_info_type'], self._elf) if rel['r_info_sym'] == 0: continue symbol = symtable.get_symbol(rel['r_info_sym']) # Some symbols have zero 'st_name', so instead what's used is # the name of the section they point at if symbol['st_name'] == 0: symsec = self._elf.get_section(symbol['st_shndx']) relocation['symbol_name'] = symbol_name = symsec.name else: symbol_name = symbol.name relocation['st_value'] = symbol['st_value'] relocation['symbol_name'] = symbol_name if section.is_RELA(): relocation['r_addend'] = rel['r_addend'] result['relocation'].append(relocation) #Symbol Section if isinstance(section, SymbolTableSection): self._init_versioninfo() if section['sh_entsize'] == 0: continue result['special_type'] = 'symbol' result['symbol'] = [] for nsym, symbol in enumerate(section.iter_symbols()): sym_dic = {} version_info = '' # readelf doesn't display version info for Solaris versioning if (section['sh_type'] == 'SHT_DYNSYM' and self._versioninfo['type'] == 'GNU'): version = self._symbol_version(nsym) if (version['name'] != symbol.name and version['index'] not in ('VER_NDX_LOCAL', 'VER_NDX_GLOBAL')): if version['filename']: # external symbol version_info = '@%(name)s (%(index)i)' % version else: # internal symbol if version['hidden']: version_info = '@%(name)s' % version else: version_info = '@@%(name)s' % version # symbol names are truncated to 25 chars, similarly to readelf sym_dic['nsym'] = nsym sym_dic['st_value'] = symbol['st_value'] sym_dic['st_size'] = symbol['st_size'] sym_dic['st_type'] = describe_symbol_type( symbol['st_info']['type']) sym_dic['bind'] = describe_symbol_bind( symbol['st_info']['bind']) sym_dic['vis'] = describe_symbol_visibility( symbol['st_other']['visibility']) sym_dic['ndx'] = describe_symbol_shndx( symbol['st_shndx']) sym_dic['name'] = symbol.name sym_dic['version'] = version_info result['symbol'].append(sym_dic) sections.append(result) return sections