Source code for plaso.parsers.winreg_parser

"""Parser for Windows NT Registry (REGF) files."""

from dfwinreg import errors as dfwinreg_errors
from dfwinreg import regf as dfwinreg_regf
from dfwinreg import registry as dfwinreg_registry
from dfwinreg import registry_searcher as dfwinreg_registry_searcher

from plaso.engine import artifact_filters
from plaso.lib import specification
from plaso.filters import path_filter
from plaso.parsers import interface
from plaso.parsers import logger
from plaso.parsers import manager


[docs] class WinRegistryParser(interface.FileObjectParser): """Parses Windows NT Registry (REGF) files.""" NAME = "winreg" DATA_FORMAT = "Windows NT Registry (REGF) file" _plugin_classes = {} _ARTIFACTS_FILTER_HELPER = artifact_filters.ArtifactDefinitionsFiltersHelper _AMCACHE_ROOT_KEY_NAMES = frozenset( [ "{11517b7c-e79d-4e20-961b-75a811715add}", "{356c48f6-2fee-e7ef-2a64-39f59ec3be22}", ] ) _CONTROL_SET_PREFIX = ("HKEY_LOCAL_MACHINE\\System\\ControlSet").lower() _NORMALIZED_CONTROL_SET_PREFIX = ( "HKEY_LOCAL_MACHINE\\System\\CurrentControlSet" ).lower()
[docs] def __init__(self): """Initializes a parser.""" super().__init__() self._path_filter = None self._plugins_per_key_path = {} self._plugins_without_key_paths = []
def _CanProcessKeyWithPlugin(self, registry_key, plugin): """Determines if a plugin can process a Windows Registry key or its values. Args: registry_key (dfwinreg.WinRegistryKey): Windows Registry key. plugin (WindowsRegistryPlugin): Windows Registry plugin. Returns: bool: True if the Registry key can be processed with the plugin. """ for registry_key_filter in plugin.FILTERS: # Skip filters that define key paths since they are already # checked by the path filter. if getattr(registry_key_filter, "key_paths", []): continue if registry_key_filter.Match(registry_key): return True return False
[docs] def EnablePlugins(self, plugin_includes): """Enables parser plugins. Args: plugin_includes (set[str]): names of the plugins to enable, where set(['*']) represents all plugins. Note the default plugin, if it exists, is always enabled and cannot be disabled. """ self._plugins_per_name = {} self._plugins_per_key_path = {} self._plugins_without_key_paths = [] if not self._plugin_classes: return key_paths = [] for plugin_name, plugin_class in self._plugin_classes.items(): if plugin_name == self._default_plugin_name: self._default_plugin = plugin_class() continue if ( plugin_includes != self.ALL_PLUGINS and plugin_name not in plugin_includes ): continue plugin_object = plugin_class() self._plugins_per_name[plugin_name] = plugin_object for registry_key_filter in plugin_object.FILTERS: plugin_key_paths = getattr(registry_key_filter, "key_paths", []) if ( not plugin_key_paths and plugin_object not in self._plugins_without_key_paths ): self._plugins_without_key_paths.append(plugin_object) continue for plugin_key_path in plugin_key_paths: lookup_path = plugin_key_path.lower() existing_plugin = self._plugins_per_key_path.get(lookup_path) if existing_plugin: logger.warning( f"Windows Registry key path: {plugin_key_path:s} defined " f"by plugin: {plugin_object.NAME:s} already set by plugin: " f"{existing_plugin.NAME:s}" ) continue self._plugins_per_key_path[lookup_path] = plugin_object key_paths.append(lookup_path) self._path_filter = path_filter.PathFilterScanTree( key_paths, case_sensitive=False, path_segment_separator="\\" )
[docs] @classmethod def GetFormatSpecification(cls): """Retrieves the format specification.""" format_specification = specification.FormatSpecification(cls.NAME) format_specification.AddNewSignature(b"regf", offset=0) return format_specification
def _ParseKeyWithPlugin(self, parser_mediator, win_registry, registry_key, plugin): """Parses the Registry key with a specific plugin. Args: parser_mediator (ParserMediator): parser mediator. win_registry (dfwinreg.WinRegistry): Windows Registry. registry_key (dfwinreg.WinRegistryKey): Windows Registry key. plugin (WindowsRegistryPlugin): Windows Registry plugin. """ kwargs = {} for attribute_name, context_key_path in plugin.CONTEXT_KEYS.items(): kwargs[attribute_name] = win_registry.GetKeyByPath(context_key_path) try: plugin.UpdateChainAndProcess(parser_mediator, registry_key, **kwargs) except (OSError, dfwinreg_errors.WinRegistryValueError) as exception: parser_mediator.ProduceExtractionWarning( f"in key: {registry_key.path:s} error: {exception!s}" ) def _NormalizeKeyPath(self, key_path): """Normalizes a Windows Registry key path. Args: key_path (str): Windows Registry key path. Returns: str: normalized Windows Registry key path. """ normalized_key_path = key_path.lower() # The Registry key path should start with: # HKEY_LOCAL_MACHINE\System\ControlSet followed by 3 digits # which makes 39 characters. if len(normalized_key_path) < 39 or not normalized_key_path.startswith( self._CONTROL_SET_PREFIX ): return normalized_key_path # Key paths that contain ControlSet### must be normalized to # CurrentControlSet. return "".join([self._NORMALIZED_CONTROL_SET_PREFIX, normalized_key_path[39:]]) def _ParseKey(self, parser_mediator, win_registry, registry_key): """Parses the Registry key with a specific plugin. Args: parser_mediator (ParserMediator): parser mediator. win_registry (dfwinreg.WinRegistry): Windows Registry. registry_key (dfwinreg.WinRegistryKey): Windows Registry key. """ matching_plugin = None logger.debug(f"Parsing Windows Registry key: {registry_key.path:s}") normalized_key_path = self._NormalizeKeyPath(registry_key.path) if self._path_filter and self._path_filter.CheckPath(normalized_key_path): matching_plugin = self._plugins_per_key_path[normalized_key_path] else: for plugin in self._plugins_without_key_paths: profiling_name = "/".join([self.NAME, plugin.NAME]) parser_mediator.SampleFormatCheckStartTiming(profiling_name) try: if self._CanProcessKeyWithPlugin(registry_key, plugin): matching_plugin = plugin break finally: parser_mediator.SampleFormatCheckStopTiming(profiling_name) if not matching_plugin: matching_plugin = self._default_plugin if matching_plugin: self._ParseKeyWithPlugin( parser_mediator, win_registry, registry_key, matching_plugin ) def _ParseRecurseKeys(self, parser_mediator, win_registry, registry_key): """Parses the Registry keys recursively. Args: parser_mediator (ParserMediator): parser mediator. win_registry (dfwinreg.WinRegistry): Windows Registry. registry_key (dfwinreg.WinRegistryKey): Windows Registry key. """ # Note that we do not use dfWinReg generators here to be able to catch # exceptions raised by corrupt files. self._ParseKey(parser_mediator, win_registry, registry_key) for subkey_index in range(registry_key.number_of_subkeys): if parser_mediator.abort: break try: subkey = registry_key.GetSubkeyByIndex(subkey_index) self._ParseRecurseKeys(parser_mediator, win_registry, subkey) except OSError as exception: parser_mediator.ProduceExtractionWarning( f"in key: {registry_key.path:s} error: {exception!s}" ) def _ParseKeysFromFindSpecs(self, parser_mediator, win_registry, find_specs): """Parses the Registry keys from FindSpecs. Args: parser_mediator (ParserMediator): parser mediator. win_registry (dfwinreg.WinRegistry): Windows Registry. find_specs (dfwinreg.FindSpecs): Keys to search for. """ searcher = dfwinreg_registry_searcher.WinRegistrySearcher(win_registry) for registry_key_path in searcher.Find(find_specs=find_specs): if parser_mediator.abort: break registry_key = searcher.GetKeyByPath(registry_key_path) self._ParseKey(parser_mediator, win_registry, registry_key)
[docs] def ParseFileObject(self, parser_mediator, file_object): """Parses a Windows Registry file-like object. Args: parser_mediator (ParserMediator): parser mediator. file_object (dfvfs.FileIO): a file-like object. """ code_page = parser_mediator.GetCodePage() registry_file = dfwinreg_regf.REGFWinRegistryFile(ascii_codepage=code_page) try: registry_file.Open(file_object) except OSError as exception: parser_mediator.ProduceExtractionWarning( f"unable to open Windows Registry file with error: {exception!s}" ) return try: win_registry = dfwinreg_registry.WinRegistry() key_path_prefix = win_registry.GetRegistryFileMapping(registry_file) registry_file.SetKeyPathPrefix(key_path_prefix) root_key = registry_file.GetRootKey() if root_key: # For now treat AMCache.hve separately. if root_key.name.lower() in self._AMCACHE_ROOT_KEY_NAMES: self._ParseRecurseKeys(parser_mediator, win_registry, root_key) elif not parser_mediator.registry_find_specs: self._ParseRecurseKeys(parser_mediator, win_registry, root_key) elif not self._ARTIFACTS_FILTER_HELPER.CheckKeyCompatibility( key_path_prefix ): logger.warning( f"Artifacts filters are not supported for Windows Registry " f'file with key path prefix: "{key_path_prefix:s}".' ) else: win_registry.MapFile(key_path_prefix, registry_file) # Note that win_registry will close the mapped registry_file. registry_file = None self._ParseKeysFromFindSpecs( parser_mediator, win_registry, parser_mediator.registry_find_specs, ) except OSError as exception: parser_mediator.ProduceExtractionWarning(f"{exception!s}") finally: if registry_file: registry_file.Close()
manager.ParsersManager.RegisterParser(WinRegistryParser)