diff --git a/plaso/containers/plist_event.py b/plaso/containers/plist_event.py index 2caeef5006..dfa258fbab 100644 --- a/plaso/containers/plist_event.py +++ b/plaso/containers/plist_event.py @@ -4,14 +4,15 @@ from plaso.containers import events from plaso.containers import time_events from plaso.lib import eventdata +from plaso.lib import timelib -class PlistEvent(time_events.PythonDatetimeEvent): +class PlistEvent(time_events.TimestampEvent): """Convenience class for a plist events.""" DATA_TYPE = u'plist:key' - def __init__(self, root, key, timestamp, desc=None, host=None, user=None): + def __init__(self, root, key, datetime_time, desc=None, host=None, user=None): """Template for creating a Plist EventObject for returning data to Plaso. All events extracted from files get passed around Plaso internally as an @@ -21,13 +22,14 @@ def __init__(self, root, key, timestamp, desc=None, host=None, user=None): the appropriate formatter for converting these attributes to output. Args: - root: A string representing the path from the root to this key. - key: A string representing the name of key. - timestamp: The date object (instance of datetime.datetime). - desc: An optional string intended for the user describing the event. - host: An optional host name if one is available within the log file. - user: An optional user name if one is available within the log file. + root (str): path from the root to this key. + key (str): name of key. + datetime_time (datetime.datetime): datetime. + desc (Optional[str]): description. + host (Optional[str]): name of host. + user (Optional[str]): name of user. """ + timestamp = timelib.Timestamp.FromPythonDatetime(datetime_time) super(PlistEvent, self).__init__( timestamp, eventdata.EventTimestamp.WRITTEN_TIME) diff --git a/plaso/containers/time_events.py b/plaso/containers/time_events.py index 7f258d3d43..c7862b0d8a 100644 --- a/plaso/containers/time_events.py +++ b/plaso/containers/time_events.py @@ -55,52 +55,3 @@ def __init__( super(DateTimeValuesEvent, self).__init__( timestamp, date_time_description, data_type=data_type) - - -class PythonDatetimeEvent(TimestampEvent): - """Convenience class for a Python DateTime time-based event.""" - - def __init__(self, datetime_time, timestamp_description, data_type=None): - """Initializes an event. - - Args: - datetime_time (datetime.datetime): datetime. - timestamp_description (str): description of the meaning of the timestamp - value. - data_type (Optional[str]): event data type. If the data type is not set - it is derived from the DATA_TYPE class attribute. - """ - timestamp = timelib.Timestamp.FromPythonDatetime(datetime_time) - super(PythonDatetimeEvent, self).__init__( - timestamp, timestamp_description, data_type=data_type) - - -class UUIDTimeEvent(TimestampEvent): - """Convenience class for an UUID version time-based event. - - Attributes: - mac_address (str): MAC address stored in the UUID. - """ - - def __init__(self, uuid, timestamp_description): - """Initializes an event. - - Args: - uuid (uuid.UUID): UUID. - timestamp_description (str): description of the meaning of the timestamp - value. - - Raises: - ValueError: if the UUID version is not supported. - """ - if uuid.version != 1: - raise ValueError(u'Unsupported UUID version.') - - timestamp = timelib.Timestamp.FromUUIDTime(uuid.time) - mac_address = u'{0:s}:{1:s}:{2:s}:{3:s}:{4:s}:{5:s}'.format( - uuid.hex[20:22], uuid.hex[22:24], uuid.hex[24:26], uuid.hex[26:28], - uuid.hex[28:30], uuid.hex[30:32]) - super(UUIDTimeEvent, self).__init__(timestamp, timestamp_description) - - self.mac_address = mac_address - self.uuid = u'{0!s}'.format(uuid) diff --git a/plaso/containers/windows_events.py b/plaso/containers/windows_events.py index 94015bdfeb..04c31afeb3 100644 --- a/plaso/containers/windows_events.py +++ b/plaso/containers/windows_events.py @@ -2,17 +2,17 @@ """This file contains the Windows specific event object classes.""" from plaso.containers import events -from plaso.containers import time_events -from plaso.lib import eventdata -class WindowsDistributedLinkTrackingCreationEvent(time_events.UUIDTimeEvent): - """Convenience class for a Windows distributed link creation event. +class WindowsDistributedLinkTrackingEventData(events.EventData): + """Windows distributed link event data. Attributes: - origin: a string containing the origin of the event (event source). - E.g. the path of the corresponding LNK file or file reference - MFT entry with the corresponding NTFS $OBJECT_ID attribute. + mac_address (str): MAC address stored in the UUID. + origin (str): origin of the event (event source). + E.g. the path of the corresponding LNK file or file reference + MFT entry with the corresponding NTFS $OBJECT_ID attribute. + uuid (str): UUID. """ DATA_TYPE = u'windows:distributed_link_tracking:creation' @@ -21,16 +21,27 @@ def __init__(self, uuid, origin): """Initializes an event object. Args: - uuid: an uuid object (instance of uuid.UUID). - origin: a string containing the origin of the event (event source). - E.g. the path of the corresponding LNK file or file reference - MFT entry with the corresponding NTFS $OBJECT_ID attribute. + uuid (uuid.UUID): UUID. + origin (str): origin of the event (event source). + E.g. the path of the corresponding LNK file or file reference + MFT entry with the corresponding NTFS $OBJECT_ID attribute. + + Raises: + ValueError: if the UUID version is not supported. """ - super(WindowsDistributedLinkTrackingCreationEvent, self).__init__( - uuid, eventdata.EventTimestamp.CREATION_TIME) + if uuid.version != 1: + raise ValueError(u'Unsupported UUID version.') + + mac_address = u'{0:s}:{1:s}:{2:s}:{3:s}:{4:s}:{5:s}'.format( + uuid.hex[20:22], uuid.hex[22:24], uuid.hex[24:26], uuid.hex[26:28], + uuid.hex[28:30], uuid.hex[30:32]) + super(WindowsDistributedLinkTrackingEventData, self).__init__( + data_type=self.DATA_TYPE) + self.mac_address = mac_address # TODO: replace origin my something machine readable. self.origin = origin + self.uuid = u'{0!s}'.format(uuid) class WindowsRegistryInstallationEventData(events.EventData): diff --git a/plaso/lib/timelib.py b/plaso/lib/timelib.py index 52a9ba0bc4..554e6c058f 100644 --- a/plaso/lib/timelib.py +++ b/plaso/lib/timelib.py @@ -70,9 +70,6 @@ class Timestamp(object): # The multiplication factor to change milliseconds to micro seconds. MILLI_SECONDS_TO_MICRO_SECONDS = 1000 - # The difference between Nov 10, 1582 and Jan 1, 1970 in 100 nanoseconds. - UUID_TIME_TO_POSIX_BASE = 12219292800 * 10000000 - @classmethod def CopyFromString(cls, time_string): """Copies a timestamp from a string containing a date and time value. @@ -530,29 +527,6 @@ def FromTimeString( return cls.FromPythonDatetime(datetime_object) - @classmethod - def FromUUIDTime(cls, uuid_time): - """Converts a UUID verion 1 time into a timestamp. - - The UUID version 1 time is a 60-bit value containing: - 100th nano seconds since 1582-10-15 00:00:00 - - Args: - uuid_time: The 60-bit UUID version 1 timestamp. - - Returns: - The timestamp which is an integer containing the number of micro seconds - since January 1, 1970, 00:00:00 UTC or 0 on error. - """ - # TODO: Add a handling for if the timestamp equals to zero. - if uuid_time < 0: - return 0 - timestamp = (uuid_time - cls.UUID_TIME_TO_POSIX_BASE) / 10 - - if timestamp > cls.TIMESTAMP_MAX_MICRO_SECONDS: - return 0 - return timestamp - @classmethod def GetNow(cls): """Retrieves the current time (now) as a timestamp in UTC. diff --git a/plaso/parsers/ntfs.py b/plaso/parsers/ntfs.py index 59a3503188..2d54d1ea18 100644 --- a/plaso/parsers/ntfs.py +++ b/plaso/parsers/ntfs.py @@ -8,6 +8,7 @@ from dfdatetime import filetime as dfdatetime_filetime from dfdatetime import semantic_time as dfdatetime_semantic_time +from dfdatetime import uuid_time as dfdatetime_uuid_time from plaso import dependencies from plaso.containers import events @@ -103,6 +104,26 @@ def GetFormatSpecification(cls): format_specification.AddNewSignature(b'FILE', offset=0) return format_specification + def _ParseDistributedTrackingIdentifier( + self, parser_mediator, uuid_string, 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_string (str): UUID string of the Distributed Tracking identifier. + origin (str): origin of the event (event source). + """ + uuid_object = uuid.UUID(uuid_string) + + if uuid_object.version == 1: + event_data = windows_events.WindowsDistributedLinkTrackingEventData( + uuid_object, origin) + date_time = dfdatetime_uuid_time.UUIDTime(timestamp=uuid_object.time) + event = time_events.DateTimeValuesEvent( + date_time, eventdata.EventTimestamp.CREATION_TIME) + parser_mediator.ProduceEventWithEventData(event, event_data) + def _ParseMFTAttribute(self, parser_mediator, mft_entry, mft_attribute): """Extract data from a NFTS $MFT attribute. @@ -218,12 +239,9 @@ def _ParseMFTAttribute(self, parser_mediator, mft_entry, mft_attribute): if mft_attribute.droid_file_identifier: try: - uuid_object = uuid.UUID(mft_attribute.droid_file_identifier) - if uuid_object.version == 1: - event_object = ( - windows_events.WindowsDistributedLinkTrackingCreationEvent( - uuid_object, display_name)) - parser_mediator.ProduceEvent(event_object) + self._ParseDistributedTrackingIdentifier( + parser_mediator, mft_attribute.droid_file_identifier, + display_name) except (TypeError, ValueError) as exception: parser_mediator.ProduceExtractionError(( @@ -233,12 +251,9 @@ def _ParseMFTAttribute(self, parser_mediator, mft_entry, mft_attribute): if mft_attribute.birth_droid_file_identifier: try: - uuid_object = uuid.UUID(mft_attribute.birth_droid_file_identifier) - if uuid_object.version == 1: - event_object = ( - windows_events.WindowsDistributedLinkTrackingCreationEvent( - uuid_object, display_name)) - parser_mediator.ProduceEvent(event_object) + self._ParseDistributedTrackingIdentifier( + parser_mediator, mft_attribute.droid_file_identifier, + display_name) except (TypeError, ValueError) as exception: parser_mediator.ProduceExtractionError(( @@ -247,7 +262,7 @@ def _ParseMFTAttribute(self, parser_mediator, mft_entry, mft_attribute): mft_attribute.attribute_type, exception)) def _ParseMFTEntry(self, parser_mediator, mft_entry): - """Extract data from a NFTS $MFT entry. + """Extracts data from a NFTS $MFT entry. Args: parser_mediator (ParserMediator): mediates interactions between parsers diff --git a/plaso/parsers/olecf_plugins/automatic_destinations.py b/plaso/parsers/olecf_plugins/automatic_destinations.py index c6f965988e..862ccc24ed 100644 --- a/plaso/parsers/olecf_plugins/automatic_destinations.py +++ b/plaso/parsers/olecf_plugins/automatic_destinations.py @@ -8,6 +8,7 @@ from dfdatetime import filetime as dfdatetime_filetime from dfdatetime import semantic_time as dfdatetime_semantic_time +from dfdatetime import uuid_time as dfdatetime_uuid_time from plaso.containers import time_events from plaso.containers import windows_events @@ -134,6 +135,31 @@ class AutomaticDestinationsOLECFPlugin(interface.OLECFPlugin): construct.String(u'path', lambda ctx: ctx.path_size * 2), construct.Padding(4)) + def _ParseDistributedTrackingIdentifier( + self, parser_mediator, uuid_data, 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_data (bytes): UUID data of the Distributed Tracking identifier. + origin (str): origin of the event (event source). + + Returns: + str: UUID string of the Distributed Tracking identifier. + """ + uuid_object = uuid.UUID(bytes_le=uuid_data) + + if uuid_object.version == 1: + event_data = windows_events.WindowsDistributedLinkTrackingEventData( + uuid_object, origin) + date_time = dfdatetime_uuid_time.UUIDTime(timestamp=uuid_object.time) + event = time_events.DateTimeValuesEvent( + date_time, eventdata.EventTimestamp.CREATION_TIME) + parser_mediator.ProduceEventWithEventData(event, event_data) + + return u'{{{0!s}}}'.format(uuid_object) + def ParseDestList(self, parser_mediator, olecf_item): """Parses the DestList OLECF item. @@ -173,13 +199,8 @@ def ParseDestList(self, parser_mediator, olecf_item): display_name = u'DestList entry at offset: 0x{0:08x}'.format(entry_offset) try: - uuid_object = uuid.UUID(bytes_le=entry.droid_volume_identifier) - droid_volume_identifier = u'{{{0!s}}}'.format(uuid_object) - - if uuid_object.version == 1: - event = windows_events.WindowsDistributedLinkTrackingCreationEvent( - uuid_object, display_name) - parser_mediator.ProduceEvent(event) + droid_volume_identifier = self._ParseDistributedTrackingIdentifier( + parser_mediator, entry.droid_volume_identifier, display_name) except (TypeError, ValueError) as exception: droid_volume_identifier = u'' @@ -188,13 +209,8 @@ def ParseDestList(self, parser_mediator, olecf_item): exception)) try: - uuid_object = uuid.UUID(bytes_le=entry.droid_file_identifier) - droid_file_identifier = u'{{{0!s}}}'.format(uuid_object) - - if uuid_object.version == 1: - event = windows_events.WindowsDistributedLinkTrackingCreationEvent( - uuid_object, display_name) - parser_mediator.ProduceEvent(event) + droid_file_identifier = self._ParseDistributedTrackingIdentifier( + parser_mediator, entry.droid_file_identifier, display_name) except (TypeError, ValueError) as exception: droid_file_identifier = u'' @@ -203,13 +219,10 @@ def ParseDestList(self, parser_mediator, olecf_item): exception)) try: - uuid_object = uuid.UUID(bytes_le=entry.birth_droid_volume_identifier) - birth_droid_volume_identifier = u'{{{0!s}}}'.format(uuid_object) - - if uuid_object.version == 1: - event = windows_events.WindowsDistributedLinkTrackingCreationEvent( - uuid_object, display_name) - parser_mediator.ProduceEvent(event) + birth_droid_volume_identifier = ( + self._ParseDistributedTrackingIdentifier( + parser_mediator, entry.birth_droid_volume_identifier, + display_name)) except (TypeError, ValueError) as exception: birth_droid_volume_identifier = u'' @@ -219,13 +232,8 @@ def ParseDestList(self, parser_mediator, olecf_item): exception)) try: - uuid_object = uuid.UUID(bytes_le=entry.birth_droid_file_identifier) - birth_droid_file_identifier = u'{{{0!s}}}'.format(uuid_object) - - if uuid_object.version == 1: - event = windows_events.WindowsDistributedLinkTrackingCreationEvent( - uuid_object, display_name) - parser_mediator.ProduceEvent(event) + birth_droid_file_identifier = self._ParseDistributedTrackingIdentifier( + parser_mediator, entry.birth_droid_file_identifier, display_name) except (TypeError, ValueError) as exception: birth_droid_file_identifier = u'' diff --git a/plaso/parsers/plist_plugins/ipod.py b/plaso/parsers/plist_plugins/ipod.py index 590636c554..29d95d1d9b 100644 --- a/plaso/parsers/plist_plugins/ipod.py +++ b/plaso/parsers/plist_plugins/ipod.py @@ -1,36 +1,28 @@ # -*- coding: utf-8 -*- """This file contains a plist plugin for the iPod/iPhone storage plist.""" +from plaso.containers import events from plaso.containers import time_events from plaso.lib import eventdata +from plaso.lib import timelib from plaso.parsers import plist from plaso.parsers.plist_plugins import interface -class IPodPlistEvent(time_events.PythonDatetimeEvent): - """An event object for an entry in the iPod plist file.""" +# TODO: add more attributes. +class IPodPlistEventData(events.Eventdata): + """iPod plist event data. - DATA_TYPE = u'ipod:device:entry' - - def __init__(self, datetime_timestamp, device_id, device_info): - """Initialize the event. - - Args: - datetime_timestamp: The timestamp for the event as a datetime object. - device_id: The device ID. - device_info: A dict that contains extracted information from the plist. - """ - super(IPodPlistEvent, self).__init__( - datetime_timestamp, eventdata.EventTimestamp.LAST_CONNECTED) + Attributes: + device_id (str): unique identifier of the iPod device. + """ - self.device_id = device_id + DATA_TYPE = u'ipod:device:entry' - # Save the other attributes. - for key, value in iter(device_info.items()): - if key == u'Connected': - continue - attribute_name = key.lower().replace(u' ', u'_') - setattr(self, attribute_name, value) + def __init__(self): + """Initializes event data.""" + super(IPodPlistEventData, self).__init__(data_type=self.DATA_TYPE) + self.device_id = None class IPodPlugin(interface.PlistPlugin): @@ -50,19 +42,26 @@ def GetEntries(self, parser_mediator, match=None, **unused_kwargs): and other components, such as storage and dfvfs. match (Optional[dict[str: object]]): keys extracted from PLIST_KEYS. """ - if not u'Devices' in match: - return + devices = match.get(u'Devices', {}) + for device_identifier, device_information in iter(devices.items()): + connected_time = device_information.get(u'Connected', None) + if not connected_time: + continue - devices = match[u'Devices'] - if not devices: - return + event_data = IPodPlistEventData() + event_data.device_id = device_identifier - for device, device_info in iter(devices.items()): - if u'Connected' not in device_info: - continue - event_object = IPodPlistEvent( - device_info.get(u'Connected'), device, device_info) - parser_mediator.ProduceEvent(event_object) + # TODO: refactor. + for key, value in iter(device_information.items()): + if key == u'Connected': + continue + attribute_name = key.lower().replace(u' ', u'_') + setattr(self, attribute_name, value) + + timestamp = timelib.Timestamp.FromPythonDatetime(connected_time) + event = time_events.TimestampEvent( + timestamp, eventdata.EventTimestamp.LAST_CONNECTED) + parser_mediator.ProduceEventWithEventData(event, event_data) plist.PlistParser.RegisterPlugin(IPodPlugin) diff --git a/plaso/parsers/winlnk.py b/plaso/parsers/winlnk.py index 7c61ad5e94..a19e1a1137 100644 --- a/plaso/parsers/winlnk.py +++ b/plaso/parsers/winlnk.py @@ -7,6 +7,7 @@ from dfdatetime import filetime as dfdatetime_filetime from dfdatetime import semantic_time as dfdatetime_semantic_time +from dfdatetime import uuid_time as dfdatetime_uuid_time from plaso import dependencies from plaso.containers import time_events @@ -108,6 +109,26 @@ def GetFormatSpecification(cls): offset=4) return format_specification + def _ParseDistributedTrackingIdentifier( + self, parser_mediator, uuid_string, 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_string (str): UUID string of the Distributed Tracking identifier. + origin (str): origin of the event (event source). + """ + uuid_object = uuid.UUID(uuid_string) + + if uuid_object.version == 1: + event_data = windows_events.WindowsDistributedLinkTrackingEventData( + uuid_object, origin) + date_time = dfdatetime_uuid_time.UUIDTime(timestamp=uuid_object.time) + event = time_events.DateTimeValuesEvent( + date_time, eventdata.EventTimestamp.CREATION_TIME) + parser_mediator.ProduceEventWithEventData(event, event_data) + def ParseFileObject( self, parser_mediator, file_object, display_name=None, **kwargs): """Parses a Windows Shortcut (LNK) file-like object. @@ -173,23 +194,23 @@ def ParseFileObject( date_time, eventdata.EventTimestamp.NOT_A_TIME, lnk_file, link_target) parser_mediator.ProduceEvent(event) - try: - uuid_object = uuid.UUID(lnk_file.droid_file_identifier) - if uuid_object.version == 1: - event = windows_events.WindowsDistributedLinkTrackingCreationEvent( - uuid_object, display_name) - parser_mediator.ProduceEvent(event) - except (TypeError, ValueError): - pass - - try: - uuid_object = uuid.UUID(lnk_file.birth_droid_file_identifier) - if uuid_object.version == 1: - event = windows_events.WindowsDistributedLinkTrackingCreationEvent( - uuid_object, display_name) - parser_mediator.ProduceEvent(event) - except (TypeError, ValueError): - pass + if lnk_file.droid_file_identifier: + try: + self._ParseDistributedTrackingIdentifier( + parser_mediator, lnk_file.droid_file_identifier, display_name) + except (TypeError, ValueError) as exception: + parser_mediator.ProduceExtractionError( + u'unable to read droid file identifier with error: {0:s}.'.format( + exception)) + + if lnk_file.birth_droid_file_identifier: + try: + self._ParseDistributedTrackingIdentifier( + parser_mediator, lnk_file.birth_droid_file_identifier, display_name) + except (TypeError, ValueError) as exception: + parser_mediator.ProduceExtractionError(( + u'unable to read birth droid file identifier with error: ' + u'{0:s}.').format(exception)) lnk_file.close() diff --git a/tests/lib/timelib.py b/tests/lib/timelib.py index d9e317bb15..5acafa5419 100644 --- a/tests/lib/timelib.py +++ b/tests/lib/timelib.py @@ -4,7 +4,6 @@ import datetime import unittest -import uuid from plaso.lib import errors from plaso.lib import timelib @@ -182,25 +181,6 @@ def testTimestampFromPosixTime(self): # POSIX time that exceeds lower bound. self.assertEqual(timelib.Timestamp.FromPosixTime(-9223372036855), 0) - def testTimestampFromUUIDTime(self): - """Test the UUID time conversion.""" - uuid_object = uuid.UUID(u'00911b54-9ef4-11e1-be53-525400123456') - - timestamp = timelib.Timestamp.FromUUIDTime(uuid_object.time) - expected_timestamp = timelib.Timestamp.CopyFromString( - u'2012-05-16 01:11:01.654408') - self.assertEqual(timestamp, expected_timestamp) - - uuid_time = 86400 * 10000000 - timestamp = timelib.Timestamp.FromUUIDTime(uuid_time) - expected_timestamp = timelib.Timestamp.CopyFromString( - u'1582-10-16 00:00:00') - self.assertEqual(timestamp, expected_timestamp) - - # UUID time that exceeds lower bound. - uuid_time = -1 - self.assertEqual(timelib.Timestamp.FromUUIDTime(uuid_time), 0) - def testMonthDict(self): """Test the month dict, both inside and outside of scope.""" self.assertEqual(timelib.MONTH_DICT[u'nov'], 11)