Source code for plaso.parsers.plist_plugins.macos_login_items

"""Plist parser plugin for Mac OS login items plist files."""

import os

from dfdatetime import hfs_time as dfdatetime_hfs_time

from dtfabric.runtime import data_maps as dtfabric_data_maps

from plaso.containers import events
from plaso.lib import dtfabric_helper
from plaso.lib import errors
from plaso.parsers import plist
from plaso.parsers.plist_plugins import interface


[docs] class MacOSLoginItemEventData(events.EventData): """Mac OS login item event data. Attributes: hidden (bool): whether this login item is hidden. name (str): name. target_creation_time (dfdatetime.DateTimeValues): date and time the target was created. target_path (str): path of the target. volume_creation_time (dfdatetime.DateTimeValues): date and time the (target) volume was created. volume_flags (int): volume flags. volume_mount_point (str): location the volume is mounted on the file system. volume_name (str): name of the volume containing the target. """ DATA_TYPE = "macos:login_items:entry"
[docs] def __init__(self): """Initializes event data.""" super().__init__(data_type=self.DATA_TYPE) self.hidden = None self.name = None self.target_creation_time = None self.target_path = None self.volume_creation_time = None self.volume_flags = None self.volume_mount_point = None self.volume_name = None
[docs] class MacOSLoginItemsPlistPlugin(interface.PlistPlugin, dtfabric_helper.DtFabricHelper): """Plist parser plugin for Mac OS login items.""" NAME = "macos_login_items_plist" DATA_FORMAT = "Mac OS com.apple.loginitems.plist file" PLIST_PATH_FILTERS = frozenset( [interface.PlistPathFilter("com.apple.loginitems.plist")] ) PLIST_KEYS = frozenset(["SessionItems"]) _DEFINITION_FILE = os.path.join(os.path.dirname(__file__), "alias_data.yaml") def _ParseAliasData(self, alias_data, event_data): """Parses alias data. Args: alias_data (bytes): alias data. event_data (MacOSLoginItemEventData): event data. Raises: ParseError: if the value cannot be parsed. """ data_type_map = self._GetDataTypeMap("alias_data_record_header") record_header = self._ReadStructureFromByteStream(alias_data, 0, data_type_map) data_offset = 8 if record_header.application_information != b"\x00\x00\x00\x00": raise errors.ParseError("Unsupported alias application information") if record_header.record_size != len(alias_data): raise errors.ParseError("Unsupported alias record size") # TODO: add format version 2 support, but need test data. data_type_map = self._GetDataTypeMap("alias_data_record_v3") record_data = self._ReadStructureFromByteStream( alias_data[data_offset:], data_offset, data_type_map ) data_offset += 50 hfs_timestamp, _ = divmod(record_data.target_creation_time, 65536) event_data.target_creation_time = dfdatetime_hfs_time.HFSTime( timestamp=hfs_timestamp ) event_data.volume_flags = record_data.volume_flags hfs_timestamp, _ = divmod(record_data.volume_creation_time, 65536) event_data.volume_creation_time = dfdatetime_hfs_time.HFSTime( timestamp=hfs_timestamp ) relative_target_path = None while data_offset < record_header.record_size: data_type_map = self._GetDataTypeMap("alias_data_tagged_value") context = dtfabric_data_maps.DataTypeMapContext() tagged_value = self._ReadStructureFromByteStream( alias_data[data_offset:], data_offset, data_type_map, context=context ) data_offset += context.byte_size if tagged_value.value_tag == 0xFFFF: break if tagged_value.value_tag == 0x000F: event_data.volume_name = tagged_value.string elif tagged_value.value_tag == 0x0012: relative_target_path = tagged_value.string elif tagged_value.value_tag == 0x0013: volume_mount_point = tagged_value.string if relative_target_path: relative_target_path = "".join( [volume_mount_point, relative_target_path] ) event_data.volume_mount_point = volume_mount_point if relative_target_path: event_data.target_path = relative_target_path # pylint: disable=arguments-differ def _ParsePlist(self, parser_mediator, top_level=None, **unused_kwargs): """Extracts login item information from the plist. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfVFS. top_level (Optional[dict[str, object]]): plist top-level item. """ session_items = top_level.get("SessionItems") if not session_items: return for custom_list_item in session_items.get("CustomListItems"): alias_data = custom_list_item.get("Alias") properties = custom_list_item.get("CustomItemProperties", {}) event_data = MacOSLoginItemEventData() event_data.name = custom_list_item.get("Name") event_data.hidden = properties.get( "com.apple.LSSharedFileList.ItemIsHidden", False ) if alias_data is not None: self._ParseAliasData(alias_data, event_data) parser_mediator.ProduceEventData(event_data)
plist.PlistParser.RegisterPlugin(MacOSLoginItemsPlistPlugin)