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