blob: 7557f398b93573e373b0ae5c1a1619d09d879e60 [file] [log] [blame]
/*
* Copyright (C) 2006 Sensory Networks, Inc.
* Written by 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.
*/
/*
** wwunpack.c
**
** 09/07/2k6 - Campioni del mondo!!!
** 14/07/2k6 - RCE'ed + standalone sect unpacker
** 15/07/2k6 - Merge started
** 17/07/2k6 - Rebuild
** 18/07/2k6 - Secured (well, hopefully...)
**
*/
/*
** Unpacks+rebuilds WWPack32 1.20
**
** Just boooooring stuff, blah.
**
*/
/*
** TODO:
**
** review
** check eax vs al
** (check for dll's)
** (have a look at older versions)
**
*/
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include "cltypes.h"
#include "others.h"
#include "wwunpack.h"
#define VAALIGN(s) (((s)/0x1000+((s)%0x1000!=0))*0x1000)
#define FIXVS(v, r) (VAALIGN((r>v)?r:v))
static int getbitmap(uint32_t *bitmap, char **src, uint8_t *bits, char *buf, unsigned int size) {
if (! CLI_ISCONTAINED(buf, size, *src, 4)) return 1;
*bitmap=cli_readint32(*src);
*src+=4;
*bits=32;
return 0;
}
static int getbits(uint8_t X, uint32_t *eax, uint32_t *bitmap, uint8_t *bits, char **src, char *buf, unsigned int size) {
*eax=*bitmap>>(32-X);
if (*bits>X) {
*bitmap<<=X;
*bits-=X;
} else if (*bits<X) {
X-=*bits;
*eax>>=X;
if (getbitmap(bitmap, src, bits, buf, size)) return 1;
*eax<<=X;
*eax|=*bitmap>>(32-X);
*bitmap<<=X;
*bits-=X;
} else {
if (getbitmap(bitmap, src, bits, buf, size)) return 1;
}
return 0;
}
static int wunpsect(char *packed, char *unpacked, unsigned int psize, unsigned int usize) {
char *src=packed, *dst=unpacked;
uint32_t bitmap, eax;
uint8_t bits;
unsigned int lostbit, getmorestuff;
uint16_t backbytes;
uint16_t backsize;
uint8_t oal;
if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;
eax=bitmap;
while (1) {
lostbit=bitmap>>31;
bitmap<<=1;
bits--;
if (!lostbit && bits) {
if (!(CLI_ISCONTAINED(packed, psize, src, 1) && CLI_ISCONTAINED(unpacked, usize, dst, 1))) return 1;
*dst++=*src++;
continue;
}
if (!bits) {
if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;
eax=bitmap;
if (!lostbit) {
if (!(CLI_ISCONTAINED(packed, psize, src, 1) && CLI_ISCONTAINED(unpacked, usize, dst, 1))) return 1;
*dst++=*src++;
continue;
}
}
if (getbits(2, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
if ((eax&0xff)>=3) {
/* 50ff - two_bytes */
uint8_t fetchbits;
if (getbits(2, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
fetchbits=(eax&0xff)+5;
eax--;
if ((int16_t)(eax&0xffff)<=0) {
/* 5113 */
backbytes=1<<fetchbits;
backbytes=(backbytes&0xff00)|((backbytes-31)&0xff);
} else {
/* 511b */
fetchbits++;
backbytes=1<<fetchbits;
backbytes-=0x9f;
}
/* 5125 */
if (getbits(fetchbits, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
if ((eax&0xffff)==0x1ff) break;
eax&=0xffff;
backbytes+=eax;
if (!(CLI_ISCONTAINED(unpacked, usize, dst-backbytes, 2) && CLI_ISCONTAINED(unpacked, usize, dst, 2))) return 1;
*dst=*(dst-backbytes);
dst++;
*dst=*(dst-backbytes);
dst++;
continue;
}
/* 5143 - more_backbytes */
oal=eax&0xff;
getmorestuff=1;
if (getbits(3, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
if ((eax&0xff)<=3) {
lostbit=0;
if ((eax&0xff)==3) {
/* next_bit_or_reseed */
lostbit=bitmap>>31;
bitmap<<=1;
bits--;
if (!bits) {
if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;
}
}
eax=eax+lostbit+5;
/* jmp more_bb_commondock */
} else { /* >3 */
/* 5160 - more_bb_morethan3 */
if ((eax&0xff)==4) {
/* next_bit_or_reseed */
lostbit=bitmap>>31;
bitmap<<=1;
bits--;
if (!bits) {
if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;
}
eax=eax+lostbit+6;
/* jmp more_bb_commondock */
} else { /* !=4 */
eax+=7;
if ((eax&0xff)>=0x0d) {
getmorestuff=0; /* jmp more_bb_PASTcommondock */
if ((eax&0xff)==0x0d) {
/* 5179 */
if (getbits(0x0e, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
eax+=0x1fe1;
} else {
/* 516c */
if (getbits(0x0f, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
eax+=0x5fe1;
}
/* jmp more_bb_PASTcommondock */
} /* al >= 0d */
} /* al != 4 */
} /* >3 */
if (getmorestuff) {
/* 5192 - more_bb_commondock */
uint16_t bk=(1<<(eax&0xff))-0x1f;
if (getbits((eax&0xff), &eax, &bitmap, &bits, &src, packed, psize)) return 1;
eax+=bk;
}
/* 51a7 - more_bb_pastcommondock */
eax&=0xffff;
backbytes=eax;
backsize=3+(oal!=1);
if (oal<1) { /* overrides backsize */
/* 51bb - more_bb_again */
/* next_bit_or_reseed */
lostbit=bitmap>>31;
bitmap<<=1;
bits--;
if (!bits) {
if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;
}
if (!lostbit) {
/* 51c2 */
/* next_bit_or_reseed */
lostbit=bitmap>>31;
bitmap<<=1;
bits--;
if (!bits) {
if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;
}
eax=5+lostbit;
/* jmp setsize_and_backcopy */
} else {
/* 51ce - more_bb_again_and_again */
if (getbits(3, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
if (eax&0xff) {
/* 51e6 */
eax+=6;
/* jmp setsize_and_backcopy */
} else {
if (getbits(4, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
if (eax&0xff) {
/* 51e4 */
eax+=7+6;
/* jmp setsize_and_backcopy */
} else {
/* 51ea - OMGWTF */
uint8_t c=4;
uint16_t d=0x0d;
while ( 1 ) {
if (c!=7){
d+=2;
d<<=1;
d--;
/* next_bit_or_reseed */
lostbit=bitmap>>31;
bitmap<<=1;
bits--;
if (!bits) {
if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;
}
c++;
if (!lostbit) continue;
if (getbits(c, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
d+=eax&0xff;
eax&=0xffffff00;
eax|=d&0xff;
} else {
if (getbits(14, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
}
break;
} /* while */
} /* OMGWTF */
} /* eax&0xff */
} /* lostbit */
/* 521b - setsize_and_backcopy */
backsize=eax&0xffff;
}
/* 521e - backcopy */
if (!(CLI_ISCONTAINED(unpacked, usize, dst-backbytes, backsize) && CLI_ISCONTAINED(unpacked, usize, dst, backsize))) return 1;
while(backsize--){
*dst=*(dst-backbytes);
dst++;
}
} /* while true */
return 0;
}
int wwunpack(char *exe, uint32_t exesz, uint32_t headsize, uint32_t min, uint32_t wwprva, uint32_t e_lfanew, char *wwp, uint32_t wwpsz, uint16_t sects) {
char *stuff=wwp+0x2a1, *packed, *unpacked;
uint32_t rva, csize;
cli_dbgmsg("in wwunpack\n");
while(1) {
if (!CLI_ISCONTAINED(wwp, wwpsz, stuff, 17)) {
cli_dbgmsg("WWPack: next chunk out ouf file, giving up.\n");
return 1;
}
if ((csize=cli_readint32(stuff+8)*4)!=(uint32_t)cli_readint32(stuff+12)+4) {
cli_dbgmsg("WWPack: inconsistent/hacked data, go figure!\n");
return 1;
}
rva = wwprva-cli_readint32(stuff);
if((packed = (char *) cli_calloc(csize, sizeof(char))) == NULL) {
cli_dbgmsg("WWPack: Can't allocate %d bytes\n", csize);
return 1;
}
unpacked=exe+headsize+rva-min;
if (!CLI_ISCONTAINED(exe, exesz, unpacked, csize)) {
free(packed);
cli_dbgmsg("WWPack: packed data out of bounds, giving up.\n");
return 1;
}
memcpy(packed, unpacked, csize);
if (wunpsect(packed, unpacked, csize, exesz-(unpacked-exe))) {
free(packed);
cli_dbgmsg("WWPack: unpacking failed.\n");
return 1;
}
free(packed);
if (!stuff[16]) break;
stuff+=17;
}
stuff=exe+e_lfanew;
stuff[6]=sects&0xff;
stuff[7]=sects>>8;
csize=cli_readint32(wwp+0x295)+wwprva+0x299;
cli_dbgmsg("WWPack: found OEP @%x\n", csize);
cli_writeint32(stuff+0x28, csize);
csize=cli_readint32(stuff+0x50)-VAALIGN(wwpsz);
cli_writeint32(stuff+0x50, csize);
stuff+=0x18+(cli_readint32(stuff+0x14)&0xffff);
while (sects--) {
uint32_t v=cli_readint32(stuff+8);
uint32_t r=cli_readint32(stuff+16);
csize=FIXVS(v, r);
cli_writeint32(stuff+8, csize);
cli_writeint32(stuff+16, csize);
cli_writeint32(stuff+20, cli_readint32(stuff+12)-min+headsize);
stuff+=0x28;
}
memset(stuff, 0, 0x28);
return 0;
}