"""Windows Registry plugin to parse the AMCache.hve Root key."""
import re
from dfdatetime import filetime as dfdatetime_filetime
from dfdatetime import posix_time as dfdatetime_posix_time
from dfdatetime import time_elements as dfdatetime_time_elements
from dfwinreg import errors as dfwinreg_errors
from plaso.containers import events
from plaso.parsers import winreg_parser
from plaso.parsers.winreg_plugins import interface
[docs]
class AMCacheFileEventData(events.EventData):
"""AMCache file event data.
Attributes:
application_key_last_written_time (dfdatetime.DateTimeValues): last written
date and time of the application key.
company_name (str): company name that created product file belongs to.
file_creation_time (dfdatetime.DateTimeValues): file entry creation date
and time.
file_description (str): description of file.
file_identifier (str): identifier of file (SHA-1 of the first 30 MiB
(31457280 bytes) of file, preceded by "0000").
file_modification_time (dfdatetime.DateTimeValues): file entry last
modification date and time.
file_name (str): name of the file.
file_reference (str): file system file reference, for example 9-1 (MFT
entry - sequence number).
file_size (int): size of file in bytes.
file_version (str): version of file.
full_path (str): full path of file.
installation_time (dfdatetime.DateTimeValues): installation date and time.
language_code (int): language code of file.
last_written_time (dfdatetime.DateTimeValues): entry last written date and
time.
link_time (dfdatetime.DateTimeValues): link date and time.
msi_installation_time (dfdatetime.DateTimeValues): MSI installation date
and time.
product_name (str): product name file belongs to.
program_identifier (str): GUID of entry under Root/Program key file belongs
to.
sha1 (str): SHA-1.
"""
DATA_TYPE = "windows:registry:amcache"
[docs]
def __init__(self):
"""Initializes event data."""
super().__init__(data_type=self.DATA_TYPE)
self.application_key_last_written_time = None
self.company_name = None
self.file_creation_time = None
self.file_description = None
self.file_identifier = None
self.file_modification_time = None
self.file_reference = None
self.file_name = None
self.file_size = None
self.file_version = None
self.full_path = None
self.installation_time = None
self.language_code = None
self.last_written_time = None
self.link_time = None
self.msi_installation_time = None
self.product_name = None
self.program_identifier = None
self.sha1 = None
[docs]
class AMCacheProgramEventData(events.EventData):
"""AMCache programs event data.
Attributes:
entry_type (str): type of entry (usually AddRemoveProgram).
file_paths (str): file paths of installed program.
files (str): list of files belonging to program.
installation_time (dfdatetime.DateTimeValues): installation date and time.
language_code (int): language_code of program.
msi_package_code (str): MSI package code of program.
msi_product_code (str): MSI product code of program.
name (str): name of installed program.
package_code (str): package code of program.
product_code (str): product code of program.
publisher (str): publisher of program.
uninstall_key (str): unicode string of uninstall registry key for program.
version (str): version of program.
"""
DATA_TYPE = "windows:registry:amcache:programs"
[docs]
def __init__(self):
"""Initializes event data."""
super().__init__(data_type=self.DATA_TYPE)
self.entry_type = None
self.file_paths = None
self.files = None
self.installation_time = None
self.language_code = None
self.msi_package_code = None
self.msi_product_code = None
self.name = None
self.package_code = None
self.product_code = None
self.publisher = None
self.uninstall_key = None
self.version = None
[docs]
class AMCachePlugin(interface.WindowsRegistryPlugin):
"""AMCache.hve Windows Registry plugin."""
NAME = "amcache"
DATA_FORMAT = "AMCache (AMCache.hve)"
FILTERS = frozenset([interface.WindowsRegistryKeyPathFilter("\\Root")])
# Contains: {value name: attribute name}
_APPLICATION_SUB_KEY_VALUES = {
"FileId": "file_identifier",
"LowerCaseLongPath": "full_path",
"Name": "file_name",
"ProductName": "product_name",
"ProductVersion": "file_version",
"ProgramId": "program_identifier",
"Publisher": "company_name",
"Size": "file_size",
}
_FILE_REFERENCE_KEY_VALUES = {
"0": "product_name",
"1": "company_name",
"3": "language_code",
"5": "file_version",
"6": "file_size",
"c": "file_description",
"15": "full_path",
"100": "program_identifier",
"101": "sha1",
}
_AMCACHE_LINK_TIME = "f"
_AMCACHE_FILE_MODIFICATION_TIME = "11"
_AMCACHE_FILE_CREATION_TIME = "12"
_AMCACHE_ENTRY_WRITE_TIME = "17"
_AMCACHE_P_INSTALLATION_TIME = "a"
_AMCACHE_P_FILES = "Files"
# Date and time string formatted as: "MM/DD/YYYY hh:mm:ss"
# for example "04/07/2014 15:18:49"
# TODO: determine if this is true for other locales.
_LINK_DATE_TIME_RE = re.compile(
r"([0-9][0-9])/([0-9][0-9])/([0-9][0-9][0-9][0-9]) "
r"([0-9][0-9]):([0-9][0-9]):([0-9][0-9])"
)
_PRODUCT_KEY_VALUES = {
"0": "name",
"1": "version",
"2": "publisher",
"3": "language_code",
"6": "entry_type",
"7": "uninstall_key",
"d": "file_paths",
"f": "product_code",
"10": "package_code",
"11": "msi_product_code",
"12": "msi_package_code",
}
def _GetValueDataAsObject(
self, parser_mediator, key_path, value_name, registry_value
):
"""Retrieves the value data as an object from a Windows Registry value.
Args:
parser_mediator (ParserMediator): mediates interactions between parsers
and other components, such as storage and dfVFS.
key_path (str): key path.
value_name (str): name of the value.
registry_value (dfwinreg.WinRegistryValue): Windows Registry value.
Returns:
object: value data or None when the value data cannot be determined.
"""
if registry_value.data is None:
return "(empty)"
try:
value_object = registry_value.GetDataAsObject()
if registry_value.DataIsMultiString():
value_object = list(value_object)
elif (
not registry_value.DataIsInteger() and not registry_value.DataIsString()
):
# Represent remaining types like REG_BINARY and
# REG_RESOURCE_REQUIREMENT_LIST.
value_object = registry_value.data
except dfwinreg_errors.WinRegistryValueError as exception:
parser_mediator.ProduceRecoveryWarning(
(
f"Unable to retrieve value data of type: "
f"{registry_value.data_type_string,:s} as object from value: "
f"{value_name:s} in key: {key_path:s} with error: {exception!s}"
)
)
value_object = None
return value_object
def _ParseApplicationSubKey(self, parser_mediator, application_sub_key):
"""Parses a Root\\InventoryApplicationFile\\%NAME%|%IDENTIFIER% key.
Args:
parser_mediator (ParserMediator): mediates interactions between parsers
and other components, such as storage and dfVFS.
application_sub_key (dfwinreg.WinRegistryKey): application sub key of the
InventoryApplicationFile Windows Registry key.
"""
event_data = AMCacheFileEventData()
for value_name, attribute_name in self._APPLICATION_SUB_KEY_VALUES.items():
value = application_sub_key.GetValueByName(value_name)
if value:
value_data = self._GetValueDataAsObject(
parser_mediator, application_sub_key.path, value_name, value
)
setattr(event_data, attribute_name, value_data)
install_date_value = application_sub_key.GetValueByName("InstallDate")
if install_date_value:
event_data.installation_time = self._ParseDateStringValue(
parser_mediator, application_sub_key.path, install_date_value
)
install_date_msi_value = application_sub_key.GetValueByName("InstallDateMsi")
if install_date_msi_value:
event_data.msi_installation_time = self._ParseDateStringValue(
parser_mediator, application_sub_key.path, install_date_msi_value
)
link_date_value = application_sub_key.GetValueByName("LinkDate")
if link_date_value:
event_data.link_time = self._ParseDateStringValue(
parser_mediator, application_sub_key.path, link_date_value
)
event_data.application_key_last_written_time = (
application_sub_key.last_written_time
)
parser_mediator.ProduceEventData(event_data)
def _ParseDateStringValue(self, parser_mediator, key_path, registry_value):
"""Parses a date and time string value.
Args:
parser_mediator (ParserMediator): mediates interactions between parsers
and other components, such as storage and dfVFS.
key_path (str): key path.
registry_value (dfwinreg.WinRegistryValue): Windows Registry value.
Returns:
dfdatetime_time_elements.TimeElements: date and time value or None
if not available.
"""
if not registry_value.DataIsString():
parser_mediator.ProduceExtractionWarning(
(
f"unsupported {registry_value.name:s} with value data type: "
f"{registry_value.data_type_string:s} in key: {key_path:s}"
)
)
return None
date_time_string = registry_value.GetDataAsObject()
if not date_time_string:
parser_mediator.ProduceExtractionWarning(
f"missing {registry_value.name:s} value data in key: {key_path:s}"
)
return None
re_match = self._LINK_DATE_TIME_RE.match(date_time_string)
if not re_match:
parser_mediator.ProduceExtractionWarning(
(
f"unsupported {registry_value.name:s} value data: "
f"{date_time_string!s} in key: {key_path:s}"
)
)
return None
month, day_of_month, year, hours, minutes, seconds = re_match.groups()
try:
year = int(year, 10)
month = int(month, 10)
day_of_month = int(day_of_month, 10)
hours = int(hours, 10)
minutes = int(minutes, 10)
seconds = int(seconds, 10)
except (TypeError, ValueError):
parser_mediator.ProduceExtractionWarning(
(
f"invalid {registry_value.name:s} date time value: "
f"{date_time_string!s} in key: {key_path:s}"
)
)
return None
time_elements_tuple = (year, month, day_of_month, hours, minutes, seconds)
try:
date_time = dfdatetime_time_elements.TimeElements(
time_elements_tuple=time_elements_tuple
)
except ValueError:
parser_mediator.ProduceExtractionWarning(
(
f"invalid {registry_value.name:s} date time value: "
f"{time_elements_tuple!s} in key: {key_path:s}"
)
)
return None
return date_time
def _ParseFileKey(self, parser_mediator, file_key):
"""Parses a Root\\File key.
Args:
parser_mediator (ParserMediator): mediates interactions between parsers
and other components, such as storage and dfVFS.
file_key (dfwinreg.WinRegistryKey): the File Windows Registry key.
"""
for volume_key in file_key.GetSubkeys():
for file_reference_key in volume_key.GetSubkeys():
self._ParseFileReferenceKey(parser_mediator, file_reference_key)
def _ParseFileReferenceKey(self, parser_mediator, file_reference_key):
"""Parses a file reference key (sub key of Root\\File\\%VOLUME%) for events.
Args:
parser_mediator (ParserMediator): mediates interactions between parsers
and other components, such as storage and dfVFS.
file_reference_key (dfwinreg.WinRegistryKey): file reference Windows
Registry key.
"""
event_data = AMCacheFileEventData()
try:
if "0000" in file_reference_key.name:
# A NTFS file reference is a combination of MFT entry and sequence
# number.
sequence_number, mft_entry = file_reference_key.name.split("0000")
mft_entry = int(mft_entry, 16)
sequence_number = int(sequence_number, 16)
event_data.file_reference = f"{mft_entry:d}-{sequence_number:d}"
else:
# A FAT file reference is the offset of the corresponding directory
# entry.
file_reference = int(file_reference_key.name, 16)
event_data.file_reference = f"{file_reference:d}"
except (ValueError, TypeError):
pass
for value_name, attribute_name in self._FILE_REFERENCE_KEY_VALUES.items():
value = file_reference_key.GetValueByName(value_name)
if not value:
continue
value_data = self._GetValueDataAsObject(
parser_mediator, file_reference_key.path, value_name, value
)
if attribute_name == "sha1" and value_data.startswith("0000"):
# Strip off the 4 leading zero's from the sha1 hash.
value_data = value_data[4:]
setattr(event_data, attribute_name, value_data)
write_time_value = file_reference_key.GetValueByName(
self._AMCACHE_ENTRY_WRITE_TIME
)
if write_time_value:
timestamp = write_time_value.GetDataAsObject()
event_data.last_written_time = dfdatetime_filetime.Filetime(
timestamp=timestamp
)
creation_time_value = file_reference_key.GetValueByName(
self._AMCACHE_FILE_CREATION_TIME
)
if creation_time_value:
timestamp = creation_time_value.GetDataAsObject()
event_data.file_creation_time = dfdatetime_filetime.Filetime(
timestamp=timestamp
)
modification_time_value = file_reference_key.GetValueByName(
self._AMCACHE_FILE_MODIFICATION_TIME
)
if modification_time_value:
timestamp = modification_time_value.GetDataAsObject()
event_data.file_modification_time = dfdatetime_filetime.Filetime(
timestamp=timestamp
)
link_time_value = file_reference_key.GetValueByName(self._AMCACHE_LINK_TIME)
if link_time_value:
timestamp = link_time_value.GetDataAsObject()
event_data.link_time = dfdatetime_posix_time.PosixTime(timestamp=timestamp)
parser_mediator.ProduceEventData(event_data)
def _ParseInventoryApplicationFileKey(
self, parser_mediator, inventory_application_file_key
):
"""Parses a Root\\InventoryApplicationFile key.
Args:
parser_mediator (ParserMediator): mediates interactions between parsers
and other components, such as storage and dfVFS.
inventory_application_file_key (dfwinreg.WinRegistryKey): the
InventoryApplicationFile Windows Registry key.
"""
for application_sub_key in inventory_application_file_key.GetSubkeys():
self._ParseApplicationSubKey(parser_mediator, application_sub_key)
def _ParseProgramKey(self, parser_mediator, program_key):
"""Parses a program key (a sub key of Root\\Programs) for events.
Args:
parser_mediator (ParserMediator): mediates interactions between parsers
and other components, such as storage and dfVFS.
program_key (dfwinreg.WinRegistryKey): program Windows Registry key.
"""
event_data = AMCacheProgramEventData()
for value_name, attribute_name in self._PRODUCT_KEY_VALUES.items():
value = program_key.GetValueByName(value_name)
if value:
value_data = self._GetValueDataAsObject(
parser_mediator, program_key.path, value_name, value
)
setattr(event_data, attribute_name, value_data)
installation_time_value = program_key.GetValueByName(
self._AMCACHE_P_INSTALLATION_TIME
)
if installation_time_value:
timestamp = installation_time_value.GetDataAsObject()
event_data.installation_time = dfdatetime_posix_time.PosixTime(
timestamp=timestamp
)
parser_mediator.ProduceEventData(event_data)
def _ParseProgramsKey(self, parser_mediator, programs_key):
"""Parses a Root\\Programs key.
Args:
parser_mediator (ParserMediator): mediates interactions between parsers
and other components, such as storage and dfVFS.
programs_key (dfwinreg.WinRegistryKey): the Programs Windows Registry key.
"""
for program_key in programs_key.GetSubkeys():
self._ParseProgramKey(parser_mediator, program_key)
def _ParseRootKey(self, parser_mediator, root_key):
"""Parses a Root key.
Args:
parser_mediator (ParserMediator): mediates interactions between parsers
and other components, such as storage and dfVFS.
root_key (dfwinreg.WinRegistryKey): the Root Windows Registry key.
"""
self._ProduceDefaultWindowsRegistryEvent(parser_mediator, root_key)
for sub_key in root_key.GetSubkeys():
self._ParseSubKey(parser_mediator, sub_key)
if sub_key.name == "File":
self._ParseFileKey(parser_mediator, sub_key)
elif sub_key.name == "InventoryApplicationFile":
self._ParseInventoryApplicationFileKey(parser_mediator, sub_key)
elif sub_key.name == "Programs":
self._ParseProgramsKey(parser_mediator, sub_key)
def _ParseSubKey(self, parser_mediator, registry_key):
"""Parses a sub key.
Args:
parser_mediator (ParserMediator): mediates interactions between parsers
and other components, such as storage and dfVFS.
registry_key (dfwinreg.WinRegistryKey): the Windows Registry key.
"""
self._ProduceDefaultWindowsRegistryEvent(parser_mediator, registry_key)
for sub_key in registry_key.GetSubkeys():
self._ParseSubKey(parser_mediator, sub_key)
winreg_parser.WinRegistryParser.RegisterPlugin(AMCachePlugin)