From 4f02998536858e8a19a040e501f7e52020072769 Mon Sep 17 00:00:00 2001 From: rabbitstack Date: Fri, 25 Apr 2025 16:11:37 +0200 Subject: [PATCH] fix(ps): Spurious process executable override If the module is loaded for the process executable, and we don't have the full executable path, override with the one from the image path if it corresponds to the process executable. --- pkg/ps/snapshotter_windows.go | 6 ++- pkg/ps/snapshotter_windows_test.go | 66 ++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/pkg/ps/snapshotter_windows.go b/pkg/ps/snapshotter_windows.go index 8e823a160..dc785375f 100644 --- a/pkg/ps/snapshotter_windows.go +++ b/pkg/ps/snapshotter_windows.go @@ -25,6 +25,7 @@ import ( "golang.org/x/sys/windows" "path/filepath" "strconv" + "strings" "sync" "time" @@ -228,7 +229,10 @@ func (s *snapshotter) AddModule(e *kevent.Kevent) error { module.SignatureLevel, _ = e.Kparams.GetUint32(kparams.ImageSignatureLevel) module.SignatureType, _ = e.Kparams.GetUint32(kparams.ImageSignatureType) - if module.IsExecutable() && len(proc.Exe) < len(module.Name) { + if strings.EqualFold(proc.Name, filepath.Base(module.Name)) && len(proc.Exe) < len(module.Name) { + // if the module is loaded for the process executable, and + // we don't have the full executable path, override with + // the one from the image path proc.Exe = module.Name } diff --git a/pkg/ps/snapshotter_windows_test.go b/pkg/ps/snapshotter_windows_test.go index 8a2a74955..69f81740a 100644 --- a/pkg/ps/snapshotter_windows_test.go +++ b/pkg/ps/snapshotter_windows_test.go @@ -467,6 +467,72 @@ func TestRemoveModule(t *testing.T) { require.Len(t, ps.Modules, 0) } +func TestOverrideProcExecutable(t *testing.T) { + hsnap := new(handle.SnapshotterMock) + hsnap.On("FindHandles", mock.Anything).Return([]htypes.Handle{}, nil) + psnap := NewSnapshotter(hsnap, &config.Config{}) + defer psnap.Close() + + evt := &kevent.Kevent{ + Type: ktypes.CreateProcess, + Kparams: kevent.Kparams{ + kparams.ProcessID: {Name: kparams.ProcessID, Type: kparams.PID, Value: uint32(os.Getpid())}, + kparams.ProcessParentID: {Name: kparams.ProcessParentID, Type: kparams.PID, Value: uint32(os.Getppid())}, + kparams.ProcessName: {Name: kparams.ProcessName, Type: kparams.UnicodeString, Value: "spotify.exe"}, + kparams.Cmdline: {Name: kparams.Cmdline, Type: kparams.UnicodeString, Value: `Spotify.exe --type=crashpad-handler /prefetch:7 --max-uploads=5 --max-db-size=20 --max-db-age=5 --monitor-self-annotation=ptype=crashpad-handler "--metrics-dir=C:\Users\admin\AppData\Local\Spotify\User Data" --url=https://crashdump.spotify.com:443/ --annotation=platform=win32 --annotation=product=spotify --annotation=version=1.1.4.197 --initial-client-data=0x5a4,0x5a0,0x5a8,0x59c,0x5ac,0x6edcbf60,0x6edcbf70,0x6edcbf7c`}, + kparams.Exe: {Name: kparams.Exe, Type: kparams.UnicodeString, Value: `Spotify.exe`}, + kparams.UserSID: {Name: kparams.UserSID, Type: kparams.WbemSID, Value: []byte{224, 8, 226, 31, 15, 167, 255, 255, 0, 0, 0, 0, 15, 167, 255, 255, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0}}, + kparams.StartTime: {Name: kparams.StartTime, Type: kparams.Time, Value: time.Now()}, + kparams.SessionID: {Name: kparams.SessionID, Type: kparams.Uint32, Value: uint32(1)}, + kparams.ProcessFlags: {Name: kparams.ProcessFlags, Type: kparams.Flags, Value: uint32(0x00000010)}, + }, + } + require.NoError(t, psnap.Write(evt)) + + var tests = []struct { + expectedExe string + evt *kevent.Kevent + }{ + {`Spotify.exe`, + &kevent.Kevent{ + Type: ktypes.LoadImage, + Kparams: kevent.Kparams{ + kparams.ProcessID: {Name: kparams.ProcessID, Type: kparams.PID, Value: uint32(os.Getpid())}, + kparams.ImagePath: {Name: kparams.ImagePath, Type: kparams.UnicodeString, Value: "C:\\Windows\\assembly\\NativeImages_v4.0.30319_32\\Microsoft.Dee252aac#\\707569faabe821b47fa4f59ecd9eb6ea\\Microsoft.Developer.IdentityService.ni.exe"}, + }, + }, + }, + {`Spotify.exe`, + &kevent.Kevent{ + Type: ktypes.LoadImage, + Kparams: kevent.Kparams{ + kparams.ProcessID: {Name: kparams.ProcessID, Type: kparams.PID, Value: uint32(os.Getpid())}, + kparams.ImagePath: {Name: kparams.ImagePath, Type: kparams.UnicodeString, Value: "C:\\Windows\\System32\\notepad.exe"}, + }, + }, + }, + {`C:\Users\admin\AppData\Roaming\Spotify\Spotify.exe`, + &kevent.Kevent{ + Type: ktypes.LoadImage, + Kparams: kevent.Kparams{ + kparams.ProcessID: {Name: kparams.ProcessID, Type: kparams.PID, Value: uint32(os.Getpid())}, + kparams.ImagePath: {Name: kparams.ImagePath, Type: kparams.UnicodeString, Value: "C:\\Users\\admin\\AppData\\Roaming\\Spotify\\Spotify.exe"}, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.expectedExe, func(t *testing.T) { + evt := tt.evt + require.NoError(t, psnap.AddModule(evt)) + ok, ps := psnap.Find(uint32(os.Getpid())) + require.True(t, ok) + assert.Equal(t, tt.expectedExe, ps.Exe) + }) + } +} + func init() { reapPeriod = time.Millisecond * 45 }