libclamav: include FSG unpacker from aCaB

git-svn: trunk@725
remotes/push_mirror/metadata
Tomasz Kojm 22 years ago
parent 20c3d44d09
commit 5f1a932bf4
  1. 4
      clamav-devel/ChangeLog
  2. 4
      clamav-devel/libclamav/Makefile.am
  3. 11
      clamav-devel/libclamav/Makefile.in
  4. 190
      clamav-devel/libclamav/fsg.c
  5. 28
      clamav-devel/libclamav/fsg.h
  6. 151
      clamav-devel/libclamav/pe.c

@ -1,3 +1,7 @@
Thu Aug 5 03:10:32 CEST 2004 (tk)
----------------------------------
* libclamav: include FSG unpacker from aCaB
Wed Aug 4 22:03:56 CEST 2004 (tk) Wed Aug 4 22:03:56 CEST 2004 (tk)
---------------------------------- ----------------------------------
* libclamav: pe: improve detection of broken executable files * libclamav: pe: improve detection of broken executable files

@ -110,6 +110,8 @@ libclamav_la_SOURCES = \
rebuildpe.c \ rebuildpe.c \
rebuildpe.h \ rebuildpe.h \
petite.c \ petite.c \
petite.h petite.h \
fsg.c \
fsg.h
lib_LTLIBRARIES = libclamav.la lib_LTLIBRARIES = libclamav.la

@ -79,7 +79,7 @@ am_libclamav_la_OBJECTS = matcher-ac.lo matcher-bm.lo matcher.lo \
blob.lo mbox.lo message.lo snprintf.lo strrcpy.lo table.lo \ blob.lo mbox.lo message.lo snprintf.lo strrcpy.lo table.lo \
text.lo ole2_extract.lo vba_extract.lo msexpand.lo pe.lo \ text.lo ole2_extract.lo vba_extract.lo msexpand.lo pe.lo \
cabd.lo lzxd.lo mszipd.lo qtmd.lo system.lo upx.lo htmlnorm.lo \ cabd.lo lzxd.lo mszipd.lo qtmd.lo system.lo upx.lo htmlnorm.lo \
chmunpack.lo rebuildpe.lo petite.lo chmunpack.lo rebuildpe.lo petite.lo fsg.lo
libclamav_la_OBJECTS = $(am_libclamav_la_OBJECTS) libclamav_la_OBJECTS = $(am_libclamav_la_OBJECTS)
DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp depcomp = $(SHELL) $(top_srcdir)/depcomp
@ -87,8 +87,8 @@ am__depfiles_maybe = depfiles
@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/blob.Plo ./$(DEPDIR)/cabd.Plo \ @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/blob.Plo ./$(DEPDIR)/cabd.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/chmunpack.Plo ./$(DEPDIR)/cvd.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/chmunpack.Plo ./$(DEPDIR)/cvd.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/dsig.Plo ./$(DEPDIR)/filetypes.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/dsig.Plo ./$(DEPDIR)/filetypes.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/htmlnorm.Plo ./$(DEPDIR)/lzxd.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/fsg.Plo ./$(DEPDIR)/htmlnorm.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/matcher-ac.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/lzxd.Plo ./$(DEPDIR)/matcher-ac.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/matcher-bm.Plo ./$(DEPDIR)/matcher.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/matcher-bm.Plo ./$(DEPDIR)/matcher.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/mbox.Plo ./$(DEPDIR)/md5.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/mbox.Plo ./$(DEPDIR)/md5.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/message.Plo ./$(DEPDIR)/msexpand.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/message.Plo ./$(DEPDIR)/msexpand.Plo \
@ -319,7 +319,9 @@ libclamav_la_SOURCES = \
rebuildpe.c \ rebuildpe.c \
rebuildpe.h \ rebuildpe.h \
petite.c \ petite.c \
petite.h petite.h \
fsg.c \
fsg.h
lib_LTLIBRARIES = libclamav.la lib_LTLIBRARIES = libclamav.la
all: all-am all: all-am
@ -397,6 +399,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cvd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cvd.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsig.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsig.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filetypes.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filetypes.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsg.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htmlnorm.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htmlnorm.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lzxd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lzxd.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/matcher-ac.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/matcher-ac.Plo@am__quote@

@ -0,0 +1,190 @@
/*
* 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.
*/
/*
** defsg.c
**
** 02/08/2k4 - Dumped and reversed
** 02/08/2k4 - Done coding
** 03/08/2k4 - Cleaning and securing
** 04/08/2k4 - Done porting
*/
/*
** Unpacks an FSG compressed section.
**
** Czesc bart, good asm, nice piece of code ;)
*/
#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"
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 unfsg(char *source, char *dest, int ssize, int dsize) {
uint8_t mydl=0x80;
uint32_t backbytes, backsize, oldback;
char *csrc = source, *cdst = dest;
int oob, lostbit = 1;
/* I assume buffers size is >0 - No checking! */
*cdst++=*csrc++;
while ( 1 ) {
if ((oob=doubledl(&csrc, &mydl, source, ssize))) {
if (oob == -1)
return -1;
/* 164 */
backsize = 0;
if ((oob=doubledl(&csrc, &mydl, source, ssize))) {
if (oob == -1)
return -1;
/* 16a */
backbytes = 0;
if ((oob=doubledl(&csrc, &mydl, source, ssize))) {
if (oob == -1)
return -1;
/* 170 */
lostbit = 1;
backsize++;
backbytes = 0x10;
while ( backbytes < 0x100 ) {
if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1)
return -1;
backbytes = backbytes*2+oob;
}
backbytes &= 0xff;
if ( ! backbytes ) {
if (cdst >= dest+dsize)
return -1;
*cdst++=0x00;
continue;
} else {
/* repne movsb - FIXME dont remove for now */
}
} else {
/* 18f */
if (csrc >= source+ssize)
return -1;
backbytes = *(unsigned char*)csrc;
backsize = backsize * 2 + (backbytes & 1);
backbytes = (backbytes & 0xff)>>1;
csrc++;
if (! backbytes)
break;
backsize+=2;
oldback = backbytes;
lostbit = 0;
}
} else {
/* 180 */
backsize = 1;
do {
if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1)
return -1;
backsize = backsize*2+oob;
if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1)
return -1;
} while (oob);
backsize = backsize - 1 - lostbit;
if (! backsize) {
/* 18a */
backsize = 1;
do {
if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1)
return -1;
backsize = backsize*2+oob;
if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1)
return -1;
} while (oob);
backbytes = oldback;
} else {
/* 198 */
if (csrc >= source+ssize)
return -1;
backbytes = *(unsigned char*)csrc;
backbytes += (backsize-1)<<8;
backsize = 1;
csrc++;
do {
if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1)
return -1;
backsize = backsize*2+oob;
if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1)
return -1;
} while (oob);
if (backbytes >= 0x7d00)
backsize++;
if (backbytes >= 0x500)
backsize++;
if (backbytes <= 0x7f)
backsize += 2;
oldback = backbytes;
}
lostbit = 0;
}
if (cdst-backbytes < dest || cdst+backsize >= dest+dsize)
return -1;
while(backsize--) {
*cdst=*(cdst-backbytes);
cdst++;
}
} else {
/* 15d */
if (cdst < dest || cdst >= dest+dsize || csrc < source || csrc >= source+ssize)
return -1;
*cdst++=*csrc++;
lostbit=1;
}
}
return 0;
}

@ -0,0 +1,28 @@
/*
* 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 __FSG_H
#define __FSG_H
#include "cltypes.h"
#include "pe.h"
int unfsg(char *, char *, int, int);
#endif

@ -35,6 +35,7 @@
#include "pe.h" #include "pe.h"
#include "upx.h" #include "upx.h"
#include "petite.h" #include "petite.h"
#include "fsg.h"
#include "scanners.h" #include "scanners.h"
#define IMAGE_DOS_SIGNATURE 0x5a4d /* MZ */ #define IMAGE_DOS_SIGNATURE 0x5a4d /* MZ */
@ -168,7 +169,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
struct pe_image_section_hdr *section_hdr; struct pe_image_section_hdr *section_hdr;
struct stat sb; struct stat sb;
char sname[9], buff[256], *tempfile; char sname[9], buff[256], *tempfile;
int i, found, upx_success = 0, broken = 0, min = 0, max = 0; int i, found, upx_success = 0, min = 0, max = 0;
int (*upxfn)(char *, int , char *, int) = NULL; int (*upxfn)(char *, int , char *, int) = NULL;
char *src, *dest; char *src, *dest;
int ssize, dsize, ndesc; int ssize, dsize, ndesc;
@ -385,7 +386,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
} }
if((ep = cli_rawaddr(EC32(optional_hdr.AddressOfEntryPoint), section_hdr, nsections)) == -1) { if((ep = EC32(optional_hdr.AddressOfEntryPoint)) >= min && (ep = cli_rawaddr(EC32(optional_hdr.AddressOfEntryPoint), section_hdr, nsections)) == -1) {
cli_dbgmsg("Possibly broken PE file\n"); cli_dbgmsg("Possibly broken PE file\n");
free(section_hdr); free(section_hdr);
if(DETECT_BROKEN) { if(DETECT_BROKEN) {
@ -398,19 +399,140 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
cli_dbgmsg("EntryPoint offset: 0x%x (%d)\n", ep, ep); cli_dbgmsg("EntryPoint offset: 0x%x (%d)\n", ep, ep);
/* UPX support */ /* UPX & FSG support */
/* try to find the first section with physical size == 0 */ /* try to find the first section with physical size == 0 */
found = 0; found = 0;
for(i = 0; i < nsections - 1; i++) { for(i = 0; i < nsections - 1; i++) {
if(!section_hdr[i].SizeOfRawData && section_hdr[i].VirtualSize && section_hdr[i+1].SizeOfRawData && section_hdr[i+1].VirtualSize) { if(!section_hdr[i].SizeOfRawData && section_hdr[i].VirtualSize && section_hdr[i + 1].SizeOfRawData && section_hdr[i + 1].VirtualSize) {
found = 1; found = 1;
cli_dbgmsg("UPX: empty section found - assuming UPX compression\n"); cli_dbgmsg("UPX/FSG: empty section found - assuming compression\n");
break;
}
}
if(found) {
/* Check EP for UPX vs. FSG */
if(lseek(desc, ep, SEEK_SET) == -1) {
cli_dbgmsg("UPX/FSG: lseek() failed\n");
free(section_hdr);
return CL_EIO;
}
if(read(desc, buff, 126) != 126) { /* i.e. 0x69 + 13 + 8 */
cli_dbgmsg("UPX/FSG: Can't read 126 bytes at 0x%x (%d)\n", ep, ep);
free(section_hdr);
return CL_EIO;
}
if(buff[0]=='\x87' || buff [1]=='\x25') {
/* FSG support - thanks to aCaB ! */
ssize = EC32(section_hdr[i + 1].SizeOfRawData);
dsize = EC32(section_hdr[i].VirtualSize);
while(found) {
uint32_t newesi, newedi, newebx, newedx;
if(limits && limits->maxfilesize && (ssize > limits->maxfilesize || dsize > limits->maxfilesize)) {
cli_dbgmsg("FSG: Sizes exceeded (ssize: %d, dsize: %d, max: %lu)\n", ssize, dsize , limits->maxfilesize);
free(section_hdr);
return CL_CLEAN;
}
if(ssize <= 0x19 || dsize <= ssize) {
cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize);
free(section_hdr);
return CL_CLEAN;
}
if((newedx = cli_readint32(buff + 2) - EC32(optional_hdr.ImageBase)) < EC32(section_hdr[i + 1].VirtualAddress) || newedx >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 4) {
cli_dbgmsg("FSG: xchg out of bounds (%x), giving up\n", newedx);
break;
}
if((src = (char *) cli_malloc(ssize)) == NULL) {
free(section_hdr);
return CL_EMEM;
}
lseek(desc, EC32(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);
free(section_hdr);
free(src);
return CL_EIO;
}
if((dest = src + newedx - EC32(section_hdr[i + 1].VirtualAddress)) < src || dest >= src + EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 4) {
cli_dbgmsg("FSG: New ESP out of bounds\n");
free(src);
break; break;
} }
if((newedx = cli_readint32(dest) - EC32(optional_hdr.ImageBase)) <= EC32(section_hdr[i + 1].VirtualAddress) || newedx >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 4) {
cli_dbgmsg("FSG: New ESP (%x) is wrong\n", newedx);
free(src);
break;
}
if((dest = src + newedx - EC32(section_hdr[i + 1].VirtualAddress)) < src || dest >= src + EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 32) {
cli_dbgmsg("FSG: New stack out of bounds\n");
free(src);
break;
}
newedi = cli_readint32(dest) - EC32(optional_hdr.ImageBase);
newesi = cli_readint32(dest + 4) - EC32(optional_hdr.ImageBase);
newebx = cli_readint32(dest + 16) - EC32(optional_hdr.ImageBase);
newedx = cli_readint32(dest + 20);
if(newedi != EC32(section_hdr[i].VirtualAddress)) {
cli_dbgmsg("FSG: Bad destination buffer (edi is %x should be %x)\n", newedi, EC32(section_hdr[i].VirtualAddress));
free(src);
break;
}
if(newesi < EC32(section_hdr[i + 1].VirtualAddress) || newesi >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData)) {
cli_dbgmsg("FSG: Source buffer out of section bounds\n");
free(src);
break;
}
if(newebx < EC32(section_hdr[i + 1].VirtualAddress) || newebx >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 16) {
cli_dbgmsg("FSG: Array of functions out of bounds\n");
free(src);
break;
}
/* FIXME: unused atm, needed for pe rebuilding */
cli_dbgmsg("FSG: found old EP @%x\n", cli_readint32(newebx + 12 - EC32(section_hdr[i + 1].VirtualAddress) + src) - EC32(optional_hdr.ImageBase));
if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
free(section_hdr);
free(src);
return CL_EMEM;
}
if(unfsg(newesi - EC32(section_hdr[i + 1].VirtualAddress) + src, dest, ssize, dsize) == -1) {
cli_dbgmsg("FSG: Unpacking failed\n");
free(src);
free(dest);
break;
}
found = 0;
upx_success = 1;
cli_dbgmsg("FSG: Successfully decompressed\n");
}
} }
if(found) { if(found) {
/* UPX support */
strncpy(sname, section_hdr[i].Name, 8); strncpy(sname, section_hdr[i].Name, 8);
sname[8] = 0; sname[8] = 0;
cli_dbgmsg("UPX: Section %d name: %s\n", i, sname); cli_dbgmsg("UPX: Section %d name: %s\n", i, sname);
@ -488,7 +610,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
} }
if(upxfn) { if(upxfn) {
int skew = cli_readint32(buff + 2) - EC32(optional_hdr.ImageBase) - EC32(section_hdr[i+1].VirtualAddress); int skew = cli_readint32(buff + 2) - EC32(optional_hdr.ImageBase) - EC32(section_hdr[i + 1].VirtualAddress);
if(buff[1] != '\xbe' || skew <= 0 || skew > 0xfff ) { /* FIXME: legit skews?? */ if(buff[1] != '\xbe' || skew <= 0 || skew > 0xfff ) { /* FIXME: legit skews?? */
skew = 0; skew = 0;
@ -517,7 +639,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
} }
if(!upx_success && upxfn != upx_inflate2d) { if(!upx_success && upxfn != upx_inflate2d) {
if(upx_inflate2d(src, ssize, dest, dsize) && upx_inflate2d(src+0x15, ssize-0x15, dest, dsize) ) { if(upx_inflate2d(src, ssize, dest, dsize) && upx_inflate2d(src + 0x15, ssize - 0x15, dest, dsize) ) {
cli_dbgmsg("UPX: NRV2D decompressor failed\n"); cli_dbgmsg("UPX: NRV2D decompressor failed\n");
} else { } else {
upx_success = 1; upx_success = 1;
@ -536,13 +658,18 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
if(!upx_success) { if(!upx_success) {
cli_dbgmsg("UPX: All decompressors failed\n"); cli_dbgmsg("UPX: All decompressors failed\n");
} else { free(src);
free(dest);
}
}
if(upx_success) {
int ndesc; int ndesc;
if(cli_leavetemps_flag) { if(cli_leavetemps_flag) {
tempfile = cli_gentemp(NULL); tempfile = cli_gentemp(NULL);
if((ndesc = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU)) < 0) { if((ndesc = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU)) < 0) {
cli_dbgmsg("UPX: Can't create file %s\n", tempfile); cli_dbgmsg("UPX/FSG: Can't create file %s\n", tempfile);
free(tempfile); free(tempfile);
free(section_hdr); free(section_hdr);
free(src); free(src);
@ -551,7 +678,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
} }
if(write(ndesc, dest, dsize) != dsize) { if(write(ndesc, dest, dsize) != dsize) {
cli_dbgmsg("Can't write %d bytes\n", dsize); cli_dbgmsg("UPX/FSG: Can't write %d bytes\n", dsize);
free(tempfile); free(tempfile);
free(section_hdr); free(section_hdr);
free(src); free(src);
@ -560,7 +687,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
} }
close(ndesc); close(ndesc);
cli_dbgmsg("UPX: Decompressed data saved in %s\n", tempfile); cli_dbgmsg("UPX/FSG: Decompressed data saved in %s\n", tempfile);
free(tempfile); free(tempfile);
} }
@ -570,11 +697,11 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
free(dest); free(dest);
return CL_VIRUS; return CL_VIRUS;
} }
}
free(src); free(src);
free(dest); free(dest);
} }
}
/* Petite */ /* Petite */

Loading…
Cancel
Save