Source code for winregrc.scripts.mru

#!/usr/bin/env python3
"""Script to extract Most Recently Used (MRU) information."""

import argparse
import logging
import sys

from dfvfs.lib import errors as dfvfs_errors

import pyfwps
import pyfwsi

from winregrc import mru
from winregrc import output_writers
from winregrc import shell_property_keys
from winregrc import volume_scanner


[docs] class StdoutWriter(output_writers.StdoutOutputWriter): """Stdout output writer.""" def _WritePropertyStore(self, fwps_store): """Writes a property store to stdout. Args: fwps_store (pyfwps.store): property store. Raises: RuntimeError: if a property value type is not supported. """ for fwps_set in iter(fwps_store.sets): for fwps_record in iter(fwps_set.records): if fwps_record.value_type == 0x0001: value_string = "<VT_NULL>" elif fwps_record.value_type in (0x0003, 0x0013, 0x0014, 0x0015): value_string = str(fwps_record.get_data_as_integer()) elif fwps_record.value_type in (0x0008, 0x001E, 0x001F): value_string = fwps_record.get_data_as_string() elif fwps_record.value_type == 0x000B: value_string = str(fwps_record.get_data_as_boolean()) elif fwps_record.value_type == 0x0040: filetime = fwps_record.get_data_as_integer() value_string = self._FormatFiletimeValue(filetime) elif fwps_record.value_type == 0x0042: # TODO: add support value_string = "<VT_STREAM>" elif fwps_record.value_type == 0x0048: value_string = fwps_record.get_data_as_guid() elif fwps_record.value_type & 0xF000 == 0x1000: # TODO: add support value_string = "<VT_VECTOR>" else: raise RuntimeError( f"Unsupported value type: 0x{fwps_record.value_type:04x}" ) if fwps_record.entry_name: entry_string = fwps_record.entry_name else: entry_string = f"{fwps_record.entry_type:d}" property_key = f"{{{fwps_set.identifier:s}}}/{entry_string:s}" shell_property_key = shell_property_keys.SHELL_PROPERTY_KEYS.get( property_key, "Unknown" ) self.WriteText( f"\tProperty: {property_key:s} ({shell_property_key:s})\n" ) self.WriteValue( f"\t\tValue (0x{fwps_record.value_type:04x})", value_string ) def _WriteShellItem(self, fwsi_item): """Writes a shell item to stdout. Args: fwsi_item (pyfwsi.item): Shell item. """ if isinstance(fwsi_item, pyfwsi.compressed_folder): shell_item_type = "Compressed Folder" elif isinstance(fwsi_item, pyfwsi.control_panel_category): shell_item_type = "Control Panel Category" elif isinstance(fwsi_item, pyfwsi.control_panel_item): shell_item_type = "Control Panel Item" elif isinstance(fwsi_item, pyfwsi.file_entry): shell_item_type = "File Entry" elif isinstance(fwsi_item, pyfwsi.network_location): shell_item_type = "Network Location" elif isinstance(fwsi_item, pyfwsi.root_folder): shell_item_type = "Root Folder" elif isinstance(fwsi_item, pyfwsi.users_property_view): shell_item_type = "Users Property View" elif isinstance(fwsi_item, pyfwsi.volume): shell_item_type = "Volume" else: shell_item_type = f"Unknown (0x{fwsi_item.class_type:02x})" self.WriteValue("\tItem type", shell_item_type) if fwsi_item.delegate_folder_identifier: self.WriteValue("\tDelegate folder", fwsi_item.delegate_folder_identifier) if isinstance(fwsi_item, pyfwsi.compressed_folder): self._WriteShellItemCompressedFolder(fwsi_item) elif isinstance(fwsi_item, pyfwsi.control_panel_category): self._WriteShellItemControlPanelCategory(fwsi_item) elif isinstance(fwsi_item, pyfwsi.control_panel_item): self._WriteShellItemControlPanelItem(fwsi_item) elif isinstance(fwsi_item, pyfwsi.file_entry): self._WriteShellItemFileEntry(fwsi_item) elif isinstance(fwsi_item, pyfwsi.network_location): self._WriteShellItemNetworkLocation(fwsi_item) elif isinstance(fwsi_item, pyfwsi.root_folder): self.WriteValue( "\tRoot shell folder identifier", fwsi_item.shell_folder_identifier ) elif isinstance(fwsi_item, pyfwsi.users_property_view): self._WriteShellItemUsersPropertyView(fwsi_item) elif isinstance(fwsi_item, pyfwsi.volume): self._WriteShellItemVolume(fwsi_item) if fwsi_item.number_of_extension_blocks: self.WriteValue( "\tNumber of extension blocks", f"{fwsi_item.number_of_extension_blocks:d}", ) for index, extension_block in enumerate(fwsi_item.extension_blocks): display_index = index + 1 self.WriteText(f"Extension block: {display_index:d}\n") # TODO: print human readable description of signature self.WriteValue("\tSignature", f"0x{extension_block.signature:04x}") if isinstance(extension_block, pyfwsi.file_entry_extension): fat_date_time = extension_block.get_creation_time_as_integer() date_time_string = self._FormatFATDateTimeValue(fat_date_time) self.WriteValue("\tCreation time", date_time_string) fat_date_time = extension_block.get_access_time_as_integer() date_time_string = self._FormatFATDateTimeValue(fat_date_time) self.WriteValue("\tAccess time", date_time_string) self.WriteValue("\tLong name", extension_block.long_name) if extension_block.localized_name: self.WriteValue( "\tLocalized name", extension_block.localized_name ) file_reference = extension_block.file_reference if file_reference is not None: if file_reference > 0x1000000000000: mft_entry = file_reference & 0xFFFFFFFFFFFF sequence_number = file_reference >> 48 file_reference = f"{mft_entry:d}-{sequence_number:d}" else: file_reference = f"0x{file_reference:04x}" self.WriteValue("\tFile reference", file_reference) # TODO: add support for other extension blocks self.WriteText("\n") def _WriteShellItemCompressedFolder(self, fwsi_item): """Writes a compressed folder shell item to stdout. Args: fwsi_item (pyfwsi.compressed_folder): compressed folder shell item. """ self.WriteValue("\tName", fwsi_item.name) def _WriteShellItemControlPanelCategory(self, fwsi_item): """Writes a control panel category shell item to stdout. Args: fwsi_item (pyfwsi.control_panel_category): control panel category shell item. """ self.WriteValue( "\tControl panel category identifier", f"{fwsi_item.identifier:d}" ) def _WriteShellItemControlPanelItem(self, fwsi_item): """Writes a control panel item shell item to stdout. Args: fwsi_item (pyfwsi.control_panel_item): control panel item shell item. """ self.WriteValue("\tControl panel item identifier", fwsi_item.identifier) def _WriteShellItemFileEntry(self, fwsi_item): """Writes a file entry shell item to stdout. Args: fwsi_item (pyfwsi.file_entry): File entry shell item. """ self.WriteValue("\tFile size", f"{fwsi_item.file_size:d}") fat_date_time = fwsi_item.get_modification_time_as_integer() date_time_string = self._FormatFATDateTimeValue(fat_date_time) self.WriteValue("\tModification time", date_time_string) self.WriteValue( "\tFile attribute flags", f"0x08{fwsi_item.file_attribute_flags:08x}" ) self.WriteValue("\tName", fwsi_item.name) def _WriteShellItemNetworkLocation(self, fwsi_item): """Writes a network location shell item to stdout. Args: fwsi_item (pyfwsi.network_location): network location shell item. """ self.WriteValue("\tNetwork location", fwsi_item.location) if fwsi_item.description: self.WriteValue("\tDescription", fwsi_item.description) if fwsi_item.comments: self.WriteValue("\tComments", fwsi_item.comments) def _WriteShellItemUsersPropertyView(self, fwsi_item): """Writes an users property view item to stdout. Args: fwsi_item (pyfwsi.users_property_view): users property view shell item. """ if fwsi_item.property_store_data: fwps_store = pyfwps.store() fwps_store.copy_from_byte_stream(fwsi_item.property_store_data) self._WritePropertyStore(fwps_store) def _WriteShellItemVolume(self, fwsi_item): """Writes a volume shell item to stdout. Args: fwsi_item (pyfwsi.volume): volume shell item. """ if fwsi_item.name: self.WriteValue("\tVolume name", fwsi_item.name) if fwsi_item.identifier: self.WriteValue("\tVolume identifier", fwsi_item.identifier) if fwsi_item.shell_folder_identifier: self.WriteValue( "\tVolume shell folder identifier", fwsi_item.shell_folder_identifier )
[docs] def WriteShellItem(self, fwsi_item): """Writes a shell item to stdout. Args: fwsi_item (pyfwsi.item): Shell item. """ self.WriteText("Shell item:\n") self._WriteShellItem(fwsi_item)
[docs] def WriteShellItemList(self, fwsi_item_list): """Writes a shell item list to stdout. Args: fwsi_item_list (pyfwsi.item_list): Shell item list. """ self.WriteText("Shell item list:\n") self.WriteValue("\tNumber of items", fwsi_item_list.number_of_items) self.WriteText("\n") for item_index, fwsi_item in enumerate(fwsi_item_list.items): display_item_index = item_index + 1 self.WriteText(f"Shell item: {display_item_index:d}\n") self._WriteShellItem(fwsi_item)
[docs] def Main(): """Entry point of console script to extract Most Recently Used information. Returns: int: exit code that is provided to sys.exit(). """ argument_parser = argparse.ArgumentParser( description=( "Extracts Most Recently Used information from a NTUSER.DAT Registry " "file." ) ) argument_parser.add_argument( "-d", "--debug", dest="debug", action="store_true", default=False, help="enable debug output.", ) argument_parser.add_argument( "-u", "--username", dest="username", action="store", metavar="USERNAME", default=None, help="username within a storage media image.", ) argument_parser.add_argument( "source", nargs="?", action="store", metavar="PATH", default=None, help=( "path of the volume containing C:\\Windows, the filename of a storage " "media image containing the C:\\Windows directory, or the path of a " "NTUSER.DAT or UsrClass.dat Registry file." ), ) options = argument_parser.parse_args() if not options.source: print("Source value is missing.") print("") argument_parser.print_help() print("") return 1 logging.basicConfig(level=logging.INFO, format="[%(levelname)s] %(message)s") output_writer = StdoutWriter() if not output_writer.Open(): print("Unable to open output writer.") print("") return 1 mediator = volume_scanner.WindowsRegistryVolumeScannerMediator() scanner = volume_scanner.WindowsRegistryVolumeScanner(mediator=mediator) volume_scanner_options = volume_scanner.VolumeScannerOptions() volume_scanner_options.partitions = ["all"] volume_scanner_options.snapshots = ["none"] volume_scanner_options.username = options.username volume_scanner_options.volumes = ["none"] try: result = scanner.ScanForWindowsVolume( options.source, options=volume_scanner_options ) except dfvfs_errors.ScannerError as exception: print(f"[ERROR] {exception!s}", file=sys.stderr) print("") return 1 except KeyboardInterrupt: print("Aborted by user.", file=sys.stderr) print("") return 1 if not result: print( f"Unable to retrieve the volume with the Windows directory from: " f"{options.source:s}." ) print("") return 1 collector_object = mru.MostRecentlyUsedCollector( debug=options.debug, output_writer=output_writer ) if not collector_object.Collect(scanner.registry): print("No Most Recently Used keys found.") return 0 if not collector_object.mru_entries: print("No Most Recently Used entries found.") return 0 for mru_entry in collector_object.mru_entries: output_writer.WriteValue("Key path", mru_entry.key_path) output_writer.WriteValue("Value name", mru_entry.value_name) if mru_entry.string: output_writer.WriteValue("String", mru_entry.string) output_writer.WriteText("\n") if mru_entry.shell_item_data: fwsi_item = pyfwsi.item() fwsi_item.copy_from_byte_stream(mru_entry.shell_item_data) output_writer.WriteShellItem(fwsi_item) elif mru_entry.shell_item_list_data: shell_item_list = pyfwsi.item_list() shell_item_list.copy_from_byte_stream(mru_entry.shell_item_list_data) output_writer.WriteShellItemList(shell_item_list) output_writer.Close() return 0
if __name__ == "__main__": sys.exit(Main())