preliminary autoit support (ea05/ea06)

minor fixes coming up later

git-svn: trunk@3340
remotes/push_mirror/metadata
aCaB 18 years ago
parent 001ad879f6
commit ed93f138f3
  1. 4
      ChangeLog
  2. 30
      acinclude.m4
  3. 3
      clamav-config.h.in
  4. 70
      configure
  5. 1
      configure.in
  6. 2
      libclamav/Makefile.am
  7. 11
      libclamav/Makefile.in
  8. 901
      libclamav/autoit.c
  9. 25
      libclamav/autoit.h
  10. 1
      libclamav/filetypes.c
  11. 3
      libclamav/filetypes.h
  12. 13
      libclamav/scanners.c

@ -1,3 +1,7 @@
Tue Oct 30 19:01:41 CET 2007 (acab)
-----------------------------------
* libclamav: Add preliminary autoit unpacking support
Tue Oct 30 16:35:41 GMT 2007 (njh)
----------------------------------
* libclamav/mbox.c: Now honours --max-files

@ -583,3 +583,33 @@ AC_DEFUN([AM_MAINTAINER_MODE],
AC_SUBST(MAINT)dnl
]
)
dnl AC_C_FPU_BIGENDIAN
dnl Detects FPU endianess
dnl FPU_WORDS_BIGENDIAN = 1 for big endian
dnl FPU_WORDS_BIGENDIAN = 0 for little endian
dnl FPU_WORDS_BIGENDIAN undefined when endianes cannot be determined
AC_DEFUN([AC_C_FPU_BIGENDIAN],
[AC_CACHE_CHECK([whether FPU byte ordering is bigendian], [ac_cv_c_fpu_bigendian],
[ac_cv_c_fpu_bigendian=unknown
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[double d = 3815911171354501045744583353695226502220105394563506259449467213186125718792664588210662403287568710818873279842508553551908601408568128557088985172985437412593385138085986771664896.0;]])],[
if grep emmeelle conftest.$ac_objext >/dev/null 2>&1 ; then
ac_cv_c_fpu_bigendian=yes
fi
if grep elleemme conftest.$ac_objext >/dev/null 2>&1 ; then
ac_cv_c_fpu_bigendian=no
fi
])])
case $ac_cv_c_fpu_bigendian in
yes)
AC_DEFINE([FPU_WORDS_BIGENDIAN], 1, [FPU byte ordering is big endian])
;;
no)
AC_DEFINE([FPU_WORDS_BIGENDIAN], 0, [FPU byte ordering is little endian])
;;
*)
AC_MSG_WARN([Unable to determine FPU endianess, some features may not be available in this build])
esac
])

@ -90,6 +90,9 @@
/* file i/o buffer size */
#undef FILEBUFF
/* FPU byte ordering is little endian */
#undef FPU_WORDS_BIGENDIAN
/* enable workaround for broken DNS servers */
#undef FRESHCLAM_DNS_FIX

70
configure vendored

@ -26186,6 +26186,76 @@ fi
{ echo "$as_me:$LINENO: result: $have_signed_rightshift_extended" >&5
echo "${ECHO_T}$have_signed_rightshift_extended" >&6; };
{ echo "$as_me:$LINENO: checking whether FPU byte ordering is bigendian" >&5
echo $ECHO_N "checking whether FPU byte ordering is bigendian... $ECHO_C" >&6; }
if test "${ac_cv_c_fpu_bigendian+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
ac_cv_c_fpu_bigendian=unknown
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
double d = 3815911171354501045744583353695226502220105394563506259449467213186125718792664588210662403287568710818873279842508553551908601408568128557088985172985437412593385138085986771664896.0;
_ACEOF
rm -f conftest.$ac_objext
if { (ac_try="$ac_compile"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
(eval "$ac_compile") 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } && {
test -z "$ac_c_werror_flag" ||
test ! -s conftest.err
} && test -s conftest.$ac_objext; then
if grep emmeelle conftest.$ac_objext >/dev/null 2>&1 ; then
ac_cv_c_fpu_bigendian=yes
fi
if grep elleemme conftest.$ac_objext >/dev/null 2>&1 ; then
ac_cv_c_fpu_bigendian=no
fi
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ echo "$as_me:$LINENO: result: $ac_cv_c_fpu_bigendian" >&5
echo "${ECHO_T}$ac_cv_c_fpu_bigendian" >&6; }
case $ac_cv_c_fpu_bigendian in
yes)
cat >>confdefs.h <<\_ACEOF
#define FPU_WORDS_BIGENDIAN 1
_ACEOF
;;
no)
cat >>confdefs.h <<\_ACEOF
#define FPU_WORDS_BIGENDIAN 0
_ACEOF
;;
*)
{ echo "$as_me:$LINENO: WARNING: Unable to determine FPU endianess, some features may not be available in this build" >&5
echo "$as_me: WARNING: Unable to determine FPU endianess, some features may not be available in this build" >&2;}
esac
ac_config_files="$ac_config_files libclamunrar/Makefile libclamav/Makefile clamscan/Makefile database/Makefile docs/Makefile clamd/Makefile clamdscan/Makefile clamav-milter/Makefile freshclam/Makefile sigtool/Makefile clamconf/Makefile etc/Makefile Makefile clamav-config libclamav.pc docs/man/clamav-milter.8 docs/man/clamconf.1 docs/man/clamd.8 docs/man/clamd.conf.5 docs/man/clamdscan.1 docs/man/clamscan.1 docs/man/freshclam.1 docs/man/freshclam.conf.5 docs/man/sigtool.1"

@ -1210,6 +1210,7 @@ if test $have_signed_rightshift_extended = yes; then
fi
AC_MSG_RESULT($have_signed_rightshift_extended);
AC_C_FPU_BIGENDIAN
AC_OUTPUT([
libclamunrar/Makefile

@ -115,6 +115,8 @@ libclamav_la_SOURCES = \
is_tar.h \
tnef.c \
tnef.h \
autoit.c \
autoit.h \
regex/strlcpy.c \
regex/regcomp.c \
regex/regerror.c \

@ -84,10 +84,10 @@ am_libclamav_la_OBJECTS = matcher-ac.lo matcher-bm.lo matcher.lo \
pe.lo upx.lo htmlnorm.lo chmunpack.lo rebuildpe.lo petite.lo \
wwunpack.lo unsp.lo aspack.lo packlibs.lo fsg.lo mew.lo \
upack.lo line.lo untar.lo unzip.lo special.lo binhex.lo \
is_tar.lo tnef.lo strlcpy.lo regcomp.lo regerror.lo regexec.lo \
regfree.lo unarj.lo LZMADecode.lo bzlib.lo infblock.lo \
nulsft.lo pdf.lo spin.lo yc.lo elf.lo sis.lo uuencode.lo \
pst.lo phishcheck.lo phish_domaincheck_db.lo \
is_tar.lo tnef.lo autoit.lo strlcpy.lo regcomp.lo regerror.lo \
regexec.lo regfree.lo unarj.lo LZMADecode.lo bzlib.lo \
infblock.lo nulsft.lo pdf.lo spin.lo yc.lo elf.lo sis.lo \
uuencode.lo pst.lo phishcheck.lo phish_domaincheck_db.lo \
phish_whitelist.lo regex_list.lo mspack.lo cab.lo entconv.lo \
hashtab.lo dconf.lo lockdb.lo
libclamav_la_OBJECTS = $(am_libclamav_la_OBJECTS)
@ -327,6 +327,8 @@ libclamav_la_SOURCES = \
is_tar.h \
tnef.c \
tnef.h \
autoit.c \
autoit.h \
regex/strlcpy.c \
regex/regcomp.c \
regex/regerror.c \
@ -462,6 +464,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LZMADecode.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aspack.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/autoit.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/binhex.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blob.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bzlib.Plo@am__quote@

@ -0,0 +1,901 @@
/*
* Copyright (C) 2007 Sourcefire Inc.
* Author: aCaB <acab@clamav.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
/* Gianluigi, you may want to include winsuck here or just make ntohl a macro */
#include <arpa/inet.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
#include "others.h"
#include "scanners.h"
/* FIXME: use unicode detection and normalization from edwin */
static unsigned int u2a(uint8_t *d, unsigned int l) {
unsigned int i=l;
uint8_t *s = d;
if(l<2) return l;
if(d[0] == 0xff && d[1] == 0xfe) {
s += 2;
l -= 2;
} else if (d[1] != 0) {
return l;
}
if(l<2) return i;
for (i = 0 ; i < l; i += 2)
*d++ = s[i];
*d = '\0';
return (unsigned int)(d-s);
}
/*********************
MT realted stuff
*********************/
struct MT {
uint32_t mt[624];
uint32_t items;
uint32_t *next;
};
static uint8_t MT_getnext(struct MT *MT) {
uint32_t r;
if (!--MT->items) {
uint32_t *mt = MT->mt;
unsigned int i;
MT->items = 624;
MT->next = mt;
for (i=0; i<227; i++)
mt[i] = ((((mt[i] ^ mt[i+1])&0x7ffffffe)^mt[i])>>1)^((0-(mt[i+1]&1))&0x9908b0df)^mt[i+397];
for (; i<623; i++)
mt[i] = ((((mt[i] ^ mt[i+1])&0x7ffffffe)^mt[i])>>1)^((0-(mt[i+1]&1))&0x9908b0df)^mt[i-227];
mt[623] = ((((mt[623] ^ mt[0])&0x7ffffffe)^mt[623])>>1)^((0-(mt[0]&1))&0x9908b0df)^mt[i-227];
}
r = *(MT->next++);
r ^= (r >> 11);
r ^= ((r & 0xff3a58ad) << 7);
r ^= ((r & 0xffffdf8c) << 15);
r ^= (r >> 18);
return (uint8_t)(r >> 1);
}
static void MT_decrypt(uint8_t *buf, unsigned int size, uint32_t seed) {
struct MT MT;
unsigned int i;
uint32_t *mt = MT.mt;
*mt=seed;
for(i=1; i<624; i++)
mt[i] = i+0x6c078965*((mt[i-1]>>30)^mt[i-1]);
MT.items = 1;
while(size--)
*buf++ ^= MT_getnext(&MT);
}
/*********************
inflate stuff
*********************/
struct UNP {
uint8_t *outputbuf;
uint8_t *inputbuf;
uint32_t cur_output;
uint32_t cur_input;
uint32_t usize;
uint32_t csize;
uint32_t bits_avail;
union {
uint32_t full;
struct {
#if WORDS_BIGENDIAN != 0
uint16_t h; /* BE */
uint16_t l;
#else
uint16_t l; /* LE */
uint16_t h;
#endif
} half;
} bitmap;
uint32_t error;
};
static uint32_t getbits(struct UNP *UNP, uint32_t size) {
UNP->bitmap.half.h = 0;
if (size > UNP->bits_avail && ((size - UNP->bits_avail - 1)/16+1)*2 > UNP->csize - UNP->cur_input) {
cli_dbgmsg("autoit: getbits() - not enough bits available");
UNP->error = 1;
return 0; /* won't infloop nor spam */
}
while (size) {
if (!UNP->bits_avail) {
UNP->bitmap.half.l |= UNP->inputbuf[UNP->cur_input++]<<8;
UNP->bitmap.half.l |= UNP->inputbuf[UNP->cur_input++];
UNP->bits_avail = 16;
}
UNP->bitmap.full<<=1;
UNP->bits_avail--;
size--;
}
return (uint32_t)UNP->bitmap.half.h;
}
/*********************
autoit3 EA05 handler
*********************/
static int ea05(int desc, cli_ctx *ctx, char *tmpd) {
uint8_t b[300], comp;
uint8_t *buf = b;
uint32_t s, m4sum=0;
int i;
unsigned int files=0;
char tempfile[1024];
struct UNP UNP;
if (cli_readn(desc, buf, 16)!=16)
return CL_CLEAN;
for (i=0; i<16; i++)
m4sum += buf[i];
while(!ctx->limits || !ctx->limits->maxfiles || files < ctx->limits->maxfiles) {
buf = b;
if (cli_readn(desc, buf, 8)!=8)
return CL_CLEAN;
/* MT_decrypt(buf,4,0x16fa); waste of time */
if((uint32_t)cli_readint32((char *)buf) != 0xceb06dff) {
cli_dbgmsg("autoit: no FILE magic found, extraction complete\n");
return CL_CLEAN;
}
s = cli_readint32((char *)buf+4) ^ 0x29bc;
buf=b;
if(cli_debug_flag && s<300) {
if (cli_readn(desc, buf, s)!=(int)s)
return CL_CLEAN;
buf[s]='\0';
MT_decrypt(buf,s,s+0xa25e);
cli_dbgmsg("autoit: magic string '%s'\n", buf);
} else {
lseek(desc, s, SEEK_CUR);
}
if (cli_readn(desc, buf, 4)!=4)
return CL_CLEAN;
s = cli_readint32((char *)buf) ^ 0x29ac;
if ((int32_t)s<0)
return CL_CLEAN; /* the original code wouldn't seek back here */
if (cli_debug_flag && s<300) {
if (cli_readn(desc, buf, s)!=(int)s)
return CL_CLEAN;
MT_decrypt(buf,s,s+0xf25e);
buf[s]='\0';
cli_dbgmsg("autoit: original filename '%s'\n", buf);
} else {
lseek(desc, s, SEEK_CUR);
}
if (cli_readn(desc, buf, 13)!=13)
return CL_CLEAN;
comp = *buf;
UNP.csize = cli_readint32((char *)buf+1) ^ 0x45aa;
cli_dbgmsg("autoit: compressed size: %x\n", UNP.csize);
cli_dbgmsg("autoit: advertised uncompressed size %x\n", cli_readint32((char *)buf+5) ^ 0x45aa);
cli_dbgmsg("autoit: ref chksum: %x\n", cli_readint32((char *)buf+9) ^ 0xc3d2);
lseek(desc, 16, SEEK_CUR);
if(ctx->limits && ctx->limits->maxfilesize && UNP.csize > ctx->limits->maxfilesize) {
cli_dbgmsg("autoit: skipping file due to size limit (%u, max: %lu)\n", UNP.csize, ctx->limits->maxfilesize);
lseek(desc, UNP.csize, SEEK_CUR);
continue;
}
if (!(buf = cli_malloc(UNP.csize)))
return CL_EMEM;
if (cli_readn(desc, buf, UNP.csize)!=(int)UNP.csize) {
cli_dbgmsg("autoit: failed to read compressed stream. broken/truncated file?\n");
free(buf);
return CL_CLEAN;
}
MT_decrypt(buf,UNP.csize,0x22af+m4sum);
if (comp == 1) {
cli_dbgmsg("autoit: file is compressed\n");
if (cli_readint32((char *)buf)!=0x35304145) {
cli_dbgmsg("autoit: bad magic or unsupported version\n");
free(buf);
continue;
}
UNP.usize = ntohl(*(uint32_t *)(buf+4));
if(ctx->limits && ctx->limits->maxfilesize && UNP.usize > ctx->limits->maxfilesize) {
cli_dbgmsg("autoit: skipping file due to size limit (%u, max: %lu)\n", UNP.csize, ctx->limits->maxfilesize);
free(buf);
continue;
}
if (!(UNP.outputbuf = cli_malloc(UNP.usize))) {
free(buf);
return CL_EMEM;
}
cli_dbgmsg("autoit: uncompressed size again: %x\n", UNP.usize);
UNP.inputbuf = buf;
UNP.cur_output = 0;
UNP.cur_input = 8;
UNP.bitmap.full = 0;
UNP.bits_avail = 0;
UNP.error = 0;
while (!UNP.error && UNP.cur_output < UNP.usize) {
if (getbits(&UNP, 1)) {
uint32_t bb, bs, addme=0;
bb = getbits(&UNP, 15);
if ((bs = getbits(&UNP, 2))==3) {
addme = 3;
if((bs = getbits(&UNP, 3))==7) {
addme = 10;
if((bs = getbits(&UNP, 5))==31) {
addme = 41;
if((bs = getbits(&UNP, 8))==255) {
addme = 296;
while((bs = getbits(&UNP, 8))==255) {
addme+=255;
}
}
}
}
}
bs += 3+addme;
if(!CLI_ISCONTAINED(UNP.outputbuf, UNP.usize, &UNP.outputbuf[UNP.cur_output], bs) ||
!CLI_ISCONTAINED(UNP.outputbuf, UNP.usize, &UNP.outputbuf[UNP.cur_output-bb], bs)) {
UNP.error = 1;
break;
}
while(bs--) {
UNP.outputbuf[UNP.cur_output]=UNP.outputbuf[UNP.cur_output-bb];
UNP.cur_output++;
}
} else {
UNP.outputbuf[UNP.cur_output] = (uint8_t)getbits(&UNP, 8);
UNP.cur_output++;
}
}
free(buf);
if (UNP.error) {
cli_dbgmsg("autoit: decompression error\n");
free(UNP.outputbuf);
continue;
}
} else {
cli_dbgmsg("autoit: file is not compressed\n");
UNP.outputbuf = buf;
UNP.usize = UNP.csize;
}
files++;
/* FIXME: TODO send to text notmalization */
/* FIXME: ad-interim solution. ideally we should only u2a unicode scripts */
UNP.usize = u2a(UNP.outputbuf, UNP.usize);
snprintf(tempfile, 1023, "%s/autoit.%.3u", tmpd, files);
tempfile[1023]='\0';
if((i = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
cli_dbgmsg("autoit: Can't create file %s\n", tempfile);
free(UNP.outputbuf);
return CL_EIO;
}
if(cli_writen(i, UNP.outputbuf, UNP.usize) != (int32_t)UNP.usize) {
cli_dbgmsg("autoit: cannot write %d bytes\n", UNP.usize);
close(i);
free(UNP.outputbuf);
return CL_EIO;
}
free(UNP.outputbuf);
if(cli_leavetemps_flag)
cli_dbgmsg("autoit: file extracted to %s\n", tempfile);
else
cli_dbgmsg("autoit: file successfully extracted\n");
fsync(i);
lseek(i, 0, SEEK_SET);
if(cli_magic_scandesc(i, ctx) == CL_VIRUS) {
close(i);
if(!cli_leavetemps_flag) unlink(tempfile);
return CL_VIRUS;
}
close(i);
if(!cli_leavetemps_flag) unlink(tempfile);
}
cli_dbgmsg("autoit: files limit reached (max: %u)\n", ctx->limits->maxfiles);
return CL_EMAXFILES;
}
/*********************
LAME realted stuff
*********************/
#ifdef FPU_WORDS_BIGENDIAN
#define ROFL(a,b) (( a << (b % (sizeof(a)<<3) )) | (a >> ( (sizeof(a)<<3) - (b % (sizeof(a)<<3 )) ) ))
struct LAME {
uint32_t c0;
uint32_t c1;
uint32_t grp1[17];
};
static double LAME_fpusht(struct LAME *l) {
union {
double as_double;
struct {
#if FPU_WORDS_BIGENDIAN == 0
uint32_t lo;
uint32_t hi;
#else
uint32_t hi;
uint32_t lo;
#endif
} as_uint;
} ret;
uint32_t rolled = ROFL(l->grp1[l->c0],9) + ROFL(l->grp1[l->c1],13);
l->grp1[l->c0] = rolled;
if (!l->c0--) l->c0 = 16;
if (!l->c1--) l->c1 = 16;
/* if (l->grp1[l->c0] == l->grp2[0]) { */
/* if (!memcmp(l->grp1, (uint32_t *)l + 0x24 - l->c0, 0x44)) */
/* return 0.0; */
/* } */
#if WORDS_BIGENDIAN == FPU_WORDS_BIGENDIAN
ret.as_uint.lo = rolled << 0x14;
ret.as_uint.hi = 0x3ff00000 | (rolled >> 0xc);
#else
do {
uint32_t tmp = rolled << 0x14;
ret.as_uint.lo = ((tmp&0xff)<<24) | (((tmp>>8)&0xff)<<16) | (((tmp>>16)&0xff)<<8) | ((tmp>>24)&0xff);
tmp = 0x3ff00000 | (rolled >> 0xc);
ret.as_uint.hi = ((tmp&0xff)<<24) | (((tmp>>8)&0xff)<<16) | (((tmp>>16)&0xff)<<8) | ((tmp>>24)&0xff);
} while(0);
#endif
return ret.as_double - 1.0;
}
static void LAME_srand(struct LAME *l, uint32_t seed) {
unsigned int i;
for (i=0; i<17; i++) {
seed *= 0x53A9B4FB; /*1403630843*/
seed = 1 - seed;
l->grp1[i] = seed;
}
l->c0 = 0;
l->c1 = 10;
for (i = 0; i < 9; i++)
LAME_fpusht(l);
}
static uint8_t LAME_getnext(struct LAME *l) {
double x;
uint8_t ret;
LAME_fpusht(l);
x = LAME_fpusht(l) * 256.0;
if ((int32_t)x < 256) ret = (uint8_t)x;
else ret=0xff;
return ret;
}
static void LAME_decrypt (uint8_t *cypher, uint32_t size, uint16_t seed) {
struct LAME lame;
/* mt_srand_timewrap(struct srand_struc bufDC); */
LAME_srand(&lame, (uint32_t)seed);
while(size--)
*cypher++^=LAME_getnext(&lame);
}
/*********************
autoit3 EA06 handler
*********************/
static int ea06(int desc, cli_ctx *ctx, char *tmpd) {
uint8_t b[600], comp, script;
uint8_t *buf;
uint32_t s;
int i;
unsigned int files=0;
char tempfile[1024];
const char prefixes[] = { '\0', '\0', '@', '$', '\0', '.', '"', '#' };
const char *opers[] = { ",", "=", ">", "<", "<>", ">=", "<=", "(", ")", "+", "-", "/", "*", "&", "[", "]", "==", "^", "+=", "-=", "/=", "*=", "&=" };
struct UNP UNP;
UNP.error = 0;
/* Useless due to a bug in CRC calculation - LMAO!!1 */
/* if (cli_readn(desc, buf, 24)!=24) */
/* return CL_CLEAN; */
/* LAME_decrypt(buf, 0x10, 0x99f2); */
/* buf+=0x10; */
lseek(desc, 16, SEEK_CUR); /* for now we just skip the garbage */
while(!ctx->limits || !ctx->limits->maxfiles || files < ctx->limits->maxfiles) {
/* FIXME: count files here */
buf = b;
if (cli_readn(desc, buf, 8)!=8)
return CL_CLEAN;
/* LAME_decrypt(buf, 4, 0x18ee); FIXME: waste of time */
if(cli_readint32((char *)buf) != 0x52ca436b) {
cli_dbgmsg("autoit: no FILE magic found, giving up\n");
return CL_CLEAN;
}
s = cli_readint32((char *)buf+4) ^ 0xadbc;
script = 0;
if(s<300) {
if (cli_readn(desc, buf, s*2)!=(int)s*2)
return CL_CLEAN;
LAME_decrypt(buf,s*2,s+0xb33f);
buf[s*2]='\0'; buf[s*2+1]='\0';
u2a(buf,s*2); /* FIXME: GET RID OF THIS */
cli_dbgmsg("autoit: magic string '%s'\n", buf);
if (s==19 && !memcmp(">>>AUTOIT SCRIPT<<<", buf, 19))
script = 1;
} else {
cli_dbgmsg("autoit: magic string too long to print\n");
lseek(desc, s*2, SEEK_CUR);
}
if (cli_readn(desc, buf, 4)!=4)
return CL_CLEAN;
s = cli_readint32((char *)buf) ^ 0xf820;
if(cli_debug_flag && s<300) {
if (cli_readn(desc, buf, s*2)!=(int)s*2)
return CL_CLEAN;
LAME_decrypt(buf,s*2,s+0xf479);
buf[s*2]='\0'; buf[s*2+1]='\0';
u2a(buf,s*2); /* FIXME: GET RID OF THIS */
cli_dbgmsg("autoit: original filename '%s'\n", buf);
} else {
lseek(desc, s*2, SEEK_CUR);
}
if (cli_readn(desc, buf, 13)!=13)
return CL_CLEAN;
comp = *buf;
UNP.csize = cli_readint32((char *)buf+1) ^ 0x87bc;
cli_dbgmsg("autoit: compressed size: %x\n", UNP.csize);
cli_dbgmsg("autoit: advertised uncompressed size %x\n", cli_readint32((char *)buf+5) ^ 0x87bc);
cli_dbgmsg("autoit: ref chksum: %x\n", cli_readint32((char *)buf+9) ^ 0xa685);
lseek(desc, 16, SEEK_CUR);
if(ctx->limits && ctx->limits->maxfilesize && UNP.csize > ctx->limits->maxfilesize) {
cli_dbgmsg("autoit: skipping file due to size limit (%u, max: %lu)\n", UNP.csize, ctx->limits->maxfilesize);
lseek(desc, UNP.csize, SEEK_CUR);
continue;
}
files++;
if (!(buf = cli_malloc(UNP.csize)))
return CL_EMEM;
if (cli_readn(desc, buf, UNP.csize)!=(int)UNP.csize) {
cli_dbgmsg("autoit: failed to read compressed stream. broken/truncated file?\n");
free(buf);
return CL_CLEAN;
}
LAME_decrypt(buf,UNP.csize,0x2477 /* + m4sum (broken by design) */ );
if (comp == 1) {
cli_dbgmsg("autoit: file is compressed\n");
if (cli_readint32((char *)buf)!=0x36304145) {
cli_dbgmsg("autoit: bad magic or unsupported version\n");
free(buf);
continue;
}
UNP.usize = ntohl(*(uint32_t *)(buf+4));
if(ctx->limits && ctx->limits->maxfilesize && UNP.usize > ctx->limits->maxfilesize) {
free(buf);
continue;
}
if (!(UNP.outputbuf = cli_malloc(UNP.usize))) {
free(buf);
return CL_EMEM;
}
cli_dbgmsg("autoit: uncompressed size again: %x\n", UNP.usize);
UNP.inputbuf = buf;
UNP.cur_output = 0;
UNP.cur_input = 8;
UNP.bitmap.full = 0;
UNP.bits_avail = 0;
while (!UNP.error && UNP.cur_output < UNP.usize) {
if (!getbits(&UNP, 1)) {
uint32_t bb, bs, addme=0;
bb = getbits(&UNP, 15);
if ((bs = getbits(&UNP, 2))==3) {
addme = 3;
if((bs = getbits(&UNP, 3))==7) {
addme = 10;
if((bs = getbits(&UNP, 5))==31) {
addme = 41;
if((bs = getbits(&UNP, 8))==255) {
addme = 296;
while((bs = getbits(&UNP, 8))==255) {
addme+=255;
}
}
}
}
}
bs += 3+addme;
if(!CLI_ISCONTAINED(UNP.outputbuf, UNP.usize, &UNP.outputbuf[UNP.cur_output], bs) ||
!CLI_ISCONTAINED(UNP.outputbuf, UNP.usize, &UNP.outputbuf[UNP.cur_output-bb], bs)) {
UNP.error = 1;
break;
}
while(bs--) {
UNP.outputbuf[UNP.cur_output]=UNP.outputbuf[UNP.cur_output-bb];
UNP.cur_output++;
}
} else {
UNP.outputbuf[UNP.cur_output] = (uint8_t)getbits(&UNP, 8);
UNP.cur_output++;
}
}
free(buf);
if (UNP.error) {
cli_dbgmsg("autoit: decompression error\n");
free(UNP.outputbuf);
continue;
}
} else {
cli_dbgmsg("autoit: file is not compressed\n");
UNP.outputbuf = buf;
UNP.usize = UNP.csize;
}
if (UNP.usize<4) {
cli_dbgmsg("autoit: file is too short\n");
free(UNP.outputbuf);
continue;
}
if (script) {
UNP.csize = UNP.usize;
if (!(buf = cli_malloc(UNP.csize))) {
free(UNP.outputbuf);
return CL_EMEM;
}
UNP.cur_output = 0;
UNP.cur_input = 4;
UNP.bits_avail = cli_readint32((char *)UNP.outputbuf);
cli_dbgmsg("autoit: script has got %u lines\n", UNP.bits_avail);
while (!UNP.error && UNP.bits_avail && UNP.cur_input < UNP.usize) {
uint8_t op;
switch((op = UNP.outputbuf[UNP.cur_input++])) {
case 5: /* <INT> */
if (UNP.cur_input >= UNP.usize-4) {
UNP.error = 1;
cli_dbgmsg("autoit: not enough space for an int\n");
break;
}
if (UNP.cur_output+12 >= UNP.csize) {
uint8_t *newout;
UNP.csize += 512;
if (!(newout = cli_realloc(buf, UNP.csize))) {
UNP.error = 1;
break;
}
buf = newout;
}
UNP.cur_output += snprintf((char *)&buf[UNP.cur_output], 12, "0x%08x ", cli_readint32((char *)&UNP.outputbuf[UNP.cur_input]));
UNP.cur_input += 4;
break;
case 0x20: /* <DOUBLE> */
if (UNP.usize < 8 || UNP.cur_input >= UNP.usize-8) {
UNP.error = 1;
cli_dbgmsg("autoit: not enough space for a double\n");
break;
}
if (UNP.cur_output+40 >= UNP.csize) {
uint8_t *newout;
UNP.csize += 512;
if (!(newout = cli_realloc(buf, UNP.csize))) {
UNP.error = 1;
break;
}
buf = newout;
}
#if FPU_WORDS_BIGENDIAN == 0
snprintf((char *)&buf[UNP.cur_output], 39, "%g ", *(double *)&UNP.outputbuf[UNP.cur_input]);
#else
do {
double x;
uint8_t *j = (uint8_t *)&x;
unsigned int i;
for(i=0; i<8; i++)
j[7-i]=UNP.outputbuf[UNP.cur_input+i];
snprintf((char *)&buf[UNP.cur_output], 39, "%g ", x); /* FIXME: check */
} while(0);
#endif
buf[UNP.cur_output+38]=' ';
buf[UNP.cur_output+39]='\0';
UNP.cur_output += strlen((char *)&buf[UNP.cur_output]);
UNP.cur_input += 8;
break;
case 0x30: /* COSTRUCT */
case 0x31: /* COMMAND */
case 0x32: /* MACRO */
case 0x33: /* VAR */
case 0x34: /* FUNC */
case 0x35: /* OBJECT */
case 0x36: /* STRING */
case 0x37: /* DIRECTIVE */
{
uint32_t chars, dchars, i;
if (UNP.cur_input >= UNP.usize-4) {
UNP.error = 1;
cli_dbgmsg("autoit: not enough space for size\n");
break;
}
chars = cli_readint32((char *)&UNP.outputbuf[UNP.cur_input]);
dchars = chars*2;
UNP.cur_input+=4;
if (UNP.usize < dchars || UNP.cur_input >= UNP.usize-dchars) {
UNP.error = 1;
cli_dbgmsg("autoit: size too big - needed %d, total %d, avail %d\n", dchars, UNP.usize, UNP.usize - UNP.cur_input);
break;
}
if (UNP.cur_output+chars+3 >= UNP.csize) {
uint8_t *newout;
UNP.csize += chars + 512;
if (!(newout = cli_realloc(buf, UNP.csize))) {
UNP.error = 1;
break;
}
buf = newout;
}
if(prefixes[op-0x30])
buf[UNP.cur_output++] = prefixes[op-0x30];
if (chars) {
for (i = 0; i<dchars; i+=2) {
UNP.outputbuf[UNP.cur_input+i] ^= (uint8_t)chars;
UNP.outputbuf[UNP.cur_input+i+1] ^= (uint8_t)(chars>>8);
}
u2a(&UNP.outputbuf[UNP.cur_input], dchars);
memcpy(&buf[UNP.cur_output], &UNP.outputbuf[UNP.cur_input], chars);
UNP.cur_output += chars;
UNP.cur_input += dchars;
}
if (op==0x36)
buf[UNP.cur_output++] = '"';
if (op!=0x34)
buf[UNP.cur_output++] = ' ';
}
break;
case 0x40: /* , */
case 0x41: /* = */
case 0x42: /* > */
case 0x43: /* < */
case 0x44: /* <> */
case 0x45: /* >= */
case 0x46: /* <= */
case 0x47: /* ( */
case 0x48: /* ) */
case 0x49: /* + */
case 0x4a: /* - */
case 0x4b: /* / */
case 0x4c: /* * */
case 0x4d: /* & */
case 0x4e: /* [ */
case 0x4f: /* ] */
case 0x50: /* == */
case 0x51: /* ^ */
case 0x52: /* += */
case 0x53: /* -= */
case 0x54: /* /= */
case 0x55: /* *= */
case 0x56: /* &= */
if (UNP.cur_output+4 >= UNP.csize) {
uint8_t *newout;
UNP.csize += 512;
if (!(newout = cli_realloc(buf, UNP.csize))) {
UNP.error = 1;
break;
}
buf = newout;
}
UNP.cur_output += snprintf((char *)&buf[UNP.cur_output], 4, "%s ", opers[op-0x40]);
break;
case 0x7f:
UNP.bits_avail--;
if (UNP.cur_output+1 >= UNP.csize) {
uint8_t *newout;
UNP.csize += 512;
if (!(newout = cli_realloc(buf, UNP.csize))) {
UNP.error = 1;
break;
}
buf = newout;
}
buf[UNP.cur_output++]='\n';
break;
default:
cli_dbgmsg("autoit: found unknown op (%x)\n", op);
UNP.error = 1;
}
}
if (UNP.error)
cli_dbgmsg("autoit: decompilation aborted - partial script may exist\n");
free(UNP.outputbuf);
} else {
buf = UNP.outputbuf;
UNP.cur_output = UNP.usize ;
}
/* FIXME: TODO send to text notmalization */
snprintf(tempfile, 1023, "%s/autoit.%.3u", tmpd, files);
tempfile[1023]='\0';
if((i = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
cli_dbgmsg("autoit: Can't create file %s\n", tempfile);
free(buf);
return CL_EIO;
}
if(cli_writen(i, buf, UNP.cur_output) != (int32_t)UNP.cur_output) {
cli_dbgmsg("autoit: cannot write %d bytes\n", UNP.usize);
close(i);
free(buf);
return CL_EIO;
}
free(buf);
if(cli_leavetemps_flag)
cli_dbgmsg("autoit: %s extracted to %s\n", (script)?"script":"file", tempfile);
else
cli_dbgmsg("autoit: %s successfully extracted\n", (script)?"script":"file");
fsync(i);
lseek(i, 0, SEEK_SET);
if(cli_magic_scandesc(i, ctx) == CL_VIRUS) {
close(i);
if(!cli_leavetemps_flag) unlink(tempfile);
return CL_VIRUS;
}
close(i);
if(!cli_leavetemps_flag) unlink(tempfile);
}
cli_dbgmsg("autoit: Files limit reached (max: %u)\n", ctx->limits->maxfiles);
return CL_EMAXFILES;
}
#endif /* FPU_WORDS_BIGENDIAN */
/*********************
autoit3 wrapper
*********************/
int cli_scanautoit(int desc, cli_ctx *ctx, off_t offset) {
uint8_t version;
int (*func)(int desc, cli_ctx *ctx, char *), r;
char *tmpd;
lseek(desc, offset, SEEK_SET);
if (cli_readn(desc, &version, 1)!=1)
return CL_EIO;
cli_dbgmsg("in scanautoit()\n");
if (!(tmpd = cli_gentemp(NULL)))
return CL_ETMPDIR;
if (mkdir(tmpd, 0700)) {
cli_dbgmsg("autoit: Can't create temporary directory %s\n", tmpd);
free(tmpd);
return CL_ETMPDIR;
}
if (cli_leavetemps_flag)
cli_dbgmsg("autoit: Extracting files to %s\n", tmpd);
switch(version) {
case 0x35:
func = ea05;
break;
case 0x36:
#ifdef FPU_WORDS_BIGENDIAN
func = ea06;
break;
#else
cli_dbgmsg("autoit: EA06 support not available\n");
return CL_CLEAN;
#endif
default:
/* NOT REACHED */
cli_dbgmsg("autoit: unknown method\n");
return CL_CLEAN;
}
r = func(desc, ctx, tmpd);
if (!cli_leavetemps_flag)
cli_rmdirs(tmpd);
free(tmpd);
return r;
}

@ -0,0 +1,25 @@
/*
* Copyright (C) 2007 Sourcefire Inc.
* Author: aCaB <acab@clamav.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#ifndef __AUTOIT_H
#define __AUTOIT_H
#include "others.h"
int cli_scanautoit(int desc, cli_ctx *ctx, off_t offset);
#endif

@ -195,6 +195,7 @@ static const struct cli_smagic_s cli_smagic[] = {
{"60ea{7}0102", "ARJ-SFX", CL_TYPE_ARJSFX},
{"60ea{7}0202", "ARJ-SFX", CL_TYPE_ARJSFX},
{"efbeadde4e756c6c736f6674496e7374", "NSIS", CL_TYPE_NULSFT},
{"a3484bbe986c4aa9994c530a86d6487d41553321454130(35|36)", "AUTOIT", CL_TYPE_AUTOIT},
{"4d5a{60-300}50450000", "PE", CL_TYPE_MSEXE},

@ -64,7 +64,8 @@ typedef enum {
CL_TYPE_RARSFX, /* on the fly */
CL_TYPE_CABSFX,
CL_TYPE_ARJSFX,
CL_TYPE_NULSFT /* on the fly */
CL_TYPE_NULSFT, /* on the fly */
CL_TYPE_AUTOIT /* FIXME_AUTOIT: Tomasz, good nuff? */
} cli_file_t;
struct cli_matched_type {

@ -85,6 +85,7 @@
#include "rtf.h"
#include "unarj.h"
#include "nulsft.h"
#include "autoit.h"
#ifdef HAVE_ZLIB_H
#include <zlib.h>
@ -1927,6 +1928,13 @@ static int cli_scanraw(int desc, cli_ctx *ctx, cli_file_t type, uint8_t typercg)
}
break;
case CL_TYPE_AUTOIT:
if(1 && type == CL_TYPE_MSEXE /* FIXME_AUTOIT: Tomasz, pls DCONF THIS */) {
cli_dbgmsg("AUTOIT signature found at %u\n", (unsigned int) fpt->offset);
nret = cli_scanautoit(desc, ctx, fpt->offset + 23);
}
break;
case CL_TYPE_MSEXE:
if(SCAN_PE && ctx->dconf->pe && fpt->offset) {
cli_dbgmsg("PE signature found at %u\n", (unsigned int) fpt->offset);
@ -2086,6 +2094,11 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx)
if(SCAN_ARCHIVE)
ret = cli_scannulsft(desc, ctx, 0);
break;
case CL_TYPE_AUTOIT:
if(1 /* FIXME_AUTOIT: DCONF THIS */)
ret = cli_scanautoit(desc, ctx, 23);
break;
/*
case CL_TYPE_MSSZDD:
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_SZDD))

Loading…
Cancel
Save