Source code for plaso.parsers.olecf_plugins.summary
# -*- coding: utf-8 -*-
"""Plugin to parse the OLECF summary/document summary information items."""
from __future__ import unicode_literals
from dfdatetime import filetime as dfdatetime_filetime
import pyolecf
from plaso.containers import events
from plaso.containers import time_events
from plaso.lib import definitions
from plaso.lib import py2to3
from plaso.parsers import olecf
from plaso.parsers.olecf_plugins import interface
[docs]class OLECFPropertySetStream(object):
"""OLECF property set stream.
Attributes:
date_time_properties (dict[str, dfdatetime.DateTimeValues]): date and time
properties and values.
"""
_CLASS_IDENTIFIER = None
_INTEGER_TYPES = frozenset([
pyolecf.value_types.INTEGER_16BIT_SIGNED,
pyolecf.value_types.INTEGER_32BIT_SIGNED,
pyolecf.value_types.FILETIME])
_STRING_TYPES = frozenset([
pyolecf.value_types.STRING_ASCII,
pyolecf.value_types.STRING_UNICODE])
_DATE_TIME_PROPERTIES = frozenset([])
_PROPERTY_NAMES = None
_PROPERTY_VALUE_MAPPINGS = None
def __init__(self, olecf_item):
"""Initialize an OLECF property set stream.
Args:
olecf_item (pyolecf.property_set_stream): OLECF item.
"""
super(OLECFPropertySetStream, self).__init__()
self._properties = {}
self.date_time_properties = {}
self._ReadPropertySet(olecf_item.set)
def _GetValueAsObject(self, property_value):
"""Retrieves the property value as a Python object.
Args:
property_value (pyolecf.property_value): OLECF property value.
Returns:
object: property value as a Python object.
"""
if property_value.type == pyolecf.value_types.BOOLEAN:
return property_value.data_as_boolean
elif property_value.type in self._INTEGER_TYPES:
return property_value.data_as_integer
elif property_value.type in self._STRING_TYPES:
return property_value.data_as_string
try:
data = property_value.data
except IOError:
data = None
return data
def _ReadPropertySet(self, property_set):
"""Reads properties from a property set.
Args:
property_set (pyolecf.property_set): OLECF property set.
"""
# Combine the values of multiple property sections
# but do not override properties that are already set.
for property_section in property_set.sections:
if property_section.class_identifier != self._CLASS_IDENTIFIER:
continue
for property_value in property_section.properties:
property_name = self._PROPERTY_NAMES.get(
property_value.identifier, None)
if not property_name:
property_name = '0x{0:04}'.format(property_value.identifier)
value = self._GetValueAsObject(property_value)
if self._PROPERTY_VALUE_MAPPINGS:
value_callback_name = self._PROPERTY_VALUE_MAPPINGS.get(
property_name, None)
if value_callback_name:
value_callback_method = getattr(self, value_callback_name, None)
if value_callback_method:
value = value_callback_method(value)
if property_name in self._DATE_TIME_PROPERTIES:
properties_dict = self.date_time_properties
value = dfdatetime_filetime.Filetime(timestamp=value)
else:
properties_dict = self._properties
if property_name not in properties_dict:
properties_dict[property_name] = value
[docs] def GetEventData(self, data_type):
"""Retrieves the properties as event data.
Args:
data_type (str): event data type.
Returns:
EventData: event data.
"""
event_data = events.EventData(data_type=data_type)
for property_name, property_value in iter(self._properties.items()):
if isinstance(property_value, py2to3.BYTES_TYPE):
property_value = repr(property_value)
setattr(event_data, property_name, property_value)
return event_data
[docs]class OLECFDocumentSummaryInformationEvent(time_events.DateTimeValuesEvent):
"""Convenience class for an OLECF Document summary information event.
Attributes:
name (str): name of the OLECF item.
"""
DATA_TYPE = 'olecf:document_summary_info'
def __init__(self, date_time, date_time_description):
"""Initializes an event.
Args:
date_time (dfdatetime.DateTimeValues): date and time values.
date_time_description (str): description of the meaning of the date
and time values.
"""
super(OLECFDocumentSummaryInformationEvent, self).__init__(
date_time, date_time_description)
self.name = 'Document Summary Information'
[docs]class OLECFSummaryInformationEvent(time_events.DateTimeValuesEvent):
"""Convenience class for an OLECF Summary information event.
Attributes:
name (str): name of the OLECF item.
"""
DATA_TYPE = 'olecf:summary_info'
def __init__(self, date_time, date_time_description):
"""Initializes an event.
Args:
date_time (dfdatetime.DateTimeValues): date and time values.
date_time_description (str): description of the meaning of the date
and time values.
"""
super(OLECFSummaryInformationEvent, self).__init__(
date_time, date_time_description)
self.name = 'Summary Information'
[docs]class OLECFDocumentSummaryInformation(OLECFPropertySetStream):
"""OLECF Document Summary information property set."""
_CLASS_IDENTIFIER = 'd5cdd502-2e9c-101b-9397-08002b2cf9ae'
_PROPERTY_NAMES = {
0x0001: 'codepage', # PIDDSI_CODEPAGE
0x0002: 'category', # PIDDSI_CATEGORY
0x0003: 'presentation_format', # PIDDSI_PRESFORMAT
0x0004: 'number_of_bytes', # PIDDSI_BYTECOUNT
0x0005: 'number_of_lines', # PIDDSI_LINECOUNT
0x0006: 'number_of_paragraphs', # PIDDSI_PARCOUNT
0x0007: 'number_of_slides', # PIDDSI_SLIDECOUNT
0x0008: 'number_of_notes', # PIDDSI_NOTECOUNT
0x0009: 'number_of_hidden_slides', # PIDDSI_HIDDENCOUNT
0x000a: 'number_of_clips', # PIDDSI_MMCLIPCOUNT
0x000b: 'scale', # PIDDSI_SCALE
0x000c: 'heading_pair', # PIDDSI_HEADINGPAIR
0x000d: 'document_parts', # PIDDSI_DOCPARTS
0x000e: 'manager', # PIDDSI_MANAGER
0x000f: 'company', # PIDDSI_COMPANY
0x0010: 'links_dirty', # PIDDSI_LINKSDIRTY
0x0011: 'number_of_characters_with_white_space', # PIDDSI_CCHWITHSPACES
0x0013: 'shared_document', # PIDDSI_SHAREDDOC
0x0017: 'application_version', # PIDDSI_VERSION
0x001a: 'content_type', # PIDDSI_CONTENTTYPE
0x001b: 'content_status', # PIDDSI_CONTENTSTATUS
0x001c: 'language', # PIDDSI_LANGUAGE
0x001d: 'document_version', # PIDDSI_DOCVERSION
}
_PROPERTY_VALUE_MAPPINGS = {
'application_version': '_FormatApplicationVersion',
}
def _FormatApplicationVersion(self, application_version):
"""Formats the application version.
Args:
application_version (int): application version.
Returns:
str: formatted application version.
"""
# The application version consists of 2 16-bit values that make up
# the version number. Where the upper 16-bit is the major number
# and the lower 16-bit the minor number.
return '{0:d}.{1:d}'.format(
application_version >> 16, application_version & 0xffff)
[docs]class OLECFSummaryInformation(OLECFPropertySetStream):
"""OLECF Summary information property set."""
_CLASS_IDENTIFIER = 'f29f85e0-4ff9-1068-ab91-08002b27b3d9'
_DATE_TIME_PROPERTIES = frozenset([
'creation_time', 'last_printed_time', 'last_save_time'])
_PROPERTY_NAMES = {
0x0001: 'codepage', # PIDSI_CODEPAGE
0x0002: 'title', # PIDSI_TITLE
0x0003: 'subject', # PIDSI_SUBJECT
0x0004: 'author', # PIDSI_AUTHOR
0x0005: 'keywords', # PIDSI_KEYWORDS
0x0006: 'comments', # PIDSI_COMMENTS
0x0007: 'template', # PIDSI_TEMPLATE
0x0008: 'last_saved_by', # PIDSI_LASTAUTHOR
0x0009: 'revision_number', # PIDSI_REVNUMBER
0x000a: 'edit_time', # PIDSI_EDITTIME
0x000b: 'last_printed_time', # PIDSI_LASTPRINTED
0x000c: 'creation_time', # PIDSI_CREATE_DTM
0x000d: 'last_save_time', # PIDSI_LASTSAVE_DTM
0x000e: 'number_of_pages', # PIDSI_PAGECOUNT
0x000f: 'number_of_words', # PIDSI_WORDCOUNT
0x0010: 'number_of_characters', # PIDSI_CHARCOUNT
0x0011: 'thumbnail', # PIDSI_THUMBNAIL
0x0012: 'application', # PIDSI_APPNAME
0x0013: 'security', # PIDSI_SECURITY
}
[docs]class DocumentSummaryInformationOLECFPlugin(interface.OLECFPlugin):
"""Plugin that parses DocumentSummaryInformation item from an OLECF file."""
NAME = 'olecf_document_summary'
DESCRIPTION = 'Parser for a DocumentSummaryInformation OLECF stream.'
# pylint: disable=anomalous-backslash-in-string
REQUIRED_ITEMS = frozenset(['\005DocumentSummaryInformation'])
# pylint 1.9.3 wants a docstring for kwargs, but this is not useful to add.
# pylint: disable=missing-param-doc
[docs] def Process(self, parser_mediator, root_item=None, **kwargs):
"""Parses a document summary information OLECF item.
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(DocumentSummaryInformationOLECFPlugin, self).Process(
parser_mediator, **kwargs)
if not root_item:
raise ValueError('Root item not set.')
root_creation_time, root_modification_time = self._GetTimestamps(root_item)
for item_name in self.REQUIRED_ITEMS:
item = root_item.get_sub_item_by_name(item_name)
if not item:
continue
summary_information = OLECFDocumentSummaryInformation(item)
event_data = summary_information.GetEventData(
data_type='olecf:document_summary_info')
event_data.name = 'Document Summary Information'
if root_creation_time:
date_time = dfdatetime_filetime.Filetime(
timestamp=root_creation_time)
event = OLECFDocumentSummaryInformationEvent(
date_time, definitions.TIME_DESCRIPTION_CREATION)
parser_mediator.ProduceEventWithEventData(event, event_data)
if root_modification_time:
date_time = dfdatetime_filetime.Filetime(
timestamp=root_modification_time)
event = OLECFDocumentSummaryInformationEvent(
date_time, definitions.TIME_DESCRIPTION_MODIFICATION)
parser_mediator.ProduceEventWithEventData(event, event_data)
[docs]class SummaryInformationOLECFPlugin(interface.OLECFPlugin):
"""Plugin that parses the SummaryInformation item from an OLECF file."""
NAME = 'olecf_summary'
DESCRIPTION = 'Parser for a SummaryInformation OLECF stream.'
# pylint: disable=anomalous-backslash-in-string
REQUIRED_ITEMS = frozenset(['\005SummaryInformation'])
_DATE_TIME_DESCRIPTIONS = {
'creation_time': 'Document Creation Time',
'last_printed_time': 'Document Last Printed Time',
'last_save_time': 'Document Last Save Time',
}
# pylint 1.9.3 wants a docstring for kwargs, but this is not useful to add.
# pylint: disable=missing-param-doc
[docs] def Process(self, parser_mediator, root_item=None, **kwargs):
"""Parses a summary information OLECF item.
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(SummaryInformationOLECFPlugin, self).Process(
parser_mediator, **kwargs)
if not root_item:
raise ValueError('Root item not set.')
root_creation_time, root_modification_time = self._GetTimestamps(root_item)
for item_name in self.REQUIRED_ITEMS:
item = root_item.get_sub_item_by_name(item_name)
if not item:
continue
summary_information = OLECFSummaryInformation(item)
event_data = summary_information.GetEventData(
data_type='olecf:summary_info')
event_data.name = 'Summary Information'
for property_name, date_time in iter(
summary_information.date_time_properties.items()):
date_time_description = self._DATE_TIME_DESCRIPTIONS.get(
property_name, definitions.TIME_DESCRIPTION_UNKNOWN)
event = OLECFSummaryInformationEvent(date_time, date_time_description)
parser_mediator.ProduceEventWithEventData(event, event_data)
if root_creation_time:
date_time = dfdatetime_filetime.Filetime(
timestamp=root_creation_time)
event = OLECFSummaryInformationEvent(
date_time, definitions.TIME_DESCRIPTION_CREATION)
parser_mediator.ProduceEventWithEventData(event, event_data)
if root_modification_time:
date_time = dfdatetime_filetime.Filetime(
timestamp=root_modification_time)
event = OLECFSummaryInformationEvent(
date_time, definitions.TIME_DESCRIPTION_MODIFICATION)
parser_mediator.ProduceEventWithEventData(event, event_data)
olecf.OLECFParser.RegisterPlugins([
DocumentSummaryInformationOLECFPlugin, SummaryInformationOLECFPlugin])