Пример #1
0
/* 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;
}
Пример #2
0
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;
}
Пример #3
0
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;
    }
}
Пример #4
0
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;
}