209 lines
8.4 KiB
Python
209 lines
8.4 KiB
Python
#!/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)
|