Skip to content

Commit

Permalink
Migrated winreg MRUList construct-based plugin to use dtfabric log2ti…
Browse files Browse the repository at this point in the history
…meline#1893 (log2timeline#2030)

* Migrated winreg MRUList construct-based plugin to use dtfabric log2timeline#1893
  • Loading branch information
joachimmetz authored and Onager committed Jul 13, 2018
1 parent bd88505 commit b8f8a4e
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 41 deletions.
17 changes: 17 additions & 0 deletions plaso/parsers/winreg_plugins/mru.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: mru
type: format
description: Most recently used (MRU) format
urls: ["https://github.com/libyal/winreg-kb/blob/master/documentation/MRU%20keys.asciidoc"]
---
name: uint16
type: integer
attributes:
format: unsigned
size: 2
units: bytes
---
name: mrulist_entries
type: sequence
description: MRUList entries
element_data_type: uint16
elements_terminator: 0
71 changes: 39 additions & 32 deletions plaso/parsers/winreg_plugins/mrulist.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@

import abc

import construct

from plaso.containers import time_events
from plaso.containers import windows_events
from plaso.lib import definitions
from plaso.lib import binary
from plaso.lib import errors
from plaso.parsers import logger
from plaso.parsers import winreg
from plaso.parsers.shared import shell_items
from plaso.parsers.winreg_plugins import dtfabric_plugin
from plaso.parsers.winreg_plugins import interface


Expand Down Expand Up @@ -48,13 +48,14 @@ def Match(self, registry_key):
return super(MRUListStringRegistryKeyFilter, self).Match(registry_key)


class BaseMRUListPlugin(interface.WindowsRegistryPlugin):
class BaseMRUListWindowsRegistryPlugin(
dtfabric_plugin.DtFabricBaseWindowsRegistryPlugin):
"""Class for common MRUList Windows Registry plugin functionality."""

_MRULIST_STRUCT = construct.Range(1, 500, construct.ULInt16('entry_letter'))

_SOURCE_APPEND = ': MRU List'

_DEFINITION_FILE = 'mru.yaml'

@abc.abstractmethod
def _ParseMRUListEntryValue(
self, parser_mediator, registry_key, entry_index, entry_letter, **kwargs):
Expand All @@ -80,23 +81,18 @@ def _ParseMRUListValue(self, registry_key):
the MRUList value.
Returns:
generator: MRUList value generator, which returns the MRU index number
and entry value.
mrulist_entries: MRUList entries or None if not available.
"""
mru_list_value = registry_key.GetValueByName('MRUList')
mrulist_value = registry_key.GetValueByName('MRUList')

# The key exists but does not contain a value named "MRUList".
if not mru_list_value:
return enumerate([])
if not mrulist_value:
return None

try:
mru_list = self._MRULIST_STRUCT.parse(mru_list_value.data)
except construct.FieldError:
logger.warning('[{0:s}] Unable to parse the MRU key: {1:s}'.format(
self.NAME, registry_key.path))
return enumerate([])
mrulist_entries_map = self._GetDataTypeMap('mrulist_entries')

return enumerate(mru_list)
return self._ReadStructureFromByteStream(
mrulist_value.data, 0, mrulist_entries_map)

def _ParseMRUListKey(self, parser_mediator, registry_key, codepage='cp1252'):
"""Extract event objects from a MRUList Registry key.
Expand All @@ -107,10 +103,19 @@ def _ParseMRUListKey(self, parser_mediator, registry_key, codepage='cp1252'):
registry_key (dfwinreg.WinRegistryKey): Windows Registry key.
codepage (Optional[str]): extended ASCII string codepage.
"""
try:
mrulist = self._ParseMRUListValue(registry_key)
except (ValueError, errors.ParseError) as exception:
parser_mediator.ProduceExtractionError(
'unable to parse MRUList value with error: {0!s}'.format(exception))
return

if not mrulist:
return

values_dict = {}
for entry_index, entry_letter in self._ParseMRUListValue(registry_key):
# TODO: detect if list ends prematurely.
# MRU lists are terminated with \0 (0x0000).
for entry_index, entry_letter in enumerate(mrulist):
# The MRU list is terminated with '\0' (0x0000).
if entry_letter == 0:
break

Expand All @@ -136,7 +141,7 @@ def _ParseMRUListKey(self, parser_mediator, registry_key, codepage='cp1252'):
parser_mediator.ProduceEventWithEventData(event, event_data)


class MRUListStringPlugin(BaseMRUListPlugin):
class MRUListStringWindowsRegistryPlugin(BaseMRUListWindowsRegistryPlugin):
"""Windows Registry plugin to parse a string MRUList."""

NAME = 'mrulist_string'
Expand Down Expand Up @@ -165,9 +170,9 @@ def _ParseMRUListEntryValue(

value = registry_key.GetValueByName('{0:s}'.format(entry_letter))
if value is None:
logger.debug(
'[{0:s}] Missing MRUList entry value: {1:s} in key: {2:s}.'.format(
self.NAME, entry_letter, registry_key.path))
parser_mediator.ProduceExtractionError(
'missing MRUList value: {0:s} in key: {1:s}.'.format(
entry_letter, registry_key.path))

elif value.DataIsString():
value_string = value.GetDataAsObject()
Expand Down Expand Up @@ -204,7 +209,8 @@ def ExtractEvents(
self._ParseMRUListKey(parser_mediator, registry_key, codepage=codepage)


class MRUListShellItemListPlugin(BaseMRUListPlugin):
class MRUListShellItemListWindowsRegistryPlugin(
BaseMRUListWindowsRegistryPlugin):
"""Windows Registry plugin to parse a shell item list MRUList."""

NAME = 'mrulist_shell_item_list'
Expand Down Expand Up @@ -239,14 +245,14 @@ def _ParseMRUListEntryValue(

value = registry_key.GetValueByName('{0:s}'.format(entry_letter))
if value is None:
logger.debug(
'[{0:s}] Missing MRUList entry value: {1:s} in key: {2:s}.'.format(
self.NAME, entry_letter, registry_key.path))
parser_mediator.ProduceExtractionError(
'missing MRUList value: {0:s} in key: {1:s}.'.format(
entry_letter, registry_key.path))

elif not value.DataIsBinaryData():
logger.debug((
'[{0:s}] Non-binary MRUList entry value: {1:s} in key: '
'{2:s}.').format(self.NAME, entry_letter, registry_key.path))
parser_mediator.ProduceExtractionError(
'Non-binary MRUList entry value: {1:s} in key: {2:s}.'.format(
entry_letter, registry_key.path))

elif value.data:
shell_items_parser = shell_items.ShellItemsParser(registry_key.path)
Expand All @@ -273,4 +279,5 @@ def ExtractEvents(


winreg.WinRegistryParser.RegisterPlugins([
MRUListStringPlugin, MRUListShellItemListPlugin])
MRUListStringWindowsRegistryPlugin,
MRUListShellItemListWindowsRegistryPlugin])
19 changes: 10 additions & 9 deletions tests/parsers/winreg_plugins/mrulist.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from tests.parsers.winreg_plugins import test_lib


class TestMRUListStringPlugin(test_lib.RegistryPluginTestCase):
class TestMRUListStringWindowsRegistryPlugin(test_lib.RegistryPluginTestCase):
"""Tests for the string MRUList plugin."""

def _CreateTestKey(self, key_path, time_string):
Expand All @@ -35,7 +35,7 @@ def _CreateTestKey(self, key_path, time_string):
'MRU', key_path=key_path, last_written_time=filetime.timestamp,
offset=1456)

value_data = 'acb'.encode('utf_16_le')
value_data = b'a\x00c\x00b\x00\x00\x00'
registry_value = dfwinreg_fake.FakeWinRegistryValue(
'MRUList', data=value_data, data_type=dfwinreg_definitions.REG_SZ,
offset=123)
Expand Down Expand Up @@ -63,7 +63,7 @@ def _CreateTestKey(self, key_path, time_string):

def testFilters(self):
"""Tests the FILTERS class attribute."""
plugin = mrulist.MRUListStringPlugin()
plugin = mrulist.MRUListStringWindowsRegistryPlugin()

key_path = (
'HKEY_CURRENT_USER\\Software\\Microsoft\\Some Windows\\'
Expand Down Expand Up @@ -98,7 +98,7 @@ def testProcess(self):
time_string = '2012-08-28 09:23:49.002031'
registry_key = self._CreateTestKey(key_path, time_string)

plugin = mrulist.MRUListStringPlugin()
plugin = mrulist.MRUListStringWindowsRegistryPlugin()
storage_writer = self._ParseKeyWithPlugin(registry_key, plugin)

self.assertEqual(storage_writer.number_of_events, 1)
Expand All @@ -123,7 +123,8 @@ def testProcess(self):
self._TestGetMessageStrings(event, expected_message, expected_short_message)


class TestMRUListShellItemListPlugin(test_lib.RegistryPluginTestCase):
class TestMRUListShellItemListWindowsRegistryPlugin(
test_lib.RegistryPluginTestCase):
"""Tests for the shell item list MRUList plugin."""

def _CreateTestKey(self, key_path, time_string):
Expand All @@ -142,13 +143,13 @@ def _CreateTestKey(self, key_path, time_string):
'DesktopStreamMRU', key_path=key_path,
last_written_time=filetime.timestamp, offset=1456)

value_data = 'a'.encode('utf_16_le')
value_data = b'a\x00\x00\x00'
registry_value = dfwinreg_fake.FakeWinRegistryValue(
'MRUList', data=value_data, data_type=dfwinreg_definitions.REG_SZ,
offset=123)
registry_key.AddValue(registry_value)

value_data = b''.join(map(chr, [
value_data = bytes(bytearray([
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,
Expand All @@ -172,7 +173,7 @@ def _CreateTestKey(self, key_path, time_string):

def testFilters(self):
"""Tests the FILTERS class attribute."""
plugin = mrulist.MRUListShellItemListPlugin()
plugin = mrulist.MRUListShellItemListWindowsRegistryPlugin()

key_path = (
'HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\'
Expand All @@ -189,7 +190,7 @@ def testProcess(self):
time_string = '2012-08-28 09:23:49.002031'
registry_key = self._CreateTestKey(key_path, time_string)

plugin = mrulist.MRUListShellItemListPlugin()
plugin = mrulist.MRUListShellItemListWindowsRegistryPlugin()
storage_writer = self._ParseKeyWithPlugin(registry_key, plugin)

self.assertEqual(storage_writer.number_of_events, 5)
Expand Down

0 comments on commit b8f8a4e

Please sign in to comment.