1 /*
2 * Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
3 * Copyright (C) 2007-2013 Sourcefire, Inc.
4 *
5 * Authors: Tomasz Kojm
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21
22 #if HAVE_CONFIG_H
23 #include "clamav-config.h"
24 #endif
25
26 #include <string.h>
27 #include <ctype.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33 #include <stdbool.h>
34
35 #include "clamav.h"
36 #include "others.h"
37 #include "matcher-ac.h"
38 #include "matcher-bm.h"
39 #include "matcher-pcre.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 "default.h"
49 #include "macho.h"
50 #include "fmap.h"
51 #include "pe_icons.h"
52 #include "regex/regex.h"
53 #include "filtering.h"
54 #include "perflogging.h"
55 #include "bytecode_priv.h"
56 #include "bytecode_api_impl.h"
57 #ifdef HAVE_YARA
58 #include "yara_clam.h"
59 #include "yara_exec.h"
60 #endif
61
62 #ifdef CLI_PERF_LOGGING
63
perf_log_filter(int32_t pos,int32_t length,int8_t trie)64 static inline void perf_log_filter(int32_t pos, int32_t length, int8_t trie)
65 {
66 cli_perf_log_add(RAW_BYTES_SCANNED, length);
67 cli_perf_log_add(FILTER_BYTES_SCANNED, length - pos);
68 cli_perf_log_count2(TRIE_SCANNED, trie, length - pos);
69 }
70
perf_log_tries(int8_t acmode,int8_t bm_called,int32_t length)71 static inline int perf_log_tries(int8_t acmode, int8_t bm_called, int32_t length)
72 {
73 if (bm_called)
74 cli_perf_log_add(BM_SCANNED, length);
75 if (acmode)
76 cli_perf_log_add(AC_SCANNED, length);
77 return 0;
78 }
79
80 #else
perf_log_filter(int32_t pos,uint32_t length,int8_t trie)81 static inline void perf_log_filter(int32_t pos, uint32_t length, int8_t trie)
82 {
83 UNUSEDPARAM(pos);
84 UNUSEDPARAM(length);
85 UNUSEDPARAM(trie);
86 }
87
perf_log_tries(int8_t acmode,int8_t bm_called,int32_t length)88 static inline int perf_log_tries(int8_t acmode, int8_t bm_called, int32_t length)
89 {
90 UNUSEDPARAM(acmode);
91 UNUSEDPARAM(bm_called);
92 UNUSEDPARAM(length);
93
94 return 0;
95 }
96 #endif
97
matcher_run(const struct cli_matcher * root,const unsigned char * buffer,uint32_t length,const char ** virname,struct cli_ac_data * mdata,uint32_t offset,const struct cli_target_info * tinfo,cli_file_t ftype,struct cli_matched_type ** ftoffset,unsigned int acmode,unsigned int pcremode,struct cli_ac_result ** acres,fmap_t * map,struct cli_bm_off * offdata,struct cli_pcre_off * poffdata,cli_ctx * ctx)98 static inline cl_error_t matcher_run(const struct cli_matcher *root,
99 const unsigned char *buffer, uint32_t length,
100 const char **virname, struct cli_ac_data *mdata,
101 uint32_t offset,
102 const struct cli_target_info *tinfo,
103 cli_file_t ftype,
104 struct cli_matched_type **ftoffset,
105 unsigned int acmode,
106 unsigned int pcremode,
107 struct cli_ac_result **acres,
108 fmap_t *map,
109 struct cli_bm_off *offdata,
110 struct cli_pcre_off *poffdata,
111 cli_ctx *ctx)
112 {
113 cl_error_t ret, saved_ret = CL_CLEAN;
114 int32_t pos = 0;
115 struct filter_match_info info;
116 uint32_t orig_length, orig_offset;
117 const unsigned char *orig_buffer;
118 unsigned int viruses_found = 0;
119
120 if (root->filter) {
121 if (filter_search_ext(root->filter, buffer, length, &info) == -1) {
122 /* for safety always scan last maxpatlen bytes */
123 pos = length - root->maxpatlen - 1;
124 if (pos < 0) pos = 0;
125 perf_log_filter(pos, length, root->type);
126 } else {
127 /* must not cut buffer for 64[4-4]6161, because we must be able to check
128 * 64! */
129 pos = info.first_match - root->maxpatlen - 1;
130 if (pos < 0) pos = 0;
131 perf_log_filter(pos, length, root->type);
132 }
133 } else {
134 perf_log_filter(0, length, root->type);
135 }
136
137 orig_length = length;
138 orig_buffer = buffer;
139 orig_offset = offset;
140 length -= pos;
141 buffer += pos;
142 offset += pos;
143 if (!root->ac_only) {
144 perf_log_tries(0, 1, length);
145 if (root->bm_offmode) {
146 /* Don't use prefiltering for BM offset mode, since BM keeps tracks
147 * of offsets itself, and doesn't work if we skip chunks of input
148 * data */
149 ret = cli_bm_scanbuff(orig_buffer, orig_length, virname, NULL, root, orig_offset, tinfo, offdata, ctx);
150 } else {
151 ret = cli_bm_scanbuff(buffer, length, virname, NULL, root, offset, tinfo, offdata, ctx);
152 }
153 if (ret != CL_CLEAN) {
154 if (ret != CL_VIRUS)
155 return ret;
156
157 /* else (ret == CL_VIRUS) */
158 if (SCAN_ALLMATCHES)
159 viruses_found = 1;
160 else {
161 ret = cli_append_virus(ctx, *virname);
162 if (ret != CL_CLEAN)
163 return ret;
164 }
165 }
166 }
167 perf_log_tries(acmode, 0, length);
168 ret = cli_ac_scanbuff(buffer, length, virname, NULL, acres, root, mdata, offset, ftype, ftoffset, acmode, ctx);
169 if (ret != CL_CLEAN) {
170 if (ret == CL_VIRUS) {
171 if (SCAN_ALLMATCHES)
172 viruses_found = 1;
173 else {
174 ret = cli_append_virus(ctx, *virname);
175 if (ret != CL_CLEAN)
176 return ret;
177 }
178 } else if (ret > CL_TYPENO && acmode & AC_SCAN_VIR)
179 saved_ret = ret;
180 else
181 return ret;
182 }
183
184 if (root->bcomp_metas) {
185 ret = cli_bcomp_scanbuf(orig_buffer, orig_length, virname, acres, root, mdata, ctx);
186 if (ret != CL_CLEAN) {
187 if (ret == CL_VIRUS) {
188 if (SCAN_ALLMATCHES)
189 viruses_found = 1;
190 else {
191 ret = cli_append_virus(ctx, *virname);
192 if (ret != CL_CLEAN)
193 return ret;
194 }
195 } else if (ret > CL_TYPENO && acmode & AC_SCAN_VIR)
196 saved_ret = ret;
197 else
198 return ret;
199 }
200 }
201
202 /* due to logical triggered, pcres cannot be evaluated until after full subsig matching */
203 /* cannot save pcre execution state without possible evasion; must scan entire buffer */
204 /* however, scanning the whole buffer may require the whole buffer being loaded into memory */
205 #if HAVE_PCRE
206 if (root->pcre_metas) {
207 int rc;
208 uint64_t maxfilesize;
209
210 if (map && (pcremode == PCRE_SCAN_FMAP)) {
211 if (offset + length >= map->len) {
212 /* check that scanned map does not exceed pcre maxfilesize limit */
213 maxfilesize = (uint64_t)cl_engine_get_num(ctx->engine, CL_ENGINE_PCRE_MAX_FILESIZE, &rc);
214 if (rc != CL_SUCCESS)
215 return rc;
216 if (maxfilesize && (map->len > maxfilesize)) {
217 cli_dbgmsg("matcher_run: pcre max filesize (map) exceeded (limit: %llu, needed: %llu)\n",
218 (long long unsigned)maxfilesize, (long long unsigned)map->len);
219 return CL_EMAXSIZE;
220 }
221
222 cli_dbgmsg("matcher_run: performing regex matching on full map: %u+%u(%u) >= %zu\n", offset, length, offset + length, map->len);
223
224 buffer = fmap_need_off_once(map, 0, map->len);
225 if (!buffer)
226 return CL_EMEM;
227
228 /* scan the full buffer */
229 ret = cli_pcre_scanbuf(buffer, map->len, virname, acres, root, mdata, poffdata, ctx);
230 }
231 } else if (pcremode == PCRE_SCAN_BUFF) {
232 /* check that scanned buffer does not exceed pcre maxfilesize limit */
233 maxfilesize = (uint64_t)cl_engine_get_num(ctx->engine, CL_ENGINE_PCRE_MAX_FILESIZE, &rc);
234 if (rc != CL_SUCCESS)
235 return rc;
236 if (maxfilesize && (length > maxfilesize)) {
237 cli_dbgmsg("matcher_run: pcre max filesize (buf) exceeded (limit: %llu, needed: %u)\n", (long long unsigned)maxfilesize, length);
238 return CL_EMAXSIZE;
239 }
240
241 cli_dbgmsg("matcher_run: performing regex matching on buffer with no map: %u+%u(%u)\n", offset, length, offset + length);
242 /* scan the specified buffer */
243 ret = cli_pcre_scanbuf(buffer, length, virname, acres, root, mdata, poffdata, ctx);
244 }
245 }
246 #endif /* HAVE_PCRE */
247 /* end experimental fragment */
248
249 if (ctx && !SCAN_ALLMATCHES && ret == CL_VIRUS) {
250 return cli_append_virus(ctx, *virname);
251 }
252 if (ctx && SCAN_ALLMATCHES && viruses_found) {
253 return CL_VIRUS;
254 }
255 if (saved_ret && ret == CL_CLEAN) {
256 return saved_ret;
257 }
258
259 return ret;
260 }
261
cli_scan_buff(const unsigned char * buffer,uint32_t length,uint32_t offset,cli_ctx * ctx,cli_file_t ftype,struct cli_ac_data ** acdata)262 cl_error_t cli_scan_buff(const unsigned char *buffer, uint32_t length, uint32_t offset, cli_ctx *ctx, cli_file_t ftype, struct cli_ac_data **acdata)
263 {
264 cl_error_t ret = CL_CLEAN;
265 unsigned int i = 0, j = 0, viruses_found = 0;
266 struct cli_ac_data mdata;
267 struct cli_matcher *groot, *troot = NULL;
268 const char *virname = NULL;
269 const struct cl_engine *engine = ctx->engine;
270
271 if (!engine) {
272 cli_errmsg("cli_scan_buff: engine == NULL\n");
273 return CL_ENULLARG;
274 }
275
276 groot = engine->root[0]; /* generic signatures */
277
278 if (ftype) {
279 for (i = 1; i < CLI_MTARGETS; i++) {
280 for (j = 0; j < cli_mtargets[i].target_count; ++j) {
281 if (cli_mtargets[i].target[j] == ftype) {
282 troot = ctx->engine->root[i];
283 break;
284 }
285 }
286 if (troot) break;
287 }
288 }
289
290 if (troot) {
291
292 if (!acdata && (ret = cli_ac_initdata(&mdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
293 return ret;
294
295 ret = matcher_run(troot, buffer, length, &virname, acdata ? (acdata[0]) : (&mdata), offset, NULL, ftype, NULL, AC_SCAN_VIR, PCRE_SCAN_BUFF, NULL, ctx->fmap, NULL, NULL, ctx);
296
297 if (!acdata)
298 cli_ac_freedata(&mdata);
299
300 if (ret == CL_EMEM)
301 return ret;
302 if (ret == CL_VIRUS) {
303 viruses_found = 1;
304 if (ctx && !SCAN_ALLMATCHES) {
305 return ret;
306 }
307 }
308 }
309
310 virname = NULL;
311
312 if (!acdata && (ret = cli_ac_initdata(&mdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
313 return ret;
314
315 ret = matcher_run(groot, buffer, length, &virname, acdata ? (acdata[1]) : (&mdata), offset, NULL, ftype, NULL, AC_SCAN_VIR, PCRE_SCAN_BUFF, NULL, ctx->fmap, NULL, NULL, ctx);
316
317 if (!acdata)
318 cli_ac_freedata(&mdata);
319
320 if (viruses_found)
321 return CL_VIRUS;
322 return ret;
323 }
324
325 /*
326 * offdata[0]: type
327 * offdata[1]: offset value
328 * offdata[2]: max shift
329 * offdata[3]: section number
330 */
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)331 cl_error_t 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)
332 {
333 char offcpy[65];
334 unsigned int n, val;
335 char *pt;
336
337 if (!info) { /* decode offset string */
338 if (!offstr) {
339 cli_errmsg("cli_caloff: offstr == NULL\n");
340 return CL_ENULLARG;
341 }
342
343 if (!strcmp(offstr, "*")) {
344 offdata[0] = *offset_max = *offset_min = CLI_OFF_ANY;
345 return CL_SUCCESS;
346 }
347
348 if (strlen(offstr) > 64) {
349 cli_errmsg("cli_caloff: Offset string too long\n");
350 return CL_EMALFDB;
351 }
352 strcpy(offcpy, offstr);
353
354 if ((pt = strchr(offcpy, ','))) {
355 if (!cli_isnumber(pt + 1)) {
356 cli_errmsg("cli_caloff: Invalid offset shift value\n");
357 return CL_EMALFDB;
358 }
359 offdata[2] = atoi(pt + 1);
360 *pt = 0;
361 } else {
362 offdata[2] = 0;
363 }
364
365 *offset_max = *offset_min = CLI_OFF_NONE;
366
367 if (!strncmp(offcpy, "EP+", 3) || !strncmp(offcpy, "EP-", 3)) {
368 if (offcpy[2] == '+')
369 offdata[0] = CLI_OFF_EP_PLUS;
370 else
371 offdata[0] = CLI_OFF_EP_MINUS;
372
373 if (!cli_isnumber(&offcpy[3])) {
374 cli_errmsg("cli_caloff: Invalid offset value\n");
375 return CL_EMALFDB;
376 }
377 offdata[1] = atoi(&offcpy[3]);
378
379 } else if (offcpy[0] == 'S') {
380 if (offcpy[1] == 'E') {
381 if (!cli_isnumber(&offcpy[2])) {
382 cli_errmsg("cli_caloff: Invalid section number\n");
383 return CL_EMALFDB;
384 }
385 offdata[0] = CLI_OFF_SE;
386 offdata[3] = atoi(&offcpy[2]);
387
388 } else if (!strncmp(offstr, "SL+", 3)) {
389 offdata[0] = CLI_OFF_SL_PLUS;
390 if (!cli_isnumber(&offcpy[3])) {
391 cli_errmsg("cli_caloff: Invalid offset value\n");
392 return CL_EMALFDB;
393 }
394 offdata[1] = atoi(&offcpy[3]);
395
396 } else if (sscanf(offcpy, "S%u+%u", &n, &val) == 2) {
397 offdata[0] = CLI_OFF_SX_PLUS;
398 offdata[1] = val;
399 offdata[3] = n;
400 } else {
401 cli_errmsg("cli_caloff: Invalid offset string\n");
402 return CL_EMALFDB;
403 }
404
405 } else if (!strncmp(offcpy, "EOF-", 4)) {
406 offdata[0] = CLI_OFF_EOF_MINUS;
407 if (!cli_isnumber(&offcpy[4])) {
408 cli_errmsg("cli_caloff: Invalid offset value\n");
409 return CL_EMALFDB;
410 }
411 offdata[1] = atoi(&offcpy[4]);
412 } else if (!strncmp(offcpy, "VI", 2)) {
413 /* versioninfo */
414 offdata[0] = CLI_OFF_VERSION;
415 } else if (strchr(offcpy, '$')) {
416 if (sscanf(offcpy, "$%u$", &n) != 1) {
417 cli_errmsg("cli_caloff: Invalid macro($) in offset: %s\n", offcpy);
418 return CL_EMALFDB;
419 }
420 if (n >= 32) {
421 cli_errmsg("cli_caloff: at most 32 macro groups supported\n");
422 return CL_EMALFDB;
423 }
424 offdata[0] = CLI_OFF_MACRO;
425 offdata[1] = n;
426 } else {
427 offdata[0] = CLI_OFF_ABSOLUTE;
428 if (!cli_isnumber(offcpy)) {
429 cli_errmsg("cli_caloff: Invalid offset value\n");
430 return CL_EMALFDB;
431 }
432 *offset_min = offdata[1] = atoi(offcpy);
433 *offset_max = *offset_min + offdata[2];
434 }
435
436 if (offdata[0] != CLI_OFF_ANY && offdata[0] != CLI_OFF_ABSOLUTE &&
437 offdata[0] != CLI_OFF_EOF_MINUS && offdata[0] != CLI_OFF_MACRO) {
438 if (target != 1 && target != 6 && target != 9) {
439 cli_errmsg("cli_caloff: Invalid offset type for target %u\n", target);
440 return CL_EMALFDB;
441 }
442 }
443
444 } else {
445 /* calculate relative offsets */
446 *offset_min = CLI_OFF_NONE;
447 if (offset_max)
448 *offset_max = CLI_OFF_NONE;
449 if (info->status == -1) {
450 // If the executable headers weren't parsed successfully then we
451 // can't process any ndb/ldb EOF-n/EP+n/EP-n/Sx+n/SEx/SL+n subsigs
452 return CL_SUCCESS;
453 }
454
455 switch (offdata[0]) {
456 case CLI_OFF_EOF_MINUS:
457 *offset_min = info->fsize - offdata[1];
458 break;
459
460 case CLI_OFF_EP_PLUS:
461 *offset_min = info->exeinfo.ep + offdata[1];
462 break;
463
464 case CLI_OFF_EP_MINUS:
465 *offset_min = info->exeinfo.ep - offdata[1];
466 break;
467
468 case CLI_OFF_SL_PLUS:
469 *offset_min = info->exeinfo.sections[info->exeinfo.nsections - 1].raw + offdata[1];
470 break;
471
472 case CLI_OFF_SX_PLUS:
473 if (offdata[3] >= info->exeinfo.nsections)
474 *offset_min = CLI_OFF_NONE;
475 else
476 *offset_min = info->exeinfo.sections[offdata[3]].raw + offdata[1];
477 break;
478
479 case CLI_OFF_SE:
480 if (offdata[3] >= info->exeinfo.nsections) {
481 *offset_min = CLI_OFF_NONE;
482 } else {
483 *offset_min = info->exeinfo.sections[offdata[3]].raw;
484 if (offset_max)
485 *offset_max = *offset_min + info->exeinfo.sections[offdata[3]].rsz + offdata[2];
486 // TODO offdata[2] == MaxShift. Won't this make offset_max
487 // extend beyond the end of the section? This doesn't seem like
488 // what we want...
489 }
490 break;
491
492 case CLI_OFF_VERSION:
493 if (offset_max)
494 *offset_min = *offset_max = CLI_OFF_ANY;
495 break;
496 default:
497 cli_errmsg("cli_caloff: Not a relative offset (type: %u)\n", offdata[0]);
498 return CL_EARG;
499 }
500
501 if (offset_max && *offset_max == CLI_OFF_NONE && *offset_min != CLI_OFF_NONE)
502 *offset_max = *offset_min + offdata[2];
503 }
504
505 return CL_SUCCESS;
506 }
507
cli_targetinfo_init(struct cli_target_info * info)508 void cli_targetinfo_init(struct cli_target_info *info)
509 {
510
511 if (NULL == info) {
512 return;
513 }
514 info->status = 0;
515 cli_exe_info_init(&(info->exeinfo), 0);
516 }
517
cli_targetinfo(struct cli_target_info * info,unsigned int target,cli_ctx * ctx)518 void cli_targetinfo(struct cli_target_info *info, unsigned int target, cli_ctx *ctx)
519 {
520 int (*einfo)(cli_ctx *, struct cli_exe_info *) = NULL;
521
522 info->fsize = ctx->fmap->len;
523
524 if (target == 1)
525 einfo = cli_pe_targetinfo;
526 else if (target == 6)
527 einfo = cli_elfheader;
528 else if (target == 9)
529 einfo = cli_machoheader;
530 else
531 return;
532
533 if (einfo(ctx, &info->exeinfo))
534 info->status = -1;
535 else
536 info->status = 1;
537 }
538
cli_targetinfo_destroy(struct cli_target_info * info)539 void cli_targetinfo_destroy(struct cli_target_info *info)
540 {
541
542 if (NULL == info) {
543 return;
544 }
545
546 cli_exe_info_destroy(&(info->exeinfo));
547 info->status = 0;
548 }
549
cli_check_fp(cli_ctx * ctx,const char * vname)550 cl_error_t cli_check_fp(cli_ctx *ctx, const char *vname)
551 {
552 cl_error_t status = CL_VIRUS;
553 char md5[33];
554 unsigned int i;
555 const char *virname = NULL;
556 fmap_t *map;
557 int32_t stack_index;
558 const char *ptr;
559 uint8_t shash1[SHA1_HASH_SIZE * 2 + 1];
560 uint8_t shash256[SHA256_HASH_SIZE * 2 + 1];
561 int have_sha1, have_sha256;
562 unsigned char *digest;
563 size_t size;
564
565 stack_index = (int32_t)ctx->recursion_level;
566
567 while (stack_index >= 0) {
568 map = ctx->recursion_stack[stack_index].fmap;
569
570 if (CL_SUCCESS != fmap_get_MD5(map, &digest)) {
571 cli_dbgmsg("cli_check_fp: Failed to get a hash for the map at stack index # %u\n", stack_index);
572 stack_index--;
573 continue;
574 }
575 size = map->len;
576
577 /*
578 * First, check the MD5 digest.
579 * MD5 is default, so it always exists.
580 */
581 if (cli_hm_scan(digest, size, &virname, ctx->engine->hm_fp, CLI_HASH_MD5) == CL_VIRUS) {
582 cli_dbgmsg("cli_check_fp(md5): Found false positive detection (fp sig: %s), size: %d\n", virname, (int)size);
583 return CL_CLEAN;
584 } else if (cli_hm_scan_wild(digest, &virname, ctx->engine->hm_fp, CLI_HASH_MD5) == CL_VIRUS) {
585 cli_dbgmsg("cli_check_fp(md5): Found false positive detection (fp sig: %s), size: *\n", virname);
586 return CL_CLEAN;
587 }
588
589 if (cli_debug_flag || ctx->engine->cb_hash) {
590 const char *name = ctx->recursion_stack[stack_index].fmap->name;
591 const char *type = cli_ftname(ctx->recursion_stack[stack_index].type);
592
593 for (i = 0; i < 16; i++)
594 sprintf(md5 + i * 2, "%02x", digest[i]);
595 md5[32] = 0;
596
597 cli_dbgmsg("FP SIGNATURE: %s:%u:%s # Name: %s, Type: %s\n",
598 md5, (unsigned int)size, vname ? vname : "Name", name ? name : "n/a", type);
599 }
600
601 have_sha1 = cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, size) || cli_hm_have_wild(ctx->engine->hm_fp, CLI_HASH_SHA1) || cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, 1);
602 have_sha256 = cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA256, size) || cli_hm_have_wild(ctx->engine->hm_fp, CLI_HASH_SHA256);
603 if (have_sha1 || have_sha256) {
604 if ((ptr = fmap_need_off_once(map, 0, size))) {
605 if (have_sha1) {
606 cl_sha1(ptr, size, &shash1[SHA1_HASH_SIZE], NULL);
607
608 if (cli_hm_scan(&shash1[SHA1_HASH_SIZE], size, &virname, ctx->engine->hm_fp, CLI_HASH_SHA1) == CL_VIRUS) {
609 cli_dbgmsg("cli_check_fp(sha1): Found false positive detection (fp sig: %s)\n", virname);
610 return CL_CLEAN;
611 }
612 if (cli_hm_scan_wild(&shash1[SHA1_HASH_SIZE], &virname, ctx->engine->hm_fp, CLI_HASH_SHA1) == CL_VIRUS) {
613 cli_dbgmsg("cli_check_fp(sha1): Found false positive detection (fp sig: %s)\n", virname);
614 return CL_CLEAN;
615 }
616 /* See whether the hash matches those loaded in from .cat files
617 * (associated with the .CAB file type) */
618 if (cli_hm_scan(&shash1[SHA1_HASH_SIZE], 1, &virname, ctx->engine->hm_fp, CLI_HASH_SHA1) == CL_VIRUS) {
619 cli_dbgmsg("cli_check_fp(sha1): Found .CAB false positive detection via catalog file\n");
620 return CL_CLEAN;
621 }
622 }
623
624 if (have_sha256) {
625 cl_sha256(ptr, size, &shash256[SHA256_HASH_SIZE], NULL);
626
627 if (cli_hm_scan(&shash256[SHA256_HASH_SIZE], size, &virname, ctx->engine->hm_fp, CLI_HASH_SHA256) == CL_VIRUS) {
628 cli_dbgmsg("cli_check_fp(sha256): Found false positive detection (fp sig: %s)\n", virname);
629 return CL_CLEAN;
630 }
631 if (cli_hm_scan_wild(&shash256[SHA256_HASH_SIZE], &virname, ctx->engine->hm_fp, CLI_HASH_SHA256) == CL_VIRUS) {
632 cli_dbgmsg("cli_check_fp(sha256): Found false positive detection (fp sig: %s)\n", virname);
633 return CL_CLEAN;
634 }
635 /* See whether the hash matches those loaded in from .cat files
636 * (associated with the .CAB file type) */
637 if (cli_hm_scan(&shash256[SHA256_HASH_SIZE], 1, &virname, ctx->engine->hm_fp, CLI_HASH_SHA256) == CL_VIRUS) {
638 cli_dbgmsg("cli_check_fp(sha256): Found .CAB false positive detection via catalog file\n");
639 return CL_CLEAN;
640 }
641 }
642 }
643 }
644
645 #ifdef HAVE__INTERNAL__SHA_COLLECT
646 if (SCAN_DEV_COLLECT_SHA && (ctx->sha_collect > 0)) {
647 if ((ptr = fmap_need_off_once(map, 0, size))) {
648 if (!have_sha256)
649 cl_sha256(ptr, size, shash256 + SHA256_HASH_SIZE, NULL);
650
651 for (i = 0; i < SHA256_HASH_SIZE; i++)
652 sprintf((char *)shash256 + i * 2, "%02x", shash256[SHA256_HASH_SIZE + i]);
653
654 if (!have_sha1)
655 cl_sha1(ptr, size, shash1 + SHA1_HASH_SIZE);
656
657 for (i = 0; i < SHA1_HASH_SIZE; i++)
658 sprintf((char *)shash1 + i * 2, "%02x", shash1[SHA1_HASH_SIZE + i]);
659
660 if (NULL == ctx->target_filepath) {
661 cli_errmsg("COLLECT:%s:%s:%u:%s:%s\n", shash256, shash1, size, vname ? vname : "noname", "NO_IDEA");
662 } else {
663 cli_errmsg("COLLECT:%s:%s:%u:%s:%s\n", shash256, shash1, size, vname ? vname : "noname", ctx->target_filepath);
664 }
665 } else
666 cli_errmsg("can't compute sha\n!");
667
668 ctx->sha_collect = -1;
669 }
670 #endif
671
672 if (ctx->engine->cb_hash)
673 ctx->engine->cb_hash(fmap_fd(ctx->fmap), size, (const unsigned char *)md5, vname ? vname : "noname", ctx->cb_ctx);
674
675 if (ctx->engine->cb_stats_add_sample) {
676 stats_section_t sections;
677 memset(§ions, 0x00, sizeof(stats_section_t));
678
679 if (!(ctx->engine->engine_options & ENGINE_OPTIONS_DISABLE_PE_STATS) &&
680 !(ctx->engine->dconf->stats & (DCONF_STATS_DISABLED | DCONF_STATS_PE_SECTION_DISABLED)))
681 cli_genhash_pe(ctx, CL_GENHASH_PE_CLASS_SECTION, 1, §ions);
682
683 // TODO We probably only want to call cb_stats_add_sample when
684 // sections.section != NULL... leaving as is for now
685 ctx->engine->cb_stats_add_sample(vname ? vname : "noname", digest, size, §ions, ctx->engine->stats_data);
686
687 if (sections.sections) {
688 free(sections.sections);
689 }
690 }
691
692 stack_index -= 1;
693 }
694
695 return status;
696 }
697
matchicon(cli_ctx * ctx,struct cli_exe_info * exeinfo,const char * grp1,const char * grp2)698 static cl_error_t matchicon(cli_ctx *ctx, struct cli_exe_info *exeinfo, const char *grp1, const char *grp2)
699 {
700 icon_groupset iconset;
701
702 if (!ctx ||
703 !ctx->engine ||
704 !ctx->engine->iconcheck ||
705 !ctx->engine->iconcheck->group_counts[0] ||
706 !ctx->engine->iconcheck->group_counts[1] ||
707 !exeinfo->res_addr) return CL_CLEAN;
708
709 if (!(ctx->dconf->pe & PE_CONF_MATCHICON))
710 return CL_CLEAN;
711
712 cli_icongroupset_init(&iconset);
713 cli_icongroupset_add(grp1 ? grp1 : "*", &iconset, 0, ctx);
714 cli_icongroupset_add(grp2 ? grp2 : "*", &iconset, 1, ctx);
715 return cli_scanicon(&iconset, ctx, exeinfo);
716 }
717
cli_bcapi_matchicon(struct cli_bc_ctx * ctx,const uint8_t * grp1,int32_t grp1len,const uint8_t * grp2,int32_t grp2len)718 int32_t cli_bcapi_matchicon(struct cli_bc_ctx *ctx, const uint8_t *grp1, int32_t grp1len,
719 const uint8_t *grp2, int32_t grp2len)
720 {
721 cl_error_t ret;
722 char group1[128], group2[128];
723 const char **oldvirname;
724 struct cli_exe_info info;
725
726 // TODO This isn't a good check, since EP will be zero for DLLs and
727 // (assuming pedata->ep is populated from exeinfo->pe) non-zero for
728 // some MachO and ELF executables
729 if (!ctx->hooks.pedata->ep) {
730 cli_dbgmsg("bytecode: matchicon only works with PE files\n");
731 return -1;
732 }
733 if ((size_t)grp1len > sizeof(group1) - 1 ||
734 (size_t)grp2len > sizeof(group2) - 1)
735 return -1;
736 oldvirname = ((cli_ctx *)ctx->ctx)->virname;
737 ((cli_ctx *)ctx->ctx)->virname = NULL;
738 memcpy(group1, grp1, grp1len);
739 memcpy(group2, grp2, grp2len);
740 group1[grp1len] = 0;
741 group2[grp2len] = 0;
742 memset(&info, 0, sizeof(info));
743 if (ctx->bc->kind == BC_PE_UNPACKER || ctx->bc->kind == BC_PE_ALL) {
744 if (le16_to_host(ctx->hooks.pedata->file_hdr.Characteristics) & 0x2000 ||
745 !ctx->hooks.pedata->dirs[2].Size)
746 info.res_addr = 0;
747 else
748 info.res_addr = le32_to_host(ctx->hooks.pedata->dirs[2].VirtualAddress);
749 } else
750 info.res_addr = ctx->resaddr; /* from target_info */
751 info.sections = (struct cli_exe_section *)ctx->sections;
752 info.nsections = ctx->hooks.pedata->nsections;
753 info.hdr_size = ctx->hooks.pedata->hdr_size;
754 cli_dbgmsg("bytecode matchicon %s %s\n", group1, group2);
755 ret = matchicon(ctx->ctx, &info, group1[0] ? group1 : NULL,
756 group2[0] ? group2 : NULL);
757 ((cli_ctx *)ctx->ctx)->virname = oldvirname;
758 return (int32_t)ret;
759 }
760
cli_scan_desc(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,const char * name)761 cl_error_t cli_scan_desc(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, const char *name)
762 {
763 cl_error_t status = CL_CLEAN;
764 int empty;
765 fmap_t *new_map = NULL;
766 fmap_t *map = ctx->fmap; /* Store off the parent fmap for easy reference */
767
768 new_map = fmap_check_empty(desc, 0, 0, &empty, name);
769 if (NULL == new_map) {
770 if (!empty) {
771 cli_dbgmsg("cli_scan_desc: Failed to allocate new map for file descriptor scan.\n");
772 status = CL_EMEM;
773 }
774 goto done;
775 }
776
777 status = cli_recursion_stack_push(ctx, new_map, ftype, true); /* Perform scan with child fmap */
778 if (CL_SUCCESS != status) {
779 cli_dbgmsg("cli_scan_desc: Failed to scan fmap.\n");
780 goto done;
781 }
782
783 status = cli_scan_fmap(ctx, ftype, ftonly, ftoffset, acmode, acres, NULL);
784
785 map->dont_cache_flag = ctx->fmap->dont_cache_flag; /* Set the parent layer's "don't cache" flag to match the child.
786 TODO: This may not be needed since `emax_reached()` should've
787 already done that for us. */
788
789 (void)cli_recursion_stack_pop(ctx); /* Restore the parent fmap */
790
791 done:
792 if (NULL != new_map) {
793 funmap(new_map);
794 }
795
796 return status;
797 }
798
intermediates_eval(cli_ctx * ctx,struct cli_ac_lsig * ac_lsig)799 static int intermediates_eval(cli_ctx *ctx, struct cli_ac_lsig *ac_lsig)
800 {
801 uint32_t i, icnt = ac_lsig->tdb.intermediates[0];
802 int32_t j = -1;
803
804 if (ctx->recursion_level < icnt)
805 return 0;
806
807 for (i = icnt; i > 0; i--) {
808 if (ac_lsig->tdb.intermediates[i] == CL_TYPE_ANY)
809 continue;
810 if (ac_lsig->tdb.intermediates[i] != cli_recursion_stack_get_type(ctx, j--))
811 return 0;
812 }
813 return 1;
814 }
815
lsig_eval(cli_ctx * ctx,struct cli_matcher * root,struct cli_ac_data * acdata,struct cli_target_info * target_info,const char * hash,uint32_t lsid)816 static cl_error_t lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info, const char *hash, uint32_t lsid)
817 {
818 cl_error_t status = CL_CLEAN;
819 unsigned evalcnt = 0;
820 uint64_t evalids = 0;
821 fmap_t *new_map = NULL;
822 struct cli_ac_lsig *ac_lsig = root->ac_lsigtable[lsid];
823 char *exp = ac_lsig->u.logic;
824 char *exp_end = exp + strlen(exp);
825
826 status = cli_ac_chkmacro(root, acdata, lsid);
827 if (status != CL_SUCCESS)
828 return status;
829
830 if (cli_ac_chklsig(exp, exp_end, acdata->lsigcnt[lsid], &evalcnt, &evalids, 0) == 1) {
831 if (ac_lsig->tdb.container && ac_lsig->tdb.container[0] != cli_recursion_stack_get_type(ctx, -2))
832 goto done;
833 if (ac_lsig->tdb.intermediates && !intermediates_eval(ctx, ac_lsig))
834 goto done;
835 if (ac_lsig->tdb.filesize && (ac_lsig->tdb.filesize[0] > ctx->fmap->len || ac_lsig->tdb.filesize[1] < ctx->fmap->len))
836 goto done;
837
838 if (ac_lsig->tdb.ep || ac_lsig->tdb.nos) {
839 if (!target_info || target_info->status != 1)
840 goto done;
841 if (ac_lsig->tdb.ep && (ac_lsig->tdb.ep[0] > target_info->exeinfo.ep || ac_lsig->tdb.ep[1] < target_info->exeinfo.ep))
842 goto done;
843 if (ac_lsig->tdb.nos && (ac_lsig->tdb.nos[0] > target_info->exeinfo.nsections || ac_lsig->tdb.nos[1] < target_info->exeinfo.nsections))
844 goto done;
845 }
846
847 if (hash && ac_lsig->tdb.handlertype) {
848 if (0 != memcmp(ctx->handlertype_hash, hash, 16)) {
849 /*
850 * Create an fmap window into our current fmap using the original offset & length, and rescan as the new type
851 *
852 * TODO: Unsure if creating an fmap is the right move, or if we should rescan with the current fmap as-is,
853 * since it's not really a container so much as it is type reassignment. This new fmap layer protect agains
854 * a possible infinite loop by applying the scan recursion limit, but maybe there's a better way?
855 * Testing with both HandlerType type reassignment sigs + Container/Intermediates sigs should indicate if
856 * a change is needed.
857 */
858 new_map = fmap_duplicate(ctx->fmap, 0, ctx->fmap->len, ctx->fmap->name);
859 if (NULL == new_map) {
860 status = CL_EMEM;
861 cli_dbgmsg("Failed to duplicate the current fmap for a re-scan as a different type.\n");
862 goto done;
863 }
864
865 memcpy(ctx->handlertype_hash, hash, 16);
866
867 status = cli_recursion_stack_push(ctx, new_map, ac_lsig->tdb.handlertype[0], true); /* Perform scan with child fmap */
868 if (CL_SUCCESS != status) {
869 cli_dbgmsg("Failed to re-scan fmap as a new type.\n");
870 goto done;
871 }
872
873 status = cli_magic_scan(ctx, ac_lsig->tdb.handlertype[0]);
874
875 (void)cli_recursion_stack_pop(ctx); /* Restore the parent fmap */
876
877 if (CL_VIRUS == status) {
878 status = CL_VIRUS;
879 goto done;
880 }
881
882 goto done;
883 }
884 }
885
886 if (ac_lsig->tdb.icongrp1 || ac_lsig->tdb.icongrp2) {
887 if (!target_info || target_info->status != 1) {
888 goto done;
889 }
890
891 if (CL_VIRUS == matchicon(ctx, &target_info->exeinfo, ac_lsig->tdb.icongrp1, ac_lsig->tdb.icongrp2)) {
892 if (!ac_lsig->bc_idx) {
893 status = cli_append_virus(ctx, ac_lsig->virname);
894 if (status != CL_CLEAN) {
895 goto done;
896 }
897 } else if (CL_VIRUS == cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, ac_lsig->bc_idx, acdata->lsigcnt[lsid], acdata->lsigsuboff_first[lsid], ctx->fmap)) {
898 status = CL_VIRUS;
899 goto done;
900 }
901 }
902 goto done;
903 }
904 if (!ac_lsig->bc_idx) {
905 status = cli_append_virus(ctx, ac_lsig->virname);
906 if (status != CL_CLEAN) {
907 goto done;
908 }
909 }
910 if (CL_VIRUS == cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, ac_lsig->bc_idx, acdata->lsigcnt[lsid], acdata->lsigsuboff_first[lsid], ctx->fmap)) {
911 status = CL_VIRUS;
912 goto done;
913 }
914 }
915
916 done:
917 if (NULL != new_map) {
918 free_duplicate_fmap(new_map);
919 }
920
921 return status;
922 }
923
924 #ifdef HAVE_YARA
yara_eval(cli_ctx * ctx,struct cli_matcher * root,struct cli_ac_data * acdata,struct cli_target_info * target_info,const char * hash,uint32_t lsid)925 static cl_error_t yara_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info, const char *hash, uint32_t lsid)
926 {
927 struct cli_ac_lsig *ac_lsig = root->ac_lsigtable[lsid];
928 cl_error_t rc;
929 YR_SCAN_CONTEXT context;
930
931 (void)hash;
932
933 memset(&context, 0, sizeof(YR_SCAN_CONTEXT));
934 context.fmap = ctx->fmap;
935 context.file_size = ctx->fmap->len;
936 if (target_info != NULL) {
937 if (target_info->status == 1)
938 context.entry_point = target_info->exeinfo.ep;
939 }
940
941 rc = yr_execute_code(ac_lsig, acdata, &context, 0, 0);
942
943 if (rc == CL_VIRUS) {
944 if (ac_lsig->flag & CLI_LSIG_FLAG_PRIVATE) {
945 rc = CL_CLEAN;
946 } else {
947 rc = cli_append_virus(ctx, ac_lsig->virname);
948 }
949 }
950 return rc;
951 }
952 #endif
953
cli_exp_eval(cli_ctx * ctx,struct cli_matcher * root,struct cli_ac_data * acdata,struct cli_target_info * target_info,const char * hash)954 cl_error_t cli_exp_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info, const char *hash)
955 {
956 uint8_t viruses_found = 0;
957 uint32_t i;
958 cl_error_t rc = CL_SUCCESS;
959
960 for (i = 0; i < root->ac_lsigs; i++) {
961 if (root->ac_lsigtable[i]->type == CLI_LSIG_NORMAL)
962 rc = lsig_eval(ctx, root, acdata, target_info, hash, i);
963 #ifdef HAVE_YARA
964 else if (root->ac_lsigtable[i]->type == CLI_YARA_NORMAL || root->ac_lsigtable[i]->type == CLI_YARA_OFFSET)
965 rc = yara_eval(ctx, root, acdata, target_info, hash, i);
966 #endif
967 if (rc == CL_VIRUS) {
968 viruses_found = 1;
969 if (SCAN_ALLMATCHES)
970 continue;
971 break;
972 }
973 }
974 if (viruses_found)
975 return CL_VIRUS;
976 return CL_CLEAN;
977 }
978
cli_scan_fmap(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)979 cl_error_t cli_scan_fmap(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)
980 {
981 const unsigned char *buff;
982 cl_error_t ret = CL_CLEAN, type = CL_CLEAN;
983 int compute_hash[CLI_HASH_AVAIL_TYPES];
984 unsigned int i = 0, j = 0, bm_offmode = 0;
985 uint32_t maxpatlen, bytes, offset = 0;
986 struct cli_ac_data gdata, tdata;
987 struct cli_bm_off toff;
988 struct cli_pcre_off gpoff, tpoff;
989 unsigned char digest[CLI_HASH_AVAIL_TYPES][32];
990 struct cli_matcher *groot = NULL, *troot = NULL;
991 struct cli_target_info info;
992 struct cli_matcher *hdb, *fp;
993 const char *virname;
994 uint32_t viruses_found = 0;
995 void *md5ctx, *sha1ctx, *sha256ctx;
996
997 if (!ctx->engine) {
998 cli_errmsg("cli_scan_fmap: engine == NULL\n");
999 return CL_ENULLARG;
1000 }
1001
1002 md5ctx = cl_hash_init("md5");
1003 if (!(md5ctx))
1004 return CL_EMEM;
1005
1006 sha1ctx = cl_hash_init("sha1");
1007 if (!(sha1ctx)) {
1008 cl_hash_destroy(md5ctx);
1009 return CL_EMEM;
1010 }
1011
1012 sha256ctx = cl_hash_init("sha256");
1013 if (!(sha256ctx)) {
1014 cl_hash_destroy(md5ctx);
1015 cl_hash_destroy(sha1ctx);
1016 return CL_EMEM;
1017 }
1018
1019 if (!ftonly)
1020 groot = ctx->engine->root[0]; /* generic signatures */
1021
1022 if (ftype) {
1023 for (i = 1; i < CLI_MTARGETS; i++) {
1024 for (j = 0; j < cli_mtargets[i].target_count; ++j) {
1025 if (cli_mtargets[i].target[j] == ftype) {
1026 troot = ctx->engine->root[i];
1027 break;
1028 }
1029 }
1030 if (troot) break;
1031 }
1032 }
1033
1034 if (ftonly) {
1035 if (!troot) {
1036 cl_hash_destroy(md5ctx);
1037 cl_hash_destroy(sha1ctx);
1038 cl_hash_destroy(sha256ctx);
1039 return CL_CLEAN;
1040 }
1041
1042 maxpatlen = troot->maxpatlen;
1043 } else {
1044 if (troot)
1045 maxpatlen = MAX(troot->maxpatlen, groot->maxpatlen);
1046 else
1047 maxpatlen = groot->maxpatlen;
1048 }
1049
1050 cli_targetinfo_init(&info);
1051 cli_targetinfo(&info, i, ctx);
1052
1053 if (-1 == info.status) {
1054 cli_dbgmsg("cli_scan_fmap: Failed to successfully parse the executable header. "
1055 "Scan features will be disabled, such as "
1056 "NDB/LDB subsigs using EOF-n/EP+n/EP-n/Sx+n/SEx/SL+n, "
1057 "fuzzy icon matching, "
1058 "MDB/IMP sigs, "
1059 "and bytecode sigs that require exe metadata\n");
1060 }
1061
1062 /* If it's a PE, check the Authenticode header. This would be more
1063 * appropriate in cli_scanpe, but scanraw->cli_scan_fmap gets
1064 * called first for PEs, and we want to determine the whitelist/blacklist
1065 * status early on so we can skip things like embedded PE extraction
1066 * (which is broken for signed binaries within signed binaries).
1067 *
1068 * If we want to add support for more signature parsing in the future
1069 * (Ex: MachO sigs), do that here too.
1070 *
1071 * One benefit of not continuing on to scan files with trusted signatures
1072 * is that the bytes associated with the exe won't get counted against the
1073 * scansize limits, which means we have an increased chance of catching
1074 * malware in container types (NSIS, iShield, etc.) where the file size is
1075 * large. A common case where this occurs is installers that embed one
1076 * or more of the various Microsoft Redistributable Setup packages. These
1077 * can easily be 5 MB or more in size, and might appear before malware
1078 * does in a given sample.
1079 */
1080
1081 if (1 == info.status && i == 1) {
1082 ret = cli_check_auth_header(ctx, &(info.exeinfo));
1083
1084 if ((ret == CL_VIRUS || ret == CL_VERIFIED) && !SCAN_ALLMATCHES) {
1085 cli_targetinfo_destroy(&info);
1086 cl_hash_destroy(md5ctx);
1087 cl_hash_destroy(sha1ctx);
1088 cl_hash_destroy(sha256ctx);
1089 return ret;
1090 }
1091
1092 ret = CL_CLEAN;
1093 }
1094
1095 if (!ftonly) {
1096 if ((ret = cli_ac_initdata(&gdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)) ||
1097 (ret = cli_ac_caloff(groot, &gdata, &info))) {
1098 cli_targetinfo_destroy(&info);
1099 cl_hash_destroy(md5ctx);
1100 cl_hash_destroy(sha1ctx);
1101 cl_hash_destroy(sha256ctx);
1102 return ret;
1103 }
1104 if ((ret = cli_pcre_recaloff(groot, &gpoff, &info, ctx))) {
1105 cli_ac_freedata(&gdata);
1106 cli_targetinfo_destroy(&info);
1107 cl_hash_destroy(md5ctx);
1108 cl_hash_destroy(sha1ctx);
1109 cl_hash_destroy(sha256ctx);
1110 return ret;
1111 }
1112 }
1113
1114 if (troot) {
1115 if ((ret = cli_ac_initdata(&tdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)) ||
1116 (ret = cli_ac_caloff(troot, &tdata, &info))) {
1117 if (!ftonly) {
1118 cli_ac_freedata(&gdata);
1119 cli_pcre_freeoff(&gpoff);
1120 }
1121 cli_targetinfo_destroy(&info);
1122 cl_hash_destroy(md5ctx);
1123 cl_hash_destroy(sha1ctx);
1124 cl_hash_destroy(sha256ctx);
1125 return ret;
1126 }
1127 if (troot->bm_offmode) {
1128 if (ctx->fmap->len >= CLI_DEFAULT_BM_OFFMODE_FSIZE) {
1129 if ((ret = cli_bm_initoff(troot, &toff, &info))) {
1130 if (!ftonly) {
1131 cli_ac_freedata(&gdata);
1132 cli_pcre_freeoff(&gpoff);
1133 }
1134
1135 cli_ac_freedata(&tdata);
1136 cli_targetinfo_destroy(&info);
1137 cl_hash_destroy(md5ctx);
1138 cl_hash_destroy(sha1ctx);
1139 cl_hash_destroy(sha256ctx);
1140 return ret;
1141 }
1142
1143 bm_offmode = 1;
1144 }
1145 }
1146 if ((ret = cli_pcre_recaloff(troot, &tpoff, &info, ctx))) {
1147 if (!ftonly) {
1148 cli_ac_freedata(&gdata);
1149 cli_pcre_freeoff(&gpoff);
1150 }
1151
1152 cli_ac_freedata(&tdata);
1153 if (bm_offmode)
1154 cli_bm_freeoff(&toff);
1155 cli_targetinfo_destroy(&info);
1156 cl_hash_destroy(md5ctx);
1157 cl_hash_destroy(sha1ctx);
1158 cl_hash_destroy(sha256ctx);
1159 return ret;
1160 }
1161 }
1162
1163 hdb = ctx->engine->hm_hdb;
1164 fp = ctx->engine->hm_fp;
1165
1166 if (!ftonly && hdb) {
1167 if (!refhash) {
1168 if (cli_hm_have_size(hdb, CLI_HASH_MD5, ctx->fmap->len) ||
1169 cli_hm_have_size(fp, CLI_HASH_MD5, ctx->fmap->len) ||
1170 cli_hm_have_wild(hdb, CLI_HASH_MD5) ||
1171 cli_hm_have_wild(fp, CLI_HASH_MD5)) {
1172 compute_hash[CLI_HASH_MD5] = 1;
1173 } else {
1174 compute_hash[CLI_HASH_MD5] = 0;
1175 }
1176 } else {
1177 compute_hash[CLI_HASH_MD5] = 0;
1178 memcpy(digest[CLI_HASH_MD5], refhash, 16);
1179 }
1180
1181 if (cli_hm_have_size(hdb, CLI_HASH_SHA1, ctx->fmap->len) ||
1182 cli_hm_have_wild(hdb, CLI_HASH_SHA1) ||
1183 cli_hm_have_size(fp, CLI_HASH_SHA1, ctx->fmap->len) ||
1184 cli_hm_have_wild(fp, CLI_HASH_SHA1)) {
1185 compute_hash[CLI_HASH_SHA1] = 1;
1186 } else {
1187 compute_hash[CLI_HASH_SHA1] = 0;
1188 }
1189
1190 if (cli_hm_have_size(hdb, CLI_HASH_SHA256, ctx->fmap->len) ||
1191 cli_hm_have_wild(hdb, CLI_HASH_SHA256) ||
1192 cli_hm_have_size(fp, CLI_HASH_SHA256, ctx->fmap->len) ||
1193 cli_hm_have_wild(fp, CLI_HASH_SHA256)) {
1194 compute_hash[CLI_HASH_SHA256] = 1;
1195 } else {
1196 compute_hash[CLI_HASH_SHA256] = 0;
1197 }
1198 }
1199
1200 while (offset < ctx->fmap->len) {
1201 bytes = MIN(ctx->fmap->len - offset, SCANBUFF);
1202 if (!(buff = fmap_need_off_once(ctx->fmap, offset, bytes)))
1203 break;
1204 if (ctx->scanned)
1205 *ctx->scanned += bytes / CL_COUNT_PRECISION;
1206
1207 if (troot) {
1208 virname = NULL;
1209 ret = matcher_run(troot, buff, bytes, &virname, &tdata, offset, &info, ftype, ftoffset, acmode, PCRE_SCAN_FMAP, acres, ctx->fmap, bm_offmode ? &toff : NULL, &tpoff, ctx);
1210
1211 if (virname) {
1212 /* virname already appended by matcher_run */
1213 viruses_found = 1;
1214 }
1215 if ((ret == CL_VIRUS && !SCAN_ALLMATCHES) || ret == CL_EMEM) {
1216 if (!ftonly) {
1217 cli_ac_freedata(&gdata);
1218 cli_pcre_freeoff(&gpoff);
1219 }
1220
1221 cli_ac_freedata(&tdata);
1222 if (bm_offmode)
1223 cli_bm_freeoff(&toff);
1224 cli_pcre_freeoff(&tpoff);
1225
1226 cli_targetinfo_destroy(&info);
1227 cl_hash_destroy(md5ctx);
1228 cl_hash_destroy(sha1ctx);
1229 cl_hash_destroy(sha256ctx);
1230 return ret;
1231 }
1232 }
1233
1234 if (!ftonly) {
1235 virname = NULL;
1236 ret = matcher_run(groot, buff, bytes, &virname, &gdata, offset, &info, ftype, ftoffset, acmode, PCRE_SCAN_FMAP, acres, ctx->fmap, NULL, &gpoff, ctx);
1237
1238 if (virname) {
1239 /* virname already appended by matcher_run */
1240 viruses_found = 1;
1241 }
1242 if ((ret == CL_VIRUS && !SCAN_ALLMATCHES) || ret == CL_EMEM) {
1243 cli_ac_freedata(&gdata);
1244 cli_pcre_freeoff(&gpoff);
1245 if (troot) {
1246 cli_ac_freedata(&tdata);
1247 if (bm_offmode)
1248 cli_bm_freeoff(&toff);
1249 cli_pcre_freeoff(&tpoff);
1250 }
1251
1252 cli_targetinfo_destroy(&info);
1253 cl_hash_destroy(md5ctx);
1254 cl_hash_destroy(sha1ctx);
1255 cl_hash_destroy(sha256ctx);
1256 return ret;
1257 } else if ((acmode & AC_SCAN_FT) && ((cli_file_t)ret >= CL_TYPENO)) {
1258 if (ret > type)
1259 type = ret;
1260 }
1261
1262 /* if (bytes <= (maxpatlen * (offset!=0))), it means the last window finished the file hashing *
1263 * since the last window is responsible for adding intersection between windows (maxpatlen) */
1264 if (hdb && (bytes > (maxpatlen * (offset != 0)))) {
1265 const void *data = buff + maxpatlen * (offset != 0);
1266 uint32_t data_len = bytes - maxpatlen * (offset != 0);
1267
1268 if (compute_hash[CLI_HASH_MD5])
1269 cl_update_hash(md5ctx, (void *)data, data_len);
1270 if (compute_hash[CLI_HASH_SHA1])
1271 cl_update_hash(sha1ctx, (void *)data, data_len);
1272 if (compute_hash[CLI_HASH_SHA256])
1273 cl_update_hash(sha256ctx, (void *)data, data_len);
1274 }
1275 }
1276
1277 if (bytes < SCANBUFF)
1278 break;
1279
1280 offset += bytes - maxpatlen;
1281 }
1282
1283 if (!ftonly && hdb) {
1284 enum CLI_HASH_TYPE hashtype, hashtype2;
1285
1286 if (compute_hash[CLI_HASH_MD5]) {
1287 cl_finish_hash(md5ctx, digest[CLI_HASH_MD5]);
1288 md5ctx = NULL;
1289 }
1290 if (refhash)
1291 compute_hash[CLI_HASH_MD5] = 1;
1292 if (compute_hash[CLI_HASH_SHA1]) {
1293 cl_finish_hash(sha1ctx, digest[CLI_HASH_SHA1]);
1294 sha1ctx = NULL;
1295 }
1296 if (compute_hash[CLI_HASH_SHA256]) {
1297 cl_finish_hash(sha256ctx, digest[CLI_HASH_SHA256]);
1298 sha256ctx = NULL;
1299 }
1300
1301 virname = NULL;
1302 for (hashtype = CLI_HASH_MD5; hashtype < CLI_HASH_AVAIL_TYPES; hashtype++) {
1303 const char *virname_w = NULL;
1304 int found = 0;
1305
1306 /* If no hash, skip to next type */
1307 if (!compute_hash[hashtype])
1308 continue;
1309
1310 /* Do hash scan */
1311 if ((ret = cli_hm_scan(digest[hashtype], ctx->fmap->len, &virname, hdb, hashtype)) == CL_VIRUS) {
1312 found += 1;
1313 }
1314 if (!found || SCAN_ALLMATCHES) {
1315 if ((ret = cli_hm_scan_wild(digest[hashtype], &virname_w, hdb, hashtype)) == CL_VIRUS)
1316 found += 2;
1317 }
1318
1319 /* If found, do immediate hash-only FP check */
1320 if (found && fp) {
1321 for (hashtype2 = CLI_HASH_MD5; hashtype2 < CLI_HASH_AVAIL_TYPES; hashtype2++) {
1322 if (!compute_hash[hashtype2])
1323 continue;
1324 if (cli_hm_scan(digest[hashtype2], ctx->fmap->len, NULL, fp, hashtype2) == CL_VIRUS) {
1325 found = 0;
1326 ret = CL_CLEAN;
1327 break;
1328 } else if (cli_hm_scan_wild(digest[hashtype2], NULL, fp, hashtype2) == CL_VIRUS) {
1329 found = 0;
1330 ret = CL_CLEAN;
1331 break;
1332 }
1333 }
1334 }
1335
1336 /* If matched size-based hash ... */
1337 if (found % 2) {
1338 viruses_found = 1;
1339 ret = cli_append_virus(ctx, virname);
1340 if (!SCAN_ALLMATCHES || ret != CL_CLEAN)
1341 break;
1342 virname = NULL;
1343 }
1344 /* If matched size-agnostic hash ... */
1345 if (found > 1) {
1346 viruses_found = 1;
1347 ret = cli_append_virus(ctx, virname_w);
1348 if (!SCAN_ALLMATCHES || ret != CL_CLEAN)
1349 break;
1350 }
1351 }
1352 }
1353
1354 cl_hash_destroy(md5ctx);
1355 cl_hash_destroy(sha1ctx);
1356 cl_hash_destroy(sha256ctx);
1357
1358 if (troot) {
1359 if (ret != CL_VIRUS || SCAN_ALLMATCHES)
1360 ret = cli_exp_eval(ctx, troot, &tdata, &info, (const char *)refhash);
1361 if (ret == CL_VIRUS)
1362 viruses_found++;
1363
1364 cli_ac_freedata(&tdata);
1365 if (bm_offmode)
1366 cli_bm_freeoff(&toff);
1367 cli_pcre_freeoff(&tpoff);
1368 }
1369
1370 if (groot) {
1371 if (ret != CL_VIRUS || SCAN_ALLMATCHES)
1372 ret = cli_exp_eval(ctx, groot, &gdata, &info, (const char *)refhash);
1373 cli_ac_freedata(&gdata);
1374 cli_pcre_freeoff(&gpoff);
1375 }
1376
1377 cli_targetinfo_destroy(&info);
1378
1379 if (SCAN_ALLMATCHES && viruses_found) {
1380 return CL_VIRUS;
1381 }
1382 if (ret == CL_VIRUS) {
1383 return CL_VIRUS;
1384 }
1385
1386 return (acmode & AC_SCAN_FT) ? type : CL_CLEAN;
1387 }
1388
1389 #define CDBRANGE(field, val) \
1390 if (field[0] != CLI_OFF_ANY) { \
1391 if (field[0] == field[1] && field[0] != val) \
1392 continue; \
1393 else if (field[0] != field[1] && ((field[0] && field[0] > val) || \
1394 (field[1] && field[1] < val))) \
1395 continue; \
1396 }
1397
cli_matchmeta(cli_ctx * ctx,const char * fname,size_t fsizec,size_t fsizer,int encrypted,unsigned int filepos,int res1,void * res2)1398 cl_error_t cli_matchmeta(cli_ctx *ctx, const char *fname, size_t fsizec, size_t fsizer, int encrypted, unsigned int filepos, int res1, void *res2)
1399 {
1400 const struct cli_cdb *cdb;
1401 unsigned int viruses_found = 0;
1402 cl_error_t ret = CL_CLEAN;
1403
1404 cli_dbgmsg("CDBNAME:%s:%llu:%s:%llu:%llu:%d:%u:%u:%p\n",
1405 cli_ftname(cli_recursion_stack_get_type(ctx, -1)), (long long unsigned)fsizec, fname, (long long unsigned)fsizec, (long long unsigned)fsizer,
1406 encrypted, filepos, res1, res2);
1407
1408 if (ctx->engine && ctx->engine->cb_meta)
1409 if (ctx->engine->cb_meta(cli_ftname(cli_recursion_stack_get_type(ctx, -1)), fsizec, fname, fsizer, encrypted, filepos, ctx->cb_ctx) == CL_VIRUS) {
1410 cli_dbgmsg("inner file blocked by callback: %s\n", fname);
1411
1412 ret = cli_append_virus(ctx, "Detected.By.Callback");
1413 viruses_found++;
1414 if (!SCAN_ALLMATCHES || ret != CL_CLEAN)
1415 return ret;
1416 }
1417
1418 if (!ctx->engine || !(cdb = ctx->engine->cdb))
1419 return CL_CLEAN;
1420
1421 do {
1422 if (cdb->ctype != CL_TYPE_ANY && cdb->ctype != cli_recursion_stack_get_type(ctx, -1))
1423 continue;
1424
1425 if (cdb->encrypted != 2 && cdb->encrypted != encrypted)
1426 continue;
1427
1428 if (cdb->res1 && (cdb->ctype == CL_TYPE_ZIP || cdb->ctype == CL_TYPE_RAR) && cdb->res1 != res1)
1429 continue;
1430
1431 CDBRANGE(cdb->csize, cli_recursion_stack_get_size(ctx, -1));
1432 CDBRANGE(cdb->fsizec, fsizec);
1433 CDBRANGE(cdb->fsizer, fsizer);
1434 CDBRANGE(cdb->filepos, filepos);
1435
1436 if (cdb->name.re_magic && (!fname || cli_regexec(&cdb->name, fname, 0, NULL, 0) == REG_NOMATCH))
1437 continue;
1438
1439 ret = cli_append_virus(ctx, cdb->virname);
1440 viruses_found++;
1441 if (!SCAN_ALLMATCHES || ret != CL_CLEAN)
1442 return ret;
1443
1444 } while ((cdb = cdb->next));
1445
1446 if (SCAN_ALLMATCHES && viruses_found)
1447 return CL_VIRUS;
1448 return CL_CLEAN;
1449 }
1450