Merge branch 'allscan'

pull/25/head
Steve Morgan 13 years ago
commit e4d0ef0184
  1. 28
      clamd/scanner.c
  2. 256
      clamd/session.c
  3. 5
      clamd/session.h
  4. 4
      clamdscan/client.c
  5. 4
      clamdscan/client.h
  6. 11
      clamdscan/proto.c
  7. 31
      clamscan/manager.c
  8. 22
      libclamav/7z_iface.c
  9. 31
      libclamav/bytecode.c
  10. 4
      libclamav/bytecode.h
  11. 3
      libclamav/bytecode_api.c
  12. 1
      libclamav/clamav.h
  13. 20
      libclamav/elf.c
  14. 3
      libclamav/macho.c
  15. 28
      libclamav/matcher-ac.c
  16. 2
      libclamav/matcher-ac.h
  17. 7
      libclamav/matcher-bm.c
  18. 2
      libclamav/matcher-bm.h
  19. 162
      libclamav/matcher.c
  20. 15
      libclamav/mbox.c
  21. 38
      libclamav/others.c
  22. 8
      libclamav/others.h
  23. 6
      libclamav/pdf.c
  24. 105
      libclamav/pe.c
  25. 3
      libclamav/pe_icons.c
  26. 22
      libclamav/phishcheck.c
  27. 2
      libclamav/readdb.c
  28. 2
      libclamav/regex_list.c
  29. 332
      libclamav/scanners.c
  30. 2
      libclamav/special.c
  31. 10
      libclamav/swf.c
  32. 17
      libclamav/untar.c
  33. 2
      libclamav/unzip.c
  34. 1
      shared/optparser.c
  35. 3
      unit_tests/check_bytecode.c
  36. 164
      unit_tests/check_clamav.c
  37. 80
      unit_tests/check_matchers.c
  38. 98
      unit_tests/check_regex.c

@ -107,6 +107,7 @@ int scan_callback(STATBUF *sb, char *filename, const char *msg, enum cli_ftw_rea
{
struct scan_cb_data *scandata = data->data;
const char *virname;
const char **virpp = &virname;
int ret;
int type = scandata->type;
struct cb_context context;
@ -227,11 +228,18 @@ int scan_callback(STATBUF *sb, char *filename, const char *msg, enum cli_ftw_rea
thrmgr_setactivetask(filename, NULL);
context.filename = filename;
context.virsize = 0;
ret = cl_scanfile_callback(filename, &virname, &scandata->scanned, scandata->engine, scandata->options, &context);
ret = cl_scanfile_callback(filename, virpp, &scandata->scanned, scandata->engine, scandata->options, &context);
thrmgr_setactivetask(NULL, NULL);
if (scandata->options & CL_SCAN_ALLMATCHES) {
virpp = (const char **)*virpp; /* temp hack for scanall mode until api augmentation */
virname = virpp[0];
}
if (thrmgr_group_need_terminate(scandata->conn->group)) {
free(filename);
if (ret == CL_VIRUS && scandata->options & CL_SCAN_ALLMATCHES)
free((void *)virpp);
logg("*Client disconnected while scanjob was active\n");
return ret == CL_ETIMEOUT ? ret : CL_BREAK;
}
@ -240,8 +248,19 @@ int scan_callback(STATBUF *sb, char *filename, const char *msg, enum cli_ftw_rea
scandata->infected++;
if (conn_reply_virus(scandata->conn, filename, virname) == -1) {
free(filename);
if (scandata->options & CL_SCAN_ALLMATCHES)
free((void *)virpp);
return CL_ETIMEOUT;
}
if (scandata->options & CL_SCAN_ALLMATCHES && virpp[1] != NULL) {
int i = 1;
while (NULL != virpp[i])
if (conn_reply_virus(scandata->conn, filename, virpp[i++]) == -1) {
free(filename);
free((void *)virpp);
return CL_ETIMEOUT;
}
}
if(context.virsize)
detstats_add(virname, filename, context.virsize, context.virhash);
if(context.virsize && optget(scandata->opts, "ExtendedDetectionInfo")->enabled)
@ -249,6 +268,11 @@ int scan_callback(STATBUF *sb, char *filename, const char *msg, enum cli_ftw_rea
else
logg("~%s: %s FOUND\n", filename, virname);
virusaction(filename, virname, scandata->opts);
if (scandata->options & CL_SCAN_ALLMATCHES && virpp[1] != NULL) {
int i = 1;
while (NULL != virpp[i])
logg("~%s: %s FOUND\n", filename, virpp[i++]);
}
} else if (ret != CL_CLEAN) {
scandata->errors++;
if (conn_reply(scandata->conn, filename, cl_strerror(ret), "ERROR") == -1) {
@ -261,6 +285,8 @@ int scan_callback(STATBUF *sb, char *filename, const char *msg, enum cli_ftw_rea
}
free(filename);
if (ret == CL_VIRUS && scandata->options & CL_SCAN_ALLMATCHES)
free((void *)virpp);
if(ret == CL_EMEM) /* stop scanning */
return ret;

@ -94,7 +94,8 @@ static struct {
{CMD16, sizeof(CMD16)-1, COMMAND_IDSESSION, 0, 0, 1},
{CMD17, sizeof(CMD17)-1, COMMAND_INSTREAM, 0, 0, 1},
{CMD19, sizeof(CMD19)-1, COMMAND_DETSTATSCLEAR, 0, 1, 1},
{CMD20, sizeof(CMD20)-1, COMMAND_DETSTATS, 0, 1, 1}
{CMD20, sizeof(CMD20)-1, COMMAND_DETSTATS, 0, 1, 1},
{CMD21, sizeof(CMD21)-1, COMMAND_ALLMATCHSCAN, 1, 0, 1}
};
enum commands parse_command(const char *cmd, const char **argument, int oldstyle)
@ -314,129 +315,135 @@ int command(client_conn_t *conn, int *virus)
}
return ret;
#else
conn_reply_error(conn, "FILDES support not compiled in.");
close(conn->scanfd);
return 0;
#endif
case COMMAND_STATS:
thrmgr_setactivetask(NULL, "STATS");
if (conn->group)
mdprintf(desc, "%u: ", conn->id);
thrmgr_printstats(desc, conn->term);
return 0;
case COMMAND_STREAM:
thrmgr_setactivetask(NULL, "STREAM");
ret = scanstream(desc, NULL, engine, options, opts, conn->term);
if (ret == CL_VIRUS)
*virus = 1;
if (ret == CL_EMEM) {
if(optget(opts, "ExitOnOOM")->enabled)
return -1;
else
return 1;
}
return 0;
case COMMAND_INSTREAMSCAN:
thrmgr_setactivetask(NULL, "INSTREAM");
ret = scanfd(conn, NULL, engine, options, opts, desc, 1);
if (ret == CL_VIRUS) {
*virus = 1;
ret = 0;
} else if (ret == CL_EMEM) {
if(optget(opts, "ExitOnOOM")->enabled)
ret = -1;
else
ret = 1;
} else if (ret == CL_ETIMEOUT) {
thrmgr_group_terminate(conn->group);
ret = 1;
} else
ret = 0;
if (ftruncate(conn->scanfd, 0) == -1) {
/* not serious, we're going to close it and unlink it anyway */
logg("*ftruncate failed: %d\n", errno);
}
close(conn->scanfd);
conn->scanfd = -1;
cli_unlink(conn->filename);
return ret;
default:
logg("!Invalid command distpached: %d\n", conn->cmdtype);
return 1;
}
scandata.type = type;
maxdirrec = optget(opts, "MaxDirectoryRecursion")->numarg;
if (optget(opts, "FollowDirectorySymlinks")->enabled)
flags |= CLI_FTW_FOLLOW_DIR_SYMLINK;
if (optget(opts, "FollowFileSymlinks")->enabled)
flags |= CLI_FTW_FOLLOW_FILE_SYMLINK;
if(!optget(opts, "CrossFilesystems")->enabled)
if(STAT(conn->filename, &sb) == 0)
scandata.dev = sb.st_dev;
ret = cli_ftw(conn->filename, flags, maxdirrec ? maxdirrec : INT_MAX, scan_callback, &data, scan_pathchk);
if (ret == CL_EMEM) {
if(optget(opts, "ExitOnOOM")->enabled)
return -1;
else
return 1;
}
if (scandata.group && type == TYPE_MULTISCAN) {
thrmgr_group_waitforall(group, &ok, &error, &total);
pthread_mutex_lock(&conn->thrpool->pool_mutex);
conn->thrpool->thr_multiscan--;
pthread_mutex_unlock(&conn->thrpool->pool_mutex);
} else {
error = scandata.errors;
total = scandata.total;
ok = total - error - scandata.infected;
}
if (ok + error == total && (error != total)) {
if (conn_reply_single(conn, conn->filename, "OK") == -1)
ret = CL_ETIMEOUT;
}
*virus = total - (ok + error);
if (ret == CL_ETIMEOUT)
thrmgr_group_terminate(conn->group);
return error;
}
static int dispatch_command(client_conn_t *conn, enum commands cmd, const char *argument)
{
int ret = 0;
int bulk;
client_conn_t *dup_conn = (client_conn_t *) malloc(sizeof(struct client_conn_tag));
if(!dup_conn) {
logg("!Can't allocate memory for client_conn\n");
return -1;
}
memcpy(dup_conn, conn, sizeof(*conn));
dup_conn->cmdtype = cmd;
if(cl_engine_addref(dup_conn->engine)) {
logg("!cl_engine_addref() failed\n");
free(dup_conn);
return -1;
}
dup_conn->scanfd = -1;
bulk = 1;
switch (cmd) {
case COMMAND_FILDES:
if (conn->scanfd == -1) {
conn_reply_error(dup_conn, "No file descriptor received.");
ret = 1;
}
dup_conn->scanfd = conn->scanfd;
/* consume FD */
conn->scanfd = -1;
break;
case COMMAND_SCAN:
case COMMAND_CONTSCAN:
case COMMAND_MULTISCAN:
conn_reply_error(conn, "FILDES support not compiled in.");
close(conn->scanfd);
return 0;
#endif
case COMMAND_STATS:
thrmgr_setactivetask(NULL, "STATS");
if (conn->group)
mdprintf(desc, "%u: ", conn->id);
thrmgr_printstats(desc, conn->term);
return 0;
case COMMAND_STREAM:
thrmgr_setactivetask(NULL, "STREAM");
ret = scanstream(desc, NULL, engine, options, opts, conn->term);
if (ret == CL_VIRUS)
*virus = 1;
if (ret == CL_EMEM) {
if(optget(opts, "ExitOnOOM")->enabled)
return -1;
else
return 1;
}
return 0;
case COMMAND_INSTREAMSCAN:
thrmgr_setactivetask(NULL, "INSTREAM");
ret = scanfd(conn, NULL, engine, options, opts, desc, 1);
if (ret == CL_VIRUS) {
*virus = 1;
ret = 0;
} else if (ret == CL_EMEM) {
if(optget(opts, "ExitOnOOM")->enabled)
ret = -1;
else
ret = 1;
} else if (ret == CL_ETIMEOUT) {
thrmgr_group_terminate(conn->group);
ret = 1;
} else
ret = 0;
if (ftruncate(conn->scanfd, 0) == -1) {
/* not serious, we're going to close it and unlink it anyway */
logg("*ftruncate failed: %d\n", errno);
}
close(conn->scanfd);
conn->scanfd = -1;
cli_unlink(conn->filename);
return ret;
case COMMAND_ALLMATCHSCAN:
thrmgr_setactivetask(NULL, "ALLMATCHSCAN");
scandata.options |= CL_SCAN_ALLMATCHES;
type = TYPE_SCAN;
break;
default:
logg("!Invalid command distpached: %d\n", conn->cmdtype);
return 1;
}
scandata.type = type;
maxdirrec = optget(opts, "MaxDirectoryRecursion")->numarg;
if (optget(opts, "FollowDirectorySymlinks")->enabled)
flags |= CLI_FTW_FOLLOW_DIR_SYMLINK;
if (optget(opts, "FollowFileSymlinks")->enabled)
flags |= CLI_FTW_FOLLOW_FILE_SYMLINK;
if(!optget(opts, "CrossFilesystems")->enabled)
if(STAT(conn->filename, &sb) == 0)
scandata.dev = sb.st_dev;
ret = cli_ftw(conn->filename, flags, maxdirrec ? maxdirrec : INT_MAX, scan_callback, &data, scan_pathchk);
if (ret == CL_EMEM) {
if(optget(opts, "ExitOnOOM")->enabled)
return -1;
else
return 1;
}
if (scandata.group && type == TYPE_MULTISCAN) {
thrmgr_group_waitforall(group, &ok, &error, &total);
pthread_mutex_lock(&conn->thrpool->pool_mutex);
conn->thrpool->thr_multiscan--;
pthread_mutex_unlock(&conn->thrpool->pool_mutex);
} else {
error = scandata.errors;
total = scandata.total;
ok = total - error - scandata.infected;
}
if (ok + error == total && (error != total)) {
if (conn_reply_single(conn, conn->filename, "OK") == -1)
ret = CL_ETIMEOUT;
}
*virus = total - (ok + error);
if (ret == CL_ETIMEOUT)
thrmgr_group_terminate(conn->group);
return error;
}
static int dispatch_command(client_conn_t *conn, enum commands cmd, const char *argument)
{
int ret = 0;
int bulk;
client_conn_t *dup_conn = (client_conn_t *) malloc(sizeof(struct client_conn_tag));
if(!dup_conn) {
logg("!Can't allocate memory for client_conn\n");
return -1;
}
memcpy(dup_conn, conn, sizeof(*conn));
dup_conn->cmdtype = cmd;
if(cl_engine_addref(dup_conn->engine)) {
logg("!cl_engine_addref() failed\n");
free(dup_conn);
return -1;
}
dup_conn->scanfd = -1;
bulk = 1;
switch (cmd) {
case COMMAND_FILDES:
if (conn->scanfd == -1) {
conn_reply_error(dup_conn, "No file descriptor received.");
ret = 1;
}
dup_conn->scanfd = conn->scanfd;
/* consume FD */
conn->scanfd = -1;
break;
case COMMAND_SCAN:
case COMMAND_CONTSCAN:
case COMMAND_MULTISCAN:
case COMMAND_ALLMATCHSCAN:
dup_conn->filename = cli_strdup_to_utf8(argument);
if (!dup_conn->filename) {
logg("!Failed to allocate memory for filename\n");
@ -608,6 +615,7 @@ int execute_or_dispatch_command(client_conn_t *conn, enum commands cmd, const ch
case COMMAND_FILDES:
case COMMAND_SCAN:
case COMMAND_INSTREAMSCAN:
case COMMAND_ALLMATCHSCAN:
return dispatch_command(conn, cmd, argument);
case COMMAND_IDSESSION:
conn->group = thrmgr_group_new();

@ -43,6 +43,8 @@
#define CMD19 "DETSTATSCLEAR"
#define CMD20 "DETSTATS"
#define CMD21 "ALLMATCHSCAN"
#include "libclamav/clamav.h"
#include "shared/optparser.h"
#include "server.h"
@ -70,7 +72,8 @@ enum commands {
COMMAND_DETSTATS,
/* internal commands */
COMMAND_MULTISCANFILE,
COMMAND_INSTREAMSCAN
COMMAND_INSTREAMSCAN,
COMMAND_ALLMATCHSCAN
};
typedef struct client_conn_tag {

@ -236,7 +236,9 @@ int client(const struct optstruct *opts, int *infected, int *err)
if(remote || scandash) {
scantype = STREAM;
session = optget(opts, "multiscan")->enabled;
} else if(optget(opts, "multiscan")->enabled) scantype = MULTI;
}
else if(optget(opts, "multiscan")->enabled) scantype = MULTI;
else if(optget(opts, "allmatch")->enabled) scantype = ALLMATCH;
else scantype = CONT;
maxrec = optget(clamdopts, "MaxDirectoryRecursion")->numarg;

@ -27,7 +27,9 @@ enum {
CONT,
MULTI,
STREAM,
FILDES
FILDES,
ALLMATCH,
MAX_SCANTYPE = ALLMATCH
};
int client(const struct optstruct *opts, int *infected, int *err);

@ -58,7 +58,7 @@ extern unsigned long int maxstream;
int printinfected;
extern struct optstruct *clamdopts;
static const char *scancmd[] = { "CONTSCAN", "MULTISCAN" };
static const char *scancmd[] = { "CONTSCAN", "MULTISCAN", "INSTREAM", "FILDES", "ALLMATCHSCAN" };
/* Connects to clamd
* Returns a FD or -1 on error */
@ -203,6 +203,7 @@ int dsresult(int sockd, int scantype, const char *filename, int *printok, int *e
switch(scantype) {
case MULTI:
case CONT:
case ALLMATCH:
if (!filename) {
logg("Filename cannot be NULL for MULTISCAN or CONTSCAN.\n");
return -1;
@ -254,7 +255,13 @@ int dsresult(int sockd, int scantype, const char *filename, int *printok, int *e
colon = strrchr(bol, ':');
}
if(!colon) {
logg("Failed to parse reply\n");
char * unkco = "UNKNOWN COMMAND";
if (!strncmp(bol, unkco, sizeof(unkco) - 1))
logg("clamd replied \"UNKNOWN COMMAND\". Command was %s\n",
(scantype < 0 || scantype > MAX_SCANTYPE) ? "unidentified" :
scancmd[scantype]);
else
logg("Failed to parse reply: \"%s\"\n", bol);
return -1;
} else if(!memcmp(eol - 7, " FOUND", 6)) {
*(eol - 7) = 0;

@ -217,6 +217,7 @@ static void scanfile(const char *filename, struct cl_engine *engine, const struc
unsigned i;
const struct optstruct *opt;
const char *virname;
const char **virpp = &virname;
STATBUF sb;
struct metachain chain;
@ -291,7 +292,7 @@ static void scanfile(const char *filename, struct cl_engine *engine, const struc
}
if((ret = cl_scandesc_callback(fd, &virname, &info.blocks, engine, options, &chain)) == CL_VIRUS) {
if((ret = cl_scandesc_callback(fd, virpp, &info.blocks, engine, options, &chain)) == CL_VIRUS) {
if(optget(opts, "archive-verbose")->enabled) {
if (chain.n > 1) {
char str[128];
@ -300,7 +301,16 @@ static void scanfile(const char *filename, struct cl_engine *engine, const struc
} else if (chain.lastvir)
logg("~%s!(%d): %s FOUND\n", filename, chain.lastvir-1, virname);
}
logg("~%s: %s FOUND\n", filename, virname);
if (options & CL_SCAN_ALLMATCHES) {
int i = 0;
virpp = (const char **)*virpp; /* horrible */
virname = virpp[0];
while (virpp[i])
logg("~%s: %s FOUND\n", filename, virpp[i++]);
free((void *)virpp);
}
else
logg("~%s: %s FOUND\n", filename, virname);
info.files++;
info.ifiles++;
@ -432,6 +442,8 @@ static int scanstdin(const struct cl_engine *engine, const struct optstruct *opt
int ret;
unsigned int fsize = 0;
const char *virname, *tmpdir;
const char **virpp = &virname;
char *file, buff[FILEBUFF];
size_t bread;
FILE *fs;
@ -474,7 +486,17 @@ static int scanstdin(const struct cl_engine *engine, const struct optstruct *opt
info.rblocks += fsize / CL_COUNT_PRECISION;
if((ret = cl_scanfile(file, &virname, &info.blocks, engine, options)) == CL_VIRUS) {
logg("stdin: %s FOUND\n", virname);
if (options & CL_SCAN_ALLMATCHES) {
int i = 0;
virpp = (const char **)*virpp; /* temp hack for scanall mode until api augmentation */
virname = virpp[0];
while (virpp[i])
logg("stdin: %s FOUND\n", virpp[i++]);
free((void *)virpp);
}
else
logg("stdin: %s FOUND\n", virname);
info.ifiles++;
if(bell)
@ -710,6 +732,9 @@ int scanmanager(const struct optstruct *opts)
}
/* set scan options */
if(optget(opts, "allmatch")->enabled)
options |= CL_SCAN_ALLMATCHES;
if(optget(opts,"phishing-ssl")->enabled)
options |= CL_SCAN_PHISHING_BLOCKSSL;

@ -81,6 +81,7 @@ int cli_7unz (cli_ctx *ctx, size_t offset) {
UInt16 utf16buf[UTFBUFSZ], *utf16name = utf16buf;
int namelen = UTFBUFSZ, found = CL_CLEAN;
Int64 begin_of_archive = offset;
UInt32 viruses_found = 0;
/* Replacement for
FileInStream_CreateVTable(&archiveStream); */
@ -150,14 +151,19 @@ int cli_7unz (cli_ctx *ctx, size_t offset) {
encrypted = 1;
if(DETECT_ENCRYPTED) {
cli_dbgmsg("cli_7unz: Encrypted files found in archive.\n");
*ctx->virname = "Heuristics.Encrypted.7Zip";
found = CL_VIRUS;
break;
cli_append_virus(ctx, "Heuristics.Encrypted.7Zip");
viruses_found++;
if(!SCAN_ALL) {
found = CL_VIRUS;
break;
}
}
}
if(cli_matchmeta(ctx, name, 0, f->Size, encrypted, i, f->CrcDefined ? f->Crc : 0, NULL)) {
found = CL_VIRUS;
break;
viruses_found++;
if (!SCAN_ALL)
break;
}
if (res != SZ_OK)
cli_dbgmsg("cli_unz: extraction failed with %d\n", res);
@ -169,14 +175,16 @@ int cli_7unz (cli_ctx *ctx, size_t offset) {
if(cli_writen(fd, outBuffer + offset, outSizeProcessed) != outSizeProcessed)
found = CL_EWRITE;
else
found = cli_magic_scandesc(fd, ctx);
if ((found = cli_magic_scandesc(fd, ctx)) == CL_VIRUS)
viruses_found++;
close(fd);
if(!ctx->engine->keeptmp && cli_unlink(name))
found = CL_EUNLINK;
free(name);
if(found != CL_CLEAN)
break;
if (!(SCAN_ALL && found == CL_VIRUS))
break;
}
}
IAlloc_Free(&allocImp, outBuffer);
@ -196,5 +204,7 @@ int cli_7unz (cli_ctx *ctx, size_t offset) {
else
cli_dbgmsg("cli_7unz: error %d\n", res);
if (SCAN_ALL && viruses_found)
return CL_VIRUS;
return found;
}

@ -2594,7 +2594,7 @@ int cli_bytecode_context_setfile(struct cli_bc_ctx *ctx, fmap_t *map)
int cli_bytecode_runlsig(cli_ctx *cctx, struct cli_target_info *tinfo,
const struct cli_all_bc *bcs, unsigned bc_idx,
const char **virname, const uint32_t* lsigcnt,
const uint32_t* lsigcnt,
const uint32_t *lsigsuboff, fmap_t *map)
{
int ret;
@ -2641,9 +2641,8 @@ int cli_bytecode_runlsig(cli_ctx *cctx, struct cli_target_info *tinfo,
if (ctx.virname) {
int rc;
cli_dbgmsg("Bytecode found virus: %s\n", ctx.virname);
if (virname)
*virname = ctx.virname;
if (!strncmp(*virname, "BC.Heuristics", 13))
cli_append_virus(cctx, ctx.virname);
if (!strncmp(ctx.virname, "BC.Heuristics", 13))
rc = cli_found_possibly_unwanted(cctx);
else
rc = CL_VIRUS;
@ -2657,7 +2656,7 @@ int cli_bytecode_runlsig(cli_ctx *cctx, struct cli_target_info *tinfo,
}
int cli_bytecode_runhook(cli_ctx *cctx, const struct cl_engine *engine, struct cli_bc_ctx *ctx,
unsigned id, fmap_t *map, const char **virname)
unsigned id, fmap_t *map)
{
const unsigned *hooks = engine->hooks[id - _BC_START_HOOKS];
unsigned i, hooks_cnt = engine->hooks_cnt[id - _BC_START_HOOKS];
@ -2690,10 +2689,13 @@ int cli_bytecode_runhook(cli_ctx *cctx, const struct cl_engine *engine, struct c
}
if (ctx->virname) {
cli_dbgmsg("Bytecode found virus: %s\n", ctx->virname);
if (virname)
*virname = ctx->virname;
cli_bytecode_context_clear(ctx);
return CL_VIRUS;
cli_append_virus(cctx, ctx->virname);
if (!(cctx->options & CL_SCAN_ALLMATCHES)) {
cli_bytecode_context_clear(ctx);
return CL_VIRUS;
}
cli_bytecode_context_reset(ctx);
continue;
}
ret = cli_bytecode_context_getresult_int(ctx);
/* TODO: use prefix here */
@ -2726,10 +2728,15 @@ int cli_bytecode_runhook(cli_ctx *cctx, const struct cl_engine *engine, struct c
}
free(tempfile);
if (ret != CL_CLEAN) {
if (ret == CL_VIRUS)
if (ret == CL_VIRUS) {
cli_dbgmsg("Scanning unpacked file by bytecode %u found a virus\n", bc->id);
cli_bytecode_context_clear(ctx);
return ret;
if (cctx->options & CL_SCAN_ALLMATCHES) {
cli_bytecode_context_reset(ctx);
continue;
}
cli_bytecode_context_clear(ctx);
return ret;
}
}
cli_bytecode_context_reset(ctx);
continue;

@ -118,8 +118,8 @@ void cli_bytecode_describe(const struct cli_bc *bc);
struct cli_exe_info;
struct cli_ctx_tag;
struct cli_target_info;
int cli_bytecode_runlsig(struct cli_ctx_tag *ctx, struct cli_target_info *info, const struct cli_all_bc *bcs, unsigned bc_idx, const char **virname, const uint32_t* lsigcnt, const uint32_t *lsigsuboff, fmap_t *map);
int cli_bytecode_runhook(struct cli_ctx_tag *cctx, const struct cl_engine *engine, struct cli_bc_ctx *ctx, unsigned id, fmap_t *map, const char **virname);
int cli_bytecode_runlsig(struct cli_ctx_tag *ctx, struct cli_target_info *info, const struct cli_all_bc *bcs, unsigned bc_idx, const uint32_t* lsigcnt, const uint32_t *lsigsuboff, fmap_t *map);
int cli_bytecode_runhook(struct cli_ctx_tag *cctx, const struct cl_engine *engine, struct cli_bc_ctx *ctx, unsigned id, fmap_t *map);
#ifdef __cplusplus
extern "C" {

@ -511,8 +511,7 @@ int32_t cli_bcapi_extract_new(struct cli_bc_ctx *ctx, int32_t id)
cctx->recursion--;
cctx->container_type = current;
if (res == CL_VIRUS) {
if (cctx->virname)
ctx->virname = *cctx->virname;
ctx->virname = cli_get_last_virus(cctx);
ctx->found = 1;
}
}

@ -142,6 +142,7 @@ typedef enum {
#define CL_SCAN_PARTIAL_MESSAGE 0x40000
#define CL_SCAN_HEURISTIC_PRECEDENCE 0x80000
#define CL_SCAN_BLOCKMACROS 0x100000
#define CL_SCAN_ALLMATCHES 0x200000
#define CL_SCAN_PERFORMANCE_INFO 0x40000000 /* collect performance timings */
#define CL_SCAN_INTERNAL_COLLECT_SHA 0x80000000 /* Enables hash output in sha-collect builds - for internal use only */

@ -73,7 +73,7 @@ int cli_scanelf(cli_ctx *ctx)
uint8_t conv = 0, err;
unsigned int format;
fmap_t *map = *ctx->fmap;
uint32_t viruses_found = 0;
cli_dbgmsg("in cli_scanelf\n");
@ -214,8 +214,7 @@ int cli_scanelf(cli_ctx *ctx)
if(phnum > 128) {
cli_dbgmsg("ELF: Suspicious number of program headers\n");
if(DETECT_BROKEN) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
cli_append_virus(ctx, "Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_EFORMAT;
@ -227,8 +226,7 @@ int cli_scanelf(cli_ctx *ctx)
if(phentsize != sizeof(struct elf_program_hdr32)) {
cli_dbgmsg("ELF: phentsize != sizeof(struct elf_program_hdr32)\n");
if(DETECT_BROKEN) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
cli_append_virus(ctx, "Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_EFORMAT;
@ -275,8 +273,7 @@ int cli_scanelf(cli_ctx *ctx)
cli_dbgmsg("ELF: Possibly broken ELF file\n");
free(program_hdr);
if(DETECT_BROKEN) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
cli_append_virus(ctx, "Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_CLEAN;
@ -296,8 +293,7 @@ int cli_scanelf(cli_ctx *ctx)
if(err) {
cli_dbgmsg("ELF: Can't calculate file offset of entry point\n");
if(DETECT_BROKEN) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
cli_append_virus(ctx, "Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_EFORMAT;
@ -319,8 +315,7 @@ int cli_scanelf(cli_ctx *ctx)
if(shentsize != sizeof(struct elf_section_hdr32)) {
cli_dbgmsg("ELF: shentsize != sizeof(struct elf_section_hdr32)\n");
if(DETECT_BROKEN) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
cli_append_virus(ctx, "Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_EFORMAT;
@ -369,8 +364,7 @@ int cli_scanelf(cli_ctx *ctx)
cli_dbgmsg("ELF: Possibly broken ELF file\n");
free(section_hdr);
if(DETECT_BROKEN) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
cli_append_virus(ctx, "Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_CLEAN;

@ -175,8 +175,7 @@ struct macho_fat_arch
if(matcher) \
return -1; \
if(DETECT_BROKEN) { \
if(ctx->virname) \
*ctx->virname = "Heuristics.Broken.Executable"; \
cli_append_virus(ctx, "Heuristics.Broken.Executable"); \
return CL_VIRUS; \
} \
return CL_EFORMAT

@ -1157,7 +1157,7 @@ void cli_ac_chkmacro(struct cli_matcher *root, struct cli_ac_data *data, unsigne
}
int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, void **customdata, struct cli_ac_result **res, const struct cli_matcher *root, struct cli_ac_data *mdata, uint32_t offset, cli_file_t ftype, struct cli_matched_type **ftoffset, unsigned int mode, const cli_ctx *ctx)
int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, void **customdata, struct cli_ac_result **res, const struct cli_matcher *root, struct cli_ac_data *mdata, uint32_t offset, cli_file_t ftype, struct cli_matched_type **ftoffset, unsigned int mode, cli_ctx *ctx)
{
struct cli_ac_node *current;
struct cli_ac_patt *patt, *pt;
@ -1359,11 +1359,18 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
pt = pt->next_same;
continue;
} else {
if(virname)
*virname = pt->virname;
if(virname) {
if (ctx && SCAN_ALL && virname == ctx->virname)
cli_append_virus(ctx, (const char *)pt->virname);
else
*virname = pt->virname;
}
if(customdata)
*customdata = pt->customdata;
return CL_VIRUS;
if (!ctx || !SCAN_ALL)
return CL_VIRUS;
pt = pt->next_same;
continue;
}
}
}
@ -1403,11 +1410,18 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
pt = pt->next_same;
continue;
} else {
if(virname)
*virname = pt->virname;
if(virname) {
if (ctx && SCAN_ALL && virname == ctx->virname)
cli_append_virus(ctx, pt->virname);
else
*virname = pt->virname;
}
if(customdata)
*customdata = pt->customdata;
return CL_VIRUS;
if (!ctx || !SCAN_ALL)
return CL_VIRUS;
pt = pt->next_same;
continue;
}
}
}

@ -93,7 +93,7 @@ int cli_ac_initdata(struct cli_ac_data *data, uint32_t partsigs, uint32_t lsigs,
void cli_ac_chkmacro(struct cli_matcher *root, struct cli_ac_data *data, unsigned lsigid1);
int cli_ac_chklsig(const char *expr, const char *end, uint32_t *lsigcnt, unsigned int *cnt, uint64_t *ids, unsigned int parse_only);
void cli_ac_freedata(struct cli_ac_data *data);
int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, void **customdata, struct cli_ac_result **res, const struct cli_matcher *root, struct cli_ac_data *mdata, uint32_t offset, cli_file_t ftype, struct cli_matched_type **ftoffset, unsigned int mode, const cli_ctx *ctx);
int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, void **customdata, struct cli_ac_result **res, const struct cli_matcher *root, struct cli_ac_data *mdata, uint32_t offset, cli_file_t ftype, struct cli_matched_type **ftoffset, unsigned int mode, cli_ctx *ctx);
int cli_ac_buildtrie(struct cli_matcher *root);
int cli_ac_init(struct cli_matcher *root, uint8_t mindepth, uint8_t maxdepth, uint8_t dconf_prefiltering);
int cli_ac_caloff(const struct cli_matcher *root, struct cli_ac_data *data, const struct cli_target_info *info);

@ -244,7 +244,7 @@ void cli_bm_free(struct cli_matcher *root)
}
}
int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_bm_patt **patt, const struct cli_matcher *root, uint32_t offset, const struct cli_target_info *info, struct cli_bm_off *offdata)
int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_bm_patt **patt, const struct cli_matcher *root, uint32_t offset, const struct cli_target_info *info, struct cli_bm_off *offdata, uint32_t *viroffset)
{
uint32_t i, j, off, off_min, off_max;
uint8_t found, pchain, shift;
@ -374,8 +374,11 @@ int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
continue;
}
}
if(virname)
if(virname) {
*virname = p->virname;
if(viroffset)
*viroffset = offset + i + j - BM_MIN_LENGTH + BM_BLOCK_SIZE;
}
if(patt)
*patt = p;
return CL_VIRUS;

@ -47,7 +47,7 @@ int cli_bm_addpatt(struct cli_matcher *root, struct cli_bm_patt *pattern, const
int cli_bm_init(struct cli_matcher *root);
int cli_bm_initoff(const struct cli_matcher *root, struct cli_bm_off *data, const struct cli_target_info *info);
void cli_bm_freeoff(struct cli_bm_off *data);
int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_bm_patt **patt, const struct cli_matcher *root, uint32_t offset, const struct cli_target_info *info, struct cli_bm_off *offdata);
int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_bm_patt **patt, const struct cli_matcher *root, uint32_t offset, const struct cli_target_info *info, struct cli_bm_off *offdata, uint32_t *viroffset);
void cli_bm_free(struct cli_matcher *root);
#endif

@ -91,13 +91,16 @@ static inline int matcher_run(const struct cli_matcher *root,
unsigned int acmode,
struct cli_ac_result **acres,
fmap_t *map,
struct cli_bm_off *offdata)
struct cli_bm_off *offdata,
uint32_t *viroffset,
cli_ctx *ctx)
{
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) {
if(filter_search_ext(root->filter, buffer, length, &info) == -1) {
@ -128,15 +131,30 @@ static inline int matcher_run(const struct cli_matcher *root,
/* 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 */
ret = cli_bm_scanbuff(orig_buffer, orig_length, virname, NULL, root, orig_offset, tinfo, offdata);
ret = cli_bm_scanbuff(orig_buffer, orig_length, virname, NULL, root, orig_offset, tinfo, offdata, viroffset);
} else {
ret = cli_bm_scanbuff(buffer, length, virname, NULL, root, offset, tinfo, offdata);
ret = cli_bm_scanbuff(buffer, length, virname, NULL, root, offset, tinfo, offdata, viroffset);
}
if (ret == CL_VIRUS) {
if (ctx) {
cli_append_virus(ctx, *virname);
#if 1
if (SCAN_ALL)
viruses_found++;
else
#endif
return ret;
}
}
if (ret == CL_VIRUS)
return ret;
}
PERF_LOG_TRIES(acmode, 0, length);
ret = cli_ac_scanbuff(buffer, length, virname, NULL, acres, root, mdata, offset, ftype, ftoffset, acmode, NULL);
#if 1
if (ctx && ret == CL_VIRUS)
cli_append_virus(ctx, *virname);
if (ctx && SCAN_ALL && viruses_found)
return CL_VIRUS;
#endif
return ret;
}
@ -146,7 +164,7 @@ int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset,
unsigned int i;
struct cli_ac_data mdata;
struct cli_matcher *groot, *troot = NULL;
const char **virname=ctx->virname;
const char *virname = NULL;
const struct cl_engine *engine=ctx->engine;
if(!engine) {
@ -170,8 +188,10 @@ int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset,
if(!acdata && (ret = cli_ac_initdata(&mdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
return ret;
ret = matcher_run(troot, buffer, length, virname, acdata ? (acdata[0]): (&mdata), offset, NULL, ftype, NULL, AC_SCAN_VIR, NULL, *ctx->fmap, NULL);
ret = matcher_run(troot, buffer, length, &virname, acdata ? (acdata[0]): (&mdata), offset, NULL, ftype, NULL, AC_SCAN_VIR, NULL, *ctx->fmap, NULL, NULL, ctx);
// if (virname)
// cli_append_virus(ctx, virname);
if(!acdata)
cli_ac_freedata(&mdata);
@ -179,11 +199,15 @@ int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset,
return ret;
}
virname = NULL;
if(!acdata && (ret = cli_ac_initdata(&mdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
return ret;
ret = matcher_run(groot, buffer, length, virname, acdata ? (acdata[1]): (&mdata), offset, NULL, ftype, NULL, AC_SCAN_VIR, NULL, *ctx->fmap, NULL);
ret = matcher_run(groot, buffer, length, &virname, acdata ? (acdata[1]): (&mdata), offset, NULL, ftype, NULL, AC_SCAN_VIR, NULL, *ctx->fmap, NULL, NULL, ctx);
// if (virname)
// cli_append_virus(ctx, virname);
if(!acdata)
cli_ac_freedata(&mdata);
@ -412,11 +436,12 @@ int cli_checkfp(unsigned char *digest, size_t size, cli_ctx *ctx)
for(i = 0; i < 16; i++)
sprintf(md5 + i * 2, "%02x", digest[i]);
md5[32] = 0;
cli_dbgmsg("FP SIGNATURE: %s:%u:%s\n", md5, (unsigned int) size, *ctx->virname ? *ctx->virname : "Name");
cli_dbgmsg("FP SIGNATURE: %s:%u:%s\n", md5, (unsigned int) size,
cli_get_last_virus(ctx) ? cli_get_last_virus(ctx) : "Name");
}
if(ctx->virname)
do_dsig_check = strncmp("W32S.", *ctx->virname, 5);
if(cli_get_last_virus(ctx))
do_dsig_check = strncmp("W32S.", cli_get_last_virus(ctx), 5);
map = *ctx->fmap;
have_sha1 = cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, size) || (cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, 1) && do_dsig_check);
@ -487,7 +512,7 @@ int cli_checkfp(unsigned char *digest, size_t size, cli_ctx *ctx)
}
}
if (ctx->engine->cb_hash)
ctx->engine->cb_hash(fmap_fd(*ctx->fmap), size, md5, ctx->virname ? *ctx->virname : NULL, ctx->cb_ctx);
ctx->engine->cb_hash(fmap_fd(*ctx->fmap), size, md5, cli_get_last_virus(ctx), ctx->cb_ctx);
return CL_VIRUS;
}
@ -572,6 +597,7 @@ int cli_lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *ac
unsigned int i, evalcnt;
uint64_t evalids;
fmap_t *map = *ctx->fmap;
unsigned int viruses_found = 0;
for(i = 0; i < root->ac_lsigs; i++) {
evalcnt = 0;
@ -598,6 +624,10 @@ int cli_lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *ac
memcpy(ctx->handlertype_hash, hash, 16);
if(cli_magic_scandesc_type(ctx, root->ac_lsigtable[i]->tdb.handlertype[0]) == CL_VIRUS) {
ctx->recursion--;
if (SCAN_ALL) {
viruses_found++;
continue;
}
return CL_VIRUS;
}
ctx->recursion--;
@ -610,25 +640,41 @@ int cli_lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *ac
continue;
if(matchicon(ctx, &target_info->exeinfo, root->ac_lsigtable[i]->tdb.icongrp1, root->ac_lsigtable[i]->tdb.icongrp2) == CL_VIRUS) {
if(!root->ac_lsigtable[i]->bc_idx) {
if(ctx->virname)
*ctx->virname = root->ac_lsigtable[i]->virname;
cli_append_virus(ctx, root->ac_lsigtable[i]->virname);
if (SCAN_ALL) {
viruses_found++;
continue;
}
return CL_VIRUS;
} else if(cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, root->ac_lsigtable[i]->bc_idx, ctx->virname, acdata->lsigcnt[i], acdata->lsigsuboff_first[i], map) == CL_VIRUS) {
} else if(cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, root->ac_lsigtable[i]->bc_idx, acdata->lsigcnt[i], acdata->lsigsuboff_first[i], map) == CL_VIRUS) {
if (SCAN_ALL) {
viruses_found++;
continue;
}
return CL_VIRUS;
}
}
continue;
}
if(!root->ac_lsigtable[i]->bc_idx) {
if(ctx->virname)
*ctx->virname = root->ac_lsigtable[i]->virname;
return CL_VIRUS;
cli_append_virus(ctx, root->ac_lsigtable[i]->virname);
if (SCAN_ALL) {
viruses_found++;
continue;
}
return CL_VIRUS;
}
if(cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, root->ac_lsigtable[i]->bc_idx, ctx->virname, acdata->lsigcnt[i], acdata->lsigsuboff_first[i], map) == CL_VIRUS) {
return CL_VIRUS;
if(cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, root->ac_lsigtable[i]->bc_idx, acdata->lsigcnt[i], acdata->lsigsuboff_first[i], map) == CL_VIRUS) {
if (SCAN_ALL) {
viruses_found++;
continue;
}
return CL_VIRUS;
}
}
}
if (SCAN_ALL && viruses_found)
return CL_VIRUS;
return CL_CLEAN;
}
@ -648,6 +694,9 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
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");
@ -749,9 +798,15 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
*ctx->scanned += bytes / CL_COUNT_PRECISION;
if(troot) {
ret = matcher_run(troot, buff, bytes, ctx->virname, &tdata, offset, &info, ftype, ftoffset, acmode, acres, map, bm_offmode ? &toff : NULL);
virname = NULL;
viroffset = 0;
ret = matcher_run(troot, buff, bytes, &virname, &tdata, offset, &info, ftype, ftoffset, acmode, acres, map, bm_offmode ? &toff : NULL, &viroffset, ctx);
if(ret == CL_VIRUS || ret == CL_EMEM) {
if (virname) {
// cli_append_virus(ctx, virname);
viruses_found++;
}
if((ret == CL_VIRUS && !SCAN_ALL) || ret == CL_EMEM) {
if(!ftonly)
cli_ac_freedata(&gdata);
cli_ac_freedata(&tdata);
@ -765,9 +820,15 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
}
if(!ftonly) {
ret = matcher_run(groot, buff, bytes, ctx->virname, &gdata, offset, &info, ftype, ftoffset, acmode, acres, map, NULL);
virname = NULL;
viroffset = 0;
ret = matcher_run(groot, buff, bytes, &virname, &gdata, offset, &info, ftype, ftoffset, acmode, acres, map, NULL, &viroffset, ctx);
if(ret == CL_VIRUS || ret == CL_EMEM) {
if (virname) {
// cli_append_virus(ctx, virname);
viruses_found++;
}
if((ret == CL_VIRUS && !SCAN_ALL) || ret == CL_EMEM) {
cli_ac_freedata(&gdata);
if(troot) {
cli_ac_freedata(&tdata);
@ -783,7 +844,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
type = ret;
}
if(hdb) {
if(hdb && !SCAN_ALL) {
const void *data = buff + maxpatlen * (offset!=0);
uint32_t data_len = bytes - maxpatlen * (offset!=0);
@ -796,12 +857,17 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
}
}
if(SCAN_ALL && viroffset) {
offset = viroffset;
continue;
}
if(bytes < SCANBUFF) break;
offset += bytes - maxpatlen;
}
if(!ftonly && hdb) {
enum CLI_HASH_TYPE hashtype;
unsigned int hvirs = 0, hfps = 0;
if(compute_hash[CLI_HASH_MD5])
cli_md5_final(digest[CLI_HASH_MD5], &md5ctx);
@ -812,31 +878,39 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
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, ctx->virname, hdb, hashtype)) == CL_VIRUS)
break;
}
if(compute_hash[hashtype] && (ret = cli_hm_scan(digest[hashtype], map->len, &virname, hdb, hashtype)) == CL_VIRUS) {
if(ret == CL_VIRUS && fp) {
for(hashtype = CLI_HASH_MD5; hashtype < CLI_HASH_AVAIL_TYPES; hashtype++) {
if(compute_hash[hashtype] && cli_hm_scan(digest[hashtype], map->len, ctx->virname, fp, hashtype) == CL_VIRUS) {
ret = CL_CLEAN;
break;
if(fp && cli_hm_scan(digest[hashtype], map->len, NULL, fp, hashtype) == CL_VIRUS) {
hfps++;
continue;
}
hvirs++;
cli_append_virus(ctx, virname);
virname = NULL;
if(!SCAN_ALL)
break;
}
}
if(hvirs > hfps)
ret = CL_VIRUS;
else
ret = CL_CLEAN;
}
if(troot) {
if(ret != CL_VIRUS)
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)
if(ret != CL_VIRUS || SCAN_ALL)
ret = cli_lsig_eval(ctx, groot, &gdata, &info, refhash);
cli_ac_freedata(&gdata);
}
@ -845,6 +919,8 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
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;
@ -854,6 +930,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
int cli_matchmeta(cli_ctx *ctx, const char *fname, size_t fsizec, size_t fsizer, int encrypted, unsigned int filepos, int res1, void *res2)
{
const struct cli_cdb *cdb;
unsigned int viruses_found = 0;
cli_dbgmsg("CDBNAME:%s:%lu:%s:%lu:%lu:%d:%u:%u:%p\n",
cli_ftname(ctx->container_type), fsizec, fname, fsizec, fsizer, encrypted, filepos, res1, res2);
@ -861,8 +938,11 @@ int cli_matchmeta(cli_ctx *ctx, const char *fname, size_t fsizec, size_t fsizer,
if (ctx->engine && ctx->engine->cb_meta)
if (ctx->engine->cb_meta(cli_ftname(ctx->container_type), fsizec, fname, fsizer, encrypted, filepos, ctx->cb_ctx) == CL_VIRUS) {
cli_dbgmsg("inner file blacklisted by callback: %s\n", fname);
*ctx->virname = "Detected.By.Callback";
return CL_VIRUS;
cli_append_virus(ctx, "Detected.By.Callback");
viruses_found++;
if(!SCAN_ALL)
return CL_VIRUS;
}
if(!ctx->engine || !(cdb = ctx->engine->cdb))
@ -895,10 +975,14 @@ int cli_matchmeta(cli_ctx *ctx, const char *fname, size_t fsizec, size_t fsizer,
if(cdb->name.re_magic && (!fname || cli_regexec(&cdb->name, fname, 0, NULL, 0) == REG_NOMATCH))
continue;
*ctx->virname = cdb->virname;
return CL_VIRUS;
cli_append_virus(ctx, cdb->virname);
viruses_found++;
if(!SCAN_ALL)
return CL_VIRUS;
} while((cdb = cdb->next));
if (SCAN_ALL && viruses_found)
return CL_VIRUS;
return CL_CLEAN;
}

@ -544,11 +544,18 @@ cli_parse_mbox(const char *dir, cli_ctx *ctx)
*/
messageDestroy(body);
}
#if 0
if((retcode == CL_CLEAN) && ctx->found_possibly_unwanted && (*ctx->virname == NULL)) {
*ctx->virname = "Heuristics.Phishing.Email";
ctx->found_possibly_unwanted = 0;
retcode = CL_VIRUS;
*ctx->virname = "Heuristics.Phishing.Email";
#else
/* TBD: Breaks unit_test/check1_clamscan.sh and check2_clamd.sh w/SCAN_ALL */
if((retcode == CL_CLEAN) && ctx->found_possibly_unwanted &&
(*ctx->virname == NULL || SCAN_ALL)) {
cli_append_virus(ctx, "Heuristics.Phishing.Email");
#endif
ctx->found_possibly_unwanted = 0;
retcode = CL_VIRUS;
}
cli_dbgmsg("cli_mbox returning %d\n", retcode);

@ -770,6 +770,44 @@ int cli_unlink(const char *pathname)
return 0;
}
void cli_append_virus(cli_ctx * ctx, const char * virname)
{
if (!ctx->virname)
return;
if (SCAN_ALL) {
if (ctx->size_viruses == 0) {
ctx->size_viruses = 2;
if (!(ctx->virname = malloc(ctx->size_viruses * sizeof(char *)))) {
cli_errmsg("cli_append_virus: fails on malloc() - virus %s virname not appended.\n", virname);
return;
}
} else if (ctx->num_viruses+1 == ctx->size_viruses) {
ctx->size_viruses *= 2;
if ((ctx->virname = realloc((void *)ctx->virname, ctx->size_viruses * sizeof (char *))) == NULL) {
cli_errmsg("cli_append_virus: fails on realloc() - virus %s virname not appended.\n", virname);
return;
}
}
ctx->virname[ctx->num_viruses++] = virname;
ctx->virname[ctx->num_viruses] = NULL;
}
else
*ctx->virname = virname;
}
const char * cli_get_last_virus(const cli_ctx * ctx)
{
if (!ctx->virname)
return NULL;
if (SCAN_ALL && ctx->num_viruses) {
return ctx->virname[ctx->num_viruses-1];
}
else
return *ctx->virname;
}
#ifdef C_WINDOWS
/*
* Windows doesn't allow you to delete a directory while it is still open

@ -55,7 +55,7 @@
* in re-enabling affected modules.
*/
#define CL_FLEVEL 72
#define CL_FLEVEL 73
#define CL_FLEVEL_DCONF CL_FLEVEL
#define CL_FLEVEL_SIGTOOL CL_FLEVEL
@ -111,6 +111,8 @@ typedef struct bitset_tag
/* internal clamav context */
typedef struct cli_ctx_tag {
const char **virname;
unsigned int num_viruses; /* manages virname when CL_SCAN_ALLMATCHES == 1 */
unsigned int size_viruses; /* manages virname when CL_SCAN_ALLMATCHES == 1 */
unsigned long int *scanned;
const struct cli_matcher *root;
const struct cl_engine *engine;
@ -324,6 +326,7 @@ extern int have_rar;
#define DETECT_BROKEN (ctx->options & CL_SCAN_BLOCKBROKEN)
#define BLOCK_MACROS (ctx->options & CL_SCAN_BLOCKMACROS)
#define SCAN_STRUCTURED (ctx->options & CL_SCAN_STRUCTURED)
#define SCAN_ALL (ctx->options & CL_SCAN_ALLMATCHES)
/* based on macros from A. Melnikoff */
#define cbswap16(v) (((v & 0xff) << 8) | (((v) >> 8) & 0xff))
@ -422,6 +425,9 @@ static inline void cli_writeint32(char *offset, uint32_t value)
}
#endif
void cli_append_virus(cli_ctx *ctx, const char *virname);
const char *cli_get_last_virus(const cli_ctx *ctx);
/* used by: spin, yc (C) aCaB */
#define __SHIFTBITS(a) (sizeof(a)<<3)
#define __SHIFTMASK(a) (__SHIFTBITS(a)-1)

@ -584,7 +584,7 @@ static int run_pdf_hooks(struct pdf_struct *pdf, enum pdf_phase phase, int fd,
cli_bytecode_context_setpdf(bc_ctx, phase, pdf->nobjs, pdf->objs,
&pdf->flags, pdf->size, pdf->startoff);
cli_bytecode_context_setctx(bc_ctx, ctx);
ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PDF, map, ctx->virname);
ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PDF, map);
cli_bytecode_context_destroy(bc_ctx);
if (fd != -1) {
funmap(map);
@ -2074,7 +2074,7 @@ int cli_pdf(const char *dir, cli_ctx *ctx, off_t offset)
/* It is encrypted, and a password/key needs to be supplied to decrypt.
* This doesn't trigger for PDFs that are encrypted but don't need
* a password to decrypt */
*ctx->virname = "Heuristics.Encrypted.PDF";
cli_append_virus(ctx, "Heuristics.Encrypted.PDF");
rc = CL_VIRUS;
}
@ -2096,7 +2096,7 @@ int cli_pdf(const char *dir, cli_ctx *ctx, off_t offset)
if (!rc && (ctx->options & CL_SCAN_ALGORITHMIC)) {
if (pdf.flags & (1 << ESCAPED_COMMON_PDFNAME)) {
/* for example /Fl#61te#44#65#63#6f#64#65 instead of /FlateDecode */
*ctx->virname = "Heuristics.PDF.ObfuscatedNameObject";
cli_append_virus(ctx, "Heuristics.PDF.ObfuscatedNameObject");
rc = cli_found_possibly_unwanted(ctx);
}
}

@ -537,6 +537,8 @@ int cli_scanpe(cli_ctx *ctx)
#ifdef HAVE__INTERNAL__SHA_COLLECT
int sha_collect = ctx->sha_collect;
#endif
const char * virname = NULL;
uint32_t viruses_found = 0;
if(!ctx) {
cli_errmsg("cli_scanpe: ctx == NULL\n");
@ -557,8 +559,7 @@ int cli_scanpe(cli_ctx *ctx)
cli_dbgmsg("Can't read new header address\n");
/* truncated header? */
if(DETECT_BROKEN_PE) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
cli_append_virus(ctx,"Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_CLEAN;
@ -687,8 +688,7 @@ int cli_scanpe(cli_ctx *ctx)
nsections = EC16(file_hdr.NumberOfSections);
if(nsections < 1 || nsections > 96) {
if(DETECT_BROKEN_PE) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
cli_append_virus(ctx,"Heuristics.Broken.Executable");
return CL_VIRUS;
}
if(!ctx->corrupted_input) {
@ -709,8 +709,7 @@ int cli_scanpe(cli_ctx *ctx)
if (EC16(file_hdr.SizeOfOptionalHeader) < sizeof(struct pe_image_optional_hdr32)) {
cli_dbgmsg("SizeOfOptionalHeader too small\n");
if(DETECT_BROKEN_PE) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
cli_append_virus(ctx,"Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_CLEAN;
@ -720,8 +719,7 @@ int cli_scanpe(cli_ctx *ctx)
if(fmap_readn(map, &optional_hdr32, at, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) {
cli_dbgmsg("Can't read optional file header\n");
if(DETECT_BROKEN_PE) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
cli_append_virus(ctx,"Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_CLEAN;
@ -734,8 +732,7 @@ int cli_scanpe(cli_ctx *ctx)
/* FIXME: need to play around a bit more with xp64 */
cli_dbgmsg("Incorrect SizeOfOptionalHeader for PE32+\n");
if(DETECT_BROKEN_PE) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
cli_append_virus(ctx,"Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_CLEAN;
@ -777,8 +774,7 @@ int cli_scanpe(cli_ctx *ctx)
if(fmap_readn(map, &optional_hdr32 + 1, at, sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) {
cli_dbgmsg("Can't read optional file header\n");
if(DETECT_BROKEN_PE) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
cli_append_virus(ctx,"Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_CLEAN;
@ -858,15 +854,13 @@ int cli_scanpe(cli_ctx *ctx)
if (DETECT_BROKEN_PE && !native && (!(pe_plus?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment)) || (pe_plus?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment))%0x1000)) {
cli_dbgmsg("Bad virtual alignemnt\n");
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
cli_append_virus(ctx,"Heuristics.Broken.Executable");
return CL_VIRUS;
}
if (DETECT_BROKEN_PE && !native && (!(pe_plus?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment)) || (pe_plus?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment))%0x200)) {
cli_dbgmsg("Bad file alignemnt\n");
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
cli_append_virus(ctx, "Heuristics.Broken.Executable");
return CL_VIRUS;
}
@ -896,8 +890,7 @@ int cli_scanpe(cli_ctx *ctx)
free(section_hdr);
free(exe_sections);
if(DETECT_BROKEN_PE) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
cli_append_virus(ctx,"Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_CLEAN;
@ -964,8 +957,7 @@ int cli_scanpe(cli_ctx *ctx)
if (DETECT_BROKEN_PE && (!valign || (exe_sections[i].urva % valign))) { /* Bad virtual alignment */
cli_dbgmsg("VirtualAddress is misaligned\n");
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
cli_append_virus(ctx, "Heuristics.Broken.Executable");
free(section_hdr);
free(exe_sections);
return CL_VIRUS;
@ -977,8 +969,7 @@ int cli_scanpe(cli_ctx *ctx)
free(section_hdr);
free(exe_sections);
if(DETECT_BROKEN_PE) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
cli_append_virus(ctx, "Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_CLEAN; /* no ninjas to see here! move along! */
@ -992,15 +983,19 @@ int cli_scanpe(cli_ctx *ctx)
unsigned char md5_dig[16];
if(cli_hm_have_size(md5_sect, CLI_HASH_MD5, exe_sections[i].rsz) &&
cli_md5sect(map, &exe_sections[i], md5_dig) &&
cli_hm_scan(md5_dig, exe_sections[i].rsz, ctx->virname, md5_sect, CLI_HASH_MD5) == CL_VIRUS) {
cli_hm_scan(md5_dig, exe_sections[i].rsz, &virname, md5_sect, CLI_HASH_MD5) == CL_VIRUS) {
if(cli_hm_scan(md5_dig, fsize, NULL, ctx->engine->hm_fp, CLI_HASH_MD5) != CL_VIRUS) {
free(section_hdr);
free(exe_sections);
return CL_VIRUS;
if (!SCAN_ALL) {
free(section_hdr);
free(exe_sections);
return CL_VIRUS;
}
}
cli_append_virus(ctx, virname);
viruses_found++;
}
}
}
if (exe_sections[i].urva>>31 || exe_sections[i].uvsz>>31 || (exe_sections[i].rsz && exe_sections[i].uraw>>31) || exe_sections[i].ursz>>31) {
@ -1008,8 +1003,7 @@ int cli_scanpe(cli_ctx *ctx)
free(section_hdr);
free(exe_sections);
if(DETECT_BROKEN_PE) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
cli_append_virus(ctx, "Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_CLEAN;
@ -1018,8 +1012,7 @@ int cli_scanpe(cli_ctx *ctx)
if(!i) {
if (DETECT_BROKEN_PE && exe_sections[i].urva!=hdr_size) { /* Bad first section RVA */
cli_dbgmsg("First section is in the wrong place\n");
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
cli_append_virus(ctx, "Heuristics.Broken.Executable");
free(section_hdr);
free(exe_sections);
return CL_VIRUS;
@ -1029,8 +1022,7 @@ int cli_scanpe(cli_ctx *ctx)
} else {
if (DETECT_BROKEN_PE && exe_sections[i].urva - exe_sections[i-1].urva != exe_sections[i-1].vsz) { /* No holes, no overlapping, no virtual disorder */
cli_dbgmsg("Virtually misplaced section (wrong order, overlapping, non contiguous)\n");
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
cli_append_virus(ctx, "Heuristics.Broken.Executable");
free(section_hdr);
free(exe_sections);
return CL_VIRUS;
@ -1051,8 +1043,7 @@ int cli_scanpe(cli_ctx *ctx)
cli_dbgmsg("EntryPoint out of file\n");
free(exe_sections);
if(DETECT_BROKEN_PE) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
cli_append_virus(ctx,"Heuristics.Broken.Executable");
return CL_VIRUS;
}
return CL_CLEAN;
@ -1112,7 +1103,7 @@ int cli_scanpe(cli_ctx *ctx)
}
cli_bytecode_context_setpe(bc_ctx, &pedata, exe_sections);
cli_bytecode_context_setctx(bc_ctx, ctx);
ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PE_ALL, map, ctx->virname);
ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PE_ALL, map);
switch (ret) {
case CL_ENULLARG:
cli_warnmsg("cli_scanpe: NULL argument supplied\n");
@ -1132,9 +1123,12 @@ int cli_scanpe(cli_ctx *ctx)
if(pt) {
pt += 15;
if((((uint32_t)cli_readint32(pt) ^ (uint32_t)cli_readint32(pt + 4)) == 0x505a4f) && (((uint32_t)cli_readint32(pt + 8) ^ (uint32_t)cli_readint32(pt + 12)) == 0xffffb) && (((uint32_t)cli_readint32(pt + 16) ^ (uint32_t)cli_readint32(pt + 20)) == 0xb8)) {
*ctx->virname = "Heuristics.W32.Parite.B";
free(exe_sections);
return CL_VIRUS;
cli_append_virus(ctx,"Heuristics.W32.Parite.B");
if (!SCAN_ALL) {
free(exe_sections);
return CL_VIRUS;
}
viruses_found++;
}
}
}
@ -1215,9 +1209,11 @@ int cli_scanpe(cli_ctx *ctx)
break;
case KZSLOOP:
if (op==kzdsize+0x48 && *kzcode==0x75 && kzlen-(int8_t)kzcode[1]-3<=kzinitlen && kzlen-(int8_t)kzcode[1]>=kzxorlen) {
*ctx->virname = "Heuristics.W32.Kriz";
cli_append_virus(ctx,"Heuristics.W32.Kriz");
free(exe_sections);
return CL_VIRUS;
if (!SCAN_ALL)
return CL_VIRUS;
viruses_found++;
}
cli_dbgmsg("kriz: loop out of bounds, corrupted sample?\n");
kzstate++;
@ -1242,9 +1238,11 @@ int cli_scanpe(cli_ctx *ctx)
if((tbuff = fmap_need_off_once(map, exe_sections[nsections - 1].raw + rsize - bw, 4096))) {
if(cli_memstr(tbuff, 4091, "\xe8\x2c\x61\x00\x00", 5)) {
*ctx->virname = dam ? "Heuristics.W32.Magistr.A.dam" : "Heuristics.W32.Magistr.A";
cli_append_virus(ctx, dam ? "Heuristics.W32.Magistr.A.dam" : "Heuristics.W32.Magistr.A");
free(exe_sections);
return CL_VIRUS;
if (!SCAN_ALL)
return CL_VIRUS;
viruses_found++;
}
}
@ -1254,9 +1252,11 @@ int cli_scanpe(cli_ctx *ctx)
if((tbuff = fmap_need_off_once(map, exe_sections[nsections - 1].raw + rsize - bw, 4096))) {
if(cli_memstr(tbuff, 4091, "\xe8\x04\x72\x00\x00", 5)) {
*ctx->virname = dam ? "Heuristics.W32.Magistr.B.dam" : "Heuristics.W32.Magistr.B";
cli_append_virus(ctx,dam ? "Heuristics.W32.Magistr.B.dam" : "Heuristics.W32.Magistr.B");
free(exe_sections);
return CL_VIRUS;
if (!SCAN_ALL)
return CL_VIRUS;
viruses_found++;
}
}
}
@ -1302,10 +1302,12 @@ int cli_scanpe(cli_ctx *ctx)
for(i=0;i<xsjs;i++) {
if(!(code = fmap_need_off_once(map, jumps[i], 9))) continue;
if((jump=cli_readint32(code))==0x60ec8b55 || (code[4]==0x0ec && ((jump==0x83ec8b55 && code[6]==0x60) || (jump==0x81ec8b55 && !code[7] && !code[8])))) {
*ctx->virname = "Heuristics.W32.Polipos.A";
cli_append_virus(ctx,"Heuristics.W32.Polipos.A");
free(jumps);
free(exe_sections);
return CL_VIRUS;
if (!SCAN_ALL)
return CL_VIRUS;
viruses_found++;
}
}
free(jumps);
@ -1324,13 +1326,16 @@ int cli_scanpe(cli_ctx *ctx)
else {
cli_parseres_special(EC32(dirs[2].VirtualAddress), EC32(dirs[2].VirtualAddress), map, exe_sections, nsections, fsize, hdr_size, 0, 0, &m, stats);
if ((ret = cli_detect_swizz(stats)) == CL_VIRUS) {
*ctx->virname = "Heuristics.Trojan.Swizzor.Gen";
cli_append_virus(ctx,"Heuristics.Trojan.Swizzor.Gen");
}
free(stats);
}
if (ret != CL_CLEAN) {
if (!(ret == CL_VIRUS && SCAN_ALL)) {
free(exe_sections);
return ret;
}
viruses_found++;
}
}
}
@ -2281,7 +2286,7 @@ int cli_scanpe(cli_ctx *ctx)
}
cli_bytecode_context_setpe(bc_ctx, &pedata, exe_sections);
cli_bytecode_context_setctx(bc_ctx, ctx);
ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PE_UNPACKER, map, ctx->virname);
ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PE_UNPACKER, map);
switch (ret) {
case CL_VIRUS:
free(exe_sections);
@ -2299,6 +2304,8 @@ int cli_scanpe(cli_ctx *ctx)
}
free(exe_sections);
if (SCAN_ALL && viruses_found)
return CL_VIRUS;
return CL_CLEAN;
}

@ -1513,8 +1513,7 @@ static int parseicon(icon_groupset *set, uint32_t rva, cli_ctx *ctx, struct cli_
if(confidence >= positivematch) {
cli_dbgmsg("confidence: %u\n", confidence);
if(ctx->virname)
*ctx->virname = matcher->icons[enginesize][x].name;
cli_append_virus(ctx,matcher->icons[enginesize][x].name);
return CL_VIRUS;
}
}

@ -735,7 +735,7 @@ int phishingScan(cli_ctx* ctx,tag_arguments_t* hrefs)
if(!pchk || pchk->is_disabled)
return CL_CLEAN;
if(!ctx->found_possibly_unwanted)
if(!ctx->found_possibly_unwanted && !SCAN_ALL)
*ctx->virname=NULL;
#if 0
FILE *f = fopen("/home/edwin/quarantine/urls","r");
@ -810,29 +810,29 @@ int phishingScan(cli_ctx* ctx,tag_arguments_t* hrefs)
case CL_PHISH_CLEAN:
continue;
case CL_PHISH_NUMERIC_IP:
*ctx->virname="Heuristics.Phishing.Email.Cloaked.NumericIP";
cli_append_virus(ctx, "Heuristics.Phishing.Email.Cloaked.NumericIP");
break;
case CL_PHISH_CLOAKED_NULL:
*ctx->virname="Heuristics.Phishing.Email.Cloaked.Null";/*fakesite%01%00@fake.example.com*/
cli_append_virus(ctx, "Heuristics.Phishing.Email.Cloaked.Null");/*fakesite%01%00@fake.example.com*/
break;
case CL_PHISH_SSL_SPOOF:
*ctx->virname="Heuristics.Phishing.Email.SSL-Spoof";
cli_append_virus(ctx, "Heuristics.Phishing.Email.SSL-Spoof");
break;
case CL_PHISH_CLOAKED_UIU:
*ctx->virname="Heuristics.Phishing.Email.Cloaked.Username";/*http://banksite@fake.example.com*/
cli_append_virus(ctx, "Heuristics.Phishing.Email.Cloaked.Username");/*http://banksite@fake.example.com*/
break;
case CL_PHISH_HASH0:
*ctx->virname="Heuristics.Safebrowsing.Suspected-malware_safebrowsing.clamav.net";
cli_append_virus(ctx, "Heuristics.Safebrowsing.Suspected-malware_safebrowsing.clamav.net");
break;
case CL_PHISH_HASH1:
*ctx->virname="Heuristics.Phishing.URL.Blacklisted";
cli_append_virus(ctx, "Heuristics.Phishing.URL.Blacklisted");
break;
case CL_PHISH_HASH2:
*ctx->virname="Heuristics.Safebrowsing.Suspected-phishing_safebrowsing.clamav.net";
cli_append_virus(ctx, "Heuristics.Safebrowsing.Suspected-phishing_safebrowsing.clamav.net");
break;
case CL_PHISH_NOMATCH:
default:
*ctx->virname="Heuristics.Phishing.Email.SpoofedDomain";
cli_append_virus(ctx, "Heuristics.Phishing.Email.SpoofedDomain");
break;
}
return cli_found_possibly_unwanted(ctx);
@ -1207,14 +1207,14 @@ static int hash_match(const struct regex_matcher *rlist, const char *host, size_
cli_dbgmsg("Looking up hash %s for %s(%u)%s(%u)\n", h, host, (unsigned)hlen, path, (unsigned)plen);
#if 0
if (prefix_matched) {
if (cli_bm_scanbuff(sha256_dig, 4, &virname, NULL, &rlist->hostkey_prefix,0,NULL,NULL) == CL_VIRUS) {
if (cli_bm_scanbuff(sha256_dig, 4, &virname, NULL, &rlist->hostkey_prefix,0,NULL,NULL,NULL) == CL_VIRUS) {
cli_dbgmsg("prefix matched\n");
*prefix_matched = 1;
} else
return CL_SUCCESS;
}
#endif
if (cli_bm_scanbuff(sha256_dig, 32, &virname, NULL, &rlist->sha256_hashes,0,NULL,NULL) == CL_VIRUS) {
if (cli_bm_scanbuff(sha256_dig, 32, &virname, NULL, &rlist->sha256_hashes,0,NULL,NULL,NULL) == CL_VIRUS) {
cli_dbgmsg("This hash matched: %s\n", h);
switch(*virname) {
case 'W':

@ -489,7 +489,7 @@ static int cli_chkign(const struct cli_matcher *ignored, const char *signame, co
if(!ignored || !signame || !entry)
return 0;
if(cli_bm_scanbuff((const unsigned char *) signame, strlen(signame), &md5_expected, NULL, ignored, 0, NULL, NULL) == CL_VIRUS) {
if(cli_bm_scanbuff((const unsigned char *) signame, strlen(signame), &md5_expected, NULL, ignored, 0, NULL, NULL,NULL) == CL_VIRUS) {
if(md5_expected) {
cli_md5_init(&md5ctx);
cli_md5_update(&md5ctx, entry, strlen(entry));

@ -357,7 +357,7 @@ static int add_hash(struct regex_matcher *matcher, char* pattern, const char fl,
if (fl != 'W' && pat->length == 32 &&
cli_hashset_contains(&matcher->sha256_pfx_set, cli_readint32(pat->pattern)) &&
cli_bm_scanbuff(pat->pattern, 32, &vname, NULL, &matcher->sha256_hashes,0,NULL,NULL) == CL_VIRUS) {
cli_bm_scanbuff(pat->pattern, 32, &vname, NULL, &matcher->sha256_hashes,0,NULL,NULL,NULL) == CL_VIRUS) {
if (*vname == 'W') {
/* hash is whitelisted in local.gdb */
cli_dbgmsg("Skipping hash %s\n", pattern);

@ -118,7 +118,7 @@ static int cli_scandir(const char *dirname, cli_ctx *ctx)
#endif
STATBUF statbuf;
char *fname;
unsigned int viruses_found = 0;
if((dd = opendir(dirname)) != NULL) {
#ifdef HAVE_READDIR_R_3
@ -145,29 +145,43 @@ static int cli_scandir(const char *dirname, cli_ctx *ctx)
if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) {
if(cli_scandir(fname, ctx) == CL_VIRUS) {
free(fname);
closedir(dd);
return CL_VIRUS;
}
if (SCAN_ALL) {
viruses_found++;
continue;
}
closedir(dd);
return CL_VIRUS;
}
} else {
if(S_ISREG(statbuf.st_mode)) {
if(cli_scanfile(fname, ctx) == CL_VIRUS) {
free(fname);
closedir(dd);
return CL_VIRUS;
}
if (SCAN_ALL) {
viruses_found++;
continue;
}
closedir(dd);
return CL_VIRUS;
}
}
}
}
free(fname);
}
}
}
}
} else {
cli_dbgmsg("cli_scandir: Can't open directory %s.\n", dirname);
return CL_EOPEN;
}
closedir(dd);
if (SCAN_ALL && viruses_found)
return CL_VIRUS;
return CL_CLEAN;
}
@ -194,7 +208,7 @@ static int cli_unrar_scanmetadata(int desc, unrar_metadata_t *metadata, cli_ctx
cli_dbgmsg("RAR: Encrypted files found in archive.\n");
ret = cli_scandesc(desc, ctx, 0, 0, NULL, AC_SCAN_VIR, NULL);
if(ret != CL_VIRUS) {
*ctx->virname = "Heuristics.Encrypted.RAR";
cli_append_virus(ctx, "Heuristics.Encrypted.RAR");
return CL_VIRUS;
}
}
@ -208,7 +222,7 @@ static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_c
unrar_metadata_t *metadata, *metadata_tmp;
char *dir;
unrar_state_t rar_state;
unsigned int viruses_found = 0;
cli_dbgmsg("in scanrar()\n");
@ -236,7 +250,7 @@ static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_c
lseek(desc, 0, SEEK_SET);
ret = cli_scandesc(desc, ctx, 0, 0, NULL, AC_SCAN_VIR, NULL);
if(ret != CL_VIRUS)
*ctx->virname = "Heuristics.Encrypted.RAR";
cli_append_virus(ctx, "Heuristics.Encrypted.RAR");
return CL_VIRUS;
}
return CL_CLEAN;
@ -286,12 +300,19 @@ static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_c
if(!ctx->engine->keeptmp)
if (cli_unlink(rar_state.filename)) ret = CL_EUNLINK;
if(rc == CL_VIRUS ) {
cli_dbgmsg("RAR: infected with %s\n",*ctx->virname);
cli_dbgmsg("RAR: infected with %s\n", cli_get_last_virus(ctx));
ret = CL_VIRUS;
break;
viruses_found++;
}
}
if(ret == CL_VIRUS) {
if(SCAN_ALL)
ret = CL_SUCCESS;
else
break;
}
if(ret == CL_SUCCESS)
ret = cli_unrar_scanmetadata(desc,rar_state.metadata_tail, ctx, rar_state.file_count, sfx_check);
@ -321,6 +342,8 @@ static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_c
}
cli_dbgmsg("RAR: Exit code: %d\n", ret);
if (SCAN_ALL && viruses_found)
return CL_VIRUS;
return ret;
}
@ -373,7 +396,7 @@ static int cli_scanarj(cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
rc = cli_magic_scandesc(metadata.ofd, ctx);
close(metadata.ofd);
if (rc == CL_VIRUS) {
cli_dbgmsg("ARJ: infected with %s\n",*ctx->virname);
cli_dbgmsg("ARJ: infected with %s\n", cli_get_last_virus(ctx));
ret = CL_VIRUS;
if (metadata.filename) {
free(metadata.filename);
@ -446,7 +469,7 @@ static int cli_scangzip_with_zib_from_the_80s(cli_ctx *ctx, unsigned char *buff)
gzclose(gz);
if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS) {
cli_dbgmsg("GZip: Infected with %s\n", *ctx->virname);
cli_dbgmsg("GZip: Infected with %s\n", cli_get_last_virus(ctx));
close(fd);
if(!ctx->engine->keeptmp) {
if (cli_unlink(tmpname)) {
@ -538,7 +561,7 @@ static int cli_scangzip(cli_ctx *ctx)
inflateEnd(&z);
if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS) {
cli_dbgmsg("GZip: Infected with %s\n", *ctx->virname);
cli_dbgmsg("GZip: Infected with %s\n", cli_get_last_virus(ctx));
close(fd);
if(!ctx->engine->keeptmp) {
if (cli_unlink(tmpname)) {
@ -648,7 +671,7 @@ static int cli_scanbzip(cli_ctx *ctx)
}
if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS ) {
cli_dbgmsg("Bzip: Infected with %s\n", *ctx->virname);
cli_dbgmsg("Bzip: Infected with %s\n", cli_get_last_virus(ctx));
}
close(fd);
if(!ctx->engine->keeptmp)
@ -700,7 +723,7 @@ static int cli_scanmscab(cli_ctx *ctx, off_t sfx_offset)
struct cab_archive cab;
struct cab_file *file;
unsigned int corrupted_input;
unsigned int viruses_found = 0;
cli_dbgmsg("in cli_scanmscab()\n");
@ -711,8 +734,11 @@ static int cli_scanmscab(cli_ctx *ctx, off_t sfx_offset)
files++;
if(cli_matchmeta(ctx, file->name, 0, file->length, 0, files, 0, NULL) == CL_VIRUS) {
ret = CL_VIRUS;
break;
if (!SCAN_ALL) {
ret = CL_VIRUS;
break;
}
viruses_found++;
}
if(ctx->engine->maxscansize && ctx->scansize >= ctx->engine->maxscansize) {
@ -751,11 +777,17 @@ static int cli_scanmscab(cli_ctx *ctx, off_t sfx_offset)
}
}
free(tempname);
if(ret == CL_VIRUS)
break;
if(ret == CL_VIRUS) {
if (SCAN_ALL)
viruses_found++;
else
break;
}
}
cab_free(&cab);
if (viruses_found)
return CL_VIRUS;
return ret;
}
@ -766,6 +798,7 @@ static int vba_scandata(const unsigned char *data, unsigned int len, cli_ctx *ct
struct cli_ac_data gmdata, tmdata;
struct cli_ac_data *mdata[2];
int ret;
unsigned int viruses_found = 0;
if((ret = cli_ac_initdata(&tmdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
return ret;
@ -779,14 +812,20 @@ static int vba_scandata(const unsigned char *data, unsigned int len, cli_ctx *ct
ret = cli_scanbuff(data, len, 0, ctx, CL_TYPE_MSOLE2, mdata);
if(ret != CL_VIRUS) {
if(ret != CL_VIRUS || SCAN_ALL) {
if (SCAN_ALL)
viruses_found++;
ret = cli_lsig_eval(ctx, troot, &tmdata, NULL, NULL);
if(ret != CL_VIRUS)
if(ret != CL_VIRUS || SCAN_ALL)
if (SCAN_ALL)
viruses_found++;
ret = cli_lsig_eval(ctx, groot, &gmdata, NULL, NULL);
}
cli_ac_freedata(&tmdata);
cli_ac_freedata(&gmdata);
if (viruses_found)
return CL_VIRUS;
return ret;
}
@ -807,6 +846,7 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
unsigned char *data;
char *hash;
uint32_t hashcnt;
unsigned int viruses_found = 0;
cli_dbgmsg("VBADir: %s\n", dirname);
@ -831,9 +871,13 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
if(ctx->scanned)
*ctx->scanned += data_len / CL_COUNT_PRECISION;
if(vba_scandata(data, data_len, ctx) == CL_VIRUS) {
free(data);
ret = CL_VIRUS;
break;
if (SCAN_ALL)
viruses_found++;
else {
free(data);
ret = CL_VIRUS;
break;
}
}
free(data);
}
@ -845,10 +889,12 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
free(vba_project->dir);
free(vba_project->offset);
free(vba_project);
if (ret == CL_VIRUS) break;
if (ret == CL_VIRUS && !SCAN_ALL)
break;
}
if(ret == CL_CLEAN && (hashcnt = uniq_get(U, "powerpoint document", 19, &hash))) {
if((ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) &&
(hashcnt = uniq_get(U, "powerpoint document", 19, &hash))) {
while(hashcnt--) {
snprintf(vbaname, 1024, "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
vbaname[sizeof(vbaname)-1] = '\0';
@ -857,6 +903,7 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
if ((fullname = cli_ppt_vba_read(fd, ctx))) {
if(cli_scandir(fullname, ctx) == CL_VIRUS) {
ret = CL_VIRUS;
viruses_found++;
}
if(!ctx->engine->keeptmp)
cli_rmdirs(fullname);
@ -866,7 +913,8 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
}
}
if (ret == CL_CLEAN && (hashcnt = uniq_get(U, "worddocument", 12, &hash))) {
if ((ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) &&
(hashcnt = uniq_get(U, "worddocument", 12, &hash))) {
while(hashcnt--) {
snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
vbaname[sizeof(vbaname)-1] = '\0';
@ -888,9 +936,13 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
if(ctx->scanned)
*ctx->scanned += vba_project->length[i] / CL_COUNT_PRECISION;
if(vba_scandata(data, vba_project->length[i], ctx) == CL_VIRUS) {
if (SCAN_ALL)
viruses_found++;
else {
free(data);
ret = CL_VIRUS;
break;
}
}
free(data);
}
@ -904,11 +956,16 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
free(vba_project->key);
free(vba_project->length);
free(vba_project);
if(ret == CL_VIRUS) break;
if(ret == CL_VIRUS) {
if (SCAN_ALL)
viruses_found++;
else
break;
}
}
}
if(ret != CL_CLEAN)
if(ret != CL_CLEAN && !(ret == CL_VIRUS && SCAN_ALL))
return ret;
/* Check directory for embedded OLE objects */
@ -921,7 +978,7 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
if (fd >= 0) {
ret = cli_scan_ole10(fd, ctx);
close(fd);
if(ret != CL_CLEAN)
if(ret != CL_CLEAN && !(ret == CL_VIRUS && SCAN_ALL))
return ret;
}
}
@ -954,10 +1011,14 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
if(LSTAT(fullname, &statbuf) != -1) {
if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode))
if (cli_vba_scandir(fullname, ctx, U) == CL_VIRUS) {
ret = CL_VIRUS;
free(fullname);
break;
}
if (SCAN_ALL)
viruses_found++;
else {
ret = CL_VIRUS;
free(fullname);
break;
}
}
}
free(fullname);
}
@ -970,9 +1031,12 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
closedir(dd);
if(BLOCK_MACROS && hasmacros) {
*ctx->virname = "Heuristics.OLE2.ContainsMacros";
cli_append_virus(ctx, "Heuristics.OLE2.ContainsMacros");
ret = CL_VIRUS;
viruses_found++;
}
if (SCAN_ALL && viruses_found)
return CL_VIRUS;
return ret;
}
@ -981,6 +1045,7 @@ static int cli_scanhtml(cli_ctx *ctx)
char *tempname, fullname[1024];
int ret=CL_CLEAN, fd;
fmap_t *map = *ctx->fmap;
unsigned int viruses_found = 0;
cli_dbgmsg("in cli_scanhtml()\n");
@ -1008,34 +1073,38 @@ static int cli_scanhtml(cli_ctx *ctx)
snprintf(fullname, 1024, "%s"PATHSEP"nocomment.html", tempname);
fd = open(fullname, O_RDONLY|O_BINARY);
if (fd >= 0) {
ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL);
close(fd);
if ((ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS)
viruses_found++;
close(fd);
}
if(ret == CL_CLEAN && map->len < 2097152) {
if((ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) && map->len < 2097152) {
/* limit to 2 MB, we're not interesting in scanning large files in notags form */
/* TODO: don't even create notags if file is over 2 MB */
snprintf(fullname, 1024, "%s"PATHSEP"notags.html", tempname);
fd = open(fullname, O_RDONLY|O_BINARY);
if(fd >= 0) {
ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL);
close(fd);
if ((ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS)
viruses_found++;
close(fd);
}
}
if(ret == CL_CLEAN) {
if(ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
snprintf(fullname, 1024, "%s"PATHSEP"javascript", tempname);
fd = open(fullname, O_RDONLY|O_BINARY);
if(fd >= 0) {
ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL);
if (ret == CL_CLEAN) {
ret = cli_scandesc(fd, ctx, CL_TYPE_TEXT_ASCII, 0, NULL, AC_SCAN_VIR, NULL);
}
close(fd);
if ((ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS)
viruses_found++;
if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
if ((ret = cli_scandesc(fd, ctx, CL_TYPE_TEXT_ASCII, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS)
viruses_found++;
}
close(fd);
}
}
if (ret == CL_CLEAN) {
if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
snprintf(fullname, 1024, "%s"PATHSEP"rfc2397", tempname);
ret = cli_scandir(fullname, ctx);
}
@ -1044,6 +1113,8 @@ static int cli_scanhtml(cli_ctx *ctx)
cli_rmdirs(tempname);
free(tempname);
if (SCAN_ALL && viruses_found)
return CL_VIRUS;
return ret;
}
@ -1061,6 +1132,7 @@ static int cli_scanscript(cli_ctx *ctx)
struct cli_ac_data *mdata[2];
fmap_t *map = *ctx->fmap;
size_t at = 0;
unsigned int viruses_found = 0;
if (!ctx || !ctx->engine->root)
return CL_ENULLARG;
@ -1094,7 +1166,7 @@ static int cli_scanscript(cli_ctx *ctx)
text_normalize_init(&state, normalized, SCANBUFF + maxpatlen);
ret = CL_CLEAN;
if ((ret = cli_ac_initdata(&tmdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
if ((ret = cli_ac_initdata(&tmdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
return ret;
if ((ret = cli_ac_initdata(&gmdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN))) {
@ -1118,8 +1190,12 @@ static int cli_scanscript(cli_ctx *ctx)
}
/* when we flush the buffer also scan */
if(cli_scanbuff(state.out, state.out_pos, offset, ctx, CL_TYPE_TEXT_ASCII, mdata) == CL_VIRUS) {
ret = CL_VIRUS;
break;
if (SCAN_ALL)
viruses_found++;
else {
ret = CL_VIRUS;
break;
}
}
if(ctx->scanned)
*ctx->scanned += state.out_pos / CL_COUNT_PRECISION;
@ -1140,14 +1216,18 @@ static int cli_scanscript(cli_ctx *ctx)
close(ofd);
}
free(normalized);
if(ret != CL_VIRUS) {
ret = cli_lsig_eval(ctx, troot, &tmdata, NULL, NULL);
if(ret != CL_VIRUS)
ret = cli_lsig_eval(ctx, groot, &gmdata, NULL, NULL);
if(ret != CL_VIRUS || SCAN_ALL) {
if ((ret = cli_lsig_eval(ctx, troot, &tmdata, NULL, NULL)) == CL_VIRUS)
viruses_found++;
if(ret != CL_VIRUS || SCAN_ALL)
if ((ret = cli_lsig_eval(ctx, groot, &gmdata, NULL, NULL)) == CL_VIRUS)
viruses_found++;
}
cli_ac_freedata(&tmdata);
cli_ac_freedata(&gmdata);
if (SCAN_ALL && viruses_found)
return CL_VIRUS;
return ret;
}
@ -1293,6 +1373,7 @@ static int cli_scanmschm(cli_ctx *ctx)
int ret = CL_CLEAN, rc;
chm_metadata_t metadata;
char *dir;
unsigned int viruses_found = 0;
cli_dbgmsg("in cli_scanmschm()\n");
@ -1325,9 +1406,13 @@ static int cli_scanmschm(cli_ctx *ctx)
rc = cli_magic_scandesc(metadata.ofd, ctx);
close(metadata.ofd);
if (rc == CL_VIRUS) {
cli_dbgmsg("CHM: infected with %s\n",*ctx->virname);
ret = CL_VIRUS;
break;
cli_dbgmsg("CHM: infected with %s\n", cli_get_last_virus(ctx));
if (SCAN_ALL)
viruses_found++;
else {
ret = CL_VIRUS;
break;
}
}
}
@ -1344,6 +1429,8 @@ static int cli_scanmschm(cli_ctx *ctx)
if (ret == CL_BREAK)
ret = CL_CLEAN;
if (SCAN_ALL && viruses_found)
return CL_VIRUS;
return ret;
}
@ -1379,7 +1466,7 @@ static int cli_scanriff(cli_ctx *ctx)
if(cli_check_riff_exploit(ctx) == 2) {
ret = CL_VIRUS;
*ctx->virname = "Heuristics.Exploit.W32.MS05-002";
cli_append_virus(ctx, "Heuristics.Exploit.W32.MS05-002");
}
return ret;
@ -1391,7 +1478,7 @@ static int cli_scanjpeg(cli_ctx *ctx)
if(cli_check_jpeg_exploit(ctx, 0) == 1) {
ret = CL_VIRUS;
*ctx->virname = "Heuristics.Exploit.W32.MS04-028";
cli_append_virus(ctx, "Heuristics.Exploit.W32.MS04-028");
}
return ret;
@ -1446,7 +1533,7 @@ static int cli_scancryptff(cli_ctx *ctx)
cli_dbgmsg("CryptFF: Scanning decrypted data\n");
if((ret = cli_magic_scandesc(ndesc, ctx)) == CL_VIRUS)
cli_dbgmsg("CryptFF: Infected with %s\n", *ctx->virname);
cli_dbgmsg("CryptFF: Infected with %s\n", cli_get_last_virus(ctx));
close(ndesc);
@ -1538,7 +1625,7 @@ static int cli_scanmail(cli_ctx *ctx)
{
char *dir;
int ret;
unsigned int viruses_found = 0;
cli_dbgmsg("Starting cli_scanmail(), recursion = %u\n", ctx->recursion);
@ -1556,10 +1643,14 @@ static int cli_scanmail(cli_ctx *ctx)
* Extract the attachments into the temporary directory
*/
if((ret = cli_mbox(dir, ctx))) {
if(!ctx->engine->keeptmp)
cli_rmdirs(dir);
free(dir);
return ret;
if (ret == CL_VIRUS && SCAN_ALL)
viruses_found++;
else {
if(!ctx->engine->keeptmp)
cli_rmdirs(dir);
free(dir);
return ret;
}
}
ret = cli_scandir(dir, ctx);
@ -1568,6 +1659,8 @@ static int cli_scanmail(cli_ctx *ctx)
cli_rmdirs(dir);
free(dir);
if (SCAN_ALL && viruses_found)
return CL_VIRUS;
return ret;
}
@ -1582,7 +1675,7 @@ static int cli_scan_structured(cli_ctx *ctx)
size_t pos = 0;
int (*ccfunc)(const unsigned char *buffer, int length);
int (*ssnfunc)(const unsigned char *buffer, int length);
unsigned int viruses_found;
if(ctx == NULL)
return CL_ENULLARG;
@ -1632,16 +1725,24 @@ static int cli_scan_structured(cli_ctx *ctx)
if(cc_count != 0 && cc_count >= ctx->engine->min_cc_count) {
cli_dbgmsg("cli_scan_structured: %u credit card numbers detected\n", cc_count);
*ctx->virname = "Heuristics.Structured.CreditCardNumber";
return CL_VIRUS;
cli_append_virus(ctx,"Heuristics.Structured.CreditCardNumber");
if (SCAN_ALL)
viruses_found++;
else
return CL_VIRUS;
}
if(ssn_count != 0 && ssn_count >= ctx->engine->min_ssn_count) {
cli_dbgmsg("cli_scan_structured: %u social security numbers detected\n", ssn_count);
*ctx->virname = "Heuristics.Structured.SSN";
return CL_VIRUS;
cli_append_virus(ctx,"Heuristics.Structured.SSN");
if (SCAN_ALL)
viruses_found++;
else
return CL_VIRUS;
}
if (SCAN_ALL && viruses_found)
return CL_VIRUS;
return CL_CLEAN;
}
@ -1707,7 +1808,7 @@ static int cli_scanembpe(cli_ctx *ctx, off_t offset)
ret = cli_magic_scandesc(fd, ctx);
ctx->corrupted_input = corrupted_input;
if(ret == CL_VIRUS) {
cli_dbgmsg("cli_scanembpe: Infected with %s\n", *ctx->virname);
cli_dbgmsg("cli_scanembpe: Infected with %s\n", cli_get_last_virus(ctx));
close(fd);
if(!ctx->engine->keeptmp) {
if (cli_unlink(tmpname)) {
@ -1903,7 +2004,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
if(ret >= CL_TYPENO) {
perf_nested_start(ctx, PERFT_RAWTYPENO, PERFT_SCAN);
ctx->recursion++;
if(nret != CL_VIRUS) {
if(nret != CL_VIRUS) { //TODO: don't need this test: nret == CL_CLEAN
lastrar = 0xdeadbeef;
fpt = ftoffset;
while(fpt) {
@ -2068,7 +2169,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
}
if(ret == CL_VIRUS)
cli_dbgmsg("%s found\n", *ctx->virname);
cli_dbgmsg("%s found\n", cli_get_last_virus(ctx));
return ret;
}
@ -2090,26 +2191,25 @@ static void emax_reached(cli_ctx *ctx) {
#define LINESTR2(x) LINESTR(x)
#define __AT__ " at line "LINESTR2(__LINE__)
#define early_ret_from_magicscan(retcode) \
do {\
cli_dbgmsg("cli_magic_scandesc: returning %d %s (no post, no cache)\n", retcode, __AT__);\
return retcode; \
#define early_ret_from_magicscan(retcode) \
do { \
cli_dbgmsg("cli_magic_scandesc: returning %d %s (no post, no cache)\n", retcode, __AT__); \
return retcode; \
} while(0)
#define ret_from_magicscan(retcode) \
do { \
cli_dbgmsg("cli_magic_scandesc: returning %d %s\n", retcode, __AT__); \
if(ctx->engine->cb_post_scan) { \
perf_start(ctx, PERFT_POSTCB); \
switch(ctx->engine->cb_post_scan(fmap_fd(*ctx->fmap), retcode, retcode == CL_VIRUS && ctx->virname ? *ctx->virname : NULL, ctx->cb_ctx)) { \
#define ret_from_magicscan(retcode) \
do { \
cli_dbgmsg("cli_magic_scandesc: returning %d %s\n", retcode, __AT__); \
if(ctx->engine->cb_post_scan) { \
perf_start(ctx, PERFT_POSTCB); \
switch(ctx->engine->cb_post_scan(fmap_fd(*ctx->fmap), retcode, ret == CL_VIRUS ? cli_get_last_virus(ctx) : NULL, ctx->cb_ctx)) { \
case CL_BREAK: \
cli_dbgmsg("cli_magic_scandesc: file whitelisted by post_scan callback\n"); \
perf_stop(ctx, PERFT_POSTCB); \
return CL_CLEAN; \
case CL_VIRUS: \
cli_dbgmsg("cli_magic_scandesc: file blacklisted by post_scan callback\n"); \
if(ctx->virname) \
*ctx->virname = "Detected.By.Callback"; \
cli_append_virus(ctx, "Detected.By.Callback"); \
perf_stop(ctx, PERFT_POSTCB); \
if (retcode != CL_VIRUS) \
return cli_checkfp(hash, hashed_size, ctx); \
@ -2140,8 +2240,7 @@ static void emax_reached(cli_ctx *ctx) {
ret_from_magicscan(CL_CLEAN); \
case CL_VIRUS: \
cli_dbgmsg("cli_magic_scandesc: file blacklisted by "#scanfn" callback\n"); \
if(ctx->virname) \
*ctx->virname = "Detected.By.Callback"; \
cli_append_virus(ctx, "Detected.By.Callback"); \
perf_stop(ctx, PERFT_PRECB); \
ret_from_magicscan(cli_checkfp(hash, hashed_size, ctx)); \
case CL_CLEAN: \
@ -2165,6 +2264,7 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
bitset_t *old_hook_lsig_matches;
const char *filetype;
int cache_clean = 0, res;
unsigned int viruses_found = 0;
cli_dbgmsg("in magic_scandesc\n");
if(ctx->engine->maxreclevel && ctx->recursion > ctx->engine->maxreclevel) {
@ -2212,7 +2312,7 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
old_hook_lsig_matches = ctx->hook_lsig_matches;
ctx->hook_lsig_matches = NULL;
if(!ctx->options || (ctx->recursion == ctx->engine->maxreclevel)) { /* raw mode (stdin, etc.) or last level of recursion */
if(!(ctx->options&~CL_SCAN_ALLMATCHES) || (ctx->recursion == ctx->engine->maxreclevel)) { /* raw mode (stdin, etc.) or last level of recursion */
if(ctx->recursion == ctx->engine->maxreclevel)
cli_dbgmsg("cli_magic_scandesc: Hit recursion limit, only scanning raw file\n");
else
@ -2221,7 +2321,7 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
CALL_PRESCAN_CB(cb_pre_scan);
/* ret_from_magicscan can be used below here*/
if((ret = cli_fmap_scandesc(ctx, 0, 0, NULL, AC_SCAN_VIR, NULL, hash)) == CL_VIRUS)
cli_dbgmsg("%s found in descriptor %d\n", *ctx->virname, fmap_fd(*ctx->fmap));
cli_dbgmsg("%s found in descriptor %d\n", cli_get_last_virus(ctx), fmap_fd(*ctx->fmap));
else if(ret == CL_CLEAN) {
if(ctx->recursion != ctx->engine->maxreclevel)
cache_clean = 1; /* Only cache if limits are not reached */
@ -2564,6 +2664,8 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
/* CL_VIRUS = malware found, check FP and report */
case CL_VIRUS:
ret = cli_checkfp(hash, hashed_size, ctx);
if (SCAN_ALL)
break;
cli_bitset_free(ctx->hook_lsig_matches);
ctx->hook_lsig_matches = old_hook_lsig_matches;
ret_from_magicscan(ret);
@ -2596,7 +2698,7 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
case CL_TYPE_TEXT_UTF16LE:
case CL_TYPE_TEXT_UTF8:
perf_nested_start(ctx, PERFT_SCRIPT, PERFT_SCAN);
if((DCONF_DOC & DOC_CONF_SCRIPT) && dettype != CL_TYPE_HTML)
if((DCONF_DOC & DOC_CONF_SCRIPT) && dettype != CL_TYPE_HTML && ret != CL_VIRUS)
ret = cli_scanscript(ctx);
if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX) && ret != CL_VIRUS && (ctx->container_type == CL_TYPE_MAIL || dettype == CL_TYPE_MAIL)) {
ret = cli_fmap_scandesc(ctx, CL_TYPE_MAIL, 0, NULL, AC_SCAN_VIR, NULL, NULL);
@ -2758,6 +2860,9 @@ static int scan_common(int desc, cl_fmap_t *map, const char **virname, unsigned
ctx.virname = virname;
ctx.scanned = scanned;
ctx.options = scanoptions;
#if 0 /* for development testing only */
ctx.options |= CL_SCAN_ALLMATCHES;
#endif
ctx.found_possibly_unwanted = 0;
ctx.container_type = CL_TYPE_ANY;
ctx.container_size = 0;
@ -2777,6 +2882,7 @@ static int scan_common(int desc, cl_fmap_t *map, const char **virname, unsigned
char link[32];
ssize_t linksz;
snprintf(link, sizeof(link), "/proc/self/fd/%u", desc);
link[sizeof(link)-1]='\0';
if((linksz=readlink(link, ctx.entry_filename, sizeof(ctx.entry_filename)-1))==-1) {
@ -2790,6 +2896,12 @@ static int scan_common(int desc, cl_fmap_t *map, const char **virname, unsigned
cli_logg_setup(&ctx);
rc = map ? cli_map_scandesc(map, 0, map->len, &ctx) : cli_magic_scandesc(desc, &ctx);
if (ctx.options & CL_SCAN_ALLMATCHES) {
*virname = (char *)ctx.virname; /* temp hack for scanall mode until api augmentation */
if (rc == CL_CLEAN && ctx.num_viruses)
rc = CL_VIRUS;
}
cli_bitset_free(ctx.hook_lsig_matches);
free(ctx.fmap);
if(rc == CL_CLEAN && ctx.found_possibly_unwanted)
@ -2811,24 +2923,24 @@ int cl_scanmap_callback(cl_fmap_t *map, const char **virname, unsigned long int
int cli_found_possibly_unwanted(cli_ctx* ctx)
{
if(ctx->virname) {
cli_dbgmsg("found Possibly Unwanted: %s\n",*ctx->virname);
if(ctx->options & CL_SCAN_HEURISTIC_PRECEDENCE) {
/* we found a heuristic match, don't scan further,
* but consider it a virus. */
cli_dbgmsg("cli_found_possibly_unwanted: CL_VIRUS\n");
return CL_VIRUS;
}
/* heuristic scan isn't taking precedence, keep scanning.
* If this is part of an archive, and
* we find a real malware we report that instead of the
* heuristic match */
ctx->found_possibly_unwanted = 1;
} else {
cli_warnmsg("cli_found_possibly_unwanted called, but virname is not set\n");
if(cli_get_last_virus(ctx)) {
cli_dbgmsg("found Possibly Unwanted: %s\n", cli_get_last_virus(ctx));
if(ctx->options & CL_SCAN_HEURISTIC_PRECEDENCE) {
/* we found a heuristic match, don't scan further,
* but consider it a virus. */
cli_dbgmsg("cli_found_possibly_unwanted: CL_VIRUS\n");
return CL_VIRUS;
}
emax_reached(ctx);
return CL_CLEAN;
/* heuristic scan isn't taking precedence, keep scanning.
* If this is part of an archive, and
* we find a real malware we report that instead of the
* heuristic match */
ctx->found_possibly_unwanted = 1;
} else {
cli_warnmsg("cli_found_possibly_unwanted called, but virname is not set\n");
}
emax_reached(ctx);
return CL_CLEAN;
}
static int cli_scanfile(const char *filename, cli_ctx *ctx)

@ -88,7 +88,7 @@ int cli_check_mydoom_log(cli_ctx *ctx)
if ((~check) != key)
return CL_CLEAN;
*ctx->virname = "Heuristics.Worm.Mydoom.M.log";
cli_append_virus(ctx, "Heuristics.Worm.Mydoom.M.log");
return CL_VIRUS;
}

@ -253,24 +253,24 @@ static int dumpscan(fmap_t *map, unsigned int offset, unsigned int size, const c
} else if(!memcmp(buff, "\xff\xd9\xff\xd8", 4)) {
cli_dbgmsg("SWF: JPEG image data (erroneous header)\n");
if(version >= 8 && SCAN_ALGO) {
*ctx->virname = "Heuristics.SWF.SuspectImage.A";
cli_append_virus(ctx, "Heuristics.SWF.SuspectImage.A");
ret = CL_VIRUS;
}
} else if(!memcmp(buff, "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a", 8)) {
cli_dbgmsg("SWF: PNG image data\n");
if(version < 8 && SCAN_ALGO) {
*ctx->virname = "Heuristics.SWF.SuspectImage.B";
cli_append_virus(ctx, "Heuristics.SWF.SuspectImage.B");
ret = CL_VIRUS;
}
} else if(!memcmp(buff, "\x47\x49\x46\x38\x39\x61", 6)) {
cli_dbgmsg("SWF: GIF89a image data\n");
if(version < 8 && SCAN_ALGO) {
*ctx->virname = "Heuristics.SWF.SuspectImage.C";
cli_append_virus(ctx, "Heuristics.SWF.SuspectImage.C");
ret = CL_VIRUS;
}
} else if(SCAN_ALGO) {
cli_warnmsg("SWF: Unknown image data\n");
*ctx->virname = "Heuristics.SWF.SuspectImage.D";
cli_append_virus(ctx, "Heuristics.SWF.SuspectImage.D");
ret = CL_VIRUS;
}
if(ret == CL_VIRUS) {
@ -279,7 +279,7 @@ static int dumpscan(fmap_t *map, unsigned int offset, unsigned int size, const c
}
ret = cli_map_scandesc(map, offset, size, ctx);
if(ctx->img_validate && ret == CL_EPARSE && SCAN_ALGO) {
*ctx->virname = "Heuristics.SWF.SuspectImage.E";
cli_append_virus(ctx, "Heuristics.SWF.SuspectImage.E");
return CL_VIRUS;
}
return ret;

@ -130,6 +130,7 @@ cli_untar(const char *dir, unsigned int posix, cli_ctx *ctx)
size_t pos = 0;
size_t currsize = 0;
char zero[BLOCKSIZE];
unsigned int num_viruses = 0;
cli_dbgmsg("In untar(%s)\n", dir);
memset(zero, 0, sizeof(zero));
@ -168,8 +169,12 @@ cli_untar(const char *dir, unsigned int posix, cli_ctx *ctx)
close(fout);
if (!ctx->engine->keeptmp)
if (cli_unlink(fullname)) return CL_EUNLINK;
if (ret==CL_VIRUS)
if (ret==CL_VIRUS) {
if (!SCAN_ALL)
return CL_VIRUS;
else
num_viruses++;
}
fout = -1;
}
@ -285,8 +290,12 @@ cli_untar(const char *dir, unsigned int posix, cli_ctx *ctx)
strncpy(name, block, 100);
name[100] = '\0';
if(cli_matchmeta(ctx, name, size, size, 0, files, 0, NULL) == CL_VIRUS)
return CL_VIRUS;
if(cli_matchmeta(ctx, name, size, size, 0, files, 0, NULL) == CL_VIRUS) {
if (!SCAN_ALL)
return CL_VIRUS;
else
num_viruses++;
}
snprintf(fullname, sizeof(fullname)-1, "%s"PATHSEP"tar%02u", dir, files);
fullname[sizeof(fullname)-1] = '\0';
@ -349,5 +358,7 @@ cli_untar(const char *dir, unsigned int posix, cli_ctx *ctx)
if (ret==CL_VIRUS)
return CL_VIRUS;
}
if (num_viruses)
return CL_VIRUS;
return CL_CLEAN;
}

@ -350,7 +350,7 @@ static unsigned int lhdr(fmap_t *map, uint32_t loff,uint32_t zsize, unsigned int
if(detect_encrypted && (LH_flags & F_ENCR) && DETECT_ENCRYPTED) {
cli_dbgmsg("cli_unzip: Encrypted files found in archive.\n");
*ctx->virname = "Heuristics.Encrypted.Zip";
cli_append_virus(ctx, "Heuristics.Encrypted.Zip");
*ret = CL_VIRUS;
fmap_unneed_off(map, loff, SIZEOF_LH);
return 0;

@ -81,6 +81,7 @@ const struct clam_option __clam_options[] = {
{ NULL, "multiscan", 'm', TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMDSCAN, "", "" },
{ NULL, "fdpass", 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMDSCAN, "", "" },
{ NULL, "stream", 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMDSCAN, "", "" },
{ NULL, "allmatch", 'z', TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN | OPT_CLAMDSCAN, "", "" },
{ NULL, "database", 'd', TYPE_STRING, NULL, -1, DATADIR, FLAG_REQUIRED | FLAG_MULTIPLE, OPT_CLAMSCAN, "", "" }, /* merge it with DatabaseDirectory (and fix conflict with --datadir */
{ NULL, "recursive", 'r', TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN, "", "" },
{ NULL, "follow-dir-symlinks", 0, TYPE_NUMBER, MATCH_NUMBER, 1, NULL, 0, OPT_CLAMSCAN, "", "" },

@ -59,8 +59,11 @@ static void runtest(const char *file, uint64_t expected, int fail, int nojit,
struct cl_engine *engine;
int fdin = -1;
char filestr[512];
char * virname = NULL;
memset(&cctx, 0, sizeof(cctx));
cctx.options |= CL_SCAN_ALLMATCHES;
cctx.virname = &virname;
cctx.engine = engine = cl_engine_new();
fail_unless(!!cctx.engine, "cannot create engine");
rc = cl_engine_compile(engine);

@ -170,7 +170,29 @@ START_TEST (test_cl_scandesc)
}
END_TEST
/* int cl_scanfile(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options) */
START_TEST (test_cl_scandesc_allscan)
{
const char *virname = NULL;
const char ** virpp = &virname;
char file[256];
unsigned long size;
unsigned long int scanned = 0;
int ret;
int fd = get_test_file(_i, file, sizeof(file), &size);
cli_dbgmsg("scanning (scandesc) %s\n", file);
ret = cl_scandesc(fd, virpp, &scanned, g_engine, CL_SCAN_ALLMATCHES+CL_SCAN_STDOPT);
virpp = (const char **)*virpp; /* allscan api hack */
cli_dbgmsg("scan end (scandesc) %s\n", file);
fail_unless_fmt(ret == CL_VIRUS, "cl_scandesc_allscan failed for %s: %s", file, cl_strerror(ret));
fail_unless_fmt(*virpp && !strcmp(*virpp, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", *virpp);
free((void *)virpp);
close(fd);
}
END_TEST
//* int cl_scanfile(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options) */
START_TEST (test_cl_scanfile)
{
const char *virname = NULL;
@ -191,6 +213,29 @@ START_TEST (test_cl_scanfile)
}
END_TEST
START_TEST (test_cl_scanfile_allscan)
{
const char *virname = NULL;
const char **virpp = &virname;
char file[256];
unsigned long size;
unsigned long int scanned = 0;
int ret;
int fd = get_test_file(_i, file, sizeof(file), &size);
close(fd);
cli_dbgmsg("scanning (scanfile_allscan) %s\n", file);
ret = cl_scanfile(file, virpp, &scanned, g_engine, CL_SCAN_ALLMATCHES+CL_SCAN_STDOPT);
virpp = (const char **)*virpp; /* allscan api hack */
cli_dbgmsg("scan end (scanfile_allscan) %s\n", file);
fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_allscan failed for %s: %s", file, cl_strerror(ret));
fail_unless_fmt(*virpp && !strcmp(*virpp, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", *virpp);
free((void *)virpp);
}
END_TEST
START_TEST (test_cl_scanfile_callback)
{
const char *virname = NULL;
@ -207,11 +252,35 @@ START_TEST (test_cl_scanfile_callback)
ret = cl_scanfile_callback(file, &virname, &scanned, g_engine, CL_SCAN_STDOPT, NULL);
cli_dbgmsg("scan end (scanfile_cb) %s\n", file);
fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile failed for %s: %s", file, cl_strerror(ret));
fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_cb failed for %s: %s", file, cl_strerror(ret));
fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
}
END_TEST
START_TEST (test_cl_scanfile_callback_allscan)
{
const char *virname = NULL;
const char **virpp = &virname;
char file[256];
unsigned long size;
unsigned long int scanned = 0;
int ret;
int fd = get_test_file(_i, file, sizeof(file), &size);
close(fd);
cli_dbgmsg("scanning (scanfile_cb_allscan) %s\n", file);
/* TODO: test callbacks */
ret = cl_scanfile_callback(file, virpp, &scanned, g_engine, CL_SCAN_ALLMATCHES+CL_SCAN_STDOPT, NULL);
virpp = (const char **)*virpp; /* allscan api hack */
cli_dbgmsg("scan end (scanfile_cb_allscan) %s\n", file);
fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_cb_allscan failed for %s: %s", file, cl_strerror(ret));
fail_unless_fmt(*virpp && !strcmp(*virpp, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", *virpp);
free((void *)virpp);
}
END_TEST
START_TEST (test_cl_scandesc_callback)
{
const char *virname = NULL;
@ -232,6 +301,31 @@ START_TEST (test_cl_scandesc_callback)
close(fd);
}
END_TEST
START_TEST (test_cl_scandesc_callback_allscan)
{
const char *virname = NULL;
const char **virpp = &virname;
char file[256];
unsigned long size;
unsigned long int scanned = 0;
int ret;
int fd = get_test_file(_i, file, sizeof(file), &size);
cli_dbgmsg("scanning (scandesc_cb_allscan) %s\n", file);
/* TODO: test callbacks */
ret = cl_scandesc_callback(fd, virpp, &scanned, g_engine, CL_SCAN_ALLMATCHES+CL_SCAN_STDOPT, NULL);
virpp = (const char **)*virpp; /* allscan api hack */
cli_dbgmsg("scan end (scandesc_cb_allscan) %s\n", file);
fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_allscan failed for %s: %s", file, cl_strerror(ret));
fail_unless_fmt(*virpp && !strcmp(*virpp, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", *virpp);
free((void *)virpp);
close(fd);
}
END_TEST
#endif
/* int cl_load(const char *path, struct cl_engine **engine, unsigned int *signo, unsigned int options) */
@ -367,6 +461,33 @@ START_TEST (test_cl_scanmap_callback_handle)
}
END_TEST
START_TEST (test_cl_scanmap_callback_handle_allscan)
{
const char *virname = NULL;
const char ** virpp = &virname;
unsigned long int scanned = 0;
cl_fmap_t *map;
int ret;
char file[256];
unsigned long size;
int fd = get_test_file(_i, file, sizeof(file), &size);
/* intentionally use different way than scanners.c for testing */
map = cl_fmap_open_handle(&fd, 0, size, pread_cb, 1);
fail_unless(!!map, "cl_fmap_open_handle");
cli_dbgmsg("scanning (handle) allscan %s\n", file);
ret = cl_scanmap_callback(map, virpp, &scanned, g_engine, CL_SCAN_ALLMATCHES+CL_SCAN_STDOPT, NULL);
virpp = (const char **)*virpp; /* allscan api hack */
cli_dbgmsg("scan end (handle) allscan %s\n", file);
fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback_allscan failed for %s: %s", file, cl_strerror(ret));
fail_unless_fmt(*virpp && !strcmp(*virpp, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", *virpp);
free((void *)virpp);
close(fd);
}
END_TEST
START_TEST (test_cl_scanmap_callback_mem)
{
const char *virname = NULL;
@ -397,6 +518,39 @@ START_TEST (test_cl_scanmap_callback_mem)
munmap(mem, size);
}
END_TEST
START_TEST (test_cl_scanmap_callback_mem_allscan)
{
const char *virname = NULL;
const char **virpp = &virname;
unsigned long int scanned = 0;
cl_fmap_t *map;
int ret;
void *mem;
unsigned long size;
char file[256];
int fd = get_test_file(_i, file, sizeof(file), &size);
mem = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
fail_unless(mem != MAP_FAILED, "mmap");
/* intentionally use different way than scanners.c for testing */
map = cl_fmap_open_memory(mem, size);
fail_unless(!!map, "cl_fmap_open_mem");
cli_dbgmsg("scanning (mem) allscan %s\n", file);
ret = cl_scanmap_callback(map, virpp, &scanned, g_engine, CL_SCAN_ALLMATCHES+CL_SCAN_STDOPT, NULL);
virpp = (const char **)*virpp; /* allscan api hack */
cli_dbgmsg("scan end (mem) allscan %s\n", file);
fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback failed for %s: %s", file, cl_strerror(ret));
fail_unless_fmt(*virpp && !strcmp(*virpp, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s for %s", *virpp, file);
close(fd);
cl_fmap_close(map);
free((void *)virpp);
munmap(mem, size);
}
END_TEST
#endif
static Suite *test_cl_suite(void)
@ -427,11 +581,17 @@ static Suite *test_cl_suite(void)
tcase_add_checked_fixture (tc_cl_scan, engine_setup, engine_teardown);
#ifdef CHECK_HAVE_LOOPS
tcase_add_loop_test(tc_cl_scan, test_cl_scandesc, 0, expected_testfiles);
tcase_add_loop_test(tc_cl_scan, test_cl_scandesc_allscan, 0, expected_testfiles);
tcase_add_loop_test(tc_cl_scan, test_cl_scanfile, 0, expected_testfiles);
tcase_add_loop_test(tc_cl_scan, test_cl_scanfile_allscan, 0, expected_testfiles);
tcase_add_loop_test(tc_cl_scan, test_cl_scandesc_callback, 0, expected_testfiles);
tcase_add_loop_test(tc_cl_scan, test_cl_scandesc_callback_allscan, 0, expected_testfiles);
tcase_add_loop_test(tc_cl_scan, test_cl_scanfile_callback, 0, expected_testfiles);
tcase_add_loop_test(tc_cl_scan, test_cl_scanfile_callback_allscan, 0, expected_testfiles);
tcase_add_loop_test(tc_cl_scan, test_cl_scanmap_callback_handle, 0, expected_testfiles);
tcase_add_loop_test(tc_cl_scan, test_cl_scanmap_callback_handle_allscan, 0, expected_testfiles);
tcase_add_loop_test(tc_cl_scan, test_cl_scanmap_callback_mem, 0, expected_testfiles);
tcase_add_loop_test(tc_cl_scan, test_cl_scanmap_callback_mem_allscan, 0, expected_testfiles);
#endif
return s;
}

@ -145,7 +145,83 @@ START_TEST (test_bm_scanbuff) {
ret = cli_parse_add(root, "Sig3", "babedead", 0, 0, "*", 0, NULL, 0);
fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed");
ret = cli_bm_scanbuff((const unsigned char*)"blah\xde\xad\xbe\xef", 12, &virname, NULL, root, 0, NULL, NULL);
ret = cli_bm_scanbuff((const unsigned char*)"blah\xde\xad\xbe\xef", 12, &virname, NULL, root, 0, NULL, NULL, NULL);
fail_unless(ret == CL_VIRUS, "cli_bm_scanbuff() failed");
fail_unless(!strncmp(virname, "Sig2", 4), "Incorrect signature matched in cli_bm_scanbuff()\n");
}
END_TEST
START_TEST (test_ac_scanbuff_allscan) {
struct cli_ac_data mdata;
struct cli_matcher *root;
unsigned int i;
int ret;
root = ctx.engine->root[0];
fail_unless(root != NULL, "root == NULL");
root->ac_only = 1;
#ifdef USE_MPOOL
root->mempool = mpool_create();
#endif
ret = cli_ac_init(root, CLI_DEFAULT_AC_MINDEPTH, CLI_DEFAULT_AC_MAXDEPTH, 1);
fail_unless(ret == CL_SUCCESS, "cli_ac_init() failed");
for(i = 0; ac_testdata[i].data; i++) {
ret = cli_parse_add(root, ac_testdata[i].virname, ac_testdata[i].hexsig, 0, 0, "*", 0, NULL, 0);
fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed");
}
ret = cli_ac_buildtrie(root);
fail_unless(ret == CL_SUCCESS, "cli_ac_buildtrie() failed");
ret = cli_ac_initdata(&mdata, root->ac_partsigs, 0, 0, CLI_DEFAULT_AC_TRACKLEN);
fail_unless(ret == CL_SUCCESS, "cli_ac_initdata() failed");
ctx.options |= CL_SCAN_ALLMATCHES;
for(i = 0; ac_testdata[i].data; i++) {
ret = cli_ac_scanbuff((const unsigned char*)ac_testdata[i].data, strlen(ac_testdata[i].data), &virname, NULL, NULL, root, &mdata, 0, 0, NULL, AC_SCAN_VIR, NULL);
fail_unless_fmt(ret == CL_VIRUS, "cli_ac_scanbuff() failed for %s", ac_testdata[i].virname);
fail_unless_fmt(!strncmp(virname, ac_testdata[i].virname, strlen(ac_testdata[i].virname)), "Dataset %u matched with %s", i, virname);
ret = cli_scanbuff((const unsigned char*)ac_testdata[i].data, strlen(ac_testdata[i].data), 0, &ctx, 0, NULL);
fail_unless_fmt(ret == CL_VIRUS, "cli_scanbuff() failed for %s", ac_testdata[i].virname);
fail_unless_fmt(!strncmp(virname, ac_testdata[i].virname, strlen(ac_testdata[i].virname)), "Dataset %u matched with %s", i, virname);
if (ctx.num_viruses) {
free((void *)ctx.virname);
ctx.num_viruses = 0;
ctx.size_viruses = 0;
}
}
cli_ac_freedata(&mdata);
}
END_TEST
START_TEST (test_bm_scanbuff_allscan) {
struct cli_matcher *root;
const char *virname = NULL;
int ret;
root = ctx.engine->root[0];
fail_unless(root != NULL, "root == NULL");
#ifdef USE_MPOOL
root->mempool = mpool_create();
#endif
ret = cli_bm_init(root);
fail_unless(ret == CL_SUCCESS, "cli_bm_init() failed");
ret = cli_parse_add(root, "Sig1", "deadbabe", 0, 0, "*", 0, NULL, 0);
fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed");
ret = cli_parse_add(root, "Sig2", "deadbeef", 0, 0, "*", 0, NULL, 0);
fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed");
ret = cli_parse_add(root, "Sig3", "babedead", 0, 0, "*", 0, NULL, 0);
fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed");
ret = cli_bm_scanbuff((const unsigned char*)"blah\xde\xad\xbe\xef", 12, &virname, NULL, root, 0, NULL, NULL, NULL);
fail_unless(ret == CL_VIRUS, "cli_bm_scanbuff() failed");
fail_unless(!strncmp(virname, "Sig2", 4), "Incorrect signature matched in cli_bm_scanbuff()\n");
}
@ -160,6 +236,8 @@ Suite *test_matchers_suite(void)
tcase_add_checked_fixture (tc_matchers, setup, teardown);
tcase_add_test(tc_matchers, test_ac_scanbuff);
tcase_add_test(tc_matchers, test_bm_scanbuff);
tcase_add_test(tc_matchers, test_ac_scanbuff_allscan);
tcase_add_test(tc_matchers, test_bm_scanbuff_allscan);
return s;
}

@ -425,12 +425,85 @@ static void do_phishing_test(const struct rtest *rtest)
}
}
static void do_phishing_test_allscan(const struct rtest *rtest)
{
char *realurl;
cli_ctx ctx;
const char *virname = NULL;
tag_arguments_t hrefs;
int rc;
memset(&ctx, 0, sizeof(ctx));
realurl = cli_strdup(rtest->realurl);
fail_unless(!!realurl, "cli_strdup");
hrefs.count = 1;
hrefs.value = cli_malloc(sizeof(*hrefs.value));
fail_unless(!!hrefs.value, "cli_malloc");
hrefs.value[0] = (unsigned char*)realurl;
hrefs.contents = cli_malloc(sizeof(*hrefs.contents));
fail_unless(!!hrefs.contents, "cli_malloc");
hrefs.tag = cli_malloc(sizeof(*hrefs.tag));
fail_unless(!!hrefs.tag, "cli_malloc");
hrefs.tag[0] = (unsigned char*)cli_strdup("href");
hrefs.contents[0] = (unsigned char*)cli_strdup(rtest->displayurl);
ctx.engine = engine;
ctx.virname = &virname;
ctx.options |= CL_SCAN_ALLMATCHES;
rc = phishingScan(&ctx, &hrefs);
html_tag_arg_free(&hrefs);
fail_unless(rc == CL_CLEAN,"phishingScan");
switch(rtest->result) {
case 0:
fail_unless_fmt(ctx.found_possibly_unwanted,
"this should be phishing, realURL: %s, displayURL: %s",
rtest->realurl, rtest->displayurl);
break;
case 1:
fail_unless_fmt(!ctx.found_possibly_unwanted,
"this should be whitelisted, realURL: %s, displayURL: %s",
rtest->realurl, rtest->displayurl);
break;
case 2:
fail_unless_fmt(!ctx.found_possibly_unwanted,
"this should be clean, realURL: %s, displayURL: %s",
rtest->realurl, rtest->displayurl);
break;
case 3:
if(!loaded_2)
fail_unless_fmt(!ctx.found_possibly_unwanted,
"this should be clean, realURL: %s, displayURL: %s",
rtest->realurl, rtest->displayurl);
else {
fail_unless_fmt(ctx.found_possibly_unwanted,
"this should be blacklisted, realURL: %s, displayURL: %s",
rtest->realurl, rtest->displayurl);
if (*ctx.virname)
fail_unless_fmt(!strstr((const char*)*ctx.virname,"Blacklisted"),
"should be blacklisted, but is: %s\n", ctx.virname);
}
break;
}
if (ctx.num_viruses)
free((void *)ctx.virname);
}
#ifdef CHECK_HAVE_LOOPS
START_TEST (phishingScan_test)
{
do_phishing_test(&rtests[_i]);
}
END_TEST
START_TEST (phishingScan_test_allscan)
{
do_phishing_test_allscan(&rtests[_i]);
}
END_TEST
#endif
#ifdef CHECK_HAVE_LOOPS
@ -515,6 +588,27 @@ START_TEST(phishing_fake_test)
}
END_TEST
START_TEST(phishing_fake_test_allscan)
{
char buf[4096];
FILE *f = fdopen(open_testfile("input/daily.pdb"),"r");
fail_unless(!!f,"fopen daily.pdb");
while(fgets(buf, sizeof(buf), f)) {
struct rtest rtest;
const char *pdb = strchr(buf,':');
fail_unless(!!pdb, "missing : in pdb");
rtest.realurl = pdb;
rtest.displayurl = pdb;
rtest.result = 2;
do_phishing_test_allscan(&rtest);
rtest.realurl = "http://fake.example.com";
rtest.result = 0;
do_phishing_test_allscan(&rtest);
}
fclose(f);
}
END_TEST
Suite *test_regex_suite(void)
{
Suite *s = suite_create("regex");
@ -539,16 +633,20 @@ Suite *test_regex_suite(void)
tcase_add_unchecked_fixture(tc_phish, psetup, pteardown);
#ifdef CHECK_HAVE_LOOPS
tcase_add_loop_test(tc_phish, phishingScan_test, 0, sizeof(rtests)/sizeof(rtests[0]));
tcase_add_loop_test(tc_phish, phishingScan_test_allscan, 0, sizeof(rtests)/sizeof(rtests[0]));
#endif
tcase_add_test(tc_phish, phishing_fake_test);
tcase_add_test(tc_phish, phishing_fake_test_allscan);
tc_phish2 = tcase_create("phishingScan with 2 dbs");
suite_add_tcase(s, tc_phish2);
tcase_add_unchecked_fixture(tc_phish2, psetup2, pteardown);
#ifdef CHECK_HAVE_LOOPS
tcase_add_loop_test(tc_phish2, phishingScan_test, 0, sizeof(rtests)/sizeof(rtests[0]));
tcase_add_loop_test(tc_phish2, phishingScan_test_allscan, 0, sizeof(rtests)/sizeof(rtests[0]));
#endif
tcase_add_test(tc_phish2, phishing_fake_test);
tcase_add_test(tc_phish2, phishing_fake_test_allscan);
#ifdef CHECK_HAVE_LOOPS
tcase_add_loop_test(tc_phish, test_url_canon, 0, sizeof(uc)/sizeof(uc[0]));
#endif

Loading…
Cancel
Save