/* * Copyright (C) 2006 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 as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 ** */ /* ** Unpacks+rebuilds WWPack32 1.20 ** ** Just boooooring stuff, blah. ** */ /* ** TODO: ** ** use cli_readint32 ** add bound checks ** check eax vs al ** */ #ifdef WWP32 #if HAVE_CONFIG_H #include "clamav-config.h" #endif #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <string.h> #include "cltypes.h" #include "pe.h" #include "rebuildpe.h" #include "others.h" #include "wwunpack.h" static void getbits(uint8_t X, uint32_t *eax, uint32_t *bitmap, uint8_t *bits, char **src) { *eax=*bitmap>>(32-X); if (*bits>X) { *bitmap<<=X; *bits-=X; } else if (*bits<X) { X-=*bits; *eax>>=X; *bitmap=*(uint32_t *)(*src); *src+=4; *eax<<=X; *eax|=*bitmap>>(32-X); *bitmap<<=X; *bits=32-X; } else { *bitmap=*(uint32_t *)(*src); *src+=4; *bits=32; } } static void wunpsect(char *src, char *dst) { uint32_t bitmap, eax; uint8_t bits; unsigned int lostbit, getmorestuff; uint16_t backbytes; uint16_t backsize; uint8_t oal; eax=bitmap=*(uint32_t *)src; src+=4; bits=32; while (1) { lostbit=bitmap>>31; bitmap<<=1; bits--; if (!lostbit && bits) { *dst++=*src++; continue; } if (!bits) { eax=bitmap=*(uint32_t *)src; bits=32; src+=4; if (!lostbit) { *dst++=*src++; continue; } } getbits(2, &eax, &bitmap, &bits, &src); if ((eax&0xff)>=3) { /* 50ff - two_bytes */ uint8_t fetchbits; getbits(2, &eax, &bitmap, &bits, &src); 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 */ getbits(fetchbits, &eax, &bitmap, &bits, &src); if ((eax&0xffff)==0x1ff) break; eax&=0xffff; backbytes+=eax; *dst=*(dst-backbytes); dst++; *dst=*(dst-backbytes); dst++; continue; } /* 5143 - more_backbytes */ oal=eax&0xff; getmorestuff=1; /* FIXME: pushf */ getbits(3, &eax, &bitmap, &bits, &src); if ((eax&0xff)<=3) { lostbit=0; if ((eax&0xff)==3) { /* next_bit_or_reseed */ lostbit=bitmap>>31; bitmap<<=1; bits--; if (!bits) { bitmap=*(uint32_t *)src; bits=32; src+=4; } } eax=eax+lostbit+5; /* FIXME: 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) { bitmap=*(uint32_t *)src; bits=32; src+=4; } eax=eax+lostbit+6; /* FIXME: jmp more_bb_commondock */ } else { /* !=4 */ eax+=7; if ((eax&0xff)>=0x0d) { getmorestuff=0; /* jmp more_bb_PASTcommondock */ if ((eax&0xff)==0x0d) { /* 5179 */ getbits(0x0e, &eax, &bitmap, &bits, &src); eax+=0x1fe1; } else { /* 516c */ getbits(0x0f, &eax, &bitmap, &bits, &src); eax+=0x5fe1; } /* FIXME: jmp more_bb_PASTcommondock */ } /* al >= 0d */ } /* al != 4 */ } /* >3 */ if (getmorestuff) { /* 5192 - more_bb_commondock */ uint16_t bk=(1<<(eax&0xff))-0x1f; getbits((eax&0xff), &eax, &bitmap, &bits, &src); eax+=bk; } /* 51a7 - more_bb_pastcommondock */ eax&=0xffff; backbytes=eax; backsize=3+(oal!=1); /* FIXME: move up and remove oal */ if (oal<1) { /* overrides backsize */ /* 51bb - more_bb_again */ /* next_bit_or_reseed */ lostbit=bitmap>>31; bitmap<<=1; bits--; if (!bits) { bitmap=*(uint32_t *)src; bits=32; src+=4; } if (!lostbit) { /* 51c2 */ /* next_bit_or_reseed */ lostbit=bitmap>>31; bitmap<<=1; bits--; if (!bits) { bitmap=*(uint32_t *)src; bits=32; src+=4; } eax=5+lostbit; /* FIXME: jmp setsize_and_backcopy */ } else { /* 51ce - more_bb_again_and_again */ getbits(3, &eax, &bitmap, &bits, &src); if (eax&0xff) { /* 51e6 */ eax+=6; /* FIXME: jmp setsize_and_backcopy */ } else { getbits(4, &eax, &bitmap, &bits, &src); if (eax&0xff) { /* 51e4 */ eax+=7+6; /* FIXME: 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) { bitmap=*(uint32_t *)src; bits=32; src+=4; } c++; if (!lostbit) continue; getbits(c, &eax, &bitmap, &bits, &src); d+=eax&0xff; eax&=0xffffff00; eax|=d&0xff; } else { getbits(14, &eax, &bitmap, &bits, &src); } break; } /* while */ } /* OMGWTF */ } /* eax&0xff */ } /* lostbit */ /* 521b - setsize_and_backcopy */ backsize=eax&0xffff; } /* 521e - backcopy */ while(backsize--){ *dst=*(dst-backbytes); dst++; } } /* while true */ } 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)!=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)) { cli_dbgmsg("WWPack: packed data out of bounds, giving up.\n"); return 1; } memcpy(packed, unpacked, csize); wunpsect(packed, unpacked); 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); #define VAALIGN(s) (((s)/0x1000+((s)%0x1000!=0))*0x1000) #define FIXVS(v, r) (VAALIGN((r>v)?r:v)) stuff+=0xf8; 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); cli_dbgmsg("WWPack: Successfully rebuilt\n", csize); return 0; } #endif