static void targetinfo(struct cli_target_info *info, unsigned int target, fmap_t *map) { cli_infomsg(NULL,"DEBUG: in targetinfo with target=%d\n",target);//CHR int (*einfo)(fmap_t *, struct cli_exe_info *) = NULL; memset(info, 0, sizeof(struct cli_target_info)); info->fsize = map->len; cli_hashset_init_noalloc(&info->exeinfo.vinfo); if(target == 1) einfo = cli_peheader; else if(target == 6) einfo = cli_elfheader; else if(target == 9) einfo = cli_machoheader; else { cli_infomsg(NULL,"DEBUG: target!=(1,6,9), do nothing and return\n");//CHR return; } if(einfo(map, &info->exeinfo)) info->status = -1; else info->status = 1; }
void cli_pcre_perf_print() { struct sigperf_elem stats[MAX_TRACKED_PCRE], *elem = stats; int i, elems = 0, max_name_len = 0, name_len; if (!p_sigid || !p_sigevents) { cli_warnmsg("cli_pcre_perf_print: statistics requested but no PCREs were loaded!\n"); return; } memset(stats, 0, sizeof(stats)); for (i=0;i<MAX_TRACKED_PCRE;i++) { union ev_val val; uint32_t count; const char * name = cli_event_get_name(p_sigevents, i*PCRE_EVENTS_PER_SIG); cli_event_get(p_sigevents, i*PCRE_EVENTS_PER_SIG, &val, &count); if (!count) { if (name) cli_dbgmsg("No event triggered for %s\n", name); continue; } if (name) name_len = strlen(name); else name_len = 0; if (name_len > max_name_len) max_name_len = name_len; elem->name = name?name:"\"noname\""; elem->usecs = val.v_int; elem->run_count = count; cli_event_get(p_sigevents, i*PCRE_EVENTS_PER_SIG+1, &val, &count); elem->match_count = count; elem++; elems++; } if (max_name_len < strlen("PCRE Expression")) max_name_len = strlen("PCRE Expression"); cli_qsort(stats, elems, sizeof(struct sigperf_elem), sigelem_comp); elem = stats; /* name runs matches microsecs avg */ cli_infomsg (NULL, "%-*s %*s %*s %*s %*s\n", max_name_len, "PCRE Expression", 8, "#runs", 8, "#matches", 12, "usecs total", 9, "usecs avg"); cli_infomsg (NULL, "%-*s %*s %*s %*s %*s\n", max_name_len, "===============", 8, "=====", 8, "========", 12, "===========", 9, "========="); while (elem->run_count) { cli_infomsg (NULL, "%-*s %*lu %*lu %*llu %*.2f\n", max_name_len, elem->name, 8, elem->run_count, 8, elem->match_count, 12, (long long unsigned)elem->usecs, 9, (double)elem->usecs/elem->run_count); elem++; } }
static inline int 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, struct cli_ac_result **acres, fmap_t *map, struct cli_bm_off *offdata, uint32_t *viroffset, cli_ctx *ctx) { cli_infomsg(NULL,"DEBUG: in matcher_run\n");//CHR int ret; int32_t pos = 0; struct filter_match_info info; uint32_t orig_length, orig_offset; const unsigned char* orig_buffer; unsigned int viruses_found = 0; if (root->filter) { cli_infomsg(NULL,"DEBUG: has filter\n");//CHR // CHR function filter_search_ext will do pre-matchon prefix for a given pattern if(filter_search_ext(root->filter, buffer, length, &info) == -1) { cli_infomsg(NULL,"DEBUG: filter and in if\n");//CHR /* for safety always scan last maxpatlen bytes */ pos = length - root->maxpatlen - 1; if (pos < 0) pos = 0; PERF_LOG_FILTER(pos, length, root->type); } else { // CHR FSM match cli_infomsg(NULL,"DEBUG: filter and in else\n");//CHR /* must not cut buffer for 64[4-4]6161, because we must be able to check * 64! */ //CHR if first_match is far more beyond max pattern length //CHR we need to move forward a little bit to speed up the following scan pos = info.first_match - root->maxpatlen - 1; cli_infomsg(NULL,"DEBUG: pos=%d\n",pos);//CHR if (pos < 0) pos = 0; PERF_LOG_FILTER(pos, length, root->type); } } else { PERF_LOG_FILTER(0, length, root->type); } orig_length = length; orig_buffer = buffer; orig_offset = offset; //CHR pos is 0 in this case length -= pos; buffer += pos; offset += pos; if (!root->ac_only) { cli_infomsg(NULL,"DEBUG: !ac_only, bm scan first\n");//CHR PERF_LOG_TRIES(0, 1, length); if (root->bm_offmode) { /* Don't use prefiltering for BM offset mode, since BM keeps tracks * of offsets itself, and doesn't work if we skip chunks of input * data */ cli_infomsg(NULL,"DEBUG: scan in bm_offmode=1 mode\n"); //CHR ret = cli_bm_scanbuff(orig_buffer, orig_length, virname, NULL, root, orig_offset, tinfo, offdata, viroffset); } else { cli_infomsg(NULL,"DEBUG: scan in bm_offmode=0 mode\n"); //CHR cli_infomsg(NULL,"DEBUG: pass into cli_bm_scanbuff with length=%d,offset=%d\n",length,offset);//CHR ret = cli_bm_scanbuff(buffer, length, virname, NULL, root, offset, tinfo, offdata, viroffset); } if (ret == CL_VIRUS) { cli_infomsg(NULL,"DEBUG: bm scan find virus, won't do ac scan\n");//CHR if (ctx) { cli_append_virus(ctx, *virname); if (SCAN_ALL) viruses_found++; else return ret; } } } PERF_LOG_TRIES(acmode, 0, length); cli_infomsg(NULL,"DEBUG: ac scan\n");//CHR ret = cli_ac_scanbuff(buffer, length, virname, NULL, acres, root, mdata, offset, ftype, ftoffset, acmode, NULL); if (ctx && ret == CL_VIRUS) cli_append_virus(ctx, *virname); if (ctx && SCAN_ALL && viruses_found) return CL_VIRUS; return ret; }
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) { //CHR ftype => type == CL_TYPE_TEXT_ASCII ? 0 : type //CHR ftonly => 0 cli_infomsg(NULL,"DEBUG: in cli_fmap_scandesc\n");//CHR const unsigned char *buff; int ret = CL_CLEAN, type = CL_CLEAN, bytes, compute_hash[CLI_HASH_AVAIL_TYPES]; unsigned int i = 0, bm_offmode = 0; uint32_t maxpatlen, offset = 0; struct cli_ac_data gdata, tdata; struct cli_bm_off toff; cli_md5_ctx md5ctx; SHA256_CTX sha256ctx; SHA1Context sha1ctx; unsigned char digest[CLI_HASH_AVAIL_TYPES][32]; struct cli_matcher *groot = NULL, *troot = NULL; struct cli_target_info info; fmap_t *map = *ctx->fmap; struct cli_matcher *hdb, *fp; const char *virname = NULL; uint32_t viroffset = 0; uint32_t viruses_found = 0; if(!ctx->engine) { cli_errmsg("cli_scandesc: engine == NULL\n"); return CL_ENULLARG; } cli_infomsg(NULL,"DEBUG: ftype=%d, ftonly=%d(using generic signatures for groot)\n",ftype,ftonly);//CHR if(!ftonly) groot = ctx->engine->root[0]; /* generic signatures */ //CHR in test.txt case, ftype=0, troot is for sepcific types: from 1 to CLI_MTARGETS if(ftype) { for(i = 1; i < CLI_MTARGETS; i++) { if(cli_mtargets[i].target == ftype) { troot = ctx->engine->root[i]; break; } } } if(ftonly) { if(!troot) return CL_CLEAN; maxpatlen = troot->maxpatlen; } else { if(troot) maxpatlen = MAX(troot->maxpatlen, groot->maxpatlen); else{ maxpatlen = groot->maxpatlen; cli_infomsg(NULL,"DEBUG: no troot, maxpatlen using groot->maxpatlen=%d\n",groot->maxpatlen);//CHR } } targetinfo(&info, i, map); if(!ftonly) // CHR init AC scan structure? 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))) { if(info.exeinfo.section) free(info.exeinfo.section); cli_hashset_destroy(&info.exeinfo.vinfo); return ret; } // not run in this case test.txt if(troot) { 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))) { if(!ftonly) cli_ac_freedata(&gdata); if(info.exeinfo.section) free(info.exeinfo.section); cli_hashset_destroy(&info.exeinfo.vinfo); return ret; } if(troot->bm_offmode) {// CHR offset mode if(map->len >= CLI_DEFAULT_BM_OFFMODE_FSIZE) { if((ret = cli_bm_initoff(troot, &toff, &info))) { if(!ftonly) cli_ac_freedata(&gdata); cli_ac_freedata(&tdata); if(info.exeinfo.section) free(info.exeinfo.section); cli_hashset_destroy(&info.exeinfo.vinfo); return ret; } bm_offmode = 1; } } } hdb = ctx->engine->hm_hdb; fp = ctx->engine->hm_fp; // hdb related if(!ftonly && hdb) { //CHR if have hdb should init mn5 contex if(!refhash) { if(cli_hm_have_size(hdb, CLI_HASH_MD5, map->len) || cli_hm_have_size(fp, CLI_HASH_MD5, map->len)) { cli_md5_init(&md5ctx); compute_hash[CLI_HASH_MD5] = 1; } else compute_hash[CLI_HASH_MD5] = 0; } else { compute_hash[CLI_HASH_MD5] = 0; memcpy(digest[CLI_HASH_MD5], refhash, 16); } if(cli_hm_have_size(hdb, CLI_HASH_SHA1, map->len) || cli_hm_have_size(fp, CLI_HASH_SHA1, map->len)) { SHA1Init(&sha1ctx); compute_hash[CLI_HASH_SHA1] = 1; } else compute_hash[CLI_HASH_SHA1] = 0; if(cli_hm_have_size(hdb, CLI_HASH_SHA256, map->len) || cli_hm_have_size(fp, CLI_HASH_SHA256, map->len)) { sha256_init(&sha256ctx); compute_hash[CLI_HASH_SHA256] = 1; } else compute_hash[CLI_HASH_SHA256] = 0; } while(offset < map->len) { bytes = MIN(map->len - offset, SCANBUFF); if(!(buff = fmap_need_off_once(map, offset, bytes))) break; if(ctx->scanned) *ctx->scanned += bytes / CL_COUNT_PRECISION; // CHR not troot for this case if(troot) { cli_infomsg(NULL,"DEBUG: not troot, should not show this msg\n");//CHR virname = NULL; viroffset = 0; // CHR run match ret = matcher_run(troot, buff, bytes, &virname, &tdata, offset, &info, ftype, ftoffset, acmode, acres, map, bm_offmode ? &toff : NULL, &viroffset, ctx); if (virname) { viruses_found++; } if((ret == CL_VIRUS && !SCAN_ALL) || ret == CL_EMEM) { if(!ftonly) cli_ac_freedata(&gdata); cli_ac_freedata(&tdata); if(bm_offmode) cli_bm_freeoff(&toff); if(info.exeinfo.section) free(info.exeinfo.section); cli_hashset_destroy(&info.exeinfo.vinfo); return ret; } } if(!ftonly) { cli_infomsg(NULL,"DEBUG: !ftonly=true, will run matcher_run with groot with generic sigs\n");//CHR virname = NULL; viroffset = 0; ret = matcher_run(groot, buff, bytes, &virname, &gdata, offset, &info, ftype, ftoffset, acmode, acres, map, NULL, &viroffset, ctx); if (virname) { viruses_found++; } if((ret == CL_VIRUS && !SCAN_ALL) || ret == CL_EMEM) { cli_ac_freedata(&gdata); if(troot) { cli_ac_freedata(&tdata); if(bm_offmode) cli_bm_freeoff(&toff); } if(info.exeinfo.section) free(info.exeinfo.section); cli_hashset_destroy(&info.exeinfo.vinfo); return ret; } else if((acmode & AC_SCAN_FT) && ret >= CL_TYPENO) { if(ret > type) type = ret; } if(hdb && !SCAN_ALL) { const void *data = buff + maxpatlen * (offset!=0); uint32_t data_len = bytes - maxpatlen * (offset!=0); if(compute_hash[CLI_HASH_MD5]) cli_md5_update(&md5ctx, data, data_len); if(compute_hash[CLI_HASH_SHA1]) SHA1Update(&sha1ctx, data, data_len); if(compute_hash[CLI_HASH_SHA256]) sha256_update(&sha256ctx, data, data_len); } } if(SCAN_ALL && viroffset) { offset = viroffset; continue; } if(bytes < SCANBUFF) break; offset += bytes - maxpatlen; } if(!ftonly && hdb) { enum CLI_HASH_TYPE hashtype, hashtype2; if(compute_hash[CLI_HASH_MD5]) cli_md5_final(digest[CLI_HASH_MD5], &md5ctx); if(refhash) compute_hash[CLI_HASH_MD5] = 1; if(compute_hash[CLI_HASH_SHA1]) SHA1Final(&sha1ctx, digest[CLI_HASH_SHA1]); if(compute_hash[CLI_HASH_SHA256]) sha256_final(&sha256ctx, digest[CLI_HASH_SHA256]); virname = NULL; for(hashtype = CLI_HASH_MD5; hashtype < CLI_HASH_AVAIL_TYPES; hashtype++) { if(compute_hash[hashtype] && (ret = cli_hm_scan(digest[hashtype], map->len, &virname, hdb, hashtype)) == CL_VIRUS) { if(fp) { for(hashtype2 = CLI_HASH_MD5; hashtype2 < CLI_HASH_AVAIL_TYPES; hashtype2++) { if(compute_hash[hashtype2] && cli_hm_scan(digest[hashtype2], map->len, NULL, fp, hashtype2) == CL_VIRUS) { ret = CL_CLEAN; break; } } } if (ret == CL_VIRUS) { viruses_found++; cli_append_virus(ctx, virname); if (!SCAN_ALL) break; } virname = NULL; } } } if(troot) { if(ret != CL_VIRUS || SCAN_ALL) ret = cli_lsig_eval(ctx, troot, &tdata, &info, refhash); if (ret == CL_VIRUS) viruses_found++; cli_ac_freedata(&tdata); if(bm_offmode) cli_bm_freeoff(&toff); } if(groot) { if(ret != CL_VIRUS || SCAN_ALL) ret = cli_lsig_eval(ctx, groot, &gdata, &info, refhash); cli_ac_freedata(&gdata); } if(info.exeinfo.section) free(info.exeinfo.section); cli_hashset_destroy(&info.exeinfo.vinfo); if (SCAN_ALL && viruses_found) return CL_VIRUS; if(ret == CL_VIRUS) return CL_VIRUS; return (acmode & AC_SCAN_FT) ? type : CL_CLEAN; }
static int scancws(cli_ctx *ctx, struct swf_file_hdr *hdr) { z_stream stream; char inbuff[FILEBUFF], outbuff[FILEBUFF]; fmap_t *map = *ctx->fmap; int offset = 8, ret, zret, outsize = 8, count, zend; char *tmpname; int fd; if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) { cli_errmsg("scancws: Can't generate temporary file\n"); return ret; } hdr->signature[0] = 'F'; if(cli_writen(fd, hdr, sizeof(struct swf_file_hdr)) != sizeof(struct swf_file_hdr)) { cli_errmsg("scancws: Can't write to file %s\n", tmpname); close(fd); if(cli_unlink(tmpname)) { free(tmpname); return CL_EUNLINK; } free(tmpname); return CL_EWRITE; } stream.avail_in = 0; stream.next_in = (Bytef *)inbuff; stream.next_out = (Bytef *)outbuff; stream.zalloc = (alloc_func) NULL; stream.zfree = (free_func) NULL; stream.opaque = (voidpf) 0; stream.avail_out = FILEBUFF; zret = inflateInit(&stream); if(zret != Z_OK) { cli_errmsg("scancws: inflateInit() failed\n"); close(fd); if(cli_unlink(tmpname)) { free(tmpname); return CL_EUNLINK; } free(tmpname); return CL_EUNPACK; } do { if(stream.avail_in == 0) { stream.next_in = (Bytef *)inbuff; ret = fmap_readn(map, inbuff, offset, FILEBUFF); if(ret < 0) { cli_errmsg("scancws: Error reading SWF file\n"); close(fd); inflateEnd(&stream); if(cli_unlink(tmpname)) { free(tmpname); return CL_EUNLINK; } free(tmpname); return CL_EUNPACK; } if(!ret) break; stream.avail_in = ret; offset += ret; } zret = inflate(&stream, Z_SYNC_FLUSH); count = FILEBUFF - stream.avail_out; if(count) { if(cli_checklimits("SWF", ctx, outsize + count, 0, 0) != CL_SUCCESS) break; if(cli_writen(fd, outbuff, count) != count) { cli_errmsg("scancws: Can't write to file %s\n", tmpname); inflateEnd(&stream); close(fd); if(cli_unlink(tmpname)) { free(tmpname); return CL_EUNLINK; } free(tmpname); return CL_EWRITE; } outsize += count; } stream.next_out = (Bytef *)outbuff; stream.avail_out = FILEBUFF; } while(zret == Z_OK); zend = inflateEnd(&stream); if((zret != Z_STREAM_END && zret != Z_OK) || zend != Z_OK) { /* * outsize is initialized to 8, it being 8 here means that we couldn't even read a single byte. * If outsize > 8, then we have data. Let's scan what we have. */ if (outsize == 8) { cli_infomsg(ctx, "scancws: Error decompressing SWF file. No data decompressed.\n"); close(fd); if(cli_unlink(tmpname)) { free(tmpname); return CL_EUNLINK; } free(tmpname); return CL_EUNPACK; } cli_infomsg(ctx, "scancws: Error decompressing SWF file. Scanning what was decompressed.\n"); } cli_dbgmsg("SWF: Decompressed[zlib] to %s, size %d\n", tmpname, outsize); /* check if declared output size matches actual output size */ if (hdr->filesize != outsize) { cli_warnmsg("SWF: declared output length != inflated stream size, %u != %llu\n", hdr->filesize, (long long unsigned)outsize); } else { cli_dbgmsg("SWF: declared output length == inflated stream size, %u == %llu\n", hdr->filesize, (long long unsigned)outsize); } ret = cli_magic_scandesc(fd, ctx); close(fd); if(!ctx->engine->keeptmp) { if(cli_unlink(tmpname)) { free(tmpname); return CL_EUNLINK; } } free(tmpname); return ret; }
static int scanzws(cli_ctx *ctx, struct swf_file_hdr *hdr) { struct CLI_LZMA lz; unsigned char inbuff[FILEBUFF], outbuff[FILEBUFF]; fmap_t *map = *ctx->fmap; /* strip off header */ off_t offset = 8; uint32_t d_insize; size_t outsize = 8; int ret, lret, count; char *tmpname; int fd; if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) { cli_errmsg("scanzws: Can't generate temporary file\n"); return ret; } hdr->signature[0] = 'F'; if(cli_writen(fd, hdr, sizeof(struct swf_file_hdr)) != sizeof(struct swf_file_hdr)) { cli_errmsg("scanzws: Can't write to file %s\n", tmpname); close(fd); if(cli_unlink(tmpname)) { free(tmpname); return CL_EUNLINK; } free(tmpname); return CL_EWRITE; } /* read 4 bytes (for compressed 32-bit filesize) [not used for LZMA] */ if (fmap_readn(map, &d_insize, offset, sizeof(d_insize)) != sizeof(d_insize)) { cli_errmsg("scanzws: Error reading SWF file\n"); close(fd); if (cli_unlink(tmpname)) { free(tmpname); return CL_EUNLINK; } free(tmpname); return CL_EREAD; } offset += sizeof(d_insize); /* check if declared input size matches actual output size */ /* map->len = header (8 bytes) + d_insize (4 bytes) + flags (5 bytes) + compressed stream */ if (d_insize != (map->len - 17)) { cli_warnmsg("SWF: declared input length != compressed stream size, %u != %llu\n", d_insize, (long long unsigned)(map->len - 17)); } else { cli_dbgmsg("SWF: declared input length == compressed stream size, %u == %llu\n", d_insize, (long long unsigned)(map->len - 17)); } /* first buffer required for initializing LZMA */ ret = fmap_readn(map, inbuff, offset, FILEBUFF); if (ret < 0) { cli_errmsg("scanzws: Error reading SWF file\n"); close(fd); if (cli_unlink(tmpname)) { free(tmpname); return CL_EUNLINK; } free(tmpname); return CL_EUNPACK; } /* nothing written, likely truncated */ if (!ret) { cli_errmsg("scanzws: possibly truncated file\n"); close(fd); if (cli_unlink(tmpname)) { free(tmpname); return CL_EUNLINK; } free(tmpname); return CL_EFORMAT; } offset += ret; memset(&lz, 0, sizeof(lz)); lz.next_in = inbuff; lz.next_out = outbuff; lz.avail_in = ret; lz.avail_out = FILEBUFF; lret = cli_LzmaInit(&lz, hdr->filesize); if (lret != LZMA_RESULT_OK) { cli_errmsg("scanzws: LzmaInit() failed\n"); close(fd); if (cli_unlink(tmpname)) { free(tmpname); return CL_EUNLINK; } free(tmpname); return CL_EUNPACK; } while (lret == LZMA_RESULT_OK) { if (lz.avail_in == 0) { lz.next_in = inbuff; ret = fmap_readn(map, inbuff, offset, FILEBUFF); if (ret < 0) { cli_errmsg("scanzws: Error reading SWF file\n"); cli_LzmaShutdown(&lz); close(fd); if (cli_unlink(tmpname)) { free(tmpname); return CL_EUNLINK; } free(tmpname); return CL_EUNPACK; } if (!ret) break; lz.avail_in = ret; offset += ret; } lret = cli_LzmaDecode(&lz); count = FILEBUFF - lz.avail_out; if (count) { if (cli_checklimits("SWF", ctx, outsize + count, 0, 0) != CL_SUCCESS) break; if (cli_writen(fd, outbuff, count) != count) { cli_errmsg("scanzws: Can't write to file %s\n", tmpname); cli_LzmaShutdown(&lz); close(fd); if (cli_unlink(tmpname)) { free(tmpname); return CL_EUNLINK; } free(tmpname); return CL_EWRITE; } outsize += count; } lz.next_out = outbuff; lz.avail_out = FILEBUFF; } cli_LzmaShutdown(&lz); if (lret != LZMA_STREAM_END && lret != LZMA_RESULT_OK) { /* outsize starts at 8, therefore, if its still 8, nothing was decompressed */ if (outsize == 8) { cli_infomsg(ctx, "scanzws: Error decompressing SWF file. No data decompressed.\n"); close(fd); if (cli_unlink(tmpname)) { free(tmpname); return CL_EUNLINK; } free(tmpname); return CL_EUNPACK; } cli_infomsg(ctx, "scanzws: Error decompressing SWF file. Scanning what was decompressed.\n"); } cli_dbgmsg("SWF: Decompressed[LZMA] to %s, size %llu\n", tmpname, (long long unsigned)outsize); /* check if declared output size matches actual output size */ if (hdr->filesize != outsize) { cli_warnmsg("SWF: declared output length != inflated stream size, %u != %llu\n", hdr->filesize, (long long unsigned)outsize); } else { cli_dbgmsg("SWF: declared output length == inflated stream size, %u == %llu\n", hdr->filesize, (long long unsigned)outsize); } ret = cli_magic_scandesc(fd, ctx); close(fd); if (!(ctx->engine->keeptmp)) { if (cli_unlink(tmpname)) { free(tmpname); return CL_EUNLINK; } } free(tmpname); return ret; }