35
34
#include "matcher-ac.h"
36
35
#include "matcher-bm.h"
40
37
#include "filetypes.h"
41
38
#include "matcher.h"
45
42
#include "special.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"
61
#ifdef CLI_PERF_LOGGING
63
static inline void PERF_LOG_FILTER(int32_t pos, int32_t length, int8_t trie)
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);
70
static inline int PERF_LOG_TRIES(int8_t acmode, int8_t bm_called, int32_t length)
73
cli_perf_log_add(BM_SCANNED, length);
75
cli_perf_log_add(AC_SCANNED, length);
80
static inline void PERF_LOG_FILTER(int32_t pos, uint32_t length, int8_t trie) {}
81
static inline int PERF_LOG_TRIES(int8_t acmode, int8_t bm_called, int32_t length) { return 0; }
46
#include "matcher-ncore.h"
84
static 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,
88
const struct cli_target_info *tinfo,
90
struct cli_matched_type **ftoffset,
92
struct cli_ac_result **acres,
94
struct cli_bm_off *offdata)
98
struct filter_match_info info;
99
uint32_t orig_length, orig_offset;
100
const unsigned char* orig_buffer;
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);
109
/* must not cut buffer for 64[4-4]6161, because we must be able to check
111
pos = info.first_match - root->maxpatlen - 1;
112
if (pos < 0) pos = 0;
113
PERF_LOG_FILTER(pos, length, root->type);
116
PERF_LOG_FILTER(0, length, root->type);
119
orig_length = length;
120
orig_buffer = buffer;
121
orig_offset = offset;
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
131
ret = cli_bm_scanbuff(orig_buffer, orig_length, virname, NULL, root, orig_offset, tinfo, offdata);
133
ret = cli_bm_scanbuff(buffer, length, virname, NULL, root, offset, tinfo, offdata);
138
PERF_LOG_TRIES(acmode, 0, length);
139
ret = cli_ac_scanbuff(buffer, length, virname, NULL, acres, root, mdata, offset, ftype, ftoffset, acmode, NULL);
143
int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset, cli_ctx *ctx, cli_file_t ftype, struct cli_ac_data **acdata)
49
static cli_file_t targettab[CL_TARGET_TABLE_SIZE] = { 0, CL_TYPE_MSEXE, CL_TYPE_MSOLE2, CL_TYPE_HTML, CL_TYPE_MAIL, CL_TYPE_GRAPHICS, CL_TYPE_ELF };
51
extern short cli_debug_flag;
53
int cli_scanbuff(const unsigned char *buffer, unsigned int length, const char **virname, const struct cl_engine *engine, cli_file_t ftype)
55
int ret = CL_CLEAN, i;
147
56
struct cli_ac_data mdata;
148
57
struct cli_matcher *groot, *troot = NULL;
149
const char **virname=ctx->virname;
150
const struct cl_engine *engine=ctx->engine;
153
61
cli_errmsg("cli_scanbuff: engine == NULL\n");
154
62
return CL_ENULLARG;
67
return cli_ncore_scanbuff(buffer, length, virname, engine, ftype, targettab);
157
70
groot = engine->root[0]; /* generic signatures */
160
for(i = 1; i < CLI_MTARGETS; i++) {
161
if(cli_mtargets[i].target == ftype) {
73
for(i = 1; i < CL_TARGET_TABLE_SIZE; i++) {
74
if(targettab[i] == ftype) {
162
75
troot = engine->root[i];
170
if(!acdata && (ret = cli_ac_initdata(&mdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
173
ret = matcher_run(troot, buffer, length, virname, acdata ? (acdata[0]): (&mdata), offset, NULL, ftype, NULL, AC_SCAN_VIR, NULL, *ctx->fmap, NULL);
176
cli_ac_freedata(&mdata);
178
if(ret == CL_VIRUS || ret == CL_EMEM)
182
if(!acdata && (ret = cli_ac_initdata(&mdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
185
ret = matcher_run(groot, buffer, length, virname, acdata ? (acdata[1]): (&mdata), offset, NULL, ftype, NULL, AC_SCAN_VIR, NULL, *ctx->fmap, NULL);
83
if((ret = cli_ac_initdata(&mdata, troot->ac_partsigs, AC_DEFAULT_TRACKLEN)))
86
if(troot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, troot, 0, ftype, -1)) != CL_VIRUS)
87
ret = cli_ac_scanbuff(buffer, length, virname, troot, &mdata, 0, 0, ftype, -1, NULL);
188
89
cli_ac_freedata(&mdata);
95
if((ret = cli_ac_initdata(&mdata, groot->ac_partsigs, AC_DEFAULT_TRACKLEN)))
98
if(groot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, groot, 0, ftype, -1)) != CL_VIRUS)
99
ret = cli_ac_scanbuff(buffer, length, virname, groot, &mdata, 0, 0, ftype, -1, NULL);
101
cli_ac_freedata(&mdata);
195
* offdata[1]: offset value
196
* offdata[2]: max shift
197
* offdata[3]: section number
199
int 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)
106
struct cli_md5_node *cli_vermd5(const unsigned char *md5, const struct cl_engine *engine)
108
struct cli_md5_node *pt;
111
if(!(pt = engine->md5_hlist[md5[0] & 0xff]))
115
if(!memcmp(pt->md5, md5, 16))
124
off_t cli_caloff(const char *offstr, struct cli_target_info *info, int fd, cli_file_t ftype, int *ret)
126
int (*einfo)(int, struct cli_exe_info *) = NULL;
202
127
unsigned int n, val;
205
if(!info) { /* decode offset string */
207
cli_errmsg("cli_caloff: offstr == NULL\n");
211
if(!strcmp(offstr, "*")) {
212
offdata[0] = *offset_max = *offset_min = CLI_OFF_ANY;
216
if(strlen(offstr) > 64) {
217
cli_errmsg("cli_caloff: Offset string too long\n");
220
strcpy(offcpy, offstr);
222
if((pt = strchr(offcpy, ','))) {
223
if(!cli_isnumber(pt + 1)) {
224
cli_errmsg("cli_caloff: Invalid offset shift value\n");
227
offdata[2] = atoi(pt + 1);
233
*offset_max = *offset_min = CLI_OFF_NONE;
235
if(!strncmp(offcpy, "EP+", 3) || !strncmp(offcpy, "EP-", 3)) {
237
offdata[0] = CLI_OFF_EP_PLUS;
239
offdata[0] = CLI_OFF_EP_MINUS;
241
if(!cli_isnumber(&offcpy[3])) {
242
cli_errmsg("cli_caloff: Invalid offset value\n");
245
offdata[1] = atoi(&offcpy[3]);
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");
254
offdata[1] = atoi(&offcpy[3]);
256
} else if(sscanf(offcpy, "S%u+%u", &n, &val) == 2) {
257
offdata[0] = CLI_OFF_SX_PLUS;
261
cli_errmsg("cli_caloff: Invalid offset string\n");
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");
271
offdata[1] = atoi(&offcpy[4]);
272
} else if(!strncmp(offcpy, "VI", 2)) {
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);
281
cli_errmsg("cli_caloff: at most 32 macro groups supported\n");
284
offdata[0] = CLI_OFF_MACRO;
287
offdata[0] = CLI_OFF_ABSOLUTE;
288
if(!cli_isnumber(offcpy)) {
289
cli_errmsg("cli_caloff: Invalid offset value\n");
292
*offset_min = offdata[1] = atoi(offcpy);
293
*offset_max = *offset_min + offdata[2];
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);
305
/* calculate relative offsets */
133
if(!strncmp(offstr, "EP", 2) || offstr[0] == 'S') {
306
135
if(info->status == -1) {
307
*offset_min = CLI_OFF_NONE;
309
*offset_max = CLI_OFF_NONE;
314
case CLI_OFF_EOF_MINUS:
315
*offset_min = info->fsize - offdata[1];
318
case CLI_OFF_EP_PLUS:
319
*offset_min = info->exeinfo.ep + offdata[1];
322
case CLI_OFF_EP_MINUS:
323
*offset_min = info->exeinfo.ep - offdata[1];
326
case CLI_OFF_SL_PLUS:
327
*offset_min = info->exeinfo.section[info->exeinfo.nsections - 1].raw + offdata[1];
330
case CLI_OFF_SX_PLUS:
331
if(offdata[3] >= info->exeinfo.nsections)
332
*offset_min = CLI_OFF_NONE;
334
*offset_min = info->exeinfo.section[offdata[3]].raw + offdata[1];
336
case CLI_OFF_VERSION:
337
*offset_min = *offset_max = CLI_OFF_ANY;
340
cli_errmsg("cli_caloff: Not a relative offset (type: %u)\n", offdata[0]);
345
if(*offset_min != CLI_OFF_NONE)
346
*offset_max = *offset_min + offdata[2];
348
*offset_max = CLI_OFF_NONE;
355
static void targetinfo(struct cli_target_info *info, unsigned int target, fmap_t *map)
357
int (*einfo)(fmap_t *, struct cli_exe_info *) = NULL;
360
memset(info, 0, sizeof(struct cli_target_info));
361
info->fsize = map->len;
362
cli_hashset_init_noalloc(&info->exeinfo.vinfo);
365
einfo = cli_peheader;
367
einfo = cli_elfheader;
369
einfo = cli_machoheader;
372
if(einfo(map, &info->exeinfo))
378
int cli_checkfp(unsigned char *digest, size_t size, cli_ctx *ctx)
387
uint8_t shash1[SHA1_HASH_SIZE*2+1];
388
uint8_t shash256[SHA256_HASH_SIZE*2+1];
389
int have_sha1, have_sha256;
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);
396
for(i = 0; i < 16; i++)
397
sprintf(md5 + i * 2, "%02x", digest[i]);
399
cli_dbgmsg("FP SIGNATURE: %s:%u:%s\n", md5, (unsigned int) size, *ctx->virname ? *ctx->virname : "Name");
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))) {
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);
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);
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))) {
430
sha256_init(&sha256);
431
sha256_update(&sha256, ptr, size);
432
sha256_final(&sha256, &shash256[SHA256_HASH_SIZE]);
434
for(i=0; i<SHA256_HASH_SIZE; i++)
435
sprintf((char *)shash256+i*2, "%02x", shash256[SHA256_HASH_SIZE+i]);
439
SHA1Update(&sha1, ptr, size);
440
SHA1Final(&sha1, &shash1[SHA1_HASH_SIZE]);
442
for(i=0; i<SHA1_HASH_SIZE; i++)
443
sprintf((char *)shash1+i*2, "%02x", shash1[SHA1_HASH_SIZE+i]);
445
cli_errmsg("COLLECT:%s:%s:%u:%s:%s\n", shash256, shash1, size, *ctx->virname, ctx->entry_filename);
447
cli_errmsg("can't compute sha\n!");
448
ctx->sha_collect = -1;
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);
458
static int matchicon(cli_ctx *ctx, struct cli_exe_info *exeinfo, const char *grp1, const char *grp2)
460
icon_groupset iconset;
464
!ctx->engine->iconcheck ||
465
!ctx->engine->iconcheck->group_counts[0] ||
466
!ctx->engine->iconcheck->group_counts[1] ||
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);
476
int32_t cli_bcapi_matchicon(struct cli_bc_ctx *ctx , const uint8_t* grp1, int32_t grp1len,
477
const uint8_t* grp2, int32_t grp2len)
480
char group1[128], group2[128];
481
const char **oldvirname;
482
struct cli_exe_info info;
484
if (!ctx->hooks.pedata->ep) {
485
cli_dbgmsg("bytecode: matchicon only works with PE files\n");
488
if ((size_t) grp1len > sizeof(group1)-1 ||
489
(size_t) grp2len > sizeof(group2)-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);
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)
139
} else if(!info->status) {
141
if(ftype == CL_TYPE_MSEXE)
142
einfo = cli_peheader;
143
else if(ftype == CL_TYPE_ELF)
144
einfo = cli_elfheader;
147
if((pos = lseek(fd, 0, SEEK_CUR)) == -1) {
148
cli_dbgmsg("Invalid descriptor\n");
149
info->status = *ret = -1;
153
lseek(fd, 0, SEEK_SET);
154
if(einfo(fd, &info->exeinfo)) {
155
lseek(fd, pos, SEEK_SET);
156
info->status = *ret = -1;
159
lseek(fd, pos, SEEK_SET);
165
if(isdigit(offstr[0])) {
168
} else if(info->status == 1 && (!strncmp(offstr, "EP+", 3) || !strncmp(offstr, "EP-", 3))) {
171
return info->exeinfo.ep + atoi(offstr + 3);
503
info.res_addr = le32_to_host(ctx->hooks.pedata->dirs[2].VirtualAddress);
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;
517
int 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)
519
int ret = CL_EMEM, empty;
520
fmap_t *map = *ctx->fmap;
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;
533
int cli_lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info, const char *hash)
535
unsigned int i, evalcnt;
537
fmap_t *map = *ctx->fmap;
539
for(i = 0; i < root->ac_lsigs; i++) {
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)
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))
549
if(root->ac_lsigtable[i]->tdb.ep || root->ac_lsigtable[i]->tdb.nos) {
550
if(!target_info || target_info->status != 1)
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))
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))
558
if(hash && root->ac_lsigtable[i]->tdb.handlertype) {
559
if(memcmp(ctx->handlertype_hash, hash, 16)) {
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) {
571
if(root->ac_lsigtable[i]->tdb.icongrp1 || root->ac_lsigtable[i]->tdb.icongrp2) {
572
if(!target_info || target_info->status != 1)
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) {
577
*ctx->virname = root->ac_lsigtable[i]->virname;
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) {
585
if(!root->ac_lsigtable[i]->bc_idx) {
587
*ctx->virname = root->ac_lsigtable[i]->virname;
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) {
598
int 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)
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;
173
return info->exeinfo.ep - atoi(offstr + 3);
175
} else if(info->status == 1 && offstr[0] == 'S') {
177
if(!strncmp(offstr, "SL", 2) && info->exeinfo.section[info->exeinfo.nsections - 1].rsz) {
179
if(sscanf(offstr, "SL+%u", &val) != 1) {
184
offset = val + info->exeinfo.section[info->exeinfo.nsections - 1].raw;
188
if(sscanf(offstr, "S%u+%u", &n, &val) != 2) {
193
if(n >= info->exeinfo.nsections || !info->exeinfo.section[n].rsz) {
198
offset = val + info->exeinfo.section[n].raw;
203
} else if(!strncmp(offstr, "EOF-", 4)) {
207
if(fstat(fd, &sb) == -1) {
208
info->status = *ret = -1;
211
info->fsize = sb.st_size;
214
return info->fsize - atoi(offstr + 4);
221
static int cli_checkfp(int fd, const struct cl_engine *engine)
223
struct cli_md5_node *md5_node;
224
unsigned char *digest;
227
if(engine->md5_hlist) {
229
if(!(digest = cli_md5digest(fd))) {
230
cli_errmsg("cli_checkfp(): Can't generate MD5 checksum\n");
234
if((md5_node = cli_vermd5(digest, engine)) && md5_node->fp) {
240
if((unsigned int) sb.st_size != md5_node->size) {
241
cli_warnmsg("Detected false positive MD5 match. Please report.\n");
243
cli_dbgmsg("Eliminated false positive match (fp sig: %s)\n", md5_node->virname);
255
int cli_validatesig(cli_file_t ftype, const char *offstr, off_t fileoff, struct cli_target_info *info, int desc, const char *virname)
261
if(offstr && desc != -1) {
262
offset = cli_caloff(offstr, info, desc, ftype, &ret);
265
cli_dbgmsg("cli_validatesig: Can't calculate offset for signature %s\n", virname);
269
if(fileoff != offset) {
270
cli_dbgmsg("Signature offset: %lu, expected: %lu (%s)\n", fileoff, offset, virname);
278
int cli_scandesc(int desc, cli_ctx *ctx, unsigned short otfrec, cli_file_t ftype, unsigned short ftonly, struct cli_matched_type **ftoffset)
280
unsigned char *buffer, *buff, *endbl, *upt;
281
int ret = CL_CLEAN, type = CL_CLEAN, i, bytes;
282
unsigned int buffersize, length, maxpatlen, shift = 0;
283
unsigned long int offset = 0;
604
284
struct cli_ac_data gdata, tdata;
605
struct cli_bm_off toff;
606
285
cli_md5_ctx md5ctx;
607
SHA256_CTX sha256ctx;
609
unsigned char digest[CLI_HASH_AVAIL_TYPES][32];
286
unsigned char digest[16];
287
struct cli_md5_node *md5_node;
610
288
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;
615
291
if(!ctx->engine) {
616
292
cli_errmsg("cli_scandesc: engine == NULL\n");
617
293
return CL_ENULLARG;
297
if(ctx->engine->ncore) {
300
ret = cli_ncore_scandesc(desc, ctx, ftype, &cont, targettab, &md5ctx);
621
307
groot = ctx->engine->root[0]; /* generic signatures */
624
for(i = 1; i < CLI_MTARGETS; i++) {
625
if(cli_mtargets[i].target == ftype) {
310
for(i = 1; i < CL_TARGET_TABLE_SIZE; i++) {
311
if(targettab[i] == ftype) {
626
312
troot = ctx->engine->root[i];
641
327
maxpatlen = groot->maxpatlen;
644
targetinfo(&info, i, map);
330
/* prepare the buffer */
331
buffersize = maxpatlen + SCANBUFF;
332
if(!(buffer = (unsigned char *) cli_calloc(buffersize, sizeof(unsigned char)))) {
333
cli_dbgmsg("cli_scandesc(): unable to cli_calloc(%u)\n", buffersize);
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);
337
if(!ftonly && (ret = cli_ac_initdata(&gdata, groot->ac_partsigs, AC_DEFAULT_TRACKLEN)))
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))) {
657
cli_ac_freedata(&gdata);
658
if(info.exeinfo.section)
659
free(info.exeinfo.section);
660
cli_hashset_destroy(&info.exeinfo.vinfo);
341
if((ret = cli_ac_initdata(&tdata, troot->ac_partsigs, AC_DEFAULT_TRACKLEN)))
663
if(troot->bm_offmode) {
664
if(map->len >= CLI_DEFAULT_BM_OFFMODE_FSIZE) {
665
if((ret = cli_bm_initoff(troot, &toff, &info))) {
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);
679
hdb = ctx->engine->hm_hdb;
680
fp = ctx->engine->hm_fp;
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;
688
compute_hash[CLI_HASH_MD5] = 0;
690
compute_hash[CLI_HASH_MD5] = 0;
691
memcpy(digest[CLI_HASH_MD5], refhash, 16);
694
if(cli_hm_have_size(hdb, CLI_HASH_SHA1, map->len) || cli_hm_have_size(fp, CLI_HASH_SHA1, map->len)) {
696
compute_hash[CLI_HASH_SHA1] = 1;
698
compute_hash[CLI_HASH_SHA1] = 0;
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;
704
compute_hash[CLI_HASH_SHA256] = 0;
707
while(offset < map->len) {
708
bytes = MIN(map->len - offset, SCANBUFF);
709
if(!(buff = fmap_need_off_once(map, offset, bytes)))
345
if(!ftonly && ctx->engine->md5_hlist)
346
cli_md5_init(&md5ctx);
349
buff += maxpatlen; /* pointer to read data block */
350
endbl = buff + SCANBUFF - maxpatlen; /* pointer to the last block
351
* length of maxpatlen
355
while((bytes = cli_readn(desc, buff + shift, SCANBUFF - shift)) > 0) {
712
358
*ctx->scanned += bytes / CL_COUNT_PRECISION;
360
length = shift + bytes;
715
ret = matcher_run(troot, buff, bytes, ctx->virname, &tdata, offset, &info, ftype, ftoffset, acmode, acres, map, bm_offmode ? &toff : NULL);
365
if(troot->ac_only || (ret = cli_bm_scanbuff(upt, length, ctx->virname, troot, offset, ftype, desc)) != CL_VIRUS)
366
ret = cli_ac_scanbuff(upt, length, ctx->virname, troot, &tdata, otfrec, offset, ftype, desc, ftoffset);
717
if(ret == CL_VIRUS || ret == CL_EMEM) {
368
if(ret == CL_VIRUS) {
719
371
cli_ac_freedata(&gdata);
720
372
cli_ac_freedata(&tdata);
722
cli_bm_freeoff(&toff);
723
if(info.exeinfo.section)
724
free(info.exeinfo.section);
725
cli_hashset_destroy(&info.exeinfo.vinfo);
374
lseek(desc, 0, SEEK_SET);
375
if(cli_checkfp(desc, ctx->engine))
731
ret = matcher_run(groot, buff, bytes, ctx->virname, &gdata, offset, &info, ftype, ftoffset, acmode, acres, map, NULL);
383
if(groot->ac_only || (ret = cli_bm_scanbuff(upt, length, ctx->virname, groot, offset, ftype, desc)) != CL_VIRUS)
384
ret = cli_ac_scanbuff(upt, length, ctx->virname, groot, &gdata, otfrec, offset, ftype, desc, ftoffset);
733
if(ret == CL_VIRUS || ret == CL_EMEM) {
386
if(ret == CL_VIRUS) {
734
388
cli_ac_freedata(&gdata);
736
390
cli_ac_freedata(&tdata);
738
cli_bm_freeoff(&toff);
740
if(info.exeinfo.section)
741
free(info.exeinfo.section);
742
cli_hashset_destroy(&info.exeinfo.vinfo);
744
} else if((acmode & AC_SCAN_FT) && ret >= CL_TYPENO) {
391
lseek(desc, 0, SEEK_SET);
392
if(cli_checkfp(desc, ctx->engine))
397
} else if(otfrec && ret >= CL_TYPENO) {
750
void *data = buff + maxpatlen * (offset!=0);
751
uint32_t data_len = bytes - maxpatlen * (offset!=0);
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);
762
if(bytes < SCANBUFF) break;
763
offset += bytes - maxpatlen;
767
enum CLI_HASH_TYPE hashtype;
769
if(compute_hash[CLI_HASH_MD5])
770
cli_md5_final(digest[CLI_HASH_MD5], &md5ctx);
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]);
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)
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) {
795
ret = cli_lsig_eval(ctx, troot, &tdata, &info, refhash);
402
if(ctx->engine->md5_hlist)
403
cli_md5_update(&md5ctx, buff + shift, bytes);
406
if(bytes + shift == SCANBUFF) {
407
memmove(buffer, endbl, maxpatlen);
425
cli_ac_freedata(&gdata);
796
427
cli_ac_freedata(&tdata);
798
cli_bm_freeoff(&toff);
803
ret = cli_lsig_eval(ctx, groot, &gdata, &info, refhash);
804
cli_ac_freedata(&gdata);
807
if(info.exeinfo.section)
808
free(info.exeinfo.section);
809
cli_hashset_destroy(&info.exeinfo.vinfo);
814
return (acmode & AC_SCAN_FT) ? type : CL_CLEAN;
817
int cli_matchmeta(cli_ctx *ctx, const char *fname, size_t fsizec, size_t fsizer, int encrypted, int filepos, int res1, void *res2)
819
const struct cli_cdb *cdb;
821
if(!(cdb = ctx->engine->cdb))
825
if(cdb->ctype != CL_TYPE_ANY && cdb->ctype != ctx->container_type)
828
if(cdb->encrypted != 2 && cdb->encrypted != encrypted)
831
if(cdb->res1 && (cdb->ctype == CL_TYPE_ZIP || cdb->ctype == CL_TYPE_RAR) && cdb->res1 != res1)
834
#define CDBRANGE(field, val) \
835
if(field[0] != CLI_OFF_ANY) { \
836
if(field[0] == field[1] && field[0] != val) \
838
else if(field[0] != field[1] && ((field[0] && field[0] > val) ||\
839
(field[1] && field[1] < val))) \
429
if(!ftonly && ctx->engine->md5_hlist) {
430
cli_md5_final(digest, &md5ctx);
432
if((md5_node = cli_vermd5(digest, ctx->engine)) && !md5_node->fp) {
438
if((unsigned int) sb.st_size != md5_node->size) {
439
cli_warnmsg("Detected false positive MD5 match. Please report.\n");
442
*ctx->virname = md5_node->virname;
843
CDBRANGE(cdb->csize, ctx->container_size);
844
CDBRANGE(cdb->fsizec, fsizec);
845
CDBRANGE(cdb->fsizer, fsizer);
846
CDBRANGE(cdb->filepos, filepos);
848
if(cdb->name.re_magic && (!fname || cli_regexec(&cdb->name, fname, 0, NULL, 0) == REG_NOMATCH))
851
*ctx->virname = cdb->virname;
854
} while((cdb = cdb->next));
449
return otfrec ? type : CL_CLEAN;