From 1db15d9a7da0fd3f8f769e06db3ad2dac1d06a4d Mon Sep 17 00:00:00 2001 From: rabbitstack Date: Tue, 12 May 2026 18:29:44 +0200 Subject: [PATCH] refactor(event): Introduce event decoder Add a dedicated parameter decoder responsible for extracting and interpreting event parameters from raw byte payloads. The decoder is designed with a modular approach where each method handles a specific type of event type or a group of events, enabling clearer separation of concerns and easier extensibility for future event formats. This refactor improves readability, maintainability, and correctness of event parsing logic, while making it easier to extend support for new event and parameter types in the future. --- pkg/event/event_windows.go | 14 +- pkg/event/param.go | 10 + pkg/event/param_decoder_windows.go | 623 +++++++++++++++ pkg/event/param_decoder_windows_test.go | 971 ++++++++++++++++++++++++ pkg/event/param_windows.go | 760 ++----------------- pkg/event/types_windows.go | 233 ++++-- 6 files changed, 1815 insertions(+), 796 deletions(-) create mode 100644 pkg/event/param_decoder_windows.go create mode 100644 pkg/event/param_decoder_windows_test.go diff --git a/pkg/event/event_windows.go b/pkg/event/event_windows.go index b4f1ee6a0..7c1d21bfc 100644 --- a/pkg/event/event_windows.go +++ b/pkg/event/event_windows.go @@ -48,13 +48,13 @@ var ( // New constructs a fresh event instance with basic fields and parameters // from the raw ETW event record. -func New(seq uint64, evt *etw.EventRecord) *Event { +func New(seq uint64, r *etw.EventRecord) *Event { var ( - pid = evt.Header.ProcessID - tid = evt.Header.ThreadID - cpu = *(*uint8)(unsafe.Pointer(&evt.BufferContext.ProcessorIndex[0])) - ts = filetime.ToEpoch(evt.Header.Timestamp) - typ = NewTypeFromEventRecord(evt) + pid = r.Header.ProcessID + tid = r.Header.ThreadID + cpu = *(*uint8)(unsafe.Pointer(&r.BufferContext.ProcessorIndex[0])) + ts = filetime.ToEpoch(r.Header.Timestamp) + typ = NewTypeFromEventRecord(r) ) e := &Event{ @@ -70,7 +70,7 @@ func New(seq uint64, evt *etw.EventRecord) *Event { Host: hostname.Get(), } - e.produceParams(evt) + e.decodeParams(r) e.adjustPID() return e diff --git a/pkg/event/param.go b/pkg/event/param.go index a7d21ce20..58f003865 100644 --- a/pkg/event/param.go +++ b/pkg/event/param.go @@ -406,6 +406,16 @@ func (pars Params) GetUint16(name string) (uint16, error) { return v, nil } +// MustGetUint8 returns the underlying uint8 value parameter. It panics if +// an error occurs while trying to get the parameter. +func (pars Params) MustGetUint8(name string) uint8 { + v, err := pars.GetUint8(name) + if err != nil { + panic(err) + } + return v +} + // MustGetUint16 returns the underlying uint16 value parameter. It panics if // an error occurs while trying to get the parameter. func (pars Params) MustGetUint16(name string) uint16 { diff --git a/pkg/event/param_decoder_windows.go b/pkg/event/param_decoder_windows.go new file mode 100644 index 000000000..ed5b09ddd --- /dev/null +++ b/pkg/event/param_decoder_windows.go @@ -0,0 +1,623 @@ +/* + * Copyright 2020-present by Nedim Sabic Sabic + * https://www.fibratus.io + * All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package event + +import ( + "encoding/binary" + "path/filepath" + "strings" + + "github.com/rabbitstack/fibratus/pkg/event/params" + "github.com/rabbitstack/fibratus/pkg/fs" + "github.com/rabbitstack/fibratus/pkg/sys/etw" + "github.com/rabbitstack/fibratus/pkg/util/filetime" + "github.com/rabbitstack/fibratus/pkg/util/key" + "github.com/rabbitstack/fibratus/pkg/util/signature" + "github.com/rabbitstack/fibratus/pkg/util/utf16" + "github.com/rabbitstack/fibratus/pkg/util/va" + "golang.org/x/sys/windows" + "golang.org/x/sys/windows/registry" +) + +// ParamDecoder parses parameters from the event buffer. +type ParamDecoder struct{} + +// DecodeRegistry parses registry events such as key creation, +// key/value access, or value mutation. +func (d *ParamDecoder) DecodeRegistry(r *etw.EventRecord, e *Event) { + // typedef struct _WMI_REGISTRY { + // LONGLONG InitialTime; + // ULONG Status; + // union{ + // ULONG Index; + // ULONG InfoClass; + // } DUMMYUNIONNAME; + // PVOID Kcb; + // WCHAR Name[1]; + // } WMI_REGISTRY, *PWMI_REGISTRY; + + // skip InitialTime (uint64) + e.AppendParam(params.NTStatus, params.Status, r.ReadUint32(8)) + // skip Index/InfoClass (uint32) + e.AppendParam(params.RegKeyHandle, params.Address, r.ReadUint64(16)) + e.AppendParam(params.RegPath, params.Key, r.ConsumeUTF16String(24)) +} + +// DecodeRegSetValueInternal decodes the payload for the registry set value +// event used for enriching the core RegSetValue event emitted by the system +// logger. +// +// The event describes a registry value modification operation and contains +// both metadata about the target registry value and a captured snapshot of +// the written data buffer. +func (d *ParamDecoder) DecodeRegSetValueInternal(r *etw.EventRecord, e *Event) { + // + valueType := r.ReadUint32(12) + // skip DataSize (uint32) + keyName, koffset := r.ReadUTF16String(20) + valueName, voffset := r.ReadUTF16String(koffset) + capturedSize := r.ReadUint16(voffset) + capturedData := r.ReadBytes(2+voffset, capturedSize) + + // copy the buffer to avoid dangling pointers + // after the callback function returns and the + // buffer lifetime evicts + b := make([]byte, capturedSize) + copy(b, capturedData) + + e.AppendParam(params.RegKeyHandle, params.Address, r.ReadUint64(0)) + e.AppendParam(params.NTStatus, params.Status, r.ReadUint32(8)) + e.AppendParam(params.RegPath, params.Key, filepath.Join(keyName, valueName)) + e.AppendEnum(params.RegValueType, valueType, key.RegistryValueTypes) + + if len(b) == 0 { + return + } + + // populate value data depending on its type + switch valueType { + case registry.SZ, registry.MULTI_SZ, registry.EXPAND_SZ: + e.AppendParam(params.RegData, params.UnicodeString, utf16.BytesToString(b, binary.LittleEndian)) + case registry.BINARY: + e.AppendParam(params.RegData, params.Binary, b) + case registry.DWORD: + var v uint32 + switch len(b) { + case 4: + v = binary.LittleEndian.Uint32(b) + case 2: + v = uint32(binary.LittleEndian.Uint16(b)) + case 1: + v = uint32(b[0]) + } + e.AppendParam(params.RegData, params.Uint32, v) + case registry.DWORD_BIG_ENDIAN: + var v uint32 + switch len(b) { + case 4: + v = binary.BigEndian.Uint32(b) + case 2: + v = uint32(binary.BigEndian.Uint16(b)) + case 1: + v = uint32(b[0]) + } + e.AppendParam(params.RegData, params.Uint32, v) + case registry.QWORD: + var v uint64 + switch len(b) { + case 8: + v = binary.LittleEndian.Uint64(b) + case 4: + v = uint64(binary.LittleEndian.Uint32(b)) + case 2: + v = uint64(binary.LittleEndian.Uint16(b)) + case 1: + v = uint64(b[0]) + } + e.AppendParam(params.RegData, params.Uint64, v) + } +} + +// DecodeFile decodes file I/O operations such as file creation, access, +// or file metadata manipulation. +func (d *ParamDecoder) DecodeFile(r *etw.EventRecord, e *Event) { + switch r.Header.EventDescriptor.Opcode { + case CreateFileID: + // typedef struct _PERFINFO_FILE_CREATE { + // LONG_PTR Irp; + // ULONG_PTR FileObject; + // ULONG IssuingThreadId; + // ULONG Options; + // ULONG Attributes; + // ULONG ShareAccess; + // WCHAR OpenPath[1]; + // } PERFINFO_FILE_CREATE, *PPERFINFO_FILE_CREATE; + e.AppendParam(params.FileIrpPtr, params.Address, r.ReadUint64(0)) + e.AppendParam(params.FileObject, params.Address, r.ReadUint64(8)) + e.AppendParam(params.ThreadID, params.TID, r.ReadUint32(16)) + e.AppendParam(params.FileCreateOptions, params.Flags, r.ReadUint32(20), WithFlags(FileCreateOptionsFlags)) + e.AppendParam(params.FileAttributes, params.Flags, r.ReadUint32(24), WithFlags(FileAttributeFlags)) + e.AppendParam(params.FileShareMask, params.Flags, r.ReadUint32(28), WithFlags(FileShareModeFlags)) + e.AppendParam(params.FilePath, params.DOSPath, r.ConsumeUTF16String(32)) + case FileOpEndID: + // typedef struct _PERFINFO_FILE_OPERATION_END { + // ULONG_PTR Irp; + // ULONG_PTR ExtraInformation; + // NTSTATUS Status; + // } PERFINFO_FILE_OPERATION_END, *PPERFINFO_FILE_OPERATION_END; + e.AppendParam(params.FileIrpPtr, params.Address, r.ReadUint64(0)) + e.AppendParam(params.FileExtraInfo, params.Address, r.ReadUint64(8)) + e.AppendParam(params.NTStatus, params.Status, r.ReadUint32(16)) + case MapViewFileID, UnmapViewFileID, MapFileRundownID: + e.AppendParam(params.FileViewBase, params.Address, r.ReadUint64(0)) + e.AppendParam(params.FileKey, params.Address, r.ReadUint64(8)) + e.AppendParam(params.MemProtect, params.Flags, uint32(r.ReadUint64(16)>>32), WithFlags(ViewProtectionFlags)) + e.AppendParam(params.FileViewSectionType, params.Enum, uint32(r.ReadUint64(16)>>52), WithEnum(ViewSectionTypes)) + e.AppendParam(params.FileViewSize, params.Uint64, r.ReadUint64(24)) + e.AppendParam(params.FileOffset, params.Uint64, r.ReadUint64(32)) + e.AppendParam(params.ProcessID, params.PID, r.ReadUint32(40)) + case SetFileInformationID, DeleteFileID, RenameFileID: + // DeleteFile, RenameFile, and SetFileInformation share the same layout + // typedef struct _PERFINFO_FILE_INFORMATION { + // ULONG_PTR Irp; + // ULONG_PTR FileObject; + // ULONG_PTR FileKey; + // ULONG_PTR ExtraInformation; + // ULONG IssuingThreadId; + // ULONG InfoClass; + // } PERFINFO_FILE_INFORMATION, *PPERFINFO_FILE_INFORMATION; + e.AppendParam(params.FileIrpPtr, params.Address, r.ReadUint64(0)) + e.AppendParam(params.FileObject, params.Address, r.ReadUint64(8)) + e.AppendParam(params.FileKey, params.Address, r.ReadUint64(16)) + e.AppendParam(params.FileExtraInfo, params.Uint64, r.ReadUint64(24)) + e.AppendParam(params.ThreadID, params.TID, r.ReadUint32(32)) + e.AppendParam(params.FileInfoClass, params.Enum, r.ReadUint32(36), WithEnum(fs.FileInfoClasses)) + case ReleaseFileID, CloseFileID: + // typedef struct _PERFINFO_FILE_SIMPLE_OPERATION { + // ULONG_PTR Irp; + // ULONG_PTR FileObject; + // ULONG_PTR FileKey; + // ULONG IssuingThreadId; + // } PERFINFO_FILE_SIMPLE_OPERATION, *PPERFINFO_FILE_SIMPLE_OPERATION; + e.AppendParam(params.FileIrpPtr, params.Address, r.ReadUint64(0)) + e.AppendParam(params.FileObject, params.Address, r.ReadUint64(8)) + e.AppendParam(params.FileKey, params.Address, r.ReadUint64(16)) + e.AppendParam(params.ThreadID, params.TID, r.ReadUint32(24)) + case ReadFileID, WriteFileID: + // typedef struct _PERFINFO_FILE_READ_WRITE { + // ULONGLONG Offset; + // ULONG_PTR Irp; + // ULONG_PTR FileObject; + // ULONG_PTR FileKey; + // ULONG IssuingThreadId; + // ULONG Size; + // ULONG Flags; + // ULONG ExtraFlags; + // } PERFINFO_FILE_READ_WRITE, *PPERFINFO_FILE_READ_WRITE; + e.AppendParam(params.FileOffset, params.Uint64, r.ReadUint64(0)) + e.AppendParam(params.FileIrpPtr, params.Address, r.ReadUint64(8)) + e.AppendParam(params.FileObject, params.Address, r.ReadUint64(16)) + e.AppendParam(params.FileKey, params.Address, r.ReadUint64(24)) + e.AppendParam(params.ThreadID, params.TID, r.ReadUint32(32)) + e.AppendParam(params.FileIoSize, params.Uint32, r.ReadUint32(34)) + case EnumDirectoryID: + // typedef struct _PERFINFO_FILE_DIRENUM { + // ULONG_PTR Irp; + // ULONG_PTR FileObject; + // ULONG_PTR FileKey; + // ULONG IssuingThreadId; + // ULONG Length; + // ULONG InfoClass; + // ULONG FileIndex; + // WCHAR FileName[1]; + // } PERFINFO_FILE_DIRENUM, *PPERFINFO_FILE_DIRENUM; + e.AppendParam(params.FileIrpPtr, params.Address, r.ReadUint64(0)) + e.AppendParam(params.FileObject, params.Address, r.ReadUint64(8)) + e.AppendParam(params.FileKey, params.Address, r.ReadUint64(16)) + e.AppendParam(params.ThreadID, params.TID, r.ReadUint32(24)) + // skip Length (uint32) + e.AppendParam(params.FileInfoClass, params.Enum, r.ReadUint32(32), WithEnum(fs.FileInfoClasses)) + // skip FileIndex (uint32) + e.AppendParam(params.FilePath, params.UnicodeString, r.ConsumeUTF16String(40)) + case FileRundownID: + e.AppendParam(params.FileObject, params.Address, r.ReadUint64(0)) + e.AppendParam(params.FilePath, params.DOSPath, r.ConsumeUTF16String(8)) + } +} + +// DecodeProcess decodes process creation/termination/rundown event payloads. +func (d *ParamDecoder) DecodeProcess(r *etw.EventRecord, e *Event) { + // typedef struct _WMI_PROCESS_INFORMATION { + // ULONG_PTR UniqueProcessKey; + // ULONG ProcessId; + // ULONG ParentId; + // ULONG SessionId; + // NTSTATUS ExitStatus; + // ULONG_PTR DirectoryTableBase; + // ULONG Flags; + // ULONG Sid; + // // Variable length sid + // // FileName (ansi string) + // // CommandLine (unicode string) + // // PackageFullName (unicode string) + // // PRAID (unicode string) + // } WMI_PROCESS_INFORMATION, *PWMI_PROCESS_INFORMATION; + const offset = 32 + sid, soffset := r.ReadSID(offset+4, true) + name, noffset := r.ReadAnsiString(soffset) + cmdline, _ := r.ReadUTF16String(noffset) + + e.AppendParam(params.ProcessObject, params.Address, r.ReadUint64(0)) + e.AppendParam(params.ProcessID, params.PID, r.ReadUint32(8)) + e.AppendParam(params.ProcessParentID, params.PID, r.ReadUint32(12)) + e.AppendParam(params.SessionID, params.Uint32, r.ReadUint32(16)) + e.AppendParam(params.ExitStatus, params.Status, r.ReadUint32(20)) + e.AppendParam(params.DTB, params.Address, r.ReadUint64(24)) + e.AppendParam(params.ProcessFlags, params.Flags, r.ReadUint32(32), WithFlags(PsCreationFlags)) + e.AppendParam(params.UserSID, params.WbemSID, sid) + e.AppendParam(params.ProcessName, params.AnsiString, name) + e.AppendParam(params.Cmdline, params.UnicodeString, cmdline) + e.AppendParam(params.ProcessRealParentID, params.PID, r.Header.ProcessID) +} + +// DecodeProcessInternal decodes process creation/rundown event payloads +// for internal events that are used to enrich the core NT Kernel logger +// process events. +func (d *ParamDecoder) DecodeProcessInternal(r *etw.EventRecord, e *Event) { + // + e.AppendParam(params.ProcessID, params.PID, r.ReadUint32(0)) + e.AppendParam(params.ProcessObject, params.Address, r.ReadUint64(4)) + + createTime := windows.NsecToFiletime(int64(r.ReadUint64(12))) + e.AppendParam(params.StartTime, params.Time, filetime.ToEpoch(uint64(createTime.Nanoseconds()))) + + e.AppendParam(params.ProcessParentID, params.PID, r.ReadUint32(20)) + // skip ParentProcessSequenceNumber (uint64) + e.AppendParam(params.SessionID, params.Uint32, r.ReadUint32(32)) + e.AppendParam(params.ProcessFlags, params.Flags, r.ReadUint32(36), WithFlags(PsCreationFlags)) + e.AppendParam(params.ProcessTokenElevationType, params.Enum, r.ReadUint32(40), WithEnum(PsTokenElevationTypes)) + e.AppendParam(params.ProcessTokenIsElevated, params.Bool, r.ReadUint32(44) > 0) + + tokenMandatoryLabel, _ := r.ReadSID(48, false) // integrity level SID size is 12 bytes + e.AppendParam(params.ProcessTokenIntegrityLevel, params.SID, tokenMandatoryLabel) + + exe, _ := r.ReadNTUnicodeString(60) + e.AppendParam(params.Exe, params.DOSPath, exe) +} + +// DecodeModule decodes module load/unload/rundown event payloads. +func (d *ParamDecoder) DecodeModule(r *etw.EventRecord, e *Event) { + // typedef struct _WMI_IMAGELOAD_INFORMATION64 { + // ULONG64 ImageBase64; + // ULONG64 ImageSize64; + // ULONG ProcessId; + // ULONG ImageChecksum; + // ULONG TimeDateStamp; + // UCHAR SignatureLevel; + // UCHAR SignatureType; + // USHORT Reserved0; + // ULONG64 DefaultBase64; + // ULONG Reserved1; + // ULONG Reserved2; + // ULONG Reserved3; + // ULONG Reserved4; + // WCHAR FileName[1]; + // } WMI_IMAGELOAD_INFORMATION64, *PWMI_IMAGELOAD_INFORMATION64; + e.AppendParam(params.ModuleBase, params.Address, r.ReadUint64(0)) + e.AppendParam(params.ModuleSize, params.Uint64, r.ReadUint64(8)) + e.AppendParam(params.ProcessID, params.PID, r.ReadUint32(16)) + e.AppendParam(params.ModuleCheckSum, params.Uint32, r.ReadUint32(20)) + // skip TimeDateStamp (uint32) + e.AppendParam(params.ModuleSignatureLevel, params.Enum, uint32(r.ReadByte(28)), WithEnum(signature.Levels)) + e.AppendParam(params.ModuleSignatureType, params.Enum, uint32(r.ReadByte(29)), WithEnum(signature.Types)) + // skip Reserved0 (uint8) + e.AppendParam(params.ModuleDefaultBase, params.Address, r.ReadUint64(32)) + // skip Reserved1-Reserved4 (uint32 * 4) + const offset = 56 + e.AppendParam(params.ModulePath, params.DOSPath, r.ConsumeUTF16String(offset)) +} + +// DecodeModuleInternal decodes module load event payload for internal events +// that are used to make the process snapshotter more resistant in light of +// module lookups that might not be registered when the event from the security +// logger session is published. +func (d *ParamDecoder) DecodeModuleInternal(r *etw.EventRecord, e *Event) { + // + e.AppendParam(params.ModuleBase, params.Address, r.ReadUint64(0)) + e.AppendParam(params.ModuleSize, params.Uint64, r.ReadUint64(8)) + e.AppendParam(params.ProcessID, params.PID, r.ReadUint32(16)) + e.AppendParam(params.ModuleCheckSum, params.Uint32, r.ReadUint32(20)) + // skip TimeDateStamp (uint32) + e.AppendParam(params.ModuleDefaultBase, params.Address, r.ReadUint64(28)) + e.AppendParam(params.ModulePath, params.DOSPath, r.ConsumeUTF16String(36)) +} + +// DecodeOpenProcess parses the event payload for OpenProcess events. +func (d *ParamDecoder) DecodeOpenProcess(r *etw.EventRecord, e *Event) { + e.AppendParam(params.ProcessID, params.PID, r.ReadUint32(0)) + e.AppendParam(params.DesiredAccess, params.Flags, r.ReadUint32(4), WithFlags(PsAccessRightFlags)) + e.AppendParam(params.NTStatus, params.Status, r.ReadUint32(8)) + e.AppendParam(params.Callstack, params.Slice, r.Callstack()) +} + +// DecodeThread decodes the event payload for thread creation/termination +// and thread rundown events. +func (d *ParamDecoder) DecodeThread(r *etw.EventRecord, e *Event) { + // typedef struct _WMI_EXTENDED_THREAD_INFORMATION64 { + // ULONG ProcessId; + // ULONG ThreadId; + // ULONG64 StackBase64; + // ULONG64 StackLimit64; + // ULONG64 UserStackBase64; + // ULONG64 UserStackLimit64; + // union { + // ULONG64 StartAddr64; + // ULONG64 Affinity; + // } DUMMYUNIONNAME; + // ULONG64 Win32StartAddr64; + // ULONG64 TebBase64; + // ULONG SubProcessTag; + // SCHAR BasePriority; + // UCHAR PagePriority; + // UCHAR IoPriority; + // UCHAR Flags; + // } WMI_EXTENDED_THREAD_INFORMATION64, *PWMI_EXTENDED_THREAD_INFORMATION64; + e.AppendParam(params.ProcessID, params.PID, r.ReadUint32(0)) + e.AppendParam(params.ThreadID, params.TID, r.ReadUint32(4)) + e.AppendParam(params.KstackBase, params.Address, r.ReadUint64(8)) + e.AppendParam(params.KstackLimit, params.Address, r.ReadUint64(16)) + e.AppendParam(params.UstackBase, params.Address, r.ReadUint64(24)) + e.AppendParam(params.UstackLimit, params.Address, r.ReadUint64(32)) + // skip StartAddr64 (uint64) + e.AppendParam(params.StartAddress, params.Address, r.ReadUint64(48)) + e.AppendParam(params.TEB, params.Address, r.ReadUint64(56)) + // skip SubProcessTag (uint32) + e.AppendParam(params.BasePrio, params.Uint8, r.ReadByte(68)) + e.AppendParam(params.PagePrio, params.Uint8, r.ReadByte(69)) + e.AppendParam(params.IOPrio, params.Uint8, r.ReadByte(70)) +} + +// DecodeOpenThread decodes the payload for the OpenThread event. +func (d *ParamDecoder) DecodeOpenThread(r *etw.EventRecord, e *Event) { + e.AppendParam(params.ProcessID, params.PID, r.ReadUint32(0)) + e.AppendParam(params.ThreadID, params.TID, r.ReadUint32(4)) + e.AppendParam(params.DesiredAccess, params.Flags, r.ReadUint32(8), WithFlags(ThreadAccessRightFlags)) + e.AppendParam(params.NTStatus, params.Status, r.ReadUint32(12)) + e.AppendParam(params.Callstack, params.Slice, r.Callstack()) +} + +// DecodeSetThreadContext decodes the payload for the SetThreadContext event. +func (d *ParamDecoder) DecodeSetThreadContext(r *etw.EventRecord, e *Event) { + e.AppendParam(params.NTStatus, params.Status, r.ReadUint32(0)) + e.AppendParam(params.Callstack, params.Slice, r.Callstack()) +} + +// DecodeThreadpool decodes payloads for thread pool events. +func (d *ParamDecoder) DecodeThreadpool(r *etw.EventRecord, e *Event) { + switch r.Header.EventDescriptor.Opcode { + case SubmitThreadpoolWorkID, SubmitThreadpoolCallbackID: + // typedef struct _ETW_TP_EVENT_CALLBACK_ENQUEUE { + // PVOID PoolId; // Pool Identifier + // PVOID TaskId; // Task Identifier + // PVOID Callback; // Callback Function + // PVOID Context; // Callback Context + // PVOID SubProcessTag; // Sub-components in a process + // } ETW_TP_EVENT_CALLBACK_ENQUEUE, *PETW_TP_EVENT_CALLBACK_ENQUEUE + e.AppendParam(params.ThreadpoolPoolID, params.Address, r.ReadUint64(0)) + e.AppendParam(params.ThreadpoolTaskID, params.Address, r.ReadUint64(8)) + e.AppendParam(params.ThreadpoolCallback, params.Address, r.ReadUint64(16)) + e.AppendParam(params.ThreadpoolContext, params.Address, r.ReadUint64(24)) + e.AppendParam(params.ThreadpoolSubprocessTag, params.Address, r.ReadUint64(32)) + case SetThreadpoolTimerID: + // typedef struct _ETW_TP_EVENT_TIMER_SET { + // LONG64 DueTime; // Due time + // PVOID SubQueue; // Sub Queue to be inserted + // PVOID Timer; // Timer to be set + // ULONG Period; // period of the timer + // ULONG WindowLength; // Tolerate period + // ULONG Absolute; // An absolute timer or relative timer + // } ETW_TP_EVENT_TIMER_SET, *PETW_TP_EVENT_TIMER_SET; + e.AppendParam(params.ThreadpoolTimerDuetime, params.Uint64, r.ReadUint64(0)) + e.AppendParam(params.ThreadpoolTimerSubqueue, params.Address, r.ReadUint64(8)) + e.AppendParam(params.ThreadpoolTimer, params.Address, r.ReadUint64(16)) + e.AppendParam(params.ThreadpoolTimerPeriod, params.Uint32, r.ReadUint32(24)) + e.AppendParam(params.ThreadpoolTimerWindow, params.Uint32, r.ReadUint32(28)) + e.AppendParam(params.ThreadpoolTimerAbsolute, params.Bool, r.ReadUint32(32) > 0) + } +} + +// DecodeHandle decodes events for handle creation/disposition events. +func (d *ParamDecoder) DecodeHandle(r *etw.EventRecord, e *Event) { + switch r.Header.EventDescriptor.Opcode { + case CreateHandleID, CloseHandleID: + // typedef struct _ETW_CREATE_HANDLE_EVENT { + // PVOID Object; + // ULONG Handle; + // USHORT ObjectType; + // } ETW_CREATE_HANDLE_EVENT, *PETW_CREATE_HANDLE_EVENT; + e.AppendParam(params.HandleObject, params.Address, r.ReadUint64(0)) + e.AppendParam(params.HandleID, params.Uint32, r.ReadUint32(8)) + e.AppendParam(params.HandleObjectTypeID, params.HandleType, r.ReadUint16(12)) + if r.BufferLen >= 16 { + e.AppendParam(params.HandleObjectName, params.UnicodeString, r.ConsumeUTF16String(14)) + } + case DuplicateHandleID: + // typedef struct _ETW_DUPLICATE_HANDLE_EVENT { + // PVOID Object; + // ULONG SourceHandle; + // ULONG TargetHandle; + // ULONG TargetProcessId; + // USHORT ObjectType; + // ULONG SourceProcessId; + // } ETW_DUPLICATE_HANDLE_EVENT, *PETW_DUPLICATE_HANDLE_EVENT; + e.AppendParam(params.HandleObject, params.Address, r.ReadUint64(0)) + e.AppendParam(params.HandleSourceID, params.Uint32, r.ReadUint32(8)) + e.AppendParam(params.HandleID, params.Uint32, r.ReadUint32(12)) + e.AppendParam(params.TargetProcessID, params.PID, r.ReadUint32(16)) + e.AppendParam(params.HandleObjectTypeID, params.HandleType, r.ReadUint16(20)) + e.AppendParam(params.ProcessID, params.PID, r.ReadUint32(22)) + } +} + +// DecodeCreateSymbolicLinkObject decodes the payload for the CreateSymbolicLinkObject event. +func (d *ParamDecoder) DecodeCreateSymbolicLinkObject(r *etw.EventRecord, e *Event) { + source, offset := r.ReadUTF16String(0) + target, offset := r.ReadUTF16String(offset) + e.AppendParam(params.LinkSource, params.UnicodeString, source) + e.AppendParam(params.LinkTarget, params.UnicodeString, target) + e.AppendParam(params.DesiredAccess, params.Flags, r.ReadUint32(offset), WithFlags(AccessMaskFlags)) + e.AppendParam(params.NTStatus, params.Status, r.ReadUint32(offset+4)) + e.AppendParam(params.Callstack, params.Slice, r.Callstack()) +} + +// DecodeStackwalk decodes stackwalk event parameters including frame return addresses. +func (d *ParamDecoder) DecodeStackwalk(r *etw.EventRecord, e *Event) { + // typedef struct _STACK_WALK_EVENT_DATA { + // ULONGLONG TimeStamp; + // ULONG ProcessId; + // ULONG ThreadId; + // PVOID Addresses[1]; // Address of captured Stack address + // } STACK_WALK_EVENT_DATA, *PSTACK_WALK_EVENT_DATA; + + // Skip TimeStamp (uint64) + e.AppendParam(params.ProcessID, params.PID, r.ReadUint32(8)) + e.AppendParam(params.ThreadID, params.TID, r.ReadUint32(12)) + + var n uint16 + var offset uint16 = 16 + + frames := (r.BufferLen - offset) / 8 + callstack := make([]va.Address, frames) + for n < frames { + callstack[n] = va.Address(r.ReadUint64(offset)) + offset += 8 + n++ + } + e.AppendParam(params.Callstack, params.Slice, callstack) +} + +// DecodeMemory decodes memory event payloads. +func (d *ParamDecoder) DecodeMemory(r *etw.EventRecord, e *Event) { + // typedef struct _PERFINFO_VIRTUAL_ALLOC { + // PVOID CapturedBase; + // SIZE_T CapturedRegionSize; + // ULONG ProcessId; + // ULONG Flags; + // } PERFINFO_VIRTUAL_ALLOC, *PPERFINFO_VIRTUAL_ALLOC; + e.AppendParam(params.MemBaseAddress, params.Address, r.ReadUint64(0)) + e.AppendParam(params.MemRegionSize, params.Uint64, r.ReadUint64(8)) + e.AppendParam(params.ProcessID, params.PID, r.ReadUint32(16)) + e.AppendParam(params.MemAllocType, params.Flags, r.ReadUint32(20), WithFlags(MemAllocationFlags)) +} + +// DecodeNetwork decodes TCP/UDP network events. All network event +// share the same schema layout. For IPv6 events, the IP fields are +// 128 bits long. +func (d *ParamDecoder) DecodeNetwork(r *etw.EventRecord, e *Event) { + // typedef struct _WMI_TCPIP { + // ULONG Context; + // ULONG Size; + // ULONG DestAddr; + // ULONG SrcAddr; + // USHORT DestPort; + // USHORT SrcPort; + // } WMI_TCPIP, *PWMI_TCPIP; + + // typedef struct _WMI_UDP { + // ULONG PID; + // USHORT Size; + // ULONG DestAddr; + // ULONG SrcAddr; + // USHORT DestPort; + // USHORT SrcPort; + // }WMI_UDP, *PWMI_UDP; + e.AppendParam(params.ProcessID, params.PID, r.ReadUint32(0)) + e.AppendParam(params.NetSize, params.Uint32, r.ReadUint32(4)) + + switch r.Header.EventDescriptor.Opcode { + case AcceptTCPv6ID, ConnectTCPv6ID, ReconnectTCPv6ID, RetransmitTCPv6ID, + DisconnectTCPv6ID, SendV6ID, RecvV6ID: + e.AppendParam(params.NetDIP, params.IPv6, r.ReadBytes(8, 16)) + e.AppendParam(params.NetSIP, params.IPv6, r.ReadBytes(24, 16)) + e.AppendParam(params.NetDport, params.Port, r.ReadUint16(40)) + e.AppendParam(params.NetSport, params.Port, r.ReadUint16(42)) + default: + e.AppendParam(params.NetDIP, params.IPv4, r.ReadUint32(8)) + e.AppendParam(params.NetSIP, params.IPv4, r.ReadUint32(12)) + e.AppendParam(params.NetDport, params.Port, r.ReadUint16(16)) + e.AppendParam(params.NetSport, params.Port, r.ReadUint16(18)) + } +} + +// DecodeDNS decodes DNS query/reply event payloads. +func (d *ParamDecoder) DecodeDNS(r *etw.EventRecord, e *Event) { + name, offset := r.ReadUTF16String(0) + e.AppendParam(params.DNSName, params.UnicodeString, name) + e.AppendParam(params.DNSRR, params.Enum, r.ReadUint32(offset), WithEnum(DNSRecordTypes)) + e.AppendParam(params.DNSOpts, params.Flags64, r.ReadUint64(offset+4), WithFlags(DNSOptsFlags)) + + if r.Header.EventDescriptor.ID == ReplyDNSID { + e.AppendParam(params.DNSRcode, params.Enum, r.ReadUint32(offset+12), WithEnum(DNSResponseCodes)) + answers := strings.Split(sanitizeDNSAnswers(r.ConsumeUTF16String(offset+16)), ";") + e.AppendParam(params.DNSAnswers, params.Slice, answers) + } +} + +// sanitizeDNSAnswers removes the "type" string from DNS answers. +func sanitizeDNSAnswers(answers string) string { + return strings.ReplaceAll(answers, "type: 5 ", "") +} diff --git a/pkg/event/param_decoder_windows_test.go b/pkg/event/param_decoder_windows_test.go new file mode 100644 index 000000000..b9ea143e2 --- /dev/null +++ b/pkg/event/param_decoder_windows_test.go @@ -0,0 +1,971 @@ +/* + * Copyright 2020-present by Nedim Sabic Sabic + * https://www.fibratus.io + * All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package event + +import ( + "testing" + "unsafe" + + "github.com/rabbitstack/fibratus/pkg/event/params" + "github.com/rabbitstack/fibratus/pkg/sys/etw" + "github.com/rabbitstack/fibratus/pkg/util/va" + "github.com/stretchr/testify/assert" +) + +func TestDecodeRegistry(t *testing.T) { + var tests = []struct { + name string + buf []byte + assertions func(t *testing.T, e *Event) + }{ + {name: "RegSetValue", + assertions: func(t *testing.T, e *Event) { + assert.Len(t, e.Params, 3) + assert.Equal(t, "StartTime", e.Params.MustGetString(params.RegPath)) + assert.Equal(t, uint32(0), e.Params.MustGetUint32(params.NTStatus)) + assert.Equal(t, uint64(0xffffde0e05e45330), e.Params.MustGetUint64(params.RegKeyHandle)) + }, + buf: []byte{ + 116, 104, 52, 53, 29, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 48, 83, 228, 5, 14, 222, 255, 255, + 83, 0, 116, 0, 97, 0, 114, 0, 116, 0, 84, 0, 105, 0, + 109, 0, 101, 0, 0, 0}, + }, + { + name: "RegCreateKey", + assertions: func(t *testing.T, e *Event) { + assert.Len(t, e.Params, 3) + assert.Equal(t, `Software\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\Capabilities`, e.Params.MustGetString(params.RegPath)) + assert.Equal(t, uint32(0), e.Params.MustGetUint32(params.NTStatus)) + assert.Equal(t, uint64(0xffffb58b742ff990), e.Params.MustGetUint64(params.RegKeyHandle)) + }, + buf: []byte{ + 248, 104, 16, 11, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 144, 249, 47, 116, 139, 181, 255, 255, + 83, 0, 111, 0, 102, 0, 116, 0, + 119, 0, 97, 0, 114, 0, 101, 0, + 92, 0, + 77, 0, 105, 0, 99, 0, 114, 0, 111, 0, 115, 0, + 111, 0, 102, 0, 116, 0, + 92, 0, + 87, 0, 105, 0, 110, 0, 100, 0, 111, 0, 119, 0, + 115, 0, + 92, 0, + 67, 0, 117, 0, 114, 0, 114, 0, 101, 0, 110, 0, + 116, 0, 86, 0, 101, 0, 114, 0, 115, 0, 105, 0, + 111, 0, 110, 0, + 92, 0, + 67, 0, 97, 0, 112, 0, 97, 0, 98, 0, 105, 0, + 108, 0, 105, 0, 116, 0, 121, 0, + 65, 0, 99, 0, 99, 0, 101, 0, 115, 0, 115, 0, + 77, 0, 97, 0, 110, 0, 97, 0, 103, 0, 101, 0, + 114, 0, + 92, 0, + 67, 0, 97, 0, 112, 0, 97, 0, 98, 0, 105, 0, + 108, 0, 105, 0, 116, 0, 105, 0, 101, 0, 115, 0, + 0, 0, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := initEventRecord(0, 0, tt.buf) + e := &Event{Params: make(Params)} + paramDecoder.DecodeRegistry(r, e) + tt.assertions(t, e) + }) + } +} + +func TestDecodeRegSetValueInternal(t *testing.T) { + buf := []byte{ + 224, 238, 210, 196, 139, 181, 255, 255, + 0, 0, 0, 0, + 1, 0, 0, 0, + 108, 0, 0, 0, + 0, 0, + 85, 0, 82, 0, 73, 0, 0, 0, + 108, 0, + 92, 0, + 77, 0, 105, 0, 99, 0, 114, 0, 111, 0, 115, 0, + 111, 0, 102, 0, 116, 0, + 92, 0, + 87, 0, 105, 0, 110, 0, 100, 0, 111, 0, 119, 0, + 115, 0, + 92, 0, + 70, 0, 108, 0, 105, 0, 103, 0, 104, 0, 116, 0, + 105, 0, 110, 0, 103, 0, + 92, 0, + 79, 0, 110, 0, 101, 0, + 83, 0, 101, 0, 116, 0, 116, 0, 105, 0, 110, 0, + 103, 0, 115, 0, + 92, 0, + 82, 0, 101, 0, 102, 0, 114, 0, 101, 0, 115, 0, + 104, 0, + 67, 0, 97, 0, 99, 0, 104, 0, 101, 0, + 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + } + + r := initEventRecord(0, 0, buf) + e := &Event{Params: make(Params)} + paramDecoder.DecodeRegSetValueInternal(r, e) + + assert.Len(t, e.Params, 5) + assert.Equal(t, "URI", e.Params.MustGetString(params.RegPath)) + assert.Equal(t, uint32(0), e.Params.MustGetUint32(params.NTStatus)) + assert.Equal(t, `\Microsoft\Windows\Flighting\OneSettings\RefreshCache`, e.Params.MustGetString(params.RegData)) + assert.Equal(t, "REG_SZ", e.GetParamAsString(params.RegValueType)) + assert.Equal(t, uint64(0xffffb58bc4d2eee0), e.Params.MustGetUint64(params.RegKeyHandle)) +} + +func TestDecodeFile(t *testing.T) { + var tests = []struct { + name string + opcode uint8 + buf []byte + assertions func(t *testing.T, e *Event) + }{ + { + name: "CreateFile", opcode: CreateFileID, + assertions: func(t *testing.T, e *Event) { + assert.Len(t, e.Params, 7) + assert.Equal(t, uint64(0xffffd78d965e07c8), e.Params.MustGetUint64(params.FileIrpPtr)) + assert.Equal(t, uint64(0xffffd78d920b6650), e.Params.MustGetUint64(params.FileObject)) + assert.Equal(t, `\Device\HarddiskVolume3\WINDOWS\AppCompat\Programs\Amcache.hve`, e.Params.MustGetString(params.FilePath)) + assert.Equal(t, "NORMAL", e.GetParamAsString(params.FileAttributes)) + assert.Equal(t, "SEQUENTIAL_ONLY|SYNCHRONOUS_IO_NONALERT|NO_COMPRESSION", e.GetParamAsString(params.FileCreateOptions)) + assert.Equal(t, uint32(6536), e.Params.MustGetTid()) + }, + buf: []byte{ + 200, 7, 94, 150, 141, 215, 255, 255, + 80, 102, 11, 146, 141, 215, 255, 255, + 136, 25, 0, 0, + 36, 128, 0, 3, + 128, 0, 0, 0, + 0, 0, 0, 0, + + 92, 0, + 68, 0, 101, 0, 118, 0, 105, 0, 99, 0, 101, 0, + 92, 0, + 72, 0, 97, 0, 114, 0, 100, 0, 100, 0, 105, 0, + 115, 0, 107, 0, + 86, 0, 111, 0, 108, 0, 117, 0, 109, 0, 101, 0, + 51, 0, + 92, 0, + 87, 0, 73, 0, 78, 0, 68, 0, 79, 0, 87, 0, + 83, 0, + 92, 0, + 65, 0, 112, 0, 112, 0, + 67, 0, 111, 0, 109, 0, 112, 0, 97, 0, 116, 0, + 92, 0, + 80, 0, 114, 0, 111, 0, 103, 0, 114, 0, 97, 0, + 109, 0, 115, 0, + 92, 0, + 65, 0, 109, 0, 99, 0, 97, 0, 99, 0, 104, 0, + 101, 0, 46, 0, 104, 0, 118, 0, 101, 0, + 0, 0, + }, + }, + { + name: "FileOpEnd", opcode: FileOpEndID, + assertions: func(t *testing.T, e *Event) { + assert.Len(t, e.Params, 3) + assert.Equal(t, uint64(0xffffd78d973df0f8), e.Params.MustGetUint64(params.FileIrpPtr)) + assert.Equal(t, uint32(0), e.Params.MustGetUint32(params.NTStatus)) + assert.Equal(t, uint64(0x28), e.Params.MustGetUint64(params.FileExtraInfo)) + }, + buf: []byte{ + 248, 240, 61, 151, 141, 215, 255, 255, + 40, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + }, + }, + { + name: "MapViewFile", opcode: MapViewFileID, + assertions: func(t *testing.T, e *Event) { + assert.Len(t, e.Params, 7) + assert.Equal(t, uint64(0xffffb58b75fb7e10), e.Params.MustGetUint64(params.FileKey)) + assert.Equal(t, uint64(0), e.Params.MustGetUint64(params.FileOffset)) + assert.Equal(t, uint32(1716), e.Params.MustGetUint32(params.ProcessID)) + assert.Equal(t, "READONLY", e.GetParamAsString(params.MemProtect)) + assert.Equal(t, "PAGEFILE", e.GetParamAsString(params.FileViewSectionType)) + assert.Equal(t, uint64(0x191ab210000), e.Params.MustGetUint64(params.FileViewBase)) + assert.Equal(t, uint64(4096), e.Params.MustGetUint64(params.FileViewSize)) + }, + buf: []byte{ + 0, 0, 33, 171, 145, 1, 0, 0, + 16, 126, 251, 117, 139, 181, 255, 255, + 0, 0, 0, 0, 0, 0, 193, 0, + 0, 16, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 180, 6, 0, 0, + }, + }, + { + name: "UnmapViewFile", opcode: UnmapViewFileID, + assertions: func(t *testing.T, e *Event) { + assert.Len(t, e.Params, 7) + assert.Equal(t, uint64(0xffffb58bc1f91010), e.Params.MustGetUint64(params.FileKey)) + assert.Equal(t, uint64(0), e.Params.MustGetUint64(params.FileOffset)) + assert.Equal(t, uint32(12448), e.Params.MustGetUint32(params.ProcessID)) + assert.Equal(t, "READWRITE", e.GetParamAsString(params.MemProtect)) + assert.Equal(t, "PAGEFILE", e.GetParamAsString(params.FileViewSectionType)) + assert.Equal(t, uint64(0x1675e410000), e.Params.MustGetUint64(params.FileViewBase)) + assert.Equal(t, uint64(921600), e.Params.MustGetUint64(params.FileViewSize)) + }, + buf: []byte{ + 0, 0, 65, 94, 103, 1, 0, 0, + 16, 16, 249, 193, 139, 181, 255, 255, + 0, 0, 0, 0, 0, 0, 196, 0, + 0, 16, 14, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 160, 48, 0, 0, + }, + }, + { + name: "SetFileInformation", opcode: SetFileInformationID, + assertions: func(t *testing.T, e *Event) { + assert.Len(t, e.Params, 6) + assert.Equal(t, "Allocation", e.GetParamAsString(params.FileInfoClass)) + assert.Equal(t, uint64(524288), e.Params.MustGetUint64(params.FileExtraInfo)) + assert.Equal(t, uint64(0xffffb58b80ccc180), e.Params.MustGetUint64(params.FileKey)) + assert.Equal(t, uint64(0xffffd78d76403780), e.Params.MustGetUint64(params.FileObject)) + assert.Equal(t, uint64(0xffffd78d9b6470f8), e.Params.MustGetUint64(params.FileIrpPtr)) + assert.Equal(t, uint32(16404), e.Params.MustGetTid()) + }, + buf: []byte{ + 248, 112, 100, 155, 141, 215, 255, 255, + 128, 55, 64, 118, 141, 215, 255, 255, + 128, 193, 204, 128, 139, 181, 255, 255, + 0, 0, 8, 0, 0, 0, 0, 0, + 20, 64, 0, 0, + 19, 0, 0, 0, + }, + }, + { + name: "DeleteFile", opcode: DeleteFileID, + assertions: func(t *testing.T, e *Event) { + assert.Len(t, e.Params, 6) + assert.Equal(t, "Disposition Extended", e.GetParamAsString(params.FileInfoClass)) + assert.Equal(t, uint64(1), e.Params.MustGetUint64(params.FileExtraInfo)) + assert.Equal(t, uint64(0xffffb58bc5e64180), e.Params.MustGetUint64(params.FileKey)) + assert.Equal(t, uint64(0xffffd78d9b6c7d80), e.Params.MustGetUint64(params.FileObject)) + assert.Equal(t, uint64(0xffffd78d7c5860f8), e.Params.MustGetUint64(params.FileIrpPtr)) + assert.Equal(t, uint32(13656), e.Params.MustGetTid()) + }, + buf: []byte{ + 248, 96, 88, 124, 141, 215, 255, 255, + 128, 125, 108, 155, 141, 215, 255, 255, + 128, 65, 230, 197, 139, 181, 255, 255, + 1, 0, 0, 0, 0, 0, 0, 0, + 88, 53, 0, 0, + 64, 0, 0, 0, + }, + }, + { + name: "ReleaseFile", opcode: ReleaseFileID, + assertions: func(t *testing.T, e *Event) { + assert.Len(t, e.Params, 4) + assert.Equal(t, uint64(0xffffb58b9268d180), e.Params.MustGetUint64(params.FileKey)) + assert.Equal(t, uint64(0xffffd78d9b4552b0), e.Params.MustGetUint64(params.FileObject)) + assert.Equal(t, uint64(0xffffd78d7ca0b0f8), e.Params.MustGetUint64(params.FileIrpPtr)) + assert.Equal(t, uint32(3096), e.Params.MustGetTid()) + }, + buf: []byte{ + 248, 176, 160, 124, 141, 215, 255, 255, + 176, 82, 69, 155, 141, 215, 255, 255, + 128, 209, 104, 146, 139, 181, 255, 255, + 24, 12, 0, 0, + }, + }, + { + name: "WriteFile", opcode: WriteFileID, + assertions: func(t *testing.T, e *Event) { + assert.Len(t, e.Params, 6) + assert.Equal(t, uint64(0xffffb58b74e78b10), e.Params.MustGetUint64(params.FileKey)) + assert.Equal(t, uint64(0xffffd78d6970ae80), e.Params.MustGetUint64(params.FileObject)) + assert.Equal(t, uint64(0xffffd78d9a786a08), e.Params.MustGetUint64(params.FileIrpPtr)) + assert.Equal(t, uint32(392), e.Params.MustGetTid()) + assert.Equal(t, uint64(573440), e.Params.MustGetUint64(params.FileOffset)) + assert.Equal(t, uint32(1073741824), e.Params.MustGetUint32(params.FileIoSize)) + }, + buf: []byte{ + 0, 192, 8, 0, 0, 0, 0, 0, + 8, 106, 120, 154, 141, 215, 255, 255, + 128, 174, 112, 105, 141, 215, 255, 255, + 16, 139, 231, 116, 139, 181, 255, 255, + 136, 1, 0, 0, + 0, 64, 1, 0, + 1, 10, 6, 0, + 0, 0, 0, 0, + }, + }, + {name: "EnumDirectory", opcode: EnumDirectoryID, + assertions: func(t *testing.T, e *Event) { + assert.Len(t, e.Params, 6) + assert.Equal(t, uint64(0xffffde0dfb917590), e.Params.MustGetUint64(params.FileKey)) + assert.Equal(t, uint64(0xffff8084cb43c990), e.Params.MustGetUint64(params.FileObject)) + assert.Equal(t, `git"*`, e.Params.MustGetString(params.FilePath)) + assert.Equal(t, uint64(0xffff8084da3e7788), e.Params.MustGetUint64(params.FileIrpPtr)) + assert.Equal(t, uint32(12860), e.Params.MustGetTid()) + }, + buf: []byte{ + 136, 119, 62, 218, 132, 128, 255, 255, + 144, 201, 67, 203, 132, 128, 255, 255, + 144, 117, 145, 251, 13, 222, 255, 255, + 60, 50, 0, 0, 116, 2, 0, 0, + 79, 0, 0, 0, 0, 0, 0, 0, + 103, 0, 105, 0, 116, 0, 34, 0, 42, 0, 0, 0, + }, + }, + { + name: "FileRundown", opcode: FileRundownID, + assertions: func(t *testing.T, e *Event) { + assert.Len(t, e.Params, 2) + assert.Equal(t, `\Device\HarddiskVolume3\Windows\System32\CatRoot\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}\Microsoft-Windows-TerminalServices-AppServerClient-Opt-WOW64-Package~31bf3856ad364e35~wow64~~10.0.26100.8115.cat`, e.Params.MustGetString(params.FilePath)) + }, + buf: []byte{ + 80, 71, 18, 158, 139, 181, 255, 255, + 92, 0, 68, 0, 101, 0, 118, 0, + 105, 0, 99, 0, 101, 0, 92, 0, + 72, 0, 97, 0, 114, 0, 100, 0, + 100, 0, 105, 0, 115, 0, 107, 0, + 86, 0, 111, 0, 108, 0, 117, 0, + 109, 0, 101, 0, 51, 0, 92, 0, + 87, 0, 105, 0, 110, 0, 100, 0, + 111, 0, 119, 0, 115, 0, 92, 0, + 83, 0, 121, 0, 115, 0, 116, 0, + 101, 0, 109, 0, 51, 0, 50, 0, + 92, 0, 67, 0, 97, 0, 116, 0, + 82, 0, 111, 0, 111, 0, 116, 0, + 92, 0, + 123, 0, 70, 0, 55, 0, 53, 0, 48, 0, + 69, 0, 54, 0, 67, 0, 51, 0, 45, 0, + 51, 0, 56, 0, 69, 0, 69, 0, 45, 0, + 49, 0, 49, 0, 68, 0, 49, 0, 45, 0, + 56, 0, 53, 0, 69, 0, 53, 0, 45, 0, + 48, 0, 48, 0, 67, 0, 48, 0, 52, 0, + 70, 0, 67, 0, 50, 0, 57, 0, 53, 0, + 69, 0, 69, 0, 125, 0, + 92, 0, + 77, 0, 105, 0, 99, 0, 114, 0, 111, 0, + 115, 0, 111, 0, 102, 0, 116, 0, 45, 0, + 87, 0, 105, 0, 110, 0, 100, 0, 111, 0, + 119, 0, 115, 0, 45, 0, + 84, 0, 101, 0, 114, 0, 109, 0, 105, 0, + 110, 0, 97, 0, 108, 0, + 83, 0, 101, 0, 114, 0, 118, 0, 105, 0, + 99, 0, 101, 0, 115, 0, 45, 0, + 65, 0, 112, 0, 112, 0, 83, 0, 101, 0, + 114, 0, 118, 0, 101, 0, 114, 0, + 67, 0, 108, 0, 105, 0, 101, 0, 110, 0, + 116, 0, 45, 0, + 79, 0, 112, 0, 116, 0, 45, 0, + 87, 0, 79, 0, 87, 0, 54, 0, 52, 0, + 45, 0, + 80, 0, 97, 0, 99, 0, 107, 0, 97, 0, + 103, 0, 101, 0, + 126, 0, 51, 0, 49, 0, 98, 0, 102, 0, + 51, 0, 56, 0, 53, 0, 54, 0, 97, 0, + 100, 0, 51, 0, 54, 0, 52, 0, 101, 0, + 51, 0, 53, 0, 126, 0, + 119, 0, 111, 0, 119, 0, 54, 0, 52, 0, + 126, 0, 126, 0, + 49, 0, 48, 0, 46, 0, 48, 0, 46, 0, + 50, 0, 54, 0, 49, 0, 48, 0, 48, 0, + 46, 0, 56, 0, 49, 0, 49, 0, 53, 0, + 46, 0, + 99, 0, 97, 0, 116, 0, + 0, 0, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := initEventRecord(tt.opcode, 0, tt.buf) + e := &Event{Params: make(Params)} + paramDecoder.DecodeFile(r, e) + tt.assertions(t, e) + }) + } +} + +func TestDecodeProcess(t *testing.T) { + buf := []byte{ + 192, 48, 161, 124, 141, 215, 255, 255, + 124, 78, 0, 0, + 128, 52, 0, 0, + 1, 0, 0, 0, + 3, 1, 0, 0, + 0, 96, 231, 68, 3, 0, 0, 0, + 0, 0, 0, 0, + 160, 162, 152, 216, 139, 181, 255, 255, + 0, 0, 0, 0, 0, 0, 0, 0, + + 1, 5, 0, 0, 0, 0, 0, 5, + 21, 0, 0, 0, + 226, 73, 191, 35, 149, 112, 61, 68, + 44, 66, 142, 178, 234, 3, 0, 0, + + 99, 111, 110, 104, 111, 115, 116, 46, 101, 120, 101, 0, + + 92, 0, 63, 0, 63, 0, 92, 0, + 67, 0, 58, 0, 92, 0, 87, 0, 73, 0, 78, 0, 68, 0, 79, 0, 87, 0, 83, 0, + 92, 0, 115, 0, 121, 0, 115, 0, 116, 0, 101, 0, 109, 0, 51, 0, 50, 0, + 92, 0, 99, 0, 111, 0, 110, 0, 104, 0, 111, 0, 115, 0, 116, 0, 46, 0, + 101, 0, 120, 0, 101, 0, + + 32, 0, 48, 0, 120, 0, 102, 0, 102, 0, 102, 0, 102, 0, 102, 0, 102, 0, 102, 0, + 32, 0, 45, 0, 70, 0, 111, 0, 114, 0, 99, 0, 101, 0, 86, 0, 49, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + } + + r := initEventRecord(0, 0, buf) + e := &Event{Params: make(Params)} + paramDecoder.DecodeProcess(r, e) + + assert.Len(t, e.Params, 11) + assert.Equal(t, `\??\C:\WINDOWS\system32\conhost.exe 0xfffffff -ForceV1`, e.Params.MustGetString(params.Cmdline)) + assert.Equal(t, uint64(0x344e76000), e.Params.MustGetUint64(params.DTB)) + assert.Equal(t, uint32(0x103), e.Params.MustGetUint32(params.ExitStatus)) + assert.Equal(t, uint64(0xffffd78d7ca130c0), e.Params.MustGetUint64(params.ProcessObject)) + assert.Equal(t, "conhost.exe", e.Params.MustGetString(params.ProcessName)) + assert.Equal(t, uint32(20092), e.Params.MustGetPid()) + assert.Equal(t, uint32(13440), e.Params.MustGetPpid()) + assert.Equal(t, uint32(13440), e.Params.MustGetUint32(params.ProcessRealParentID)) + assert.Equal(t, uint32(1), e.Params.MustGetUint32(params.SessionID)) + assert.Equal(t, "S-1-5-21-599738850-1144877205-2995667500-1002", e.GetParamAsString(params.UserSID)) +} + +func TestDecodeProcessInternal(t *testing.T) { + buf := []byte{ + 88, 77, 0, 0, + 13, 195, 0, 0, + 0, 0, 0, 0, + + 102, 161, 153, 7, 34, 222, 220, 1, + + 172, 26, 0, 0, + 11, 195, 0, 0, + 0, 0, 0, 0, + + 1, 0, 0, 0, + 0, 0, 0, 0, + 2, 0, 0, 0, + 1, 0, 0, 0, + 1, 1, 0, 0, + + 0, 0, 0, 16, + 0, 48, 0, 0, + + 92, 0, + 68, 0, 101, 0, 118, 0, 105, 0, 99, 0, 101, 0, + 92, 0, + 72, 0, 97, 0, 114, 0, 100, 0, 100, 0, 105, 0, + 115, 0, 107, 0, + 86, 0, 111, 0, 108, 0, 117, 0, 109, 0, 101, 0, + 51, 0, + 92, 0, + 80, 0, 114, 0, 111, 0, 103, 0, 114, 0, 97, 0, + 109, 0, + 32, 0, + 70, 0, 105, 0, 108, 0, 101, 0, 115, 0, + 92, 0, + 71, 0, 105, 0, 116, 0, + 92, 0, + 109, 0, 105, 0, 110, 0, 103, 0, 119, 0, 54, 0, + 52, 0, + 92, 0, + 98, 0, 105, 0, 110, 0, + 92, 0, + 103, 0, 105, 0, 116, 0, 46, 0, 101, 0, 120, 0, + 101, 0, + 0, 0, + + 95, 10, 66, 0, + 139, 104, 27, 105, + + 0, 0, 0, 0, 0, 0, 0, 0, + } + + r := initEventRecord(0, 0, buf) + e := &Event{Params: make(Params)} + paramDecoder.DecodeProcessInternal(r, e) + + assert.Len(t, e.Params, 10) + assert.Equal(t, `\Device\HarddiskVolume3\Program Files\Git\mingw64\bin\git.exe`, e.Params.MustGetString(params.Exe)) + assert.Equal(t, uint64(0xc30d), e.Params.MustGetUint64(params.ProcessObject)) + assert.Equal(t, uint32(19800), e.Params.MustGetPid()) + assert.Equal(t, uint32(6828), e.Params.MustGetPpid()) + assert.Equal(t, uint32(1), e.Params.MustGetUint32(params.SessionID)) + assert.Equal(t, "FULL", e.GetParamAsString(params.ProcessTokenElevationType)) + assert.Equal(t, "HIGH", e.GetParamAsString(params.ProcessTokenIntegrityLevel)) + assert.True(t, e.Params.MustGetBool(params.ProcessTokenIsElevated)) +} + +func TestDecodeModule(t *testing.T) { + buf := []byte{ + 0, 0, 32, 9, 253, 127, 0, 0, + 0, 128, 0, 0, 0, 0, 0, 0, + 168, 21, 0, 0, + 93, 190, 0, 0, + 32, 96, 25, 187, 12, 7, 0, 0, + + 0, 0, 32, 9, 253, 127, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + + 92, 0, + 68, 0, 101, 0, 118, 0, 105, 0, 99, 0, 101, 0, + 92, 0, + 72, 0, 97, 0, 114, 0, 100, 0, 100, 0, 105, 0, + 115, 0, 107, 0, + 86, 0, 111, 0, 108, 0, 117, 0, 109, 0, 101, 0, + 51, 0, + 92, 0, + 87, 0, 105, 0, 110, 0, 100, 0, 111, 0, 119, 0, + 115, 0, + 92, 0, + 83, 0, 121, 0, 115, 0, 116, 0, 101, 0, 109, 0, + 51, 0, 50, 0, + 92, 0, + 110, 0, 111, 0, 114, 0, 109, 0, 97, 0, 108, 0, + 105, 0, 122, 0, 46, 0, + 100, 0, 108, 0, 108, 0, + 0, 0, + } + + r := initEventRecord(0, 0, buf) + e := &Event{Params: make(Params)} + paramDecoder.DecodeModule(r, e) + + assert.Len(t, e.Params, 8) + assert.Equal(t, uint64(0x7ffd09200000), e.Params.MustGetUint64(params.ModuleBase)) + assert.Equal(t, uint32(48733), e.Params.MustGetUint32(params.ModuleCheckSum)) + assert.Equal(t, uint64(0x7ffd09200000), e.Params.MustGetUint64(params.ModuleDefaultBase)) + assert.Equal(t, `\Device\HarddiskVolume3\Windows\System32\normaliz.dll`, e.Params.MustGetString(params.ModulePath)) + assert.Equal(t, uint64(32768), e.Params.MustGetUint64(params.ModuleSize)) + assert.Equal(t, uint32(5544), e.Params.MustGetPid()) + assert.Equal(t, "WINDOWS", e.GetParamAsString(params.ModuleSignatureLevel)) + assert.Equal(t, "FILE_VERIFIED", e.GetParamAsString(params.ModuleSignatureType)) +} + +func TestDecodeModuleInternal(t *testing.T) { + buf := []byte{ + 0, 0, 150, 252, 252, 127, 0, 0, + 0, 96, 8, 0, 0, 0, 0, 0, + 96, 68, 0, 0, + 231, 125, 8, 0, + 42, 234, 60, 109, 0, 0, + + 150, 252, 252, 127, 0, 0, + + 92, 0, + 68, 0, 101, 0, 118, 0, 105, 0, 99, 0, 101, 0, + 92, 0, + 72, 0, 97, 0, 114, 0, 100, 0, 100, 0, 105, 0, + 115, 0, 107, 0, + 86, 0, 111, 0, 108, 0, 117, 0, 109, 0, 101, 0, + 51, 0, + 92, 0, + 87, 0, 105, 0, 110, 0, 100, 0, 111, 0, 119, 0, + 115, 0, + 92, 0, + 83, 0, 121, 0, 115, 0, 116, 0, 101, 0, 109, 0, + 51, 0, 50, 0, + 92, 0, + 70, 0, 87, 0, 80, 0, 85, 0, 67, 0, 76, 0, + 78, 0, 84, 0, 46, 0, + 68, 0, 76, 0, 76, 0, + 0, 0, + } + + r := initEventRecord(0, 0, buf) + e := &Event{Params: make(Params)} + paramDecoder.DecodeModuleInternal(r, e) + + assert.Len(t, e.Params, 6) + assert.Equal(t, uint64(0x7ffcfc960000), e.Params.MustGetUint64(params.ModuleBase)) + assert.Equal(t, uint32(556519), e.Params.MustGetUint32(params.ModuleCheckSum)) + assert.Equal(t, uint64(0x7ffcfc960000), e.Params.MustGetUint64(params.ModuleDefaultBase)) + assert.Equal(t, `\Device\HarddiskVolume3\Windows\System32\FWPUCLNT.DLL`, e.Params.MustGetString(params.ModulePath)) + assert.Equal(t, uint64(548864), e.Params.MustGetUint64(params.ModuleSize)) + assert.Equal(t, uint32(17504), e.Params.MustGetPid()) +} + +func TestDecodeOpenProcess(t *testing.T) { + buf := []byte{ + 112, 22, 0, 0, + 0, 16, 0, 0, + 0, 0, 0, 0, + } + + r := initEventRecord(0, 0, buf) + e := &Event{Params: make(Params)} + paramDecoder.DecodeOpenProcess(r, e) + + assert.Len(t, e.Params, 4) + assert.Equal(t, "QUERY_LIMITED_INFORMATION", e.GetParamAsString(params.DesiredAccess)) + assert.Equal(t, uint32(5744), e.Params.MustGetPid()) + assert.Equal(t, uint32(0), e.Params.MustGetUint32(params.NTStatus)) +} + +func TestDecodeThread(t *testing.T) { + buf := []byte{ + 8, 20, 0, 0, + 228, 6, 0, 0, + 0, 128, + 128, 12, 10, 252, 255, 255, + 0, 16, + 128, 12, 10, 252, 255, 255, + 0, 0, + 16, 206, 88, 0, 0, 0, 0, 128, + 15, 206, 88, 0, 0, 0, 255, 255, + 0, 0, 0, 0, + 128, 90, 99, 9, 253, 127, 0, 0, + 0, 240, 233, 205, 88, 0, 0, 0, + 0, 0, 0, 0, + 8, 5, 2, 0, + 0, 0, + } + + r := initEventRecord(0, 0, buf) + e := &Event{Params: make(Params)} + paramDecoder.DecodeThread(r, e) + + assert.Len(t, e.Params, 11) + assert.Equal(t, uint8(2), e.Params.MustGetUint8(params.BasePrio)) + assert.Equal(t, uint8(0), e.Params.MustGetUint8(params.IOPrio)) + assert.Equal(t, uint8(0), e.Params.MustGetUint8(params.PagePrio)) + assert.Equal(t, uint64(0xfffffc0a0c808000), e.Params.MustGetUint64(params.KstackBase)) + assert.Equal(t, uint64(0xfffffc0a0c801000), e.Params.MustGetUint64(params.KstackLimit)) + assert.Equal(t, uint32(5128), e.Params.MustGetPid()) + assert.Equal(t, uint32(1764), e.Params.MustGetTid()) + assert.Equal(t, uint64(0xf00000007ffd0963), e.Params.MustGetUint64(params.StartAddress)) + assert.Equal(t, uint64(0x58cde9), e.Params.MustGetUint64(params.TEB)) + assert.Equal(t, uint64(0x58ce100000), e.Params.MustGetUint64(params.UstackBase)) + assert.Equal(t, uint64(0x58ce0f8000), e.Params.MustGetUint64(params.UstackLimit)) +} + +func TestDecodeOpenThread(t *testing.T) { + buf := []byte{ + 104, 17, 0, 0, + 76, 47, 0, 0, + 255, 255, 31, 0, + 0, 0, 0, 0, + } + + r := initEventRecord(0, 0, buf) + e := &Event{Params: make(Params)} + paramDecoder.DecodeOpenThread(r, e) + + assert.Len(t, e.Params, 5) + assert.Equal(t, "ALL_ACCESS", e.GetParamAsString(params.DesiredAccess)) + assert.Equal(t, uint32(4456), e.Params.MustGetPid()) + assert.Equal(t, uint32(12108), e.Params.MustGetTid()) + assert.Equal(t, uint32(0), e.Params.MustGetUint32(params.NTStatus)) +} + +func TestDecodeSetThreadContext(t *testing.T) { + buf := []byte{ + 0, 0, 0, 0, + } + r := initEventRecord(0, 0, buf) + e := &Event{Params: make(Params)} + paramDecoder.DecodeSetThreadContext(r, e) + + assert.Len(t, e.Params, 2) + assert.Equal(t, uint32(0), e.Params.MustGetUint32(params.NTStatus)) +} + +func TestDecodeCreateSymbolicLinkObject(t *testing.T) { + buf := []byte{ + 83, 0, 101, 0, 115, 0, 115, 0, + 105, 0, 111, 0, 110, 0, 0, 0, + + 92, 0, 83, 0, 101, 0, 115, 0, + 115, 0, 105, 0, 111, 0, 110, 0, + 115, 0, 92, 0, + 49, 0, + 92, 0, + 65, 0, 112, 0, 112, 0, + 67, 0, 111, 0, 110, 0, 116, 0, + 97, 0, 105, 0, 110, 0, 101, 0, + 114, 0, + 78, 0, 97, 0, 109, 0, 101, 0, + 100, 0, + 79, 0, 98, 0, 106, 0, 101, 0, + 99, 0, 116, 0, 115, 0, + 92, 0, + + 83, 0, 45, 0, + 49, 0, 45, 0, + 49, 0, 53, 0, 45, 0, + 50, 0, 45, 0, + 49, 0, 54, 0, 48, 0, 57, 0, + 52, 0, 55, 0, 51, 0, 55, 0, + 57, 0, 56, 0, 45, 0, + 49, 0, 50, 0, 51, 0, 49, 0, + 57, 0, 50, 0, 51, 0, 48, 0, + 49, 0, 55, 0, 45, 0, + 54, 0, 56, 0, 52, 0, 50, 0, + 54, 0, 56, 0, 49, 0, 53, 0, + 51, 0, 45, 0, + 52, 0, 50, 0, 54, 0, 56, 0, + 53, 0, 49, 0, 52, 0, 51, 0, + 50, 0, 56, 0, 45, 0, + 56, 0, 56, 0, 50, 0, 55, 0, + 55, 0, 51, 0, 54, 0, 52, 0, + 54, 0, 45, 0, + 50, 0, 55, 0, 54, 0, 48, 0, + 53, 0, 56, 0, 53, 0, 55, 0, + 55, 0, 51, 0, 45, 0, + 49, 0, 55, 0, 54, 0, 48, 0, + 57, 0, 51, 0, 56, 0, 49, 0, + 53, 0, 55, 0, + 0, 0, + + 1, 0, + 15, 0, + 0, 0, 0, 0, + } + + r := initEventRecord(0, 0, buf) + e := &Event{Params: make(Params)} + paramDecoder.DecodeCreateSymbolicLinkObject(r, e) + + assert.Len(t, e.Params, 5) + assert.Equal(t, "DELETE|READ_CONTROL|WRITE_DAC|WRITE_OWNER", e.GetParamAsString(params.DesiredAccess)) + assert.Equal(t, "Session", e.GetParamAsString(params.LinkSource)) + assert.Equal(t, `\Sessions\1\AppContainerNamedObjects\S-1-15-2-1609473798-1231923017-684268153-4268514328-882773646-2760585773-1760938157`, e.GetParamAsString(params.LinkTarget)) + assert.Equal(t, uint32(0), e.Params.MustGetUint32(params.NTStatus)) +} + +func TestDecodeStackWalk(t *testing.T) { + buf := []byte{ + 41, 41, 119, 69, 58, 0, 0, 0, + 12, 15, 0, 0, + 160, 29, 0, 0, + + 148, 12, 254, 189, 5, 248, 255, 255, + 175, 137, 229, 189, 5, 248, 255, 255, + 134, 47, 242, 189, 5, 248, 255, 255, + 36, 109, 255, 80, 5, 248, 255, 255, + 175, 186, 130, 79, 5, 248, 255, 255, + 160, 177, 130, 79, 5, 248, 255, 255, + 224, 104, 137, 79, 5, 248, 255, 255, + 59, 149, 250, 189, 5, 248, 255, 255, + 179, 148, 250, 189, 5, 248, 255, 255, + 59, 168, 73, 190, 5, 248, 255, 255, + 218, 136, 73, 190, 5, 248, 255, 255, + 227, 101, 73, 190, 5, 248, 255, 255, + 196, 202, 73, 190, 5, 248, 255, 255, + 85, 217, 43, 190, 5, 248, 255, 255, + + 20, 69, 114, 9, 253, 127, 0, 0, + 31, 51, 25, 6, 253, 127, 0, 0, + 105, 96, 138, 36, 246, 127, 0, 0, + 109, 37, 146, 36, 246, 127, 0, 0, + 227, 37, 146, 36, 246, 127, 0, 0, + } + + r := initEventRecord(0, 0, buf) + e := &Event{Params: make(Params)} + paramDecoder.DecodeStackwalk(r, e) + + assert.Len(t, e.Params, 3) + assert.Equal(t, uint32(3852), e.Params.MustGetPid()) + assert.Equal(t, uint32(7584), e.Params.MustGetTid()) + assert.Equal(t, []va.Address{0xfffff805bdfe0c94, 0xfffff805bde589af, 0xfffff805bdf22f86, 0xfffff80550ff6d24, 0xfffff8054f82baaf, 0xfffff8054f82b1a0, 0xfffff8054f8968e0, 0xfffff805bdfa953b, 0xfffff805bdfa94b3, 0xfffff805be49a83b, 0xfffff805be4988da, 0xfffff805be4965e3, 0xfffff805be49cac4, 0xfffff805be2bd955, 0x7ffd09724514, 0x7ffd0619331f, 0x7ff6248a6069, 0x7ff62492256d, 0x7ff6249225e3}, e.Params.MustGetSlice(params.Callstack)) +} + +func TestDecodeMemory(t *testing.T) { + buf := []byte{ + 0, 176, 27, 242, 110, 2, 0, 0, + 0, 16, 0, 0, 0, 0, 0, 0, + 112, 13, 0, 0, + 0, 16, 0, 0, + } + + r := initEventRecord(0, 0, buf) + e := &Event{Params: make(Params)} + paramDecoder.DecodeMemory(r, e) + + assert.Len(t, e.Params, 4) + assert.Equal(t, uint32(3440), e.Params.MustGetPid()) + assert.Equal(t, uint64(4096), e.Params.MustGetUint64(params.MemRegionSize)) + assert.Equal(t, uint64(0x26ef21bb000), e.Params.MustGetUint64(params.MemBaseAddress)) + assert.Equal(t, "COMMIT", e.GetParamAsString(params.MemAllocType)) +} + +func TestDecodeNetwork(t *testing.T) { + var tests = []struct { + name string + opcode uint8 + buf []byte + assertions func(t *testing.T, e *Event) + }{ + { + name: "SendTCPv4", opcode: SendV4ID, + assertions: func(t *testing.T, e *Event) { + assert.Len(t, e.Params, 6) + assert.Equal(t, "172.64.148.235", e.GetParamAsString(params.NetDIP)) + assert.Equal(t, uint16(443), e.Params.MustGetUint16(params.NetDport)) + assert.Equal(t, "192.168.1.44", e.GetParamAsString(params.NetSIP)) + assert.Equal(t, uint16(61552), e.Params.MustGetUint16(params.NetSport)) + assert.Equal(t, uint32(12448), e.Params.MustGetPid()) + assert.Equal(t, uint32(28), e.Params.MustGetUint32(params.NetSize)) + }, + buf: []byte{ + 160, 48, 0, 0, + 28, 0, 0, 0, + 172, 64, 148, 235, + 192, 168, 1, 44, + 1, 187, 240, 112, + 106, 198, 40, 0, + 107, 198, 40, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + }, + }, + { + name: "ConnectTCPv4", opcode: ConnectTCPv4ID, + assertions: func(t *testing.T, e *Event) { + assert.Len(t, e.Params, 6) + assert.Equal(t, "151.101.193.91", e.GetParamAsString(params.NetDIP)) + assert.Equal(t, uint16(443), e.Params.MustGetUint16(params.NetDport)) + assert.Equal(t, "192.168.1.44", e.GetParamAsString(params.NetSIP)) + assert.Equal(t, uint16(61931), e.Params.MustGetUint16(params.NetSport)) + assert.Equal(t, uint32(12448), e.Params.MustGetPid()) + assert.Equal(t, uint32(0), e.Params.MustGetUint32(params.NetSize)) + }, + buf: []byte{ + 160, 48, 0, 0, + 0, 0, 0, 0, + 151, 101, 193, 91, + 192, 168, 1, 44, + 1, 187, 241, 235, + 0, 0, 1, 0, + 255, 255, 0, 0, + 8, 0, 9, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + }, + }, + { + name: "RecvUDPv6", opcode: RecvV6ID, + assertions: func(t *testing.T, e *Event) { + assert.Len(t, e.Params, 6) + assert.Equal(t, "ff02::c", e.GetParamAsString(params.NetDIP)) + assert.Equal(t, uint16(1900), e.Params.MustGetUint16(params.NetDport)) + assert.Equal(t, "fe80::1", e.GetParamAsString(params.NetSIP)) + assert.Equal(t, uint16(56797), e.Params.MustGetUint16(params.NetSport)) + assert.Equal(t, uint32(5128), e.Params.MustGetPid()) + assert.Equal(t, uint32(127), e.Params.MustGetUint32(params.NetSize)) + }, + buf: []byte{ + 8, 20, 0, 0, + 127, 0, 0, 0, + 255, 2, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 12, + 254, 128, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 1, 7, 108, + 221, 221, 0, 0, 0, 0, + 0, 0, 0, 0, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := initEventRecord(tt.opcode, 0, tt.buf) + e := &Event{Params: make(Params)} + paramDecoder.DecodeNetwork(r, e) + tt.assertions(t, e) + }) + } +} + +func TestDecodeDNS(t *testing.T) { + buf := []byte{ + 105, 0, 109, 0, 103, 0, 45, 0, + 112, 0, 114, 0, 111, 0, 100, 0, + 46, 0, + 112, 0, 111, 0, 99, 0, 107, 0, + 101, 0, 116, 0, 46, 0, + 112, 0, 114, 0, 111, 0, 100, 0, + 46, 0, + 99, 0, 108, 0, 111, 0, 117, 0, + 100, 0, 111, 0, 112, 0, 115, 0, + 46, 0, + 109, 0, 111, 0, 122, 0, 103, 0, + 99, 0, 112, 0, 46, 0, + 110, 0, 101, 0, 116, 0, + 0, 0, + + 28, 0, 0, 0, + 193, 8, 16, 0, + 0, 128, 0, 0, + 0, 0, 0, 0, + + 50, 0, 54, 0, 48, 0, 48, 0, + 58, 0, 49, 0, 57, 0, 48, 0, + 49, 0, 58, 0, 48, 0, + 58, 0, 101, 0, 57, 0, 56, 0, + 56, 0, 58, 0, 58, 0, + 59, 0, + 0, 0, + } + + r := initEventRecord(0, ReplyDNSID, buf) + e := &Event{Params: make(Params)} + paramDecoder.DecodeDNS(r, e) + + assert.Len(t, e.Params, 5) + assert.Equal(t, []string{"2600:1901:0:e988::", ""}, e.Params.MustGetSlice(params.DNSAnswers)) + assert.Equal(t, "img-prod.pocket.prod.cloudops.mozgcp.net", e.Params.MustGetString(params.DNSName)) + assert.Equal(t, "ACCEPT_TRUNCATED_RESPONSE|NO_NETBT|NO_MULTICAST|DONT_RESET_TTL_VALUES", e.GetParamAsString(params.DNSOpts)) + assert.Equal(t, "NOERROR", e.GetParamAsString(params.DNSRcode)) + assert.Equal(t, "AAAA", e.GetParamAsString(params.DNSRR)) +} + +func initEventRecord(opcode uint8, id uint16, buf []byte) *etw.EventRecord { + return &etw.EventRecord{ + Header: etw.EventHeader{ + ProcessID: 13440, + EventDescriptor: etw.EventDescriptor{ + Opcode: opcode, + ID: id, + }, + }, + BufferLen: uint16(len(buf)), + Buffer: uintptr(unsafe.Pointer(&buf[0])), + } +} diff --git a/pkg/event/param_windows.go b/pkg/event/param_windows.go index 322f7be9e..b5f437f1e 100644 --- a/pkg/event/param_windows.go +++ b/pkg/event/param_windows.go @@ -19,31 +19,24 @@ package event import ( - "encoding/binary" "expvar" "fmt" "net" - "path/filepath" "strconv" "strings" "time" "unsafe" - "github.com/rabbitstack/fibratus/pkg/util/utf16" - "github.com/rabbitstack/fibratus/pkg/event/params" "github.com/rabbitstack/fibratus/pkg/fs" htypes "github.com/rabbitstack/fibratus/pkg/handle/types" "github.com/rabbitstack/fibratus/pkg/sys" "github.com/rabbitstack/fibratus/pkg/sys/etw" - "github.com/rabbitstack/fibratus/pkg/util/filetime" "github.com/rabbitstack/fibratus/pkg/util/ip" "github.com/rabbitstack/fibratus/pkg/util/key" "github.com/rabbitstack/fibratus/pkg/util/ntstatus" - "github.com/rabbitstack/fibratus/pkg/util/signature" "github.com/rabbitstack/fibratus/pkg/util/va" "golang.org/x/sys/windows" - "golang.org/x/sys/windows/registry" ) // unknownKeysCount counts the number of times the registry key failed to convert from native format @@ -215,716 +208,55 @@ func (pars Params) MustGetSID() *windows.SID { return sid } -// produceParams parses the event binary layout to extract +var paramDecoder = &ParamDecoder{} + +// decodeParams parses the event binary layout to extract // the parameters. Each event is annotated with the schema // version number which helps us determine when the event // schema changes in order to parse new fields. -func (e *Event) produceParams(evt *etw.EventRecord) { - switch e.Type { - case ProcessRundown, CreateProcess, TerminateProcess: - var ( - kproc uint64 - pid, ppid uint32 - sessionID uint32 - exitStatus uint32 - dtb uint64 - flags uint32 - sid []byte - name string - cmdline string - ) - var offset uint16 - var soffset uint16 - var noffset uint16 - if evt.Version() >= 1 { - pid = evt.ReadUint32(8) - ppid = evt.ReadUint32(12) - sessionID = evt.ReadUint32(16) - exitStatus = evt.ReadUint32(20) - } - if evt.Version() >= 2 { - kproc = evt.ReadUint64(0) - } - if evt.Version() >= 3 { - dtb = evt.ReadUint64(24) +func (e *Event) decodeParams(r *etw.EventRecord) { + switch r.Header.ProviderID { + case RegistryEventGUID: + paramDecoder.DecodeRegistry(r, e) + case FileEventGUID: + paramDecoder.DecodeFile(r, e) + case StackWalkEventGUID: + paramDecoder.DecodeStackwalk(r, e) + case AuditAPIEventGUID: + switch r.Header.EventDescriptor.ID { + case OpenProcessID: + paramDecoder.DecodeOpenProcess(r, e) + case OpenThreadID: + paramDecoder.DecodeOpenThread(r, e) + case SetThreadContextID: + paramDecoder.DecodeSetThreadContext(r, e) + case CreateSymbolicLinkObjectID: + paramDecoder.DecodeCreateSymbolicLinkObject(r, e) + } + case MemEventGUID: + paramDecoder.DecodeMemory(r, e) + case NetworkTCPEventGUID, NetworkUDPEventGUID: + paramDecoder.DecodeNetwork(r, e) + case DNSEventGUID: + paramDecoder.DecodeDNS(r, e) + case ProcessEventGUID: + paramDecoder.DecodeProcess(r, e) + case ModuleEventGUID: + paramDecoder.DecodeModule(r, e) + case ThreadEventGUID: + paramDecoder.DecodeThread(r, e) + case ThreadpoolEventGUID: + paramDecoder.DecodeThreadpool(r, e) + case HandleEventGUID: + paramDecoder.DecodeHandle(r, e) + case RegistryKernelEventGUID: + paramDecoder.DecodeRegSetValueInternal(r, e) + case ProcessKernelEventGUID: + switch r.Header.EventDescriptor.ID { + case CreateProcessInternalID, ProcessRundownInternalID: + paramDecoder.DecodeProcessInternal(r, e) + case LoadModuleInternalID: + paramDecoder.DecodeModuleInternal(r, e) } - if evt.Version() >= 4 { - flags = evt.ReadUint32(32) - } - switch { - case evt.Version() >= 4: - offset = 36 - case evt.Version() >= 3: - offset = 32 - default: - offset = 24 - } - sid, soffset = evt.ReadSID(offset, true) - name, noffset = evt.ReadAnsiString(soffset) - cmdline, _ = evt.ReadUTF16String(noffset) - e.AppendParam(params.ProcessObject, params.Address, kproc) - e.AppendParam(params.ProcessID, params.PID, pid) - e.AppendParam(params.ProcessParentID, params.PID, ppid) - e.AppendParam(params.ProcessRealParentID, params.PID, evt.Header.ProcessID) - e.AppendParam(params.SessionID, params.Uint32, sessionID) - e.AppendParam(params.ExitStatus, params.Status, exitStatus) - e.AppendParam(params.DTB, params.Address, dtb) - e.AppendParam(params.ProcessFlags, params.Flags, flags, WithFlags(PsCreationFlags)) - e.AppendParam(params.UserSID, params.WbemSID, sid) - e.AppendParam(params.ProcessName, params.AnsiString, name) - e.AppendParam(params.Cmdline, params.UnicodeString, cmdline) - case CreateProcessInternal, ProcessRundownInternal: - var ( - pid uint32 - createTime windows.Filetime - ppid uint32 - sessionID uint32 - flags uint32 - tokenElevationType uint32 - tokenIsElevated uint32 - tokenMandatoryLabel []byte - exe string - ) - - pid = evt.ReadUint32(0) - - if (e.IsCreateProcessInternal() && evt.Version() >= 3) || (e.IsProcessRundownInternal() && evt.Version() >= 1) { - createTime = windows.NsecToFiletime(int64(evt.ReadUint64(12))) // skip sequence number (8 bytes) - - ppid = evt.ReadUint32(20) - sessionID = evt.ReadUint32(32) // skip parent sequence number (8 bytes) - flags = evt.ReadUint32(36) - tokenElevationType = evt.ReadUint32(40) - tokenIsElevated = evt.ReadUint32(44) - - tokenMandatoryLabel, _ = evt.ReadSID(48, false) // integrity level SID size is 12 bytes - - exe, _ = evt.ReadNTUnicodeString(60) - } else { - createTime = windows.NsecToFiletime(int64(evt.ReadUint64(8))) - ppid = evt.ReadUint32(16) - sessionID = evt.ReadUint32(20) - flags = evt.ReadUint32(24) - exe, _ = evt.ReadNTUnicodeString(28) - } - - e.AppendParam(params.ProcessID, params.PID, pid) - e.AppendParam(params.StartTime, params.Time, filetime.ToEpoch(uint64(createTime.Nanoseconds()))) - e.AppendParam(params.ProcessParentID, params.PID, ppid) - e.AppendParam(params.SessionID, params.Uint32, sessionID) - e.AppendParam(params.ProcessFlags, params.Flags, flags, WithFlags(PsCreationFlags)) - e.AppendParam(params.ProcessTokenElevationType, params.Enum, tokenElevationType, WithEnum(PsTokenElevationTypes)) - e.AppendParam(params.ProcessTokenIsElevated, params.Bool, tokenIsElevated > 0) - e.AppendParam(params.ProcessTokenIntegrityLevel, params.SID, tokenMandatoryLabel) - e.AppendParam(params.Exe, params.DOSPath, exe) - case OpenProcess: - processID := evt.ReadUint32(0) - desiredAccess := evt.ReadUint32(4) - status := evt.ReadUint32(8) - e.AppendParam(params.ProcessID, params.PID, processID) - e.AppendParam(params.DesiredAccess, params.Flags, desiredAccess, WithFlags(PsAccessRightFlags)) - e.AppendParam(params.NTStatus, params.Status, status) - - // append callstack for interested flags - if desiredAccess == AllAccess || ((desiredAccess & windows.PROCESS_VM_READ) != 0) || ((desiredAccess & windows.PROCESS_VM_WRITE) != 0) || - ((desiredAccess & windows.PROCESS_VM_OPERATION) != 0) || ((desiredAccess & windows.PROCESS_DUP_HANDLE) != 0) || - ((desiredAccess & windows.PROCESS_TERMINATE) != 0) || ((desiredAccess & windows.PROCESS_CREATE_PROCESS) != 0) || - ((desiredAccess & windows.PROCESS_CREATE_THREAD) != 0) || ((desiredAccess & windows.PROCESS_SET_INFORMATION) != 0) { - e.AppendParam(params.Callstack, params.Slice, evt.Callstack()) - } - case CreateThread, TerminateThread, ThreadRundown: - var ( - pid uint32 - tid uint32 - kstack, klimit uint64 - ustack, ulimit uint64 - startAddress uint64 - teb uint64 - basePrio uint8 - pagePrio uint8 - ioPrio uint8 - ) - if evt.Version() >= 1 { - pid = evt.ReadUint32(0) - tid = evt.ReadUint32(4) - } else { - pid = evt.ReadUint32(4) - tid = evt.ReadUint32(0) - } - if evt.Version() >= 2 { - kstack = evt.ReadUint64(8) - klimit = evt.ReadUint64(16) - ustack = evt.ReadUint64(24) - ulimit = evt.ReadUint64(32) - startAddress = evt.ReadUint64(48) - teb = evt.ReadUint64(56) - } - if evt.Version() >= 3 { - basePrio = evt.ReadByte(69) - pagePrio = evt.ReadByte(70) - ioPrio = evt.ReadByte(71) - } - e.AppendParam(params.ProcessID, params.PID, pid) - e.AppendParam(params.ThreadID, params.TID, tid) - e.AppendParam(params.KstackBase, params.Address, kstack) - e.AppendParam(params.KstackLimit, params.Address, klimit) - e.AppendParam(params.UstackBase, params.Address, ustack) - e.AppendParam(params.UstackLimit, params.Address, ulimit) - e.AppendParam(params.StartAddress, params.Address, startAddress) - e.AppendParam(params.TEB, params.Address, teb) - e.AppendParam(params.BasePrio, params.Uint8, basePrio) - e.AppendParam(params.PagePrio, params.Uint8, pagePrio) - e.AppendParam(params.IOPrio, params.Uint8, ioPrio) - case OpenThread: - processID := evt.ReadUint32(0) - threadID := evt.ReadUint32(4) - desiredAccess := evt.ReadUint32(8) - status := evt.ReadUint32(12) - e.AppendParam(params.ProcessID, params.PID, processID) - e.AppendParam(params.ThreadID, params.TID, threadID) - e.AppendParam(params.DesiredAccess, params.Flags, desiredAccess, WithFlags(ThreadAccessRightFlags)) - e.AppendParam(params.NTStatus, params.Status, status) - - // append callstack for interested flags - if desiredAccess == AllAccess || ((desiredAccess & windows.THREAD_SET_CONTEXT) != 0) || ((desiredAccess & windows.THREAD_SET_THREAD_TOKEN) != 0) || - ((desiredAccess & windows.THREAD_IMPERSONATE) != 0) || ((desiredAccess & windows.THREAD_DIRECT_IMPERSONATION) != 0) || - ((desiredAccess & windows.THREAD_SUSPEND_RESUME) != 0) || ((desiredAccess & windows.THREAD_TERMINATE) != 0) || - ((desiredAccess & windows.THREAD_SET_INFORMATION) != 0) { - e.AppendParam(params.Callstack, params.Slice, evt.Callstack()) - } - case SetThreadContext: - status := evt.ReadUint32(0) - e.AppendParam(params.NTStatus, params.Status, status) - if evt.HasStackTrace() { - e.AppendParam(params.Callstack, params.Slice, evt.Callstack()) - } - case CreateHandle, CloseHandle: - object := evt.ReadUint64(0) - handleID := evt.ReadUint32(8) - typeID := evt.ReadUint16(12) - var handleName string - if evt.BufferLen >= 16 { - handleName = evt.ConsumeUTF16String(14) - } - e.AppendParam(params.HandleObject, params.Address, object) - e.AppendParam(params.HandleID, params.Uint32, handleID) - e.AppendParam(params.HandleObjectTypeID, params.HandleType, typeID) - e.AppendParam(params.HandleObjectName, params.UnicodeString, handleName) - case DuplicateHandle: - object := evt.ReadUint64(0) - srcHandleID := evt.ReadUint32(8) - dstHandleID := evt.ReadUint32(12) - targetPID := evt.ReadUint32(16) - typeID := evt.ReadUint16(20) - sourcePID := evt.ReadUint32(22) - e.AppendParam(params.HandleObject, params.Address, object) - e.AppendParam(params.HandleID, params.Uint32, dstHandleID) - e.AppendParam(params.HandleSourceID, params.Uint32, srcHandleID) - e.AppendParam(params.HandleObjectTypeID, params.HandleType, typeID) - e.AppendParam(params.ProcessID, params.PID, sourcePID) - e.AppendParam(params.TargetProcessID, params.PID, targetPID) - case LoadModule, UnloadModule, ModuleRundown: - var ( - pid uint32 - checksum uint32 - defaultBase uint64 - filename string - sigLevel, sigType uint8 - ) - var offset uint16 - imageBase := evt.ReadUint64(0) - imageSize := evt.ReadUint64(8) - if evt.Version() >= 1 { - pid = evt.ReadUint32(16) - } - if evt.Version() >= 2 { - checksum = evt.ReadUint32(20) - defaultBase = evt.ReadUint64(30) - } - if evt.Version() >= 3 { - sigLevel = evt.ReadByte(28) - sigType = evt.ReadByte(29) - defaultBase = evt.ReadUint64(32) - } - switch { - case evt.Version() >= 3: - offset = 56 - case evt.Version() >= 2: - offset = 54 - case evt.Version() >= 1: - offset = 20 - default: - offset = 16 - } - filename = evt.ConsumeUTF16String(offset) - e.AppendParam(params.ProcessID, params.PID, pid) - e.AppendParam(params.ModuleCheckSum, params.Uint32, checksum) - e.AppendParam(params.ModuleDefaultBase, params.Address, defaultBase) - e.AppendParam(params.ModuleBase, params.Address, imageBase) - e.AppendParam(params.ModuleSize, params.Uint64, imageSize) - e.AppendParam(params.ModulePath, params.DOSPath, filename) - e.AppendParam(params.ModuleSignatureLevel, params.Enum, uint32(sigLevel), WithEnum(signature.Levels)) - e.AppendParam(params.ModuleSignatureType, params.Enum, uint32(sigType), WithEnum(signature.Types)) - case LoadModuleInternal: - var ( - pid uint32 - checksum uint32 - defaultBase uint64 - imageBase uint64 - imageSize uint64 - filename string - ) - - imageBase = evt.ReadUint64(0) - imageSize = evt.ReadUint64(8) - pid = evt.ReadUint32(16) - checksum = evt.ReadUint32(20) - defaultBase = evt.ReadUint64(28) // skip timestamp (4 bytes) - filename = evt.ConsumeUTF16String(36) - - e.AppendParam(params.ProcessID, params.PID, pid) - e.AppendParam(params.ModuleCheckSum, params.Uint32, checksum) - e.AppendParam(params.ModuleDefaultBase, params.Address, defaultBase) - e.AppendParam(params.ModuleBase, params.Address, imageBase) - e.AppendParam(params.ModuleSize, params.Uint64, imageSize) - e.AppendParam(params.ModulePath, params.DOSPath, filename) - case RegOpenKey, RegCloseKey, - RegCreateKCB, RegDeleteKCB, - RegKCBRundown, RegCreateKey, - RegDeleteKey, RegDeleteValue, - RegQueryKey, RegQueryValue, - RegSetValue: - var ( - status uint32 - keyHandle uint64 - keyName string - ) - if evt.Version() >= 2 { - status = evt.ReadUint32(8) - keyHandle = evt.ReadUint64(16) - } else { - status = evt.ReadUint32(0) - keyHandle = evt.ReadUint64(4) - } - if evt.Version() >= 1 { - keyName = evt.ConsumeUTF16String(24) - } else { - keyName = evt.ConsumeUTF16String(20) - } - e.AppendParam(params.RegKeyHandle, params.Address, keyHandle) - e.AppendParam(params.RegPath, params.Key, keyName) - e.AppendParam(params.NTStatus, params.Status, status) - case RegSetValueInternal: - keyObject := evt.ReadUint64(0) - status := evt.ReadUint32(8) - valueType := evt.ReadUint32(12) - keyName, koffset := evt.ReadUTF16String(20) // skip data size param (4 bytes) - valueName, voffset := evt.ReadUTF16String(koffset) - capturedSize := evt.ReadUint16(voffset) - capturedData := evt.ReadBytes(2+voffset, capturedSize) - - // copy the buffer as it points to invalid - // memory when the callback function returns - b := make([]byte, capturedSize) - copy(b, capturedData) - - e.AppendParam(params.RegKeyHandle, params.Address, keyObject) - e.AppendParam(params.NTStatus, params.Status, status) - e.AppendParam(params.RegPath, params.Key, filepath.Join(keyName, valueName)) - e.AppendEnum(params.RegValueType, valueType, key.RegistryValueTypes) - - if len(b) > 0 { - switch valueType { - case registry.SZ, registry.MULTI_SZ, registry.EXPAND_SZ: - e.AppendParam(params.RegData, params.UnicodeString, utf16.BytesToString(b, binary.LittleEndian)) - case registry.BINARY: - e.AppendParam(params.RegData, params.Binary, b) - case registry.DWORD: - var v uint32 - switch len(b) { - case 4: - v = binary.LittleEndian.Uint32(b) - case 2: - v = uint32(binary.LittleEndian.Uint16(b)) - case 1: - v = uint32(b[0]) - } - e.AppendParam(params.RegData, params.Uint32, v) - case registry.DWORD_BIG_ENDIAN: - var v uint32 - switch len(b) { - case 4: - v = binary.BigEndian.Uint32(b) - case 2: - v = uint32(binary.BigEndian.Uint16(b)) - case 1: - v = uint32(b[0]) - } - e.AppendParam(params.RegData, params.Uint32, v) - case registry.QWORD: - var v uint64 - switch len(b) { - case 8: - v = binary.LittleEndian.Uint64(b) - case 4: - v = uint64(binary.LittleEndian.Uint32(b)) - case 2: - v = uint64(binary.LittleEndian.Uint16(b)) - case 1: - v = uint64(b[0]) - } - e.AppendParam(params.RegData, params.Uint64, v) - } - } - case CreateFile: - var ( - irp uint64 - fileObject uint64 - tid uint32 - createOptions uint32 - fileAttributes uint32 - shareAccess uint32 - filename string - ) - if evt.Version() >= 2 { - irp = evt.ReadUint64(0) - fileObject = evt.ReadUint64(8) - tid = evt.ReadUint32(16) - createOptions = evt.ReadUint32(20) - fileAttributes = evt.ReadUint32(24) - shareAccess = evt.ReadUint32(28) - filename = evt.ConsumeUTF16String(32) - } else { - fileObject = evt.ReadUint64(0) - filename = evt.ConsumeUTF16String(8) - } - e.AppendParam(params.FileIrpPtr, params.Address, irp) - e.AppendParam(params.FileObject, params.Address, fileObject) - e.AppendParam(params.ThreadID, params.TID, tid) - e.AppendParam(params.FileShareMask, params.Flags, shareAccess, WithFlags(FileShareModeFlags)) - e.AppendParam(params.FileAttributes, params.Flags, fileAttributes, WithFlags(FileAttributeFlags)) - e.AppendParam(params.FileCreateOptions, params.Flags, createOptions, WithFlags(FileCreateOptionsFlags)) - e.AppendParam(params.FilePath, params.DOSPath, filename) - case FileOpEnd: - var ( - irp uint64 - extraInfo uint64 - status uint32 - ) - if evt.Version() >= 2 { - irp = evt.ReadUint64(0) - extraInfo = evt.ReadUint64(8) - status = evt.ReadUint32(16) - } - e.AppendParam(params.FileIrpPtr, params.Address, irp) - e.AppendParam(params.FileExtraInfo, params.Address, extraInfo) - e.AppendParam(params.NTStatus, params.Status, status) - case FileRundown: - var ( - fileObject uint64 - filename string - ) - if evt.Version() >= 2 { - fileObject = evt.ReadUint64(0) - filename = evt.ConsumeUTF16String(8) - } - e.AppendParam(params.FileObject, params.Address, fileObject) - e.AppendParam(params.FilePath, params.DOSPath, filename) - case ReleaseFile, CloseFile: - var ( - irp uint64 - fileObject uint64 - fileKey uint64 - tid uint32 - ) - if evt.Version() >= 2 { - irp = evt.ReadUint64(0) - } - if evt.Version() >= 3 { - fileObject = evt.ReadUint64(8) - fileKey = evt.ReadUint64(16) - tid = evt.ReadUint32(24) - } - e.AppendParam(params.FileIrpPtr, params.Address, irp) - e.AppendParam(params.FileObject, params.Address, fileObject) - e.AppendParam(params.FileKey, params.Address, fileKey) - e.AppendParam(params.ThreadID, params.TID, tid) - case DeleteFile, RenameFile, SetFileInformation: - var ( - irp uint64 - fileObject uint64 - fileKey uint64 - tid uint32 - extraInfo uint64 - infoClass uint32 - ) - if evt.Version() >= 2 { - irp = evt.ReadUint64(0) - } - if evt.Version() >= 3 { - fileObject = evt.ReadUint64(8) - fileKey = evt.ReadUint64(16) - extraInfo = evt.ReadUint64(24) - tid = evt.ReadUint32(32) - infoClass = evt.ReadUint32(36) - } else { - tid = evt.ReadUint32(8) - fileObject = evt.ReadUint64(12) - fileKey = evt.ReadUint64(18) - extraInfo = evt.ReadUint64(28) - } - e.AppendParam(params.FileIrpPtr, params.Address, irp) - e.AppendParam(params.FileObject, params.Address, fileObject) - e.AppendParam(params.FileKey, params.Address, fileKey) - e.AppendParam(params.ThreadID, params.TID, tid) - e.AppendParam(params.FileExtraInfo, params.Uint64, extraInfo) - e.AppendParam(params.FileInfoClass, params.Enum, infoClass, WithEnum(fs.FileInfoClasses)) - case ReadFile, WriteFile: - var ( - irp uint64 - offset uint64 - fileObject uint64 - fileKey uint64 - tid uint32 - size uint32 - ) - if evt.Version() >= 2 { - offset = evt.ReadUint64(0) - irp = evt.ReadUint64(8) - } - if evt.Version() >= 3 { - fileObject = evt.ReadUint64(16) - fileKey = evt.ReadUint64(24) - tid = evt.ReadUint32(32) - size = evt.ReadUint32(34) - } else { - fileObject = evt.ReadUint64(20) - fileKey = evt.ReadUint64(28) - tid = evt.ReadUint32(16) - } - e.AppendParam(params.FileIrpPtr, params.Address, irp) - e.AppendParam(params.FileObject, params.Address, fileObject) - e.AppendParam(params.FileKey, params.Address, fileKey) - e.AppendParam(params.ThreadID, params.TID, tid) - e.AppendParam(params.FileOffset, params.Uint64, offset) - e.AppendParam(params.FileIoSize, params.Uint32, size) - case EnumDirectory: - var ( - irp uint64 - fileObject uint64 - fileKey uint64 - tid uint32 - infoClass uint32 - filename string - ) - if evt.Version() >= 2 { - irp = evt.ReadUint64(0) - } - if evt.Version() >= 3 { - fileObject = evt.ReadUint64(8) - fileKey = evt.ReadUint64(16) - tid = evt.ReadUint32(24) - infoClass = evt.ReadUint32(32) - filename = evt.ConsumeUTF16String(38) - } else { - tid = evt.ReadUint32(8) - fileObject = evt.ReadUint64(12) - fileKey = evt.ReadUint64(20) - } - e.AppendParam(params.FileIrpPtr, params.Address, irp) - e.AppendParam(params.FileObject, params.Address, fileObject) - e.AppendParam(params.ThreadID, params.TID, tid) - e.AppendParam(params.FileKey, params.Address, fileKey) - e.AppendParam(params.FilePath, params.UnicodeString, filename) - e.AppendParam(params.FileInfoClass, params.Enum, infoClass, WithEnum(fs.FileInfoClasses)) - case MapViewFile, UnmapViewFile, MapFileRundown: - var ( - viewBase uint64 - fileKey uint64 - extraInfo uint64 - viewSize uint64 - pid uint32 - offset uint64 - ) - viewBase = evt.ReadUint64(0) - fileKey = evt.ReadUint64(8) - extraInfo = evt.ReadUint64(16) - viewSize = evt.ReadUint64(24) - if evt.Version() >= 3 { - offset = evt.ReadUint64(32) - } - if evt.Version() >= 3 { - pid = evt.ReadUint32(40) - } else { - pid = evt.ReadUint32(32) - } - protect := uint32(extraInfo >> 32) - section := uint32(extraInfo >> 52) - e.AppendParam(params.FileViewBase, params.Address, viewBase) - e.AppendParam(params.FileKey, params.Address, fileKey) - e.AppendParam(params.FileViewSize, params.Uint64, viewSize) - e.AppendParam(params.FileOffset, params.Uint64, offset) - e.AppendParam(params.ProcessID, params.PID, pid) - e.AppendParam(params.MemProtect, params.Flags, protect, WithFlags(ViewProtectionFlags)) - e.AppendParam(params.FileViewSectionType, params.Enum, section, WithEnum(ViewSectionTypes)) - case SendTCPv4, - SendUDPv4, - RecvTCPv4, - RecvUDPv4, - DisconnectTCPv4, - RetransmitTCPv4, - ReconnectTCPv4, - ConnectTCPv4, - AcceptTCPv4: - var ( - pid uint32 - size uint32 - dip uint32 - sip uint32 - dport uint16 - sport uint16 - ) - if evt.Version() >= 1 { - pid = evt.ReadUint32(0) - size = evt.ReadUint32(4) - dip = evt.ReadUint32(8) - sip = evt.ReadUint32(12) - dport = evt.ReadUint16(16) - sport = evt.ReadUint16(18) - } else { - dip = evt.ReadUint32(0) - sip = evt.ReadUint32(4) - dport = evt.ReadUint16(8) - sport = evt.ReadUint16(10) - size = evt.ReadUint32(12) - pid = evt.ReadUint32(16) - } - e.AppendParam(params.ProcessID, params.PID, pid) - e.AppendParam(params.NetSize, params.Uint32, size) - e.AppendParam(params.NetDIP, params.IPv4, dip) - e.AppendParam(params.NetSIP, params.IPv4, sip) - e.AppendParam(params.NetDport, params.Port, dport) - e.AppendParam(params.NetSport, params.Port, sport) - case SendTCPv6, - SendUDPv6, - RecvTCPv6, - RecvUDPv6, - DisconnectTCPv6, - RetransmitTCPv6, - ReconnectTCPv6, - ConnectTCPv6, - AcceptTCPv6: - var ( - pid uint32 - size uint32 - dip []byte - sip []byte - dport uint16 - sport uint16 - ) - if evt.Version() >= 2 { - pid = evt.ReadUint32(0) - size = evt.ReadUint32(4) - dip = evt.ReadBytes(8, 16) - sip = evt.ReadBytes(24, 16) - dport = evt.ReadUint16(40) - sport = evt.ReadUint16(42) - } - e.AppendParam(params.ProcessID, params.PID, pid) - e.AppendParam(params.NetSize, params.Uint32, size) - e.AppendParam(params.NetDIP, params.IPv6, dip) - e.AppendParam(params.NetSIP, params.IPv6, sip) - e.AppendParam(params.NetDport, params.Port, dport) - e.AppendParam(params.NetSport, params.Port, sport) - case VirtualAlloc, VirtualFree: - var ( - baseAddress uint64 - regionSize uint64 - pid uint32 - flags uint32 - ) - if evt.Version() >= 1 { - baseAddress = evt.ReadUint64(0) - regionSize = evt.ReadUint64(8) - pid = evt.ReadUint32(16) - flags = evt.ReadUint32(20) - } - e.AppendParam(params.MemBaseAddress, params.Address, baseAddress) - e.AppendParam(params.MemRegionSize, params.Uint64, regionSize) - e.AppendParam(params.ProcessID, params.PID, pid) - e.AppendParam(params.MemAllocType, params.Flags, flags, WithFlags(MemAllocationFlags)) - case QueryDNS, ReplyDNS: - var ( - name string - rr uint32 - opts uint64 - ) - var offset uint16 - name, offset = evt.ReadUTF16String(0) - rr = evt.ReadUint32(offset) - opts = evt.ReadUint64(offset + 4) - e.AppendParam(params.DNSName, params.UnicodeString, name) - e.AppendParam(params.DNSRR, params.Enum, rr, WithEnum(DNSRecordTypes)) - e.AppendParam(params.DNSOpts, params.Flags64, opts, WithFlags(DNSOptsFlags)) - if e.Type == ReplyDNS { - rcode := evt.ReadUint32(offset + 12) - answers := evt.ConsumeUTF16String(offset + 16) - e.AppendParam(params.DNSRcode, params.Enum, rcode, WithEnum(DNSResponseCodes)) - e.AppendParam(params.DNSAnswers, params.Slice, strings.Split(sanitizeDNSAnswers(answers), ";")) - } - case StackWalk: - e.AppendParam(params.ProcessID, params.PID, evt.ReadUint32(8)) - e.AppendParam(params.ThreadID, params.TID, evt.ReadUint32(12)) - var n uint16 - var offset uint16 = 16 - frames := (evt.BufferLen - offset) / 8 - callstack := make([]va.Address, frames) - for n < frames { - callstack[n] = va.Address(evt.ReadUint64(offset)) - offset += 8 - n++ - } - e.AppendParam(params.Callstack, params.Slice, callstack) - case CreateSymbolicLinkObject: - source, offset := evt.ReadUTF16String(0) - target, offset := evt.ReadUTF16String(offset) - desiredAccess := evt.ReadUint32(offset) - status := evt.ReadUint32(offset + 4) - e.AppendParam(params.LinkSource, params.UnicodeString, source) - e.AppendParam(params.LinkTarget, params.UnicodeString, target) - e.AppendParam(params.DesiredAccess, params.Flags, desiredAccess, WithFlags(AccessMaskFlags)) - e.AppendParam(params.NTStatus, params.Status, status) - if evt.HasStackTrace() { - e.AppendParam(params.Callstack, params.Slice, evt.Callstack()) - } - case SubmitThreadpoolWork, SubmitThreadpoolCallback: - poolID := evt.ReadUint64(0) - taskID := evt.ReadUint64(8) - callback := evt.ReadUint64(16) - ctx := evt.ReadUint64(24) - tag := evt.ReadUint64(32) - e.AppendParam(params.ThreadpoolPoolID, params.Address, poolID) - e.AppendParam(params.ThreadpoolTaskID, params.Address, taskID) - e.AppendParam(params.ThreadpoolCallback, params.Address, callback) - e.AppendParam(params.ThreadpoolContext, params.Address, ctx) - e.AppendParam(params.ThreadpoolSubprocessTag, params.Address, tag) - case SetThreadpoolTimer: - duetime := evt.ReadUint64(0) - subqueue := evt.ReadUint64(8) - timer := evt.ReadUint64(16) - period := evt.ReadUint32(24) - window := evt.ReadUint32(28) - absolute := evt.ReadUint32(32) - e.AppendParam(params.ThreadpoolTimerDuetime, params.Uint64, duetime) - e.AppendParam(params.ThreadpoolTimerSubqueue, params.Address, subqueue) - e.AppendParam(params.ThreadpoolTimer, params.Address, timer) - e.AppendParam(params.ThreadpoolTimerPeriod, params.Uint32, period) - e.AppendParam(params.ThreadpoolTimerWindow, params.Uint32, window) - e.AppendParam(params.ThreadpoolTimerAbsolute, params.Bool, absolute > 0) } } - -// sanitizeDNSAnswers removes the "type" string from DNS answers. -func sanitizeDNSAnswers(answers string) string { - return strings.ReplaceAll(answers, "type: 5 ", "") -} diff --git a/pkg/event/types_windows.go b/pkg/event/types_windows.go index 157ed50de..93ff22551 100644 --- a/pkg/event/types_windows.go +++ b/pkg/event/types_windows.go @@ -31,7 +31,7 @@ import ( type Source uint8 const ( - // SystemLogger event is emitted by the system provider + // SystemLogger event is emitted by the system provider. SystemLogger Source = iota // SecurityTelemetryLogger event is emitted by the combination of multiple providers. // Most notably, DNS, thread pool, and kernel audit API providers are in charge of @@ -65,174 +65,257 @@ var ( AuditAPIEventGUID = windows.GUID{Data1: 0xe02a841c, Data2: 0x75a3, Data3: 0x4fa7, Data4: [8]byte{0xaf, 0xc8, 0xae, 0x09, 0xcf, 0x9b, 0x7f, 0x23}} // DNSEventGUID represents DNS provider event GUID DNSEventGUID = windows.GUID{Data1: 0x1c95126e, Data2: 0x7eea, Data3: 0x49a9, Data4: [8]byte{0xa3, 0xfe, 0xa3, 0x78, 0xb0, 0x3d, 0xdb, 0x4d}} - // ThreadpoolGUID represents the thread pool event GUID - ThreadpoolGUID = windows.GUID{Data1: 0xc861d0e2, Data2: 0xa2c1, Data3: 0x4d36, Data4: [8]byte{0x9f, 0x9c, 0x97, 0x0b, 0xab, 0x94, 0x3a, 0x12}} + // ThreadpoolEventGUID represents the thread pool event GUID + ThreadpoolEventGUID = windows.GUID{Data1: 0xc861d0e2, Data2: 0xa2c1, Data3: 0x4d36, Data4: [8]byte{0x9f, 0x9c, 0x97, 0x0b, 0xab, 0x94, 0x3a, 0x12}} // ProcessKernelEventGUID represents the Process Kernel event GUID ProcessKernelEventGUID = windows.GUID{Data1: 0x22fb2cd6, Data2: 0x0e7b, Data3: 0x422b, Data4: [8]byte{0xa0, 0xc7, 0x2f, 0xad, 0x1f, 0xd0, 0xe7, 0x16}} // RegistryKernelEventGUID represents the Registry Kernel event GUID RegistryKernelEventGUID = windows.GUID{Data1: 0x70eb4f03, Data2: 0xc1de, Data3: 0x4f73, Data4: [8]byte{0xa0, 0x51, 0x33, 0xd1, 0x3d, 0x54, 0x13, 0xbd}} + // StackWalkEventGUID represents the StackWalk event GUID + StackWalkEventGUID = windows.GUID{Data1: 0xdef2fe46, Data2: 0x7bd6, Data3: 0x4b80, Data4: [8]byte{0xbd, 0x94, 0xf5, 0x7f, 0xe2, 0x0d, 0x0c, 0xe3}} +) + +const ( + CreateProcessID uint8 = 1 + CreateProcessInternalID uint16 = 1 + TerminateProcessID uint8 = 2 + ProcessRundownID uint8 = 3 + OpenProcessID uint16 = 5 + ProcessRundownInternalID uint16 = 15 + + CreateThreadID uint8 = 1 + TerminateThreadID uint8 = 2 + ThreadRundownID uint8 = 3 + SetThreadContextID uint16 = 4 + OpenThreadID uint16 = 6 + + UnloadModuleID uint8 = 2 + ModuleRundownID uint8 = 3 + LoadModuleInternalID uint16 = 5 + LoadModuleID uint8 = 10 + + FileRundownID uint8 = 36 + MapViewFileID uint8 = 37 + UnmapViewFileID uint8 = 38 + MapFileRundownID uint8 = 39 + CreateFileID uint8 = 64 + ReleaseFileID uint8 = 65 + CloseFileID uint8 = 66 + ReadFileID uint8 = 67 + WriteFileID uint8 = 68 + SetFileInformationID uint8 = 69 + DeleteFileID uint8 = 70 + RenameFileID uint8 = 71 + EnumDirectoryID uint8 = 72 + FileOpEndID uint8 = 76 + + RegCreateKeyID uint8 = 10 + RegOpenKeyID uint8 = 11 + RegDeleteKeyID uint8 = 12 + RegQueryKeyID uint8 = 13 + RegSetValueID uint8 = 14 + RegDeleteValueID uint8 = 15 + RegQueryValueID uint8 = 16 + RegCreateKCBID uint8 = 22 + RegDeleteKCBID uint8 = 23 + RegKCBRundownID uint8 = 25 + RegCloseKeyID uint8 = 27 + RegSetValueInternalID uint16 = 36 + + AcceptTCPv4ID uint8 = 15 + AcceptTCPv6ID uint8 = 31 + SendV4ID uint8 = 10 + SendV6ID uint8 = 26 + RecvV4ID uint8 = 11 + RecvV6ID uint8 = 27 + ConnectTCPv4ID uint8 = 12 + ConnectTCPv6ID uint8 = 28 + DisconnectTCPv4ID uint8 = 13 + DisconnectTCPv6ID uint8 = 29 + ReconnectTCPv4ID uint8 = 16 + ReconnectTCPv6ID uint8 = 32 + RetransmitTCPv4ID uint8 = 14 + RetransmitTCPv6ID uint8 = 30 + + VirtualAllocID uint8 = 98 + VirtualFreeID uint8 = 99 + + CreateHandleID uint8 = 32 + CloseHandleID uint8 = 33 + DuplicateHandleID uint8 = 34 + + QueryDNSID uint16 = 3006 + ReplyDNSID uint16 = 3008 + + CreateSymbolicLinkObjectID uint16 = 3 + + StackWalkID uint8 = 32 + + SubmitThreadpoolWorkID uint8 = 32 + SubmitThreadpoolCallbackID uint8 = 34 + SetThreadpoolTimerID uint8 = 44 ) var ( // CreateProcess identifies process creation kernel events - CreateProcess = pack(ProcessEventGUID, 1) + CreateProcess = pack(ProcessEventGUID, uint16(CreateProcessID)) // TerminateProcess identifies process termination kernel events - TerminateProcess = pack(ProcessEventGUID, 2) + TerminateProcess = pack(ProcessEventGUID, uint16(TerminateProcessID)) // ProcessRundown represents the start data collection process event that enumerates processes that are currently running at the time the kernel session starts - ProcessRundown = pack(ProcessEventGUID, 3) + ProcessRundown = pack(ProcessEventGUID, uint16(ProcessRundownID)) // OpenProcess identifies the kernel events that are triggered when the process handle is acquired - OpenProcess = pack(AuditAPIEventGUID, 5) + OpenProcess = pack(AuditAPIEventGUID, OpenProcessID) // CreateProcessInternal identifies the process creation event emitted by the Microsoft Windows Kernel Process provider. // The only purpose of this event is to enrich the process state with some extra attributes, and populates the snapshotter // for events running in the Security Telemetry session that might miss process lookups because the core NT Kernel Provider // hasn't still published the CreateProcess or ProcessRundown event - CreateProcessInternal = pack(ProcessKernelEventGUID, 1) + CreateProcessInternal = pack(ProcessKernelEventGUID, CreateProcessInternalID) // ProcessRundownInternal same as above but for process rundown events originating from the Microsoft Windows Kernel Process provider. - ProcessRundownInternal = pack(ProcessKernelEventGUID, 15) + ProcessRundownInternal = pack(ProcessKernelEventGUID, ProcessRundownInternalID) // CreateThread identifies thread creation kernel events - CreateThread = pack(ThreadEventGUID, 1) + CreateThread = pack(ThreadEventGUID, uint16(CreateThreadID)) // TerminateThread identifies thread termination kernel events - TerminateThread = pack(ThreadEventGUID, 2) + TerminateThread = pack(ThreadEventGUID, uint16(TerminateThreadID)) // ThreadRundown represents the start data collection thread event that enumerates threads that are currently running at the time the kernel session starts - ThreadRundown = pack(ThreadEventGUID, 3) + ThreadRundown = pack(ThreadEventGUID, uint16(ThreadRundownID)) // OpenThread identifies the kernel events that are triggered when the process acquires a thread handle - OpenThread = pack(AuditAPIEventGUID, 6) + OpenThread = pack(AuditAPIEventGUID, OpenThreadID) // SetThreadContext identifies the kernel event that is fired when the thread context is changed - SetThreadContext = pack(AuditAPIEventGUID, 4) + SetThreadContext = pack(AuditAPIEventGUID, SetThreadContextID) // MapViewFile represents events that map a view of a file mapping into the address space of a calling process - MapViewFile = pack(FileEventGUID, 37) + MapViewFile = pack(FileEventGUID, uint16(MapViewFileID)) // UnmapViewFile represents events that unmap a view of a file mapping from the address space of a calling process - UnmapViewFile = pack(FileEventGUID, 38) + UnmapViewFile = pack(FileEventGUID, uint16(UnmapViewFileID)) // MapFileRundown represents the event that is emitted at the start of the tracing session to enumerate I/O mapped files - MapFileRundown = pack(FileEventGUID, 39) + MapFileRundown = pack(FileEventGUID, uint16(MapFileRundownID)) // FileRundown events are generated by kernel rundown logger to enumerate all open files on the start of the kernel session - FileRundown = pack(FileEventGUID, 36) + FileRundown = pack(FileEventGUID, uint16(FileRundownID)) // CreateFile represents events that create/open a file or I/O device - CreateFile = pack(FileEventGUID, 64) + CreateFile = pack(FileEventGUID, uint16(CreateFileID)) // ReleaseFile represents events that occur when the last file handle is disposed - ReleaseFile = pack(FileEventGUID, 65) + ReleaseFile = pack(FileEventGUID, uint16(ReleaseFileID)) // CloseFile represents events that dispose existing kernel file objects - CloseFile = pack(FileEventGUID, 66) + CloseFile = pack(FileEventGUID, uint16(CloseFileID)) // ReadFile represents events that read data from the file or I/O device - ReadFile = pack(FileEventGUID, 67) + ReadFile = pack(FileEventGUID, uint16(ReadFileID)) // WriteFile represents events that write data to the file or I/O device - WriteFile = pack(FileEventGUID, 68) + WriteFile = pack(FileEventGUID, uint16(WriteFileID)) // SetFileInformation represents events that set file information - SetFileInformation = pack(FileEventGUID, 69) + SetFileInformation = pack(FileEventGUID, uint16(SetFileInformationID)) // DeleteFile identifies file deletion events - DeleteFile = pack(FileEventGUID, 70) + DeleteFile = pack(FileEventGUID, uint16(DeleteFileID)) // RenameFile identifies events that are responsible for renaming files - RenameFile = pack(FileEventGUID, 71) + RenameFile = pack(FileEventGUID, uint16(RenameFileID)) // EnumDirectory identifies enumerate directory and directory notification events - EnumDirectory = pack(FileEventGUID, 72) + EnumDirectory = pack(FileEventGUID, uint16(EnumDirectoryID)) // FileOpEnd signals the finalization of the file operation - FileOpEnd = pack(FileEventGUID, 76) + FileOpEnd = pack(FileEventGUID, uint16(FileOpEndID)) // RegCreateKey represents registry key creation kernel events - RegCreateKey = pack(RegistryEventGUID, 10) + RegCreateKey = pack(RegistryEventGUID, uint16(RegCreateKeyID)) // RegOpenKey represents registry open key kernel events - RegOpenKey = pack(RegistryEventGUID, 11) + RegOpenKey = pack(RegistryEventGUID, uint16(RegOpenKeyID)) // RegCloseKey represents registry close key kernel event. - RegCloseKey = pack(RegistryEventGUID, 27) + RegCloseKey = pack(RegistryEventGUID, uint16(RegCloseKeyID)) // RegDeleteKey represents registry key deletion kernel events - RegDeleteKey = pack(RegistryEventGUID, 12) + RegDeleteKey = pack(RegistryEventGUID, uint16(RegDeleteKeyID)) // RegQueryKey represents registry query key kernel events - RegQueryKey = pack(RegistryEventGUID, 13) + RegQueryKey = pack(RegistryEventGUID, uint16(RegQueryKeyID)) // RegSetValue represents registry set value kernel events - RegSetValue = pack(RegistryEventGUID, 14) + RegSetValue = pack(RegistryEventGUID, uint16(RegSetValueID)) // RegDeleteValue are kernel events for registry value removals - RegDeleteValue = pack(RegistryEventGUID, 15) + RegDeleteValue = pack(RegistryEventGUID, uint16(RegDeleteValueID)) // RegQueryValue are kernel events for registry value queries - RegQueryValue = pack(RegistryEventGUID, 16) + RegQueryValue = pack(RegistryEventGUID, uint16(RegQueryValueID)) // RegCreateKCB represents kernel events for KCB (Key Control Block) creation requests - RegCreateKCB = pack(RegistryEventGUID, 22) + RegCreateKCB = pack(RegistryEventGUID, uint16(RegCreateKCBID)) // RegDeleteKCB represents kernel events for KCB(Key Control Block) closures - RegDeleteKCB = pack(RegistryEventGUID, 23) + RegDeleteKCB = pack(RegistryEventGUID, uint16(RegDeleteKCBID)) // RegKCBRundown enumerates the registry keys open at the start of the kernel session. - RegKCBRundown = pack(RegistryEventGUID, 25) + RegKCBRundown = pack(RegistryEventGUID, uint16(RegKCBRundownID)) // RegSetValueInternal is the internal event that is used to // enrich the corresponding public RegSetValue event with // extra attributes - RegSetValueInternal = pack(RegistryKernelEventGUID, 36) + RegSetValueInternal = pack(RegistryKernelEventGUID, RegSetValueInternalID) // UnloadModule represents unload module kernel events - UnloadModule = pack(ModuleEventGUID, 2) + UnloadModule = pack(ModuleEventGUID, uint16(UnloadModuleID)) // ModuleRundown represents kernel events that is triggered to enumerate all loaded modules - ModuleRundown = pack(ModuleEventGUID, 3) + ModuleRundown = pack(ModuleEventGUID, uint16(ModuleRundownID)) // LoadModule represents module load kernel events that are triggered when a DLL or executable file is loaded - LoadModule = pack(ModuleEventGUID, 10) + LoadModule = pack(ModuleEventGUID, uint16(LoadModuleID)) // LoadModuleInternal same as for process internal event originating from the Microsoft Windows Kernel Process provider - LoadModuleInternal = pack(ProcessKernelEventGUID, 5) + LoadModuleInternal = pack(ProcessKernelEventGUID, LoadModuleInternalID) // AcceptTCPv4 represents the TCPv4 kernel events for accepting connection requests from the socket queue. - AcceptTCPv4 = pack(NetworkTCPEventGUID, 15) + AcceptTCPv4 = pack(NetworkTCPEventGUID, uint16(AcceptTCPv4ID)) // AcceptTCPv6 represents the TCPv6 kernel events for accepting connection requests from the socket queue. - AcceptTCPv6 = pack(NetworkTCPEventGUID, 31) + AcceptTCPv6 = pack(NetworkTCPEventGUID, uint16(AcceptTCPv6ID)) // SendTCPv4 represents the TCPv4 kernel events for sending data to the connected socket. - SendTCPv4 = pack(NetworkTCPEventGUID, 10) + SendTCPv4 = pack(NetworkTCPEventGUID, uint16(SendV4ID)) // SendTCPv6 represents the TCPv6 kernel events for sending data to the connected socket. - SendTCPv6 = pack(NetworkTCPEventGUID, 26) + SendTCPv6 = pack(NetworkTCPEventGUID, uint16(SendV6ID)) // SendUDPv4 represents the UDPv4 kernel events for sending datagrams to connectionless sockets. - SendUDPv4 = pack(NetworkUDPEventGUID, 10) + SendUDPv4 = pack(NetworkUDPEventGUID, uint16(SendV4ID)) // SendUDPv6 represents the UDPv6 kernel events for sending datagrams to connectionless sockets. - SendUDPv6 = pack(NetworkUDPEventGUID, 26) + SendUDPv6 = pack(NetworkUDPEventGUID, uint16(SendV6ID)) // RecvTCPv4 represents the TCP IPv4 network receive event. - RecvTCPv4 = pack(NetworkTCPEventGUID, 11) + RecvTCPv4 = pack(NetworkTCPEventGUID, uint16(RecvV4ID)) // RecvTCPv6 represents the TCP IPv6 network receive event. - RecvTCPv6 = pack(NetworkTCPEventGUID, 27) + RecvTCPv6 = pack(NetworkTCPEventGUID, uint16(RecvV6ID)) // RecvUDPv4 represents the UDP IPv4 network receive event. - RecvUDPv4 = pack(NetworkUDPEventGUID, 11) + RecvUDPv4 = pack(NetworkUDPEventGUID, uint16(RecvV4ID)) // RecvUDPv6 represents the UDP IPv6 network receive event. - RecvUDPv6 = pack(NetworkUDPEventGUID, 27) + RecvUDPv6 = pack(NetworkUDPEventGUID, uint16(RecvV6ID)) // ConnectTCPv4 represents the TCP IPv4 network connect event. - ConnectTCPv4 = pack(NetworkTCPEventGUID, 12) + ConnectTCPv4 = pack(NetworkTCPEventGUID, uint16(ConnectTCPv4ID)) // ConnectTCPv6 represents the TCP IPv6 network connect event. - ConnectTCPv6 = pack(NetworkTCPEventGUID, 28) + ConnectTCPv6 = pack(NetworkTCPEventGUID, uint16(ConnectTCPv6ID)) // DisconnectTCPv4 is the TCP IPv4 network disconnect event. - DisconnectTCPv4 = pack(NetworkTCPEventGUID, 13) + DisconnectTCPv4 = pack(NetworkTCPEventGUID, uint16(DisconnectTCPv4ID)) // DisconnectTCPv6 is the TCP IPv6 network disconnect event. - DisconnectTCPv6 = pack(NetworkTCPEventGUID, 29) + DisconnectTCPv6 = pack(NetworkTCPEventGUID, uint16(DisconnectTCPv6ID)) // ReconnectTCPv4 is the TCP IPv4 network reconnect event. - ReconnectTCPv4 = pack(NetworkTCPEventGUID, 16) + ReconnectTCPv4 = pack(NetworkTCPEventGUID, uint16(ReconnectTCPv4ID)) // ReconnectTCPv6 is the TCP IPv6 network reconnect event. - ReconnectTCPv6 = pack(NetworkTCPEventGUID, 32) + ReconnectTCPv6 = pack(NetworkTCPEventGUID, uint16(ReconnectTCPv6ID)) // RetransmitTCPv4 is the TCP IPv4 network retransmit event. - RetransmitTCPv4 = pack(NetworkTCPEventGUID, 14) + RetransmitTCPv4 = pack(NetworkTCPEventGUID, uint16(RetransmitTCPv4ID)) // RetransmitTCPv6 is the TCP IPv6 network retransmit event. - RetransmitTCPv6 = pack(NetworkTCPEventGUID, 30) + RetransmitTCPv6 = pack(NetworkTCPEventGUID, uint16(RetransmitTCPv6ID)) // CreateHandle represents handle creation event - CreateHandle = pack(HandleEventGUID, 32) + CreateHandle = pack(HandleEventGUID, uint16(CreateHandleID)) // CloseHandle represents handle closure event - CloseHandle = pack(HandleEventGUID, 33) + CloseHandle = pack(HandleEventGUID, uint16(CloseHandleID)) // DuplicateHandle represents handle duplication event - DuplicateHandle = pack(HandleEventGUID, 34) + DuplicateHandle = pack(HandleEventGUID, uint16(DuplicateHandleID)) // VirtualAlloc represents virtual memory allocation event - VirtualAlloc = pack(MemEventGUID, 98) + VirtualAlloc = pack(MemEventGUID, uint16(VirtualAllocID)) // VirtualFree represents virtual memory release event - VirtualFree = pack(MemEventGUID, 99) + VirtualFree = pack(MemEventGUID, uint16(VirtualFreeID)) // QueryDNS represents DNS query events - QueryDNS = pack(DNSEventGUID, 3006) + QueryDNS = pack(DNSEventGUID, QueryDNSID) // ReplyDNS represents the DNS response events - ReplyDNS = pack(DNSEventGUID, 3008) + ReplyDNS = pack(DNSEventGUID, ReplyDNSID) // StackWalk represents stack walk event with the collection of return addresses - StackWalk = pack(windows.GUID{Data1: 0xdef2fe46, Data2: 0x7bd6, Data3: 0x4b80, Data4: [8]byte{0xbd, 0x94, 0xf5, 0x7f, 0xe2, 0x0d, 0x0c, 0xe3}}, 32) + StackWalk = pack(StackWalkEventGUID, uint16(StackWalkID)) // CreateSymbolicLinkObject represents the event emitted by the object manager when the new symbolic link is created within the object manager directory - CreateSymbolicLinkObject = pack(AuditAPIEventGUID, 3) + CreateSymbolicLinkObject = pack(AuditAPIEventGUID, CreateSymbolicLinkObjectID) // SubmitThreadpoolWork represents the event that enqueues the work item to the thread pool - SubmitThreadpoolWork = pack(ThreadpoolGUID, 32) + SubmitThreadpoolWork = pack(ThreadpoolEventGUID, uint16(SubmitThreadpoolWorkID)) //SubmitThreadpoolCallback represents the event that submits the thread pool callback for execution within the work item - SubmitThreadpoolCallback = pack(ThreadpoolGUID, 34) + SubmitThreadpoolCallback = pack(ThreadpoolEventGUID, uint16(SubmitThreadpoolCallbackID)) // SetThreadpoolTimer represents the event that sets the thread pool timer object - SetThreadpoolTimer = pack(ThreadpoolGUID, 44) + SetThreadpoolTimer = pack(ThreadpoolEventGUID, uint16(SetThreadpoolTimerID)) // UnknownType designates unknown event type UnknownType = pack(windows.GUID{}, 0) @@ -609,7 +692,7 @@ func (t Type) ID() uint { // Source designates the provenance of this event type. func (t Type) Source() Source { switch t.GUID() { - case AuditAPIEventGUID, DNSEventGUID, ThreadpoolGUID, ProcessKernelEventGUID, RegistryKernelEventGUID: + case AuditAPIEventGUID, DNSEventGUID, ThreadpoolEventGUID, ProcessKernelEventGUID, RegistryKernelEventGUID: return SecurityTelemetryLogger default: return SystemLogger