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