5353 moduleCount = expvar .NewInt ("process.module.count" )
5454 mmapCount = expvar .NewInt ("process.mmap.count" )
5555 pebReadErrors = expvar .NewInt ("process.peb.read.errors" )
56+ processEnrichments = expvar .NewInt ("process.enrichments" )
5657)
5758
5859type snapshotter struct {
@@ -146,6 +147,7 @@ func (s *snapshotter) Write(e *event.Event) error {
146147 s .mu .Lock ()
147148 defer s .mu .Unlock ()
148149 processCount .Add (1 )
150+
149151 pid , err := e .Params .GetPid ()
150152 if err != nil {
151153 return err
@@ -154,8 +156,45 @@ func (s *snapshotter) Write(e *event.Event) error {
154156 if err != nil {
155157 return err
156158 }
159+
157160 proc , err := s .newProcState (pid , ppid , e )
158- s .procs [pid ] = proc
161+ if ps := s .procs [pid ]; ps == nil && (e .IsCreateProcessInternal () || e .IsProcessRundownInternal ()) {
162+ // only modify the state if there is no process derived from the NT kernel logger process events
163+ s .procs [pid ] = proc
164+ } else if ps , ok := s .procs [pid ]; ok && (e .IsCreateProcessInternal () || e .IsProcessRundownInternal ()) {
165+ // process state derived from the core kernel events exists - enrich it
166+ ps .TokenIntegrityLevel = proc .TokenIntegrityLevel
167+ ps .TokenElevationType = proc .TokenElevationType
168+ ps .IsTokenElevated = proc .IsTokenElevated
169+ if len (proc .Exe ) > len (ps .Exe ) {
170+ // prefer full executable path
171+ ps .Exe = proc .Exe
172+ }
173+ s .procs [pid ] = ps
174+ } else if ps , ok := s .procs [pid ]; ok && (e .IsCreateProcess () || e .IsProcessRundown ()) && ps .TokenIntegrityLevel != "" {
175+ // enrich the existing process state with the newly arrived NT kernel logger process events
176+ // but obtain the integrity level and executable path from the previous proc state
177+ processEnrichments .Add (1 )
178+ proc .TokenIntegrityLevel = ps .TokenIntegrityLevel
179+ proc .TokenElevationType = ps .TokenElevationType
180+ proc .IsTokenElevated = ps .IsTokenElevated
181+
182+ if len (ps .Exe ) > len (proc .Exe ) {
183+ // prefer full executable path
184+ proc .Exe = ps .Exe
185+ e .AppendParam (params .Exe , params .Path , ps .Exe )
186+ }
187+
188+ e .AppendParam (params .ProcessIntegrityLevel , params .AnsiString , ps .TokenIntegrityLevel )
189+ e .AppendParam (params .ProcessTokenElevationType , params .AnsiString , ps .TokenElevationType )
190+ e .AppendParam (params .ProcessTokenIsElevated , params .Bool , ps .IsTokenElevated )
191+
192+ s .procs [pid ] = proc
193+ } else {
194+ // in all other cases append the process state
195+ s .procs [pid ] = proc
196+ }
197+
159198 // adjust the process which is generating
160199 // the event. For `CreateProcess` events
161200 // the process context is scoped to the
@@ -165,9 +204,10 @@ func (s *snapshotter) Write(e *event.Event) error {
165204 // snapshot state
166205 if e .IsProcessRundown () {
167206 e .PS = proc
168- } else {
207+ } else if ! e . IsProcessRundownInternal () && ! e . IsCreateProcessInternal () {
169208 e .PS = s .procs [e .PID ]
170209 }
210+
171211 return err
172212}
173213
@@ -317,6 +357,23 @@ func (s *snapshotter) Close() error {
317357}
318358
319359func (s * snapshotter ) newProcState (pid , ppid uint32 , e * event.Event ) (* pstypes.PS , error ) {
360+ if e .IsCreateProcessInternal () || e .IsProcessRundownInternal () {
361+ proc := & pstypes.PS {
362+ PID : pid ,
363+ Ppid : ppid ,
364+ Exe : e .GetParamAsString (params .Exe ),
365+ TokenIntegrityLevel : e .GetParamAsString (params .ProcessIntegrityLevel ),
366+ TokenElevationType : e .GetParamAsString (params .ProcessTokenElevationType ),
367+ IsTokenElevated : e .Params .TryGetBool (params .ProcessTokenIsElevated ),
368+ Threads : make (map [uint32 ]pstypes.Thread ),
369+ Modules : make ([]pstypes.Module , 0 ),
370+ Handles : make ([]htypes.Handle , 0 ),
371+ Mmaps : make ([]pstypes.Mmap , 0 ),
372+ }
373+
374+ return proc , nil
375+ }
376+
320377 proc := pstypes .New (
321378 pid ,
322379 ppid ,
@@ -369,12 +426,38 @@ func (s *snapshotter) newProcState(pid, ppid uint32, e *event.Event) (*pstypes.P
369426 access := uint32 (windows .PROCESS_QUERY_INFORMATION | windows .PROCESS_VM_READ )
370427 process , err := windows .OpenProcess (access , false , pid )
371428 if err != nil {
372- return proc , nil
429+ process , err = windows .OpenProcess (windows .PROCESS_QUERY_INFORMATION , false , pid )
430+ if err != nil {
431+ return proc , nil
432+ }
373433 }
374434 //nolint:errcheck
375435 defer windows .CloseHandle (process )
376436
377- // read PEB
437+ // query token attributes if not enriched by internal event
438+ if s .procs [pid ] == nil {
439+ var token windows.Token
440+ err = windows .OpenProcessToken (process , windows .TOKEN_QUERY , & token )
441+ if err != nil {
442+ goto readPEB
443+ }
444+ defer token .Close ()
445+
446+ // get process token integrity level
447+ tokenMandatoryLabel , err := sys .GetProcessTokenInformation [windows.Tokenmandatorylabel ](token , windows .TokenIntegrityLevel )
448+ if err != nil {
449+ goto readPEB
450+ }
451+
452+ proc .TokenIntegrityLevel = sys .RidToString (tokenMandatoryLabel .Label .Sid )
453+ proc .IsTokenElevated = token .IsElevated ()
454+
455+ e .AppendParam (params .ProcessIntegrityLevel , params .AnsiString , proc .TokenIntegrityLevel )
456+ e .AppendParam (params .ProcessTokenIsElevated , params .Bool , proc .IsTokenElevated )
457+ }
458+
459+ readPEB:
460+ // read PEB (Process Environment Block)
378461 peb , err := ReadPEB (process )
379462 if err != nil {
380463 pebReadErrors .Add (1 )
@@ -525,27 +608,52 @@ func (s *snapshotter) Find(pid uint32) (bool, *pstypes.PS) {
525608 }
526609 proc .StartTime = time .Unix (0 , ct .Nanoseconds ())
527610
611+ // get process creation attributes
612+ var isWOW64 bool
613+ if err := windows .IsWow64Process (process , & isWOW64 ); err == nil && isWOW64 {
614+ proc .IsWOW64 = true
615+ }
616+ if isPackaged , err := sys .IsProcessPackaged (process ); err == nil && isPackaged {
617+ proc .IsPackaged = true
618+ }
619+ if prot , err := sys .QueryInformationProcess [sys.PsProtection ](process , sys .ProcessProtectionInformation ); err == nil && prot != nil {
620+ proc .IsProtected = prot .IsProtected ()
621+ }
622+
528623 // get process token attributes
529624 var token windows.Token
625+ var tokenUser * windows.Tokenuser
626+ var tokenMandatoryLabel * windows.Tokenmandatorylabel
627+
530628 err = windows .OpenProcessToken (process , windows .TOKEN_QUERY , & token )
531629 if err != nil {
532- return false , proc
630+ goto readPEB
533631 }
534632 defer token .Close ()
535- usr , err : = token .GetTokenUser ()
633+ tokenUser , err = token .GetTokenUser ()
536634 if err != nil {
537- return false , proc
635+ goto readPEB
636+ }
637+ proc .SID = tokenUser .User .Sid .String ()
638+ proc .Username , proc .Domain , _ , _ = tokenUser .User .Sid .LookupAccount ("" )
639+
640+ // get process token integrity level
641+ tokenMandatoryLabel , err = sys .GetProcessTokenInformation [windows.Tokenmandatorylabel ](token , windows .TokenIntegrityLevel )
642+ if err != nil {
643+ goto readPEB
538644 }
539- proc .SID = usr .User .Sid .String ()
540- proc .Username , proc .Domain , _ , _ = usr .User .Sid .LookupAccount ("" )
645+
646+ proc .TokenIntegrityLevel = sys .RidToString (tokenMandatoryLabel .Label .Sid )
647+ proc .IsTokenElevated = token .IsElevated ()
541648
542649 // retrieve process handles
543650 proc .Handles , err = s .hsnap .FindHandles (pid )
544651 if err != nil {
545- return false , proc
652+ goto readPEB
546653 }
547654
548- // read PEB
655+ readPEB:
656+ // read PEB (Process Environment Block)
549657 peb , err := ReadPEB (process )
550658 if err != nil {
551659 pebReadErrors .Add (1 )
@@ -556,18 +664,6 @@ func (s *snapshotter) Find(pid uint32) (bool, *pstypes.PS) {
556664 proc .SessionID = peb .GetSessionID ()
557665 proc .Cwd = peb .GetCurrentWorkingDirectory ()
558666
559- // get process creation attributes
560- var isWOW64 bool
561- if err := windows .IsWow64Process (process , & isWOW64 ); err == nil && isWOW64 {
562- proc .IsWOW64 = true
563- }
564- if isPackaged , err := sys .IsProcessPackaged (process ); err == nil && isPackaged {
565- proc .IsPackaged = true
566- }
567- if prot , err := sys .QueryInformationProcess [sys.PsProtection ](process , sys .ProcessProtectionInformation ); err == nil && prot != nil {
568- proc .IsProtected = prot .IsProtected ()
569- }
570-
571667 return false , proc
572668}
573669
0 commit comments