31
24
#include "matcher.h"
32
25
#include "matcher-bm.h"
33
26
#include "filetypes.h"
34
#include "filtering.h"
28
/* TODO: Check prefix regularity and automatically transfer some signatures
38
32
#define BM_MIN_LENGTH 3
33
/* #define BM_TEST_OFFSET 5 */
39
34
#define BM_BLOCK_SIZE 3
40
36
#define HASH(a,b,c) (211 * a + 37 * b + c)
42
int cli_bm_addpatt(struct cli_matcher *root, struct cli_bm_patt *pattern, const char *offset)
39
int cli_bm_addpatt(struct cli_matcher *root, struct cli_bm_patt *pattern)
45
43
const unsigned char *pt = pattern->pattern;
46
44
struct cli_bm_patt *prev, *next = NULL;
50
47
if(pattern->length < BM_MIN_LENGTH) {
51
cli_errmsg("cli_bm_addpatt: Signature for %s is too short\n", pattern->virname);
55
if((ret = cli_caloff(offset, NULL, root->type, pattern->offdata, &pattern->offset_min, &pattern->offset_max))) {
56
cli_errmsg("cli_bm_addpatt: Can't calculate offset for signature %s\n", pattern->virname);
59
if(pattern->offdata[0] != CLI_OFF_ANY) {
60
if(pattern->offdata[0] == CLI_OFF_ABSOLUTE)
61
root->bm_absoff_num++;
63
root->bm_reloff_num++;
66
/* bm_offmode doesn't use the prefilter for BM signatures anyway, so
67
* don't add these to the filter. */
68
if(root->filter && !root->bm_offmode) {
69
/* the bm_suffix load balancing below can shorten the sig,
70
* we want to see the entire signature! */
71
if (filter_add_static(root->filter, pattern->pattern, pattern->length, pattern->virname) == -1) {
72
cli_warnmsg("cli_bm_addpatt: cannot use filter for trie\n");
73
mpool_free(root->mempool, root->filter);
76
/* TODO: should this affect maxpatlen? */
79
#if BM_MIN_LENGTH == BM_BLOCK_SIZE
80
/* try to load balance bm_suffix (at the cost of bm_shift) */
81
for(i = 0; i < pattern->length - BM_BLOCK_SIZE + 1; i++) {
82
idx = HASH(pt[i], pt[i + 1], pt[i + 2]);
83
if(!root->bm_suffix[idx]) {
85
pattern->prefix = pattern->pattern;
86
pattern->prefix_length = i;
87
pattern->pattern = &pattern->pattern[i];
89
pt = pattern->pattern;
96
for(i = 0; i <= BM_MIN_LENGTH - BM_BLOCK_SIZE; i++) {
48
cli_errmsg("Signature for %s is too short\n", pattern->virname);
52
for(i = BM_MIN_LENGTH - BM_BLOCK_SIZE; i >= 0; i--) {
97
53
idx = HASH(pt[i], pt[i + 1], pt[i + 2]);
98
54
root->bm_shift[idx] = MIN(root->bm_shift[idx], BM_MIN_LENGTH - BM_BLOCK_SIZE - i);
57
i = BM_MIN_LENGTH - BM_BLOCK_SIZE;
58
idx = HASH(pt[i], pt[i + 1], pt[i + 2]);
101
60
prev = next = root->bm_suffix[idx];
103
if(pt[0] >= next->pattern0)
63
if(pt[0] >= next->pattern[0])
106
66
next = next->next;
109
69
if(next == root->bm_suffix[idx]) {
110
70
pattern->next = root->bm_suffix[idx];
111
if(root->bm_suffix[idx])
112
pattern->cnt = root->bm_suffix[idx]->cnt;
113
71
root->bm_suffix[idx] = pattern;
115
73
pattern->next = prev->next;
116
74
prev->next = pattern;
118
pattern->pattern0 = pattern->pattern[0];
119
root->bm_suffix[idx]->cnt++;
121
if(root->bm_offmode) {
122
root->bm_pattab = (struct cli_bm_patt **) mpool_realloc2(root->mempool, root->bm_pattab, (root->bm_patterns + 1) * sizeof(struct cli_bm_patt *));
123
if(!root->bm_pattab) {
124
cli_errmsg("cli_bm_addpatt: Can't allocate memory for root->bm_pattab\n");
127
root->bm_pattab[root->bm_patterns] = pattern;
128
if(pattern->offdata[0] != CLI_OFF_ABSOLUTE)
129
pattern->offset_min = root->bm_patterns;
136
80
int cli_bm_init(struct cli_matcher *root)
138
uint16_t i, size = HASH(255, 255, 255) + 1;
140
assert (root->mempool && "mempool must be initialized");
143
if(!(root->bm_shift = (uint8_t *) mpool_calloc(root->mempool, size, sizeof(uint8_t))))
83
unsigned int size = HASH(256, 256, 256);
86
cli_dbgmsg("in cli_bm_init()\n");
87
cli_dbgmsg("BM: Number of indexes = %d\n", size);
89
if(!(root->bm_shift = (int *) cli_malloc(size * sizeof(int))))
146
if(!(root->bm_suffix = (struct cli_bm_patt **) mpool_calloc(root->mempool, size, sizeof(struct cli_bm_patt *)))) {
147
mpool_free(root->mempool, root->bm_shift);
92
if(!(root->bm_suffix = (struct cli_bm_patt **) cli_calloc(size, sizeof(struct cli_bm_patt *)))) {
151
97
for(i = 0; i < size; i++)
152
98
root->bm_shift[i] = BM_MIN_LENGTH - BM_BLOCK_SIZE + 1;
157
int cli_bm_initoff(const struct cli_matcher *root, struct cli_bm_off *data, const struct cli_target_info *info)
161
struct cli_bm_patt *patt;
164
if(!root->bm_patterns) {
165
data->offtab = data->offset = NULL;
166
data->cnt = data->pos = 0;
170
data->cnt = data->pos = 0;
171
data->offtab = (uint32_t *) cli_malloc(root->bm_patterns * sizeof(uint32_t));
173
cli_errmsg("cli_bm_initoff: Can't allocate memory for data->offtab\n");
176
data->offset = (uint32_t *) cli_malloc(root->bm_patterns * sizeof(uint32_t));
178
cli_errmsg("cli_bm_initoff: Can't allocate memory for data->offset\n");
182
for(i = 0; i < root->bm_patterns; i++) {
183
patt = root->bm_pattab[i];
184
if(patt->offdata[0] == CLI_OFF_ABSOLUTE) {
185
data->offtab[data->cnt] = patt->offset_min + patt->prefix_length;
186
if(data->offtab[data->cnt] >= info->fsize)
189
} else if((ret = cli_caloff(NULL, info, root->type, patt->offdata, &data->offset[patt->offset_min], NULL))) {
190
cli_errmsg("cli_bm_initoff: Can't calculate relative offset in signature for %s\n", patt->virname);
194
} else if((data->offset[patt->offset_min] != CLI_OFF_NONE) && (data->offset[patt->offset_min] + patt->length <= info->fsize)) {
195
if(!data->cnt || (data->offset[patt->offset_min] + patt->prefix_length != data->offtab[data->cnt - 1])) {
196
data->offtab[data->cnt] = data->offset[patt->offset_min] + patt->prefix_length;
197
if(data->offtab[data->cnt] >= info->fsize)
204
cli_qsort(data->offtab, data->cnt, sizeof(uint32_t), NULL);
208
void cli_bm_freeoff(struct cli_bm_off *data)
216
103
void cli_bm_free(struct cli_matcher *root)
218
struct cli_bm_patt *patt, *prev;
219
uint16_t i, size = HASH(255, 255, 255) + 1;
105
struct cli_bm_patt *b1, *b2;
107
unsigned int size = HASH(256, 256, 256);
222
110
if(root->bm_shift)
223
mpool_free(root->mempool, root->bm_shift);
226
mpool_free(root->mempool, root->bm_pattab);
111
free(root->bm_shift);
228
113
if(root->bm_suffix) {
229
114
for(i = 0; i < size; i++) {
230
patt = root->bm_suffix[i];
235
mpool_free(root->mempool, prev->prefix);
237
mpool_free(root->mempool, prev->pattern);
239
mpool_free(root->mempool, prev->virname);
240
mpool_free(root->mempool, prev);
115
b1 = root->bm_suffix[i];
243
mpool_free(root->mempool, root->bm_suffix);
128
free(root->bm_suffix);
247
int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_bm_patt **patt, const struct cli_matcher *root, uint32_t offset, const struct cli_target_info *info, struct cli_bm_off *offdata)
132
int cli_bm_scanbuff(const unsigned char *buffer, unsigned int length, const char **virname, const struct cli_matcher *root, unsigned long int offset, cli_file_t ftype, int fd)
249
uint32_t i, j, off, off_min, off_max;
250
uint8_t found, pchain, shift;
251
uint16_t idx, idxchk;
134
unsigned int i, j, shift, off, found = 0;
252
137
struct cli_bm_patt *p;
253
const unsigned char *bp, *pt;
138
const unsigned char *bp;
254
139
unsigned char prefix;
257
if(!root || !root->bm_shift)
140
struct cli_target_info info;
260
146
if(length < BM_MIN_LENGTH)
263
i = BM_MIN_LENGTH - BM_BLOCK_SIZE;
267
if(offdata->pos == offdata->cnt)
269
for(; offdata->pos && offdata->offtab[offdata->pos] > offset; offdata->pos--);
270
if(offdata->offtab[offdata->pos] < offset)
272
if(offdata->pos >= offdata->cnt)
274
i += offdata->offtab[offdata->pos] - offset;
276
for(; i < length - BM_BLOCK_SIZE + 1; ) {
149
memset(&info, 0, sizeof(info));
151
for(i = BM_MIN_LENGTH - BM_BLOCK_SIZE; i < length - BM_BLOCK_SIZE + 1; ) {
277
152
idx = HASH(buffer[i], buffer[i + 1], buffer[i + 2]);
278
154
shift = root->bm_shift[idx];
281
158
prefix = buffer[i - BM_MIN_LENGTH + BM_BLOCK_SIZE];
282
159
p = root->bm_suffix[idx];
283
if(p && p->cnt == 1 && p->pattern0 != prefix) {
285
off = offset + i - BM_MIN_LENGTH + BM_BLOCK_SIZE;
286
for(; offdata->pos < offdata->cnt && off >= offdata->offtab[offdata->pos]; offdata->pos++);
287
if(offdata->pos == offdata->cnt || off >= offdata->offtab[offdata->pos])
289
i += offdata->offtab[offdata->pos] - off;
297
if(p->pattern0 != prefix) {
161
while(p && p->pattern[0] != prefix)
164
while(p && p->pattern[0] == prefix) {
304
165
off = i - BM_MIN_LENGTH + BM_BLOCK_SIZE;
305
166
bp = buffer + off;
307
if((off + p->length > length) || (p->prefix_length > off)) {
168
#ifdef BM_TEST_OFFSET
169
if(bp[BM_TEST_OFFSET] != p->pattern[BM_TEST_OFFSET]) {
313
if(p->offdata[0] == CLI_OFF_ABSOLUTE) {
314
if(p->offset_min != offset + off - p->prefix_length) {
318
} else if((offdata->offset[p->offset_min] == CLI_OFF_NONE) || (offdata->offset[p->offset_min] != offset + off - p->prefix_length)) {
324
idxchk = MIN(p->length, length - off) - 1;
326
if((bp[idxchk] != p->pattern[idxchk]) || (bp[idxchk / 2] != p->pattern[idxchk / 2])) {
332
if(p->prefix_length) {
333
off -= p->prefix_length;
334
bp -= p->prefix_length;
175
idxtest = MIN (p->length, length - off ) - 1;
177
if(bp[idxtest] != p->pattern[idxtest]) {
341
for(j = 0; j < p->length + p->prefix_length && off < length; j++, off++) {
184
for(j = 0; j < p->length && off < length; j++, off++) {
185
if(bp[j] != p->pattern[j]) {
348
if(found && (p->boundary & BM_BOUNDARY_EOL)) {
355
if(found && p->length + p->prefix_length == j) {
356
if(!offdata && (p->offset_min != CLI_OFF_ANY)) {
357
if(p->offdata[0] != CLI_OFF_ABSOLUTE) {
362
ret = cli_caloff(NULL, info, root->type, p->offdata, &off_min, &off_max);
363
if(ret != CL_SUCCESS) {
364
cli_errmsg("cli_bm_scanbuff: Can't calculate relative offset in signature for %s\n", p->virname);
368
off_min = p->offset_min;
369
off_max = p->offset_max;
371
off = offset + i - p->prefix_length - BM_MIN_LENGTH + BM_BLOCK_SIZE;
372
if(off_min == CLI_OFF_NONE || off_max < off || off_min > off) {
191
if(found && p->length == j) {
193
if(p->target || p->offset) {
194
off = offset + i - BM_MIN_LENGTH + BM_BLOCK_SIZE;
196
if((fd == -1 && !ftype) || !cli_validatesig(ftype, p->offset, off, &info, fd, p->virname)) {
378
203
*virname = p->virname;
205
if(info.exeinfo.section)
206
free(info.exeinfo.section);
389
off = offset + i - BM_MIN_LENGTH + BM_BLOCK_SIZE;
390
for(; offdata->pos < offdata->cnt && off >= offdata->offtab[offdata->pos]; offdata->pos++);
391
if(offdata->pos == offdata->cnt || off >= offdata->offtab[offdata->pos])
393
i += offdata->offtab[offdata->pos] - off;
220
if(info.exeinfo.section)
221
free(info.exeinfo.section);