third_party/pefile_py3/pefile.py
def parse_export_directory(self, rva, size, forwarded_only=False):
        """Parse the export directory.

        Given the RVA of the export directory, it will process all
        its entries.

        The exports will be made available as a list of ExportData
        instances in the 'IMAGE_DIRECTORY_ENTRY_EXPORT' PE attribute.
        """

        try:
            export_dir =  self.__unpack_data__(
                self.__IMAGE_EXPORT_DIRECTORY_format__,
                self.get_data( rva, Structure(self.__IMAGE_EXPORT_DIRECTORY_format__).sizeof() ),
                file_offset = self.get_offset_from_rva(rva) )
        except PEFormatError:
            self.__warnings.append(
                'Error parsing export directory at RVA: 0x%x' % ( rva ) )
            return

        if not export_dir:
            return

        # We keep track of the bytes left in the file and use it to set a upper
        # bound in the number of items that can be read from the different
        # arrays.
        def length_until_eof(rva):
            return len(self.__data__) - self.get_offset_from_rva(rva)

        try:
            address_of_names = self.get_data(
                export_dir.AddressOfNames,
                min(length_until_eof(export_dir.AddressOfNames),
                    export_dir.NumberOfNames*4))
            address_of_name_ordinals = self.get_data(
                export_dir.AddressOfNameOrdinals,
                min(length_until_eof(export_dir.AddressOfNameOrdinals),
                    export_dir.NumberOfNames*4))
            address_of_functions = self.get_data(
                export_dir.AddressOfFunctions,
                min(length_until_eof(export_dir.AddressOfFunctions),
                    export_dir.NumberOfFunctions*4))
        except PEFormatError:
            self.__warnings.append(
                'Error parsing export directory at RVA: 0x%x' % ( rva ) )
            return

        exports = []

        max_failed_entries_before_giving_up = 10

        section = self.get_section_by_rva(export_dir.AddressOfNames)
        # Overly generous upper bound
        safety_boundary = len(self.__data__)
        if section:
            safety_boundary = (
                section.VirtualAddress + len(section.get_data()) -
                export_dir.AddressOfNames)

        symbol_counts = collections.defaultdict(int)
        export_parsing_loop_completed_normally = True
        for i in range(min(export_dir.NumberOfNames, int(safety_boundary / 4))):
            symbol_ordinal = self.get_word_from_data(
                address_of_name_ordinals, i)

            if (symbol_ordinal is not None and
                symbol_ordinal*4 < len(address_of_functions)):
                symbol_address = self.get_dword_from_data(
                    address_of_functions, symbol_ordinal)
            else:
                # Corrupt? a bad pointer... we assume it's all
                # useless, no exports
                return None
            if symbol_address is None or symbol_address == 0:
                continue

            # If the function's RVA points within the export directory
            # it will point to a string with the forwarded symbol's string
            # instead of pointing the the function start address.
            if symbol_address >= rva and symbol_address < rva+size:
                forwarder_str = self.get_string_at_rva(symbol_address)
                try:
                    forwarder_offset = self.get_offset_from_rva( symbol_address )
                except PEFormatError:
                    continue
            else:
                if forwarded_only:
                    continue
                forwarder_str = None
                forwarder_offset = None

            symbol_name_address = self.get_dword_from_data(address_of_names, i)
            if symbol_name_address is None:
                max_failed_entries_before_giving_up -= 1
                if max_failed_entries_before_giving_up <= 0:
                    export_parsing_loop_completed_normally = False
                    break

            symbol_name = self.get_string_at_rva(symbol_name_address, MAX_SYMBOL_NAME_LENGTH)
            if not is_valid_function_name(symbol_name):
                export_parsing_loop_completed_normally = False
                break
            try:
                symbol_name_offset = self.get_offset_from_rva(symbol_name_address)
            except PEFormatError:
                max_failed_entries_before_giving_up -= 1
                if max_failed_entries_before_giving_up <= 0:
                    export_parsing_loop_completed_normally = False
                    break
                try:
                    symbol_name_offset = self.get_offset_from_rva( symbol_name_address )
                except PEFormatError:
                    max_failed_entries_before_giving_up -= 1
                    if max_failed_entries_before_giving_up <= 0:
                        export_parsing_loop_completed_normally = False
                        break
                    continue

            # File 0b1d3d3664915577ab9a32188d29bbf3542b86c7b9ce333e245496c3018819f1
            # was being parsed as potentially containing millions of exports.
            # Checking for duplicates addresses the issue.
            symbol_counts[(symbol_name, symbol_address)] += 1
            if symbol_counts[(symbol_name, symbol_address)] > 10:
                self.__warnings.append(
                    f'Export directory contains more than 10 repeated entries '
                    f'({symbol_name}, {symbol_address:#02x}). Assuming corrupt.')
                break
            elif len(symbol_counts) > self.max_symbol_exports:
                self.__warnings.append(
                    'Export directory contains more than {} symbol entries. '
                    'Assuming corrupt.'.format(self.max_symbol_exports))
                break

            exports.append(
                ExportData(
                    pe = self,
                    ordinal = export_dir.Base+symbol_ordinal,
                    ordinal_offset = self.get_offset_from_rva( export_dir.AddressOfNameOrdinals + 2*i ),
                    address = symbol_address,
                    address_offset = self.get_offset_from_rva( export_dir.AddressOfFunctions + 4*symbol_ordinal ),
                    name = symbol_name,
                    name_offset = symbol_name_offset,
                    forwarder = forwarder_str,
                    forwarder_offset = forwarder_offset ))

        if not export_parsing_loop_completed_normally:
            self.__warnings.append(
                'RVA AddressOfNames in the export directory points to an invalid address: %x' %
                export_dir.AddressOfNames)

        ordinals = {exp.ordinal for exp in exports}

        max_failed_entries_before_giving_up = 10

        section = self.get_section_by_rva(export_dir.AddressOfFunctions)
        # Overly generous upper bound
        safety_boundary = len(self.__data__)
        if section:
            safety_boundary = (
                section.VirtualAddress + len(section.get_data()) -
                export_dir.AddressOfFunctions)

        symbol_counts = collections.defaultdict(int)
        export_parsing_loop_completed_normally = True
        for idx in range(min(
                export_dir.NumberOfFunctions,
                int(safety_boundary / 4))):

            if not idx+export_dir.Base in ordinals:
                try:
                    symbol_address = self.get_dword_from_data(
                        address_of_functions, idx)
                except PEFormatError:
                    symbol_address = None

                if symbol_address is None:
                    max_failed_entries_before_giving_up -= 1
                    if max_failed_entries_before_giving_up <= 0:
                        export_parsing_loop_completed_normally = False
                        break

                if symbol_address == 0:
                    continue

                # Checking for forwarder again.
                if symbol_address is not None and symbol_address >= rva and symbol_address < rva+size:
                    forwarder_str = self.get_string_at_rva(symbol_address)
                else:
                    forwarder_str = None

                # File 0b1d3d3664915577ab9a32188d29bbf3542b86c7b9ce333e245496c3018819f1
                # was being parsed as potentially containing millions of exports.
                # Checking for duplicates addresses the issue.
                symbol_counts[symbol_address] += 1
                if symbol_counts[symbol_address] > self.max_repeated_symbol:
                # if most_common and most_common[0][1] > 10:
                    self.__warnings.append(
                        'Export directory contains more than {} repeated '
                        'ordinal entries (0x{:x}). Assuming corrupt.'.format(
                            self.max_repeated_symbol, symbol_address))
                    break
                elif len(symbol_counts) > self.max_symbol_exports:
                    self.__warnings.append(
                        'Export directory contains more than {} ordinal entries. Assuming corrupt.'.format(
                            self.max_symbol_exports))
                    break

                exports.append(
                    ExportData(
                        ordinal = export_dir.Base+idx,
                        address = symbol_address,
                        name = None,
                        forwarder = forwarder_str))

        if not export_parsing_loop_completed_normally:
            self.__warnings.append(
                'RVA AddressOfFunctions in the export directory points to an invalid address: %x' %
                export_dir.AddressOfFunctions)
            return

        if not exports and export_dir.all_zeroes():
            return None
        return ExportDirData(struct=export_dir, symbols=exports,
                             name=self.get_string_at_rva(export_dir.Name))
Parse the export directory.

        Given the RVA of the export directory, it will process all
        its entries.

        The exports will be made available as a list of ExportData
        instances in the 'IMAGE_DIRECTORY_ENTRY_EXPORT' PE attribute.
        
Parse the export directory.
Given the RVA of the export directory, it will process all
its entries.

The exports will be made available as a list of ExportData
instances in the 'IMAGE_DIRECTORY_ENTRY_EXPORT' PE attribute.
Parse the export directory . Given the RVA of the export directory it will process all its entries . The exports will be made available as a list of ExportData instances in the ' IMAGE_DIRECTORY_ENTRY_EXPORT ' PE attribute .
def parse_export_directory(self, rva, size, forwarded_only=False):
        try:
            export_dir =  self.__unpack_data__(
                self.__IMAGE_EXPORT_DIRECTORY_format__,
                self.get_data( rva, Structure(self.__IMAGE_EXPORT_DIRECTORY_format__).sizeof() ),
                file_offset = self.get_offset_from_rva(rva) )
        except PEFormatError:
            self.__warnings.append(
                'Error parsing export directory at RVA: 0x%x' % ( rva ) )
            return
        if not export_dir:
            return
        def length_until_eof(rva):
            return len(self.__data__) - self.get_offset_from_rva(rva)
        try:
            address_of_names = self.get_data(
                export_dir.AddressOfNames,
                min(length_until_eof(export_dir.AddressOfNames),
                    export_dir.NumberOfNames*4))
            address_of_name_ordinals = self.get_data(
                export_dir.AddressOfNameOrdinals,
                min(length_until_eof(export_dir.AddressOfNameOrdinals),
                    export_dir.NumberOfNames*4))
            address_of_functions = self.get_data(
                export_dir.AddressOfFunctions,
                min(length_until_eof(export_dir.AddressOfFunctions),
                    export_dir.NumberOfFunctions*4))
        except PEFormatError:
            self.__warnings.append(
                'Error parsing export directory at RVA: 0x%x' % ( rva ) )
            return
        exports = []
        max_failed_entries_before_giving_up = 10
        section = self.get_section_by_rva(export_dir.AddressOfNames)
        safety_boundary = len(self.__data__)
        if section:
            safety_boundary = (
                section.VirtualAddress + len(section.get_data()) -
                export_dir.AddressOfNames)
        symbol_counts = collections.defaultdict(int)
        export_parsing_loop_completed_normally = True
        for i in range(min(export_dir.NumberOfNames, int(safety_boundary / 4))):
            symbol_ordinal = self.get_word_from_data(
                address_of_name_ordinals, i)
            if (symbol_ordinal is not None and
                symbol_ordinal*4 < len(address_of_functions)):
                symbol_address = self.get_dword_from_data(
                    address_of_functions, symbol_ordinal)
            else:
                return None
            if symbol_address is None or symbol_address == 0:
                continue
            if symbol_address >= rva and symbol_address < rva+size:
                forwarder_str = self.get_string_at_rva(symbol_address)
                try:
                    forwarder_offset = self.get_offset_from_rva( symbol_address )
                except PEFormatError:
                    continue
            else:
                if forwarded_only:
                    continue
                forwarder_str = None
                forwarder_offset = None
            symbol_name_address = self.get_dword_from_data(address_of_names, i)
            if symbol_name_address is None:
                max_failed_entries_before_giving_up -= 1
                if max_failed_entries_before_giving_up <= 0:
                    export_parsing_loop_completed_normally = False
                    break
            symbol_name = self.get_string_at_rva(symbol_name_address, MAX_SYMBOL_NAME_LENGTH)
            if not is_valid_function_name(symbol_name):
                export_parsing_loop_completed_normally = False
                break
            try:
                symbol_name_offset = self.get_offset_from_rva(symbol_name_address)
            except PEFormatError:
                max_failed_entries_before_giving_up -= 1
                if max_failed_entries_before_giving_up <= 0:
                    export_parsing_loop_completed_normally = False
                    break
                try:
                    symbol_name_offset = self.get_offset_from_rva( symbol_name_address )
                except PEFormatError:
                    max_failed_entries_before_giving_up -= 1
                    if max_failed_entries_before_giving_up <= 0:
                        export_parsing_loop_completed_normally = False
                        break
                    continue
            symbol_counts[(symbol_name, symbol_address)] += 1
            if symbol_counts[(symbol_name, symbol_address)] > 10:
                self.__warnings.append(
                    f'Export directory contains more than 10 repeated entries '
                    f'({symbol_name}, {symbol_address:#02x}). Assuming corrupt.')
                break
            elif len(symbol_counts) > self.max_symbol_exports:
                self.__warnings.append(
                    'Export directory contains more than {} symbol entries. '
                    'Assuming corrupt.'.format(self.max_symbol_exports))
                break
            exports.append(
                ExportData(
                    pe = self,
                    ordinal = export_dir.Base+symbol_ordinal,
                    ordinal_offset = self.get_offset_from_rva( export_dir.AddressOfNameOrdinals + 2*i ),
                    address = symbol_address,
                    address_offset = self.get_offset_from_rva( export_dir.AddressOfFunctions + 4*symbol_ordinal ),
                    name = symbol_name,
                    name_offset = symbol_name_offset,
                    forwarder = forwarder_str,
                    forwarder_offset = forwarder_offset ))
        if not export_parsing_loop_completed_normally:
            self.__warnings.append(
                'RVA AddressOfNames in the export directory points to an invalid address: %x' %
                export_dir.AddressOfNames)
        ordinals = {exp.ordinal for exp in exports}
        max_failed_entries_before_giving_up = 10
        section = self.get_section_by_rva(export_dir.AddressOfFunctions)
        safety_boundary = len(self.__data__)
        if section:
            safety_boundary = (
                section.VirtualAddress + len(section.get_data()) -
                export_dir.AddressOfFunctions)
        symbol_counts = collections.defaultdict(int)
        export_parsing_loop_completed_normally = True
        for idx in range(min(
                export_dir.NumberOfFunctions,
                int(safety_boundary / 4))):
            if not idx+export_dir.Base in ordinals:
                try:
                    symbol_address = self.get_dword_from_data(
                        address_of_functions, idx)
                except PEFormatError:
                    symbol_address = None
                if symbol_address is None:
                    max_failed_entries_before_giving_up -= 1
                    if max_failed_entries_before_giving_up <= 0:
                        export_parsing_loop_completed_normally = False
                        break
                if symbol_address == 0:
                    continue
                if symbol_address is not None and symbol_address >= rva and symbol_address < rva+size:
                    forwarder_str = self.get_string_at_rva(symbol_address)
                else:
                    forwarder_str = None
                symbol_counts[symbol_address] += 1
                if symbol_counts[symbol_address] > self.max_repeated_symbol:
                    self.__warnings.append(
                        'Export directory contains more than {} repeated '
                        'ordinal entries (0x{:x}). Assuming corrupt.'.format(
                            self.max_repeated_symbol, symbol_address))
                    break
                elif len(symbol_counts) > self.max_symbol_exports:
                    self.__warnings.append(
                        'Export directory contains more than {} ordinal entries. Assuming corrupt.'.format(
                            self.max_symbol_exports))
                    break
                exports.append(
                    ExportData(
                        ordinal = export_dir.Base+idx,
                        address = symbol_address,
                        name = None,
                        forwarder = forwarder_str))
        if not export_parsing_loop_completed_normally:
            self.__warnings.append(
                'RVA AddressOfFunctions in the export directory points to an invalid address: %x' %
                export_dir.AddressOfFunctions)
            return
        if not exports and export_dir.all_zeroes():
            return None
        return ExportDirData(struct=export_dir, symbols=exports,
                             name=self.get_string_at_rva(export_dir.Name))
def parse_export_directory ( self , rva , size , forwarded_only = False ) : try : export_dir = self . __unpack_data__ ( self . __IMAGE_EXPORT_DIRECTORY_format__ , self . get_data ( rva , Structure ( self . __IMAGE_EXPORT_DIRECTORY_format__ ) . sizeof ( ) ) , file_offset = self . get_offset_from_rva ( rva ) ) except PEFormatError : self . __warnings . append ( 'Error parsing export directory at RVA: 0x%x' % ( rva ) ) return if not export_dir : return def length_until_eof ( rva ) : return len ( self . __data__ ) - self . get_offset_from_rva ( rva ) try : address_of_names = self . get_data ( export_dir . AddressOfNames , min ( length_until_eof ( export_dir . AddressOfNames ) , export_dir . NumberOfNames * 4 ) ) address_of_name_ordinals = self . get_data ( export_dir . AddressOfNameOrdinals , min ( length_until_eof ( export_dir . AddressOfNameOrdinals ) , export_dir . NumberOfNames * 4 ) ) address_of_functions = self . get_data ( export_dir . AddressOfFunctions , min ( length_until_eof ( export_dir . AddressOfFunctions ) , export_dir . NumberOfFunctions * 4 ) ) except PEFormatError : self . __warnings . append ( 'Error parsing export directory at RVA: 0x%x' % ( rva ) ) return exports = [ ] max_failed_entries_before_giving_up = 10 section = self . get_section_by_rva ( export_dir . AddressOfNames ) safety_boundary = len ( self . __data__ ) if section : safety_boundary = ( section . VirtualAddress + len ( section . get_data ( ) ) - export_dir . AddressOfNames ) symbol_counts = collections . defaultdict ( int ) export_parsing_loop_completed_normally = True for i in range ( min ( export_dir . NumberOfNames , int ( safety_boundary / 4 ) ) ) : symbol_ordinal = self . get_word_from_data ( address_of_name_ordinals , i ) if ( symbol_ordinal is not None and symbol_ordinal * 4 < len ( address_of_functions ) ) : symbol_address = self . get_dword_from_data ( address_of_functions , symbol_ordinal ) else : return None if symbol_address is None or symbol_address == 0 : continue if symbol_address >= rva and symbol_address < rva + size : forwarder_str = self . get_string_at_rva ( symbol_address ) try : forwarder_offset = self . get_offset_from_rva ( symbol_address ) except PEFormatError : continue else : if forwarded_only : continue forwarder_str = None forwarder_offset = None symbol_name_address = self . get_dword_from_data ( address_of_names , i ) if symbol_name_address is None : max_failed_entries_before_giving_up -= 1 if max_failed_entries_before_giving_up <= 0 : export_parsing_loop_completed_normally = False break symbol_name = self . get_string_at_rva ( symbol_name_address , MAX_SYMBOL_NAME_LENGTH ) if not is_valid_function_name ( symbol_name ) : export_parsing_loop_completed_normally = False break try : symbol_name_offset = self . get_offset_from_rva ( symbol_name_address ) except PEFormatError : max_failed_entries_before_giving_up -= 1 if max_failed_entries_before_giving_up <= 0 : export_parsing_loop_completed_normally = False break try : symbol_name_offset = self . get_offset_from_rva ( symbol_name_address ) except PEFormatError : max_failed_entries_before_giving_up -= 1 if max_failed_entries_before_giving_up <= 0 : export_parsing_loop_completed_normally = False break continue symbol_counts [ ( symbol_name , symbol_address ) ] += 1 if symbol_counts [ ( symbol_name , symbol_address ) ] > 10 : self . __warnings . append ( f'Export directory contains more than 10 repeated entries ' f'({symbol_name}, {symbol_address:#02x}). Assuming corrupt.' ) break elif len ( symbol_counts ) > self . max_symbol_exports : self . __warnings . append ( 'Export directory contains more than {} symbol entries. ' 'Assuming corrupt.' . format ( self . max_symbol_exports ) ) break exports . append ( ExportData ( pe = self , ordinal = export_dir . Base + symbol_ordinal , ordinal_offset = self . get_offset_from_rva ( export_dir . AddressOfNameOrdinals + 2 * i ) , address = symbol_address , address_offset = self . get_offset_from_rva ( export_dir . AddressOfFunctions + 4 * symbol_ordinal ) , name = symbol_name , name_offset = symbol_name_offset , forwarder = forwarder_str , forwarder_offset = forwarder_offset ) ) if not export_parsing_loop_completed_normally : self . __warnings . append ( 'RVA AddressOfNames in the export directory points to an invalid address: %x' % export_dir . AddressOfNames ) ordinals = { exp . ordinal for exp in exports } max_failed_entries_before_giving_up = 10 section = self . get_section_by_rva ( export_dir . AddressOfFunctions ) safety_boundary = len ( self . __data__ ) if section : safety_boundary = ( section . VirtualAddress + len ( section . get_data ( ) ) - export_dir . AddressOfFunctions ) symbol_counts = collections . defaultdict ( int ) export_parsing_loop_completed_normally = True for idx in range ( min ( export_dir . NumberOfFunctions , int ( safety_boundary / 4 ) ) ) : if not idx + export_dir . Base in ordinals : try : symbol_address = self . get_dword_from_data ( address_of_functions , idx ) except PEFormatError : symbol_address = None if symbol_address is None : max_failed_entries_before_giving_up -= 1 if max_failed_entries_before_giving_up <= 0 : export_parsing_loop_completed_normally = False break if symbol_address == 0 : continue if symbol_address is not None and symbol_address >= rva and symbol_address < rva + size : forwarder_str = self . get_string_at_rva ( symbol_address ) else : forwarder_str = None symbol_counts [ symbol_address ] += 1 if symbol_counts [ symbol_address ] > self . max_repeated_symbol : self . __warnings . append ( 'Export directory contains more than {} repeated ' 'ordinal entries (0x{:x}). Assuming corrupt.' . format ( self . max_repeated_symbol , symbol_address ) ) break elif len ( symbol_counts ) > self . max_symbol_exports : self . __warnings . append ( 'Export directory contains more than {} ordinal entries. Assuming corrupt.' . format ( self . max_symbol_exports ) ) break exports . append ( ExportData ( ordinal = export_dir . Base + idx , address = symbol_address , name = None , forwarder = forwarder_str ) ) if not export_parsing_loop_completed_normally : self . __warnings . append ( 'RVA AddressOfFunctions in the export directory points to an invalid address: %x' % export_dir . AddressOfFunctions ) return if not exports and export_dir . all_zeroes ( ) : return None return ExportDirData ( struct = export_dir , symbols = exports , name = self . get_string_at_rva ( export_dir . Name ) )
Parse the export directory.
Parse the export directory .
"""Parse the export directory.

        Given the RVA of the export directory, it will process all
        its entries.

        The exports will be made available as a list of ExportData
        instances in the 'IMAGE_DIRECTORY_ENTRY_EXPORT' PE attribute.
        """ # We keep track of the bytes left in the file and use it to set a upper # bound in the number of items that can be read from the different # arrays. # Overly generous upper bound # Corrupt? a bad pointer... we assume it's all # useless, no exports # If the function's RVA points within the export directory # it will point to a string with the forwarded symbol's string # instead of pointing the the function start address. # File 0b1d3d3664915577ab9a32188d29bbf3542b86c7b9ce333e245496c3018819f1 # was being parsed as potentially containing millions of exports. # Checking for duplicates addresses the issue. # Overly generous upper bound # Checking for forwarder again. # File 0b1d3d3664915577ab9a32188d29bbf3542b86c7b9ce333e245496c3018819f1 # was being parsed as potentially containing millions of exports. # Checking for duplicates addresses the issue. # if most_common and most_common[0][1] > 10:
self
rva
size
forwarded_only