189 lines
6.6 KiB
Python
189 lines
6.6 KiB
Python
|
#!/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.
|
||
|
"""Parser for Windows NT shell items."""
|
||
|
|
||
|
import pyfwsi
|
||
|
|
||
|
from plaso.events import shell_item_events
|
||
|
from plaso.lib import eventdata
|
||
|
from plaso.winnt import shell_folder_ids
|
||
|
|
||
|
|
||
|
if pyfwsi.get_version() < '20140714':
|
||
|
raise ImportWarning(
|
||
|
u'Shell item support functions require at least pyfwsi 20140714.')
|
||
|
|
||
|
|
||
|
class ShellItemsParser(object):
|
||
|
"""Parses for Windows NT shell items."""
|
||
|
|
||
|
NAME = 'shell_items'
|
||
|
|
||
|
def __init__(self, origin):
|
||
|
"""Initializes the parser.
|
||
|
|
||
|
Args:
|
||
|
origin: A string containing the origin of the event (event source).
|
||
|
"""
|
||
|
super(ShellItemsParser, self).__init__()
|
||
|
self._origin = origin
|
||
|
self._path_segments = []
|
||
|
|
||
|
def _BuildParserChain(self, parser_chain=None):
|
||
|
"""Return the parser chain with the addition of the current parser.
|
||
|
|
||
|
Args:
|
||
|
parser_chain: Optional string containing the parsing chain up to this
|
||
|
point. The default is None.
|
||
|
|
||
|
Returns:
|
||
|
The parser chain, with the addition of the current parser.
|
||
|
"""
|
||
|
if not parser_chain:
|
||
|
return self.NAME
|
||
|
|
||
|
return u'/'.join([parser_chain, self.NAME])
|
||
|
|
||
|
|
||
|
def _ParseShellItem(
|
||
|
self, parser_context, shell_item, file_entry=None, parser_chain=None):
|
||
|
"""Parses a shell item.
|
||
|
|
||
|
Args:
|
||
|
parser_context: A parser context object (instance of ParserContext).
|
||
|
shell_item: the shell item (instance of pyfwsi.item).
|
||
|
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.
|
||
|
"""
|
||
|
path_segment = None
|
||
|
|
||
|
if isinstance(shell_item, pyfwsi.root_folder):
|
||
|
description = shell_folder_ids.DESCRIPTIONS.get(
|
||
|
shell_item.shell_folder_identifier, None)
|
||
|
|
||
|
if description:
|
||
|
path_segment = description
|
||
|
else:
|
||
|
path_segment = u'{{{0:s}}}'.format(shell_item.shell_folder_identifier)
|
||
|
|
||
|
elif isinstance(shell_item, pyfwsi.volume):
|
||
|
if shell_item.name:
|
||
|
path_segment = shell_item.name
|
||
|
elif shell_item.identifier:
|
||
|
path_segment = u'{{{0:s}}}'.format(shell_item.identifier)
|
||
|
|
||
|
elif isinstance(shell_item, pyfwsi.file_entry):
|
||
|
long_name = u''
|
||
|
localized_name = u''
|
||
|
file_reference = u''
|
||
|
for extension_block in shell_item.extension_blocks:
|
||
|
if isinstance(extension_block, pyfwsi.file_entry_extension):
|
||
|
long_name = extension_block.long_name
|
||
|
localized_name = extension_block.localized_name
|
||
|
file_reference = extension_block.file_reference
|
||
|
if file_reference:
|
||
|
file_reference = u'{0:d}-{1:d}'.format(
|
||
|
file_reference & 0xffffffffffff, file_reference >> 48)
|
||
|
|
||
|
fat_date_time = extension_block.get_creation_time_as_integer()
|
||
|
if fat_date_time:
|
||
|
event_object = shell_item_events.ShellItemFileEntryEvent(
|
||
|
fat_date_time, eventdata.EventTimestamp.CREATION_TIME,
|
||
|
shell_item.name, long_name, localized_name, file_reference,
|
||
|
self._origin)
|
||
|
parser_context.ProduceEvent(
|
||
|
event_object, file_entry=file_entry,
|
||
|
parser_chain=parser_chain)
|
||
|
|
||
|
fat_date_time = extension_block.get_access_time_as_integer()
|
||
|
if fat_date_time:
|
||
|
event_object = shell_item_events.ShellItemFileEntryEvent(
|
||
|
fat_date_time, eventdata.EventTimestamp.ACCESS_TIME,
|
||
|
shell_item.name, long_name, localized_name, file_reference,
|
||
|
self._origin)
|
||
|
parser_context.ProduceEvent(
|
||
|
event_object, file_entry=file_entry,
|
||
|
parser_chain=parser_chain)
|
||
|
|
||
|
fat_date_time = shell_item.get_modification_time_as_integer()
|
||
|
if fat_date_time:
|
||
|
event_object = shell_item_events.ShellItemFileEntryEvent(
|
||
|
fat_date_time, eventdata.EventTimestamp.MODIFICATION_TIME,
|
||
|
shell_item.name, long_name, localized_name, file_reference,
|
||
|
self._origin)
|
||
|
parser_context.ProduceEvent(
|
||
|
event_object, file_entry=file_entry,
|
||
|
parser_chain=parser_chain)
|
||
|
|
||
|
if long_name:
|
||
|
path_segment = long_name
|
||
|
elif shell_item.name:
|
||
|
path_segment = shell_item.name
|
||
|
|
||
|
elif isinstance(shell_item, pyfwsi.network_location):
|
||
|
if shell_item.location:
|
||
|
path_segment = shell_item.location
|
||
|
|
||
|
if path_segment is None and shell_item.class_type == 0x00:
|
||
|
# TODO: check for signature 0x23febbee
|
||
|
pass
|
||
|
|
||
|
if path_segment is None:
|
||
|
path_segment = u'UNKNOWN: 0x{0:02x}'.format(shell_item.class_type)
|
||
|
|
||
|
self._path_segments.append(path_segment)
|
||
|
|
||
|
def CopyToPath(self):
|
||
|
"""Copies the shell items to a path.
|
||
|
|
||
|
Returns:
|
||
|
A Unicode string containing the converted shell item list path or None.
|
||
|
"""
|
||
|
if not self._path_segments:
|
||
|
return
|
||
|
|
||
|
return u', '.join(self._path_segments)
|
||
|
|
||
|
def Parse(
|
||
|
self, parser_context, byte_stream, codepage='cp1252',
|
||
|
file_entry=None, parser_chain=None):
|
||
|
"""Parses the shell items from the byte stream.
|
||
|
|
||
|
Args:
|
||
|
parser_context: A parser context object (instance of ParserContext).
|
||
|
byte_stream: a string holding the shell items data.
|
||
|
codepage: Optional byte stream 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._path_segments = []
|
||
|
shell_item_list = pyfwsi.item_list()
|
||
|
shell_item_list.copy_from_byte_stream(byte_stream, ascii_codepage=codepage)
|
||
|
# Add ourselves to the parser chain, so it is used for subsequent object
|
||
|
# creation.
|
||
|
parser_chain = self._BuildParserChain(parser_chain)
|
||
|
|
||
|
for shell_item in shell_item_list.items:
|
||
|
self._ParseShellItem(
|
||
|
parser_context, shell_item, file_entry=file_entry,
|
||
|
parser_chain=parser_chain)
|