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 by ' f'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, registry_key, plugin): """Parses the Registry key with a specific plugin. Args: parser_mediator (ParserMediator): parser mediator. registry_key (dfwinreg.WinRegistryKey): Windows Registry key. plugin (WindowsRegistryPlugin): Windows Registry plugin. """ try: plugin.UpdateChainAndProcess(parser_mediator, registry_key) 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, registry_key): """Parses the Registry key with a specific plugin. Args: parser_mediator (ParserMediator): parser mediator. 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, registry_key, matching_plugin) def _ParseRecurseKeys(self, parser_mediator, registry_key): """Parses the Registry keys recursively. Args: parser_mediator (ParserMediator): parser mediator. 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, 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, 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.WinRegistryKey): root Windows Registry key. 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, 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, root_key) elif not parser_mediator.registry_find_specs: self._ParseRecurseKeys(parser_mediator, 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)