/* Hashes a file onto the provided buffer and looks it up the cache. Returns CL_VIRUS if found, CL_CLEAN if not FIXME or a recoverable error, and returns CL_EREAD if unrecoverable */ int cache_check(unsigned char *hash, cli_ctx *ctx) { fmap_t *map; size_t todo, at = 0; void *hashctx; int ret; if(!ctx || !ctx->engine || !ctx->engine->cache) return CL_VIRUS; if (ctx->engine->engine_options & ENGINE_OPTIONS_DISABLE_CACHE) { cli_dbgmsg("cache_check: Caching disabled. Returning CL_VIRUS.\n"); return CL_VIRUS; } map = *ctx->fmap; todo = map->len; hashctx = cl_hash_init("md5"); if (!(hashctx)) return CL_VIRUS; while(todo) { const void *buf; size_t readme = todo < FILEBUFF ? todo : FILEBUFF; if(!(buf = fmap_need_off_once(map, at, readme))) { cl_hash_destroy(hashctx); return CL_EREAD; } todo -= readme; at += readme; if (cl_update_hash(hashctx, (void *)buf, readme)) { cl_hash_destroy(hashctx); cli_errmsg("cache_check: error reading while generating hash!\n"); return CL_EREAD; } } cl_finish_hash(hashctx, hash); ret = cache_lookup_hash(hash, map->len, ctx->engine->cache, ctx->recursion); cli_dbgmsg("cache_check: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x is %s\n", hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15], (ret == CL_VIRUS) ? "negative" : "positive"); return ret; }
int cache_get_MD5(unsigned char *hash, cli_ctx *ctx) { fmap_t *map; size_t todo, at = 0; void *hashctx; map = *ctx->fmap; todo = map->len; hashctx = cl_hash_init("md5"); if (!(hashctx)) return CL_VIRUS; while(todo) { const void *buf; size_t readme = todo < FILEBUFF ? todo : FILEBUFF; if(!(buf = fmap_need_off_once(map, at, readme))) { cl_hash_destroy(hashctx); return CL_EREAD; } todo -= readme; at += readme; if (cl_update_hash(hashctx, (void *)buf, readme)) { cl_hash_destroy(hashctx); cli_errmsg("cache_check: error reading while generating hash!\n"); return CL_EREAD; } } cl_finish_hash(hashctx, hash); return CL_CLEAN; }
static void cli_tgzload_cleanup(int comp, struct cli_dbio *dbio, int fdd) { cli_dbgmsg("in cli_tgzload_cleanup()\n"); if(comp) { gzclose(dbio->gzs); dbio->gzs = NULL; } else { fclose(dbio->fs); dbio->fs = NULL; } if(dbio->buf != NULL) { free(dbio->buf); dbio->buf = NULL; } if (dbio->hashctx) { cl_hash_destroy(dbio->hashctx); dbio->hashctx = NULL; } }
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) { const unsigned char *buff; int ret = CL_CLEAN, type = CL_CLEAN, bytes, compute_hash[CLI_HASH_AVAIL_TYPES]; unsigned int i = 0, j = 0, bm_offmode = 0; uint32_t maxpatlen, offset = 0; struct cli_ac_data gdata, tdata; struct cli_bm_off toff; struct cli_pcre_off gpoff, tpoff; 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 viruses_found = 0; void *md5ctx, *sha1ctx, *sha256ctx; if(!ctx->engine) { cli_errmsg("cli_scandesc: engine == NULL\n"); return CL_ENULLARG; } md5ctx = cl_hash_init("md5"); if (!(md5ctx)) return CL_EMEM; sha1ctx = cl_hash_init("sha1"); if (!(sha1ctx)) { cl_hash_destroy(md5ctx); return CL_EMEM; } sha256ctx = cl_hash_init("sha256"); if (!(sha256ctx)) { cl_hash_destroy(md5ctx); cl_hash_destroy(sha1ctx); return CL_EMEM; } if(!ftonly) groot = ctx->engine->root[0]; /* generic signatures */ if(ftype) { for(i = 1; i < CLI_MTARGETS; i++) { for (j = 0; j < cli_mtargets[i].target_count; ++j) { if(cli_mtargets[i].target[j] == ftype) { troot = ctx->engine->root[i]; break; } } if (troot) break; } } if(ftonly) { if(!troot) { cl_hash_destroy(md5ctx); cl_hash_destroy(sha1ctx); cl_hash_destroy(sha256ctx); return CL_CLEAN; } maxpatlen = troot->maxpatlen; } else { if(troot) maxpatlen = MAX(troot->maxpatlen, groot->maxpatlen); else maxpatlen = groot->maxpatlen; } cli_targetinfo(&info, i, map); if(!ftonly) { 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); cl_hash_destroy(md5ctx); cl_hash_destroy(sha1ctx); cl_hash_destroy(sha256ctx); return ret; } if((ret = cli_pcre_recaloff(groot, &gpoff, &info, ctx))) { cli_ac_freedata(&gdata); if(info.exeinfo.section) free(info.exeinfo.section); cli_hashset_destroy(&info.exeinfo.vinfo); cl_hash_destroy(md5ctx); cl_hash_destroy(sha1ctx); cl_hash_destroy(sha256ctx); return ret; } } 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); cli_pcre_freeoff(&gpoff); } if(info.exeinfo.section) free(info.exeinfo.section); cli_hashset_destroy(&info.exeinfo.vinfo); cl_hash_destroy(md5ctx); cl_hash_destroy(sha1ctx); cl_hash_destroy(sha256ctx); return ret; } if(troot->bm_offmode) { if(map->len >= CLI_DEFAULT_BM_OFFMODE_FSIZE) { if((ret = cli_bm_initoff(troot, &toff, &info))) { if(!ftonly) { cli_ac_freedata(&gdata); cli_pcre_freeoff(&gpoff); } cli_ac_freedata(&tdata); if(info.exeinfo.section) free(info.exeinfo.section); cli_hashset_destroy(&info.exeinfo.vinfo); cl_hash_destroy(md5ctx); cl_hash_destroy(sha1ctx); cl_hash_destroy(sha256ctx); return ret; } bm_offmode = 1; } } if ((ret = cli_pcre_recaloff(troot, &tpoff, &info, ctx))) { if(!ftonly) { cli_ac_freedata(&gdata); cli_pcre_freeoff(&gpoff); } 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); cl_hash_destroy(md5ctx); cl_hash_destroy(sha1ctx); cl_hash_destroy(sha256ctx); return ret; } } hdb = ctx->engine->hm_hdb; fp = ctx->engine->hm_fp; if(!ftonly && hdb) { if(!refhash) { if(cli_hm_have_size(hdb, CLI_HASH_MD5, map->len) || cli_hm_have_size(fp, CLI_HASH_MD5, map->len) || cli_hm_have_wild(hdb, CLI_HASH_MD5) || cli_hm_have_wild(fp, CLI_HASH_MD5)) { 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_wild(hdb, CLI_HASH_SHA1) || cli_hm_have_size(fp, CLI_HASH_SHA1, map->len) || cli_hm_have_wild(fp, CLI_HASH_SHA1) ) { 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_wild(hdb, CLI_HASH_SHA256) || cli_hm_have_size(fp, CLI_HASH_SHA256, map->len) || cli_hm_have_wild(fp, CLI_HASH_SHA256)) { 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; if(troot) { virname = NULL; ret = matcher_run(troot, buff, bytes, &virname, &tdata, offset, &info, ftype, ftoffset, acmode, PCRE_SCAN_FMAP, acres, map, bm_offmode ? &toff : NULL, &tpoff, ctx); if (virname) { /* virname already appended by matcher_run */ viruses_found = 1; } if((ret == CL_VIRUS && !SCAN_ALL) || ret == CL_EMEM) { if(!ftonly) { cli_ac_freedata(&gdata); cli_pcre_freeoff(&gpoff); } cli_ac_freedata(&tdata); if(bm_offmode) cli_bm_freeoff(&toff); cli_pcre_freeoff(&tpoff); if(info.exeinfo.section) free(info.exeinfo.section); cli_hashset_destroy(&info.exeinfo.vinfo); cl_hash_destroy(md5ctx); cl_hash_destroy(sha1ctx); cl_hash_destroy(sha256ctx); return ret; } } if(!ftonly) { virname = NULL; ret = matcher_run(groot, buff, bytes, &virname, &gdata, offset, &info, ftype, ftoffset, acmode, PCRE_SCAN_FMAP, acres, map, NULL, &gpoff, ctx); if (virname) { /* virname already appended by matcher_run */ viruses_found = 1; } if((ret == CL_VIRUS && !SCAN_ALL) || ret == CL_EMEM) { cli_ac_freedata(&gdata); cli_pcre_freeoff(&gpoff); if(troot) { cli_ac_freedata(&tdata); if(bm_offmode) cli_bm_freeoff(&toff); cli_pcre_freeoff(&tpoff); } if(info.exeinfo.section) free(info.exeinfo.section); cli_hashset_destroy(&info.exeinfo.vinfo); cl_hash_destroy(md5ctx); cl_hash_destroy(sha1ctx); cl_hash_destroy(sha256ctx); return ret; } else if((acmode & AC_SCAN_FT) && ret >= CL_TYPENO) { if(ret > type) type = ret; } /* if (bytes <= (maxpatlen * (offset!=0))), it means the last window finished the file hashing * * since the last window is responsible for adding intersection between windows (maxpatlen) */ if(hdb && (bytes > (maxpatlen * (offset!=0)))) { const void *data = buff + maxpatlen * (offset!=0); uint32_t data_len = bytes - maxpatlen * (offset!=0); if(compute_hash[CLI_HASH_MD5]) cl_update_hash(md5ctx, (void *)data, data_len); if(compute_hash[CLI_HASH_SHA1]) cl_update_hash(sha1ctx, (void *)data, data_len); if(compute_hash[CLI_HASH_SHA256]) cl_update_hash(sha256ctx, (void *)data, data_len); } } if(bytes < SCANBUFF) break; offset += bytes - maxpatlen; } if(!ftonly && hdb) { enum CLI_HASH_TYPE hashtype, hashtype2; if(compute_hash[CLI_HASH_MD5]) { cl_finish_hash(md5ctx, digest[CLI_HASH_MD5]); md5ctx = NULL; } if(refhash) compute_hash[CLI_HASH_MD5] = 1; if(compute_hash[CLI_HASH_SHA1]) { cl_finish_hash(sha1ctx, digest[CLI_HASH_SHA1]); sha1ctx = NULL; } if(compute_hash[CLI_HASH_SHA256]) { cl_finish_hash(sha256ctx, digest[CLI_HASH_SHA256]); sha256ctx = NULL; } virname = NULL; for(hashtype = CLI_HASH_MD5; hashtype < CLI_HASH_AVAIL_TYPES; hashtype++) { const char * virname_w = NULL; int found = 0; /* If no hash, skip to next type */ if(!compute_hash[hashtype]) continue; /* Do hash scan */ if((ret = cli_hm_scan(digest[hashtype], map->len, &virname, hdb, hashtype)) == CL_VIRUS) { found += 1; } if(!found || SCAN_ALL) { if ((ret = cli_hm_scan_wild(digest[hashtype], &virname_w, hdb, hashtype)) == CL_VIRUS) found += 2; } /* If found, do immediate hash-only FP check */ if (found && fp) { for(hashtype2 = CLI_HASH_MD5; hashtype2 < CLI_HASH_AVAIL_TYPES; hashtype2++) { if(!compute_hash[hashtype2]) continue; if(cli_hm_scan(digest[hashtype2], map->len, NULL, fp, hashtype2) == CL_VIRUS) { found = 0; ret = CL_CLEAN; break; } else if(cli_hm_scan_wild(digest[hashtype2], NULL, fp, hashtype2) == CL_VIRUS) { found = 0; ret = CL_CLEAN; break; } } } /* If matched size-based hash ... */ if (found % 2) { viruses_found = 1; cli_append_virus(ctx, virname); if (!SCAN_ALL) break; virname = NULL; } /* If matched size-agnostic hash ... */ if (found > 1) { viruses_found = 1; cli_append_virus(ctx, virname_w); if (!SCAN_ALL) break; } } } cl_hash_destroy(md5ctx); cl_hash_destroy(sha1ctx); cl_hash_destroy(sha256ctx); if(troot) { if(ret != CL_VIRUS || SCAN_ALL) ret = cli_exp_eval(ctx, troot, &tdata, &info, (const char *)refhash); if (ret == CL_VIRUS) viruses_found++; cli_ac_freedata(&tdata); if(bm_offmode) cli_bm_freeoff(&toff); cli_pcre_freeoff(&tpoff); } if(groot) { if(ret != CL_VIRUS || SCAN_ALL) ret = cli_exp_eval(ctx, groot, &gdata, &info, (const char *)refhash); cli_ac_freedata(&gdata); cli_pcre_freeoff(&gpoff); } 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; }