#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"
#if WORDS_BIGENDIAN == 0
#define EC32(v) (v)
#else
static inline uint32_t EC32(uint32_t v)
{
return ((v >> 24) | ((v & 0x00FF0000) >> 8) | ((v & 0x0000FF00) << 8) | (v << 24));
}
#endif
static int doubledl(char **scur, uint8_t *mydlptr, char *buffer, int buffersize)
{
unsigned char mydl = *mydlptr;
unsigned char olddl = mydl;
mydl*=2;
if ( !(olddl & 0x7f)) {
if ( *scur < buffer || *scur >= buffer+buffersize-1 )
return -1;
olddl = **scur;
mydl = olddl*2+1;
*scur=*scur + 1;
}
*mydlptr = mydl;
return (olddl>>7)&1;
}
int petite_inflate2x_1to9(char *buf, uint32_t minrva, int bufsz, struct pe_image_section_hdr *sections, int sectcount, uint32_t Imagebase, uint32_t pep, int desc, int version, uint32_t ResRva, uint32_t ResSize)
{
char *adjbuf = buf - minrva;
char *packed = NULL;
uint32_t thisrva=0, bottom = 0, enc_ep=0, irva=0, workdone=0, grown=0x355, skew=0x35;
int j = 0, oob, mangled = 0, check4resources=0;
struct SECTION *usects = NULL;
void *tmpsct = NULL;
if ( version == 2 )
packed = adjbuf + EC32(sections[sectcount-1].VirtualAddress) + 0x1b8;
if ( version == 1 ) {
packed = adjbuf + EC32(sections[sectcount-1].VirtualAddress) + 0x178;
grown=0x323;
skew=0x34;
}
while (1) {
char *ssrc, *ddst;
uint32_t size, srva;
int backbytes, oldback, backsize, addsize;
if ( packed < buf || packed >= buf+bufsz-4) {
if (usects)
free(usects);
return -1;
}
srva = cli_readint32(packed);
if (! srva) {
int t, upd = 1;
if ( j <= 0 )
return -1;
while ( upd ) {
upd = 0;
for (t = 0; t < j-1 ; t++) {
uint32_t trva, trsz, tvsz;
if ( usects[t].rva <= usects[t+1].rva )
continue;
trva = usects[t].rva;
trsz = usects[t].rsz;
tvsz = usects[t].vsz;
usects[t].rva = usects[t+1].rva;
usects[t].rsz = usects[t+1].rsz;
usects[t].vsz = usects[t+1].vsz;
usects[t+1].rva = trva;
usects[t+1].rsz = trsz;
usects[t+1].vsz = tvsz;
upd = 1;
}
}
for (t = 0; t < j-1 ; t++) {
if ( usects[t].vsz != usects[t+1].rva - usects[t].rva )
usects[t].vsz = usects[t+1].rva - usects[t].rva;
}
if (enc_ep) {
uint32_t virtaddr = pep + 5 + Imagebase, tmpep;
int rndm = 0, dummy = 1;
uint32_t *thunk = (uint32_t*)(adjbuf+irva);
uint32_t *imports;
if ( version == 2 ) {
while ( (char *)thunk >=buf && (char *)thunk<buf+bufsz-4 && dummy ) {
uint32_t api;
if (! *thunk ) {
workdone = 1;
break;
}
imports = (uint32_t *) (adjbuf + EC32(*thunk++));
dummy = 0;
while ( (char *)imports >=buf && (char *)imports<buf+bufsz-4 ) {
dummy = 0;
if ( ! (api = EC32(*imports++)) ) {
dummy = 1;
break;
}
if ( (api != (api | 0x80000000)) && mangled && --rndm < 0) {
api = virtaddr;
virtaddr +=5;
rndm = virtaddr & 7;
} else {
api = 0xbff01337;
}
if (EC32(sections[sectcount-1].VirtualAddress)+Imagebase < api )
enc_ep--;
if ( api < virtaddr )
enc_ep--;
tmpep = (enc_ep & 0xfffffff8)>>3 & 0x1fffffff;
enc_ep = (enc_ep & 7)<<29 | tmpep;
}
}
} else
workdone = 1;
enc_ep = pep+5+enc_ep;
if ( workdone == 1 )
cli_dbgmsg("Petite: Old EP: %x\n", enc_ep);
else
cli_dbgmsg("Petite: In troubles while attempting to decrypt old EP\n");
}
for (t = 0; t < j ; t++) {
usects[t].raw = (usects[t-1].raw + usects[t-1].rsz)*(t>0);
if (usects[t].rsz != 0)
memmove(buf + usects[t].raw, adjbuf + usects[t].rva, usects[t].rsz);
}
cli_dbgmsg("Petite: Sections dump:\n");
for (t = 0; t < j ; t++)
cli_dbgmsg("Petite: .SECT%d RVA:%x VSize:%x ROffset: %x, RSize:% x\n", t, usects[t].rva, usects[t].vsz, usects[t].raw, usects[t].rsz);
if ( (ssrc = rebuildpe(buf, usects, j, Imagebase, enc_ep, ResRva, ResSize)) ) {
write(desc, ssrc, 0x148+0x80+0x28*j+usects[j-1].raw+usects[j-1].rsz);
free(ssrc);
} else
cli_dbgmsg("Petite: Rebuilding failed\n");
free(usects);
return workdone;
}
size = srva & 0x7fffffff;
if ( srva != size ) {
check4resources=0;
if ( packed < buf || packed >= buf+bufsz-12) {
if (usects)
free(usects);
return -1;
}
bottom = cli_readint32(packed+8) + 4;
ssrc = adjbuf + cli_readint32(packed+4) - (size-1)*4;
ddst = adjbuf + cli_readint32(packed+8) - (size-1)*4;
if ( ssrc < buf || ssrc + size*4 >= buf + bufsz || ddst < buf || ddst + size*4 >= buf + bufsz ) {
if (usects)
free(usects);
return -1;
}
memmove(ddst, ssrc, size*4);
packed += 0x0c;
} else {
uint32_t check1, check2;
uint8_t mydl = 0;
uint8_t goback;
if ( packed < buf || packed >= buf+bufsz-16) {
if (usects)
free(usects);
return -1;
}
size = cli_readint32(packed+4);
packed += 0x10;
thisrva=cli_readint32(packed-8);
if ( ! (tmpsct = realloc(usects, sizeof(struct SECTION) * (j+1))) ) {
if (usects)
free(usects);
return -1;
}
usects = (struct SECTION *) tmpsct;
usects[j].rva = thisrva;
usects[j].rsz = size;
if ( (int)(bottom - thisrva) >0 )
usects[j].vsz = bottom - thisrva;
else
usects[j].vsz = size;
usects[j].raw = 0;
if (!size) {
j++;
continue;
}
ssrc = adjbuf + srva;
ddst = adjbuf + thisrva;
if (!check4resources) {
int q;
for ( q = 0 ; q < sectcount ; q++ ) {
if ( thisrva <= EC32(sections[q].VirtualAddress) || thisrva >= EC32(sections[q].VirtualAddress) + EC32(sections[q].VirtualSize))
continue;
usects[j].rva = EC32(sections[q].VirtualAddress);
usects[j].rsz = thisrva - EC32(sections[q].VirtualAddress) + size;
break;
}
}
j++;
if ( size < 0x10000 ) {
check1 = 0x0FFFFC060;
check2 = 0x0FFFFFC60;
goback = 5;
} else if ( size < 0x40000 ) {
check1 = 0x0FFFF8180;
check2 = 0x0FFFFF980;
goback = 7;
} else {
check1 = 0x0FFFF8300;
check2 = 0x0FFFFFB00;
goback = 8;
}
if ( ddst < buf || ddst >= buf+bufsz-1 || ssrc < buf || ssrc >= buf+bufsz-1 ) {
free(usects);
return -1;
}
size--;
*ddst++=*ssrc++;
backbytes=0;
oldback = 0;
while (size > 0) {
oob = doubledl(&ssrc, &mydl, buf, bufsz);
if ( oob == -1 ) {
free(usects);
return -1;
}
if (!oob) {
if ( ddst < buf || ddst >= buf+bufsz-1 || ssrc < buf || ssrc >= buf+bufsz-1 ) {
free(usects);
return -1;
}
*ddst++ = (char)((*ssrc++)^(size & 0xff));
size--;
} else {
addsize = 0;
backbytes++;
while (1) {
if ( (oob = doubledl(&ssrc, &mydl, buf, bufsz)) == -1 ) {
free(usects);
return -1;
}
backbytes = backbytes*2 + oob;
if ( (oob = doubledl(&ssrc, &mydl, buf, bufsz)) == -1 ) {
free(usects);
return -1;
}
if (!oob)
break;
}
backbytes -= 3;
if ( backbytes >= 0 ) {
backsize = goback;
do {
if ( (oob = doubledl(&ssrc, &mydl, buf, bufsz)) == -1 ) {
free(usects);
return -1;
}
backbytes = backbytes*2 + oob;
backsize--;
} while (backsize);
backbytes^=0xffffffff;
addsize += 1 + ( backbytes < check2 ) + ( backbytes < check1 );
oldback = backbytes;
} else {
backsize = backbytes+1;
backbytes = oldback;
}
if ( (oob = doubledl(&ssrc, &mydl, buf, bufsz)) == -1 ) {
free(usects);
return -1;
}
backsize = backsize*2 + oob;
if ( (oob = doubledl(&ssrc, &mydl, buf, bufsz)) == -1 ) {
free(usects);
return -1;
}
backsize = backsize*2 + oob;
if (!backsize) {
backsize++;
while (1) {
if ( (oob = doubledl(&ssrc, &mydl, buf, bufsz)) == -1 ) {
free(usects);
return -1;
}
backsize = backsize*2 + oob;
if ( (oob = doubledl(&ssrc, &mydl, buf, bufsz)) == -1 ) {
free(usects);
return -1;
}
if (!oob)
break;
}
backsize+=2;
}
backsize+=addsize;
size-=backsize;
if ( ddst<buf || ddst+backsize>=buf+bufsz || ddst+backbytes<buf || ddst+backbytes+backsize>=buf+bufsz ) {
free(usects);
return -1;
}
while(backsize--) {
*ddst=*(ddst+backbytes);
ddst++;
}
backbytes=0;
backsize=0;
}
}
if ( j &&
(
( (usects[j-1].rsz > grown ) &&
cli_readint32(ddst-grown+5+0x4f) == 0x645ec033 &&
cli_readint32(ddst-grown+5+0x4f+4) == 0x1b8b188b )
||
( (usects[j-1].rsz > grown+skew ) &&
cli_readint32(ddst-grown+5+0x4f-skew) == 0x645ec033 &&
cli_readint32(ddst-grown+5+0x4f+4-skew) == 0x1b8b188b )
)
)
{
uint32_t test1, test2;
int reloc = skew*(cli_readint32(ddst-grown+5+0x4f-skew) == 0x645ec033);
test1 = cli_readint32(ddst-grown+0x0f-8-reloc)^0x9d6661aa;
test2 = cli_readint32(ddst-grown+0x0f-4-reloc)^0xe908c483;
cli_dbgmsg("Petite: Found petite code in sect%d(%x). Let's strip it.\n", j-1, usects[j-1].rva);
if (test1 == test2) {
irva = cli_readint32(ddst-grown+0x121-reloc);
enc_ep = cli_readint32(ddst-grown+0x0f-reloc)^test1;
mangled = (cli_readint32(ddst-grown+0x1c0-reloc) != 0x90909090);
cli_dbgmsg("Petite: Encrypted EP: %x | Array of imports: %x\n",enc_ep, irva);
}
usects[j-1].rsz -= grown+reloc;
}
check4resources++;
}
}
}