/* * Copyright (C) 2013-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. * Copyright (C) 2007-2013 Sourcefire, Inc. * * Authors: Alberto Wu * * 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 #include #include #include #if HAVE_STRING_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #include "clamav.h" #include "others.h" #include "scanners.h" #include "autoit.h" #include "fmap.h" #include "fpu.h" static int fpu_words = FPU_ENDIAN_INITME; /* FIXME: use unicode detection and normalization from edwin */ static unsigned int u2a(uint8_t *dest, unsigned int len) { uint8_t *src = dest; unsigned int i, j; if (len < 2) return len; if (len > 4 && src[0] == 0xff && src[1] == 0xfe && src[2]) { len -= 2; src += 2; } else { unsigned int cnt = 0; j = (len > 20) ? 20 : (len & ~1); for (i = 0; i < j; i += 2) cnt += (src[i] != 0 && src[i + 1] == 0); if (cnt * 4 < j) return len; } j = len; len >>= 1; for (i = 0; i < j; i += 2) *dest++ = src[i]; return len; } /********************* MT realted stuff *********************/ struct MT { uint32_t *next; uint32_t items; uint32_t mt[624]; }; 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; MT.next = MT.mt; 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\n"); 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(cli_ctx *ctx, const uint8_t *base, char *tmpd) { uint8_t b[300], comp; uint32_t s, m4sum = 0; int i, ret, det = 0; unsigned int files = 0; char tempfile[1024]; struct UNP UNP; fmap_t *map = *ctx->fmap; if (!fmap_need_ptr_once(map, base, 16)) return CL_CLEAN; for (i = 0; i < 16; i++) m4sum += *base++; while ((ret = cli_checklimits("autoit", ctx, 0, 0, 0)) == CL_CLEAN) { if (!fmap_need_ptr_once(map, base, 8)) return (det ? CL_VIRUS : CL_CLEAN); /* MT_decrypt(buf,4,0x16fa); waste of time */ if ((uint32_t)cli_readint32(base) != 0xceb06dff) { cli_dbgmsg("autoit: no FILE magic found, extraction complete\n"); return (det ? CL_VIRUS : CL_CLEAN); } s = cli_readint32(base + 4) ^ 0x29bc; if ((int32_t)s < 0) return (det ? CL_VIRUS : CL_CLEAN); /* the original code wouldn't seek back here */ base += 8; if (cli_debug_flag && s < sizeof(b)) { if (!fmap_need_ptr_once(map, base, s)) return (det ? CL_VIRUS : CL_CLEAN); memcpy(b, base, s); MT_decrypt(b, s, s + 0xa25e); b[s] = '\0'; cli_dbgmsg("autoit: magic string '%s'\n", b); } base += s; if (!fmap_need_ptr_once(map, base, 4)) return (det ? CL_VIRUS : CL_CLEAN); s = cli_readint32(base) ^ 0x29ac; if ((int32_t)s < 0) return (det ? CL_VIRUS : CL_CLEAN); /* the original code wouldn't seek back here */ base += 4; if (cli_debug_flag && s < sizeof(b)) { if (!fmap_need_ptr_once(map, base, s)) return (det ? CL_VIRUS : CL_CLEAN); memcpy(b, base, s); MT_decrypt(b, s, s + 0xf25e); b[s] = '\0'; cli_dbgmsg("autoit: original filename '%s'\n", b); } base += s; if (!fmap_need_ptr_once(map, base, 13)) return (det ? CL_VIRUS : CL_CLEAN); comp = *base; UNP.csize = cli_readint32(base + 1) ^ 0x45aa; if ((int32_t)UNP.csize < 0) { cli_dbgmsg("autoit: bad file size - giving up\n"); return (det ? CL_VIRUS : CL_CLEAN); } if (!UNP.csize) { cli_dbgmsg("autoit: skipping empty file\n"); base += 13 + 16; continue; } cli_dbgmsg("autoit: compressed size: %x\n", UNP.csize); cli_dbgmsg("autoit: advertised uncompressed size %x\n", cli_readint32(base + 5) ^ 0x45aa); cli_dbgmsg("autoit: ref chksum: %x\n", cli_readint32(base + 9) ^ 0xc3d2); base += 13 + 16; if (cli_checklimits("autoit", ctx, UNP.csize, 0, 0) != CL_CLEAN) { base += UNP.csize; continue; } if (comp == 1 && UNP.csize < sizeof(union unaligned_32)) { cli_dbgmsg("autoit: compressed size too small, skipping\n"); continue; } if (!(UNP.inputbuf = cli_malloc(UNP.csize))) return CL_EMEM; if (!fmap_need_ptr_once(map, base, UNP.csize)) { cli_dbgmsg("autoit: failed to read compressed stream. broken/truncated file?\n"); free(UNP.inputbuf); return (det ? CL_VIRUS : CL_CLEAN); } memcpy(UNP.inputbuf, base, UNP.csize); base += UNP.csize; MT_decrypt(UNP.inputbuf, UNP.csize, 0x22af + m4sum); if (comp == 1) { cli_dbgmsg("autoit: file is compressed\n"); if (cli_readint32(UNP.inputbuf) != 0x35304145) { cli_dbgmsg("autoit: bad magic or unsupported version\n"); free(UNP.inputbuf); continue; } if (!(UNP.usize = be32_to_host(*(uint32_t *)(UNP.inputbuf + 4)))) UNP.usize = UNP.csize; /* only a specifically crafted or badly corrupted sample should land here */ if (cli_checklimits("autoit", ctx, UNP.usize, 0, 0) != CL_CLEAN) { free(UNP.inputbuf); continue; } if (!(UNP.outputbuf = cli_malloc(UNP.usize))) { free(UNP.inputbuf); return CL_EMEM; } cli_dbgmsg("autoit: uncompressed size again: %x\n", UNP.usize); 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(UNP.inputbuf); /* Sometimes the autoit exe is in turn packed/lamed with a runtime compressor and similar shit. * However, since the autoit script doesn't compress a second time very well, chances are we're * still able to match the headers and unpack something (see sample 0811129) * I'd rather unpack something (although possibly highly corrupted) than nothing at all * * - Fortuna audaces iuvat - */ if (UNP.error) { cli_dbgmsg("autoit: decompression error after %u bytes - partial file may exist\n", UNP.cur_output); UNP.usize = UNP.cur_output; } } else { cli_dbgmsg("autoit: file is not compressed\n"); UNP.outputbuf = UNP.inputbuf; UNP.usize = UNP.csize; } if (UNP.usize < 4) { cli_dbgmsg("autoit: file is too short\n"); free(UNP.outputbuf); continue; } files++; /* FIXME: REGRESSION NEEDED! */ /* UNP.usize = u2a(UNP.outputbuf, UNP.usize); */ snprintf(tempfile, 1023, "%s" PATHSEP "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_ECREAT; } if (cli_writen(i, UNP.outputbuf, UNP.usize) != UNP.usize) { cli_dbgmsg("autoit: cannot write %d bytes\n", UNP.usize); close(i); free(UNP.outputbuf); return CL_EWRITE; } free(UNP.outputbuf); if (ctx->engine->keeptmp) cli_dbgmsg("autoit: file extracted to %s\n", tempfile); else cli_dbgmsg("autoit: file successfully extracted\n"); if (lseek(i, 0, SEEK_SET) == -1) { cli_dbgmsg("autoit: call to lseek() has failed\n"); close(i); return CL_ESEEK; } if (cli_magic_scandesc(i, tempfile, ctx) == CL_VIRUS) { if (!SCAN_ALLMATCHES) { close(i); if (!ctx->engine->keeptmp) if (cli_unlink(tempfile)) return CL_EUNLINK; return CL_VIRUS; } det = 1; } close(i); if (!ctx->engine->keeptmp) if (cli_unlink(tempfile)) return CL_EUNLINK; } return (det ? CL_VIRUS : ret); } /********************* LAME realted stuff *********************/ #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 { uint32_t lo; uint32_t hi; } 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 (fpu_words == FPU_ENDIAN_LITTLE) { ret.as_uint.lo = rolled << 0x14; ret.as_uint.hi = 0x3ff00000 | (rolled >> 0xc); } else { ret.as_uint.hi = rolled << 0x14; ret.as_uint.lo = 0x3ff00000 | (rolled >> 0xc); } 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(cli_ctx *ctx, const uint8_t *base, char *tmpd) { uint8_t b[600], comp, script, *buf; uint32_t s; int i, ret, det = 0; unsigned int files = 0; char tempfile[1024]; const char prefixes[] = {'\0', '\0', '@', '$', '\0', '.', '"', '#'}; const char *opers[] = {",", "=", ">", "<", "<>", ">=", "<=", "(", ")", "+", "-", "/", "*", "&", "[", "]", "==", "^", "+=", "-=", "/=", "*=", "&=", "?", ":"}; struct UNP UNP; fmap_t *map = *ctx->fmap; /* 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; */ base += 16; /* for now we just skip the garbage */ while ((ret = cli_checklimits("cli_autoit", ctx, 0, 0, 0)) == CL_CLEAN) { if (!fmap_need_ptr_once(map, base, 8)) return (det ? CL_VIRUS : CL_CLEAN); /* LAME_decrypt(buf, 4, 0x18ee); waste of time */ if (cli_readint32(base) != 0x52ca436b) { cli_dbgmsg("autoit: no FILE magic found, giving up\n"); return (det ? CL_VIRUS : CL_CLEAN); } script = 0; s = cli_readint32(base + 4) ^ 0xadbc; if ((int32_t)(s * 2) < 0) return (det ? CL_VIRUS : CL_CLEAN); /* the original code wouldn't seek back here */ base += 8; if (s < sizeof(b) / 2) { if (!fmap_need_ptr_once(map, base, s * 2)) return (det ? CL_VIRUS : CL_CLEAN); memcpy(b, base, s * 2); LAME_decrypt(b, s * 2, s + 0xb33f); u2a(b, s * 2); cli_dbgmsg("autoit: magic string '%s'\n", b); if (s == 19 && !memcmp(">>>AUTOIT SCRIPT<<<", b, 19)) script = 1; } else { cli_dbgmsg("autoit: magic string too long to print\n"); } base += s * 2; if (!fmap_need_ptr_once(map, base, 4)) return (det ? CL_VIRUS : CL_CLEAN); s = cli_readint32(base) ^ 0xf820; if ((int32_t)(s * 2) < 0) return (det ? CL_VIRUS : CL_CLEAN); /* the original code wouldn't seek back here */ base += 4; if (cli_debug_flag && s < sizeof(b) / 2) { if (!fmap_need_ptr_once(map, base, s * 2)) return (det ? CL_VIRUS : CL_CLEAN); memcpy(b, base, s * 2); LAME_decrypt(b, s * 2, s + 0xf479); b[s * 2] = '\0'; b[s * 2 + 1] = '\0'; u2a(b, s * 2); cli_dbgmsg("autoit: original filename '%s'\n", b); } base += s * 2; if (!fmap_need_ptr_once(map, base, 13)) return (det ? CL_VIRUS : CL_CLEAN); comp = *base; UNP.csize = cli_readint32(base + 1) ^ 0x87bc; if ((int32_t)UNP.csize < 0) { cli_dbgmsg("autoit: bad file size - giving up\n"); return (det ? CL_VIRUS : CL_CLEAN); } if (!UNP.csize) { cli_dbgmsg("autoit: skipping empty file\n"); base += 13 + 16; continue; } cli_dbgmsg("autoit: compressed size: %x\n", UNP.csize); cli_dbgmsg("autoit: advertised uncompressed size %x\n", cli_readint32(base + 5) ^ 0x87bc); cli_dbgmsg("autoit: ref chksum: %x\n", cli_readint32(base + 9) ^ 0xa685); base += 13 + 16; if (cli_checklimits("autoit", ctx, UNP.csize, 0, 0) != CL_CLEAN) { base += UNP.csize; continue; } if (comp == 1 && UNP.csize < sizeof(union unaligned_32)) { cli_dbgmsg("autoit: compressed size too small, skipping\n"); continue; } files++; if (!(UNP.inputbuf = cli_malloc(UNP.csize))) return CL_EMEM; if (!fmap_need_ptr_once(map, base, UNP.csize)) { cli_dbgmsg("autoit: failed to read compressed stream. broken/truncated file?\n"); free(UNP.inputbuf); return (det ? CL_VIRUS : CL_CLEAN); } memcpy(UNP.inputbuf, base, UNP.csize); base += UNP.csize; LAME_decrypt(UNP.inputbuf, UNP.csize, 0x2477 /* + m4sum (broken by design) */); if (comp == 1) { cli_dbgmsg("autoit: file is compressed\n"); if (cli_readint32(UNP.inputbuf) != 0x36304145) { cli_dbgmsg("autoit: bad magic or unsupported version\n"); free(UNP.inputbuf); continue; } if (!(UNP.usize = be32_to_host(*(uint32_t *)(UNP.inputbuf + 4)))) UNP.usize = UNP.csize; /* only a specifically crafted or badly corrupted sample should land here */ if (cli_checklimits("autoit", ctx, UNP.usize, 0, 0) != CL_CLEAN) { free(UNP.inputbuf); continue; } if (!(UNP.outputbuf = cli_malloc(UNP.usize))) { free(UNP.inputbuf); return CL_EMEM; } cli_dbgmsg("autoit: uncompressed size again: %x\n", UNP.usize); 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(UNP.inputbuf); if (UNP.error) { cli_dbgmsg("autoit: decompression error after %u bytes - partial file may exist\n", UNP.cur_output); UNP.usize = UNP.cur_output; } } else { cli_dbgmsg("autoit: file is not compressed\n"); UNP.outputbuf = UNP.inputbuf; 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); UNP.error = 0; 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: /* */ 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; } snprintf((char *)&buf[UNP.cur_output], 12, "0x%08x ", cli_readint32((char *)&UNP.outputbuf[UNP.cur_input])); UNP.cur_output += 11; UNP.cur_input += 4; break; case 0x10: /* */ { uint64_t val; if (UNP.usize < 8 || UNP.cur_input >= UNP.usize - 8) { UNP.error = 1; cli_dbgmsg("autoit: not enough space for an int64\n"); break; } if (UNP.cur_output + 20 >= UNP.csize) { uint8_t *newout; UNP.csize += 512; if (!(newout = cli_realloc(buf, UNP.csize))) { UNP.error = 1; break; } buf = newout; } val = (uint64_t)cli_readint32((char *)&UNP.outputbuf[UNP.cur_input + 4]); val <<= 32; val += (uint64_t)cli_readint32((char *)&UNP.outputbuf[UNP.cur_input]); snprintf((char *)&buf[UNP.cur_output], 20, "0x%016lx ", (unsigned long int)val); UNP.cur_output += 19; UNP.cur_input += 8; break; } case 0x20: /* */ 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 == FPU_ENDIAN_LITTLE) 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); 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: /* &= */ case 0x57: /* ? */ case 0x58: /* : */ 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 (0x%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; } snprintf(tempfile, 1023, "%s" PATHSEP "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_ECREAT; } if (cli_writen(i, buf, UNP.cur_output) != UNP.cur_output) { cli_dbgmsg("autoit: cannot write %d bytes\n", UNP.usize); close(i); free(buf); return CL_EWRITE; } free(buf); if (ctx->engine->keeptmp) cli_dbgmsg("autoit: %s extracted to %s\n", (script) ? "script" : "file", tempfile); else cli_dbgmsg("autoit: %s successfully extracted\n", (script) ? "script" : "file"); if (lseek(i, 0, SEEK_SET) == -1) { cli_dbgmsg("autoit: call to lseek() has failed\n"); close(i); return CL_ESEEK; } if (cli_magic_scandesc(i, tempfile, ctx) == CL_VIRUS) { if (!SCAN_ALLMATCHES) { close(i); if (!ctx->engine->keeptmp) if (cli_unlink(tempfile)) return CL_EUNLINK; return CL_VIRUS; } det = 1; } close(i); if (!ctx->engine->keeptmp) if (cli_unlink(tempfile)) return CL_EUNLINK; } return (det ? CL_VIRUS : ret); } /********************* autoit3 wrapper *********************/ int cli_scanautoit(cli_ctx *ctx, off_t offset) { const uint8_t *version; int r; char *tmpd; fmap_t *map = *ctx->fmap; cli_dbgmsg("in scanautoit()\n"); if (!(version = fmap_need_off_once(map, offset, sizeof(*version)))) return CL_EREAD; if (!(tmpd = cli_gentemp(ctx->engine->tmpdir))) return CL_ETMPDIR; if (mkdir(tmpd, 0700)) { cli_dbgmsg("autoit: Can't create temporary directory %s\n", tmpd); free(tmpd); return CL_ETMPDIR; } if (ctx->engine->keeptmp) cli_dbgmsg("autoit: Extracting files to %s\n", tmpd); switch (*version) { case 0x35: r = ea05(ctx, version + 1, tmpd); break; case 0x36: if (fpu_words == FPU_ENDIAN_INITME) fpu_words = get_fpu_endian(); if (fpu_words == FPU_ENDIAN_UNKNOWN) { cli_dbgmsg("autoit: EA06 support not available" "(cannot extract ea06 doubles, unknown floating double representation).\n"); r = CL_CLEAN; } else r = ea06(ctx, version + 1, tmpd); break; default: /* NOT REACHED */ cli_dbgmsg("autoit: unknown method\n"); r = CL_CLEAN; } if (!ctx->engine->keeptmp) cli_rmdirs(tmpd); free(tmpd); return r; }