You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
78 lines
3.1 KiB
78 lines
3.1 KiB
5 years ago
|
#-------------------------------------------------------------------------------
|
||
|
# elftools: elf/hash.py
|
||
|
#
|
||
|
# ELF hash table sections
|
||
|
#
|
||
|
# Andreas Ziegler (andreas.ziegler@fau.de)
|
||
|
# This code is in the public domain
|
||
|
#-------------------------------------------------------------------------------
|
||
|
|
||
|
from ..common.utils import struct_parse
|
||
|
|
||
|
|
||
|
class HashSection(object):
|
||
|
""" Minimal part of an ELF hash section to find the number of symbols in the
|
||
|
symbol table - useful for super-stripped binaries without section
|
||
|
headers where only the start of the symbol table is known from the
|
||
|
dynamic segment. The layout and contents are nicely described at
|
||
|
https://flapenguin.me/2017/04/24/elf-lookup-dt-hash/.
|
||
|
"""
|
||
|
def __init__(self, stream, offset, elffile):
|
||
|
self._stream = stream
|
||
|
self._offset = offset
|
||
|
self._elffile = elffile
|
||
|
self.params = struct_parse(self._elffile.structs.Elf_Hash,
|
||
|
self._stream,
|
||
|
self._offset)
|
||
|
|
||
|
def get_number_of_symbols(self):
|
||
|
""" Get the number of symbols from the hash table parameters.
|
||
|
"""
|
||
|
return self.params['nchains']
|
||
|
|
||
|
|
||
|
class GNUHashSection(object):
|
||
|
""" Minimal part of a GNU hash section to find the number of symbols in the
|
||
|
symbol table - useful for super-stripped binaries without section
|
||
|
headers where only the start of the symbol table is known from the
|
||
|
dynamic segment. The layout and contents are nicely described at
|
||
|
https://flapenguin.me/2017/05/10/elf-lookup-dt-gnu-hash/.
|
||
|
"""
|
||
|
def __init__(self, stream, offset, elffile):
|
||
|
self._stream = stream
|
||
|
self._offset = offset
|
||
|
self._elffile = elffile
|
||
|
self.params = struct_parse(self._elffile.structs.Gnu_Hash,
|
||
|
self._stream,
|
||
|
self._offset)
|
||
|
|
||
|
def get_number_of_symbols(self):
|
||
|
""" Get the number of symbols in the hash table by finding the bucket
|
||
|
with the highest symbol index and walking to the end of its chain.
|
||
|
"""
|
||
|
# Element sizes in the hash table
|
||
|
wordsize = self._elffile.structs.Elf_word('').sizeof()
|
||
|
xwordsize = self._elffile.structs.Elf_xword('').sizeof()
|
||
|
|
||
|
# Find highest index in buckets array
|
||
|
max_idx = max(self.params['buckets'])
|
||
|
if max_idx < self.params['symoffset']:
|
||
|
return self.params['symoffset']
|
||
|
|
||
|
# Position the stream at the start of the corresponding chain
|
||
|
chain_pos = self._offset + 4 * wordsize + \
|
||
|
self.params['bloom_size'] * xwordsize + \
|
||
|
self.params['nbuckets'] * wordsize + \
|
||
|
(max_idx - self.params['symoffset']) * wordsize
|
||
|
|
||
|
# Walk the chain to its end (lowest bit is set)
|
||
|
while True:
|
||
|
cur_hash = struct_parse(self._elffile.structs.Elf_word('elem'),
|
||
|
self._stream,
|
||
|
chain_pos)
|
||
|
if cur_hash & 1:
|
||
|
return max_idx + 1
|
||
|
|
||
|
max_idx += 1
|
||
|
chain_pos += wordsize
|