Source code for plaso.parsers.olecf_plugins.automatic_destinations

# -*- coding: utf-8 -*-
"""Plugin to parse .automaticDestinations-ms OLECF files."""

import os
import re

from dfdatetime import filetime as dfdatetime_filetime

from plaso.containers import events
from plaso.containers import windows_events
from plaso.lib import dtfabric_helper
from plaso.lib import errors
from plaso.parsers import olecf
from plaso.parsers import winlnk
from plaso.parsers.olecf_plugins import interface


[docs] class AutomaticDestinationsDestListEntryEventData(events.EventData): """.automaticDestinations-ms DestList entry event data. Attributes: birth_droid_file_identifier (str): birth droid file identifier. birth_droid_volume_identifier (str): birth droid volume identifier. droid_file_identifier (str): droid file identifier. droid_volume_identifier (str): droid volume identifier. entry_number (int): DestList entry number. hostname (str): hostname. modification_time (dfdatetime.DateTimeValues): last modification date and time. offset (int): offset of the DestList entry relative to the start of the DestList stream, from which the event data was extracted. path (str): path. pin_status (int): pin status. """ DATA_TYPE = 'olecf:dest_list:entry'
[docs] def __init__(self): """Initializes event data.""" super(AutomaticDestinationsDestListEntryEventData, self).__init__( data_type=self.DATA_TYPE) self.birth_droid_file_identifier = None self.birth_droid_volume_identifier = None self.droid_file_identifier = None self.droid_volume_identifier = None self.entry_number = None self.hostname = None self.modification_time = None self.offset = None self.path = None self.pin_status = None
[docs] class AutomaticDestinationsOLECFPlugin( interface.OLECFPlugin, dtfabric_helper.DtFabricHelper): """Plugin that parses an .automaticDestinations-ms OLECF file.""" NAME = 'olecf_automatic_destinations' DATA_FORMAT = ( 'Automatic destinations jump list OLE compound file ' '(.automaticDestinations-ms)') REQUIRED_ITEMS = frozenset(['DestList']) _DEFINITION_FILE = os.path.join( os.path.dirname(__file__), 'automatic_destinations.yaml') _RE_LNK_ITEM_NAME = re.compile(r'^[1-9a-f][0-9a-f]*$') # We cannot use the parser registry here since winlnk could be disabled. # TODO: see if there is a more elegant solution for this. _WINLNK_PARSER = winlnk.WinLnkParser() def _ParseDistributedTrackingIdentifier( self, parser_mediator, uuid_object, origin): """Extracts data from a Distributed Tracking identifier. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfVFS. uuid_object (uuid.UUID): UUID of the Distributed Tracking identifier. origin (str): origin of the event (event source). Returns: str: UUID string of the Distributed Tracking identifier. """ if uuid_object.version == 1: event_data = windows_events.WindowsDistributedLinkTrackingEventData( uuid_object, origin) parser_mediator.ProduceEventData(event_data) return '{{{0!s}}}'.format(uuid_object)
[docs] def ParseDestList(self, parser_mediator, olecf_item): """Parses the DestList OLECF item. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfVFS. olecf_item (pyolecf.item): OLECF item. Raises: WrongParser: if the DestList cannot be parsed. """ # The DestList stream can be of size 0 if the Jump List is empty. if olecf_item.size == 0: return header_map = self._GetDataTypeMap('dest_list_header') try: header, entry_offset = self._ReadStructureFromFileObject( olecf_item, 0, header_map) except (ValueError, errors.ParseError) as exception: raise errors.WrongParser( 'Unable to parse DestList header with error: {0!s}'.format( exception)) if header.format_version == 1: entry_map = self._GetDataTypeMap('dest_list_entry_v1') elif header.format_version in (2, 3, 4): entry_map = self._GetDataTypeMap('dest_list_entry_v2') else: parser_mediator.ProduceExtractionWarning( 'unsupported format version: {0:d}.'.format(header.format_version)) return while entry_offset < olecf_item.size: try: entry, entry_data_size = self._ReadStructureFromFileObject( olecf_item, entry_offset, entry_map) except (ValueError, errors.ParseError) as exception: raise errors.WrongParser( 'Unable to parse DestList entry with error: {0!s}'.format( exception)) display_name = 'DestList entry at offset: 0x{0:08x}'.format(entry_offset) try: droid_volume_identifier = self._ParseDistributedTrackingIdentifier( parser_mediator, entry.droid_volume_identifier, display_name) except (TypeError, ValueError) as exception: droid_volume_identifier = '' parser_mediator.ProduceExtractionWarning( 'unable to read droid volume identifier with error: {0!s}'.format( exception)) try: droid_file_identifier = self._ParseDistributedTrackingIdentifier( parser_mediator, entry.droid_file_identifier, display_name) except (TypeError, ValueError) as exception: droid_file_identifier = '' parser_mediator.ProduceExtractionWarning( 'unable to read droid file identifier with error: {0!s}'.format( exception)) try: birth_droid_volume_identifier = ( self._ParseDistributedTrackingIdentifier( parser_mediator, entry.birth_droid_volume_identifier, display_name)) except (TypeError, ValueError) as exception: birth_droid_volume_identifier = '' parser_mediator.ProduceExtractionWarning(( 'unable to read birth droid volume identifier with error: ' '{0:s}').format( exception)) try: birth_droid_file_identifier = self._ParseDistributedTrackingIdentifier( parser_mediator, entry.birth_droid_file_identifier, display_name) except (TypeError, ValueError) as exception: birth_droid_file_identifier = '' parser_mediator.ProduceExtractionWarning(( 'unable to read birth droid file identifier with error: ' '{0:s}').format( exception)) event_data = AutomaticDestinationsDestListEntryEventData() event_data.birth_droid_file_identifier = birth_droid_file_identifier event_data.birth_droid_volume_identifier = birth_droid_volume_identifier event_data.droid_file_identifier = droid_file_identifier event_data.droid_volume_identifier = droid_volume_identifier event_data.entry_number = entry.entry_number event_data.hostname = entry.hostname or None event_data.offset = entry_offset event_data.path = entry.path or None event_data.pin_status = entry.pin_status if entry.last_modification_time: event_data.modification_time = dfdatetime_filetime.Filetime( timestamp=entry.last_modification_time) parser_mediator.ProduceEventData(event_data) entry_offset += entry_data_size
[docs] def Process(self, parser_mediator, root_item=None, **kwargs): """Extracts events from an OLECF file. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfVFS. root_item (Optional[pyolecf.item]): root item of the OLECF file. Raises: ValueError: If the root_item is not set. """ # This will raise if unhandled keyword arguments are passed. super(AutomaticDestinationsOLECFPlugin, self).Process( parser_mediator, **kwargs) if not root_item: raise ValueError('Root item not set.') for item in root_item.sub_items: if item.name == 'DestList': self.ParseDestList(parser_mediator, item) elif self._RE_LNK_ITEM_NAME.match(item.name): display_name = parser_mediator.GetDisplayName() if display_name: display_name = '{0:s} # {1:s}'.format(display_name, item.name) else: display_name = '# {0:s}'.format(item.name) parser_mediator.AppendToParserChain(self._WINLNK_PARSER.NAME) try: item.seek(0, os.SEEK_SET) self._WINLNK_PARSER.ParseFileLNKFile( parser_mediator, item, display_name) finally: parser_mediator.PopFromParserChain()
# TODO: check for trailing data? olecf.OLECFParser.RegisterPlugin(AutomaticDestinationsOLECFPlugin)