def get_registry_query_or_enum_value_extra_details(metadata, event, extra_detail_io, details_info): event.category = "Read" # RegQueryValue and RegEnumValue are always Read key_value_information_class = RegistryKeyValueInformationClass(details_info["information_class"]) if event.operation == RegistryOperation.RegEnumValue.name: event.details["Index"] = details_info["index"] # Only in enum if not extra_detail_io: # There is no extra details event.details["Length"] = details_info["length"] return extra_detail_io.seek(4, 1) # Unknown field reg_type_name = get_reg_type_name(read_u32(extra_detail_io)) if key_value_information_class == RegistryKeyValueInformationClass.KeyValueFullInformation: offset_to_data = read_u32(extra_detail_io) length_value = read_u32(extra_detail_io) name_size = read_u32(extra_detail_io) event.details["Name"] = read_utf16(extra_detail_io, name_size) extra_detail_io.seek(offset_to_data, 0) # the stream starts at the start of the struct so the seek is good elif key_value_information_class == RegistryKeyValueInformationClass.KeyValuePartialInformation: length_value = read_u32(extra_detail_io) else: # Only KeyValuePartialInformation and KeyValueFullInformation have Data property event.details["Type"] = reg_type_name # the Type is still known... return event.details["Type"] = reg_type_name # I do this assignment here because "Name" comes before "Type" event.details["Length"] = length_value if length_value > 0: event.details["Data"] = read_registry_data(extra_detail_io, reg_type_name, length_value)
def get_filesystem_read_write_file_details(io, metadata, event, details_io, extra_detail_io): event.category = "Read" if event.operation == "ReadFile" else "Write" details_io.seek(0x4, 1) io_flags_and_priority = read_u32(details_io) io_flags = io_flags_and_priority & 0xe000ff priority = (io_flags_and_priority >> 0x11) & 7 details_io.seek(0x4, 1) length = read_u32(details_io) if metadata.sizeof_pvoid == 8: details_io.seek(4, 1) # Padding for 64 bit details_io.seek(0x4, 1) if metadata.sizeof_pvoid == 8: details_io.seek(4, 1) # Padding for 64 bit offset = read_s64(details_io) event.details["Offset"] = offset if extra_detail_io: length = read_u32(extra_detail_io) event.details["Length"] = length if io_flags != 0: event.details["I/O Flags"] = get_filesysyem_io_flags(io_flags) if priority != 0: event.details["Priority"] = FilesystemPriority.get(priority, "0x{:x}".format(priority))
def get_process_started_details(io, metadata, event, extra_detail_io): event.details["Parent PID"] = read_u32(io) command_line_info = read_detail_string_info(io) current_directory_info = read_detail_string_info(io) environment_character_count = read_u32(io) event.details["Command line"] = read_detail_string(io, command_line_info) event.details["Current directory"] = read_detail_string(io, current_directory_info) event.details["Environment"] = read_utf16_multisz(io, environment_character_count * 2)
def __init__(self, io): super(HostnamesTable, self).__init__() number_of_hostnames = read_u32(io) for _ in range(number_of_hostnames): ip = io.read(16) hostname_len = read_u32(io) hostname = read_utf16(io, hostname_len) self[ip] = hostname
def __init__(self, io): super(PortsTable, self).__init__() number_of_ports = read_u32(io) for _ in range(number_of_ports): port_value = read_u16(io) is_tcp = bool(read_u16(io)) port_len = read_u32(io) port_name = read_utf16(io, port_len) self[(port_value, is_tcp)] = port_name
def get_filesystem_ioctl_details(io, metadata, event, details_io, extra_detail_io): details_io.seek(0x8, 1) write_length = read_u32(details_io) read_length = read_u32(details_io) if metadata.sizeof_pvoid == 8: details_io.seek(4, 1) # Padding for 64 bit details_io.seek(0x4, 1) if metadata.sizeof_pvoid == 8: details_io.seek(4, 1) # Padding for 64 bit ioctl = read_u32(details_io) event.details["Control"] = get_ioctl_name(ioctl) if event.details["Control"] in ["FSCTL_OFFLOAD_READ", "FSCTL_GET_REPARSE_POINT", "FSCTL_READ_RAW_ENCRYPTED"]: event.category = "Read" elif event.details["Control"] in ["FSCTL_OFFLOAD_WRITE", "FSCTL_MOVE_FILE", "FSCTL_DELETE_REPARSE_POINT", "FSCTL_WRITE_RAW_ENCRYPTED", "FSCTL_PIPE_TRANSCEIVE", "FSCTL_PIPE_INTERNAL_TRANSCEIVE"]: event.category = "Write" elif event.details["Control"] in ["FSCTL_SET_COMPRESSION", "FSCTL_WRITE_PROPERTY_DATA", "FSCTL_SET_OBJECT_ID", "FSCTL_DELETE_OBJECT_ID", "FSCTL_SET_REPARSE_POINT", "FSCTL_SET_SPARSE", "FSCTL_SET_ENCRYPTION", "FSCTL_CREATE_USN_JOURNAL", "FSCTL_WRITE_USN_CLOSE_RECORD", "FSCTL_EXTEND_VOLUME", "FSCTL_DELETE_USN_JOURNAL"]: event.category = "Write Metadata" elif event.details["Control"] in ["FSCTL_QUERY_RETRIEVAL_POINTERS", "FSCTL_GET_COMPRESSION", "FSCTL_QUERY_FAT_BPB", "FSCTL_QUERY_FAT_BPB", "FSCTL_FILESYSTEM_GET_STATISTICS", "FSCTL_GET_NTFS_VOLUME_DATA", "FSCTL_GET_NTFS_FILE_RECORD", "FSCTL_GET_VOLUME_BITMAP", "FSCTL_GET_RETRIEVAL_POINTERS", "FSCTL_IS_VOLUME_DIRTY", "FSCTL_READ_PROPERTY_DATA", "FSCTL_FIND_FILES_BY_SID", "FSCTL_GET_OBJECT_ID", "FSCTL_READ_USN_JOURNAL", "FSCTL_SET_OBJECT_ID_EXTENDED", "FSCTL_CREATE_OR_GET_OBJECT_ID", "FSCTL_READ_FILE_USN_DATA", "FSCTL_QUERY_USN_JOURNAL"]: event.category = "Read Metadata" if event.operation == "FileSystemControl": if event.details["Control"] == "FSCTL_PIPE_INTERNAL_WRITE": event.details["Length"] = write_length elif event.details["Control"] == "FSCTL_OFFLOAD_READ": details_io.seek(0x8, 1) event.details["Offset"] = read_s64(io) event.details["Length"] = read_u64(io) elif event.details["Control"] == "FSCTL_OFFLOAD_WRITE": event.details["Offset"] = read_s64(io) event.details["Length"] = read_u64(io) elif event.details["Control"] == "FSCTL_PIPE_INTERNAL_READ": event.details["Length"] = read_length elif event.details["Control"] in ["FSCTL_PIPE_TRANSCEIVE", "FSCTL_PIPE_INTERNAL_TRANSCEIVE"]: event.details["WriteLength"] = write_length event.details["ReadLength"] = read_length
def __init__(self, io, total_size): super(StringsTable, self).__init__() stream = BytesIO(io.read(total_size)) number_of_strings = read_u32(stream) # relative offsets to strings are not essential since they come one after another # strings_offsets_array = [read_u32(stream) for _ in range(number_of_strings)] stream.seek(number_of_strings * 4, 1) # jump over the strings offsets array strings = [''] * number_of_strings for i in range(number_of_strings): string_size = read_u32(stream) strings[i] = read_utf16(stream, string_size) self.extend(strings)
def get_registry_set_info_key_extra_details(metadata, event, extra_detail_io, details_info): event.category = "Write Metadata" event.details["KeySetInformationClass"] = RegistryKeySetInformationClass.get( details_info["key_set_information_class"], "<Unknown: {}>".format(details_info["key_set_information_class"]) ) event.details["Length"] = details_info["length"] if details_info["length"] > 0: if event.details["KeySetInformationClass"] == "KeyWriteTimeInformation": event.details["LastWriteTime"] = read_filetime(extra_detail_io) elif event.details["KeySetInformationClass"] == "KeyWow64FlagsInformation": event.details["Wow64Flags"] = read_u32(extra_detail_io) elif event.details["KeySetInformationClass"] == "KeyWriteTimeInformation": event.details["HandleTags"] = read_u32(extra_detail_io)
def __init__(self, io): stream = BytesIO(io.read(self.SIZE)) self.signature = stream.read(4) assert self.signature == b"PML_", "Wrong PML header" self.version = read_u32(stream) if self.version not in [9]: raise NotImplementedError("Not supporting PML version {}".format(self.version)) self.is_64bit = read_u32(stream) self.computer_name = read_utf16(stream, 0x20) self.system_root = read_utf16(stream, 0x208) self.number_of_events = read_u32(stream) stream.seek(8, 1) # Unknown field self.events_offset = read_u64(stream) self.events_offsets_array_offset = read_u64(stream) self.process_table_offset = read_u64(stream) self.strings_table_offset = read_u64(stream) self.unknown_table_offset = read_u64(stream) stream.seek(12, 1) # Unknown fields self.windows_major_number = read_u32(stream) self.windows_minor_number = read_u32(stream) self.windows_build_number = read_u32(stream) self.windows_build_number_after_decimal_point = read_u32(stream) self.service_pack_name = read_utf16(stream, 0x32) stream.seek(0xd6, 1) # Unknown field self.number_of_logical_processors = read_u32(stream) self.ram_memory_size = read_u64(stream) self.header_size = read_u64(stream) self.hosts_and_ports_tables_offset = read_u64(stream)
def __init__(self, io): super(StringsTable, self).__init__() string_table_start = io.tell() number_of_strings = read_u32(io) strings_offsets_array = [ read_u32(io) for _ in range(number_of_strings) ] strings = [''] * number_of_strings for i, offset in enumerate(strings_offsets_array): io.seek(string_table_start + offset, 0) string_size = read_u32(io) strings[i] = read_utf16(io, string_size) self.extend(strings)
def get_filesystem_notify_change_directory_details(io, metadata, event, details_io, extra_detail_io): event.category = "Read Metadata" details_io.seek(0x10, 1) if metadata.sizeof_pvoid == 8: details_io.seek(4, 1) # Padding for 64 bit event.details["Filter"] = get_filesysyem_notify_change_flags(read_u32(details_io))
def __init__(self, io, total_size, number_of_events): super(EventOffsetsArray, self).__init__() stream = BytesIO(io.read(total_size)) offsets = [0] * number_of_events for i in range(number_of_events): offsets[i] = read_u32(stream) _ = read_u8(stream) # Unknown flags self.extend(offsets)
def get_filesystem_create_file_details(io, metadata, event, details_io, extra_detail_io): event.details["Desired Access"] = get_filesystem_access_mask_string(read_u32(io)) impersonating_sid_length = read_u8(io) io.seek(0x3, 1) # padding details_io.seek(0x10, 1) if metadata.sizeof_pvoid == 8: details_io.seek(4, 1) # Padding for 64 bit disposition_and_options = read_u32(details_io) disposition = disposition_and_options >> 0x18 options = disposition_and_options & 0xffffff if metadata.sizeof_pvoid == 8: details_io.seek(4, 1) # Padding for 64 bit attributes = read_u16(details_io) share_mode = read_u16(details_io) event.details["Disposition"] = get_enum_name_or(FilesystemDisposition, disposition, "<unknown>") event.details["Options"] = get_filesysyem_create_options(options) event.details["Attributes"] = get_filesysyem_create_attributes(attributes) event.details["ShareMode"] = get_filesysyem_create_share_mode(share_mode) details_io.seek(0x4 + metadata.sizeof_pvoid * 2, 1) allocation = read_u32(details_io) allocation_value = allocation if disposition in [FilesystemDisposition.Supersede, FilesystemDisposition.Create, FilesystemDisposition.OpenIf, FilesystemDisposition.OverwriteIf] else "n/a" event.details["AllocationSize"] = allocation_value if impersonating_sid_length: event.details["Impersonating"] = get_sid_string(io.read(impersonating_sid_length)) open_result = None if extra_detail_io: open_result = read_u32(extra_detail_io) event.details["OpenResult"] = get_enum_name_or(FilesystemOpenResult, open_result, "<unknown>") if open_result in [FilesystemOpenResult.Superseded, FilesystemOpenResult.Created, FilesystemOpenResult.Overwritten]: event.category = "Write" elif open_result in [FilesystemOpenResult.Opened, FilesystemOpenResult.Exists, FilesystemOpenResult.DoesNotExist]: pass elif event.details["Disposition"] in ["Open", "<unknown>"]: pass else: event.category = "Write"
def __init__(self, io, read_pvoid, strings_table): super(ProcessTable, self).__init__() self._read_pvoid = read_pvoid self._strings_table = strings_table process_table_start = io.tell() number_of_processes = read_u32(io) # The array of process indexes is not essential becuase they appear in the process structure itself. # process_index_array = [read_u32(io) for _ in range(number_of_processes)] io.seek(number_of_processes * 4, 1) # jump over the process indexes array process_offsets_array = [ read_u32(io) for _ in range(number_of_processes) ] for offset in process_offsets_array: io.seek(process_table_start + offset, 0) process_index, process = self.__read_process(io) self[process_index] = process
def get_process_created_details(io, metadata, event, extra_detail_io): io.seek(4, 1) # Unknown fields event.details["PID"] = read_u32(io) io.seek(0x24, 1) # Unknown fields unknown_size1 = read_u8(io) unknown_size2 = read_u8(io) path_info = read_detail_string_info(io) command_line_info = read_detail_string_info(io) io.seek(2 + unknown_size1 + unknown_size2, 1) # Unknown fields event.path = read_detail_string(io, path_info) event.details["Command line"] = read_detail_string(io, command_line_info)
def get_registry_open_or_create_key_extra_details(metadata, event, extra_detail_io, details_info): event.category = "Read" if 0 == details_info["desired_access"]: return event.details["Desired Access"] = get_registry_access_mask_string(details_info["desired_access"]) if not extra_detail_io: return if event.details["Desired Access"] == "Maximum Allowed": event.details["Granted Access"] = get_registry_access_mask_string(read_u32(extra_detail_io)) else: extra_detail_io.seek(4, 1) disposition = read_u32(extra_detail_io) try: event.details["Disposition"] = RegistryDisposition(disposition).name if event.details["Disposition"] == RegistryDisposition.REG_CREATED_NEW_KEY.name: event.category = "Write" except ValueError: pass
def get_registry_event_details(io, metadata, event, extra_detail_io): path_info = read_detail_string_info(io) details_info = dict() # information that is needed by the extra details structure if event.operation in [RegistryOperation.RegLoadKey.name, RegistryOperation.RegRenameKey.name]: details_info["new_path_info"] = read_detail_string_info(io) extra_detail_io = io # the new path is a part of the details structure elif event.operation in [RegistryOperation.RegOpenKey.name, RegistryOperation.RegCreateKey.name]: io.seek(2, 1) # Unknown field details_info["desired_access"] = read_u32(io) elif event.operation in [RegistryOperation.RegQueryKey.name, RegistryOperation.RegQueryValue.name]: io.seek(2, 1) # Unknown field details_info["length"] = read_u32(io) details_info["information_class"] = read_u32(io) elif event.operation in [RegistryOperation.RegEnumValue.name, RegistryOperation.RegEnumKey.name]: io.seek(2, 1) # Unknown field details_info["length"] = read_u32(io) details_info["index"] = read_u32(io) details_info["information_class"] = read_u32(io) elif event.operation == RegistryOperation.RegSetInfoKey.name: io.seek(2, 1) # Unknown field details_info["key_set_information_class"] = read_u32(io) io.seek(4, 1) # Unknown field details_info["length"] = read_u16(io) io.seek(2, 1) # Unknown field extra_detail_io = io # For RegSetInfoKey the data is in the details structure elif event.operation == RegistryOperation.RegSetValue.name: io.seek(2, 1) # Unknown field details_info["reg_type"] = read_u32(io) details_info["length"] = read_u32(io) details_info["data_length"] = read_u32(io) extra_detail_io = io # For RegSetValue the data is in the details structure event.path = read_detail_string(io, path_info) # Get the extra details structure if metadata.should_get_details and event.operation in RegistryExtraDetailsHandler: RegistryExtraDetailsHandler[event.operation](metadata, event, extra_detail_io, details_info)
def get_process_exit_details(io, metadata, event, extra_details_io): event.details["Exit Status"] = read_u32(io) kernel_time = read_duration(io) user_time = read_duration(io) working_set = read_u64(io) peak_working_set = read_u64(io) private_bytes = read_u64(io) peak_private_bytes = read_u64(io) event.details["User Time"] = user_time event.details["Kernel Time"] = kernel_time event.details["Private Bytes"] = private_bytes event.details["Peak Private Bytes"] = peak_private_bytes event.details["Working Set"] = working_set event.details["Peak Working Set"] = peak_working_set
def __init__(self, io): stream = BytesIO(io.read(self.SIZE)) self.signature = stream.read(4) if self.signature != b"PML_": raise PMLError( "not a Process Monitor backing file (signature missing).") self.version = read_u32(stream) if self.version not in [9]: raise NotImplementedError("Not supporting PML version {}".format( self.version)) self.is_64bit = read_u32(stream) self.computer_name = read_utf16(stream, 0x20) self.system_root = read_utf16(stream, 0x208) self.number_of_events = read_u32(stream) stream.seek(8, 1) # Unknown field self.events_offset = read_u64(stream) self.events_offsets_array_offset = read_u64(stream) self.process_table_offset = read_u64(stream) self.strings_table_offset = read_u64(stream) # currently not being parsed because I don't know how to show icons in python. # Docs of this table's layout are in "docs\PML Format.md" self.icon_table_offset = read_u64(stream) stream.seek(12, 1) # Unknown fields self.windows_major_number = read_u32(stream) self.windows_minor_number = read_u32(stream) self.windows_build_number = read_u32(stream) self.windows_build_number_after_decimal_point = read_u32(stream) self.service_pack_name = read_utf16(stream, 0x32) stream.seek(0xd6, 1) # Unknown field self.number_of_logical_processors = read_u32(stream) self.ram_memory_size = read_u64(stream) self.header_size = read_u64(stream) self.hosts_and_ports_tables_offset = read_u64(stream) if self.events_offset == 0 or self.events_offsets_array_offset == 0 or self.process_table_offset == 0 or self.strings_table_offset == 0 or self.icon_table_offset == 0: raise PMLError( "PML was not closed cleanly during capture and is corrupt.") if self.header_size != self.SIZE or self.hosts_and_ports_tables_offset == 0: raise PMLError("PML is corrupt and cannot be opened.")
def read_registry_data(io, reg_type_name, length=0): """Reads registry data (which is present in the Detail column in original Procmon) according to ``reg_type`` """ if reg_type_name == RegistryTypes.REG_DWORD.name: return read_u32(io) elif reg_type_name == RegistryTypes.REG_QWORD.name: return read_u64(io) elif reg_type_name == RegistryTypes.REG_EXPAND_SZ.name or reg_type_name == RegistryTypes.REG_SZ.name: return read_utf16(io) elif reg_type_name == RegistryTypes.REG_BINARY.name: # Assuming the stream ends at the end of the extra detail, so just read everything return io.read(length) elif reg_type_name == RegistryTypes.REG_MULTI_SZ.name: return read_utf16_multisz(io, length) return ''
def __read_module(self, stream): _ = read_pvoid(stream, self._is_64bit) # Unknown field base_address = read_pvoid(stream, self._is_64bit) size = read_u32(stream) image_path = self._strings_table[read_u32(stream)] version = self._strings_table[read_u32(stream)] company = self._strings_table[read_u32(stream)] description = self._strings_table[read_u32(stream)] timestamp = read_u32(stream) stream.seek(0x18, 1) # Unknown field return Module(base_address=base_address, size=size, path=image_path, version=version, company=company, description=description, timestamp=timestamp)
def __init__(self, io, total_size, is_64bit, strings_table): super(ProcessTable, self).__init__() self._is_64bit = is_64bit self._strings_table = strings_table stream = BytesIO(io.read(total_size)) number_of_processes = read_u32(stream) # The array of process indexes is not essential becuase they appear in the process structure itself. # process_index_array = [read_u32(stream) for _ in range(number_of_processes)] stream.seek(number_of_processes * 4, 1) # jump over the process indexes array # relative offsets to processes are not essential since they come one after another # process_offsets_array = [read_u32(stream) for _ in range(number_of_processes)] stream.seek(number_of_processes * 4, 1) # jump over the process offsets array for _ in range(number_of_processes): process_index, process = self.__read_process(stream) self[process_index] = process
def get_network_event_details(io, metadata, event, extra_detail_io): flags = read_u16(io) is_source_ipv4 = flags & 1 != 0 is_dest_ipv4 = flags & 2 != 0 is_tcp = flags & 4 != 0 protocol = "TCP" if is_tcp else "UDP" event.operation = protocol + " " + event.operation io.seek(2, 1) # Unknown field event.details['Length'] = read_u32(io) source_ip = io.read(16) dest_ip = io.read(16) source_port = read_u16(io) dest_port = read_u16(io) event.path = "{}:{} -> {}:{}".format( metadata.hostname_idx(source_ip, is_source_ipv4), metadata.port_idx(source_port, is_tcp), metadata.hostname_idx(dest_ip, is_dest_ipv4), metadata.port_idx(dest_port, is_tcp)) extra_details = read_utf16_multisz(io) for i in range(len(extra_details) // 2): event.details[extra_details[i * 2]] = extra_details[i * 2 + 1]
def read_event(io, metadata): """Reads the event that the stream points to. :param io: the stream. :param metadata: metadata of the PML file. :return: Event object. """ COMMON_EVENT_INFO_SIZE = 0x34 # the size of the fields that are common to all events. stream = BytesIO(io.read(COMMON_EVENT_INFO_SIZE)) process = metadata.process_idx(read_u32(stream)) tid = read_u32(stream) event_class = EventClass(read_u32(stream)) operation = EventClassOperation[event_class](read_u16(stream)) stream.seek(6, 1) # Unknown field duration = read_duration(stream) date = read_filetime(stream) result = read_u32(stream) stacktrace_depth = read_u16(stream) stream.seek(2, 1) # Unknown field details_size = read_u32(stream) extra_details_offset = read_u32(stream) stream = BytesIO(io.read(stacktrace_depth * sizeof_pvoid(metadata.is_64bit))) stacktrace = [read_pvoid(stream, metadata.is_64bit) for _ in range(stacktrace_depth)] details = OrderedDict() event = Event(process=process, tid=tid, event_class=event_class, operation=operation, duration=duration, date=date, result=result, stacktrace=stacktrace, category='', path='', details=details) details_stream = BytesIO(io.read(details_size)) extra_details_stream = None if extra_details_offset > 0: # The extra details structure surprisingly can be separated from the event structure extra_details_offset -= \ (COMMON_EVENT_INFO_SIZE + details_size + stacktrace_depth * sizeof_pvoid(metadata.is_64bit)) assert extra_details_offset >= 0 current_offset = io.tell() io.seek(extra_details_offset, 1) extra_details_stream_size = read_u16(io) extra_details_stream = BytesIO(io.read(extra_details_stream_size)) io.seek(current_offset, 0) get_event_details(details_stream, metadata, event, extra_details_stream) return event
def __read_process(self, stream): process_index = read_u32(stream) pid = read_u32(stream) parent_pid = read_u32(stream) stream.seek(4, 1) # Unknown field authentication_id = read_u64(stream) session = read_u32(stream) stream.seek(4, 1) # Unknown field start_time = read_filetime(stream) end_time = read_filetime(stream) virtualized = read_u32(stream) is_process_64bit = read_u32(stream) integrity = self._strings_table[read_u32(stream)] user = self._strings_table[read_u32(stream)] process_name = self._strings_table[read_u32(stream)] image_path = self._strings_table[read_u32(stream)] command_line = self._strings_table[read_u32(stream)] company = self._strings_table[read_u32(stream)] version = self._strings_table[read_u32(stream)] description = self._strings_table[read_u32(stream)] _ = read_pvoid(stream, self._is_64bit) # Unknown field _ = read_u64(stream) # Unknown field number_of_modules = read_u32(stream) modules = [self.__read_module(stream) for _ in range(number_of_modules)] return process_index, Process(pid=pid, parent_pid=parent_pid, authentication_id=authentication_id, session=session, virtualized=virtualized, is_process_64bit=is_process_64bit, integrity=integrity, user=user, process_name=process_name, image_path=image_path, command_line=command_line, company=company, version=version, description=description, start_time=start_time, end_time=end_time, modules=modules)
def get_filesystem_query_directory_details(io, metadata, event, details_io, extra_detail_io): event.category = "Read Metadata" directory_name_info = read_detail_string_info(io) directory_name = read_detail_string(io, directory_name_info) if directory_name: event.path = event.path + directory_name if event.path[-1] == "\\" else event.path + "\\" + directory_name event.details['Filter'] = directory_name details_io.seek(0x10, 1) if metadata.sizeof_pvoid == 8: details_io.seek(4, 1) # Padding for 64 bit details_io.seek(0x4, 1) if metadata.sizeof_pvoid == 8: details_io.seek(4, 1) # Padding for 64 bit file_information_class = FileInformationClass(read_u32(details_io)) event.details["FileInformationClass"] = file_information_class.name if extra_detail_io and file_information_class in [FileInformationClass.FileDirectoryInformation, FileInformationClass.FileFullDirectoryInformation, FileInformationClass.FileBothDirectoryInformation, FileInformationClass.FileNamesInformation, FileInformationClass.FileIdBothDirectoryInformation, FileInformationClass.FileIdFullDirectoryInformation]: extra_detail_length = len(extra_detail_io.getvalue()) next_entry_offset = -1 # hack so the first iteration won't exit current_entry_offset = 1 i = 0 if directory_name else -1 while True: i += 1 if next_entry_offset == 0 or (current_entry_offset + next_entry_offset) > extra_detail_length: break # No more structures extra_detail_io.seek(current_entry_offset + next_entry_offset, 0) current_entry_offset = extra_detail_io.tell() next_entry_offset = read_u32(extra_detail_io) file_index = read_u32(extra_detail_io) if file_information_class == FileInformationClass.FileNamesInformation: # FILE_NAMES_INFORMATION structure file_name_length = read_u32(extra_detail_io) event.details[str(i)] = read_utf16(extra_detail_io, file_name_length) continue creation_time = read_filetime(extra_detail_io) last_access_time = read_filetime(extra_detail_io) last_write_time = read_filetime(extra_detail_io) change_time = read_filetime(extra_detail_io) end_of_file = read_u64(extra_detail_io) allocation_size = read_u64(extra_detail_io) file_attributes = read_u32(extra_detail_io) file_name_length = read_u32(extra_detail_io) if file_information_class == FileInformationClass.FileDirectoryInformation: # FILE_DIRECTORY_INFORMATION structure event.details[str(i)] = read_utf16(extra_detail_io, file_name_length) continue ea_size = read_u32(extra_detail_io) if file_information_class == FileInformationClass.FileFullDirectoryInformation: # FILE_FULL_DIR_INFORMATION structure event.details[str(i)] = read_utf16(extra_detail_io, file_name_length) continue if file_information_class == FileInformationClass.FileIdFullDirectoryInformation: # FILE_ID_FULL_DIR_INFORMATION structure file_id = read_u64(extra_detail_io) event.details[str(i)] = read_utf16(extra_detail_io, file_name_length) continue short_name_length = read_u8(extra_detail_io) extra_detail_io.seek(1, 1) # Padding short_name = extra_detail_io.read(12 * 2) if file_information_class == FileInformationClass.FileBothDirectoryInformation: # FILE_BOTH_DIR_INFORMATION structure event.details[str(i)] = read_utf16(extra_detail_io, file_name_length) continue # FILE_ID_BOTH_DIR_INFORMATION structure extra_detail_io.seek(2, 1) # Padding file_id = read_u64(extra_detail_io) event.details[str(i)] = read_utf16(extra_detail_io, file_name_length) continue
def get_registry_query_or_enum_key_extra_details(metadata, event, extra_detail_io, details_info): event.category = "Read" # RegQueryKey and RegEnumKey is always Read key_information_class = RegistryKeyInformationClass(details_info["information_class"]) if event.operation == RegistryOperation.RegEnumKey.name: event.details["Index"] = details_info["index"] # Only in enum elif event.operation == RegistryOperation.RegQueryKey.name: event.details["Query"] = key_information_class.name # Only in query if not extra_detail_io: # There is no extra details event.details["Length"] = details_info["length"] return if key_information_class == RegistryKeyInformationClass.Name: # KEY_NAME_INFORMATION structure name_size = read_u32(extra_detail_io) event.details["Name"] = read_utf16(extra_detail_io, name_size) elif key_information_class == RegistryKeyInformationClass.HandleTags: event.details["HandleTags"] = read_u32(extra_detail_io) elif key_information_class == RegistryKeyInformationClass.Flags: event.details["UserFlags"] = read_u32(extra_detail_io) elif key_information_class == RegistryKeyInformationClass.Cached: # KEY_CACHED_INFORMATION structure event.details["LastWriteTime"] = read_filetime(extra_detail_io) event.details["TitleIndex"] = read_u32(extra_detail_io) event.details["SubKeys"] = read_u32(extra_detail_io) event.details["MaxNameLen"] = read_u32(extra_detail_io) event.details["Values"] = read_u32(extra_detail_io) event.details["MaxValueNameLen"] = read_u32(extra_detail_io) event.details["MaxValueDataLen"] = read_u32(extra_detail_io) elif key_information_class == RegistryKeyInformationClass.Basic: # KEY_BASIC_INFORMATION structure event.details["LastWriteTime"] = read_filetime(extra_detail_io) event.details["TitleIndex"] = read_u32(extra_detail_io) name_size = read_u32(extra_detail_io) event.details["Name"] = read_utf16(extra_detail_io, name_size) elif key_information_class == RegistryKeyInformationClass.Full: # KEY_FULL_INFORMATION structure event.details["LastWriteTime"] = read_filetime(extra_detail_io) event.details["TitleIndex"] = read_u32(extra_detail_io) event.details["ClassOffset"] = read_u32(extra_detail_io) event.details["ClassLength"] = read_u32(extra_detail_io) event.details["SubKeys"] = read_u32(extra_detail_io) event.details["MaxNameLen"] = read_u32(extra_detail_io) event.details["MaxClassLen"] = read_u32(extra_detail_io) event.details["Values"] = read_u32(extra_detail_io) event.details["MaxValueNameLen"] = read_u32(extra_detail_io) event.details["MaxValueDataLen"] = read_u32(extra_detail_io) elif key_information_class == RegistryKeyInformationClass.Node: # KEY_NODE_INFORMATION structure event.details["LastWriteTime"] = read_filetime(extra_detail_io) event.details["TitleIndex"] = read_u32(extra_detail_io) event.details["ClassOffset"] = read_u32(extra_detail_io) event.details["ClassLength"] = read_u32(extra_detail_io) name_size = read_u32(extra_detail_io) event.details["Name"] = read_utf16(extra_detail_io, name_size)
def get_load_image_details(io, metadata, event, extra_detail_io): event.details["Image Base"] = metadata.read_pvoid(io) event.details["Image Size"] = read_u32(io) path_info = read_detail_string_info(io) io.seek(2, 1) # Unknown field event.path = read_detail_string(io, path_info)
def get_thread_create_details(io, metadata, event, extra_detail_io): event.details["Thread ID"] = read_u32(io)