UPX decompression

git-svn: trunk@601
This commit is contained in:
Tomasz Kojm 2004-06-12 00:16:01 +00:00
parent ac75a532b4
commit 342e27a516
6 changed files with 429 additions and 27 deletions

View file

@ -1,3 +1,11 @@
Sat Jun 12 02:11:12 CEST 2004 (tk)
----------------------------------
* libclamav: pe: integrate with UPX decompressor from aCaB <acab*clamav.net>
(with support for NRV2B, NRV2D and NRV2E compression).
To protect against compressed files with hacked headers,
the PE parser tries to find a signature of the UPX
decompression routine at EP + 0x78.
Fri Jun 11 22:11:31 CEST 2004 (tk) Fri Jun 11 22:11:31 CEST 2004 (tk)
---------------------------------- ----------------------------------
* libclamav: pe: add dumper; RVA calculation; fix error codes * libclamav: pe: add dumper; RVA calculation; fix error codes

View file

@ -94,6 +94,8 @@ libclamav_la_SOURCES = \
mspack/qtmd.c \ mspack/qtmd.c \
mspack/qtm.h \ mspack/qtm.h \
mspack/system.c \ mspack/system.c \
mspack/system.h mspack/system.h \
upx.c \
upx.h
lib_LTLIBRARIES = libclamav.la lib_LTLIBRARIES = libclamav.la

View file

@ -1,4 +1,4 @@
# Makefile.in generated by automake 1.6.3 from Makefile.am. # Makefile.in generated by automake 1.6.1 from Makefile.am.
# @configure_input@ # @configure_input@
# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 # Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
@ -66,7 +66,6 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@ INSTALL_DATA = @INSTALL_DATA@
install_sh_DATA = $(install_sh) -c -m 644 install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_HEADER = $(INSTALL_DATA) INSTALL_HEADER = $(INSTALL_DATA)
transform = @program_transform_name@ transform = @program_transform_name@
@ -196,7 +195,9 @@ libclamav_la_SOURCES = \
mspack/qtmd.c \ mspack/qtmd.c \
mspack/qtm.h \ mspack/qtm.h \
mspack/system.c \ mspack/system.c \
mspack/system.h mspack/system.h \
upx.c \
upx.h
lib_LTLIBRARIES = libclamav.la lib_LTLIBRARIES = libclamav.la
@ -212,7 +213,7 @@ am_libclamav_la_OBJECTS = matcher.lo md5.lo others.lo readdb.lo cvd.lo \
zzip-file.lo zzip-info.lo zzip-io.lo zzip-stat.lo zzip-zip.lo \ zzip-file.lo zzip-info.lo zzip-io.lo zzip-stat.lo zzip-zip.lo \
strc.lo blob.lo mbox.lo message.lo snprintf.lo strrcpy.lo \ strc.lo blob.lo mbox.lo message.lo snprintf.lo strrcpy.lo \
table.lo text.lo ole2_extract.lo vba_extract.lo msexpand.lo \ table.lo text.lo ole2_extract.lo vba_extract.lo msexpand.lo \
pe.lo cabd.lo lzxd.lo mszipd.lo qtmd.lo system.lo pe.lo cabd.lo lzxd.lo mszipd.lo qtmd.lo system.lo upx.lo
libclamav_la_OBJECTS = $(am_libclamav_la_OBJECTS) libclamav_la_OBJECTS = $(am_libclamav_la_OBJECTS)
DEFS = @DEFS@ DEFS = @DEFS@
@ -234,7 +235,7 @@ am__depfiles_maybe = depfiles
@AMDEP_TRUE@ ./$(DEPDIR)/str.Plo ./$(DEPDIR)/strc.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/str.Plo ./$(DEPDIR)/strc.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/strrcpy.Plo ./$(DEPDIR)/system.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/strrcpy.Plo ./$(DEPDIR)/system.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/table.Plo ./$(DEPDIR)/text.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/table.Plo ./$(DEPDIR)/text.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/unrarlib.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/unrarlib.Plo ./$(DEPDIR)/upx.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/vba_extract.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/vba_extract.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/zzip-dir.Plo ./$(DEPDIR)/zzip-err.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/zzip-dir.Plo ./$(DEPDIR)/zzip-err.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/zzip-file.Plo ./$(DEPDIR)/zzip-info.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/zzip-file.Plo ./$(DEPDIR)/zzip-info.Plo \
@ -285,12 +286,6 @@ uninstall-libLTLIBRARIES:
clean-libLTLIBRARIES: clean-libLTLIBRARIES:
-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
test -z "$dir" && dir=.; \
echo "rm -f \"$${dir}/so_locations\""; \
rm -f "$${dir}/so_locations"; \
done
zzip-dir.lo: zziplib/zzip-dir.c zzip-dir.lo: zziplib/zzip-dir.c
zzip-err.lo: zziplib/zzip-err.c zzip-err.lo: zziplib/zzip-err.c
zzip-file.lo: zziplib/zzip-file.c zzip-file.lo: zziplib/zzip-file.c
@ -338,6 +333,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/table.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/table.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/text.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/text.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unrarlib.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unrarlib.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upx.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vba_extract.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vba_extract.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zzip-dir.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zzip-dir.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zzip-err.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zzip-err.Plo@am__quote@
@ -672,7 +668,7 @@ top_distdir = ..
distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
distdir: $(DISTFILES) distdir: $(DISTFILES)
@list='$(DISTFILES)'; for file in $$list; do \ @for file in $(DISTFILES); do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
if test "$$dir" != "$$file" && test "$$dir" != "."; then \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
@ -718,7 +714,7 @@ mostlyclean-generic:
clean-generic: clean-generic:
distclean-generic: distclean-generic:
-rm -f Makefile $(CONFIG_CLEAN_FILES) -rm -f Makefile $(CONFIG_CLEAN_FILES) stamp-h stamp-h[0-9]*
maintainer-clean-generic: maintainer-clean-generic:
@echo "This command is intended for maintainers to use" @echo "This command is intended for maintainers to use"

View file

@ -35,11 +35,16 @@
#include "cltypes.h" #include "cltypes.h"
#include "clamav.h" #include "clamav.h"
#include "others.h" #include "others.h"
#include "upx.h"
#define IMAGE_DOS_SIGNATURE 0x5a4d /* MZ */ #define IMAGE_DOS_SIGNATURE 0x5a4d /* MZ */
#define IMAGE_NT_SIGNATURE 0x00004550 #define IMAGE_NT_SIGNATURE 0x00004550
#define IMAGE_OPTIONAL_SIGNATURE 0x010b #define IMAGE_OPTIONAL_SIGNATURE 0x010b
#define UPX_NRV2B "\x11\xc9\x75\x20\x41\x01\xdb\x75\x07\x8b\x1e\x83\xee\xfc\x11\xdb\x11\xc9\x01\xdb\x73\xef\x75\x09"
#define UPX_NRV2D "\x8b\x1e\x83\xee\xfc\x11\xdb\x11\xc9\x01\xdb\x75\x07\x8b\x1e\x83\xee\xfc\x11\xdb\x11\xc9\x75\x20"
#define UPX_NRV2E "\x83\xf0\xff\x74\x75\xd1\xf8\x89\xc5\xeb\x0b\x01\xdb\x75\x07\x8b\x1e\x83\xee\xfc\x11\xdb\x72\xcc"
struct pe_image_file_hdr { struct pe_image_file_hdr {
uint32_t Magic; uint32_t Magic;
uint16_t Machine; uint16_t Machine;
@ -109,7 +114,6 @@ struct pe_image_section_hdr {
uint32_t Characteristics; uint32_t Characteristics;
}; };
static uint32_t cli_rawaddr(uint32_t rva, struct pe_image_section_hdr *shp, uint16_t nos) static uint32_t cli_rawaddr(uint32_t rva, struct pe_image_section_hdr *shp, uint16_t nos)
{ {
int i, found = 0; int i, found = 0;
@ -140,19 +144,19 @@ static int cli_ddump(int desc, int offset, int size, const char *file)
if((pos = lseek(desc, 0, SEEK_CUR)) == -1) { if((pos = lseek(desc, 0, SEEK_CUR)) == -1) {
cli_dbgmsg("Invalid descriptor\n"); cli_dbgmsg("Invalid descriptor\n");
return -1; return CL_EIO;
} }
if(lseek(desc, offset, SEEK_SET) == -1) { if(lseek(desc, offset, SEEK_SET) == -1) {
cli_dbgmsg("lseek() failed\n"); cli_dbgmsg("lseek() failed\n");
lseek(desc, pos, SEEK_SET); lseek(desc, pos, SEEK_SET);
return -1; return CL_EIO;
} }
if((ndesc = open(file, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU)) < 0) { if((ndesc = open(file, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU)) < 0) {
cli_dbgmsg("Can't create file %s\n", file); cli_dbgmsg("Can't create file %s\n", file);
lseek(desc, pos, SEEK_SET); lseek(desc, pos, SEEK_SET);
return -1; return CL_EIO;
} }
while((bread = read(desc, buff, FILEBUFF)) > 0) { while((bread = read(desc, buff, FILEBUFF)) > 0) {
@ -162,7 +166,7 @@ static int cli_ddump(int desc, int offset, int size, const char *file)
lseek(desc, pos, SEEK_SET); lseek(desc, pos, SEEK_SET);
close(ndesc); close(ndesc);
unlink(file); unlink(file);
return -1; return CL_EIO;
} }
break; break;
} else { } else {
@ -171,7 +175,7 @@ static int cli_ddump(int desc, int offset, int size, const char *file)
lseek(desc, pos, SEEK_SET); lseek(desc, pos, SEEK_SET);
close(ndesc); close(ndesc);
unlink(file); unlink(file);
return -1; return CL_EIO;
} }
} }
sum += bread; sum += bread;
@ -191,8 +195,9 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
struct pe_image_optional_hdr optional_hdr; struct pe_image_optional_hdr optional_hdr;
struct pe_image_section_hdr *section_hdr; struct pe_image_section_hdr *section_hdr;
struct stat sb; struct stat sb;
char sname[9]; char sname[9], buff[24], *tempfile;
int i; int i, found;
int (*upxfn)(char *, int , char *, int) = NULL;
if(read(desc, &e_magic, sizeof(e_magic)) != sizeof(e_magic)) { if(read(desc, &e_magic, sizeof(e_magic)) != sizeof(e_magic)) {
@ -321,8 +326,9 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
if(read(desc, &section_hdr[i], sizeof(struct pe_image_section_hdr)) != sizeof(struct pe_image_section_hdr)) { if(read(desc, &section_hdr[i], sizeof(struct pe_image_section_hdr)) != sizeof(struct pe_image_section_hdr)) {
cli_dbgmsg("Can't read section header\n"); cli_dbgmsg("Can't read section header\n");
cli_warnmsg("Possibly broken PE file\n");
free(section_hdr); free(section_hdr);
return -1; return CL_CLEAN;
} }
strncpy(sname, section_hdr[i].Name, 8); strncpy(sname, section_hdr[i].Name, 8);
@ -364,7 +370,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
if(fstat(desc, &sb) == -1) { if(fstat(desc, &sb) == -1) {
cli_dbgmsg("fstat failed\n"); cli_dbgmsg("fstat failed\n");
free(section_hdr); free(section_hdr);
return -1; return CL_EIO;
} }
ep = cli_rawaddr(optional_hdr.AddressOfEntryPoint, section_hdr, file_hdr.NumberOfSections); ep = cli_rawaddr(optional_hdr.AddressOfEntryPoint, section_hdr, file_hdr.NumberOfSections);
@ -372,13 +378,114 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
if(section_hdr[i].PointerToRawData + section_hdr[i].SizeOfRawData > sb.st_size || ep == -1) { if(section_hdr[i].PointerToRawData + section_hdr[i].SizeOfRawData > sb.st_size || ep == -1) {
cli_warnmsg("Possibly broken PE file\n"); cli_warnmsg("Possibly broken PE file\n");
free(section_hdr); free(section_hdr);
return -1; return CL_CLEAN;
} }
cli_dbgmsg("EntryPoint: 0x%x (%d)\n", ep, ep); cli_dbgmsg("EntryPoint offset: 0x%x (%d)\n", ep, ep);
if(lseek(desc, ep + 0x78, SEEK_SET) == -1) {
cli_dbgmsg("lseek() failed\n");
free(section_hdr);
return CL_EIO;
}
if(read(desc, buff, 24) != 24) {
cli_dbgmsg("Can't read 24 bytes at 0x%x (%d)\n", ep + 0x78, ep + 0x78);
} else {
if(!memcmp(buff, UPX_NRV2B, 24)) {
cli_dbgmsg("UPX: NRV2B decompressor detected\n");
upxfn = upx_inflate2b;
} else if(!memcmp(buff, UPX_NRV2D, 24)) {
cli_dbgmsg("UPX: NRV2D decompressor detected\n");
upxfn = upx_inflate2d;
} else if(!memcmp(buff, UPX_NRV2E, 24)) {
cli_dbgmsg("UPX: NRV2E decompressor detected\n");
upxfn = upx_inflate2e;
}
}
if(upxfn) {
/* try to find the first section with physical size == 0 */
found = 0;
for(i = 0; i < file_hdr.NumberOfSections; i++) {
if(!section_hdr[i].SizeOfRawData) {
found = 1;
break;
}
}
if(found) {
uint32_t ssize, dsize;
char *src, *dest;
/* we assume (i + 1) is UPX1 */
if(strncmp(section_hdr[i].Name, "UPX0", 4) || strncmp(section_hdr[i + 1].Name, "UPX1", 4))
cli_dbgmsg("Possibly hacked UPX section headers\n");
/* FIXME: use file operations in case of big files */
ssize = section_hdr[i + 1].SizeOfRawData;
dsize = section_hdr[i].VirtualSize + section_hdr[i + 1].VirtualSize;
if((src = (char *) malloc(ssize)) == NULL) {
free(section_hdr);
return CL_EMEM;
}
if((dest = (char *) malloc(dsize)) == NULL) {
free(section_hdr);
free(src);
return CL_EMEM;
}
lseek(desc, section_hdr[i + 1].PointerToRawData, SEEK_SET);
if(read(desc, src, ssize) != ssize) {
cli_dbgmsg("Can't read raw data of section %d\n", i + 1);
free(section_hdr);
free(src);
free(dest);
return CL_EMEM;
}
if(upxfn(src, ssize, dest, dsize)) {
cli_dbg("UPX decompression failed\n");
} else {
int ndesc;
tempfile = cl_gentemp(NULL);
if((ndesc = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU)) < 0) {
cli_dbgmsg("Can't create file %s\n", tempfile);
free(section_hdr);
free(src);
free(dest);
return CL_EIO;
}
if(write(ndesc, dest, dsize) != dsize) {
cli_dbgmsg("Can't write %d bytes\n", dsize);
free(section_hdr);
free(src);
free(dest);
return CL_EIO;
}
close(ndesc);
/* TODO: scan and unlink file */
/* unlink(tempfile); */
free(tempfile);
}
free(src);
free(dest);
} else {
cli_dbgmsg("UPX sections not found\n");
}
}
/* to be continued ... */ /* to be continued ... */
free(section_hdr); free(section_hdr);
return 0; return CL_CLEAN;
} }

View file

@ -0,0 +1,263 @@
/*
* Copyright (C) 2004 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
** 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
*/
/*
** 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
/* [doubleebx] */
static int doubleebx(char *src, int *myebx, int *scur, int ssize)
{
int oldebx = *myebx;
*myebx*=2;
if ( !(oldebx & 0x7fffffff)) {
if (*scur<0 || ssize-*scur<4)
return 0;
oldebx = *(int*)(src+*scur);
*myebx = oldebx*2+1;
*scur+=4;
}
return (oldebx>>31)&1;
}
/* [inflate] */
int upx_inflate2b(char *src, int ssize, char *dst, int dsize)
{
int backbytes, backsize, unp_offset = -1, i;
int myebx = 0;
int scur=0, dcur=0;
while (1) {
while (doubleebx(src, &myebx, &scur, ssize)) {
if (scur<0 || scur>=ssize || dcur<0 || dcur>=dsize)
return -1;
dst[dcur++] = src[scur++];
}
backbytes = 1;
while (1) {
backbytes = backbytes*2+doubleebx(src, &myebx, &scur, ssize);
if (doubleebx(src, &myebx, &scur, ssize))
break;
}
backsize = 0;
backbytes-=3;
if ( backbytes >= 0 ) {
if (scur<0 || scur>=ssize)
return -1;
backbytes<<=8;
backbytes+=(unsigned char)(src[scur++]);
backbytes^=0xffffffff;
if (!backbytes)
break;
unp_offset = backbytes;
}
backsize = doubleebx(src, &myebx, &scur, ssize);
backsize = backsize*2 + doubleebx(src, &myebx, &scur, ssize);
if (!backsize) {
backsize++;
do {
backsize = backsize*2 + doubleebx(src, &myebx, &scur, ssize);
} while (!doubleebx(src, &myebx, &scur, ssize));
backsize+=2;
}
if ( (unsigned int)unp_offset < 0xfffff300 )
backsize++;
backsize++;
for (i = 0; i < backsize; i++) {
if (dcur+i<0 || dcur+i>=dsize || dcur+unp_offset+i<0 || dcur+unp_offset+i>=dsize)
return -1;
dst[dcur + i] = dst[dcur + unp_offset + i];
}
dcur+=backsize;
}
return 0;
}
int upx_inflate2d(char *src, int ssize, char *dst, int dsize)
{
int backbytes, backsize, unp_offset = -1, i;
int myebx = 0;
int scur=0, dcur=0;
while (1) {
while (doubleebx(src, &myebx, &scur, ssize)) {
if (scur<0 || scur>=ssize || dcur<0 || dcur>=dsize)
return -1;
dst[dcur++] = src[scur++];
}
backbytes = 1;
while (1) {
backbytes = backbytes*2+doubleebx(src, &myebx, &scur, ssize);
if (doubleebx(src, &myebx, &scur, ssize))
break;
backbytes--;
backbytes=backbytes*2+doubleebx(src, &myebx, &scur, ssize);
}
backsize = 0;
backbytes-=3;
if ( backbytes >= 0 ) {
if (scur<0 || scur>=ssize)
return -1;
backbytes<<=8;
backbytes+=(unsigned char)(src[scur++]);
backbytes^=0xffffffff;
if (!backbytes)
break;
backsize = backbytes & 1;
backbytes>>=1;
unp_offset = backbytes;
}
else
backsize = doubleebx(src, &myebx, &scur, ssize);
backsize = backsize*2 + doubleebx(src, &myebx, &scur, ssize);
if (!backsize) {
backsize++;
do {
backsize = backsize*2 + doubleebx(src, &myebx, &scur, ssize);
} while (!doubleebx(src, &myebx, &scur, ssize));
backsize+=2;
}
if ( (unsigned int)unp_offset < 0xfffffb00 )
backsize++;
backsize++;
for (i = 0; i < backsize; i++) {
if (dcur+i<0 || dcur+i>=dsize || dcur+unp_offset+i<0 || dcur+unp_offset+i>=dsize)
return -1;
dst[dcur + i] = dst[dcur + unp_offset + i];
}
dcur+=backsize;
}
return 0;
}
int upx_inflate2e(char *src, int ssize, char *dst, int dsize)
{
int backbytes, backsize, unp_offset = -1, i;
int myebx = 0;
int scur=0, dcur=0;
while (1) {
while (doubleebx(src, &myebx, &scur, ssize)) {
if (scur<0 || scur>=ssize || dcur<0 || dcur>=dsize)
return -1;
dst[dcur++] = src[scur++];
}
backbytes = 1;
while (1) {
backbytes = backbytes*2+doubleebx(src, &myebx, &scur, ssize);
if (doubleebx(src, &myebx, &scur, ssize))
break;
backbytes--;
backbytes=backbytes*2+doubleebx(src, &myebx, &scur, ssize);
}
backsize = 0;
backbytes-=3;
if ( backbytes >= 0 ) {
if (scur<0 || scur>=ssize)
return -1;
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) */
backbytes>>=1;
unp_offset = backbytes;
}
else
backsize = doubleebx(src, &myebx, &scur, ssize); /* Using backsize to carry on the doubleebx result (UPX uses CF) */
if (backsize) { /* i.e. IF ( last sar shifted out 1 bit || last doubleebx()==1 ) */
backsize = doubleebx(src, &myebx, &scur, ssize);
}
else {
backsize = 1;
if (doubleebx(src, &myebx, &scur, ssize))
backsize = 2 + doubleebx(src, &myebx, &scur, ssize);
else {
do {
backsize = backsize * 2 + doubleebx(src, &myebx, &scur, ssize);
} while (!doubleebx(src, &myebx, &scur, ssize));
backsize+=2;
}
}
if ( (unsigned int)unp_offset < 0xfffffb00 )
backsize++;
backsize+=2;
for (i = 0; i < backsize; i++) {
if (dcur+i<0 || dcur+i>=dsize || dcur+unp_offset+i<0 || dcur+unp_offset+i>=dsize)
return -1;
dst[dcur + i] = dst[dcur + unp_offset + i];
}
dcur+=backsize;
}
return 0;
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (C) 2004 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __UPX_H
#define __UPX_H
int upx_inflate2b(char *, int , char *, int);
int upx_inflate2d(char *, int , char *, int);
int upx_inflate2e(char *, int , char *, int);
#endif