Conflicts:
libclamav/matcher-bm.c
libclamav/matcher-bm.h
libclamav/matcher.c
libclamav/pe.c
libclamav/phishcheck.c
libclamav/regex_list.c
... | ... |
@@ -1,3 +1,15 @@ |
1 |
+Tue Sep 1 20:50:12 CEST 2009 (tk) |
|
2 |
+---------------------------------- |
|
3 |
+ * libclamav: use BM matcher in offset mode for PE files larger than 256kB |
|
4 |
+ (10% speedup on average; 30-40% for large executables) |
|
5 |
+ |
|
6 |
+Tue Sep 1 11:11:43 CEST 2009 (tk) |
|
7 |
+---------------------------------- |
|
8 |
+ * libclamav: in bm_offmode only load sigs with non-floating absolute and |
|
9 |
+ relative offsets into BM matcher (load other ones into AC) |
|
10 |
+ and use per-file computed offset table to pick up best shifts |
|
11 |
+ (not enabled by default, bb#1300) |
|
12 |
+ |
|
1 | 13 |
Sun Aug 30 23:56:49 CEST 2009 (acab) |
2 | 14 |
------------------------------------ |
3 | 15 |
* libclamav: unify CL_TYPE_MAIL scanning |
... | ... |
@@ -25,14 +25,11 @@ |
25 | 25 |
#define CLI_DEFAULT_AC_MAXDEPTH 3 |
26 | 26 |
#define CLI_DEFAULT_AC_TRACKLEN 8 |
27 | 27 |
|
28 |
-#define CLI_DEFAULT_MOVETOAC_LEN 8 /* all static sigs shorter than |
|
29 |
- * this value will automatically |
|
30 |
- * go to AC instead of BM |
|
31 |
- */ |
|
32 |
- |
|
33 | 28 |
#define CLI_DEFAULT_LSIG_BUFSIZE 32768 |
34 | 29 |
#define CLI_DEFAULT_DBIO_BUFSIZE CLI_DEFAULT_LSIG_BUFSIZE + 1 |
35 | 30 |
|
31 |
+#define CLI_DEFAULT_BM_OFFMODE_FSIZE 262144 |
|
32 |
+ |
|
36 | 33 |
#define CLI_DEFAULT_MAXSCANSIZE 104857600 |
37 | 34 |
#define CLI_DEFAULT_MAXFILESIZE 26214400 |
38 | 35 |
#define CLI_DEFAULT_MAXRECLEVEL 16 |
... | ... |
@@ -851,7 +851,7 @@ int cli_ac_caloff(const struct cli_matcher *root, struct cli_ac_data *data, stru |
851 | 851 |
if(info.exeinfo.section) |
852 | 852 |
free(info.exeinfo.section); |
853 | 853 |
return ret; |
854 |
- } else if(data->offset[patt->offset_min] + patt->length > info.fsize) { |
|
854 |
+ } else if((data->offset[patt->offset_min] != CLI_OFF_NONE) && (data->offset[patt->offset_min] + patt->length > info.fsize)) { |
|
855 | 855 |
data->offset[patt->offset_min] = CLI_OFF_NONE; |
856 | 856 |
} |
857 | 857 |
} |
... | ... |
@@ -104,6 +104,17 @@ int cli_bm_addpatt(struct cli_matcher *root, struct cli_bm_patt *pattern, const |
104 | 104 |
pattern->pattern0 = pattern->pattern[0]; |
105 | 105 |
root->bm_suffix[idx]->cnt++; |
106 | 106 |
|
107 |
+ if(root->bm_offmode) { |
|
108 |
+ root->bm_pattab = (struct cli_bm_patt **) mpool_realloc2(root->mempool, root->bm_pattab, (root->bm_patterns + 1) * sizeof(struct cli_bm_patt *)); |
|
109 |
+ if(!root->bm_pattab) { |
|
110 |
+ cli_errmsg("cli_bm_addpatt: Can't allocate memory for root->bm_pattab\n"); |
|
111 |
+ return CL_EMEM; |
|
112 |
+ } |
|
113 |
+ root->bm_pattab[root->bm_patterns] = pattern; |
|
114 |
+ if(pattern->offdata[0] != CLI_OFF_ABSOLUTE) |
|
115 |
+ pattern->offset_min = root->bm_patterns; |
|
116 |
+ } |
|
117 |
+ |
|
107 | 118 |
root->bm_patterns++; |
108 | 119 |
return CL_SUCCESS; |
109 | 120 |
} |
... | ... |
@@ -114,6 +125,7 @@ int cli_bm_init(struct cli_matcher *root) |
114 | 114 |
#ifdef USE_MPOOL |
115 | 115 |
assert (root->mempool && "mempool must be initialized"); |
116 | 116 |
#endif |
117 |
+ |
|
117 | 118 |
if(!(root->bm_shift = (uint8_t *) mpool_calloc(root->mempool, size, sizeof(uint8_t)))) |
118 | 119 |
return CL_EMEM; |
119 | 120 |
|
... | ... |
@@ -128,6 +140,73 @@ int cli_bm_init(struct cli_matcher *root) |
128 | 128 |
return CL_SUCCESS; |
129 | 129 |
} |
130 | 130 |
|
131 |
+static int qcompare(const void *a, const void *b) |
|
132 |
+{ |
|
133 |
+ return *(const uint32_t *)a - *(const uint32_t *)b; |
|
134 |
+} |
|
135 |
+ |
|
136 |
+int cli_bm_initoff(const struct cli_matcher *root, struct cli_bm_off *data, struct F_MAP *map) |
|
137 |
+{ |
|
138 |
+ int ret; |
|
139 |
+ unsigned int i; |
|
140 |
+ struct cli_bm_patt *patt; |
|
141 |
+ struct cli_target_info info; |
|
142 |
+ |
|
143 |
+ |
|
144 |
+ if(!root->bm_patterns) { |
|
145 |
+ data->offtab = data->offset = 0; |
|
146 |
+ data->cnt = data->pos = 0; |
|
147 |
+ return CL_SUCCESS; |
|
148 |
+ } |
|
149 |
+ memset(&info, 0, sizeof(info)); |
|
150 |
+ info.fsize = map->len; |
|
151 |
+ |
|
152 |
+ data->cnt = data->pos = 0; |
|
153 |
+ data->offtab = (uint32_t *) cli_malloc(root->bm_patterns * sizeof(uint32_t)); |
|
154 |
+ if(!data->offtab) { |
|
155 |
+ cli_errmsg("cli_bm_initoff: Can't allocate memory for data->offtab\n"); |
|
156 |
+ return CL_EMEM; |
|
157 |
+ } |
|
158 |
+ data->offset = (uint32_t *) cli_malloc(root->bm_patterns * sizeof(uint32_t)); |
|
159 |
+ if(!data->offset) { |
|
160 |
+ cli_errmsg("cli_bm_initoff: Can't allocate memory for data->offset\n"); |
|
161 |
+ free(data->offtab); |
|
162 |
+ return CL_EMEM; |
|
163 |
+ } |
|
164 |
+ for(i = 0; i < root->bm_patterns; i++) { |
|
165 |
+ patt = root->bm_pattab[i]; |
|
166 |
+ if(patt->offdata[0] == CLI_OFF_ABSOLUTE) { |
|
167 |
+ data->offtab[data->cnt] = patt->offset_min + patt->prefix_length; |
|
168 |
+ data->cnt++; |
|
169 |
+ } else if((ret = cli_caloff(NULL, &info, map, root->type, patt->offdata, &data->offset[patt->offset_min], NULL))) { |
|
170 |
+ cli_errmsg("cli_bm_initoff: Can't calculate relative offset in signature for %s\n", patt->virname); |
|
171 |
+ if(info.exeinfo.section) |
|
172 |
+ free(info.exeinfo.section); |
|
173 |
+ free(data->offtab); |
|
174 |
+ free(data->offset); |
|
175 |
+ return ret; |
|
176 |
+ } else if((data->offset[patt->offset_min] != CLI_OFF_NONE) && (data->offset[patt->offset_min] + patt->length <= info.fsize)) { |
|
177 |
+ if(!data->cnt || (data->offset[patt->offset_min] != data->offtab[data->cnt - 1])) { |
|
178 |
+ data->offtab[data->cnt] = data->offset[patt->offset_min] + patt->prefix_length; |
|
179 |
+ data->cnt++; |
|
180 |
+ } |
|
181 |
+ } |
|
182 |
+ } |
|
183 |
+ if(info.exeinfo.section) |
|
184 |
+ free(info.exeinfo.section); |
|
185 |
+ |
|
186 |
+ qsort(data->offtab, data->cnt, sizeof(uint32_t), qcompare); |
|
187 |
+ return CL_SUCCESS; |
|
188 |
+} |
|
189 |
+ |
|
190 |
+void cli_bm_freeoff(struct cli_bm_off *data) |
|
191 |
+{ |
|
192 |
+ free(data->offset); |
|
193 |
+ data->offset = NULL; |
|
194 |
+ free(data->offtab); |
|
195 |
+ data->offtab = NULL; |
|
196 |
+} |
|
197 |
+ |
|
131 | 198 |
void cli_bm_free(struct cli_matcher *root) |
132 | 199 |
{ |
133 | 200 |
struct cli_bm_patt *patt, *prev; |
... | ... |
@@ -137,6 +216,9 @@ void cli_bm_free(struct cli_matcher *root) |
137 | 137 |
if(root->bm_shift) |
138 | 138 |
mpool_free(root->mempool, root->bm_shift); |
139 | 139 |
|
140 |
+ if(root->bm_pattab) |
|
141 |
+ mpool_free(root->mempool, root->bm_pattab); |
|
142 |
+ |
|
140 | 143 |
if(root->bm_suffix) { |
141 | 144 |
for(i = 0; i < size; i++) { |
142 | 145 |
patt = root->bm_suffix[i]; |
... | ... |
@@ -156,7 +238,7 @@ void cli_bm_free(struct cli_matcher *root) |
156 | 156 |
} |
157 | 157 |
} |
158 | 158 |
|
159 |
-int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_matcher *root, uint32_t offset, struct F_MAP *map) |
|
159 |
+int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_matcher *root, uint32_t offset, struct F_MAP *map, struct cli_bm_off *offdata) |
|
160 | 160 |
{ |
161 | 161 |
uint32_t i, j, off, off_min, off_max; |
162 | 162 |
uint8_t found, pchain, shift; |
... | ... |
@@ -174,7 +256,13 @@ int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **v |
174 | 174 |
return CL_CLEAN; |
175 | 175 |
|
176 | 176 |
memset(&info, 0, sizeof(info)); |
177 |
- for(i = BM_MIN_LENGTH - BM_BLOCK_SIZE; i < length - BM_BLOCK_SIZE + 1; ) { |
|
177 |
+ i = BM_MIN_LENGTH - BM_BLOCK_SIZE; |
|
178 |
+ if(offdata) { |
|
179 |
+ if(offdata->pos == offdata->cnt) |
|
180 |
+ return CL_CLEAN; |
|
181 |
+ i += offdata->offtab[offdata->pos] - offset; |
|
182 |
+ } |
|
183 |
+ for(; i < length - BM_BLOCK_SIZE + 1; ) { |
|
178 | 184 |
idx = HASH(buffer[i], buffer[i + 1], buffer[i + 2]); |
179 | 185 |
shift = root->bm_shift[idx]; |
180 | 186 |
|
... | ... |
@@ -182,7 +270,15 @@ int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **v |
182 | 182 |
prefix = buffer[i - BM_MIN_LENGTH + BM_BLOCK_SIZE]; |
183 | 183 |
p = root->bm_suffix[idx]; |
184 | 184 |
if(p && p->cnt == 1 && p->pattern0 != prefix) { |
185 |
- i++; |
|
185 |
+ if(offdata) { |
|
186 |
+ off = offset + i - BM_MIN_LENGTH + BM_BLOCK_SIZE; |
|
187 |
+ for(; off >= offdata->offtab[offdata->pos] && offdata->pos < offdata->cnt; offdata->pos++); |
|
188 |
+ if(offdata->pos == offdata->cnt || off >= offdata->offtab[offdata->pos]) |
|
189 |
+ return CL_CLEAN; |
|
190 |
+ i += offdata->offtab[offdata->pos] - off; |
|
191 |
+ } else { |
|
192 |
+ i++; |
|
193 |
+ } |
|
186 | 194 |
continue; |
187 | 195 |
} |
188 | 196 |
pchain = 0; |
... | ... |
@@ -202,6 +298,18 @@ int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **v |
202 | 202 |
continue; |
203 | 203 |
} |
204 | 204 |
|
205 |
+ if(offdata) { |
|
206 |
+ if(p->offdata[0] == CLI_OFF_ABSOLUTE) { |
|
207 |
+ if(p->offset_min != offset + off - p->prefix_length) { |
|
208 |
+ p = p->next; |
|
209 |
+ continue; |
|
210 |
+ } |
|
211 |
+ } else if((offdata->offset[p->offset_min] == CLI_OFF_NONE) || (offdata->offset[p->offset_min] != offset + off - p->prefix_length)) { |
|
212 |
+ p = p->next; |
|
213 |
+ continue; |
|
214 |
+ } |
|
215 |
+ } |
|
216 |
+ |
|
205 | 217 |
idxchk = MIN(p->length, length - off) - 1; |
206 | 218 |
if(idxchk) { |
207 | 219 |
if((bp[idxchk] != p->pattern[idxchk]) || (bp[idxchk / 2] != p->pattern[idxchk / 2])) { |
... | ... |
@@ -227,7 +335,7 @@ int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **v |
227 | 227 |
} |
228 | 228 |
|
229 | 229 |
if(found && p->length + p->prefix_length == j) { |
230 |
- if(p->offset_min != CLI_OFF_ANY) { |
|
230 |
+ if(!offdata && (p->offset_min != CLI_OFF_ANY)) { |
|
231 | 231 |
if(p->offdata[0] != CLI_OFF_ABSOLUTE) { |
232 | 232 |
ret = cli_caloff(NULL, &info, map, root->type, p->offdata, &off_min, &off_max); |
233 | 233 |
if(ret != CL_SUCCESS) { |
... | ... |
@@ -252,14 +360,21 @@ int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **v |
252 | 252 |
free(info.exeinfo.section); |
253 | 253 |
return CL_VIRUS; |
254 | 254 |
} |
255 |
- |
|
256 | 255 |
p = p->next; |
257 | 256 |
} |
258 |
- |
|
259 | 257 |
shift = 1; |
260 | 258 |
} |
261 | 259 |
|
262 |
- i += shift; |
|
260 |
+ if(offdata) { |
|
261 |
+ off = offset + i - BM_MIN_LENGTH + BM_BLOCK_SIZE; |
|
262 |
+ for(; off >= offdata->offtab[offdata->pos] && offdata->pos < offdata->cnt; offdata->pos++); |
|
263 |
+ if(offdata->pos == offdata->cnt || off >= offdata->offtab[offdata->pos]) |
|
264 |
+ return CL_CLEAN; |
|
265 |
+ i += offdata->offtab[offdata->pos] - off; |
|
266 |
+ } else { |
|
267 |
+ i += shift; |
|
268 |
+ } |
|
269 |
+ |
|
263 | 270 |
} |
264 | 271 |
|
265 | 272 |
if(info.exeinfo.section) |
... | ... |
@@ -36,9 +36,15 @@ struct cli_bm_patt { |
36 | 36 |
unsigned char pattern0; |
37 | 37 |
}; |
38 | 38 |
|
39 |
+struct cli_bm_off { |
|
40 |
+ uint32_t *offset, *offtab, cnt, pos; |
|
41 |
+}; |
|
42 |
+ |
|
39 | 43 |
int cli_bm_addpatt(struct cli_matcher *root, struct cli_bm_patt *pattern, const char *offset); |
40 | 44 |
int cli_bm_init(struct cli_matcher *root); |
41 |
-int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_matcher *root, uint32_t offset, struct F_MAP *map); |
|
45 |
+int cli_bm_initoff(const struct cli_matcher *root, struct cli_bm_off *data, struct F_MAP *map); |
|
46 |
+void cli_bm_freeoff(struct cli_bm_off *data); |
|
47 |
+int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_matcher *root, uint32_t offset, struct F_MAP *map, struct cli_bm_off *offdata); |
|
42 | 48 |
void cli_bm_free(struct cli_matcher *root); |
43 | 49 |
|
44 | 50 |
#endif |
... | ... |
@@ -77,7 +77,7 @@ int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset, |
77 | 77 |
if(!acdata && (ret = cli_ac_initdata(&mdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN))) |
78 | 78 |
return ret; |
79 | 79 |
|
80 |
- if(troot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, troot, offset, NULL)) != CL_VIRUS) |
|
80 |
+ if(troot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, troot, offset, NULL, NULL)) != CL_VIRUS) |
|
81 | 81 |
ret = cli_ac_scanbuff(buffer, length, virname, NULL, NULL, troot, acdata ? (acdata[0]) : (&mdata), offset, ftype, NULL, AC_SCAN_VIR, NULL); |
82 | 82 |
|
83 | 83 |
if(!acdata) |
... | ... |
@@ -90,7 +90,7 @@ int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset, |
90 | 90 |
if(!acdata && (ret = cli_ac_initdata(&mdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN))) |
91 | 91 |
return ret; |
92 | 92 |
|
93 |
- if(groot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, groot, offset, NULL)) != CL_VIRUS) |
|
93 |
+ if(groot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, groot, offset, NULL, NULL)) != CL_VIRUS) |
|
94 | 94 |
ret = cli_ac_scanbuff(buffer, length, virname, NULL, NULL, groot, acdata ? (acdata[1]) : (&mdata), offset, ftype, NULL, AC_SCAN_VIR, NULL); |
95 | 95 |
|
96 | 96 |
if(!acdata) |
... | ... |
@@ -199,7 +199,9 @@ int cli_caloff(const char *offstr, struct cli_target_info *info, struct F_MAP *m |
199 | 199 |
} else { |
200 | 200 |
/* calculate relative offsets */ |
201 | 201 |
if(info->status == -1) { |
202 |
- *offset_min = *offset_max = 0; |
|
202 |
+ *offset_min = CLI_OFF_NONE; |
|
203 |
+ if(offset_max) |
|
204 |
+ *offset_max = CLI_OFF_NONE; |
|
203 | 205 |
return CL_SUCCESS; |
204 | 206 |
} |
205 | 207 |
|
... | ... |
@@ -222,7 +224,9 @@ int cli_caloff(const char *offstr, struct cli_target_info *info, struct F_MAP *m |
222 | 222 |
if(einfo(map, &info->exeinfo)) { |
223 | 223 |
/* einfo *may* fail */ |
224 | 224 |
info->status = -1; |
225 |
- *offset_min = *offset_max = 0; |
|
225 |
+ *offset_min = CLI_OFF_NONE; |
|
226 |
+ if(offset_max) |
|
227 |
+ *offset_max = CLI_OFF_NONE; |
|
226 | 228 |
return CL_SUCCESS; |
227 | 229 |
} |
228 | 230 |
info->status = 1; |
... | ... |
@@ -247,7 +251,7 @@ int cli_caloff(const char *offstr, struct cli_target_info *info, struct F_MAP *m |
247 | 247 |
|
248 | 248 |
case CLI_OFF_SX_PLUS: |
249 | 249 |
if(offdata[3] >= info->exeinfo.nsections) |
250 |
- *offset_min = 0; |
|
250 |
+ *offset_min = CLI_OFF_NONE; |
|
251 | 251 |
else |
252 | 252 |
*offset_min = info->exeinfo.section[offdata[3]].raw + offdata[1]; |
253 | 253 |
break; |
... | ... |
@@ -257,9 +261,7 @@ int cli_caloff(const char *offstr, struct cli_target_info *info, struct F_MAP *m |
257 | 257 |
return CL_EARG; |
258 | 258 |
} |
259 | 259 |
|
260 |
- if(!*offset_min) |
|
261 |
- *offset_max = 0; |
|
262 |
- else |
|
260 |
+ if(offset_max && *offset_min != CLI_OFF_NONE) |
|
263 | 261 |
*offset_max = *offset_min + offdata[2]; |
264 | 262 |
} |
265 | 263 |
|
... | ... |
@@ -287,7 +289,7 @@ int cli_checkfp(int fd, cli_ctx *ctx) |
287 | 287 |
return 0; |
288 | 288 |
} |
289 | 289 |
|
290 |
- if(cli_bm_scanbuff(digest, 16, &virname, ctx->engine->md5_fp, 0, NULL) == CL_VIRUS) { |
|
290 |
+ if(cli_bm_scanbuff(digest, 16, &virname, ctx->engine->md5_fp, 0, NULL, NULL) == CL_VIRUS) { |
|
291 | 291 |
cli_dbgmsg("cli_checkfp(): Found false positive detection (fp sig: %s)\n", virname); |
292 | 292 |
free(digest); |
293 | 293 |
lseek(fd, pos, SEEK_SET); |
... | ... |
@@ -318,10 +320,11 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli |
318 | 318 |
{ |
319 | 319 |
unsigned char *buff; |
320 | 320 |
int ret = CL_CLEAN, type = CL_CLEAN, bytes; |
321 |
- unsigned int i, evalcnt; |
|
321 |
+ unsigned int i, evalcnt, bm_offmode = 0; |
|
322 | 322 |
uint32_t maxpatlen, offset = 0; |
323 | 323 |
uint64_t evalids; |
324 | 324 |
struct cli_ac_data gdata, tdata; |
325 |
+ struct cli_bm_off toff; |
|
325 | 326 |
cli_md5_ctx md5ctx; |
326 | 327 |
unsigned char digest[16]; |
327 | 328 |
struct cli_matcher *groot = NULL, *troot = NULL; |
... | ... |
@@ -366,6 +369,17 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli |
366 | 366 |
cli_ac_freedata(&gdata); |
367 | 367 |
return ret; |
368 | 368 |
} |
369 |
+ if(troot->bm_offmode) { |
|
370 |
+ if(map->len >= CLI_DEFAULT_BM_OFFMODE_FSIZE) { |
|
371 |
+ if((ret = cli_bm_initoff(troot, &toff, map))) { |
|
372 |
+ if(!ftonly) |
|
373 |
+ cli_ac_freedata(&gdata); |
|
374 |
+ cli_ac_freedata(&tdata); |
|
375 |
+ return ret; |
|
376 |
+ } |
|
377 |
+ bm_offmode = 1; |
|
378 |
+ } |
|
379 |
+ } |
|
369 | 380 |
} |
370 | 381 |
|
371 | 382 |
if(!ftonly && ctx->engine->md5_hdb) |
... | ... |
@@ -380,13 +394,14 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli |
380 | 380 |
*ctx->scanned += bytes / CL_COUNT_PRECISION; |
381 | 381 |
|
382 | 382 |
if(troot) { |
383 |
- if(troot->ac_only || (ret = cli_bm_scanbuff(buff, bytes, ctx->virname, troot, offset, map)) != CL_VIRUS) |
|
383 |
+ if(troot->ac_only || (ret = cli_bm_scanbuff(buff, bytes, ctx->virname, troot, offset, map, bm_offmode ? &toff : NULL)) != CL_VIRUS) |
|
384 | 384 |
ret = cli_ac_scanbuff(buff, bytes, ctx->virname, NULL, NULL, troot, &tdata, offset, ftype, ftoffset, acmode, NULL); |
385 |
- |
|
386 | 385 |
if(ret == CL_VIRUS) { |
387 | 386 |
if(!ftonly) |
388 | 387 |
cli_ac_freedata(&gdata); |
389 | 388 |
cli_ac_freedata(&tdata); |
389 |
+ if(bm_offmode) |
|
390 |
+ cli_bm_freeoff(&toff); |
|
390 | 391 |
|
391 | 392 |
if(cli_checkfp(map->fd, ctx)) |
392 | 393 |
return CL_CLEAN; |
... | ... |
@@ -396,13 +411,15 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli |
396 | 396 |
} |
397 | 397 |
|
398 | 398 |
if(!ftonly) { |
399 |
- if(groot->ac_only || (ret = cli_bm_scanbuff(buff, bytes, ctx->virname, groot, offset, map)) != CL_VIRUS) |
|
399 |
+ if(groot->ac_only || (ret = cli_bm_scanbuff(buff, bytes, ctx->virname, groot, offset, map, NULL)) != CL_VIRUS) |
|
400 | 400 |
ret = cli_ac_scanbuff(buff, bytes, ctx->virname, NULL, NULL, groot, &gdata, offset, ftype, ftoffset, acmode, NULL); |
401 |
- |
|
402 | 401 |
if(ret == CL_VIRUS) { |
403 | 402 |
cli_ac_freedata(&gdata); |
404 |
- if(troot) |
|
403 |
+ if(troot) { |
|
405 | 404 |
cli_ac_freedata(&tdata); |
405 |
+ if(bm_offmode) |
|
406 |
+ cli_bm_freeoff(&toff); |
|
407 |
+ } |
|
406 | 408 |
if(cli_checkfp(map->fd, ctx)) |
407 | 409 |
return CL_CLEAN; |
408 | 410 |
else |
... | ... |
@@ -433,6 +450,8 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli |
433 | 433 |
} |
434 | 434 |
} |
435 | 435 |
cli_ac_freedata(&tdata); |
436 |
+ if(bm_offmode) |
|
437 |
+ cli_bm_freeoff(&toff); |
|
436 | 438 |
} |
437 | 439 |
|
438 | 440 |
if(groot) { |
... | ... |
@@ -459,7 +478,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli |
459 | 459 |
|
460 | 460 |
if(!ftonly && ctx->engine->md5_hdb) { |
461 | 461 |
cli_md5_final(digest, &md5ctx); |
462 |
- if(cli_bm_scanbuff(digest, 16, ctx->virname, ctx->engine->md5_hdb, 0, NULL) == CL_VIRUS && (cli_bm_scanbuff(digest, 16, NULL, ctx->engine->md5_fp, 0, NULL) != CL_VIRUS)) |
|
462 |
+ if(cli_bm_scanbuff(digest, 16, ctx->virname, ctx->engine->md5_hdb, 0, NULL, NULL) == CL_VIRUS && (cli_bm_scanbuff(digest, 16, NULL, ctx->engine->md5_fp, 0, NULL, NULL) != CL_VIRUS)) |
|
463 | 463 |
return CL_VIRUS; |
464 | 464 |
} |
465 | 465 |
|
... | ... |
@@ -73,10 +73,10 @@ struct cli_matcher { |
73 | 73 |
|
74 | 74 |
/* Extended Boyer-Moore */ |
75 | 75 |
uint8_t *bm_shift; |
76 |
- struct cli_bm_patt **bm_suffix; |
|
76 |
+ struct cli_bm_patt **bm_suffix, **bm_pattab; |
|
77 | 77 |
struct cli_hashset md5_sizes_hs; |
78 | 78 |
uint32_t *soff, soff_len; /* for PE section sigs */ |
79 |
- uint32_t bm_patterns, bm_reloff_num, bm_absoff_num; |
|
79 |
+ uint32_t bm_offmode, bm_patterns, bm_reloff_num, bm_absoff_num; |
|
80 | 80 |
|
81 | 81 |
/* Extended Aho-Corasick */ |
82 | 82 |
uint32_t ac_partsigs, ac_nodes, ac_patterns, ac_lsigs; |
... | ... |
@@ -900,9 +900,8 @@ int cli_scanpe(cli_ctx *ctx) |
900 | 900 |
for(j = 0; j < md5_sect->soff_len && md5_sect->soff[j] <= exe_sections[i].rsz; j++) { |
901 | 901 |
if(md5_sect->soff[j] == exe_sections[i].rsz) { |
902 | 902 |
unsigned char md5_dig[16]; |
903 |
- if(cli_md5sect(map, &exe_sections[i], md5_dig) && cli_bm_scanbuff(md5_dig, 16, ctx->virname, ctx->engine->md5_mdb, 0, NULL) == CL_VIRUS) { |
|
904 |
- if(cli_bm_scanbuff(md5_dig, 16, NULL, ctx->engine->md5_fp, 0, NULL) != CL_VIRUS) { |
|
905 |
- |
|
903 |
+ if(cli_md5sect(map, &exe_sections[i], md5_dig) && cli_bm_scanbuff(md5_dig, 16, ctx->virname, ctx->engine->md5_mdb, 0, NULL, NULL) == CL_VIRUS) { |
|
904 |
+ if(cli_bm_scanbuff(md5_dig, 16, NULL, ctx->engine->md5_fp, 0, NULL, NULL) != CL_VIRUS) { |
|
906 | 905 |
free(section_hdr); |
907 | 906 |
free(exe_sections); |
908 | 907 |
return cli_checkfp(map->fd, ctx) ? CL_CLEAN : CL_VIRUS; |
... | ... |
@@ -1198,13 +1198,13 @@ static int hash_match(const struct regex_matcher *rlist, const char *host, size_ |
1198 | 1198 |
h[64]='\0'; |
1199 | 1199 |
cli_dbgmsg("Looking up hash %s for %s(%u)%s(%u)\n", h, host, (unsigned)hlen, path, (unsigned)plen); |
1200 | 1200 |
if (prefix_matched) { |
1201 |
- if (cli_bm_scanbuff(sha256_dig, 4, &virname, &rlist->hostkey_prefix,0,NULL) == CL_VIRUS) { |
|
1201 |
+ if (cli_bm_scanbuff(sha256_dig, 4, &virname, &rlist->hostkey_prefix,0,NULL,NULL) == CL_VIRUS) { |
|
1202 | 1202 |
cli_dbgmsg("prefix matched\n"); |
1203 | 1203 |
*prefix_matched = 1; |
1204 | 1204 |
} else |
1205 | 1205 |
return CL_SUCCESS; |
1206 | 1206 |
} |
1207 |
- if (cli_bm_scanbuff(sha256_dig, 32, &virname, &rlist->sha256_hashes,0,NULL) == CL_VIRUS) { |
|
1207 |
+ if (cli_bm_scanbuff(sha256_dig, 32, &virname, &rlist->sha256_hashes,0,NULL,NULL) == CL_VIRUS) { |
|
1208 | 1208 |
cli_dbgmsg("This hash matched: %s\n", h); |
1209 | 1209 |
switch(*virname) { |
1210 | 1210 |
case 'W': |
... | ... |
@@ -246,7 +246,7 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex |
246 | 246 |
free(pt); |
247 | 247 |
} |
248 | 248 |
|
249 |
- } else if(root->ac_only || type || lsigid /* || (hexlen / 2 < CLI_DEFAULT_MOVETOAC_LEN) FIXME: unit tests */ || strpbrk(hexsig, "?(")) { |
|
249 |
+ } else if(root->ac_only || type || lsigid || strpbrk(hexsig, "?(") || (root->bm_offmode && (!strcmp(offset, "*") || strchr(offset, ',')))) { |
|
250 | 250 |
if((ret = cli_ac_addsig(root, virname, hexsig, 0, 0, 0, rtype, type, 0, 0, offset, lsigid, options))) { |
251 | 251 |
cli_errmsg("cli_parse_add(): Problem adding signature (3).\n"); |
252 | 252 |
return ret; |
... | ... |
@@ -322,7 +322,7 @@ static int cli_initroots(struct cl_engine *engine, unsigned int options) |
322 | 322 |
} |
323 | 323 |
} |
324 | 324 |
} |
325 |
- |
|
325 |
+ engine->root[1]->bm_offmode = 1; /* BM offset mode for PE files */ |
|
326 | 326 |
return CL_SUCCESS; |
327 | 327 |
} |
328 | 328 |
|
... | ... |
@@ -455,7 +455,7 @@ static int add_hash(struct regex_matcher *matcher, char* pattern, const char fl, |
455 | 455 |
|
456 | 456 |
if (fl != 'W' && pat->length == 32 && |
457 | 457 |
cli_hashset_contains(&matcher->sha256_pfx_set, cli_readint32(pat->pattern)) && |
458 |
- cli_bm_scanbuff(pat->pattern, 32, &vname, &matcher->sha256_hashes,0,NULL) == CL_VIRUS) { |
|
458 |
+ cli_bm_scanbuff(pat->pattern, 32, &vname, &matcher->sha256_hashes,0,NULL,NULL) == CL_VIRUS) { |
|
459 | 459 |
if (*vname == 'W') { |
460 | 460 |
/* hash is whitelisted in local.gdb */ |
461 | 461 |
cli_dbgmsg("Skipping hash %s\n", pattern); |
... | ... |
@@ -116,7 +116,7 @@ START_TEST (test_bm_scanbuff) { |
116 | 116 |
ret = cli_parse_add(root, "Sig3", "babedead", 0, 0, "*", 0, NULL, 0); |
117 | 117 |
fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed"); |
118 | 118 |
|
119 |
- ret = cli_bm_scanbuff("blah\xde\xad\xbe\xef", 12, &virname, root, 0, -1); |
|
119 |
+ ret = cli_bm_scanbuff("blah\xde\xad\xbe\xef", 12, &virname, root, 0, -1,NULL); |
|
120 | 120 |
fail_unless(ret == CL_VIRUS, "cli_bm_scanbuff() failed"); |
121 | 121 |
fail_unless(!strncmp(virname, "Sig2", 4), "Incorrect signature matched in cli_bm_scanbuff()\n"); |
122 | 122 |
cli_bm_free(root); |