Skip to content

Commit

Permalink
346870043: Migrated winreg TaskScheduler construct-based plugin to us…
Browse files Browse the repository at this point in the history
…e dtfabric log2timeline#1893 (log2timeline#2006)

* Migrated winreg TaskScheduler construct-based plugin to use dtfabric log2timeline#1893
  • Loading branch information
joachimmetz authored and Onager committed Jul 10, 2018
1 parent c406158 commit 65fe392
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 38 deletions.
63 changes: 28 additions & 35 deletions plaso/parsers/winreg_plugins/task_scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@

from __future__ import unicode_literals

import construct

from dfdatetime import filetime as dfdatetime_filetime

from plaso.containers import events
from plaso.containers import windows_events
from plaso.containers import time_events
from plaso.lib import definitions
from plaso.lib import errors
from plaso.parsers import winreg
from plaso.parsers.winreg_plugins import dtfabric_plugin
from plaso.parsers.winreg_plugins import interface


Expand All @@ -32,7 +32,8 @@ def __init__(self):
self.task_identifier = None


class TaskCachePlugin(interface.WindowsRegistryPlugin):
class TaskCacheWindowsRegistryPlugin(
dtfabric_plugin.DtFabricBaseWindowsRegistryPlugin):
"""Plugin that parses a Task Cache key."""

NAME = 'windows_task_cache'
Expand All @@ -47,26 +48,7 @@ class TaskCachePlugin(interface.WindowsRegistryPlugin):
'https://github.com/libyal/winreg-kb/blob/master/documentation/'
'Task%20Scheduler%20Keys.asciidoc')]

_DYNAMIC_INFO_STRUCT = construct.Struct(
'dynamic_info_record',
construct.ULInt32('unknown1'),
construct.ULInt64('last_registered_time'),
construct.ULInt64('launch_time'),
construct.ULInt32('unknown2'),
construct.ULInt32('unknown3'))

_DYNAMIC_INFO_STRUCT_SIZE = _DYNAMIC_INFO_STRUCT.sizeof()

_DYNAMIC_INFO2_STRUCT = construct.Struct(
'dynamic_info2_record',
construct.ULInt32('unknown1'),
construct.ULInt64('last_registered_time'),
construct.ULInt64('launch_time'),
construct.ULInt32('unknown2'),
construct.ULInt32('unknown3'),
construct.ULInt64('unknown_time'))

_DYNAMIC_INFO2_STRUCT_SIZE = _DYNAMIC_INFO2_STRUCT.sizeof()
_DEFINITION_FILE = 'task_scheduler.yaml'

def _GetIdValue(self, registry_key):
"""Retrieves the Id value from Task Cache Tree key.
Expand Down Expand Up @@ -122,20 +104,23 @@ def ExtractEvents(self, parser_mediator, registry_key, **kwargs):
guid_string = id_value.GetDataAsObject()
task_guids[guid_string] = value_key.name

dynamic_info_map = self._GetDataTypeMap('dynamic_info_record')
dynamic_info2_map = self._GetDataTypeMap('dynamic_info2_record')

dynamic_info_size = dynamic_info_map.GetByteSize()
dynamic_info2_size = dynamic_info2_map.GetByteSize()

for sub_key in tasks_key.GetSubkeys():
dynamic_info_value = sub_key.GetValueByName('DynamicInfo')
if not dynamic_info_value:
continue

dynamic_info_record_map = None
dynamic_info_value_data_size = len(dynamic_info_value.data)
if dynamic_info_value_data_size == self._DYNAMIC_INFO_STRUCT_SIZE:
dynamic_info_struct = self._DYNAMIC_INFO_STRUCT.parse(
dynamic_info_value.data)

elif dynamic_info_value_data_size == self._DYNAMIC_INFO2_STRUCT_SIZE:
dynamic_info_struct = self._DYNAMIC_INFO_STRUCT.parse(
dynamic_info_value.data)

if dynamic_info_value_data_size == dynamic_info_size:
dynamic_info_record_map = dynamic_info_map
elif dynamic_info_value_data_size == dynamic_info2_size:
dynamic_info_record_map = dynamic_info2_map
else:
if not dynamic_info_size_error_reported:
parser_mediator.ProduceExtractionError(
Expand All @@ -144,6 +129,14 @@ def ExtractEvents(self, parser_mediator, registry_key, **kwargs):
dynamic_info_size_error_reported = True
continue

try:
dynamic_info_record = self._ReadStructureFromByteStream(
dynamic_info_value.data, 0, dynamic_info_record_map)
except (ValueError, errors.ParseError) as exception:
parser_mediator.ProduceExtractionError(
'unable to parse DynamicInfo record with error: {0!s}.'.format(
exception))

name = task_guids.get(sub_key.name, sub_key.name)

values_dict = {}
Expand All @@ -163,7 +156,7 @@ def ExtractEvents(self, parser_mediator, registry_key, **kwargs):
event_data.task_name = name
event_data.task_identifier = sub_key.name

last_registered_time = dynamic_info_struct.get('last_registered_time')
last_registered_time = dynamic_info_record.last_registered_time
if last_registered_time:
# Note this is likely either the last registered time or
# the update time.
Expand All @@ -172,15 +165,15 @@ def ExtractEvents(self, parser_mediator, registry_key, **kwargs):
date_time, 'Last registered time')
parser_mediator.ProduceEventWithEventData(event, event_data)

launch_time = dynamic_info_struct.get('launch_time')
launch_time = dynamic_info_record.launch_time
if launch_time:
# Note this is likely the launch time.
date_time = dfdatetime_filetime.Filetime(timestamp=launch_time)
event = time_events.DateTimeValuesEvent(
date_time, 'Launch time')
parser_mediator.ProduceEventWithEventData(event, event_data)

unknown_time = dynamic_info_struct.get('unknown_time')
unknown_time = getattr(dynamic_info_record, 'unknown_time', None)
if unknown_time:
date_time = dfdatetime_filetime.Filetime(timestamp=unknown_time)
event = time_events.DateTimeValuesEvent(
Expand All @@ -190,4 +183,4 @@ def ExtractEvents(self, parser_mediator, registry_key, **kwargs):
# TODO: Add support for the Triggers value.


winreg.WinRegistryParser.RegisterPlugin(TaskCachePlugin)
winreg.WinRegistryParser.RegisterPlugin(TaskCacheWindowsRegistryPlugin)
52 changes: 52 additions & 0 deletions plaso/parsers/winreg_plugins/task_scheduler.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: task_cache
type: format
description: Task Scheduler Cache format
urls: ["https://github.com/libyal/winreg-kb/blob/master/documentation/Task%20Scheduler%20Keys.asciidoc"]
---
name: uint32
type: integer
attributes:
format: unsigned
size: 4
units: bytes
---
name: uint64
type: integer
attributes:
format: unsigned
size: 8
units: bytes
---
name: dynamic_info_record
type: structure
attributes:
byte_order: little-endian
members:
- name: unknown1
data_type: uint32
- name: last_registered_time
data_type: uint64
- name: launch_time
data_type: uint64
- name: unknown2
data_type: uint32
- name: unknown3
data_type: uint32
---
name: dynamic_info2_record
type: structure
attributes:
byte_order: little-endian
members:
- name: unknown1
data_type: uint32
- name: last_registered_time
data_type: uint64
- name: launch_time
data_type: uint64
- name: unknown2
data_type: uint32
- name: unknown3
data_type: uint32
- name: unknown_time
data_type: uint64
6 changes: 3 additions & 3 deletions tests/parsers/winreg_plugins/task_scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
from tests.parsers.winreg_plugins import test_lib


class TaskCachePluginTest(test_lib.RegistryPluginTestCase):
class TaskCacheWindowsRegistryPluginTest(test_lib.RegistryPluginTestCase):
"""Tests for the Task Cache key Windows Registry plugin."""

def testFilters(self):
"""Tests the FILTERS class attribute."""
plugin = task_scheduler.TaskCachePlugin()
plugin = task_scheduler.TaskCacheWindowsRegistryPlugin()

key_path = (
'HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\'
Expand All @@ -38,7 +38,7 @@ def testProcess(self):
win_registry = self._GetWinRegistryFromFileEntry(test_file_entry)
registry_key = win_registry.GetKeyByPath(key_path)

plugin = task_scheduler.TaskCachePlugin()
plugin = task_scheduler.TaskCacheWindowsRegistryPlugin()
storage_writer = self._ParseKeyWithPlugin(
registry_key, plugin, file_entry=test_file_entry)

Expand Down

0 comments on commit 65fe392

Please sign in to comment.