extract and scan PE files embedded into other executables or fake zip files generated by some worms

git-svn: trunk@2934
remotes/push_mirror/metadata
Tomasz Kojm 19 years ago
parent 50b456e90f
commit ee99255a6d
  1. 5
      ChangeLog
  2. 2
      libclamav/execs.h
  3. 2
      libclamav/filetypes.c
  4. 2
      libclamav/filetypes.h
  5. 29
      libclamav/matcher-ac.c
  6. 3
      libclamav/matcher-ac.h
  7. 2
      libclamav/matcher.c
  8. 4
      libclamav/pe.c
  9. 103
      libclamav/scanners.c

@ -1,3 +1,8 @@
Mon Mar 12 20:31:07 CET 2007 (tk)
---------------------------------
* libclamav: extract and scan PE files embedded into other executables or
fake zip files generated by some worms
Mon Mar 12 19:55:31 CET 2007 (acab)
-----------------------------------
* libclamav/packlibs.h: Removed stale EXPERIMENTAL ifdef

@ -21,6 +21,7 @@
#define __EXECS_H
#include "cltypes.h"
#include <sys/types.h>
struct cli_exe_section {
uint32_t rva;
@ -34,6 +35,7 @@ struct cli_exe_section {
struct cli_exe_info {
uint32_t ep;
uint16_t nsections;
off_t offset;
struct cli_exe_section *section;
};

@ -194,6 +194,8 @@ static const struct cli_smagic_s cli_smagic[] = {
{"504b0304", "ZIP-SFX", CL_TYPE_ZIPSFX},
{"4d534346", "CAB-SFX", CL_TYPE_CABSFX},
{"4d5a{180-300}50450000", "PE", CL_TYPE_MSEXE},
{NULL, NULL, CL_TYPE_UNKNOWN_DATA}
};

@ -25,7 +25,7 @@
#define MAGIC_BUFFER_SIZE 256
#define CL_TYPENO 500
#define SFX_MAX_TESTS 10
#define MAX_EMBEDDED_OBJ 10
typedef enum {
CL_TYPE_UNKNOWN_TEXT = CL_TYPENO,

@ -314,10 +314,18 @@ int cli_ac_initdata(struct cli_ac_data *data, unsigned int partsigs, unsigned in
if(!partsigs)
return CL_SUCCESS;
data->inioff = (off_t *) cli_malloc(partsigs * sizeof(off_t));
if(!data->inioff) {
cli_errmsg("cli_ac_init(): unable to cli_malloc(%u)\n", partsigs * sizeof(off_t));
return CL_EMEM;
}
memset(data->inioff, -1, partsigs * sizeof(off_t));
data->partcnt = (unsigned int *) cli_calloc(partsigs, sizeof(unsigned int));
if(!data->partcnt) {
cli_errmsg("cli_ac_init(): unable to cli_calloc(%u, %u)\n", partsigs, sizeof(unsigned int));
free(data->inioff);
return CL_EMEM;
}
@ -325,6 +333,7 @@ int cli_ac_initdata(struct cli_ac_data *data, unsigned int partsigs, unsigned in
if(!data->offcnt) {
cli_errmsg("cli_ac_init(): unable to cli_calloc(%u, %u)\n", partsigs, sizeof(uint8_t));
free(data->inioff);
free(data->partcnt);
return CL_EMEM;
}
@ -333,6 +342,7 @@ int cli_ac_initdata(struct cli_ac_data *data, unsigned int partsigs, unsigned in
if(!data->offidx) {
cli_errmsg("cli_ac_init(): unable to cli_calloc(%u, %u)\n", partsigs, sizeof(uint8_t));
free(data->inioff);
free(data->partcnt);
free(data->offcnt);
return CL_EMEM;
@ -342,6 +352,7 @@ int cli_ac_initdata(struct cli_ac_data *data, unsigned int partsigs, unsigned in
if(!data->maxshift) {
cli_errmsg("cli_ac_init(): unable to cli_malloc(%u)\n", partsigs * sizeof(int));
free(data->inioff);
free(data->partcnt);
free(data->offcnt);
free(data->offidx);
@ -354,6 +365,7 @@ int cli_ac_initdata(struct cli_ac_data *data, unsigned int partsigs, unsigned in
if(!data->partoff) {
cli_errmsg("cli_ac_init(): unable to cli_calloc(%u, %u)\n", partsigs, sizeof(unsigned int));
free(data->inioff);
free(data->partcnt);
free(data->offcnt);
free(data->offidx);
@ -374,6 +386,7 @@ int cli_ac_initdata(struct cli_ac_data *data, unsigned int partsigs, unsigned in
free(data->partoff[j]);
free(data->partoff);
free(data->inioff);
free(data->partcnt);
free(data->offcnt);
free(data->offidx);
@ -392,6 +405,7 @@ void cli_ac_freedata(struct cli_ac_data *data)
if(data && data->partsigs) {
free(data->inioff);
free(data->partcnt);
free(data->offcnt);
free(data->offidx);
@ -446,6 +460,9 @@ int cli_ac_scanbuff(const unsigned char *buffer, unsigned int length, const char
if(pt->sigid) { /* it's a partial signature */
if(pt->partno == 1)
mdata->inioff[pt->sigid - 1] = curroff;
if(mdata->partcnt[pt->sigid - 1] + 1 == pt->partno) {
offnum = mdata->offcnt[pt->sigid - 1];
if(offnum < AC_DEFAULT_TRACKLEN) {
@ -491,10 +508,10 @@ int cli_ac_scanbuff(const unsigned char *buffer, unsigned int length, const char
if(++mdata->partcnt[pt->sigid - 1] + 1 == pt->parts) {
if(pt->type) {
if(otfrec) {
if(pt->type > type || pt->type >= CL_TYPE_SFX) {
cli_dbgmsg("Matched signature for file type %s\n", pt->virname);
if(pt->type > type || pt->type >= CL_TYPE_SFX || pt->type == CL_TYPE_MSEXE) {
cli_dbgmsg("Matched signature for file type %s at %u\n", pt->virname, (unsigned int) mdata->inioff[pt->sigid - 1]);
type = pt->type;
if(ftoffset && (!*ftoffset || (*ftoffset)->cnt < SFX_MAX_TESTS) && ftype == CL_TYPE_MSEXE && type >= CL_TYPE_SFX) {
if(ftoffset && (!*ftoffset || (*ftoffset)->cnt < MAX_EMBEDDED_OBJ) && ((ftype == CL_TYPE_MSEXE && type >= CL_TYPE_SFX) || ((ftype == CL_TYPE_MSEXE || ftype == CL_TYPE_ZIP) && type == CL_TYPE_MSEXE))) {
if(!(tnode = cli_calloc(1, sizeof(struct cli_matched_type)))) {
cli_errmsg("cli_ac_scanbuff(): Can't allocate memory for new type node\n");
if(info.exeinfo.section)
@ -503,7 +520,7 @@ int cli_ac_scanbuff(const unsigned char *buffer, unsigned int length, const char
}
tnode->type = type;
tnode->offset = -1; /* we don't remember the offset of the first part */
tnode->offset = mdata->inioff[pt->sigid - 1];
if(*ftoffset)
tnode->cnt = (*ftoffset)->cnt + 1;
@ -530,10 +547,10 @@ int cli_ac_scanbuff(const unsigned char *buffer, unsigned int length, const char
} else { /* old type signature */
if(pt->type) {
if(otfrec) {
if(pt->type > type || pt->type >= CL_TYPE_SFX) {
if(pt->type > type || pt->type >= CL_TYPE_SFX || pt->type == CL_TYPE_MSEXE) {
cli_dbgmsg("Matched signature for file type %s at %u\n", pt->virname, curroff);
type = pt->type;
if(ftoffset && (!*ftoffset ||(*ftoffset)->cnt < SFX_MAX_TESTS) && ftype == CL_TYPE_MSEXE && type >= CL_TYPE_SFX) {
if(ftoffset && (!*ftoffset || (*ftoffset)->cnt < MAX_EMBEDDED_OBJ) && ((ftype == CL_TYPE_MSEXE && type >= CL_TYPE_SFX) || ((ftype == CL_TYPE_MSEXE || ftype == CL_TYPE_ZIP) && type == CL_TYPE_MSEXE))) {
if(!(tnode = cli_calloc(1, sizeof(struct cli_matched_type)))) {
cli_errmsg("cli_ac_scanbuff(): Can't allocate memory for new type node\n");
if(info.exeinfo.section)

@ -20,6 +20,8 @@
#ifndef __MATCHER_AC_H
#define __MATCHER_AC_H
#include <sys/types.h>
#include "clamav.h"
#include "matcher.h"
#include "filetypes.h"
@ -30,6 +32,7 @@
struct cli_ac_data {
unsigned int partsigs;
off_t *inioff;
unsigned int *partcnt;
unsigned int **partoff;
uint8_t *offcnt;

@ -272,7 +272,7 @@ int cli_validatesig(cli_file_t ftype, const char *offstr, off_t fileoff, struct
}
if(maxshift) {
if((fileoff < offset) || (fileoff > offset + maxshift)) {
if((fileoff < offset) || (fileoff > offset + (off_t) maxshift)) {
cli_dbgmsg("Signature offset: %lu, expected: [%lu..%lu] (%s)\n", fileoff, offset, offset + maxshift, virname);
return 0;
}

@ -2819,7 +2819,7 @@ int cli_peheader(int desc, struct cli_exe_info *peinfo)
return -1;
}
fsize = sb.st_size;
fsize = sb.st_size - peinfo->offset;
if(cli_readn(desc, &e_magic, sizeof(e_magic)) != sizeof(e_magic)) {
cli_dbgmsg("Can't read DOS signature\n");
@ -2845,7 +2845,7 @@ int cli_peheader(int desc, struct cli_exe_info *peinfo)
return -1;
}
if(lseek(desc, e_lfanew, SEEK_SET) < 0) {
if(lseek(desc, peinfo->offset + e_lfanew, SEEK_SET) < 0) {
/* probably not a PE file */
cli_dbgmsg("Can't lseek to e_lfanew\n");
return -1;

@ -1680,17 +1680,84 @@ static int cli_scanmail(int desc, cli_ctx *ctx)
return ret;
}
static int cli_scanembpe(int desc, cli_ctx *ctx)
{
int fd, bytes, ret = CL_CLEAN;
unsigned long int size = 0;
char buff[512];
char *tmpname;
tmpname = cli_gentemp(NULL);
if(!tmpname)
return CL_EMEM;
if((fd = open(tmpname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
cli_errmsg("cli_scanembpe: Can't create file %s\n", tmpname);
free(tmpname);
return CL_EIO;
}
while((bytes = read(desc, buff, sizeof(buff))) > 0) {
size += bytes;
if(ctx->limits && ctx->limits->maxfilesize && (size + sizeof(buff) > ctx->limits->maxfilesize)) {
cli_dbgmsg("cli_scanembpe: Size exceeded (stopped at %lu, max: %lu)\n", size, ctx->limits->maxfilesize);
/* BLOCKMAX should be ignored here */
break;
}
if(cli_writen(fd, buff, bytes) != bytes) {
cli_dbgmsg("cli_scanembpe: Can't write to temporary file\n");
close(fd);
if(!cli_leavetemps_flag)
unlink(tmpname);
free(tmpname);
return CL_EIO;
}
}
if(fsync(fd) == -1) {
cli_dbgmsg("cli_scanembpe: Can't synchronise descriptor %d\n", fd);
close(fd);
if(!cli_leavetemps_flag)
unlink(tmpname);
free(tmpname);
return CL_EFSYNC;
}
lseek(fd, 0, SEEK_SET);
if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS) {
cli_dbgmsg("cli_scanembpe: Infected with %s\n", *ctx->virname);
close(fd);
if(!cli_leavetemps_flag)
unlink(tmpname);
free(tmpname);
return CL_VIRUS;
}
close(fd);
if(!cli_leavetemps_flag)
unlink(tmpname);
free(tmpname);
/* intentionally ignore possible errors from cli_magic_scandesc */
return CL_CLEAN;
}
static int cli_scanraw(int desc, cli_ctx *ctx, cli_file_t type)
{
int ret = CL_CLEAN, nret = CL_CLEAN;
unsigned short ftrec;
struct cli_matched_type *ftoffset = NULL, *fpt;
uint32_t lastzip, lastrar;
struct cli_exe_info peinfo;
switch(type) {
case CL_TYPE_UNKNOWN_TEXT:
case CL_TYPE_MSEXE:
case CL_TYPE_ZIP:
ftrec = 1;
break;
default:
@ -1705,13 +1772,17 @@ static int cli_scanraw(int desc, cli_ctx *ctx, cli_file_t type)
ret = cli_scandesc(desc, ctx, ftrec, type, 0, &ftoffset);
if(ret >= CL_TYPENO) {
lseek(desc, 0, SEEK_SET);
nret = cli_scandesc(desc, ctx, 0, ret, 1, NULL);
if(nret == CL_VIRUS)
cli_dbgmsg("%s found in descriptor %d when scanning file type %u\n", *ctx->virname, desc, ret);
if(ret < CL_TYPE_SFX && ret != CL_TYPE_MSEXE) {
lseek(desc, 0, SEEK_SET);
nret = cli_scandesc(desc, ctx, 0, ret, 1, NULL);
if(nret == CL_VIRUS)
cli_dbgmsg("%s found in descriptor %d when scanning file type %u\n", *ctx->virname, desc, ret);
}
ret == CL_TYPE_MAIL ? ctx->mrec++ : ctx->arec++;
if(nret != CL_VIRUS) switch(ret) {
case CL_TYPE_HTML:
if(SCAN_HTML && type == CL_TYPE_UNKNOWN_TEXT && (DCONF_DOC & DOC_CONF_HTML))
@ -1751,6 +1822,30 @@ static int cli_scanraw(int desc, cli_ctx *ctx, cli_file_t type)
}
break;
case CL_TYPE_MSEXE:
if(SCAN_PE && ctx->dconf->pe) {
fpt = ftoffset;
while(fpt) {
if(fpt->type == CL_TYPE_MSEXE && fpt->offset) {
cli_dbgmsg("PE signature found at %u\n", (unsigned int) fpt->offset);
memset(&peinfo, 0, sizeof(struct cli_exe_info));
peinfo.offset = fpt->offset;
lseek(desc, fpt->offset, SEEK_SET);
if(cli_peheader(desc, &peinfo) == 0) {
cli_dbgmsg("*** Detected embedded PE file ***\n");
if(peinfo.section)
free(peinfo.section);
lseek(desc, fpt->offset, SEEK_SET);
if((nret = cli_scanembpe(desc, ctx)) == CL_VIRUS)
break;
}
}
fpt = fpt->next;
}
}
break;
default:
break;
}

Loading…
Cancel
Save