libclamav: improve handling of signature offsets

0.96
Tomasz Kojm 16 years ago
parent 25c241ef61
commit 33872a43de
  1. 4
      ChangeLog
  2. 5
      libclamav/default.h
  3. 6
      libclamav/filetypes.c
  4. 152
      libclamav/matcher-ac.c
  5. 8
      libclamav/matcher-ac.h
  6. 38
      libclamav/matcher-bm.c
  7. 10
      libclamav/matcher-bm.h
  8. 281
      libclamav/matcher.c
  9. 21
      libclamav/matcher.h
  10. 4
      libclamav/pe.c
  11. 4
      libclamav/phishcheck.c
  12. 83
      libclamav/readdb.c
  13. 2
      libclamav/readdb.h
  14. 8
      libclamav/regex_list.c
  15. 12
      unit_tests/check_matchers.c

@ -1,3 +1,7 @@
Fri Aug 14 14:37:21 CEST 2009 (tk)
----------------------------------
* libclamav: improve handling of signature offsets
Tue Aug 11 02:04:54 CEST 2009 (acab)
------------------------------------
* libclamav/7z/Types.h: workaround "Byte" clash in lzma/7z (bb#805 - regression)

@ -25,6 +25,11 @@
#define CLI_DEFAULT_AC_MAXDEPTH 3
#define CLI_DEFAULT_AC_TRACKLEN 8
#define CLI_DEFAULT_MOVETOAC_LEN 8 /* all static sigs shorter than
* this value will automatically
* go to AC instead of BM
*/
#define CLI_DEFAULT_LSIG_BUFSIZE 32768
#define CLI_DEFAULT_DBIO_BUFSIZE CLI_DEFAULT_LSIG_BUFSIZE + 1

@ -176,7 +176,7 @@ cli_file_t cli_filetype2(int desc, const struct cl_engine *engine)
if(cli_ac_initdata(&mdata, root->ac_partsigs, root->ac_lsigs, CLI_DEFAULT_AC_TRACKLEN))
return ret;
sret = cli_ac_scanbuff(buff, bread, NULL, NULL, NULL, engine->root[0], &mdata, 0, ret, desc, NULL, AC_SCAN_FT, NULL);
sret = cli_ac_scanbuff(buff, bread, NULL, NULL, NULL, engine->root[0], &mdata, 0, ret, NULL, AC_SCAN_FT, NULL);
cli_ac_freedata(&mdata);
@ -188,7 +188,7 @@ cli_file_t cli_filetype2(int desc, const struct cl_engine *engine)
decoded = (unsigned char *) cli_utf16toascii((char *) buff, bread);
if(decoded) {
sret = cli_ac_scanbuff(decoded, strlen((char *) decoded), NULL, NULL, NULL, engine->root[0], &mdata, 0, CL_TYPE_TEXT_ASCII, desc, NULL, AC_SCAN_FT, NULL);
sret = cli_ac_scanbuff(decoded, strlen((char *) decoded), NULL, NULL, NULL, engine->root[0], &mdata, 0, CL_TYPE_TEXT_ASCII, NULL, AC_SCAN_FT, NULL);
free(decoded);
if(sret == CL_TYPE_HTML)
ret = CL_TYPE_HTML_UTF16;
@ -221,7 +221,7 @@ cli_file_t cli_filetype2(int desc, const struct cl_engine *engine)
return ret;
if(out_area.length > 0) {
sret = cli_ac_scanbuff(decodedbuff, out_area.length, NULL, NULL, NULL, engine->root[0], &mdata, 0, 0, desc, NULL, AC_SCAN_FT, NULL); /* FIXME: can we use CL_TYPE_TEXT_ASCII instead of 0? */
sret = cli_ac_scanbuff(decodedbuff, out_area.length, NULL, NULL, NULL, engine->root[0], &mdata, 0, 0, NULL, AC_SCAN_FT, NULL); /* FIXME: can we use CL_TYPE_TEXT_ASCII instead of 0? */
if(sret == CL_TYPE_HTML) {
cli_dbgmsg("cli_filetype2: detected HTML signature in Unicode file\n");
/* htmlnorm is able to handle any unicode now, since it skips null chars */

@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2008 Sourcefire, Inc.
* Copyright (C) 2007-2009 Sourcefire, Inc.
*
* Authors: Tomasz Kojm
*
@ -386,8 +386,6 @@ void cli_ac_free(struct cli_matcher *root)
patt = root->ac_pattable[i];
mpool_free(root->mempool, patt->prefix ? patt->prefix : patt->pattern);
mpool_free(root->mempool, patt->virname);
if(patt->offset)
mpool_free(root->mempool, patt->offset);
if(patt->alt)
mpool_ac_free_alt(root->mempool, patt);
mpool_free(root->mempool, patt);
@ -395,6 +393,9 @@ void cli_ac_free(struct cli_matcher *root)
if(root->ac_pattable)
mpool_free(root->mempool, root->ac_pattable);
if(root->ac_reloff)
mpool_free(root->mempool, root->ac_reloff);
for(i = 0; i < root->ac_nodes; i++) {
if(!IS_LEAF(root->ac_nodetable[i]))
mpool_free(root->mempool, root->ac_nodetable[i]->trans);
@ -812,6 +813,31 @@ int cli_ac_initdata(struct cli_ac_data *data, uint32_t partsigs, uint32_t lsigs,
return CL_SUCCESS;
}
int cli_ac_caloff(struct cli_matcher *root, int fd)
{
int ret;
unsigned int i;
struct cli_ac_patt *patt;
struct cli_target_info info;
memset(&info, 0, sizeof(info));
for(i = 0; i < root->ac_reloff_num; i++) {
patt = root->ac_reloff[i];
if(fd == -1) {
patt->offset_min = CLI_OFF_NONE;
} else if((ret = cli_caloff(NULL, &info, fd, root->type, patt->offdata, &patt->offset_min, &patt->offset_max))) {
cli_errmsg("cli_ac_caloff: Can't calculate relative offset in signature for %s\n", patt->virname);
if(info.exeinfo.section)
free(info.exeinfo.section);
return ret;
}
}
if(info.exeinfo.section)
free(info.exeinfo.section);
return CL_SUCCESS;
}
void cli_ac_freedata(struct cli_ac_data *data)
{
uint32_t i;
@ -867,7 +893,7 @@ inline static int ac_addtype(struct cli_matched_type **list, cli_file_t type, of
return CL_SUCCESS;
}
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, int fd, 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, const cli_ctx *ctx)
{
struct cli_ac_node *current;
struct cli_ac_patt *patt, *pt;
@ -875,11 +901,9 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
uint16_t j;
int32_t **offmatrix;
uint8_t found;
struct cli_target_info info;
int type = CL_CLEAN;
struct cli_ac_result *newres;
if(!root->ac_root)
return CL_CLEAN;
@ -888,7 +912,6 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
return CL_ENULLARG;
}
memset(&info, 0, sizeof(info));
current = root->ac_root;
for(i = 0; i < length; i++) {
@ -902,24 +925,44 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
patt = current->list;
while(patt) {
bp = i + 1 - patt->depth;
if(ac_findmatch(buffer, bp, length, patt, &matchend)) {
pt = patt;
pt = patt;
/*
while(pt) {
if((pt->type && !(mode & AC_SCAN_FT)) || (!pt->type && !(mode & AC_SCAN_VIR))) {
pt = pt->next_same;
continue;
}
if(pt->offset_min == CLI_OFF_NONE) {
pt = pt->next_same;
continue;
}
realoff = offset + bp - pt->prefix_length;
if(pt->offset_min != CLI_OFF_ANY && (!pt->sigid || pt->partno == 1)) {
if(pt->offset_max > realoff || pt->offset_min < realoff) {
pt = pt->next_same;
continue;
}
}
break;
}
*/
if(pt && ac_findmatch(buffer, bp, length, patt, &matchend)) {
while(pt) {
if((pt->type && !(mode & AC_SCAN_FT)) || (!pt->type && !(mode & AC_SCAN_VIR))) {
pt = pt->next_same;
continue;
}
if(pt->offset_min == CLI_OFF_NONE) {
pt = pt->next_same;
continue;
}
realoff = offset + bp - pt->prefix_length;
if(pt->offset && (!pt->sigid || pt->partno == 1)) {
if(!cli_validatesig(ftype, pt->offset, realoff, &info, fd, pt->virname)) {
if(pt->offset_min != CLI_OFF_ANY && (!pt->sigid || pt->partno == 1)) {
if(pt->offset_max > realoff || pt->offset_min < realoff) {
pt = pt->next_same;
continue;
}
}
if(pt->sigid) { /* it's a partial signature */
if(pt->partno != 1 && (!mdata->offmatrix[pt->sigid - 1] || !mdata->offmatrix[pt->sigid - 1][pt->partno - 2][0])) {
@ -931,8 +974,6 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
mdata->offmatrix[pt->sigid - 1] = cli_malloc(pt->parts * sizeof(int32_t *));
if(!mdata->offmatrix[pt->sigid - 1]) {
cli_errmsg("cli_ac_scanbuff: Can't allocate memory for mdata->offmatrix[%u]\n", pt->sigid - 1);
if(info.exeinfo.section)
free(info.exeinfo.section);
return CL_EMEM;
}
@ -941,8 +982,6 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
cli_errmsg("cli_ac_scanbuff: Can't allocate memory for mdata->offmatrix[%u][0]\n", pt->sigid - 1);
free(mdata->offmatrix[pt->sigid - 1]);
mdata->offmatrix[pt->sigid - 1] = NULL;
if(info.exeinfo.section)
free(info.exeinfo.section);
return CL_EMEM;
}
memset(mdata->offmatrix[pt->sigid - 1][0], -1, pt->parts * (CLI_DEFAULT_AC_TRACKLEN + 1) * sizeof(int32_t));
@ -981,25 +1020,17 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
} else if(found && pt->partno == pt->parts) {
if(pt->type) {
if(pt->type == CL_TYPE_IGNORED && (!pt->rtype || ftype == pt->rtype)) {
if(info.exeinfo.section)
free(info.exeinfo.section);
if(pt->type == CL_TYPE_IGNORED && (!pt->rtype || ftype == pt->rtype))
return CL_TYPE_IGNORED;
}
if((pt->type > type || pt->type >= CL_TYPE_SFX || pt->type == CL_TYPE_MSEXE) && (!pt->rtype || ftype == pt->rtype)) {
cli_dbgmsg("Matched signature for file type %s\n", pt->virname);
type = pt->type;
if(ftoffset && (!*ftoffset || (*ftoffset)->cnt < MAX_EMBEDDED_OBJ || type == CL_TYPE_ZIPSFX) && (type >= CL_TYPE_SFX || ((ftype == CL_TYPE_MSEXE || ftype == CL_TYPE_ZIP || ftype == CL_TYPE_MSOLE2) && type == CL_TYPE_MSEXE))) {
/* FIXME: we don't know which offset of the first part is the correct one */
for(j = 1; j <= CLI_DEFAULT_AC_TRACKLEN && offmatrix[0][j] != -1; j++) {
if(ac_addtype(ftoffset, type, offmatrix[pt->parts - 1][j], ctx)) {
if(info.exeinfo.section)
free(info.exeinfo.section);
for(j = 1; j <= CLI_DEFAULT_AC_TRACKLEN && offmatrix[0][j] != -1; j++)
if(ac_addtype(ftoffset, type, offmatrix[pt->parts - 1][j], ctx))
return CL_EMEM;
}
}
}
memset(offmatrix[0], -1, pt->parts * (CLI_DEFAULT_AC_TRACKLEN + 1) * sizeof(int32_t));
@ -1016,11 +1047,8 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
if(res) {
newres = (struct cli_ac_result *) malloc(sizeof(struct cli_ac_result));
if(!newres) {
if(info.exeinfo.section)
free(info.exeinfo.section);
if(!newres)
return CL_EMEM;
}
newres->virname = pt->virname;
newres->customdata = pt->customdata;
newres->next = *res;
@ -1033,10 +1061,6 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
*virname = pt->virname;
if(customdata)
*customdata = pt->customdata;
if(info.exeinfo.section)
free(info.exeinfo.section);
return CL_VIRUS;
}
}
@ -1044,22 +1068,16 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
} else { /* old type signature */
if(pt->type) {
if(pt->type == CL_TYPE_IGNORED && (!pt->rtype || ftype == pt->rtype)) {
if(info.exeinfo.section)
free(info.exeinfo.section);
if(pt->type == CL_TYPE_IGNORED && (!pt->rtype || ftype == pt->rtype))
return CL_TYPE_IGNORED;
}
if((pt->type > type || pt->type >= CL_TYPE_SFX || pt->type == CL_TYPE_MSEXE) && (!pt->rtype || ftype == pt->rtype)) {
cli_dbgmsg("Matched signature for file type %s at %u\n", pt->virname, realoff);
type = pt->type;
if(ftoffset && (!*ftoffset || (*ftoffset)->cnt < MAX_EMBEDDED_OBJ || type == CL_TYPE_ZIPSFX) && (type >= CL_TYPE_SFX || ((ftype == CL_TYPE_MSEXE || ftype == CL_TYPE_ZIP || ftype == CL_TYPE_MSOLE2) && type == CL_TYPE_MSEXE))) {
if(ac_addtype(ftoffset, type, realoff, ctx)) {
if(info.exeinfo.section)
free(info.exeinfo.section);
if(ac_addtype(ftoffset, type, realoff, ctx))
return CL_EMEM;
}
}
}
} else {
@ -1071,11 +1089,8 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
if(res) {
newres = (struct cli_ac_result *) malloc(sizeof(struct cli_ac_result));
if(!newres) {
if(info.exeinfo.section)
free(info.exeinfo.section);
if(!newres)
return CL_EMEM;
}
newres->virname = pt->virname;
newres->customdata = pt->customdata;
newres->next = *res;
@ -1088,10 +1103,6 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
*virname = pt->virname;
if(customdata)
*customdata = pt->customdata;
if(info.exeinfo.section)
free(info.exeinfo.section);
return CL_VIRUS;
}
}
@ -1104,9 +1115,6 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
}
}
if(info.exeinfo.section)
free(info.exeinfo.section);
return (mode & AC_SCAN_FT) ? type : CL_CLEAN;
}
@ -1445,26 +1453,32 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
if(new->lsigid[0])
root->ac_lsigtable[new->lsigid[1]]->virname = new->virname;
if(offset) {
new->offset = cli_mpool_strdup(root->mempool, offset);
if(!new->offset) {
mpool_free(root->mempool, new->prefix ? new->prefix : new->pattern);
mpool_ac_free_alt(root->mempool, new);
mpool_free(root->mempool, new->virname);
mpool_free(root->mempool, new);
return CL_EMEM;
}
ret = cli_caloff(offset, NULL, -1, root->type, new->offdata, &new->offset_min, &new->offset_max);
if(ret != CL_SUCCESS) {
mpool_free(root->mempool, new->prefix ? new->prefix : new->pattern);
mpool_ac_free_alt(root->mempool, new);
mpool_free(root->mempool, new->virname);
mpool_free(root->mempool, new);
return ret;
}
if((ret = cli_ac_addpatt(root, new))) {
mpool_free(root->mempool, new->prefix ? new->prefix : new->pattern);
mpool_free(root->mempool, new->virname);
mpool_ac_free_alt(root->mempool, new);
if(new->offset)
mpool_free(root->mempool, new->offset);
mpool_free(root->mempool, new);
return ret;
}
if(new->offdata[0] != CLI_OFF_ANY && new->offdata[0] != CLI_OFF_ABSOLUTE) {
root->ac_reloff = (struct cli_ac_patt **) mpool_realloc2(root->mempool, root->ac_reloff, (root->ac_reloff_num + 1) * sizeof(struct cli_ac_patt *));
if(!root->ac_reloff) {
cli_errmsg("cli_ac_addsig: Can't allocate memory for root->ac_reloff\n");
return CL_EMEM;
}
root->ac_reloff[root->ac_reloff_num] = new;
root->ac_reloff_num++;
}
return CL_SUCCESS;
}

@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2008 Sourcefire, Inc.
* Copyright (C) 2007-2009 Sourcefire, Inc.
*
* Authors: Tomasz Kojm
*
@ -50,7 +50,7 @@ struct cli_ac_patt {
uint32_t sigid;
uint32_t lsigid[3];
uint16_t ch[2];
char *virname, *offset;
char *virname;
void *customdata;
uint16_t ch_mindist[2];
uint16_t ch_maxdist[2];
@ -59,6 +59,7 @@ struct cli_ac_patt {
struct cli_ac_patt *next, *next_same;
uint8_t depth;
uint16_t rtype, type;
uint32_t offdata[4], offset_min, offset_max;
};
struct cli_ac_node {
@ -81,9 +82,10 @@ int cli_ac_addpatt(struct cli_matcher *root, struct cli_ac_patt *pattern);
int cli_ac_initdata(struct cli_ac_data *data, uint32_t partsigs, uint32_t lsigs, uint8_t tracklen);
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, int fd, 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, const 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);
int cli_ac_caloff(struct cli_matcher *root, int fd);
void cli_ac_free(struct cli_matcher *root);
int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hexsig, uint32_t sigid, uint16_t parts, uint16_t partno, uint16_t rtype, uint16_t type, uint32_t mindist, uint32_t maxdist, const char *offset, const uint32_t *lsigid, unsigned int options);

@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2008 Sourcefire, Inc.
* Copyright (C) 2007-2009 Sourcefire, Inc.
*
* Authors: Tomasz Kojm
*
@ -38,11 +38,12 @@
#define BM_BLOCK_SIZE 3
#define HASH(a,b,c) (211 * a + 37 * b + c)
int cli_bm_addpatt(struct cli_matcher *root, struct cli_bm_patt *pattern)
int cli_bm_addpatt(struct cli_matcher *root, struct cli_bm_patt *pattern, const char *offset)
{
uint16_t idx, i;
const unsigned char *pt = pattern->pattern;
struct cli_bm_patt *prev, *next = NULL;
int ret;
if(pattern->length < BM_MIN_LENGTH) {
@ -50,6 +51,13 @@ int cli_bm_addpatt(struct cli_matcher *root, struct cli_bm_patt *pattern)
return CL_EMALFDB;
}
if((ret = cli_caloff(offset, NULL, -1, root->type, pattern->offdata, &pattern->offset_min, &pattern->offset_max))) {
cli_errmsg("cli_bm_addpatt: Can't calculate offset for signature %s\n", pattern->virname);
return ret;
}
if(pattern->offdata[0] != CLI_OFF_ANY && pattern->offdata[0] != CLI_OFF_ABSOLUTE)
root->bm_reloff_num++;
#if BM_MIN_LENGTH == BM_BLOCK_SIZE
/* try to load balance bm_suffix (at the cost of bm_shift) */
for(i = 0; i < pattern->length - BM_BLOCK_SIZE + 1; i++) {
@ -137,8 +145,6 @@ void cli_bm_free(struct cli_matcher *root)
mpool_free(root->mempool, prev->pattern);
if(prev->virname)
mpool_free(root->mempool, prev->virname);
if(prev->offset)
mpool_free(root->mempool, prev->offset);
mpool_free(root->mempool, prev);
}
}
@ -146,7 +152,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_matcher *root, uint32_t offset, cli_file_t ftype, int fd)
int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_matcher *root, uint32_t offset, int fd)
{
uint32_t i, j, off;
uint8_t found, pchain, shift;
@ -154,7 +160,8 @@ int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
struct cli_bm_patt *p;
const unsigned char *bp, *pt;
unsigned char prefix;
struct cli_target_info info;
struct cli_target_info info;
int ret;
if(!root || !root->bm_shift)
@ -164,7 +171,6 @@ int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
return CL_CLEAN;
memset(&info, 0, sizeof(info));
for(i = BM_MIN_LENGTH - BM_BLOCK_SIZE; i < length - BM_BLOCK_SIZE + 1; ) {
idx = HASH(buffer[i], buffer[i + 1], buffer[i + 2]);
shift = root->bm_shift[idx];
@ -214,21 +220,26 @@ int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
}
if(found && p->length + p->prefix_length == j) {
if(p->offset) {
if(p->offset_min != CLI_OFF_ANY) {
if(p->offdata[0] != CLI_OFF_ABSOLUTE) {
ret = cli_caloff(NULL, &info, fd, root->type, p->offdata, &p->offset_min, &p->offset_max);
if(ret != CL_SUCCESS) {
cli_errmsg("cli_bm_scanbuff: Can't calculate relative offset in signature for %s\n", p->virname);
if(info.exeinfo.section)
free(info.exeinfo.section);
return ret;
}
}
off = offset + i - p->prefix_length - BM_MIN_LENGTH + BM_BLOCK_SIZE;
if(!cli_validatesig(ftype, p->offset, off, &info, fd, p->virname)) {
if(p->offset_max > off || p->offset_min < off) {
p = p->next;
continue;
}
}
if(virname)
*virname = p->virname;
if(info.exeinfo.section)
free(info.exeinfo.section);
return CL_VIRUS;
}
@ -243,6 +254,5 @@ int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
if(info.exeinfo.section)
free(info.exeinfo.section);
return CL_CLEAN;
}

@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2008 Sourcefire, Inc.
* Copyright (C) 2007-2009 Sourcefire, Inc.
*
* Authors: Tomasz Kojm
*
@ -27,17 +27,17 @@
struct cli_bm_patt {
unsigned char *pattern, *prefix;
char *virname, *offset;
char *virname;
uint32_t offdata[4], offset_min, offset_max;
struct cli_bm_patt *next;
uint16_t length, prefix_length;
uint16_t cnt;
unsigned char pattern0;
uint8_t target;
};
int cli_bm_addpatt(struct cli_matcher *root, struct cli_bm_patt *pattern);
int cli_bm_addpatt(struct cli_matcher *root, struct cli_bm_patt *pattern, const char *offset);
int cli_bm_init(struct cli_matcher *root);
int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_matcher *root, uint32_t offset, cli_file_t ftype, int fd);
int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_matcher *root, uint32_t offset, int fd);
void cli_bm_free(struct cli_matcher *root);
#endif

@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2008 Sourcefire, Inc.
* Copyright (C) 2007-2009 Sourcefire, Inc.
*
* Authors: Tomasz Kojm
*
@ -76,8 +76,8 @@ 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, CLI_DEFAULT_AC_TRACKLEN)))
return ret;
if(troot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, troot, offset, ftype, -1)) != CL_VIRUS)
ret = cli_ac_scanbuff(buffer, length, virname, NULL, NULL, troot, acdata ? (acdata[0]) : (&mdata), offset, ftype, -1, NULL, AC_SCAN_VIR, NULL);
if(troot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, troot, offset, -1)) != CL_VIRUS)
ret = cli_ac_scanbuff(buffer, length, virname, NULL, NULL, troot, acdata ? (acdata[0]) : (&mdata), offset, ftype, NULL, AC_SCAN_VIR, NULL);
if(!acdata)
cli_ac_freedata(&mdata);
@ -89,8 +89,8 @@ int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset,
if(!acdata && (ret = cli_ac_initdata(&mdata, groot->ac_partsigs, groot->ac_lsigs, CLI_DEFAULT_AC_TRACKLEN)))
return ret;
if(groot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, groot, offset, ftype, -1)) != CL_VIRUS)
ret = cli_ac_scanbuff(buffer, length, virname, NULL, NULL, groot, acdata ? (acdata[1]) : (&mdata), offset, ftype, -1, NULL, AC_SCAN_VIR, NULL);
if(groot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, groot, offset, -1)) != CL_VIRUS)
ret = cli_ac_scanbuff(buffer, length, virname, NULL, NULL, groot, acdata ? (acdata[1]) : (&mdata), offset, ftype, NULL, AC_SCAN_VIR, NULL);
if(!acdata)
cli_ac_freedata(&mdata);
@ -98,112 +98,188 @@ int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset,
return ret;
}
off_t cli_caloff(const char *offstr, struct cli_target_info *info, int fd, cli_file_t ftype, int *ret, unsigned int *maxshift)
/*
* offdata[0]: type
* offdata[1]: offset value
* offdata[2]: max shift
* offdata[3]: section number
*/
int cli_caloff(const char *offstr, struct cli_target_info *info, int fd, unsigned int target, uint32_t *offdata, uint32_t *offset_min, uint32_t *offset_max)
{
int (*einfo)(int, struct cli_exe_info *) = NULL;
char offcpy[65];
unsigned int n, val;
const char *pt;
off_t pos, offset;
*ret = 0;
char *pt;
off_t pos;
struct stat sb;
if((pt = strchr(offstr, ',')))
*maxshift = atoi(++pt);
if(isdigit(offstr[0]))
return atoi(offstr);
if(!info) { /* decode offset string */
if(!offstr) {
cli_errmsg("cli_caloff: offstr == NULL\n");
return CL_ENULLARG;
}
if(fd == -1) {
*ret = -1;
return 0;
}
if(!strcmp(offstr, "*")) {
offdata[0] = *offset_max = *offset_min = CLI_OFF_ANY;
return CL_SUCCESS;
}
if(!strncmp(offstr, "EP", 2) || offstr[0] == 'S') {
if(strlen(offstr) > 64) {
cli_errmsg("cli_caloff: Offset string too long\n");
return CL_EMALFDB;
}
strcpy(offcpy, offstr);
if(info->status == -1) {
*ret = -1;
return 0;
if((pt = strchr(offcpy, ','))) {
if(!cli_isnumber(pt + 1)) {
cli_errmsg("cli_caloff: Invalid offset shift value\n");
return CL_EMALFDB;
}
offdata[2] = atoi(pt + 1);
*pt = 0;
} else {
offdata[2] = 0;
}
} else if(!info->status) {
*offset_max = *offset_min = CLI_OFF_NONE;
if(ftype == CL_TYPE_MSEXE)
einfo = cli_peheader;
else if(ftype == CL_TYPE_ELF)
einfo = cli_elfheader;
else if(ftype == CL_TYPE_MACHO)
einfo = cli_machoheader;
if(!strncmp(offcpy, "EP+", 3) || !strncmp(offcpy, "EP-", 3)) {
if(offcpy[2] == '+')
offdata[0] = CLI_OFF_EP_PLUS;
else
offdata[0] = CLI_OFF_EP_MINUS;
if(einfo) {
if((pos = lseek(fd, 0, SEEK_CUR)) == -1) {
cli_dbgmsg("Invalid descriptor\n");
info->status = *ret = -1;
return 0;
if(!cli_isnumber(&offcpy[3])) {
cli_errmsg("cli_caloff: Invalid offset value\n");
return CL_EMALFDB;
}
offdata[1] = atoi(&offcpy[3]);
} else if(offcpy[0] == 'S') {
if(!strncmp(offstr, "SL+", 3)) {
offdata[0] = CLI_OFF_SL_PLUS;
if(!cli_isnumber(&offcpy[3])) {
cli_errmsg("cli_caloff: Invalid offset value\n");
return CL_EMALFDB;
}
offdata[1] = atoi(&offcpy[3]);
} else if(sscanf(offcpy, "S%u+%u", &n, &val) == 2) {
offdata[0] = CLI_OFF_SX_PLUS;
offdata[1] = val;
offdata[3] = n;
} else {
cli_errmsg("cli_caloff: Invalid offset string\n");
return CL_EMALFDB;
}
lseek(fd, 0, SEEK_SET);
if(einfo(fd, &info->exeinfo)) {
lseek(fd, pos, SEEK_SET);
info->status = *ret = -1;
return 0;
}
lseek(fd, pos, SEEK_SET);
info->status = 1;
} else if(!strncmp(offcpy, "EOF-", 4)) {
offdata[0] = CLI_OFF_EOF_MINUS;
if(!cli_isnumber(&offcpy[4])) {
cli_errmsg("cli_caloff: Invalid offset value\n");
return CL_EMALFDB;
}
offdata[1] = atoi(&offcpy[4]);
} else {
offdata[0] = CLI_OFF_ABSOLUTE;
if(!cli_isnumber(offcpy)) {
cli_errmsg("cli_caloff: Invalid offset value\n");
return CL_EMALFDB;
}
*offset_min = offdata[1] = atoi(offcpy);
*offset_max = *offset_min + offdata[2];
}
}
if(info->status == 1 && (!strncmp(offstr, "EP+", 3) || !strncmp(offstr, "EP-", 3))) {
if(offstr[2] == '+')
return info->exeinfo.ep + atoi(offstr + 3);
else
return info->exeinfo.ep - atoi(offstr + 3);
} else if(info->status == 1 && offstr[0] == 'S') {
if(offdata[0] != CLI_OFF_ANY && offdata[0] != CLI_OFF_ABSOLUTE && offdata[0] != CLI_OFF_EOF_MINUS) {
if(target != 1 && target != 6 && target != 9) {
cli_errmsg("cli_caloff: Invalid offset type for target %u\n", target);
return CL_EMALFDB;
}
}
if(!strncmp(offstr, "SL", 2) && info->exeinfo.section[info->exeinfo.nsections - 1].rsz) {
} else {
/* calculate relative offsets */
if(info->status == -1) {
*offset_min = *offset_max = 0;
return CL_SUCCESS;
}
if(sscanf(offstr, "SL+%u", &val) != 1) {
*ret = -1;
return 0;
if((offdata[0] == CLI_OFF_EOF_MINUS)) {
if(!info->fsize) {
if(fstat(fd, &sb) == -1) {
cli_errmsg("cli_caloff: fstat(%d) failed\n", fd);
return CL_ESTAT;
}
info->fsize = sb.st_size;
}
offset = val + info->exeinfo.section[info->exeinfo.nsections - 1].raw;
} else {
} else if(!info->status) {
if(target == 1)
einfo = cli_peheader;
else if(target == 6)
einfo = cli_elfheader;
else if(target == 9)
einfo = cli_machoheader;
if(sscanf(offstr, "S%u+%u", &n, &val) != 2) {
*ret = -1;
return 0;
if(!einfo) {
cli_errmsg("cli_caloff: Invalid offset/filetype\n");
return CL_EMALFDB;
}
if(n >= info->exeinfo.nsections || !info->exeinfo.section[n].rsz) {
*ret = -1;
return 0;
if((pos = lseek(fd, 0, SEEK_CUR)) == -1) {
cli_errmsg("cli_caloff: lseek(%d) failed\n", fd);
return CL_ESEEK;
}
offset = val + info->exeinfo.section[n].raw;
lseek(fd, 0, SEEK_SET);
if(einfo(fd, &info->exeinfo)) {
/* einfo *may* fail */
lseek(fd, pos, SEEK_SET);
info->status = -1;
*offset_min = *offset_max = 0;
return CL_SUCCESS;
}
lseek(fd, pos, SEEK_SET);
info->status = 1;
}
return offset;
switch(offdata[0]) {
case CLI_OFF_EOF_MINUS:
*offset_min = info->fsize - offdata[1];
break;
} else if(!strncmp(offstr, "EOF-", 4)) {
struct stat sb;
case CLI_OFF_EP_PLUS:
*offset_min = info->exeinfo.ep + offdata[1];
break;
if(!info->fsize) {
if(fstat(fd, &sb) == -1) {
info->status = *ret = -1;
return 0;
}
info->fsize = sb.st_size;
case CLI_OFF_EP_MINUS:
*offset_min = info->exeinfo.ep - offdata[1];
break;
case CLI_OFF_SL_PLUS:
*offset_min = info->exeinfo.section[info->exeinfo.nsections - 1].raw + offdata[1];
break;
case CLI_OFF_SX_PLUS:
if(offdata[3] >= info->exeinfo.nsections)
*offset_min = 0;
else
*offset_min = info->exeinfo.section[offdata[3]].raw + offdata[1];
break;
default:
cli_errmsg("cli_caloff: Not a relative offset (type: %u)\n", offdata[0]);
return CL_EARG;
}
return info->fsize - atoi(offstr + 4);
if(!*offset_min)
*offset_max = 0;
else
*offset_max = *offset_min + offdata[2];
}
*ret = -1;
return 0;
return CL_SUCCESS;
}
int cli_checkfp(int fd, cli_ctx *ctx)
@ -227,7 +303,7 @@ int cli_checkfp(int fd, cli_ctx *ctx)
return 0;
}
if(cli_bm_scanbuff(digest, 16, &virname, ctx->engine->md5_fp, 0, 0, -1) == CL_VIRUS) {
if(cli_bm_scanbuff(digest, 16, &virname, ctx->engine->md5_fp, 0, -1) == CL_VIRUS) {
cli_dbgmsg("cli_checkfp(): Found false positive detection (fp sig: %s)\n", virname);
free(digest);
lseek(fd, pos, SEEK_SET);
@ -240,33 +316,6 @@ int cli_checkfp(int fd, cli_ctx *ctx)
return 0;
}
int cli_validatesig(cli_file_t ftype, const char *offstr, off_t fileoff, struct cli_target_info *info, int desc, const char *virname)
{
off_t offset;
int ret;
unsigned int maxshift = 0;
if(offstr) {
offset = cli_caloff(offstr, info, desc, ftype, &ret, &maxshift);
if(ret == -1)
return 0;
if(maxshift) {
if((fileoff < offset) || (fileoff > offset + (off_t) maxshift)) {
/* cli_dbgmsg("Signature offset: %lu, expected: [%lu..%lu] (%s)\n", (unsigned long int) fileoff, (unsigned long int) offset, (unsigned long int) (offset + maxshift), virname); */
return 0;
}
} else if(fileoff != offset) {
/* cli_dbgmsg("Signature offset: %lu, expected: %lu (%s)\n", (unsigned long int) fileoff, (unsigned long int) offset, virname); */
return 0;
}
}
return 1;
}
int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode)
{
unsigned char *buffer, *buff, *endbl, *upt;
@ -316,12 +365,16 @@ int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struc
return CL_EMEM;
}
if(!ftonly && (ret = cli_ac_initdata(&gdata, groot->ac_partsigs, groot->ac_lsigs, CLI_DEFAULT_AC_TRACKLEN)))
return ret;
if(!ftonly)
if((ret = cli_ac_caloff(groot, desc)) || (ret = cli_ac_initdata(&gdata, groot->ac_partsigs, groot->ac_lsigs, CLI_DEFAULT_AC_TRACKLEN)))
return ret;
if(troot) {
if((ret = cli_ac_initdata(&tdata, troot->ac_partsigs, troot->ac_lsigs, CLI_DEFAULT_AC_TRACKLEN)))
if((ret = cli_ac_caloff(troot, desc)) || (ret = cli_ac_initdata(&tdata, troot->ac_partsigs, troot->ac_lsigs, CLI_DEFAULT_AC_TRACKLEN))) {
if(!ftonly)
cli_ac_freedata(&gdata);
return ret;
}
}
if(!ftonly && ctx->engine->md5_hdb)
@ -344,8 +397,8 @@ int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struc
length += maxpatlen;
if(troot) {
if(troot->ac_only || (ret = cli_bm_scanbuff(upt, length, ctx->virname, troot, offset, ftype, desc)) != CL_VIRUS)
ret = cli_ac_scanbuff(upt, length, ctx->virname, NULL, NULL, troot, &tdata, offset, ftype, desc, ftoffset, acmode, NULL);
if(troot->ac_only || (ret = cli_bm_scanbuff(upt, length, ctx->virname, troot, offset, desc)) != CL_VIRUS)
ret = cli_ac_scanbuff(upt, length, ctx->virname, NULL, NULL, troot, &tdata, offset, ftype, ftoffset, acmode, NULL);
if(ret == CL_VIRUS) {
free(buffer);
@ -361,8 +414,8 @@ int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struc
}
if(!ftonly) {
if(groot->ac_only || (ret = cli_bm_scanbuff(upt, length, ctx->virname, groot, offset, ftype, desc)) != CL_VIRUS)
ret = cli_ac_scanbuff(upt, length, ctx->virname, NULL, NULL, groot, &gdata, offset, ftype, desc, ftoffset, acmode, NULL);
if(groot->ac_only || (ret = cli_bm_scanbuff(upt, length, ctx->virname, groot, offset, desc)) != CL_VIRUS)
ret = cli_ac_scanbuff(upt, length, ctx->virname, NULL, NULL, groot, &gdata, offset, ftype, ftoffset, acmode, NULL);
if(ret == CL_VIRUS) {
free(buffer);
@ -439,7 +492,7 @@ int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struc
if(!ftonly && ctx->engine->md5_hdb) {
cli_md5_final(digest, &md5ctx);
if(cli_bm_scanbuff(digest, 16, ctx->virname, ctx->engine->md5_hdb, 0, 0, -1) == CL_VIRUS && (cli_bm_scanbuff(digest, 16, NULL, ctx->engine->md5_fp, 0, 0, -1) != CL_VIRUS))
if(cli_bm_scanbuff(digest, 16, ctx->virname, ctx->engine->md5_hdb, 0, -1) == CL_VIRUS && (cli_bm_scanbuff(digest, 16, NULL, ctx->engine->md5_fp, 0, -1) != CL_VIRUS))
return CL_VIRUS;
}

@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2008 Sourcefire, Inc.
* Copyright (C) 2007-2009 Sourcefire, Inc.
*
* Authors: Tomasz Kojm
*
@ -69,18 +69,22 @@ struct cli_ac_lsig {
};
struct cli_matcher {
unsigned int type;
/* Extended Boyer-Moore */
uint8_t *bm_shift;
struct cli_bm_patt **bm_suffix;
struct cli_hashset md5_sizes_hs;
uint32_t *soff, soff_len; /* for PE section sigs */
uint32_t bm_patterns;
uint32_t bm_patterns, bm_reloff_num;
/* Extended Aho-Corasick */
uint32_t ac_partsigs, ac_nodes, ac_patterns, ac_lsigs;
struct cli_ac_lsig **ac_lsigtable;
struct cli_ac_node *ac_root, **ac_nodetable;
struct cli_ac_patt **ac_pattable;
struct cli_ac_patt **ac_reloff;
uint32_t ac_reloff_num;
uint8_t ac_mindepth, ac_maxdepth;
uint16_t maxpatlen;
@ -124,13 +128,20 @@ struct cli_target_info {
int8_t status; /* 0 == not initialised, 1 == initialised OK, -1 == error */
};
#define CLI_OFF_ANY 0xffffffff
#define CLI_OFF_NONE 0xfffffffe
#define CLI_OFF_ABSOLUTE 1
#define CLI_OFF_EOF_MINUS 2
#define CLI_OFF_EP_PLUS 3
#define CLI_OFF_EP_MINUS 4
#define CLI_OFF_SL_PLUS 5
#define CLI_OFF_SX_PLUS 6
int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset, cli_ctx *ctx, cli_file_t ftype, struct cli_ac_data **acdata);
int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode);
int cli_validatesig(cli_file_t ftype, const char *offstr, off_t fileoff, struct cli_target_info *info, int desc, const char *virname);
off_t cli_caloff(const char *offstr, struct cli_target_info *info, int fd, cli_file_t ftype, int *ret, unsigned int *maxshift);
int cli_caloff(const char *offstr, struct cli_target_info *info, int fd, unsigned int target, uint32_t *offdata, uint32_t *offset_min, uint32_t *offset_max);
int cli_checkfp(int fd, cli_ctx *ctx);

@ -928,8 +928,8 @@ int cli_scanpe(int desc, cli_ctx *ctx)
for(j = 0; j < md5_sect->soff_len && md5_sect->soff[j] <= exe_sections[i].rsz; j++) {
if(md5_sect->soff[j] == exe_sections[i].rsz) {
unsigned char md5_dig[16];
if(cli_md5sect(desc, &exe_sections[i], md5_dig) && cli_bm_scanbuff(md5_dig, 16, ctx->virname, ctx->engine->md5_mdb, 0, 0, -1) == CL_VIRUS) {
if(cli_bm_scanbuff(md5_dig, 16, NULL, ctx->engine->md5_fp, 0, 0, -1) != CL_VIRUS) {
if(cli_md5sect(desc, &exe_sections[i], md5_dig) && cli_bm_scanbuff(md5_dig, 16, ctx->virname, ctx->engine->md5_mdb, 0, -1) == CL_VIRUS) {
if(cli_bm_scanbuff(md5_dig, 16, NULL, ctx->engine->md5_fp, 0, -1) != CL_VIRUS) {
free(section_hdr);
free(exe_sections);

@ -1198,13 +1198,13 @@ static int hash_match(const struct regex_matcher *rlist, const char *host, size_
h[64]='\0';
cli_dbgmsg("Looking up hash %s for %s(%u)%s(%u)\n", h, host, (unsigned)hlen, path, (unsigned)plen);
if (prefix_matched) {
if (cli_bm_scanbuff(sha256_dig, 4, &virname, &rlist->hostkey_prefix,0,0,-1) == CL_VIRUS) {
if (cli_bm_scanbuff(sha256_dig, 4, &virname, &rlist->hostkey_prefix,0,-1) == CL_VIRUS) {
cli_dbgmsg("prefix matched\n");
*prefix_matched = 1;
} else
return CL_SUCCESS;
}
if (cli_bm_scanbuff(sha256_dig, 32, &virname, &rlist->sha256_hashes,0,0,-1) == CL_VIRUS) {
if (cli_bm_scanbuff(sha256_dig, 32, &virname, &rlist->sha256_hashes,0,-1) == CL_VIRUS) {
cli_dbgmsg("This hash matched: %s\n", h);
switch(*virname) {
case 'W':

@ -120,10 +120,11 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex
struct cli_bm_patt *bm_new;
char *pt, *hexcpy, *start, *n;
int ret, asterisk = 0;
unsigned int i, j, len, parts = 0;
unsigned int i, j, hexlen, parts = 0;
int mindist = 0, maxdist = 0, error = 0;
hexlen = strlen(hexsig);
if(strchr(hexsig, '{')) {
root->ac_partsigs++;
@ -131,8 +132,7 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex
if(!(hexcpy = cli_strdup(hexsig)))
return CL_EMEM;
len = strlen(hexsig);
for(i = 0; i < len; i++)
for(i = 0; i < hexlen; i++)
if(hexsig[i] == '{' || hexsig[i] == '*')
parts++;
@ -224,8 +224,7 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex
} else if(strchr(hexsig, '*')) {
root->ac_partsigs++;
len = strlen(hexsig);
for(i = 0; i < len; i++)
for(i = 0; i < hexlen; i++)
if(hexsig[i] == '*')
parts++;
@ -247,7 +246,7 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex
free(pt);
}
} else if(root->ac_only || strpbrk(hexsig, "?(") || type || lsigid) {
} else if(root->ac_only || type || lsigid /* || (hexlen / 2 < CLI_DEFAULT_MOVETOAC_LEN) FIXME: unit tests */ || strpbrk(hexsig, "?(")) {
if((ret = cli_ac_addsig(root, virname, hexsig, 0, 0, 0, rtype, type, 0, 0, offset, lsigid, options))) {
cli_errmsg("cli_parse_add(): Problem adding signature (3).\n");
return ret;
@ -262,7 +261,7 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex
mpool_free(root->mempool, bm_new);
return CL_EMALFDB;
}
bm_new->length = strlen(hexsig) / 2;
bm_new->length = hexlen / 2;
bm_new->virname = cli_mpool_virname(root->mempool, (char *) virname, options & CL_DB_OFFICIAL);
if(!bm_new->virname) {
@ -271,22 +270,10 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex
return CL_EMEM;
}
if(offset) {
bm_new->offset = cli_mpool_strdup(root->mempool, offset);
if(!bm_new->offset) {
mpool_free(root->mempool, bm_new->pattern);
mpool_free(root->mempool, bm_new->virname);
mpool_free(root->mempool, bm_new);
return CL_EMEM;
}
}
bm_new->target = target;
if(bm_new->length > root->maxpatlen)
root->maxpatlen = bm_new->length;
if((ret = cli_bm_addpatt(root, bm_new))) {
if((ret = cli_bm_addpatt(root, bm_new, offset))) {
cli_errmsg("cli_parse_add(): Problem adding signature (4).\n");
mpool_free(root->mempool, bm_new->pattern);
mpool_free(root->mempool, bm_new->virname);
@ -308,14 +295,14 @@ static int cli_initroots(struct cl_engine *engine, unsigned int options)
if(!engine->root[i]) {
cli_dbgmsg("Initializing engine->root[%d]\n", i);
root = engine->root[i] = (struct cli_matcher *) mpool_calloc(engine->mempool, 1, sizeof(struct cli_matcher));
#ifdef USE_MPOOL
root->mempool = engine->mempool;
#endif
if(!root) {
cli_errmsg("cli_initroots: Can't allocate memory for cli_matcher\n");
return CL_EMEM;
}
#ifdef USE_MPOOL
root->mempool = engine->mempool;
#endif
root->type = i;
if(cli_mtargets[i].ac_only || engine->ac_only)
root->ac_only = 1;
@ -511,7 +498,7 @@ static int cli_loaddb(FILE *fs, struct cl_engine *engine, unsigned int *signo, u
if(*pt == '=') continue;
if((ret = cli_parse_add(root, start, pt, 0, 0, NULL, 0, NULL, options))) {
if((ret = cli_parse_add(root, start, pt, 0, 0, "*", 0, NULL, options))) {
ret = CL_EMALFDB;
break;
}
@ -576,27 +563,6 @@ static int cli_loadpdb(FILE *fs, struct cl_engine *engine, unsigned int *signo,
return CL_SUCCESS;
}
static int cli_checkoffset(const char *offset, unsigned int type)
{
unsigned int foo;
const char *pt = offset;
if(isdigit(*offset)) {
while(*pt++)
if(!strchr("0123456789,", *pt))
return 1;
return 0;
}
if(!strncmp(offset, "EOF-", 4))
return 0;
if((type == 1 || type == 6 || type == 9) && (!strncmp(offset, "EP+", 3) || !strncmp(offset, "EP-", 3) || (sscanf(offset, "SL+%u", &foo) == 1) || (sscanf(offset, "S%u+%u", &foo, &foo) == 2)))
return 0;
return 1;
}
#define NDB_TOKENS 6
static int cli_loadndb(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned short sdb, unsigned int options, struct cli_dbio *dbio, const char *dbname)
{
@ -680,15 +646,6 @@ static int cli_loadndb(FILE *fs, struct cl_engine *engine, unsigned int *signo,
root = engine->root[target];
offset = tokens[2];
if(!strcmp(offset, "*"))
offset = NULL;
if(offset && cli_checkoffset(offset, target)) {
cli_errmsg("Incorrect offset '%s' for signature type-%u\n", offset, target);
ret = CL_EMALFDB;
break;
}
sig = tokens[3];
if((ret = cli_parse_add(root, virname, sig, 0, 0, offset, target, NULL, options))) {
@ -1025,19 +982,11 @@ static int cli_loadldb(FILE *fs, struct cl_engine *engine, unsigned int *signo,
*pt = 0;
sig = ++pt;
offset = tokens[3 + i];
if(!strcmp(offset, "*"))
offset = NULL;
} else {
offset = NULL;
offset = "*";
sig = tokens[3 + i];
}
if(offset && cli_checkoffset(offset, tdb.target[0])) {
cli_errmsg("Incorrect offset '%s' in subsignature id %u for signature type-%u\n", offset, i, tdb.target[0]);
ret = CL_EMALFDB;
break;
}
if((ret = cli_parse_add(root, virname, sig, 0, 0, offset, target, lsigid, options))) {
ret = CL_EMALFDB;
break;
@ -1131,7 +1080,7 @@ static int cli_loadftm(FILE *fs, struct cl_engine *engine, unsigned int options,
}
if(atoi(tokens[0]) == 1) { /* A-C */
if((ret = cli_parse_add(engine->root[0], tokens[3], tokens[2], rtype, type, strcmp(tokens[1], "*") ? tokens[1] : NULL, 0, NULL, options)))
if((ret = cli_parse_add(engine->root[0], tokens[3], tokens[2], rtype, type, tokens[1], 0, NULL, options)))
break;
} else if(atoi(tokens[0]) == 0) { /* memcmp() */
@ -1394,7 +1343,7 @@ static int cli_loadmd5(FILE *fs, struct cl_engine *engine, unsigned int *signo,
MD5_DB;
}
if((ret = cli_bm_addpatt(db, new))) {
if((ret = cli_bm_addpatt(db, new, "0"))) {
cli_errmsg("cli_loadmd5: Error adding BM pattern\n");
mpool_free(engine->mempool, new->pattern);
mpool_free(engine->mempool, new->virname);
@ -2203,7 +2152,7 @@ int cl_engine_compile(struct cl_engine *engine)
if((root = engine->root[i])) {
if((ret = cli_ac_buildtrie(root)))
return ret;
cli_dbgmsg("matcher[%u]: %s: AC sigs: %u BM sigs: %u %s\n", i, cli_mtargets[i].name, root->ac_patterns, root->bm_patterns, root->ac_only ? "(ac_only mode)" : "");
cli_dbgmsg("matcher[%u]: %s: AC sigs: %u (reloff: %u) BM sigs: %u (reloff: %u) %s\n", i, cli_mtargets[i].name, root->ac_patterns, root->ac_reloff_num, root->bm_patterns, root->bm_reloff_num, root->ac_only ? "(ac_only mode)" : "");
}
}

@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2008 Sourcefire, Inc.
* Copyright (C) 2007-2009 Sourcefire, Inc.
*
* Authors: Tomasz Kojm
*

@ -305,7 +305,7 @@ int regex_list_match(struct regex_matcher* matcher,char* real_url,const char* di
* negatives */
return 0;
}
rc = cli_ac_scanbuff((const unsigned char*)bufrev,buffer_len, NULL, (void*)&regex, &res, &matcher->suffixes,&mdata,0,0,-1,NULL,AC_SCAN_VIR,NULL);
rc = cli_ac_scanbuff((const unsigned char*)bufrev,buffer_len, NULL, (void*)&regex, &res, &matcher->suffixes,&mdata,0,0,NULL,AC_SCAN_VIR,NULL);
free(bufrev);
cli_ac_freedata(&mdata);
@ -455,7 +455,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, &matcher->sha256_hashes,0,0,-1) == CL_VIRUS) {
cli_bm_scanbuff(pat->pattern, 32, &vname, &matcher->sha256_hashes,0,-1) == CL_VIRUS) {
if (*vname == 'W') {
/* hash is whitelisted in local.gdb */
cli_dbgmsg("Skipping hash %s\n", pattern);
@ -471,7 +471,7 @@ static int add_hash(struct regex_matcher *matcher, char* pattern, const char fl,
}
*pat->virname = fl;
cli_hashset_addkey(&matcher->sha256_pfx_set, cli_readint32(pat->pattern));
if((rc = cli_bm_addpatt(bm, pat))) {
if((rc = cli_bm_addpatt(bm, pat, "*"))) {
cli_errmsg("add_hash: failed to add BM pattern\n");
free(pat->pattern);
free(pat->virname);
@ -675,7 +675,7 @@ static int add_newsuffix(struct regex_matcher *matcher, struct regex_list *info,
new->partno = 0;
new->mindist = 0;
new->maxdist = 0;
new->offset = 0;
new->offset_min = CLI_OFF_ANY;
new->length = len;
new->ch[0] = new->ch[1] |= CLI_MATCH_IGNORE;

@ -69,7 +69,7 @@ START_TEST (test_ac_scanbuff) {
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, NULL, 0, NULL, 0);
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");
}
@ -80,7 +80,7 @@ START_TEST (test_ac_scanbuff) {
fail_unless(ret == CL_SUCCESS, "cli_ac_initdata() failed");
for(i = 0; ac_testdata[i].data; i++) {
ret = cli_ac_scanbuff(ac_testdata[i].data, strlen(ac_testdata[i].data), &virname, NULL, NULL, root, &mdata, 0, 0, -1, NULL, AC_SCAN_VIR, NULL);
ret = cli_ac_scanbuff(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);
}
@ -109,14 +109,14 @@ START_TEST (test_bm_scanbuff) {
ret = cli_bm_init(root);
fail_unless(ret == CL_SUCCESS, "cli_bm_init() failed");
ret = cli_parse_add(root, "Sig1", "deadbabe", 0, 0, NULL, 0, NULL, 0);
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, NULL, 0, NULL, 0);
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, NULL, 0, NULL, 0);
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("blah\xde\xad\xbe\xef", 12, &virname, root, 0, 0, -1);
ret = cli_bm_scanbuff("blah\xde\xad\xbe\xef", 12, &virname, root, 0, -1);
fail_unless(ret == CL_VIRUS, "cli_bm_scanbuff() failed");
fail_unless(!strncmp(virname, "Sig2", 4), "Incorrect signature matched in cli_bm_scanbuff()\n");
cli_bm_free(root);

Loading…
Cancel
Save