def GetSpecificationStore(cls, parser_filter_expression=None): """Retrieves the specification store for the parsers. This method will create a specification store for parsers that define a format specification and a list of parser names for those that do not. Args: parser_filter_expression: optional string containing the parser filter expression, where None represents all parsers and plugins. Returns: A tuple of a format specification store (instance of FormatSpecificationStore) and the list of remaining parser names that do not have a format specification. """ specification_store = specification.FormatSpecificationStore() remainder_list = [] for parser_name, parser_class in cls.GetParsers( parser_filter_expression=parser_filter_expression): format_specification = parser_class.GetFormatSpecification() if format_specification is not None: specification_store.AddSpecification(format_specification) else: remainder_list.append(parser_name) return specification_store, remainder_list
def testMatches(self): """Tests the Matches function.""" specification_store = specification.FormatSpecificationStore() format_specification = specification.FormatSpecification('regf') format_specification.AddNewSignature(b'regf', offset=0) specification_store.AddSpecification(format_specification) test_filter = file_entry_filters.SignaturesFileEntryFilter( specification_store, ['regf']) # Test a filter match. test_path = self._GetTestFilePath(['NTUSER.DAT']) os_path_spec = path_spec_factory.Factory.NewPathSpec( dfvfs_definitions.TYPE_INDICATOR_OS, location=test_path) file_entry = path_spec_resolver.Resolver.OpenFileEntry(os_path_spec) self.assertTrue(test_filter.Matches(file_entry)) # Test a filter non-match. test_path = self._GetTestFilePath(['test_pe.exe']) os_path_spec = path_spec_factory.Factory.NewPathSpec( dfvfs_definitions.TYPE_INDICATOR_OS, location=test_path) file_entry = path_spec_resolver.Resolver.OpenFileEntry(os_path_spec) self.assertFalse(test_filter.Matches(file_entry))
def GetSpecificationStore(cls, parser_filter_string=None): """Retrieves the specification store for the parsers. This method will create a specification store for parsers that define a format specification and a list of parser names for those that do not. Args: parser_filter_string: Optional parser filter string. The default is None. Returns: A tuple of a format specification store (instance of FormatSpecificationStore) and the list of remaining parser names that do not have a format specification. """ specification_store = specification.FormatSpecificationStore() remainder_list = [] for parser_name, parser_class in cls.GetParsers( parser_filter_string=parser_filter_string): format_specification = parser_class.GetFormatSpecification() if format_specification is not None: specification_store.AddSpecification(format_specification) else: remainder_list.append(parser_name) return specification_store, remainder_list
def testGetScanner(self): """Tests the _GetScanner function.""" test_filter = file_entry_filters.SignaturesFileEntryFilter(None, []) test_filter._GetScanner(None, []) self.assertIsNone(test_filter._file_scanner) specification_store = specification.FormatSpecificationStore() format_specification = specification.FormatSpecification('no_offset') format_specification.AddNewSignature(b'test1') specification_store.AddSpecification(format_specification) format_specification = specification.FormatSpecification( 'negative_offset') format_specification.AddNewSignature(b'test2', offset=-4) specification_store.AddSpecification(format_specification) format_specification = specification.FormatSpecification( 'positive_offset') format_specification.AddNewSignature(b'test3', offset=4) specification_store.AddSpecification(format_specification) with self.assertRaises(TypeError): # Currently pysigscan does not support patterns without an offset. test_filter._GetScanner(specification_store, ['no_offset']) file_scanner = test_filter._GetScanner(specification_store, ['negative_offset']) self.assertIsNotNone(file_scanner) file_scanner = test_filter._GetScanner(specification_store, ['positive_offset']) self.assertIsNotNone(file_scanner)
def GetFormatsWithSignatures(cls, parser_filter_expression=None): """Retrieves the format specifications that have signatures. This method will create a specification store for parsers that define a format specification with signatures and a list of parser names for those that do not. Args: parser_filter_expression (Optional[str]): parser filter expression, where None represents all parsers and plugins. Returns: tuple: containing: * FormatSpecificationStore: format specifications with signaures. * list[str[: remaining parser names that do not have a format specification with signatures. """ specification_store = specification.FormatSpecificationStore() remainder_list = [] for parser_name, parser_class in cls.GetParsers( parser_filter_expression=parser_filter_expression): format_specification = parser_class.GetFormatSpecification() if format_specification and format_specification.signatures: specification_store.AddSpecification(format_specification) else: remainder_list.append(parser_name) return specification_store, remainder_list
def _ReadSpecificationFile(self, path): """Reads the format specification file. Args: path (str): path of the format specification file. Returns: FormatSpecificationStore: format specification store. """ specification_store = specification.FormatSpecificationStore() with io.open( path, 'rt', encoding=self._SPECIFICATION_FILE_ENCODING) as file_object: for line in file_object.readlines(): line = line.strip() if not line or line.startswith('#'): continue try: identifier, offset, pattern = line.split() except ValueError: logger.error('[skipping] invalid line: {0:s}'.format(line)) continue try: offset = int(offset, 10) except ValueError: logger.error( '[skipping] invalid offset in line: {0:s}'.format( line)) continue try: # TODO: find another way to do this that doesn't use an undocumented # API. pattern = codecs.escape_decode(pattern)[0] # ValueError is raised when the patterns contains invalid escaped # characters, such as "\xg1". except ValueError: logger.error( '[skipping] invalid pattern in line: {0:s}'.format( line)) continue format_specification = specification.FormatSpecification( identifier) format_specification.AddNewSignature(pattern, offset=offset) specification_store.AddSpecification(format_specification) return specification_store
def testAddSpecification(self): """Function to test the AddSpecification function.""" store = specification.FormatSpecificationStore() format_regf = specification.FormatSpecification(u'REGF') format_regf.AddNewSignature(b'regf', offset=0) format_esedb = specification.FormatSpecification(u'ESEDB') format_esedb.AddNewSignature(b'\xef\xcd\xab\x89', offset=4) store.AddSpecification(format_regf) store.AddSpecification(format_esedb) with self.assertRaises(KeyError): store.AddSpecification(format_regf)
def ReadSpecificationFile(self, path): """Reads the format specification file. Args: path: the path of the format specification file. Returns: The format specification store (instance of FormatSpecificationStore). """ specification_store = specification.FormatSpecificationStore() with open(path, 'rb') as file_object: for line in file_object.readlines(): line = line.strip() if not line or line.startswith(b'#'): continue try: identifier, offset, pattern = line.split() except ValueError: logging.error(u'[skipping] invalid line: {0:s}'.format( line.decode(u'utf-8'))) continue try: offset = int(offset, 10) except ValueError: logging.error( u'[skipping] invalid offset in line: {0:s}'.format( line.decode(u'utf-8'))) continue try: pattern = pattern.decode(u'string_escape') # ValueError is raised e.g. when the patterns contains "\xg1". except ValueError: logging.error( u'[skipping] invalid pattern in line: {0:s}'.format( line.decode(u'utf-8'))) continue format_specification = specification.FormatSpecification( identifier) format_specification.AddNewSignature(pattern, offset=offset) specification_store.AddSpecification(format_specification) return specification_store
def GetFormatsWithSignatures(cls, parser_filter_expression=None): """Retrieves the format specifications that have signatures. This method will create a specification store for parsers that define a format specification with signatures and a list of parser names for those that do not. Args: parser_filter_expression (Optional[str]): parser filter expression, where None represents all parsers and plugins. The parser filter expression is a comma separated value string that denotes a list of parser names to include and/or exclude. Each entry can have the value of: * A name of a single parser (case insensitive), such as msiecf. * A glob name for a single parser, such as '*msie*' (case insensitive). Returns: tuple: containing: * FormatSpecificationStore: format specifications with signatures. * list[str]: names of parsers that do not have format specifications with signatures, or have signatures but also need to be applied 'brute force'. """ specification_store = specification.FormatSpecificationStore() remainder_list = [] for parser_name, parser_class in cls._GetParsers( parser_filter_expression=parser_filter_expression): format_specification = parser_class.GetFormatSpecification() if format_specification and format_specification.signatures: specification_store.AddSpecification(format_specification) # The plist parser is a special case, where it both defines a signature # and also needs to be applied 'brute-force' to non-matching files, # as the signature matches binary plists, but not XML or JSON plists. if parser_name == 'plist': remainder_list.append(parser_name) else: remainder_list.append(parser_name) return specification_store, remainder_list
def GetFormatsWithSignatures(cls, parser_filter_expression=None): """Retrieves the format specifications that have signatures. This method will create a specification store for parsers that define a format specification with signatures and a list of parser names for those that do not. Args: parser_filter_expression (Optional[str]): parser filter expression, where None represents all parsers and plugins. A parser filter expression is a comma separated value string that denotes which parsers and plugins should be used. See filters/parser_filter.py for details of the expression syntax. This function does not support presets, and requires a parser filter expression where presets have been expanded. Returns: tuple: containing: * FormatSpecificationStore: format specifications with signatures. * list[str]: names of parsers that do not have format specifications with signatures, or have signatures but also need to be applied 'brute force'. """ specification_store = specification.FormatSpecificationStore() remainder_list = [] for parser_name, parser_class in cls._GetParsers( parser_filter_expression=parser_filter_expression): format_specification = parser_class.GetFormatSpecification() if format_specification and format_specification.signatures: specification_store.AddSpecification(format_specification) # The plist parser is a special case, where it both defines a signature # and also needs to be applied 'brute-force' to non-matching files, # as the signature matches binary plists, but not XML or JSON plists. if parser_name == 'plist': remainder_list.append(parser_name) else: remainder_list.append(parser_name) return specification_store, remainder_list
def testPrint(self): """Tests the Print function.""" output_writer = cli_test_lib.TestBinaryOutputWriter(encoding='utf-8') specification_store = specification.FormatSpecificationStore() specification_store.AddNewSpecification('7z') test_filter = file_entry_filters.SignaturesFileEntryFilter( specification_store, ['7z', 'bzip2']) test_filter.Print(output_writer) expected_output = [b'\tsignature identifiers: 7z', b''] output = output_writer.ReadOutput() # Compare the output as list of lines which makes it easier to spot # differences. self.assertEqual(output.split(b'\n'), expected_output)