Import from old repository
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2012 The Plaso Project Authors.
|
||||
# Please see the AUTHORS file for details on individual authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
@@ -0,0 +1,142 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2013 The Plaso Project Authors.
|
||||
# Please see the AUTHORS file for details on individual authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""Interface and plugins for caching of Windows Registry objects."""
|
||||
|
||||
import abc
|
||||
|
||||
from plaso.lib import errors
|
||||
from plaso.lib import registry
|
||||
|
||||
|
||||
class WinRegistryCache(object):
|
||||
"""Class that implements the Windows Registry objects cache.
|
||||
|
||||
There are some values that are valid for the duration of an entire run
|
||||
against an image, such as code_page, etc.
|
||||
|
||||
However there are other values that should only be valid for each
|
||||
Windows Registry file, such as a current_control_set. The Windows Registry
|
||||
objects cache is designed to store those short lived cache values, so they
|
||||
can be calculated once for each Windows Registry file, yet do not live
|
||||
across all files parsed within an image.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the cache object."""
|
||||
super(WinRegistryCache, self).__init__()
|
||||
self.attributes = {}
|
||||
|
||||
def BuildCache(self, hive, reg_type):
|
||||
"""Builds up the cache.
|
||||
|
||||
Args:
|
||||
hive: The WinRegistry object.
|
||||
reg_type: The Registry type, eg. "SYSTEM", "NTUSER".
|
||||
"""
|
||||
for _, cl in WinRegCachePlugin.classes.items():
|
||||
try:
|
||||
plugin = cl(reg_type)
|
||||
value = plugin.Process(hive)
|
||||
if value:
|
||||
self.attributes[plugin.ATTRIBUTE] = value
|
||||
except errors.WrongPlugin:
|
||||
pass
|
||||
|
||||
|
||||
class WinRegCachePlugin(object):
|
||||
"""Class that implement the Window Registry cache plugin interface."""
|
||||
|
||||
__metaclass__ = registry.MetaclassRegistry
|
||||
__abstract = True
|
||||
|
||||
# Define the needed attributes.
|
||||
ATTRIBUTE = ''
|
||||
|
||||
REG_TYPE = ''
|
||||
REG_KEY = ''
|
||||
|
||||
def __init__(self, reg_type):
|
||||
"""Initialize the plugin.
|
||||
|
||||
Args:
|
||||
reg_type: The detected Windows Registry type. This value should match
|
||||
the REG_TYPE value defined by the plugins.
|
||||
"""
|
||||
super(WinRegCachePlugin, self).__init__()
|
||||
if self.REG_TYPE.lower() != reg_type.lower():
|
||||
raise errors.WrongPlugin(u'Not the correct Windows Registry type.')
|
||||
|
||||
def Process(self, hive):
|
||||
"""Extract the correct key and get the value.
|
||||
|
||||
Args:
|
||||
hive: The Windows Registry hive object (instance of WinRegistry).
|
||||
"""
|
||||
if not self.REG_KEY:
|
||||
return
|
||||
|
||||
key = hive.GetKeyByPath(self.REG_KEY)
|
||||
|
||||
if not key:
|
||||
return
|
||||
|
||||
return self.GetValue(key)
|
||||
|
||||
@abc.abstractmethod
|
||||
def GetValue(self, key):
|
||||
"""Extract the attribute from the provided key."""
|
||||
|
||||
|
||||
class CurrentControl(WinRegCachePlugin):
|
||||
"""Fetch information about the current control set."""
|
||||
|
||||
ATTRIBUTE = 'current_control_set'
|
||||
|
||||
REG_TYPE = 'SYSTEM'
|
||||
REG_KEY = '\\Select'
|
||||
|
||||
def GetValue(self, key):
|
||||
"""Extract current control set information."""
|
||||
value = key.GetValue('Current')
|
||||
|
||||
if not value and not value.DataIsInteger():
|
||||
return None
|
||||
|
||||
key_number = value.data
|
||||
|
||||
# If the value is Zero then we need to check
|
||||
# other keys.
|
||||
# The default behavior is:
|
||||
# 1. Use the "Current" value.
|
||||
# 2. Use the "Default" value.
|
||||
# 3. Use the "LastKnownGood" value.
|
||||
if key_number == 0:
|
||||
default_value = key.GetValue('Default')
|
||||
lastgood_value = key.GetValue('LastKnownGood')
|
||||
|
||||
if default_value and default_value.DataIsInteger():
|
||||
key_number = default_value.data
|
||||
|
||||
if not key_number:
|
||||
if lastgood_value and lastgood_value.DataIsInteger():
|
||||
key_number = lastgood_value.data
|
||||
|
||||
if key_number <= 0 or key_number > 999:
|
||||
return None
|
||||
|
||||
return u'ControlSet{0:03d}'.format(key_number)
|
||||
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2013 The Plaso Project Authors.
|
||||
# Please see the AUTHORS file for details on individual authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""Tests for the Windows Registry objects cache."""
|
||||
|
||||
import unittest
|
||||
|
||||
from plaso.winreg import cache
|
||||
from plaso.winreg import test_lib
|
||||
from plaso.winreg import winregistry
|
||||
|
||||
|
||||
class CacheTest(test_lib.WinRegTestCase):
|
||||
"""Tests for the Windows Registry objects cache."""
|
||||
|
||||
def testBuildCache(self):
|
||||
"""Tests creating a Windows Registry objects cache."""
|
||||
registry = winregistry.WinRegistry(
|
||||
winregistry.WinRegistry.BACKEND_PYREGF)
|
||||
|
||||
test_file = self._GetTestFilePath(['SYSTEM'])
|
||||
file_entry = self._GetTestFileEntry(test_file)
|
||||
winreg_file = registry.OpenFile(file_entry, codepage='cp1252')
|
||||
|
||||
winreg_cache = cache.WinRegistryCache()
|
||||
|
||||
# Test if this function does not raise an exception.
|
||||
winreg_cache.BuildCache(winreg_file, 'SYSTEM')
|
||||
|
||||
self.assertEqual(
|
||||
winreg_cache.attributes['current_control_set'], 'ControlSet001')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,227 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2012 The Plaso Project Authors.
|
||||
# Please see the AUTHORS file for details on individual authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""The interface for Windows Registry related objects."""
|
||||
|
||||
import abc
|
||||
|
||||
|
||||
class WinRegKey(object):
|
||||
"""Abstract class to represent the Windows Registry key interface."""
|
||||
|
||||
PATH_SEPARATOR = u'\\'
|
||||
|
||||
@abc.abstractproperty
|
||||
def path(self):
|
||||
"""The path of the key."""
|
||||
|
||||
@abc.abstractproperty
|
||||
def name(self):
|
||||
"""The name of the key."""
|
||||
|
||||
@abc.abstractproperty
|
||||
def offset(self):
|
||||
"""The offset of the key within the Windows Registry file."""
|
||||
|
||||
@abc.abstractproperty
|
||||
def last_written_timestamp(self):
|
||||
"""The last written time of the key represented as a timestamp."""
|
||||
|
||||
@abc.abstractproperty
|
||||
def number_of_values(self):
|
||||
"""The number of values within the key."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def GetValue(self, name):
|
||||
"""Retrieves a value by name.
|
||||
|
||||
Args:
|
||||
name: Name of the value or an empty string for the default value.
|
||||
|
||||
Returns:
|
||||
An instance of a Windows Registry value object (WinRegValue) if
|
||||
a corresponding value was found or None if not.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def GetValues(self):
|
||||
"""Retrieves all values within the key.
|
||||
|
||||
Yields:
|
||||
Windows Registry value objects (instances of WinRegValue) that represent
|
||||
the values stored within the key.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def number_of_subkeys(self):
|
||||
"""The number of subkeys within the key."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def GetSubkey(self, name):
|
||||
"""Retrive a subkey by name.
|
||||
|
||||
Args:
|
||||
name: The relative path of the current key to the desired one.
|
||||
|
||||
Returns:
|
||||
The subkey with the relative path of name or None if not found.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def GetSubkeys(self):
|
||||
"""Retrieves all subkeys within the key.
|
||||
|
||||
Yields:
|
||||
Windows Registry key objects (instances of WinRegKey) that represent
|
||||
the subkeys stored within the key.
|
||||
"""
|
||||
|
||||
|
||||
class WinRegValue(object):
|
||||
"""Abstract class to represent the Windows Registry value interface."""
|
||||
|
||||
REG_NONE = 0
|
||||
REG_SZ = 1
|
||||
REG_EXPAND_SZ = 2
|
||||
REG_BINARY = 3
|
||||
REG_DWORD = 4
|
||||
REG_DWORD_LITTLE_ENDIAN = 4
|
||||
REG_DWORD_BIG_ENDIAN = 5
|
||||
REG_LINK = 6
|
||||
REG_MULTI_SZ = 7
|
||||
REG_RESOURCE_LIST = 8
|
||||
REG_FULL_RESOURCE_DESCRIPTOR = 9
|
||||
REG_RESOURCE_REQUIREMENT_LIST = 10
|
||||
REG_QWORD = 11
|
||||
|
||||
_DATA_TYPE_STRINGS = {
|
||||
0: u'REG_NONE',
|
||||
1: u'REG_SZ',
|
||||
2: u'REG_EXPAND_SZ',
|
||||
3: u'REG_BINARY',
|
||||
4: u'REG_DWORD_LE',
|
||||
5: u'REG_DWORD_BE',
|
||||
6: u'REG_LINK',
|
||||
7: u'REG_MULTI_SZ',
|
||||
8: u'REG_RESOURCE_LIST',
|
||||
9: u'REG_FULL_RESOURCE_DESCRIPTOR',
|
||||
10: u'REG_RESOURCE_REQUIREMENT_LIST',
|
||||
11: u'REG_QWORD'
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
"""Default constructor for the Windows Registry value."""
|
||||
self._data = u''
|
||||
|
||||
@abc.abstractproperty
|
||||
def name(self):
|
||||
"""The name of the value."""
|
||||
|
||||
@abc.abstractproperty
|
||||
def offset(self):
|
||||
"""The offset of the value within the Windows Registry file."""
|
||||
|
||||
@abc.abstractproperty
|
||||
def data_type(self):
|
||||
"""Numeric value that contains the data type."""
|
||||
|
||||
@property
|
||||
def data_type_string(self):
|
||||
"""String representation of the data type."""
|
||||
return self._DATA_TYPE_STRINGS.get(self.data_type, u'UNKNOWN')
|
||||
|
||||
@abc.abstractproperty
|
||||
def raw_data(self):
|
||||
"""The value data as a byte string."""
|
||||
|
||||
@abc.abstractproperty
|
||||
def data(self):
|
||||
"""The value data as a native Python object."""
|
||||
|
||||
def DataIsInteger(self):
|
||||
"""Determines, based on the data type, if the data is an integer.
|
||||
|
||||
The data types considered strings are: REG_DWORD (REG_DWORD_LITTLE_ENDIAN),
|
||||
REG_DWORD_BIG_ENDIAN and REG_QWORD.
|
||||
|
||||
Returns:
|
||||
True if the data is an integer, false otherwise.
|
||||
"""
|
||||
return self.data_type in [
|
||||
self.REG_DWORD, self.REG_DWORD_BIG_ENDIAN, self.REG_QWORD]
|
||||
|
||||
def DataIsString(self):
|
||||
"""Determines, based on the data type, if the data is a string.
|
||||
|
||||
The data types considered strings are: REG_SZ and REG_EXPAND_SZ.
|
||||
|
||||
Returns:
|
||||
True if the data is a string, false otherwise.
|
||||
"""
|
||||
return self.data_type in [self.REG_SZ, self.REG_EXPAND_SZ]
|
||||
|
||||
def DataIsMultiString(self):
|
||||
"""Determines, based on the data type, if the data is a multi string.
|
||||
|
||||
The data types considered multi strings are: REG_MULTI_SZ.
|
||||
|
||||
Returns:
|
||||
True if the data is a multi string, false otherwise.
|
||||
"""
|
||||
return self.data_type == self.REG_MULTI_SZ
|
||||
|
||||
def DataIsBinaryData(self):
|
||||
"""Determines, based on the data type, if the data is binary data.
|
||||
|
||||
The data types considered binary data are: REG_BINARY.
|
||||
|
||||
Returns:
|
||||
True if the data is a multi string, false otherwise.
|
||||
"""
|
||||
return self.data_type == self.REG_BINARY
|
||||
|
||||
|
||||
class WinRegFile(object):
|
||||
"""Abstract class to represent the Windows Registry file interface."""
|
||||
|
||||
def __init__(self):
|
||||
"""Default constructor for the Windows Registry file."""
|
||||
self._mounted_key_path = u''
|
||||
|
||||
@abc.abstractmethod
|
||||
def Open(self, file_object, codepage='cp1252'):
|
||||
"""Opens the Windows Registry file.
|
||||
|
||||
Args:
|
||||
file_object: The file-like object of the Windows Registry file.
|
||||
codepage: Optional codepage for ASCII strings, default is cp1252.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def Close(self):
|
||||
"""Closes the Windows Registry file."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def GetKeyByPath(self, registry_path):
|
||||
"""Retrieves a specific key defined by the Registry path.
|
||||
|
||||
Args:
|
||||
path: the Registry path.
|
||||
|
||||
Returns:
|
||||
The key (instance of WinRegKey) if available or None otherwise.
|
||||
"""
|
||||
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2014 The Plaso Project Authors.
|
||||
# Please see the AUTHORS file for details on individual authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""The Windows Registry key path expander."""
|
||||
|
||||
|
||||
class WinRegistryKeyPathExpander(object):
|
||||
"""Class that implements the Windows Registry key path expander object."""
|
||||
|
||||
def __init__(self, reg_cache=None):
|
||||
"""Initialize the path expander object.
|
||||
|
||||
Args:
|
||||
reg_cache: Optional Registry objects cache (insance of WinRegistryCache).
|
||||
"""
|
||||
super(WinRegistryKeyPathExpander, self).__init__()
|
||||
self._reg_cache = reg_cache
|
||||
|
||||
def ExpandPath(self, key_path, pre_obj=None):
|
||||
"""Expand a Registry key path based on attributes in pre calculated values.
|
||||
|
||||
A Registry key path may contain paths that are attributes, based on
|
||||
calculations from either preprocessing or based on each individual
|
||||
Windows Registry file.
|
||||
|
||||
An attribute is defined as anything within a curly bracket, eg.
|
||||
"\\System\\{my_attribute}\\Path\\Keyname". If the attribute my_attribute
|
||||
is defined in either the preprocessing object or the Registry objects
|
||||
cache it's value will be replaced with the attribute name, e.g.
|
||||
"\\System\\MyValue\\Path\\Keyname".
|
||||
|
||||
If the Registry path needs to have curly brackets in the path then
|
||||
they need to be escaped with another curly bracket, eg
|
||||
"\\System\\{my_attribute}\\{{123-AF25-E523}}\\KeyName". In this
|
||||
case the {{123-AF25-E523}} will be replaced with "{123-AF25-E523}".
|
||||
|
||||
Args:
|
||||
key_path: The Registry key path before being expanded.
|
||||
pre_obj: Optional preprocess object that contains stored values from
|
||||
the image.
|
||||
|
||||
Returns:
|
||||
A Registry key path that's expanded based on attribute values.
|
||||
|
||||
Raises:
|
||||
KeyError: If an attribute name is in the key path yet not set in
|
||||
either the Registry objects cache nor in the preprocessing
|
||||
object a KeyError will be raised.
|
||||
"""
|
||||
expanded_key_path = u''
|
||||
key_dict = {}
|
||||
if self._reg_cache:
|
||||
key_dict.update(self._reg_cache.attributes.items())
|
||||
|
||||
if pre_obj:
|
||||
key_dict.update(pre_obj.__dict__.items())
|
||||
|
||||
try:
|
||||
expanded_key_path = key_path.format(**key_dict)
|
||||
except KeyError as exception:
|
||||
raise KeyError(u'Unable to expand path with error: {0:s}'.format(
|
||||
exception))
|
||||
|
||||
if not expanded_key_path:
|
||||
raise KeyError(u'Unable to expand path, no value returned.')
|
||||
|
||||
return expanded_key_path
|
||||
@@ -0,0 +1,220 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2012 The Plaso Project Authors.
|
||||
# Please see the AUTHORS file for details on individual authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""Windows Registry related functions and classes for testing."""
|
||||
|
||||
import construct
|
||||
import os
|
||||
import unittest
|
||||
|
||||
from dfvfs.lib import definitions
|
||||
from dfvfs.path import factory as path_spec_factory
|
||||
from dfvfs.resolver import resolver as path_spec_resolver
|
||||
|
||||
from plaso.winreg import interface
|
||||
|
||||
|
||||
class TestRegKey(interface.WinRegKey):
|
||||
"""Implementation of the Registry key interface for testing."""
|
||||
|
||||
def __init__(self, path, last_written_timestamp, values, offset=0,
|
||||
subkeys=None):
|
||||
"""An abstract object for a Windows Registry key.
|
||||
|
||||
This implementation is more a manual one, so it can be used for
|
||||
testing the Registry plugins without requiring a full blown
|
||||
Windows Registry file to extract key values.
|
||||
|
||||
Args:
|
||||
path: The full key name and path.
|
||||
last_written_timestamp: An integer containing the the last written
|
||||
timestamp of the Registry key.
|
||||
values: A list of TestRegValue values this key holds.
|
||||
offset: A byte offset into the Windows Registry file where the entry lies.
|
||||
subkeys: A list of subkeys this key has.
|
||||
"""
|
||||
super(TestRegKey, self).__init__()
|
||||
self._name = None
|
||||
self._path = path
|
||||
self._last_written_timestamp = last_written_timestamp
|
||||
self._values = values
|
||||
self._offset = offset
|
||||
if subkeys is None:
|
||||
self._subkeys = []
|
||||
else:
|
||||
self._subkeys = subkeys
|
||||
|
||||
@property
|
||||
def path(self):
|
||||
"""The path of the key."""
|
||||
return self._path
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""The name of the key."""
|
||||
if not self._name and self._path:
|
||||
self._name = self._path.split(self.PATH_SEPARATOR)[-1]
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def offset(self):
|
||||
"""The offset of the key within the Windows Registry file."""
|
||||
return self._offset
|
||||
|
||||
@property
|
||||
def last_written_timestamp(self):
|
||||
"""The last written time of the key represented as a timestamp."""
|
||||
return self._last_written_timestamp
|
||||
|
||||
def number_of_values(self):
|
||||
"""The number of values within the key."""
|
||||
return len(self._values)
|
||||
|
||||
def GetValue(self, name):
|
||||
"""Return a WinRegValue object for a specific Registry key path."""
|
||||
for value in self._values:
|
||||
if value.name == name:
|
||||
return value
|
||||
|
||||
def GetValues(self):
|
||||
"""Return a list of all values from the Registry key."""
|
||||
return self._values
|
||||
|
||||
def number_of_subkeys(self):
|
||||
"""The number of subkeys within the key."""
|
||||
return len(self._subkeys)
|
||||
|
||||
def GetSubkey(self, name):
|
||||
"""Retrieve a subkey by name.
|
||||
|
||||
Args:
|
||||
name: The relative path of the current key to the desired one.
|
||||
|
||||
Returns:
|
||||
The subkey with the relative path of name or None if not found.
|
||||
"""
|
||||
for subkey in self._subkeys:
|
||||
if subkey.name == name:
|
||||
return subkey
|
||||
return
|
||||
|
||||
def GetSubkeys(self):
|
||||
"""Return a list of all subkeys."""
|
||||
return self._subkeys
|
||||
|
||||
|
||||
class TestRegValue(interface.WinRegValue):
|
||||
"""Implementation of the Registry value interface for testing."""
|
||||
|
||||
_INT32_BIG_ENDIAN = construct.SBInt32('value')
|
||||
_INT32_LITTLE_ENDIAN = construct.SLInt32('value')
|
||||
_INT64_LITTLE_ENDIAN = construct.SLInt64('value')
|
||||
|
||||
def __init__(self, name, data, data_type, offset=0):
|
||||
"""Set up the test reg value object."""
|
||||
super(TestRegValue, self).__init__()
|
||||
self._name = name
|
||||
self._data = data
|
||||
self._data_type = data_type
|
||||
self._offset = offset
|
||||
self._type_str = ''
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""The name of the value."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def offset(self):
|
||||
"""The offset of the value within the Windows Registry file."""
|
||||
return self._offset
|
||||
|
||||
@property
|
||||
def data_type(self):
|
||||
"""Numeric value that contains the data type."""
|
||||
return self._data_type
|
||||
|
||||
@property
|
||||
def raw_data(self):
|
||||
"""The value data as a byte string."""
|
||||
return self._data
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
"""The value data as a native Python object."""
|
||||
if not self._data:
|
||||
return None
|
||||
|
||||
if self._data_type in [self.REG_SZ, self.REG_EXPAND_SZ, self.REG_LINK]:
|
||||
try:
|
||||
return unicode(self._data.decode('utf-16-le'))
|
||||
except UnicodeError:
|
||||
pass
|
||||
|
||||
elif self._data_type == self.REG_DWORD and len(self._data) == 4:
|
||||
return self._INT32_LITTLE_ENDIAN.parse(self._data)
|
||||
|
||||
elif self._data_type == self.REG_DWORD_BIG_ENDIAN and len(self._data) == 4:
|
||||
return self._INT32_BIG_ENDIAN.parse(self._data)
|
||||
|
||||
elif self._data_type == self.REG_QWORD and len(self._data) == 8:
|
||||
return self._INT64_LITTLE_ENDIAN.parse(self._data)
|
||||
|
||||
elif self._data_type == self.REG_MULTI_SZ:
|
||||
try:
|
||||
utf16_string = unicode(self._data.decode('utf-16-le'))
|
||||
return filter(None, utf16_string.split('\x00'))
|
||||
except UnicodeError:
|
||||
pass
|
||||
|
||||
return self._data
|
||||
|
||||
|
||||
class WinRegTestCase(unittest.TestCase):
|
||||
"""The unit test case for winreg."""
|
||||
|
||||
_TEST_DATA_PATH = os.path.join(os.getcwd(), 'test_data')
|
||||
|
||||
# Show full diff results, part of TestCase so does not follow our naming
|
||||
# conventions.
|
||||
maxDiff = None
|
||||
|
||||
def _GetTestFilePath(self, path_segments):
|
||||
"""Retrieves the path of a test file relative to the test data directory.
|
||||
|
||||
Args:
|
||||
path_segments: the path segments inside the test data directory.
|
||||
|
||||
Returns:
|
||||
A path of the test file.
|
||||
"""
|
||||
# Note that we need to pass the individual path segments to os.path.join
|
||||
# and not a list.
|
||||
return os.path.join(self._TEST_DATA_PATH, *path_segments)
|
||||
|
||||
def _GetTestFileEntry(self, path):
|
||||
"""Retrieves the test file entry.
|
||||
|
||||
Args:
|
||||
path: the path of the test file.
|
||||
|
||||
Returns:
|
||||
The test file entry (instance of dfvfs.FileEntry).
|
||||
"""
|
||||
path_spec = path_spec_factory.Factory.NewPathSpec(
|
||||
definitions.TYPE_INDICATOR_OS, location=path)
|
||||
return path_spec_resolver.Resolver.OpenFileEntry(path_spec)
|
||||
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2013 The Plaso Project Authors.
|
||||
# Please see the AUTHORS file for details on individual authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""This file contains Windows Registry utility functions."""
|
||||
|
||||
from plaso.winreg import interface
|
||||
|
||||
|
||||
def WinRegBasename(path):
|
||||
"""Determines the basename for a Windows Registry path.
|
||||
|
||||
Trailing key separators are igored.
|
||||
|
||||
Args:
|
||||
path: a Windows registy path with \\ as the key separator.
|
||||
|
||||
Returns:
|
||||
The basename (or last path segment).
|
||||
"""
|
||||
# Strip trailing key separators.
|
||||
while path and path[-1] == interface.WinRegKey.PATH_SEPARATOR:
|
||||
path = path[:-1]
|
||||
if path:
|
||||
_, _, path = path.rpartition(interface.WinRegKey.PATH_SEPARATOR)
|
||||
return path
|
||||
|
||||
# TOOD: create a function to return the values as a dict.
|
||||
# this function should replace the repeated code blocks in multiple plugins.
|
||||
|
||||
# TODO: create a function to extract string data from a registry value.
|
||||
@@ -0,0 +1,384 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2012 The Plaso Project Authors.
|
||||
# Please see the AUTHORS file for details on individual authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""Pyregf specific implementation for the Windows Registry file access."""
|
||||
|
||||
import logging
|
||||
|
||||
from plaso.lib import errors
|
||||
from plaso.lib import timelib
|
||||
from plaso.winreg import interface
|
||||
|
||||
import pyregf
|
||||
|
||||
|
||||
if pyregf.get_version() < '20130716':
|
||||
raise ImportWarning('WinPyregf requires at least pyregf 20130716.')
|
||||
|
||||
|
||||
class WinPyregfKey(interface.WinRegKey):
|
||||
"""Implementation of a Windows Registry key using pyregf."""
|
||||
|
||||
def __init__(self, pyregf_key, parent_path=u'', root=False):
|
||||
"""Initializes a Windows Registry key object.
|
||||
|
||||
Args:
|
||||
pyregf_key: An instance of a pyregf.key object.
|
||||
parent_path: The path of the parent key.
|
||||
root: A boolean key indicating we are dealing with a root key.
|
||||
"""
|
||||
super(WinPyregfKey, self).__init__()
|
||||
self._pyregf_key = pyregf_key
|
||||
# Adding few checks to make sure the root key is not
|
||||
# invalid in plugin checks (root key is equal to the
|
||||
# path separator).
|
||||
if parent_path == self.PATH_SEPARATOR:
|
||||
parent_path = u''
|
||||
if root:
|
||||
self._path = self.PATH_SEPARATOR
|
||||
else:
|
||||
self._path = self.PATH_SEPARATOR.join(
|
||||
[parent_path, self._pyregf_key.name])
|
||||
|
||||
# pylint: disable=method-hidden
|
||||
@property
|
||||
def path(self):
|
||||
"""The path of the key."""
|
||||
return self._path
|
||||
|
||||
# pylint: disable=function-redefined,arguments-differ,method-hidden
|
||||
@path.setter
|
||||
def path(self, value):
|
||||
"""Set the value of the path explicitly."""
|
||||
self._path = value
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""The name of the key."""
|
||||
return self._pyregf_key.name
|
||||
|
||||
@property
|
||||
def offset(self):
|
||||
"""The offset of the key within the Windows Registry file."""
|
||||
return self._pyregf_key.offset
|
||||
|
||||
@property
|
||||
def last_written_timestamp(self):
|
||||
"""The last written time of the key represented as a timestamp."""
|
||||
return timelib.Timestamp.FromFiletime(
|
||||
self._pyregf_key.get_last_written_time_as_integer())
|
||||
|
||||
@property
|
||||
def number_of_values(self):
|
||||
"""The number of values within the key."""
|
||||
return self._pyregf_key.number_of_values
|
||||
|
||||
def GetValue(self, name):
|
||||
"""Retrieves a value by name.
|
||||
|
||||
Args:
|
||||
name: Name of the value or an empty string for the default value.
|
||||
|
||||
Returns:
|
||||
A Windows Registry value object (instance of WinRegValue) if
|
||||
a corresponding value was found or None if not.
|
||||
"""
|
||||
# Value names are not unique and pyregf provides first match for
|
||||
# the value. If this becomes problematic this method needs to
|
||||
# be changed into a generator, iterating through all returned value
|
||||
# for a given name.
|
||||
pyregf_value = self._pyregf_key.get_value_by_name(name)
|
||||
if pyregf_value:
|
||||
return WinPyregfValue(pyregf_value)
|
||||
return None
|
||||
|
||||
@property
|
||||
def number_of_subkeys(self):
|
||||
"""The number of subkeys within the key."""
|
||||
return self._pyregf_key.number_of_sub_keys
|
||||
|
||||
def GetValues(self):
|
||||
"""Retrieves all values within the key.
|
||||
|
||||
Yields:
|
||||
Windows Registry value objects (instances of WinRegValue) that represent
|
||||
the values stored within the key.
|
||||
"""
|
||||
for pyregf_value in self._pyregf_key.values:
|
||||
yield WinPyregfValue(pyregf_value)
|
||||
|
||||
def GetSubkey(self, name):
|
||||
"""Retrive a subkey by name.
|
||||
|
||||
Args:
|
||||
name: The relative path of the current key to the desired one.
|
||||
|
||||
Returns:
|
||||
The subkey with the relative path of name or None if not found.
|
||||
"""
|
||||
subkey = self._pyregf_key.get_sub_key_by_name(name)
|
||||
|
||||
if subkey:
|
||||
return WinPyregfKey(subkey, self.path)
|
||||
|
||||
path_subkey = self._pyregf_key.get_sub_key_by_path(name)
|
||||
if path_subkey:
|
||||
path, _, _ = name.rpartition('\\')
|
||||
path = u'\\'.join([self.path, path])
|
||||
return WinPyregfKey(path_subkey, path)
|
||||
|
||||
def GetSubkeys(self):
|
||||
"""Retrieves all subkeys within the key.
|
||||
|
||||
Yields:
|
||||
Windows Registry key objects (instances of WinRegKey) that represent
|
||||
the subkeys stored within the key.
|
||||
"""
|
||||
for pyregf_key in self._pyregf_key.sub_keys:
|
||||
yield WinPyregfKey(pyregf_key, self.path)
|
||||
|
||||
|
||||
class WinPyregfValue(interface.WinRegValue):
|
||||
"""Implementation of a Windows Registry value using pyregf."""
|
||||
|
||||
def __init__(self, pyregf_value):
|
||||
"""Initializes a Windows Registry value object.
|
||||
|
||||
Args:
|
||||
pyregf_value: An instance of a pyregf.value object.
|
||||
"""
|
||||
super(WinPyregfValue, self).__init__()
|
||||
self._pyregf_value = pyregf_value
|
||||
self._type_str = ''
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""The name of the value."""
|
||||
return self._pyregf_value.name
|
||||
|
||||
@property
|
||||
def offset(self):
|
||||
"""The offset of the value within the Windows Registry file."""
|
||||
return self._pyregf_value.offset
|
||||
|
||||
@property
|
||||
def data_type(self):
|
||||
"""Numeric value that contains the data type."""
|
||||
return self._pyregf_value.type
|
||||
|
||||
@property
|
||||
def raw_data(self):
|
||||
"""The value data as a byte string."""
|
||||
try:
|
||||
return self._pyregf_value.data
|
||||
except IOError:
|
||||
raise errors.WinRegistryValueError(
|
||||
'Unable to read data from value: {0:s}'.format(
|
||||
self._pyregf_value.name))
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
"""The value data as a native Python object."""
|
||||
if self._pyregf_value.type in [
|
||||
self.REG_SZ, self.REG_EXPAND_SZ, self.REG_LINK]:
|
||||
try:
|
||||
return self._pyregf_value.data_as_string
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
elif self._pyregf_value.type in [
|
||||
self.REG_DWORD, self.REG_DWORD_BIG_ENDIAN, self.REG_QWORD]:
|
||||
try:
|
||||
return self._pyregf_value.data_as_integer
|
||||
except (IOError, OverflowError):
|
||||
# TODO: Rethink this approach. The value is not -1, but we cannot
|
||||
# return the raw data, since the calling plugin expects an integer
|
||||
# here.
|
||||
return -1
|
||||
|
||||
# TODO: Add support for REG_MULTI_SZ to pyregf.
|
||||
elif self._pyregf_value.type == self.REG_MULTI_SZ:
|
||||
if self._pyregf_value.data is None:
|
||||
return u''
|
||||
|
||||
try:
|
||||
utf16_string = unicode(self._pyregf_value.data.decode('utf-16-le'))
|
||||
return filter(None, utf16_string.split('\x00'))
|
||||
except UnicodeError:
|
||||
pass
|
||||
|
||||
return self._pyregf_value.data
|
||||
|
||||
|
||||
class WinPyregfFile(interface.WinRegFile):
|
||||
"""Implementation of a Windows Registry file pyregf."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initializes a Windows Registry key object."""
|
||||
super(WinPyregfFile, self).__init__()
|
||||
self._pyregf_file = pyregf.file()
|
||||
self.name = ''
|
||||
self._base_key = None
|
||||
|
||||
def Open(self, file_entry, codepage='cp1252'):
|
||||
"""Opens the Windows Registry file.
|
||||
|
||||
Args:
|
||||
file_entry: The file entry object.
|
||||
name: The name of the file.
|
||||
codepage: Optional codepage for ASCII strings, default is cp1252.
|
||||
"""
|
||||
# TODO: Add a more elegant error handling to this issue. There are some
|
||||
# code pages that are not supported by the parent library. However we
|
||||
# need to properly set the codepage so the library can properly interpret
|
||||
# values in the Registry.
|
||||
try:
|
||||
self._pyregf_file.set_ascii_codepage(codepage)
|
||||
|
||||
except (TypeError, IOError):
|
||||
logging.error((
|
||||
u'Unable to set the Windows Registry file codepage: {0:s}. '
|
||||
u'Ignoring provided value.').format(codepage))
|
||||
|
||||
self._file_object = file_entry.GetFileObject()
|
||||
self._pyregf_file.open_file_object(self._file_object)
|
||||
|
||||
self._base_key = self._pyregf_file.get_root_key()
|
||||
|
||||
# TODO: move to a pyvfs like Registry sub-system.
|
||||
self.name = file_entry.name
|
||||
|
||||
def Close(self):
|
||||
"""Closes the Windows Registry file."""
|
||||
self._pyregf_file.close()
|
||||
self._file_object.close()
|
||||
|
||||
def GetKeyByPath(self, path):
|
||||
"""Retrieves a specific key defined by the Registry path.
|
||||
|
||||
Args:
|
||||
path: the Registry path.
|
||||
|
||||
Returns:
|
||||
The key (instance of WinRegKey) if available or None otherwise.
|
||||
"""
|
||||
if not path:
|
||||
return None
|
||||
|
||||
if not self._base_key:
|
||||
return None
|
||||
|
||||
pyregf_key = self._base_key.get_sub_key_by_path(path)
|
||||
|
||||
if not pyregf_key:
|
||||
return None
|
||||
|
||||
if pyregf_key.name == self._base_key.name:
|
||||
root = True
|
||||
else:
|
||||
root = False
|
||||
|
||||
parent_path, _, _ = path.rpartition(interface.WinRegKey.PATH_SEPARATOR)
|
||||
return WinPyregfKey(pyregf_key, parent_path, root)
|
||||
|
||||
|
||||
class WinRegistry(object):
|
||||
"""Provides access to the Windows Registry file."""
|
||||
# TODO: deprecate this class.
|
||||
|
||||
def __init__(self, file_entry, codepage='cp1252'):
|
||||
"""Constructor for the Registry object.
|
||||
|
||||
Args:
|
||||
file_entry: A file entry object.
|
||||
codepage: The codepage of the Registry hive, used for string
|
||||
representation.
|
||||
"""
|
||||
self._pyregf_file = pyregf.file()
|
||||
|
||||
try:
|
||||
# TODO: Add a more elegant error handling to this issue. There are some
|
||||
# code pages that are not supported by the parent library. However we
|
||||
# need to properly set the codepage so the library can properly interpret
|
||||
# values in the Registry.
|
||||
self._pyregf_file.set_ascii_codepage(codepage)
|
||||
except (TypeError, IOError):
|
||||
logging.error(
|
||||
u'Unable to set the Registry codepage to: {}. Not setting it'.format(
|
||||
codepage))
|
||||
|
||||
file_object = file_entry.GetFileObject()
|
||||
self._pyregf_file.open_file_object(file_object)
|
||||
|
||||
def GetRoot(self):
|
||||
"""Return the root key of the Registry hive."""
|
||||
key = WinPyregfKey(self._pyregf_file.get_root_key())
|
||||
# Change root key name to avoid key based plugins failing.
|
||||
key.path = ''
|
||||
return key
|
||||
|
||||
def GetKey(self, key):
|
||||
"""Return a Registry key as a WinPyregfKey object."""
|
||||
if not key:
|
||||
return None
|
||||
|
||||
my_key = self._pyregf_file.get_key_by_path(key)
|
||||
if not my_key:
|
||||
return None
|
||||
|
||||
path, _, _ = key.rpartition('\\')
|
||||
|
||||
return WinPyregfKey(my_key, path)
|
||||
|
||||
def __contains__(self, key):
|
||||
"""Check if a certain Registry key exists within the hive."""
|
||||
try:
|
||||
return bool(self.GetKey(key))
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
def GetAllSubkeys(self, key):
|
||||
"""Generator that returns all sub keys of any given Registry key.
|
||||
|
||||
Args:
|
||||
key: A Windows Registry key string or object (instance of WinPyregfKey).
|
||||
|
||||
Yields:
|
||||
Windows Registry key objects (instances of WinPyregfKey) that represent
|
||||
the subkeys stored within the key.
|
||||
"""
|
||||
# TODO: refactor this function.
|
||||
# TODO: remove the hasattr check.
|
||||
if not hasattr(key, 'GetSubkeys'):
|
||||
key = self.GetKey(key)
|
||||
|
||||
for subkey in key.GetSubkeys():
|
||||
yield subkey
|
||||
if subkey.number_of_subkeys != 0:
|
||||
for s in self.GetAllSubkeys(subkey):
|
||||
yield s
|
||||
|
||||
def __iter__(self):
|
||||
"""Default iterator, returns all subkeys of the Windows Registry file."""
|
||||
root = self.GetRoot()
|
||||
for key in self.GetAllSubkeys(root):
|
||||
yield key
|
||||
|
||||
|
||||
def GetLibraryVersion():
|
||||
"""Return the pyregf and libregf version."""
|
||||
return pyregf.get_version()
|
||||
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2012 The Plaso Project Authors.
|
||||
# Please see the AUTHORS file for details on individual authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""Tests for the pyregf Windows Registry back-end."""
|
||||
|
||||
import unittest
|
||||
|
||||
from plaso.winreg import test_lib
|
||||
from plaso.winreg import winpyregf
|
||||
|
||||
|
||||
class RegistryUnitTest(test_lib.WinRegTestCase):
|
||||
"""Tests for the pyregf Windows Registry back-end."""
|
||||
|
||||
def _KeyPathCompare(self, winreg_file, key_path):
|
||||
"""Retrieves a key from the file and checks if the path key matches.
|
||||
|
||||
Args:
|
||||
winreg_file: the Windows Registry file (instance of WinPyregfFile).
|
||||
key_path: the key path to retrieve and compare.
|
||||
"""
|
||||
key = winreg_file.GetKeyByPath(key_path)
|
||||
self.assertEquals(key.path, key_path)
|
||||
|
||||
def testListKeys(self):
|
||||
test_file = self._GetTestFilePath(['NTUSER.DAT'])
|
||||
file_entry = self._GetTestFileEntry(test_file)
|
||||
winreg_file = winpyregf.WinRegistry(file_entry)
|
||||
keys = list(winreg_file)
|
||||
|
||||
# Count the number of Registry keys in the hive.
|
||||
self.assertEquals(len(keys), 1126)
|
||||
|
||||
def testWinPyregf(self):
|
||||
test_file = self._GetTestFilePath(['NTUSER.DAT'])
|
||||
file_entry = self._GetTestFileEntry(test_file)
|
||||
winreg_file = winpyregf.WinPyregfFile()
|
||||
winreg_file.Open(file_entry)
|
||||
|
||||
self._KeyPathCompare(winreg_file, u'\\')
|
||||
self._KeyPathCompare(winreg_file, u'\\Printers')
|
||||
self._KeyPathCompare(winreg_file, u'\\Printers\\Connections')
|
||||
self._KeyPathCompare(winreg_file, u'\\Software')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2013 The Plaso Project Authors.
|
||||
# Please see the AUTHORS file for details on individual authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""This file contains the Windows Registry class."""
|
||||
|
||||
from plaso.winreg import interface
|
||||
from plaso.winreg import winpyregf
|
||||
|
||||
|
||||
class WinRegistry(object):
|
||||
"""Class to provided a uniform way to access the Windows Registry."""
|
||||
|
||||
BACKEND_PYREGF = 1
|
||||
|
||||
_KNOWN_KEYS = {
|
||||
'NTUSER.DAT': '\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer',
|
||||
'SAM': '\\SAM\\Domains\\Account\\Users',
|
||||
'SECURITY': '\\Policy\\PolAdtEv',
|
||||
'SOFTWARE': '\\Microsoft\\Windows\\CurrentVersion\\App Paths',
|
||||
'SYSTEM': '\\Select',
|
||||
}
|
||||
|
||||
# TODO: this list is not finished yet and will need some more research.
|
||||
# For now an empty string represent the root and None an unknown or
|
||||
# not mounted.
|
||||
_FILENAME_MOUNTED_PATHS = {
|
||||
'DEFAULT': None,
|
||||
'NTUSER.DAT': 'HKEY_CURRENT_USER',
|
||||
'NTUSER.MAN': None,
|
||||
'REG.DAT': '',
|
||||
'SAM': 'HKEY_LOCAL_MACHINE\\SAM',
|
||||
'SECURITY': 'HKEY_LOCAL_MACHINE\\Security',
|
||||
'SOFTWARE': 'HKEY_LOCAL_MACHINE\\Software',
|
||||
'SYSTEM': 'HKEY_LOCAL_MACHINE\\System',
|
||||
'SYSCACHE.HVE': None,
|
||||
'SYSTEM.DAT': 'HKEY_LOCAL_MACHINE',
|
||||
'USERDIFF': None,
|
||||
'USERS.DAT': 'HKEY_USERS',
|
||||
'USRCLASS.DAT': 'HKEY_CURRENT_USER\\Software\\Classes',
|
||||
}
|
||||
|
||||
def __init__(self, backend=1):
|
||||
"""Initializes the Windows Registry.
|
||||
|
||||
Args:
|
||||
backend: The back-end to use to read the Registry structures, the
|
||||
default is 1 (pyregf).
|
||||
"""
|
||||
self._backend = backend
|
||||
self._files = {}
|
||||
|
||||
@classmethod
|
||||
def GetMountedPath(cls, filename):
|
||||
"""Determines the mounted path based on the filename.
|
||||
|
||||
Args:
|
||||
filename: The name of the Windows Registry file.
|
||||
|
||||
Returns:
|
||||
The mounted path if successful or None otherwise.
|
||||
"""
|
||||
return cls._FILENAME_MOUNTED_PATHS.get(filename.upper(), None)
|
||||
|
||||
def OpenFile(self, file_entry, codepage='cp1252'):
|
||||
"""Opens the file object based on the back-end.
|
||||
|
||||
Args:
|
||||
file_entry: The file entry object.
|
||||
codepage: Optional extended ASCII string codepage. The default is cp1252.
|
||||
|
||||
Returns:
|
||||
The a Windows Registry file (instance of WinRegFile) if successful
|
||||
or None otherwise.
|
||||
"""
|
||||
winreg_file = None
|
||||
|
||||
if self._backend == self.BACKEND_PYREGF:
|
||||
winreg_file = winpyregf.WinPyregfFile()
|
||||
|
||||
if winreg_file:
|
||||
winreg_file.Open(file_entry, codepage=codepage)
|
||||
|
||||
return winreg_file
|
||||
|
||||
def MountFile(self, winreg_file, mounted_path):
|
||||
"""Mounts a file in the Registry.
|
||||
|
||||
Args:
|
||||
winreg_file: The Windows Registry file (instance of WinRegFile).
|
||||
mounted_path: The path of the key where the Windows Registry file
|
||||
is mounted.
|
||||
|
||||
Raises:
|
||||
KeyError: if mounted path is already set.
|
||||
ValueError: if mounted path is not set.
|
||||
"""
|
||||
if not mounted_path:
|
||||
raise ValueError(u'Missing mounted path value')
|
||||
|
||||
if mounted_path in self._files:
|
||||
raise KeyError(u'Mounted path: {0:s} already set.'.format(mounted_path))
|
||||
|
||||
self._files[mounted_path] = winreg_file
|
||||
|
||||
def GetKeyByPath(self, path):
|
||||
"""Retrieves a specific key defined by the Registry path.
|
||||
|
||||
Returns:
|
||||
The key (instance of WinRegKey) if available or None otherwise.
|
||||
"""
|
||||
mounted_path = None
|
||||
if self._files:
|
||||
for mounted_path in self._files.keys():
|
||||
if path.startswith(mounted_path):
|
||||
break
|
||||
|
||||
if not mounted_path:
|
||||
return None
|
||||
|
||||
winreg_file = self._files[mounted_path]
|
||||
|
||||
mounted_path_length = len(mounted_path)
|
||||
|
||||
if mounted_path.endswith(interface.WinRegKey.PATH_SEPARATOR):
|
||||
mounted_path_length -= 1
|
||||
|
||||
path = path[mounted_path_length:]
|
||||
|
||||
if not winreg_file:
|
||||
return None
|
||||
|
||||
winreg_key = winreg_file.GetKeyByPath(path)
|
||||
|
||||
# TODO: correct the path of the key for the mounted location.
|
||||
|
||||
return winreg_key
|
||||
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2012 The Plaso Project Authors.
|
||||
# Please see the AUTHORS file for details on individual authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""This file contains the tests for the Windows Registry library."""
|
||||
|
||||
import unittest
|
||||
|
||||
from plaso.winreg import test_lib
|
||||
from plaso.winreg import winregistry
|
||||
|
||||
|
||||
class RegistryUnitTest(test_lib.WinRegTestCase):
|
||||
"""Tests for the Windows Registry library."""
|
||||
|
||||
def testMountFile(self):
|
||||
"""Tests mounting REGF files in the Registry."""
|
||||
registry = winregistry.WinRegistry(
|
||||
winregistry.WinRegistry.BACKEND_PYREGF)
|
||||
|
||||
test_file = self._GetTestFilePath(['SOFTWARE'])
|
||||
file_entry = self._GetTestFileEntry(test_file)
|
||||
winreg_file = registry.OpenFile(file_entry, codepage='cp1252')
|
||||
|
||||
registry.MountFile(winreg_file, u'HKEY_LOCAL_MACHINE\\Software')
|
||||
|
||||
test_file = self._GetTestFilePath(['NTUSER-WIN7.DAT'])
|
||||
file_entry = self._GetTestFileEntry(test_file)
|
||||
winreg_file = registry.OpenFile(file_entry, codepage='cp1252')
|
||||
|
||||
with self.assertRaises(KeyError):
|
||||
registry.MountFile(winreg_file, u'HKEY_LOCAL_MACHINE\\Software')
|
||||
|
||||
registry.MountFile(winreg_file, u'HKEY_CURRENT_USER')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user