libclamav/upx.c
342e27a5
 /*
c442ca9c
  *  Copyright (C) 2013-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
  *  Copyright (C) 2007-2013 Sourcefire, Inc.
2023340a
  *
  *  Authors: Alberto Wu
342e27a5
  *
  *  This program is free software; you can redistribute it and/or modify
632be7ba
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
342e27a5
  *
  *  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
48b7b4a7
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  *  MA 02110-1301, USA.
342e27a5
  */
 
 /*
 ** upxdec.c
 **
 ** 05/05/2k4 - 1st attempt
 ** 08/05/2k4 - Now works as a charm :D
 ** 09/05/2k4 - Moved code outta main(), got rid of globals for thread safety, added bound checking, minor cleaning
 ** 04/06/2k4 - Now we handle 2B, 2D and 2E :D
4a24fe30
 ** 28/08/2k4 - PE rebuild for nested packers
62640917
 ** 12/12/2k4 - Improved PE rebuild code and added some debug info on failure
e70fc970
 ** 23/03/2k7 - New approach for rebuilding:
fbd8fb5b
                o Get imports via magic
                o Get imports via leascan
                o if (!pe) pe=scan4pe();
 	       o if (!pe) forgepe();
 */
 
 /*
342e27a5
 ** This code unpacks a dumped UPX1 section to a file.
 ** It was written reversing the loader found on some Win32 UPX compressed trojans; while porting
 ** it to C i've kinda followed the asm flow so it will probably be a bit hard to read.
 ** This code DOES NOT revert the uncompressed section to its original state as no E8/E9 fixup and
 ** of cause no IAT rebuild are performed.
 **
 ** The Win32 asm unpacker is really a little programming jewel, pretty damn rare in these days of
 ** bloatness. My gratitude to whoever wrote it.
 */
 
a9082ea2
 #if HAVE_CONFIG_H
 #include "clamav-config.h"
 #endif
342e27a5
 
 #include <stdlib.h>
 #include <string.h>
 
60d8d2c3
 #include "clamav.h"
4a24fe30
 #include "others.h"
fc83da82
 #include "upx.h"
fbd8fb5b
 #include "str.h"
f2b223fe
 #include "lzma_iface.h"
4a24fe30
 
57866af1
 #define PEALIGN(o,a) (((a))?(((o)/(a))*(a)):(o))
 #define PESALIGN(o,a) (((a))?(((o)/(a)+((o)%(a)!=0))*(a)):(o))
 
4a24fe30
 #define HEADERS "\
 \x4D\x5A\x90\x00\x02\x00\x00\x00\x04\x00\x0F\x00\xFF\xFF\x00\x00\
 \xB0\x00\x00\x00\x00\x00\x00\x00\x40\x00\x1A\x00\x00\x00\x00\x00\
 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xD0\x00\x00\x00\
 \x0E\x1F\xB4\x09\xBA\x0D\x00\xCD\x21\xB4\x4C\xCD\x21\x54\x68\x69\
 \x73\x20\x66\x69\x6C\x65\x20\x77\x61\x73\x20\x63\x72\x65\x61\x74\
 \x65\x64\x20\x62\x79\x20\x43\x6C\x61\x6D\x41\x56\x20\x66\x6F\x72\
 \x20\x69\x6E\x74\x65\x72\x6E\x61\x6C\x20\x75\x73\x65\x20\x61\x6E\
 \x64\x20\x73\x68\x6F\x75\x6C\x64\x20\x6E\x6F\x74\x20\x62\x65\x20\
 \x72\x75\x6E\x2E\x0D\x0A\x43\x6C\x61\x6D\x41\x56\x20\x2D\x20\x41\
 \x20\x47\x50\x4C\x20\x76\x69\x72\x75\x73\x20\x73\x63\x61\x6E\x6E\
 \x65\x72\x20\x2D\x20\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\
 \x63\x6C\x61\x6D\x61\x76\x2E\x6E\x65\x74\x0D\x0A\x24\x00\x00\x00\
 "
a85e56eb
 #define FAKEPE "\
 \x50\x45\x00\x00\x4C\x01\x01\x00\x43\x4C\x41\x4D\x00\x00\x00\x00\
 \x00\x00\x00\x00\xE0\x00\x83\x8F\x0B\x01\x00\x00\x00\x10\x00\x00\
 \x00\x10\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x10\x00\x00\
 \x00\x10\x00\x00\x00\x00\x40\x00\x00\x10\x00\x00\x00\x02\x00\x00\
 \x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x0A\x00\x00\x00\x00\x00\
 \xFF\xFF\xFF\xFF\x00\x02\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\
 \x00\x00\x10\x00\x00\x10\x00\x00\x00\x00\x10\x00\x00\x10\x00\x00\
 \x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
 \x00\x00\x00\x00\x00\x00\x00\x00\x2e\x63\x6c\x61\x6d\x30\x31\x00\
 \xFF\xFF\xFF\xFF\x00\x10\x00\x00\xFF\xFF\xFF\xFF\x00\x02\x00\x00\
 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\
 "
4a24fe30
 
fb5cb257
 static char *checkpe(char *dst, uint32_t dsize, char *pehdr, uint32_t *valign, unsigned int *sectcnt)
 {
e70fc970
   char *sections;
fb5cb257
   if (!CLI_ISCONTAINED(dst, dsize,  pehdr, 0xf8)) return NULL;
 
   if (cli_readint32(pehdr) != 0x4550 ) return NULL;
ad590a71
 
fb5cb257
   if (!(*valign=cli_readint32(pehdr+0x38))) return NULL;
ad590a71
 
e70fc970
   sections = pehdr+0xf8;
fb5cb257
   if (!(*sectcnt = (unsigned char)pehdr[6] + (unsigned char)pehdr[7]*256)) return NULL;
ad590a71
 
fb5cb257
   if (!CLI_ISCONTAINED(dst, dsize, sections, *sectcnt*0x28)) return NULL;
 
e70fc970
   return sections;
 }
 
4a24fe30
 /* PE from UPX */
 
f304dc68
 static int pefromupx (const char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0, uint32_t upx1, uint32_t *magic, uint32_t dend)
4a24fe30
 {
5cd3f734
   char *imports, *sections=NULL, *pehdr=NULL, *newbuf;
fbd8fb5b
   unsigned int sectcnt=0, upd=1;
fb5cb257
   uint32_t realstuffsz=0, valign=0;
dddbbad7
   uint32_t foffset=0xd0+0xf8;
4a24fe30
 
96c6f74b
   if((dst == NULL) || (src == NULL))
     return 0;
 
fbd8fb5b
   while ((valign=magic[sectcnt++])) {
1d7231d3
     if (CLI_ISCONTAINED(src, ssize - 5, src + ep - upx1 + valign - 2, 2) &&
fbd8fb5b
 	 src[ep - upx1 + valign - 2] == '\x8d' && /* lea edi, ...                  */
 	 src[ep - upx1 + valign - 1] == '\xbe' )  /* ... [esi + offset]          */
       break;
   }
4a24fe30
 
1d7231d3
   if (!valign && CLI_ISCONTAINED(src, ssize - 8, src + ep - upx1 + 0x80, 8)) {
5cd3f734
     const char *pt = &src[ep - upx1 + 0x80];
fbd8fb5b
     cli_dbgmsg("UPX: bad magic - scanning for imports\n");
ad590a71
 
5cd3f734
     while ((pt=cli_memstr(pt, ssize - (pt-src) - 8, "\x8d\xbe", 2))) {
fbd8fb5b
       if (pt[6] == '\x8b' && pt[7] == '\x07') { /* lea edi, [esi+imports] / mov eax, [edi] */
 	valign=pt-src+2-ep+upx1;
 	break;
       }
       pt++;
     }
62640917
   }
fbd8fb5b
 
   if (valign && CLI_ISCONTAINED(src, ssize, src + ep - upx1 + valign, 4)) {
     imports = dst + cli_readint32(src + ep - upx1 + valign);
ad590a71
 
fbd8fb5b
     realstuffsz = imports-dst;
ad590a71
 
fbd8fb5b
     if (realstuffsz >= *dsize ) {
e70fc970
       cli_dbgmsg("UPX: wrong realstuff size\n");
       /* fallback and eventually craft */
     } else {
       pehdr = imports;
       while (CLI_ISCONTAINED(dst, *dsize,  pehdr, 8) && cli_readint32(pehdr)) {
 	pehdr+=8;
 	while(CLI_ISCONTAINED(dst, *dsize,  pehdr, 2) && *pehdr) {
fbd8fb5b
 	  pehdr++;
e70fc970
 	  while (CLI_ISCONTAINED(dst, *dsize,  pehdr, 2) && *pehdr)
 	    pehdr++;
 	  pehdr++;
 	}
4a24fe30
 	pehdr++;
fbd8fb5b
       }
ad590a71
 
e70fc970
       pehdr+=4;
       if (!(sections=checkpe(dst, *dsize, pehdr, &valign, &sectcnt))) pehdr=NULL;
4a24fe30
     }
   }
 
e70fc970
   if (!pehdr && dend>0xf8+0x28) {
     cli_dbgmsg("UPX: no luck - scanning for PE\n");
     pehdr = &dst[dend-0xf8-0x28];
a85e56eb
     while (pehdr>dst) {
e70fc970
       if ((sections=checkpe(dst, *dsize, pehdr, &valign, &sectcnt)))
 	break;
       pehdr--;
     }
fb5cb257
     if (!(realstuffsz = pehdr-dst)) pehdr=NULL;
62640917
   }
e70fc970
 
   if (!pehdr) {
a85e56eb
     uint32_t rebsz = PESALIGN(dend, 0x1000);
7cd9337a
     cli_dbgmsg("UPX: no luck - brutally crafting a reasonable PE\n");
a85e56eb
     if (!(newbuf = (char *)cli_calloc(rebsz+0x200, sizeof(char)))) {
       cli_dbgmsg("UPX: malloc failed - giving up rebuild\n");
       return 0;
     }
     memcpy(newbuf, HEADERS, 0xd0);
     memcpy(newbuf+0xd0, FAKEPE, 0x120);
     memcpy(newbuf+0x200, dst, dend);
     memcpy(dst, newbuf, dend+0x200);
     free(newbuf);
     cli_writeint32(dst+0xd0+0x50, rebsz+0x1000);
     cli_writeint32(dst+0xd0+0x100, rebsz);
     cli_writeint32(dst+0xd0+0x108, rebsz);
     *dsize=rebsz+0x200;
     cli_dbgmsg("UPX: PE structure added to uncompressed data\n");
     return 1;
62640917
   }
416ee422
 
   if (!sections)
     sectcnt = 0;
57866af1
   foffset = PESALIGN(foffset+0x28*sectcnt, valign);
ad590a71
 
4a24fe30
   for (upd = 0; upd <sectcnt ; upd++) {
1027f3e1
     uint32_t vsize=PESALIGN((uint32_t)cli_readint32(sections+8), valign);
     uint32_t urva=PEALIGN((uint32_t)cli_readint32(sections+12), valign);
ad590a71
 
4a24fe30
     /* Within bounds ? */
dddbbad7
     if (!CLI_ISCONTAINED(upx0, realstuffsz, urva, vsize)) {
62640917
       cli_dbgmsg("UPX: Sect %d out of bounds - giving up rebuild\n", upd);
4a24fe30
       return 0;
62640917
     }
ad590a71
 
4a24fe30
     cli_writeint32(sections+8, vsize);
57866af1
     cli_writeint32(sections+12, urva);
     cli_writeint32(sections+16, vsize);
4a24fe30
     cli_writeint32(sections+20, foffset);
89b2d2dc
     if (foffset + vsize < foffset) {
         /* Integer overflow */
         return 0;
     }
57866af1
     foffset+=vsize;
ad590a71
 
4a24fe30
     sections+=0x28;
   }
 
   cli_writeint32(pehdr+8, 0x4d414c43);
57866af1
   cli_writeint32(pehdr+0x3c, valign);
4a24fe30
 
57866af1
   if (!(newbuf = (char *) cli_calloc(foffset, sizeof(char)))) {
e4804cde
     cli_dbgmsg("UPX: malloc failed - giving up rebuild\n");
4a24fe30
     return 0;
62640917
   }
ad590a71
 
4a24fe30
   memcpy(newbuf, HEADERS, 0xd0);
   memcpy(newbuf+0xd0, pehdr,0xf8+0x28*sectcnt);
   sections = pehdr+0xf8;
   for (upd = 0; upd <sectcnt ; upd++) {
f1275fb0
       uint32_t offset1, offset2, offset3;
       offset1 = (uint32_t)cli_readint32(sections+20);
       offset2 = (uint32_t)cli_readint32(sections+16);
58ca7ee2
       if (offset1 > foffset || offset2 > foffset || offset1 + offset2 > foffset) {
           free(newbuf);
           return 1;
       }
 
f1275fb0
       offset3 = (uint32_t)cli_readint32(sections+12);
58ca7ee2
       if (offset3-upx0 > *dsize) {
           free(newbuf);
           return 1;
       }
     memcpy(newbuf+offset1, dst+offset3-upx0, offset2);
4a24fe30
     sections+=0x28;
   }
 
   /* CBA restoring the imports they'll look different from the originals anyway... */
   /* ...and yeap i miss the icon too :P */
 
57866af1
   if (foffset > *dsize + 8192) {
9907dae1
     cli_dbgmsg("UPX: wrong raw size - giving up rebuild\n");
1ff5f3b8
     free(newbuf);
9907dae1
     return 0;
   }
4a24fe30
   memcpy(dst, newbuf, foffset);
   *dsize = foffset;
   free(newbuf);
 
   cli_dbgmsg("UPX: PE structure rebuilt from compressed file\n");
   return 1;
 }
 
a9082ea2
 
342e27a5
 /* [doubleebx] */
 
f304dc68
 static int doubleebx(const char *src, uint32_t *myebx, uint32_t *scur, uint32_t ssize)
342e27a5
 {
1027f3e1
   uint32_t oldebx = *myebx;
342e27a5
 
   *myebx*=2;
   if ( !(oldebx & 0x7fffffff)) {
dddbbad7
     if (! CLI_ISCONTAINED(src, ssize, src+*scur, 4))
7f3c1d03
       return -1;
343316ab
     oldebx = cli_readint32(src+*scur);
342e27a5
     *myebx = oldebx*2+1;
     *scur+=4;
   }
1027f3e1
   return (oldebx>>31);
342e27a5
 }
 
 /* [inflate] */
 
f304dc68
 int upx_inflate2b(const char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep)
342e27a5
 {
1027f3e1
   int32_t backbytes, unp_offset = -1;
696fdd17
   uint32_t backsize, myebx = 0, scur=0, dcur=0, i, magic[]={0x108,0x110,0xd5,0};
1027f3e1
   int oob;
ad590a71
 
342e27a5
   while (1) {
7f3c1d03
     while ((oob = doubleebx(src, &myebx, &scur, ssize)) == 1) {
1027f3e1
       if (scur>=ssize || dcur>=*dsize)
342e27a5
 	return -1;
       dst[dcur++] = src[scur++];
     }
 
7f3c1d03
     if ( oob == -1 )
       return -1;
ad590a71
 
342e27a5
     backbytes = 1;
 
     while (1) {
7f3c1d03
       if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
         return -1;
40c0b110
       if (((int64_t) backbytes + oob ) > INT32_MAX / 2)
         return -1;
7f3c1d03
       backbytes = backbytes*2+oob;
       if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
 	return -1;
       if (oob)
         break;
342e27a5
     }
 
     backbytes-=3;
ad590a71
 
342e27a5
     if ( backbytes >= 0 ) {
 
1027f3e1
       if (scur>=ssize)
342e27a5
 	return -1;
a4757f4a
             if (backbytes & 0xff000000)
                 return -1;
342e27a5
       backbytes<<=8;
       backbytes+=(unsigned char)(src[scur++]);
       backbytes^=0xffffffff;
 
       if (!backbytes)
 	break;
       unp_offset = backbytes;
     }
 
1027f3e1
     if ( (backsize = (uint32_t)doubleebx(src, &myebx, &scur, ssize)) == 0xffffffff)
7f3c1d03
       return -1;
     if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
       return -1;
a4757f4a
         if (backsize + oob > UINT32_MAX / 2)
             return -1;
7f3c1d03
     backsize = backsize*2 + oob;
342e27a5
     if (!backsize) {
       backsize++;
       do {
7f3c1d03
         if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
           return -1;
a4757f4a
                 if (backsize + oob > UINT32_MAX / 2)
                     return -1;
7f3c1d03
 	backsize = backsize*2 + oob;
       } while ((oob = doubleebx(src, &myebx, &scur, ssize)) == 0);
       if ( oob == -1 )
         return -1;
a4757f4a
             if (backsize + 2 > UINT32_MAX)
                 return -1;
342e27a5
       backsize+=2;
     }
 
dddbbad7
     if ( (uint32_t)unp_offset < 0xfffff300 )
342e27a5
       backsize++;
 
     backsize++;
a9082ea2
 
1027f3e1
     if (!CLI_ISCONTAINED(dst, *dsize, dst+dcur+unp_offset, backsize) || !CLI_ISCONTAINED(dst, *dsize, dst+dcur, backsize) || unp_offset >=0)
       return -1;
     for (i = 0; i < backsize; i++)
342e27a5
       dst[dcur + i] = dst[dcur + unp_offset + i];
     dcur+=backsize;
   }
4a24fe30
 
e70fc970
   return pefromupx (src, ssize, dst, dsize, ep, upx0, upx1, magic, dcur);
342e27a5
 }
 
f304dc68
 int upx_inflate2d(const char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep)
342e27a5
 {
1027f3e1
   int32_t backbytes, unp_offset = -1;
fbd8fb5b
   uint32_t backsize, myebx = 0, scur=0, dcur=0, i, magic[]={0x11c,0x124,0};
1027f3e1
   int oob;
342e27a5
 
   while (1) {
7f3c1d03
     while ( (oob = doubleebx(src, &myebx, &scur, ssize)) == 1) {
1027f3e1
       if (scur>=ssize || dcur>=*dsize)
342e27a5
 	return -1;
       dst[dcur++] = src[scur++];
     }
 
7f3c1d03
     if ( oob == -1 )
       return -1;
 
342e27a5
     backbytes = 1;
 
     while (1) {
7f3c1d03
       if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
         return -1;
40c0b110
       if (((int64_t) backbytes + oob ) > INT32_MAX / 2)
         return -1;
7f3c1d03
       backbytes = backbytes*2+oob;
       if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
         return -1;
       if (oob)
342e27a5
 	break;
       backbytes--;
7f3c1d03
       if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
         return -1;
40c0b110
       if (((int64_t) backbytes + oob ) > INT32_MAX / 2)
         return -1;
7f3c1d03
       backbytes=backbytes*2+oob;
342e27a5
     }
 
7f3c1d03
     backsize = 0;
342e27a5
     backbytes-=3;
ad590a71
 
342e27a5
     if ( backbytes >= 0 ) {
 
1027f3e1
       if (scur>=ssize)
342e27a5
 	return -1;
a4757f4a
             if (backbytes & 0xff000000)
                 return -1;
342e27a5
       backbytes<<=8;
       backbytes+=(unsigned char)(src[scur++]);
       backbytes^=0xffffffff;
 
       if (!backbytes)
 	break;
       backsize = backbytes & 1;
adc98193
       CLI_SAR(backbytes,1);
342e27a5
       unp_offset = backbytes;
1027f3e1
     } else {
       if ( (backsize = (uint32_t)doubleebx(src, &myebx, &scur, ssize)) == 0xffffffff )
7f3c1d03
         return -1;
     }
ad590a71
 
7f3c1d03
     if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
       return -1;
a4757f4a
         if (backsize + oob > UINT32_MAX / 2)
             return -1;
7f3c1d03
     backsize = backsize*2 + oob;
342e27a5
     if (!backsize) {
       backsize++;
       do {
7f3c1d03
         if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
           return -1;
a4757f4a
                 if (backsize + oob > UINT32_MAX / 2)
                     return -1;
7f3c1d03
 	backsize = backsize*2 + oob;
       } while ( (oob = doubleebx(src, &myebx, &scur, ssize)) == 0);
       if ( oob == -1 )
         return -1;
a4757f4a
             if (backsize + 2 > UINT32_MAX)
                 return -1;
342e27a5
       backsize+=2;
     }
 
ad590a71
     if ( (uint32_t)unp_offset < 0xfffffb00 )
342e27a5
       backsize++;
 
     backsize++;
1027f3e1
     if (!CLI_ISCONTAINED(dst, *dsize, dst+dcur+unp_offset, backsize) || !CLI_ISCONTAINED(dst, *dsize, dst+dcur, backsize) || unp_offset >=0 )
       return -1;
     for (i = 0; i < backsize; i++)
342e27a5
       dst[dcur + i] = dst[dcur + unp_offset + i];
     dcur+=backsize;
   }
4a24fe30
 
e70fc970
   return pefromupx (src, ssize, dst, dsize, ep, upx0, upx1, magic, dcur);
342e27a5
 }
 
f304dc68
 int upx_inflate2e(const char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep)
342e27a5
 {
1027f3e1
   int32_t backbytes, unp_offset = -1;
fbd8fb5b
   uint32_t backsize, myebx = 0, scur=0, dcur=0, i, magic[]={0x128,0x130,0};
1027f3e1
   int oob;
342e27a5
 
82fafc19
   for(;;) {
7f3c1d03
     while ( (oob = doubleebx(src, &myebx, &scur, ssize)) ) {
       if (oob == -1)
         return -1;
1027f3e1
       if (scur>=ssize || dcur>=*dsize)
342e27a5
 	return -1;
       dst[dcur++] = src[scur++];
     }
 
     backbytes = 1;
 
82fafc19
     for(;;) {
7f3c1d03
       if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
         return -1;
40c0b110
       if (((int64_t) backbytes + oob ) > INT32_MAX / 2)
         return -1;
7f3c1d03
       backbytes = backbytes*2+oob;
       if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
         return -1;
       if ( oob )
342e27a5
 	break;
       backbytes--;
7f3c1d03
       if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
         return -1;
40c0b110
       if (((int64_t) backbytes + oob ) > INT32_MAX / 2)
         return -1;
7f3c1d03
       backbytes=backbytes*2+oob;
342e27a5
     }
 
     backbytes-=3;
ad590a71
 
342e27a5
     if ( backbytes >= 0 ) {
 
1027f3e1
       if (scur>=ssize)
342e27a5
 	return -1;
a4757f4a
             if (backbytes & 0xff000000)
                 return -1;
342e27a5
       backbytes<<=8;
       backbytes+=(unsigned char)(src[scur++]);
       backbytes^=0xffffffff;
 
       if (!backbytes)
 	break;
       backsize = backbytes & 1; /* Using backsize to carry on the shifted out bit (UPX uses CF) */
adc98193
       CLI_SAR(backbytes,1);
342e27a5
       unp_offset = backbytes;
1027f3e1
     } else {
       if ( (backsize = (uint32_t)doubleebx(src, &myebx, &scur, ssize)) == 0xffffffff )
7f3c1d03
         return -1;
     } /* Using backsize to carry on the doubleebx result (UPX uses CF) */
342e27a5
 
     if (backsize) { /* i.e. IF ( last sar shifted out 1 bit || last doubleebx()==1 ) */
1027f3e1
       if ( (backsize = (uint32_t)doubleebx(src, &myebx, &scur, ssize)) == 0xffffffff )
7f3c1d03
         return -1;
1027f3e1
     } else {
342e27a5
       backsize = 1;
7f3c1d03
       if ((oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
         return -1;
       if (oob) {
 	if ((oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
 	  return -1;
a4757f4a
                 if (backsize + oob > UINT32_MAX / 2)
                     return -1;
7f3c1d03
 	  backsize = 2 + oob;
1027f3e1
 	} else {
 	  do {
 	    if ((oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
 	      return -1;
a4757f4a
                     if (backsize + oob > UINT32_MAX / 2)
                         return -1;
1027f3e1
 	    backsize = backsize * 2 + oob;
 	  } while ((oob = doubleebx(src, &myebx, &scur, ssize)) == 0);
 	  if (oob == -1)
 	    return -1;
a4757f4a
                 if (backsize + 2 > UINT32_MAX)
                     return -1;
1027f3e1
 	  backsize+=2;
7f3c1d03
 	}
342e27a5
     }
ad590a71
 
     if ( (uint32_t)unp_offset < 0xfffffb00 )
342e27a5
       backsize++;
 
a4757f4a
         if (backsize + 2 > UINT32_MAX)
             return -1;
342e27a5
     backsize+=2;
1027f3e1
 
     if (!CLI_ISCONTAINED(dst, *dsize, dst+dcur+unp_offset, backsize) || !CLI_ISCONTAINED(dst, *dsize, dst+dcur, backsize) || unp_offset >=0 )
       return -1;
     for (i = 0; i < backsize; i++)
342e27a5
       dst[dcur + i] = dst[dcur + unp_offset + i];
     dcur+=backsize;
   }
4a24fe30
 
e70fc970
   return pefromupx (src, ssize, dst, dsize, ep, upx0, upx1, magic, dcur);
342e27a5
 }
f2b223fe
 
1c6bead7
 int upx_inflatelzma(const char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep, uint32_t properties) {
87787e76
   struct CLI_LZMA l;
f2b223fe
   uint32_t magic[]={0xb16,0xb1e,0};
03d44bbf
   unsigned char fake_lzmahdr[5];
f2b223fe
 
87787e76
   memset(&l, 0, sizeof(l));
03d44bbf
   cli_writeint32(fake_lzmahdr + 1, *dsize);
1c6bead7
   uint8_t lc = properties & 0xff;
8bd189e3
   uint8_t lp = (properties >> 8) & 0xff;
ad590a71
   uint8_t pb = (properties >> 16) & 0xff;
8bd189e3
   if (lc >= 9 || lp >= 5 || pb >= 5)
       return -1;
1c6bead7
 
8bd189e3
   *fake_lzmahdr = lc + 9* ( 5* pb + lp);
03d44bbf
   l.next_in = fake_lzmahdr;
   l.avail_in = 5;
   if(cli_LzmaInit(&l, *dsize) != LZMA_RESULT_OK)
       return 0;
   l.avail_in = ssize;
   l.avail_out = *dsize;
   l.next_in = (unsigned char*)src+2;
   l.next_out = (unsigned char*)dst;
f2b223fe
 
87787e76
   if(cli_LzmaDecode(&l)==LZMA_RESULT_DATA_ERROR) {
f2b223fe
 /*     __asm__ __volatile__("int3"); */
87787e76
     cli_LzmaShutdown(&l);
f2b223fe
     return -1;
   }
87787e76
   cli_LzmaShutdown(&l);
f2b223fe
 
   return pefromupx (src, ssize, dst, dsize, ep, upx0, upx1, magic, *dsize);
 }