source: clamav/trunk/libclamav/matcher.c@ 319

Last change on this file since 319 was 319, checked in by Yuri Dario, 14 years ago

clamav: update trunk to 0.97.

File size: 25.0 KB
Line 
1/*
2 * Copyright (C) 2007-2009 Sourcefire, Inc.
3 *
4 * Authors: Tomasz Kojm
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1301, USA.
19 */
20
21#if HAVE_CONFIG_H
22#include "clamav-config.h"
23#endif
24
25#include <string.h>
26#include <ctype.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#ifdef HAVE_UNISTD_H
30#include <unistd.h>
31#endif
32
33#include "clamav.h"
34#include "others.h"
35#include "matcher-ac.h"
36#include "matcher-bm.h"
37#include "md5.h"
38#include "sha1.h"
39#include "sha256.h"
40#include "filetypes.h"
41#include "matcher.h"
42#include "pe.h"
43#include "elf.h"
44#include "execs.h"
45#include "special.h"
46#include "scanners.h"
47#include "str.h"
48#include "cltypes.h"
49#include "default.h"
50#include "macho.h"
51#include "fmap.h"
52#include "pe_icons.h"
53#include "regex/regex.h"
54#include "filtering.h"
55#include "perflogging.h"
56#include "bytecode_priv.h"
57#include "bytecode_api_impl.h"
58#include "sha256.h"
59#include "sha1.h"
60
61#ifdef CLI_PERF_LOGGING
62
63static inline void PERF_LOG_FILTER(int32_t pos, int32_t length, int8_t trie)
64{
65 cli_perf_log_add(RAW_BYTES_SCANNED, length);
66 cli_perf_log_add(FILTER_BYTES_SCANNED, length - pos);
67 cli_perf_log_count2(TRIE_SCANNED, trie, length - pos);
68}
69
70static inline int PERF_LOG_TRIES(int8_t acmode, int8_t bm_called, int32_t length)
71{
72 if (bm_called)
73 cli_perf_log_add(BM_SCANNED, length);
74 if (acmode)
75 cli_perf_log_add(AC_SCANNED, length);
76 return 0;
77}
78
79#else
80static inline void PERF_LOG_FILTER(int32_t pos, uint32_t length, int8_t trie) {}
81static inline int PERF_LOG_TRIES(int8_t acmode, int8_t bm_called, int32_t length) { return 0; }
82#endif
83
84static inline int matcher_run(const struct cli_matcher *root,
85 const unsigned char *buffer, uint32_t length,
86 const char **virname, struct cli_ac_data *mdata,
87 uint32_t offset,
88 const struct cli_target_info *tinfo,
89 cli_file_t ftype,
90 struct cli_matched_type **ftoffset,
91 unsigned int acmode,
92 struct cli_ac_result **acres,
93 fmap_t *map,
94 struct cli_bm_off *offdata)
95{
96 int ret;
97 int32_t pos = 0;
98 struct filter_match_info info;
99 uint32_t orig_length, orig_offset;
100 const unsigned char* orig_buffer;
101
102 if (root->filter) {
103 if(filter_search_ext(root->filter, buffer, length, &info) == -1) {
104 /* for safety always scan last maxpatlen bytes */
105 pos = length - root->maxpatlen - 1;
106 if (pos < 0) pos = 0;
107 PERF_LOG_FILTER(pos, length, root->type);
108 } else {
109 /* must not cut buffer for 64[4-4]6161, because we must be able to check
110 * 64! */
111 pos = info.first_match - root->maxpatlen - 1;
112 if (pos < 0) pos = 0;
113 PERF_LOG_FILTER(pos, length, root->type);
114 }
115 } else {
116 PERF_LOG_FILTER(0, length, root->type);
117 }
118
119 orig_length = length;
120 orig_buffer = buffer;
121 orig_offset = offset;
122 length -= pos;
123 buffer += pos;
124 offset += pos;
125 if (!root->ac_only) {
126 PERF_LOG_TRIES(0, 1, length);
127 if (root->bm_offmode) {
128 /* Don't use prefiltering for BM offset mode, since BM keeps tracks
129 * of offsets itself, and doesn't work if we skip chunks of input
130 * data */
131 ret = cli_bm_scanbuff(orig_buffer, orig_length, virname, NULL, root, orig_offset, tinfo, offdata);
132 } else {
133 ret = cli_bm_scanbuff(buffer, length, virname, NULL, root, offset, tinfo, offdata);
134 }
135 if (ret == CL_VIRUS)
136 return ret;
137 }
138 PERF_LOG_TRIES(acmode, 0, length);
139 ret = cli_ac_scanbuff(buffer, length, virname, NULL, acres, root, mdata, offset, ftype, ftoffset, acmode, NULL);
140 return ret;
141}
142
143int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset, cli_ctx *ctx, cli_file_t ftype, struct cli_ac_data **acdata)
144{
145 int ret = CL_CLEAN;
146 unsigned int i;
147 struct cli_ac_data mdata;
148 struct cli_matcher *groot, *troot = NULL;
149 const char **virname=ctx->virname;
150 const struct cl_engine *engine=ctx->engine;
151
152 if(!engine) {
153 cli_errmsg("cli_scanbuff: engine == NULL\n");
154 return CL_ENULLARG;
155 }
156
157 groot = engine->root[0]; /* generic signatures */
158
159 if(ftype) {
160 for(i = 1; i < CLI_MTARGETS; i++) {
161 if(cli_mtargets[i].target == ftype) {
162 troot = engine->root[i];
163 break;
164 }
165 }
166 }
167
168 if(troot) {
169
170 if(!acdata && (ret = cli_ac_initdata(&mdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
171 return ret;
172
173 ret = matcher_run(troot, buffer, length, virname, acdata ? (acdata[0]): (&mdata), offset, NULL, ftype, NULL, AC_SCAN_VIR, NULL, *ctx->fmap, NULL);
174
175 if(!acdata)
176 cli_ac_freedata(&mdata);
177
178 if(ret == CL_VIRUS || ret == CL_EMEM)
179 return ret;
180 }
181
182 if(!acdata && (ret = cli_ac_initdata(&mdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
183 return ret;
184
185 ret = matcher_run(groot, buffer, length, virname, acdata ? (acdata[1]): (&mdata), offset, NULL, ftype, NULL, AC_SCAN_VIR, NULL, *ctx->fmap, NULL);
186
187 if(!acdata)
188 cli_ac_freedata(&mdata);
189
190 return ret;
191}
192
193/*
194 * offdata[0]: type
195 * offdata[1]: offset value
196 * offdata[2]: max shift
197 * offdata[3]: section number
198 */
199int cli_caloff(const char *offstr, const struct cli_target_info *info, unsigned int target, uint32_t *offdata, uint32_t *offset_min, uint32_t *offset_max)
200{
201 char offcpy[65];
202 unsigned int n, val;
203 char *pt;
204
205 if(!info) { /* decode offset string */
206 if(!offstr) {
207 cli_errmsg("cli_caloff: offstr == NULL\n");
208 return CL_ENULLARG;
209 }
210
211 if(!strcmp(offstr, "*")) {
212 offdata[0] = *offset_max = *offset_min = CLI_OFF_ANY;
213 return CL_SUCCESS;
214 }
215
216 if(strlen(offstr) > 64) {
217 cli_errmsg("cli_caloff: Offset string too long\n");
218 return CL_EMALFDB;
219 }
220 strcpy(offcpy, offstr);
221
222 if((pt = strchr(offcpy, ','))) {
223 if(!cli_isnumber(pt + 1)) {
224 cli_errmsg("cli_caloff: Invalid offset shift value\n");
225 return CL_EMALFDB;
226 }
227 offdata[2] = atoi(pt + 1);
228 *pt = 0;
229 } else {
230 offdata[2] = 0;
231 }
232
233 *offset_max = *offset_min = CLI_OFF_NONE;
234
235 if(!strncmp(offcpy, "EP+", 3) || !strncmp(offcpy, "EP-", 3)) {
236 if(offcpy[2] == '+')
237 offdata[0] = CLI_OFF_EP_PLUS;
238 else
239 offdata[0] = CLI_OFF_EP_MINUS;
240
241 if(!cli_isnumber(&offcpy[3])) {
242 cli_errmsg("cli_caloff: Invalid offset value\n");
243 return CL_EMALFDB;
244 }
245 offdata[1] = atoi(&offcpy[3]);
246
247 } else if(offcpy[0] == 'S') {
248 if(!strncmp(offstr, "SL+", 3)) {
249 offdata[0] = CLI_OFF_SL_PLUS;
250 if(!cli_isnumber(&offcpy[3])) {
251 cli_errmsg("cli_caloff: Invalid offset value\n");
252 return CL_EMALFDB;
253 }
254 offdata[1] = atoi(&offcpy[3]);
255
256 } else if(sscanf(offcpy, "S%u+%u", &n, &val) == 2) {
257 offdata[0] = CLI_OFF_SX_PLUS;
258 offdata[1] = val;
259 offdata[3] = n;
260 } else {
261 cli_errmsg("cli_caloff: Invalid offset string\n");
262 return CL_EMALFDB;
263 }
264
265 } else if(!strncmp(offcpy, "EOF-", 4)) {
266 offdata[0] = CLI_OFF_EOF_MINUS;
267 if(!cli_isnumber(&offcpy[4])) {
268 cli_errmsg("cli_caloff: Invalid offset value\n");
269 return CL_EMALFDB;
270 }
271 offdata[1] = atoi(&offcpy[4]);
272 } else if(!strncmp(offcpy, "VI", 2)) {
273 /* versioninfo */
274 offdata[0] = CLI_OFF_VERSION;
275 } else if (strchr(offcpy, '$')) {
276 if (sscanf(offcpy, "$%u$", &n) != 1) {
277 cli_errmsg("cli_caloff: Invalid macro($) in offset: %s\n", offcpy);
278 return CL_EMALFDB;
279 }
280 if (n >= 32) {
281 cli_errmsg("cli_caloff: at most 32 macro groups supported\n");
282 return CL_EMALFDB;
283 }
284 offdata[0] = CLI_OFF_MACRO;
285 offdata[1] = n;
286 } else {
287 offdata[0] = CLI_OFF_ABSOLUTE;
288 if(!cli_isnumber(offcpy)) {
289 cli_errmsg("cli_caloff: Invalid offset value\n");
290 return CL_EMALFDB;
291 }
292 *offset_min = offdata[1] = atoi(offcpy);
293 *offset_max = *offset_min + offdata[2];
294 }
295
296 if(offdata[0] != CLI_OFF_ANY && offdata[0] != CLI_OFF_ABSOLUTE &&
297 offdata[0] != CLI_OFF_EOF_MINUS && offdata[0] != CLI_OFF_MACRO) {
298 if(target != 1 && target != 6 && target != 9) {
299 cli_errmsg("cli_caloff: Invalid offset type for target %u\n", target);
300 return CL_EMALFDB;
301 }
302 }
303
304 } else {
305 /* calculate relative offsets */
306 if(info->status == -1) {
307 *offset_min = CLI_OFF_NONE;
308 if(offset_max)
309 *offset_max = CLI_OFF_NONE;
310 return CL_SUCCESS;
311 }
312
313 switch(offdata[0]) {
314 case CLI_OFF_EOF_MINUS:
315 *offset_min = info->fsize - offdata[1];
316 break;
317
318 case CLI_OFF_EP_PLUS:
319 *offset_min = info->exeinfo.ep + offdata[1];
320 break;
321
322 case CLI_OFF_EP_MINUS:
323 *offset_min = info->exeinfo.ep - offdata[1];
324 break;
325
326 case CLI_OFF_SL_PLUS:
327 *offset_min = info->exeinfo.section[info->exeinfo.nsections - 1].raw + offdata[1];
328 break;
329
330 case CLI_OFF_SX_PLUS:
331 if(offdata[3] >= info->exeinfo.nsections)
332 *offset_min = CLI_OFF_NONE;
333 else
334 *offset_min = info->exeinfo.section[offdata[3]].raw + offdata[1];
335 break;
336 case CLI_OFF_VERSION:
337 *offset_min = *offset_max = CLI_OFF_ANY;
338 break;
339 default:
340 cli_errmsg("cli_caloff: Not a relative offset (type: %u)\n", offdata[0]);
341 return CL_EARG;
342 }
343
344 if(offset_max) {
345 if(*offset_min != CLI_OFF_NONE)
346 *offset_max = *offset_min + offdata[2];
347 else
348 *offset_max = CLI_OFF_NONE;
349 }
350 }
351
352 return CL_SUCCESS;
353}
354
355static void targetinfo(struct cli_target_info *info, unsigned int target, fmap_t *map)
356{
357 int (*einfo)(fmap_t *, struct cli_exe_info *) = NULL;
358
359
360 memset(info, 0, sizeof(struct cli_target_info));
361 info->fsize = map->len;
362 cli_hashset_init_noalloc(&info->exeinfo.vinfo);
363
364 if(target == 1)
365 einfo = cli_peheader;
366 else if(target == 6)
367 einfo = cli_elfheader;
368 else if(target == 9)
369 einfo = cli_machoheader;
370 else return;
371
372 if(einfo(map, &info->exeinfo))
373 info->status = -1;
374 else
375 info->status = 1;
376}
377
378int cli_checkfp(unsigned char *digest, size_t size, cli_ctx *ctx)
379{
380 char md5[33];
381 unsigned int i;
382 const char *virname;
383 SHA1Context sha1;
384 SHA256_CTX sha256;
385 fmap_t *map;
386 char *ptr;
387 uint8_t shash1[SHA1_HASH_SIZE*2+1];
388 uint8_t shash256[SHA256_HASH_SIZE*2+1];
389 int have_sha1, have_sha256;
390
391 if(cli_hm_scan(digest, size, &virname, ctx->engine->hm_fp, CLI_HASH_MD5) == CL_VIRUS) {
392 cli_dbgmsg("cli_checkfp(md5): Found false positive detection (fp sig: %s)\n", virname);
393 return CL_CLEAN;
394 }
395
396 for(i = 0; i < 16; i++)
397 sprintf(md5 + i * 2, "%02x", digest[i]);
398 md5[32] = 0;
399 cli_dbgmsg("FP SIGNATURE: %s:%u:%s\n", md5, (unsigned int) size, *ctx->virname ? *ctx->virname : "Name");
400
401 map = *ctx->fmap;
402 have_sha1 = cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, size);
403 have_sha256 = cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA256, size);
404 if(have_sha1 || have_sha256) {
405 if((ptr = fmap_need_off_once(map, 0, size))) {
406 if(have_sha1) {
407 SHA1Init(&sha1);
408 SHA1Update(&sha1, ptr, size);
409 SHA1Final(&sha1, &shash1[SHA1_HASH_SIZE]);
410 if(cli_hm_scan(&shash1[SHA1_HASH_SIZE], size, &virname, ctx->engine->hm_fp, CLI_HASH_SHA1) == CL_VIRUS){
411 cli_dbgmsg("cli_checkfp(sha1): Found false positive detection (fp sig: %s)\n", virname);
412 return CL_CLEAN;
413 }
414 }
415 if(have_sha256) {
416 sha256_init(&sha256);
417 sha256_update(&sha256, ptr, size);
418 sha256_final(&sha256, &shash256[SHA256_HASH_SIZE]);
419 if(cli_hm_scan(&shash256[SHA256_HASH_SIZE], size, &virname, ctx->engine->hm_fp, CLI_HASH_SHA256) == CL_VIRUS){
420 cli_dbgmsg("cli_checkfp(sha256): Found false positive detection (fp sig: %s)\n", virname);
421 return CL_CLEAN;
422 }
423 }
424 }
425 }
426#ifdef HAVE__INTERNAL__SHA_COLLECT
427 if((ctx->options & CL_SCAN_INTERNAL_COLLECT_SHA) && ctx->sha_collect>0) {
428 if((ptr = fmap_need_off_once(map, 0, size))) {
429 if(!have_sha256) {
430 sha256_init(&sha256);
431 sha256_update(&sha256, ptr, size);
432 sha256_final(&sha256, &shash256[SHA256_HASH_SIZE]);
433 }
434 for(i=0; i<SHA256_HASH_SIZE; i++)
435 sprintf((char *)shash256+i*2, "%02x", shash256[SHA256_HASH_SIZE+i]);
436
437 if(!have_sha1) {
438 SHA1Init(&sha1);
439 SHA1Update(&sha1, ptr, size);
440 SHA1Final(&sha1, &shash1[SHA1_HASH_SIZE]);
441 }
442 for(i=0; i<SHA1_HASH_SIZE; i++)
443 sprintf((char *)shash1+i*2, "%02x", shash1[SHA1_HASH_SIZE+i]);
444
445 cli_errmsg("COLLECT:%s:%s:%u:%s:%s\n", shash256, shash1, size, *ctx->virname, ctx->entry_filename);
446 } else
447 cli_errmsg("can't compute sha\n!");
448 ctx->sha_collect = -1;
449 }
450#endif
451
452 if (ctx->engine->cb_hash)
453 ctx->engine->cb_hash(ctx->fmap[0]->fd, size, md5, ctx->virname ? *ctx->virname : NULL, ctx->cb_ctx);
454
455 return CL_VIRUS;
456}
457
458static int matchicon(cli_ctx *ctx, struct cli_exe_info *exeinfo, const char *grp1, const char *grp2)
459{
460 icon_groupset iconset;
461
462 if(!ctx ||
463 !ctx->engine ||
464 !ctx->engine->iconcheck ||
465 !ctx->engine->iconcheck->group_counts[0] ||
466 !ctx->engine->iconcheck->group_counts[1] ||
467 !exeinfo->res_addr
468 ) return CL_CLEAN;
469
470 cli_icongroupset_init(&iconset);
471 cli_icongroupset_add(grp1 ? grp1 : "*", &iconset, 0, ctx);
472 cli_icongroupset_add(grp2 ? grp2 : "*", &iconset, 1, ctx);
473 return cli_scanicon(&iconset, exeinfo->res_addr, ctx, exeinfo->section, exeinfo->nsections, exeinfo->hdr_size);
474}
475
476int32_t cli_bcapi_matchicon(struct cli_bc_ctx *ctx , const uint8_t* grp1, int32_t grp1len,
477 const uint8_t* grp2, int32_t grp2len)
478{
479 int ret;
480 char group1[128], group2[128];
481 const char **oldvirname;
482 struct cli_exe_info info;
483
484 if (!ctx->hooks.pedata->ep) {
485 cli_dbgmsg("bytecode: matchicon only works with PE files\n");
486 return -1;
487 }
488 if ((size_t) grp1len > sizeof(group1)-1 ||
489 (size_t) grp2len > sizeof(group2)-1)
490 return -1;
491 oldvirname = ((cli_ctx*)ctx->ctx)->virname;
492 ((cli_ctx*)ctx->ctx)->virname = NULL;
493 memcpy(group1, grp1, grp1len);
494 memcpy(group2, grp2, grp2len);
495 group1[grp1len] = 0;
496 group2[grp2len] = 0;
497 memset(&info, 0, sizeof(info));
498 if (ctx->bc->kind == BC_PE_UNPACKER || ctx->bc->kind == BC_PE_ALL) {
499 if(le16_to_host(ctx->hooks.pedata->file_hdr.Characteristics) & 0x2000 ||
500 !ctx->hooks.pedata->dirs[2].Size)
501 info.res_addr = 0;
502 else
503 info.res_addr = le32_to_host(ctx->hooks.pedata->dirs[2].VirtualAddress);
504 } else
505 info.res_addr = ctx->resaddr; /* from target_info */
506 info.section = (struct cli_exe_section*)ctx->sections;
507 info.nsections = ctx->hooks.pedata->nsections;
508 info.hdr_size = ctx->hooks.pedata->hdr_size;
509 cli_dbgmsg("bytecode matchicon %s %s\n", group1, group2);
510 ret = matchicon(ctx->ctx, &info, group1[0] ? group1 : NULL,
511 group2[0] ? group2 : NULL);
512 ((cli_ctx*)ctx->ctx)->virname = oldvirname;
513 return ret;
514}
515
516
517int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres)
518{
519 int ret = CL_EMEM, empty;
520 fmap_t *map = *ctx->fmap;
521
522 if((*ctx->fmap = fmap_check_empty(desc, 0, 0, &empty))) {
523 ret = cli_fmap_scandesc(ctx, ftype, ftonly, ftoffset, acmode, acres, NULL);
524 map->dont_cache_flag = (*ctx->fmap)->dont_cache_flag;
525 funmap(*ctx->fmap);
526 }
527 *ctx->fmap = map;
528 if(empty)
529 return CL_CLEAN;
530 return ret;
531}
532
533int cli_lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info, const char *hash)
534{
535 unsigned int i, evalcnt;
536 uint64_t evalids;
537 fmap_t *map = *ctx->fmap;
538
539 for(i = 0; i < root->ac_lsigs; i++) {
540 evalcnt = 0;
541 evalids = 0;
542 cli_ac_chkmacro(root, acdata, i);
543 if(cli_ac_chklsig(root->ac_lsigtable[i]->logic, root->ac_lsigtable[i]->logic + strlen(root->ac_lsigtable[i]->logic), acdata->lsigcnt[i], &evalcnt, &evalids, 0) == 1) {
544 if(root->ac_lsigtable[i]->tdb.container && root->ac_lsigtable[i]->tdb.container[0] != ctx->container_type)
545 continue;
546 if(root->ac_lsigtable[i]->tdb.filesize && (root->ac_lsigtable[i]->tdb.filesize[0] > map->len || root->ac_lsigtable[i]->tdb.filesize[1] < map->len))
547 continue;
548
549 if(root->ac_lsigtable[i]->tdb.ep || root->ac_lsigtable[i]->tdb.nos) {
550 if(!target_info || target_info->status != 1)
551 continue;
552 if(root->ac_lsigtable[i]->tdb.ep && (root->ac_lsigtable[i]->tdb.ep[0] > target_info->exeinfo.ep || root->ac_lsigtable[i]->tdb.ep[1] < target_info->exeinfo.ep))
553 continue;
554 if(root->ac_lsigtable[i]->tdb.nos && (root->ac_lsigtable[i]->tdb.nos[0] > target_info->exeinfo.nsections || root->ac_lsigtable[i]->tdb.nos[1] < target_info->exeinfo.nsections))
555 continue;
556 }
557
558 if(hash && root->ac_lsigtable[i]->tdb.handlertype) {
559 if(memcmp(ctx->handlertype_hash, hash, 16)) {
560 ctx->recursion++;
561 memcpy(ctx->handlertype_hash, hash, 16);
562 if(cli_magic_scandesc_type(map->fd, ctx, root->ac_lsigtable[i]->tdb.handlertype[0]) == CL_VIRUS) {
563 ctx->recursion--;
564 return CL_VIRUS;
565 }
566 ctx->recursion--;
567 continue;
568 }
569 }
570
571 if(root->ac_lsigtable[i]->tdb.icongrp1 || root->ac_lsigtable[i]->tdb.icongrp2) {
572 if(!target_info || target_info->status != 1)
573 continue;
574 if(matchicon(ctx, &target_info->exeinfo, root->ac_lsigtable[i]->tdb.icongrp1, root->ac_lsigtable[i]->tdb.icongrp2) == CL_VIRUS) {
575 if(!root->ac_lsigtable[i]->bc_idx) {
576 if(ctx->virname)
577 *ctx->virname = root->ac_lsigtable[i]->virname;
578 return CL_VIRUS;
579 } else if(cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, root->ac_lsigtable[i]->bc_idx, ctx->virname, acdata->lsigcnt[i], acdata->lsigsuboff_first[i], map) == CL_VIRUS) {
580 return CL_VIRUS;
581 }
582 }
583 continue;
584 }
585 if(!root->ac_lsigtable[i]->bc_idx) {
586 if(ctx->virname)
587 *ctx->virname = root->ac_lsigtable[i]->virname;
588 return CL_VIRUS;
589 }
590 if(cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, root->ac_lsigtable[i]->bc_idx, ctx->virname, acdata->lsigcnt[i], acdata->lsigsuboff_first[i], map) == CL_VIRUS) {
591 return CL_VIRUS;
592 }
593 }
594 }
595 return CL_CLEAN;
596}
597
598int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, unsigned char *refhash)
599{
600 unsigned char *buff;
601 int ret = CL_CLEAN, type = CL_CLEAN, bytes, compute_hash[CLI_HASH_AVAIL_TYPES];
602 unsigned int i = 0, bm_offmode = 0;
603 uint32_t maxpatlen, offset = 0;
604 struct cli_ac_data gdata, tdata;
605 struct cli_bm_off toff;
606 cli_md5_ctx md5ctx;
607 SHA256_CTX sha256ctx;
608 SHA1Context sha1ctx;
609 unsigned char digest[CLI_HASH_AVAIL_TYPES][32];
610 struct cli_matcher *groot = NULL, *troot = NULL;
611 struct cli_target_info info;
612 fmap_t *map = *ctx->fmap;
613 struct cli_matcher *hdb, *fp;
614
615 if(!ctx->engine) {
616 cli_errmsg("cli_scandesc: engine == NULL\n");
617 return CL_ENULLARG;
618 }
619
620 if(!ftonly)
621 groot = ctx->engine->root[0]; /* generic signatures */
622
623 if(ftype) {
624 for(i = 1; i < CLI_MTARGETS; i++) {
625 if(cli_mtargets[i].target == ftype) {
626 troot = ctx->engine->root[i];
627 break;
628 }
629 }
630 }
631
632 if(ftonly) {
633 if(!troot)
634 return CL_CLEAN;
635
636 maxpatlen = troot->maxpatlen;
637 } else {
638 if(troot)
639 maxpatlen = MAX(troot->maxpatlen, groot->maxpatlen);
640 else
641 maxpatlen = groot->maxpatlen;
642 }
643
644 targetinfo(&info, i, map);
645
646 if(!ftonly)
647 if((ret = cli_ac_initdata(&gdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)) || (ret = cli_ac_caloff(groot, &gdata, &info))) {
648 if(info.exeinfo.section)
649 free(info.exeinfo.section);
650 cli_hashset_destroy(&info.exeinfo.vinfo);
651 return ret;
652 }
653
654 if(troot) {
655 if((ret = cli_ac_initdata(&tdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)) || (ret = cli_ac_caloff(troot, &tdata, &info))) {
656 if(!ftonly)
657 cli_ac_freedata(&gdata);
658 if(info.exeinfo.section)
659 free(info.exeinfo.section);
660 cli_hashset_destroy(&info.exeinfo.vinfo);
661 return ret;
662 }
663 if(troot->bm_offmode) {
664 if(map->len >= CLI_DEFAULT_BM_OFFMODE_FSIZE) {
665 if((ret = cli_bm_initoff(troot, &toff, &info))) {
666 if(!ftonly)
667 cli_ac_freedata(&gdata);
668 cli_ac_freedata(&tdata);
669 if(info.exeinfo.section)
670 free(info.exeinfo.section);
671 cli_hashset_destroy(&info.exeinfo.vinfo);
672 return ret;
673 }
674 bm_offmode = 1;
675 }
676 }
677 }
678
679 hdb = ctx->engine->hm_hdb;
680 fp = ctx->engine->hm_fp;
681
682 if(!ftonly && hdb) {
683 if(!refhash) {
684 if(cli_hm_have_size(hdb, CLI_HASH_MD5, map->len) || cli_hm_have_size(fp, CLI_HASH_MD5, map->len)) {
685 cli_md5_init(&md5ctx);
686 compute_hash[CLI_HASH_MD5] = 1;
687 } else
688 compute_hash[CLI_HASH_MD5] = 0;
689 } else {
690 compute_hash[CLI_HASH_MD5] = 0;
691 memcpy(digest[CLI_HASH_MD5], refhash, 16);
692 }
693
694 if(cli_hm_have_size(hdb, CLI_HASH_SHA1, map->len) || cli_hm_have_size(fp, CLI_HASH_SHA1, map->len)) {
695 SHA1Init(&sha1ctx);
696 compute_hash[CLI_HASH_SHA1] = 1;
697 } else
698 compute_hash[CLI_HASH_SHA1] = 0;
699
700 if(cli_hm_have_size(hdb, CLI_HASH_SHA256, map->len) || cli_hm_have_size(fp, CLI_HASH_SHA256, map->len)) {
701 sha256_init(&sha256ctx);
702 compute_hash[CLI_HASH_SHA256] = 1;
703 } else
704 compute_hash[CLI_HASH_SHA256] = 0;
705 }
706
707 while(offset < map->len) {
708 bytes = MIN(map->len - offset, SCANBUFF);
709 if(!(buff = fmap_need_off_once(map, offset, bytes)))
710 break;
711 if(ctx->scanned)
712 *ctx->scanned += bytes / CL_COUNT_PRECISION;
713
714 if(troot) {
715 ret = matcher_run(troot, buff, bytes, ctx->virname, &tdata, offset, &info, ftype, ftoffset, acmode, acres, map, bm_offmode ? &toff : NULL);
716
717 if(ret == CL_VIRUS || ret == CL_EMEM) {
718 if(!ftonly)
719 cli_ac_freedata(&gdata);
720 cli_ac_freedata(&tdata);
721 if(bm_offmode)
722 cli_bm_freeoff(&toff);
723 if(info.exeinfo.section)
724 free(info.exeinfo.section);
725 cli_hashset_destroy(&info.exeinfo.vinfo);
726 return ret;
727 }
728 }
729
730 if(!ftonly) {
731 ret = matcher_run(groot, buff, bytes, ctx->virname, &gdata, offset, &info, ftype, ftoffset, acmode, acres, map, NULL);
732
733 if(ret == CL_VIRUS || ret == CL_EMEM) {
734 cli_ac_freedata(&gdata);
735 if(troot) {
736 cli_ac_freedata(&tdata);
737 if(bm_offmode)
738 cli_bm_freeoff(&toff);
739 }
740 if(info.exeinfo.section)
741 free(info.exeinfo.section);
742 cli_hashset_destroy(&info.exeinfo.vinfo);
743 return ret;
744 } else if((acmode & AC_SCAN_FT) && ret >= CL_TYPENO) {
745 if(ret > type)
746 type = ret;
747 }
748
749 if(hdb) {
750 void *data = buff + maxpatlen * (offset!=0);
751 uint32_t data_len = bytes - maxpatlen * (offset!=0);
752
753 if(compute_hash[CLI_HASH_MD5])
754 cli_md5_update(&md5ctx, data, data_len);
755 if(compute_hash[CLI_HASH_SHA1])
756 SHA1Update(&sha1ctx, data, data_len);
757 if(compute_hash[CLI_HASH_SHA256])
758 sha256_update(&sha256ctx, data, data_len);
759 }
760 }
761
762 if(bytes < SCANBUFF) break;
763 offset += bytes - maxpatlen;
764 }
765
766 if(!ftonly && hdb) {
767 enum CLI_HASH_TYPE hashtype;
768
769 if(compute_hash[CLI_HASH_MD5])
770 cli_md5_final(digest[CLI_HASH_MD5], &md5ctx);
771 if(refhash)
772 compute_hash[CLI_HASH_MD5] = 1;
773 if(compute_hash[CLI_HASH_SHA1])
774 SHA1Final(&sha1ctx, digest[CLI_HASH_SHA1]);
775 if(compute_hash[CLI_HASH_SHA256])
776 sha256_final(&sha256ctx, digest[CLI_HASH_SHA256]);
777
778 for(hashtype = CLI_HASH_MD5; hashtype < CLI_HASH_AVAIL_TYPES; hashtype++) {
779 if(compute_hash[hashtype] && (ret = cli_hm_scan(digest[hashtype], map->len, ctx->virname, hdb, hashtype)) == CL_VIRUS)
780 break;
781 }
782
783 if(ret == CL_VIRUS && fp) {
784 for(hashtype = CLI_HASH_MD5; hashtype < CLI_HASH_AVAIL_TYPES; hashtype++) {
785 if(compute_hash[hashtype] && cli_hm_scan(digest[hashtype], map->len, ctx->virname, fp, hashtype) == CL_VIRUS) {
786 ret = CL_CLEAN;
787 break;
788 }
789 }
790 }
791 }
792
793 if(troot) {
794 if(ret != CL_VIRUS)
795 ret = cli_lsig_eval(ctx, troot, &tdata, &info, refhash);
796 cli_ac_freedata(&tdata);
797 if(bm_offmode)
798 cli_bm_freeoff(&toff);
799 }
800
801 if(groot) {
802 if(ret != CL_VIRUS)
803 ret = cli_lsig_eval(ctx, groot, &gdata, &info, refhash);
804 cli_ac_freedata(&gdata);
805 }
806
807 if(info.exeinfo.section)
808 free(info.exeinfo.section);
809 cli_hashset_destroy(&info.exeinfo.vinfo);
810
811 if(ret == CL_VIRUS)
812 return CL_VIRUS;
813
814 return (acmode & AC_SCAN_FT) ? type : CL_CLEAN;
815}
816
817int cli_matchmeta(cli_ctx *ctx, const char *fname, size_t fsizec, size_t fsizer, int encrypted, int filepos, int res1, void *res2)
818{
819 const struct cli_cdb *cdb;
820
821 if(!(cdb = ctx->engine->cdb))
822 return CL_CLEAN;
823
824 do {
825 if(cdb->ctype != CL_TYPE_ANY && cdb->ctype != ctx->container_type)
826 continue;
827
828 if(cdb->encrypted != 2 && cdb->encrypted != encrypted)
829 continue;
830
831 if(cdb->res1 && (cdb->ctype == CL_TYPE_ZIP || cdb->ctype == CL_TYPE_RAR) && cdb->res1 != res1)
832 continue;
833
834#define CDBRANGE(field, val) \
835 if(field[0] != CLI_OFF_ANY) { \
836 if(field[0] == field[1] && field[0] != val) \
837 continue; \
838 else if(field[0] != field[1] && ((field[0] && field[0] > val) ||\
839 (field[1] && field[1] < val))) \
840 continue; \
841 }
842
843 CDBRANGE(cdb->csize, ctx->container_size);
844 CDBRANGE(cdb->fsizec, fsizec);
845 CDBRANGE(cdb->fsizer, fsizer);
846 CDBRANGE(cdb->filepos, filepos);
847
848 if(cdb->name.re_magic && (!fname || cli_regexec(&cdb->name, fname, 0, NULL, 0) == REG_NOMATCH))
849 continue;
850
851 *ctx->virname = cdb->virname;
852 return CL_VIRUS;
853
854 } while((cdb = cdb->next));
855
856 return CL_CLEAN;
857}
Note: See TracBrowser for help on using the repository browser.