forked from hillu/go-yara
-
Notifications
You must be signed in to change notification settings - Fork 4
/
rule.go
270 lines (239 loc) · 6.36 KB
/
rule.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
// Copyright © 2015-2020 Hilko Bengen <[email protected]>
// All rights reserved.
//
// Use of this source code is governed by the license that can be
// found in the LICENSE file.
package yara
/*
#include <yara.h>
// rule_identifier is a union accessor function.
// (CGO does not represent them properly to Go code.)
static const char* rule_identifier(YR_RULE* r) {
return r->identifier;
}
// rule_namespace is a union accessor function.
// (CGO does not represent them properly to Go code.)
static const char* rule_namespace(YR_RULE* r) {
return r->ns->name;
}
// rule_tags returns pointers to the tag names associated with a rule,
// using YARA's own implementation.
static void rule_tags(YR_RULE* r, const char *tags[], int *n) {
const char *tag;
int i = 0;
yr_rule_tags_foreach(r, tag) {
if (i < *n)
tags[i] = tag;
i++;
};
*n = i;
return;
}
// rule_tags returns pointers to the meta variables associated with a
// rule, using YARA's own implementation.
static void rule_metas(YR_RULE* r, const YR_META *metas[], int *n) {
const YR_META *meta;
int i = 0;
yr_rule_metas_foreach(r, meta) {
if (i < *n)
metas[i] = meta;
i++;
};
*n = i;
return;
}
// meta_get is a union accessor function.
// (CGO does not represent them properly to Go code.)
static void meta_get(YR_META *m, const char** identifier, char** string) {
*identifier = m->identifier;
*string = (char*)m->string;
return;
}
// rule_strings returns pointers to the matching strings associated
// with a rule, using YARA's macro-based implementation.
static void rule_strings(YR_RULE* r, const YR_STRING *strings[], int *n) {
const YR_STRING *string;
int i = 0;
yr_rule_strings_foreach(r, string) {
if (i < *n)
strings[i] = string;
i++;
}
*n = i;
return;
}
// string_identifier is a union accessor function.
// (CGO does not represent them properly to Go code.)
static const char* string_identifier(YR_STRING* s) {
return s->identifier;
}
// string_matches returns pointers to the string match objects
// associated with a string, using YARA's macro-based implementation.
static void string_matches(YR_SCAN_CONTEXT *ctx, YR_STRING* s, const YR_MATCH *matches[], int *n) {
const YR_MATCH *match;
int i = 0;
yr_string_matches_foreach(ctx, s, match) {
if (i < *n)
matches[i] = match;
i++;
};
*n = i;
return;
}
*/
import "C"
import "unsafe"
// Rule represents a single rule as part of a ruleset.
type Rule struct {
cptr *C.YR_RULE
// Save underlying YR_RULES from being discarded through GC
rules *Rules
}
// Identifier returns the rule's name.
func (r *Rule) Identifier() string {
return C.GoString(C.rule_identifier(r.cptr))
}
// Namespace returns the rule's namespace.
func (r *Rule) Namespace() string {
return C.GoString(C.rule_namespace(r.cptr))
}
// Tags returns the rule's tags.
func (r *Rule) Tags() (tags []string) {
var size C.int
C.rule_tags(r.cptr, nil, &size)
if size == 0 {
return
}
tagptrs := make([]*C.char, int(size))
C.rule_tags(r.cptr, &tagptrs[0], &size)
for _, t := range tagptrs {
tags = append(tags, C.GoString(t))
}
return
}
// Meta represents a rule meta variable. Value can be of type string,
// int, boolean, or nil.
type Meta struct {
Identifier string
Value interface{}
}
// Metas returns the rule's meta variables as a list of Meta
// objects.
func (r *Rule) Metas() (metas []Meta) {
var size C.int
C.rule_metas(r.cptr, nil, &size)
if size == 0 {
return
}
mptrs := make([]*C.YR_META, int(size))
C.rule_metas(r.cptr, &mptrs[0], &size)
for _, cptr := range mptrs {
var cid, cstr *C.char
C.meta_get(cptr, &cid, &cstr)
id := C.GoString(cid)
var val interface{}
switch cptr._type {
case C.META_TYPE_STRING:
val = C.GoString(cstr)
case C.META_TYPE_INTEGER:
val = int(cptr.integer)
case C.META_TYPE_BOOLEAN:
val = (cptr.integer != 0)
}
metas = append(metas, Meta{id, val})
}
return
}
// IsPrivate returns true if the rule is marked as private.
func (r *Rule) IsPrivate() bool {
return r.cptr.flags&C.RULE_FLAGS_PRIVATE != 0
}
// IsGlobal returns true if the rule is marked as global.
func (r *Rule) IsGlobal() bool {
return r.cptr.flags&C.RULE_FLAGS_GLOBAL != 0
}
// String represents a string as part of a rule.
type String struct {
cptr *C.YR_STRING
// Save underlying YR_RULES from being discarded through GC
rules *Rules
}
// Strings returns the rule's strings.
func (r *Rule) Strings() (strs []String) {
var size C.int
C.rule_strings(r.cptr, nil, &size)
if size == 0 {
return
}
ptrs := make([]*C.YR_STRING, int(size))
C.rule_strings(r.cptr, &ptrs[0], &size)
for _, ptr := range ptrs {
strs = append(strs, String{ptr, r.rules})
}
return
}
// Identifier returns the string's name.
func (s *String) Identifier() string {
return C.GoString(C.string_identifier(s.cptr))
}
// Match represents a string match.
type Match struct {
cptr *C.YR_MATCH
// Save underlying YR_RULES from being discarded through GC
rules *Rules
}
// Matches returns all matches that have been recorded for the string.
func (s *String) Matches(sc *ScanContext) (matches []Match) {
if sc == nil || sc.cptr == nil {
return
}
var size C.int
C.string_matches(sc.cptr, s.cptr, nil, &size)
ptrs := make([]*C.YR_MATCH, int(size))
if size == 0 {
return
}
C.string_matches(sc.cptr, s.cptr, &ptrs[0], &size)
for _, ptr := range ptrs {
matches = append(matches, Match{ptr, s.rules})
}
return
}
// Base returns the base offset of the memory block in which the
// string match occurred.
func (m *Match) Base() int64 {
return int64(m.cptr.base)
}
// Offset returns the offset at which the string match occurred.
func (m *Match) Offset() int64 {
return int64(m.cptr.offset)
}
// Length returns the length of the match.
func (m *Match) Length() int64 {
return int64(m.cptr.match_length)
}
// Data returns the blob of data associated with the string match.
func (m *Match) Data() []byte {
return C.GoBytes(unsafe.Pointer(m.cptr.data), C.int(m.cptr.data_length))
}
func (r *Rule) getMatchStrings(sc *ScanContext) (matchstrings []MatchString) {
for _, s := range r.Strings() {
for _, m := range s.Matches(sc) {
matchstrings = append(matchstrings, MatchString{
Name: s.Identifier(),
Base: uint64(m.Base()),
Offset: uint64(m.Offset()),
Data: m.Data(),
})
}
}
return
}
// Enable enables a single rule.
func (r *Rule) Enable() {
C.yr_rule_enable(r.cptr)
}
// Disable disables a single rule.
func (r *Rule) Disable() {
C.yr_rule_disable(r.cptr)
}