def ParseDynamicInfo(self, value_data, cached_task): """Parses the DynamicInfo value data. Args: value_data (bytes): DynamicInfo value data. cached_task (CachedTask): cached task. Raises: ParseError: if the value data could not be parsed. """ if self._debug: self._output_writer.WriteDebugData('DynamicInfo value data:', value_data) value_data_size = len(value_data) if value_data_size == 28: data_type_map = self._GetDataTypeMap('dynamic_info_record') elif value_data_size == 36: data_type_map = self._GetDataTypeMap('dynamic_info2_record') if not data_type_map: raise errors.ParseError( 'Unsupported value data size: {0:d}.'.format(value_data_size)) try: dynamic_info = data_type_map.MapByteStream(value_data) except (dtfabric_errors.ByteStreamTooSmallError, dtfabric_errors.MappingError) as exception: raise errors.ParseError(exception) cached_task.last_registered_time = self._ParseFiletime( dynamic_info.last_registered_time) cached_task.launch_time = self._ParseFiletime(dynamic_info.launch_time) if self._debug: value_string = '0x{0:08x}'.format(dynamic_info.unknown1) self._output_writer.WriteValue('Unknown1', value_string) # Note this is likely either the last registered time or # the update time. self._DebugPrintFiletimeValue('Last registered time', dynamic_info.last_registered_time) # Note this is likely the launch time. self._DebugPrintFiletimeValue('Launch time', dynamic_info.launch_time) value_string = '0x{0:08x}'.format(dynamic_info.unknown2) self._output_writer.WriteValue('Unknown2', value_string) value_string = '0x{0:08x}'.format(dynamic_info.unknown3) self._output_writer.WriteValue('Unknown3', value_string) if dynamic_info.unknown_time is not None: self._DebugPrintFiletimeValue('Unknown time', dynamic_info.unknown_time) self._output_writer.WriteText('')
def _ParseMountedDevicesValue(self, registry_value): """Parses a Windows mounted devices Windows Registry value. Args: registry_value (dfwinreg.WinRegistryValue): a mounted devices Windows Registry value. Returns: MountedDevice: a mounted device. Raises: ParseError: if the value could not be parsed. """ mounted_device = MountedDevice(registry_value.name) value_data_size = len(registry_value.data) if value_data_size == 12: data_type_map = self._GetDataTypeMap( 'mounted_devices_mbr_partition') try: partition_values = self._ReadStructureFromByteStream( registry_value.data, 0, data_type_map, 'Mounted devices MBR partition values') except (ValueError, errors.ParseError) as exception: raise errors.ParseError(( 'Unable to parse Mounted devices MBR partition values with ' 'error: {0!s}').format(exception)) mounted_device.disk_identity = partition_values.disk_identity mounted_device.partition_offset = partition_values.partition_offset elif value_data_size == 24: data_type_map = self._GetDataTypeMap( 'mounted_devices_gpt_partition') try: partition_values = self._ReadStructureFromByteStream( registry_value.data, 0, data_type_map, 'Mounted devices GPT partition values') except (ValueError, errors.ParseError) as exception: raise errors.ParseError(( 'Unable to parse Mounted devices GPT partition values with ' 'error: {0!s}').format(exception)) mounted_device.partition_identifier = ( partition_values.partition_identifier) else: mounted_device.device = registry_value.data.decode('utf-16-le') return mounted_device
def _ReadStructureFromByteStream( self, byte_stream, file_offset, data_type_map, description, context=None): """Reads a structure from a byte stream. Args: byte_stream (bytes): byte stream. file_offset (int): offset of the structure data relative to the start of the file-like object. data_type_map (dtfabric.DataTypeMap): data type map of the structure. description (str): description of the structure. context (Optional[dtfabric.DataTypeMapContext]): data type map context. Returns: object: structure values object. Raises: ParseError: if the structure cannot be read. ValueError: if file-like object or data type map is missing. """ if not byte_stream: raise ValueError('Missing byte stream.') if not data_type_map: raise ValueError('Missing data type map.') try: return data_type_map.MapByteStream(byte_stream, context=context) except (dtfabric_errors.ByteStreamTooSmallError, dtfabric_errors.MappingError) as exception: raise errors.ParseError(( 'Unable to map {0:s} data at offset: 0x{1:08x} with error: ' '{2!s}').format(description, file_offset, exception))
def ParseTZIValue(self, value_data, time_zone): """Parses the TZI value data. Args: value_data (bytes): TZI value data. time_zone (TimeZone): time zone. Raises: ParseError: if the value data could not be parsed. """ data_type_map = self._GetDataTypeMap('tzi_record') try: tzi_record = self._ReadStructureFromByteStream( value_data, 0, data_type_map, 'TZI record') except (ValueError, errors.ParseError) as exception: raise errors.ParseError( 'Unable to parse TZI record value with error: {0!s}'.format( exception)) if self._debug: self._DebugPrintStructureObject(tzi_record, self._DEBUG_INFO_TZI_RECORD) if tzi_record.standard_bias: time_zone.offset = tzi_record.standard_bias else: time_zone.offset = tzi_record.bias
def _GetCachedEntryDataTypeMap(self, format_type, value_data, cached_entry_offset): """Determines the cached entry data type map. Args: format_type (int): format type. value_data (bytes): value data. cached_entry_offset (int): offset of the first cached entry data relative to the start of the value data. Returns: dtfabric.DataTypeMap: data type map which contains a data type definition, such as a structure, that can be mapped onto binary data or None if the data type map is not defined. Raises: ParseError: if the cached entry data type map cannot be determined. """ if format_type not in self._SUPPORTED_FORMAT_TYPES: raise errors.ParseError( 'Unsupported format type: {0:d}'.format(format_type)) data_type_map_name = '' if format_type == self._FORMAT_TYPE_XP: data_type_map_name = 'appcompatcache_cached_entry_xp_32bit' elif format_type in (self._FORMAT_TYPE_8, self._FORMAT_TYPE_10): data_type_map_name = 'appcompatcache_cached_entry_header_8' else: cached_entry = self._ParseCommon2003CachedEntry( value_data, cached_entry_offset) # Assume the entry is 64-bit if the 32-bit path offset is 0 and # the 64-bit path offset is set. if (cached_entry.path_offset_32bit == 0 and cached_entry.path_offset_64bit != 0): number_of_bits = '64' else: number_of_bits = '32' if format_type == self._FORMAT_TYPE_2003: data_type_map_name = ( 'appcompatcache_cached_entry_2003_{0:s}bit'.format( number_of_bits)) elif format_type == self._FORMAT_TYPE_VISTA: data_type_map_name = ( 'appcompatcache_cached_entry_vista_{0:s}bit'.format( number_of_bits)) elif format_type == self._FORMAT_TYPE_7: data_type_map_name = ('appcompatcache_cached_entry_7_{0:s}bit'. format(number_of_bits)) return self._GetDataTypeMap(data_type_map_name)
def _ParseCommon2003CachedEntry(self, value_data, cached_entry_offset): """Parses the cached entry structure common for Windows 2003, Vista and 7. Args: value_data (bytes): value data. cached_entry_offset (int): offset of the first cached entry data relative to the start of the value data. Returns: appcompatcache_cached_entry_2003_common: cached entry structure common for Windows 2003, Windows Vista and Windows 7. Raises: ParseError: if the value data could not be parsed. """ cached_entry_data = value_data[cached_entry_offset:] data_type_map = self._GetDataTypeMap( 'appcompatcache_cached_entry_2003_common') try: cached_entry = self._ReadStructureFromByteStream( cached_entry_data, cached_entry_offset, data_type_map, 'cached entry') except (ValueError, errors.ParseError) as exception: raise errors.ParseError( 'Unable to parse cached entry value with error: {0!s}'.format( exception)) if cached_entry.path_size > cached_entry.maximum_path_size: raise errors.ParseError('Path size value out of bounds.') path_end_of_string_size = (cached_entry.maximum_path_size - cached_entry.path_size) if cached_entry.path_size == 0 or path_end_of_string_size != 2: raise errors.ParseError('Unsupported path size values.') return cached_entry
def ParseEntry(self, format_version, entry_data): """Parses an UserAssist entry. Args: format_version (int): format version. entry_data (bytes): entry data. Returns: user_assist_entry_v3|user_assist_entry_v5: UserAssist entry. Raises: ParseError: if the value data could not be parsed. """ if format_version == 3: data_type_map = self._GetDataTypeMap('user_assist_entry_v3') entry_data_size = 16 elif format_version == 5: data_type_map = self._GetDataTypeMap('user_assist_entry_v5') entry_data_size = 72 if entry_data_size != len(entry_data): raise errors.ParseError( ('Version: {0:d} size mismatch (calculated: {1:d}, ' 'stored: {2:d}).').format(format_version, entry_data_size, len(entry_data))) try: user_assist_entry = self._ReadStructureFromByteStream( entry_data, 0, data_type_map, 'UserAssist entry') except (ValueError, errors.ParseError) as exception: raise errors.ParseError( 'Unable to parse UserAssist entry value with error: {0!s}'. format(exception)) if self._debug: self._DebugPrintEntry(format_version, user_assist_entry) return user_assist_entry
def _ParseHeader(self, value_data): """Parses a header from the value data. Args: value_data (bytes): value data. Returns: tuple: contains: programscache_header: header. int: header data size. Raises: ParseError: if the header could not be parsed. """ data_type_map = self._GetDataTypeMap('programscache_header') data_size = data_type_map.GetByteSize() if self._debug: self._DebugPrintData('Header data', value_data[:data_size]) try: header = self._ReadStructureFromByteStream(value_data, 0, data_type_map, 'header') except (ValueError, errors.ParseError) as exception: raise errors.ParseError( 'Unable to parse header value with error: {0!s}'.format( exception)) if self._debug: self._DebugPrintHeader(header) if header.format_version not in (1, 9, 12, 19): raise errors.ParseError('Unsupported format.') return header, data_size
def ParseCValue(self, value_data): """Parses the C value data. Args: value_data (bytes): F value data. Raises: ParseError: if the value data could not be parsed. """ data_type_map = self._GetDataTypeMap('c_value') try: c_value = self._ReadStructureFromByteStream( value_data, 0, data_type_map, 'C value') except (ValueError, errors.ParseError) as exception: raise errors.ParseError( 'Unable to parse C value with error: {0!s}'.format(exception)) if self._debug: self._DebugPrintStructureObject(c_value, self._DEBUG_INFO_C_VALUE)
def CheckSignature(self, value_data): """Parses and validates the signature. Args: value_data (bytes): value data. Returns: int: format type or None if format could not be determined. Raises: ParseError: if the value data could not be parsed. """ data_type_map = self._GetDataTypeMap('uint32le') try: signature = self._ReadStructureFromByteStream( value_data, 0, data_type_map, 'signature') except (ValueError, errors.ParseError) as exception: raise errors.ParseError( 'Unable to parse signature value with error: {0!s}'.format( exception)) format_type = self._HEADER_SIGNATURES.get(signature, None) if format_type == self._FORMAT_TYPE_2003: # TODO: determine which format version is used (2003 or Vista). return self._FORMAT_TYPE_2003 if format_type == self._FORMAT_TYPE_8: cached_entry_signature = value_data[signature:signature + 4] if cached_entry_signature in (self._CACHED_ENTRY_SIGNATURE_8_0, self._CACHED_ENTRY_SIGNATURE_8_1): return self._FORMAT_TYPE_8 elif format_type == self._FORMAT_TYPE_10: # Windows 10 uses the same cache entry signature as Windows 8.1 cached_entry_signature = value_data[signature:signature + 4] if cached_entry_signature == self._CACHED_ENTRY_SIGNATURE_8_1: return self._FORMAT_TYPE_10 return format_type
def _ParseEntryFooter(self, value_data, value_data_offset): """Parses an entry footer from the value data. Args: value_data (bytes): value data. value_data_offset (int): offset of the entry footer relative to the start of the value data. Returns: tuple: contains: programscache_entry_footer: entry footer. int: entry footer data size. Raises: ParseError: if the entry footer could not be parsed. """ data_type_map = self._GetDataTypeMap('programscache_entry_footer') data_size = data_type_map.GetByteSize() if self._debug: self._DebugPrintData( 'Entry footer data', value_data[value_data_offset:value_data_offset + data_size]) try: entry_footer = self._ReadStructureFromByteStream( value_data[value_data_offset:], value_data_offset, data_type_map, 'entry footer') except (ValueError, errors.ParseError) as exception: raise errors.ParseError( 'Unable to parse entry footer value with error: {0!s}'.format( exception)) if self._debug: self._DebugPrintEntryFooter(entry_footer) return entry_footer, data_size
def ParseFValue(self, value_data, user_account): """Parses the F value data. Args: value_data (bytes): F value data. user_account (UserAccount): user account. Raises: ParseError: if the value data could not be parsed. """ data_type_map = self._GetDataTypeMap('f_value') try: f_value = self._ReadStructureFromByteStream( value_data, 0, data_type_map, 'F value') except (ValueError, errors.ParseError) as exception: raise errors.ParseError( 'Unable to parse F value with error: {0!s}'.format(exception)) # TODO: change FILETIME timestamps into date time values. # date_time = self._ParseFiletime(f_value.last_login_time) user_account.last_login_time = f_value.last_login_time user_account.last_password_set_time = f_value.last_password_set_time user_account.account_expiration_time = f_value.account_expiration_time user_account.last_password_failure_time = f_value.last_password_failure_time user_account.rid = f_value.rid user_account.primary_gid = f_value.primary_gid user_account.user_account_control_flags = f_value.user_account_control_flags user_account.codepage = f_value.codepage user_account.number_of_password_failures = ( f_value.number_of_password_failures) user_account.number_of_logons = f_value.number_of_logons if self._debug: self._DebugPrintFValue(f_value)
def _ProcessKeyWithMRUListValue(self, registry_key): """Processes a Windows Registry key that contains a MRUList value. Args: registry_key (dfwinreg.WinRegistryKey): Windows Registry key. Returns: bool: True if a Most Recently Used (MRU) key was found, False if not. Raises: ParseError: if the MRUList value could not be parsed. """ registry_value = registry_key.GetValueByName('MRUList') data_type_map = self._GetDataTypeMap('mrulist_entries') context = dtfabric_data_maps.DataTypeMapContext(values={ 'data_size': len(registry_value.data)}) try: mrulist_entries = self._ReadStructureFromByteStream( registry_value.data, 0, data_type_map, 'MRUList entries', context=context) except (ValueError, errors.ParseError) as exception: raise errors.ParseError( 'Unable to parse MRUList entries with error: {0!s}'.format(exception)) mrulist = set([]) recovered_mrulist = set([]) is_recovered = False for entry_letter in mrulist_entries: if entry_letter == 0: is_recovered = True entry_letter = chr(entry_letter) if is_recovered: recovered_mrulist.add(entry_letter) else: mrulist.add(entry_letter) result = False for registry_value in registry_key.GetValues(): if registry_value.name in ('MRUList', 'NodeSlot', 'NodeSlots'): continue if self._debug: description = 'Key: {0:s}\nValue: {1:s}'.format( registry_key.path, registry_value.name) self._output_writer.WriteText(description) if self._InKeyPaths(registry_key.path, self._SHELL_ITEM_MRU_KEY_PATHS): self._ProcessMRUEntryShellItem( registry_key.path, registry_value.name, registry_value.data) elif self._InKeyPaths( registry_key.path, self._SHELL_ITEM_LIST_MRU_KEY_PATHS): self._ProcessMRUEntryShellItemList( registry_key.path, registry_value.name, registry_value.data) elif self._InKeyPaths( registry_key.path, self._STRING_AND_SHELL_ITEM_MRU_KEY_PATHS): self._ProcessMRUEntryStringAndShellItem( registry_key.path, registry_value.name, registry_value.data) elif self._InKeyPaths( registry_key.path, self._STRING_AND_SHELL_ITEM_LIST_MRU_KEY_PATHS): self._ProcessMRUEntryStringAndShellItemList( registry_key.path, registry_value.name, registry_value.data) else: self._ProcessMRUEntryString( registry_key.path, registry_value.name, registry_value.data) result = True return result
def ParseVValue(self, value_data, user_account): """Parses the V value data. Args: value_data (bytes): V value data. user_account (UserAccount): user account. Raises: ParseError: if the value data could not be parsed. """ data_type_map = self._GetDataTypeMap('v_value') try: v_value = self._ReadStructureFromByteStream( value_data, 0, data_type_map, 'V value') except (ValueError, errors.ParseError) as exception: raise errors.ParseError( 'Unable to parse V value with error: {0!s}'.format(exception)) for index in range(0, 17): user_information_descriptor = v_value[index] data_start_offset = user_information_descriptor.offset + 0xcc data_end_offset = data_start_offset + user_information_descriptor.size descriptor_data = value_data[data_start_offset:data_end_offset] if self._debug: self._DebugPrintUserInformationDescriptor( index, user_information_descriptor, data_start_offset, descriptor_data) if index == 0: if self._debug: value_string = self._FormatSecurityDescriptor(descriptor_data) self._DebugPrintText('Security descriptor:\n') self._DebugPrintText(value_string) self._DebugPrintText('\n') elif index == 1: user_account.username = descriptor_data.decode( 'utf-16-le').rstrip('\x00') if self._debug: self._DebugPrintValue('Username', user_account.username) self._DebugPrintText('\n') elif index == 2: user_account.full_name = descriptor_data.decode( 'utf-16-le').rstrip('\x00') if self._debug: self._DebugPrintValue('Full name', user_account.full_name) self._DebugPrintText('\n') elif index == 3: user_account.comment = descriptor_data.decode( 'utf-16-le').rstrip('\x00') if self._debug: self._DebugPrintValue('Comment', user_account.comment) self._DebugPrintText('\n') elif index == 4: user_account.user_comment = descriptor_data.decode( 'utf-16-le').rstrip('\x00') if self._debug: self._DebugPrintValue( 'User comment', user_account.user_comment) self._DebugPrintText('\n') if self._debug: self._DebugPrintText('\n')
def ParseVValue(self, value_data, user_account): """Parses the V value data. Args: value_data (bytes): V value data. user_account (UserAccount): user account. Raises: ParseError: if the value data could not be parsed. """ data_type_map = self._GetDataTypeMap('v_value') try: v_value = self._ReadStructureFromByteStream( value_data, 0, data_type_map, 'V value') except (ValueError, errors.ParseError) as exception: raise errors.ParseError( 'Unable to parse F value with error: {0!s}'.format(exception)) for index in range(0, 17): user_information_descriptor = v_value[index] data_start_offset = user_information_descriptor.offset + 0xcc data_end_offset = data_start_offset + user_information_descriptor.size descriptor_data = value_data[data_start_offset:data_end_offset] if self._debug: description_string = 'Descriptor: {0:d} description'.format( index + 1) value_string = self._USER_INFORMATION_DESCRIPTORS[index] self._DebugPrintValue(description_string, value_string) value_description = 'Descriptor: {0:d} offset'.format(index + 1) value_string = '0x{0:08x} (0x{1:08x})'.format( user_information_descriptor.offset, data_start_offset) self._DebugPrintValue(value_description, value_string) value_description = 'Descriptor: {0:d} size'.format(index + 1) self._DebugPrintDecimalValue(value_description, user_information_descriptor.size) unknown1_string = 'Descriptor: {0:d} unknown1'.format(index + 1) value_string = '0x{0:08x}'.format( user_information_descriptor.unknown1) self._DebugPrintValue(unknown1_string, value_string) data_string = 'Descriptor: {0:d} data:'.format(index + 1) self._DebugPrintData(data_string, descriptor_data) if index == 1: user_account.username = descriptor_data.decode( 'utf-16-le').rstrip('\x00') if self._debug: self._DebugPrintValue('Username', user_account.username) self._DebugPrintText('\n') elif index == 2: user_account.full_name = descriptor_data.decode( 'utf-16-le').rstrip('\x00') if self._debug: self._DebugPrintValue('Full name', user_account.full_name) self._DebugPrintText('\n') elif index == 3: user_account.comment = descriptor_data.decode( 'utf-16-le').rstrip('\x00') if self._debug: self._DebugPrintValue('Comment', user_account.comment) self._DebugPrintText('\n') elif index == 4: user_account.user_comment = descriptor_data.decode( 'utf-16-le').rstrip('\x00') if self._debug: self._DebugPrintValue('User comment', user_account.user_comment) self._DebugPrintText('\n') if self._debug: self._DebugPrintText('\n')
def _ProcessKeyWithMRUListExValue(self, registry_key): """Processes a Windows Registry key that contains a MRUListEx value. Args: registry_key (dfwinreg.WinRegistryKey): Windows Registry key. Returns: bool: True if a Most Recently Used (MRU) key was found, False if not. """ # TODO: determine what trailing data is in: # HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ # ComDlg32\CIDSizeMRU registry_value = registry_key.GetValueByName('MRUListEx') data_type_map = self._GetDataTypeMap('mrulistex_entries') context = dtfabric_data_maps.DataTypeMapContext( values={'data_size': len(registry_value.data)}) try: mrulistex_entries = self._ReadStructureFromByteStream( registry_value.data, 0, data_type_map, 'MRUListEx entries', context=context) except (ValueError, errors.ParseError) as exception: raise errors.ParseError( 'Unable to parse MRUListEx entries with error: {0!s}'.format( exception)) mrulistex = set([]) recovered_mrulistex = set([]) is_recovered = False for entry_number in mrulistex_entries: if entry_number == 0: is_recovered = True if is_recovered: recovered_mrulistex.add(entry_number) else: mrulistex.add(entry_number) result = False for registry_value in registry_key.GetValues(): if registry_value.name in ('MRUListEx', 'NodeSlot', 'NodeSlots'): continue if self._debug: description = 'Key: {0:s}\nValue: {1:s}'.format( registry_key.path, registry_value.name) self._output_writer.WriteText(description) if self._InKeyPaths(registry_key.path, self._SHELL_ITEM_MRU_KEY_PATHS): self._ProcessMRUEntryShellItem(registry_key.path, registry_value.name, registry_value.data) elif self._InKeyPaths(registry_key.path, self._SHELL_ITEM_LIST_MRU_KEY_PATHS): self._ProcessMRUEntryShellItemList(registry_key.path, registry_value.name, registry_value.data) elif self._InKeyPaths(registry_key.path, self._STRING_AND_SHELL_ITEM_MRU_KEY_PATHS): self._ProcessMRUEntryStringAndShellItem( registry_key.path, registry_value.name, registry_value.data) elif self._InKeyPaths( registry_key.path, self._STRING_AND_SHELL_ITEM_LIST_MRU_KEY_PATHS): self._ProcessMRUEntryStringAndShellItemList( registry_key.path, registry_value.name, registry_value.data) else: self._ProcessMRUEntryString(registry_key.path, registry_value.name, registry_value.data) result = True return result
def Parse(self, value_data): """Parses the value data. Args: value_data (bytes): value data. Raises: ParseError: if the value data could not be parsed. """ if self._debug: self._DebugPrintData('Value data', value_data) header, value_data_offset = self._ParseHeader(value_data) if header.format_version == 1: value_data_offset += 4 elif header.format_version == 9: data_type_map = self._GetDataTypeMap('programscache_header9') try: header9 = self._ReadStructureFromByteStream( value_data[value_data_offset:], value_data_offset, data_type_map, 'header9') except (ValueError, errors.ParseError) as exception: raise errors.ParseError( 'Unable to parse header9 value with error: {0!s}'.format( exception)) value_data_offset += data_type_map.GetByteSize() if self._debug: value_string = '0x{0:08x}'.format(header9.unknown1) self._DebugPrintValue('Unknown1', value_string) elif header.format_version in (12, 19): uuid_object = uuid.UUID(bytes_le=value_data[4:20]) value_data_offset += 16 if self._debug: value_string = '{0!s}'.format(uuid_object) self._DebugPrintValue('Known folder identifier', value_string) sentinel = 0 if header.format_version != 9: entry_footer, data_size = self._ParseEntryFooter( value_data, value_data_offset) value_data_offset += data_size sentinel = entry_footer.sentinel if self._debug: self._DebugPrintText('\n') value_data_size = len(value_data) while sentinel in (0, 1): if value_data_offset >= value_data_size: break data_type_map = self._GetDataTypeMap('programscache_entry_header') try: entry_header = self._ReadStructureFromByteStream( value_data[value_data_offset:], value_data_offset, data_type_map, 'entry header') except (ValueError, errors.ParseError) as exception: raise errors.ParseError( 'Unable to parse entry header value with error: {0!s}'. format(exception)) if self._debug: value_string = '0x{0:08x}'.format(value_data_offset) self._DebugPrintValue('Entry data offset', value_string) self._DebugPrintEntryHeader(entry_header) value_data_offset += data_type_map.GetByteSize() entry_data_size = entry_header.data_size shell_item_list = pyfwsi.item_list() shell_item_list.copy_from_byte_stream( value_data[value_data_offset:]) for shell_item in iter(shell_item_list.items): if self._debug: self._DebugPrintShellItem(shell_item) value_data_offset += entry_data_size entry_footer, data_size = self._ParseEntryFooter( value_data, value_data_offset) value_data_offset += data_size if self._debug: self._DebugPrintText('\n') if entry_footer.sentinel == 2 and value_data_offset < value_data_size: # TODO: determine the logic to this value. while ord(value_data[value_data_offset]) != 0x00: value_data_offset += 1 value_data_offset += 7 entry_footer, data_size = self._ParseEntryFooter( value_data, value_data_offset) value_data_offset += data_size if self._debug: self._DebugPrintText('\n') if value_data_offset < value_data_size: value_string = '0x{0:08x}'.format(value_data_offset) self._DebugPrintValue('Trailing data offset', value_string) self._DebugPrintData('Trailing data:', value_data[value_data_offset:])
def ParseHeader(self, format_type, value_data): """Parses the header. Args: format_type (int): format type. value_data (bytes): value data. Returns: AppCompatCacheHeader: header. Raises: ParseError: if the value data could not be parsed. """ data_type_map_name = self._HEADER_DATA_TYPE_MAP_NAMES.get( format_type, None) if not data_type_map_name: raise errors.ParseError( 'Unsupported format type: {0:d}'.format(format_type)) data_type_map = self._GetDataTypeMap(data_type_map_name) context = dtfabric_data_maps.DataTypeMapContext() try: header = self._ReadStructureFromByteStream(value_data, 0, data_type_map, 'header', context=context) except (ValueError, errors.ParseError) as exception: raise errors.ParseError( 'Unable to parse header value with error: {0!s}'.format( exception)) header_data_size = context.byte_size if format_type == self._FORMAT_TYPE_10: header_data_size = header.signature cache_header = AppCompatCacheHeader() cache_header.header_size = header_data_size cache_header.number_of_cached_entries = getattr( header, 'number_of_cached_entries', None) if self._debug: self._DebugPrintHeader(format_type, header) if format_type == self._FORMAT_TYPE_XP: if self._debug: self._DebugPrintText('LRU entries:') data_offset = 16 number_of_lru_entries = header.number_of_lru_entries if 0 <= number_of_lru_entries <= 96: data_type_map = self._GetDataTypeMap('uint32le') for lru_entry_index in range(number_of_lru_entries): try: lru_entry = self._ReadStructureFromByteStream( value_data[data_offset:data_offset + 4], data_offset, data_type_map, 'LRU entry') except (ValueError, errors.ParseError) as exception: raise errors.ParseError( 'Unable to parse LRU entry value with error: {0!s}' .format(exception)) data_offset += 4 if self._debug: description = 'LRU entry: {0:d}'.format( lru_entry_index) value_string = '{0:d} (offset: 0x{1:08x})'.format( lru_entry, 400 + (lru_entry * 552)) self._DebugPrintValue(description, value_string) if self._debug: self._DebugPrintText('\n') if self._debug: self._DebugPrintData('Unknown data', value_data[data_offset:400]) self._cached_entry_data_type_map = None return cache_header
def ParseCachedEntry(self, format_type, value_data, cached_entry_index, cached_entry_offset): """Parses a cached entry. Args: format_type (int): format type. value_data (bytes): value data. cached_entry_index (int): cached entry index. cached_entry_offset (int): offset of the first cached entry data relative to the start of the value data. Returns: AppCompatCacheCachedEntry: cached entry. Raises: ParseError: if the value data could not be parsed. """ if not self._cached_entry_data_type_map: self._cached_entry_data_type_map = self._GetCachedEntryDataTypeMap( format_type, value_data, cached_entry_offset) if not self._cached_entry_data_type_map: raise errors.ParseError( 'Unable to determine cached entry data type.') cached_entry_size = self._cached_entry_data_type_map.GetSizeHint() cached_entry_end_offset = cached_entry_offset + cached_entry_size cached_entry_data = value_data[ cached_entry_offset:cached_entry_end_offset] if self._debug: if format_type not in (self._FORMAT_TYPE_8, self._FORMAT_TYPE_10): description = 'Cached entry: {0:d} data'.format( cached_entry_index) self._DebugPrintData(description, cached_entry_data) try: cached_entry = self._ReadStructureFromByteStream( cached_entry_data, cached_entry_offset, self._cached_entry_data_type_map, 'cached entry') except (ValueError, errors.ParseError) as exception: if self._debug: if format_type in (self._FORMAT_TYPE_8, self._FORMAT_TYPE_10): description = 'Cached entry: {0:d} header data'.format( cached_entry_index) self._DebugPrintData(description, cached_entry_data) raise errors.ParseError( 'Unable to parse cached entry value with error: {0!s}'.format( exception)) if format_type in (self._FORMAT_TYPE_8, self._FORMAT_TYPE_10): if cached_entry.signature not in ( self._CACHED_ENTRY_SIGNATURE_8_0, self._CACHED_ENTRY_SIGNATURE_8_1): if self._debug: description = 'Cached entry: {0:d} header data'.format( cached_entry_index) self._DebugPrintData(description, cached_entry_data) raise errors.ParseError('Unsupported cache entry signature') cached_entry_object = AppCompatCacheCachedEntry() data_offset = 0 data_size = 0 if format_type == self._FORMAT_TYPE_XP: if self._debug: self._DebugPrintCachedEntryXP(cached_entry) # TODO: have dtFabric handle string conversion. string_size = 0 for string_index in range(0, 528, 2): if (cached_entry.path[string_index] == 0 and cached_entry.path[string_index + 1] == 0): break string_size += 2 last_modification_time = cached_entry.last_modification_time path = bytearray( cached_entry.path[0:string_size]).decode('utf-16-le') cached_entry_object.last_update_time = cached_entry.last_update_time elif format_type in (self._FORMAT_TYPE_2003, self._FORMAT_TYPE_VISTA, self._FORMAT_TYPE_7): if self._debug: self._DebugPrintCachedEntry2003(cached_entry) last_modification_time = cached_entry.last_modification_time if format_type in (self._FORMAT_TYPE_VISTA, self._FORMAT_TYPE_7): cached_entry_object.insertion_flags = cached_entry.insertion_flags cached_entry_object.shim_flags = cached_entry.shim_flags path_size = cached_entry.path_size maximum_path_size = cached_entry.maximum_path_size path_offset = cached_entry.path_offset if path_offset > 0 and path_size > 0: path_size += path_offset maximum_path_size += path_offset if self._debug: self._DebugPrintData( 'Path data', value_data[path_offset:maximum_path_size]) path = value_data[path_offset:path_size].decode('utf-16-le') if self._debug: self._DebugPrintValue('Path', path) if format_type == self._FORMAT_TYPE_7: data_offset = cached_entry.data_offset data_size = cached_entry.data_size elif format_type in (self._FORMAT_TYPE_8, self._FORMAT_TYPE_10): cached_entry_data_size = cached_entry.cached_entry_data_size cached_entry_size = 12 + cached_entry_data_size cached_entry_end_offset = cached_entry_offset + cached_entry_size cached_entry_data = value_data[ cached_entry_offset:cached_entry_end_offset] if self._debug: description = 'Cached entry: {0:d} data'.format( cached_entry_index) self._DebugPrintData(description, cached_entry_data) if format_type == self._FORMAT_TYPE_10: data_type_map_name = 'appcompatcache_cached_entry_body_10' elif cached_entry.signature == self._CACHED_ENTRY_SIGNATURE_8_0: data_type_map_name = 'appcompatcache_cached_entry_body_8_0' elif cached_entry.signature == self._CACHED_ENTRY_SIGNATURE_8_1: data_type_map_name = 'appcompatcache_cached_entry_body_8_1' data_type_map = self._GetDataTypeMap(data_type_map_name) context = dtfabric_data_maps.DataTypeMapContext() try: cached_entry_body = self._ReadStructureFromByteStream( cached_entry_data[12:], cached_entry_offset + 12, data_type_map, 'cached entry body', context=context) except (ValueError, errors.ParseError) as exception: raise errors.ParseError( 'Unable to parse cached entry body with error: {0!s}'. format(exception)) if self._debug: self._DebugPrintCachedEntry8(cached_entry, cached_entry_body) last_modification_time = cached_entry_body.last_modification_time path = cached_entry_body.path if format_type == self._FORMAT_TYPE_8: cached_entry_object.insertion_flags = cached_entry_body.insertion_flags cached_entry_object.shim_flags = cached_entry_body.shim_flags data_offset = cached_entry_offset + context.byte_size data_size = cached_entry_body.data_size if self._debug: self._DebugPrintText('\n') cached_entry_object.cached_entry_size = cached_entry_size cached_entry_object.file_size = getattr(cached_entry, 'file_size', None) cached_entry_object.last_modification_time = last_modification_time cached_entry_object.path = path if data_size > 0: cached_entry_object.data = value_data[data_offset:data_offset + data_size] if self._debug: self._DebugPrintData('Data', cached_entry_object.data) return cached_entry_object