Import from old repository

This commit is contained in:
Stefan
2020-04-06 18:48:34 +02:00
commit 0da6783a45
762 changed files with 103065 additions and 0 deletions
+17
View File
@@ -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.
+142
View File
@@ -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)
+49
View File
@@ -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()
+227
View File
@@ -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.
"""
+81
View File
@@ -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
+220
View File
@@ -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)
+44
View File
@@ -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.
+384
View File
@@ -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()
+61
View File
@@ -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()
+149
View File
@@ -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
+51
View File
@@ -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()