# -*- coding: utf-8 -*-
"""Parser for Windows NT Registry (REGF) files."""
from __future__ import unicode_literals
from artifacts import definitions as artifact_types
from dfwinreg import errors as dfwinreg_errors
from dfwinreg import interface as dfwinreg_interface
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
class FileObjectWinRegistryFileReader(dfwinreg_interface.WinRegistryFileReader):
"""A single file-like object Windows Registry file reader."""
# pylint: disable=arguments-differ
def Open(self, file_object, ascii_codepage='cp1252'):
"""Opens a Windows Registry file-like object.
Args:
file_object (dfvfs.FileIO): Windows Registry file-like object.
ascii_codepage (Optional[str]): ASCII string codepage.
Returns:
WinRegistryFile: Windows Registry file or None.
"""
registry_file = dfwinreg_regf.REGFWinRegistryFile(
ascii_codepage=ascii_codepage)
# We don't catch any IOErrors here since we want to produce a parse error
# from the parser if this happens.
registry_file.Open(file_object)
return registry_file
[docs]class WinRegistryParser(interface.FileObjectParser):
"""Parses Windows NT Registry (REGF) files."""
NAME = 'winreg'
DESCRIPTION = 'Parser for Windows NT Registry (REGF) files.'
_plugin_classes = {}
_CONTROL_SET_PREFIX = (
'HKEY_LOCAL_MACHINE\\System\\ControlSet').lower()
_NORMALIZED_CONTROL_SET_PREFIX = (
'HKEY_LOCAL_MACHINE\\System\\CurrentControlSet').lower()
def __init__(self):
"""Initializes a parser object."""
super(WinRegistryParser, self).__init__()
self._plugin_per_key_path = {}
self._plugins_without_key_paths = []
default_plugin_list_index = None
key_paths = []
for list_index, plugin in enumerate(self._plugins):
if plugin.NAME == 'winreg_default':
default_plugin_list_index = list_index
continue
for registry_key_filter in plugin.FILTERS:
plugin_key_paths = getattr(registry_key_filter, 'key_paths', [])
if (not plugin_key_paths and
plugin not in self._plugins_without_key_paths):
self._plugins_without_key_paths.append(plugin)
continue
for plugin_key_path in plugin_key_paths:
plugin_key_path = plugin_key_path.lower()
if plugin_key_path in self._plugin_per_key_path:
logger.warning((
'Windows Registry key path: {0:s} defined by plugin: {1:s} '
'already set by plugin: {2:s}').format(
plugin_key_path, plugin.NAME,
self._plugin_per_key_path[plugin_key_path].NAME))
continue
self._plugin_per_key_path[plugin_key_path] = plugin
key_paths.append(plugin_key_path)
if default_plugin_list_index is not None:
self._default_plugin = self._plugins.pop(default_plugin_list_index)
self._path_filter = path_filter.PathFilterScanTree(
key_paths, case_sensitive=False, path_segment_separator='\\')
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
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): Windwos Registry key.
plugin (WindowsRegistryPlugin): Windows Registry plugin.
"""
try:
plugin.UpdateChainAndProcess(parser_mediator, registry_key)
except (IOError, dfwinreg_errors.WinRegistryValueError) as exception:
parser_mediator.ProduceExtractionError(
'in key: {0:s} error: {1!s}'.format(registry_key.path, exception))
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): Windwos Registry key.
"""
matching_plugin = None
normalized_key_path = self._NormalizeKeyPath(registry_key.path)
if self._path_filter.CheckPath(normalized_key_path):
matching_plugin = self._plugin_per_key_path[normalized_key_path]
else:
for plugin in self._plugins_without_key_paths:
if self._CanProcessKeyWithPlugin(registry_key, plugin):
matching_plugin = plugin
break
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, root_key):
"""Parses the Registry keys recursively.
Args:
parser_mediator (ParserMediator): parser mediator.
root_key (dfwinreg.WinRegistryKey): root Windows Registry key.
"""
for registry_key in root_key.RecurseKeys():
if parser_mediator.abort:
break
self._ParseKey(parser_mediator, registry_key)
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 iter(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.
"""
win_registry_reader = FileObjectWinRegistryFileReader()
try:
registry_file = win_registry_reader.Open(file_object)
except IOError as exception:
parser_mediator.ProduceExtractionError(
'unable to open Windows Registry file with error: {0!s}'.format(
exception))
return
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 not root_key:
return
find_specs = parser_mediator.knowledge_base.GetValue(
artifact_filters.ArtifactDefinitionsFilterHelper.KNOWLEDGE_BASE_VALUE)
registry_find_specs = None
if find_specs:
registry_find_specs = find_specs.get(
artifact_types.TYPE_INDICATOR_WINDOWS_REGISTRY_KEY)
key_path_compatible = (
artifact_filters.ArtifactDefinitionsFilterHelper.CheckKeyCompatibility(
key_path_prefix))
if registry_find_specs and key_path_compatible:
try:
win_registry.MapFile(key_path_prefix, registry_file)
self._ParseKeysFromFindSpecs(
parser_mediator, win_registry, registry_find_specs)
except IOError as exception:
parser_mediator.ProduceExtractionError('{0!s}'.format(exception))
else:
if registry_find_specs and not key_path_compatible:
logger.warning((
'Artifacts Registry Filters are not supported for '
'the registry prefix {0:s}. Parsing entire file.').format(
key_path_prefix))
try:
self._ParseRecurseKeys(parser_mediator, root_key)
except IOError as exception:
parser_mediator.ProduceExtractionError('{0!s}'.format(exception))
manager.ParsersManager.RegisterParser(WinRegistryParser)