Browse code

libclamav: include FSG unpacker from aCaB

git-svn-id: file:///var/lib/svn/clamav-devel/trunk/clamav-devel@725 77e5149b-7576-45b1-b177-96237e5ba77b

Tomasz Kojm authored on 2004/08/05 10:15:59
Showing 6 changed files
... ...
@@ -1,3 +1,7 @@
1
+Thu Aug  5 03:10:32 CEST 2004 (tk)
2
+----------------------------------
3
+  * libclamav: include FSG unpacker from aCaB
4
+
1 5
 Wed Aug  4 22:03:56 CEST 2004 (tk)
2 6
 ----------------------------------
3 7
   * libclamav: pe: improve detection of broken executable files
... ...
@@ -110,6 +110,8 @@ libclamav_la_SOURCES = \
110 110
 	rebuildpe.c \
111 111
 	rebuildpe.h \
112 112
 	petite.c \
113
-	petite.h
113
+	petite.h \
114
+	fsg.c \
115
+	fsg.h
114 116
 
115 117
 lib_LTLIBRARIES = libclamav.la
... ...
@@ -79,7 +79,7 @@ am_libclamav_la_OBJECTS = matcher-ac.lo matcher-bm.lo matcher.lo \
79 79
 	blob.lo mbox.lo message.lo snprintf.lo strrcpy.lo table.lo \
80 80
 	text.lo ole2_extract.lo vba_extract.lo msexpand.lo pe.lo \
81 81
 	cabd.lo lzxd.lo mszipd.lo qtmd.lo system.lo upx.lo htmlnorm.lo \
82
-	chmunpack.lo rebuildpe.lo petite.lo
82
+	chmunpack.lo rebuildpe.lo petite.lo fsg.lo
83 83
 libclamav_la_OBJECTS = $(am_libclamav_la_OBJECTS)
84 84
 DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
85 85
 depcomp = $(SHELL) $(top_srcdir)/depcomp
... ...
@@ -87,8 +87,8 @@ am__depfiles_maybe = depfiles
87 87
 @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/blob.Plo ./$(DEPDIR)/cabd.Plo \
88 88
 @AMDEP_TRUE@	./$(DEPDIR)/chmunpack.Plo ./$(DEPDIR)/cvd.Plo \
89 89
 @AMDEP_TRUE@	./$(DEPDIR)/dsig.Plo ./$(DEPDIR)/filetypes.Plo \
90
-@AMDEP_TRUE@	./$(DEPDIR)/htmlnorm.Plo ./$(DEPDIR)/lzxd.Plo \
91
-@AMDEP_TRUE@	./$(DEPDIR)/matcher-ac.Plo \
90
+@AMDEP_TRUE@	./$(DEPDIR)/fsg.Plo ./$(DEPDIR)/htmlnorm.Plo \
91
+@AMDEP_TRUE@	./$(DEPDIR)/lzxd.Plo ./$(DEPDIR)/matcher-ac.Plo \
92 92
 @AMDEP_TRUE@	./$(DEPDIR)/matcher-bm.Plo ./$(DEPDIR)/matcher.Plo \
93 93
 @AMDEP_TRUE@	./$(DEPDIR)/mbox.Plo ./$(DEPDIR)/md5.Plo \
94 94
 @AMDEP_TRUE@	./$(DEPDIR)/message.Plo ./$(DEPDIR)/msexpand.Plo \
... ...
@@ -319,7 +319,9 @@ libclamav_la_SOURCES = \
319 319
 	rebuildpe.c \
320 320
 	rebuildpe.h \
321 321
 	petite.c \
322
-	petite.h
322
+	petite.h \
323
+	fsg.c \
324
+	fsg.h
323 325
 
324 326
 lib_LTLIBRARIES = libclamav.la
325 327
 all: all-am
... ...
@@ -397,6 +399,7 @@ distclean-compile:
397 397
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cvd.Plo@am__quote@
398 398
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsig.Plo@am__quote@
399 399
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filetypes.Plo@am__quote@
400
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsg.Plo@am__quote@
400 401
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htmlnorm.Plo@am__quote@
401 402
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lzxd.Plo@am__quote@
402 403
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/matcher-ac.Plo@am__quote@
403 404
new file mode 100644
... ...
@@ -0,0 +1,190 @@
0
+/*
1
+ *  Copyright (C) 2004 aCaB <acab@clamav.net>
2
+ *
3
+ *  This program is free software; you can redistribute it and/or modify
4
+ *  it under the terms of the GNU General Public License as published by
5
+ *  the Free Software Foundation; either version 2 of the License, or
6
+ *  (at your option) any later version.
7
+ *
8
+ *  This program is distributed in the hope that it will be useful,
9
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
+ *  GNU General Public License for more details.
12
+ *
13
+ *  You should have received a copy of the GNU General Public License
14
+ *  along with this program; if not, write to the Free Software
15
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16
+ */
17
+
18
+/*
19
+** defsg.c
20
+** 
21
+** 02/08/2k4 - Dumped and reversed
22
+** 02/08/2k4 - Done coding
23
+** 03/08/2k4 - Cleaning and securing
24
+** 04/08/2k4 - Done porting
25
+*/
26
+
27
+/*
28
+** Unpacks an FSG compressed section.
29
+**
30
+** Czesc bart, good asm, nice piece of code ;)
31
+*/
32
+
33
+#if HAVE_CONFIG_H
34
+#include "clamav-config.h"
35
+#endif
36
+
37
+#include <stdio.h>
38
+#include <stdlib.h>
39
+#include <sys/types.h>
40
+#include <sys/stat.h>
41
+#include <unistd.h>
42
+#include <string.h>
43
+
44
+#include "cltypes.h"
45
+#include "pe.h"
46
+#include "rebuildpe.h"
47
+#include "others.h"
48
+
49
+
50
+static int doubledl(char **scur, uint8_t *mydlptr, char *buffer, int buffersize)
51
+{
52
+  unsigned char mydl = *mydlptr;
53
+  unsigned char olddl = mydl;
54
+
55
+  mydl*=2;
56
+  if ( !(olddl & 0x7f)) {
57
+    if ( *scur < buffer || *scur >= buffer+buffersize-1 )
58
+      return -1;
59
+    olddl = **scur;
60
+    mydl = olddl*2+1;
61
+    *scur=*scur + 1;
62
+  }
63
+  *mydlptr = mydl;
64
+  return (olddl>>7)&1;
65
+}
66
+
67
+int unfsg(char *source, char *dest, int ssize, int dsize) {
68
+  uint8_t mydl=0x80;
69
+  uint32_t backbytes, backsize, oldback;
70
+  char *csrc = source, *cdst = dest;
71
+  int oob, lostbit = 1;
72
+
73
+  /* I assume buffers size is >0 - No checking! */
74
+  *cdst++=*csrc++;
75
+
76
+  while ( 1 ) {
77
+    if ((oob=doubledl(&csrc, &mydl, source, ssize))) {
78
+      if (oob == -1)
79
+	return -1;
80
+      /* 164 */
81
+      backsize = 0;
82
+      if ((oob=doubledl(&csrc, &mydl, source, ssize))) {
83
+	if (oob == -1)
84
+	  return -1;
85
+	/* 16a */
86
+	backbytes = 0;
87
+	if ((oob=doubledl(&csrc, &mydl, source, ssize))) {
88
+	  if (oob == -1)
89
+	    return -1;
90
+	  /* 170 */
91
+	  lostbit = 1;
92
+	  backsize++;
93
+	  backbytes = 0x10;
94
+	  while ( backbytes < 0x100 ) {
95
+	    if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1)
96
+	      return -1;
97
+	    backbytes = backbytes*2+oob;
98
+	  }
99
+	  backbytes &= 0xff;
100
+	  if ( ! backbytes ) {
101
+	    if (cdst >= dest+dsize)
102
+	      return -1;
103
+	    *cdst++=0x00;
104
+	    continue;
105
+	  } else {
106
+	    /* repne movsb - FIXME dont remove for now */
107
+	  }
108
+	} else {
109
+	  /* 18f */
110
+	  if (csrc >= source+ssize)
111
+	    return -1;
112
+	  backbytes = *(unsigned char*)csrc;
113
+	  backsize = backsize * 2 + (backbytes & 1);
114
+	  backbytes = (backbytes & 0xff)>>1;
115
+	  csrc++;
116
+	  if (! backbytes)
117
+	    break;
118
+	  backsize+=2;
119
+	  oldback = backbytes;
120
+	  lostbit = 0;
121
+	}
122
+      } else {
123
+	/* 180 */
124
+	backsize = 1;
125
+	do {
126
+	  if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1)
127
+	    return -1;
128
+	  backsize = backsize*2+oob;
129
+	  if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1)
130
+	    return -1;
131
+	} while (oob);
132
+
133
+	backsize = backsize - 1 - lostbit;
134
+	if (! backsize) {
135
+	  /* 18a */
136
+	  backsize = 1;
137
+	  do {
138
+	    if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1)
139
+	      return -1;
140
+	    backsize = backsize*2+oob;
141
+	    if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1)
142
+	      return -1;
143
+	  } while (oob);
144
+
145
+	  backbytes = oldback;
146
+	} else {
147
+	  /* 198 */
148
+	  if (csrc >= source+ssize)
149
+	    return -1;
150
+	  backbytes = *(unsigned char*)csrc;
151
+	  backbytes += (backsize-1)<<8;
152
+	  backsize = 1;
153
+	  csrc++;
154
+	  do {
155
+	    if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1)
156
+	      return -1;
157
+	    backsize = backsize*2+oob;
158
+	    if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1)
159
+	      return -1;
160
+	  } while (oob);
161
+
162
+          if (backbytes >= 0x7d00)
163
+            backsize++;
164
+          if (backbytes >= 0x500)
165
+            backsize++;
166
+          if (backbytes <= 0x7f)
167
+            backsize += 2;
168
+
169
+	  oldback = backbytes;
170
+	}
171
+	lostbit = 0;
172
+      }
173
+      if (cdst-backbytes < dest || cdst+backsize >= dest+dsize)
174
+	return -1;
175
+      while(backsize--) {
176
+	*cdst=*(cdst-backbytes);
177
+	cdst++;
178
+      }
179
+
180
+    } else {
181
+      /* 15d */
182
+      if (cdst < dest || cdst >= dest+dsize || csrc < source || csrc >= source+ssize)
183
+	return -1;
184
+      *cdst++=*csrc++;
185
+      lostbit=1;
186
+    }
187
+  }
188
+  return 0;
189
+}
0 190
new file mode 100644
... ...
@@ -0,0 +1,28 @@
0
+/*
1
+ *  Copyright (C) 2004 aCaB <acab@clamav.net>
2
+ *
3
+ *  This program is free software; you can redistribute it and/or modify
4
+ *  it under the terms of the GNU General Public License as published by
5
+ *  the Free Software Foundation; either version 2 of the License, or
6
+ *  (at your option) any later version.
7
+ *
8
+ *  This program is distributed in the hope that it will be useful,
9
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
+ *  GNU General Public License for more details.
12
+ *
13
+ *  You should have received a copy of the GNU General Public License
14
+ *  along with this program; if not, write to the Free Software
15
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16
+ */
17
+
18
+#ifndef __FSG_H
19
+#define __FSG_H
20
+
21
+#include "cltypes.h"
22
+#include "pe.h"
23
+
24
+int unfsg(char *, char *, int, int);
25
+
26
+#endif
27
+
... ...
@@ -35,6 +35,7 @@
35 35
 #include "pe.h"
36 36
 #include "upx.h"
37 37
 #include "petite.h"
38
+#include "fsg.h"
38 39
 #include "scanners.h"
39 40
 
40 41
 #define IMAGE_DOS_SIGNATURE	    0x5a4d	    /* MZ */
... ...
@@ -168,7 +169,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
168 168
 	struct pe_image_section_hdr *section_hdr;
169 169
 	struct stat sb;
170 170
 	char sname[9], buff[256], *tempfile;
171
-	int i, found, upx_success = 0, broken = 0, min = 0, max = 0;
171
+	int i, found, upx_success = 0, min = 0, max = 0;
172 172
 	int (*upxfn)(char *, int , char *, int) = NULL;
173 173
 	char *src, *dest;
174 174
 	int ssize, dsize, ndesc;
... ...
@@ -385,7 +386,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
385 385
 
386 386
     }
387 387
 
388
-    if((ep = cli_rawaddr(EC32(optional_hdr.AddressOfEntryPoint), section_hdr, nsections)) == -1) {
388
+    if((ep = EC32(optional_hdr.AddressOfEntryPoint)) >= min && (ep = cli_rawaddr(EC32(optional_hdr.AddressOfEntryPoint), section_hdr, nsections)) == -1) {
389 389
 	cli_dbgmsg("Possibly broken PE file\n");
390 390
 	free(section_hdr);
391 391
 	if(DETECT_BROKEN) {
... ...
@@ -398,151 +399,277 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
398 398
 
399 399
     cli_dbgmsg("EntryPoint offset: 0x%x (%d)\n", ep, ep);
400 400
 
401
-    /* UPX support */
401
+    /* UPX & FSG support */
402 402
 
403 403
     /* try to find the first section with physical size == 0 */
404 404
     found = 0;
405 405
     for(i = 0; i < nsections - 1; i++) {
406
-	if(!section_hdr[i].SizeOfRawData && section_hdr[i].VirtualSize && section_hdr[i+1].SizeOfRawData && section_hdr[i+1].VirtualSize) {
406
+	if(!section_hdr[i].SizeOfRawData && section_hdr[i].VirtualSize && section_hdr[i + 1].SizeOfRawData && section_hdr[i + 1].VirtualSize) {
407 407
 	    found = 1;
408
-	    cli_dbgmsg("UPX: empty section found - assuming UPX compression\n");
408
+	    cli_dbgmsg("UPX/FSG: empty section found - assuming compression\n");
409 409
 	    break;
410 410
 	}
411 411
     }
412 412
 
413 413
     if(found) {
414
-	strncpy(sname, section_hdr[i].Name, 8);
415
-	sname[8] = 0;
416
-	cli_dbgmsg("UPX: Section %d name: %s\n", i, sname);
417
-	strncpy(sname, section_hdr[i + 1].Name, 8);
418
-	sname[8] = 0;
419
-	cli_dbgmsg("UPX: Section %d name: %s\n", i + 1, sname);
420
-
421
-	if(strncmp(section_hdr[i].Name, "UPX0", 4) || strncmp(section_hdr[i + 1].Name, "UPX1", 4))
422
-	    cli_dbgmsg("UPX: Possibly hacked UPX section headers\n");
423
-
424
-	/* we assume (i + 1) is UPX1 */
425
-	ssize = EC32(section_hdr[i + 1].SizeOfRawData);
426
-	dsize = EC32(section_hdr[i].VirtualSize) + EC32(section_hdr[i + 1].VirtualSize);
427 414
 
428
-	if(limits && limits->maxfilesize && (ssize > limits->maxfilesize || dsize > limits->maxfilesize)) {
429
-	    cli_dbgmsg("UPX: Sizes exceeded (ssize: %d, dsize: %d, max: %lu)\n", ssize, dsize , limits->maxfilesize);
415
+	/* Check EP for UPX vs. FSG */
416
+	if(lseek(desc, ep, SEEK_SET) == -1) {
417
+	    cli_dbgmsg("UPX/FSG: lseek() failed\n");
430 418
 	    free(section_hdr);
431
-	    return CL_CLEAN;
419
+	    return CL_EIO;
432 420
 	}
433 421
 
434
-	if(ssize <= 0x19 || dsize <= ssize) { /* FIXME: What are reasonable values? */
435
-	    cli_dbgmsg("UPX: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize);
436
-	    free(section_hdr);
437
-	    return CL_CLEAN;
422
+	if(read(desc, buff, 126) != 126) { /* i.e. 0x69 + 13 + 8 */
423
+	    cli_dbgmsg("UPX/FSG: Can't read 126 bytes at 0x%x (%d)\n", ep, ep);
424
+            free(section_hdr);
425
+	    return CL_EIO;
438 426
 	}
439 427
 
440
-	/* FIXME: use file operations in case of big files */
441
-	if((src = (char *) cli_malloc(ssize)) == NULL) {
442
-	    free(section_hdr);
443
-	    return CL_EMEM;
444
-	}
428
+	if(buff[0]=='\x87' || buff [1]=='\x25') {
445 429
 
446
-	if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
447
-	    free(section_hdr);
448
-	    free(src);
449
-	    return CL_EMEM;
450
-	}
430
+	    /* FSG support - thanks to aCaB ! */
451 431
 
452
-	lseek(desc, EC32(section_hdr[i + 1].PointerToRawData), SEEK_SET);
453
-	if(read(desc, src, ssize) != ssize) {
454
-	    cli_dbgmsg("Can't read raw data of section %d\n", i);
455
-	    free(section_hdr);
456
-	    free(src);
457
-	    free(dest);
458
-	    return CL_EIO;
459
-	}
432
+	    ssize = EC32(section_hdr[i + 1].SizeOfRawData);
433
+	    dsize = EC32(section_hdr[i].VirtualSize);
460 434
 
461
-	/* try to detect UPX code */
435
+	    while(found) {
436
+		    uint32_t newesi, newedi, newebx, newedx;
462 437
 
463
-	if(lseek(desc, ep, SEEK_SET) == -1) {
464
-	    cli_dbgmsg("lseek() failed\n");
465
-	    free(section_hdr);
466
-	    free(src);
467
-	    free(dest);
468
-	    return CL_EIO;
469
-	}
438
+		if(limits && limits->maxfilesize && (ssize > limits->maxfilesize || dsize > limits->maxfilesize)) {
439
+		    cli_dbgmsg("FSG: Sizes exceeded (ssize: %d, dsize: %d, max: %lu)\n", ssize, dsize , limits->maxfilesize);
440
+		    free(section_hdr);
441
+		    return CL_CLEAN;
442
+		}
470 443
 
471
-	if(read(desc, buff, 126) != 126) { /* i.e. 0x69 + 13 + 8 */
472
-	    cli_dbgmsg("UPX: Can't read 126 bytes at 0x%x (%d)\n", ep, ep);
473
-	    free(section_hdr);
474
-	    free(src);
475
-	    free(dest);
476
-	    return CL_EIO;
477
-	} else {
478
-	    if(cli_memstr(UPX_NRV2B, 24, buff + 0x69, 13) || cli_memstr(UPX_NRV2B, 24, buff + 0x69 + 8, 13)) {
479
-		cli_dbgmsg("UPX: Looks like a NRV2B decompression routine\n");
480
-		upxfn = upx_inflate2b;
481
-	    } else if(cli_memstr(UPX_NRV2D, 24, buff + 0x69, 13) || cli_memstr(UPX_NRV2D, 24, buff + 0x69 + 8, 13)) {
482
-		cli_dbgmsg("UPX: Looks like a NRV2D decompression routine\n");
483
-		upxfn = upx_inflate2d;
484
-	    } else if(cli_memstr(UPX_NRV2E, 24, buff + 0x69, 13) || cli_memstr(UPX_NRV2E, 24, buff + 0x69 + 8, 13)) {
485
-		cli_dbgmsg("UPX: Looks like a NRV2E decompression routine\n");
486
-		upxfn = upx_inflate2e;
444
+		if(ssize <= 0x19 || dsize <= ssize) {
445
+		    cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize);
446
+		    free(section_hdr);
447
+		    return CL_CLEAN;
448
+		}
449
+
450
+		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) {
451
+		    cli_dbgmsg("FSG: xchg out of bounds (%x), giving up\n", newedx);
452
+		    break;
453
+		}
454
+
455
+		if((src = (char *) cli_malloc(ssize)) == NULL) {
456
+		    free(section_hdr);
457
+		    return CL_EMEM;
458
+		}
459
+
460
+		lseek(desc, EC32(section_hdr[i + 1].PointerToRawData), SEEK_SET);
461
+		if(read(desc, src, ssize) != ssize) {
462
+		    cli_dbgmsg("Can't read raw data of section %d\n", i);
463
+		    free(section_hdr);
464
+		    free(src);
465
+		    return CL_EIO;
466
+		}
467
+
468
+		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) {
469
+		    cli_dbgmsg("FSG: New ESP out of bounds\n");
470
+		    free(src);
471
+		    break;
472
+		}
473
+
474
+		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) {
475
+		    cli_dbgmsg("FSG: New ESP (%x) is wrong\n", newedx);
476
+		    free(src);
477
+		    break;
478
+		}
479
+ 
480
+		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) {
481
+		    cli_dbgmsg("FSG: New stack out of bounds\n");
482
+		    free(src);
483
+		    break;
484
+		}
485
+
486
+		newedi = cli_readint32(dest) - EC32(optional_hdr.ImageBase);
487
+		newesi = cli_readint32(dest + 4) - EC32(optional_hdr.ImageBase);
488
+		newebx = cli_readint32(dest + 16) - EC32(optional_hdr.ImageBase);
489
+		newedx = cli_readint32(dest + 20);
490
+
491
+		if(newedi != EC32(section_hdr[i].VirtualAddress)) {
492
+		    cli_dbgmsg("FSG: Bad destination buffer (edi is %x should be %x)\n", newedi, EC32(section_hdr[i].VirtualAddress));
493
+		    free(src);
494
+		    break;
495
+		}
496
+
497
+		if(newesi < EC32(section_hdr[i + 1].VirtualAddress) || newesi >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData)) {
498
+		    cli_dbgmsg("FSG: Source buffer out of section bounds\n");
499
+		    free(src);
500
+		    break;
501
+		}
502
+
503
+		if(newebx < EC32(section_hdr[i + 1].VirtualAddress) || newebx >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 16) {
504
+		    cli_dbgmsg("FSG: Array of functions out of bounds\n");
505
+		    free(src);
506
+		    break;
507
+		}
508
+
509
+		/* FIXME: unused atm, needed for pe rebuilding */
510
+		cli_dbgmsg("FSG: found old EP @%x\n", cli_readint32(newebx + 12 - EC32(section_hdr[i + 1].VirtualAddress) + src) - EC32(optional_hdr.ImageBase));
511
+
512
+		if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
513
+		    free(section_hdr);
514
+		    free(src);
515
+		    return CL_EMEM;
516
+		}
517
+
518
+		if(unfsg(newesi - EC32(section_hdr[i + 1].VirtualAddress) + src, dest, ssize, dsize) == -1) {
519
+		    cli_dbgmsg("FSG: Unpacking failed\n");
520
+		    free(src);
521
+		    free(dest);
522
+		    break;
523
+		}
524
+
525
+		found = 0;
526
+		upx_success = 1;
527
+		cli_dbgmsg("FSG: Successfully decompressed\n");
487 528
 	    }
488 529
 	}
489 530
 
490
-	if(upxfn) {
491
-		int skew = cli_readint32(buff + 2) - EC32(optional_hdr.ImageBase) - EC32(section_hdr[i+1].VirtualAddress);
531
+	if(found) {
492 532
 
493
-	    if(buff[1] != '\xbe' || skew <= 0 || skew > 0xfff ) { /* FIXME: legit skews?? */
494
-		skew = 0; 
495
-		if(!upxfn(src, ssize, dest, dsize))
496
-		    upx_success = 1;
533
+	    /* UPX support */
497 534
 
498
-	    } else {
499
-		cli_dbgmsg("UPX: UPX1 seems skewed by %d bytes\n", skew);
500
-		if(!upxfn(src + skew, ssize - skew, dest, dsize) || !upxfn(src, ssize, dest, dsize))
501
-		    upx_success = 1;
535
+	    strncpy(sname, section_hdr[i].Name, 8);
536
+	    sname[8] = 0;
537
+	    cli_dbgmsg("UPX: Section %d name: %s\n", i, sname);
538
+	    strncpy(sname, section_hdr[i + 1].Name, 8);
539
+	    sname[8] = 0;
540
+	    cli_dbgmsg("UPX: Section %d name: %s\n", i + 1, sname);
541
+
542
+	    if(strncmp(section_hdr[i].Name, "UPX0", 4) || strncmp(section_hdr[i + 1].Name, "UPX1", 4))
543
+		cli_dbgmsg("UPX: Possibly hacked UPX section headers\n");
544
+
545
+	    /* we assume (i + 1) is UPX1 */
546
+	    ssize = EC32(section_hdr[i + 1].SizeOfRawData);
547
+	    dsize = EC32(section_hdr[i].VirtualSize) + EC32(section_hdr[i + 1].VirtualSize);
548
+
549
+	    if(limits && limits->maxfilesize && (ssize > limits->maxfilesize || dsize > limits->maxfilesize)) {
550
+		cli_dbgmsg("UPX: Sizes exceeded (ssize: %d, dsize: %d, max: %lu)\n", ssize, dsize , limits->maxfilesize);
551
+		free(section_hdr);
552
+		return CL_CLEAN;
502 553
 	    }
503 554
 
504
-	    if(upx_success)
505
-		cli_dbgmsg("UPX: Successfully decompressed\n");
506
-	    else
507
-		cli_dbgmsg("UPX: Prefered decompressor failed\n");
508
-	}
555
+	    if(ssize <= 0x19 || dsize <= ssize) { /* FIXME: What are reasonable values? */
556
+		cli_dbgmsg("UPX: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize);
557
+		free(section_hdr);
558
+		return CL_CLEAN;
559
+	    }
509 560
 
510
-	if(!upx_success && upxfn != upx_inflate2b) {
511
-	    if(upx_inflate2b(src, ssize, dest, dsize) && upx_inflate2b(src + 0x15, ssize - 0x15, dest, dsize) ) {
512
-		cli_dbgmsg("UPX: NRV2B decompressor failed\n");
513
-	    } else {
514
-		upx_success = 1;
515
-		cli_dbgmsg("UPX: Successfully decompressed with NRV2B\n");
561
+	    /* FIXME: use file operations in case of big files */
562
+	    if((src = (char *) cli_malloc(ssize)) == NULL) {
563
+		free(section_hdr);
564
+		return CL_EMEM;
516 565
 	    }
517
-	}
518 566
 
519
-	if(!upx_success && upxfn != upx_inflate2d) {
520
-	    if(upx_inflate2d(src, ssize, dest, dsize) && upx_inflate2d(src+0x15, ssize-0x15, dest, dsize) ) {
521
-		cli_dbgmsg("UPX: NRV2D decompressor failed\n");
522
-	    } else {
523
-		upx_success = 1;
524
-		cli_dbgmsg("UPX: Successfully decompressed with NRV2D\n");
567
+	    if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
568
+		free(section_hdr);
569
+		free(src);
570
+		return CL_EMEM;
571
+	    }
572
+
573
+	    lseek(desc, EC32(section_hdr[i + 1].PointerToRawData), SEEK_SET);
574
+	    if(read(desc, src, ssize) != ssize) {
575
+		cli_dbgmsg("Can't read raw data of section %d\n", i);
576
+		free(section_hdr);
577
+		free(src);
578
+		free(dest);
579
+		return CL_EIO;
525 580
 	    }
526
-	}
527 581
 
528
-	if(!upx_success && upxfn != upx_inflate2e) {
529
-	    if(upx_inflate2e(src, ssize, dest, dsize) && upx_inflate2e(src + 0x15, ssize - 0x15, dest, dsize) ) {
530
-		cli_dbgmsg("UPX: NRV2E decompressor failed\n");
582
+	    /* try to detect UPX code */
583
+
584
+	    if(lseek(desc, ep, SEEK_SET) == -1) {
585
+		cli_dbgmsg("lseek() failed\n");
586
+		free(section_hdr);
587
+		free(src);
588
+		free(dest);
589
+		return CL_EIO;
590
+	    }
591
+
592
+	    if(read(desc, buff, 126) != 126) { /* i.e. 0x69 + 13 + 8 */
593
+		cli_dbgmsg("UPX: Can't read 126 bytes at 0x%x (%d)\n", ep, ep);
594
+		free(section_hdr);
595
+		free(src);
596
+		free(dest);
597
+		return CL_EIO;
531 598
 	    } else {
532
-		upx_success = 1;
533
-		cli_dbgmsg("UPX: Successfully decompressed with NRV2E\n");
599
+		if(cli_memstr(UPX_NRV2B, 24, buff + 0x69, 13) || cli_memstr(UPX_NRV2B, 24, buff + 0x69 + 8, 13)) {
600
+		    cli_dbgmsg("UPX: Looks like a NRV2B decompression routine\n");
601
+		    upxfn = upx_inflate2b;
602
+		} else if(cli_memstr(UPX_NRV2D, 24, buff + 0x69, 13) || cli_memstr(UPX_NRV2D, 24, buff + 0x69 + 8, 13)) {
603
+		    cli_dbgmsg("UPX: Looks like a NRV2D decompression routine\n");
604
+		    upxfn = upx_inflate2d;
605
+		} else if(cli_memstr(UPX_NRV2E, 24, buff + 0x69, 13) || cli_memstr(UPX_NRV2E, 24, buff + 0x69 + 8, 13)) {
606
+		    cli_dbgmsg("UPX: Looks like a NRV2E decompression routine\n");
607
+		    upxfn = upx_inflate2e;
608
+		}
609
+	    }
610
+
611
+	    if(upxfn) {
612
+		    int skew = cli_readint32(buff + 2) - EC32(optional_hdr.ImageBase) - EC32(section_hdr[i + 1].VirtualAddress);
613
+
614
+		if(buff[1] != '\xbe' || skew <= 0 || skew > 0xfff ) { /* FIXME: legit skews?? */
615
+		    skew = 0; 
616
+		    if(!upxfn(src, ssize, dest, dsize))
617
+			upx_success = 1;
618
+
619
+		} else {
620
+		    cli_dbgmsg("UPX: UPX1 seems skewed by %d bytes\n", skew);
621
+		    if(!upxfn(src + skew, ssize - skew, dest, dsize) || !upxfn(src, ssize, dest, dsize))
622
+			upx_success = 1;
623
+		}
624
+
625
+		if(upx_success)
626
+		    cli_dbgmsg("UPX: Successfully decompressed\n");
627
+		else
628
+		    cli_dbgmsg("UPX: Prefered decompressor failed\n");
629
+	    }
630
+
631
+	    if(!upx_success && upxfn != upx_inflate2b) {
632
+		if(upx_inflate2b(src, ssize, dest, dsize) && upx_inflate2b(src + 0x15, ssize - 0x15, dest, dsize) ) {
633
+		    cli_dbgmsg("UPX: NRV2B decompressor failed\n");
634
+		} else {
635
+		    upx_success = 1;
636
+		    cli_dbgmsg("UPX: Successfully decompressed with NRV2B\n");
637
+		}
638
+	    }
639
+
640
+	    if(!upx_success && upxfn != upx_inflate2d) {
641
+		if(upx_inflate2d(src, ssize, dest, dsize) && upx_inflate2d(src + 0x15, ssize - 0x15, dest, dsize) ) {
642
+		    cli_dbgmsg("UPX: NRV2D decompressor failed\n");
643
+		} else {
644
+		    upx_success = 1;
645
+		    cli_dbgmsg("UPX: Successfully decompressed with NRV2D\n");
646
+		}
647
+	    }
648
+
649
+	    if(!upx_success && upxfn != upx_inflate2e) {
650
+		if(upx_inflate2e(src, ssize, dest, dsize) && upx_inflate2e(src + 0x15, ssize - 0x15, dest, dsize) ) {
651
+		    cli_dbgmsg("UPX: NRV2E decompressor failed\n");
652
+		} else {
653
+		    upx_success = 1;
654
+		    cli_dbgmsg("UPX: Successfully decompressed with NRV2E\n");
655
+		}
656
+	    }
657
+
658
+	    if(!upx_success) {
659
+		cli_dbgmsg("UPX: All decompressors failed\n");
660
+		free(src);
661
+		free(dest);
534 662
 	    }
535 663
 	}
536 664
 
537
-	if(!upx_success) {
538
-	    cli_dbgmsg("UPX: All decompressors failed\n");
539
-	} else {
540
-	    int ndesc;
665
+	if(upx_success) {
666
+		int ndesc;
541 667
 
542 668
 	    if(cli_leavetemps_flag) {
543 669
 		tempfile = cli_gentemp(NULL);
544 670
 		if((ndesc = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU)) < 0) {
545
-		    cli_dbgmsg("UPX: Can't create file %s\n", tempfile);
671
+		    cli_dbgmsg("UPX/FSG: Can't create file %s\n", tempfile);
546 672
 		    free(tempfile);
547 673
 		    free(section_hdr);
548 674
 		    free(src);
... ...
@@ -551,7 +678,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
551 551
 		}
552 552
 
553 553
 		if(write(ndesc, dest, dsize) != dsize) {
554
-		    cli_dbgmsg("Can't write %d bytes\n", dsize);
554
+		    cli_dbgmsg("UPX/FSG: Can't write %d bytes\n", dsize);
555 555
 		    free(tempfile);
556 556
 		    free(section_hdr);
557 557
 		    free(src);
... ...
@@ -560,7 +687,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
560 560
 		}
561 561
 
562 562
 		close(ndesc);
563
-		cli_dbgmsg("UPX: Decompressed data saved in %s\n", tempfile);
563
+		cli_dbgmsg("UPX/FSG: Decompressed data saved in %s\n", tempfile);
564 564
 		free(tempfile);
565 565
 	    }
566 566
 
... ...
@@ -570,10 +697,10 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
570 570
 		free(dest);
571 571
 		return CL_VIRUS;
572 572
 	    }
573
-	}
574 573
 
575
-	free(src);
576
-	free(dest);
574
+	    free(src);
575
+	    free(dest);
576
+	}
577 577
     }
578 578
 
579 579
     /* Petite */