Skip to content

Commit 2c7609e

Browse files
committed
chore(yara): Control RWX page scans per process
If the process is performing many VirtualAlloc calls with RWX page protection, and one call results in a rule match, then we don't need to repeatedly initiate the scan for the same process.
1 parent c5c131c commit 2c7609e

File tree

1 file changed

+21
-3
lines changed

1 file changed

+21
-3
lines changed

pkg/yara/scanner.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"github.com/rabbitstack/fibratus/pkg/kevent/kparams"
3232
"github.com/rabbitstack/fibratus/pkg/kevent/ktypes"
3333
"github.com/rabbitstack/fibratus/pkg/util/signature"
34+
"github.com/rabbitstack/fibratus/pkg/util/va"
3435
"golang.org/x/sys/windows"
3536
"golang.org/x/sys/windows/registry"
3637
"os"
@@ -69,6 +70,8 @@ type scanner struct {
6970
config config.Config
7071

7172
psnap ps.Snapshotter
73+
74+
rwxs map[uint32]va.Address // contains scanned and matched RWX process allocations
7275
}
7376

7477
// NewScanner creates a new YARA scanner.
@@ -103,7 +106,7 @@ func NewScanner(psnap ps.Snapshotter, config config.Config) (Scanner, error) {
103106
return nil
104107
}
105108
rulesInCompiler.Add(1)
106-
log.Infof("loading yara rule(s) from %s", filepath.Join(path, fi.Name()))
109+
log.Infof("loading yara rule(s) from %s", path)
107110

108111
return nil
109112
})
@@ -136,6 +139,7 @@ func NewScanner(psnap ps.Snapshotter, config config.Config) (Scanner, error) {
136139
rules: rules,
137140
config: config,
138141
psnap: psnap,
142+
rwxs: make(map[uint32]va.Address),
139143
}, nil
140144
}
141145

@@ -165,7 +169,11 @@ func parseCompilerErrors(errors []yara.CompilerMessage) error {
165169

166170
func (s scanner) CanEnqueue() bool { return false }
167171

168-
func (s scanner) ProcessEvent(evt *kevent.Kevent) (bool, error) {
172+
func (s *scanner) ProcessEvent(evt *kevent.Kevent) (bool, error) {
173+
if evt.IsTerminateProcess() {
174+
// cleanup
175+
delete(s.rwxs, evt.Kparams.MustGetPid())
176+
}
169177
return s.Scan(evt)
170178
}
171179

@@ -264,12 +272,16 @@ func (s scanner) Scan(e *kevent.Kevent) (bool, error) {
264272
}
265273
// scan process allocating RWX memory region
266274
pid := e.Kparams.MustGetPid()
267-
if e.PID != 4 && e.Kparams.TryGetUint32(kparams.MemProtect) == windows.PAGE_EXECUTE_READWRITE {
275+
addr := e.Kparams.TryGetAddress(kparams.MemBaseAddress)
276+
if e.PID != 4 && e.Kparams.TryGetUint32(kparams.MemProtect) == windows.PAGE_EXECUTE_READWRITE && !s.isRwxMatched(pid) {
268277
log.Debugf("scanning RWX allocation. pid: %d, exe: %s, addr: %s", pid, e.GetParamAsString(kparams.Exe),
269278
e.GetParamAsString(kparams.MemBaseAddress))
270279
matches, err = s.scan(pid)
271280
allocScans.Add(1)
272281
isScanned = true
282+
if len(matches) > 0 {
283+
s.rwxs[pid] = addr
284+
}
273285
}
274286
case ktypes.MapViewFile:
275287
if s.config.SkipMmaps {
@@ -443,3 +455,9 @@ func (s scanner) Close() {
443455
s.c.Destroy()
444456
}
445457
}
458+
459+
// isRwxMatched returns true if the process already triggered RWX allocation rule match.
460+
func (s *scanner) isRwxMatched(pid uint32) (ok bool) {
461+
_, ok = s.rwxs[pid]
462+
return ok
463+
}

0 commit comments

Comments
 (0)