diff --git a/cmd/fibratus/app/list/list.go b/cmd/fibratus/app/list/list.go
index 92ab1eff6..055795d7a 100644
--- a/cmd/fibratus/app/list/list.go
+++ b/cmd/fibratus/app/list/list.go
@@ -21,15 +21,16 @@ package list
import (
"bufio"
"fmt"
+ "os"
+ "path/filepath"
+ "strings"
+
"github.com/jedib0t/go-pretty/v6/table"
"github.com/rabbitstack/fibratus/internal/bootstrap"
"github.com/rabbitstack/fibratus/pkg/config"
"github.com/rabbitstack/fibratus/pkg/event"
"github.com/rabbitstack/fibratus/pkg/filter/fields"
"github.com/spf13/cobra"
- "os"
- "path/filepath"
- "strings"
)
var Command = &cobra.Command{
@@ -130,7 +131,7 @@ func listEvents(cmd *cobra.Command, args []string) {
t.AppendHeader(table.Row{"Name", "Category", "Description"})
t.SetStyle(table.StyleLight)
- for _, ev := range event.GetTypesMeta() {
+ for _, ev := range event.GetTypesInfo() {
t.AppendRow(table.Row{ev.Name, ev.Category, ev.Description})
}
diff --git a/go.mod b/go.mod
index 25f8b279b..b15fa21d4 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,6 @@ require (
github.com/Masterminds/sprig/v3 v3.2.2
github.com/Microsoft/go-winio v0.4.14
github.com/antchfx/htmlquery v1.2.5
- github.com/bits-and-blooms/bitset v1.13.0
github.com/briandowns/spinner v1.12.0
github.com/cenkalti/backoff/v4 v4.3.0
github.com/dustin/go-humanize v1.0.0
diff --git a/go.sum b/go.sum
index b3a239c3c..b1ad4f534 100644
--- a/go.sum
+++ b/go.sum
@@ -21,8 +21,6 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5
github.com/aws/aws-sdk-go v1.34.13/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
-github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
-github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/briandowns/spinner v1.12.0 h1:72O0PzqGJb6G3KgrcIOtL/JAGGZ5ptOMCn9cUHmqsmw=
github.com/briandowns/spinner v1.12.0/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
diff --git a/internal/etw/consumer.go b/internal/etw/consumer.go
index b63634970..0044309c6 100644
--- a/internal/etw/consumer.go
+++ b/internal/etw/consumer.go
@@ -78,8 +78,8 @@ func (c *Consumer) ProcessEvent(r *etw.EventRecord) error {
return nil
}
- if !c.config.EventSource.EventExists(r.ID()) {
- eventsUnknown.Add(1)
+ etype := event.NewTypeFromEventRecord(r)
+ if etype == event.Unknown {
return nil
}
if event.IsCurrentProcDropped(r.Header.ProcessID) && r.Header.ProviderID != etw.WindowsKernelProcessGUID {
@@ -92,13 +92,13 @@ func (c *Consumer) ProcessEvent(r *etw.EventRecord) error {
}
defer c.approvers.Cleanup(rec)
- if c.config.EventSource.ExcludeEvent(rec.ID()) {
+ if c.config.EventSource.ExcludeEvent(etype) {
eventsExcluded.Add(1)
return nil
}
eventsProcessed.Add(1)
- evt := event.New(c.sequencer.Get(), rec)
+ evt := event.New(c.sequencer.Get(), rec, etype)
// Dispatch each event to the processor chain.
// Processors may further augment the event with
diff --git a/internal/etw/processors/fs_windows.go b/internal/etw/processors/fs_windows.go
index 0e9a0df19..2027db94e 100644
--- a/internal/etw/processors/fs_windows.go
+++ b/internal/etw/processors/fs_windows.go
@@ -71,7 +71,7 @@ func newFsProcessor(
}
func (f *fsProcessor) ProcessEvent(e *event.Event) (*event.Event, bool, error) {
- if e.Category == event.File {
+ if e.Category() == event.File {
evt, err := f.processEvent(e)
return evt, false, err
}
@@ -100,7 +100,7 @@ func (f *fsProcessor) processEvent(e *event.Event) (*event.Event, error) {
totalRundownFiles.Add(1)
f.files[fileObject] = &FileInfo{Name: filepath, Type: fs.GetFileType(filepath, 0)}
}
- case event.MapFileRundown:
+ case event.MapViewOfSection:
fileKey := e.Params.MustGetUint64(params.FileKey)
fileinfo := f.files[fileKey]
@@ -144,7 +144,7 @@ func (f *fsProcessor) processEvent(e *event.Event) (*event.Event, error) {
// delete file metadata by file object address
fileObject := e.Params.MustGetUint64(params.FileObject)
delete(f.files, fileObject)
- case event.UnmapViewFile:
+ case event.UnmapViewOfSection:
ok, proc := f.psnap.Find(e.PID)
addr := e.Params.TryGetAddress(params.FileViewBase)
if ok {
@@ -157,11 +157,13 @@ func (f *fsProcessor) processEvent(e *event.Event) (*event.Event, error) {
totalMapRundownFiles.Add(-1)
return e, f.psnap.RemoveMmap(e.PID, addr)
+ case event.FileOpEnd:
+ return e, nil
default:
var fileObject uint64
fileKey := e.Params.MustGetUint64(params.FileKey)
- if !e.IsMapViewFile() {
+ if !e.IsMapViewOfSection() {
fileObject = e.Params.MustGetUint64(params.FileObject)
}
@@ -202,7 +204,7 @@ func (f *fsProcessor) processEvent(e *event.Event) (*event.Event, error) {
e.AppendParam(params.FilePath, params.Path, fileinfo.Name)
}
- if e.IsMapViewFile() {
+ if e.IsMapViewOfSection() {
return e, f.psnap.AddMmap(e)
}
}
diff --git a/internal/etw/processors/fs_windows_test.go b/internal/etw/processors/fs_windows_test.go
index 70b841ccd..7e593d2e4 100644
--- a/internal/etw/processors/fs_windows_test.go
+++ b/internal/etw/processors/fs_windows_test.go
@@ -46,8 +46,7 @@ func TestFsProcessor(t *testing.T) {
{
"process file rundown",
&event.Event{
- Type: event.FileRundown,
- Category: event.File,
+ Type: event.FileRundown,
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(124567380264)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\user32.dll"},
@@ -69,9 +68,8 @@ func TestFsProcessor(t *testing.T) {
{
"process mapped file rundown",
&event.Event{
- PID: 10233,
- Type: event.MapFileRundown,
- Category: event.File,
+ PID: 10233,
+ Type: event.MapViewSectionRundown,
Params: event.Params{
params.FileKey: {Name: params.FileKey, Type: params.Uint64, Value: uint64(124567380264)},
params.FileViewSize: {Name: params.FileViewSize, Type: params.Uint64, Value: uint64(3098)},
@@ -99,8 +97,7 @@ func TestFsProcessor(t *testing.T) {
{
"release file and remove file info",
&event.Event{
- Type: event.ReleaseFile,
- Category: event.File,
+ Type: event.ReleaseFile,
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(18446738026482168384)},
params.FileKey: {Name: params.FileKey, Type: params.Uint64, Value: uint64(14446538026482168384)},
@@ -122,9 +119,8 @@ func TestFsProcessor(t *testing.T) {
{
"unmap view file",
&event.Event{
- PID: 10233,
- Type: event.UnmapViewFile,
- Category: event.File,
+ PID: 10233,
+ Type: event.UnmapViewOfSection,
Params: event.Params{
params.FileKey: {Name: params.FileKey, Type: params.Uint64, Value: uint64(124567380264)},
params.FileViewSize: {Name: params.FileViewSize, Type: params.Uint64, Value: uint64(3098)},
@@ -147,8 +143,7 @@ func TestFsProcessor(t *testing.T) {
{
"process write file",
&event.Event{
- Type: event.WriteFile,
- Category: event.File,
+ Type: event.WriteFile,
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(18446738026482168384)},
params.FileKey: {Name: params.FileKey, Type: params.Uint64, Value: uint64(14446538026482168384)},
@@ -173,8 +168,7 @@ func TestFsProcessor(t *testing.T) {
{
"process write file consult handle snapshotter",
&event.Event{
- Type: event.WriteFile,
- Category: event.File,
+ Type: event.WriteFile,
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(18446738026482168384)},
params.FileKey: {Name: params.FileKey, Type: params.Uint64, Value: uint64(14446538026482168384)},
@@ -198,8 +192,7 @@ func TestFsProcessor(t *testing.T) {
{
"process enum directory",
&event.Event{
- Type: event.EnumDirectory,
- Category: event.File,
+ Type: event.EnumDirectory,
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(18446738026482168384)},
params.FileKey: {Name: params.FileKey, Type: params.Uint64, Value: uint64(14446538026482168384)},
diff --git a/internal/etw/processors/mem_windows.go b/internal/etw/processors/memory_windows.go
similarity index 98%
rename from internal/etw/processors/mem_windows.go
rename to internal/etw/processors/memory_windows.go
index 2e51c4c49..4149a9947 100644
--- a/internal/etw/processors/mem_windows.go
+++ b/internal/etw/processors/memory_windows.go
@@ -48,7 +48,7 @@ func (m memProcessor) Close() {
}
func (m memProcessor) ProcessEvent(e *event.Event) (*event.Event, bool, error) {
- if e.Category == event.Mem {
+ if e.Category() == event.Memory {
pid := e.Params.MustGetPid()
if e.IsVirtualAlloc() {
// retrieve info about the range of pages and enrich the event
diff --git a/internal/etw/processors/mem_windows_test.go b/internal/etw/processors/memory_windows_test.go
similarity index 97%
rename from internal/etw/processors/mem_windows_test.go
rename to internal/etw/processors/memory_windows_test.go
index dcf666b3e..ef671833e 100644
--- a/internal/etw/processors/mem_windows_test.go
+++ b/internal/etw/processors/memory_windows_test.go
@@ -19,6 +19,9 @@
package processors
import (
+ "os"
+ "testing"
+
"github.com/rabbitstack/fibratus/pkg/event"
"github.com/rabbitstack/fibratus/pkg/event/params"
"github.com/rabbitstack/fibratus/pkg/ps"
@@ -28,8 +31,6 @@ import (
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"golang.org/x/sys/windows"
- "os"
- "testing"
)
func TestMemProcessor(t *testing.T) {
@@ -47,8 +48,7 @@ func TestMemProcessor(t *testing.T) {
{
"virtual alloc",
&event.Event{
- Type: event.VirtualAlloc,
- Category: event.Mem,
+ Type: event.VirtualAlloc,
Params: event.Params{
params.MemRegionSize: {Name: params.MemRegionSize, Type: params.Uint64, Value: uint64(1024)},
params.MemBaseAddress: {Name: params.MemBaseAddress, Type: params.Address, Value: uint64(base)},
@@ -73,8 +73,7 @@ func TestMemProcessor(t *testing.T) {
{
"virtual free",
&event.Event{
- Type: event.VirtualFree,
- Category: event.Mem,
+ Type: event.VirtualFree,
Params: event.Params{
params.MemRegionSize: {Name: params.MemRegionSize, Type: params.Uint64, Value: uint64(1024)},
params.MemBaseAddress: {Name: params.MemBaseAddress, Type: params.Address, Value: uint64(base)},
diff --git a/internal/etw/processors/net_windows.go b/internal/etw/processors/net_windows.go
index a09001f2b..4c32f955e 100644
--- a/internal/etw/processors/net_windows.go
+++ b/internal/etw/processors/net_windows.go
@@ -21,7 +21,6 @@ package processors
import (
"github.com/rabbitstack/fibratus/pkg/event"
"github.com/rabbitstack/fibratus/pkg/event/params"
- "github.com/rabbitstack/fibratus/pkg/network"
"github.com/rabbitstack/fibratus/pkg/util/ports"
)
@@ -38,14 +37,7 @@ func (netProcessor) Name() ProcessorType { return Net }
func (n netProcessor) Close() {}
func (n *netProcessor) ProcessEvent(e *event.Event) (*event.Event, bool, error) {
- if e.Category == event.Net {
- if e.IsNetworkTCP() && !e.IsDNS() {
- e.AppendEnum(params.NetL4Proto, uint32(network.TCP), network.ProtoNames)
- }
- if e.IsNetworkUDP() && !e.IsDNS() {
- e.AppendEnum(params.NetL4Proto, uint32(network.UDP), network.ProtoNames)
- }
-
+ if e.Category() == event.Network {
if e.IsDNS() {
return e, false, nil
}
diff --git a/internal/etw/processors/net_windows_test.go b/internal/etw/processors/net_windows_test.go
index 6f6e36bc0..94247b8df 100644
--- a/internal/etw/processors/net_windows_test.go
+++ b/internal/etw/processors/net_windows_test.go
@@ -19,12 +19,14 @@
package processors
import (
+ "net"
+ "testing"
+
"github.com/rabbitstack/fibratus/pkg/event"
"github.com/rabbitstack/fibratus/pkg/event/params"
+ "github.com/rabbitstack/fibratus/pkg/network"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "net"
- "testing"
)
func TestNetworkProcessor(t *testing.T) {
@@ -36,13 +38,13 @@ func TestNetworkProcessor(t *testing.T) {
{
"send tcpv4",
&event.Event{
- Type: event.SendTCPv4,
- Category: event.Net,
+ Type: event.Send,
Params: event.Params{
- params.NetDport: {Name: params.NetDport, Type: params.Uint16, Value: uint16(443)},
- params.NetSport: {Name: params.NetSport, Type: params.Uint16, Value: uint16(43123)},
- params.NetSIP: {Name: params.NetSIP, Type: params.IPv4, Value: net.ParseIP("127.0.0.1")},
- params.NetDIP: {Name: params.NetDIP, Type: params.IPv4, Value: net.ParseIP("8.8.8.8")},
+ params.NetDport: {Name: params.NetDport, Type: params.Uint16, Value: uint16(443)},
+ params.NetSport: {Name: params.NetSport, Type: params.Uint16, Value: uint16(43123)},
+ params.NetSIP: {Name: params.NetSIP, Type: params.IPv4, Value: net.ParseIP("127.0.0.1")},
+ params.NetDIP: {Name: params.NetDIP, Type: params.IPv4, Value: net.ParseIP("8.8.8.8")},
+ params.NetL4Proto: {Name: params.NetL4Proto, Type: params.Enum, Value: uint32(network.TCP), Enum: network.ProtoNames},
},
},
func(e *event.Event, t *testing.T) {
@@ -58,13 +60,13 @@ func TestNetworkProcessor(t *testing.T) {
{
"recv udp6",
&event.Event{
- Type: event.RecvUDPv6,
- Category: event.Net,
+ Type: event.Recv,
Params: event.Params{
- params.NetDport: {Name: params.NetDport, Type: params.Uint16, Value: uint16(53)},
- params.NetSport: {Name: params.NetSport, Type: params.Uint16, Value: uint16(43123)},
- params.NetSIP: {Name: params.NetSIP, Type: params.IPv4, Value: net.ParseIP("127.0.0.1")},
- params.NetDIP: {Name: params.NetDIP, Type: params.IPv4, Value: net.ParseIP("8.8.8.8")},
+ params.NetDport: {Name: params.NetDport, Type: params.Uint16, Value: uint16(53)},
+ params.NetSport: {Name: params.NetSport, Type: params.Uint16, Value: uint16(43123)},
+ params.NetSIP: {Name: params.NetSIP, Type: params.IPv4, Value: net.ParseIP("127.0.0.1")},
+ params.NetDIP: {Name: params.NetDIP, Type: params.IPv4, Value: net.ParseIP("8.8.8.8")},
+ params.NetL4Proto: {Name: params.NetL4Proto, Type: params.Enum, Value: uint32(network.UDP), Enum: network.ProtoNames},
},
},
func(e *event.Event, t *testing.T) {
diff --git a/internal/etw/processors/registry_windows.go b/internal/etw/processors/registry_windows.go
index d3979493f..87b25a579 100644
--- a/internal/etw/processors/registry_windows.go
+++ b/internal/etw/processors/registry_windows.go
@@ -102,7 +102,7 @@ func newRegistryProcessor(hsnap handle.Snapshotter) Processor {
}
func (r *registryProcessor) ProcessEvent(e *event.Event) (*event.Event, bool, error) {
- if e.Category == event.Registry {
+ if e.Category() == event.Registry {
evt, err := r.processEvent(e)
return evt, false, err
}
diff --git a/internal/etw/processors/registry_windows_test.go b/internal/etw/processors/registry_windows_test.go
index 25fd6aa7e..9b75d879c 100644
--- a/internal/etw/processors/registry_windows_test.go
+++ b/internal/etw/processors/registry_windows_test.go
@@ -47,8 +47,7 @@ func TestRegistryProcessor(t *testing.T) {
{
"process KCB rundown",
&event.Event{
- Type: event.RegKCBRundown,
- Category: event.Registry,
+ Type: event.RegKCBRundown,
Params: event.Params{
params.RegPath: {Name: params.RegPath, Type: params.UnicodeString, Value: `\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services\bthserv\Parameters`},
params.RegKCB: {Name: params.RegKCB, Type: params.Uint64, Value: uint64(18446666033549154696)},
@@ -68,8 +67,7 @@ func TestRegistryProcessor(t *testing.T) {
{
"process delete KCB",
&event.Event{
- Type: event.RegDeleteKCB,
- Category: event.Registry,
+ Type: event.RegDeleteKCB,
Params: event.Params{
params.RegPath: {Name: params.RegPath, Type: params.UnicodeString, Value: `\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services\bthserv\Parameters`},
params.RegKCB: {Name: params.RegKCB, Type: params.Uint64, Value: uint64(18446666033549154696)},
@@ -90,8 +88,7 @@ func TestRegistryProcessor(t *testing.T) {
{
"full key name",
&event.Event{
- Type: event.RegOpenKey,
- Category: event.Registry,
+ Type: event.RegOpenKey,
Params: event.Params{
params.RegPath: {Name: params.RegPath, Type: params.Key, Value: `\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services\bthserv\Parameters`},
params.RegKCB: {Name: params.RegKCB, Type: params.Uint64, Value: uint64(0)},
@@ -109,8 +106,7 @@ func TestRegistryProcessor(t *testing.T) {
{
"incomplete key name",
&event.Event{
- Type: event.RegOpenKey,
- Category: event.Registry,
+ Type: event.RegOpenKey,
Params: event.Params{
params.RegPath: {Name: params.RegPath, Type: params.Key, Value: `Pid`},
params.RegKCB: {Name: params.RegKCB, Type: params.Uint64, Value: uint64(18446666033549154696)},
@@ -130,9 +126,8 @@ func TestRegistryProcessor(t *testing.T) {
{
"incomplete key name consult handle snapshotter",
&event.Event{
- Type: event.RegOpenKey,
- Category: event.Registry,
- PID: 23234,
+ Type: event.RegOpenKey,
+ PID: 23234,
Params: event.Params{
params.RegPath: {Name: params.RegPath, Type: params.Key, Value: `Pid`},
params.RegKCB: {Name: params.RegKCB, Type: params.Uint64, Value: uint64(18446666033549154696)},
@@ -153,9 +148,8 @@ func TestRegistryProcessor(t *testing.T) {
{
"process registry set value",
&event.Event{
- Type: event.RegSetValue,
- Category: event.Registry,
- PID: 23234,
+ Type: event.RegSetValue,
+ PID: 23234,
Params: event.Params{
params.RegPath: {Name: params.RegPath, Type: params.Key, Value: `\REGISTRY\MACHINE\SYSTEM\CurrentControlSet\Control\Windows\Directory`},
params.RegKCB: {Name: params.RegKCB, Type: params.Uint64, Value: uint64(0)},
@@ -175,9 +169,8 @@ func TestRegistryProcessor(t *testing.T) {
{
"process registry set value from internal event",
&event.Event{
- Type: event.RegSetValue,
- Category: event.Registry,
- PID: 23234,
+ Type: event.RegSetValue,
+ PID: 23234,
Params: event.Params{
params.RegPath: {Name: params.RegPath, Type: params.Key, Value: `\REGISTRY\MACHINE\SYSTEM\CurrentControlSet\Control\Windows\Directory`},
params.RegKCB: {Name: params.RegKCB, Type: params.Uint64, Value: uint64(0)},
diff --git a/internal/etw/source.go b/internal/etw/source.go
index 65376cac4..db0924c0a 100644
--- a/internal/etw/source.go
+++ b/internal/etw/source.go
@@ -60,8 +60,6 @@ var (
eventsFailed = expvar.NewMap("eventsource.events.failed")
// eventsProcessed counts the number of total processed events
eventsProcessed = expvar.NewInt("eventsource.events.processed")
- // eventsUnknown counts the number of published events which types are not present in the internal catalog
- eventsUnknown = expvar.NewInt("eventsource.events.unknown")
// eventsExcluded counts the number of excluded events
eventsExcluded = expvar.NewInt("eventsource.events.excluded")
// buffersRead amount of buffers fetched from the ETW session
@@ -138,7 +136,11 @@ func (e *EventSource) Open(config *config.Config) error {
config.EventSource.EnableMemEvents = config.EventSource.EnableMemEvents && (e.r.HasMemEvents || (config.Yara.Enabled && !config.Yara.SkipAllocs))
config.EventSource.EnableDNSEvents = config.EventSource.EnableDNSEvents && e.r.HasDNSEvents
config.EventSource.EnableAuditAPIEvents = config.EventSource.EnableAuditAPIEvents && e.r.HasAuditAPIEvents
- for _, typ := range event.All() {
+
+ for _, typ := range event.AllTypes() {
+ if typ.OnlyState() || typ.StateSnapshot() {
+ continue
+ }
if typ == event.CreateProcess || typ == event.TerminateProcess ||
typ == event.LoadModule || typ == event.UnloadModule {
// always allow fundamental events
@@ -146,7 +148,7 @@ func (e *EventSource) Open(config *config.Config) error {
}
// allow events required for memory/file scanning
- if typ == event.MapViewFile && config.Yara.Enabled && !config.Yara.SkipMmaps {
+ if typ == event.MapViewOfSection && config.Yara.Enabled && !config.Yara.SkipMmaps {
continue
}
if typ == event.VirtualAlloc && config.Yara.Enabled && !config.Yara.SkipAllocs {
@@ -179,13 +181,10 @@ func (e *EventSource) Open(config *config.Config) error {
// modified value. This data is used to attach various parameters
// to the RegSetValue event published by the NT Kernel Logger
if config.EventSource.EnableRegistryEvents {
- // undocumented ETW feature to enable captured data in RegSetValue events
- val := 0x2
- eventFilterDescriptor := etw.EventFilterDescriptor{
- Ptr: uintptr(unsafe.Pointer(&val)),
+ trace.AddProvider(etw.WindowsKernelRegistryGUID, false, WithKeywords(etw.SetValueKeyword), WithEventFilterDescriptors(etw.EventFilterDescriptor{
+ Ptr: uintptr(unsafe.Pointer(&etw.CaptureRegistryValue)),
Size: 4,
- }
- trace.AddProvider(etw.WindowsKernelRegistryGUID, false, WithKeywords(etw.SetValueKeyword), WithEventFilterDescriptors(eventFilterDescriptor))
+ }))
}
if config.EventSource.EnableDNSEvents {
diff --git a/internal/etw/source_test.go b/internal/etw/source_test.go
index 8582d0479..319b6230e 100644
--- a/internal/etw/source_test.go
+++ b/internal/etw/source_test.go
@@ -180,9 +180,9 @@ func TestEventSourceEnableFlagsDynamically(t *testing.T) {
event.RegSetValue,
event.CreateFile,
event.RenameFile,
- event.MapViewFile,
+ event.MapViewOfSection,
event.OpenProcess,
- event.ConnectTCPv4,
+ event.Connect,
},
}
cfg := &config.Config{
@@ -222,7 +222,7 @@ func TestEventSourceEnableFlagsDynamically(t *testing.T) {
require.False(t, cfg.EventSource.TestDropMask(event.UnloadModule))
require.True(t, cfg.EventSource.TestDropMask(event.WriteFile))
- require.True(t, cfg.EventSource.TestDropMask(event.UnmapViewFile))
+ require.True(t, cfg.EventSource.TestDropMask(event.UnmapViewOfSection))
require.False(t, cfg.EventSource.TestDropMask(event.OpenProcess))
}
@@ -259,7 +259,7 @@ func TestEventSourceEnableFlagsDynamicallyWithYaraEnabled(t *testing.T) {
event.RegSetValue,
event.RenameFile,
event.OpenProcess,
- event.ConnectTCPv4,
+ event.Connect,
},
}
cfg := &config.Config{
@@ -300,7 +300,7 @@ func TestEventSourceEnableFlagsDynamicallyWithYaraEnabled(t *testing.T) {
require.True(t, flags&etw.VirtualAlloc != 0)
require.False(t, cfg.EventSource.TestDropMask(event.CreateFile))
- require.True(t, cfg.EventSource.TestDropMask(event.MapViewFile))
+ require.True(t, cfg.EventSource.TestDropMask(event.MapViewOfSection))
require.False(t, cfg.EventSource.TestDropMask(event.VirtualAlloc))
}
@@ -481,7 +481,7 @@ func TestEventSourceAllEvents(t *testing.T) {
return nil
},
func(e *event.Event) bool {
- return e.CurrentPid() && (e.Type == event.ConnectTCPv4 || e.Type == event.ConnectTCPv6)
+ return e.CurrentPid() && e.Type == event.Connect
},
false,
},
@@ -534,7 +534,7 @@ func TestEventSourceAllEvents(t *testing.T) {
return nil
},
func(e *event.Event) bool {
- return e.CurrentPid() && e.Type == event.MapViewFile &&
+ return e.CurrentPid() && e.Type == event.MapViewOfSection &&
e.GetParamAsString(params.MemProtect) == "EXECUTE_READWRITE|READONLY" &&
e.GetParamAsString(params.FileViewSectionType) == "IMAGE"
},
@@ -581,7 +581,7 @@ func TestEventSourceAllEvents(t *testing.T) {
return sys.NtUnmapViewOfSection(windows.CurrentProcess(), viewBase)
},
func(e *event.Event) bool {
- return e.CurrentPid() && e.Type == event.UnmapViewFile &&
+ return e.CurrentPid() && e.Type == event.UnmapViewOfSection &&
e.GetParamAsString(params.MemProtect) == "READONLY" &&
e.Params.MustGetUint64(params.FileViewBase) == uint64(viewBase)
},
@@ -629,7 +629,7 @@ func TestEventSourceAllEvents(t *testing.T) {
},
func(e *event.Event) bool {
return e.CurrentPid() && e.Type == event.QueryDNS && e.IsDNS() &&
- e.Type.Subcategory() == event.DNS &&
+ e.Subcategory() == event.DNS &&
e.GetParamAsString(params.DNSName) == "dns.google" &&
e.GetParamAsString(params.DNSRR) == "A"
},
@@ -643,7 +643,7 @@ func TestEventSourceAllEvents(t *testing.T) {
},
func(e *event.Event) bool {
return e.CurrentPid() && e.Type == event.ReplyDNS && e.IsDNS() &&
- e.Type.Subcategory() == event.DNS &&
+ e.Subcategory() == event.DNS &&
e.GetParamAsString(params.DNSName) == "dns.google" &&
e.GetParamAsString(params.DNSRR) == "AAAA" &&
e.GetParamAsString(params.DNSRcode) == "NOERROR" &&
diff --git a/internal/etw/stackext.go b/internal/etw/stackext.go
index a210e3770..8bbde214b 100644
--- a/internal/etw/stackext.go
+++ b/internal/etw/stackext.go
@@ -22,7 +22,6 @@ import (
"github.com/rabbitstack/fibratus/pkg/config"
"github.com/rabbitstack/fibratus/pkg/event"
"github.com/rabbitstack/fibratus/pkg/sys/etw"
- "golang.org/x/sys/windows"
)
// StackExtensions manages stack tracing enablement
@@ -39,15 +38,8 @@ func NewStackExtensions(config config.EventSourceConfig) *StackExtensions {
// AddStackTracing enables stack tracing for the specified event type.
func (s *StackExtensions) AddStackTracing(typ event.Type) {
- if !s.config.TestDropMask(typ) {
- s.ids = append(s.ids, etw.NewClassicEventID(typ.GUID(), typ.HookID()))
- }
-}
-
-// AddStackTracingWith enables stack tracing for the specified provider GUID and event hook id.
-func (s *StackExtensions) AddStackTracingWith(guid windows.GUID, hookID uint16) {
- if !s.config.TestDropMask(event.TypeFromParts(guid, hookID)) {
- s.ids = append(s.ids, etw.NewClassicEventID(guid, hookID))
+ if !s.config.TestDropMask(typ) && !typ.EventID().IsEmpty() {
+ s.ids = append(s.ids, typ.EventID())
}
}
@@ -69,7 +61,7 @@ func (s *StackExtensions) EnableProcessCallstack() {
s.AddStackTracing(event.TerminateThread)
}
if s.config.EnableModuleEvents {
- s.AddStackTracingWith(event.ProcessEventGUID, event.LoadModule.HookID())
+ s.AddStackTracing(event.LoadModule)
}
}
diff --git a/internal/etw/stackext_test.go b/internal/etw/stackext_test.go
index 48b92b2b1..0833f55ec 100644
--- a/internal/etw/stackext_test.go
+++ b/internal/etw/stackext_test.go
@@ -19,12 +19,13 @@
package etw
import (
+ "testing"
+ "time"
+
"github.com/rabbitstack/fibratus/pkg/config"
"github.com/rabbitstack/fibratus/pkg/event"
"github.com/rabbitstack/fibratus/pkg/sys/etw"
"github.com/stretchr/testify/assert"
- "testing"
- "time"
)
func TestStackExtensions(t *testing.T) {
@@ -50,11 +51,11 @@ func TestStackExtensions(t *testing.T) {
exts.EnableMemoryCallstack()
assert.Len(t, exts.EventIds(), 7)
- assert.Contains(t, exts.EventIds(), etw.ClassicEventID{GUID: event.ProcessEventGUID, Type: uint8(event.CreateProcess.HookID())})
- assert.Contains(t, exts.EventIds(), etw.ClassicEventID{GUID: event.ThreadEventGUID, Type: uint8(event.CreateThread.HookID())})
- assert.Contains(t, exts.EventIds(), etw.ClassicEventID{GUID: event.ThreadEventGUID, Type: uint8(event.TerminateThread.HookID())})
- assert.Contains(t, exts.EventIds(), etw.ClassicEventID{GUID: event.FileEventGUID, Type: uint8(event.CreateFile.HookID())})
- assert.Contains(t, exts.EventIds(), etw.ClassicEventID{GUID: event.FileEventGUID, Type: uint8(event.RenameFile.HookID())})
- assert.Contains(t, exts.EventIds(), etw.ClassicEventID{GUID: event.FileEventGUID, Type: uint8(event.DeleteFile.HookID())})
- assert.Contains(t, exts.EventIds(), etw.ClassicEventID{GUID: event.MemEventGUID, Type: uint8(event.VirtualAlloc.HookID())})
+ assert.Contains(t, exts.EventIds(), etw.ClassicEventID{GUID: event.ProcessEventGUID, Type: event.CreateProcessID})
+ assert.Contains(t, exts.EventIds(), etw.ClassicEventID{GUID: event.ThreadEventGUID, Type: event.CreateThreadID})
+ assert.Contains(t, exts.EventIds(), etw.ClassicEventID{GUID: event.ThreadEventGUID, Type: event.TerminateThreadID})
+ assert.Contains(t, exts.EventIds(), etw.ClassicEventID{GUID: event.FileEventGUID, Type: event.CreateFileID})
+ assert.Contains(t, exts.EventIds(), etw.ClassicEventID{GUID: event.FileEventGUID, Type: event.RenameFileID})
+ assert.Contains(t, exts.EventIds(), etw.ClassicEventID{GUID: event.FileEventGUID, Type: event.DeleteFileID})
+ assert.Contains(t, exts.EventIds(), etw.ClassicEventID{GUID: event.MemoryEventGUID, Type: event.VirtualAllocID})
}
diff --git a/internal/evasion/direct_syscall_test.go b/internal/evasion/direct_syscall_test.go
index 80a394b73..097264317 100644
--- a/internal/evasion/direct_syscall_test.go
+++ b/internal/evasion/direct_syscall_test.go
@@ -19,13 +19,14 @@
package evasion
import (
+ "testing"
+ "time"
+
"github.com/rabbitstack/fibratus/pkg/callstack"
"github.com/rabbitstack/fibratus/pkg/event"
"github.com/rabbitstack/fibratus/pkg/event/params"
"github.com/rabbitstack/fibratus/pkg/fs"
"github.com/stretchr/testify/require"
- "testing"
- "time"
)
func TestDirectSyscall(t *testing.T) {
@@ -39,9 +40,7 @@ func TestDirectSyscall(t *testing.T) {
PID: 859,
CPU: 1,
Seq: 2,
- Name: "CreateFile",
Timestamp: time.Now(),
- Category: event.File,
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\user32.dll"},
@@ -60,9 +59,7 @@ func TestDirectSyscall(t *testing.T) {
PID: 859,
CPU: 1,
Seq: 2,
- Name: "CreateFile",
Timestamp: time.Now(),
- Category: event.File,
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\user32.dll"},
@@ -82,9 +79,7 @@ func TestDirectSyscall(t *testing.T) {
PID: 859,
CPU: 1,
Seq: 2,
- Name: "CreateFile",
Timestamp: time.Now(),
- Category: event.File,
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\user32.dll"},
@@ -104,9 +99,7 @@ func TestDirectSyscall(t *testing.T) {
PID: 859,
CPU: 1,
Seq: 2,
- Name: "CreateFile",
Timestamp: time.Now(),
- Category: event.File,
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\user32.dll"},
@@ -123,7 +116,7 @@ func TestDirectSyscall(t *testing.T) {
}
for _, tt := range tests {
- t.Run(tt.evt.Name, func(t *testing.T) {
+ t.Run(tt.evt.Name(), func(t *testing.T) {
eva := NewDirectSyscall()
matches, err := eva.Eval(tt.evt)
require.NoError(t, err)
diff --git a/internal/evasion/indirect_syscall_test.go b/internal/evasion/indirect_syscall_test.go
index 7b07a655d..d8d7881f8 100644
--- a/internal/evasion/indirect_syscall_test.go
+++ b/internal/evasion/indirect_syscall_test.go
@@ -45,9 +45,7 @@ func TestIndirectSyscall(t *testing.T) {
PID: 859,
CPU: 1,
Seq: 2,
- Name: "CreateFile",
Timestamp: time.Now(),
- Category: event.File,
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\user32.dll"},
@@ -73,9 +71,7 @@ func TestIndirectSyscall(t *testing.T) {
PID: 859,
CPU: 1,
Seq: 2,
- Name: "SetThreadContext",
Timestamp: time.Now(),
- Category: event.Thread,
PS: &pstypes.PS{
Modules: []pstypes.Module{
{Name: "C:\\Windows\\System32\\ntdll.dll", Size: 32358, Checksum: 23123343, BaseAddress: getNtdllAddress(), DefaultBaseAddress: getNtdllAddress()},
@@ -96,9 +92,7 @@ func TestIndirectSyscall(t *testing.T) {
PID: 859,
CPU: 1,
Seq: 2,
- Name: "CreateFile",
Timestamp: time.Now(),
- Category: event.File,
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\user32.dll"},
@@ -115,7 +109,7 @@ func TestIndirectSyscall(t *testing.T) {
}
for _, tt := range tests {
- t.Run(tt.evt.Name, func(t *testing.T) {
+ t.Run(tt.evt.Name(), func(t *testing.T) {
eva := NewIndirectSyscall()
matches, err := eva.Eval(tt.evt)
require.NoError(t, err)
diff --git a/internal/evasion/scanner_test.go b/internal/evasion/scanner_test.go
index 1cf73a887..19d5b84fa 100644
--- a/internal/evasion/scanner_test.go
+++ b/internal/evasion/scanner_test.go
@@ -41,9 +41,7 @@ func TestScannerProcessEvent(t *testing.T) {
PID: 859,
CPU: 1,
Seq: 2,
- Name: "CreateFile",
Timestamp: time.Now(),
- Category: event.File,
Metadata: event.Metadata{},
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
diff --git a/pkg/aggregator/aggregator_test.go b/pkg/aggregator/aggregator_test.go
index b48b1a50b..39e5fd679 100644
--- a/pkg/aggregator/aggregator_test.go
+++ b/pkg/aggregator/aggregator_test.go
@@ -19,15 +19,16 @@
package aggregator
import (
+ "net"
+ "testing"
+ "time"
+
"github.com/rabbitstack/fibratus/pkg/event"
"github.com/rabbitstack/fibratus/pkg/event/params"
"github.com/rabbitstack/fibratus/pkg/outputs"
"github.com/rabbitstack/fibratus/pkg/outputs/console"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "net"
- "testing"
- "time"
)
func TestNewBufferedAggregator(t *testing.T) {
@@ -46,7 +47,7 @@ func TestNewBufferedAggregator(t *testing.T) {
for i := 0; i < 4; i++ {
evt := &event.Event{
- Type: event.SendTCPv4,
+ Type: event.Send,
Tid: 2484,
PID: 859,
Params: event.Params{
@@ -63,7 +64,7 @@ func TestNewBufferedAggregator(t *testing.T) {
for i := 0; i < 2; i++ {
evt := &event.Event{
- Type: event.SendTCPv4,
+ Type: event.Send,
Tid: 2484,
PID: 859,
Seq: uint64(i),
diff --git a/pkg/aggregator/transformers/remove/remove_test.go b/pkg/aggregator/transformers/remove/remove_test.go
index 0e114be1a..3add65007 100644
--- a/pkg/aggregator/transformers/remove/remove_test.go
+++ b/pkg/aggregator/transformers/remove/remove_test.go
@@ -19,18 +19,19 @@
package remove
import (
+ "net"
+ "testing"
+
"github.com/rabbitstack/fibratus/pkg/aggregator/transformers"
"github.com/rabbitstack/fibratus/pkg/event"
"github.com/rabbitstack/fibratus/pkg/event/params"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "net"
- "testing"
)
func TestTransform(t *testing.T) {
evt := &event.Event{
- Type: event.SendTCPv4,
+ Type: event.Send,
Tid: 2484,
PID: 859,
Params: event.Params{
diff --git a/pkg/aggregator/transformers/rename/rename_test.go b/pkg/aggregator/transformers/rename/rename_test.go
index 8a90259f4..d4cc20dd4 100644
--- a/pkg/aggregator/transformers/rename/rename_test.go
+++ b/pkg/aggregator/transformers/rename/rename_test.go
@@ -19,18 +19,19 @@
package rename
import (
+ "net"
+ "testing"
+
"github.com/rabbitstack/fibratus/pkg/aggregator/transformers"
"github.com/rabbitstack/fibratus/pkg/event"
"github.com/rabbitstack/fibratus/pkg/event/params"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "net"
- "testing"
)
func TestTransform(t *testing.T) {
evt := &event.Event{
- Type: event.SendTCPv4,
+ Type: event.Send,
Tid: 2484,
PID: 859,
Params: event.Params{
diff --git a/pkg/aggregator/transformers/tags/tags_test.go b/pkg/aggregator/transformers/tags/tags_test.go
index 4d3a84cf4..c6a161daf 100644
--- a/pkg/aggregator/transformers/tags/tags_test.go
+++ b/pkg/aggregator/transformers/tags/tags_test.go
@@ -32,7 +32,7 @@ import (
func TestTransform(t *testing.T) {
evt := &event.Event{
- Type: event.SendTCPv4,
+ Type: event.Send,
Tid: 2484,
PID: 859,
Params: event.Params{
diff --git a/pkg/aggregator/transformers/trim/trim_test.go b/pkg/aggregator/transformers/trim/trim_test.go
index 43270822b..b5dfa31bd 100644
--- a/pkg/aggregator/transformers/trim/trim_test.go
+++ b/pkg/aggregator/transformers/trim/trim_test.go
@@ -19,26 +19,24 @@
package trim
import (
+ "testing"
+ "time"
+
"github.com/rabbitstack/fibratus/pkg/aggregator/transformers"
"github.com/rabbitstack/fibratus/pkg/event"
"github.com/rabbitstack/fibratus/pkg/event/params"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "testing"
- "time"
)
func TestTransform(t *testing.T) {
evt := &event.Event{
- Type: event.CreateFile,
- Tid: 2484,
- PID: 859,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Category: event.File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: event.CreateFile,
+ Tid: 2484,
+ PID: 859,
+ CPU: 1,
+ Seq: 2,
+ Host: "archrabbit",
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "\\Device\\HarddiskVolume2\\Windows\\system32\\user32.dll"},
diff --git a/pkg/alertsender/alert.go b/pkg/alertsender/alert.go
index eebb3a43b..a785cc9b8 100644
--- a/pkg/alertsender/alert.go
+++ b/pkg/alertsender/alert.go
@@ -267,8 +267,8 @@ func (a Alert) MarshalJSON() ([]byte, error) {
Ancestors []string `json:"ancestors"`
} `json:"proc,omitempty"`
}{
- Name: e.Name,
- Category: string(e.Category),
+ Name: e.Name(),
+ Category: e.Category().String(),
Timestamp: e.Timestamp,
Params: make(map[string]any),
Callstack: make([]string, 0, len(e.Callstack)),
diff --git a/pkg/alertsender/alert_test.go b/pkg/alertsender/alert_test.go
index 2e7b5b08d..4425badfa 100644
--- a/pkg/alertsender/alert_test.go
+++ b/pkg/alertsender/alert_test.go
@@ -46,13 +46,11 @@ func TestAlertString(t *testing.T) {
},
{
NewAlertWithEvents("Credential discovery via VaultCmd.exe", "Suspicious vault enumeration via VaultCmd tool", nil, Normal, []*event.Event{{
- Type: event.CreateProcess,
- Category: event.Process,
+ Type: event.CreateProcess,
Params: event.Params{
params.Cmdline: {Name: params.Cmdline, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\svchost-fake.exe -k RPCSS"},
params.ProcessName: {Name: params.ProcessName, Type: params.AnsiString, Value: "svchost-fake.exe"}},
- Name: "CreateProcess",
- PID: 1023,
+ PID: 1023,
PS: &pstypes.PS{
Name: "svchost.exe",
Cmdline: "C:\\Windows\\System32\\svchost.exe",
@@ -68,13 +66,11 @@ func TestAlertString(t *testing.T) {
},
{
NewAlertWithEvents("Credential discovery via VaultCmd.exe", "", nil, Normal, []*event.Event{{
- Type: event.CreateProcess,
- Category: event.Process,
+ Type: event.CreateProcess,
Params: event.Params{
params.Cmdline: {Name: params.Cmdline, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\svchost-fake.exe -k RPCSS"},
params.ProcessName: {Name: params.ProcessName, Type: params.AnsiString, Value: "svchost-fake.exe"}},
- Name: "CreateProcess",
- PID: 1023,
+ PID: 1023,
PS: &pstypes.PS{
Name: "svchost.exe",
Cmdline: "C:\\Windows\\System32\\svchost.exe",
@@ -99,13 +95,11 @@ func TestAlertString(t *testing.T) {
func TestAlertJSON(t *testing.T) {
alert := NewAlertWithEvents("Credential discovery via VaultCmd.exe", "Suspicious vault enumeration via VaultCmd tool", nil, Normal, []*event.Event{{
- Type: event.CreateProcess,
- Category: event.Process,
+ Type: event.CreateProcess,
Params: event.Params{
params.Cmdline: {Name: params.Cmdline, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\svchost-fake.exe -k RPCSS"},
params.ProcessName: {Name: params.ProcessName, Type: params.AnsiString, Value: "svchost-fake.exe"}},
- Name: "CreateProcess",
- PID: 1023,
+ PID: 1023,
PS: &pstypes.PS{
Name: "svchost.exe",
Cmdline: "C:\\Windows\\System32\\svchost.exe",
diff --git a/pkg/alertsender/eventlog/eventlog_test.go b/pkg/alertsender/eventlog/eventlog_test.go
index 0d9ae3891..7b765d7f2 100644
--- a/pkg/alertsender/eventlog/eventlog_test.go
+++ b/pkg/alertsender/eventlog/eventlog_test.go
@@ -41,16 +41,13 @@ func TestEventlogSender(t *testing.T) {
require.NoError(t, s.Send(alertsender.Alert{
Events: []*event.Event{
{
- Type: event.CreateFile,
- Tid: 2484,
- PID: 859,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Timestamp: time.Now(),
- Category: event.File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: event.CreateFile,
+ Tid: 2484,
+ PID: 859,
+ CPU: 1,
+ Seq: 2,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\user32.dll"},
@@ -136,16 +133,13 @@ func TestEventlogSender(t *testing.T) {
},
},
{
- Type: event.CreateProcess,
- Tid: 2184,
- PID: 1022,
- CPU: 2,
- Seq: 3,
- Name: "CreateProcess",
- Timestamp: time.Now(),
- Category: event.File,
- Host: "archrabbit",
- Description: "Creates a new process",
+ Type: event.CreateProcess,
+ Tid: 2184,
+ PID: 1022,
+ CPU: 2,
+ Seq: 3,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: event.Params{
params.Cmdline: {Name: params.Cmdline, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\svchost.exe -k RPCSS"},
params.Exe: {Name: params.Exe, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\svchost.exe"},
diff --git a/pkg/alertsender/mail/renderer_test.go b/pkg/alertsender/mail/renderer_test.go
index 751244347..e5438d3a9 100644
--- a/pkg/alertsender/mail/renderer_test.go
+++ b/pkg/alertsender/mail/renderer_test.go
@@ -19,6 +19,10 @@
package mail
import (
+ "strings"
+ "testing"
+ "time"
+
"github.com/antchfx/htmlquery"
"github.com/rabbitstack/fibratus/pkg/alertsender"
"github.com/rabbitstack/fibratus/pkg/event"
@@ -30,9 +34,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/sys/windows"
- "strings"
- "testing"
- "time"
)
func TestRenderHTMLTemplate(t *testing.T) {
@@ -51,16 +52,13 @@ func TestRenderHTMLTemplate(t *testing.T) {
},
Events: []*event.Event{
{
- Type: event.CreateFile,
- Tid: 2484,
- PID: 859,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Timestamp: time.Now(),
- Category: event.File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: event.CreateFile,
+ Tid: 2484,
+ PID: 859,
+ CPU: 1,
+ Seq: 2,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\user32.dll"},
@@ -146,16 +144,13 @@ func TestRenderHTMLTemplate(t *testing.T) {
},
},
{
- Type: event.CreateProcess,
- Tid: 2184,
- PID: 1022,
- CPU: 2,
- Seq: 3,
- Name: "CreateProcess",
- Timestamp: time.Now(),
- Category: event.File,
- Host: "archrabbit",
- Description: "Creates a new process",
+ Type: event.CreateProcess,
+ Tid: 2184,
+ PID: 1022,
+ CPU: 2,
+ Seq: 3,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: event.Params{
params.Cmdline: {Name: params.Cmdline, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\svchost.exe -k RPCSS"},
params.Exe: {Name: params.Exe, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\svchost.exe"},
diff --git a/pkg/cap/header.go b/pkg/cap/header.go
index c1720164c..7df0a4e5c 100644
--- a/pkg/cap/header.go
+++ b/pkg/cap/header.go
@@ -34,7 +34,7 @@ const magic = 0x6669627261747573
// major represents the major digit of the cap file format. Incrementing the major digit makes older cap readers not
// capable to replay the capture file
-const major = uint8(2)
+const major = uint8(3)
// minor represents the minor digit of the cap file format
const minor = uint8(0)
diff --git a/pkg/cap/version/version_windows.go b/pkg/cap/version/version_windows.go
index d2172bbe9..7585230e5 100644
--- a/pkg/cap/version/version_windows.go
+++ b/pkg/cap/version/version_windows.go
@@ -26,6 +26,8 @@ const (
EvtSecV1 Version = iota + 1
// EvtSecV2 is the v2 of the event section
EvtSecV2
+ // EvtSecV3 is the v3 of the event section
+ EvtSecV3
)
const (
diff --git a/pkg/cap/writer_windows.go b/pkg/cap/writer_windows.go
index bd381a263..2cc95f989 100644
--- a/pkg/cap/writer_windows.go
+++ b/pkg/cap/writer_windows.go
@@ -48,7 +48,7 @@ type stats struct {
procsWritten uint64
}
-func (s *stats) incKevts(evt *event.Event) {
+func (s *stats) incEvts(evt *event.Event) {
if !evt.Type.OnlyState() {
atomic.AddUint64(&s.evtsWritten, 1)
}
@@ -201,7 +201,7 @@ func (w *writer) Write(evtsc <-chan *event.Event, errs <-chan error) chan error
continue
}
// update stats
- w.stats.incKevts(evt)
+ w.stats.incEvts(evt)
w.stats.incBytes(uint64(l))
w.stats.incProcs(evt)
case err := <-errs:
@@ -223,7 +223,7 @@ func (w *writer) write(b []byte) error {
overflowEvents.Add(1)
return fmt.Errorf("event size overflow by %d bytes", l-maxKevtSize)
}
- if err := w.ws(section.Event, capver.EvtSecV2, 0, uint32(l)); err != nil {
+ if err := w.ws(section.Event, capver.EvtSecV3, 0, uint32(l)); err != nil {
evtWriteErrors.Add(1)
return err
}
diff --git a/pkg/cap/writer_windows_test.go b/pkg/cap/writer_windows_test.go
index d13907715..590e05def 100644
--- a/pkg/cap/writer_windows_test.go
+++ b/pkg/cap/writer_windows_test.go
@@ -67,16 +67,13 @@ func TestWrite(t *testing.T) {
for i := 0; i < 100; i++ {
evt := &event.Event{
- Type: event.CreateFile,
- Tid: 2484,
- PID: 859,
- CPU: uint8(i / 2),
- Seq: uint64(i + 1),
- Name: "CreateFile",
- Timestamp: time.Now(),
- Category: event.File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: event.CreateFile,
+ Tid: 2484,
+ PID: 859,
+ CPU: uint8(i / 2),
+ Seq: uint64(i + 1),
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "\\Device\\HarddiskVolume2\\Windows\\system32\\user32.dll"},
diff --git a/pkg/config/eventsource.go b/pkg/config/eventsource.go
index d99ad49a9..2d691a316 100644
--- a/pkg/config/eventsource.go
+++ b/pkg/config/eventsource.go
@@ -26,7 +26,7 @@ import (
"time"
"github.com/rabbitstack/fibratus/pkg/event"
- "github.com/rabbitstack/fibratus/pkg/util/bitmask"
+ "github.com/rabbitstack/fibratus/pkg/util/bitmap"
pstypes "github.com/rabbitstack/fibratus/pkg/ps/types"
"github.com/spf13/viper"
@@ -97,8 +97,7 @@ type EventSourceConfig struct {
// ExcludedImages are process image names that will be rejected if they generate a kernel event.
ExcludedImages []string `json:"blacklist.images" yaml:"blacklist.images"`
- dropMasks *bitmask.Bitmask
- allMasks *bitmask.Bitmask
+ dropBitmap bitmap.Bitmap[event.Type]
excludedImages map[string]bool
}
@@ -121,21 +120,14 @@ func (c *EventSourceConfig) initFromViper(v *viper.Viper) {
c.ExcludedEvents = v.GetStringSlice(excludedEvents)
c.ExcludedImages = v.GetStringSlice(excludedImages)
- c.dropMasks = bitmask.New()
- c.allMasks = bitmask.New()
-
c.excludedImages = make(map[string]bool)
for _, name := range c.ExcludedEvents {
- if typ := event.NameToType(name); typ != event.UnknownType {
- c.dropMasks.Set(typ.ID())
+ if typ, ok := event.ParseType(name); ok {
+ c.dropBitmap.Set(typ)
}
}
- for _, typ := range event.AllWithState() {
- c.allMasks.Set(typ.ID())
- }
-
for _, name := range c.ExcludedImages {
c.excludedImages[name] = true
}
@@ -145,53 +137,34 @@ func (c *EventSourceConfig) initFromViper(v *viper.Viper) {
func (c *EventSourceConfig) Init() {
c.excludedImages = make(map[string]bool)
- if c.dropMasks == nil {
- c.dropMasks = bitmask.New()
- }
for _, name := range c.ExcludedEvents {
- for _, typ := range event.NameToTypes(name) {
- if typ != event.UnknownType {
- c.dropMasks.Set(typ.ID())
- }
+ if typ, ok := event.ParseType(name); ok {
+ c.dropBitmap.Set(typ)
}
}
for _, name := range c.ExcludedImages {
c.excludedImages[name] = true
}
-
- if c.allMasks == nil {
- c.allMasks = bitmask.New()
- }
- for _, typ := range event.AllWithState() {
- c.allMasks.Set(typ.ID())
- }
}
// SetDropMask inserts the event mask in the bitset to
// instruct the given event type should be dropped from
// the event stream.
func (c *EventSourceConfig) SetDropMask(typ event.Type) {
- c.dropMasks.Set(typ.ID())
+ c.dropBitmap.Set(typ)
}
// TestDropMask checks if the specified event type has
// the drop mask in the bitset.
func (c *EventSourceConfig) TestDropMask(typ event.Type) bool {
- return c.dropMasks.IsSet(typ.ID())
-}
-
-// ExcludeEvent determines whether the supplied short
-// event ID exists in the bitset of excluded events.
-func (c *EventSourceConfig) ExcludeEvent(id uint) bool {
- return c.dropMasks.IsSet(id)
+ return c.dropBitmap.Has(typ)
}
-// EventExists determines if the provided event ID exists
-// in the internal event catalog by checking the event ID
-// bitmask.
-func (c *EventSourceConfig) EventExists(id uint) bool {
- return c.allMasks.IsSet(id)
+// ExcludeEvent determines whether the event type is declared
+// in the exclusion list.
+func (c *EventSourceConfig) ExcludeEvent(typ event.Type) bool {
+ return c.dropBitmap.Has(typ)
}
// ExcludeImage determines whether the process generating event is present in the
diff --git a/pkg/config/eventsource_test.go b/pkg/config/eventsource_test.go
index 157b88eb7..815fb8ff9 100644
--- a/pkg/config/eventsource_test.go
+++ b/pkg/config/eventsource_test.go
@@ -56,7 +56,7 @@ func TestEventSourceConfig(t *testing.T) {
assert.False(t, c.EventSource.EnableModuleEvents)
assert.False(t, c.EventSource.EnableFileIOEvents)
- assert.False(t, c.EventSource.ExcludeEvent(event.CreateProcess.ID()))
+ assert.False(t, c.EventSource.ExcludeEvent(event.CreateProcess))
assert.True(t, c.EventSource.ExcludeImage(&pstypes.PS{Name: "svchost.exe"}))
assert.False(t, c.EventSource.ExcludeImage(&pstypes.PS{Name: "explorer.exe"}))
diff --git a/pkg/event/batch_test.go b/pkg/event/batch_test.go
index e53039d1b..f82d6d91f 100644
--- a/pkg/event/batch_test.go
+++ b/pkg/event/batch_test.go
@@ -20,6 +20,9 @@ package event
import (
"encoding/json"
+ "testing"
+ "time"
+
"github.com/magiconair/properties/assert"
"github.com/rabbitstack/fibratus/pkg/event/params"
htypes "github.com/rabbitstack/fibratus/pkg/handle/types"
@@ -27,22 +30,17 @@ import (
"github.com/rabbitstack/fibratus/pkg/util/va"
"github.com/stretchr/testify/require"
"golang.org/x/sys/windows"
- "testing"
- "time"
)
func TestBatchMarshalJSON(t *testing.T) {
evt := &Event{
- Type: CreateFile,
- Tid: 2484,
- PID: 859,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Timestamp: time.Now(),
- Category: File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: CreateFile,
+ Tid: 2484,
+ PID: 859,
+ CPU: 1,
+ Seq: 2,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "\\Device\\HarddiskVolume2\\Windows\\system32\\user32.dll"},
@@ -101,16 +99,13 @@ func TestBatchMarshalJSON(t *testing.T) {
}
evt1 := &Event{
- Type: CreateFile,
- Tid: 2484,
- PID: 459,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Timestamp: time.Now(),
- Category: File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: CreateFile,
+ Tid: 2484,
+ PID: 459,
+ CPU: 1,
+ Seq: 2,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "\\Device\\HarddiskVolume2\\Windows\\system32\\user32.dll"},
@@ -169,16 +164,13 @@ func TestBatchMarshalJSON(t *testing.T) {
}
evt2 := &Event{
- Type: CreateFile,
- Tid: 2484,
- PID: 829,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Timestamp: time.Now(),
- Category: File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: CreateFile,
+ Tid: 2484,
+ PID: 829,
+ CPU: 1,
+ Seq: 2,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "\\Device\\HarddiskVolume2\\Windows\\system32\\user32.dll"},
diff --git a/pkg/event/bitset.go b/pkg/event/bitset.go
deleted file mode 100644
index abfb0a157..000000000
--- a/pkg/event/bitset.go
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright 2021-2022 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 (
- "github.com/bits-and-blooms/bitset"
- "github.com/rabbitstack/fibratus/pkg/util/bitmask"
-)
-
-// BitSetType defines the bitset type
-type BitSetType uint8
-
-const (
- // BitmaskBitSet designates the mask-based event id bitset
- BitmaskBitSet BitSetType = iota + 1
- // TypeBitSet designates the uint16 number space event type bitset
- TypeBitSet
- // CategoryBitSet designates the event category bitset
- CategoryBitSet
-)
-
-// BitSets handles the group of category/event type bitsets
-// and the bitmask for evaluating event ids bits.
-type BitSets struct {
- bitmask *bitmask.Bitmask
- cats *bitset.BitSet
- types *bitset.BitSet
-}
-
-// SetBit sets the bit dictated by the bitset type.
-func (b *BitSets) SetBit(bs BitSetType, typ Type) {
- switch bs {
- case BitmaskBitSet:
- if b.bitmask == nil {
- b.bitmask = bitmask.New()
- }
- b.bitmask.Set(typ.ID())
-
- case TypeBitSet:
- if b.types == nil {
- b.types = bitset.New(uint(MaxTypeID() + 1))
- }
- b.types.Set(uint(typ.HookID()))
-
- case CategoryBitSet:
- if b.cats == nil {
- b.cats = bitset.New(MaxCategoryIndex + 1)
- }
- b.cats.Set(uint(typ.Category().Index()))
- }
-}
-
-// SetCategoryBit toggles the category bit in the bitset.
-func (b *BitSets) SetCategoryBit(c Category) {
- if b.cats == nil {
- b.cats = bitset.New(MaxCategoryIndex + 1)
- }
- b.cats.Set(uint(c.Index()))
-}
-
-// IsBitSet checks if any of the populated bitsets
-// contain the type, event ID, or category bit.
-// This method evaluates first the event type bitset.
-// The event type bitset should only be initialized
-// if all event types pertain to the same category.
-// Otherwise, event id bitset and last category bitset
-// are tested for respective bits.
-func (b *BitSets) IsBitSet(evt *Event) bool {
- if b.types != nil && b.types.Test(uint(evt.Type.HookID())) {
- return true
- }
- return (b.bitmask != nil && b.bitmask.IsSet(evt.Type.ID())) ||
- (b.cats != nil && b.cats.Test(uint(evt.Category.Index())))
-}
-
-// IsInitialized checks if the given bitset type is initialized.
-func (b *BitSets) IsInitialized(bs BitSetType) bool {
- switch bs {
- case BitmaskBitSet:
- return b.bitmask != nil
- case TypeBitSet:
- return b.types != nil
- case CategoryBitSet:
- return b.cats != nil
- }
- return false
-}
diff --git a/pkg/event/bitset_test.go b/pkg/event/bitset_test.go
deleted file mode 100644
index df69110db..000000000
--- a/pkg/event/bitset_test.go
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright 2021-2022 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"
-
- "github.com/rabbitstack/fibratus/pkg/util/bitmask"
-
- "github.com/rabbitstack/fibratus/pkg/sys/etw"
- "github.com/stretchr/testify/assert"
-)
-
-func TestBitmask(t *testing.T) {
- var tests = []struct {
- typ Type
- expected bool
- }{
- {TerminateThread, true},
- {TerminateProcess, true},
- {CreateThread, true},
- {CreateFile, false},
- {WriteFile, false},
- {LoadModule, false},
- {MapFileRundown, true},
- {ProcessRundown, true},
- }
-
- b := bitmask.New()
- for _, typ := range AllWithState() {
- if typ == WriteFile || typ == LoadModule || typ == CreateFile {
- continue
- }
- b.Set(typ.ID())
- }
-
- for _, tt := range tests {
- t.Run(tt.typ.String(), func(t *testing.T) {
- assert.Equal(t, tt.expected, b.IsSet(tt.typ.ID()))
- })
- }
-}
-
-func TestBitSets(t *testing.T) {
- var tests = []struct {
- evt *Event
- expected bool
- }{
- {&Event{Type: TerminateThread}, true},
- {&Event{Type: TerminateProcess}, true},
- {&Event{Type: CreateThread, Category: Thread}, true},
- {&Event{Type: CreateFile}, false},
- {&Event{Type: WriteFile}, false},
- {&Event{Type: LoadModule}, false},
- {&Event{Type: MapFileRundown}, true},
- {&Event{Type: ProcessRundown}, true},
- }
-
- var bitsets BitSets
-
- bitsets.SetBit(BitmaskBitSet, TerminateThread)
- bitsets.SetBit(TypeBitSet, TerminateProcess)
- bitsets.SetBit(CategoryBitSet, CreateThread)
- bitsets.SetBit(TypeBitSet, MapFileRundown)
- bitsets.SetBit(BitmaskBitSet, ProcessRundown)
-
- for _, tt := range tests {
- t.Run(tt.evt.Type.String(), func(t *testing.T) {
- assert.Equal(t, tt.expected, bitsets.IsBitSet(tt.evt))
- })
- }
-}
-
-func BenchmarkBitmask(b *testing.B) {
- b.ReportAllocs()
-
- bm := bitmask.New()
- bm.Set(TerminateThread.ID())
- bm.Set(CreateThread.ID())
- bm.Set(TerminateProcess.ID())
- bm.Set(CreateFile.ID())
-
- evt := &etw.EventRecord{Header: etw.EventHeader{ProviderID: ThreadEventGUID, EventDescriptor: etw.EventDescriptor{Opcode: 2}}}
-
- b.ResetTimer()
-
- for i := 0; i < b.N; i++ {
- if !bm.IsSet(evt.ID()) {
- panic("mask should be present")
- }
- }
-}
-
-func BenchmarkStdlibMap(b *testing.B) {
- b.ReportAllocs()
-
- evts := make(map[Type]bool)
- evts[TerminateThread] = true
- evts[CreateThread] = true
- evts[TerminateProcess] = true
- evts[CreateFile] = true
-
- evt := etw.EventRecord{Header: etw.EventHeader{ProviderID: ThreadEventGUID, EventDescriptor: etw.EventDescriptor{Opcode: 2}}}
- etype := NewTypeFromEventRecord(&evt)
-
- b.ResetTimer()
-
- for i := 0; i < b.N; i++ {
- if !evts[etype] {
- panic("event should be present")
- }
- }
-}
diff --git a/pkg/event/category.go b/pkg/event/category.go
index 6204a5214..1e807d365 100644
--- a/pkg/event/category.go
+++ b/pkg/event/category.go
@@ -18,102 +18,99 @@
package event
-import (
- "slices"
-
- "github.com/rabbitstack/fibratus/pkg/util/hashers"
-)
-
// Category is the type alias for event categories
-type Category string
+type Category uint8
// Subcategory is the type alias for event subcategories
-type Subcategory string
+type Subcategory uint8
const (
// Registry is the category for registry related events
- Registry Category = "registry"
+ Registry Category = iota + 1
// File is the category for file system events
- File Category = "file"
- // Net is the category for network events
- Net Category = "net"
+ File
+ // Network is the category for network events
+ Network
// Process is the category for process events
- Process Category = "process"
+ Process
// Thread is the category for thread events
- Thread Category = "thread"
+ Thread
// Module is the category for module (dll, exe, sys) events
- Module Category = "module"
- // Driver is the category for driver events
- Driver Category = "driver"
- // Mem is the category for memory events
- Mem Category = "mem"
+ Module
+ // Memory is the category for memory events
+ Memory
// Object the category for object manager events
- Object Category = "object"
+ Object
// Other is the category for uncategorized events
- Other Category = "other"
- // Unknown is the category for events that couldn't match any of the previous categories
- Unknown Category = "unknown"
+ Other
+ MaxCategory // sentinel
)
const (
// DNS designates the DNS (Domain Name Service) event subcategory
- DNS Subcategory = "dns"
- // None identifies no subcategory
- None Subcategory = "none"
+ DNS Subcategory = iota + 1
+ MaxSubcategory // sentinel
)
-// Hash obtains the hash of the category string.
-func (c Category) Hash() uint32 {
- return hashers.FnvUint32([]byte(c))
-}
-
-// MaxCategoryIndex designates the maximum category index.
-const MaxCategoryIndex = 11
-
-// Index returns a numerical category index.
-func (c Category) Index() uint8 {
+// String returns the category string representation.
+func (c Category) String() string {
switch c {
case Registry:
- return 1
+ return "registry"
case File:
- return 2
- case Net:
- return 3
+ return "file"
+ case Network:
+ return "network"
case Process:
- return 4
+ return "process"
case Thread:
- return 5
+ return "thread"
case Module:
- return 6
- case Driver:
- return 7
- case Mem:
- return 8
+ return "module"
+ case Memory:
+ return "memory"
case Object:
- return 9
+ return "object"
case Other:
- return 10
+ return "other"
default:
- return MaxCategoryIndex
+ return "unknown"
}
}
-// Categories returns all available categories.
-func Categories() []string {
- return []string{
- string(Registry),
- string(File),
- string(Net),
- string(Process),
- string(Thread),
- string(Module),
- string(Mem),
- string(Driver),
- string(Other),
- string(Unknown),
- string(Object),
+func (sc Subcategory) String() string {
+ switch sc {
+ case DNS:
+ return "dns"
+ default:
+ return "unknown"
}
}
+var categories = map[string]Category{
+ "registry": Registry,
+ "file": File,
+ "network": Network,
+ "process": Process,
+ "thread": Thread,
+ "module": Module,
+ "memory": Memory,
+ "object": Object,
+ "other": Other,
+}
+
+// NumCategories returns a total number of recognized categories.
+func NumCategories() int { return len(categories) }
+
+// ParseCategory converts the category from the bare string. Returns
+// the category and the bool indicating if the conversion succeeded.
+func ParseCategory(s string) (Category, bool) {
+ c, ok := categories[s]
+ return c, ok
+}
+
// IsCategoryKnown indicates if the category is known given its name.
-func IsCategoryKnown(name string) bool { return slices.Contains(Categories(), name) }
+func IsCategoryKnown(s string) (exists bool) {
+ _, exists = ParseCategory(s)
+ return
+}
diff --git a/pkg/event/event.go b/pkg/event/event.go
index 66ca2905c..ba1b03039 100644
--- a/pkg/event/event.go
+++ b/pkg/event/event.go
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2020 by Nedim Sabic Sabic
+ * Copyright 2019-2026 by Nedim Sabic Sabic
* https://www.fibratus.io
* All Rights Reserved.
*
@@ -86,12 +86,6 @@ type Event struct {
CPU uint8 `json:"cpu"`
_ uint8 // padding
- // Name is the human friendly name of the event.
- Name string `json:"name"`
- // Category designates the category to which this event pertains.
- Category Category `json:"category"`
- // Description is the short explanation that describes the purpose of the event.
- Description string `json:"description"`
// Host is the machine name that reported the generated event.
Host string `json:"host"`
// Params stores the collection of event parameters.
@@ -107,6 +101,26 @@ type Event struct {
mmux sync.RWMutex
}
+// Name returns the human friendly event name.
+func (e *Event) Name() string {
+ return e.Type.String()
+}
+
+// Category designates the category to which this event pertains.
+func (e *Event) Category() Category {
+ return table[e.Type].Category
+}
+
+// Subcategory designates the subcategory to which this event pertains.
+func (e *Event) Subcategory() Subcategory {
+ return table[e.Type].Subcategory
+}
+
+// Description is the short explanation that describes the purpose of the event.
+func (e *Event) Description() string {
+ return table[e.Type].Description
+}
+
// String returns event's string representation.
func (e *Event) String() string {
e.mmux.RLock()
@@ -132,9 +146,9 @@ func (e *Event) String() string {
e.Tid,
e.Type,
e.CPU,
- e.Name,
- e.Category,
- e.Description,
+ e.Name(),
+ e.Category(),
+ e.Description(),
e.Host,
e.Timestamp,
e.Params,
@@ -161,9 +175,9 @@ func (e *Event) String() string {
e.Tid,
e.Type,
e.CPU,
- e.Name,
- e.Category,
- e.Description,
+ e.Name(),
+ e.Category(),
+ e.Description(),
e.Host,
e.Timestamp,
e.Params,
@@ -191,8 +205,8 @@ func (e *Event) StringShort() string {
e.Seq,
e.PID,
e.Tid,
- e.Name,
- e.Category,
+ e.Name(),
+ e.Category(),
e.Host,
e.Timestamp,
e.Params,
@@ -212,8 +226,8 @@ func (e *Event) StringShort() string {
e.Seq,
e.PID,
e.Tid,
- e.Name,
- e.Category,
+ e.Name(),
+ e.Category(),
e.Host,
e.Timestamp,
e.Params,
diff --git a/pkg/event/event_windows.go b/pkg/event/event_windows.go
index 38f1eb95f..b9825a5b7 100644
--- a/pkg/event/event_windows.go
+++ b/pkg/event/event_windows.go
@@ -27,6 +27,7 @@ import (
"unsafe"
"github.com/rabbitstack/fibratus/pkg/event/params"
+ "github.com/rabbitstack/fibratus/pkg/network"
"github.com/rabbitstack/fibratus/pkg/sys"
"github.com/rabbitstack/fibratus/pkg/sys/etw"
"github.com/rabbitstack/fibratus/pkg/util/filetime"
@@ -49,13 +50,12 @@ var (
// New constructs a fresh event instance with basic fields and parameters
// from the raw ETW event record.
-func New(seq uint64, r *etw.EventRecord) *Event {
+func New(seq uint64, r *etw.EventRecord, typ Type) *Event {
var (
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{
@@ -64,8 +64,6 @@ func New(seq uint64, r *etw.EventRecord) *Event {
Tid: tid,
CPU: cpu,
Type: typ,
- Category: typ.Category(),
- Name: typ.String(),
Params: make(map[string]*Param),
Timestamp: ts,
Host: hostname.Get(),
@@ -86,7 +84,7 @@ func (e *Event) RawTimestamp() uint64 {
}
func (e *Event) adjustPID() {
- switch e.Category {
+ switch e.Category() {
case Module:
// sometimes the pid present in event header is invalid
// but, we can get the valid one from the event parameters
@@ -94,16 +92,7 @@ func (e *Event) adjustPID() {
e.PID, _ = e.Params.GetPid()
}
case File:
- if !e.IsMapViewFile() && !e.IsUnmapViewFile() {
- // take thread id from the event parameters
- e.Tid, _ = e.Params.GetTid()
- }
- switch {
- case e.InvalidPid() && e.Type == MapFileRundown:
- // a valid pid for map rundown events
- // is located in the event parameters
- e.PID = e.Params.MustGetPid()
- case e.InvalidPid():
+ if e.InvalidPid() {
// on some Windows versions the value of
// the PID is invalid in the event header
access := uint32(windows.THREAD_QUERY_LIMITED_INFORMATION)
@@ -123,7 +112,7 @@ func (e *Event) adjustPID() {
if e.IsCreateProcess() {
e.PID, _ = e.Params.GetPid()
}
- case Net:
+ case Network:
if !e.IsDNS() {
e.PID, _ = e.Params.GetPid()
}
@@ -132,6 +121,12 @@ func (e *Event) adjustPID() {
e.PID, _ = e.Params.GetPid()
e.Tid, _ = e.Params.GetTid()
}
+ case Memory:
+ if e.Type == MapViewSectionRundown {
+ // a valid pid for map rundown events
+ // is located in the event parameters
+ e.PID = e.Params.MustGetPid()
+ }
}
}
@@ -158,23 +153,17 @@ func IsCurrentProcDropped(pid uint32) bool { return DropCurrentProc && pid == cu
// IsNetworkTCP determines whether the event pertains to network TCP events.
func (e *Event) IsNetworkTCP() bool {
- return e.Category == Net && !e.IsNetworkUDP()
-}
-
-// IsNetworkUDP determines whether the event pertains to network UDP events.
-func (e *Event) IsNetworkUDP() bool {
- return e.Type == RecvUDPv4 || e.Type == RecvUDPv6 || e.Type == SendUDPv4 || e.Type == SendUDPv6
+ return e.Category() == Network && network.L4Proto(e.Params.MustGetUint32(params.NetL4Proto)) == network.TCP
}
// IsDNS determines whether the event is a DNS question/answer.
func (e *Event) IsDNS() bool {
- return e.Type.Subcategory() == DNS
+ return e.Subcategory() == DNS
}
// IsRundown determines if this is a rundown events.
func (e *Event) IsRundown() bool {
- return e.Type == ProcessRundown || e.Type == ThreadRundown || e.Type == ModuleRundown ||
- e.Type == FileRundown || e.Type == RegKCBRundown
+ return e.Type.StateSnapshot()
}
// IsSuccess checks if the event contains the status parameter
@@ -228,8 +217,8 @@ func (e *Event) IsRegCreateKey() bool { return e.Type == RegCreateKey
func (e *Event) IsProcessRundown() bool { return e.Type == ProcessRundown }
func (e *Event) IsProcessRundownInternal() bool { return e.Type == ProcessRundownInternal }
func (e *Event) IsVirtualAlloc() bool { return e.Type == VirtualAlloc }
-func (e *Event) IsMapViewFile() bool { return e.Type == MapViewFile }
-func (e *Event) IsUnmapViewFile() bool { return e.Type == UnmapViewFile }
+func (e *Event) IsMapViewOfSection() bool { return e.Type == MapViewOfSection }
+func (e *Event) IsUnmapViewOfSection() bool { return e.Type == UnmapViewOfSection }
func (e *Event) IsStackWalk() bool { return e.Type == StackWalk }
func (e *Event) IsOpenThread() bool { return e.Type == OpenThread }
func (e *Event) IsOpenProcess() bool { return e.Type == OpenProcess }
@@ -336,7 +325,7 @@ func (e *Event) RundownKey() uint64 {
binary.LittleEndian.PutUint64(b, fileObject)
return hashers.FnvUint64(b)
- case MapFileRundown:
+ case MapViewSectionRundown:
b := make([]byte, 12)
fileKey, _ := e.Params.GetUint64(params.FileKey)
binary.LittleEndian.PutUint32(b, e.PID)
@@ -362,7 +351,7 @@ func (e *Event) PartialKey() uint64 {
switch e.Type {
case WriteFile, ReadFile:
return e.Params.MustGetUint64(params.FileObject) + uint64(e.PID)
- case MapViewFile, UnmapViewFile:
+ case MapViewOfSection, UnmapViewOfSection:
return e.Params.MustGetUint64(params.FileViewBase) + uint64(e.PID)
case CreateFile:
file, _ := e.Params.GetString(params.FilePath)
@@ -378,38 +367,34 @@ func (e *Event) PartialKey() uint64 {
tid := e.Params.MustGetUint32(params.ThreadID)
access := e.Params.MustGetUint32(params.DesiredAccess)
return uint64(tid + access + e.PID)
- case AcceptTCPv4, RecvTCPv4, RecvUDPv4:
- b := make([]byte, 10)
- ip, _ := e.Params.GetIP(params.NetSIP)
- port, _ := e.Params.GetUint16(params.NetSport)
- binary.LittleEndian.PutUint32(b, e.PID)
- binary.LittleEndian.PutUint32(b, binary.BigEndian.Uint32(ip.To4()))
- binary.LittleEndian.PutUint16(b, port)
- return hashers.FnvUint64(b)
- case AcceptTCPv6, RecvTCPv6, RecvUDPv6:
- b := make([]byte, 22)
+ case Accept, Recv:
+ var b []byte
ip, _ := e.Params.GetIP(params.NetSIP)
+ if ip.To4() != nil {
+ b = make([]byte, 10)
+ binary.LittleEndian.PutUint32(b, binary.BigEndian.Uint32(ip.To4()))
+ } else {
+ b = make([]byte, 22)
+ binary.LittleEndian.PutUint64(b, binary.BigEndian.Uint64(ip.To16()[0:8]))
+ binary.LittleEndian.PutUint64(b, binary.BigEndian.Uint64(ip.To16()[8:16]))
+ }
port, _ := e.Params.GetUint16(params.NetSport)
binary.LittleEndian.PutUint32(b, e.PID)
- binary.LittleEndian.PutUint64(b, binary.BigEndian.Uint64(ip.To16()[0:8]))
- binary.LittleEndian.PutUint64(b, binary.BigEndian.Uint64(ip.To16()[8:16]))
binary.LittleEndian.PutUint16(b, port)
return hashers.FnvUint64(b)
- case ConnectTCPv4, SendTCPv4, SendUDPv4:
- b := make([]byte, 10)
- ip, _ := e.Params.GetIP(params.NetDIP)
- port, _ := e.Params.GetUint16(params.NetDport)
- binary.LittleEndian.PutUint32(b, e.PID)
- binary.LittleEndian.PutUint32(b, binary.BigEndian.Uint32(ip.To4()))
- binary.LittleEndian.PutUint16(b, port)
- return hashers.FnvUint64(b)
- case ConnectTCPv6, SendTCPv6, SendUDPv6:
- b := make([]byte, 22)
+ case Connect, Send:
+ var b []byte
ip, _ := e.Params.GetIP(params.NetDIP)
+ if ip.To4() != nil {
+ b = make([]byte, 10)
+ binary.LittleEndian.PutUint32(b, binary.BigEndian.Uint32(ip.To4()))
+ } else {
+ b = make([]byte, 22)
+ binary.LittleEndian.PutUint64(b, binary.BigEndian.Uint64(ip.To16()[0:8]))
+ binary.LittleEndian.PutUint64(b, binary.BigEndian.Uint64(ip.To16()[8:16]))
+ }
port, _ := e.Params.GetUint16(params.NetDport)
binary.LittleEndian.PutUint32(b, e.PID)
- binary.LittleEndian.PutUint64(b, binary.BigEndian.Uint64(ip.To16()[0:8]))
- binary.LittleEndian.PutUint64(b, binary.BigEndian.Uint64(ip.To16()[8:16]))
binary.LittleEndian.PutUint16(b, port)
return hashers.FnvUint64(b)
case RegOpenKey, RegQueryKey, RegQueryValue,
@@ -523,21 +508,21 @@ func (e *Event) Summary() string {
case RegQueryValue:
key := e.GetParamAsString(params.RegPath)
return printSummary(e, fmt.Sprintf("queried %s value", key))
- case AcceptTCPv4, AcceptTCPv6:
+ case Accept:
ip, _ := e.Params.GetIP(params.NetSIP)
port, _ := e.Params.GetUint16(params.NetSport)
return printSummary(e, fmt.Sprintf("accepted connection from %v and %d port", ip, port))
- case ConnectTCPv4, ConnectTCPv6:
+ case Connect:
ip, _ := e.Params.GetIP(params.NetDIP)
port, _ := e.Params.GetUint16(params.NetDport)
return printSummary(e, fmt.Sprintf("connected to %v and %d port", ip, port))
- case SendTCPv4, SendTCPv6, SendUDPv4, SendUDPv6:
+ case Send:
ip, _ := e.Params.GetIP(params.NetDIP)
port, _ := e.Params.GetUint16(params.NetDport)
size, _ := e.Params.GetUint32(params.NetSize)
return printSummary(e, fmt.Sprintf("sent %d bytes to %v and %d port",
size, ip, port))
- case RecvTCPv4, RecvTCPv6, RecvUDPv4, RecvUDPv6:
+ case Recv:
ip, _ := e.Params.GetIP(params.NetSIP)
port, _ := e.Params.GetUint16(params.NetSport)
size, _ := e.Params.GetUint32(params.NetSize)
@@ -549,10 +534,10 @@ func (e *Event) Summary() string {
case VirtualFree:
addr := e.GetParamAsString(params.MemBaseAddress)
return printSummary(e, fmt.Sprintf("released memory at %s address", addr))
- case MapViewFile:
+ case MapViewOfSection:
sec := e.GetParamAsString(params.FileViewSectionType)
return printSummary(e, fmt.Sprintf("mapped view of %s section", sec))
- case UnmapViewFile:
+ case UnmapViewOfSection:
sec := e.GetParamAsString(params.FileViewSectionType)
return printSummary(e, fmt.Sprintf("unmapped view of %s section", sec))
case QueryDNS:
diff --git a/pkg/event/event_windows_test.go b/pkg/event/event_windows_test.go
index 573c2c511..a12094ab2 100644
--- a/pkg/event/event_windows_test.go
+++ b/pkg/event/event_windows_test.go
@@ -19,41 +19,25 @@
package event
import (
+ "testing"
+ "time"
+
"github.com/rabbitstack/fibratus/pkg/event/params"
"github.com/rabbitstack/fibratus/pkg/fs"
pstypes "github.com/rabbitstack/fibratus/pkg/ps/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "testing"
- "time"
)
-func TestEventIsNetworkTCP(t *testing.T) {
- e1 := Event{Type: AcceptTCPv4, Category: Net}
- e2 := Event{Type: SendUDPv6, Category: Net}
- assert.True(t, e1.IsNetworkTCP())
- assert.False(t, e2.IsNetworkTCP())
-}
-
-func TestEventIsNetworkUDP(t *testing.T) {
- e1 := Event{Type: RecvUDPv4}
- e2 := Event{Type: SendTCPv6}
- assert.True(t, e1.IsNetworkUDP())
- assert.False(t, e2.IsNetworkUDP())
-}
-
func TestEventSummary(t *testing.T) {
evt := &Event{
- Type: CreateFile,
- Tid: 2484,
- PID: 859,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Timestamp: time.Now(),
- Category: File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: CreateFile,
+ Tid: 2484,
+ PID: 859,
+ CPU: 1,
+ Seq: 2,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\user32.dll"},
diff --git a/pkg/event/formatter.go b/pkg/event/formatter.go
index d1181ada7..7a3e0361b 100644
--- a/pkg/event/formatter.go
+++ b/pkg/event/formatter.go
@@ -209,13 +209,10 @@ func (f *ColorFormatter) colourTag(tag string, e *Event) string {
case seq:
// sequence number is ok to render as dim gray
return colorizer.SpanDim(colorizer.Span(colorizer.Gray, strconv.FormatUint(e.Seq, 10)))
-
case ts:
return f.colourTimestamp(e)
-
case cpu:
return colorizer.Span(colorizer.Yellow, strconv.FormatUint(uint64(e.CPU), 10))
-
case proc:
// render process name with bold green as it is the most important
// identity anchor on the line. Analysts scan for it first.
@@ -224,85 +221,70 @@ func (f *ColorFormatter) colourTag(tag string, e *Event) string {
return colorizer.Span(colorizer.Gray, "N/A")
}
return colorizer.SpanBold(colorizer.Green, ps.Name)
-
case pid:
return colorizer.Span(colorizer.Green, strconv.FormatUint(uint64(e.PID), 10))
-
case ppid:
ps := e.PS
if ps == nil {
return colorizer.Span(colorizer.Gray, "N/A")
}
return colorizer.Span(colorizer.Green, strconv.FormatUint(uint64(ps.Ppid), 10))
-
case tid:
return colorizer.Span(colorizer.Green, strconv.FormatUint(uint64(e.Tid), 10))
-
case exe:
ps := e.PS
if ps == nil {
return colorizer.Span(colorizer.Gray, "N/A")
}
return colorizer.Span(colorizer.White, ps.Exe)
-
case pexe:
ps := e.PS
if ps == nil || ps.Parent == nil {
return colorizer.Span(colorizer.Gray, "N/A")
}
return colorizer.Span(colorizer.White, ps.Parent.Exe)
-
case cmd:
ps := e.PS
if ps == nil {
return colorizer.Span(colorizer.Gray, "N/A")
}
return colorizer.Span(colorizer.White, ps.Cmdline)
-
case pcmd:
ps := e.PS
if ps == nil || ps.Parent == nil {
return colorizer.Span(colorizer.Gray, "N/A")
}
return colorizer.Span(colorizer.White, ps.Parent.Cmdline)
-
case cwd:
ps := e.PS
if ps == nil {
return colorizer.Span(colorizer.Gray, "N/A")
}
return colorizer.Span(colorizer.White, ps.Cwd)
-
case sid:
ps := e.PS
if ps == nil {
return colorizer.Span(colorizer.Gray, "N/A")
}
return colorizer.Span(colorizer.Gray, ps.SID)
-
case pproc:
ps := e.PS
if ps == nil || ps.Parent == nil {
return colorizer.Span(colorizer.Gray, "N/A")
}
return colorizer.Span(colorizer.Green, ps.Parent.Name)
-
case typ:
return e.Type.color()
-
case cat:
- return colorizer.Span(colorizer.Magenta, string(e.Category))
-
+ return colorizer.Span(colorizer.Magenta, e.Category().String())
case parameters:
return e.Params.Colorize()
-
case pe:
ps := e.PS
if ps == nil || ps.PE == nil {
return colorizer.Span(colorizer.Gray, "N/A")
}
return colorizer.Span(colorizer.Magenta, ps.PE.String())
-
case cstack:
return fmt.Sprintf("\n%s", e.Callstack.Colorize())
}
diff --git a/pkg/event/formatter_test.go b/pkg/event/formatter_test.go
index 044a4c128..657dba714 100644
--- a/pkg/event/formatter_test.go
+++ b/pkg/event/formatter_test.go
@@ -19,13 +19,14 @@
package event
import (
+ "github.com/rabbitstack/fibratus/pkg/event/params"
htypes "github.com/rabbitstack/fibratus/pkg/handle/types"
pstypes "github.com/rabbitstack/fibratus/pkg/ps/types"
"github.com/stretchr/testify/assert"
- kpars "github.com/rabbitstack/fibratus/pkg/event/params"
- "github.com/stretchr/testify/require"
"testing"
+
+ "github.com/stretchr/testify/require"
)
func TestTemplateUnknownField(t *testing.T) {
@@ -54,10 +55,10 @@ func TestFormat(t *testing.T) {
template := "{{ .Seq }} {{.CPU}} - ({{.Type}}) -- pid: {{ .Params.Pid }} ({{.Params}}) {{ .Meta }}"
f, err := NewFormatter(template)
require.NoError(t, err)
- params := Params{
- kpars.ProcessID: {Name: kpars.ProcessID, Type: kpars.PID, Value: uint32(876)},
+ pars := Params{
+ params.ProcessID: {Name: params.ProcessID, Type: params.PID, Value: uint32(876)},
}
- s := f.Format(&Event{CPU: uint8(4), Name: "CreateProcess", Seq: uint64(1999), Params: params, Metadata: map[MetadataKey]any{"key1": "value1"}})
+ s := f.Format(&Event{CPU: uint8(4), Type: CreateProcess, Seq: uint64(1999), Params: pars, Metadata: map[MetadataKey]any{"key1": "value1"}})
assert.Equal(t, "1999 4 - (CreateProcess) -- pid: 876 (pid➜ 876) key1: value1", string(s))
}
@@ -65,14 +66,13 @@ func TestFormatPS(t *testing.T) {
template := "{{ .Seq }} {{ .Process }} ({{ .Cwd }}) {{ .Ppid }} ({{ .Sid }})"
f, err := NewFormatter(template)
require.NoError(t, err)
- params := Params{
- kpars.ProcessID: {Name: kpars.ProcessID, Type: kpars.PID, Value: uint32(876)},
+ pars := Params{
+ params.ProcessID: {Name: params.ProcessID, Type: params.PID, Value: uint32(876)},
}
s := f.Format(&Event{
CPU: uint8(4),
- Name: "CreateProcess",
Seq: uint64(1999),
- Params: params,
+ Params: pars,
PS: &pstypes.PS{
Name: "cmd.exe",
Cwd: "C:/Windows/System32",
@@ -92,47 +92,86 @@ func TestNormalizeTemplate(t *testing.T) {
}
func TestIsTemplateBalanced(t *testing.T) {
- ok, pos := isTemplateBalanced("{{ .Seq }} {{.CPU}}")
- require.True(t, ok)
- assert.Equal(t, -1, pos)
-
- ok, pos = isTemplateBalanced("{{ .Seq }} ({{.CPU}}) [] {{.Type}}")
- require.True(t, ok)
- assert.Equal(t, -1, pos)
-
- ok, pos = isTemplateBalanced("{{ .Seq }} {.CPU}} {{.Type}}")
- require.False(t, ok)
- assert.Equal(t, 2, pos)
-
- ok, pos = isTemplateBalanced("{.Seq}")
- require.False(t, ok)
- assert.Equal(t, 1, pos)
-
- ok, pos = isTemplateBalanced("{{ .Seq }} .CPU }}")
- require.False(t, ok)
- assert.Equal(t, 2, pos)
-
- ok, pos = isTemplateBalanced("{{{ .Seq }} {{.CPU}} {{} {{ .Params }} { .Params.pid}}")
- require.False(t, ok)
- assert.Equal(t, 1, pos)
-
- ok, pos = isTemplateBalanced("{{ .Seq }} {{.CPU}} {{} {{ .Params }} { .Params.pid}}")
- require.False(t, ok)
- assert.Equal(t, 3, pos)
-
- ok, pos = isTemplateBalanced("({{ .Seq }}) {{.CPU}} {{}} {{ .Params }} { .Params.pid}}")
- require.False(t, ok)
- assert.Equal(t, 5, pos)
-
- ok, pos = isTemplateBalanced("{{ .Seq } {{.CPU}} {.Type}}")
- require.False(t, ok)
- assert.Equal(t, 1, pos)
+ tests := []struct {
+ name string
+ input string
+ wantOK bool
+ wantPos int
+ }{
+ {
+ name: "balanced templates",
+ input: "{{ .Seq }} {{.CPU}}",
+ wantOK: true,
+ wantPos: -1,
+ },
+ {
+ name: "balanced templates with other delimiters",
+ input: "{{ .Seq }} ({{.CPU}}) [] {{.Type}}",
+ wantOK: true,
+ wantPos: -1,
+ },
+ {
+ name: "single opening brace",
+ input: "{{ .Seq }} {.CPU}} {{.Type}}",
+ wantOK: false,
+ wantPos: 2,
+ },
+ {
+ name: "single template",
+ input: "{.Seq}",
+ wantOK: false,
+ wantPos: 1,
+ },
+ {
+ name: "unmatched closing braces",
+ input: "{{ .Seq }} .CPU }}",
+ wantOK: false,
+ wantPos: 2,
+ },
+ {
+ name: "triple opening brace",
+ input: "{{{ .Seq }} {{.CPU}} {{} {{ .Params }} { .Params.pid}}",
+ wantOK: false,
+ wantPos: 1,
+ },
+ {
+ name: "empty template",
+ input: "{{ .Seq }} {{.CPU}} {{} {{ .Params }} { .Params.pid}}",
+ wantOK: false,
+ wantPos: 3,
+ },
+ {
+ name: "empty template with other delimiters",
+ input: "({{ .Seq }}) {{.CPU}} {{}} {{ .Params }} { .Params.pid}}",
+ wantOK: false,
+ wantPos: 5,
+ },
+ {
+ name: "malformed closing delimiter",
+ input: "{{ .Seq } {{.CPU}} {.Type}}",
+ wantOK: false,
+ wantPos: 1,
+ },
+ {
+ name: "unmatched closing brace",
+ input: "{{ .Seq }} {{.CPU}} {.Type}}",
+ wantOK: false,
+ wantPos: 3,
+ },
+ {
+ name: "malformed template in complex input",
+ input: "{{ .Seq }} {{.CPU}} - ({{.Type}}) -- pid: {{]} {{ .Params.Pid }} ({{.Params}}) {{ .Meta }}",
+ wantOK: false,
+ wantPos: 4,
+ },
+ }
- ok, pos = isTemplateBalanced("{{ .Seq }} {{.CPU}} {.Type}}")
- require.False(t, ok)
- assert.Equal(t, 3, pos)
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ ok, pos := isTemplateBalanced(tt.input)
- ok, pos = isTemplateBalanced("{{ .Seq }} {{.CPU}} - ({{.Type}}) -- pid: {{]} {{ .Params.Pid }} ({{.Params}}) {{ .Meta }}")
- require.False(t, ok)
- assert.Equal(t, 4, pos)
+ require.Equal(t, tt.wantOK, ok)
+ assert.Equal(t, tt.wantPos, pos)
+ })
+ }
}
diff --git a/pkg/event/formatter_windows.go b/pkg/event/formatter_windows.go
index c441ae650..3c55f3f54 100644
--- a/pkg/event/formatter_windows.go
+++ b/pkg/event/formatter_windows.go
@@ -33,9 +33,9 @@ func (f *Formatter) Format(evt *Event) []byte {
tid: strconv.FormatUint(uint64(evt.Tid), 10),
seq: strconv.FormatUint(evt.Seq, 10),
cpu: strconv.FormatUint(uint64(evt.CPU), 10),
- typ: evt.Name,
- cat: evt.Category,
- desc: evt.Description,
+ typ: evt.Name(),
+ cat: evt.Category(),
+ desc: evt.Description(),
host: evt.Host,
meta: evt.Metadata.String(),
parameters: evt.Params.String(),
diff --git a/pkg/event/marshaller_test.go b/pkg/event/marshaller_test.go
index 37be2a3e6..2906b7f62 100644
--- a/pkg/event/marshaller_test.go
+++ b/pkg/event/marshaller_test.go
@@ -49,16 +49,13 @@ func TestMarshaller(t *testing.T) {
require.NoError(t, err)
evt := &Event{
- Type: CreateFile,
- Tid: 2484,
- PID: 859,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Timestamp: now,
- Category: File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: CreateFile,
+ Tid: 2484,
+ PID: 859,
+ CPU: 1,
+ Seq: 2,
+ Timestamp: now,
+ Host: "archrabbit",
Params: Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "\\Device\\HarddiskVolume2\\Windows\\system32\\user32.dll"},
@@ -77,7 +74,7 @@ func TestMarshaller(t *testing.T) {
b := evt.MarshalRaw()
require.NotEmpty(t, b)
- clone, err := NewFromCapture(b, capver.EvtSecV2)
+ clone, err := NewFromCapture(b, capver.EvtSecV3)
require.NoError(t, err)
assert.Equal(t, uint64(2), clone.Seq)
@@ -85,9 +82,9 @@ func TestMarshaller(t *testing.T) {
assert.Equal(t, uint32(2484), clone.Tid)
assert.Equal(t, CreateFile, clone.Type)
assert.Equal(t, uint8(1), clone.CPU)
- assert.Equal(t, "CreateFile", clone.Name)
- assert.Equal(t, File, clone.Category)
- assert.Equal(t, "Creates or opens a new file, directory, I/O device, pipe, console", clone.Description)
+ assert.Equal(t, "CreateFile", clone.Name())
+ assert.Equal(t, File, clone.Category())
+ assert.Equal(t, "Creates or opens a new file, directory, I/O device, pipe, console", clone.Description())
assert.Equal(t, "archrabbit", clone.Host)
assert.Equal(t, now, clone.Timestamp)
@@ -108,16 +105,13 @@ func TestMarshaller(t *testing.T) {
func TestEventMarshalJSON(t *testing.T) {
evt := &Event{
- Type: CreateFile,
- Tid: 2484,
- PID: 859,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Timestamp: time.Now(),
- Category: File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: CreateFile,
+ Tid: 2484,
+ PID: 859,
+ CPU: 1,
+ Seq: 2,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "\\Device\\HarddiskVolume2\\Windows\\system32\\user32.dll"},
@@ -225,16 +219,13 @@ func TestUnmarshalHugeHandles(t *testing.T) {
require.NoError(t, err)
evt := &Event{
- Type: CreateProcess,
- Tid: 2484,
- PID: 859,
- CPU: 1,
- Seq: 2,
- Name: "CreateProcess",
- Timestamp: time.Now(),
- Category: File,
- Host: "archrabbit",
- Description: "Creates a new process",
+ Type: CreateProcess,
+ Tid: 2484,
+ PID: 859,
+ CPU: 1,
+ Seq: 2,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "\\Device\\HarddiskVolume2\\Windows\\system32\\user32.dll"},
@@ -278,7 +269,7 @@ func TestUnmarshalHugeHandles(t *testing.T) {
}
s := evt.MarshalRaw()
- clone, err := NewFromCapture(s, capver.EvtSecV2)
+ clone, err := NewFromCapture(s, capver.EvtSecV3)
require.NoError(t, err)
require.NotNil(t, clone)
}
@@ -287,16 +278,13 @@ func TestEventMarshalJSONMultiple(t *testing.T) {
for i := 0; i < 10; i++ {
seq := uint64(i + 1)
evt := &Event{
- Type: CreateFile,
- Tid: 2484,
- PID: 859,
- CPU: 1,
- Seq: seq,
- Name: "CreateFile",
- Timestamp: time.Now(),
- Category: File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: CreateFile,
+ Tid: 2484,
+ PID: 859,
+ CPU: 1,
+ Seq: seq,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "\\Device\\HarddiskVolume2\\Windows\\system32\\user32.dll"},
@@ -367,16 +355,13 @@ func TestEventMarshalJSONMultiple(t *testing.T) {
func BenchmarkEventMarshalJSON(b *testing.B) {
evt := &Event{
- Type: CreateFile,
- Tid: 2484,
- PID: 859,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Timestamp: time.Now(),
- Category: File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: CreateFile,
+ Tid: 2484,
+ PID: 859,
+ CPU: 1,
+ Seq: 2,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "\\Device\\HarddiskVolume2\\Windows\\system32\\user32.dll"},
@@ -451,16 +436,13 @@ func BenchmarkEventMarshalJSON(b *testing.B) {
func BenchmarkEventMarshalJSONStdlib(b *testing.B) {
evt := &Event{
- Type: CreateFile,
- Tid: 2484,
- PID: 859,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Timestamp: time.Now(),
- Category: File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: CreateFile,
+ Tid: 2484,
+ PID: 859,
+ CPU: 1,
+ Seq: 2,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "\\Device\\HarddiskVolume2\\Windows\\system32\\user32.dll"},
@@ -537,16 +519,13 @@ func BenchmarkEventMarshalJSONStdlib(b *testing.B) {
func BenchmarkMarshal(b *testing.B) {
evt := &Event{
- Type: CreateFile,
- Tid: 2484,
- PID: 859,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Timestamp: time.Now(),
- Category: File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: CreateFile,
+ Tid: 2484,
+ PID: 859,
+ CPU: 1,
+ Seq: 2,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "\\Device\\HarddiskVolume2\\Windows\\system32\\user32.dll"},
@@ -565,16 +544,13 @@ func BenchmarkMarshal(b *testing.B) {
func BenchmarkUnmarshal(b *testing.B) {
evt := &Event{
- Type: CreateFile,
- Tid: 2484,
- PID: 859,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Timestamp: time.Now(),
- Category: File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: CreateFile,
+ Tid: 2484,
+ PID: 859,
+ CPU: 1,
+ Seq: 2,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "\\Device\\HarddiskVolume2\\Windows\\system32\\user32.dll"},
@@ -586,11 +562,11 @@ func BenchmarkUnmarshal(b *testing.B) {
buf := evt.MarshalRaw()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
- ke, err := NewFromCapture(buf, capver.EvtSecV2)
+ evt, err := NewFromCapture(buf, capver.EvtSecV3)
if err != nil {
b.Fatal(err)
}
- if ke.Name == "" {
+ if evt.Name() == "" {
b.Fatal("invalid unmarshal byte slice")
}
}
diff --git a/pkg/event/marshaller_windows.go b/pkg/event/marshaller_windows.go
index 5ded48295..1473e454b 100644
--- a/pkg/event/marshaller_windows.go
+++ b/pkg/event/marshaller_windows.go
@@ -64,21 +64,11 @@ func (e *Event) MarshalRaw() []byte {
b = append(b, bytes.WriteUint32(e.Tid)...)
// write type and CPU
- b = append(b, e.Type[:]...)
+ b = append(b, bytes.WriteUint16(uint16(e.Type))...)
b = append(b, e.CPU)
// for the string fields we have to write the length prior to
// the string buffer itself, so we can decode the string correctly
- //
- // write event name
- b = append(b, bytes.WriteUint16(uint16(len(e.Name)))...)
- b = append(b, e.Name...)
- // write category
- b = append(b, bytes.WriteUint16(uint16(len(e.Category)))...)
- b = append(b, e.Category...)
- // write description
- b = append(b, bytes.WriteUint16(uint16(len(e.Description)))...)
- b = append(b, e.Description...)
// write host name
b = append(b, bytes.WriteUint16(uint16(len(e.Host)))...)
b = append(b, e.Host...)
@@ -201,8 +191,6 @@ func (e *Event) UnmarshalRaw(b []byte, ver capver.Version) error {
e.PID = bytes.ReadUint32(b[8:])
e.Tid = bytes.ReadUint32(b[12:])
- // read type and CPU
- var typ Type
// set start index depending
// on event section version
var idx uint32
@@ -211,41 +199,25 @@ func (e *Event) UnmarshalRaw(b []byte, ver capver.Version) error {
idx = 33
case capver.EvtSecV2:
idx = 34
+ case capver.EvtSecV3:
+ idx = 18
}
- copy(typ[:], b[16:idx])
- e.Type = typ
+
+ e.Type = Type(bytes.ReadUint16(b[16:idx]))
e.CPU = b[idx : idx+1][0]
idx++ // increment index
var offset uint32
- // read event name
+ // read host name
l := bytes.ReadUint16(b[inc(idx, 0):])
buf := b[inc(idx, 2):]
offset = uint32(l)
- e.Name = string((*[1<<30 - 1]byte)(unsafe.Pointer(&buf[0]))[:l:l])
-
- // read category
- l = bytes.ReadUint16(b[inc(idx, 2)+offset:])
- buf = b[inc(idx, 4)+offset:]
- offset += uint32(l)
- e.Category = Category(string((*[1<<30 - 1]byte)(unsafe.Pointer(&buf[0]))[:l:l]))
-
- // read description
- l = bytes.ReadUint16(b[inc(idx, 4)+offset:])
- buf = b[inc(idx, 6)+offset:]
- offset += uint32(l)
- e.Description = string((*[1<<30 - 1]byte)(unsafe.Pointer(&buf[0]))[:l:l])
-
- // read host name
- l = bytes.ReadUint16(b[inc(idx, 6)+offset:])
- buf = b[inc(idx, 8)+offset:]
- offset += uint32(l)
e.Host = string((*[1<<30 - 1]byte)(unsafe.Pointer(&buf[0]))[:l:l])
// read timestamp
- l = bytes.ReadUint16(b[inc(idx, 8)+offset:])
- buf = b[inc(idx, 10)+offset:]
+ l = bytes.ReadUint16(b[inc(idx, 2)+offset:])
+ buf = b[inc(idx, 4)+offset:]
offset += uint32(l)
if len(buf) > 0 {
var err error
@@ -256,87 +228,87 @@ func (e *Event) UnmarshalRaw(b []byte, ver capver.Version) error {
}
// read parameters
- nparams := bytes.ReadUint16(b[inc(idx, 10)+offset:])
+ nparams := bytes.ReadUint16(b[inc(idx, 4)+offset:])
// accumulates the offset of all parameter name and value lengths
var poffset uint32
for i := 0; i < int(nparams); i++ {
- // read Param type
- typ := bytes.ReadUint16(b[inc(idx, 12)+offset+poffset:])
- // read Param name
- kparamNameLength := uint32(bytes.ReadUint16(b[inc(idx, 14)+offset+poffset:]))
- buf = b[inc(idx, 16)+offset+poffset:]
- kparamName := string((*[1<<30 - 1]byte)(unsafe.Pointer(&buf[0]))[:kparamNameLength:kparamNameLength])
+ // read param type
+ typ := bytes.ReadUint16(b[inc(idx, 6)+offset+poffset:])
+ // read param name
+ paramNameLength := uint32(bytes.ReadUint16(b[inc(idx, 8)+offset+poffset:]))
+ buf = b[inc(idx, 10)+offset+poffset:]
+ kparamName := string((*[1<<30 - 1]byte)(unsafe.Pointer(&buf[0]))[:paramNameLength:paramNameLength])
- pi := inc(idx, 16) // parameter index
+ pi := inc(idx, 10) // parameter index
var val params.Value
switch params.Type(typ) {
case params.AnsiString, params.UnicodeString, params.Path:
// read string parameter
- l := bytes.ReadUint16(b[pi+offset+kparamNameLength+poffset:])
- buf = b[inc(idx, 18)+offset+kparamNameLength+poffset:]
+ l := bytes.ReadUint16(b[pi+offset+paramNameLength+poffset:])
+ buf = b[inc(idx, 12)+offset+paramNameLength+poffset:]
if len(buf) > 0 {
val = string((*[1<<30 - 1]byte)(unsafe.Pointer(&buf[0]))[:l:l])
}
// increment parameter offset by string by type length + name length bytes + length of
// the string parameter + string parameter size
- poffset += kparamNameLength + 6 + uint32(l)
+ poffset += paramNameLength + 6 + uint32(l)
case params.Uint64, params.Address, params.Flags64:
- val = bytes.ReadUint64(b[pi+offset+kparamNameLength+poffset:])
+ val = bytes.ReadUint64(b[pi+offset+paramNameLength+poffset:])
// increment parameter offset by type length + name length sizes + size of uint64
- poffset += kparamNameLength + 4 + 8
+ poffset += paramNameLength + 4 + 8
case params.Int64:
- val = int64(bytes.ReadUint64(b[pi+offset+kparamNameLength+poffset:]))
+ val = int64(bytes.ReadUint64(b[pi+offset+paramNameLength+poffset:]))
// increment parameter offset by type length + name length sizes + size of int64
- poffset += kparamNameLength + 4 + 8
+ poffset += paramNameLength + 4 + 8
case params.Double:
- val = float64(bytes.ReadUint64(b[pi+offset+kparamNameLength+poffset:]))
- poffset += kparamNameLength + 4 + 8
+ val = float64(bytes.ReadUint64(b[pi+offset+paramNameLength+poffset:]))
+ poffset += paramNameLength + 4 + 8
case params.Float:
- val = float32(bytes.ReadUint32(b[pi+offset+kparamNameLength+poffset:]))
- poffset += kparamNameLength + 4 + 4
+ val = float32(bytes.ReadUint32(b[pi+offset+paramNameLength+poffset:]))
+ poffset += paramNameLength + 4 + 4
case params.IPv4:
- val = ip.ToIPv4(bytes.ReadUint32(b[pi+offset+kparamNameLength+poffset:]))
+ val = ip.ToIPv4(bytes.ReadUint32(b[pi+offset+paramNameLength+poffset:]))
// // increment by IPv4 length
- poffset += kparamNameLength + 4 + 4
+ poffset += paramNameLength + 4 + 4
case params.IPv6:
- val = ip.ToIPv6(b[pi+offset+kparamNameLength+poffset : pi+offset+kparamNameLength+poffset+16])
+ val = ip.ToIPv6(b[pi+offset+paramNameLength+poffset : pi+offset+paramNameLength+poffset+16])
// increment by IPv6 length
- poffset += kparamNameLength + 4 + 16
+ poffset += paramNameLength + 4 + 16
case params.PID, params.TID:
- val = bytes.ReadUint32(b[pi+offset+kparamNameLength+poffset:])
- poffset += kparamNameLength + 4 + 4
+ val = bytes.ReadUint32(b[pi+offset+paramNameLength+poffset:])
+ poffset += paramNameLength + 4 + 4
case params.Int32:
- val = int32(bytes.ReadUint32(b[pi+offset+kparamNameLength+poffset:]))
- poffset += kparamNameLength + 4 + 4
+ val = int32(bytes.ReadUint32(b[pi+offset+paramNameLength+poffset:]))
+ poffset += paramNameLength + 4 + 4
case params.Uint32, params.Enum, params.Flags, params.Status:
- val = bytes.ReadUint32(b[pi+offset+kparamNameLength+poffset:])
- poffset += kparamNameLength + 4 + 4
+ val = bytes.ReadUint32(b[pi+offset+paramNameLength+poffset:])
+ poffset += paramNameLength + 4 + 4
case params.Uint16, params.Port:
- val = bytes.ReadUint16(b[pi+offset+kparamNameLength+poffset:])
- poffset += kparamNameLength + 4 + 2
+ val = bytes.ReadUint16(b[pi+offset+paramNameLength+poffset:])
+ poffset += paramNameLength + 4 + 2
case params.Int16:
- val = int16(bytes.ReadUint16(b[pi+offset+kparamNameLength+poffset:]))
- poffset += kparamNameLength + 4 + 2
+ val = int16(bytes.ReadUint16(b[pi+offset+paramNameLength+poffset:]))
+ poffset += paramNameLength + 4 + 2
case params.Uint8:
- val = b[pi+offset+kparamNameLength+poffset : pi+offset+kparamNameLength+poffset+1][0]
- poffset += kparamNameLength + 4 + 1
+ val = b[pi+offset+paramNameLength+poffset : pi+offset+paramNameLength+poffset+1][0]
+ poffset += paramNameLength + 4 + 1
case params.Int8:
- val = int8(b[pi+offset+kparamNameLength+poffset : pi+offset+kparamNameLength+poffset+1][0])
- poffset += kparamNameLength + 4 + 1
+ val = int8(b[pi+offset+paramNameLength+poffset : pi+offset+paramNameLength+poffset+1][0])
+ poffset += paramNameLength + 4 + 1
case params.Bool:
- v := b[pi+offset+kparamNameLength+poffset : pi+offset+kparamNameLength+poffset+1][0]
+ v := b[pi+offset+paramNameLength+poffset : pi+offset+paramNameLength+poffset+1][0]
if v == 1 {
val = true
} else {
val = false
}
- poffset += kparamNameLength + 4 + 1
+ poffset += paramNameLength + 4 + 1
case params.Time:
// read ts length
- l := bytes.ReadUint16(b[pi+offset+kparamNameLength+poffset:])
- buf = b[inc(idx, 18)+offset+kparamNameLength+poffset:]
+ l := bytes.ReadUint16(b[pi+offset+paramNameLength+poffset:])
+ buf = b[inc(idx, 12)+offset+paramNameLength+poffset:]
if len(buf) > 0 {
var err error
val, err = time.Parse(time.RFC3339Nano, string((*[1<<30 - 1]byte)(unsafe.Pointer(&buf[0]))[:l:l]))
@@ -344,19 +316,19 @@ func (e *Event) UnmarshalRaw(b []byte, ver capver.Version) error {
unmarshalTimestampErrors.Add(1)
}
}
- poffset += kparamNameLength + 6 + uint32(l)
+ poffset += paramNameLength + 6 + uint32(l)
case params.Slice:
// read slice element type
- typ := b[pi+offset+kparamNameLength+poffset]
+ typ := b[pi+offset+paramNameLength+poffset]
// read slice size
- l := bytes.ReadUint16(b[inc(idx, 17)+offset+kparamNameLength+poffset:])
+ l := bytes.ReadUint16(b[inc(idx, 11)+offset+paramNameLength+poffset:])
var off uint32
switch typ {
case 's':
s := make([]string, l)
for i := 0; i < int(l); i++ {
- size := bytes.ReadUint16(b[inc(idx, 19)+offset+kparamNameLength+poffset+off:])
- buf := b[inc(idx, 22)+offset+kparamNameLength+poffset+off:]
+ size := bytes.ReadUint16(b[inc(idx, 13)+offset+paramNameLength+poffset+off:])
+ buf := b[inc(idx, 15)+offset+paramNameLength+poffset+off:]
s[i] = string((*[1<<30 - 1]byte)(unsafe.Pointer(&buf[0]))[:size:size])
off += 2 + uint32(size)
}
@@ -364,19 +336,19 @@ func (e *Event) UnmarshalRaw(b []byte, ver capver.Version) error {
case '8':
v := make([]uint64, l)
for i := 0; i < int(l); i++ {
- bytes.ReadUint64(b[inc(idx, 22)+offset+kparamNameLength+poffset+off:])
+ bytes.ReadUint64(b[inc(idx, 16)+offset+paramNameLength+poffset+off:])
off += 8
}
val = v
}
- poffset += kparamNameLength + 4 + 1 + 2 + off
+ poffset += paramNameLength + 4 + 1 + 2 + off
case params.Binary, params.SID, params.WbemSID:
- l := bytes.ReadUint32(b[pi+offset+kparamNameLength+poffset:])
- buf = b[inc(idx, 18)+offset+kparamNameLength+poffset:]
+ l := bytes.ReadUint32(b[pi+offset+paramNameLength+poffset:])
+ buf = b[inc(idx, 12)+offset+paramNameLength+poffset:]
if len(buf) > 0 {
val = buf[:l]
}
- poffset += kparamNameLength + 8 + l
+ poffset += paramNameLength + 8 + l
}
if val != nil {
@@ -387,16 +359,16 @@ func (e *Event) UnmarshalRaw(b []byte, ver capver.Version) error {
offset += poffset
// read metadata tags
- ntags := bytes.ReadUint16(b[inc(idx, 12)+offset:])
+ ntags := bytes.ReadUint16(b[inc(idx, 6)+offset:])
var moffset uint32
for i := 0; i < int(ntags); i++ {
// read key
- klen := uint32(bytes.ReadUint16(b[inc(idx, 14)+offset+moffset:]))
- buf = b[inc(idx, 16)+offset+moffset:]
+ klen := uint32(bytes.ReadUint16(b[inc(idx, 8)+offset+moffset:]))
+ buf = b[inc(idx, 10)+offset+moffset:]
key := string((*[1<<30 - 1]byte)(unsafe.Pointer(&buf[0]))[:klen:klen])
// read value
- vlen := uint32(bytes.ReadUint16(b[inc(idx, 16)+offset+klen+moffset:]))
- buf = b[inc(idx, 18)+offset+klen+moffset:]
+ vlen := uint32(bytes.ReadUint16(b[inc(idx, 10)+offset+klen+moffset:]))
+ buf = b[inc(idx, 12)+offset+klen+moffset:]
value := string((*[1<<30 - 1]byte)(unsafe.Pointer(&buf[0]))[:vlen:vlen])
// increment the offset by the length of the key + length value + size of uint16 * 2
// that corresponds to bytes storing the lengths of keys/values
@@ -409,9 +381,9 @@ func (e *Event) UnmarshalRaw(b []byte, ver capver.Version) error {
offset += moffset
// read process state
- sec := section.Read(b[inc(idx, 14)+offset:])
+ sec := section.Read(b[inc(idx, 8)+offset:])
if sec.Size() != 0 {
- ps, err := ptypes.NewFromCapture(b[inc(idx, 24)+offset:], sec)
+ ps, err := ptypes.NewFromCapture(b[inc(idx, 18)+offset:], sec)
if err != nil {
return err
}
@@ -441,9 +413,9 @@ func (e *Event) MarshalJSON() []byte {
js.writeObjectField("tid").writeUint32(e.Tid).writeMore()
js.writeObjectField("cpu").writeUint8(e.CPU).writeMore()
- js.writeObjectField("name").writeString(e.Name).writeMore()
- js.writeObjectField("category").writeString(string(e.Category)).writeMore()
- js.writeObjectField("description").writeString(e.Description).writeMore()
+ js.writeObjectField("name").writeString(e.Name()).writeMore()
+ js.writeObjectField("category").writeString(e.Category().String()).writeMore()
+ js.writeObjectField("description").writeString(e.Description()).writeMore()
js.writeObjectField("host").writeString(e.Host).writeMore()
timestamp := make([]byte, 0)
diff --git a/pkg/event/metainfo_windows.go b/pkg/event/metainfo_windows.go
index 9e7a7b941..4817fbcd2 100644
--- a/pkg/event/metainfo_windows.go
+++ b/pkg/event/metainfo_windows.go
@@ -23,229 +23,147 @@ import (
"slices"
)
+// Flags represents the event flags
+type Flags uint8
+
+const (
+ // OnlyState indicates the event produces internal state
+ // and is never published to the event stream.
+ OnlyState Flags = 1 << 1
+
+ // StateSnapshot indicates that the event is published once
+ // at startup time and populates the internal state.
+ StateSnapshot Flags = 1 << 2
+
+ // WaitStack indicates that the event awaits the stack walk
+ // event that carries call stack return addresses.
+ WaitStack Flags = 1 << 3
+)
+
// Info describes the event meta info such as human-readable name, category and description.
type Info struct {
// Name is the human-readable representation of the event (e.g. CreateProcess, DeleteFile).
Name string
- // Category designates the category to which event pertains. (e.g. process, net)
+ // Category designates the category to which event pertains. (e.g. process, network)
Category Category
+ // Subcategory designates the event subcategory if any. For example, the network category
+ // can be further subcategorized, such as DNS subcategory.
+ Subcategory Subcategory
+ // Source describes the event source origin for this event. For example, if it was captured
+ // from the NT Kernel Logger or a different event source.
+ Source Source
// Description is the short explanation that describes the purpose of the event.
Description string
+ // Flags describes additional properties of the event.
+ Flags Flags
}
-var events = map[Type]Info{
- CreateProcess: {"CreateProcess", Process, "Creates a new process and its primary thread"},
- TerminateProcess: {"TerminateProcess", Process, "Terminates the process and all of its threads"},
- OpenProcess: {"OpenProcess", Process, "Opens the process handle"},
- CreateThread: {"CreateThread", Thread, "Creates a thread to execute within the virtual address space of the calling process"},
- TerminateThread: {"TerminateThread", Thread, "Terminates a thread within the process"},
- OpenThread: {"OpenThread", Thread, "Opens the thread handle"},
- SetThreadContext: {"SetThreadContext", Thread, "Sets the thread context"},
- ReadFile: {"ReadFile", File, "Reads data from the file or I/O device"},
- WriteFile: {"WriteFile", File, "Writes data to the file or I/O device"},
- CreateFile: {"CreateFile", File, "Creates or opens a file or I/O device"},
- CloseFile: {"CloseFile", File, "Closes the file handle"},
- DeleteFile: {"DeleteFile", File, "Removes the file from the file system"},
- RenameFile: {"RenameFile", File, "Changes the file name"},
- SetFileInformation: {"SetFileInformation", File, "Sets the file meta information"},
- EnumDirectory: {"EnumDirectory", File, "Enumerates a directory or dispatches a directory change notification to registered listeners"},
- RegCreateKey: {"RegCreateKey", Registry, "Creates a registry key or opens it if the key already exists"},
- RegOpenKey: {"RegOpenKey", Registry, "Opens the registry key"},
- RegCloseKey: {"RegCloseKey", Registry, "Closes the registry key"},
- RegSetValue: {"RegSetValue", Registry, "Sets the data for the value of a registry key"},
- RegQueryValue: {"RegQueryValue", Registry, "Reads the data for the value of a registry key"},
- RegQueryKey: {"RegQueryKey", Registry, "Enumerates subkeys of the parent key"},
- RegDeleteKey: {"RegDeleteKey", Registry, "Removes the registry key"},
- RegDeleteValue: {"RegDeleteValue", Registry, "Removes the registry value"},
- AcceptTCPv4: {"Accept", Net, "Accepts the connection request from the socket queue"},
- AcceptTCPv6: {"Accept", Net, "Accepts the connection request from the socket queue"},
- SendTCPv4: {"Send", Net, "Sends data over the wire"},
- SendTCPv6: {"Send", Net, "Sends data over the wire"},
- SendUDPv4: {"Send", Net, "Sends data over the wire"},
- SendUDPv6: {"Send", Net, "Sends data over the wire"},
- RecvTCPv4: {"Recv", Net, "Receives data from the socket"},
- RecvTCPv6: {"Recv", Net, "Receives data from the socket"},
- RecvUDPv4: {"Recv", Net, "Receives data from the socket"},
- RecvUDPv6: {"Recv", Net, "Receives data from the socket"},
- ConnectTCPv4: {"Connect", Net, "Connects establishes a connection to the socket"},
- ConnectTCPv6: {"Connect", Net, "Connects establishes a connection to the socket"},
- DisconnectTCPv4: {"Disconnect", Net, "Terminates data reception on the socket"},
- DisconnectTCPv6: {"Disconnect", Net, "Terminates data reception on the socket"},
- ReconnectTCPv4: {"Reconnect", Net, "Reconnects to the socket"},
- ReconnectTCPv6: {"Reconnect", Net, "Reconnects to the socket"},
- RetransmitTCPv4: {"Retransmit", Net, "Retransmits unacknowledged TCP segments"},
- RetransmitTCPv6: {"Retransmit", Net, "Retransmits unacknowledged TCP segments"},
- LoadModule: {"LoadModule", Module, "Loads the module into the address space of the calling process"},
- UnloadModule: {"UnloadModule", Module, "Unloads the module from the address space of the calling process"},
- VirtualAlloc: {"VirtualAlloc", Mem, "Reserves, commits, or changes the state of a region of memory within the process virtual address space"},
- VirtualFree: {"VirtualFree", Mem, "Releases or decommits a region of memory within the process virtual address space"},
- MapViewFile: {"MapViewFile", File, "Maps a view of a file mapping into the address space of a calling process"},
- UnmapViewFile: {"UnmapViewFile", File, "Unmaps a mapped view of a file from the calling process's address space"},
- QueryDNS: {"QueryDns", Net, "Sends a DNS query to the name server"},
- ReplyDNS: {"ReplyDNS", Net, "Receives the response from the DNS server"},
- CreateSymbolicLinkObject: {"CreateSymbolicLinkObject", Object, "Creates the symbolic link within the object manager directory"},
-}
+var table = [MaxEvent]Info{
+ CreateProcess: {Name: "CreateProcess", Category: Process, Source: SystemLogger, Description: "Creates a new process and its primary thread", Flags: WaitStack},
+ TerminateProcess: {Name: "TerminateProcess", Category: Process, Source: SystemLogger, Description: "Terminates the process and all of its threads"},
+ OpenProcess: {Name: "OpenProcess", Category: Process, Source: SecurityTelemetryLogger, Description: "Opens the process handle"},
+ ProcessRundown: {Name: "ProcessRundown", Category: Process, Source: SecurityTelemetryLogger, Description: "Builds the snapshot state of running processes in the system.", Flags: OnlyState | StateSnapshot},
+ CreateProcessInternal: {Name: "CreateProcessInternal", Category: Process, Source: SystemLogger, Description: "Only purpose of this event is to enrich the process state with some extra attributes. Never published to the event stream", Flags: OnlyState},
+ ProcessRundownInternal: {Name: "ProcessRundownInternal", Category: Process, Source: SecurityTelemetryLogger, Description: "Opens the process handle", Flags: OnlyState | StateSnapshot},
-var types = map[string]Type{
- "CreateProcess": CreateProcess,
- "TerminateProcess": TerminateProcess,
- "OpenProcess": OpenProcess,
- "CreateThread": CreateThread,
- "TerminateThread": TerminateThread,
- "OpenThread": OpenThread,
- "SetThreadContext": SetThreadContext,
- "LoadModule": LoadModule,
- "UnloadModule": UnloadModule,
- "CreateFile": CreateFile,
- "CloseFile": CloseFile,
- "ReadFile": ReadFile,
- "WriteFile": WriteFile,
- "SetFileInformation": SetFileInformation,
- "DeleteFile": DeleteFile,
- "RenameFile": RenameFile,
- "EnumDirectory": EnumDirectory,
- "RegCreateKey": RegCreateKey,
- "RegOpenKey": RegOpenKey,
- "RegSetValue": RegSetValue,
- "RegQueryValue": RegQueryValue,
- "RegQueryKey": RegQueryKey,
- "RegDeleteKey": RegDeleteKey,
- "RegDeleteValue": RegDeleteValue,
- "RegCloseKey": RegCloseKey,
- "AcceptTCP4": AcceptTCPv4,
- "AcceptTCP6": AcceptTCPv6,
- "SendTCP4": SendTCPv4,
- "SendTCP6": SendTCPv6,
- "SendUDP4": SendUDPv4,
- "SendUDP6": SendUDPv6,
- "RecvTCP4": RecvTCPv4,
- "RecvTCP6": RecvTCPv6,
- "RecvUDP4": RecvUDPv4,
- "RecvUDP6": RecvUDPv6,
- "ConnectTCP4": ConnectTCPv4,
- "ConnectTCP6": ConnectTCPv6,
- "ReconnectTCP4": ReconnectTCPv4,
- "ReconnectTCP6": ReconnectTCPv6,
- "DisconnectTCP4": DisconnectTCPv4,
- "DisconnectTCP6": DisconnectTCPv6,
- "RetransmitTCP4": RetransmitTCPv4,
- "RetransmitTCP6": RetransmitTCPv6,
- "VirtualAlloc": VirtualAlloc,
- "VirtualFree": VirtualFree,
- "MapViewFile": MapViewFile,
- "UnmapViewFile": UnmapViewFile,
- "QueryDns": QueryDNS,
- "ReplyDns": ReplyDNS,
- "CreateSymbolicLinkObject": CreateSymbolicLinkObject,
-}
+ CreateThread: {Name: "CreateThread", Category: Thread, Source: SystemLogger, Description: "Creates a thread to execute within the virtual address space of the calling process", Flags: WaitStack},
+ TerminateThread: {Name: "TerminateThread", Category: Thread, Source: SystemLogger, Description: "Terminates a thread within the process", Flags: WaitStack},
+ OpenThread: {Name: "OpenThread", Category: Thread, Source: SecurityTelemetryLogger, Description: "Opens the thread handle"},
+ SetThreadContext: {Name: "SetThreadContext", Category: Thread, Source: SecurityTelemetryLogger, Description: "Sets the thread context"},
+ StackWalk: {Name: "StackWalk", Category: Thread, Source: SystemLogger, Description: "Delivers call stack return addresses. Never published to the event stream", Flags: OnlyState},
+ ThreadRundown: {Name: "ThreadRundown", Category: Thread, Source: SystemLogger, Description: "Builds the snapshot state of running threads in the system", Flags: OnlyState | StateSnapshot},
-// All returns all event types.
-func All() []Type {
- s := make([]Type, 0, len(types))
- for _, typ := range types {
- s = append(s, typ)
- }
- return s
-}
+ UnloadModule: {Name: "UnloadModule", Category: Module, Source: SystemLogger, Description: "Unloads the module from the address space of the calling process"},
+ LoadModule: {Name: "LoadModule", Category: Module, Source: SystemLogger, Description: "Loads the module into the address space of the calling process", Flags: WaitStack},
+ ModuleRundown: {Name: "ModuleRundown", Category: Module, Source: SystemLogger, Description: "Builds the snapshot of loaded modules in the system", Flags: OnlyState | StateSnapshot},
+ LoadModuleInternal: {Name: "LoadModuleInternal", Category: Module, Source: SecurityTelemetryLogger, Description: "Only purpose is to populate the module state. Never published to the event stream", Flags: OnlyState},
-// AllWithState returns all event types +
-// event types used for state management.
-func AllWithState() []Type {
- s := All()
-
- s = append(s, ProcessRundown)
- s = append(s, ThreadRundown)
- s = append(s, ModuleRundown)
- s = append(s, FileRundown)
- s = append(s, RegKCBRundown)
- s = append(s, RegCreateKCB)
- s = append(s, RegDeleteKCB)
- s = append(s, FileOpEnd)
- s = append(s, ReleaseFile)
- s = append(s, MapFileRundown)
- s = append(s, StackWalk)
- s = append(s, CreateProcessInternal)
- s = append(s, ProcessRundownInternal)
- s = append(s, LoadModuleInternal)
- s = append(s, RegSetValueInternal)
-
- return s
-}
+ RegCreateKey: {Name: "RegCreateKey", Category: Registry, Source: SystemLogger, Description: "Creates a registry key or opens it if the key already exists", Flags: WaitStack},
+ RegOpenKey: {Name: "RegOpenKey", Category: Registry, Source: SystemLogger, Description: "Opens the registry key"},
+ RegDeleteKey: {Name: "RegDeleteKey", Category: Registry, Source: SystemLogger, Description: "Removes the registry key", Flags: WaitStack},
+ RegQueryKey: {Name: "RegQueryKey", Category: Registry, Source: SystemLogger, Description: "Enumerates subkeys of the parent key"},
+ RegSetValue: {Name: "RegSetValue", Category: Registry, Source: SystemLogger, Description: "Sets the data for the value of a registry key", Flags: WaitStack},
+ RegSetValueInternal: {Name: "RegSetValueInternal", Category: Registry, Source: SecurityTelemetryLogger, Description: "Closes the registry key", Flags: OnlyState},
+ RegDeleteValue: {Name: "RegDeleteValue", Category: Registry, Source: SystemLogger, Description: "Removes the registry value", Flags: WaitStack},
+ RegQueryValue: {Name: "RegQueryValue", Category: Registry, Source: SystemLogger, Description: "Reads the data for the value of a registry key"},
+ RegCloseKey: {Name: "RegCloseKey", Category: Registry, Source: SystemLogger, Description: "Closes the registry key. Never published to the event stream", Flags: OnlyState},
+ RegCreateKCB: {Name: "RegCreateKCB", Category: Registry, Source: SystemLogger, Description: "Create the Key Control Block. Never published to the event stream", Flags: OnlyState},
+ RegDeleteKCB: {Name: "RegDeleteKCB", Category: Registry, Source: SystemLogger, Description: "Removes the Key Control Block. Never published to the event stream", Flags: OnlyState},
+ RegKCBRundown: {Name: "RegKCBRundown", Category: Registry, Source: SystemLogger, Description: "Builds the snapshot of existing Key Control Block objects", Flags: OnlyState | StateSnapshot},
-// MaxTypeID returns the maximum event type (hook id) value.
-func MaxTypeID() uint16 {
- types := AllWithState()
- ids := make([]uint16, len(types))
- for i, t := range types {
- ids[i] = t.HookID()
- }
- return slices.Max(ids)
-}
+ CreateFile: {Name: "CreateFile", Category: File, Source: SystemLogger, Description: "Creates or opens a new file, directory, I/O device, pipe, console"},
+ ReleaseFile: {Name: "ReleaseFile", Category: File, Source: SystemLogger, Description: "Closes the last handle to the file object. Never published to the event stream", Flags: OnlyState},
+ CloseFile: {Name: "CloseFile", Category: File, Source: SystemLogger, Description: "Closes the file handle. Never published to the event stream", Flags: OnlyState},
+ ReadFile: {Name: "ReadFile", Category: File, Source: SystemLogger, Description: "Reads data from the file or I/O device"},
+ WriteFile: {Name: "WriteFile", Category: File, Source: SystemLogger, Description: "Writes data to the file or I/O device"},
+ SetFileInformation: {Name: "SetFileInformation", Category: File, Source: SystemLogger, Description: "Sets the file meta information"},
+ DeleteFile: {Name: "DeleteFile", Category: File, Source: SystemLogger, Description: "Removes the file from the file system", Flags: WaitStack},
+ RenameFile: {Name: "RenameFile", Category: File, Source: SystemLogger, Description: "Changes the file name", Flags: WaitStack},
+ EnumDirectory: {Name: "EnumDirectory", Category: File, Source: SystemLogger, Description: "Enumerates a directory or dispatches a directory change notification to registered listeners"},
+ FileRundown: {Name: "FileRundown", Category: File, Source: SystemLogger, Description: "Builds the snapshot of existing file objects", Flags: OnlyState | StateSnapshot},
+ FileOpEnd: {Name: "FileOpEnd", Category: File, Source: SystemLogger, Description: "Reports the I/O request packet status. Never published to the event stream", Flags: OnlyState},
-// TypeToEventInfo maps the event type to the structure storing detailed information about the event.
-func TypeToEventInfo(typ Type) Info {
- if info, ok := events[typ]; ok {
- return info
- }
- return Info{Name: "N/A", Category: Unknown}
+ Accept: {Name: "Accept", Category: Network, Source: SystemLogger, Description: "Accepts the connection request from the socket queue"},
+ Send: {Name: "Send", Category: Network, Source: SystemLogger, Description: "Sends data over the wire"},
+ Recv: {Name: "Recv", Category: Network, Source: SystemLogger, Description: "Receives data from the socket"},
+ Connect: {Name: "Connect", Category: Network, Source: SystemLogger, Description: "Connects establishes a connection to the socket"},
+ Disconnect: {Name: "Disconnect", Category: Network, Source: SystemLogger, Description: "Terminates data reception on the socket"},
+ Reconnect: {Name: "Reconnect", Category: Network, Source: SystemLogger, Description: "Reconnects to the socket"},
+ Retransmit: {Name: "Retransmit", Category: Network, Source: SystemLogger, Description: "Retransmits unacknowledged TCP segments"},
+ QueryDNS: {Name: "QueryDns", Category: Network, Subcategory: DNS, Source: SecurityTelemetryLogger, Description: "Sends a DNS query to the name server"},
+ ReplyDNS: {Name: "ReplyDNS", Category: Network, Subcategory: DNS, Source: SecurityTelemetryLogger, Description: "Receives the response from the DNS server"},
+
+ MapViewOfSection: {Name: "MapViewOfSection", Category: Memory, Source: SystemLogger, Description: "Maps a view of a file mapping into the address space of a calling process"},
+ UnmapViewOfSection: {Name: "UnmapViewOfSection", Category: Memory, Source: SystemLogger, Description: "Unmaps a mapped view of a file from the calling process's address space"},
+ MapViewSectionRundown: {Name: "MapViewSectionRundown", Category: Memory, Source: SystemLogger, Description: "Builds the snapshot of existing memory section views", Flags: OnlyState | StateSnapshot},
+ VirtualAlloc: {Name: "VirtualAlloc", Category: Memory, Source: SystemLogger, Description: "Reserves, commits, or changes the state of a region of memory within the process virtual address space", Flags: WaitStack},
+ VirtualFree: {Name: "VirtualFree", Category: Memory, Source: SystemLogger, Description: "Releases or decommits a region of memory within the process virtual address space"},
+
+ CreateSymbolicLinkObject: {Name: "CreateSymbolicLinkObject", Category: Object, Source: SecurityTelemetryLogger, Description: "Creates the symbolic link within the object manager directory"},
}
-// NameToType converts a human-readable event name to its internal type representation.
-func NameToType(name string) Type {
- if typ, ok := types[name]; ok {
- return typ
+// All returns all event types.
+func AllTypes() []Type {
+ types := make([]Type, 0)
+ for i := range table {
+ if Type(i) == Unknown {
+ continue
+ }
+ types = append(types, Type(i))
}
- return UnknownType
+ return types
}
-// NameToTypes maps the event name to internal type representations, specifically, network
-// events that have multiple internal types for a single event name. For example, the Accept
-// event name has AcceptTCP4 and AcceptTCP6 types.
-func NameToTypes(name string) []Type {
- switch name {
- case "Accept":
- return []Type{AcceptTCPv4, AcceptTCPv6}
- case "Send":
- return []Type{SendTCPv4, SendTCPv6, SendUDPv4, SendUDPv6}
- case "Recv":
- return []Type{RecvTCPv4, RecvTCPv6, RecvUDPv4, RecvUDPv6}
- case "Connect":
- return []Type{ConnectTCPv4, ConnectTCPv6}
- case "Reconnect":
- return []Type{ReconnectTCPv4, ReconnectTCPv6}
- case "Disconnect":
- return []Type{DisconnectTCPv4, DisconnectTCPv6}
- case "Retransmit":
- return []Type{RetransmitTCPv4, RetransmitTCPv6}
- default:
- return []Type{NameToType(name)}
- }
+// GetTypeInfo returns metadata about the specified event type.
+func GetTypeInfo(typ Type) Info {
+ return table[typ]
}
-// GetTypesMeta returns event types metadata.
-func GetTypesMeta() []Info {
- typs := make([]Info, 0)
-outer:
- for _, ev := range events {
- for _, typ := range typs {
- if typ.Name == ev.Name {
- continue outer
- }
- }
- typs = append(typs, ev)
- }
- slices.SortFunc(typs, func(a, b Info) int {
+// GetTypesInfo returns event types metadata excluding only-state events.
+func GetTypesInfo() []Info {
+ t := table[:]
+ t = slices.DeleteFunc(t, func(info Info) bool {
+ return info.Flags&OnlyState != 0 || info.Name == ""
+ })
+ slices.SortFunc(t, func(a, b Info) int {
return cmp.Or(cmp.Compare(a.Category, b.Category), cmp.Compare(a.Name, b.Name))
})
- return typs
+ return t
}
-// IsKnown indicates if the event type is known given the event name.
-func IsKnown(name string) bool {
- for _, evt := range GetTypesMeta() {
- if evt.Name == name {
- return true
- }
+// NameToType converts a human-readable event name to its internal type representation.
+func ParseType(s string) (Type, bool) {
+ i := slices.IndexFunc(table[:], func(info Info) bool {
+ return info.Name == s
+ })
+ if i == -1 {
+ return Unknown, false
}
- return false
+ return Type(i), true
+}
+
+// IsKnown indicates if the event type is known given the event name.
+func IsTypeKnown(s string) (exists bool) {
+ _, exists = ParseType(s)
+ return
}
diff --git a/pkg/event/metainfo_windows_test.go b/pkg/event/metainfo_windows_test.go
index e23be0d5c..3c5096555 100644
--- a/pkg/event/metainfo_windows_test.go
+++ b/pkg/event/metainfo_windows_test.go
@@ -19,28 +19,33 @@
package event
import (
- "github.com/stretchr/testify/assert"
"testing"
-)
-
-func TestEventNameToType(t *testing.T) {
- typ := NameToType("CreateProcess")
- assert.Equal(t, CreateProcess, typ)
+ "github.com/stretchr/testify/assert"
+)
- typ = NameToType("CreateRemoteThread")
- assert.Equal(t, UnknownType, typ)
+func TestParseType(t *testing.T) {
+ var tests = []struct {
+ name string
+ expectedType Type
+ }{
+ {"CreateProcess", CreateProcess},
+ {"CreateRemoteThread", Unknown},
+ {"FileOpEnd", FileOpEnd},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ etype, _ := ParseType(tt.name)
+ assert.Equal(t, tt.expectedType, etype)
+ })
+ }
}
func TestEventToEventInfo(t *testing.T) {
- info := TypeToEventInfo(CreateProcess)
+ info := GetTypeInfo(CreateProcess)
assert.Equal(t, "CreateProcess", info.Name)
assert.Equal(t, Process, info.Category)
assert.Equal(t, "Creates a new process and its primary thread", info.Description)
-
- info = TypeToEventInfo(UnknownType)
- assert.Equal(t, "N/A", info.Name)
- assert.Equal(t, Unknown, info.Category)
- assert.Empty(t, info.Description)
}
diff --git a/pkg/event/param_decoder_windows.go b/pkg/event/param_decoder_windows.go
index 813247a70..6f55d224a 100644
--- a/pkg/event/param_decoder_windows.go
+++ b/pkg/event/param_decoder_windows.go
@@ -25,6 +25,7 @@ import (
"github.com/rabbitstack/fibratus/pkg/event/params"
"github.com/rabbitstack/fibratus/pkg/fs"
+ "github.com/rabbitstack/fibratus/pkg/network"
"github.com/rabbitstack/fibratus/pkg/sys/etw"
"github.com/rabbitstack/fibratus/pkg/util/filetime"
"github.com/rabbitstack/fibratus/pkg/util/key"
@@ -149,8 +150,8 @@ func (d *ParamDecoder) DecodeRegSetValueInternal(r *etw.EventRecord, e *Event) {
// 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:
+ switch e.Type {
+ case CreateFile:
// typedef struct _PERFINFO_FILE_CREATE {
// LONG_PTR Irp;
// ULONG_PTR FileObject;
@@ -173,7 +174,7 @@ func (d *ParamDecoder) DecodeFile(r *etw.EventRecord, e *Event) {
e.AppendParam(params.NTStatus, params.Status, status)
e.AppendEnum(params.FileOperation, disposition, fs.FileCreateDispositions)
e.AppendParam(params.Callstack, params.Slice, r.ReadEventHeaderFileExtendedDataItemsCallstack())
- case FileOpEndID:
+ case FileOpEnd:
// typedef struct _PERFINFO_FILE_OPERATION_END {
// ULONG_PTR Irp;
// ULONG_PTR ExtraInformation;
@@ -182,7 +183,7 @@ func (d *ParamDecoder) DecodeFile(r *etw.EventRecord, e *Event) {
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:
+ case MapViewOfSection, UnmapViewOfSection, MapViewSectionRundown:
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))
@@ -190,7 +191,7 @@ func (d *ParamDecoder) DecodeFile(r *etw.EventRecord, e *Event) {
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:
+ case SetFileInformation, DeleteFile, RenameFile:
// DeleteFile, RenameFile, and SetFileInformation share the same layout
// typedef struct _PERFINFO_FILE_INFORMATION {
// ULONG_PTR Irp;
@@ -206,7 +207,7 @@ func (d *ParamDecoder) DecodeFile(r *etw.EventRecord, e *Event) {
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:
+ case ReleaseFile, CloseFile:
// typedef struct _PERFINFO_FILE_SIMPLE_OPERATION {
// ULONG_PTR Irp;
// ULONG_PTR FileObject;
@@ -217,7 +218,7 @@ func (d *ParamDecoder) DecodeFile(r *etw.EventRecord, e *Event) {
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:
+ case ReadFile, WriteFile:
// typedef struct _PERFINFO_FILE_READ_WRITE {
// ULONGLONG Offset;
// ULONG_PTR Irp;
@@ -234,7 +235,7 @@ func (d *ParamDecoder) DecodeFile(r *etw.EventRecord, e *Event) {
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:
+ case EnumDirectory:
// typedef struct _PERFINFO_FILE_DIRENUM {
// ULONG_PTR Irp;
// ULONG_PTR FileObject;
@@ -253,7 +254,7 @@ func (d *ParamDecoder) DecodeFile(r *etw.EventRecord, e *Event) {
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:
+ case FileRundown:
e.AppendParam(params.FileObject, params.Address, r.ReadUint64(0))
e.AppendParam(params.FilePath, params.DOSPath, r.ConsumeUTF16String(8))
}
@@ -527,6 +528,12 @@ func (d *ParamDecoder) DecodeNetwork(r *etw.EventRecord, e *Event) {
e.AppendParam(params.NetDport, params.Port, r.ReadUint16(16))
e.AppendParam(params.NetSport, params.Port, r.ReadUint16(18))
}
+
+ if r.Header.ProviderID == NetworkTCPEventGUID {
+ e.AppendEnum(params.NetL4Proto, uint32(network.TCP), network.ProtoNames)
+ } else {
+ e.AppendEnum(params.NetL4Proto, uint32(network.UDP), network.ProtoNames)
+ }
}
// DecodeDNS decodes DNS query/reply event payloads.
diff --git a/pkg/event/param_decoder_windows_test.go b/pkg/event/param_decoder_windows_test.go
index 014c6023b..46110e69c 100644
--- a/pkg/event/param_decoder_windows_test.go
+++ b/pkg/event/param_decoder_windows_test.go
@@ -26,6 +26,7 @@ import (
"github.com/rabbitstack/fibratus/pkg/sys/etw"
"github.com/rabbitstack/fibratus/pkg/util/va"
"github.com/stretchr/testify/assert"
+ "golang.org/x/sys/windows"
)
func TestDecodeRegistry(t *testing.T) {
@@ -141,6 +142,7 @@ func TestDecodeFile(t *testing.T) {
var tests = []struct {
name string
opcode uint8
+ event *Event
buf []byte
assertions func(t *testing.T, e *Event)
}{
@@ -158,6 +160,7 @@ func TestDecodeFile(t *testing.T) {
assert.Equal(t, "Success", e.GetParamAsString(params.NTStatus))
assert.Contains(t, e.Params, params.Callstack)
},
+ event: &Event{Params: make(Params), Type: CreateFile},
buf: []byte{
200, 7, 94, 150, 141, 215, 255, 255,
80, 102, 11, 146, 141, 215, 255, 255,
@@ -196,6 +199,7 @@ func TestDecodeFile(t *testing.T) {
assert.Equal(t, uint32(0), e.Params.MustGetUint32(params.NTStatus))
assert.Equal(t, uint64(0x28), e.Params.MustGetUint64(params.FileExtraInfo))
},
+ event: &Event{Params: make(Params), Type: FileOpEnd},
buf: []byte{
248, 240, 61, 151, 141, 215, 255, 255,
40, 0, 0, 0,
@@ -204,7 +208,7 @@ func TestDecodeFile(t *testing.T) {
},
},
{
- name: "MapViewFile", opcode: MapViewFileID,
+ name: "MapViewOfSection", opcode: MapViewOfSectionID,
assertions: func(t *testing.T, e *Event) {
assert.Len(t, e.Params, 7)
assert.Equal(t, uint64(0xffffb58b75fb7e10), e.Params.MustGetUint64(params.FileKey))
@@ -215,6 +219,7 @@ func TestDecodeFile(t *testing.T) {
assert.Equal(t, uint64(0x191ab210000), e.Params.MustGetUint64(params.FileViewBase))
assert.Equal(t, uint64(4096), e.Params.MustGetUint64(params.FileViewSize))
},
+ event: &Event{Params: make(Params), Type: MapViewOfSection},
buf: []byte{
0, 0, 33, 171, 145, 1, 0, 0,
16, 126, 251, 117, 139, 181, 255, 255,
@@ -225,7 +230,7 @@ func TestDecodeFile(t *testing.T) {
},
},
{
- name: "UnmapViewFile", opcode: UnmapViewFileID,
+ name: "UnmapViewOfSection", opcode: UnmapViewOfSectionID,
assertions: func(t *testing.T, e *Event) {
assert.Len(t, e.Params, 7)
assert.Equal(t, uint64(0xffffb58bc1f91010), e.Params.MustGetUint64(params.FileKey))
@@ -236,6 +241,7 @@ func TestDecodeFile(t *testing.T) {
assert.Equal(t, uint64(0x1675e410000), e.Params.MustGetUint64(params.FileViewBase))
assert.Equal(t, uint64(921600), e.Params.MustGetUint64(params.FileViewSize))
},
+ event: &Event{Params: make(Params), Type: UnmapViewOfSection},
buf: []byte{
0, 0, 65, 94, 103, 1, 0, 0,
16, 16, 249, 193, 139, 181, 255, 255,
@@ -256,6 +262,7 @@ func TestDecodeFile(t *testing.T) {
assert.Equal(t, uint64(0xffffd78d9b6470f8), e.Params.MustGetUint64(params.FileIrpPtr))
assert.Equal(t, uint32(16404), e.Params.MustGetTid())
},
+ event: &Event{Params: make(Params), Type: SetFileInformation},
buf: []byte{
248, 112, 100, 155, 141, 215, 255, 255,
128, 55, 64, 118, 141, 215, 255, 255,
@@ -276,6 +283,7 @@ func TestDecodeFile(t *testing.T) {
assert.Equal(t, uint64(0xffffd78d7c5860f8), e.Params.MustGetUint64(params.FileIrpPtr))
assert.Equal(t, uint32(13656), e.Params.MustGetTid())
},
+ event: &Event{Params: make(Params), Type: DeleteFile},
buf: []byte{
248, 96, 88, 124, 141, 215, 255, 255,
128, 125, 108, 155, 141, 215, 255, 255,
@@ -294,6 +302,7 @@ func TestDecodeFile(t *testing.T) {
assert.Equal(t, uint64(0xffffd78d7ca0b0f8), e.Params.MustGetUint64(params.FileIrpPtr))
assert.Equal(t, uint32(3096), e.Params.MustGetTid())
},
+ event: &Event{Params: make(Params), Type: ReleaseFile},
buf: []byte{
248, 176, 160, 124, 141, 215, 255, 255,
176, 82, 69, 155, 141, 215, 255, 255,
@@ -312,6 +321,7 @@ func TestDecodeFile(t *testing.T) {
assert.Equal(t, uint64(573440), e.Params.MustGetUint64(params.FileOffset))
assert.Equal(t, uint32(1073741824), e.Params.MustGetUint32(params.FileIoSize))
},
+ event: &Event{Params: make(Params), Type: WriteFile},
buf: []byte{
0, 192, 8, 0, 0, 0, 0, 0,
8, 106, 120, 154, 141, 215, 255, 255,
@@ -332,6 +342,7 @@ func TestDecodeFile(t *testing.T) {
assert.Equal(t, uint64(0xffff8084da3e7788), e.Params.MustGetUint64(params.FileIrpPtr))
assert.Equal(t, uint32(12860), e.Params.MustGetTid())
},
+ event: &Event{Params: make(Params), Type: EnumDirectory},
buf: []byte{
136, 119, 62, 218, 132, 128, 255, 255,
144, 201, 67, 203, 132, 128, 255, 255,
@@ -347,6 +358,7 @@ func TestDecodeFile(t *testing.T) {
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))
},
+ event: &Event{Params: make(Params), Type: FileRundown},
buf: []byte{
80, 71, 18, 158, 139, 181, 255, 255,
92, 0, 68, 0, 101, 0, 118, 0,
@@ -407,9 +419,8 @@ func TestDecodeFile(t *testing.T) {
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)
+ paramDecoder.DecodeFile(r, tt.event)
+ tt.assertions(t, tt.event)
})
}
}
@@ -830,18 +841,20 @@ func TestDecodeNetwork(t *testing.T) {
name string
opcode uint8
buf []byte
+ providerID windows.GUID
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.Len(t, e.Params, 7)
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))
+ assert.Equal(t, "TCP", e.GetParamAsString(params.NetL4Proto))
},
buf: []byte{
160, 48, 0, 0,
@@ -854,17 +867,19 @@ func TestDecodeNetwork(t *testing.T) {
0, 0, 0, 0,
0, 0, 0, 0,
},
+ providerID: NetworkTCPEventGUID,
},
{
name: "ConnectTCPv4", opcode: ConnectTCPv4ID,
assertions: func(t *testing.T, e *Event) {
- assert.Len(t, e.Params, 6)
+ assert.Len(t, e.Params, 7)
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))
+ assert.Equal(t, "TCP", e.GetParamAsString(params.NetL4Proto))
},
buf: []byte{
160, 48, 0, 0,
@@ -878,17 +893,19 @@ func TestDecodeNetwork(t *testing.T) {
0, 0, 0, 0,
0, 0, 0, 0,
},
+ providerID: NetworkTCPEventGUID,
},
{
name: "RecvUDPv6", opcode: RecvV6ID,
assertions: func(t *testing.T, e *Event) {
- assert.Len(t, e.Params, 6)
+ assert.Len(t, e.Params, 7)
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))
+ assert.Equal(t, "UDP", e.GetParamAsString(params.NetL4Proto))
},
buf: []byte{
8, 20, 0, 0,
@@ -904,12 +921,13 @@ func TestDecodeNetwork(t *testing.T) {
221, 221, 0, 0, 0, 0,
0, 0, 0, 0,
},
+ providerID: NetworkUDPEventGUID,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- r := initEventRecord(tt.opcode, 0, tt.buf)
+ r := initEventRecord(tt.opcode, 0, tt.buf, withProviderID(tt.providerID))
e := &Event{Params: make(Params)}
paramDecoder.DecodeNetwork(r, e)
tt.assertions(t, e)
@@ -960,10 +978,28 @@ func TestDecodeDNS(t *testing.T) {
assert.Equal(t, "AAAA", e.GetParamAsString(params.DNSRR))
}
-func initEventRecord(opcode uint8, id uint16, buf []byte) *etw.EventRecord {
+type option func(*options)
+
+type options struct {
+ providerID windows.GUID
+}
+
+func withProviderID(id windows.GUID) option {
+ return func(o *options) {
+ o.providerID = id
+ }
+}
+
+func initEventRecord(opcode uint8, id uint16, buf []byte, opts ...option) *etw.EventRecord {
+ var options options
+ for _, opt := range opts {
+ opt(&options)
+ }
+
return &etw.EventRecord{
Header: etw.EventHeader{
- ProcessID: 13440,
+ ProcessID: 13440,
+ ProviderID: options.providerID,
EventDescriptor: etw.EventDescriptor{
Opcode: opcode,
ID: id,
diff --git a/pkg/event/param_windows.go b/pkg/event/param_windows.go
index 691505629..7d718eb0e 100644
--- a/pkg/event/param_windows.go
+++ b/pkg/event/param_windows.go
@@ -213,14 +213,14 @@ var paramDecoder = &ParamDecoder{}
// version number which helps us determine when the event
// schema changes in order to parse new fields.
func (e *Event) decodeParams(r *etw.EventRecord) {
- switch r.Header.ProviderID {
- case RegistryEventGUID:
+ switch r.Header.ProviderID.Data1 {
+ case RegistryEventGUID.Data1:
paramDecoder.DecodeRegistry(r, e)
- case FileEventGUID:
+ case FileEventGUID.Data1:
paramDecoder.DecodeFile(r, e)
- case StackWalkEventGUID:
+ case StackWalkEventGUID.Data1:
paramDecoder.DecodeStackwalk(r, e)
- case AuditAPIEventGUID:
+ case AuditAPIEventGUID.Data1:
switch r.Header.EventDescriptor.ID {
case OpenProcessID:
paramDecoder.DecodeOpenProcess(r, e)
@@ -231,21 +231,21 @@ func (e *Event) decodeParams(r *etw.EventRecord) {
case CreateSymbolicLinkObjectID:
paramDecoder.DecodeCreateSymbolicLinkObject(r, e)
}
- case MemEventGUID:
+ case MemoryEventGUID.Data1:
paramDecoder.DecodeMemory(r, e)
- case NetworkTCPEventGUID, NetworkUDPEventGUID:
+ case NetworkTCPEventGUID.Data1, NetworkUDPEventGUID.Data1:
paramDecoder.DecodeNetwork(r, e)
- case DNSEventGUID:
+ case DNSEventGUID.Data1:
paramDecoder.DecodeDNS(r, e)
- case ProcessEventGUID:
+ case ProcessEventGUID.Data1:
paramDecoder.DecodeProcess(r, e)
- case ModuleEventGUID:
+ case ModuleEventGUID.Data1:
paramDecoder.DecodeModule(r, e)
- case ThreadEventGUID:
+ case ThreadEventGUID.Data1:
paramDecoder.DecodeThread(r, e)
- case RegistryKernelEventGUID:
+ case RegistryKernelEventGUID.Data1:
paramDecoder.DecodeRegSetValueInternal(r, e)
- case ProcessKernelEventGUID:
+ case ProcessKernelEventGUID.Data1:
switch r.Header.EventDescriptor.ID {
case CreateProcessInternalID, ProcessRundownInternalID:
paramDecoder.DecodeProcessInternal(r, e)
diff --git a/pkg/event/queue.go b/pkg/event/queue.go
index a580e253d..f76460ca1 100644
--- a/pkg/event/queue.go
+++ b/pkg/event/queue.go
@@ -109,7 +109,7 @@ func (q *Queue) Close() { q.decorator.Stop() }
func (q *Queue) Push(e *Event) error {
if q.stackEnrichment {
// store pending event for callstack enrichment
- if e.Type.CanEnrichStack() {
+ if e.Type.WaitStack() {
q.decorator.Push(e)
return nil
}
diff --git a/pkg/event/queue_test.go b/pkg/event/queue_test.go
index cd3fed7a0..c1ab2345b 100644
--- a/pkg/event/queue_test.go
+++ b/pkg/event/queue_test.go
@@ -70,9 +70,7 @@ func TestQueuePush(t *testing.T) {
PID: 859,
CPU: 1,
Seq: 2,
- Name: "CreateFile",
Timestamp: time.Now(),
- Category: File,
Params: Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\user32.dll"},
@@ -97,9 +95,7 @@ func TestQueuePush(t *testing.T) {
PID: 859,
CPU: 1,
Seq: 2,
- Name: "CreateFile",
Timestamp: time.Now(),
- Category: File,
Params: Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\user32.dll"},
@@ -124,9 +120,7 @@ func TestQueuePush(t *testing.T) {
PID: 859,
CPU: 1,
Seq: 2,
- Name: "CreateFile",
Timestamp: time.Now(),
- Category: File,
Params: Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\user32.dll"},
@@ -152,9 +146,7 @@ func TestQueuePush(t *testing.T) {
PID: 859,
CPU: 1,
Seq: 2,
- Name: "CreateFile",
Timestamp: time.Now(),
- Category: File,
Params: Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\user32.dll"},
diff --git a/pkg/event/stackwalk.go b/pkg/event/stackwalk.go
index 752ae39ad..c6a7fb7ae 100644
--- a/pkg/event/stackwalk.go
+++ b/pkg/event/stackwalk.go
@@ -221,7 +221,7 @@ func (s *StackwalkDecorator) flush() []error {
if evt.PS != nil {
stackwalkFlushesProcs.Add(evt.PS.Name, 1)
}
- stackwalkFlushesEvents.Add(evt.Name, 1)
+ stackwalkFlushesEvents.Add(evt.Name(), 1)
}
return errs
diff --git a/pkg/event/types_windows.go b/pkg/event/types_windows.go
index c80687f01..d67e29bc5 100644
--- a/pkg/event/types_windows.go
+++ b/pkg/event/types_windows.go
@@ -19,11 +19,8 @@
package event
import (
- "encoding/binary"
-
"github.com/rabbitstack/fibratus/pkg/sys/etw"
"github.com/rabbitstack/fibratus/pkg/util/colorizer"
- "github.com/rabbitstack/fibratus/pkg/util/hashers"
"golang.org/x/sys/windows"
)
@@ -34,13 +31,13 @@ const (
// 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
- // publishing the events.
+ // Most notably, DNS, and kernel audit API providers are in charge of publishing the
+ // events.
SecurityTelemetryLogger
)
-// Type identifies an event type. It comprises the event GUID + hook ID to uniquely identify the event
-type Type [18]byte
+// Type identifies an event type.
+type Type uint16
var (
// ProcessEventGUID represents process provider event GUID
@@ -57,8 +54,8 @@ var (
NetworkTCPEventGUID = windows.GUID{Data1: 0x9a280ac0, Data2: 0xc8e0, Data3: 0x11d1, Data4: [8]byte{0x84, 0xe2, 0x0, 0xc0, 0x4f, 0xb9, 0x98, 0xa2}}
// NetworkUDPEventGUID represents network UDP provider event GUID
NetworkUDPEventGUID = windows.GUID{Data1: 0xbf3a50c5, Data2: 0xa9c9, Data3: 0x4988, Data4: [8]byte{0xa0, 0x05, 0x2d, 0xf0, 0xb7, 0xc8, 0x0f, 0x80}}
- // MemEventGUID represents memory provider event GUID
- MemEventGUID = windows.GUID{Data1: 0x3d6fa8d3, Data2: 0xfe05, Data3: 0x11d0, Data4: [8]byte{0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c}}
+ // MemoryEventGUID represents memory provider event GUID
+ MemoryEventGUID = windows.GUID{Data1: 0x3d6fa8d3, Data2: 0xfe05, Data3: 0x11d0, Data4: [8]byte{0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c}}
// AuditAPIEventGUID represents audit API calls event GUID
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
@@ -71,6 +68,65 @@ var (
StackWalkEventGUID = windows.GUID{Data1: 0xdef2fe46, Data2: 0x7bd6, Data3: 0x4b80, Data4: [8]byte{0xbd, 0x94, 0xf5, 0x7f, 0xe2, 0x0d, 0x0c, 0xe3}}
)
+const (
+ Unknown Type = iota
+ CreateProcess
+ TerminateProcess
+ ProcessRundown
+ OpenProcess
+ CreateProcessInternal // only purpose of this event is to enrich the process state with some extra attributes
+ ProcessRundownInternal // populates the snapshotter for events running in the Security Telemetry session
+ CreateThread
+ TerminateThread
+ ThreadRundown
+ OpenThread
+ SetThreadContext
+ StackWalk
+ UnloadModule
+ LoadModule
+ ModuleRundown
+ LoadModuleInternal // only purpose is to populate the module state for events running in the Security Telemetry session
+ RegCreateKey
+ RegOpenKey
+ RegDeleteKey
+ RegQueryKey
+ RegSetValue
+ RegSetValueInternal // internal event that is used to enrich the corresponding public RegSetValue event with captured data
+ RegDeleteValue
+ RegQueryValue
+ RegCloseKey
+ RegCreateKCB
+ RegDeleteKCB
+ RegKCBRundown
+ CreateFile
+ ReleaseFile
+ CloseFile
+ ReadFile
+ WriteFile
+ SetFileInformation
+ DeleteFile
+ RenameFile
+ EnumDirectory
+ FileRundown
+ FileOpEnd
+ Accept
+ Send
+ Recv
+ Connect
+ Disconnect
+ Reconnect
+ Retransmit
+ QueryDNS
+ ReplyDNS
+ MapViewOfSection
+ UnmapViewOfSection
+ MapViewSectionRundown
+ VirtualAlloc
+ VirtualFree
+ CreateSymbolicLinkObject
+ MaxEvent // sentinel
+)
+
const (
CreateProcessID uint8 = 1
CreateProcessInternalID uint16 = 1
@@ -90,20 +146,20 @@ const (
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
+ FileRundownID uint8 = 36
+ MapViewOfSectionID uint8 = 37
+ UnmapViewOfSectionID uint8 = 38
+ MapViewSectionRundownID 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
@@ -144,530 +200,211 @@ const (
StackWalkID uint8 = 32
)
-var (
- // CreateProcess identifies process creation kernel events
- CreateProcess = pack(ProcessEventGUID, uint16(CreateProcessID))
- // TerminateProcess identifies process termination kernel events
- 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, uint16(ProcessRundownID))
- // OpenProcess identifies the kernel events that are triggered when the process handle is acquired
- 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, CreateProcessInternalID)
- // ProcessRundownInternal same as above but for process rundown events originating from the Microsoft Windows Kernel Process provider.
- ProcessRundownInternal = pack(ProcessKernelEventGUID, ProcessRundownInternalID)
-
- // CreateThread identifies thread creation kernel events
- CreateThread = pack(ThreadEventGUID, uint16(CreateThreadID))
- // TerminateThread identifies thread termination kernel events
- 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, uint16(ThreadRundownID))
- // OpenThread identifies the kernel events that are triggered when the process acquires a thread handle
- OpenThread = pack(AuditAPIEventGUID, OpenThreadID)
- // SetThreadContext identifies the kernel event that is fired when the thread context is changed
- 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, uint16(MapViewFileID))
- // UnmapViewFile represents events that unmap a view of a file mapping from the address space of a calling process
- 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, 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, uint16(FileRundownID))
- // CreateFile represents events that create/open a file or I/O device
- CreateFile = pack(FileEventGUID, uint16(CreateFileID))
- // ReleaseFile represents events that occur when the last file handle is disposed
- ReleaseFile = pack(FileEventGUID, uint16(ReleaseFileID))
- // CloseFile represents events that dispose existing kernel file objects
- CloseFile = pack(FileEventGUID, uint16(CloseFileID))
- // ReadFile represents events that read data from the file or I/O device
- ReadFile = pack(FileEventGUID, uint16(ReadFileID))
- // WriteFile represents events that write data to the file or I/O device
- WriteFile = pack(FileEventGUID, uint16(WriteFileID))
- // SetFileInformation represents events that set file information
- SetFileInformation = pack(FileEventGUID, uint16(SetFileInformationID))
- // DeleteFile identifies file deletion events
- DeleteFile = pack(FileEventGUID, uint16(DeleteFileID))
- // RenameFile identifies events that are responsible for renaming files
- RenameFile = pack(FileEventGUID, uint16(RenameFileID))
- // EnumDirectory identifies enumerate directory and directory notification events
- EnumDirectory = pack(FileEventGUID, uint16(EnumDirectoryID))
- // FileOpEnd signals the finalization of the file operation
- FileOpEnd = pack(FileEventGUID, uint16(FileOpEndID))
-
- // RegCreateKey represents registry key creation kernel events
- RegCreateKey = pack(RegistryEventGUID, uint16(RegCreateKeyID))
- // RegOpenKey represents registry open key kernel events
- RegOpenKey = pack(RegistryEventGUID, uint16(RegOpenKeyID))
- // RegCloseKey represents registry close key kernel event.
- RegCloseKey = pack(RegistryEventGUID, uint16(RegCloseKeyID))
- // RegDeleteKey represents registry key deletion kernel events
- RegDeleteKey = pack(RegistryEventGUID, uint16(RegDeleteKeyID))
- // RegQueryKey represents registry query key kernel events
- RegQueryKey = pack(RegistryEventGUID, uint16(RegQueryKeyID))
- // RegSetValue represents registry set value kernel events
- RegSetValue = pack(RegistryEventGUID, uint16(RegSetValueID))
- // RegDeleteValue are kernel events for registry value removals
- RegDeleteValue = pack(RegistryEventGUID, uint16(RegDeleteValueID))
- // RegQueryValue are kernel events for registry value queries
- RegQueryValue = pack(RegistryEventGUID, uint16(RegQueryValueID))
- // RegCreateKCB represents kernel events for KCB (Key Control Block) creation requests
- RegCreateKCB = pack(RegistryEventGUID, uint16(RegCreateKCBID))
- // RegDeleteKCB represents kernel events for KCB(Key Control Block) closures
- RegDeleteKCB = pack(RegistryEventGUID, uint16(RegDeleteKCBID))
- // RegKCBRundown enumerates the registry keys open at the start of the kernel session.
- 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, RegSetValueInternalID)
-
- // UnloadModule represents unload module kernel events
- UnloadModule = pack(ModuleEventGUID, uint16(UnloadModuleID))
- // ModuleRundown represents kernel events that is triggered to enumerate all loaded modules
- 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, uint16(LoadModuleID))
- // LoadModuleInternal same as for process internal event originating from the Microsoft Windows Kernel Process provider
- LoadModuleInternal = pack(ProcessKernelEventGUID, LoadModuleInternalID)
-
- // AcceptTCPv4 represents the TCPv4 kernel events for accepting connection requests from the socket queue.
- AcceptTCPv4 = pack(NetworkTCPEventGUID, uint16(AcceptTCPv4ID))
- // AcceptTCPv6 represents the TCPv6 kernel events for accepting connection requests from the socket queue.
- AcceptTCPv6 = pack(NetworkTCPEventGUID, uint16(AcceptTCPv6ID))
- // SendTCPv4 represents the TCPv4 kernel events for sending data to the connected socket.
- SendTCPv4 = pack(NetworkTCPEventGUID, uint16(SendV4ID))
- // SendTCPv6 represents the TCPv6 kernel events for sending data to the connected socket.
- SendTCPv6 = pack(NetworkTCPEventGUID, uint16(SendV6ID))
- // SendUDPv4 represents the UDPv4 kernel events for sending datagrams to connectionless sockets.
- SendUDPv4 = pack(NetworkUDPEventGUID, uint16(SendV4ID))
- // SendUDPv6 represents the UDPv6 kernel events for sending datagrams to connectionless sockets.
- SendUDPv6 = pack(NetworkUDPEventGUID, uint16(SendV6ID))
- // RecvTCPv4 represents the TCP IPv4 network receive event.
- RecvTCPv4 = pack(NetworkTCPEventGUID, uint16(RecvV4ID))
- // RecvTCPv6 represents the TCP IPv6 network receive event.
- RecvTCPv6 = pack(NetworkTCPEventGUID, uint16(RecvV6ID))
- // RecvUDPv4 represents the UDP IPv4 network receive event.
- RecvUDPv4 = pack(NetworkUDPEventGUID, uint16(RecvV4ID))
- // RecvUDPv6 represents the UDP IPv6 network receive event.
- RecvUDPv6 = pack(NetworkUDPEventGUID, uint16(RecvV6ID))
- // ConnectTCPv4 represents the TCP IPv4 network connect event.
- ConnectTCPv4 = pack(NetworkTCPEventGUID, uint16(ConnectTCPv4ID))
- // ConnectTCPv6 represents the TCP IPv6 network connect event.
- ConnectTCPv6 = pack(NetworkTCPEventGUID, uint16(ConnectTCPv6ID))
- // DisconnectTCPv4 is the TCP IPv4 network disconnect event.
- DisconnectTCPv4 = pack(NetworkTCPEventGUID, uint16(DisconnectTCPv4ID))
- // DisconnectTCPv6 is the TCP IPv6 network disconnect event.
- DisconnectTCPv6 = pack(NetworkTCPEventGUID, uint16(DisconnectTCPv6ID))
- // ReconnectTCPv4 is the TCP IPv4 network reconnect event.
- ReconnectTCPv4 = pack(NetworkTCPEventGUID, uint16(ReconnectTCPv4ID))
- // ReconnectTCPv6 is the TCP IPv6 network reconnect event.
- ReconnectTCPv6 = pack(NetworkTCPEventGUID, uint16(ReconnectTCPv6ID))
- // RetransmitTCPv4 is the TCP IPv4 network retransmit event.
- RetransmitTCPv4 = pack(NetworkTCPEventGUID, uint16(RetransmitTCPv4ID))
- // RetransmitTCPv6 is the TCP IPv6 network retransmit event.
- RetransmitTCPv6 = pack(NetworkTCPEventGUID, uint16(RetransmitTCPv6ID))
-
- // VirtualAlloc represents virtual memory allocation event
- VirtualAlloc = pack(MemEventGUID, uint16(VirtualAllocID))
- // VirtualFree represents virtual memory release event
- VirtualFree = pack(MemEventGUID, uint16(VirtualFreeID))
-
- // QueryDNS represents DNS query events
- QueryDNS = pack(DNSEventGUID, QueryDNSID)
- // ReplyDNS represents the DNS response events
- ReplyDNS = pack(DNSEventGUID, ReplyDNSID)
-
- // StackWalk represents stack walk event with the collection of return addresses
- 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, CreateSymbolicLinkObjectID)
-
- // UnknownType designates unknown event type
- UnknownType = pack(windows.GUID{}, 0)
-)
-
-// NewTypeFromEventRecord creates a new event type from ETW event record.
-func NewTypeFromEventRecord(ev *etw.EventRecord) Type {
- return pack(ev.Header.ProviderID, ev.HookID())
-}
-
-// String returns the string representation of the event type. Returns an empty string
-// if the event type is not recognized.
-func (t Type) String() string {
- switch t {
- case CreateProcess, CreateProcessInternal:
- return "CreateProcess"
- case TerminateProcess:
- return "TerminateProcess"
- case ProcessRundown, ProcessRundownInternal:
- return "ProcessRundown"
- case OpenProcess:
- return "OpenProcess"
- case CreateThread:
- return "CreateThread"
- case TerminateThread:
- return "TerminateThread"
- case ThreadRundown:
- return "ThreadRundown"
- case OpenThread:
- return "OpenThread"
- case SetThreadContext:
- return "SetThreadContext"
- case CreateFile:
- return "CreateFile"
- case CloseFile:
- return "CloseFile"
- case ReleaseFile:
- return "ReleaseFile"
- case ReadFile:
- return "ReadFile"
- case WriteFile:
- return "WriteFile"
- case SetFileInformation:
- return "SetFileInformation"
- case DeleteFile:
- return "DeleteFile"
- case RenameFile:
- return "RenameFile"
- case EnumDirectory:
- return "EnumDirectory"
- case FileOpEnd:
- return "FileOpEnd"
- case FileRundown:
- return "FileRundown"
- case MapViewFile:
- return "MapViewFile"
- case UnmapViewFile:
- return "UnmapViewFile"
- case MapFileRundown:
- return "MapFileRundown"
- case RegKCBRundown:
- return "RegKCBRundown"
- case RegOpenKey:
- return "RegOpenKey"
- case RegCloseKey:
- return "RegCloseKey"
- case RegCreateKey:
- return "RegCreateKey"
- case RegDeleteKey:
- return "RegDeleteKey"
- case RegDeleteValue:
- return "RegDeleteValue"
- case RegQueryKey:
- return "RegQueryKey"
- case RegQueryValue:
- return "RegQueryValue"
- case RegCreateKCB:
- return "RegCreateKCB"
- case RegSetValue, RegSetValueInternal:
- return "RegSetValue"
- case LoadModule, LoadModuleInternal:
- return "LoadModule"
- case UnloadModule:
- return "UnloadModule"
- case ModuleRundown:
- return "ModuleRundown"
- case AcceptTCPv4, AcceptTCPv6:
- return "Accept"
- case SendTCPv4, SendTCPv6, SendUDPv4, SendUDPv6:
- return "Send"
- case RecvTCPv4, RecvTCPv6, RecvUDPv4, RecvUDPv6:
- return "Recv"
- case ConnectTCPv4, ConnectTCPv6:
- return "Connect"
- case ReconnectTCPv4, ReconnectTCPv6:
- return "Reconnect"
- case DisconnectTCPv4, DisconnectTCPv6:
- return "Disconnect"
- case RetransmitTCPv4, RetransmitTCPv6:
- return "Retransmit"
- case VirtualAlloc:
- return "VirtualAlloc"
- case VirtualFree:
- return "VirtualFree"
- case QueryDNS:
- return "QueryDns"
- case ReplyDNS:
- return "ReplyDns"
- case StackWalk:
- return "StackWalk"
- case CreateSymbolicLinkObject:
- return "CreateSymbolicLinkObject"
- default:
- return ""
+// NewTypeFromEventRecord derives the event type from the Data1 member of the provider GUID
+// and the opcode/event ID integer.
+// Go only jump-tables switches over integer types and only when case values are reasonably
+// dense. A switch over provider ID which is GUID struct compiles to a sequential chain of
+// struct-equality compares instead of a jump table.
+// So we split the GUID into a fast-reject key and switch on that instead. The first member of
+// the GUID (Data1) is a dense uint32 integer and is certainly unique across all providers.
+func NewTypeFromEventRecord(r *etw.EventRecord) Type {
+ switch r.Header.ProviderID.Data1 {
+ case RegistryEventGUID.Data1:
+ switch r.Header.EventDescriptor.Opcode {
+ case RegCreateKeyID:
+ return RegCreateKey
+ case RegOpenKeyID:
+ return RegOpenKey
+ case RegDeleteKeyID:
+ return RegDeleteKey
+ case RegQueryKeyID:
+ return RegQueryKey
+ case RegSetValueID:
+ return RegSetValue
+ case RegDeleteValueID:
+ return RegDeleteValue
+ case RegQueryValueID:
+ return RegQueryValue
+ case RegCreateKCBID:
+ return RegCreateKCB
+ case RegDeleteKCBID:
+ return RegDeleteKCB
+ case RegKCBRundownID:
+ return RegKCBRundown
+ case RegCloseKeyID:
+ return RegCloseKey
+ }
+ case FileEventGUID.Data1:
+ switch r.Header.EventDescriptor.Opcode {
+ case FileRundownID:
+ return FileRundown
+ case MapViewOfSectionID:
+ return MapViewOfSection
+ case UnmapViewOfSectionID:
+ return UnmapViewOfSection
+ case MapViewSectionRundownID:
+ return MapViewSectionRundown
+ case CreateFileID:
+ return CreateFile
+ case ReleaseFileID:
+ return ReleaseFile
+ case CloseFileID:
+ return CloseFile
+ case ReadFileID:
+ return ReadFile
+ case WriteFileID:
+ return WriteFile
+ case SetFileInformationID:
+ return SetFileInformation
+ case DeleteFileID:
+ return DeleteFile
+ case RenameFileID:
+ return RenameFile
+ case EnumDirectoryID:
+ return EnumDirectory
+ case FileOpEndID:
+ return FileOpEnd
+ }
+ case AuditAPIEventGUID.Data1:
+ switch r.Header.EventDescriptor.ID {
+ case OpenProcessID:
+ return OpenProcess
+ case OpenThreadID:
+ return OpenThread
+ case SetThreadContextID:
+ return SetThreadContext
+ case CreateSymbolicLinkObjectID:
+ return CreateSymbolicLinkObject
+ }
+ case StackWalkEventGUID.Data1:
+ return StackWalk
+ case MemoryEventGUID.Data1:
+ switch r.Header.EventDescriptor.Opcode {
+ case VirtualAllocID:
+ return VirtualAlloc
+ case VirtualFreeID:
+ return VirtualFree
+ }
+ case NetworkTCPEventGUID.Data1:
+ switch r.Header.EventDescriptor.Opcode {
+ case AcceptTCPv4ID, AcceptTCPv6ID:
+ return Accept
+ case SendV4ID, SendV6ID:
+ return Send
+ case RecvV4ID, RecvV6ID:
+ return Recv
+ case ConnectTCPv4ID, ConnectTCPv6ID:
+ return Connect
+ case DisconnectTCPv4ID, DisconnectTCPv6ID:
+ return Disconnect
+ case ReconnectTCPv4ID, ReconnectTCPv6ID:
+ return Reconnect
+ case RetransmitTCPv4ID, RetransmitTCPv6ID:
+ return Retransmit
+ }
+ case NetworkUDPEventGUID.Data1:
+ switch r.Header.EventDescriptor.Opcode {
+ case SendV4ID, SendV6ID:
+ return Send
+ case RecvV4ID, RecvV6ID:
+ return Recv
+ }
+ case DNSEventGUID.Data1:
+ switch r.Header.EventDescriptor.ID {
+ case QueryDNSID:
+ return QueryDNS
+ case ReplyDNSID:
+ return ReplyDNS
+ }
+ case ProcessEventGUID.Data1:
+ switch r.Header.EventDescriptor.Opcode {
+ case CreateProcessID:
+ return CreateProcess
+ case TerminateProcessID:
+ return TerminateProcess
+ case ProcessRundownID:
+ return ProcessRundown
+ }
+ case ProcessKernelEventGUID.Data1:
+ switch r.Header.EventDescriptor.ID {
+ case CreateProcessInternalID:
+ return CreateProcessInternal
+ case ProcessRundownInternalID:
+ return ProcessRundownInternal
+ case LoadModuleInternalID:
+ return LoadModuleInternal
+ }
+ case ModuleEventGUID.Data1:
+ switch r.Header.EventDescriptor.Opcode {
+ case UnloadModuleID:
+ return UnloadModule
+ case ModuleRundownID:
+ return ModuleRundown
+ case LoadModuleID:
+ return LoadModule
+ }
+ case ThreadEventGUID.Data1:
+ switch r.Header.EventDescriptor.Opcode {
+ case CreateThreadID:
+ return CreateThread
+ case TerminateThreadID:
+ return TerminateThread
+ case ThreadRundownID:
+ return ThreadRundown
+ }
}
+ return Unknown
}
-// Category determines the category to which the event type pertains.
-func (t Type) Category() Category {
- switch t {
- case CreateProcess, CreateProcessInternal, TerminateProcess, OpenProcess, ProcessRundown, ProcessRundownInternal:
- return Process
- case CreateThread, TerminateThread, OpenThread, SetThreadContext, ThreadRundown, StackWalk:
- return Thread
- case LoadModule, UnloadModule, ModuleRundown, LoadModuleInternal:
- return Module
- case CreateFile, ReadFile, WriteFile, EnumDirectory, DeleteFile, RenameFile, CloseFile, SetFileInformation,
- FileRundown, FileOpEnd, ReleaseFile, MapViewFile, UnmapViewFile, MapFileRundown:
- return File
- case RegCreateKey, RegDeleteKey, RegOpenKey, RegCloseKey, RegQueryKey, RegQueryValue, RegSetValue, RegDeleteValue,
- RegKCBRundown, RegDeleteKCB, RegCreateKCB, RegSetValueInternal:
- return Registry
- case AcceptTCPv4, AcceptTCPv6,
- ConnectTCPv4, ConnectTCPv6,
- ReconnectTCPv4, ReconnectTCPv6,
- RetransmitTCPv4, RetransmitTCPv6,
- DisconnectTCPv4, DisconnectTCPv6,
- SendTCPv4, SendTCPv6, SendUDPv4, SendUDPv6,
- RecvTCPv4, RecvTCPv6, RecvUDPv4, RecvUDPv6,
- QueryDNS, ReplyDNS:
- return Net
- case VirtualAlloc, VirtualFree:
- return Mem
- case CreateSymbolicLinkObject:
- return Object
- default:
- return Unknown
- }
-}
+// String returns the event type string representation.
+func (t Type) String() string { return table[t].Name }
-// Subcategory determines the event subcategory, if any.
-func (t Type) Subcategory() Subcategory {
- switch t {
- case QueryDNS, ReplyDNS:
- return DNS
- default:
- return None
- }
-}
+// OnlyState determines whether the event type is solely used for state management.
+func (t Type) OnlyState() bool { return table[t].Flags&OnlyState != 0 }
-// Description returns a brief description of the event type.
-func (t Type) Description() string {
+// IsRundown indicates if this type represents a rundown event that seeds the state.
+func (t Type) StateSnapshot() bool { return table[t].Flags&StateSnapshot != 0 }
+
+// WaitStack determines if the event waits for call stack return addresses.
+func (t Type) WaitStack() bool { return table[t].Flags&WaitStack != 0 }
+
+// EventID produces a native ETW classic event identifier to
+// indicate which event types are enabled for stack walk tracing.
+func (t Type) EventID() etw.ClassicEventID {
switch t {
case CreateProcess:
- return "Creates a new process and its primary thread"
- case TerminateProcess:
- return "Terminates the process and all of its threads"
- case OpenProcess:
- return "Opens the process handle"
+ return etw.ClassicEventID{GUID: ProcessEventGUID, Type: CreateProcessID}
case CreateThread:
- return "Creates a thread to execute within the virtual address space of the calling process"
+ return etw.ClassicEventID{GUID: ThreadEventGUID, Type: CreateThreadID}
case TerminateThread:
- return "Terminates a thread within the process"
- case OpenThread:
- return "Opens the thread handle"
- case SetThreadContext:
- return "Sets the thread context"
- case ReadFile:
- return "Reads data from the file or I/O device"
- case WriteFile:
- return "Writes data to the file or I/O device"
+ return etw.ClassicEventID{GUID: ThreadEventGUID, Type: TerminateThreadID}
+ case LoadModule:
+ return etw.ClassicEventID{GUID: ProcessEventGUID, Type: LoadModuleID}
case CreateFile:
- return "Creates or opens a file or I/O device"
- case CloseFile:
- return "Closes the file handle"
+ return etw.ClassicEventID{GUID: FileEventGUID, Type: CreateFileID}
case DeleteFile:
- return "Removes the file from the file system"
+ return etw.ClassicEventID{GUID: FileEventGUID, Type: DeleteFileID}
case RenameFile:
- return "Changes the file name"
- case SetFileInformation:
- return "Sets the file meta information"
- case EnumDirectory:
- return "Enumerates a directory or dispatches a directory change notification to registered listeners"
- case MapViewFile:
- return "Maps a view of a file mapping into the address space of a calling process"
- case UnmapViewFile:
- return "Unmaps a mapped view of a file from the calling process's address space"
+ return etw.ClassicEventID{GUID: FileEventGUID, Type: RenameFileID}
case RegCreateKey:
- return "Creates a registry key or opens it if the key already exists"
- case RegOpenKey:
- return "Opens the registry key"
- case RegCloseKey:
- return "Closes the registry key"
- case RegSetValue:
- return "Sets the data for the value of a registry key"
- case RegQueryValue:
- return "Reads the data for the value of a registry key"
- case RegQueryKey:
- return "Enumerates subkeys of the parent key"
+ return etw.ClassicEventID{GUID: RegistryEventGUID, Type: RegCreateKeyID}
case RegDeleteKey:
- return "Removes the registry key"
+ return etw.ClassicEventID{GUID: RegistryEventGUID, Type: RegDeleteKeyID}
+ case RegSetValue:
+ return etw.ClassicEventID{GUID: RegistryEventGUID, Type: RegSetValueID}
case RegDeleteValue:
- return "Removes the registry value"
- case AcceptTCPv4, AcceptTCPv6:
- return "Accepts the connection request from the socket queue"
- case ConnectTCPv4, ConnectTCPv6:
- return "Connects establishes a connection to the socket"
- case DisconnectTCPv4, DisconnectTCPv6:
- return "Terminates data reception on the socket"
- case ReconnectTCPv4, ReconnectTCPv6:
- return "Reconnects to the socket"
- case RetransmitTCPv4, RetransmitTCPv6:
- return "Retransmits unacknowledged TCP segments"
- case SendTCPv4, SendUDPv4, SendTCPv6, SendUDPv6:
- return "Sends data over the wire"
- case RecvTCPv4, RecvUDPv4, RecvTCPv6, RecvUDPv6:
- return "Receives data from the socket"
- case LoadModule:
- return "Loads the module into the address space of the calling process"
- case UnloadModule:
- return "Unloads the module from the address space of the calling process"
+ return etw.ClassicEventID{GUID: RegistryEventGUID, Type: RegDeleteValueID}
case VirtualAlloc:
- return "Reserves, commits, or changes the state of a region of memory within the process virtual address space"
- case VirtualFree:
- return "Releases or decommits a region of memory within the process virtual address space"
- case QueryDNS:
- return "Sends a DNS query to the name server"
- case ReplyDNS:
- return "Receives the response from the DNS server"
- case CreateSymbolicLinkObject:
- return "Creates the symbolic link within the object manager directory"
+ return etw.ClassicEventID{GUID: MemoryEventGUID, Type: VirtualAllocID}
default:
- return ""
- }
-}
-
-// Hash calculates the hash number of the event type.
-func (t Type) Hash() uint32 {
- if t == UnknownType {
- return 0
- }
- return hashers.FnvUint32([]byte(t.String()))
-}
-
-// Exists determines whether particular event type exists.
-func (t Type) Exists() bool {
- return t.String() != ""
-}
-
-// OnlyState determines whether the event type is solely used for state management.
-func (t Type) OnlyState() bool {
- switch t {
- case ProcessRundown,
- ProcessRundownInternal,
- CreateProcessInternal,
- ThreadRundown,
- ModuleRundown,
- LoadModuleInternal,
- FileRundown,
- RegKCBRundown,
- FileOpEnd,
- ReleaseFile,
- MapFileRundown,
- RegCreateKCB,
- RegDeleteKCB,
- RegSetValueInternal:
- return true
- default:
- return false
- }
-}
-
-// CanEnrichStack determines if the event can be enriched with a callstack.
-func (t Type) CanEnrichStack() bool {
- switch t {
- case CreateProcess,
- CreateThread,
- TerminateThread,
- LoadModule,
- RegCreateKey,
- RegDeleteKey,
- RegSetValue,
- RegDeleteValue,
- DeleteFile,
- RenameFile,
- VirtualAlloc:
- return true
- default:
- return false
- }
-}
-
-// UnmarshalYAML converts the Type name to Type array type.
-func (t *Type) UnmarshalYAML(unmarshal func(interface{}) error) error {
- var typ string
- err := unmarshal(&typ)
- if err != nil {
- return err
- }
- *t = NameToType(typ)
- return nil
-}
-
-// GUID returns the event GUID from the raw event type.
-func (t *Type) GUID() windows.GUID {
- return windows.GUID{
- Data1: binary.BigEndian.Uint32(t[0:4]),
- Data2: binary.BigEndian.Uint16(t[4:6]),
- Data3: binary.BigEndian.Uint16(t[6:8]),
- Data4: [8]byte{t[8], t[9], t[10], t[11], t[12], t[13], t[14], t[15]},
- }
-}
-
-// HookID returns the event operation code (hook ID) from the raw event type.
-func (t *Type) HookID() uint16 {
- return binary.BigEndian.Uint16(t[16:])
-}
-
-// ID is an unsigned integer that uniquely
-// identifies the event. Handy for bitmask
-// operations.
-func (t Type) ID() uint {
- id := uint(t[0])<<56 |
- uint(t[1])<<48 |
- uint(t[2])<<40 |
- uint(t[3])<<32 |
- uint(t[4])<<24 |
- uint(t[5])<<16 |
- uint(t.HookID())
- return id
-}
-
-// Source designates the provenance of this event type.
-func (t Type) Source() Source {
- switch t.GUID() {
- case AuditAPIEventGUID, DNSEventGUID, ProcessKernelEventGUID, RegistryKernelEventGUID:
- return SecurityTelemetryLogger
- default:
- return SystemLogger
- }
-}
-
-// TypeFromParts builds the event type from provider GUID and hook ID.
-func TypeFromParts(g windows.GUID, id uint16) Type { return pack(g, id) }
-
-// pack merges event provider GUID and the hook ID into `Type` array.
-// The type provides a convenient way for comparing event types.
-func pack(g windows.GUID, id uint16) Type {
- return [18]byte{
- byte(g.Data1 >> 24), byte(g.Data1 >> 16), byte(g.Data1 >> 8), byte(g.Data1),
- byte(g.Data2 >> 8), byte(g.Data2),
- byte(g.Data3 >> 8), byte(g.Data3),
- g.Data4[0],
- g.Data4[1],
- g.Data4[2],
- g.Data4[3],
- g.Data4[4],
- g.Data4[5],
- g.Data4[6],
- g.Data4[7],
- byte(id >> 8), byte(id),
+ return etw.ClassicEventID{}
}
}
// color return the colorized event type to render by the color formatter.
func (t Type) color() string {
switch t {
- case CreateFile, ReadFile, CloseFile, SetFileInformation, MapViewFile, UnmapViewFile:
+ case CreateFile, ReadFile, CloseFile, SetFileInformation:
return colorizer.SpanBold(colorizer.Cyan, t.String())
case RenameFile:
return colorizer.SpanBold(colorizer.Amber, t.String())
@@ -693,18 +430,17 @@ func (t Type) color() string {
return colorizer.SpanBold(colorizer.Amber, t.String())
case LoadModule, UnloadModule:
return colorizer.SpanBold(colorizer.Magenta, t.String())
- case SendTCPv4, SendTCPv6, SendUDPv4, SendUDPv6,
- RecvTCPv4, RecvTCPv6, RecvUDPv4, RecvUDPv6:
+ case Send, Recv:
return colorizer.SpanBold(colorizer.Blue, t.String())
- case ConnectTCPv4, ConnectTCPv6:
+ case Connect:
return colorizer.SpanBold(colorizer.Teal, t.String())
- case DisconnectTCPv4, DisconnectTCPv6:
+ case Disconnect:
return colorizer.SpanBold(colorizer.Blue, t.String())
- case AcceptTCPv4, AcceptTCPv6:
+ case Accept:
return colorizer.SpanBold(colorizer.Teal, t.String())
case QueryDNS, ReplyDNS:
return colorizer.SpanBold(colorizer.Indigo, t.String())
- case VirtualAlloc, VirtualFree:
+ case VirtualAlloc, VirtualFree, MapViewOfSection, UnmapViewOfSection:
return colorizer.SpanBold(colorizer.Magenta, t.String())
case CreateSymbolicLinkObject:
return colorizer.SpanBold(colorizer.Lavender, t.String())
@@ -729,21 +465,19 @@ func (t Type) arrow() string {
var clr uint8
switch t {
case TerminateProcess, TerminateThread, DeleteFile, RegDeleteKey,
- RegDeleteValue, UnloadModule, VirtualFree, UnmapViewFile:
+ RegDeleteValue, UnloadModule, VirtualFree, UnmapViewOfSection:
clr = colorizer.Red
case CreateProcess, CreateFile, WriteFile, RenameFile, SetFileInformation,
- RegCreateKey, RegSetValue, CreateThread, SetThreadContext, VirtualAlloc, MapViewFile,
- ConnectTCPv4, ConnectTCPv6, AcceptTCPv4, AcceptTCPv6,
- SendTCPv4, SendTCPv6, SendUDPv4, SendUDPv6:
+ RegCreateKey, RegSetValue, CreateThread, SetThreadContext, VirtualAlloc,
+ MapViewOfSection, Connect, Accept, Send:
clr = colorizer.Amber
- case ReadFile, EnumDirectory, LoadModule, RegOpenKey, RegQueryKey, RegQueryValue, OpenProcess,
- OpenThread, RecvTCPv4, RecvTCPv6, RecvUDPv4, RecvUDPv6:
+ case ReadFile, EnumDirectory, LoadModule, RegOpenKey, RegQueryKey, RegQueryValue,
+ OpenProcess, OpenThread, Recv:
clr = colorizer.Teal
case QueryDNS, ReplyDNS:
clr = colorizer.Indigo
default:
clr = colorizer.Gray
}
-
return colorizer.SpanBold(clr, "› ")
}
diff --git a/pkg/event/types_windows_test.go b/pkg/event/types_windows_test.go
index 84863c4db..c20a83668 100644
--- a/pkg/event/types_windows_test.go
+++ b/pkg/event/types_windows_test.go
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2020 by Nedim Sabic Sabic
+ * Copyright 2019-2026 by Nedim Sabic Sabic
* https://www.fibratus.io
* All Rights Reserved.
*
@@ -22,126 +22,442 @@ import (
"testing"
"github.com/rabbitstack/fibratus/pkg/sys/etw"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
"golang.org/x/sys/windows"
)
-func TestEventTypePackAllBytes(t *testing.T) {
- assert.Equal(t, byte(0x3d), CreateProcess[0])
- assert.Equal(t, byte(0x6f), CreateProcess[1])
- assert.Equal(t, byte(0xa8), CreateProcess[2])
- assert.Equal(t, byte(0xd0), CreateProcess[3])
-
- assert.Equal(t, byte(0xfe), CreateProcess[4])
- assert.Equal(t, byte(0x05), CreateProcess[5])
-
- assert.Equal(t, byte(0x11), CreateProcess[6])
- assert.Equal(t, byte(0xd0), CreateProcess[7])
-
- assert.Equal(t, byte(0x9d), CreateProcess[8])
- assert.Equal(t, byte(0xda), CreateProcess[9])
- assert.Equal(t, byte(0x0), CreateProcess[10])
- assert.Equal(t, byte(0xc0), CreateProcess[11])
- assert.Equal(t, byte(0x4f), CreateProcess[12])
- assert.Equal(t, byte(0xd7), CreateProcess[13])
- assert.Equal(t, byte(0xba), CreateProcess[14])
- assert.Equal(t, byte(0x7c), CreateProcess[15])
- assert.Equal(t, byte(0x0), CreateProcess[16])
- assert.Equal(t, byte(0x1), CreateProcess[17])
-
- assert.Equal(t, byte(0x0b), QueryDNS[16])
- assert.Equal(t, byte(0xbe), QueryDNS[17])
-}
-
-func TestEventTypeComparison(t *testing.T) {
- var tests = []struct {
- name string
- ktyp Type
- wants Type
+func TestNewTypeFromEventRecord(t *testing.T) {
+ tests := []struct {
+ name string
+ provider windows.GUID
+ id uint16
+ opcode uint8
+ want Type
}{
+ // Registry
{
- "equals CreateProcess",
- pack(windows.GUID{Data1: 0x3d6fa8d0, Data2: 0xfe05, Data3: 0x11d0, Data4: [8]byte{0x9d, 0xda, 0x0, 0xc0, 0x4f, 0xd7, 0xba, 0x7c}}, 1),
- CreateProcess,
+ name: "Registry/CreateKey",
+ provider: RegistryEventGUID,
+ opcode: RegCreateKeyID,
+ want: RegCreateKey,
},
{
- "equals TerminateProcess",
- pack(windows.GUID{Data1: 0x3d6fa8d0, Data2: 0xfe05, Data3: 0x11d0, Data4: [8]byte{0x9d, 0xda, 0x0, 0xc0, 0x4f, 0xd7, 0xba, 0x7c}}, 2),
- TerminateProcess,
+ name: "Registry/OpenKey",
+ provider: RegistryEventGUID,
+ opcode: RegOpenKeyID,
+ want: RegOpenKey,
+ },
+ {
+ name: "Registry/DeleteKey",
+ provider: RegistryEventGUID,
+ opcode: RegDeleteKeyID,
+ want: RegDeleteKey,
+ },
+ {
+ name: "Registry/QueryKey",
+ provider: RegistryEventGUID,
+ opcode: RegQueryKeyID,
+ want: RegQueryKey,
+ },
+ {
+ name: "Registry/SetValue",
+ provider: RegistryEventGUID,
+ opcode: RegSetValueID,
+ want: RegSetValue,
+ },
+ {
+ name: "Registry/DeleteValue",
+ provider: RegistryEventGUID,
+ opcode: RegDeleteValueID,
+ want: RegDeleteValue,
+ },
+ {
+ name: "Registry/QueryValue",
+ provider: RegistryEventGUID,
+ opcode: RegQueryValueID,
+ want: RegQueryValue,
+ },
+ {
+ name: "Registry/CreateKCB",
+ provider: RegistryEventGUID,
+ opcode: RegCreateKCBID,
+ want: RegCreateKCB,
+ },
+ {
+ name: "Registry/DeleteKCB",
+ provider: RegistryEventGUID,
+ opcode: RegDeleteKCBID,
+ want: RegDeleteKCB,
+ },
+ {
+ name: "Registry/KCBRundown",
+ provider: RegistryEventGUID,
+ opcode: RegKCBRundownID,
+ want: RegKCBRundown,
+ },
+ {
+ name: "Registry/CloseKey",
+ provider: RegistryEventGUID,
+ opcode: RegCloseKeyID,
+ want: RegCloseKey,
},
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- lhs, rhs := tt.ktyp, tt.wants
- assert.Equal(t, lhs, rhs)
- })
- }
-}
+ // File
+ {
+ name: "File/FileRundown",
+ provider: FileEventGUID,
+ opcode: FileRundownID,
+ want: FileRundown,
+ },
+ {
+ name: "File/MapViewOfSection",
+ provider: FileEventGUID,
+ opcode: MapViewOfSectionID,
+ want: MapViewOfSection,
+ },
+ {
+ name: "File/UnmapViewOfSection",
+ provider: FileEventGUID,
+ opcode: UnmapViewOfSectionID,
+ want: UnmapViewOfSection,
+ },
+ {
+ name: "File/MapViewSectionRundown",
+ provider: FileEventGUID,
+ opcode: MapViewSectionRundownID,
+ want: MapViewSectionRundown,
+ },
+ {
+ name: "File/CreateFile",
+ provider: FileEventGUID,
+ opcode: CreateFileID,
+ want: CreateFile,
+ },
+ {
+ name: "File/ReleaseFile",
+ provider: FileEventGUID,
+ opcode: ReleaseFileID,
+ want: ReleaseFile,
+ },
+ {
+ name: "File/CloseFile",
+ provider: FileEventGUID,
+ opcode: CloseFileID,
+ want: CloseFile,
+ },
+ {
+ name: "File/ReadFile",
+ provider: FileEventGUID,
+ opcode: ReadFileID,
+ want: ReadFile,
+ },
+ {
+ name: "File/WriteFile",
+ provider: FileEventGUID,
+ opcode: WriteFileID,
+ want: WriteFile,
+ },
+ {
+ name: "File/SetFileInformation",
+ provider: FileEventGUID,
+ opcode: SetFileInformationID,
+ want: SetFileInformation,
+ },
+ {
+ name: "File/DeleteFile",
+ provider: FileEventGUID,
+ opcode: DeleteFileID,
+ want: DeleteFile,
+ },
+ {
+ name: "File/RenameFile",
+ provider: FileEventGUID,
+ opcode: RenameFileID,
+ want: RenameFile,
+ },
+ {
+ name: "File/EnumDirectory",
+ provider: FileEventGUID,
+ opcode: EnumDirectoryID,
+ want: EnumDirectory,
+ },
+ {
+ name: "File/FileOpEnd",
+ provider: FileEventGUID,
+ opcode: FileOpEndID,
+ want: FileOpEnd,
+ },
-func TestNewEventTypeFromEventRecord(t *testing.T) {
- assert.Equal(t, CreateProcess, NewTypeFromEventRecord(&etw.EventRecord{
- Header: etw.EventHeader{
- ProviderID: windows.GUID{Data1: 0x3d6fa8d0, Data2: 0xfe05, Data3: 0x11d0, Data4: [8]byte{0x9d, 0xda, 0x0, 0xc0, 0x4f, 0xd7, 0xba, 0x7c}},
- EventDescriptor: etw.EventDescriptor{
- Opcode: 1,
- },
- },
- }))
- assert.Equal(t, OpenProcess, NewTypeFromEventRecord(&etw.EventRecord{
- Header: etw.EventHeader{
- ProviderID: windows.GUID{Data1: 0xe02a841c, Data2: 0x75a3, Data3: 0x4fa7, Data4: [8]byte{0xaf, 0xc8, 0xae, 0x09, 0xcf, 0x9b, 0x7f, 0x23}},
- EventDescriptor: etw.EventDescriptor{
- ID: 5,
- },
- },
- }))
-}
+ // Audit API -- these use EventDescriptor.ID, not Opcode.
+ {
+ name: "AuditAPI/OpenProcess",
+ provider: AuditAPIEventGUID,
+ id: OpenProcessID,
+ want: OpenProcess,
+ },
+ {
+ name: "AuditAPI/OpenThread",
+ provider: AuditAPIEventGUID,
+ id: OpenThreadID,
+ want: OpenThread,
+ },
+ {
+ name: "AuditAPI/SetThreadContext",
+ provider: AuditAPIEventGUID,
+ id: SetThreadContextID,
+ want: SetThreadContext,
+ },
+ {
+ name: "AuditAPI/CreateSymbolicLinkObject",
+ provider: AuditAPIEventGUID,
+ id: CreateSymbolicLinkObjectID,
+ want: CreateSymbolicLinkObject,
+ },
-func TestEventTypeExists(t *testing.T) {
- require.True(t, AcceptTCPv4.Exists())
- require.True(t, AcceptTCPv6.Exists())
-}
+ // Stack walk
+ {
+ name: "StackWalk",
+ provider: StackWalkEventGUID,
+ want: StackWalk,
+ },
-func TestGUIDAndHookIDFromEventType(t *testing.T) {
- var tests = []struct {
- Type Type
- opcode uint16
- guid windows.GUID
- }{
+ // Memory
+ {
+ name: "Memory/VirtualAlloc",
+ provider: MemoryEventGUID,
+ opcode: VirtualAllocID,
+ want: VirtualAlloc,
+ },
+ {
+ name: "Memory/VirtualFree",
+ provider: MemoryEventGUID,
+ opcode: VirtualFreeID,
+ want: VirtualFree,
+ },
+
+ // TCP
{
- LoadModule,
- 10,
- windows.GUID{Data1: 0x2cb15d1d, Data2: 0x5fc1, Data3: 0x11d2, Data4: [8]byte{0xab, 0xe1, 0x0, 0xa0, 0xc9, 0x11, 0xf5, 0x18}},
+ name: "TCP/AcceptIPv4",
+ provider: NetworkTCPEventGUID,
+ opcode: AcceptTCPv4ID,
+ want: Accept,
},
{
- WriteFile,
- 68,
- windows.GUID{Data1: 0x90cbdc39, Data2: 0x4a3e, Data3: 0x11d1, Data4: [8]byte{0x84, 0xf4, 0x0, 0x0, 0xf8, 0x04, 0x64, 0xe3}},
+ name: "TCP/AcceptIPv6",
+ provider: NetworkTCPEventGUID,
+ opcode: AcceptTCPv6ID,
+ want: Accept,
+ },
+ {
+ name: "TCP/SendIPv4",
+ provider: NetworkTCPEventGUID,
+ opcode: SendV4ID,
+ want: Send,
+ },
+ {
+ name: "TCP/SendIPv6",
+ provider: NetworkTCPEventGUID,
+ opcode: SendV6ID,
+ want: Send,
+ },
+ {
+ name: "TCP/RecvIPv4",
+ provider: NetworkTCPEventGUID,
+ opcode: RecvV4ID,
+ want: Recv,
+ },
+ {
+ name: "TCP/RecvIPv6",
+ provider: NetworkTCPEventGUID,
+ opcode: RecvV6ID,
+ want: Recv,
+ },
+ {
+ name: "TCP/ConnectIPv4",
+ provider: NetworkTCPEventGUID,
+ opcode: ConnectTCPv4ID,
+ want: Connect,
+ },
+ {
+ name: "TCP/ConnectIPv6",
+ provider: NetworkTCPEventGUID,
+ opcode: ConnectTCPv6ID,
+ want: Connect,
+ },
+ {
+ name: "TCP/DisconnectIPv4",
+ provider: NetworkTCPEventGUID,
+ opcode: DisconnectTCPv4ID,
+ want: Disconnect,
+ },
+ {
+ name: "TCP/DisconnectIPv6",
+ provider: NetworkTCPEventGUID,
+ opcode: DisconnectTCPv6ID,
+ want: Disconnect,
+ },
+ {
+ name: "TCP/ReconnectIPv4",
+ provider: NetworkTCPEventGUID,
+ opcode: ReconnectTCPv4ID,
+ want: Reconnect,
+ },
+ {
+ name: "TCP/ReconnectIPv6",
+ provider: NetworkTCPEventGUID,
+ opcode: ReconnectTCPv6ID,
+ want: Reconnect,
+ },
+ {
+ name: "TCP/RetransmitIPv4",
+ provider: NetworkTCPEventGUID,
+ opcode: RetransmitTCPv4ID,
+ want: Retransmit,
+ },
+ {
+ name: "TCP/RetransmitIPv6",
+ provider: NetworkTCPEventGUID,
+ opcode: RetransmitTCPv6ID,
+ want: Retransmit,
+ },
+
+ // UDP
+ {
+ name: "UDP/SendIPv4",
+ provider: NetworkUDPEventGUID,
+ opcode: SendV4ID,
+ want: Send,
+ },
+ {
+ name: "UDP/SendIPv6",
+ provider: NetworkUDPEventGUID,
+ opcode: SendV6ID,
+ want: Send,
+ },
+ {
+ name: "UDP/RecvIPv4",
+ provider: NetworkUDPEventGUID,
+ opcode: RecvV4ID,
+ want: Recv,
+ },
+ {
+ name: "UDP/RecvIPv6",
+ provider: NetworkUDPEventGUID,
+ opcode: RecvV6ID,
+ want: Recv,
+ },
+
+ // DNS -- uses EventDescriptor.ID.
+ {
+ name: "DNS/Query",
+ provider: DNSEventGUID,
+ id: QueryDNSID,
+ want: QueryDNS,
+ },
+ {
+ name: "DNS/Reply",
+ provider: DNSEventGUID,
+ id: ReplyDNSID,
+ want: ReplyDNS,
+ },
+
+ // Process
+ {
+ name: "Process/CreateProcess",
+ provider: ProcessEventGUID,
+ opcode: CreateProcessID,
+ want: CreateProcess,
+ },
+ {
+ name: "Process/TerminateProcess",
+ provider: ProcessEventGUID,
+ opcode: TerminateProcessID,
+ want: TerminateProcess,
+ },
+ {
+ name: "Process/ProcessRundown",
+ provider: ProcessEventGUID,
+ opcode: ProcessRundownID,
+ want: ProcessRundown,
+ },
+
+ // Process kernel -- uses EventDescriptor.ID.
+ {
+ name: "ProcessKernel/CreateProcessInternal",
+ provider: ProcessKernelEventGUID,
+ id: CreateProcessInternalID,
+ want: CreateProcessInternal,
+ },
+ {
+ name: "ProcessKernel/ProcessRundownInternal",
+ provider: ProcessKernelEventGUID,
+ id: ProcessRundownInternalID,
+ want: ProcessRundownInternal,
+ },
+ {
+ name: "ProcessKernel/LoadModuleInternal",
+ provider: ProcessKernelEventGUID,
+ id: LoadModuleInternalID,
+ want: LoadModuleInternal,
+ },
+
+ // Module
+ {
+ name: "Module/UnloadModule",
+ provider: ModuleEventGUID,
+ opcode: UnloadModuleID,
+ want: UnloadModule,
+ },
+ {
+ name: "Module/ModuleRundown",
+ provider: ModuleEventGUID,
+ opcode: ModuleRundownID,
+ want: ModuleRundown,
+ },
+ {
+ name: "Module/LoadModule",
+ provider: ModuleEventGUID,
+ opcode: LoadModuleID,
+ want: LoadModule,
+ },
+
+ // Thread
+ {
+ name: "Thread/CreateThread",
+ provider: ThreadEventGUID,
+ opcode: CreateThreadID,
+ want: CreateThread,
+ },
+ {
+ name: "Thread/TerminateThread",
+ provider: ThreadEventGUID,
+ opcode: TerminateThreadID,
+ want: TerminateThread,
+ },
+ {
+ name: "Thread/ThreadRundown",
+ provider: ThreadEventGUID,
+ opcode: ThreadRundownID,
+ want: ThreadRundown,
},
}
for _, tt := range tests {
- t.Run(tt.Type.String(), func(t *testing.T) {
- assert.Equal(t, tt.guid.String(), tt.Type.GUID().String())
- assert.Equal(t, tt.opcode, tt.Type.HookID())
- })
- }
-}
+ t.Run(tt.name, func(t *testing.T) {
+ r := &etw.EventRecord{
+ Header: etw.EventHeader{
+ ProviderID: tt.provider,
+ EventDescriptor: etw.EventDescriptor{
+ ID: tt.id,
+ Opcode: tt.opcode,
+ },
+ },
+ }
-func TestIDEquality(t *testing.T) {
- evt := etw.EventRecord{Header: etw.EventHeader{ProviderID: ThreadEventGUID, EventDescriptor: etw.EventDescriptor{Opcode: 1}}}
- typ := CreateThread
- require.Equal(t, typ.ID(), evt.ID())
-}
+ got := NewTypeFromEventRecord(r)
-func TestEventTypeIDCollision(t *testing.T) {
- ids := make(map[uint]Type)
- for _, typ := range AllWithState() {
- if etype, ok := ids[typ.ID()]; ok {
- t.Fatalf("id collision for %s event type. Mapped event type: %s", typ.String(), etype.String())
- }
- ids[typ.ID()] = typ
+ if got != tt.want {
+ t.Fatalf("NewTypeFromEventRecord() = %v, want %v", got, tt.want)
+ }
+ })
}
}
diff --git a/pkg/filament/dict.go b/pkg/filament/dict.go
index 967ec7dcf..0150d334b 100644
--- a/pkg/filament/dict.go
+++ b/pkg/filament/dict.go
@@ -62,9 +62,9 @@ func newEventDict(evt *event.Event) (*cpython.Dict, error) {
dict.Insert(pid, cpython.NewPyObjectFromValue(evt.PID))
dict.Insert(tid, cpython.NewPyObjectFromValue(evt.Tid))
dict.Insert(cpu, cpython.NewPyObjectFromValue(evt.CPU))
- dict.Insert(name, cpython.NewPyObjectFromValue(evt.Name))
- dict.Insert(cat, cpython.NewPyObjectFromValue(string(evt.Category)))
- dict.Insert(desc, cpython.NewPyObjectFromValue(evt.Description))
+ dict.Insert(name, cpython.NewPyObjectFromValue(evt.Name()))
+ dict.Insert(cat, cpython.NewPyObjectFromValue(evt.Category().String()))
+ dict.Insert(desc, cpython.NewPyObjectFromValue(evt.Description()))
dict.Insert(host, cpython.NewPyObjectFromValue(evt.Host))
dict.Insert(ts, cpython.NewPyObjectFromValue(evt.Timestamp))
diff --git a/pkg/filament/dict_test.go b/pkg/filament/dict_test.go
index 7d714cf25..308c240ca 100644
--- a/pkg/filament/dict_test.go
+++ b/pkg/filament/dict_test.go
@@ -22,14 +22,15 @@
package filament
import (
+ "net"
+ "testing"
+ "time"
+
"github.com/rabbitstack/fibratus/pkg/event"
"github.com/rabbitstack/fibratus/pkg/event/params"
"github.com/rabbitstack/fibratus/pkg/filament/cpython"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "net"
- "testing"
- "time"
)
func TestProduceEventDict(t *testing.T) {
@@ -41,16 +42,15 @@ func TestProduceEventDict(t *testing.T) {
defer cpython.Finalize()
now := time.Now()
evt := &event.Event{
- Seq: uint64(12456738026482168384),
- Tid: 2484,
- PID: 859,
- CPU: 1,
- Name: "CreateFile",
- Timestamp: now,
- Category: event.File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Seq: uint64(12456738026482168384),
+ Tid: 2484,
+ PID: 859,
+ CPU: 1,
+ Type: event.CreateFile,
+ Timestamp: now,
+ Host: "archrabbit",
}
+
dict, err := newEventDict(evt)
require.NoError(t, err)
require.NotNil(t, dict)
@@ -80,7 +80,7 @@ func TestProduceEventDictWithIPAddresses(t *testing.T) {
defer cpython.Finalize()
evt := &event.Event{
- Name: "Send",
+ Type: event.Send,
Tid: 2484,
PID: 859,
Params: event.Params{
@@ -112,15 +112,13 @@ func BenchmarkTestProduceEventDict(b *testing.B) {
defer cpython.Finalize()
evt := &event.Event{
- Seq: uint64(12456738026482168384),
- Tid: 2484,
- PID: 859,
- CPU: 1,
- Name: "CreateFile",
- Timestamp: time.Now(),
- Category: event.File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Seq: uint64(12456738026482168384),
+ Tid: 2484,
+ PID: 859,
+ CPU: 1,
+ Type: event.CreateFile,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
}
for i := 0; i < b.N; i++ {
diff --git a/pkg/filament/filament_test.go b/pkg/filament/filament_test.go
index 0e457e361..57e57c3b6 100644
--- a/pkg/filament/filament_test.go
+++ b/pkg/filament/filament_test.go
@@ -72,10 +72,8 @@ func TestOnNextEvent(t *testing.T) {
Type: event.RegCreateKey,
Tid: 2484,
PID: 859,
- Name: "RegCreateKey",
Host: "archrabbit",
CPU: uint8(i / 2),
- Category: event.Registry,
Seq: uint64(i),
Timestamp: time.Now(),
Params: event.Params{
@@ -105,7 +103,7 @@ func TestFilamentFilter(t *testing.T) {
require.NotNil(t, filament)
defer filament.Close()
require.NotNil(t, filament.Filter())
- kpars := event.Params{
+ pars := event.Params{
params.Cmdline: {Name: params.Cmdline, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\svchost.exe -k RPCSS"},
params.ProcessName: {Name: params.ProcessName, Type: params.AnsiString, Value: "svchost.exe"},
params.ProcessID: {Name: params.ProcessID, Type: params.Uint32, Value: uint32(1234)},
@@ -114,8 +112,7 @@ func TestFilamentFilter(t *testing.T) {
evt := &event.Event{
Type: event.CreateProcess,
- Params: kpars,
- Name: "CreateProcess",
+ Params: pars,
}
require.True(t, filament.Filter().Eval(evt))
diff --git a/pkg/filter/accessor.go b/pkg/filter/accessor.go
index 52e7ee717..ea14a98f8 100644
--- a/pkg/filter/accessor.go
+++ b/pkg/filter/accessor.go
@@ -77,11 +77,11 @@ func (*evtAccessor) Get(f Field, evt *event.Event) (params.Value, error) {
case fields.EvtCPU, fields.KevtCPU:
return evt.CPU, nil
case fields.EvtName, fields.KevtName:
- return evt.Name, nil
+ return evt.Name(), nil
case fields.EvtCategory, fields.KevtCategory:
- return string(evt.Category), nil
+ return evt.Category().String(), nil
case fields.EvtDesc, fields.KevtDesc:
- return evt.Description, nil
+ return evt.Description(), nil
case fields.EvtHost, fields.KevtHost:
return evt.Host, nil
case fields.EvtTime, fields.KevtTime:
diff --git a/pkg/filter/accessor_windows.go b/pkg/filter/accessor_windows.go
index 0f2062416..e39cd59ef 100644
--- a/pkg/filter/accessor_windows.go
+++ b/pkg/filter/accessor_windows.go
@@ -76,7 +76,7 @@ type psAccessor struct {
func (psAccessor) SetFields([]Field) {}
func (psAccessor) SetSegments([]fields.Segment) {}
func (psAccessor) IsFieldAccessible(e *event.Event) bool {
- return e.PS != nil || e.Category == event.Process
+ return e.PS != nil || e.Category() == event.Process
}
func newPSAccessor(psnap psnap.Snapshotter) Accessor { return &psAccessor{psnap: psnap} }
@@ -475,7 +475,7 @@ type threadAccessor struct{}
func (threadAccessor) SetFields([]Field) {}
func (threadAccessor) SetSegments([]fields.Segment) {}
func (threadAccessor) IsFieldAccessible(e *event.Event) bool {
- return !e.Callstack.IsEmpty() || e.Category == event.Thread
+ return !e.Callstack.IsEmpty() || e.Category() == event.Thread
}
func newThreadAccessor() Accessor {
@@ -676,7 +676,9 @@ type fileAccessor struct{}
func (fileAccessor) SetFields(fields []Field) {}
func (fileAccessor) SetSegments([]fields.Segment) {}
-func (fileAccessor) IsFieldAccessible(e *event.Event) bool { return e.Category == event.File }
+func (fileAccessor) IsFieldAccessible(e *event.Event) bool {
+ return e.Category() == event.File || e.Category() == event.Memory
+}
func newFileAccessor() Accessor {
return &fileAccessor{}
@@ -770,7 +772,7 @@ func (moduleAccessor) SetFields(fields []Field) {}
func (moduleAccessor) SetSegments([]fields.Segment) {}
func (moduleAccessor) IsFieldAccessible(e *event.Event) bool {
- return e.Category == event.Module
+ return e.Category() == event.Module
}
func newModuleAccessor() Accessor {
@@ -868,7 +870,7 @@ type registryAccessor struct{}
func (registryAccessor) SetFields([]Field) {}
func (registryAccessor) SetSegments([]fields.Segment) {}
func (registryAccessor) IsFieldAccessible(e *event.Event) bool {
- return e.Category == event.Registry
+ return e.Category() == event.Registry
}
func newRegistryAccessor() Accessor {
@@ -920,7 +922,7 @@ func (n *networkAccessor) SetFields(flds []Field) {
func (networkAccessor) SetSegments([]fields.Segment) {}
func (networkAccessor) IsFieldAccessible(e *event.Event) bool {
- return e.Category == event.Net
+ return e.Category() == event.Network
}
func newNetworkAccessor() Accessor { return &networkAccessor{} }
@@ -1205,7 +1207,7 @@ type memAccessor struct{}
func (memAccessor) SetFields([]Field) {}
func (memAccessor) SetSegments([]fields.Segment) {}
-func (memAccessor) IsFieldAccessible(e *event.Event) bool { return e.Category == event.Mem }
+func (memAccessor) IsFieldAccessible(e *event.Event) bool { return e.Category() == event.Memory }
func newMemAccessor() Accessor {
return &memAccessor{}
@@ -1236,7 +1238,7 @@ type dnsAccessor struct{}
func (dnsAccessor) SetFields([]Field) {}
func (dnsAccessor) SetSegments([]fields.Segment) {}
func (dnsAccessor) IsFieldAccessible(e *event.Event) bool {
- return e.Type.Subcategory() == event.DNS
+ return e.Subcategory() == event.DNS
}
func newDNSAccessor() Accessor {
diff --git a/pkg/filter/accessor_windows_test.go b/pkg/filter/accessor_windows_test.go
index 6d52f0717..0035e7f52 100644
--- a/pkg/filter/accessor_windows_test.go
+++ b/pkg/filter/accessor_windows_test.go
@@ -79,67 +79,67 @@ func TestIsFieldAccessible(t *testing.T) {
}{
{
newEventAccessor(),
- &event.Event{Type: event.QueryDNS, Category: event.Net},
+ &event.Event{Type: event.QueryDNS},
true,
},
{
newPSAccessor(nil),
- &event.Event{Type: event.CreateProcess, Category: event.Process},
+ &event.Event{Type: event.CreateProcess},
true,
},
{
newPSAccessor(nil),
- &event.Event{PS: &ptypes.PS{}, Type: event.CreateFile, Category: event.File},
+ &event.Event{PS: &ptypes.PS{}, Type: event.CreateFile},
true,
},
{
newPSAccessor(nil),
- &event.Event{Type: event.SetThreadContext, Category: event.Thread},
+ &event.Event{Type: event.SetThreadContext},
false,
},
{
newThreadAccessor(),
- &event.Event{Type: event.SetThreadContext, Category: event.Thread},
+ &event.Event{Type: event.SetThreadContext},
true,
},
{
newThreadAccessor(),
- &event.Event{Type: event.CreateProcess, Category: event.Process, Callstack: []callstack.Frame{{Addr: 0x7ffb5c1d0396, Offset: 0x61, Symbol: "CreateProcessW", Module: "C:\\WINDOWS\\System32\\KERNELBASE.dll"}}},
+ &event.Event{Type: event.CreateProcess, Callstack: []callstack.Frame{{Addr: 0x7ffb5c1d0396, Offset: 0x61, Symbol: "CreateProcessW", Module: "C:\\WINDOWS\\System32\\KERNELBASE.dll"}}},
true,
},
{
newThreadAccessor(),
- &event.Event{Type: event.RegSetValue, Category: event.Registry, Callstack: []callstack.Frame{{Addr: 0x7ffb5c1d0396, Offset: 0x61, Symbol: "CreateProcessW", Module: "C:\\WINDOWS\\System32\\KERNELBASE.dll"}}},
+ &event.Event{Type: event.RegSetValue, Callstack: []callstack.Frame{{Addr: 0x7ffb5c1d0396, Offset: 0x61, Symbol: "CreateProcessW", Module: "C:\\WINDOWS\\System32\\KERNELBASE.dll"}}},
true,
},
{
newRegistryAccessor(),
- &event.Event{Type: event.RegSetValue, Category: event.Registry, Callstack: []callstack.Frame{{Addr: 0x7ffb5c1d0396, Offset: 0x61, Symbol: "CreateProcessW", Module: "C:\\WINDOWS\\System32\\KERNELBASE.dll"}}},
+ &event.Event{Type: event.RegSetValue, Callstack: []callstack.Frame{{Addr: 0x7ffb5c1d0396, Offset: 0x61, Symbol: "CreateProcessW", Module: "C:\\WINDOWS\\System32\\KERNELBASE.dll"}}},
true,
},
{
newNetworkAccessor(),
- &event.Event{Type: event.RegSetValue, Category: event.Registry, Callstack: []callstack.Frame{{Addr: 0x7ffb5c1d0396, Offset: 0x61, Symbol: "CreateProcessW", Module: "C:\\WINDOWS\\System32\\KERNELBASE.dll"}}},
+ &event.Event{Type: event.RegSetValue, Callstack: []callstack.Frame{{Addr: 0x7ffb5c1d0396, Offset: 0x61, Symbol: "CreateProcessW", Module: "C:\\WINDOWS\\System32\\KERNELBASE.dll"}}},
false,
},
{
newNetworkAccessor(),
- &event.Event{Type: event.ConnectTCPv6, Category: event.Net},
+ &event.Event{Type: event.Connect},
true,
},
{
newDNSAccessor(),
- &event.Event{Type: event.ReplyDNS, Category: event.Net},
+ &event.Event{Type: event.ReplyDNS},
true,
},
{
newModuleAccessor(),
- &event.Event{Type: event.LoadModule, Category: event.Module},
+ &event.Event{Type: event.LoadModule},
true,
},
{
newMemAccessor(),
- &event.Event{Type: event.VirtualAlloc, Category: event.Mem},
+ &event.Event{Type: event.VirtualAlloc},
true,
},
}
diff --git a/pkg/filter/filter_test.go b/pkg/filter/filter_test.go
index 1c3fb95ae..b79aa493d 100644
--- a/pkg/filter/filter_test.go
+++ b/pkg/filter/filter_test.go
@@ -175,8 +175,7 @@ func TestProcFilter(t *testing.T) {
}
evt := &event.Event{
- Type: event.CreateProcess,
- Category: event.Process,
+ Type: event.CreateProcess,
Params: event.Params{
params.Cmdline: {Name: params.Cmdline, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\svchost.exe -k DcomLaunch -p -s LSM"},
params.ProcessName: {Name: params.ProcessName, Type: params.AnsiString, Value: "svchost.exe"},
@@ -190,8 +189,7 @@ func TestProcFilter(t *testing.T) {
params.ProcessTokenIsElevated: {Name: params.ProcessTokenIsElevated, Type: params.Bool, Value: true},
params.ProcessTokenElevationType: {Name: params.ProcessTokenElevationType, Type: params.AnsiString, Value: "DEFAULT"},
},
- Name: "CreateProcess",
- PID: 1234,
+ PID: 1234,
PS: &pstypes.PS{
Name: "svchost.exe",
Cmdline: "C:\\Windows\\System32\\svchost.exe -k DcomLaunch -p -s LSM",
@@ -226,13 +224,11 @@ func TestProcFilter(t *testing.T) {
evt.Timestamp, _ = time.Parse(time.RFC3339, "2011-05-03T15:04:05.323Z")
evt1 := &event.Event{
- Type: event.OpenProcess,
- Category: event.Process,
+ Type: event.OpenProcess,
Params: event.Params{
params.DesiredAccess: {Name: params.DesiredAccess, Type: params.Flags, Value: uint32(0x1400), Flags: event.PsAccessRightFlags},
},
- Name: "OpenProcess",
- PID: 1023,
+ PID: 1023,
PS: &pstypes.PS{
Name: "svchost.exe",
Parent: parent,
@@ -246,13 +242,11 @@ func TestProcFilter(t *testing.T) {
}
evt2 := &event.Event{
- Type: event.OpenProcess,
- Category: event.Process,
+ Type: event.OpenProcess,
Params: event.Params{
params.DesiredAccess: {Name: params.DesiredAccess, Type: params.Flags, Value: uint32(0x1400), Flags: event.PsAccessRightFlags},
},
- Name: "OpenProcess",
- PID: 1023,
+ PID: 1023,
}
var tests = []struct {
@@ -424,11 +418,9 @@ func TestThreadFilter(t *testing.T) {
params.StartAddressModule: {Name: params.StartAddressModule, Type: params.UnicodeString, Value: "C:\\Windows\\System32\\kernel32.dll"},
}
evt := &event.Event{
- Type: event.CreateThread,
- Params: pars,
- Name: "CreateThread",
- PID: windows.GetCurrentProcessId(),
- Category: event.Thread,
+ Type: event.CreateThread,
+ Params: pars,
+ PID: windows.GetCurrentProcessId(),
PS: &pstypes.PS{
Name: "svchost.exe",
Envs: map[string]string{"ALLUSERSPROFILE": "C:\\ProgramData", "OS": "Windows_NT", "ProgramFiles(x86)": "C:\\Program Files (x86)"},
@@ -615,15 +607,12 @@ func TestThreadFilter(t *testing.T) {
func TestFileFilter(t *testing.T) {
evt := &event.Event{
- Type: event.CreateFile,
- Tid: 2484,
- PID: 859,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Category: event.File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: event.CreateFile,
+ Tid: 2484,
+ PID: 859,
+ CPU: 1,
+ Seq: 2,
+ Host: "archrabbit",
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\user32.dll"},
@@ -705,9 +694,7 @@ func TestFileInfoFilter(t *testing.T) {
{
`file.info_class = 'Allocation'`,
&event.Event{
- Category: event.File,
- Type: event.SetFileInformation,
- Name: "SetFileInformation",
+ Type: event.SetFileInformation,
Params: event.Params{
params.FileInfoClass: {Name: params.FileInfoClass, Type: params.Enum, Value: fs.AllocationClass, Enum: fs.FileInfoClasses},
},
@@ -717,9 +704,7 @@ func TestFileInfoFilter(t *testing.T) {
{
`file.info.allocation_size = 64500`,
&event.Event{
- Category: event.File,
- Type: event.SetFileInformation,
- Name: "SetFileInformation",
+ Type: event.SetFileInformation,
Params: event.Params{
params.FileInfoClass: {Name: params.FileInfoClass, Type: params.Enum, Value: fs.AllocationClass, Enum: fs.FileInfoClasses},
params.FileExtraInfo: {Name: params.FileExtraInfo, Type: params.Uint64, Value: uint64(64500)},
@@ -730,9 +715,7 @@ func TestFileInfoFilter(t *testing.T) {
{
`file.info.eof_size = 64500`,
&event.Event{
- Category: event.File,
- Type: event.SetFileInformation,
- Name: "SetFileInformation",
+ Type: event.SetFileInformation,
Params: event.Params{
params.FileInfoClass: {Name: params.FileInfoClass, Type: params.Enum, Value: fs.EOFClass, Enum: fs.FileInfoClasses},
params.FileExtraInfo: {Name: params.FileExtraInfo, Type: params.Uint64, Value: uint64(64500)},
@@ -743,9 +726,7 @@ func TestFileInfoFilter(t *testing.T) {
{
`file.info.eof_size = 64500`,
&event.Event{
- Category: event.File,
- Type: event.SetFileInformation,
- Name: "SetFileInformation",
+ Type: event.SetFileInformation,
Params: event.Params{
params.FileInfoClass: {Name: params.FileInfoClass, Type: params.Enum, Value: fs.DispositionClass, Enum: fs.FileInfoClasses},
params.FileExtraInfo: {Name: params.FileExtraInfo, Type: params.Uint64, Value: uint64(1)},
@@ -756,9 +737,7 @@ func TestFileInfoFilter(t *testing.T) {
{
`file.info.is_disposition_delete_file = true`,
&event.Event{
- Category: event.File,
- Type: event.DeleteFile,
- Name: "DeleteFile",
+ Type: event.DeleteFile,
Params: event.Params{
params.FileInfoClass: {Name: params.FileInfoClass, Type: params.Enum, Value: fs.DispositionClass, Enum: fs.FileInfoClasses},
params.FileExtraInfo: {Name: params.FileExtraInfo, Type: params.Uint64, Value: uint64(1)},
@@ -782,16 +761,13 @@ func TestFileInfoFilter(t *testing.T) {
func TestEventFilter(t *testing.T) {
evt := &event.Event{
- Type: event.CreateFile,
- Tid: 2484,
- PID: 859,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Category: event.File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
- Evasions: uint32(evasion.IndirectSyscall),
+ Type: event.CreateFile,
+ Tid: 2484,
+ PID: 859,
+ CPU: 1,
+ Seq: 2,
+ Host: "archrabbit",
+ Evasions: uint32(evasion.IndirectSyscall),
Params: event.Params{
params.ProcessID: {Name: params.ProcessID, Type: params.PID, Value: uint32(3434)},
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
@@ -860,13 +836,12 @@ func TestEventFilter(t *testing.T) {
func TestNetFilter(t *testing.T) {
evt := &event.Event{
- Type: event.SendTCPv4,
+ Type: event.Accept,
Tid: 2484,
PID: 859,
PS: &pstypes.PS{
Name: "cmd.exe",
},
- Category: event.Net,
Params: event.Params{
params.NetDport: {Name: params.NetDport, Type: params.Uint16, Value: uint16(443)},
params.NetSport: {Name: params.NetSport, Type: params.Uint16, Value: uint16(43123)},
@@ -911,13 +886,12 @@ func TestNetFilter(t *testing.T) {
}
evt1 := &event.Event{
- Type: event.SendTCPv4,
+ Type: event.Send,
Tid: 2484,
PID: 859,
PS: &pstypes.PS{
Name: "cmd.exe",
},
- Category: event.Net,
Params: event.Params{
params.NetDport: {Name: params.NetDport, Type: params.Uint16, Value: uint16(53)},
params.NetSport: {Name: params.NetSport, Type: params.Uint16, Value: uint16(43123)},
@@ -950,10 +924,9 @@ func TestNetFilter(t *testing.T) {
func TestRegistryFilter(t *testing.T) {
evt := &event.Event{
- Type: event.RegSetValue,
- Tid: 2484,
- PID: 859,
- Category: event.Registry,
+ Type: event.RegSetValue,
+ Tid: 2484,
+ PID: 859,
Params: event.Params{
params.RegPath: {Name: params.RegPath, Type: params.UnicodeString, Value: `HKEY_LOCAL_MACHINE\SYSTEM\Setup\Pid`},
params.RegData: {Name: params.RegData, Type: params.Uint32, Value: uint32(10234)},
@@ -994,8 +967,7 @@ func TestModuleFilter(t *testing.T) {
fs.GetMetadataStore().AddFile(filepath.Join(os.Getenv("windir"), "System32", "kernel32.dll"), &fs.FileInfo{IsDLL: true})
e1 := &event.Event{
- Type: event.LoadModule,
- Category: event.Module,
+ Type: event.LoadModule,
Params: event.Params{
params.ModulePath: {Name: params.ModulePath, Type: params.UnicodeString, Value: filepath.Join(os.Getenv("windir"), "System32", "kernel32.dll")},
params.ProcessID: {Name: params.ProcessID, Type: params.PID, Value: uint32(1023)},
@@ -1065,8 +1037,7 @@ func TestModuleFilter(t *testing.T) {
// now exercise unsigned/unchecked signature
e2 := &event.Event{
- Type: event.LoadModule,
- Category: event.Module,
+ Type: event.LoadModule,
Params: event.Params{
params.ModulePath: {Name: params.ModulePath, Type: params.UnicodeString, Value: filepath.Join(os.Getenv("windir"), "System32", "kernel32.dll")},
params.ProcessID: {Name: params.ProcessID, Type: params.PID, Value: uint32(1023)},
@@ -1119,8 +1090,7 @@ func TestModuleFilter(t *testing.T) {
assert.NotNil(t, signature.GetSignatures().GetSignature(key))
e3 := &event.Event{
- Type: event.LoadModule,
- Category: event.Module,
+ Type: event.LoadModule,
Params: event.Params{
params.ModulePath: {Name: params.ModulePath, Type: params.UnicodeString, Value: "..\\pe\\_fixtures\\mscorlib.dll"},
params.ProcessID: {Name: params.ProcessID, Type: params.PID, Value: uint32(1023)},
@@ -1273,10 +1243,8 @@ func TestMemFilter(t *testing.T) {
}
evt := &event.Event{
- Type: event.VirtualAlloc,
- Params: pars,
- Name: "VirtualAlloc",
- Category: event.Mem,
+ Type: event.VirtualAlloc,
+ Params: pars,
PS: &pstypes.PS{
Name: "svchost.exe",
Envs: map[string]string{"ALLUSERSPROFILE": "C:\\ProgramData", "OS": "Windows_NT", "ProgramFiles(x86)": "C:\\Program Files (x86)"},
@@ -1318,7 +1286,6 @@ func TestDNSFilter(t *testing.T) {
PS: &pstypes.PS{
Name: "cmd.exe",
},
- Category: event.Net,
Params: event.Params{
params.DNSName: {Name: params.DNSName, Type: params.UnicodeString, Value: "r3.o.lencr.org"},
params.DNSRR: {Name: params.DNSRR, Type: params.Enum, Value: uint32(0x0001), Enum: event.DNSRecordTypes},
@@ -1364,10 +1331,8 @@ func TestInterpolateFields(t *testing.T) {
interpolated: "Credential discovery via VaultCmd.exe (VaultCmd.exe /listcreds:Windows Credentials /all) and user LOCAL\\tor",
evts: []*event.Event{
{
- Type: event.CreateProcess,
- Category: event.Process,
- Name: "CreateProcess",
- PID: 1023,
+ Type: event.CreateProcess,
+ PID: 1023,
PS: &pstypes.PS{
Name: "VaultCmd.exe",
Ppid: 345,
@@ -1384,10 +1349,8 @@ func TestInterpolateFields(t *testing.T) {
interpolated: "Credential discovery via N/A and pid 1023",
evts: []*event.Event{
{
- Type: event.CreateProcess,
- Category: event.Process,
- Name: "CreateProcess",
- PID: 1023,
+ Type: event.CreateProcess,
+ PID: 1023,
},
},
},
@@ -1396,10 +1359,8 @@ func TestInterpolateFields(t *testing.T) {
interpolated: "Suspicious thread start module C:\\Windows\\System32\\vault.dll",
evts: []*event.Event{
{
- Type: event.CreateThread,
- Category: event.Thread,
- Name: "CreateThread",
- PID: 1023,
+ Type: event.CreateThread,
+ PID: 1023,
Params: event.Params{
params.StartAddressModule: {Name: params.StartAddressModule, Type: params.UnicodeString, Value: "C:\\Windows\\System32\\vault.dll"},
},
@@ -1416,10 +1377,8 @@ and subsequently write the C:\Users
eo\Temp\lsass.dump dump file to the disk device`,
evts: []*event.Event{
{
- Type: event.OpenProcess,
- Category: event.Process,
- Name: "OpenProcess",
- PID: 1023,
+ Type: event.OpenProcess,
+ PID: 1023,
PS: &pstypes.PS{
Name: "taskmgr.exe",
Ppid: 345,
@@ -1427,10 +1386,8 @@ eo\Temp\lsass.dump dump file to the disk device`,
},
},
{
- Type: event.WriteFile,
- Category: event.File,
- Name: "WriteFile",
- PID: 1023,
+ Type: event.WriteFile,
+ PID: 1023,
Params: event.Params{
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "C:\\Users\neo\\Temp\\lsass.dump"},
},
@@ -1452,10 +1409,8 @@ and subsequently write the C:\Users
eo\Temp\lsass.dump dump file to the disk device`,
evts: []*event.Event{
{
- Type: event.OpenProcess,
- Category: event.Process,
- Name: "OpenProcess",
- PID: 1023,
+ Type: event.OpenProcess,
+ PID: 1023,
PS: &pstypes.PS{
Name: "taskmgr.exe",
Ppid: 345,
@@ -1463,10 +1418,8 @@ eo\Temp\lsass.dump dump file to the disk device`,
},
},
{
- Type: event.WriteFile,
- Category: event.File,
- Name: "WriteFile",
- PID: 1023,
+ Type: event.WriteFile,
+ PID: 1023,
Params: event.Params{
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "C:\\Users\neo\\Temp\\lsass.dump"},
},
@@ -1503,7 +1456,6 @@ func BenchmarkFilterRun(b *testing.B) {
evt := &event.Event{
Type: event.CreateProcess,
Params: pars,
- Name: "CreateProcess",
}
for i := 0; i < b.N; i++ {
diff --git a/pkg/filter/ql/literal.go b/pkg/filter/ql/literal.go
index 65140dea1..9e632b289 100644
--- a/pkg/filter/ql/literal.go
+++ b/pkg/filter/ql/literal.go
@@ -27,6 +27,7 @@ import (
"github.com/rabbitstack/fibratus/pkg/event"
"github.com/rabbitstack/fibratus/pkg/filter/fields"
+ "github.com/rabbitstack/fibratus/pkg/util/bitmap"
"github.com/rabbitstack/fibratus/pkg/filter/ql/functions"
)
@@ -288,8 +289,10 @@ type SequenceExpr struct {
// Alias represents the sequence expression alias when bound fields are used.
Alias string
- bitsets event.BitSets
- types []event.Type
+ eventBitmap bitmap.Bitmap[event.Type]
+ categoryBitmap bitmap.Bitmap[event.Category]
+
+ types []event.Type
}
func (e *SequenceExpr) init() {
@@ -343,39 +346,26 @@ func (e *SequenceExpr) walk() {
WalkFunc(e.Expr, walk)
- uniqCats := make(map[event.Category]bool)
-
// initialize event type/category buckets for every such field
for name, values := range stringFields {
for _, v := range values {
switch name {
case fields.EvtName:
- for _, typ := range event.NameToTypes(v) {
- if typ == event.UnknownType {
- continue
- }
- e.types = append(e.types, typ)
- uniqCats[event.TypeToEventInfo(typ).Category] = true
+ typ, ok := event.ParseType(v)
+ if !ok {
+ continue
}
+ e.types = append(e.types, typ)
+ e.eventBitmap.Set(typ)
case fields.EvtCategory:
- e.bitsets.SetCategoryBit(event.Category(v))
+ category, ok := event.ParseCategory(v)
+ if !ok {
+ continue
+ }
+ e.categoryBitmap.Set(category)
}
}
}
-
- for _, t := range e.types {
- switch len(uniqCats) {
- case 0:
- continue
- case 1:
- // happy path can use a single bitmask for all
- // event types pertaining to the same category
- e.bitsets.SetBit(event.TypeBitSet, t)
- default:
- // use map-backed bitmask for event identifiers
- e.bitsets.SetBit(event.BitmaskBitSet, t)
- }
- }
}
// IsEvaluable determines if the expression should be evaluated by inspecting
@@ -383,7 +373,7 @@ func (e *SequenceExpr) walk() {
// to be evaluated when the incoming event type, ID, or category pertains to the one
// defined in the field literal.
func (e *SequenceExpr) IsEvaluable(evt *event.Event) bool {
- return e.bitsets.IsBitSet(evt)
+ return e.eventBitmap.Has(evt.Type) || e.categoryBitmap.Has(evt.Category())
}
// HasBoundFields determines if this sequence expression references any bound field.
@@ -434,7 +424,7 @@ func (s *Sequence) init() {
for _, expr := range s.Expressions {
for _, etype := range expr.types {
- sources[etype.Source()] = true
+ sources[event.GetTypeInfo(etype).Source] = true
}
}
diff --git a/pkg/filter/ql/literal_test.go b/pkg/filter/ql/literal_test.go
index 3c978cbf5..19067b5c7 100644
--- a/pkg/filter/ql/literal_test.go
+++ b/pkg/filter/ql/literal_test.go
@@ -19,64 +19,28 @@
package ql
import (
+ "testing"
+
"github.com/rabbitstack/fibratus/pkg/event"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "testing"
)
func TestSequenceExprIsEvaluable(t *testing.T) {
var tests = []struct {
- expr string
- evt *event.Event
- isEval bool
- assertions func(t *testing.T, sexpr *SequenceExpr)
+ expr string
+ evt *event.Event
+ isEval bool
}{
- {"evt.name = 'CreateProcess'", &event.Event{Type: event.CreateProcess, Category: event.Process}, true,
- func(t *testing.T, sexpr *SequenceExpr) {
- assert.True(t, sexpr.bitsets.IsInitialized(event.TypeBitSet))
- assert.False(t, sexpr.bitsets.IsInitialized(event.BitmaskBitSet))
- assert.False(t, sexpr.bitsets.IsInitialized(event.CategoryBitSet))
- },
- },
- {"evt.name = 'CreateProcess'", &event.Event{Type: event.TerminateProcess, Category: event.Process}, false, nil},
- {"evt.name = 'CreateProcess' or evt.name = 'TerminateThread'", &event.Event{Type: event.TerminateProcess, Category: event.Process}, false, nil},
- {"evt.name = 'CreateProcess' or evt.category = 'object'", &event.Event{Type: event.TerminateProcess, Category: event.Process}, false, nil},
- {"evt.name = 'CreateProcess' or evt.name = 'OpenProcess'", &event.Event{Type: event.OpenProcess, Category: event.Process}, true,
- func(t *testing.T, sexpr *SequenceExpr) {
- assert.True(t, sexpr.bitsets.IsInitialized(event.TypeBitSet))
- assert.False(t, sexpr.bitsets.IsInitialized(event.BitmaskBitSet))
- assert.False(t, sexpr.bitsets.IsInitialized(event.CategoryBitSet))
- },
- },
- {"evt.name = 'CreateProcess' or evt.name = 'CreateThread'", &event.Event{Type: event.CreateThread, Category: event.Thread}, true,
- func(t *testing.T, sexpr *SequenceExpr) {
- assert.False(t, sexpr.bitsets.IsInitialized(event.TypeBitSet))
- assert.True(t, sexpr.bitsets.IsInitialized(event.BitmaskBitSet))
- assert.False(t, sexpr.bitsets.IsInitialized(event.CategoryBitSet))
- },
- },
- {"evt.name = 'CreateProcess' or evt.category = 'registry'", &event.Event{Type: event.RegSetValue, Category: event.Registry}, true,
- func(t *testing.T, sexpr *SequenceExpr) {
- assert.True(t, sexpr.bitsets.IsInitialized(event.TypeBitSet))
- assert.False(t, sexpr.bitsets.IsInitialized(event.BitmaskBitSet))
- assert.True(t, sexpr.bitsets.IsInitialized(event.CategoryBitSet))
- },
- },
- {"evt.name = 'CreateProcess' or evt.name = 'OpenProcess' or evt.category = 'registry'", &event.Event{Type: event.OpenProcess, Category: event.Process}, true,
- func(t *testing.T, sexpr *SequenceExpr) {
- assert.True(t, sexpr.bitsets.IsInitialized(event.TypeBitSet))
- assert.False(t, sexpr.bitsets.IsInitialized(event.BitmaskBitSet))
- assert.True(t, sexpr.bitsets.IsInitialized(event.CategoryBitSet))
- },
- },
- {"evt.name = 'CreateProcess' or evt.name = 'SetThreadContext' or evt.category = 'registry'", &event.Event{Type: event.CreateProcess, Category: event.Process}, true,
- func(t *testing.T, sexpr *SequenceExpr) {
- assert.False(t, sexpr.bitsets.IsInitialized(event.TypeBitSet))
- assert.True(t, sexpr.bitsets.IsInitialized(event.BitmaskBitSet))
- assert.True(t, sexpr.bitsets.IsInitialized(event.CategoryBitSet))
- },
- },
+ {"evt.name = 'CreateProcess'", &event.Event{Type: event.CreateProcess}, true},
+ {"evt.name = 'CreateProcess'", &event.Event{Type: event.TerminateProcess}, false},
+ {"evt.name = 'CreateProcess' or evt.name = 'TerminateThread'", &event.Event{Type: event.TerminateProcess}, false},
+ {"evt.name = 'CreateProcess' or evt.category = 'object'", &event.Event{Type: event.TerminateProcess}, false},
+ {"evt.name = 'CreateProcess' or evt.name = 'OpenProcess'", &event.Event{Type: event.OpenProcess}, true},
+ {"evt.name = 'CreateProcess' or evt.name = 'CreateThread'", &event.Event{Type: event.CreateThread}, true},
+ {"evt.name = 'CreateProcess' or evt.category = 'registry'", &event.Event{Type: event.RegSetValue}, true},
+ {"evt.name = 'CreateProcess' or evt.name = 'OpenProcess' or evt.category = 'registry'", &event.Event{Type: event.OpenProcess}, true},
+ {"evt.name = 'CreateProcess' or evt.name = 'SetThreadContext' or evt.category = 'registry'", &event.Event{Type: event.CreateProcess}, true},
}
for _, tt := range tests {
@@ -90,9 +54,6 @@ func TestSequenceExprIsEvaluable(t *testing.T) {
sexpr.walk()
assert.Equal(t, tt.isEval, sexpr.IsEvaluable(tt.evt))
- if tt.assertions != nil {
- tt.assertions(t, sexpr)
- }
})
}
}
diff --git a/pkg/outputs/amqp/amqp_test.go b/pkg/outputs/amqp/amqp_test.go
index 9a1539635..f7413f32c 100644
--- a/pkg/outputs/amqp/amqp_test.go
+++ b/pkg/outputs/amqp/amqp_test.go
@@ -21,11 +21,12 @@ package amqp
import (
"encoding/json"
"fmt"
- "github.com/rabbitstack/fibratus/pkg/util/va"
- "golang.org/x/sys/windows"
"testing"
"time"
+ "github.com/rabbitstack/fibratus/pkg/util/va"
+ "golang.org/x/sys/windows"
+
"github.com/phayes/freeport"
"github.com/rabbitstack/fibratus/pkg/event"
"github.com/rabbitstack/fibratus/pkg/event/params"
@@ -194,16 +195,13 @@ func amqpURL(port int) string {
//nolint:unused
func getBatch() *event.Batch {
evt := &event.Event{
- Type: event.CreateFile,
- Tid: 2484,
- PID: 859,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Timestamp: time.Now(),
- Category: event.File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: event.CreateFile,
+ Tid: 2484,
+ PID: 859,
+ CPU: 1,
+ Seq: 2,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "\\Device\\HarddiskVolume2\\Windows\\system32\\user32.dll"},
@@ -262,16 +260,13 @@ func getBatch() *event.Batch {
}
evt1 := &event.Event{
- Type: event.CreateFile,
- Tid: 2484,
- PID: 459,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Timestamp: time.Now(),
- Category: event.File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: event.CreateFile,
+ Tid: 2484,
+ PID: 459,
+ CPU: 1,
+ Seq: 2,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "\\Device\\HarddiskVolume2\\Windows\\system32\\user32.dll"},
@@ -330,16 +325,13 @@ func getBatch() *event.Batch {
}
evt2 := &event.Event{
- Type: event.CreateFile,
- Tid: 2484,
- PID: 829,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Timestamp: time.Now(),
- Category: event.File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: event.CreateFile,
+ Tid: 2484,
+ PID: 829,
+ CPU: 1,
+ Seq: 2,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "\\Device\\HarddiskVolume2\\Windows\\system32\\user32.dll"},
diff --git a/pkg/outputs/elasticsearch/elasticsearch_test.go b/pkg/outputs/elasticsearch/elasticsearch_test.go
index b956e8aba..d25c93dbb 100644
--- a/pkg/outputs/elasticsearch/elasticsearch_test.go
+++ b/pkg/outputs/elasticsearch/elasticsearch_test.go
@@ -21,8 +21,6 @@ package elasticsearch
import (
"bytes"
"encoding/json"
- "github.com/rabbitstack/fibratus/pkg/util/va"
- "golang.org/x/sys/windows"
"io"
"net/http"
"net/http/httptest"
@@ -30,6 +28,9 @@ import (
"testing"
"time"
+ "github.com/rabbitstack/fibratus/pkg/util/va"
+ "golang.org/x/sys/windows"
+
"github.com/olivere/elastic/v7"
"github.com/rabbitstack/fibratus/pkg/event"
"github.com/rabbitstack/fibratus/pkg/event/params"
@@ -161,16 +162,13 @@ func getBatch() *event.Batch {
ts, _ := time.Parse(time.RFC3339, "2018-05-03T15:04:05.323Z")
evt := &event.Event{
- Type: event.CreateFile,
- Tid: 2484,
- PID: 859,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Timestamp: ts,
- Category: event.File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: event.CreateFile,
+ Tid: 2484,
+ PID: 859,
+ CPU: 1,
+ Seq: 2,
+ Timestamp: ts,
+ Host: "archrabbit",
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "\\Device\\HarddiskVolume2\\Windows\\system32\\user32.dll"},
@@ -229,16 +227,13 @@ func getBatch() *event.Batch {
}
evt1 := &event.Event{
- Type: event.CreateFile,
- Tid: 2484,
- PID: 459,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Timestamp: ts,
- Category: event.File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: event.CreateFile,
+ Tid: 2484,
+ PID: 459,
+ CPU: 1,
+ Seq: 2,
+ Timestamp: ts,
+ Host: "archrabbit",
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "\\Device\\HarddiskVolume2\\Windows\\system32\\user32.dll"},
@@ -297,16 +292,13 @@ func getBatch() *event.Batch {
}
evt2 := &event.Event{
- Type: event.CreateFile,
- Tid: 2484,
- PID: 829,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Timestamp: ts,
- Category: event.File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: event.CreateFile,
+ Tid: 2484,
+ PID: 829,
+ CPU: 1,
+ Seq: 2,
+ Timestamp: ts,
+ Host: "archrabbit",
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "\\Device\\HarddiskVolume2\\Windows\\system32\\user32.dll"},
diff --git a/pkg/outputs/http/http_test.go b/pkg/outputs/http/http_test.go
index c3995b560..e46e18a30 100644
--- a/pkg/outputs/http/http_test.go
+++ b/pkg/outputs/http/http_test.go
@@ -21,9 +21,6 @@ package http
import (
"compress/gzip"
"encoding/json"
- "github.com/rabbitstack/fibratus/pkg/outputs"
- "github.com/rabbitstack/fibratus/pkg/util/va"
- "golang.org/x/sys/windows"
"io"
"log"
"net"
@@ -32,6 +29,10 @@ import (
"testing"
"time"
+ "github.com/rabbitstack/fibratus/pkg/outputs"
+ "github.com/rabbitstack/fibratus/pkg/util/va"
+ "golang.org/x/sys/windows"
+
"github.com/stretchr/testify/assert"
"github.com/rabbitstack/fibratus/pkg/event"
@@ -148,16 +149,13 @@ func TestHttpGzipPublish(t *testing.T) {
func getBatch() *event.Batch {
evt := &event.Event{
- Type: event.CreateFile,
- Tid: 2484,
- PID: 859,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Timestamp: time.Now(),
- Category: event.File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: event.CreateFile,
+ Tid: 2484,
+ PID: 859,
+ CPU: 1,
+ Seq: 2,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "\\Device\\HarddiskVolume2\\Windows\\system32\\user32.dll"},
@@ -216,16 +214,13 @@ func getBatch() *event.Batch {
}
evt1 := &event.Event{
- Type: event.CreateFile,
- Tid: 2484,
- PID: 459,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Timestamp: time.Now(),
- Category: event.File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: event.CreateFile,
+ Tid: 2484,
+ PID: 459,
+ CPU: 1,
+ Seq: 2,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "\\Device\\HarddiskVolume2\\Windows\\system32\\user32.dll"},
@@ -284,16 +279,13 @@ func getBatch() *event.Batch {
}
evt2 := &event.Event{
- Type: event.CreateFile,
- Tid: 2484,
- PID: 829,
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Timestamp: time.Now(),
- Category: event.File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: event.CreateFile,
+ Tid: 2484,
+ PID: 829,
+ CPU: 1,
+ Seq: 2,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "\\Device\\HarddiskVolume2\\Windows\\system32\\user32.dll"},
diff --git a/pkg/rules/_fixtures/field_values/correct_category_name_field.yml b/pkg/rules/_fixtures/field_values/correct_category_name_field.yml
index 377b123cb..0970eb35a 100644
--- a/pkg/rules/_fixtures/field_values/correct_category_name_field.yml
+++ b/pkg/rules/_fixtures/field_values/correct_category_name_field.yml
@@ -1,5 +1,5 @@
name: match https connections
id: 8f36f8e0-a5c2-498f-9563-eea306daa586
version: 1.0.0
-condition: evt.category = 'net' and net.dport = 443
+condition: evt.category = 'network' and net.dport = 443
min-engine-version: 2.0.0
diff --git a/pkg/rules/_fixtures/field_values/incorrect_category_name_field.yml b/pkg/rules/_fixtures/field_values/incorrect_category_name_field.yml
index 0970eb35a..a3fa11c3c 100644
--- a/pkg/rules/_fixtures/field_values/incorrect_category_name_field.yml
+++ b/pkg/rules/_fixtures/field_values/incorrect_category_name_field.yml
@@ -1,5 +1,5 @@
name: match https connections
id: 8f36f8e0-a5c2-498f-9563-eea306daa586
version: 1.0.0
-condition: evt.category = 'network' and net.dport = 443
+condition: evt.category = 'pipe' and net.dport = 443
min-engine-version: 2.0.0
diff --git a/pkg/rules/_fixtures/merged_filters/filter3.yml b/pkg/rules/_fixtures/merged_filters/filter3.yml
index 66ac3f5e1..66fe167e8 100644
--- a/pkg/rules/_fixtures/merged_filters/filter3.yml
+++ b/pkg/rules/_fixtures/merged_filters/filter3.yml
@@ -1,5 +1,5 @@
name: match http connections
id: 6f36f8e0-a5c2-498f-9563-eea306daa586
version: 1.0.0
-condition: evt.category = 'net' and net.dport = 80
+condition: evt.category = 'network' and net.dport = 80
min-engine-version: 2.0.0
diff --git a/pkg/rules/compiler.go b/pkg/rules/compiler.go
index 65e76d7ed..a45a87bc4 100644
--- a/pkg/rules/compiler.go
+++ b/pkg/rules/compiler.go
@@ -125,7 +125,7 @@ func (c *compiler) compile() (map[*config.FilterConfig]filter.Filter, *config.Ru
for _, v := range values {
switch field {
case fields.EvtName, fields.KevtName:
- if !event.IsKnown(v) {
+ if !event.IsTypeKnown(v) {
return nil, nil, ErrUnknownEventName(f.Name, v)
}
case fields.EvtCategory, fields.KevtCategory:
@@ -266,7 +266,11 @@ func (c *compiler) containsEventTypes(root ql.Node, types ...event.Type) bool {
evts := make([]event.Type, 0, len(vals))
for _, v := range vals {
- evts = append(evts, event.NameToType(v))
+ typ, ok := event.ParseType(v)
+ if !ok {
+ continue
+ }
+ evts = append(evts, typ)
}
for _, typ := range types {
@@ -337,42 +341,46 @@ func (c *compiler) buildCompileResult(filters map[*config.FilterConfig]filter.Fi
for name, values := range f.GetStringFields() {
for _, v := range values {
if name == fields.EvtName || name == fields.EvtCategory {
- types := event.NameToTypes(v)
- for _, typ := range types {
- switch typ.Category() {
- case event.Process:
- rs.HasProcEvents = true
- case event.Thread:
- rs.HasThreadEvents = true
- case event.Module:
- rs.HasModuleEvents = true
- case event.File:
- rs.HasFileEvents = true
- case event.Net:
- rs.HasNetworkEvents = true
- case event.Registry:
- rs.HasRegistryEvents = true
- case event.Mem:
- rs.HasMemEvents = true
- }
- if typ.Subcategory() == event.DNS {
- rs.HasDNSEvents = true
- }
- if typ == event.MapViewFile || typ == event.UnmapViewFile {
- rs.HasVAMapEvents = true
- }
- if typ == event.OpenProcess || typ == event.OpenThread || typ == event.SetThreadContext ||
- typ == event.CreateSymbolicLinkObject {
- rs.HasAuditAPIEvents = true
- }
-
- if m[typ] {
- continue
- }
-
- events = append(events, typ)
- m[typ] = true
+ typ, ok := event.ParseType(v)
+ if !ok {
+ continue
+ }
+
+ info := event.GetTypeInfo(typ)
+
+ switch info.Category {
+ case event.Process:
+ rs.HasProcEvents = true
+ case event.Thread:
+ rs.HasThreadEvents = true
+ case event.Module:
+ rs.HasModuleEvents = true
+ case event.File:
+ rs.HasFileEvents = true
+ case event.Network:
+ rs.HasNetworkEvents = true
+ case event.Registry:
+ rs.HasRegistryEvents = true
+ case event.Memory:
+ rs.HasMemEvents = true
+ }
+ if info.Subcategory == event.DNS {
+ rs.HasDNSEvents = true
+ }
+ if typ == event.MapViewOfSection || typ == event.UnmapViewOfSection {
+ rs.HasVAMapEvents = true
}
+ if typ == event.OpenProcess || typ == event.OpenThread || typ == event.SetThreadContext ||
+ typ == event.CreateSymbolicLinkObject {
+ rs.HasAuditAPIEvents = true
+ }
+
+ if m[typ] {
+ continue
+ }
+
+ events = append(events, typ)
+ m[typ] = true
}
}
}
diff --git a/pkg/rules/compiler_test.go b/pkg/rules/compiler_test.go
index 404bf0c64..4bb2ab9bc 100644
--- a/pkg/rules/compiler_test.go
+++ b/pkg/rules/compiler_test.go
@@ -44,8 +44,7 @@ func TestCompile(t *testing.T) {
assert.Contains(t, rs.UsedEvents, event.CreateProcess)
assert.Contains(t, rs.UsedEvents, event.LoadModule)
assert.Contains(t, rs.UsedEvents, event.QueryDNS)
- assert.Contains(t, rs.UsedEvents, event.ConnectTCPv4)
- assert.Contains(t, rs.UsedEvents, event.ConnectTCPv6)
+ assert.Contains(t, rs.UsedEvents, event.Connect)
}
func TestCompileMinEngineVersion(t *testing.T) {
@@ -82,7 +81,7 @@ func TestCompileEventCategoryFieldNames(t *testing.T) {
{"_fixtures/field_values/incorrect_event_name_field.yml", ErrUnknownEventName("match https connections", "RecvTcp4")},
{"_fixtures/field_values/incorrect_event_name_in_operator.yml", ErrUnknownEventName("match https connections", "CreateProc")},
{"_fixtures/field_values/correct_category_name_field.yml", nil},
- {"_fixtures/field_values/incorrect_category_name_field.yml", ErrUnknownCategoryName("match https connections", "network")},
+ {"_fixtures/field_values/incorrect_category_name_field.yml", ErrUnknownCategoryName("match https connections", "pipe")},
}
for _, tt := range tests {
diff --git a/pkg/rules/engine.go b/pkg/rules/engine.go
index cd0f4974a..618880af8 100644
--- a/pkg/rules/engine.go
+++ b/pkg/rules/engine.go
@@ -81,13 +81,13 @@ type compiledFilter struct {
// filterset contains compiled filters indexed by event type and category.
type filterset struct {
types map[event.Type][]*compiledFilter
- categories map[uint8][]*compiledFilter
+ categories map[event.Category][]*compiledFilter
}
func newFilterset() *filterset {
fs := &filterset{
types: make(map[event.Type][]*compiledFilter),
- categories: make(map[uint8][]*compiledFilter),
+ categories: make(map[event.Category][]*compiledFilter),
}
return fs
}
@@ -100,7 +100,7 @@ func (f *filterset) collect(e *event.Event) []*compiledFilter {
if len(f.categories) == 0 {
return f.types[e.Type]
}
- return append(f.types[e.Type], f.categories[e.Category.Index()]...)
+ return append(f.types[e.Type], f.categories[e.Category()]...)
}
func newCompiledFilter(f filter.Filter, c *config.FilterConfig, ss *sequenceState) *compiledFilter {
@@ -196,12 +196,17 @@ func (e *Engine) Compile() (*config.RulesCompileResult, error) {
for _, v := range values {
switch name {
case fields.EvtName:
- for _, typ := range event.NameToTypes(v) {
- e.filters.types[typ] = append(e.filters.types[typ], fltr)
+ typ, ok := event.ParseType(v)
+ if !ok {
+ continue
}
+ e.filters.types[typ] = append(e.filters.types[typ], fltr)
case fields.EvtCategory:
- category := event.Category(v)
- e.filters.categories[category.Index()] = append(e.filters.categories[category.Index()], fltr)
+ category, ok := event.ParseCategory(v)
+ if !ok {
+ continue
+ }
+ e.filters.categories[category] = append(e.filters.categories[category], fltr)
}
}
}
diff --git a/pkg/rules/engine_test.go b/pkg/rules/engine_test.go
index f3d649052..96974545c 100644
--- a/pkg/rules/engine_test.go
+++ b/pkg/rules/engine_test.go
@@ -116,11 +116,9 @@ func wrapProcessEvent(e *event.Event, fn func(*event.Event) (bool, error)) bool
func fireRules(t *testing.T, c *config.Config) bool {
e := NewEngine(new(ps.SnapshotterMock), c)
evt := &event.Event{
- Type: event.RecvTCPv4,
- Name: "Recv",
- Tid: 2484,
- PID: 859,
- Category: event.Net,
+ Type: event.Recv,
+ Tid: 2484,
+ PID: 859,
Params: event.Params{
params.NetDport: {Name: params.NetDport, Type: params.Uint16, Value: uint16(443)},
params.NetSport: {Name: params.NetSport, Type: params.Uint16, Value: uint16(43123)},
@@ -141,7 +139,7 @@ func TestCompileIndexableFilters(t *testing.T) {
compileRules(t, e)
- assert.Len(t, e.filters.types, 5)
+ assert.Len(t, e.filters.types, 2)
assert.Len(t, e.filters.categories, 1)
var tests = []struct {
@@ -149,10 +147,7 @@ func TestCompileIndexableFilters(t *testing.T) {
wants int
}{
{&event.Event{Type: event.CreateProcess}, 2},
- {&event.Event{Type: event.RecvUDPv6}, 3},
- {&event.Event{Type: event.RecvTCPv4}, 3},
- {&event.Event{Type: event.RecvTCPv4, Category: event.Net}, 4},
- {&event.Event{Category: event.Net}, 1},
+ {&event.Event{Type: event.Recv}, 4},
}
for _, tt := range tests {
@@ -189,8 +184,6 @@ func TestRunSequenceRule(t *testing.T) {
Seq: 1,
Type: event.CreateProcess,
Timestamp: time.Now(),
- Category: event.Process,
- Name: "CreateProcess",
Tid: 2484,
PID: 2243,
PS: &types.PS{
@@ -208,10 +201,8 @@ func TestRunSequenceRule(t *testing.T) {
Seq: 2,
Type: event.CreateFile,
Timestamp: time.Now().Add(time.Millisecond * 250),
- Name: "CreateFile",
Tid: 2484,
PID: 2243,
- Category: event.File,
PS: &types.PS{
Name: "firefox.exe",
Exe: "C:\\Program Files\\Mozilla Firefox\\firefox.exe",
@@ -226,10 +217,8 @@ func TestRunSequenceRule(t *testing.T) {
e3 := &event.Event{
Seq: 4,
- Type: event.ConnectTCPv4,
+ Type: event.Connect,
Timestamp: time.Now().Add(time.Second),
- Category: event.Net,
- Name: "Connect",
Tid: 244,
PID: 2243,
PS: &types.PS{
@@ -279,8 +268,6 @@ func TestRunSequenceRuleWithPsUUIDLink(t *testing.T) {
Seq: 1,
Type: event.CreateProcess,
Timestamp: time.Now(),
- Category: event.Process,
- Name: "CreateProcess",
Tid: 2243,
PID: uint32(os.Getpid()),
PS: &types.PS{
@@ -299,10 +286,8 @@ func TestRunSequenceRuleWithPsUUIDLink(t *testing.T) {
Seq: 2,
Type: event.CreateFile,
Timestamp: time.Now().Add(time.Second),
- Name: "CreateFile",
Tid: 2484,
PID: uint32(os.Getpid()),
- Category: event.File,
PS: &types.PS{
PID: uint32(os.Getpid()),
Name: "firefox.exe",
@@ -342,8 +327,6 @@ func TestRunSimpleAndSequenceRules(t *testing.T) {
Seq: 1,
Type: event.CreateProcess,
Timestamp: time.Now(),
- Category: event.Process,
- Name: "CreateProcess",
Tid: 2484,
PID: 2243,
PS: &types.PS{
@@ -360,10 +343,8 @@ func TestRunSimpleAndSequenceRules(t *testing.T) {
Seq: 2,
Type: event.CreateFile,
Timestamp: time.Now().Add(time.Millisecond * 544),
- Name: "CreateFile",
Tid: 2484,
PID: 2243,
- Category: event.File,
PS: &types.PS{
Name: "cmd.exe",
Exe: "C:\\Windows\\system32\\cmd.exe",
@@ -378,8 +359,6 @@ func TestRunSimpleAndSequenceRules(t *testing.T) {
Seq: 10,
Type: event.CreateProcess,
Timestamp: time.Now().Add(time.Second * 2),
- Category: event.Process,
- Name: "CreateProcess",
Tid: 2484,
PID: 2243,
PS: &types.PS{
@@ -427,11 +406,9 @@ func TestAlertAction(t *testing.T) {
compileRules(t, e)
evt := &event.Event{
- Type: event.RecvTCPv4,
- Name: "Recv",
- Tid: 2484,
- PID: 859,
- Category: event.Net,
+ Type: event.Recv,
+ Tid: 2484,
+ PID: 859,
PS: &types.PS{
Name: "cmd.exe",
},
@@ -489,10 +466,8 @@ func TestKillAction(t *testing.T) {
evt := &event.Event{
Type: event.CreateProcess,
Timestamp: time.Now(),
- Name: "CreateProcess",
Tid: 2484,
PID: pi.ProcessId,
- Category: event.Process,
PS: &types.PS{
Name: "calc.exe",
Exe: "C:\\Windows\\system32\\calc.exe",
@@ -520,11 +495,9 @@ func BenchmarkRunRules(b *testing.B) {
evts := []*event.Event{
{
- Type: event.ConnectTCPv4,
- Name: "Recv",
- Tid: 2484,
- PID: 859,
- Category: event.Net,
+ Type: event.Connect,
+ Tid: 2484,
+ PID: 859,
PS: &types.PS{
Name: "cmd.exe",
},
@@ -537,11 +510,9 @@ func BenchmarkRunRules(b *testing.B) {
Metadata: make(map[event.MetadataKey]any),
},
{
- Type: event.CreateProcess,
- Name: "CreateProcess",
- Category: event.Process,
- Tid: 2484,
- PID: 859,
+ Type: event.CreateProcess,
+ Tid: 2484,
+ PID: 859,
PS: &types.PS{
Name: "powershell.exe",
},
@@ -556,11 +527,9 @@ func BenchmarkRunRules(b *testing.B) {
Metadata: make(map[event.MetadataKey]any),
},
{
- Type: event.CreateFile,
- Name: "CreateFile",
- Category: event.File,
- Tid: 2484,
- PID: 859,
+ Type: event.CreateFile,
+ Tid: 2484,
+ PID: 859,
PS: &types.PS{
Name: "powershell.exe",
},
diff --git a/pkg/rules/sequence_test.go b/pkg/rules/sequence_test.go
index eb6397f55..dcf475307 100644
--- a/pkg/rules/sequence_test.go
+++ b/pkg/rules/sequence_test.go
@@ -66,7 +66,6 @@ func TestSequenceState(t *testing.T) {
e1 := &event.Event{
Type: event.CreateProcess,
- Name: "CreateProcess",
Tid: 2484,
PID: 859,
Timestamp: time.Now(),
@@ -82,7 +81,6 @@ func TestSequenceState(t *testing.T) {
e2 := &event.Event{
Type: event.CreateFile,
- Name: "CreateFile",
Tid: 2484,
PID: 4143,
Timestamp: time.Now().Add(time.Second * 5),
@@ -108,7 +106,6 @@ func TestSequenceState(t *testing.T) {
e3 := &event.Event{
Type: event.CreateProcess,
- Name: "CreateProcess",
Timestamp: time.Now().Add(time.Second * 10),
Tid: 2484,
PID: 4143,
@@ -171,7 +168,6 @@ func TestSequenceState(t *testing.T) {
// expire entire sequence
e4 := &event.Event{
Type: event.TerminateProcess,
- Name: "TerminateProcess",
Tid: 2484,
PID: 859,
PS: &pstypes.PS{
@@ -212,7 +208,6 @@ func TestSimpleSequence(t *testing.T) {
}{
{[]*event.Event{{
Type: event.CreateProcess,
- Name: "CreateProcess",
Timestamp: time.Now(),
Tid: 2484,
PID: 859,
@@ -226,11 +221,9 @@ func TestSimpleSequence(t *testing.T) {
Metadata: map[event.MetadataKey]any{"foo": "bar", "fooz": "barzz"},
}, {
Type: event.CreateFile,
- Name: "CreateFile",
Timestamp: time.Now().Add(time.Second),
Tid: 2484,
PID: 859,
- Category: event.File,
PS: &pstypes.PS{
Name: "cmd.exe",
},
@@ -240,7 +233,6 @@ func TestSimpleSequence(t *testing.T) {
Metadata: map[event.MetadataKey]any{"foo": "bar", "fooz": "barzz"}}}, []bool{false, true}},
{[]*event.Event{{
Type: event.CreateProcess,
- Name: "CreateProcess",
Timestamp: time.Now(),
Tid: 2484,
PID: 859,
@@ -254,11 +246,9 @@ func TestSimpleSequence(t *testing.T) {
Metadata: map[event.MetadataKey]any{"foo": "bar", "fooz": "barzz"},
}, {
Type: event.CreateFile,
- Name: "CreateFile",
Timestamp: time.Now().Add(time.Second),
Tid: 2484,
PID: 859,
- Category: event.File,
PS: &pstypes.PS{
Name: "cmd.exe",
},
@@ -297,7 +287,6 @@ func TestSimpleSequenceMultiplePartials(t *testing.T) {
e1 := &event.Event{
Type: event.CreateProcess,
Timestamp: time.Now().Add(time.Duration(i) * time.Millisecond),
- Name: "CreateProcess",
Tid: 2484,
PID: pid % 2,
PS: &pstypes.PS{
@@ -312,10 +301,8 @@ func TestSimpleSequenceMultiplePartials(t *testing.T) {
e2 := &event.Event{
Type: event.CreateFile,
Timestamp: time.Now().Add(time.Duration(i) * time.Millisecond * 2),
- Name: "CreateFile",
Tid: 2484,
PID: pid * 2,
- Category: event.File,
PS: &pstypes.PS{
Name: "cmd.exe",
Exe: "C:\\Windows\\system32\\cmd.exe",
@@ -337,7 +324,6 @@ func TestSimpleSequenceMultiplePartials(t *testing.T) {
Seq: 20,
Type: event.CreateProcess,
Timestamp: time.Now().Add(time.Second),
- Name: "CreateProcess",
Tid: 2484,
PID: 859,
PS: &pstypes.PS{
@@ -357,10 +343,8 @@ func TestSimpleSequenceMultiplePartials(t *testing.T) {
Type: event.CreateFile,
Seq: 22,
Timestamp: time.Now().Add(time.Second * time.Duration(2)),
- Name: "CreateFile",
Tid: 2484,
PID: 859,
- Category: event.File,
PS: &pstypes.PS{
Name: "cmd.exe",
Exe: "C:\\Windows\\system32\\cmd.exe",
@@ -404,7 +388,6 @@ func TestUnconstrainedSequenceMatches(t *testing.T) {
Seq: 20,
Type: event.CreateProcess,
Timestamp: time.Now().Add(time.Second),
- Name: "CreateProcess",
Tid: 2484,
PID: 859,
PS: &pstypes.PS{
@@ -424,7 +407,6 @@ func TestUnconstrainedSequenceMatches(t *testing.T) {
Seq: 21,
Type: event.CreateProcess,
Timestamp: time.Now().Add(time.Second * 2),
- Name: "CreateProcess",
Tid: 2484,
PID: 1859,
PS: &pstypes.PS{
@@ -444,10 +426,8 @@ func TestUnconstrainedSequenceMatches(t *testing.T) {
Type: event.CreateFile,
Seq: 25,
Timestamp: time.Now().Add(time.Second * 3),
- Name: "CreateFile",
Tid: 2484,
PID: 3859,
- Category: event.File,
PS: &pstypes.PS{
Name: "cmd.exe",
Exe: "C:\\Windows\\system32\\cmd.exe",
@@ -490,7 +470,6 @@ func TestSimpleSequenceDeadline(t *testing.T) {
e1 := &event.Event{
Type: event.CreateProcess,
Timestamp: time.Now(),
- Name: "CreateProcess",
Tid: 2484,
PID: 859,
PS: &pstypes.PS{
@@ -508,10 +487,8 @@ func TestSimpleSequenceDeadline(t *testing.T) {
e2 := &event.Event{
Type: event.CreateFile,
Timestamp: time.Now().Add(time.Millisecond * 200),
- Name: "CreateFile",
Tid: 2484,
PID: 859,
- Category: event.File,
PS: &pstypes.PS{
Name: "cmd.exe",
Exe: "C:\\Windows\\system32\\svchost.exe",
@@ -562,7 +539,6 @@ func TestSequenceMultiLinks(t *testing.T) {
e1 := &event.Event{
Type: event.CreateProcess,
Timestamp: time.Now(),
- Name: "CreateProcess",
Tid: 2484,
PID: 859,
PS: &pstypes.PS{
@@ -580,10 +556,8 @@ func TestSequenceMultiLinks(t *testing.T) {
e2 := &event.Event{
Type: event.CreateFile,
Timestamp: time.Now().Add(time.Second),
- Name: "CreateFile",
Tid: 2484,
PID: 859,
- Category: event.File,
PS: &pstypes.PS{
Name: "cmd.exe",
Exe: "C:\\Windows\\system32\\svchost.exe",
@@ -616,8 +590,6 @@ func TestComplexSequence(t *testing.T) {
Seq: 1,
Type: event.CreateProcess,
Timestamp: time.Now(),
- Category: event.Process,
- Name: "CreateProcess",
Tid: 2484,
PID: 2243,
PS: &pstypes.PS{
@@ -637,10 +609,8 @@ func TestComplexSequence(t *testing.T) {
Seq: 2,
Type: event.CreateFile,
Timestamp: time.Now().Add(time.Millisecond * 250),
- Name: "CreateFile",
Tid: 2484,
PID: 2243,
- Category: event.File,
PS: &pstypes.PS{
Name: "firefox.exe",
Exe: "C:\\Program Files\\Mozilla Firefox\\firefox.exe",
@@ -660,10 +630,8 @@ func TestComplexSequence(t *testing.T) {
e3 := &event.Event{
Seq: 4,
- Type: event.ConnectTCPv4,
+ Type: event.Connect,
Timestamp: time.Now().Add(time.Second),
- Category: event.Net,
- Name: "Connect",
Tid: 244,
PID: 2243,
PS: &pstypes.PS{
@@ -710,10 +678,8 @@ func TestSequenceOOO(t *testing.T) {
e1 := &event.Event{
Type: event.CreateFile,
Timestamp: time.Now(),
- Name: "CreateFile",
Tid: 2484,
PID: 859,
- Category: event.File,
PS: &pstypes.PS{
Name: "cmd.exe",
Exe: "C:\\Windows\\system32\\rundll32.exe",
@@ -732,7 +698,6 @@ func TestSequenceOOO(t *testing.T) {
e2 := &event.Event{
Type: event.OpenProcess,
Timestamp: time.Now(),
- Name: "OpenProcess",
Tid: 2484,
PID: 859,
PS: &pstypes.PS{
@@ -771,7 +736,6 @@ func TestSequenceGC(t *testing.T) {
e := &event.Event{
Type: event.OpenProcess,
Timestamp: time.Now(),
- Name: "OpenProcess",
Tid: 2484,
PID: 859,
PS: &pstypes.PS{
@@ -816,7 +780,6 @@ func TestSequenceExpire(t *testing.T) {
{
Type: event.OpenProcess,
Timestamp: time.Now(),
- Name: "OpenProcess",
Tid: 2484,
PID: 4143,
PS: &pstypes.PS{
@@ -832,7 +795,6 @@ func TestSequenceExpire(t *testing.T) {
},
{
Type: event.TerminateProcess,
- Name: "TerminateProcess",
Tid: 2484,
PID: 859,
PS: &pstypes.PS{
@@ -859,8 +821,6 @@ func TestSequenceExpire(t *testing.T) {
Seq: 1,
Type: event.CreateProcess,
Timestamp: time.Now(),
- Category: event.Process,
- Name: "CreateProcess",
Tid: 2484,
PID: 2243,
PS: &pstypes.PS{
@@ -877,8 +837,6 @@ func TestSequenceExpire(t *testing.T) {
Seq: 2,
Type: event.CreateProcess,
Timestamp: time.Now().Add(time.Second),
- Category: event.Process,
- Name: "CreateProcess",
Tid: 2484,
PID: 12243,
PS: &pstypes.PS{
@@ -897,7 +855,6 @@ func TestSequenceExpire(t *testing.T) {
},
{
Type: event.TerminateProcess,
- Name: "TerminateProcess",
Tid: 2484,
PID: 859,
PS: &pstypes.PS{
@@ -956,7 +913,6 @@ func TestSequenceBoundFields(t *testing.T) {
e1 := &event.Event{
Type: event.CreateProcess,
Timestamp: time.Now(),
- Name: "CreateProcess",
Tid: 2484,
PID: 859,
PS: &pstypes.PS{
@@ -973,7 +929,6 @@ func TestSequenceBoundFields(t *testing.T) {
e2 := &event.Event{
Type: event.CreateProcess,
Timestamp: time.Now().Add(time.Millisecond * 20),
- Name: "CreateProcess",
Tid: 2484,
PID: 859,
PS: &pstypes.PS{
@@ -990,10 +945,8 @@ func TestSequenceBoundFields(t *testing.T) {
e3 := &event.Event{
Type: event.CreateFile,
Timestamp: time.Now().Add(time.Second),
- Name: "CreateFile",
Tid: 2484,
PID: 859,
- Category: event.File,
PS: &pstypes.PS{
Name: "cmd.exe",
Exe: "C:\\Windows\\system32\\svchost.exe",
@@ -1006,12 +959,10 @@ func TestSequenceBoundFields(t *testing.T) {
}
e4 := &event.Event{
- Type: event.ConnectTCPv4,
+ Type: event.Connect,
Timestamp: time.Now().Add(time.Second * 3),
- Name: "Connect",
Tid: 2484,
PID: 859,
- Category: event.File,
PS: &pstypes.PS{
Name: "cmd.exe",
Exe: "C:\\Windows\\system32\\svchost.exe",
@@ -1050,8 +1001,6 @@ func TestSequenceBoundFieldsWithFunctions(t *testing.T) {
e1 := &event.Event{
Type: event.CreateFile,
- Name: "CreateFile",
- Category: event.File,
Timestamp: time.Now(),
Tid: 2484,
PID: 859,
@@ -1067,8 +1016,6 @@ func TestSequenceBoundFieldsWithFunctions(t *testing.T) {
e2 := &event.Event{
Type: event.RegSetValue,
- Name: "RegSetValue",
- Category: event.Registry,
Timestamp: time.Now().Add(time.Millisecond * 5),
Tid: 2484,
PID: 859,
@@ -1112,7 +1059,6 @@ func TestIsExpressionEvaluable(t *testing.T) {
e1 := &event.Event{
Type: event.CreateProcess,
- Name: "CreateProcess",
Tid: 2484,
PID: 859,
PS: &pstypes.PS{
@@ -1127,7 +1073,6 @@ func TestIsExpressionEvaluable(t *testing.T) {
e2 := &event.Event{
Type: event.RenameFile,
- Name: "RenameFile",
Tid: 2484,
PID: 859,
PS: &pstypes.PS{
diff --git a/pkg/symbolize/symbolizer_test.go b/pkg/symbolize/symbolizer_test.go
index 1d27b1886..506905880 100644
--- a/pkg/symbolize/symbolizer_test.go
+++ b/pkg/symbolize/symbolizer_test.go
@@ -143,16 +143,13 @@ func TestProcessCallstackPeExports(t *testing.T) {
}
e := &event.Event{
- Type: event.CreateFile,
- Tid: 2484,
- PID: uint32(os.Getpid()),
- CPU: 1,
- Seq: 2,
- Name: "CreateFile",
- Timestamp: time.Now(),
- Category: event.File,
- Host: "archrabbit",
- Description: "Creates or opens a new file, directory, I/O device, pipe, console",
+ Type: event.CreateFile,
+ Tid: 2484,
+ PID: uint32(os.Getpid()),
+ CPU: 1,
+ Seq: 2,
+ Timestamp: time.Now(),
+ Host: "archrabbit",
Params: event.Params{
params.FileObject: {Name: params.FileObject, Type: params.Uint64, Value: uint64(12456738026482168384)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: "C:\\Windows\\system32\\mimi.dll"},
@@ -205,9 +202,7 @@ func TestProcessCallstackPeExports(t *testing.T) {
PID: uint32(os.Getpid()),
CPU: 1,
Seq: 2,
- Name: "UnloadModule",
Timestamp: time.Now(),
- Category: event.Module,
Params: event.Params{
params.ModuleBase: {Name: params.ModuleBase, Type: params.Address, Value: uint64(0x7ffb5d8e11c4)},
params.FilePath: {Name: params.FilePath, Type: params.UnicodeString, Value: `C:\Windows\System32\user32.dll`},
@@ -266,9 +261,7 @@ func TestProcessCallstack(t *testing.T) {
PID: 2232,
CPU: 1,
Seq: 2,
- Name: "CreatedProcess",
Timestamp: time.Now(),
- Category: event.Process,
Host: "archrabbit",
Params: event.Params{
params.ProcessParentID: {Name: params.ProcessParentID, Type: params.PID, Value: (uint32(os.Getpid()))},
@@ -289,9 +282,7 @@ func TestProcessCallstack(t *testing.T) {
PID: 12345,
CPU: 1,
Seq: 3,
- Name: "TerminateProcess",
Timestamp: time.Now(),
- Category: event.Process,
Host: "archrabbit",
Params: event.Params{
params.ProcessID: {Name: params.ProcessID, Type: params.PID, Value: uint32(os.Getpid())},
@@ -359,9 +350,7 @@ func TestKernelCallstackSymbolizationFromDriverStore(t *testing.T) {
PID: 2232,
CPU: 1,
Seq: 2,
- Name: "CreatedProcess",
Timestamp: time.Now(),
- Category: event.Process,
Host: "archrabbit",
Params: event.Params{
params.ProcessParentID: {Name: params.ProcessParentID, Type: params.PID, Value: uint32(os.Getpid())},
@@ -465,9 +454,7 @@ func TestSymbolizeEventParamAddress(t *testing.T) {
PID: uint32(os.Getpid()),
CPU: 1,
Seq: 2,
- Name: "CreateThread",
Timestamp: time.Now(),
- Category: event.Thread,
Host: "archrabbit",
Params: event.Params{
params.Callstack: {Name: params.Callstack, Type: params.Slice, Value: []va.Address{0x7ffb5c1d0396, 0x7ffb5d8e61f4, 0x7ffb3138592e, 0x7ffb313853b2, 0x2638e59e0a5}},
@@ -514,9 +501,7 @@ func TestProcessCallstackProcsTTL(t *testing.T) {
PID: 1232,
CPU: 1,
Seq: 2,
- Name: "CreatedProcess",
Timestamp: time.Now().Add(time.Millisecond * time.Duration(n)),
- Category: event.Process,
Host: "archrabbit",
Params: event.Params{
params.ProcessParentID: {Name: params.ProcessParentID, Type: params.PID, Value: (uint32(os.Getpid()))},
diff --git a/pkg/sys/etw/types.go b/pkg/sys/etw/types.go
index cea293271..2d9fbaf53 100644
--- a/pkg/sys/etw/types.go
+++ b/pkg/sys/etw/types.go
@@ -64,6 +64,9 @@ const ImageKeyword = 0x40
// SetValueKeyword enables registry key value set events for Microsoft Windows Kernel Registry provider
const SetValueKeyword = 0x100
+// CaptureRegistryValue is the undocumented ETW feature to enable captured data in RegSetValue events
+var CaptureRegistryValue = 0x2
+
const (
// EventHeaderExtTypeStackTrace64 indicates that the extended data contains the call stack if the event is captured on a 64-bit host
EventHeaderExtTypeStackTrace64 uint16 = 0x0006
@@ -559,6 +562,11 @@ type ClassicEventID struct {
_ [7]uint8 // reserved
}
+// IsEmpty indicates if event id has been initialized.
+func (e ClassicEventID) IsEmpty() bool {
+ return (e.GUID.Data1 == 0 && e.GUID.Data2 == 0 && e.GUID.Data3 == 0 && len(e.GUID.Data4[:]) == 0) || e.Type == 0
+}
+
// EventFilterDescriptor defines the filter data that
// a session passes to the provider's enable callback.
type EventFilterDescriptor struct {
@@ -674,32 +682,6 @@ func (e *EventRecord) Version() uint8 {
return e.Header.EventDescriptor.Version
}
-// HookID returns either the opcode or the event ID.
-func (e *EventRecord) HookID() uint16 {
- if e.Header.EventDescriptor.Opcode > 0 {
- return uint16(e.Header.EventDescriptor.Opcode)
- }
- return e.Header.EventDescriptor.ID
-}
-
-// ID is an unsigned integer that uniquely
-// identifies the event. Handy for bitmask
-// operations.
-func (e *EventRecord) ID() uint {
- d1 := e.Header.ProviderID.Data1
- d2 := e.Header.ProviderID.Data2
-
- id := uint(byte(d1>>24))<<56 |
- uint(byte(d1>>16))<<48 |
- uint(byte(d1>>8))<<40 |
- uint(byte(d1))<<32 |
- uint(byte(d2>>8))<<24 |
- uint(byte(d2))<<16 |
- uint(e.HookID())
-
- return id
-}
-
// Clone makes a copy of this event record and returns the
// copy itself and the event buffer. The buffer must outlive
// the event record instance. Both are drawn from pools.
diff --git a/pkg/util/bitmap/bitmap.go b/pkg/util/bitmap/bitmap.go
new file mode 100644
index 000000000..3ead349a2
--- /dev/null
+++ b/pkg/util/bitmap/bitmap.go
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021-2026 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 bitmap
+
+// Bitmap is a set of bits backed by a uint64. The type parameter
+// T represents the type used to identify bits. It may be any unsigned
+// integer type or an alias of one. Valid bit values range from 0 to 63.
+type Bitmap[T ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64] uint64
+
+// Has reports whether the bit identified by b is set.
+func (s Bitmap[T]) Has(b T) bool {
+ return s&(1<
sequence
maxspan 40s
by ps.uuid, file.view.base
- |unmap_view_file and
+ |unmap_view_of_section and
file.view.type = 'PAGEFILE' and file.view.protection = 'READONLY' and
(file.view.size = 12288 or (file.view.size = 4096 and
not (ps.exe imatches '?:\\Windows\\explorer.exe') and
@@ -38,8 +38,8 @@ condition: >
not (ps.name iin ('procexp.exe', 'procexp64.exe') and ps.signature.trusted = true and ps.signature.subject imatches '*Microsoft Corporation*')
)
|
- |map_view_file and file.view.size = 12288 and file.view.type = 'PAGEFILE' and file.view.protection = 'READWRITE'|
+ |map_view_of_section and file.view.size = 12288 and file.view.type = 'PAGEFILE' and file.view.protection = 'READWRITE'|
severity: high
-min-engine-version: 3.0.0
+min-engine-version: 3.2.0
diff --git a/rules/defense_evasion_potential_ntdll_unhooking_via_file_mapping.yml b/rules/defense_evasion_potential_ntdll_unhooking_via_file_mapping.yml
index d57bf6df9..99652e033 100644
--- a/rules/defense_evasion_potential_ntdll_unhooking_via_file_mapping.yml
+++ b/rules/defense_evasion_potential_ntdll_unhooking_via_file_mapping.yml
@@ -1,6 +1,6 @@
name: Potential NTDLL unhooking via file mapping
id: b000955d-90df-44eb-8e32-8269d395f0ef
-version: 1.0.1
+version: 1.0.2
description: |
Identifies processes that map a fresh image view of NTDLL.dll
from disk, a behavior commonly associated with user-mode API
@@ -18,7 +18,7 @@ references:
- https://github.com/hwbp/NTDLL-Unhook
condition: >
- map_view_file and
+ map_view_of_section and
file.view.type = 'IMAGE' and evt.pid not in (0, 4) and
file.path imatches
(
@@ -36,4 +36,4 @@ condition: >
severity: high
-min-engine-version: 3.0.0
+min-engine-version: 3.2.0
diff --git a/rules/defense_evasion_potential_process_injection_via_tainted_memory_section.yml b/rules/defense_evasion_potential_process_injection_via_tainted_memory_section.yml
index 89d877e76..2484ce030 100644
--- a/rules/defense_evasion_potential_process_injection_via_tainted_memory_section.yml
+++ b/rules/defense_evasion_potential_process_injection_via_tainted_memory_section.yml
@@ -1,6 +1,6 @@
name: Potential process injection via tainted memory section
id: 8e4182f3-02e7-4e95-afc3-93d18c9a9c09
-version: 1.0.8
+version: 1.0.9
description: |
Identifies potential process injection when the adversary creates and maps a memory
section with RW protection rights followed by mapping of the same memory section in
@@ -25,6 +25,7 @@ condition: >
maxspan 1m
|map_view_of_section and
file.view.protection = 'READWRITE' and evt.pid != 4 and file.view.size >= 4096 and
+ file.view.type in ('IMAGE', 'IMAGE_NO_EXECUTE', 'PAGEFILE') and
ps.exe not imatches
(
'?:\\Program Files\\*.exe',
@@ -52,4 +53,4 @@ condition: >
action:
- name: kill
-min-engine-version: 3.0.0
+min-engine-version: 3.2.0
diff --git a/rules/defense_evasion_process_execution_from_hollowed_memory_section.yml b/rules/defense_evasion_process_execution_from_hollowed_memory_section.yml
index b9e3f2374..b764c9b33 100644
--- a/rules/defense_evasion_process_execution_from_hollowed_memory_section.yml
+++ b/rules/defense_evasion_process_execution_from_hollowed_memory_section.yml
@@ -1,6 +1,6 @@
name: Process execution from hollowed memory section
id: 2a3fbae8-5e8c-4b71-b9da-56c3958c0d53
-version: 2.1.4
+version: 2.1.5
description: |
Adversaries may inject malicious code into suspended and hollowed processes in order to
evade process-based defenses. Process hollowing is a method of executing arbitrary code
@@ -23,7 +23,7 @@ condition: >
maxspan 40s
|unmap_view_of_section and
evt.pid != 4 and ps.sid not in ('S-1-5-18', 'S-1-5-19', 'S-1-5-20') and
- file.view.size > 20000 and file.view.protection != 'READONLY' and
+ file.view.type in ('IMAGE', 'IMAGE_NO_EXECUTE') and file.view.size > 20000 and file.view.protection != 'READONLY' and
(file.name = '' or file.extension != '.dll') and
ps.parent.exe not imatches
(
@@ -47,4 +47,4 @@ output: >
Process %2.ps.exe executed from hollowed memory section
severity: high
-min-engine-version: 3.0.0
+min-engine-version: 3.2.0
diff --git a/rules/defense_evasion_process_execution_from_remote_memory_section.yml b/rules/defense_evasion_process_execution_from_remote_memory_section.yml
index 675f14035..d23446acf 100644
--- a/rules/defense_evasion_process_execution_from_remote_memory_section.yml
+++ b/rules/defense_evasion_process_execution_from_remote_memory_section.yml
@@ -1,6 +1,6 @@
name: Process execution from remote memory section
id: 6e4cc918-a30e-4167-ba26-6356d6384f30
-version: 1.0.0
+version: 1.0.1
description: |
Detects execution of a process image originating from a memory section
mapped without a backing file, a strong indicator of advanced process
@@ -21,9 +21,9 @@ references:
condition: >
sequence
maxspan 1m
- |map_view_file and
+ |map_view_of_section and
evt.pid != 4 and ps.sid not in ('S-1-5-18', 'S-1-5-19', 'S-1-5-20') and
- file.view.size > 50000 and file.path = '' and file.view.type = 'IMAGE' and
+ file.view.type in ('IMAGE', 'IMAGE_NO_EXECUTE') and file.view.size > 50000 and file.path = '' and file.view.type = 'IMAGE' and
ps.exe not imatches
(
'?:\\Windows\\System32\\dwm.exe',
@@ -51,4 +51,4 @@ output: >
Process %3.ps.exe executed from a remotely mapped memory section with no backing file
severity: high
-min-engine-version: 3.0.0
+min-engine-version: 3.2.0
diff --git a/rules/macros/macros.yml b/rules/macros/macros.yml
index f4677eb4c..5205a48fd 100644
--- a/rules/macros/macros.yml
+++ b/rules/macros/macros.yml
@@ -91,17 +91,11 @@
- macro: virtual_free
expr: evt.name = 'VirtualFree'
-- macro: map_view_file
- expr: evt.name = 'MapViewFile'
-
-- macro: unmap_view_file
- expr: evt.name = 'UnmapViewFile'
-
- macro: map_view_of_section
- expr: map_view_file and file.view.type in ('IMAGE', 'IMAGE_NO_EXECUTE', 'PAGEFILE')
+ expr: evt.name = 'MapViewOfSection'
- macro: unmap_view_of_section
- expr: unmap_view_file and file.view.type in ('IMAGE', 'IMAGE_NO_EXECUTE')
+ expr: evt.name = 'UnmapViewOfSection'
- macro: query_dns
expr: evt.name = 'QueryDns'