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 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 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 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. """ process_idx, tid, event_class_val, operation_val, _, _, duration, date, result, stacktrace_depth, _, \ details_size, extra_details_offset = CommonEventStruct.unpack(io.read(CommonEventStruct.size)) process = metadata.process_idx(process_idx) event_class = EventClass(event_class_val) operation = EventClassOperation[event_class](operation_val) sizeof_stacktrace = stacktrace_depth * metadata.sizeof_pvoid if metadata.should_get_stacktrace: stream = BytesIO(io.read(sizeof_stacktrace)) stacktrace = [ metadata.read_pvoid(stream) for _ in range(stacktrace_depth) ] else: io.seek(sizeof_stacktrace, 1) stacktrace = [] details = OrderedDict() event = Event(process=process, tid=tid, event_class=event_class, operation=operation, duration=duration, date_filetime=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 -= \ (CommonEventStruct.size + details_size + sizeof_stacktrace) 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 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 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 read_detail_string_info(io): """Reads the info field about a detail string (contains is_ascii and number of characters) """ flags = read_u16(io) return flags >> 15 == 1, flags & (2 ** 15 - 1) # is_ascii, char_count