class UsnRecordBase(): # Fields that are shared by both the USN record version 2 and 3 (4 is unknown at this moment) RECORD_LENGTH = ('record length', 0, 3) MAJOR_VERSION = ('major version', 4, 5) MINOR_VERSION = ('minor version', 6, 7) REASON_MAP = { 0x00000001: 'DATA_OVERWRITE', 0x00000002: 'DATA_EXTEND', 0x00000004: 'DATA_TRUNCATION', 0x00000010: 'NAMED_DATA_OVERWRITE', 0x00000020: 'NAMED_DATA_EXTEND', 0x00000040: 'NAMED_DATA_TRUNCATION', 0x00000100: 'FILE_CREATE', 0x00000200: 'FILE_DELETE', 0x00000400: 'EA_CHANGE', 0x00000800: 'SECURITY_CHANGE', 0x00001000: 'RENAME_OLD_NAME', 0x00002000: 'RENAME_NEW_NAME', 0x00004000: 'INDEXABLE_CHANGE', 0x00008000: 'BASIC_INFO_CHANGE', 0x00010000: 'HARD_LINK_CHANGE', 0x00020000: 'COMPRESSION_CHANGE', 0x00040000: 'ENCRYPTION_CHANGE', 0x00080000: 'OBJECT_ID_CHANGE', 0x00100000: 'REPARSE_POINT_CHANGE', 0x00200000: 'STREAM_CHANGE', 0x80000000: 'CLOSE' } REASON_TUPLE = ( (0x00000001, 'DATA_OVERWRITE'), (0x00000002, 'DATA_EXTEND'), (0x00000004, 'DATA_TRUNCATION'), (0x00000010, 'NAMED_DATA_OVERWRITE'), (0x00000020, 'NAMED_DATA_EXTEND'), (0x00000040, 'NAMED_DATA_TRUNCATION'), (0x00000100, 'FILE_CREATE'), (0x00000200, 'FILE_DELETE'), (0x00000400, 'EA_CHANGE'), (0x00000800, 'SECURITY_CHANGE'), (0x00001000, 'RENAME_OLD_NAME'), (0x00002000, 'RENAME_NEW_NAME'), (0x00004000, 'INDEXABLE_CHANGE'), (0x00008000, 'BASIC_INFO_CHANGE'), (0x00010000, 'HARD_LINK_CHANGE'), (0x00020000, 'COMPRESSION_CHANGE'), (0x00040000, 'ENCRYPTION_CHANGE'), (0x00080000, 'OBJECT_ID_CHANGE'), (0x00100000, 'REPARSE_POINT_CHANGE'), (0x00200000, 'STREAM_CHANGE'), (0x80000000, 'CLOSE') ) # Source info USN_SOURCE_DATA_MANAGEMENT = 0x00000001 USN_SOURCE_AUXILARY_DATA = 0x00000002 USN_SOURCE_REPLICATION_MANAGEMENT = 0x00000004 def __init__(self, data=None, offset_bytes=None): record_length = reverse_hexlify_int(data[0:4]) self.data = data[0:record_length] self.offset_bytes = offset_bytes self.file_attributes_object = FileAttributesFlag(self.file_attributes) #################################################################################################################### # Raw values @property def record_length_raw(self): return self.data[0:4] @property def major_version_raw(self): return self.data[4:6] @property def minor_version_raw(self): return self.data[6:8] # Placeholders to be overridden by subclasses. @property def file_reference_number_raw(self): raise NotImplementedError() @property def parent_file_reference_number_raw(self): raise NotImplementedError() @property def usn_raw(self): raise NotImplementedError() @property def timestamp_raw(self): raise NotImplementedError() @property def reason_raw(self): raise NotImplementedError() @property def source_info_raw(self): raise NotImplementedError() @property def security_id_raw(self): raise NotImplementedError() @property def file_attributes_raw(self): raise NotImplementedError() @property def file_name_length_raw(self): raise NotImplementedError() @property def file_name_offset_raw(self): raise NotImplementedError() @property def file_name_raw(self): return self.data[self.file_name_offset : self.file_name_offset + self.file_name_length] #################################################################################################################### # Interpreted values @property def record_length(self): return reverse_hexlify_int(self.record_length_raw) @property def major_version(self): return reverse_hexlify_int(self.major_version_raw) @property def minor_version(self): return reverse_hexlify_int(self.minor_version_raw) @property def file_reference_number(self): return hexlify(self.file_reference_number_raw) @property def parent_file_reference_number(self): return hexlify(self.parent_file_reference_number_raw) @property def usn(self): return reverse_hexlify_int(self.usn_raw) @property def timestamp(self): return reverse_hexlify_int(self.timestamp_raw) @property def reason(self): return reverse_hexlify_int(self.reason_raw) @property def source_info(self): return reverse_hexlify_int(self.source_info_raw) @property def security_id(self): return reverse_hexlify_int(self.security_id_raw) @property def file_attributes(self): return reverse_hexlify_int(self.file_attributes_raw) @property def file_name_length(self): return reverse_hexlify_int(self.file_name_length_raw) @property def file_name_offset(self): return reverse_hexlify_int(self.file_name_offset_raw) @property def file_name(self): return self.file_name_raw.decode('utf-16') #################################################################################################################### # Derived values @property def timestamp_datetime(self): if not hasattr(self, '_timestamp_datetime'): self._timestamp_datetime = filetime_to_datetime(self.timestamp_raw) return self._timestamp_datetime @property def usn_source_data_management_flag_set(self): return bool(self.source_info & UsnRecordV2.USN_SOURCE_DATA_MANAGEMENT) @property def usn_source_auxiliary_data_flag_set(self): return bool(self.source_info & UsnRecordV2.USN_SOURCE_AUXILARY_DATA) @property def usn_source_replication_management_flag_set(self): return bool(self.source_info & UsnRecordV2.USN_SOURCE_REPLICATION_MANAGEMENT) @property def file_attributes_string(self): return '|'.join(self.file_attributes_object.reason_list()) @property def reason_string(self): return '|'.join([second for first, second in self.REASON_TUPLE if self.reason & first]) #################################################################################################################### # Printing def all_fields_described(self): return ( (UsnRecordBase.RECORD_LENGTH, self.record_length, self.record_length_raw), (UsnRecordBase.MAJOR_VERSION, self.major_version, self.major_version_raw), (UsnRecordBase.MINOR_VERSION, self.minor_version, self.minor_version_raw), ) def extra_pairs(self): return () def formatted_csv(self): return [ self.record_length, self.major_version, self.minor_version, #self.file_reference_number, #self.parent_file_reference_number, self.usn, self.timestamp_datetime, self.reason_string, self.source_info, self.security_id, self.file_attributes_string, self.file_name_length, self.file_name_offset, self.file_name ] def formatted_csv_column_headers(self): formatted = [ 'record length', 'major version', 'minor version', #'file reference number', #'parent file reference number', 'usn', 'timestamp', 'reason', 'source info', 'security id', 'file attributes', 'file name length', 'file name offset', 'file name' ] return formatted def print(self): _INDENT = ' ' for (description, low, high), value, value_raw in self.all_fields_described(): print(_INDENT + '%-26s | %-5s | %-18s | %s' % (description, str(low) + '-' + str(high), value, hexlify(value_raw))) #print() #print(_INDENT + '%-47s | %s' % ('parent directory file reference sequence number', self.parent_directory_file_reference_sequence_number)) #print(_INDENT + '%-47s | %s' % ('parent_directory_file_reference_mft entry', self.parent_directory_file_reference_mft_entry)) #print(_INDENT + '%-47s | %s' % ('file creation time datetime', self.file_creation_time_datetime)) #print(_INDENT + '%-47s | %s' % ('file modified time datetime', self.file_modification_time_datetime)) #print(_INDENT + '%-47s | %s' % ('mft modified time datetime', self.mft_modification_time_datetime)) #print(_INDENT + '%-47s | %s' % ('file access time datetime', self.file_access_time_datetime)) #self.print_attribute_bottom() def print(self): pass def writeout_parsed(self, out, indent=0): for (description, low, high), value, value_raw in self.all_fields_described(): out.write('%s%-26s | %-5s | %-18s | %s\n' % (indent * ' ', description, str(low) + '-' + str(high), value, hexlify(value_raw))) for key, val in self.extra_pairs(): out.write('%-15s%s\n' % (key + ':', val))
class StandardInformation(Attribute): CREATION_TIME = ('creation time', 0, 7) FILE_ALTERED_TIME = ('file altered time', 8, 15) MFT_ALTERED_TIME = ('mft altered time', 16, 23) FILE_ACCESSED_TIME = ('file accessed time', 24, 31) FLAGS = ('flags', 32, 35) MAXIMUM_NUMBER_OF_VERSIONS = ('maximum version of numbers', 36, 39) VERSION_NUMBER = ('version number', 40, 43) CLASS_ID = ('class id', 44, 47) OWNER_ID = ('owner id', 48, 51) SECURITY_ID = ('security id', 52, 55) QUOTA_CHARGED = ('quota charged', 56, 63) USN = ('USN', 64, 71) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.content_data = self.data[self.header.content_offset:self.header. content_offset + self.header.content_size] self.flags_set = FileAttributesFlag(self.flags) #################################################################################################################### # Raw values @property def creation_time_raw(self): return self.content_data[0:8] @property def file_altered_time_raw(self): return self.content_data[8:16] @property def mft_altered_time_raw(self): return self.content_data[16:24] @property def file_accessed_time_raw(self): return self.content_data[24:32] @property def flags_raw(self): return self.content_data[32:36] @property def maximum_number_of_versions_raw(self): return self.content_data[36:40] @property def version_number_raw(self): return self.content_data[40:44] @property def class_id_raw(self): return self.content_data[44:48] @property def owner_id_raw(self): return self.content_data[48:52] @property def security_id_raw(self): return self.content_data[52:56] @property def quota_charged_raw(self): return self.content_data[56:64] @property def usn_raw(self): return self.content_data[64:72] #################################################################################################################### # Interpreted values @property def creation_time(self): return reverse_hexlify_int(self.creation_time_raw) @property def file_altered_time(self): return reverse_hexlify_int(self.file_altered_time_raw) @property def mft_altered_time(self): return reverse_hexlify_int(self.mft_altered_time_raw) @property def file_accessed_time(self): return reverse_hexlify_int(self.file_accessed_time_raw) @property def flags(self): return reverse_hexlify_int(self.flags_raw) @property def maximum_number_of_versions(self): return reverse_hexlify_int(self.maximum_number_of_versions_raw) @property def version_number(self): return reverse_hexlify_int(self.version_number_raw) @property def class_id(self): return reverse_hexlify_int(self.class_id_raw) @property def owner_id(self): return reverse_hexlify_int(self.owner_id_raw) @property def security_id(self): return reverse_hexlify_int(self.security_id_raw) @property def quota_charged(self): return reverse_hexlify_int(self.quota_charged_raw) @property def usn(self): return reverse_hexlify_int(self.usn_raw) #################################################################################################################### # Derived values @property def creation_time_datetime(self): if not hasattr(self, '_creation_time_datetime'): self._creation_time_datetime = filetime_to_datetime( self.creation_time_raw) return self._creation_time_datetime @property def file_altered_time_datetime(self): if not hasattr(self, '_file_altered_time_datetime'): self._file_altered_time_datetime = filetime_to_datetime( self.file_altered_time_raw) return self._file_altered_time_datetime @property def mft_altered_time_datetime(self): if not hasattr(self, '_mft_altered_time_datetime'): self._mft_altered_time_datetime = filetime_to_datetime( self.mft_altered_time_raw) return self._mft_altered_time_datetime @property def file_accessed_time_datetime(self): if not hasattr(self, '_file_accessed_time_datetime'): self._file_accessed_time_datetime = filetime_to_datetime( self.file_accessed_time_raw) return self._file_accessed_time_datetime @property def flags_string(self): return '|'.join(self.flags_set.reason_list()) #################################################################################################################### # Printing def all_fields_described(self): base_tuple = ((StandardInformation.CREATION_TIME, self.creation_time, self.creation_time_raw), (StandardInformation.FILE_ALTERED_TIME, self.file_altered_time, self.file_altered_time_raw), (StandardInformation.MFT_ALTERED_TIME, self.mft_altered_time, self.mft_altered_time_raw), (StandardInformation.FILE_ACCESSED_TIME, self.file_accessed_time, self.file_accessed_time_raw), (StandardInformation.FLAGS, self.flags, self.flags_raw), (StandardInformation.MAXIMUM_NUMBER_OF_VERSIONS, self.maximum_number_of_versions, self.maximum_number_of_versions_raw), (StandardInformation.VERSION_NUMBER, self.version_number, self.version_number_raw), (StandardInformation.CLASS_ID, self.class_id, self.class_id_raw)) if len(self.content_data) == 48: return base_tuple elif len(self.content_data) == 72: return base_tuple + ( (StandardInformation.OWNER_ID, self.owner_id, self.owner_id_raw), (StandardInformation.SECURITY_ID, self.security_id, self.security_id_raw), (StandardInformation.QUOTA_CHARGED, self.quota_charged, self.quota_charged_raw), (StandardInformation.USN, self.usn, self.usn_raw)) else: raise Exception('StandardInformation is of length ' + str(len(self.content_data)) + ', case unaccounted for') def extra_pairs(self): return (('creation time datetime', self.creation_time_datetime), ('file altered time datetime', self.file_altered_time_datetime), ('mft altered time datetime', self.mft_altered_time_datetime), ('file accessed time datetime', self.file_accessed_time_datetime)) @staticmethod def format_csv_column_headers(): return [ 'SI creation time', 'SI file altered time', 'SI mft altered time', 'SI file accessed time', 'SI flags', 'SI maximum number of versions', 'SI version number', 'SI class id', 'SI owner id', 'SI security id', 'SI quota charged', 'SI usn' ] def format_csv(self): return [ self.creation_time_datetime, self.file_altered_time_datetime, self.mft_altered_time_datetime, self.file_accessed_time_datetime, self.flags_string, self.maximum_number_of_versions, self.version_number, self.class_id, self.owner_id, self.security_id, self.quota_charged, self.usn ]
class StandardInformation(Attribute): CREATION_TIME = ('creation time', 0, 7) FILE_ALTERED_TIME = ('file altered time', 8,15) MFT_ALTERED_TIME = ('mft altered time', 16, 23) FILE_ACCESSED_TIME = ('file accessed time', 24, 31) FLAGS = ('flags', 32, 35) MAXIMUM_NUMBER_OF_VERSIONS = ('maximum version of numbers', 36, 39) VERSION_NUMBER = ('version number', 40, 43) CLASS_ID = ('class id', 44, 47) OWNER_ID = ('owner id', 48, 51) SECURITY_ID = ('security id', 52, 55) QUOTA_CHARGED = ('quota charged', 56, 63) USN = ('USN', 64, 71) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.content_data = self.data[ self.header.content_offset: self.header.content_offset + self.header.content_size] self.flags_set = FileAttributesFlag(self.flags) #################################################################################################################### # Raw values @property def creation_time_raw(self): return self.content_data[0:8] @property def file_altered_time_raw(self): return self.content_data[8:16] @property def mft_altered_time_raw(self): return self.content_data[16:24] @property def file_accessed_time_raw(self): return self.content_data[24:32] @property def flags_raw(self): return self.content_data[32:36] @property def maximum_number_of_versions_raw(self): return self.content_data[36:40] @property def version_number_raw(self): return self.content_data[40:44] @property def class_id_raw(self): return self.content_data[44:48] @property def owner_id_raw(self): return self.content_data[48:52] @property def security_id_raw(self): return self.content_data[52:56] @property def quota_charged_raw(self): return self.content_data[56:64] @property def usn_raw(self): return self.content_data[64:72] #################################################################################################################### # Interpreted values @property def creation_time(self): return reverse_hexlify_int(self.creation_time_raw) @property def file_altered_time(self): return reverse_hexlify_int(self.file_altered_time_raw) @property def mft_altered_time(self): return reverse_hexlify_int(self.mft_altered_time_raw) @property def file_accessed_time(self): return reverse_hexlify_int(self.file_accessed_time_raw) @property def flags(self): return reverse_hexlify_int(self.flags_raw) @property def maximum_number_of_versions(self): return reverse_hexlify_int(self.maximum_number_of_versions_raw) @property def version_number(self): return reverse_hexlify_int(self.version_number_raw) @property def class_id(self): return reverse_hexlify_int(self.class_id_raw) @property def owner_id(self): return reverse_hexlify_int(self.owner_id_raw) @property def security_id(self): return reverse_hexlify_int(self.security_id_raw) @property def quota_charged(self): return reverse_hexlify_int(self.quota_charged_raw) @property def usn(self): return reverse_hexlify_int(self.usn_raw) #################################################################################################################### # Derived values @property def creation_time_datetime(self): if not hasattr(self, '_creation_time_datetime'): self._creation_time_datetime = filetime_to_datetime(self.creation_time_raw) return self._creation_time_datetime @property def file_altered_time_datetime(self): if not hasattr(self, '_file_altered_time_datetime'): self._file_altered_time_datetime = filetime_to_datetime(self.file_altered_time_raw) return self._file_altered_time_datetime @property def mft_altered_time_datetime(self): if not hasattr(self, '_mft_altered_time_datetime'): self._mft_altered_time_datetime = filetime_to_datetime(self.mft_altered_time_raw) return self._mft_altered_time_datetime @property def file_accessed_time_datetime(self): if not hasattr(self, '_file_accessed_time_datetime'): self._file_accessed_time_datetime = filetime_to_datetime(self.file_accessed_time_raw) return self._file_accessed_time_datetime @property def flags_string(self): return '|'.join(self.flags_set.reason_list()) #################################################################################################################### # Printing def all_fields_described(self): base_tuple = ( (StandardInformation.CREATION_TIME, self.creation_time, self.creation_time_raw), (StandardInformation.FILE_ALTERED_TIME, self.file_altered_time, self.file_altered_time_raw), (StandardInformation.MFT_ALTERED_TIME, self.mft_altered_time, self.mft_altered_time_raw), (StandardInformation.FILE_ACCESSED_TIME,self.file_accessed_time, self.file_accessed_time_raw), (StandardInformation.FLAGS, self.flags, self.flags_raw), (StandardInformation.MAXIMUM_NUMBER_OF_VERSIONS, self.maximum_number_of_versions, self.maximum_number_of_versions_raw), (StandardInformation.VERSION_NUMBER, self.version_number, self.version_number_raw), (StandardInformation.CLASS_ID, self.class_id, self.class_id_raw) ) if len(self.content_data) == 48: return base_tuple elif len(self.content_data) == 72: return base_tuple + ( (StandardInformation.OWNER_ID, self.owner_id, self.owner_id_raw), (StandardInformation.SECURITY_ID, self.security_id, self.security_id_raw), (StandardInformation.QUOTA_CHARGED, self.quota_charged, self.quota_charged_raw), (StandardInformation.USN, self.usn, self.usn_raw) ) else: raise Exception('StandardInformation is of length ' + str(len(self.content_data)) + ', case unaccounted for') def extra_pairs(self): return ( ('creation time datetime', self.creation_time_datetime), ('file altered time datetime', self.file_altered_time_datetime), ('mft altered time datetime', self.mft_altered_time_datetime), ('file accessed time datetime', self.file_accessed_time_datetime) ) @staticmethod def format_csv_column_headers(): return [ 'SI creation time', 'SI file altered time', 'SI mft altered time', 'SI file accessed time', 'SI flags', 'SI maximum number of versions', 'SI version number', 'SI class id', 'SI owner id', 'SI security id', 'SI quota charged', 'SI usn' ] def format_csv(self): return [ self.creation_time_datetime, self.file_altered_time_datetime, self.mft_altered_time_datetime, self.file_accessed_time_datetime, self.flags_string, self.maximum_number_of_versions, self.version_number, self.class_id, self.owner_id, self.security_id, self.quota_charged, self.usn ]
class FileName(Attribute): PARENT_DIRECTORY_FILE = ('parent directory file', 0, 7) FILE_CREATION_TIME = ('file creation time', 8, 15) FILE_MODIFICATION_TIME = ('file modification time', 16, 23) MFT_MODIFICATION_TIME = ('mft modification time', 24, 31) FILE_ACCESS_TIME = ('file access time', 32, 39) FILE_ALLOCATED_SIZE = ('file allocated size', 40, 47) FILE_REAL_SIZE = ('file real size', 48, 55) FLAGS = ('flags', 56, 59) REPARSE_VALUE = ('reparse value', 60, 63) NAME_LENGTH = ('name length', 64, 64) NAMESPACE = ('namespace', 65, 65) NAME = ('name', 66, '+') def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.content_data = self.data[self.header.content_offset:self.header. content_offset + self.header.content_size] self.flags_set = FileAttributesFlag(self.flags) #################################################################################################################### # Raw values @property def parent_directory_file_reference_raw(self): return self.content_data[0:8] @property def file_creation_time_raw(self): return self.content_data[8:16] @property def file_modification_time_raw(self): return self.content_data[16:24] @property def mft_modification_time_raw(self): return self.content_data[24:32] @property def file_access_time_raw(self): return self.content_data[32:40] @property def file_allocated_size_raw(self): return self.content_data[40:48] @property def file_real_size_raw(self): return self.content_data[48:56] @property def flags_raw(self): return self.content_data[56:60] @property def reparse_value_raw(self): return self.content_data[60:64] @property def name_length_raw(self): return self.content_data[64:65] @property def namespace_raw(self): return self.content_data[65:66] @property def name_raw(self): return self.content_data[66:66 + self.name_length * 2] #################################################################################################################### # Interpreted values @property def parent_directory_file_reference(self): return hexlify(self.parent_directory_file_reference_raw).decode() @property def file_creation_time(self): return reverse_hexlify_int(self.file_creation_time_raw) @property def file_modification_time(self): return reverse_hexlify_int(self.file_modification_time_raw) @property def mft_modification_time(self): return reverse_hexlify_int(self.mft_modification_time_raw) @property def file_access_time(self): return reverse_hexlify_int(self.file_access_time_raw) @property def file_allocated_size(self): return reverse_hexlify_int(self.file_allocated_size_raw) @property def file_real_size(self): return reverse_hexlify_int(self.file_allocated_size_raw) @property def flags(self): return reverse_hexlify_int(self.flags_raw) @property def reparse_value(self): return reverse_hexlify_int(self.reparse_value_raw) @property def name_length(self): return reverse_hexlify_int(self.name_length_raw) @property def namespace(self): return reverse_hexlify_int(self.namespace_raw) @property def name(self): return self.name_raw.decode('utf-16') #################################################################################################################### # Derived values @property def parent_directory_file_reference_sequence_number(self): return reverse_hexlify_int( self.parent_directory_file_reference_raw[6:8]) @property def parent_directory_file_reference_mft_entry(self): return reverse_hexlify_int( self.parent_directory_file_reference_raw[0:6]) @property def file_creation_time_datetime(self): try: if not hasattr(self, '_file_creation_time_datetime'): self._file_creation_time_datetime = filetime_to_datetime( self.file_creation_time_raw) return self._file_creation_time_datetime except ValueError: return None @property def file_modification_time_datetime(self): try: if not hasattr(self, '_file_modification_time_datetime'): self._file_modification_time_datetime = filetime_to_datetime( self.file_modification_time_raw) return self._file_modification_time_datetime except ValueError: return None @property def mft_modification_time_datetime(self): try: if not hasattr(self, '_mft_modification_time_datetime'): self._mft_modification_time_datetime = filetime_to_datetime( self.mft_modification_time_raw) return self._mft_modification_time_datetime except ValueError: return None @property def file_access_time_datetime(self): try: if not hasattr(self, '_file_access_time_datetime'): self._file_access_time_datetime = filetime_to_datetime( self.file_access_time_raw) return self._file_access_time_datetime except ValueError: return None @property def flags_string(self): return '|'.join(self.flags_set.reason_list()) #################################################################################################################### # Printing def all_fields_described(self): return ((FileName.PARENT_DIRECTORY_FILE, self.parent_directory_file_reference, self.parent_directory_file_reference_raw), (FileName.FILE_CREATION_TIME, self.file_creation_time, self.file_creation_time_raw), (FileName.FILE_MODIFICATION_TIME, self.file_modification_time, self.file_modification_time_raw), (FileName.MFT_MODIFICATION_TIME, self.mft_modification_time, self.file_modification_time_raw), (FileName.FILE_ACCESS_TIME, self.file_access_time, self.file_access_time_raw), (FileName.FILE_ALLOCATED_SIZE, self.file_allocated_size, self.file_allocated_size_raw), (FileName.FILE_REAL_SIZE, self.file_real_size, self.file_real_size_raw), (FileName.FLAGS, self.flags, self.flags_raw), (FileName.REPARSE_VALUE, self.reparse_value, self.reparse_value_raw), (FileName.NAME_LENGTH, self.name_length, self.name_length_raw), (FileName.NAMESPACE, self.namespace, self.namespace_raw), (FileName.NAME, self.name, self.name_raw)) def extra_pairs(self): return (('parent directory file reference sequence number', self.parent_directory_file_reference_sequence_number), ('parent_directory_file_reference_mft entry', self.parent_directory_file_reference_mft_entry), ('file creation time datetime', self.file_creation_time_datetime), ('file modified time datetime', self.file_modification_time_datetime), ('mft modified time datetime', self.mft_modification_time_datetime), ('file access time datetime', self.file_access_time_datetime)) @staticmethod def format_csv_column_headers(): return [ 'FN file creation time', 'FN file modification time', 'FN mft modification time', 'FN file access time', 'FN file allocated size', 'FN file real size', 'FN flags', 'FN reparse value', 'FN name length', 'FN namespace', 'FN name', 'FN pdfme', 'FN pdfsn' ] def format_csv(self): return [ self.file_creation_time_datetime, self.file_modification_time_datetime, self.mft_modification_time_datetime, self.file_access_time_datetime, self.file_allocated_size, self.file_real_size, self.flags_string, self.reparse_value, self.name_length, self.namespace, self.name, self.parent_directory_file_reference_mft_entry, self.parent_directory_file_reference_sequence_number ]
class FileName(Attribute): PARENT_DIRECTORY_FILE = ('parent directory file', 0, 7) FILE_CREATION_TIME = ('file creation time', 8, 15) FILE_MODIFICATION_TIME = ('file modification time', 16, 23) MFT_MODIFICATION_TIME = ('mft modification time', 24, 31) FILE_ACCESS_TIME = ('file access time', 32, 39) FILE_ALLOCATED_SIZE = ('file allocated size', 40, 47) FILE_REAL_SIZE = ('file real size', 48, 55) FLAGS = ('flags', 56, 59) REPARSE_VALUE = ('reparse value', 60, 63) NAME_LENGTH = ('name length', 64, 64) NAMESPACE = ('namespace', 65, 65) NAME = ('name', 66, '+') def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.content_data = self.data[ self.header.content_offset: self.header.content_offset + self.header.content_size] self.flags_set = FileAttributesFlag(self.flags) #################################################################################################################### # Raw values @property def parent_directory_file_reference_raw(self): return self.content_data[0:8] @property def file_creation_time_raw(self): return self.content_data[8:16] @property def file_modification_time_raw(self): return self.content_data[16:24] @property def mft_modification_time_raw(self): return self.content_data[24:32] @property def file_access_time_raw(self): return self.content_data[32:40] @property def file_allocated_size_raw(self): return self.content_data[40:48] @property def file_real_size_raw(self): return self.content_data[48:56] @property def flags_raw(self): return self.content_data[56:60] @property def reparse_value_raw(self): return self.content_data[60:64] @property def name_length_raw(self): return self.content_data[64:65] @property def namespace_raw(self): return self.content_data[65:66] @property def name_raw(self): return self.content_data[66:66+self.name_length*2] #################################################################################################################### # Interpreted values @property def parent_directory_file_reference(self): return hexlify(self.parent_directory_file_reference_raw).decode() @property def file_creation_time(self): return reverse_hexlify_int(self.file_creation_time_raw) @property def file_modification_time(self): return reverse_hexlify_int(self.file_modification_time_raw) @property def mft_modification_time(self): return reverse_hexlify_int(self.mft_modification_time_raw) @property def file_access_time(self): return reverse_hexlify_int(self.file_access_time_raw) @property def file_allocated_size(self): return reverse_hexlify_int(self.file_allocated_size_raw) @property def file_real_size(self): return reverse_hexlify_int(self.file_allocated_size_raw) @property def flags(self): return reverse_hexlify_int(self.flags_raw) @property def reparse_value(self): return reverse_hexlify_int(self.reparse_value_raw) @property def name_length(self): return reverse_hexlify_int(self.name_length_raw) @property def namespace(self): return reverse_hexlify_int(self.namespace_raw) @property def name(self): return self.name_raw.decode('utf-16') #################################################################################################################### # Derived values @property def parent_directory_file_reference_sequence_number(self): return reverse_hexlify_int(self.parent_directory_file_reference_raw[6:8]) @property def parent_directory_file_reference_mft_entry(self): return reverse_hexlify_int(self.parent_directory_file_reference_raw[0:6]) @property def file_creation_time_datetime(self): try: if not hasattr(self, '_file_creation_time_datetime'): self._file_creation_time_datetime = filetime_to_datetime(self.file_creation_time_raw) return self._file_creation_time_datetime except ValueError: return None @property def file_modification_time_datetime(self): try: if not hasattr(self, '_file_modification_time_datetime'): self._file_modification_time_datetime = filetime_to_datetime(self.file_modification_time_raw) return self._file_modification_time_datetime except ValueError: return None @property def mft_modification_time_datetime(self): try: if not hasattr(self, '_mft_modification_time_datetime'): self._mft_modification_time_datetime = filetime_to_datetime(self.mft_modification_time_raw) return self._mft_modification_time_datetime except ValueError: return None @property def file_access_time_datetime(self): try: if not hasattr(self, '_file_access_time_datetime'): self._file_access_time_datetime = filetime_to_datetime(self.file_access_time_raw) return self._file_access_time_datetime except ValueError: return None @property def flags_string(self): return '|'.join(self.flags_set.reason_list()) #################################################################################################################### # Printing def all_fields_described(self): return ( (FileName.PARENT_DIRECTORY_FILE, self.parent_directory_file_reference, self.parent_directory_file_reference_raw), (FileName.FILE_CREATION_TIME, self.file_creation_time, self.file_creation_time_raw), (FileName.FILE_MODIFICATION_TIME, self.file_modification_time, self.file_modification_time_raw), (FileName.MFT_MODIFICATION_TIME, self.mft_modification_time, self.file_modification_time_raw), (FileName.FILE_ACCESS_TIME, self.file_access_time, self.file_access_time_raw), (FileName.FILE_ALLOCATED_SIZE, self.file_allocated_size, self.file_allocated_size_raw), (FileName.FILE_REAL_SIZE, self.file_real_size, self.file_real_size_raw), (FileName.FLAGS, self.flags, self.flags_raw), (FileName.REPARSE_VALUE, self.reparse_value, self.reparse_value_raw), (FileName.NAME_LENGTH, self.name_length, self.name_length_raw), (FileName.NAMESPACE, self.namespace, self.namespace_raw), (FileName.NAME, self.name, self.name_raw) ) def extra_pairs(self): return ( ('parent directory file reference sequence number', self.parent_directory_file_reference_sequence_number), ('parent_directory_file_reference_mft entry', self.parent_directory_file_reference_mft_entry), ('file creation time datetime', self.file_creation_time_datetime), ('file modified time datetime', self.file_modification_time_datetime), ('mft modified time datetime', self.mft_modification_time_datetime), ('file access time datetime', self.file_access_time_datetime) ) @staticmethod def format_csv_column_headers(): return [ 'FN file creation time', 'FN file modification time', 'FN mft modification time', 'FN file access time', 'FN file allocated size', 'FN file real size', 'FN flags', 'FN reparse value', 'FN name length', 'FN namespace', 'FN name', 'FN pdfme', 'FN pdfsn' ] def format_csv(self): return [ self.file_creation_time_datetime, self.file_modification_time_datetime, self.mft_modification_time_datetime, self.file_access_time_datetime, self.file_allocated_size, self.file_real_size, self.flags_string, self.reparse_value, self.name_length, self.namespace, self.name, self.parent_directory_file_reference_mft_entry, self.parent_directory_file_reference_sequence_number ]