Beispiel #1
0
 def _dump_elf(cls, buf):
     """
     Dump the symbol table of an ELF file.
     Needs pyelftools (https://github.com/eliben/pyelftools)
     """
     from elftools.elf.elffile import ELFFile
     from elftools.elf import descriptions
     from io import BytesIO
     f = ELFFile(BytesIO(buf))
     print("ELF file:")
     for sec in f.iter_sections():
         if sec['sh_type'] == 'SHT_SYMTAB':
             symbols = sorted(sec.iter_symbols(), key=lambda sym: sym.name)
             print("    symbols:")
             for sym in symbols:
                 if not sym.name:
                     continue
                 print("    - %r: size=%d, value=0x%x, type=%s, bind=%s" % (
                     sym.name.decode(),
                     sym['st_size'],
                     sym['st_value'],
                     descriptions.describe_symbol_type(
                         sym['st_info']['type']),
                     descriptions.describe_symbol_bind(
                         sym['st_info']['bind']),
                 ))
     print()
Beispiel #2
0
    def display_symbol_tables(self):
        """ Display the symbol tables contained in the file
        """
        for section in self.elffile.iter_sections():
            if not isinstance(section, SymbolTableSection):
                continue

            if section['sh_entsize'] == 0:
                self._emitline("\nSymbol table '%s' has a sh_entsize of zero!" % (
                    bytes2str(section.name)))
                continue

            self._emitline("\nSymbol table '%s' contains %s entries:" % (
                bytes2str(section.name), section.num_symbols()))

            if self.elffile.elfclass == 32:
                self._emitline('   Num:    Value  Size Type    Bind   Vis      Ndx Name')
            else: # 64
                self._emitline('   Num:    Value          Size Type    Bind   Vis      Ndx Name')

            for nsym, symbol in enumerate(section.iter_symbols()):
                # symbol names are truncated to 25 chars, similarly to readelf
                self._emitline('%6d: %s %5d %-7s %-6s %-7s %4s %.25s' % (
                    nsym,
                    self._format_hex(symbol['st_value'], fullhex=True, lead0x=False),
                    symbol['st_size'],
                    describe_symbol_type(symbol['st_info']['type']),
                    describe_symbol_bind(symbol['st_info']['bind']),
                    describe_symbol_visibility(symbol['st_other']['visibility']),
                    describe_symbol_shndx(symbol['st_shndx']),
                    bytes2str(symbol.name)))
Beispiel #3
0
 def _dump_elf(cls, buf):
     """
     Dump the symbol table of an ELF file.
     Needs pyelftools (https://github.com/eliben/pyelftools)
     """
     from elftools.elf.elffile import ELFFile
     from elftools.elf import descriptions
     from io import BytesIO
     f = ELFFile(BytesIO(buf))
     print("ELF file:")
     for sec in f.iter_sections():
         if sec['sh_type'] == 'SHT_SYMTAB':
             symbols = sorted(sec.iter_symbols(), key=lambda sym: sym.name)
             print("    symbols:")
             for sym in symbols:
                 if not sym.name:
                     continue
                 print("    - %r: size=%d, value=0x%x, type=%s, bind=%s"
                       % (sym.name.decode(),
                          sym['st_size'],
                          sym['st_value'],
                          descriptions.describe_symbol_type(sym['st_info']['type']),
                          descriptions.describe_symbol_bind(sym['st_info']['bind']),
                          ))
     print()
Beispiel #4
0
    def elf_symbol_tables(self):
        symbol_tables_list = []

        def add_info(dic):
            symbol_tables_list.append(dic)

        self._init_versioninfo()

        symbol_tables = [
            s for s in self.elffile.iter_sections()
            if isinstance(s, SymbolTableSection)
        ]

        if not symbol_tables and self.elffile.num_sections() == 0:
            return None

        for section in symbol_tables:
            if not isinstance(section, SymbolTableSection):
                continue

            if section['sh_entsize'] == 0:
                continue

            for nsym, symbol in enumerate(section.iter_symbols()):
                version_info = ''
                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_info = {}
                symbol_info['index'] = nsym
                symbol_info['Value'] = self._format_hex(symbol['st_value'],
                                                        fullhex=True,
                                                        lead0x=False)
                symbol_info['Size'] = symbol['st_size']
                symbol_info['Type'] = describe_symbol_type(
                    symbol['st_info']['type'])
                symbol_info['Bind'] = describe_symbol_bind(
                    symbol['st_info']['bind'])
                symbol_info['Vis'] = describe_symbol_visibility(
                    symbol['st_other']['visibility'])
                symbol_info['Ndx'] = describe_symbol_shndx(symbol['st_shndx'])
                symbol_info['Name'] = symbol.name
                symbol_info['version_info'] = version_info
                add_info(symbol_info)
        return symbol_tables_list
Beispiel #5
0
    def display_symbol_tables(self):
        """ Display the symbol tables contained in the file
        """
        self._init_versioninfo()

        for section in self.elffile.iter_sections():
            if not isinstance(section, SymbolTableSection):
                continue

            if section['sh_entsize'] == 0:
                self._emitline("\nSymbol table '%s' has a sh_entsize of zero!" % (
                    bytes2str(section.name)))
                continue

            self._emitline("\nSymbol table '%s' contains %s entries:" % (
                bytes2str(section.name), section.num_symbols()))

            if self.elffile.elfclass == 32:
                self._emitline('   Num:    Value  Size Type    Bind   Vis      Ndx Name')
            else: # 64
                self._emitline('   Num:    Value          Size Type    Bind   Vis      Ndx Name')

            for nsym, symbol in enumerate(section.iter_symbols()):

                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'] != bytes2str(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
                self._emitline('%6d: %s %5d %-7s %-6s %-7s %4s %.25s%s' % (
                    nsym,
                    self._format_hex(
                        symbol['st_value'], fullhex=True, lead0x=False),
                    symbol['st_size'],
                    describe_symbol_type(symbol['st_info']['type']),
                    describe_symbol_bind(symbol['st_info']['bind']),
                    describe_symbol_visibility(symbol['st_other']['visibility']),
                    describe_symbol_shndx(symbol['st_shndx']),
                    bytes2str(symbol.name),
                    version_info))
Beispiel #6
0
 def _get_symbol_tables(self):
     symbol_tables = []
     for section in self.elf.iter_sections():
         if not isinstance(section, SymbolTableSection):
             continue
         for nsym, symbol in enumerate(section.iter_symbols()):
             symbol_tables.append({
                 "value": self._print_addr(symbol["st_value"]),
                 "type": describe_symbol_type(symbol["st_info"]["type"]),
                 "bind": describe_symbol_bind(symbol["st_info"]["bind"]),
                 "ndx_name": symbol.name,
             })
     return symbol_tables
Beispiel #7
0
 def _get_symbol_tables(self):
     symbol_tables = []
     for section in self.elf.iter_sections():
         if not isinstance(section, SymbolTableSection):
             continue
         for nsym, symbol in enumerate(section.iter_symbols()):
             symbol_tables.append({
                 "value": self._print_addr(symbol["st_value"]),
                 "type": describe_symbol_type(symbol["st_info"]["type"]),
                 "bind": describe_symbol_bind(symbol["st_info"]["bind"]),
                 "ndx_name": symbol.name,
             })
     return symbol_tables
Beispiel #8
0
    def _get_symbol_tables(self) -> List[Dict[str, str]]:
        symbol_tables = []
        for section in self.elf.iter_sections():
            if not isinstance(section, SymbolTableSection):
                continue
            symbol_tables.extend(
                {
                    "value": self._print_addr(symbol["st_value"]),
                    "type": describe_symbol_type(symbol["st_info"]["type"]),
                    "bind": describe_symbol_bind(symbol["st_info"]["bind"]),
                    "ndx_name": symbol.name,
                }
                for symbol in section.iter_symbols()
            )

        return symbol_tables
Beispiel #9
0
    def display_symbol_tables(self):
        """ Display the symbol tables contained in the file
        """
        for section in self.elffile.iter_sections():
            if not isinstance(section, SymbolTableSection):
                continue

            if section['sh_entsize'] == 0:
                self._emitline(
                    "\nSymbol table '%s' has a sh_entsize of zero!" %
                    (bytes2str(section.name)))
                continue

            self._emitline("\nSymbol table '%s' contains %s entries:" %
                           (bytes2str(section.name), section.num_symbols()))

            if self.elffile.elfclass == 32:
                self._emitline(
                    '   Num:    Value  Size Type    Bind   Vis      Ndx Name')
            else:  # 64
                self._emitline(
                    '   Num:    Value          Size Type    Bind   Vis      Ndx Name'
                )

            for nsym, symbol in enumerate(section.iter_symbols()):
                # symbol names are truncated to 25 chars, similarly to readelf
                self._emitline(
                    '%6d: %s %5d %-7s %-6s %-7s %4s %.25s' %
                    (nsym,
                     self._format_hex(symbol['st_value'],
                                      fullhex=True,
                                      lead0x=False), symbol['st_size'],
                     describe_symbol_type(symbol['st_info']['type']),
                     describe_symbol_bind(symbol['st_info']['bind']),
                     describe_symbol_visibility(
                         symbol['st_other']['visibility']),
                     describe_symbol_shndx(
                         symbol['st_shndx']), bytes2str(symbol.name)))
Beispiel #10
0
    def get_symbols(self):
        """Return a set of symbols from the dwarf symbol tables"""
        symbols = {}

        # We want .symtab and .dynsym
        tables = [
            (idx, s)
            for idx, s in enumerate(self.elffile.iter_sections())
            if isinstance(s, SymbolTableSection)
        ]

        for idx, section in tables:
            # Symbol table has no entries if this is zero
            # section.num_symbols() shows count, section.name is name
            if section["sh_entsize"] == 0:
                continue

            # We need the index of the symbol to look up versions
            for sym_idx, symbol in enumerate(section.iter_symbols()):

                # Version info is from the versym / verneed / verdef sections.
                version_info = self._get_symbol_version(section, sym_idx, symbol)

                # We aren't considering st_value, which could be many things
                # https://docs.oracle.com/cd/E19683-01/816-1386/6m7qcoblj/index.html#chapter6-35166
                symbols[symbol.name] = {
                    "version_info": version_info,
                    "type": describe_symbol_type(symbol["st_info"]["type"]),
                    "binding": describe_symbol_bind(symbol["st_info"]["bind"]),
                    "visibility": describe_symbol_visibility(
                        symbol["st_other"]["visibility"]
                    ),
                    "defined": describe_symbol_shndx(
                        self._get_symbol_shndx(symbol, sym_idx, idx)
                    ).strip(),
                }

        return symbols
Beispiel #11
0
    def scan(self, data, file, options, expire_at):
        with io.BytesIO(data) as elf_io:
            try:
                elf = elffile.ELFFile(elf_io)

                self.event.setdefault('header', {})
                for (key, value) in elf.header.items():
                    if key == 'e_flags':
                        self.event['header']['flags'] = value
                    elif key == 'e_shnum':
                        self.event['header']['section_headers'] = value
                    elif key == 'e_phnum':
                        self.event['header']['program_headers'] = value
                    elif key == 'e_version':
                        self.event['header'][
                            'file_version'] = descriptions.describe_e_version_numeric(
                                value)
                    elif key == 'e_machine':
                        self.event['header'][
                            'machine'] = descriptions.describe_e_machine(value)
                    elif key == 'e_type':
                        self.event['header'][
                            'file_type'] = descriptions.describe_e_type(value)
                    elif key == 'e_ident':
                        for x, y in value.items():
                            if x == 'EI_DATA':
                                self.event['header'][
                                    'data'] = descriptions.describe_ei_data(y)
                            elif x == 'EI_OSABI':
                                self.event['header'][
                                    'os_abi'] = descriptions.describe_ei_osabi(
                                        y)
                            elif x == 'EI_VERSION':
                                self.event['header'][
                                    'header_version'] = descriptions.describe_ei_version(
                                        y)
                            elif x == 'EI_CLASS':
                                self.event['header'][
                                    'class'] = descriptions.describe_ei_class(
                                        y)
                            elif x == 'EI_ABIVERSION':
                                self.event['header']['abi_version'] = y

                try:
                    self.event.setdefault('shared_libraries', [])
                    self.event.setdefault('imports', [])
                    self.event.setdefault('exports', [])
                    for section in elf.iter_sections():
                        if not section.is_null():
                            if isinstance(section, dynamic.DynamicSection):
                                for tag in section.iter_tags():
                                    if tag.entry.d_tag == 'DT_NEEDED':
                                        if tag.needed not in self.event[
                                                'shared_libraries']:
                                            self.event[
                                                'shared_libraries'].append(
                                                    tag.needed)

                            # Attempt to organize symbols into imports and exports
                            # This is the most comprehensive explanation I've seen for organizing these symbols: http://www.m4b.io/elf/export/binary/analysis/2015/05/25/what-is-an-elf-export.html
                            if isinstance(section,
                                          sections.SymbolTableSection):
                                for symbol in section.iter_symbols():
                                    if descriptions.describe_symbol_type(
                                            symbol['st_info']['type']) in [
                                                'FUNC', 'OBJECT'
                                            ]:
                                        if descriptions.describe_symbol_bind(
                                                symbol['st_info']['bind']) in [
                                                    'GLOBAL', 'WEAK'
                                                ]:
                                            if descriptions.describe_symbol_shndx(
                                                    symbol['st_shndx']
                                            ) == 'UND':
                                                if symbol.name not in self.event[
                                                        'imports']:
                                                    self.event[
                                                        'imports'].append(
                                                            symbol.name)
                                            else:
                                                if symbol.name not in self.event[
                                                        'exports']:
                                                    self.event[
                                                        'exports'].append(
                                                            symbol.name)

                except OverflowError:
                    self.flags.append('overflow_error')

                self.event.setdefault('segments', [])
                segment_cache = {}
                for segment in elf.iter_segments():
                    for section in elf.iter_sections():
                        if not section.is_null(
                        ) and segment.section_in_segment(section):
                            key = segment.header['p_type']
                            if key not in self.event['segments']:
                                self.event['segments'].append(key)
                                segment_cache.setdefault(key, [])
                            segment_cache[key].append(section.name)

                self.event.setdefault('segment_sections', [])
                for (key, value) in segment_cache.items():
                    section_dict = {'segment': key, 'sections': value}
                    if section_dict not in self.event['segment_sections']:
                        self.event['segment_sections'].append(section_dict)

            except exceptions.ELFParseError:
                self.flags.append('elf_parse_error')
Beispiel #12
0
    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
Beispiel #13
0
    def CollectBinaryElfinfo(self):
        """Returns various informations symbol and versions present in elf header
    We will analyse 5 sections:
     - version definitions and
       version needed: contains version interface defined for this binary
                       and for each required soname, the version interfaces
                       required
     - symbol table: contains list of symbol name
     - version symbol table: maps the symbol against version interface
     - syminfo: contains special linking flags for each symbol
    The amount of data might be too large for it to fit in memory at one time,
    therefore the rest_client is passed to facilitate saving data.
    """
        md5_sum = self._compute_md5_sum()
        if self.rest_client.BlobExists('elfdump', md5_sum):
            logging.debug('We already have info about %r.', self._binary_path)
            return md5_sum

        sections = self._get_sections_of_interest('verneed', 'verdef',
                                                  'syminfo', 'symbols')
        versions_needed = []
        if 'verneed' in sections:
            for verneed, vernaux_iter in sections['verneed'].iter_versions():
                versions_needed.extend([{
                    'index': vernaux['vna_other'],
                    'soname': verneed.name,
                    'version': vernaux.name
                } for vernaux in vernaux_iter])

            versions_needed.sort(key=lambda x: x['index'])
            for version in versions_needed:
                del version['index']

        version_definitions = []
        if 'verdef' in sections:
            for verdef, verdaux_iter in sections['verdef'].iter_versions():
                version_name = verdaux_iter.next().name
                dependencies = [x.name for x in verdaux_iter]
                version_definitions.append({
                    'index': verdef['vd_ndx'],
                    'version': version_name,
                    'dependencies': dependencies
                })

            if version_definitions:
                version_definitions.sort(key=lambda x: x['index'])
                # the first "version definition" entry is the base soname
                # we don't care about this information
                version_definitions.pop(0)
                for version in version_definitions:
                    del version['index']

        symbols = []
        if 'symbols' in sections:
            versions_info = (version_definitions + versions_needed)
            symbol_iter = sections['symbols'].iter_symbols()
            # We skip the first symbol which is always the 'UNDEF' symbol entry
            symbol_iter.next()
            for index, sym in enumerate(symbol_iter, start=1):

                symbol = {
                    'bind': describe_symbol_bind(sym['st_info']['bind']),
                    'shndx': self._describe_symbol_shndx(sym['st_shndx']),
                    'symbol': sym.name,
                    'flags': None,
                    'soname': None,
                    'version': None
                }

                if 'versym' in sections:
                    versym = sections['versym'].get_symbol(index)
                    if not versym['ndx'] in [
                            'VER_NDX_LOCAL', 'VER_NDX_GLOBAL'
                    ]:
                        # if versym is 2 or more, it's an index on the version
                        # definition and version needed tables
                        version = versions_info[versym['ndx'] - 2]
                        symbol['version'] = version['version']
                        if 'soname' in version:
                            symbol['soname'] = version['soname']

                if 'syminfo' in sections:
                    syminfo = sections['syminfo'].get_symbol(index)
                    # We only use the information from syminfo if:
                    # - there is at least one flag that uses the boundto value,
                    # - boundto is an index and not special value (SYMINFO_BT_SELF...)
                    if (syminfo['si_flags'] &
                        (SUNW_SYMINFO_FLAGS.SYMINFO_FLG_DIRECT
                         | SUNW_SYMINFO_FLAGS.SYMINFO_FLG_DIRECTBIND
                         | SUNW_SYMINFO_FLAGS.SYMINFO_FLG_LAZYLOAD
                         | SUNW_SYMINFO_FLAGS.SYMINFO_FLG_FILTER)
                            and isinstance(syminfo['si_boundto'], int)):
                        symbol['flags'] = describe_syminfo_flags(
                            syminfo['si_flags'])
                        symbol['soname'] = self._describe_symbol_boundto(
                            syminfo)

                symbols.append(representations.ElfSymInfo(**symbol))

            symbols.sort(key=lambda m: m.symbol)

        binary_info = {
            'version definition': version_definitions,
            'version needed': versions_needed,
            'symbol table': symbols
        }
        self.rest_client.SaveBlob('elfdump', md5_sum, binary_info)
        return md5_sum
  def CollectBinaryElfinfo(self):
    """Returns various informations symbol and versions present in elf header
    We will analyse 5 sections:
     - version definitions and
       version needed: contains version interface defined for this binary
                       and for each required soname, the version interfaces
                       required
     - symbol table: contains list of symbol name
     - version symbol table: maps the symbol against version interface
     - syminfo: contains special linking flags for each symbol
    The amount of data might be too large for it to fit in memory at one time,
    therefore the rest_client is passed to facilitate saving data.
    """
    md5_sum = self._compute_md5_sum()
    if self.rest_client.BlobExists('elfdump', md5_sum):
      logging.debug('We already have info about %r.', self._binary_path)
      return md5_sum

    sections = self._get_sections_of_interest('verneed', 'verdef',
                                              'syminfo', 'symbols')
    versions_needed = []
    if 'verneed' in sections:
      for verneed, vernaux_iter in sections['verneed'].iter_versions():
        versions_needed.extend([{'index': vernaux['vna_other'],
                                 'soname': verneed.name,
                                 'version': vernaux.name}
                                for vernaux in vernaux_iter])

      versions_needed.sort(key=lambda x: x['index'])
      for version in versions_needed:
        del version['index']

    version_definitions = []
    if 'verdef' in sections:
      for verdef, verdaux_iter in sections['verdef'].iter_versions():
        version_name = verdaux_iter.next().name
        dependencies = [x.name for x in verdaux_iter]
        version_definitions.append({'index': verdef['vd_ndx'],
                                    'version': version_name,
                                    'dependencies': dependencies})

      if version_definitions:
        version_definitions.sort(key=lambda x: x['index'])
        # the first "version definition" entry is the base soname
        # we don't care about this information
        version_definitions.pop(0)
        for version in version_definitions:
          del version['index']

    symbols = []
    if 'symbols' in sections:
      versions_info = (version_definitions + versions_needed)
      symbol_iter = sections['symbols'].iter_symbols()
      # We skip the first symbol which is always the 'UNDEF' symbol entry
      symbol_iter.next()
      for index, sym in enumerate(symbol_iter, start=1):

        symbol = {'bind': describe_symbol_bind(sym['st_info']['bind']),
                  'shndx': self._describe_symbol_shndx(sym['st_shndx']),
                  'symbol': sym.name,
                  'flags': None, 'soname': None, 'version': None}

        if 'versym' in sections:
          versym = sections['versym'].get_symbol(index)
          if not versym['ndx'] in ['VER_NDX_LOCAL', 'VER_NDX_GLOBAL']:
            # if versym is 2 or more, it's an index on the version
            # definition and version needed tables
            version = versions_info[versym['ndx'] - 2]
            symbol['version'] = version['version']
            if 'soname' in version:
              symbol['soname'] = version['soname']

        if 'syminfo' in sections:
          syminfo = sections['syminfo'].get_symbol(index)
          # We only use the information from syminfo if:
          # - there is at least one flag that uses the boundto value,
          # - boundto is an index and not special value (SYMINFO_BT_SELF...)
          if (syminfo['si_flags'] & (
                SUNW_SYMINFO_FLAGS.SYMINFO_FLG_DIRECT |
                SUNW_SYMINFO_FLAGS.SYMINFO_FLG_DIRECTBIND |
                SUNW_SYMINFO_FLAGS.SYMINFO_FLG_LAZYLOAD |
                SUNW_SYMINFO_FLAGS.SYMINFO_FLG_FILTER)
              and isinstance(syminfo['si_boundto'], int)):
            symbol['flags'] = describe_syminfo_flags(syminfo['si_flags'])
            symbol['soname'] = self._describe_symbol_boundto(syminfo)

        symbols.append(representations.ElfSymInfo(**symbol))

      symbols.sort(key=lambda m: m.symbol)

    binary_info = {'version definition': version_definitions,
                   'version needed': versions_needed,
                   'symbol table': symbols}
    self.rest_client.SaveBlob('elfdump', md5_sum, binary_info)
    return md5_sum
Beispiel #15
0
    def display_symbol_tables(self):
        """ Display the symbol tables contained in the file
		"""
        self._init_versioninfo()

        listSyms = []
        setClasses = set()

        for section in self.elffile.iter_sections():
            if not isinstance(section, SymbolTableSection):
                continue

            if section['sh_entsize'] == 0:
                continue

            for nsym, symbolobj in enumerate(section.iter_symbols()):

                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'] != symbolobj.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

                demang = demangler.demangle(symbolobj.name)

                nnn = indexStartsWith(demang, "vtable for ")
                if nnn:
                    setClasses.add(nnn)
                    continue

                nnn = indexStartsWith(demang, "typeinfo name for ")
                if nnn:
                    setClasses.add(nnn)
                    continue

                nnn = indexStartsWith(demang, "typeinfo for ")
                if nnn:
                    setClasses.add(nnn)
                    continue

                nnn = indexStartsWith(demang, "non-virtual thunk to ")
                if nnn:
                    # No need to duplicate the symbol.
                    # demang = nnn
                    continue

                # Related to virtual inheritance.
                # http://stackoverflow.com/questions/6258559/what-is-the-vtt-for-a-class
                nnn = indexStartsWith(demang, "VTT for ")
                # TODO: Use it to build class hierarchy ???
                if nnn:
                    continue

                sym = ElfSym(
                    demang, symbolobj.name,
                    describe_symbol_type(symbolobj['st_info']['type']),
                    describe_symbol_bind(symbolobj['st_info']['bind']),
                    describe_symbol_visibility(
                        symbolobj['st_other']['visibility']),
                    describe_symbol_shndx(symbolobj['st_shndx']), version_info)

                listSyms.append(sym)

        return (listSyms, setClasses)
Beispiel #16
0
# vim:ts=4 sw=4 expandtab
import sys

from elftools.elf.elffile import ELFFile
from elftools.elf.sections import SymbolTableSection
from elftools.elf.descriptions import (
    describe_symbol_type, describe_symbol_bind, describe_symbol_visibility,
    describe_symbol_shndx, describe_reloc_type, describe_dyn_tag,
    )

IGNORE_TYPES=('STT_NOTYPE', 'STT_SECTION', 'STT_FILE')
f = ELFFile(open(sys.argv[1], 'r'))
for sect in f.iter_sections():
    if not isinstance(sect, SymbolTableSection):
        continue
    for sym in sect.iter_symbols():
        if sym['st_info']['type'] in IGNORE_TYPES:
            continue
        """
        print '{} rawtype {} rawbind {} rawvis {}'.format(
            sym.name,
            sym['st_info']['type'],
            sym['st_info']['bind'],
            sym['st_other']['visibility'],
        )
        """
        print '{} {}'.format(
            sym.name,
            describe_symbol_bind(sym['st_info']['bind']),
        )