Skip to content

Commit 12912d7

Browse files
secDre4merhillu
authored andcommitted
feat: support TooManyMatches callback
1 parent 28e9138 commit 12912d7

File tree

2 files changed

+46
-6
lines changed

2 files changed

+46
-6
lines changed

rules_callback.go

+20
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ package yara
99
/*
1010
#include <stdlib.h>
1111
#include <yara.h>
12+
13+
// rules_table is part of a union and as such not reachable from go code.
14+
static YR_RULE* find_rule(YR_RULES* r, uint rule_idx) {
15+
return &r->rules_table[rule_idx];
16+
}
1217
*/
1318
import "C"
1419
import (
@@ -70,6 +75,12 @@ type ScanCallbackConsoleLog interface {
7075
ConsoleLog(*ScanContext, string)
7176
}
7277

78+
// ScanCallbackTooManyMatches can be used to receive information about
79+
// strings that match too many times.
80+
type ScanCallbackTooManyMatches interface {
81+
TooManyMatches(*ScanContext, *Rule, string) (bool, error)
82+
}
83+
7384
// scanCallbackContainer is used by to pass a ScanCallback (and
7485
// associated data) between ScanXxx methods and scanCallbackFunc(). It
7586
// stores the public callback interface and a list of malloc()'d C
@@ -147,6 +158,15 @@ func scanCallbackFunc(ctx *C.YR_SCAN_CONTEXT, message C.int, messageData, userDa
147158
if c, ok := cbc.ScanCallback.(ScanCallbackConsoleLog); ok {
148159
c.ConsoleLog(s, C.GoString((*C.char)(messageData)))
149160
}
161+
case C.CALLBACK_MSG_TOO_MANY_MATCHES:
162+
if c, ok := cbc.ScanCallback.(ScanCallbackTooManyMatches); ok {
163+
yrString := String{(*C.YR_STRING)(messageData), cbc.rules}
164+
rule := &Rule{
165+
cptr: C.find_rule(cbc.rules.cptr, yrString.cptr.rule_idx),
166+
owner: cbc.rules,
167+
}
168+
abort, err = c.TooManyMatches(s, rule, yrString.Identifier())
169+
}
150170
}
151171

152172
if err != nil {

rules_test.go

+26-6
Original file line numberDiff line numberDiff line change
@@ -243,12 +243,13 @@ func TestRule(t *testing.T) {
243243
}
244244

245245
type testCallback struct {
246-
t *testing.T
247-
finished bool
248-
modules map[string]struct{}
249-
matched map[string]struct{}
250-
notMatched map[string]struct{}
251-
logged []string
246+
t *testing.T
247+
finished bool
248+
modules map[string]struct{}
249+
matched map[string]struct{}
250+
notMatched map[string]struct{}
251+
logged []string
252+
tooManyMatches []string
252253
}
253254

254255
func newTestCallback(t *testing.T) *testCallback {
@@ -258,6 +259,7 @@ func newTestCallback(t *testing.T) *testCallback {
258259
make(map[string]struct{}),
259260
make(map[string]struct{}),
260261
nil,
262+
nil,
261263
}
262264
}
263265

@@ -291,6 +293,10 @@ func (c *testCallback) ModuleImported(*ScanContext, *Object) (bool, error) {
291293
func (c *testCallback) ConsoleLog(_ *ScanContext, s string) {
292294
c.logged = append(c.logged, s)
293295
}
296+
func (c *testCallback) TooManyMatches(_ *ScanContext, r *Rule, s string) (bool, error) {
297+
c.tooManyMatches = append(c.logged, fmt.Sprintf("%s:%s", r.Identifier(), s))
298+
return false, nil
299+
}
294300

295301
func TestImportDataCallback(t *testing.T) {
296302
cb := newTestCallback(t)
@@ -338,3 +344,17 @@ func TestConsoleCallback(t *testing.T) {
338344
t.Errorf("console log does not containi expected hello world string: %v", cb.logged)
339345
}
340346
}
347+
348+
func TestTooManyMatches(t *testing.T) {
349+
cb := newTestCallback(t)
350+
r := makeRules(t, `
351+
rule t { strings: $s1 = "\x00" condition: #s1 == 10000000 }
352+
`)
353+
354+
if err := r.ScanMem(make([]byte, 10000000), 0, 0, cb); err != nil {
355+
t.Error(err)
356+
}
357+
if len(cb.tooManyMatches) != 1 || cb.tooManyMatches[0] != "t:$s1" {
358+
t.Errorf("too many matches does not contain regularly matching string: %v", cb.tooManyMatches)
359+
}
360+
}

0 commit comments

Comments
 (0)