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
+42
View File
@@ -0,0 +1,42 @@
#!/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 import statements for the Registry plugins."""
from plaso.parsers.winreg_plugins import appcompatcache
from plaso.parsers.winreg_plugins import bagmru
from plaso.parsers.winreg_plugins import ccleaner
from plaso.parsers.winreg_plugins import default
from plaso.parsers.winreg_plugins import lfu
from plaso.parsers.winreg_plugins import mountpoints
from plaso.parsers.winreg_plugins import mrulist
from plaso.parsers.winreg_plugins import mrulistex
from plaso.parsers.winreg_plugins import msie_zones
from plaso.parsers.winreg_plugins import officemru
from plaso.parsers.winreg_plugins import outlook
from plaso.parsers.winreg_plugins import run
from plaso.parsers.winreg_plugins import sam_users
from plaso.parsers.winreg_plugins import services
from plaso.parsers.winreg_plugins import shutdown
from plaso.parsers.winreg_plugins import task_scheduler
from plaso.parsers.winreg_plugins import terminal_server
from plaso.parsers.winreg_plugins import typedurls
from plaso.parsers.winreg_plugins import userassist
from plaso.parsers.winreg_plugins import usb
from plaso.parsers.winreg_plugins import usbstor
from plaso.parsers.winreg_plugins import winrar
from plaso.parsers.winreg_plugins import winver
@@ -0,0 +1,624 @@
#!/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.
"""Windows Registry plugin to parse the Application Compatibility Cache key."""
import construct
import logging
from plaso.events import time_events
from plaso.lib import binary
from plaso.lib import eventdata
from plaso.parsers import winreg
from plaso.parsers.winreg_plugins import interface
class AppCompatCacheEvent(time_events.FiletimeEvent):
"""Class that contains the event object for AppCompatCache entries."""
DATA_TYPE = 'windows:registry:appcompatcache'
def __init__(
self, filetime, usage, key, entry_index, path, offset):
"""Initializes a Windows Registry event.
Args:
filetime: The FILETIME timestamp value.
usage: The description of the usage of the time value.
key: Name of the Registry key being parsed.
entry_index: The cache entry index number for the record.
path: The full path to the executable.
offset: The (data) offset of the Registry key or value.
"""
super(AppCompatCacheEvent, self).__init__(filetime, usage)
self.keyname = key
self.offset = offset
self.entry_index = entry_index
self.path = path
class AppCompatCacheHeader(object):
"""Class that contains the Application Compatibility Cache header."""
def __init__(self):
"""Initializes the header object."""
super(AppCompatCacheHeader, self).__init__()
self.number_of_cached_entries = 0
self.header_size = 0
class AppCompatCacheCachedEntry(object):
"""Class that contains the Application Compatibility Cache cached entry."""
def __init__(self):
"""Initializes the cached entry object."""
super(AppCompatCacheCachedEntry, self).__init__()
self.cached_entry_size = 0
self.data = None
self.file_size = None
self.insertion_flags = None
self.last_modification_time = None
self.last_update_time = None
self.shim_flags = None
self.path = None
class AppCompatCachePlugin(interface.KeyPlugin):
"""Class that parses the Application Compatibility Cache Registry data."""
NAME = 'winreg_appcompatcache'
DESCRIPTION = u'Parser for Application Compatibility Cache Registry data.'
REG_KEYS = [
u'\\{current_control_set}\\Control\\Session Manager\\AppCompatibility',
u'\\{current_control_set}\\Control\\Session Manager\\AppCompatCache']
REG_TYPE = 'SYSTEM'
URL = [
(u'https://code.google.com/p/winreg-kb/wiki/'
u'ApplicationCompatibilityCacheKey')]
_FORMAT_TYPE_2000 = 1
_FORMAT_TYPE_XP = 2
_FORMAT_TYPE_2003 = 3
_FORMAT_TYPE_VISTA = 4
_FORMAT_TYPE_7 = 5
_FORMAT_TYPE_8 = 6
# AppCompatCache format signature used in Windows XP.
_HEADER_SIGNATURE_XP = 0xdeadbeef
# AppCompatCache format used in Windows XP.
_HEADER_XP_32BIT_STRUCT = construct.Struct(
'appcompatcache_header_xp',
construct.ULInt32('signature'),
construct.ULInt32('number_of_cached_entries'),
construct.ULInt32('unknown1'),
construct.ULInt32('unknown2'),
construct.Padding(384))
_CACHED_ENTRY_XP_32BIT_STRUCT = construct.Struct(
'appcompatcache_cached_entry_xp_32bit',
construct.Array(528, construct.Byte('path')),
construct.ULInt64('last_modification_time'),
construct.ULInt64('file_size'),
construct.ULInt64('last_update_time'))
# AppCompatCache format signature used in Windows 2003, Vista and 2008.
_HEADER_SIGNATURE_2003 = 0xbadc0ffe
# AppCompatCache format used in Windows 2003.
_HEADER_2003_STRUCT = construct.Struct(
'appcompatcache_header_2003',
construct.ULInt32('signature'),
construct.ULInt32('number_of_cached_entries'))
_CACHED_ENTRY_2003_32BIT_STRUCT = construct.Struct(
'appcompatcache_cached_entry_2003_32bit',
construct.ULInt16('path_size'),
construct.ULInt16('maximum_path_size'),
construct.ULInt32('path_offset'),
construct.ULInt64('last_modification_time'),
construct.ULInt64('file_size'))
_CACHED_ENTRY_2003_64BIT_STRUCT = construct.Struct(
'appcompatcache_cached_entry_2003_64bit',
construct.ULInt16('path_size'),
construct.ULInt16('maximum_path_size'),
construct.ULInt32('unknown1'),
construct.ULInt64('path_offset'),
construct.ULInt64('last_modification_time'),
construct.ULInt64('file_size'))
# AppCompatCache format used in Windows Vista and 2008.
_CACHED_ENTRY_VISTA_32BIT_STRUCT = construct.Struct(
'appcompatcache_cached_entry_vista_32bit',
construct.ULInt16('path_size'),
construct.ULInt16('maximum_path_size'),
construct.ULInt32('path_offset'),
construct.ULInt64('last_modification_time'),
construct.ULInt32('insertion_flags'),
construct.ULInt32('shim_flags'))
_CACHED_ENTRY_VISTA_64BIT_STRUCT = construct.Struct(
'appcompatcache_cached_entry_vista_64bit',
construct.ULInt16('path_size'),
construct.ULInt16('maximum_path_size'),
construct.ULInt32('unknown1'),
construct.ULInt64('path_offset'),
construct.ULInt64('last_modification_time'),
construct.ULInt32('insertion_flags'),
construct.ULInt32('shim_flags'))
# AppCompatCache format signature used in Windows 7 and 2008 R2.
_HEADER_SIGNATURE_7 = 0xbadc0fee
# AppCompatCache format used in Windows 7 and 2008 R2.
_HEADER_7_STRUCT = construct.Struct(
'appcompatcache_header_7',
construct.ULInt32('signature'),
construct.ULInt32('number_of_cached_entries'),
construct.Padding(120))
_CACHED_ENTRY_7_32BIT_STRUCT = construct.Struct(
'appcompatcache_cached_entry_7_32bit',
construct.ULInt16('path_size'),
construct.ULInt16('maximum_path_size'),
construct.ULInt32('path_offset'),
construct.ULInt64('last_modification_time'),
construct.ULInt32('insertion_flags'),
construct.ULInt32('shim_flags'),
construct.ULInt32('data_size'),
construct.ULInt32('data_offset'))
_CACHED_ENTRY_7_64BIT_STRUCT = construct.Struct(
'appcompatcache_cached_entry_7_64bit',
construct.ULInt16('path_size'),
construct.ULInt16('maximum_path_size'),
construct.ULInt32('unknown1'),
construct.ULInt64('path_offset'),
construct.ULInt64('last_modification_time'),
construct.ULInt32('insertion_flags'),
construct.ULInt32('shim_flags'),
construct.ULInt64('data_size'),
construct.ULInt64('data_offset'))
# AppCompatCache format used in Windows 8.0 and 8.1.
_HEADER_SIGNATURE_8 = 0x00000080
_HEADER_8_STRUCT = construct.Struct(
'appcompatcache_header_8',
construct.ULInt32('signature'),
construct.Padding(124))
_CACHED_ENTRY_HEADER_8_STRUCT = construct.Struct(
'appcompatcache_cached_entry_header_8',
construct.ULInt32('signature'),
construct.ULInt32('unknown1'),
construct.ULInt32('cached_entry_data_size'),
construct.ULInt16('path_size'))
# AppCompatCache format used in Windows 8.0.
_CACHED_ENTRY_SIGNATURE_8_0 = '00ts'
# AppCompatCache format used in Windows 8.1.
_CACHED_ENTRY_SIGNATURE_8_1 = '10ts'
def _CheckSignature(self, value_data):
"""Parses and validates the signature.
Args:
value_data: a binary string containing the value data.
Returns:
The format type if successful or None otherwise.
"""
signature = construct.ULInt32('signature').parse(value_data)
if signature == self._HEADER_SIGNATURE_XP:
return self._FORMAT_TYPE_XP
elif signature == self._HEADER_SIGNATURE_2003:
# TODO: determine which format version is used (2003 or Vista).
return self._FORMAT_TYPE_2003
elif signature == self._HEADER_SIGNATURE_7:
return self._FORMAT_TYPE_7
elif signature == self._HEADER_SIGNATURE_8:
if value_data[signature:signature + 4] in [
self._CACHED_ENTRY_SIGNATURE_8_0, self._CACHED_ENTRY_SIGNATURE_8_1]:
return self._FORMAT_TYPE_8
def _DetermineCacheEntrySize(
self, format_type, value_data, cached_entry_offset):
"""Determines the size of a cached entry.
Args:
format_type: integer value that contains the format type.
value_data: a binary string containing the value data.
cached_entry_offset: integer value that contains the offset of
the first cached entry data relative to the start of
the value data.
Returns:
The cached entry size if successful or None otherwise.
Raises:
RuntimeError: if the format type is not supported.
"""
if format_type not in [
self._FORMAT_TYPE_XP, self._FORMAT_TYPE_2003, self._FORMAT_TYPE_VISTA,
self._FORMAT_TYPE_7, self._FORMAT_TYPE_8]:
raise RuntimeError(
u'[{0:s}] Unsupported format type: {1:d}'.format(
self.NAME, format_type))
cached_entry_data = value_data[cached_entry_offset:]
cached_entry_size = 0
if format_type == self._FORMAT_TYPE_XP:
cached_entry_size = self._CACHED_ENTRY_XP_32BIT_STRUCT.sizeof()
elif format_type in [
self._FORMAT_TYPE_2003, self._FORMAT_TYPE_VISTA, self._FORMAT_TYPE_7]:
path_size = construct.ULInt16('path_size').parse(cached_entry_data[0:2])
maximum_path_size = construct.ULInt16('maximum_path_size').parse(
cached_entry_data[2:4])
path_offset_32bit = construct.ULInt32('path_offset').parse(
cached_entry_data[4:8])
path_offset_64bit = construct.ULInt32('path_offset').parse(
cached_entry_data[8:16])
if maximum_path_size < path_size:
logging.error(
u'[{0:s}] Path size value out of bounds.'.format(self.NAME))
return
path_end_of_string_size = maximum_path_size - path_size
if path_size == 0 or path_end_of_string_size != 2:
logging.error(
u'[{0:s}] Unsupported path size values.'.format(self.NAME))
return
# Assume the entry is 64-bit if the 32-bit path offset is 0 and
# the 64-bit path offset is set.
if path_offset_32bit == 0 and path_offset_64bit != 0:
if format_type == self._FORMAT_TYPE_2003:
cached_entry_size = self._CACHED_ENTRY_2003_64BIT_STRUCT.sizeof()
elif format_type == self._FORMAT_TYPE_VISTA:
cached_entry_size = self._CACHED_ENTRY_VISTA_64BIT_STRUCT.sizeof()
elif format_type == self._FORMAT_TYPE_7:
cached_entry_size = self._CACHED_ENTRY_7_64BIT_STRUCT.sizeof()
else:
if format_type == self._FORMAT_TYPE_2003:
cached_entry_size = self._CACHED_ENTRY_2003_32BIT_STRUCT.sizeof()
elif format_type == self._FORMAT_TYPE_VISTA:
cached_entry_size = self._CACHED_ENTRY_VISTA_32BIT_STRUCT.sizeof()
elif format_type == self._FORMAT_TYPE_7:
cached_entry_size = self._CACHED_ENTRY_7_32BIT_STRUCT.sizeof()
elif format_type == self._FORMAT_TYPE_8:
cached_entry_size = self._CACHED_ENTRY_HEADER_8_STRUCT.sizeof()
return cached_entry_size
def _ParseHeader(self, format_type, value_data):
"""Parses the header.
Args:
format_type: integer value that contains the format type.
value_data: a binary string containing the value data.
Returns:
A header object (instance of AppCompatCacheHeader).
Raises:
RuntimeError: if the format type is not supported.
"""
if format_type not in [
self._FORMAT_TYPE_XP, self._FORMAT_TYPE_2003, self._FORMAT_TYPE_VISTA,
self._FORMAT_TYPE_7, self._FORMAT_TYPE_8]:
raise RuntimeError(
u'[{0:s}] Unsupported format type: {1:d}'.format(
self.NAME, format_type))
# TODO: change to collections.namedtuple or use __slots__ if the overhead
# of a regular object becomes a problem.
header_object = AppCompatCacheHeader()
if format_type == self._FORMAT_TYPE_XP:
header_object.header_size = self._HEADER_XP_32BIT_STRUCT.sizeof()
header_struct = self._HEADER_XP_32BIT_STRUCT.parse(value_data)
elif format_type == self._FORMAT_TYPE_2003:
header_object.header_size = self._HEADER_2003_STRUCT.sizeof()
header_struct = self._HEADER_2003_STRUCT.parse(value_data)
elif format_type == self._FORMAT_TYPE_VISTA:
header_object.header_size = self._HEADER_VISTA_STRUCT.sizeof()
header_struct = self._HEADER_VISTA_STRUCT.parse(value_data)
elif format_type == self._FORMAT_TYPE_7:
header_object.header_size = self._HEADER_7_STRUCT.sizeof()
header_struct = self._HEADER_7_STRUCT.parse(value_data)
elif format_type == self._FORMAT_TYPE_8:
header_object.header_size = self._HEADER_8_STRUCT.sizeof()
header_struct = self._HEADER_8_STRUCT.parse(value_data)
if format_type in [
self._FORMAT_TYPE_XP, self._FORMAT_TYPE_2003, self._FORMAT_TYPE_VISTA,
self._FORMAT_TYPE_7]:
header_object.number_of_cached_entries = header_struct.get(
'number_of_cached_entries')
return header_object
def _ParseCachedEntry(
self, format_type, value_data, cached_entry_offset, cached_entry_size):
"""Parses a cached entry.
Args:
format_type: integer value that contains the format type.
value_data: a binary string containing the value data.
cached_entry_offset: integer value that contains the offset of
the cached entry data relative to the start of
the value data.
cached_entry_size: integer value that contains the cached entry data size.
Returns:
A cached entry object (instance of AppCompatCacheCachedEntry).
Raises:
RuntimeError: if the format type is not supported.
"""
if format_type not in [
self._FORMAT_TYPE_XP, self._FORMAT_TYPE_2003, self._FORMAT_TYPE_VISTA,
self._FORMAT_TYPE_7, self._FORMAT_TYPE_8]:
raise RuntimeError(
u'[{0:s}] Unsupported format type: {1:d}'.format(
self.NAME, format_type))
cached_entry_data = value_data[
cached_entry_offset:cached_entry_offset + cached_entry_size]
cached_entry_struct = None
if format_type == self._FORMAT_TYPE_XP:
if cached_entry_size == self._CACHED_ENTRY_XP_32BIT_STRUCT.sizeof():
cached_entry_struct = self._CACHED_ENTRY_XP_32BIT_STRUCT.parse(
cached_entry_data)
elif format_type == self._FORMAT_TYPE_2003:
if cached_entry_size == self._CACHED_ENTRY_2003_32BIT_STRUCT.sizeof():
cached_entry_struct = self._CACHED_ENTRY_2003_32BIT_STRUCT.parse(
cached_entry_data)
elif cached_entry_size == self._CACHED_ENTRY_2003_64BIT_STRUCT.sizeof():
cached_entry_struct = self._CACHED_ENTRY_2003_64BIT_STRUCT.parse(
cached_entry_data)
elif format_type == self._FORMAT_TYPE_VISTA:
if cached_entry_size == self._CACHED_ENTRY_VISTA_32BIT_STRUCT.sizeof():
cached_entry_struct = self._CACHED_ENTRY_VISTA_32BIT_STRUCT.parse(
cached_entry_data)
elif cached_entry_size == self._CACHED_ENTRY_VISTA_64BIT_STRUCT.sizeof():
cached_entry_struct = self._CACHED_ENTRY_VISTA_64BIT_STRUCT.parse(
cached_entry_data)
elif format_type == self._FORMAT_TYPE_7:
if cached_entry_size == self._CACHED_ENTRY_7_32BIT_STRUCT.sizeof():
cached_entry_struct = self._CACHED_ENTRY_7_32BIT_STRUCT.parse(
cached_entry_data)
elif cached_entry_size == self._CACHED_ENTRY_7_64BIT_STRUCT.sizeof():
cached_entry_struct = self._CACHED_ENTRY_7_64BIT_STRUCT.parse(
cached_entry_data)
elif format_type == self._FORMAT_TYPE_8:
if cached_entry_data[0:4] not in [
self._CACHED_ENTRY_SIGNATURE_8_0, self._CACHED_ENTRY_SIGNATURE_8_1]:
raise RuntimeError(
u'[{0:s}] Unsupported cache entry signature'.format(self.NAME))
if cached_entry_size == self._CACHED_ENTRY_HEADER_8_STRUCT.sizeof():
cached_entry_struct = self._CACHED_ENTRY_HEADER_8_STRUCT.parse(
cached_entry_data)
cached_entry_data_size = cached_entry_struct.get(
'cached_entry_data_size')
cached_entry_size = 12 + cached_entry_data_size
cached_entry_data = value_data[
cached_entry_offset:cached_entry_offset + cached_entry_size]
if not cached_entry_struct:
raise RuntimeError(
u'[{0:s}] Unsupported cache entry size: {1:d}'.format(
self.NAME, cached_entry_size))
cached_entry_object = AppCompatCacheCachedEntry()
cached_entry_object.cached_entry_size = cached_entry_size
path_offset = 0
data_size = 0
if format_type == self._FORMAT_TYPE_XP:
string_size = 0
for string_index in xrange(0, 528, 2):
if (ord(cached_entry_data[string_index]) == 0 and
ord(cached_entry_data[string_index + 1]) == 0):
break
string_size += 2
cached_entry_object.path = binary.Ut16StreamCopyToString(
cached_entry_data[0:string_size])
elif format_type in [
self._FORMAT_TYPE_2003, self._FORMAT_TYPE_VISTA, self._FORMAT_TYPE_7]:
path_size = cached_entry_struct.get('path_size')
path_offset = cached_entry_struct.get('path_offset')
elif format_type == self._FORMAT_TYPE_8:
path_size = cached_entry_struct.get('path_size')
cached_entry_data_offset = 14 + path_size
cached_entry_object.path = binary.Ut16StreamCopyToString(
cached_entry_data[14:cached_entry_data_offset])
remaining_data = cached_entry_data[cached_entry_data_offset:]
cached_entry_object.insertion_flags = construct.ULInt32(
'insertion_flags').parse(remaining_data[0:4])
cached_entry_object.shim_flags = construct.ULInt32(
'shim_flags').parse(remaining_data[4:8])
if cached_entry_data[0:4] == self._CACHED_ENTRY_SIGNATURE_8_0:
cached_entry_data_offset += 8
elif cached_entry_data[0:4] == self._CACHED_ENTRY_SIGNATURE_8_1:
cached_entry_data_offset += 10
remaining_data = cached_entry_data[cached_entry_data_offset:]
if format_type in [
self._FORMAT_TYPE_XP, self._FORMAT_TYPE_2003, self._FORMAT_TYPE_VISTA,
self._FORMAT_TYPE_7]:
cached_entry_object.last_modification_time = cached_entry_struct.get(
'last_modification_time')
elif format_type == self._FORMAT_TYPE_8:
cached_entry_object.last_modification_time = construct.ULInt64(
'last_modification_time').parse(remaining_data[0:8])
if format_type in [self._FORMAT_TYPE_XP, self._FORMAT_TYPE_2003]:
cached_entry_object.file_size = cached_entry_struct.get('file_size')
elif format_type in [self._FORMAT_TYPE_VISTA, self._FORMAT_TYPE_7]:
cached_entry_object.insertion_flags = cached_entry_struct.get(
'insertion_flags')
cached_entry_object.shim_flags = cached_entry_struct.get('shim_flags')
if format_type == self._FORMAT_TYPE_XP:
cached_entry_object.last_update_time = cached_entry_struct.get(
'last_update_time')
if format_type == self._FORMAT_TYPE_7:
data_offset = cached_entry_struct.get('data_offset')
data_size = cached_entry_struct.get('data_size')
elif format_type == self._FORMAT_TYPE_8:
data_offset = cached_entry_offset + cached_entry_data_offset + 12
data_size = construct.ULInt32('data_size').parse(remaining_data[8:12])
if path_offset > 0 and path_size > 0:
path_size += path_offset
cached_entry_object.path = binary.Ut16StreamCopyToString(
value_data[path_offset:path_size])
if data_size > 0:
data_size += data_offset
cached_entry_object.data = value_data[data_offset:data_size]
return cached_entry_object
def GetEntries(self, parser_context, key=None, file_entry=None,
parser_chain=None, **unused_kwargs):
"""Extracts event objects from a Application Compatibility Cache key.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
"""
value = key.GetValue('AppCompatCache')
if not value:
return
value_data = value.data
value_data_size = len(value.data)
format_type = self._CheckSignature(value_data)
if not format_type:
# TODO: Instead of logging emit a parser error object that once that
# mechanism is implemented.
logging.error(
u'AppCompatCache format error: [{0:s}] Unsupported signature'.format(
key.path))
return
header_object = self._ParseHeader(format_type, value_data)
# On Windows Vista and 2008 when the cache is empty it will
# only consist of the header.
if value_data_size <= header_object.header_size:
return
cached_entry_offset = header_object.header_size
cached_entry_size = self._DetermineCacheEntrySize(
format_type, value_data, cached_entry_offset)
if not cached_entry_size:
# TODO: Instead of logging emit a parser error object that once that
# mechanism is implemented.
logging.error(
u'AppCompatCache format error: [{0:s}] Unsupported cached entry '
u'size.'.format(key.path))
return
cached_entry_index = 0
while cached_entry_offset < value_data_size:
cached_entry_object = self._ParseCachedEntry(
format_type, value_data, cached_entry_offset, cached_entry_size)
if cached_entry_object.last_modification_time is not None:
# TODO: refactor to file modification event.
event_object = AppCompatCacheEvent(
cached_entry_object.last_modification_time,
u'File Last Modification Time', key.path,
cached_entry_index + 1, cached_entry_object.path,
cached_entry_offset)
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
if cached_entry_object.last_update_time is not None:
# TODO: refactor to process run event.
event_object = AppCompatCacheEvent(
cached_entry_object.last_update_time,
eventdata.EventTimestamp.LAST_RUNTIME, key.path,
cached_entry_index + 1, cached_entry_object.path,
cached_entry_offset)
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
cached_entry_offset += cached_entry_object.cached_entry_size
cached_entry_index += 1
if (header_object.number_of_cached_entries != 0 and
cached_entry_index >= header_object.number_of_cached_entries):
break
winreg.WinRegistryParser.RegisterPlugin(AppCompatCachePlugin)
@@ -0,0 +1,73 @@
#!/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.
"""Tests for the Application Compatibility Cache key Windows Registry plugin."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.lib import timelib_test
from plaso.parsers.winreg_plugins import appcompatcache
from plaso.parsers.winreg_plugins import test_lib
class AppCompatCacheRegistryPluginTest(test_lib.RegistryPluginTestCase):
"""Tests for the AppCompatCache Windows Registry plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = appcompatcache.AppCompatCachePlugin()
def testProcess(self):
"""Tests the Process function."""
knowledge_base_values = {'current_control_set': u'ControlSet001'}
test_file_entry = self._GetTestFileEntryFromPath(['SYSTEM'])
key_path = u'\\ControlSet001\\Control\\Session Manager\\AppCompatCache'
winreg_key = self._GetKeyFromFileEntry(test_file_entry, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(
self._plugin, winreg_key,
knowledge_base_values=knowledge_base_values, file_entry=test_file_entry)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 330)
event_object = event_objects[9]
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2012-04-04 01:46:37.932964')
self.assertEquals(event_object.timestamp, expected_timestamp)
self.assertEquals(event_object.pathspec, test_file_entry.path_spec)
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
self.assertEquals(event_object.keyname, key_path)
expected_msg = (
u'[{0:s}] Cached entry: 10 Path: '
u'\\??\\C:\\Windows\\PSEXESVC.EXE'.format(event_object.keyname))
expected_msg_short = (
u'Path: \\??\\C:\\Windows\\PSEXESVC.EXE')
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
if __name__ == '__main__':
unittest.main()
+206
View File
@@ -0,0 +1,206 @@
#!/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.
"""This file contains BagMRU Windows Registry plugins (shellbags)."""
import logging
import construct
from plaso.events import windows_events
from plaso.parsers.shared import shell_items
from plaso.parsers import winreg
from plaso.parsers.winreg_plugins import interface
class BagMRUPlugin(interface.KeyPlugin):
"""Class that defines a BagMRU Windows Registry plugin."""
NAME = 'winreg_bagmru'
DESCRIPTION = u'Parser for BagMRU Registry data.'
# TODO: remove REG_TYPE and use HKEY_CURRENT_USER instead.
REG_TYPE = 'any'
REG_KEYS = frozenset([
u'\\Software\\Microsoft\\Windows\\Shell\\BagMRU',
u'\\Software\\Microsoft\\Windows\\ShellNoRoam\\BagMRU',
(u'\\Local Settings\\Software\\Microsoft\\Windows\\'
u'Shell\\BagMRU'),
(u'\\Local Settings\\Software\\Microsoft\\Windows\\'
u'ShellNoRoam\\BagMRU'),
(u'\\Wow6432Node\\Local Settings\\Software\\'
u'Microsoft\\Windows\\Shell\\BagMRU'),
(u'\\Wow6432Node\\Local Settings\\Software\\'
u'Microsoft\\Windows\\ShellNoRoam\\BagMRU')])
URLS = [u'https://code.google.com/p/winreg-kb/wiki/MRUKeys']
_MRULISTEX_STRUCT = construct.Range(1, 500, construct.ULInt32('entry_number'))
def _ParseMRUListExEntryValue(
self, parser_context, key, entry_index, entry_number, text_dict,
value_strings, parent_value_string, codepage='cp1252', file_entry=None,
parser_chain=None, **unused_kwargs):
"""Parses the MRUListEx entry value.
Args:
parser_context: A parser context object (instance of ParserContext).
key: the Registry key (instance of winreg.WinRegKey) that contains
the MRUListEx value.
entry_index: integer value representing the MRUListEx entry index.
entry_number: integer value representing the entry number.
text_dict: text dictionary object to append textual strings.
value_strings: value string dictionary object to append value strings.
parent_value_string: string containing the parent value string.
codepage: Optional extended ASCII string codepage. The default is cp1252.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
value = key.GetValue(u'{0:d}'.format(entry_number))
value_string = u''
if value is None:
logging.debug(
u'[{0:s}] Missing MRUListEx entry value: {1:d} in key: {2:s}.'.format(
self.name, entry_number, key.path))
elif not value.DataIsBinaryData():
logging.debug((
u'[{0:s}] Non-binary MRUListEx entry value: {1:d} in key: '
u'{2:s}.').format(self.name, entry_number, key.path))
elif value.data:
shell_items_parser = shell_items.ShellItemsParser(key.path)
shell_items_parser.Parse(
parser_context, value.data, codepage=codepage, file_entry=file_entry,
parser_chain=parser_chain)
value_string = shell_items_parser.CopyToPath()
if parent_value_string:
value_string = u', '.join([parent_value_string, value_string])
value_strings[entry_number] = value_string
value_string = u'Shell item list: [{0:s}]'.format(value_string)
value_text = u'Index: {0:d} [MRU Value {1:d}]'.format(
entry_index + 1, entry_number)
text_dict[value_text] = value_string
def _ParseMRUListExValue(self, key):
"""Parsed the MRUListEx value in a given Registry key.
Args:
key: the Registry key (instance of winreg.WinRegKey) that contains
the MRUListEx value.
Returns:
A MRUListEx value generator, which returns the MRU index number
and entry value.
"""
mru_list_value = key.GetValue('MRUListEx')
if not mru_list_value:
return enumerate([])
try:
mru_list = self._MRULISTEX_STRUCT.parse(mru_list_value.data)
except construct.FieldError:
logging.warning(u'[{0:s}] Unable to parse the MRU key: {1:s}'.format(
self.name, key.path))
return enumerate([])
return enumerate(mru_list)
def _ParseSubKey(
self, parser_context, key, parent_value_string, registry_type=None,
file_entry=None, parser_chain=None, codepage='cp1252'):
"""Extract event objects from a MRUListEx Registry key.
Args:
parser_context: A parser context object (instance of ParserContext).
key: the Registry key (instance of winreg.WinRegKey).
parent_value_string: string containing the parent value string.
registry_type: Optional Registry type string. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
codepage: Optional extended ASCII string codepage. The default is cp1252.
"""
text_dict = {}
value_strings = {}
for index, entry_number in self._ParseMRUListExValue(key):
# TODO: detect if list ends prematurely.
# MRU lists are terminated with 0xffffffff (-1).
if entry_number == 0xffffffff:
break
self._ParseMRUListExEntryValue(
parser_context, key, index, entry_number, text_dict, value_strings,
parent_value_string, codepage=codepage, file_entry=file_entry,
parser_chain=parser_chain)
event_object = windows_events.WindowsRegistryEvent(
key.last_written_timestamp, key.path, text_dict,
offset=key.offset, registry_type=registry_type, urls=self.URLS,
source_append=': BagMRU')
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
for index, entry_number in self._ParseMRUListExValue(key):
# TODO: detect if list ends prematurely.
# MRU lists are terminated with 0xffffffff (-1).
if entry_number == 0xffffffff:
break
sub_key = key.GetSubkey(u'{0:d}'.format(entry_number))
if not sub_key:
logging.debug(
u'[{0:s}] Missing BagMRU sub key: {1:d} in key: {2:s}.'.format(
self.name, key.path, entry_number))
continue
value_string = value_strings.get(entry_number, u'')
self._ParseSubKey(
parser_context, sub_key, value_string, file_entry=file_entry,
parser_chain=parser_chain, codepage=codepage)
def GetEntries(
self, parser_context, key=None, registry_type=None, codepage='cp1252',
file_entry=None, parser_chain=None, **unused_kwargs):
"""Extract event objects from a Registry key containing a MRUListEx value.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
codepage: Optional extended ASCII string codepage. The default is cp1252.
"""
self._ParseSubKey(
parser_context, key, u'', registry_type=registry_type,
codepage=codepage, parser_chain=parser_chain, file_entry=file_entry)
winreg.WinRegistryParser.RegisterPlugin(BagMRUPlugin)
@@ -0,0 +1,99 @@
#!/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.
"""Tests for the BagMRU Windows Registry plugin."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.lib import timelib_test
from plaso.parsers.winreg_plugins import bagmru
from plaso.parsers.winreg_plugins import test_lib
class TestBagMRUPlugin(test_lib.RegistryPluginTestCase):
"""Tests for the BagMRU plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = bagmru.BagMRUPlugin()
def testProcess(self):
"""Tests the Process function."""
test_file_entry = self._GetTestFileEntryFromPath(['NTUSER.DAT'])
key_path = (
u'\\Software\\Microsoft\\Windows\\ShellNoRoam\\BagMRU')
winreg_key = self._GetKeyFromFileEntry(test_file_entry, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(
self._plugin, winreg_key, file_entry=test_file_entry)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 15)
event_object = event_objects[0]
self.assertEquals(event_object.pathspec, test_file_entry.path_spec)
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2009-08-04 15:19:16.997750')
self.assertEquals(event_object.timestamp, expected_timestamp)
expected_msg = (
u'[{0:s}] '
u'Index: 1 [MRU Value 0]: '
u'Shell item list: [My Computer]').format(key_path)
expected_msg_short = (
u'[{0:s}] Index: 1 [MRU Value 0]: Shel...').format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
event_object = event_objects[1]
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2009-08-04 15:19:10.669625')
self.assertEquals(event_object.timestamp, expected_timestamp)
expected_msg = (
u'[{0:s}\\0] '
u'Index: 1 [MRU Value 0]: '
u'Shell item list: [My Computer, C:\\]').format(key_path)
expected_msg_short = (
u'[{0:s}\\0] Index: 1 [MRU Value 0]: Sh...').format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
event_object = event_objects[14]
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2009-08-04 15:19:16.997750')
self.assertEquals(event_object.timestamp, expected_timestamp)
# The winreg_formatter will add a space after the key path even when there
# is not text.
expected_msg = u'[{0:s}\\0\\0\\0\\0\\0] '.format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg)
if __name__ == '__main__':
unittest.main()
+87
View File
@@ -0,0 +1,87 @@
#!/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.
"""Parser for the CCleaner Registry key."""
from plaso.events import windows_events
from plaso.lib import timelib
from plaso.parsers import winreg
from plaso.parsers.winreg_plugins import interface
__author__ = 'Marc Seguin (segumarc@gmail.com)'
class CCleanerPlugin(interface.KeyPlugin):
"""Gathers the CCleaner Keys for NTUSER hive."""
NAME = 'winreg_ccleaner'
DESCRIPTION = u'Parser for CCleaner Registry data.'
REG_KEYS = [u'\\Software\\Piriform\\CCleaner']
REG_TYPE = 'NTUSER'
URLS = [(u'http://cheeky4n6monkey.blogspot.com/2012/02/writing-ccleaner'
u'-regripper-plugin-part_05.html')]
def GetEntries(
self, parser_context, key=None, registry_type=None, file_entry=None,
parser_chain=None, **unused_kwargs):
"""Extracts event objects from a CCleaner Registry key.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
for value in key.GetValues():
if not value.name or not value.data:
continue
text_dict = {}
text_dict[value.name] = value.data
if value.name == u'UpdateKey':
timestamp = timelib.Timestamp.FromTimeString(
value.data, timezone=parser_context.timezone)
event_object = windows_events.WindowsRegistryEvent(
timestamp, key.path, text_dict, offset=key.offset,
registry_type=registry_type)
elif value.name == '0':
event_object = windows_events.WindowsRegistryEvent(
key.timestamp, key.path, text_dict, offset=key.offset,
registry_type=registry_type)
else:
# TODO: change this event not to set a timestamp of 0.
event_object = windows_events.WindowsRegistryEvent(
0, key.path, text_dict, offset=key.offset,
registry_type=registry_type)
event_object.source_append = u': CCleaner Registry key'
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
winreg.WinRegistryParser.RegisterPlugin(CCleanerPlugin)
@@ -0,0 +1,83 @@
#!/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 CCleaner Windows Registry plugin."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.lib import timelib_test
from plaso.parsers.winreg_plugins import ccleaner
from plaso.parsers.winreg_plugins import test_lib
__author__ = 'Marc Seguin (segumarc@gmail.com)'
class CCleanerRegistryPluginTest(test_lib.RegistryPluginTestCase):
"""Tests for the CCleaner Windows Registry plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = ccleaner.CCleanerPlugin()
def testProcess(self):
"""Tests the Process function."""
test_file_entry = self._GetTestFileEntryFromPath(['NTUSER-CCLEANER.DAT'])
key_path = u'\\Software\\Piriform\\CCleaner'
winreg_key = self._GetKeyFromFileEntry(test_file_entry, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(
self._plugin, winreg_key, file_entry=test_file_entry)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 17)
event_object = event_objects[0]
self.assertEquals(event_object.pathspec, test_file_entry.path_spec)
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2013-07-13 10:03:14')
self.assertEquals(event_object.timestamp, expected_timestamp)
regvalue_identifier = u'UpdateKey'
expected_value = u'07/13/2013 10:03:14 AM'
self._TestRegvalue(event_object, regvalue_identifier, expected_value)
expected_string = u'[{0:s}] {1:s}: {2:s}'.format(
key_path, regvalue_identifier, expected_value)
self._TestGetMessageStrings(event_object, expected_string, expected_string)
event_object = event_objects[2]
self.assertEquals(event_object.timestamp, 0)
regvalue_identifier = u'(App)Delete Index.dat files'
expected_value = u'True'
self._TestRegvalue(event_object, regvalue_identifier, expected_value)
expected_string = u'[{0:s}] {1:s}: {2:s}'.format(
key_path, regvalue_identifier, expected_value)
self._TestGetMessageStrings(event_object, expected_string, expected_string)
if __name__ == '__main__':
unittest.main()
+120
View File
@@ -0,0 +1,120 @@
#!/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 default Windows Registry plugin."""
from plaso.events import windows_events
from plaso.lib import utils
from plaso.parsers import winreg
from plaso.parsers.winreg_plugins import interface
class DefaultPlugin(interface.KeyPlugin):
"""Default plugin that extracts minimum information from every registry key.
The default plugin will parse every registry key that is passed to it and
extract minimum information, such as a list of available values and if
possible content of those values. The timestamp used is the timestamp
when the registry key was last modified.
"""
NAME = 'winreg_default'
DESCRIPTION = u'Parser for Registry data.'
REG_TYPE = 'any'
REG_KEYS = []
# This is a special case, plugins normally never overwrite the priority.
# However the default plugin should only run when all others plugins have
# tried and failed.
WEIGHT = 3
def GetEntries(
self, parser_context, key=None, registry_type=None, file_entry=None,
parser_chain=None, **unused_kwargs):
"""Returns an event object based on a Registry key name and values.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
"""
text_dict = {}
if key.number_of_values == 0:
text_dict[u'Value'] = u'No values stored in key.'
else:
for value in key.GetValues():
if not value.name:
value_name = '(default)'
else:
value_name = u'{0:s}'.format(value.name)
if value.data is None:
value_string = u'[{0:s}] Empty'.format(
value.data_type_string)
elif value.DataIsString():
string_decode = utils.GetUnicodeString(value.data)
value_string = u'[{0:s}] {1:s}'.format(
value.data_type_string, string_decode)
elif value.DataIsInteger():
value_string = u'[{0:s}] {1:d}'.format(
value.data_type_string, value.data)
elif value.DataIsMultiString():
if type(value.data) not in (list, tuple):
value_string = u'[{0:s}]'.format(value.data_type_string)
# TODO: Add a flag or some sort of an anomaly alert.
else:
value_string = u'[{0:s}] {1:s}'.format(
value.data_type_string, u''.join(value.data))
else:
value_string = u'[{0:s}]'.format(value.data_type_string)
text_dict[value_name] = value_string
event_object = windows_events.WindowsRegistryEvent(
key.last_written_timestamp, key.path, text_dict,
offset=key.offset, registry_type=registry_type)
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
# Even though the DefaultPlugin is derived from KeyPlugin it needs to
# overwrite the Process function to make sure it is called when no other
# plugin is available.
def Process(
self, parser_context, key=None, registry_type=None,
parser_chain=None, **kwargs):
"""Process the key and return a generator to extract event objects.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
"""
# Note that we should NOT call the Process function of the KeyPlugin here.
parser_chain = self._BuildParserChain(parser_chain)
self.GetEntries(
parser_context, key=key, registry_type=registry_type,
parser_chain=parser_chain, **kwargs)
winreg.WinRegistryParser.RegisterPlugin(DefaultPlugin)
@@ -0,0 +1,79 @@
#!/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 default Windows Registry plugin."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.parsers.winreg_plugins import default
from plaso.parsers.winreg_plugins import test_lib
from plaso.winreg import test_lib as winreg_test_lib
class TestDefaultRegistry(test_lib.RegistryPluginTestCase):
"""Tests for the default Windows Registry plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = default.DefaultPlugin()
def testProcess(self):
"""Tests the Process function."""
key_path = u'\\Microsoft\\Some Windows\\InterestingApp\\MRU'
values = []
values.append(winreg_test_lib.TestRegValue(
'MRUList', 'acb'.encode('utf_16_le'), 1, 123))
values.append(winreg_test_lib.TestRegValue(
'a', 'Some random text here'.encode('utf_16_le'), 1, 1892))
values.append(winreg_test_lib.TestRegValue(
'b', 'c:/evil.exe'.encode('utf_16_le'), 3, 612))
values.append(winreg_test_lib.TestRegValue(
'c', 'C:/looks_legit.exe'.encode('utf_16_le'), 1, 1001))
winreg_key = winreg_test_lib.TestRegKey(
key_path, 1346145829002031, values, 1456)
event_queue_consumer = self._ParseKeyWithPlugin(self._plugin, winreg_key)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 1)
event_object = event_objects[0]
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
self.assertEquals(event_object.timestamp, 1346145829002031)
expected_msg = (
u'[{0:s}] '
u'MRUList: [REG_SZ] acb '
u'a: [REG_SZ] Some random text here '
u'b: [REG_BINARY] '
u'c: [REG_SZ] C:/looks_legit.exe').format(key_path)
expected_msg_short = (
u'[{0:s}] MRUList: [REG_SZ] acb a: [REG_SZ...').format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
if __name__ == '__main__':
unittest.main()
+263
View File
@@ -0,0 +1,263 @@
#!/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 Windows Registry plugin objects interface."""
import abc
import logging
from plaso.parsers import plugins
from plaso.winreg import path_expander as winreg_path_expander
class RegistryPlugin(plugins.BasePlugin):
"""Class that defines the Windows Registry plugin object interface."""
__abstract = True
NAME = 'winreg'
DESCRIPTION = u'Parser for Registry data.'
# Indicate the type of hive this plugin belongs to (eg. NTUSER, SOFTWARE).
REG_TYPE = 'any'
# URLS should contain a list of URLs with additional information about this
# key or value.
URLS = []
# WEIGHT is a simple integer value representing the priority of this plugin.
# The weight can be used by some parser implementation to prioritize the
# order in which plugins are run against the Windows Registry keys.
# By default no the Windows Registry plugin should overwrite this value,
# it should only be defined in interfaces extending the base class, providing
# higher level of prioritization to Windows Registry plugins.
WEIGHT = 3
def __init__(self, reg_cache=None):
"""Initializes Windows Registry plugin object.
Args:
reg_cache: Optional Windows Registry objects cache (instance of
WinRegistryCache). The default is None.
"""
super(RegistryPlugin, self).__init__()
# TODO: Clean this up, this value is stored but not used.
self._reg_cache = reg_cache
@abc.abstractmethod
def GetEntries(
self, parser_context, file_entry=None, key=None, registry_type=None,
parser_chain=None, codepage='cp1252', **kwargs):
"""Extracts event objects from the Windows Registry key.
Args:
parser_context: A parser context object (instance of ParserContext).
file_entry: optional file entry object (instance of dfvfs.FileEntry).
The default is None.
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type. The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
codepage: Optional extended ASCII string codepage. The default is cp1252.
"""
def Process(self, parser_context, parser_chain=None, key=None, **kwargs):
"""Processes a Windows Registry key or value.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
Raises:
ValueError: If the key value is not set.
"""
if key is None:
raise ValueError(u'Key is not set.')
del kwargs['file_entry']
del kwargs['registry_type']
del kwargs['codepage']
# This will raise if unhandled keyword arguments are passed.
super(RegistryPlugin, self).Process(parser_context, parser_chain, **kwargs)
class KeyPlugin(RegistryPlugin):
"""Class that defines the Windows Registry key-based plugin interface."""
__abstract = True
# A list of all the Windows Registry key paths this plugins supports.
# Each of these key paths can contain a path that needs to be expanded,
# such as {current_control_set}, etc.
REG_KEYS = []
WEIGHT = 1
def __init__(self, reg_cache=None):
"""Initializes key-based Windows Registry plugin object.
Args:
reg_cache: Optional Windows Registry objects cache (instance of
WinRegistryCache). The default is None.
"""
super(KeyPlugin, self).__init__(reg_cache=reg_cache)
self._path_expander = winreg_path_expander.WinRegistryKeyPathExpander(
reg_cache=reg_cache)
self.expanded_keys = None
def ExpandKeys(self, parser_context):
"""Builds a list of expanded keys this plugin supports.
Args:
parser_context: A parser context object (instance of ParserContext).
"""
self.expanded_keys = []
for registry_key in self.REG_KEYS:
expanded_key = u''
try:
# TODO: deprecate direct use of pre_obj.
expanded_key = self._path_expander.ExpandPath(
registry_key, pre_obj=parser_context.knowledge_base.pre_obj)
except KeyError as exception:
logging.debug((
u'Unable to expand Registry key {0:s} for plugin {1:s} with '
u'error: {2:s}').format(registry_key, self.NAME, exception))
continue
if not expanded_key:
continue
self.expanded_keys.append(expanded_key)
# Special case of Wow6432 Windows Registry redirection.
# URL: http://msdn.microsoft.com/en-us/library/windows/desktop/\
# ms724072%28v=vs.85%29.aspx
if expanded_key.startswith('\\Software'):
_, first, second = expanded_key.partition('\\Software')
self.expanded_keys.append(u'{0:s}\\Wow6432Node{1:s}'.format(
first, second))
if self.REG_TYPE == 'SOFTWARE' or self.REG_TYPE == 'any':
self.expanded_keys.append(u'\\Wow6432Node{0:s}'.format(expanded_key))
@abc.abstractmethod
def GetEntries(
self, parser_context, file_entry=None, key=None, registry_type=None,
codepage='cp1252', parser_chain=None, **kwargs):
"""Extracts event objects from the Windows Registry key.
Args:
parser_context: A parser context object (instance of ParserContext).
file_entry: optional file entry object (instance of dfvfs.FileEntry).
The default is None.
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type. The default is None.
codepage: Optional extended ASCII string codepage. The default is cp1252.
"""
def Process(
self, parser_context, file_entry=None, key=None, registry_type=None,
codepage='cp1252', parser_chain=None, **kwargs):
"""Processes a Windows Registry key.
Args:
parser_context: A parser context object (instance of ParserContext).
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
codepage: Optional extended ASCII string codepage. The default is cp1252.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
if self.expanded_keys is None:
self.ExpandKeys(parser_context)
parser_chain = self._BuildParserChain(parser_chain)
super(KeyPlugin, self).Process(
parser_context, file_entry=file_entry, key=key,
registry_type=registry_type, codepage=codepage,
parser_chain=parser_chain, **kwargs)
if key and key.path in self.expanded_keys:
self.GetEntries(
parser_context, file_entry=file_entry, key=key,
registry_type=registry_type, codepage=codepage,
parser_chain=parser_chain, **kwargs)
class ValuePlugin(RegistryPlugin):
"""Class that defines the Windows Registry value-based plugin interface."""
__abstract = True
# REG_VALUES should be defined as a frozenset.
REG_VALUES = frozenset()
WEIGHT = 2
@abc.abstractmethod
def GetEntries(
self, parser_context, file_entry=None, key=None, registry_type=None,
parser_chain=None, codepage='cp1252', **kwargs):
"""Extracts event objects from the Windows Registry key.
Args:
parser_context: A parser context object (instance of ParserContext).
file_entry: optional file entry object (instance of dfvfs.FileEntry).
The default is None.
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
codepage: Optional extended ASCII string codepage. The default is cp1252.
"""
def Process(
self, parser_context, file_entry=None, key=None, registry_type=None,
parser_chain=None, codepage='cp1252', **kwargs):
"""Processes a Windows Registry value.
Args:
parser_context: A parser context object (instance of ParserContext).
file_entry: optional file entry object (instance of dfvfs.FileEntry).
The default is None.
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
codepage: Optional extended ASCII string codepage. The default is cp1252.
"""
parser_chain = self._BuildParserChain(parser_chain)
super(ValuePlugin, self).Process(
parser_context, file_entry=file_entry, key=key,
registry_type=registry_type, codepage=codepage, **kwargs)
values = frozenset([val.name for val in key.GetValues()])
if self.REG_VALUES.issubset(values):
self.GetEntries(
parser_context, file_entry=file_entry, key=key,
registry_type=registry_type, parser_chain=parser_chain,
codepage=codepage, **kwargs)
+126
View File
@@ -0,0 +1,126 @@
#!/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.
"""Plug-in to collect the Less Frequently Used Keys."""
from plaso.events import windows_events
from plaso.parsers import winreg
from plaso.parsers.winreg_plugins import interface
class BootVerificationPlugin(interface.KeyPlugin):
"""Plug-in to collect the Boot Verification Key."""
NAME = 'winreg_boot_verify'
DESCRIPTION = u'Parser for Boot Verification Registry data.'
REG_TYPE = 'SYSTEM'
REG_KEYS = [u'\\{current_control_set}\\Control\\BootVerificationProgram']
URLS = ['http://technet.microsoft.com/en-us/library/cc782537(v=ws.10).aspx']
def GetEntries(
self, parser_context, key=None, registry_type=None, file_entry=None,
parser_chain=None, **unused_kwargs):
"""Gather the BootVerification key values and return one event for all.
This key is rare, so its presence is suspect.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
"""
text_dict = {}
for value in key.GetValues():
text_dict[value.name] = value.data
event_object = windows_events.WindowsRegistryEvent(
key.last_written_timestamp, key.path, text_dict, offset=key.offset,
registry_type=registry_type, urls=self.URLS)
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
class BootExecutePlugin(interface.KeyPlugin):
"""Plug-in to collect the BootExecute Value from the Session Manager key."""
NAME = 'winreg_boot_execute'
DESCRIPTION = u'Parser for Boot Execution Registry data.'
REG_TYPE = 'SYSTEM'
REG_KEYS = [u'\\{current_control_set}\\Control\\Session Manager']
URLS = ['http://technet.microsoft.com/en-us/library/cc963230.aspx']
def GetEntries(
self, parser_context, file_entry=None, key=None, registry_type=None,
parser_chain=None, **unused_kwargs):
"""Gather the BootExecute Value, compare to default, return event.
The rest of the values in the Session Manager key are in a separate event.
Args:
parser_context: A parser context object (instance of ParserContext).
file_entry: optional file entry object (instance of dfvfs.FileEntry).
The default is None.
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
text_dict = {}
for value in key.GetValues():
if value.name == 'BootExecute':
# MSDN: claims that the data type of this value is REG_BINARY
# although REG_MULTI_SZ is known to be used as well.
if value.DataIsString():
value_string = value.data
elif value.DataIsMultiString():
value_string = u''.join(value.data)
elif value.DataIsBinaryData():
value_string = value.data
else:
value_string = u''
error_string = (
u'Key: {0:s}, value: {1:s}: unsupported value data type: '
u'{2:s}.').format(key.path, value.name, value.data_type_string)
parser_context.ProduceParseError(
self.NAME, error_string, file_entry=file_entry)
# TODO: why does this have a separate event object? Remove this.
value_dict = {'BootExecute': value_string}
event_object = windows_events.WindowsRegistryEvent(
key.last_written_timestamp, key.path, value_dict, offset=key.offset,
registry_type=registry_type, urls=self.URLS)
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
else:
text_dict[value.name] = value.data
event_object = windows_events.WindowsRegistryEvent(
key.last_written_timestamp, key.path, text_dict, offset=key.offset,
registry_type=registry_type, urls=self.URLS)
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
winreg.WinRegistryParser.RegisterPlugins([
BootVerificationPlugin, BootExecutePlugin])
+155
View File
@@ -0,0 +1,155 @@
#!/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 Less Frequently Used (LFU) Windows Registry plugin."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.lib import timelib_test
from plaso.parsers.winreg_plugins import lfu
from plaso.parsers.winreg_plugins import test_lib
from plaso.winreg import cache
from plaso.winreg import test_lib as winreg_test_lib
class TestBootExecutePlugin(test_lib.RegistryPluginTestCase):
"""Tests for the LFU BootExecute Windows Registry plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
registry_cache = cache.WinRegistryCache()
registry_cache.attributes['current_control_set'] = 'ControlSet001'
self._plugin = lfu.BootExecutePlugin(reg_cache=registry_cache)
def testProcess(self):
"""Tests the Process function."""
key_path = u'\\ControlSet001\\Control\\Session Manager'
values = []
values.append(winreg_test_lib.TestRegValue(
'BootExecute', 'autocheck autochk *\x00'.encode('utf_16_le'), 7, 123))
values.append(winreg_test_lib.TestRegValue(
'CriticalSectionTimeout', '2592000'.encode('utf_16_le'), 1, 153))
values.append(winreg_test_lib.TestRegValue(
'ExcludeFromKnownDlls', '\x00'.encode('utf_16_le'), 7, 163))
values.append(winreg_test_lib.TestRegValue(
'GlobalFlag', '0'.encode('utf_16_le'), 1, 173))
values.append(winreg_test_lib.TestRegValue(
'HeapDeCommitFreeBlockThreshold', '0'.encode('utf_16_le'), 1, 183))
values.append(winreg_test_lib.TestRegValue(
'HeapDeCommitTotalFreeThreshold', '0'.encode('utf_16_le'), 1, 203))
values.append(winreg_test_lib.TestRegValue(
'HeapSegmentCommit', '0'.encode('utf_16_le'), 1, 213))
values.append(winreg_test_lib.TestRegValue(
'HeapSegmentReserve', '0'.encode('utf_16_le'), 1, 223))
values.append(winreg_test_lib.TestRegValue(
'NumberOfInitialSessions', '2'.encode('utf_16_le'), 1, 243))
timestamp = timelib_test.CopyStringToTimestamp('2012-08-31 20:45:29')
winreg_key = winreg_test_lib.TestRegKey(key_path, timestamp, values, 153)
event_queue_consumer = self._ParseKeyWithPlugin(self._plugin, winreg_key)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 2)
event_object = event_objects[0]
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2012-08-31 20:45:29')
self.assertEquals(event_object.timestamp, expected_timestamp)
expected_string = (
u'[{0:s}] BootExecute: autocheck autochk *').format(key_path)
self._TestGetMessageStrings(event_object, expected_string, expected_string)
event_object = event_objects[1]
expected_msg = (
u'[{0:s}] '
u'CriticalSectionTimeout: 2592000 '
u'ExcludeFromKnownDlls: [] '
u'GlobalFlag: 0 '
u'HeapDeCommitFreeBlockThreshold: 0 '
u'HeapDeCommitTotalFreeThreshold: 0 '
u'HeapSegmentCommit: 0 '
u'HeapSegmentReserve: 0 '
u'NumberOfInitialSessions: 2').format(key_path)
expected_msg_short = (
u'[{0:s}] CriticalSectionTimeout: 2592000 Excl...').format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
class TestBootVerificationRegistry(test_lib.RegistryPluginTestCase):
"""Tests for the LFU BootVerification Windows Registry plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
registry_cache = cache.WinRegistryCache()
registry_cache.attributes['current_control_set'] = 'ControlSet001'
self._plugin = lfu.BootVerificationPlugin(reg_cache=registry_cache)
def testProcess(self):
"""Tests the Process function."""
key_path = u'\\ControlSet001\\Control\\BootVerificationProgram'
values = []
values.append(winreg_test_lib.TestRegValue(
'ImagePath',
'C:\\WINDOWS\\system32\\googleupdater.exe'.encode('utf_16_le'), 1,
123))
timestamp = timelib_test.CopyStringToTimestamp('2012-08-31 20:45:29')
winreg_key = winreg_test_lib.TestRegKey(key_path, timestamp, values, 153)
event_queue_consumer = self._ParseKeyWithPlugin(self._plugin, winreg_key)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 1)
event_object = event_objects[0]
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2012-08-31 20:45:29')
self.assertEquals(event_object.timestamp, expected_timestamp)
expected_msg = (
u'[{0:s}] '
u'ImagePath: C:\\WINDOWS\\system32\\googleupdater.exe').format(
key_path)
expected_msg_short = (
u'[{0:s}] ImagePath: C:\\WINDOWS\\system...').format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,88 @@
#!/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.
"""This file contains the MountPoints2 plugin."""
from plaso.events import windows_events
from plaso.parsers import winreg
from plaso.parsers.winreg_plugins import interface
class MountPoints2Plugin(interface.KeyPlugin):
"""Windows Registry plugin for parsing the MountPoints2 key."""
NAME = 'winreg_mountpoints2'
DESCRIPTION = u'Parser for mount points Registry data.'
REG_TYPE = 'NTUSER'
REG_KEYS = [
(u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\'
u'MountPoints2')]
URLS = [u'http://support.microsoft.com/kb/932463']
def GetEntries(
self, parser_context, key=None, registry_type=None, file_entry=None,
parser_chain=None, **unused_kwargs):
"""Retrieves information from the MountPoints2 registry key.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
"""
for subkey in key.GetSubkeys():
name = subkey.name
if not name:
continue
text_dict = {}
text_dict[u'Volume'] = name
# Get the label if it exists.
label_value = subkey.GetValue('_LabelFromReg')
if label_value:
text_dict[u'Label'] = label_value.data
if name.startswith('{'):
text_dict[u'Type'] = u'Volume'
elif name.startswith('#'):
# The format is: ##Server_Name#Share_Name.
text_dict[u'Type'] = u'Remote Drive'
server_name, _, share_name = name[2:].partition('#')
text_dict[u'Remote_Server'] = server_name
text_dict[u'Share_Name'] = u'\\{0:s}'.format(
share_name.replace(u'#', u'\\'))
else:
text_dict[u'Type'] = u'Drive'
event_object = windows_events.WindowsRegistryEvent(
subkey.last_written_timestamp, key.path, text_dict,
offset=subkey.offset, registry_type=registry_type, urls=self.URLS)
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
winreg.WinRegistryParser.RegisterPlugin(MountPoints2Plugin)
@@ -0,0 +1,72 @@
#!/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.
"""Tests for the MountPoints2 Windows Registry plugin."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.lib import timelib_test
from plaso.parsers.winreg_plugins import mountpoints
from plaso.parsers.winreg_plugins import test_lib
class MountPoints2PluginTest(test_lib.RegistryPluginTestCase):
"""Tests for the MountPoints2 Windows Registry plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = mountpoints.MountPoints2Plugin()
def testProcess(self):
"""Tests the Process function."""
test_file_entry = self._GetTestFileEntryFromPath(['NTUSER-WIN7.DAT'])
key_path = self._plugin.REG_KEYS[0]
winreg_key = self._GetKeyFromFileEntry(test_file_entry, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(
self._plugin, winreg_key, file_entry=test_file_entry)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 5)
event_object = event_objects[0]
self.assertEquals(event_object.pathspec, test_file_entry.path_spec)
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2011-08-23 17:10:14.960960')
self.assertEquals(event_object.timestamp, expected_timestamp)
regvalue = event_object.regvalue
self.assertEquals(regvalue.get('Share_Name'), r'\home\nfury')
expected_string = (
u'[{0:s}] Label: Home Drive Remote_Server: controller Share_Name: '
u'\\home\\nfury Type: Remote Drive Volume: '
u'##controller#home#nfury').format(key_path)
expected_string_short = u'{0:s}...'.format(expected_string[0:77])
self._TestGetMessageStrings(
event_object, expected_string, expected_string_short)
if __name__ == '__main__':
unittest.main()
+308
View File
@@ -0,0 +1,308 @@
#!/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 a MRUList Registry plugin."""
import abc
import logging
import construct
from plaso.events import windows_events
from plaso.lib import binary
from plaso.parsers import winreg
from plaso.parsers.shared import shell_items
from plaso.parsers.winreg_plugins import interface
# A mixin class is used here to not to have the duplicate functionality
# to parse the MRUList Registry values. However multiple inheritance
# and thus mixins are to be used sparsely in this codebase, hence we need
# to find a better solution in not needing to distinguish between key and
# value plugins.
# TODO: refactor Registry key and value plugin to rid ourselves of the mixin.
class MRUListPluginMixin(object):
"""Class for common MRUList Windows Registry plugin functionality."""
_MRULIST_STRUCT = construct.Range(1, 500, construct.ULInt16('entry_letter'))
@abc.abstractmethod
def _ParseMRUListEntryValue(
self, parser_context, key, entry_index, entry_letter, file_entry=None,
parser_chain=None, **kwargs):
"""Parses the MRUList entry value.
Args:
parser_context: A parser context object (instance of ParserContext).
key: the Registry key (instance of winreg.WinRegKey) that contains
the MRUList value.
entry_index: integer value representing the MRUList entry index.
entry_letter: character value representing the entry.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
Returns:
A string containing the value.
"""
def _ParseMRUListValue(self, key):
"""Parses the MRUList value in a given Registry key.
Args:
key: the Registry key (instance of winreg.WinRegKey) that contains
the MRUList value.
Returns:
A MRUList value generator, which returns the MRU index number
and entry value.
"""
mru_list_value = key.GetValue('MRUList')
# The key exists but does not contain a value named "MRUList".
if not mru_list_value:
return enumerate([])
try:
mru_list = self._MRULIST_STRUCT.parse(mru_list_value.raw_data)
except construct.FieldError:
logging.warning(u'[{0:s}] Unable to parse the MRU key: {1:s}'.format(
self.NAME, key.path))
return enumerate([])
return enumerate(mru_list)
def _ParseMRUListKey(
self, parser_context, key, registry_type=None, file_entry=None,
parser_chain=None, codepage='cp1252'):
"""Extract event objects from a MRUList Registry key.
Args:
parser_context: A parser context object (instance of ParserContext).
key: the Registry key (instance of winreg.WinRegKey).
registry_type: Optional Registry type string. The default is None.
codepage: Optional extended ASCII string codepage. The default is cp1252.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
text_dict = {}
for entry_index, entry_letter in self._ParseMRUListValue(key):
# TODO: detect if list ends prematurely.
# MRU lists are terminated with \0 (0x0000).
if entry_letter == 0:
break
entry_letter = chr(entry_letter)
value_string = self._ParseMRUListEntryValue(
parser_context, key, entry_index, entry_letter,
codepage=codepage, file_entry=file_entry, parser_chain=parser_chain)
value_text = u'Index: {0:d} [MRU Value {1:s}]'.format(
entry_index + 1, entry_letter)
text_dict[value_text] = value_string
event_object = windows_events.WindowsRegistryEvent(
key.last_written_timestamp, key.path, text_dict,
offset=key.offset, registry_type=registry_type,
source_append=': MRU List')
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
class MRUListStringPlugin(interface.ValuePlugin, MRUListPluginMixin):
"""Windows Registry plugin to parse a string MRUList."""
NAME = 'winreg_mrulist_string'
DESCRIPTION = u'Parser for Most Recently Used (MRU) Registry data.'
REG_TYPE = 'any'
REG_VALUES = frozenset(['MRUList', 'a'])
URLS = [u'http://forensicartifacts.com/tag/mru/']
def _ParseMRUListEntryValue(
self, parser_context, key, entry_index, entry_letter, **unused_kwargs):
"""Parses the MRUList entry value.
Args:
parser_context: A parser context object (instance of ParserContext).
key: the Registry key (instance of winreg.WinRegKey) that contains
the MRUList value.
entry_index: integer value representing the MRUList entry index.
entry_letter: character value representing the entry.
Returns:
A string containing the value.
"""
value_string = u''
value = key.GetValue(u'{0:s}'.format(entry_letter))
if value is None:
logging.debug(
u'[{0:s}] Missing MRUList entry value: {1:s} in key: {2:s}.'.format(
self.NAME, entry_letter, key.path))
elif value.DataIsString():
value_string = value.data
elif value.DataIsBinaryData():
logging.debug((
u'[{0:s}] Non-string MRUList entry value: {1:s} parsed as string '
u'in key: {2:s}.').format(self.NAME, entry_letter, key.path))
utf16_stream = binary.ByteStreamCopyToUtf16Stream(value.data)
try:
value_string = utf16_stream.decode('utf-16-le')
except UnicodeDecodeError as exception:
value_string = binary.HexifyBuffer(utf16_stream)
logging.warning((
u'[{0:s}] Unable to decode UTF-16 stream: {1:s} in MRUList entry '
u'value: {2:s} in key: {3:s} with error: {4:s}').format(
self.NAME, value_string, entry_letter, key.path, exception))
return value_string
def GetEntries(
self, parser_context, file_entry=None, key=None, registry_type=None,
parser_chain=None, codepage='cp1252', **unused_kwargs):
"""Extracts event objects from a MRU list.
Args:
parser_context: A parser context object (instance of ParserContext).
file_entry: optional file entry object (instance of dfvfs.FileEntry).
The default is None.
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
codepage: Optional extended ASCII string codepage. The default is cp1252.
"""
self._ParseMRUListKey(
parser_context, key, registry_type=registry_type,
parser_chain=parser_chain, file_entry=file_entry, codepage=codepage)
def Process(
self, parser_context, file_entry=None, key=None, registry_type=None,
codepage='cp1252', parser_chain=None, **kwargs):
"""Determine if we can process this Registry key or not.
Args:
parser_context: A parser context object (instance of ParserContext).
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
codepage: Optional extended ASCII string codepage. The default is cp1252.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
# Prevent this plugin triggering on sub paths of non-string MRUList values.
if u'Explorer\\DesktopStreamMRU' in key.path:
return
super(MRUListStringPlugin, self).Process(
parser_context, file_entry=file_entry, key=key,
registry_type=registry_type, codepage=codepage,
parser_chain=parser_chain, **kwargs)
class MRUListShellItemListPlugin(interface.KeyPlugin, MRUListPluginMixin):
"""Windows Registry plugin to parse a shell item list MRUList."""
NAME = 'winreg_mrulist_shell_item_list'
DESCRIPTION = u'Parser for Most Recently Used (MRU) Registry data.'
REG_TYPE = 'any'
REG_KEYS = frozenset([
(u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\'
u'DesktopStreamMRU')])
URLS = [u'https://github.com/libyal/winreg-kb/wiki/MRU-keys']
def _ParseMRUListEntryValue(
self, parser_context, key, entry_index, entry_letter, codepage='cp1252',
file_entry=None, parser_chain=None, **unused_kwargs):
"""Parses the MRUList entry value.
Args:
parser_context: A parser context object (instance of ParserContext).
key: the Registry key (instance of winreg.WinRegKey) that contains
the MRUList value.
entry_index: integer value representing the MRUList entry index.
entry_letter: character value representing the entry.
codepage: Optional extended ASCII string codepage. The default is cp1252.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
Returns:
A string containing the value.
"""
value_string = u''
value = key.GetValue(u'{0:s}'.format(entry_letter))
if value is None:
logging.debug(
u'[{0:s}] Missing MRUList entry value: {1:s} in key: {2:s}.'.format(
self.NAME, entry_letter, key.path))
elif not value.DataIsBinaryData():
logging.debug((
u'[{0:s}] Non-binary MRUList entry value: {1:s} in key: '
u'{2:s}.').format(self.NAME, entry_letter, key.path))
elif value.data:
shell_items_parser = shell_items.ShellItemsParser(key.path)
shell_items_parser.Parse(
parser_context, value.data, codepage=codepage, file_entry=file_entry,
parser_chain=parser_chain)
value_string = u'Shell item list: [{0:s}]'.format(
shell_items_parser.CopyToPath())
return value_string
def GetEntries(
self, parser_context, key=None, registry_type=None, codepage='cp1252',
file_entry=None, parser_chain=None, **unused_kwargs):
"""Extract event objects from a Registry key containing a MRUList value.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
codepage: Optional extended ASCII string codepage. The default is cp1252.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
self._ParseMRUListKey(
parser_context, key, registry_type=registry_type, codepage=codepage,
parser_chain=parser_chain, file_entry=file_entry)
winreg.WinRegistryParser.RegisterPlugins([
MRUListStringPlugin, MRUListShellItemListPlugin])
@@ -0,0 +1,171 @@
#!/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 MRUList Windows Registry plugin."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.lib import timelib_test
from plaso.parsers.winreg_plugins import mrulist
from plaso.parsers.winreg_plugins import test_lib
from plaso.winreg import test_lib as winreg_test_lib
class TestMRUListStringPlugin(test_lib.RegistryPluginTestCase):
"""Tests for the string MRUList plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = mrulist.MRUListStringPlugin()
def testProcess(self):
"""Tests the Process function."""
key_path = u'\\Microsoft\\Some Windows\\InterestingApp\\MRU'
values = []
values.append(winreg_test_lib.TestRegValue(
'MRUList', 'acb'.encode('utf_16_le'),
winreg_test_lib.TestRegValue.REG_SZ, offset=123))
values.append(winreg_test_lib.TestRegValue(
'a', 'Some random text here'.encode('utf_16_le'),
winreg_test_lib.TestRegValue.REG_SZ, offset=1892))
values.append(winreg_test_lib.TestRegValue(
'b', 'c:/evil.exe'.encode('utf_16_le'),
winreg_test_lib.TestRegValue.REG_BINARY, offset=612))
values.append(winreg_test_lib.TestRegValue(
'c', 'C:/looks_legit.exe'.encode('utf_16_le'),
winreg_test_lib.TestRegValue.REG_SZ, offset=1001))
timestamp = timelib_test.CopyStringToTimestamp('2012-08-28 09:23:49.002031')
winreg_key = winreg_test_lib.TestRegKey(
key_path, timestamp, values, 1456)
event_queue_consumer = self._ParseKeyWithPlugin(self._plugin, winreg_key)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 1)
event_object = event_objects[0]
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2012-08-28 09:23:49.002031')
self.assertEquals(event_object.timestamp, expected_timestamp)
expected_msg = (
u'[{0:s}] '
u'Index: 1 [MRU Value a]: Some random text here '
u'Index: 2 [MRU Value c]: C:/looks_legit.exe '
u'Index: 3 [MRU Value b]: c:/evil.exe').format(key_path)
expected_msg_short = (
u'[{0:s}] Index: 1 [MRU Value a]: Some ran...').format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
class TestMRUListShellItemListPlugin(test_lib.RegistryPluginTestCase):
"""Tests for the shell item list MRUList plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = mrulist.MRUListShellItemListPlugin()
def testProcess(self):
"""Tests the Process function."""
key_path = (
u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\'
u'DesktopStreamMRU')
values = []
data = ''.join(map(chr, [
0x14, 0x00, 0x1f, 0x00, 0xe0, 0x4f, 0xd0, 0x20, 0xea, 0x3a, 0x69, 0x10,
0xa2, 0xd8, 0x08, 0x00, 0x2b, 0x30, 0x30, 0x9d, 0x19, 0x00, 0x23, 0x43,
0x3a, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xee, 0x15, 0x00, 0x31,
0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x3e, 0x7a, 0x60, 0x10, 0x80, 0x57,
0x69, 0x6e, 0x6e, 0x74, 0x00, 0x00, 0x18, 0x00, 0x31, 0x00, 0x00, 0x00,
0x00, 0x00, 0x2e, 0x3e, 0xe4, 0x62, 0x10, 0x00, 0x50, 0x72, 0x6f, 0x66,
0x69, 0x6c, 0x65, 0x73, 0x00, 0x00, 0x25, 0x00, 0x31, 0x00, 0x00, 0x00,
0x00, 0x00, 0x2e, 0x3e, 0xe4, 0x62, 0x10, 0x00, 0x41, 0x64, 0x6d, 0x69,
0x6e, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x00, 0x41, 0x44,
0x4d, 0x49, 0x4e, 0x49, 0x7e, 0x31, 0x00, 0x17, 0x00, 0x31, 0x00, 0x00,
0x00, 0x00, 0x00, 0x2e, 0x3e, 0xe4, 0x62, 0x10, 0x00, 0x44, 0x65, 0x73,
0x6b, 0x74, 0x6f, 0x70, 0x00, 0x00, 0x00, 0x00]))
values.append(winreg_test_lib.TestRegValue(
'MRUList', 'a'.encode('utf_16_le'),
winreg_test_lib.TestRegValue.REG_SZ, offset=123))
values.append(winreg_test_lib.TestRegValue(
'a', data, winreg_test_lib.TestRegValue.REG_BINARY, offset=612))
timestamp = timelib_test.CopyStringToTimestamp('2012-08-28 09:23:49.002031')
winreg_key = winreg_test_lib.TestRegKey(
key_path, timestamp, values, 1456)
event_queue_consumer = self._ParseKeyWithPlugin(self._plugin, winreg_key)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 5)
# A MRUList event object.
event_object = event_objects[4]
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2012-08-28 09:23:49.002031')
self.assertEquals(event_object.timestamp, expected_timestamp)
expected_msg = (
u'[{0:s}] '
u'Index: 1 [MRU Value a]: Shell item list: '
u'[My Computer, C:\\, Winnt, Profiles, Administrator, Desktop]').format(
key_path)
expected_msg_short = u'[{0:s}] Index:...'.format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
# A shell item event object.
event_object = event_objects[0]
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2011-01-14 12:03:52')
self.assertEquals(event_object.timestamp, expected_timestamp)
expected_msg = (
u'Name: Winnt '
u'Origin: {0:s}').format(key_path)
expected_msg_short = (
u'Name: Winnt '
u'Origin: \\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\'
u'Deskt...')
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
if __name__ == '__main__':
unittest.main()
+528
View File
@@ -0,0 +1,528 @@
#!/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 MRUListEx Windows Registry plugins."""
import abc
import logging
import construct
from plaso.events import windows_events
from plaso.lib import binary
from plaso.parsers import winreg
from plaso.parsers.shared import shell_items
from plaso.parsers.winreg_plugins import interface
# A mixin class is used here to not to have the duplicate functionality
# to parse the MRUListEx Registry values. However multiple inheritance
# and thus mixins are to be used sparsely in this codebase, hence we need
# to find a better solution in not needing to distinguish between key and
# value plugins.
# TODO: refactor Registry key and value plugin to rid ourselves of the mixin.
class MRUListExPluginMixin(object):
"""Class for common MRUListEx Windows Registry plugin functionality."""
_MRULISTEX_STRUCT = construct.Range(1, 500, construct.ULInt32('entry_number'))
@abc.abstractmethod
def _ParseMRUListExEntryValue(
self, parser_context, key, entry_index, entry_number, **kwargs):
"""Parses the MRUListEx entry value.
Args:
parser_context: A parser context object (instance of ParserContext).
key: the Registry key (instance of winreg.WinRegKey) that contains
the MRUListEx value.
entry_index: integer value representing the MRUListEx entry index.
entry_number: integer value representing the entry number.
Returns:
A string containing the value.
"""
def _ParseMRUListExValue(self, key):
"""Parses the MRUListEx value in a given Registry key.
Args:
key: the Registry key (instance of winreg.WinRegKey) that contains
the MRUListEx value.
Returns:
A MRUListEx value generator, which returns the MRU index number
and entry value.
"""
mru_list_value = key.GetValue('MRUListEx')
# The key exists but does not contain a value named "MRUListEx".
if not mru_list_value:
return enumerate([])
try:
mru_list = self._MRULISTEX_STRUCT.parse(mru_list_value.data)
except construct.FieldError:
logging.warning(u'[{0:s}] Unable to parse the MRU key: {1:s}'.format(
self.NAME, key.path))
return enumerate([])
return enumerate(mru_list)
def _ParseMRUListExKey(
self, parser_context, key, registry_type=None, codepage='cp1252',
file_entry=None, parser_chain=None):
"""Extract event objects from a MRUListEx Registry key.
Args:
parser_context: A parser context object (instance of ParserContext).
key: the Registry key (instance of winreg.WinRegKey).
registry_type: Optional Registry type string. The default is None.
codepage: Optional extended ASCII string codepage. The default is cp1252.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
"""
text_dict = {}
for entry_index, entry_number in self._ParseMRUListExValue(key):
# TODO: detect if list ends prematurely.
# MRU lists are terminated with 0xffffffff (-1).
if entry_number == 0xffffffff:
break
value_string = self._ParseMRUListExEntryValue(
parser_context, key, entry_index, entry_number,
codepage=codepage, file_entry=file_entry, parser_chain=parser_chain)
value_text = u'Index: {0:d} [MRU Value {1:d}]'.format(
entry_index + 1, entry_number)
text_dict[value_text] = value_string
event_object = windows_events.WindowsRegistryEvent(
key.last_written_timestamp, key.path, text_dict,
offset=key.offset, registry_type=registry_type,
source_append=': MRUListEx')
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
class MRUListExStringPlugin(interface.ValuePlugin, MRUListExPluginMixin):
"""Windows Registry plugin to parse a string MRUListEx."""
NAME = 'winreg_mrulistex_string'
DESCRIPTION = u'Parser for Most Recently Used (MRU) Registry data.'
REG_TYPE = 'any'
REG_VALUES = frozenset(['MRUListEx', '0'])
URLS = [
u'http://forensicartifacts.com/2011/02/recentdocs/',
u'https://github.com/libyal/winreg-kb/wiki/MRU-keys']
_STRING_STRUCT = construct.Struct(
'string_and_shell_item',
construct.RepeatUntil(
lambda obj, ctx: obj == '\x00\x00', construct.Field('string', 2)))
def _ParseMRUListExEntryValue(
self, parser_context, key, entry_index, entry_number, **unused_kwargs):
"""Parses the MRUListEx entry value.
Args:
parser_context: A parser context object (instance of ParserContext).
key: the Registry key (instance of winreg.WinRegKey) that contains
the MRUListEx value.
entry_index: integer value representing the MRUListEx entry index.
entry_number: integer value representing the entry number.
Returns:
A string containing the value.
"""
value_string = u''
value = key.GetValue(u'{0:d}'.format(entry_number))
if value is None:
logging.debug(
u'[{0:s}] Missing MRUListEx entry value: {1:d} in key: {2:s}.'.format(
self.NAME, entry_number, key.path))
elif value.DataIsString():
value_string = value.data
elif value.DataIsBinaryData():
logging.debug((
u'[{0:s}] Non-string MRUListEx entry value: {1:d} parsed as string '
u'in key: {2:s}.').format(self.NAME, entry_number, key.path))
utf16_stream = binary.ByteStreamCopyToUtf16Stream(value.data)
try:
value_string = utf16_stream.decode('utf-16-le')
except UnicodeDecodeError as exception:
value_string = binary.HexifyBuffer(utf16_stream)
logging.warning((
u'[{0:s}] Unable to decode UTF-16 stream: {1:s} in MRUListEx entry '
u'value: {2:d} in key: {3:s} with error: {4:s}').format(
self.NAME, value_string, entry_number, key.path, exception))
return value_string
def GetEntries(
self, parser_context, key=None, registry_type=None, codepage='cp1252',
file_entry=None, parser_chain=None, **unused_kwargs):
"""Extract event objects from a Registry key containing a MRUListEx value.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
codepage: Optional extended ASCII string codepage. The default is cp1252.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
"""
self._ParseMRUListExKey(
parser_context, key, registry_type=registry_type, codepage=codepage,
parser_chain=parser_chain, file_entry=file_entry)
def Process(self, parser_context, key=None, codepage='cp1252', **kwargs):
"""Determine if we can process this Registry key or not.
Args:
parser_context: A parser context object (instance of ParserContext).
key: A Windows Registry key (instance of WinRegKey).
codepage: Optional extended ASCII string codepage. The default is cp1252.
"""
# Prevent this plugin triggering on sub paths of non-string MRUListEx
# values.
if (u'BagMRU' in key.path or u'Explorer\\StreamMRU' in key.path or
u'\\Explorer\\ComDlg32\\OpenSavePidlMRU' in key.path):
return
super(MRUListExStringPlugin, self).Process(
parser_context, key=key, codepage=codepage, **kwargs)
class MRUListExShellItemListPlugin(interface.KeyPlugin, MRUListExPluginMixin):
"""Windows Registry plugin to parse a shell item list MRUListEx."""
NAME = 'winreg_mrulistex_shell_item_list'
DESCRIPTION = u'Parser for Most Recently Used (MRU) Registry data.'
REG_TYPE = 'any'
REG_KEYS = frozenset([
# The regular expression indicated a file extension (.jpg) or '*'.
(u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\'
u'OpenSavePidlMRU'),
u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StreamMRU'])
def _ParseMRUListExEntryValue(
self, parser_context, key, entry_index, entry_number, codepage='cp1252',
file_entry=None, parser_chain=None, **unused_kwargs):
"""Parses the MRUListEx entry value.
Args:
parser_context: A parser context object (instance of ParserContext).
key: the Registry key (instance of winreg.WinRegKey) that contains
the MRUListEx value.
entry_index: integer value representing the MRUListEx entry index.
entry_number: integer value representing the entry number.
codepage: Optional extended ASCII string codepage. The default is cp1252.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
Returns:
A string containing the value.
"""
value_string = u''
value = key.GetValue(u'{0:d}'.format(entry_number))
if value is None:
logging.debug(
u'[{0:s}] Missing MRUListEx entry value: {1:d} in key: {2:s}.'.format(
self.NAME, entry_number, key.path))
elif not value.DataIsBinaryData():
logging.debug((
u'[{0:s}] Non-binary MRUListEx entry value: {1:d} in key: '
u'{2:s}.').format(self.NAME, entry_number, key.path))
elif value.data:
shell_items_parser = shell_items.ShellItemsParser(key.path)
shell_items_parser.Parse(
parser_context, value.data, codepage=codepage, file_entry=file_entry,
parser_chain=parser_chain)
value_string = u'Shell item list: [{0:s}]'.format(
shell_items_parser.CopyToPath())
return value_string
def GetEntries(
self, parser_context, key=None, registry_type=None, codepage='cp1252',
file_entry=None, parser_chain=None, **unused_kwargs):
"""Extract event objects from a Registry key containing a MRUListEx value.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
codepage: Optional extended ASCII string codepage. The default is cp1252.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
"""
if key.name != u'OpenSavePidlMRU':
self._ParseMRUListExKey(
parser_context, key, registry_type=registry_type, codepage=codepage,
parser_chain=parser_chain, file_entry=file_entry)
if key.name == u'OpenSavePidlMRU':
# For the OpenSavePidlMRU MRUListEx we also need to parse its subkeys
# since the Registry key path does not support wildcards yet.
for subkey in key.GetSubkeys():
self._ParseMRUListExKey(
parser_context, subkey, registry_type=registry_type,
codepage=codepage, parser_chain=parser_chain, file_entry=file_entry)
class MRUListExStringAndShellItemPlugin(
interface.KeyPlugin, MRUListExPluginMixin):
"""Windows Registry plugin to parse a string and shell item MRUListEx."""
NAME = 'winreg_mrulistex_string_and_shell_item'
DESCRIPTION = u'Parser for Most Recently Used (MRU) Registry data.'
REG_TYPE = 'any'
REG_KEYS = frozenset([
u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RecentDocs'])
_STRING_AND_SHELL_ITEM_STRUCT = construct.Struct(
'string_and_shell_item',
construct.RepeatUntil(
lambda obj, ctx: obj == '\x00\x00', construct.Field('string', 2)),
construct.Anchor('shell_item'))
def _ParseMRUListExEntryValue(
self, parser_context, key, entry_index, entry_number, codepage='cp1252',
file_entry=None, parser_chain=None, **unused_kwargs):
"""Parses the MRUListEx entry value.
Args:
parser_context: A parser context object (instance of ParserContext).
key: the Registry key (instance of winreg.WinRegKey) that contains
the MRUListEx value.
entry_index: integer value representing the MRUListEx entry index.
entry_number: integer value representing the entry number.
codepage: Optional extended ASCII string codepage. The default is cp1252.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
Returns:
A string containing the value.
"""
value_string = u''
value = key.GetValue(u'{0:d}'.format(entry_number))
if value is None:
logging.debug(
u'[{0:s}] Missing MRUListEx entry value: {1:d} in key: {2:s}.'.format(
self.NAME, entry_number, key.path))
elif not value.DataIsBinaryData():
logging.debug((
u'[{0:s}] Non-binary MRUListEx entry value: {1:d} in key: '
u'{2:s}.').format(self.NAME, entry_number, key.path))
elif value.data:
value_struct = self._STRING_AND_SHELL_ITEM_STRUCT.parse(value.data)
try:
# The struct includes the end-of-string character that we need
# to strip off.
path = ''.join(value_struct.string).decode('utf16')[:-1]
except UnicodeDecodeError as exception:
logging.warning((
u'[{0:s}] Unable to decode string MRUListEx entry value: {1:d} '
u'in key: {2:s} with error: {3:s}').format(
self.NAME, entry_number, key.path, exception))
path = u''
if path:
shell_item_list_data = value.data[value_struct.shell_item:]
if not shell_item_list_data:
logging.debug((
u'[{0:s}] Missing shell item in MRUListEx entry value: {1:d}'
u'in key: {2:s}').format(self.NAME, entry_number, key.path))
value_string = u'Path: {0:s}'.format(path)
else:
shell_items_parser = shell_items.ShellItemsParser(key.path)
shell_items_parser.Parse(
parser_context, shell_item_list_data, codepage=codepage,
parser_chain=parser_chain, file_entry=file_entry)
value_string = u'Path: {0:s}, Shell item: [{1:s}]'.format(
path, shell_items_parser.CopyToPath())
return value_string
def GetEntries(
self, parser_context, key=None, registry_type=None, codepage='cp1252',
file_entry=None, parser_chain=None, **unused_kwargs):
"""Extract event objects from a Registry key containing a MRUListEx value.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
codepage: Optional extended ASCII string codepage. The default is cp1252.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
self._ParseMRUListExKey(
parser_context, key, registry_type=registry_type, codepage=codepage,
parser_chain=parser_chain, file_entry=file_entry)
if key.name == u'RecentDocs':
# For the RecentDocs MRUListEx we also need to parse its subkeys
# since the Registry key path does not support wildcards yet.
for subkey in key.GetSubkeys():
self._ParseMRUListExKey(
parser_context, subkey, registry_type=registry_type,
codepage=codepage, parser_chain=parser_chain, file_entry=file_entry)
class MRUListExStringAndShellItemListPlugin(
interface.KeyPlugin, MRUListExPluginMixin):
"""Windows Registry plugin to parse a string and shell item list MRUListEx."""
NAME = 'winreg_mrulistex_string_and_shell_item_list'
DESCRIPTION = u'Parser for Most Recently Used (MRU) Registry data.'
REG_TYPE = 'any'
REG_KEYS = frozenset([
(u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\'
u'LastVisitedPidlMRU')])
_STRING_AND_SHELL_ITEM_LIST_STRUCT = construct.Struct(
'string_and_shell_item',
construct.RepeatUntil(
lambda obj, ctx: obj == '\x00\x00', construct.Field('string', 2)),
construct.Anchor('shell_item_list'))
def _ParseMRUListExEntryValue(
self, parser_context, key, entry_index, entry_number, codepage='cp1252',
file_entry=None, parser_chain=None, **unused_kwargs):
"""Parses the MRUListEx entry value.
Args:
parser_context: A parser context object (instance of ParserContext).
key: the Registry key (instance of winreg.WinRegKey) that contains
the MRUListEx value.
entry_index: integer value representing the MRUListEx entry index.
entry_number: integer value representing the entry number.
codepage: Optional extended ASCII string codepage. The default is cp1252.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
Returns:
A string containing the value.
"""
value_string = u''
value = key.GetValue(u'{0:d}'.format(entry_number))
if value is None:
logging.debug(
u'[{0:s}] Missing MRUListEx entry value: {1:d} in key: {2:s}.'.format(
self.NAME, entry_number, key.path))
elif not value.DataIsBinaryData():
logging.debug((
u'[{0:s}] Non-binary MRUListEx entry value: {1:d} in key: '
u'{2:s}.').format(self.NAME, entry_number, key.path))
elif value.data:
value_struct = self._STRING_AND_SHELL_ITEM_LIST_STRUCT.parse(value.data)
try:
# The struct includes the end-of-string character that we need
# to strip off.
path = ''.join(value_struct.string).decode('utf16')[:-1]
except UnicodeDecodeError as exception:
logging.warning((
u'[{0:s}] Unable to decode string MRUListEx entry value: {1:d} '
u'in key: {2:s} with error: {3:s}').format(
self.NAME, entry_number, key.path, exception))
path = u''
if path:
shell_item_list_data = value.data[value_struct.shell_item_list:]
if not shell_item_list_data:
logging.debug((
u'[{0:s}] Missing shell item in MRUListEx entry value: {1:d}'
u'in key: {2:s}').format(self.NAME, entry_number, key.path))
value_string = u'Path: {0:s}'.format(path)
else:
shell_items_parser = shell_items.ShellItemsParser(key.path)
shell_items_parser.Parse(
parser_context, shell_item_list_data, codepage=codepage,
parser_chain=parser_chain, file_entry=file_entry)
value_string = u'Path: {0:s}, Shell item list: [{1:s}]'.format(
path, shell_items_parser.CopyToPath())
return value_string
def GetEntries(
self, parser_context, key=None, registry_type=None, codepage='cp1252',
file_entry=None, parser_chain=None, **unused_kwargs):
"""Extract event objects from a Registry key containing a MRUListEx value.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
codepage: Optional extended ASCII string codepage. The default is cp1252.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
self._ParseMRUListExKey(
parser_context, key, registry_type=registry_type, codepage=codepage,
parser_chain=parser_chain, file_entry=file_entry)
winreg.WinRegistryParser.RegisterPlugins([
MRUListExStringPlugin, MRUListExShellItemListPlugin,
MRUListExStringAndShellItemPlugin, MRUListExStringAndShellItemListPlugin])
@@ -0,0 +1,303 @@
#!/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 MRUListEx Windows Registry plugin."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.lib import timelib_test
from plaso.parsers.winreg_plugins import mrulistex
from plaso.parsers.winreg_plugins import test_lib
from plaso.winreg import interface as winreg_interface
from plaso.winreg import test_lib as winreg_test_lib
class TestMRUListExStringPlugin(test_lib.RegistryPluginTestCase):
"""Tests for the string MRUListEx plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = mrulistex.MRUListExStringPlugin()
def testProcess(self):
"""Tests the Process function."""
key_path = u'\\Microsoft\\Some Windows\\InterestingApp\\MRUlist'
values = []
# The order is: 201
values.append(winreg_test_lib.TestRegValue(
'MRUListEx', '\x02\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00',
winreg_interface.WinRegValue.REG_BINARY, 123))
values.append(winreg_test_lib.TestRegValue(
'0', 'Some random text here'.encode('utf_16_le'),
winreg_interface.WinRegValue.REG_SZ, 1892))
values.append(winreg_test_lib.TestRegValue(
'1', 'c:\\evil.exe'.encode('utf_16_le'),
winreg_interface.WinRegValue.REG_BINARY, 612))
values.append(winreg_test_lib.TestRegValue(
'2', 'C:\\looks_legit.exe'.encode('utf_16_le'),
winreg_interface.WinRegValue.REG_SZ, 1001))
winreg_key = winreg_test_lib.TestRegKey(
key_path, 1346145829002031, values, 1456)
event_queue_consumer = self._ParseKeyWithPlugin(self._plugin, winreg_key)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 1)
# A MRUListEx event object.
event_object = event_objects[0]
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2012-08-28 09:23:49.002031')
self.assertEquals(event_object.timestamp, expected_timestamp)
expected_msg = (
u'[{0:s}] '
u'Index: 1 [MRU Value 2]: C:\\looks_legit.exe '
u'Index: 2 [MRU Value 0]: Some random text here '
u'Index: 3 [MRU Value 1]: c:\\evil.exe').format(key_path)
expected_msg_short = (
u'[{0:s}] Index: 1 [MRU Value 2]: C:\\l...').format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
class TestMRUListExShellItemListPlugin(test_lib.RegistryPluginTestCase):
"""Tests for the shell item list MRUListEx plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = mrulistex.MRUListExShellItemListPlugin()
def testProcess(self):
"""Tests the Process function."""
test_file_entry = self._GetTestFileEntryFromPath(['NTUSER-WIN7.DAT'])
key_path = (
u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\'
u'OpenSavePidlMRU')
winreg_key = self._GetKeyFromFileEntry(test_file_entry, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(
self._plugin, winreg_key, file_entry=test_file_entry)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 65)
# A MRUListEx event object.
event_object = event_objects[40]
self.assertEquals(event_object.pathspec, test_file_entry.path_spec)
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2011-08-28 22:48:28.159308')
self.assertEquals(event_object.timestamp, expected_timestamp)
expected_msg = (
u'[{0:s}\\exe] '
u'Index: 1 [MRU Value 1]: Shell item list: [My Computer, P:\\, '
u'Application Tools, Firefox 6.0, Firefox Setup 6.0.exe] '
u'Index: 2 [MRU Value 0]: Shell item list: [Computers and Devices, '
u'UNKNOWN: 0x00, \\\\controller\\WebDavShare, Firefox Setup 3.6.12.exe'
u']').format(key_path)
expected_msg_short = (
u'[\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\'
u'OpenSavePidlMRU...')
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
# A shell item event object.
event_object = event_objects[0]
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2012-03-08 22:16:02')
self.assertEquals(event_object.timestamp, expected_timestamp)
expected_msg = (
u'Name: ALLOYR~1 '
u'Long name: Alloy Research '
u'NTFS file reference: 44518-33 '
u'Origin: {0:s}\\*').format(key_path)
expected_msg_short = (
u'Name: ALLOYR~1 '
u'NTFS file reference: 44518-33 '
u'Origin: \\Software\\Microsoft\\Wind...')
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
class TestMRUListExStringAndShellItemPlugin(test_lib.RegistryPluginTestCase):
"""Tests for the string and shell item MRUListEx plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = mrulistex.MRUListExStringAndShellItemPlugin()
def testProcess(self):
"""Tests the Process function."""
test_file_entry = self._GetTestFileEntryFromPath(['NTUSER-WIN7.DAT'])
key_path = (
u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RecentDocs')
winreg_key = self._GetKeyFromFileEntry(test_file_entry, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(
self._plugin, winreg_key, file_entry=test_file_entry)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 6)
# A MRUListEx event object.
event_object = event_objects[0]
self.assertEquals(event_object.pathspec, test_file_entry.path_spec)
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2012-04-01 13:52:39.113741')
self.assertEquals(event_object.timestamp, expected_timestamp)
expected_msg = (
u'[{0:s}] '
u'Index: 1 [MRU Value 17]: Path: The SHIELD, '
u'Shell item: [The SHIELD.lnk] '
u'Index: 10 [MRU Value 11]: Path: 5031RR_BalancedLeadership.pdf, '
u'Shell item: [5031RR_BalancedLeadership.lnk] '
u'Index: 11 [MRU Value 10]: '
u'Path: SA-23E Mitchell-Hyundyne Starfury.docx, '
u'Shell item: [SA-23E Mitchell-Hyundyne Starfury.lnk] '
u'Index: 12 [MRU Value 9]: Path: StarFury.docx, '
u'Shell item: [StarFury (3).lnk] '
u'Index: 13 [MRU Value 6]: Path: StarFury.zip, '
u'Shell item: [StarFury.lnk] '
u'Index: 14 [MRU Value 4]: Path: VIBRANIUM.docx, '
u'Shell item: [VIBRANIUM.lnk] '
u'Index: 15 [MRU Value 5]: Path: ADAMANTIUM-Background.docx, '
u'Shell item: [ADAMANTIUM-Background.lnk] '
u'Index: 16 [MRU Value 3]: Path: Pictures, '
u'Shell item: [Pictures.lnk] '
u'Index: 17 [MRU Value 2]: Path: nick_fury_77831.jpg, '
u'Shell item: [nick_fury_77831.lnk] '
u'Index: 18 [MRU Value 1]: Path: Downloads, '
u'Shell item: [Downloads.lnk] '
u'Index: 19 [MRU Value 0]: Path: wallpaper_medium.jpg, '
u'Shell item: [wallpaper_medium.lnk] '
u'Index: 2 [MRU Value 18]: '
u'Path: captain_america_shield_by_almogrem-d48x9x8.jpg, '
u'Shell item: [captain_america_shield_by_almogrem-d48x9x8.lnk] '
u'Index: 3 [MRU Value 16]: Path: captain-america-shield-front.jpg, '
u'Shell item: [captain-america-shield-front.lnk] '
u'Index: 4 [MRU Value 12]: Path: Leadership, '
u'Shell item: [Leadership.lnk] '
u'Index: 5 [MRU Value 15]: Path: followership.pdf, '
u'Shell item: [followership.lnk] '
u'Index: 6 [MRU Value 14]: Path: leaderqualities.pdf, '
u'Shell item: [leaderqualities.lnk] '
u'Index: 7 [MRU Value 13]: Path: htlhtl.pdf, '
u'Shell item: [htlhtl.lnk] '
u'Index: 8 [MRU Value 8]: Path: StarFury, '
u'Shell item: [StarFury (2).lnk] '
u'Index: 9 [MRU Value 7]: Path: Earth_SA-26_Thunderbolt.jpg, '
u'Shell item: [Earth_SA-26_Thunderbolt.lnk]').format(key_path)
expected_msg_short = (
u'[{0:s}] Index: 1 [MR...').format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
class TestMRUListExStringAndShellItemListPlugin(
test_lib.RegistryPluginTestCase):
"""Tests for the string and shell item list MRUListEx plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = mrulistex.MRUListExStringAndShellItemListPlugin()
def testProcess(self):
"""Tests the Process function."""
test_file_entry = self._GetTestFileEntryFromPath(['NTUSER-WIN7.DAT'])
key_path = (
u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\'
u'LastVisitedPidlMRU')
winreg_key = self._GetKeyFromFileEntry(test_file_entry, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(
self._plugin, winreg_key, file_entry=test_file_entry)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 31)
# A MRUListEx event object.
event_object = event_objects[30]
self.assertEquals(event_object.pathspec, test_file_entry.path_spec)
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2012-04-01 13:52:38.966290')
self.assertEquals(event_object.timestamp, expected_timestamp)
expected_msg = (
u'[{0:s}] '
u'Index: 1 [MRU Value 1]: Path: chrome.exe, '
u'Shell item list: [Users Libraries, UNKNOWN: 0x00, UNKNOWN: 0x00, '
u'UNKNOWN: 0x00] '
u'Index: 2 [MRU Value 7]: '
u'Path: {{48E1ED6B-CF49-4609-B1C1-C082BFC3D0B4}}, '
u'Shell item list: [Shared Documents Folder (Users Files), '
u'UNKNOWN: 0x00, Alloy Research] '
u'Index: 3 [MRU Value 6]: '
u'Path: {{427865A0-03AF-4F25-82EE-10B6CB1DED3E}}, '
u'Shell item list: [Users Libraries, UNKNOWN: 0x00, UNKNOWN: 0x00] '
u'Index: 4 [MRU Value 5]: '
u'Path: {{24B5C9BB-48B5-47FF-8343-40481DBA1E2B}}, '
u'Shell item list: [My Computer, C:\\, Users, nfury, Documents] '
u'Index: 5 [MRU Value 4]: '
u'Path: {{0B8CFE96-DB69-4D33-8E3C-36EAB4F709E0}}, '
u'Shell item list: [My Computer, C:\\, Users, nfury, Documents, '
u'Alloy Research] '
u'Index: 6 [MRU Value 3]: '
u'Path: {{D4F85F66-003D-4127-BCE9-CAD7A57B2857}}, '
u'Shell item list: [Users Libraries, UNKNOWN: 0x00, UNKNOWN: 0x00] '
u'Index: 7 [MRU Value 0]: Path: iexplore.exe, '
u'Shell item list: [My Computer, P:\\, Application Tools, Firefox 6.0] '
u'Index: 8 [MRU Value 2]: Path: Skype.exe, '
u'Shell item list: [Users Libraries, UNKNOWN: 0x00]').format(key_path)
expected_msg_short = (
u'[\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\'
u'LastVisitedPidl...')
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
if __name__ == '__main__':
unittest.main()
+292
View File
@@ -0,0 +1,292 @@
#!/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 MSIE zone settings plugin."""
from plaso.events import windows_events
from plaso.parsers import winreg
from plaso.parsers.winreg_plugins import interface
__author__ = 'Elizabeth Schweinsberg (beth@bethlogic.net)'
class MsieZoneSettingsPlugin(interface.KeyPlugin):
"""Windows Registry plugin for parsing the MSIE Zones settings."""
NAME = 'winreg_msie_zone'
DESCRIPTION = u'Parser for Internet Explorer zone settings Registry data.'
REG_TYPE = 'NTUSER'
REG_KEYS = [
(u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings'
u'\\Zones'),
(u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings'
u'\\Lockdown_Zones')]
URLS = ['http://support.microsoft.com/kb/182569']
ZONE_NAMES = {
'0': '0 (My Computer)',
'1': '1 (Local Intranet Zone)',
'2': '2 (Trusted sites Zone)',
'3': '3 (Internet Zone)',
'4': '4 (Restricted Sites Zone)',
'5': '5 (Custom)'
}
KNOWN_PERMISSIONS_VALUE_NAMES = [
'1001', '1004', '1200', '1201', '1400', '1402', '1405', '1406', '1407',
'1601', '1604', '1606', '1607', '1608', '1609', '1800', '1802', '1803',
'1804', '1809', '1A04', '2000', '2001', '2004', '2100', '2101', '2102',
'2200', '2201', '2300']
CONTROL_VALUES_PERMISSIONS = {
0x00000000: '0 (Allow)',
0x00000001: '1 (Prompt User)',
0x00000003: '3 (Not Allowed)',
0x00010000: '0x00010000 (Administrator approved)'
}
CONTROL_VALUES_SAFETY = {
0x00010000: '0x00010000 (High safety)',
0x00020000: '0x00020000 (Medium safety)',
0x00030000: '0x00030000 (Low safety)'
}
CONTROL_VALUES_1A00 = {
0x00000000: ('0x00000000 (Automatic logon with current user name and '
'password)'),
0x00010000: '0x00010000 (Prompt for user name and password)',
0x00020000: '0x00020000 (Automatic logon only in Intranet zone)',
0x00030000: '0x00030000 (Anonymous logon)'
}
CONTROL_VALUES_1C00 = {
0x00000000: '0x00000000 (Disable Java)',
0x00010000: '0x00010000 (High safety)',
0x00020000: '0x00020000 (Medium safety)',
0x00030000: '0x00030000 (Low safety)',
0x00800000: '0x00800000 (Custom)'
}
FEATURE_CONTROLS = {
'1200': 'Run ActiveX controls and plug-ins',
'1400': 'Active scripting',
'1001': 'Download signed ActiveX controls',
'1004': 'Download unsigned ActiveX controls',
'1201': 'Initialize and script ActiveX controls not marked as safe',
'1206': 'Allow scripting of IE Web browser control',
'1207': 'Reserved',
'1208': 'Allow previously unused ActiveX controls to run without prompt',
'1209': 'Allow Scriptlets',
'120A': 'Override Per-Site (domain-based) ActiveX restrictions',
'120B': 'Override Per-Site (domain-based) ActiveX restrictions',
'1402': 'Scripting of Java applets',
'1405': 'Script ActiveX controls marked as safe for scripting',
'1406': 'Access data sources across domains',
'1407': 'Allow Programmatic clipboard access',
'1408': 'Reserved',
'1601': 'Submit non-encrypted form data',
'1604': 'Font download',
'1605': 'Run Java',
'1606': 'Userdata persistence',
'1607': 'Navigate sub-frames across different domains',
'1608': 'Allow META REFRESH',
'1609': 'Display mixed content',
'160A': 'Include local directory path when uploading files to a server',
'1800': 'Installation of desktop items',
'1802': 'Drag and drop or copy and paste files',
'1803': 'File Download',
'1804': 'Launching programs and files in an IFRAME',
'1805': 'Launching programs and files in webview',
'1806': 'Launching applications and unsafe files',
'1807': 'Reserved',
'1808': 'Reserved',
'1809': 'Use Pop-up Blocker',
'180A': 'Reserved',
'180B': 'Reserved',
'180C': 'Reserved',
'180D': 'Reserved',
'1A00': 'User Authentication: Logon',
'1A02': 'Allow persistent cookies that are stored on your computer',
'1A03': 'Allow per-session cookies (not stored)',
'1A04': 'Don\'t prompt for client cert selection when no certs exists',
'1A05': 'Allow 3rd party persistent cookies',
'1A06': 'Allow 3rd party session cookies',
'1A10': 'Privacy Settings',
'1C00': 'Java permissions',
'1E05': 'Software channel permissions',
'1F00': 'Reserved',
'2000': 'Binary and script behaviors',
'2001': '.NET: Run components signed with Authenticode',
'2004': '.NET: Run components not signed with Authenticode',
'2100': 'Open files based on content, not file extension',
'2101': 'Web sites in less privileged zone can navigate into this zone',
'2102': ('Allow script initiated windows without size/position '
'constraints'),
'2103': 'Allow status bar updates via script',
'2104': 'Allow websites to open windows without address or status bars',
'2105': 'Allow websites to prompt for information using scripted windows',
'2200': 'Automatic prompting for file downloads',
'2201': 'Automatic prompting for ActiveX controls',
'2300': 'Allow web pages to use restricted protocols for active content',
'2301': 'Use Phishing Filter',
'2400': '.NET: XAML browser applications',
'2401': '.NET: XPS documents',
'2402': '.NET: Loose XAML',
'2500': 'Turn on Protected Mode',
'2600': 'Enable .NET Framework setup',
'{AEBA21FA-782A-4A90-978D-B72164C80120}': 'First Party Cookie',
'{A8A88C49-5EB2-4990-A1A2-0876022C854F}': 'Third Party Cookie'
}
def GetEntries(
self, parser_context, file_entry=None, key=None, registry_type=None,
parser_chain=None, **unused_kwargs):
"""Retrieves information of the Internet Settings Zones values.
The MSIE Feature controls are stored in the Zone specific subkeys in:
Internet Settings\\Zones key
Internet Settings\\Lockdown_Zones key
Args:
parser_context: A parser context object (instance of ParserContext).
file_entry: optional file entry object (instance of dfvfs.FileEntry).
The default is None.
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
text_dict = {}
if key.number_of_values == 0:
error_string = u'Key: {0:s} missing values.'.format(key.path)
parser_context.ProduceParseError(
self.NAME, error_string, file_entry=file_entry)
else:
for value in key.GetValues():
if not value.name:
value_name = '(default)'
else:
value_name = u'{0:s}'.format(value.name)
if value.DataIsString():
value_string = u'[{0:s}] {1:s}'.format(
value.data_type_string, value.data)
elif value.DataIsInteger():
value_string = u'[{0:s}] {1:d}'.format(
value.data_type_string, value.data)
elif value.DataIsMultiString():
value_string = u'[{0:s}] {1:s}'.format(
value.data_type_string, u''.join(value.data))
else:
value_string = u'[{0:s}]'.format(value.data_type_string)
text_dict[value_name] = value_string
# Generate at least one event object for the key.
event_object = windows_events.WindowsRegistryEvent(
key.last_written_timestamp, key.path, text_dict, offset=key.offset,
registry_type=registry_type, urls=self.URLS)
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
if key.number_of_subkeys == 0:
error_string = u'Key: {0:s} missing subkeys.'.format(key.path)
parser_context.ProduceParseError(
self.NAME, error_string, file_entry=file_entry)
return
for zone_key in key.GetSubkeys():
# TODO: these values are stored in the Description value of the
# zone key. This solution will break on zone values that are larger
# than 5.
path = u'{0:s}\\{1:s}'.format(key.path, self.ZONE_NAMES[zone_key.name])
text_dict = {}
# TODO: this plugin currently just dumps the values and does not
# distinguish between what is a feature control or not.
for value in zone_key.GetValues():
# Ignore the default value.
if not value.name:
continue
if value.DataIsString():
value_string = value.data
elif value.DataIsInteger():
if value.name in self.KNOWN_PERMISSIONS_VALUE_NAMES:
value_string = self.CONTROL_VALUES_PERMISSIONS.get(
value.data, u'UNKNOWN')
elif value.name == '1A00':
value_string = self.CONTROL_VALUES_1A00.get(value.data, u'UNKNOWN')
elif value.name == '1C00':
value_string = self.CONTROL_VALUES_1C00.get(value.data, u'UNKNOWN')
elif value.name == '1E05':
value_string = self.CONTROL_VALUES_SAFETY.get(
value.data, u'UNKNOWN')
else:
value_string = u'{0:d}'.format(value.data)
else:
value_string = u'[{0:s}]'.format(value.data_type_string)
if len(value.name) == 4 and value.name != 'Icon':
value_description = self.FEATURE_CONTROLS.get(value.name, 'UNKNOWN')
else:
value_description = self.FEATURE_CONTROLS.get(value.name, '')
if value_description:
feature_control = u'[{0:s}] {1:s}'.format(
value.name, value_description)
else:
feature_control = u'[{0:s}]'.format(value.name)
text_dict[feature_control] = value_string
event_object = windows_events.WindowsRegistryEvent(
zone_key.last_written_timestamp, path, text_dict,
offset=zone_key.offset, registry_type=registry_type,
urls=self.URLS)
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
class MsieZoneSettingsSoftwareZonesPlugin(MsieZoneSettingsPlugin):
"""Parses the Zones key in the Software hive."""
NAME = 'winreg_msie_zone_software'
REG_TYPE = 'SOFTWARE'
REG_KEYS = [
u'\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Zones',
(u'\\Microsoft\\Windows\\CurrentVersion\\Internet Settings'
u'\\Lockdown_Zones'),
(u'\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Internet Settings'
u'\\Zones'),
(u'\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Internet Settings'
u'\\Lockdown_Zones')]
winreg.WinRegistryParser.RegisterPlugins([
MsieZoneSettingsPlugin, MsieZoneSettingsSoftwareZonesPlugin])
@@ -0,0 +1,384 @@
#!/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 MSIE Zone settings Windows Registry plugin."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.lib import timelib_test
from plaso.parsers.winreg_plugins import msie_zones
from plaso.parsers.winreg_plugins import test_lib
class MsieZoneSettingsSoftwareZonesPluginTest(test_lib.RegistryPluginTestCase):
"""Tests for Internet Settings Zones plugin on the Software hive."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = msie_zones.MsieZoneSettingsSoftwareZonesPlugin()
self._test_file = self._GetTestFilePath(['SOFTWARE'])
def testProcessForZone(self):
"""Tests the Process function."""
key_path = u'\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Zones'
winreg_key = self._GetKeyFromFile(self._test_file, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(self._plugin, winreg_key)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 6)
event_object = event_objects[1]
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2011-08-28 21:32:44.937675')
self.assertEquals(event_object.timestamp, expected_timestamp)
regvalue_identifier = u'[1200] Run ActiveX controls and plug-ins'
expected_value = u'0 (Allow)'
self._TestRegvalue(event_object, regvalue_identifier, expected_value)
expected_msg = (
u'[{0:s}\\0 (My Computer)] '
u'[1001] Download signed ActiveX controls: 0 (Allow) '
u'[1004] Download unsigned ActiveX controls: 0 (Allow) '
u'[1200] Run ActiveX controls and plug-ins: 0 (Allow) '
u'[1201] Initialize and script ActiveX controls not marked as safe: 1 '
u'(Prompt User) '
u'[1206] Allow scripting of IE Web browser control: 0 '
u'[1207] Reserved: 0 '
u'[1208] Allow previously unused ActiveX controls to run without '
u'prompt: 0 '
u'[1209] Allow Scriptlets: 0 '
u'[120A] Override Per-Site (domain-based) ActiveX restrictions: 0 '
u'[120B] Override Per-Site (domain-based) ActiveX restrictions: 0 '
u'[1400] Active scripting: 0 (Allow) '
u'[1402] Scripting of Java applets: 0 (Allow) '
u'[1405] Script ActiveX controls marked as safe for scripting: 0 '
u'(Allow) '
u'[1406] Access data sources across domains: 0 (Allow) '
u'[1407] Allow Programmatic clipboard access: 0 (Allow) '
u'[1408] Reserved: 0 '
u'[1409] UNKNOWN: 3 '
u'[1601] Submit non-encrypted form data: 0 (Allow) '
u'[1604] Font download: 0 (Allow) '
u'[1605] Run Java: 0 '
u'[1606] Userdata persistence: 0 (Allow) '
u'[1607] Navigate sub-frames across different domains: 0 (Allow) '
u'[1608] Allow META REFRESH: 0 (Allow) '
u'[1609] Display mixed content: 1 (Prompt User) '
u'[160A] Include local directory path when uploading files to a '
u'server: 0 '
u'[1802] Drag and drop or copy and paste files: 0 (Allow) '
u'[1803] File Download: 0 (Allow) '
u'[1804] Launching programs and files in an IFRAME: 0 (Allow) '
u'[1805] Launching programs and files in webview: 0 '
u'[1806] Launching applications and unsafe files: 0 '
u'[1807] Reserved: 0 '
u'[1808] Reserved: 0 '
u'[1809] Use Pop-up Blocker: 3 (Not Allowed) '
u'[180A] Reserved: 0 '
u'[180C] Reserved: 0 '
u'[180D] Reserved: 0 '
u'[180E] UNKNOWN: 0 '
u'[180F] UNKNOWN: 0 '
u'[1A00] User Authentication: Logon: 0x00000000 (Automatic logon with '
u'current user name and password) '
u'[1A02] Allow persistent cookies that are stored on your computer: 0 '
u'[1A03] Allow per-session cookies (not stored): 0 '
u'[1A04] Don\'t prompt for client cert selection when no certs exists: '
u'0 (Allow) '
u'[1A05] Allow 3rd party persistent cookies: 0 '
u'[1A06] Allow 3rd party session cookies: 0 '
u'[1A10] Privacy Settings: 0 '
u'[1C00] Java permissions: 0x00020000 (Medium safety) '
u'[2000] Binary and script behaviors: 0 (Allow) '
u'[2001] .NET: Run components signed with Authenticode: '
u'3 (Not Allowed) '
u'[2004] .NET: Run components not signed with Authenticode: '
u'3 (Not Allowed) '
u'[2005] UNKNOWN: 0 '
u'[2007] UNKNOWN: 3 '
u'[2100] Open files based on content, not file extension: 0 (Allow) '
u'[2101] Web sites in less privileged zone can navigate into this '
u'zone: 3 (Not Allowed) '
u'[2102] Allow script initiated windows without size/position '
u'constraints: 0 (Allow) '
u'[2103] Allow status bar updates via script: 0 '
u'[2104] Allow websites to open windows without address or status '
u'bars: 0 '
u'[2105] Allow websites to prompt for information using scripted '
u'windows: 0 '
u'[2106] UNKNOWN: 0 '
u'[2107] UNKNOWN: 0 '
u'[2200] Automatic prompting for file downloads: 0 (Allow) '
u'[2201] Automatic prompting for ActiveX controls: 0 (Allow) '
u'[2300] Allow web pages to use restricted protocols for active '
u'content: 1 (Prompt User) '
u'[2301] Use Phishing Filter: 3 '
u'[2400] .NET: XAML browser applications: 0 '
u'[2401] .NET: XPS documents: 0 '
u'[2402] .NET: Loose XAML: 0 '
u'[2500] Turn on Protected Mode: 3 '
u'[2600] Enable .NET Framework setup: 0 '
u'[2700] UNKNOWN: 3 '
u'[2701] UNKNOWN: 0 '
u'[2702] UNKNOWN: 3 '
u'[2703] UNKNOWN: 3 '
u'[2708] UNKNOWN: 0 '
u'[2709] UNKNOWN: 0 '
u'[CurrentLevel]: 0 '
u'[Description]: Your computer '
u'[DisplayName]: Computer '
u'[Flags]: 33 '
u'[Icon]: shell32.dll#0016 '
u'[LowIcon]: inetcpl.cpl#005422 '
u'[PMDisplayName]: Computer '
u'[Protected Mode]').format(key_path)
expected_msg_short = u'[{0:s}\\0 (My Computer)] [...'.format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
def testProcessForLockDown(self):
"""Tests the Process function for the lockdown zone key."""
key_path = (
u'\\Microsoft\\Windows\\CurrentVersion\\Internet Settings'
u'\\Lockdown_Zones')
winreg_key = self._GetKeyFromFile(self._test_file, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(self._plugin, winreg_key)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 6)
event_object = event_objects[1]
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2011-08-28 21:32:44.937675')
self.assertEquals(event_object.timestamp, expected_timestamp)
regvalue_identifier = u'[1200] Run ActiveX controls and plug-ins'
expected_value = u'3 (Not Allowed)'
self._TestRegvalue(event_object, regvalue_identifier, expected_value)
expected_msg = (
u'[{0:s}\\0 (My Computer)] '
u'[1001] Download signed ActiveX controls: 1 (Prompt User) '
u'[1004] Download unsigned ActiveX controls: 3 (Not Allowed) '
u'[1200] Run ActiveX controls and plug-ins: 3 (Not Allowed) '
u'[1201] Initialize and script ActiveX controls not marked as safe: 3 '
u'(Not Allowed) '
u'[1206] Allow scripting of IE Web browser control: 0 '
u'[1207] Reserved: 3 '
u'[1208] Allow previously unused ActiveX controls to run without '
u'prompt: 3 '
u'[1209] Allow Scriptlets: 3 '
u'[120A] Override Per-Site (domain-based) ActiveX restrictions: 3 '
u'[120B] Override Per-Site (domain-based) ActiveX restrictions: 0 '
u'[1400] Active scripting: 1 (Prompt User) '
u'[1402] Scripting of Java applets: 0 (Allow) '
u'[1405] Script ActiveX controls marked as safe for scripting: 0 '
u'(Allow) '
u'[1406] Access data sources across domains: 0 (Allow) '
u'[1407] Allow Programmatic clipboard access: 1 (Prompt User) '
u'[1408] Reserved: 3 '
u'[1409] UNKNOWN: 3 '
u'[1601] Submit non-encrypted form data: 0 (Allow) '
u'[1604] Font download: 0 (Allow) '
u'[1605] Run Java: 0 '
u'[1606] Userdata persistence: 0 (Allow) '
u'[1607] Navigate sub-frames across different domains: 0 (Allow) '
u'[1608] Allow META REFRESH: 0 (Allow) '
u'[1609] Display mixed content: 1 (Prompt User) '
u'[160A] Include local directory path when uploading files to a '
u'server: 0 '
u'[1802] Drag and drop or copy and paste files: 0 (Allow) '
u'[1803] File Download: 0 (Allow) '
u'[1804] Launching programs and files in an IFRAME: 0 (Allow) '
u'[1805] Launching programs and files in webview: 0 '
u'[1806] Launching applications and unsafe files: 0 '
u'[1807] Reserved: 0 '
u'[1808] Reserved: 0 '
u'[1809] Use Pop-up Blocker: 3 (Not Allowed) '
u'[180A] Reserved: 0 '
u'[180C] Reserved: 0 '
u'[180D] Reserved: 0 '
u'[180E] UNKNOWN: 0 '
u'[180F] UNKNOWN: 0 '
u'[1A00] User Authentication: Logon: 0x00000000 (Automatic logon with '
u'current user name and password) '
u'[1A02] Allow persistent cookies that are stored on your computer: 0 '
u'[1A03] Allow per-session cookies (not stored): 0 '
u'[1A04] Don\'t prompt for client cert selection when no certs exists: '
u'3 (Not Allowed) '
u'[1A05] Allow 3rd party persistent cookies: 0 '
u'[1A06] Allow 3rd party session cookies: 0 '
u'[1A10] Privacy Settings: 0 '
u'[1C00] Java permissions: 0x00000000 (Disable Java) '
u'[2000] Binary and script behaviors: 0x00010000 '
u'(Administrator approved) '
u'[2005] UNKNOWN: 3 '
u'[2100] Open files based on content, not file extension: 3 '
u'(Not Allowed) '
u'[2101] Web sites in less privileged zone can navigate into this '
u'zone: 3 (Not Allowed) '
u'[2102] Allow script initiated windows without size/position '
u'constraints: '
u'3 (Not Allowed) '
u'[2103] Allow status bar updates via script: 3 '
u'[2104] Allow websites to open windows without address or status '
u'bars: 3 '
u'[2105] Allow websites to prompt for information using scripted '
u'windows: 3 '
u'[2106] UNKNOWN: 3 '
u'[2107] UNKNOWN: 3 '
u'[2200] Automatic prompting for file downloads: 3 (Not Allowed) '
u'[2201] Automatic prompting for ActiveX controls: 3 (Not Allowed) '
u'[2301] Use Phishing Filter: 3 '
u'[2400] .NET: XAML browser applications: 0 '
u'[2401] .NET: XPS documents: 0 '
u'[2402] .NET: Loose XAML: 0 '
u'[2500] Turn on Protected Mode: 3 '
u'[2600] Enable .NET Framework setup: 0 '
u'[2700] UNKNOWN: 3 '
u'[2701] UNKNOWN: 3 '
u'[2702] UNKNOWN: 3 '
u'[2703] UNKNOWN: 3 '
u'[2708] UNKNOWN: 0 '
u'[2709] UNKNOWN: 0 '
u'[CurrentLevel]: 0 '
u'[Description]: Your computer '
u'[DisplayName]: Computer '
u'[Flags]: 33 '
u'[Icon]: shell32.dll#0016 '
u'[LowIcon]: inetcpl.cpl#005422 '
u'[PMDisplayName]: Computer '
u'[Protected Mode]').format(key_path)
expected_msg_short = u'[{0:s}\\0 (My Com...'.format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
class MsieZoneSettingsUserZonesPluginTest(test_lib.RegistryPluginTestCase):
"""Tests for Internet Settings Zones plugin on the User hive."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = msie_zones.MsieZoneSettingsPlugin()
self._test_file = self._GetTestFilePath(['NTUSER-WIN7.DAT'])
def testProcessForZone(self):
"""Tests the Process function."""
key_path = (
u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings'
u'\\Zones')
winreg_key = self._GetKeyFromFile(self._test_file, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(self._plugin, winreg_key)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 6)
event_object = event_objects[1]
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2011-09-16 21:12:40.145514')
self.assertEquals(event_object.timestamp, expected_timestamp)
regvalue_identifier = u'[1200] Run ActiveX controls and plug-ins'
expected_value = u'0 (Allow)'
self._TestRegvalue(event_object, regvalue_identifier, expected_value)
expected_msg = (
u'[{0:s}\\0 (My Computer)] '
u'[1200] Run ActiveX controls and plug-ins: 0 (Allow) '
u'[1400] Active scripting: 0 (Allow) '
u'[2001] .NET: Run components signed with Authenticode: 3 (Not '
u'Allowed) '
u'[2004] .NET: Run components not signed with Authenticode: 3 (Not '
u'Allowed) '
u'[2007] UNKNOWN: 3 '
u'[CurrentLevel]: 0 '
u'[Description]: Your computer '
u'[DisplayName]: Computer '
u'[Flags]: 33 [Icon]: shell32.dll#0016 '
u'[LowIcon]: inetcpl.cpl#005422 '
u'[PMDisplayName]: Computer '
u'[Protected Mode]').format(key_path)
expected_msg_short = u'[{0:s}\\0 (My Com...'.format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
def testProcessForLockDown(self):
"""Tests the Process function."""
key_path = (
u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings'
u'\\Lockdown_Zones')
winreg_key = self._GetKeyFromFile(self._test_file, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(self._plugin, winreg_key)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 6)
event_object = event_objects[1]
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2011-09-16 21:12:40.145514')
self.assertEquals(event_object.timestamp, expected_timestamp)
regvalue_identifier = u'[1200] Run ActiveX controls and plug-ins'
expected_value = u'3 (Not Allowed)'
self._TestRegvalue(event_object, regvalue_identifier, expected_value)
expected_msg = (
u'[{0:s}\\0 (My Computer)] '
u'[1200] Run ActiveX controls and plug-ins: 3 (Not Allowed) '
u'[1400] Active scripting: 1 (Prompt User) '
u'[CurrentLevel]: 0 '
u'[Description]: Your computer '
u'[DisplayName]: Computer '
u'[Flags]: 33 '
u'[Icon]: shell32.dll#0016 '
u'[LowIcon]: inetcpl.cpl#005422 '
u'[PMDisplayName]: Computer '
u'[Protected Mode]').format(key_path)
expected_msg_short = u'[{0:s}\\...'.format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
if __name__ == '__main__':
unittest.main()
+116
View File
@@ -0,0 +1,116 @@
#!/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 a parser for MS Office MRUs for Plaso."""
import logging
import re
from plaso.events import windows_events
from plaso.lib import timelib
from plaso.parsers import winreg
from plaso.parsers.winreg_plugins import interface
__author__ = 'David Nides (david.nides@gmail.com)'
class OfficeMRUPlugin(interface.KeyPlugin):
"""Plugin that parses Microsoft Office MRU keys."""
NAME = 'winreg_office_mru'
DESCRIPTION = u'Parser for Microsoft Office MRU Registry data.'
REG_TYPE = 'NTUSER'
REG_KEYS = [
u'\\Software\\Microsoft\\Office\\14.0\\Word\\Place MRU',
u'\\Software\\Microsoft\\Office\\14.0\\Access\\File MRU',
u'\\Software\\Microsoft\\Office\\14.0\\Access\\Place MRU',
u'\\Software\\Microsoft\\Office\\14.0\\PowerPoint\\File MRU',
u'\\Software\\Microsoft\\Office\\14.0\\PowerPoint\\Place MRU',
u'\\Software\\Microsoft\\Office\\14.0\\Excel\\File MRU',
u'\\Software\\Microsoft\\Office\\14.0\\Excel\\Place MRU',
u'\\Software\\Microsoft\\Office\\14.0\\Word\\File MRU']
_RE_VALUE_NAME = re.compile(r'^Item [0-9]+$', re.I)
# The Office 12 item MRU is formatted as:
# [F00000000][T%FILETIME%]*\\%FILENAME%
# The Office 14 item MRU is formatted as:
# [F00000000][T%FILETIME%][O00000000]*%FILENAME%
_RE_VALUE_DATA = re.compile(r'\[F00000000\]\[T([0-9A-Z]+)\].*\*[\\]?(.*)')
def GetEntries(
self, parser_context, key=None, registry_type=None, file_entry=None,
parser_chain=None, **unused_kwargs):
"""Collect Values under Office 2010 MRUs and return events for each one.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
# TODO: Test other Office versions to make sure this plugin is applicable.
for value in key.GetValues():
# Ignore any value not in the form: 'Item [0-9]+'.
if not value.name or not self._RE_VALUE_NAME.search(value.name):
continue
# Ignore any value that is empty or that does not contain a string.
if not value.data or not value.DataIsString():
continue
values = self._RE_VALUE_DATA.findall(value.data)
# Values will contain a list containing a tuple containing 2 values.
if len(values) != 1 or len(values[0]) != 2:
continue
try:
filetime = int(values[0][0], 16)
except ValueError:
logging.warning('Unable to convert filetime string to an integer.')
filetime = 0
# TODO: why this behavior? Only the first Item is stored with its
# timestamp. Shouldn't this be: Store all the Item # values with
# their timestamp and store the entire MRU as one event with the
# registry key last written time?
if value.name == 'Item 1':
timestamp = timelib.Timestamp.FromFiletime(filetime)
else:
timestamp = 0
text_dict = {}
text_dict[value.name] = value.data
event_object = windows_events.WindowsRegistryEvent(
timestamp, key.path, text_dict, offset=key.offset,
registry_type=registry_type,
source_append=': Microsoft Office MRU')
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
winreg.WinRegistryParser.RegisterPlugin(OfficeMRUPlugin)
@@ -0,0 +1,76 @@
#!/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 Microsoft Office MRUs Windows Registry plugin."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.lib import timelib_test
from plaso.parsers.winreg_plugins import officemru
from plaso.parsers.winreg_plugins import test_lib
__author__ = 'David Nides (david.nides@gmail.com)'
class OfficeMRUPluginTest(test_lib.RegistryPluginTestCase):
"""Tests for the Microsoft Office MRUs Windows Registry plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = officemru.OfficeMRUPlugin()
def testProcess(self):
"""Tests the Process function."""
test_file_entry = self._GetTestFileEntryFromPath(['NTUSER-WIN7.DAT'])
key_path = u'\\Software\\Microsoft\\Office\\14.0\\Word\\File MRU'
winreg_key = self._GetKeyFromFileEntry(test_file_entry, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(
self._plugin, winreg_key, file_entry=test_file_entry)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 5)
event_object = event_objects[0]
self.assertEquals(event_object.pathspec, test_file_entry.path_spec)
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2012-03-13 18:27:15.083')
self.assertEquals(event_object.timestamp, expected_timestamp)
regvalue_identifier = u'Item 1'
expected_value = (
u'[F00000000][T01CD0146EA1EADB0][O00000000]*'
u'C:\\Users\\nfury\\Documents\\StarFury\\StarFury\\'
u'SA-23E Mitchell-Hyundyne Starfury.docx')
self._TestRegvalue(event_object, regvalue_identifier, expected_value)
expected_msg = u'[{0:s}] {1:s}: {2:s}'.format(
key_path, regvalue_identifier, expected_value)
expected_msg_short = u'[{0:s}] {1:s}: [F00000000][T01CD0146...'.format(
key_path, regvalue_identifier)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
if __name__ == '__main__':
unittest.main()
+97
View File
@@ -0,0 +1,97 @@
#!/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 an Outlook Registry parser."""
from plaso.events import windows_events
from plaso.parsers import winreg
from plaso.parsers.winreg_plugins import interface
__author__ = 'David Nides (david.nides@gmail.com)'
class OutlookSearchMRUPlugin(interface.KeyPlugin):
"""Windows Registry plugin parsing Outlook Search MRU keys."""
NAME = 'winreg_outlook_mru'
DESCRIPTION = u'Parser for Microsoft Outlook search MRU Registry data.'
REG_KEYS = [
u'\\Software\\Microsoft\\Office\\15.0\\Outlook\\Search',
u'\\Software\\Microsoft\\Office\\14.0\\Outlook\\Search']
# TODO: The catalog for Office 2013 (15.0) contains binary values not
# dword values. Check if Office 2007 and 2010 have the same. Re-enable the
# plug-ins once confirmed and OutlookSearchMRUPlugin has been extended to
# handle the binary data or create a OutlookSearchCatalogMRUPlugin.
# Registry keys for:
# MS Outlook 2007 Search Catalog:
# '\\Software\\Microsoft\\Office\\12.0\\Outlook\\Catalog'
# MS Outlook 2010 Search Catalog:
# '\\Software\\Microsoft\\Office\\14.0\\Outlook\\Search\\Catalog'
# MS Outlook 2013 Search Catalog:
# '\\Software\\Microsoft\\Office\\15.0\\Outlook\\Search\\Catalog'
REG_TYPE = 'NTUSER'
def GetEntries(
self, parser_context, key=None, registry_type=None, file_entry=None,
parser_chain=None, **unused_kwargs):
"""Collect the values under Outlook and return event for each one.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
value_index = 0
for value in key.GetValues():
# Ignore the default value.
if not value.name:
continue
# Ignore any value that is empty or that does not contain an integer.
if not value.data or not value.DataIsInteger():
continue
# TODO: change this 32-bit integer into something meaningful, for now
# the value name is the most interesting part.
text_dict = {}
text_dict[value.name] = '0x{0:08x}'.format(value.data)
if value_index == 0:
timestamp = key.last_written_timestamp
else:
timestamp = 0
event_object = windows_events.WindowsRegistryEvent(
timestamp, key.path, text_dict, offset=key.offset,
registry_type=registry_type,
source_append=': PST Paths')
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
value_index += 1
winreg.WinRegistryParser.RegisterPlugin(OutlookSearchMRUPlugin)
@@ -0,0 +1,103 @@
#!/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 Outlook Windows Registry plugins."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.parsers.winreg_plugins import outlook
from plaso.parsers.winreg_plugins import test_lib
from plaso.winreg import test_lib as winreg_test_lib
class MSOutlook2013SearchMRUPluginTest(test_lib.RegistryPluginTestCase):
"""Tests for the Outlook Search MRU Windows Registry plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = outlook.OutlookSearchMRUPlugin()
def testProcess(self):
"""Tests the Process function."""
key_path = u'\\Software\\Microsoft\\Office\\15.0\\Outlook\\Search'
values = []
values.append(winreg_test_lib.TestRegValue(
('C:\\Users\\username\\AppData\\Local\\Microsoft\\Outlook\\'
'username@example.com.ost'), '\xcf\x2b\x37\x00',
winreg_test_lib.TestRegValue.REG_DWORD, offset=1892))
winreg_key = winreg_test_lib.TestRegKey(
key_path, 1346145829002031, values, 1456)
event_queue_consumer = self._ParseKeyWithPlugin(self._plugin, winreg_key)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
expected_msg = (
u'[{0:s}] '
u'C:\\Users\\username\\AppData\\Local\\Microsoft\\Outlook\\'
u'username@example.com.ost: 0x00372bcf').format(key_path)
expected_msg_short = u'[{0:s}] C:\\Users\\username\\AppData\\Lo...'.format(
key_path)
self.assertEquals(len(event_objects), 1)
event_object = event_objects[0]
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
self.assertEquals(event_object.timestamp, 1346145829002031)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
# TODO: The catalog for Office 2013 (15.0) contains binary values not
# dword values. Check if Office 2007 and 2010 have the same. Re-enable the
# plug-ins once confirmed and OutlookSearchMRUPlugin has been extended to
# handle the binary data or create a OutlookSearchCatalogMRUPlugin.
# class MSOutlook2013SearchCatalogMRUPluginTest(unittest.TestCase):
# """Tests for the Outlook Search Catalog MRU Windows Registry plugin."""
#
# def setUp(self):
# """Sets up the needed objects used throughout the test."""
# self._plugin = outlook.MSOutlook2013SearchCatalogMRUPlugin()
#
# def testProcess(self):
# """Tests the Process function."""
# key_path = (
# u'\\Software\\Microsoft\\Office\\15.0\\Outlook\\Search\\Catalog')
# values = []
#
# values.append(winreg_test_lib.TestRegValue(
# ('C:\\Users\\username\\AppData\\Local\\Microsoft\\Outlook\\'
# 'username@example.com.ost'), '\x94\x01\x00\x00\x00\x00',
# winreg_test_lib.TestRegValue.REG_BINARY, offset=827))
#
# winreg_key = winreg_test_lib.TestRegKey(
# key_path, 1346145829002031, values, 3421)
#
# # TODO: add test for Catalog key.
if __name__ == '__main__':
unittest.main()
+90
View File
@@ -0,0 +1,90 @@
#!/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 Run/RunOnce Key plugins for Plaso."""
from plaso.events import windows_events
from plaso.parsers import winreg
from plaso.parsers.winreg_plugins import interface
class RunUserPlugin(interface.KeyPlugin):
"""Windows Registry plugin for parsing user specific auto runs."""
NAME = 'winreg_run'
DESCRIPTION = u'Parser for run and run once Registry data.'
REG_TYPE = 'NTUSER'
REG_KEYS = [
u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Run',
u'\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce']
URLS = ['http://msdn.microsoft.com/en-us/library/aa376977(v=vs.85).aspx']
def GetEntries(
self, parser_context, key=None, registry_type=None, file_entry=None,
parser_chain=None, **unused_kwargs):
"""Collect the Values under the Run Key and return an event for each one.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
for value in key.GetValues():
# Ignore the default value.
if not value.name:
continue
# Ignore any value that is empty or that does not contain a string.
if not value.data or not value.DataIsString():
continue
text_dict = {}
text_dict[value.name] = value.data
event_object = windows_events.WindowsRegistryEvent(
key.last_written_timestamp, key.path, text_dict, offset=key.offset,
urls=self.URLS, registry_type=registry_type,
source_append=': Run Key')
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
class RunSoftwarePlugin(RunUserPlugin):
"""Windows Registry plugin for parsing system wide auto runs."""
NAME = 'winreg_run_software'
REG_TYPE = 'SOFTWARE'
REG_KEYS = [
u'\\Microsoft\\Windows\\CurrentVersion\\Run',
u'\\Microsoft\\Windows\\CurrentVersion\\RunOnce',
u'\\Microsoft\\Windows\\CurrentVersion\\RunOnce\\Setup',
u'\\Microsoft\\Windows\\CurrentVersion\\RunServices',
u'\\Microsoft\\Windows\\CurrentVersion\\RunServicesOnce']
winreg.WinRegistryParser.RegisterPlugins([
RunUserPlugin, RunSoftwarePlugin])
+179
View File
@@ -0,0 +1,179 @@
#!/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 Run Windows Registry plugin."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.parsers.winreg_plugins import run
from plaso.parsers.winreg_plugins import test_lib
class RunNtuserPlugintest(test_lib.RegistryPluginTestCase):
"""Tests for the Run Windows Registry plugin on the User hive."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = run.RunUserPlugin()
def testProcess(self):
"""Tests the Process function."""
test_file_entry = self._GetTestFileEntryFromPath(['NTUSER-RunTests.DAT'])
key_path = u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Run'
winreg_key = self._GetKeyFromFileEntry(test_file_entry, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(
self._plugin, winreg_key, file_entry=test_file_entry)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 1)
event_object = event_objects[0]
self.assertEquals(event_object.pathspec, test_file_entry.path_spec)
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
# Timestamp is: 2012-04-05T17:03:53.992061+00:00
self.assertEquals(event_object.timestamp, 1333645433992061)
expected_msg = (
u'[{0:s}] Sidebar: %ProgramFiles%\\Windows Sidebar\\Sidebar.exe '
u'/autoRun').format(key_path)
expected_msg_short = (
u'[{0:s}] Sidebar: %ProgramFiles%\\Wind...').format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
class RunOnceNtuserPlugintest(test_lib.RegistryPluginTestCase):
"""Tests for the RunOnce Windows Registry plugin on the User hive."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = run.RunUserPlugin()
def testProcess(self):
"""Tests the Process function."""
test_file_entry = self._GetTestFileEntryFromPath(['NTUSER-RunTests.DAT'])
key_path = u'\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce'
winreg_key = self._GetKeyFromFileEntry(test_file_entry, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(
self._plugin, winreg_key, file_entry=test_file_entry)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 1)
event_object = event_objects[0]
self.assertEquals(event_object.pathspec, test_file_entry.path_spec)
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
# Timestamp is: 2012-04-05T17:03:53.992061+00:00
self.assertEquals(event_object.timestamp, 1333645433992061)
expected_msg = (
u'[{0:s}] mctadmin: C:\\Windows\\System32\\mctadmin.exe').format(
key_path)
expected_msg_short = (
u'[{0:s}] mctadmin: C:\\Windows\\Sys...').format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
class RunSoftwarePluginTest(test_lib.RegistryPluginTestCase):
"""Tests for the Run Windows Registry plugin on the Software hive."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = run.RunSoftwarePlugin()
def testProcess(self):
"""Tests the Process function."""
test_file_entry = self._GetTestFileEntryFromPath(['SOFTWARE-RunTests'])
key_path = u'\\Microsoft\\Windows\\CurrentVersion\\Run'
winreg_key = self._GetKeyFromFileEntry(test_file_entry, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(
self._plugin, winreg_key, file_entry=test_file_entry)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 3)
event_object = event_objects[0]
self.assertEquals(event_object.pathspec, test_file_entry.path_spec)
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
# Timestamp is: 2011-09-16T20:57:09.067575+00:00
self.assertEquals(event_object.timestamp, 1316206629067575)
expected_msg = (
u'[{0:s}] VMware Tools: \"C:\\Program Files\\VMware\\VMware Tools'
u'\\VMwareTray.exe\"').format(key_path)
expected_msg_short = (
u'[{0:s}] VMware Tools: \"C:\\Program Files\\VMwar...').format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
self.assertEquals(event_objects[1].timestamp, 1316206629067575)
class RunOnceSoftwarePluginTest(test_lib.RegistryPluginTestCase):
"""Tests for the RunOnce Windows Registry plugin on the Software hive."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = run.RunSoftwarePlugin()
def testProcess(self):
"""Tests the Process function."""
test_file_entry = self._GetTestFileEntryFromPath(['SOFTWARE-RunTests'])
key_path = u'\\Microsoft\\Windows\\CurrentVersion\\RunOnce'
winreg_key = self._GetKeyFromFileEntry(test_file_entry, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(
self._plugin, winreg_key, file_entry=test_file_entry)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 1)
event_object = event_objects[0]
self.assertEquals(event_object.pathspec, test_file_entry.path_spec)
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
# Timestamp is: 2012-04-06T14:07:27.750000+00:00
self.assertEquals(event_object.timestamp, 1333721247750000)
expected_msg = (
u'[{0:s}] *WerKernelReporting: %SYSTEMROOT%\\SYSTEM32\\WerFault.exe '
u'-k -rq').format(key_path)
expected_msg_short = (
u'[{0:s}] *WerKernelReporting: %SYSTEMROOT%...').format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
if __name__ == '__main__':
unittest.main()
+191
View File
@@ -0,0 +1,191 @@
#!/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.
"""This file contains the SAM Users & Names key plugin."""
import construct
import logging
from plaso.events import windows_events
from plaso.lib import binary
from plaso.lib import eventdata
from plaso.lib import timelib
from plaso.parsers import winreg
from plaso.parsers.winreg_plugins import interface
__author__ = 'Preston Miller, dpmforensics.com, github.com/prmiller91'
class UsersPlugin(interface.KeyPlugin):
"""SAM Windows Registry plugin for Users Account information."""
NAME = 'winreg_sam_users'
DESCRIPTION = u'Parser for SAM Users and Names Registry keys.'
REG_KEYS = [u'\\SAM\\Domains\\Account\\Users']
REG_TYPE = 'SAM'
F_VALUE_STRUCT = construct.Struct(
'f_struct', construct.Padding(8), construct.ULInt64('last_login'),
construct.Padding(8), construct.ULInt64('password_reset'),
construct.Padding(16), construct.ULInt16('rid'), construct.Padding(16),
construct.ULInt8('login_count'))
V_VALUE_HEADER = construct.Struct(
'v_header', construct.Array(11, construct.ULInt32('values')))
V_VALUE_HEADER_SIZE = 0xCC
def GetEntries(
self, parser_context, key=None, registry_type=None, file_entry=None,
parser_chain=None, **unused_kwargs):
"""Collect data from Users and Names and produce event objects.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
name_dict = {}
name_key = key.GetSubkey('Names')
if not name_key:
logging.error(u'Unable to locate Names key.')
return
values = [(v.name, v.last_written_timestamp) for v in name_key.GetSubkeys()]
name_dict = dict(values)
for subkey in key.GetSubkeys():
text_dict = {}
if subkey.name == 'Names':
continue
text_dict['user_guid'] = subkey.name
parsed_v_value = self._ParseVValue(subkey)
if not parsed_v_value:
logging.error(u'V Value was not succesfully parsed by ParseVValue.')
return
username = parsed_v_value[0]
full_name = parsed_v_value[1]
comments = parsed_v_value[2]
if username:
text_dict['username'] = username
if full_name:
text_dict['full_name'] = full_name
if comments:
text_dict['comments'] = comments
if name_dict:
account_create_time = name_dict.get(text_dict.get('username'), 0)
else:
account_create_time = 0
f_data = self._ParseFValue(subkey)
last_login_time = timelib.Timestamp.FromFiletime(f_data.last_login)
password_reset_time = timelib.Timestamp.FromFiletime(
f_data.password_reset)
text_dict['account_rid'] = f_data.rid
text_dict['login_count'] = f_data.login_count
if account_create_time > 0:
event_object = windows_events.WindowsRegistryEvent(
account_create_time, key.path, text_dict,
usage=eventdata.EventTimestamp.ACCOUNT_CREATED,
offset=key.offset, registry_type=registry_type,
source_append=u'User Account Information')
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
if last_login_time > 0:
event_object = windows_events.WindowsRegistryEvent(
last_login_time, key.path, text_dict,
usage=eventdata.EventTimestamp.LAST_LOGIN_TIME,
offset=key.offset,
registry_type=registry_type,
source_append=u'User Account Information')
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
if password_reset_time > 0:
event_object = windows_events.WindowsRegistryEvent(
password_reset_time, key.path, text_dict,
usage=eventdata.EventTimestamp.LAST_PASSWORD_RESET,
offset=key.offset, registry_type=registry_type,
source_append=u'User Account Information')
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
def _ParseVValue(self, key):
"""Parses V value and returns name, fullname, and comments data.
Args:
key: Registry key (instance of winreg.WinRegKey).
Returns:
name: Name data parsed with name start and length values.
fullname: Fullname data parsed with fullname start and length values.
comments: Comments data parsed with comments start and length values.
"""
v_value = key.GetValue('V')
if not v_value:
logging.error(u'Unable to locate V Value in key.')
return
try:
structure = self.V_VALUE_HEADER.parse(v_value.data)
except construct.FieldError as exception:
logging.error(
u'Unable to extract V value header data: {:s}'.format(exception))
return
name_offset = structure.values()[0][3] + self.V_VALUE_HEADER_SIZE
full_name_offset = structure.values()[0][6] + self.V_VALUE_HEADER_SIZE
comments_offset = structure.values()[0][9] + self.V_VALUE_HEADER_SIZE
name_raw = v_value.data[
name_offset:name_offset + structure.values()[0][4]]
full_name_raw = v_value.data[
full_name_offset:full_name_offset + structure.values()[0][7]]
comments_raw = v_value.data[
comments_offset:comments_offset + structure.values()[0][10]]
name = binary.ReadUtf16(name_raw)
full_name = binary.ReadUtf16(full_name_raw)
comments = binary.ReadUtf16(comments_raw)
return name, full_name, comments
def _ParseFValue(self, key):
"""Parses F value and returns parsed F data construct object.
Args:
key: Registry key (instance of winreg.WinRegKey).
Returns:
f_data: Construct parsed F value containing rid, login count,
and timestamp information.
"""
f_value = key.GetValue('F')
if not f_value:
logging.error(u'Unable to locate F Value in key.')
return
try:
f_data = self.F_VALUE_STRUCT.parse(f_value.data)
except construct.FieldError as exception:
logging.error(
u'Unable to extract F value data: {:s}'.format(exception))
return
return f_data
winreg.WinRegistryParser.RegisterPlugin(UsersPlugin)
@@ -0,0 +1,80 @@
#!/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.
"""Tests for the Users key plugin."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.lib import event
from plaso.lib import timelib_test
from plaso.parsers.winreg_plugins import test_lib
from plaso.parsers.winreg_plugins import sam_users
__author__ = 'Preston Miller, dpmforensics.com, github.com/prmiller91'
class UsersPluginTest(test_lib.RegistryPluginTestCase):
"""Tests for the SAM Users key plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = sam_users.UsersPlugin()
def testProcess(self):
"""Tests the Process function."""
test_file = self._GetTestFilePath(['SAM'])
key_path = u'\\SAM\\Domains\\Account\\Users'
winreg_key = self._GetKeyFromFile(test_file, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(
self._plugin, winreg_key)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 7)
event_object = event_objects[0]
self._TestRegvalue(event_object, u'account_rid', 500)
self._TestRegvalue(event_object, u'login_count', 6)
self._TestRegvalue(event_object, u'user_guid', u'000001F4')
self._TestRegvalue(event_object, u'username', u'Administrator')
expected_msg = (
u'[\\SAM\\Domains\\Account\\Users] '
u'account_rid: 500 '
u'comments: Built-in account for administering the computer/domain '
u'login_count: 6 '
u'user_guid: 000001F4 '
u'username: Administrator')
# Match UTC timestamp.
time = long(timelib_test.CopyStringToTimestamp(
u'2014-09-24 03:36:06.358837'))
self.assertEquals(event_object.timestamp, time)
expected_msg_short = (
u'[\\SAM\\Domains\\Account\\Users] '
u'account_rid: 500 '
u'comments: Built-in account for ...')
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
if __name__ == '__main__':
unittest.main()
+98
View File
@@ -0,0 +1,98 @@
#!/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.
"""Plug-in to format the Services and Drivers key with Start and Type values."""
from plaso.events import windows_events
from plaso.parsers import winreg
from plaso.parsers.winreg_plugins import interface
class ServicesPlugin(interface.ValuePlugin):
"""Plug-in to format the Services and Drivers keys having Type and Start."""
NAME = 'winreg_services'
DESCRIPTION = u'Parser for services and drivers Registry data.'
REG_VALUES = frozenset(['Type', 'Start'])
REG_TYPE = 'SYSTEM'
URLS = ['http://support.microsoft.com/kb/103000']
def GetServiceDll(self, key):
"""Get the Service DLL for a service, if it exists.
Checks for a ServiceDLL for in the Parameters subkey of a service key in
the Registry.
Args:
key: A Windows Registry key (instance of WinRegKey).
"""
parameters_key = key.GetSubkey('Parameters')
if parameters_key:
service_dll = parameters_key.GetValue('ServiceDll')
if service_dll:
return service_dll.data
else:
return None
def GetEntries(
self, parser_context, key=None, registry_type=None, file_entry=None,
parser_chain=None, **unused_kwargs):
"""Create one event for each subkey under Services that has Type and Start.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
text_dict = {}
service_type_value = key.GetValue('Type')
service_start_value = key.GetValue('Start')
# Grab the ServiceDLL value if it exists.
if service_type_value and service_start_value:
service_dll = self.GetServiceDll(key)
if service_dll:
text_dict['ServiceDll'] = service_dll
# Gather all the other string and integer values and insert as they are.
for value in key.GetValues():
if not value.name:
continue
if value.name not in text_dict:
if value.DataIsString() or value.DataIsInteger():
text_dict[value.name] = value.data
elif value.DataIsMultiString():
text_dict[value.name] = u', '.join(value.data)
# Create a specific service event, so that we can recognize and expand
# certain values when we're outputting the event.
event_object = windows_events.WindowsRegistryServiceEvent(
key.last_written_timestamp, key.path, text_dict, offset=key.offset,
registry_type=registry_type, urls=self.URLS)
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
winreg.WinRegistryParser.RegisterPlugin(ServicesPlugin)
@@ -0,0 +1,170 @@
#!/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 tests for Services Windows Registry plugin."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.lib import timelib_test
from plaso.parsers.winreg_plugins import services
from plaso.parsers.winreg_plugins import test_lib
from plaso.winreg import test_lib as winreg_test_lib
class ServicesRegistryPluginTest(test_lib.RegistryPluginTestCase):
"""The unit test for Services Windows Registry plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = services.ServicesPlugin()
def testProcess(self):
"""Tests the Process function on a virtual key."""
key_path = u'\\ControlSet001\\services\\TestDriver'
values = []
values.append(winreg_test_lib.TestRegValue(
'Type', '\x02\x00\x00\x00', 4, 123))
values.append(winreg_test_lib.TestRegValue(
'Start', '\x02\x00\x00\x00', 4, 127))
values.append(winreg_test_lib.TestRegValue(
'ErrorControl', '\x01\x00\x00\x00', 4, 131))
values.append(winreg_test_lib.TestRegValue(
'Group', 'Pnp Filter'.encode('utf_16_le'), 1, 140))
values.append(winreg_test_lib.TestRegValue(
'DisplayName', 'Test Driver'.encode('utf_16_le'), 1, 160))
values.append(winreg_test_lib.TestRegValue(
'DriverPackageId',
'testdriver.inf_x86_neutral_dd39b6b0a45226c4'.encode('utf_16_le'), 1,
180))
values.append(winreg_test_lib.TestRegValue(
'ImagePath', 'C:\\Dell\\testdriver.sys'.encode('utf_16_le'), 1, 200))
timestamp = timelib_test.CopyStringToTimestamp(
'2012-08-28 09:23:49.002031')
winreg_key = winreg_test_lib.TestRegKey(
key_path, timestamp, values, 1456)
event_queue_consumer = self._ParseKeyWithPlugin(self._plugin, winreg_key)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 1)
event_object = event_objects[0]
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2012-08-28 09:23:49.002031')
self.assertEquals(event_object.timestamp, expected_timestamp)
expected_msg = (
u'[{0:s}] '
u'DisplayName: Test Driver '
u'DriverPackageId: testdriver.inf_x86_neutral_dd39b6b0a45226c4 '
u'ErrorControl: Normal (1) '
u'Group: Pnp Filter '
u'ImagePath: C:\\Dell\\testdriver.sys '
u'Start: Auto Start (2) '
u'Type: File System Driver (0x2)').format(key_path)
expected_msg_short = (
u'[{0:s}] '
u'DisplayName: Test Driver '
u'DriverPackageId...').format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
def testProcessFile(self):
"""Tests the Process function on a key in a file."""
test_file_entry = self._GetTestFileEntryFromPath(['SYSTEM'])
key_path = u'\\ControlSet001\\services'
winreg_key = self._GetKeyFromFileEntry(test_file_entry, key_path)
event_objects = []
# Select a few service subkeys to perform additional testing.
bits_event_objects = None
mc_task_manager_event_objects = None
rdp_video_miniport_event_objects = None
for winreg_subkey in winreg_key.GetSubkeys():
event_queue_consumer = self._ParseKeyWithPlugin(
self._plugin, winreg_subkey, file_entry=test_file_entry)
sub_event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
event_objects.extend(sub_event_objects)
if winreg_subkey.name == 'BITS':
bits_event_objects = sub_event_objects
elif winreg_subkey.name == 'McTaskManager':
mc_task_manager_event_objects = sub_event_objects
elif winreg_subkey.name == 'RdpVideoMiniport':
rdp_video_miniport_event_objects = sub_event_objects
self.assertEquals(len(event_objects), 416)
# Test the BITS subkey event objects.
self.assertEquals(len(bits_event_objects), 1)
event_object = bits_event_objects[0]
self.assertEquals(event_object.pathspec, test_file_entry.path_spec)
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2012-04-06 20:43:27.639075')
self.assertEquals(event_object.timestamp, expected_timestamp)
self._TestRegvalue(event_object, u'Type', 0x20)
self._TestRegvalue(event_object, u'Start', 3)
self._TestRegvalue(
event_object, u'ServiceDll', u'%SystemRoot%\\System32\\qmgr.dll')
# Test the McTaskManager subkey event objects.
self.assertEquals(len(mc_task_manager_event_objects), 1)
event_object = mc_task_manager_event_objects[0]
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2011-09-16 20:49:16.877415')
self.assertEquals(event_object.timestamp, expected_timestamp)
self._TestRegvalue(event_object, u'DisplayName', u'McAfee Task Manager')
self._TestRegvalue(event_object, u'Type', 0x10)
# Test the RdpVideoMiniport subkey event objects.
self.assertEquals(len(rdp_video_miniport_event_objects), 1)
event_object = rdp_video_miniport_event_objects[0]
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2011-09-17 13:37:59.347157')
self.assertEquals(event_object.timestamp, expected_timestamp)
self._TestRegvalue(event_object, u'Start', 3)
expected_value = u'System32\\drivers\\rdpvideominiport.sys'
self._TestRegvalue(event_object, u'ImagePath', expected_value)
if __name__ == '__main__':
unittest.main()
+78
View File
@@ -0,0 +1,78 @@
#!/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.
"""This file contains the LastShutdown value plugin."""
import construct
import logging
from plaso.events import windows_events
from plaso.lib import eventdata
from plaso.lib import timelib
from plaso.parsers import winreg
from plaso.parsers.winreg_plugins import interface
__author__ = 'Preston Miller, dpmforensics.com, github.com/prmiller91'
class ShutdownPlugin(interface.KeyPlugin):
"""Windows Registry plugin for parsing the last shutdown time of a system."""
NAME = 'winreg_shutdown'
DESCRIPTION = u'Parser for ShutdownTime Registry value.'
REG_KEYS = [u'\\{current_control_set}\\Control\\Windows']
REG_TYPE = 'SYSTEM'
FILETIME_STRUCT = construct.ULInt64('filetime_timestamp')
def GetEntries(
self, parser_context, key=None, registry_type=None, file_entry=None,
parser_chain=None, **unused_kwargs):
"""Collect ShutdownTime value under Windows and produce an event object.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
shutdown_value = key.GetValue('ShutdownTime')
if not shutdown_value:
return
text_dict = {}
text_dict['Description'] = shutdown_value.name
try:
filetime = self.FILETIME_STRUCT.parse(shutdown_value.data)
except construct.FieldError as exception:
logging.error(
u'Unable to extract shutdown timestamp: {0:s}'.format(exception))
return
timestamp = timelib.Timestamp.FromFiletime(filetime)
event_object = windows_events.WindowsRegistryEvent(
timestamp, key.path, text_dict,
usage=eventdata.EventTimestamp.LAST_SHUTDOWN, offset=key.offset,
registry_type=registry_type,
source_append=u'Shutdown Entry')
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
winreg.WinRegistryParser.RegisterPlugin(ShutdownPlugin)
@@ -0,0 +1,79 @@
#!/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.
"""Tests for the LastShutdown value plugin."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.lib import timelib_test
from plaso.parsers.winreg_plugins import test_lib
from plaso.parsers.winreg_plugins import shutdown
__author__ = 'Preston Miller, dpmforensics.com, github.com/prmiller91'
class ShutdownPluginTest(test_lib.RegistryPluginTestCase):
"""Tests for the LastShutdown value plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = shutdown.ShutdownPlugin()
def testProcess(self):
"""Tests the Process function."""
knowledge_base_values = {'current_control_set': u'ControlSet001'}
test_file_entry = self._GetTestFileEntryFromPath(['SYSTEM'])
key_path = u'\\ControlSet001\\Control\\Windows'
winreg_key = self._GetKeyFromFileEntry(test_file_entry, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(
self._plugin, winreg_key, knowledge_base_values=knowledge_base_values,
file_entry=test_file_entry)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 1)
event_object = event_objects[0]
self.assertEquals(event_object.pathspec, test_file_entry.path_spec)
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_value = u'ShutdownTime'
self._TestRegvalue(event_object, u'Description', expected_value)
expected_msg = (
u'[\\ControlSet001\\Control\\Windows] '
u'Description: ShutdownTime')
# Match UTC timestamp.
time = long(timelib_test.CopyStringToTimestamp(
u'2012-04-04 01:58:40.839249'))
self.assertEquals(event_object.timestamp, time)
expected_msg_short = (
u'[\\ControlSet001\\Control\\Windows] '
u'Description: ShutdownTime')
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,169 @@
#!/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.
"""This file contains the Task Scheduler Registry keys plugins."""
import logging
import construct
from plaso.events import windows_events
from plaso.events import time_events
from plaso.parsers import winreg
from plaso.parsers.winreg_plugins import interface
class TaskCacheEvent(time_events.FiletimeEvent):
"""Convenience class for a Task Cache event."""
DATA_TYPE = 'task_scheduler:task_cache:entry'
def __init__(
self, timestamp, timestamp_description, task_name, task_identifier):
"""Initializes the event.
Args:
timestamp: The FILETIME value for the timestamp.
timestamp_description: The usage string for the timestamp value.
task_name: String containing the name of the task.
task_identifier: String containing the identifier of the task.
"""
super(TaskCacheEvent, self).__init__(timestamp, timestamp_description)
self.offset = 0
self.task_name = task_name
self.task_identifier = task_identifier
class TaskCachePlugin(interface.KeyPlugin):
"""Plugin that parses a Task Cache key."""
NAME = 'winreg_task_cache'
DESCRIPTION = u'Parser for Task Scheduler cache Registry data.'
REG_TYPE = 'SOFTWARE'
REG_KEYS = [
u'\\Microsoft\\Windows NT\\CurrentVersion\\Schedule\\TaskCache']
URL = [
u'https://code.google.com/p/winreg-kb/wiki/TaskSchedulerKeys']
_DYNAMIC_INFO_STRUCT = construct.Struct(
'dynamic_info_record',
construct.ULInt32('version'),
construct.ULInt64('last_registered_time'),
construct.ULInt64('launch_time'),
construct.Padding(8))
_DYNAMIC_INFO_STRUCT_SIZE = _DYNAMIC_INFO_STRUCT.sizeof()
def _GetIdValue(self, key):
"""Retrieves the Id value from Task Cache Tree key.
Args:
key: A Windows Registry key (instance of WinRegKey).
Yields:
A tuple containing a Windows Registry Key (instance of WinRegKey) and
a Windows Registry value (instance of WinRegValue).
"""
id_value = key.GetValue(u'Id')
if id_value:
yield key, id_value
for sub_key in key.GetSubkeys():
for value_key, id_value in self._GetIdValue(sub_key):
yield value_key, id_value
def GetEntries(
self, parser_context, key=None, registry_type=None, file_entry=None,
parser_chain=None, **unused_kwargs):
"""Parses a Task Cache Registry key.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
tasks_key = key.GetSubkey(u'Tasks')
tree_key = key.GetSubkey(u'Tree')
if not tasks_key or not tree_key:
logging.warning(u'Task Cache is missing a Tasks or Tree sub key.')
return
task_guids = {}
for sub_key in tree_key.GetSubkeys():
for value_key, id_value in self._GetIdValue(sub_key):
# The GUID is in the form {%GUID%} and stored an UTF-16 little-endian
# string and should be 78 bytes in size.
if len(id_value.raw_data) != 78:
logging.warning(
u'[{0:s}] unsupported Id value data size.'.format(self.NAME))
continue
task_guids[id_value.data] = value_key.name
for sub_key in tasks_key.GetSubkeys():
dynamic_info_value = sub_key.GetValue(u'DynamicInfo')
if not dynamic_info_value:
continue
if len(dynamic_info_value.raw_data) != self._DYNAMIC_INFO_STRUCT_SIZE:
logging.warning(
u'[{0:s}] unsupported DynamicInfo value data size.'.format(
self.NAME))
continue
dynamic_info = self._DYNAMIC_INFO_STRUCT.parse(
dynamic_info_value.raw_data)
name = task_guids.get(sub_key.name, sub_key.name)
text_dict = {}
text_dict[u'Task: {0:s}'.format(name)] = u'[ID: {0:s}]'.format(
sub_key.name)
event_object = windows_events.WindowsRegistryEvent(
key.last_written_timestamp, key.path, text_dict, offset=key.offset,
registry_type=registry_type)
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
if dynamic_info.last_registered_time:
# Note this is likely either the last registered time or
# the update time.
event_object = TaskCacheEvent(
dynamic_info.last_registered_time, u'Last registered time', name,
sub_key.name)
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
if dynamic_info.launch_time:
# Note this is likely the launch time.
event_object = TaskCacheEvent(
dynamic_info.launch_time, u'Launch time', name, sub_key.name)
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
# TODO: Add support for the Triggers value.
winreg.WinRegistryParser.RegisterPlugin(TaskCachePlugin)
@@ -0,0 +1,87 @@
#!/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.
"""Tests for the Task Scheduler Windows Registry plugin."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.lib import timelib_test
from plaso.parsers.winreg_plugins import task_scheduler
from plaso.parsers.winreg_plugins import test_lib
class TaskCachePluginTest(test_lib.RegistryPluginTestCase):
"""Tests for the Task Cache key Windows Registry plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = task_scheduler.TaskCachePlugin()
def testProcess(self):
"""Tests the Process function."""
test_file = self._GetTestFilePath(['SOFTWARE-RunTests'])
key_path = (
u'\\Microsoft\\Windows NT\\CurrentVersion\\Schedule\\TaskCache')
winreg_key = self._GetKeyFromFile(test_file, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(self._plugin, winreg_key)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 174)
event_object = event_objects[0]
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2009-07-14 04:53:25.811618')
self.assertEquals(event_object.timestamp, expected_timestamp)
regvalue_identifier = u'Task: SynchronizeTime'
expected_value = u'[ID: {044A6734-E90E-4F8F-B357-B2DC8AB3B5EC}]'
self._TestRegvalue(event_object, regvalue_identifier, expected_value)
expected_msg = u'[{0:s}] {1:s}: {2:s}'.format(
key_path, regvalue_identifier, expected_value)
expected_msg_short = u'[{0:s}] Task: SynchronizeTi...'.format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
event_object = event_objects[1]
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2009-07-14 05:08:50.811626')
self.assertEquals(event_object.timestamp, expected_timestamp)
regvalue_identifier = u'Task: SynchronizeTime'
expected_msg = (
u'Task: SynchronizeTime '
u'[Identifier: {044A6734-E90E-4F8F-B357-B2DC8AB3B5EC}]')
expected_msg_short = (
u'Task: SynchronizeTime')
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,127 @@
#!/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 Terminal Server Registry plugins."""
from plaso.events import windows_events
from plaso.parsers import winreg
from plaso.parsers.winreg_plugins import interface
__author__ = 'David Nides (david.nides@gmail.com)'
class TerminalServerClientPlugin(interface.KeyPlugin):
"""Windows Registry plugin for Terminal Server Client Connection keys."""
NAME = 'winreg_rdp'
DESCRIPTION = u'Parser for Terminal Server Client Connection Registry data.'
REG_TYPE = 'NTUSER'
REG_KEYS = [
u'\\Software\\Microsoft\\Terminal Server Client\\Servers',
u'\\Software\\Microsoft\\Terminal Server Client\\Default\\AddIns\\RDPDR']
def GetEntries(
self, parser_context, key=None, registry_type=None, file_entry=None,
parser_chain=None, **unused_kwargs):
"""Collect Values in Servers and return event for each one.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
for subkey in key.GetSubkeys():
username_value = subkey.GetValue('UsernameHint')
if (username_value and username_value.data and
username_value.DataIsString()):
username = username_value.data
else:
username = u'None'
text_dict = {}
text_dict['UsernameHint'] = username
event_object = windows_events.WindowsRegistryEvent(
key.last_written_timestamp, key.path, text_dict, offset=key.offset,
registry_type=registry_type,
source_append=': RDP Connection')
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
class TerminalServerClientMRUPlugin(interface.KeyPlugin):
"""Windows Registry plugin for Terminal Server Client Connection MRUs keys."""
NAME = 'winreg_rdp_mru'
DESCRIPTION = u'Parser for Terminal Server Client MRU Registry data.'
REG_TYPE = 'NTUSER'
REG_KEYS = [
u'\\Software\\Microsoft\\Terminal Server Client\\Default',
u'\\Software\\Microsoft\\Terminal Server Client\\LocalDevices']
def GetEntries(
self, parser_context, key=None, registry_type=None, file_entry=None,
parser_chain=None, **unused_kwargs):
"""Collect MRU Values and return event for each one.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
"""
for value in key.GetValues():
# TODO: add a check for the value naming scheme.
# Ignore the default value.
if not value.name:
continue
# Ignore any value that is empty or that does not contain a string.
if not value.data or not value.DataIsString():
continue
text_dict = {}
text_dict[value.name] = value.data
if value.name == 'MRU0':
timestamp = key.last_written_timestamp
else:
timestamp = 0
event_object = windows_events.WindowsRegistryEvent(
timestamp, key.path, text_dict, offset=key.offset,
registry_type=registry_type,
source_append=u': RDP Connection')
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
winreg.WinRegistryParser.RegisterPlugins([
TerminalServerClientPlugin, TerminalServerClientMRUPlugin])
@@ -0,0 +1,130 @@
#!/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 Terminal Server Windows Registry plugin."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.lib import timelib_test
from plaso.parsers.winreg_plugins import terminal_server
from plaso.parsers.winreg_plugins import test_lib
from plaso.winreg import test_lib as winreg_test_lib
class ServersTerminalServerClientPluginTest(test_lib.RegistryPluginTestCase):
"""Tests for the Terminal Server Client Windows Registry plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = terminal_server.TerminalServerClientPlugin()
def testProcess(self):
"""Tests the Process function."""
key_path = u'\\Software\\Microsoft\\Terminal Server Client\\Servers'
values = []
values.append(winreg_test_lib.TestRegValue(
'UsernameHint', 'DOMAIN\\username'.encode('utf_16_le'),
winreg_test_lib.TestRegValue.REG_SZ, offset=1892))
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2012-08-28 09:23:49.002031')
server_key_path = (
u'\\Software\\Microsoft\\Terminal Server Client\\Servers\\myserver.com')
server_key = winreg_test_lib.TestRegKey(
server_key_path, expected_timestamp, values, offset=1456)
winreg_key = winreg_test_lib.TestRegKey(
key_path, expected_timestamp, None, offset=865, subkeys=[server_key])
event_queue_consumer = self._ParseKeyWithPlugin(self._plugin, winreg_key)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 1)
event_object = event_objects[0]
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
self.assertEquals(event_object.timestamp, expected_timestamp)
expected_msg = u'[{0:s}] UsernameHint: DOMAIN\\username'.format(key_path)
expected_msg_short = (
u'[{0:s}] UsernameHint: DOMAIN\\use...').format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
class DefaultTerminalServerClientMRUPluginTest(test_lib.RegistryPluginTestCase):
"""Tests for the Terminal Server Client MRU Windows Registry plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = terminal_server.TerminalServerClientMRUPlugin()
def testProcess(self):
"""Tests the Process function."""
key_path = u'\\Software\\Microsoft\\Terminal Server Client\\Default'
values = []
values.append(winreg_test_lib.TestRegValue(
'MRU0', '192.168.16.60'.encode('utf_16_le'),
winreg_test_lib.TestRegValue.REG_SZ, offset=1892))
values.append(winreg_test_lib.TestRegValue(
'MRU1', 'computer.domain.com'.encode('utf_16_le'),
winreg_test_lib.TestRegValue.REG_SZ, 612))
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2012-08-28 09:23:49.002031')
winreg_key = winreg_test_lib.TestRegKey(
key_path, expected_timestamp, values, 1456)
event_queue_consumer = self._ParseKeyWithPlugin(self._plugin, winreg_key)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 2)
event_object = event_objects[0]
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
self.assertEquals(event_object.timestamp, expected_timestamp)
expected_msg = u'[{0:s}] MRU0: 192.168.16.60'.format(key_path)
expected_msg_short = u'[{0:s}] MRU0: 192.168.16.60'.format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
event_object = event_objects[1]
self.assertEquals(event_object.timestamp, 0)
expected_msg = u'[{0:s}] MRU1: computer.domain.com'.format(key_path)
expected_msg_short = u'[{0:s}] MRU1: computer.domain.com'.format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
if __name__ == '__main__':
unittest.main()
+106
View File
@@ -0,0 +1,106 @@
#!/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.
"""Windows Registry plugin related functions and classes for testing."""
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.engine import single_process
from plaso.parsers import test_lib
from plaso.winreg import winregistry
class RegistryPluginTestCase(test_lib.ParserTestCase):
"""The unit test case for a Windows Registry plugin."""
def _GetKeyFromFile(self, path, key_path):
"""Retrieves a Windows Registry key from a file.
Args:
path: The path to the file, as a string.
key_path: The path of the key to parse.
Returns:
A Windows Registry key (instance of WinRegKey).
"""
path_spec = path_spec_factory.Factory.NewPathSpec(
definitions.TYPE_INDICATOR_OS, location=path)
file_entry = path_spec_resolver.Resolver.OpenFileEntry(path_spec)
return self._GetKeyFromFileEntry(file_entry, key_path)
def _GetKeyFromFileEntry(self, file_entry, key_path):
"""Retrieves a Windows Registry key from a file.
Args:
file_entry: A dfVFS file_entry object that references a test file.
key_path: The path of the key to parse.
Returns:
A Windows Registry key (instance of WinRegKey).
"""
registry = winregistry.WinRegistry(winregistry.WinRegistry.BACKEND_PYREGF)
winreg_file = registry.OpenFile(file_entry, codepage='cp1252')
return winreg_file.GetKeyByPath(key_path)
def _ParseKeyWithPlugin(
self, plugin_object, winreg_key, knowledge_base_values=None,
file_entry=None, parser_chain=None):
"""Parses a key within a Windows Registry file using the plugin object.
Args:
plugin_object: The plugin object.
winreg_key: The Windows Registry Key.
knowledge_base_values: Optional dict containing the knowledge base
values. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
Returns:
An event object queue consumer object (instance of
TestEventObjectQueueConsumer).
"""
self.assertNotEquals(winreg_key, None)
event_queue = single_process.SingleProcessQueue()
event_queue_consumer = test_lib.TestEventObjectQueueConsumer(event_queue)
parse_error_queue = single_process.SingleProcessQueue()
parser_context = self._GetParserContext(
event_queue, parse_error_queue,
knowledge_base_values=knowledge_base_values)
plugin_object.Process(
parser_context, key=winreg_key, parser_chain=parser_chain,
file_entry=file_entry)
return event_queue_consumer
def _TestRegvalue(self, event_object, identifier, expected_value):
"""Tests a specific 'regvalue' attribute within the event object.
Args:
event_object: the event object (instance of EventObject).
identifier: the identifier of the 'regvalue' attribute.
expected_value: the expected value of the 'regvalue' attribute.
"""
self.assertTrue(hasattr(event_object, 'regvalue'))
self.assertIn(identifier, event_object.regvalue)
self.assertEquals(event_object.regvalue[identifier], expected_value)
+84
View File
@@ -0,0 +1,84 @@
#!/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 typed URLs plugins for Plaso."""
import re
from plaso.events import windows_events
from plaso.parsers import winreg
from plaso.parsers.winreg_plugins import interface
__author__ = 'David Nides (david.nides@gmail.com)'
class TypedURLsPlugin(interface.KeyPlugin):
"""A Windows Registry plugin for typed URLs history."""
NAME = 'winreg_typed_urls'
DESCRIPTION = u'Parser for Internet Explorer typed URLs Registry data.'
REG_TYPE = 'NTUSER'
REG_KEYS = [
u'\\Software\\Microsoft\\Internet Explorer\\TypedURLs',
u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\TypedPaths']
_RE_VALUE_NAME = re.compile(r'^url[0-9]+$', re.I)
def GetEntries(
self, parser_context, key=None, registry_type=None, file_entry=None,
parser_chain=None, **unused_kwargs):
"""Collect typed URLs values.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
registry_type: Optional Registry type string. The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
for value in key.GetValues():
# Ignore any value not in the form: 'url[0-9]+'.
if not value.name or not self._RE_VALUE_NAME.search(value.name):
continue
# Ignore any value that is empty or that does not contain a string.
if not value.data or not value.DataIsString():
continue
# TODO: shouldn't this behavior be, put all the typed urls
# into a single event object with the last written time of the key?
if value.name == 'url1':
timestamp = key.last_written_timestamp
else:
timestamp = 0
text_dict = {}
text_dict[value.name] = value.data
event_object = windows_events.WindowsRegistryEvent(
timestamp, key.path, text_dict, offset=key.offset,
registry_type=registry_type,
source_append=u': Typed URLs')
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
winreg.WinRegistryParser.RegisterPlugin(TypedURLsPlugin)
@@ -0,0 +1,112 @@
#!/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 MSIE typed URLs Windows Registry plugin."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.lib import timelib_test
from plaso.parsers.winreg_plugins import test_lib
from plaso.parsers.winreg_plugins import typedurls
__author__ = 'David Nides (david.nides@gmail.com)'
class MsieTypedURLsPluginTest(test_lib.RegistryPluginTestCase):
"""Tests for the MSIE typed URLs Windows Registry plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = typedurls.TypedURLsPlugin()
def testProcess(self):
"""Tests the Process function."""
test_file_entry = self._GetTestFileEntryFromPath(['NTUSER-WIN7.DAT'])
key_path = u'\\Software\\Microsoft\\Internet Explorer\\TypedURLs'
winreg_key = self._GetKeyFromFileEntry(test_file_entry, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(
self._plugin, winreg_key, file_entry=test_file_entry)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 13)
event_object = event_objects[0]
self.assertEquals(event_object.pathspec, test_file_entry.path_spec)
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2012-03-12 21:23:53.307749')
self.assertEquals(event_object.timestamp, expected_timestamp)
regvalue_identifier = u'url1'
expected_value = u'http://cnn.com/'
self._TestRegvalue(event_object, regvalue_identifier, expected_value)
expected_string = u'[{0:s}] {1:s}: {2:s}'.format(
key_path, regvalue_identifier, expected_value)
self._TestGetMessageStrings(event_object, expected_string, expected_string)
class TypedPathsPluginTest(test_lib.RegistryPluginTestCase):
"""Tests for the typed paths Windows Registry plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = typedurls.TypedURLsPlugin()
def testProcess(self):
"""Tests the Process function."""
test_file_entry = self._GetTestFileEntryFromPath(['NTUSER-WIN7.DAT'])
key_path = (
u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\TypedPaths')
winreg_key = self._GetKeyFromFileEntry(test_file_entry, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(
self._plugin, winreg_key, file_entry=test_file_entry)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 1)
event_object = event_objects[0]
self.assertEquals(event_object.pathspec, test_file_entry.path_spec)
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2010-11-10 07:58:15.811625')
self.assertEquals(event_object.timestamp, expected_timestamp)
regvalue_identifier = u'url1'
expected_value = u'\\\\controller'
self._TestRegvalue(event_object, regvalue_identifier, expected_value)
expected_msg = u'[{0:s}] {1:s}: {2:s}'.format(
key_path, regvalue_identifier, expected_value)
expected_msg_short = u'[{0:s}] {1:s}: \\\\cont...'.format(
key_path, regvalue_identifier)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
if __name__ == '__main__':
unittest.main()
+87
View File
@@ -0,0 +1,87 @@
#!/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.
"""This file contains the USB key plugin."""
import logging
from plaso.events import windows_events
from plaso.lib import eventdata
from plaso.parsers import winreg
from plaso.parsers.winreg_plugins import interface
__author__ = 'Preston Miller, dpmforensics.com, github.com/prmiller91'
class USBPlugin(interface.KeyPlugin):
"""USB Windows Registry plugin for last connection time."""
NAME = 'winreg_usb'
DESCRIPTION = u'Parser for USB storage Registry data.'
REG_KEYS = [u'\\{current_control_set}\\Enum\\USB']
REG_TYPE = 'SYSTEM'
def GetEntries(
self, parser_context, key=None, registry_type=None, file_entry=None,
parser_chain=None, **unused_kwargs):
"""Collect SubKeys under USB and produce an event object for each one.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
for subkey in key.GetSubkeys():
text_dict = {}
text_dict['subkey_name'] = subkey.name
vendor_identification = None
product_identification = None
try:
subkey_name_parts = subkey.name.split(u'&')
if len(subkey_name_parts) >= 2:
vendor_identification = subkey_name_parts[0]
product_identification = subkey_name_parts[1]
except ValueError as exception:
logging.warning(
u'Unable to split string: {0:s} with error: {1:s}'.format(
subkey.name, exception))
if vendor_identification and product_identification:
text_dict['vendor'] = vendor_identification
text_dict['product'] = product_identification
for devicekey in subkey.GetSubkeys():
text_dict['serial'] = devicekey.name
# Last USB connection per USB device recorded in the Registry.
event_object = windows_events.WindowsRegistryEvent(
devicekey.last_written_timestamp, key.path, text_dict,
usage=eventdata.EventTimestamp.LAST_CONNECTED, offset=key.offset,
registry_type=registry_type,
source_append=': USB Entries')
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
winreg.WinRegistryParser.RegisterPlugin(USBPlugin)
+80
View File
@@ -0,0 +1,80 @@
#!/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.
"""Tests for the USB Windows Registry plugin."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.lib import event
from plaso.lib import timelib_test
from plaso.parsers.winreg_plugins import test_lib
from plaso.parsers.winreg_plugins import usb
__author__ = 'Preston Miller, dpmforensics.com, github.com/prmiller91'
class USBPluginTest(test_lib.RegistryPluginTestCase):
"""Tests for the USB Windows Registry plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = usb.USBPlugin()
def testProcess(self):
"""Tests the Process function."""
knowledge_base_values = {u'current_control_set': u'ControlSet001'}
test_file_entry = self._GetTestFileEntryFromPath([u'SYSTEM'])
key_path = u'\\ControlSet001\\Enum\\USB'
winreg_key = self._GetKeyFromFileEntry(test_file_entry, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(
self._plugin, winreg_key, knowledge_base_values=knowledge_base_values,
file_entry=test_file_entry)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 7)
event_object = event_objects[3]
self.assertEquals(event_object.pathspec, test_file_entry.path_spec)
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_value = u'VID_0E0F&PID_0002'
self._TestRegvalue(event_object, u'subkey_name', expected_value)
self._TestRegvalue(event_object, u'vendor', u'VID_0E0F')
self._TestRegvalue(event_object, u'product', u'PID_0002')
expected_msg = (
r'[\ControlSet001\Enum\USB] product: PID_0002 serial: 6&2ab01149&0&2 '
r'subkey_name: VID_0E0F&PID_0002 vendor: VID_0E0F')
# Match UTC timestamp.
time = long(timelib_test.CopyStringToTimestamp(
u'2012-04-07 10:31:37.625246'))
self.assertEquals(event_object.timestamp, time)
expected_msg_short = u'{0:s}...'.format(expected_msg[0:77])
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
if __name__ == '__main__':
unittest.main()
+133
View File
@@ -0,0 +1,133 @@
#!/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 USBStor keys plugins."""
import logging
from plaso.events import windows_events
from plaso.lib import eventdata
from plaso.parsers import winreg
from plaso.parsers.winreg_plugins import interface
__author__ = 'David Nides (david.nides@gmail.com)'
class USBStorPlugin(interface.KeyPlugin):
"""USBStor key plugin."""
NAME = 'winreg_usbstor'
DESCRIPTION = u'Parser for USB storage Registry data.'
REG_KEYS = [u'\\{current_control_set}\\Enum\\USBSTOR']
REG_TYPE = 'SYSTEM'
def GetEntries(
self, parser_context, key=None, registry_type=None, file_entry=None,
parser_chain=None, **unused_kwargs):
"""Collect Values under USBStor and return an event object for each one.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
for subkey in key.GetSubkeys():
text_dict = {}
text_dict['subkey_name'] = subkey.name
# Time last USB device of this class was first inserted.
event_object = windows_events.WindowsRegistryEvent(
subkey.last_written_timestamp, key.path, text_dict,
usage=eventdata.EventTimestamp.FIRST_CONNECTED, offset=key.offset,
registry_type=registry_type,
source_append=': USBStor Entries')
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
# TODO: Determine if these 4 fields always exist.
try:
device_type, vendor, product, revision = subkey.name.split('&')
except ValueError as exception:
logging.warning(
u'Unable to split string: {0:s} with error: {1:s}'.format(
subkey.name, exception))
text_dict['device_type'] = device_type
text_dict['vendor'] = vendor
text_dict['product'] = product
text_dict['revision'] = revision
for devicekey in subkey.GetSubkeys():
text_dict['serial'] = devicekey.name
friendly_name_value = devicekey.GetValue('FriendlyName')
if friendly_name_value:
text_dict['friendly_name'] = friendly_name_value.data
else:
text_dict.pop('friendly_name', None)
# ParentIdPrefix applies to Windows XP Only.
parent_id_prefix_value = devicekey.GetValue('ParentIdPrefix')
if parent_id_prefix_value:
text_dict['parent_id_prefix'] = parent_id_prefix_value.data
else:
text_dict.pop('parent_id_prefix', None)
# Win7 - Last Connection.
# Vista/XP - Time of an insert.
event_object = windows_events.WindowsRegistryEvent(
devicekey.last_written_timestamp, key.path, text_dict,
usage=eventdata.EventTimestamp.LAST_CONNECTED, offset=key.offset,
registry_type=registry_type,
source_append=': USBStor Entries')
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
# Build list of first Insertion times.
first_insert = []
device_parameter_key = devicekey.GetSubkey('Device Parameters')
if device_parameter_key:
first_insert.append(device_parameter_key.last_written_timestamp)
log_configuration_key = devicekey.GetSubkey('LogConf')
if (log_configuration_key and
log_configuration_key.last_written_timestamp not in first_insert):
first_insert.append(log_configuration_key.last_written_timestamp)
properties_key = devicekey.GetSubkey('Properties')
if (properties_key and
properties_key.last_written_timestamp not in first_insert):
first_insert.append(properties_key.last_written_timestamp)
# Add first Insertion times.
for timestamp in first_insert:
event_object = windows_events.WindowsRegistryEvent(
timestamp, key.path, text_dict,
usage=eventdata.EventTimestamp.LAST_CONNECTED, offset=key.offset,
registry_type=registry_type,
source_append=': USBStor Entries')
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
winreg.WinRegistryParser.RegisterPlugin(USBStorPlugin)
@@ -0,0 +1,84 @@
#!/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 USBStor Windows Registry plugin."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.parsers.winreg_plugins import test_lib
from plaso.parsers.winreg_plugins import usbstor
class USBStorPlugin(test_lib.RegistryPluginTestCase):
"""Tests for the USBStor Windows Registry plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = usbstor.USBStorPlugin()
def testProcess(self):
"""Tests the Process function."""
knowledge_base_values = {'current_control_set': u'ControlSet001'}
test_file_entry = self._GetTestFileEntryFromPath(['SYSTEM'])
key_path = u'\\ControlSet001\\Enum\\USBSTOR'
winreg_key = self._GetKeyFromFileEntry(test_file_entry, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(
self._plugin, winreg_key, knowledge_base_values=knowledge_base_values,
file_entry=test_file_entry)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 3)
event_object = event_objects[0]
self.assertEquals(event_object.pathspec, test_file_entry.path_spec)
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
self.assertEquals(event_object.timestamp, 1333794697640871)
expected_value = u'Disk&Ven_HP&Prod_v100w&Rev_1024'
self._TestRegvalue(event_object, u'subkey_name', expected_value)
self._TestRegvalue(event_object, u'device_type', u'Disk')
self._TestRegvalue(event_object, u'vendor', u'Ven_HP')
self._TestRegvalue(event_object, u'product', u'Prod_v100w')
self._TestRegvalue(event_object, u'revision', u'Rev_1024')
expected_msg = (
u'[{0:s}] '
u'device_type: Disk '
u'friendly_name: HP v100w USB Device '
u'product: Prod_v100w '
u'revision: Rev_1024 '
u'serial: AA951D0000007252&0 '
u'subkey_name: Disk&Ven_HP&Prod_v100w&Rev_1024 '
u'vendor: Ven_HP').format(key_path)
expected_msg_short = (
u'[{0:s}] '
u'device_type: Disk '
u'friendly_name: HP v100w USB D...').format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
if __name__ == '__main__':
unittest.main()
+208
View File
@@ -0,0 +1,208 @@
#!/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 UserAssist Windows Registry plugin."""
import logging
import construct
from plaso.events import windows_events
from plaso.lib import timelib
from plaso.parsers import winreg
from plaso.parsers.winreg_plugins import interface
from plaso.winnt import environ_expand
from plaso.winnt import known_folder_ids
class UserAssistPlugin(interface.KeyPlugin):
"""Plugin that parses an UserAssist key."""
NAME = 'winreg_userassist'
DESCRIPTION = u'Parser for User Assist Registry data.'
REG_TYPE = 'NTUSER'
REG_KEYS = [
(u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer'
u'\\UserAssist\\{{FA99DFC7-6AC2-453A-A5E2-5E2AFF4507BD}}'),
(u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer'
u'\\UserAssist\\{{F4E57C4B-2036-45F0-A9AB-443BCFE33D9F}}'),
(u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer'
u'\\UserAssist\\{{F2A1CB5A-E3CC-4A2E-AF9D-505A7009D442}}'),
(u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer'
u'\\UserAssist\\{{CEBFF5CD-ACE2-4F4F-9178-9926F41749EA}}'),
(u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer'
u'\\UserAssist\\{{CAA59E3C-4792-41A5-9909-6A6A8D32490E}}'),
(u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer'
u'\\UserAssist\\{{B267E3AD-A825-4A09-82B9-EEC22AA3B847}}'),
(u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer'
u'\\UserAssist\\{{A3D53349-6E61-4557-8FC7-0028EDCEEBF6}}'),
(u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer'
u'\\UserAssist\\{{9E04CAB2-CC14-11DF-BB8C-A2F1DED72085}}'),
(u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer'
u'\\UserAssist\\{{75048700-EF1F-11D0-9888-006097DEACF9}}'),
(u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer'
u'\\UserAssist\\{{5E6AB780-7743-11CF-A12B-00AA004AE837}}'),
(u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer'
u'\\UserAssist\\{{0D6D4F41-2994-4BA0-8FEF-620E43CD2812}}'),
(u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer'
u'\\UserAssist\\{{BCB48336-4DDD-48FF-BB0B-D3190DACB3E2}}')]
URL = [
u'http://blog.didierstevens.com/programs/userassist/',
u'https://code.google.com/p/winreg-kb/wiki/UserAssistKeys',
u'http://intotheboxes.files.wordpress.com/2010/04'
u'/intotheboxes_2010_q1.pdf']
# UserAssist format version used in Windows 2000, XP, 2003, Vista.
USERASSIST_V3_STRUCT = construct.Struct(
'userassist_entry',
construct.Padding(4),
construct.ULInt32('count'),
construct.ULInt64('timestamp'))
# UserAssist format version used in Windows 2008, 7, 8.
USERASSIST_V5_STRUCT = construct.Struct(
'userassist_entry',
construct.Padding(4),
construct.ULInt32('count'),
construct.ULInt32('app_focus_count'),
construct.ULInt32('focus_duration'),
construct.Padding(44),
construct.ULInt64('timestamp'),
construct.Padding(4))
def GetEntries(
self, parser_context, key=None, registry_type=None, file_entry=None,
parser_chain=None, **unused_kwargs):
"""Parses a UserAssist Registry key.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
version_value = key.GetValue('Version')
count_subkey = key.GetSubkey('Count')
if not version_value:
logging.error(u'missing version value')
elif not version_value.DataIsInteger():
logging.error(u'unsupported version value data type')
elif version_value.data not in [3, 5]:
logging.error(u'unsupported version: {0:d}'.format(version_value.data))
elif not count_subkey:
logging.error(u'missing count subkey')
else:
userassist_entry_index = 0
for value in count_subkey.GetValues():
try:
value_name = value.name.decode('rot-13')
except UnicodeEncodeError as exception:
logging.debug((
u'Unable to decode UserAssist string: {0:s} with error: {1:s}.\n'
u'Attempting piecewise decoding.').format(
value.name, exception))
characters = []
for char in value.name:
if ord(char) < 128:
try:
characters.append(char.decode('rot-13'))
except UnicodeEncodeError:
characters.append(char)
else:
characters.append(char)
value_name = u''.join(characters)
if version_value.data == 5:
path_segments = value_name.split(u'\\')
for segment_index in range(0, len(path_segments)):
# Remove the { } from the path segment to get the GUID.
guid = path_segments[segment_index][1:-1]
path_segments[segment_index] = known_folder_ids.PATHS.get(
guid, path_segments[segment_index])
value_name = u'\\'.join(path_segments)
# Check if we might need to substitute values.
if '%' in value_name:
# TODO: deprecate direct use of pre_obj.
value_name = environ_expand.ExpandWindowsEnvironmentVariables(
value_name, parser_context.knowledge_base.pre_obj)
if not value.DataIsBinaryData():
logging.error(u'unsupported value data type: {0:s}'.format(
value.data_type_string))
elif version_value.data == 3:
if len(value.data) != self.USERASSIST_V3_STRUCT.sizeof():
logging.error(u'unsupported value data size: {0:d}'.format(
len(value.data)))
else:
parsed_data = self.USERASSIST_V3_STRUCT.parse(value.data)
filetime = parsed_data.get('timestamp', 0)
count = parsed_data.get('count', 0)
if count > 5:
count -= 5
text_dict = {}
text_dict[value_name] = u'[Count: {0:d}]'.format(count)
event_object = windows_events.WindowsRegistryEvent(
timelib.Timestamp.FromFiletime(filetime), count_subkey.path,
text_dict, offset=value.offset, registry_type=registry_type)
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
elif version_value.data == 5:
if len(value.data) != self.USERASSIST_V5_STRUCT.sizeof():
logging.error(u'unsupported value data size: {0:d}'.format(
len(value.data)))
parsed_data = self.USERASSIST_V5_STRUCT.parse(value.data)
userassist_entry_index += 1
count = parsed_data.get('count', None)
app_focus_count = parsed_data.get('app_focus_count', None)
focus_duration = parsed_data.get('focus_duration', None)
timestamp = parsed_data.get('timestamp', 0)
text_dict = {}
text_dict[value_name] = (
u'[UserAssist entry: {0:d}, Count: {1:d}, '
u'Application focus count: {2:d}, Focus duration: {3:d}]').format(
userassist_entry_index, count, app_focus_count,
focus_duration)
event_object = windows_events.WindowsRegistryEvent(
timelib.Timestamp.FromFiletime(timestamp), count_subkey.path,
text_dict, offset=count_subkey.offset,
registry_type=registry_type)
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
winreg.WinRegistryParser.RegisterPlugin(UserAssistPlugin)
@@ -0,0 +1,112 @@
#!/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 UserAssist Windows Registry plugin."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.lib import timelib_test
from plaso.parsers.winreg_plugins import test_lib
from plaso.parsers.winreg_plugins import userassist
class UserAssistPluginTest(test_lib.RegistryPluginTestCase):
"""Tests for the UserAssist Windows Registry plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = userassist.UserAssistPlugin()
def testProcessOnWinXP(self):
"""Tests the Process function on a Windows XP Registry file."""
test_file_entry = self._GetTestFileEntryFromPath(['NTUSER.DAT'])
key_path = (
u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\UserAssist'
u'\\{75048700-EF1F-11D0-9888-006097DEACF9}')
winreg_key = self._GetKeyFromFileEntry(test_file_entry, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(
self._plugin, winreg_key, file_entry=test_file_entry)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 14)
event_object = event_objects[0]
self.assertEquals(event_object.pathspec, test_file_entry.path_spec)
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2009-08-04 15:11:22.811067')
self.assertEquals(event_object.timestamp, expected_timestamp)
regvalue_identifier = u'UEME_RUNPIDL:%csidl2%\\MSN.lnk'
expected_value = u'[Count: 14]'
self._TestRegvalue(event_object, regvalue_identifier, expected_value)
expected_msg = u'[{0:s}\\Count] {1:s}: {2:s}'.format(
key_path, regvalue_identifier, expected_value)
# The short message contains the first 76 characters of the key path.
expected_msg_short = u'[{0:s}...'.format(key_path[:76])
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
def testProcessOnWin7(self):
"""Tests the Process function on a Windows 7 Registry file."""
test_file_entry = self._GetTestFileEntryFromPath(['NTUSER-WIN7.DAT'])
key_path = (
u'\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\UserAssist'
u'\\{CEBFF5CD-ACE2-4F4F-9178-9926F41749EA}')
winreg_key = self._GetKeyFromFileEntry(test_file_entry, key_path)
event_queue_consumer = self._ParseKeyWithPlugin(
self._plugin, winreg_key, file_entry=test_file_entry)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 62)
event_object = event_objects[0]
self.assertEquals(event_object.pathspec, test_file_entry.path_spec)
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2010-11-10 07:49:37.078067')
self.assertEquals(event_object.timestamp, expected_timestamp)
regvalue_identifier = u'Microsoft.Windows.GettingStarted'
expected_value = (
u'[UserAssist entry: 1, Count: 14, Application focus count: 21, '
u'Focus duration: 420000]')
self._TestRegvalue(event_object, regvalue_identifier, expected_value)
expected_msg = u'[{0:s}\\Count] {1:s}: {2:s}'.format(
key_path, regvalue_identifier, expected_value)
# The short message contains the first 76 characters of the key path.
expected_msg_short = u'[{0:s}...'.format(key_path[:76])
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
if __name__ == '__main__':
unittest.main()
+87
View File
@@ -0,0 +1,87 @@
#!/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 a parser for WinRAR for Plaso."""
import re
from plaso.events import windows_events
from plaso.parsers import winreg
from plaso.parsers.winreg_plugins import interface
__author__ = 'David Nides (david.nides@gmail.com)'
class WinRarHistoryPlugin(interface.KeyPlugin):
"""Windows Registry plugin for parsing WinRAR History keys."""
# TODO: Create NTUSER.DAT test file with WinRAR data.
NAME = 'winreg_winrar'
DESCRIPTION = u'Parser for WinRAR History Registry data.'
REG_TYPE = 'NTUSER'
REG_KEYS = [
u'\\Software\\WinRAR\\DialogEditHistory\\ExtrPath',
u'\\Software\\WinRAR\\DialogEditHistory\\ArcName',
u'\\Software\\WinRAR\\ArcHistory']
_RE_VALUE_NAME = re.compile(r'^[0-9]+$', re.I)
def GetEntries(
self, parser_context, key=None, registry_type=None, file_entry=None,
parser_chain=None, **unused_kwargs):
"""Collect values under WinRAR ArcHistory and return event for each one.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
for value in key.GetValues():
# Ignore any value not in the form: '[0-9]+'.
if not value.name or not self._RE_VALUE_NAME.search(value.name):
continue
# Ignore any value that is empty or that does not contain a string.
if not value.data or not value.DataIsString():
continue
if value.name == '0':
timestamp = key.last_written_timestamp
else:
timestamp = 0
text_dict = {}
text_dict[value.name] = value.data
# TODO: shouldn't this behavior be, put all the values
# into a single event object with the last written time of the key?
event_object = windows_events.WindowsRegistryEvent(
timestamp, key.path, text_dict, offset=key.offset,
registry_type=registry_type,
source_append=': WinRAR History')
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
winreg.WinRegistryParser.RegisterPlugin(WinRarHistoryPlugin)
@@ -0,0 +1,83 @@
#!/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 WinRAR Windows Registry plugin."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.lib import timelib_test
from plaso.parsers.winreg_plugins import test_lib
from plaso.parsers.winreg_plugins import winrar
from plaso.winreg import test_lib as winreg_test_lib
class WinRarArcHistoryPluginTest(test_lib.RegistryPluginTestCase):
"""Tests for the WinRAR ArcHistory Windows Registry plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = winrar.WinRarHistoryPlugin()
def testProcess(self):
"""Tests the Process function."""
key_path = u'\\Software\\WinRAR\\ArcHistory'
values = []
values.append(winreg_test_lib.TestRegValue(
'0', 'C:\\Downloads\\The Sleeping Dragon CD1.iso'.encode('utf_16_le'),
winreg_test_lib.TestRegValue.REG_SZ, offset=1892))
values.append(winreg_test_lib.TestRegValue(
'1', 'C:\\Downloads\\plaso-static.rar'.encode('utf_16_le'),
winreg_test_lib.TestRegValue.REG_SZ, offset=612))
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2012-08-28 09:23:49.002031')
winreg_key = winreg_test_lib.TestRegKey(
key_path, expected_timestamp, values, offset=1456)
event_queue_consumer = self._ParseKeyWithPlugin(self._plugin, winreg_key)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 2)
event_object = event_objects[0]
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
self.assertEquals(event_object.timestamp, expected_timestamp)
expected_string = (
u'[{0:s}] 0: C:\\Downloads\\The Sleeping Dragon CD1.iso').format(
key_path)
self._TestGetMessageStrings(event_object, expected_string, expected_string)
event_object = event_objects[1]
self.assertEquals(event_object.timestamp, 0)
expected_string = u'[{0:s}] 1: C:\\Downloads\\plaso-static.rar'.format(
key_path)
self._TestGetMessageStrings(event_object, expected_string, expected_string)
if __name__ == '__main__':
unittest.main()
+102
View File
@@ -0,0 +1,102 @@
#!/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.
"""Plug-in to collect information about the Windows version."""
import construct
from plaso.events import windows_events
from plaso.lib import timelib
from plaso.parsers import winreg
from plaso.parsers.winreg_plugins import interface
class WinVerPlugin(interface.KeyPlugin):
"""Plug-in to collect information about the Windows version."""
NAME = 'winreg_winver'
DESCRIPTION = u'Parser for Windows version Registry data.'
REG_KEYS = [u'\\Microsoft\\Windows NT\\CurrentVersion']
REG_TYPE = 'SOFTWARE'
URLS = []
INT_STRUCT = construct.ULInt32('install')
# TODO: Refactor remove this function in a later CL.
def GetValueString(self, key, value_name):
"""Retrieves a specific string value from the Registry key.
Args:
key: A Windows Registry key (instance of WinRegKey).
value_name: The name of the value.
Returns:
A string value if one is available, otherwise an empty string.
"""
value = key.GetValue(value_name)
if not value:
return ''
if not value.data or not value.DataIsString():
return ''
return value.data
def GetEntries(
self, parser_context, key=None, registry_type=None, file_entry=None,
parser_chain=None, **unused_kwargs):
"""Gather minimal information about system install and return an event.
Args:
parser_context: A parser context object (instance of ParserContext).
key: Optional Registry key (instance of winreg.WinRegKey).
The default is None.
registry_type: Optional Registry type string. The default is None.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
"""
text_dict = {}
text_dict[u'Owner'] = self.GetValueString(key, 'RegisteredOwner')
text_dict[u'sp'] = self.GetValueString(key, 'CSDBuildNumber')
text_dict[u'Product name'] = self.GetValueString(key, 'ProductName')
text_dict[u' Windows Version Information'] = u''
install_raw = key.GetValue('InstallDate').raw_data
# TODO: move this to a function in utils with a more descriptive name
# e.g. CopyByteStreamToInt32BigEndian.
try:
install = self.INT_STRUCT.parse(install_raw)
except construct.FieldError:
install = 0
event_object = windows_events.WindowsRegistryEvent(
timelib.Timestamp.FromPosixTime(install), key.path, text_dict,
usage='OS Install Time', offset=key.offset,
registry_type=registry_type, urls=self.URLS)
event_object.prodname = text_dict[u'Product name']
event_object.source_long = 'SOFTWARE WinVersion key'
if text_dict[u'Owner']:
event_object.owner = text_dict[u'Owner']
parser_context.ProduceEvent(
event_object, parser_chain=parser_chain, file_entry=file_entry)
winreg.WinRegistryParser.RegisterPlugin(WinVerPlugin)
@@ -0,0 +1,85 @@
#!/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 WinVer Windows Registry plugin."""
import unittest
# pylint: disable=unused-import
from plaso.formatters import winreg as winreg_formatter
from plaso.lib import timelib_test
from plaso.parsers.winreg_plugins import test_lib
from plaso.parsers.winreg_plugins import winver
from plaso.winreg import test_lib as winreg_test_lib
class WinVerPluginTest(test_lib.RegistryPluginTestCase):
"""Tests for the WinVer Windows Registry plugin."""
def setUp(self):
"""Sets up the needed objects used throughout the test."""
self._plugin = winver.WinVerPlugin()
def testWinVer(self):
"""Test the WinVer plugin."""
key_path = u'\\Microsoft\\Windows NT\\CurrentVersion'
values = []
values.append(winreg_test_lib.TestRegValue(
'ProductName', 'MyTestOS'.encode('utf_16_le'), 1, 123))
values.append(winreg_test_lib.TestRegValue(
'CSDBuildNumber', '5'.encode('utf_16_le'), 1, 1892))
values.append(winreg_test_lib.TestRegValue(
'RegisteredOwner', 'A Concerned Citizen'.encode('utf_16_le'), 1, 612))
values.append(winreg_test_lib.TestRegValue(
'InstallDate', '\x13\x1aAP', 3, 1001))
winreg_key = winreg_test_lib.TestRegKey(
key_path, 1346445929000000, values, 153)
event_queue_consumer = self._ParseKeyWithPlugin(self._plugin, winreg_key)
event_objects = self._GetEventObjectsFromQueue(event_queue_consumer)
self.assertEquals(len(event_objects), 1)
event_object = event_objects[0]
# This should just be the plugin name, as we're invoking it directly,
# and not through the parser.
self.assertEquals(event_object.parser, self._plugin.plugin_name)
expected_timestamp = timelib_test.CopyStringToTimestamp(
'2012-08-31 20:09:55')
self.assertEquals(event_object.timestamp, expected_timestamp)
# Note that the double spaces here are intentional.
expected_msg = (
u'[{0:s}] '
u'Windows Version Information: '
u'Owner: A Concerned Citizen '
u'Product name: MyTestOS sp: 5').format(key_path)
expected_msg_short = (
u'[{0:s}] '
u'Windows Version Information: '
u'Owner: ...').format(key_path)
self._TestGetMessageStrings(event_object, expected_msg, expected_msg_short)
# TODO: Write a test for a non-synthetic key
if __name__ == '__main__':
unittest.main()