bugfix/hardening of unpacking code

git-svn: trunk@1808
remotes/push_mirror/metadata
aCaB 20 years ago
parent 1f280d214d
commit dddbbad7e7
  1. 3
      clamav-devel/ChangeLog
  2. 24
      clamav-devel/libclamav/fsg.c
  3. 2
      clamav-devel/libclamav/pe.c
  4. 87
      clamav-devel/libclamav/petite.c
  5. 61
      clamav-devel/libclamav/upx.c
  6. 6
      clamav-devel/libclamav/upx.h

@ -1,3 +1,6 @@
Tue Jan 10 01:53:20 CET 2006 (acab)
* libclamav: bugfix/hardening of unpacking code
Sat Jan 7 04:27:05 CET 2006 (tk)
---------------------------------
* libclamav/sis.c: extract and scan SIS packages

@ -47,24 +47,9 @@
#include "pe.h"
#include "rebuildpe.h"
#include "others.h"
#include "fsg.h"
#if WORDS_BIGENDIAN == 0
#define EC16(v) (v)
#define EC32(v) (v)
#else
static inline uint16_t EC16(uint16_t v)
{
return ((v >> 8) + (v << 8));
}
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)
static int doubledl(char **scur, uint8_t *mydlptr, char *buffer, uint32_t buffersize)
{
unsigned char mydl = *mydlptr;
unsigned char olddl = mydl;
@ -119,8 +104,6 @@ static int unfsg(char *source, char *dest, int ssize, int dsize, char **endsrc,
return -1;
*cdst++=0x00;
continue;
} else {
/* repne movsb - FIXME dont remove for now */
}
} else {
/* 18f */
@ -187,7 +170,7 @@ static int unfsg(char *source, char *dest, int ssize, int dsize, char **endsrc,
}
lostbit = 0;
}
if ((backsize > (uint32_t)(dest + dsize - cdst)) || (backbytes > (uint32_t)(cdst - dest)))
if (!CLI_ISCONTAINED(dest, dsize, cdst, backsize) || !CLI_ISCONTAINED(dest, dsize, cdst-backbytes, backsize))
return -1;
while(backsize--) {
*cdst=*(cdst-backbytes);
@ -208,11 +191,10 @@ static int unfsg(char *source, char *dest, int ssize, int dsize, char **endsrc,
return 0;
}
int unfsg_200(char *source, char *dest, int ssize, int dsize, uint32_t rva, uint32_t base, uint32_t ep, int file) {
char *fake, *tsrc;
struct SECTION section; // Yup, just one ;)
if ( unfsg(source, dest, ssize, dsize, &fake, &fake) ) return -1;
section.raw=0;

@ -167,7 +167,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
char sname[9], buff[4096], *tempfile;
unsigned int i, found, upx_success = 0, min = 0, max = 0, err, broken = 0;
unsigned int ssize = 0, dsize = 0, dll = 0, pe_plus = 0;
int (*upxfn)(char *, int , char *, int *, uint32_t, uint32_t, uint32_t) = NULL;
int (*upxfn)(char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t) = NULL;
char *src = NULL, *dest = NULL;
int ndesc, ret;

@ -58,7 +58,6 @@
#include "pe.h"
#include "rebuildpe.h"
#include "others.h"
#include "petite.h"
#if WORDS_BIGENDIAN == 0
#define EC32(v) (v)
@ -69,7 +68,9 @@ static inline uint32_t EC32(uint32_t v)
}
#endif
static int doubledl(char **scur, uint8_t *mydlptr, char *buffer, int buffersize)
#define MAX(a,b) ((a > b) ? a : b)
static int doubledl(char **scur, uint8_t *mydlptr, char *buffer, uint32_t buffersize)
{
unsigned char mydl = *mydlptr;
unsigned char olddl = mydl;
@ -86,7 +87,7 @@ static int doubledl(char **scur, uint8_t *mydlptr, char *buffer, int buffersize)
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)
int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_image_section_hdr *sections, unsigned 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;
@ -119,7 +120,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, int bufsz, struct pe_image
uint32_t size, srva;
int backbytes, oldback, backsize, addsize;
if ( packed < buf || packed >= buf+bufsz-4) {
if ( ! CLI_ISCONTAINED(buf, bufsz, packed, 4)) {
if (usects)
free(usects);
return -1;
@ -170,26 +171,28 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, int bufsz, struct pe_image
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;
char *thunk = adjbuf+irva;
char *imports;
if ( version == 2 ) { /* 2.2 onley */
while ( (char *)thunk >=buf && (char *)thunk<buf+bufsz-4 && dummy ) {
while ( dummy && CLI_ISCONTAINED(buf, bufsz, thunk, 4) ) {
uint32_t api;
if (! *thunk ) {
if (! cli_readint32(thunk)) {
workdone = 1;
break;
}
imports = (uint32_t *) (adjbuf + EC32(*thunk++));
imports = adjbuf + cli_readint32(thunk);
thunk+=4;
dummy = 0;
while ( (char *)imports >=buf && (char *)imports<buf+bufsz-4 ) {
dummy = 0;
while ( CLI_ISCONTAINED(buf, bufsz, imports, 4)) {
dummy = 0;
if ( ! (api = EC32(*imports++)) ) {
imports+=4;
if ( ! (api = cli_readint32(imports-4)) ) {
dummy = 1;
break;
}
@ -220,7 +223,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, int bufsz, struct pe_image
/* Let's compact data */
for (t = 0; t < j ; t++) {
usects[t].raw = (usects[t-1].raw + usects[t-1].rsz)*(t>0);
if (usects[t].rsz != 0)
if (usects[t].rsz != 0 && CLI_ISCONTAINED(buf, bufsz, buf + usects[t].raw, usects[t].rsz))
memmove(buf + usects[t].raw, adjbuf + usects[t].rva, usects[t].rsz);
}
@ -249,7 +252,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, int bufsz, struct pe_image
- 1 time for the all_the_rest section
*/
if ( packed < buf || packed >= buf+bufsz-12) {
if ( ! CLI_ISCONTAINED(buf, bufsz, packed+4, 8) ) {
if (usects)
free(usects);
return -1;
@ -259,7 +262,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, int bufsz, struct pe_image
ssrc = adjbuf + cli_readint32(packed+4) - (size-1)*4;
ddst = adjbuf + cli_readint32(packed+8) - (size-1)*4;
if ( ssrc < buf || size*4 >= buf + bufsz - ssrc || ddst < buf || size*4 >= buf + bufsz - ddst ) {
if ( !CLI_ISCONTAINED(buf, bufsz, ssrc, size*4) || !CLI_ISCONTAINED(buf, bufsz, ddst, size*4) ) {
if (usects)
free(usects);
return -1;
@ -275,15 +278,15 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, int bufsz, struct pe_image
/* Unpak each original section in turn */
if ( packed < buf || packed >= buf+bufsz-16) {
if ( ! CLI_ISCONTAINED(buf, bufsz, packed+4, 8)) {
if (usects)
free(usects);
return -1;
}
size = cli_readint32(packed+4); /* How many bytes to unpack */
thisrva=cli_readint32(packed+8); /* RVA of the original section */
packed += 0x10;
thisrva=cli_readint32(packed-8); /* RVA of the original section */
/* Alloc 1 more struct */
if ( ! (tmpsct = realloc(usects, sizeof(struct SECTION) * (j+1))) ) {
@ -350,7 +353,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, int bufsz, struct pe_image
* func to get called instead... ehehe very smart ;)
*/
if ( ddst < buf || ddst >= buf+bufsz-1 || ssrc < buf || ssrc >= buf+bufsz-1 ) {
if ( !CLI_ISCONTAINED(buf, bufsz, ssrc, 1) || !CLI_ISCONTAINED(buf, bufsz, ddst, 1)) {
free(usects);
return -1;
}
@ -368,7 +371,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, int bufsz, struct pe_image
return -1;
}
if (!oob) {
if ( ddst < buf || ddst >= buf+bufsz-1 || ssrc < buf || ssrc >= buf+bufsz-1 ) {
if ( !CLI_ISCONTAINED(buf, bufsz, ssrc, 1) || !CLI_ISCONTAINED(buf, bufsz, ddst, 1) ) {
free(usects);
return -1;
}
@ -438,7 +441,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, int bufsz, struct pe_image
}
backsize+=addsize;
size-=backsize;
if(backsize < 0 || backbytes >= 0 || (buf - ddst > backbytes - backsize) || (ddst - buf >= bufsz - backsize)) {
if(!CLI_ISCONTAINED(buf, bufsz, ddst, backsize) || !CLI_ISCONTAINED(buf, bufsz, ddst+backbytes, backsize)) {
free(usects);
return -1;
}
@ -455,36 +458,46 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, int bufsz, struct pe_image
* We've done version adjustments already, see above
*/
if ( j &&
( /* LONG MAGIC = 33C05E64 8B188B1B 8D63D65D */
( (usects[j-1].rsz > grown ) &&
cli_readint32(ddst-grown+5+0x4f) == 0x645ec033 &&
cli_readint32(ddst-grown+5+0x4f+4) == 0x1b8b188b )
||
/* This crap is ugly! Gotta make it all pretty one day or another */
( (usects[j-1].rsz > grown+skew ) &&
if ( j ) {
int strippetite=0;
uint32_t reloc;
/* LONG MAGIC = 33C05E64 8B188B1B 8D63D65D */
if ( usects[j-1].rsz > grown &&
CLI_ISCONTAINED(buf, bufsz, ddst-grown+5+0x4f, 8) &&
cli_readint32(ddst-grown+5+0x4f) == 0x645ec033 &&
cli_readint32(ddst-grown+5+0x4f+4) == 0x1b8b188b
) {
reloc = 0;
strippetite = 1;
}
if ( !strippetite &&
usects[j-1].rsz > grown+skew &&
CLI_ISCONTAINED(buf, bufsz, ddst-grown+5+0x4f-skew, 8) &&
cli_readint32(ddst-grown+5+0x4f-skew) == 0x645ec033 &&
cli_readint32(ddst-grown+5+0x4f+4-skew) == 0x1b8b188b )
)
)
{
cli_readint32(ddst-grown+5+0x4f+4-skew) == 0x1b8b188b
) {
reloc = skew; /* If the original exe had a .reloc were skewed */
strippetite = 1;
}
if (strippetite && CLI_ISCONTAINED(buf, bufsz, ddst-grown+0x0f-8-reloc, 8)) {
uint32_t test1, test2;
/* If the original exe had a .reloc were skewed */
int reloc = skew*(cli_readint32(ddst-grown+5+0x4f-skew) == 0x645ec033);
/* REMINDER: DON'T BPX IN HERE U DUMBASS!!!!!!!!!!!!!!!!!!!!!!!! */
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) {
if (test1 == test2 && CLI_ISCONTAINED(buf, bufsz, ddst-grown+0x0f-reloc, 0x1c0-0x0f+4)) {
irva = cli_readint32(ddst-grown+0x121-reloc);
enc_ep = cli_readint32(ddst-grown+0x0f-reloc)^test1;
mangled = ((uint32_t) cli_readint32(ddst-grown+0x1c0-reloc) != 0x90909090); /* FIXME: Magic's too short??? */
cli_dbgmsg("Petite: Encrypted EP: %x | Array of imports: %x\n",enc_ep, irva);
}
usects[j-1].rsz -= grown+reloc;
}
}
}
check4resources++;
} /* outer else */
} /* while true */

@ -70,11 +70,12 @@
/* PE from UPX */
int pefromupx (char *src, char *dst, int *dsize, uint32_t ep, uint32_t upx0, uint32_t upx1, uint32_t magic)
int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0, uint32_t upx1, uint32_t magic)
{
char *imports, *sections, *pehdr, *newbuf;
int sectcnt, upd=1, realstuffsz;
int foffset=0xd0+0xf8;
int sectcnt, upd=1;
uint32_t realstuffsz;
uint32_t foffset=0xd0+0xf8;
if((dst == NULL) || (src == NULL))
return 0;
@ -83,17 +84,17 @@ int pefromupx (char *src, char *dst, int *dsize, uint32_t ep, uint32_t upx0, uin
realstuffsz = imports-dst;
if ( realstuffsz < 0 || realstuffsz > *dsize ) {
if (realstuffsz >= *dsize ) {
cli_dbgmsg("UPX: wrong realstuff size - giving up rebuild\n");
return 0;
}
pehdr = imports;
while (pehdr+7 < dst+*dsize && cli_readint32(pehdr)) {
while (CLI_ISCONTAINED(dst, *dsize, pehdr, 8) && cli_readint32(pehdr)) {
pehdr+=8;
while(pehdr+1 < dst+*dsize && *pehdr) {
while(CLI_ISCONTAINED(dst, *dsize, pehdr, 2) && *pehdr) {
pehdr++;
while (pehdr+1 < dst+*dsize && *pehdr)
while (CLI_ISCONTAINED(dst, *dsize, pehdr, 2) && *pehdr)
pehdr++;
pehdr++;
}
@ -101,7 +102,7 @@ int pefromupx (char *src, char *dst, int *dsize, uint32_t ep, uint32_t upx0, uin
}
pehdr+=4;
if (pehdr+0xf8 > dst+*dsize) {
if (!CLI_ISCONTAINED(dst, *dsize, pehdr, 0xf8)) {
cli_dbgmsg("UPX: sections out of bounds - giving up rebuild\n");
return 0;
}
@ -124,7 +125,7 @@ int pefromupx (char *src, char *dst, int *dsize, uint32_t ep, uint32_t upx0, uin
foffset+=0x28*sectcnt;
if (pehdr + 0xf8 + 0x28*sectcnt >= dst + *dsize) {
if (!CLI_ISCONTAINED(dst, *dsize, sections, 0x28*sectcnt)) {
cli_dbgmsg("UPX: Not enough space for all sects - giving up rebuild\n");
return 0;
}
@ -137,7 +138,7 @@ int pefromupx (char *src, char *dst, int *dsize, uint32_t ep, uint32_t upx0, uin
vsize=(((vsize/0x1000)+1)*0x1000); /* FIXME: get bounds from header */
/* Within bounds ? */
if ( urva < upx0 || urva + vsize > upx0 + realstuffsz) {
if (!CLI_ISCONTAINED(upx0, realstuffsz, urva, vsize)) {
cli_dbgmsg("UPX: Sect %d out of bounds - giving up rebuild\n", upd);
return 0;
}
@ -193,26 +194,12 @@ int pefromupx (char *src, char *dst, int *dsize, uint32_t ep, uint32_t upx0, uin
static int doubleebx(char *src, int32_t *myebx, int *scur, int ssize)
{
int32_t oldebx = *myebx;
#if WORDS_BIGENDIAN == 1
char *pt;
int32_t shift, i = 0;
#endif
*myebx*=2;
if ( !(oldebx & 0x7fffffff)) {
if (*scur<0 || ssize-*scur<4)
if (! CLI_ISCONTAINED(src, ssize, src+*scur, 4))
return -1;
#if WORDS_BIGENDIAN == 0
oldebx = *(int*)(src+*scur);
#else
oldebx = 0;
pt = src + *scur;
for(shift = 0; shift < 32; shift += 8) {
oldebx |= (pt[i] & 0xff ) << shift;
i++;
}
#endif
oldebx = cli_readint32(src+*scur);
*myebx = oldebx*2+1;
*scur+=4;
}
@ -221,10 +208,10 @@ static int doubleebx(char *src, int32_t *myebx, int *scur, int ssize)
/* [inflate] */
int upx_inflate2b(char *src, int ssize, char *dst, int *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep)
int upx_inflate2b(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep)
{
int32_t backbytes, unp_offset = -1, myebx = 0;
int scur=0, dcur=0, i, backsize,oob;
int scur=0, dcur=0, i, backsize, oob;
while (1) {
while ((oob = doubleebx(src, &myebx, &scur, ssize)) == 1) {
@ -248,7 +235,7 @@ int upx_inflate2b(char *src, int ssize, char *dst, int *dsize, uint32_t upx0, ui
break;
}
backsize = 0;
backsize = 0;
backbytes-=3;
if ( backbytes >= 0 ) {
@ -282,7 +269,7 @@ int upx_inflate2b(char *src, int ssize, char *dst, int *dsize, uint32_t upx0, ui
backsize+=2;
}
if ( (unsigned int)unp_offset < 0xfffff300 )
if ( (uint32_t)unp_offset < 0xfffff300 )
backsize++;
backsize++;
@ -296,7 +283,7 @@ int upx_inflate2b(char *src, int ssize, char *dst, int *dsize, uint32_t upx0, ui
}
if ( ep - upx1 + 0x108 <= (uint32_t)ssize-5 && /* Wondering how we got so far?! */
if ( ep - upx1 + 0x108 <= ssize-5 && /* Wondering how we got so far?! */
src[ep - upx1 + 0x106] == '\x8d' && /* lea edi, ... */
src[ep - upx1 + 0x107] == '\xbe' ) /* ... [esi + offset] */
return pefromupx (src, dst, dsize, ep, upx0, upx1, 0x108);
@ -305,7 +292,7 @@ int upx_inflate2b(char *src, int ssize, char *dst, int *dsize, uint32_t upx0, ui
return 0;
}
int upx_inflate2d(char *src, int ssize, char *dst, int *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep)
int upx_inflate2d(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep)
{
int32_t backbytes, unp_offset = -1, myebx = 0;
int scur=0, dcur=0, i, backsize, oob;
@ -373,7 +360,7 @@ int upx_inflate2d(char *src, int ssize, char *dst, int *dsize, uint32_t upx0, ui
backsize+=2;
}
if ( (unsigned int)unp_offset < 0xfffffb00 )
if ( (uint32_t)unp_offset < 0xfffffb00 )
backsize++;
backsize++;
@ -385,7 +372,7 @@ int upx_inflate2d(char *src, int ssize, char *dst, int *dsize, uint32_t upx0, ui
dcur+=backsize;
}
if ( ep - upx1 + 0x124 <= (uint32_t)ssize-5 ) { /* Wondering how we got so far?! */
if ( ep - upx1 + 0x124 <= ssize-5 ) { /* Wondering how we got so far?! */
if ( src[ep - upx1 + 0x11a] == '\x8d' && src[ep - upx1 + 0x11b] == '\xbe' )
return pefromupx (src, dst, dsize, ep, upx0, upx1, 0x11c);
if ( src[ep - upx1 + 0x122] == '\x8d' && src[ep - upx1 + 0x123] == '\xbe' )
@ -395,7 +382,7 @@ int upx_inflate2d(char *src, int ssize, char *dst, int *dsize, uint32_t upx0, ui
return 0;
}
int upx_inflate2e(char *src, int ssize, char *dst, int *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep)
int upx_inflate2e(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep)
{
int32_t backbytes, unp_offset = -1, myebx = 0;
int scur=0, dcur=0, i, backsize, oob;
@ -472,7 +459,7 @@ int upx_inflate2e(char *src, int ssize, char *dst, int *dsize, uint32_t upx0, ui
}
}
if ( (unsigned int)unp_offset < 0xfffffb00 )
if ( (uint32_t)unp_offset < 0xfffffb00 )
backsize++;
backsize+=2;
@ -484,7 +471,7 @@ int upx_inflate2e(char *src, int ssize, char *dst, int *dsize, uint32_t upx0, ui
dcur+=backsize;
}
if ( ep - upx1 + 0x130 <= (uint32_t)ssize-5 ) { /* Wondering how we got so far?! */
if ( ep - upx1 + 0x130 <= ssize-5 ) { /* Wondering how we got so far?! */
if ( src[ep - upx1 + 0x126] == '\x8d' && src[ep - upx1 + 0x127] == '\xbe' )
return pefromupx (src, dst, dsize, ep, upx0, upx1, 0x128);
if ( src[ep - upx1 + 0x12e] == '\x8d' && src[ep - upx1 + 0x12f] == '\xbe' )

@ -21,8 +21,8 @@
#include "cltypes.h"
int upx_inflate2b(char *, int, char *, int *, uint32_t, uint32_t, uint32_t);
int upx_inflate2d(char *, int, char *, int *, uint32_t, uint32_t, uint32_t);
int upx_inflate2e(char *, int, char *, int *, uint32_t, uint32_t, uint32_t);
int upx_inflate2b(char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t);
int upx_inflate2d(char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t);
int upx_inflate2e(char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t);
#endif

Loading…
Cancel
Save