Browse code

New PE parsing model - Accurate virtual and raw size and offset calculations - Proper parsing of executables with weird/handcrafted/uncommon headers - Proper handling (or skipping) of ghost sections at various places in the code - Rebuild improvements for various unpackers - Adjusted alignment on rebuilt executables - Proper handling of out of sections offsets - Broken exe detection now mimics the XPSP2 loader (*) - Lots of misc improvements and fixes

(*) Except for SizeOfImage check which is still to be implemented


git-svn: trunk@2520

aCaB authored on 2006/11/27 07:23:11
Showing 14 changed files
... ...
@@ -1,3 +1,19 @@
1
+Sun Nov 26 23:04:20 CET 2006 (acab)
2
+-----------------------------------
3
+  * libclamav: New PE parsing model
4
+		- Accurate virtual and raw size and offset calculations
5
+		- Proper parsing of executables with
6
+		  weird/handcrafted/uncommon headers
7
+		- Proper handling (or skipping) of ghost sections at various
8
+		  places in the code
9
+		- Rebuild improvements for various unpackers
10
+		- Adjusted alignment on rebuilt executables
11
+		- Proper handling of out of sections offsets
12
+		- Broken exe detection now mimics the XPSP2 loader (*)
13
+		- Lots of misc improvements and fixes
14
+		(*) Except for SizeOfImage check which is still to be
15
+		implemented
16
+
1 17
 Fri Nov 24 02:01:48 CET 2006 (tk)
2 18
 ---------------------------------
3 19
   * libclamav: don't call phishing_init() if not needed (bb#147),
... ...
@@ -47,7 +47,7 @@
47 47
 
48 48
 int unfsg_200(char *source, char *dest, int ssize, int dsize, uint32_t rva, uint32_t base, uint32_t ep, int file) {
49 49
   char *tsrc;
50
-  struct SECTION section; /* Yup, just one ;) */
50
+  struct cli_exe_section section; /* Yup, just one ;) */
51 51
   
52 52
   if ( cli_unfsg(source, dest, ssize, dsize, NULL, NULL) ) return -1;
53 53
   
... ...
@@ -55,13 +55,8 @@ int unfsg_200(char *source, char *dest, int ssize, int dsize, uint32_t rva, uint
55 55
   section.rsz = dsize;
56 56
   section.vsz = dsize;
57 57
   section.rva = rva;
58
-  if ( (tsrc = rebuildpe(dest, &section, 1, base, ep, 0, 0)) ) {
59
-    if (cli_writen(file, tsrc, 0x148+0x80+0x28+dsize)==-1) {
60
-      free(tsrc);
61
-      return 0;
62
-    }
63
-    free(tsrc);
64
-  } else {
58
+
59
+  if (!cli_rebuildpe(dest, &section, 1, base, ep, 0, 0, file)) {
65 60
     cli_dbgmsg("FSG: Rebuilding failed\n");
66 61
     return 0;
67 62
   }
... ...
@@ -69,7 +64,7 @@ int unfsg_200(char *source, char *dest, int ssize, int dsize, uint32_t rva, uint
69 69
 }
70 70
 
71 71
 
72
-int unfsg_133(char *source, char *dest, int ssize, int dsize, struct SECTION *sections, int sectcount, uint32_t base, uint32_t ep, int file) {
72
+int unfsg_133(char *source, char *dest, int ssize, int dsize, struct cli_exe_section *sections, int sectcount, uint32_t base, uint32_t ep, int file) {
73 73
   char *tsrc=source, *tdst=dest;
74 74
   int i, upd=1, offs=0, lastsz=dsize;
75 75
 
... ...
@@ -118,16 +113,9 @@ int unfsg_133(char *source, char *dest, int ssize, int dsize, struct SECTION *se
118 118
     cli_dbgmsg("FSG: .SECT%d RVA:%x VSize:%x ROffset: %x, RSize:% x\n", i, sections[i].rva, sections[i].vsz, sections[i].raw, sections[i].rsz);
119 119
   }
120 120
 
121
-  if ( (tsrc = rebuildpe(dest, sections, sectcount+1, base, ep, 0, 0)) ) {
122
-    if (cli_writen(file, tsrc, 0x148+0x80+0x28*(sectcount+1)+offs)==-1) {
123
-      free(tsrc);
124
-      return 0;
125
-    }
126
-    free(tsrc);
127
-  } else {
121
+  if (!cli_rebuildpe(dest, sections, sectcount+1, base, ep, 0, 0, file)) {
128 122
     cli_dbgmsg("FSG: Rebuilding failed\n");
129 123
     return 0;
130 124
   }
131
-
132 125
   return 1;
133 126
 }
... ...
@@ -21,10 +21,10 @@
21 21
 #define __FSG_H
22 22
 
23 23
 #include "cltypes.h"
24
-#include "rebuildpe.h"
24
+#include "execs.h"
25 25
 
26 26
 int unfsg_200(char *, char *, int, int, uint32_t, uint32_t, uint32_t, int);
27
-int unfsg_133(char *, char *, int , int, struct SECTION *, int, uint32_t, uint32_t, int);
27
+int unfsg_133(char *, char *, int , int, struct cli_exe_section *, int, uint32_t, uint32_t, int);
28 28
 
29 29
 #endif
30 30
 
... ...
@@ -301,7 +301,7 @@ static off_t cli_caloff(const char *offstr, struct cli_target_info *info, int fd
301 301
 
302 302
     } else if(info->status == 1 && offstr[0] == 'S') {
303 303
 
304
-	if(!strncmp(offstr, "SL", 2)) {
304
+	if(!strncmp(offstr, "SL", 2) && info->exeinfo.section[info->exeinfo.nsections - 1].rsz) {
305 305
 
306 306
 	    if(sscanf(offstr, "SL+%lu", &offset) != 1) {
307 307
 		*ret = -1;
... ...
@@ -317,7 +317,7 @@ static off_t cli_caloff(const char *offstr, struct cli_target_info *info, int fd
317 317
 		return 0;
318 318
 	    }
319 319
 
320
-	    if(n >= info->exeinfo.nsections) {
320
+	    if(n >= info->exeinfo.nsections || !info->exeinfo.section[n].rsz) {
321 321
 		*ret = -1;
322 322
 		return 0;
323 323
 	    }
... ...
@@ -46,7 +46,6 @@
46 46
 #include "suecrypt.h"
47 47
 #include "unsp.h"
48 48
 #include "scanners.h"
49
-#include "rebuildpe.h"
50 49
 #include "str.h"
51 50
 #include "execs.h"
52 51
 #include "md5.h"
... ...
@@ -78,13 +77,22 @@ struct offset_list {
78 78
     struct offset_list *next;
79 79
 };
80 80
 
81
-static uint32_t cli_rawaddr(uint32_t rva, struct pe_image_section_hdr *shp, uint16_t nos, unsigned int *err, uint32_t valign, uint32_t falign)
81
+static uint32_t cli_rawaddr(uint32_t rva, struct cli_exe_section *shp, uint16_t nos, unsigned int *err,	size_t fsize)
82 82
 {
83 83
 	int i, found = 0;
84
+	uint32_t ret;
84 85
 
86
+    if (rva<0x1000) { /* Out of section EP - mapped to imagebase+rva */
87
+        if (rva >= fsize) {
88
+	    *err=1;
89
+	    return 0;
90
+	}
91
+        *err=0;
92
+	return rva;
93
+    }
85 94
 
86
-    for(i = 0; i < nos; i++) {
87
-      if(PEALIGN(EC32(shp[i].VirtualAddress), valign) <= rva && PEALIGN(EC32(shp[i].VirtualAddress), valign) + PESALIGN(EC32(shp[i].SizeOfRawData), falign) > rva) {
95
+    for(i = nos-1; i >= 0; i--) {
96
+        if(shp[i].rsz && shp[i].rva <= rva && shp[i].rsz > rva - shp[i].rva) {
88 97
 	    found = 1;
89 98
 	    break;
90 99
 	}
... ...
@@ -95,31 +103,32 @@ static uint32_t cli_rawaddr(uint32_t rva, struct pe_image_section_hdr *shp, uint
95 95
 	return 0;
96 96
     }
97 97
 
98
+    ret = rva - shp[i].rva + shp[i].raw;
98 99
     *err = 0;
99
-    return rva - PEALIGN(EC32(shp[i].VirtualAddress), valign) + PEALIGN(EC32(shp[i].PointerToRawData), falign);
100
+    return ret;
100 101
 }
101 102
 
102 103
 static void xckriz(char **opcode, int *len, int checksize, int reg) {
103
-	while(*len>6) {
104
-		if (**opcode>='\x48' && **opcode<='\x4f' && **opcode!='\x4c') {
105
-			if ((char)(**opcode-reg)=='\x48') break;
106
-			(*len)--;
107
-			(*opcode)++;
108
-			continue;
109
-		}
110
-		if (**opcode>='\xb8' && **opcode<='\xbf' && **opcode!='\xbc') {
111
-			if (checksize && cli_readint32(*opcode+1)==0x0fd2) break;
112
-			(*len)-=5;
113
-			(*opcode)+=5;
114
-			continue;
115
-		}
116
-		if (**opcode=='\x81') {
117
-			(*len)-=6;
118
-			(*opcode)+=6;
119
-			continue;
120
-		}
121
-		break;
104
+    while(*len>6) {
105
+        if (**opcode>='\x48' && **opcode<='\x4f' && **opcode!='\x4c') {
106
+	    if ((char)(**opcode-reg)=='\x48') break;
107
+	    (*len)--;
108
+	    (*opcode)++;
109
+	    continue;
110
+	}
111
+	if (**opcode>='\xb8' && **opcode<='\xbf' && **opcode!='\xbc') {
112
+	    if (checksize && cli_readint32(*opcode+1)==0x0fd2) break;
113
+	    (*len)-=5;
114
+	    (*opcode)+=5;
115
+	    continue;
116
+	}
117
+	if (**opcode=='\x81') {
118
+	    (*len)-=6;
119
+	    (*opcode)+=6;
120
+	    continue;
122 121
 	}
122
+	break;
123
+    }
123 124
 }
124 125
 
125 126
 
... ...
@@ -177,30 +186,23 @@ static int cli_ddump(int desc, int offset, int size, const char *file)
177 177
 }
178 178
 */
179 179
 
180
-static unsigned char *cli_md5sect(int fd, uint32_t offset, uint32_t size)
180
+static unsigned int cli_md5sect(int fd, uint32_t offset, uint32_t size, unsigned char *digest)
181 181
 {
182 182
 	size_t bread, sum = 0;
183 183
 	off_t pos;
184 184
 	char buff[FILEBUFF];
185
-	unsigned char *digest;
186 185
 	MD5_CTX md5ctx;
187 186
 
188 187
 
189 188
     if((pos = lseek(fd, 0, SEEK_CUR)) == -1) {
190 189
 	cli_dbgmsg("cli_md5sect: Invalid descriptor %d\n", fd);
191
-	return NULL;
190
+	return 0;
192 191
     }
193 192
 
194 193
     if(lseek(fd, offset, SEEK_SET) == -1) {
195 194
 	cli_dbgmsg("cli_md5sect: lseek() failed\n");
196 195
 	lseek(fd, pos, SEEK_SET);
197
-	return NULL;
198
-    }
199
-
200
-    digest = cli_calloc(16, sizeof(char));
201
-    if(!digest) {
202
-	cli_errmsg("cli_md5sect: Can't allocate memory for digest\n");
203
-	return NULL;
196
+	return 0;
204 197
     }
205 198
 
206 199
     MD5_Init(&md5ctx);
... ...
@@ -217,7 +219,7 @@ static unsigned char *cli_md5sect(int fd, uint32_t offset, uint32_t size)
217 217
 
218 218
     MD5_Final(digest, &md5ctx);
219 219
     lseek(fd, pos, SEEK_SET);
220
-    return digest;
220
+    return 1;
221 221
 }
222 222
 
223 223
 int cli_scanpe(int desc, cli_ctx *ctx)
... ...
@@ -225,24 +227,30 @@ int cli_scanpe(int desc, cli_ctx *ctx)
225 225
 	uint16_t e_magic; /* DOS signature ("MZ") */
226 226
 	uint16_t nsections;
227 227
 	uint32_t e_lfanew; /* address of new exe header */
228
-	uint32_t ep; /* entry point (raw) */
228
+	uint32_t ep, vep; /* entry point (raw, virtual) */
229 229
 	uint8_t polipos = 0;
230 230
 	time_t timestamp;
231 231
 	struct pe_image_file_hdr file_hdr;
232
-	struct pe_image_optional_hdr32 optional_hdr32;
233
-	struct pe_image_optional_hdr64 optional_hdr64;
232
+	union {
233
+	    struct pe_image_optional_hdr64 opt64;
234
+	    struct pe_image_optional_hdr32 opt32;
235
+	} pe_opt;
236
+	struct pe_image_optional_hdr64 optional_hdr64 = pe_opt.opt64;
237
+	struct pe_image_optional_hdr32 optional_hdr32 = pe_opt.opt32;
234 238
 	struct pe_image_section_hdr *section_hdr;
235 239
 	struct cli_md5_node *md5_sect;
236 240
 	struct stat sb;
237 241
 	char sname[9], buff[4096], *tempfile;
238
-	unsigned char *ubuff, *md5_dig;
242
+	unsigned char *ubuff;
239 243
 	ssize_t bytes;
240
-	unsigned int i, found, upx_success = 0, min = 0, max = 0, err, broken = 0;
244
+	unsigned int i, found, upx_success = 0, min = 0, max = 0, err;
241 245
 	unsigned int ssize = 0, dsize = 0, dll = 0, pe_plus = 0;
242 246
 	int (*upxfn)(char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t) = NULL;
243 247
 	char *src = NULL, *dest = NULL;
244 248
 	int ndesc, ret = CL_CLEAN;
245 249
 	size_t fsize;
250
+	uint32_t valign, falign;
251
+	struct cli_exe_section *exe_sections;
246 252
 
247 253
 
248 254
     if(cli_readn(desc, &e_magic, sizeof(e_magic)) != sizeof(e_magic)) {
... ...
@@ -394,7 +402,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
394 394
     }
395 395
 
396 396
     nsections = EC16(file_hdr.NumberOfSections);
397
-    if(nsections < 1 || nsections > 99) {
397
+    if(nsections < 1 || nsections > 96) {
398 398
 	if(DETECT_BROKEN) {
399 399
 	    if(ctx->virname)
400 400
 		*ctx->virname = "Broken.Executable";
... ...
@@ -413,111 +421,123 @@ int cli_scanpe(int desc, cli_ctx *ctx)
413 413
 
414 414
     cli_dbgmsg("SizeOfOptionalHeader: %x\n", EC16(file_hdr.SizeOfOptionalHeader));
415 415
 
416
-    if(EC16(file_hdr.SizeOfOptionalHeader) != sizeof(struct pe_image_optional_hdr32) && EC16(file_hdr.SizeOfOptionalHeader)!=0x148) {
417
-	if(EC16(file_hdr.SizeOfOptionalHeader) == sizeof(struct pe_image_optional_hdr64)) {
418
-	    pe_plus = 1;
419
-	} else {
420
-	    cli_dbgmsg("Incorrect value of SizeOfOptionalHeader\n");
421
-	    if(DETECT_BROKEN) {
422
-		if(ctx->virname)
423
-		    *ctx->virname = "Broken.Executable";
424
-		return CL_VIRUS;
425
-	    }
426
-	    return CL_CLEAN;
416
+    if (EC16(file_hdr.SizeOfOptionalHeader) < sizeof(struct pe_image_optional_hdr32)) {
417
+        cli_dbgmsg("SizeOfOptionalHeader too small\n");
418
+	if(DETECT_BROKEN) {
419
+	    if(ctx->virname)
420
+	        *ctx->virname = "Broken.Executable";
421
+	    return CL_VIRUS;
427 422
 	}
423
+	return CL_CLEAN;
428 424
     }
429 425
 
430
-    if(!pe_plus) { /* PE */
426
+    if(cli_readn(desc, &optional_hdr32, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) {
427
+        cli_dbgmsg("Can't read optional file header\n");
428
+	if(DETECT_BROKEN) {
429
+	    if(ctx->virname)
430
+	        *ctx->virname = "Broken.Executable";
431
+	    return CL_VIRUS;
432
+	}
433
+	return CL_CLEAN;
434
+    }
431 435
 
432
-	if(cli_readn(desc, &optional_hdr32, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) {
433
-	    cli_dbgmsg("Can't read optional file header\n");
436
+    /* This will be a chicken and egg problem until we drop 9x */
437
+    if(EC32(optional_hdr64.Magic)==PE32P_SIGNATURE) {
438
+        if(EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr64)) {
439
+	    /* FIXME: need to play around a bit more with xp64 */
440
+	    cli_dbgmsg("Incorrect SizeOfOptionalHeader for PE32+\n");
434 441
 	    if(DETECT_BROKEN) {
435
-		if(ctx->virname)
442
+	        if(ctx->virname)
436 443
 		    *ctx->virname = "Broken.Executable";
437 444
 		return CL_VIRUS;
438 445
 	    }
439 446
 	    return CL_CLEAN;
440 447
 	}
441
-	if (EC16(file_hdr.SizeOfOptionalHeader)==0x148) {
442
-	  cli_dbgmsg("Found long header\n");
443
-	  lseek(desc, (0x148-0xe0), SEEK_CUR); /* Seek to the end of the long header */
444
-	}
445
-
446
-	if(EC16(optional_hdr32.Magic) != PE32_SIGNATURE) {
448
+	pe_plus = 1;
449
+    } else {
450
+        /*
451
+	    either it's got a PE32_SIGNATURE or
452
+	    we enable win9x compatibility in that we don't honor magic (see bb#119)
453
+	    either way it's a 32bit thingy
454
+	*/
455
+        if(EC16(optional_hdr32.Magic) != PE32_SIGNATURE) {
447 456
 	    cli_warnmsg("Incorrect magic number in optional header\n");
448 457
 	    if(DETECT_BROKEN) {
449
-		if(ctx->virname)
458
+	        if(ctx->virname)
450 459
 		    *ctx->virname = "Broken.Executable";
451 460
 		return CL_VIRUS;
452 461
 	    }
453 462
 	}
463
+	cli_dbgmsg("9x compatibility mode\n");
464
+    }
465
+
466
+    if(!pe_plus) { /* PE */
467
+	if (EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr32)) {
468
+	    /* Seek to the end of the long header */
469
+	    lseek(desc, (EC16(file_hdr.SizeOfOptionalHeader)-sizeof(struct pe_image_optional_hdr32)), SEEK_CUR);
470
+	}
471
+
472
+	vep = EC32(optional_hdr32.AddressOfEntryPoint);
454 473
 	cli_dbgmsg("File format: PE\n");
455 474
 
456 475
 	cli_dbgmsg("MajorLinkerVersion: %d\n", optional_hdr32.MajorLinkerVersion);
457 476
 	cli_dbgmsg("MinorLinkerVersion: %d\n", optional_hdr32.MinorLinkerVersion);
458
-	cli_dbgmsg("SizeOfCode: %d\n", EC32(optional_hdr32.SizeOfCode));
459
-	cli_dbgmsg("SizeOfInitializedData: %d\n", EC32(optional_hdr32.SizeOfInitializedData));
460
-	cli_dbgmsg("SizeOfUninitializedData: %d\n", EC32(optional_hdr32.SizeOfUninitializedData));
461
-	cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", EC32(optional_hdr32.AddressOfEntryPoint));
477
+	cli_dbgmsg("SizeOfCode: 0x%x\n", EC32(optional_hdr32.SizeOfCode));
478
+	cli_dbgmsg("SizeOfInitializedData: 0x%x\n", EC32(optional_hdr32.SizeOfInitializedData));
479
+	cli_dbgmsg("SizeOfUninitializedData: 0x%x\n", EC32(optional_hdr32.SizeOfUninitializedData));
480
+	cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", vep);
462 481
 	cli_dbgmsg("BaseOfCode: 0x%x\n", EC32(optional_hdr32.BaseOfCode));
463
-	cli_dbgmsg("SectionAlignment: %d\n", EC32(optional_hdr32.SectionAlignment));
464
-	cli_dbgmsg("FileAlignment: %d\n", EC32(optional_hdr32.FileAlignment));
482
+	cli_dbgmsg("SectionAlignment: 0x%x\n", EC32(optional_hdr32.SectionAlignment));
483
+	cli_dbgmsg("FileAlignment: 0x%x\n", EC32(optional_hdr32.FileAlignment));
465 484
 	cli_dbgmsg("MajorSubsystemVersion: %d\n", EC16(optional_hdr32.MajorSubsystemVersion));
466 485
 	cli_dbgmsg("MinorSubsystemVersion: %d\n", EC16(optional_hdr32.MinorSubsystemVersion));
467
-	cli_dbgmsg("SizeOfImage: %d\n", EC32(optional_hdr32.SizeOfImage));
468
-	cli_dbgmsg("SizeOfHeaders: %d\n", EC32(optional_hdr32.SizeOfHeaders));
486
+	cli_dbgmsg("SizeOfImage: 0x%x\n", EC32(optional_hdr32.SizeOfImage));
487
+	cli_dbgmsg("SizeOfHeaders: 0x%x\n", EC32(optional_hdr32.SizeOfHeaders));
469 488
 	cli_dbgmsg("NumberOfRvaAndSizes: %d\n", EC32(optional_hdr32.NumberOfRvaAndSizes));
470 489
 
471 490
     } else { /* PE+ */
472
-
473
-	if(cli_readn(desc, &optional_hdr64, sizeof(struct pe_image_optional_hdr64)) != sizeof(struct pe_image_optional_hdr64)) {
474
-	    cli_dbgmsg("Can't optional file header\n");
491
+        /* read the remaining part of the header */
492
+        if(cli_readn(desc, &optional_hdr32 + 1, sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) {
493
+	    cli_dbgmsg("Can't read optional file header\n");
475 494
 	    if(DETECT_BROKEN) {
476
-		if(ctx->virname)
495
+	        if(ctx->virname)
477 496
 		    *ctx->virname = "Broken.Executable";
478 497
 		return CL_VIRUS;
479 498
 	    }
480 499
 	    return CL_CLEAN;
481 500
 	}
482 501
 
483
-	if(EC16(optional_hdr64.Magic) != PE32P_SIGNATURE) {
484
-	    cli_warnmsg("Incorrect magic number in optional header\n");
485
-	    if(DETECT_BROKEN) {
486
-		if(ctx->virname)
487
-		    *ctx->virname = "Broken.Executable";
488
-		return CL_VIRUS;
489
-	    }
490
-	}
502
+	vep = EC32(optional_hdr64.AddressOfEntryPoint);
491 503
 	cli_dbgmsg("File format: PE32+\n");
492 504
 
493 505
 	cli_dbgmsg("MajorLinkerVersion: %d\n", optional_hdr64.MajorLinkerVersion);
494 506
 	cli_dbgmsg("MinorLinkerVersion: %d\n", optional_hdr64.MinorLinkerVersion);
495
-	cli_dbgmsg("SizeOfCode: %d\n", EC32(optional_hdr64.SizeOfCode));
496
-	cli_dbgmsg("SizeOfInitializedData: %d\n", EC32(optional_hdr64.SizeOfInitializedData));
497
-	cli_dbgmsg("SizeOfUninitializedData: %d\n", EC32(optional_hdr64.SizeOfUninitializedData));
498
-	cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", EC32(optional_hdr64.AddressOfEntryPoint));
507
+	cli_dbgmsg("SizeOfCode: 0x%x\n", EC32(optional_hdr64.SizeOfCode));
508
+	cli_dbgmsg("SizeOfInitializedData: 0x%x\n", EC32(optional_hdr64.SizeOfInitializedData));
509
+	cli_dbgmsg("SizeOfUninitializedData: 0x%x\n", EC32(optional_hdr64.SizeOfUninitializedData));
510
+	cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", vep);
499 511
 	cli_dbgmsg("BaseOfCode: 0x%x\n", EC32(optional_hdr64.BaseOfCode));
500
-	cli_dbgmsg("SectionAlignment: %d\n", EC32(optional_hdr64.SectionAlignment));
501
-	cli_dbgmsg("FileAlignment: %d\n", EC32(optional_hdr64.FileAlignment));
512
+	cli_dbgmsg("SectionAlignment: 0x%x\n", EC32(optional_hdr64.SectionAlignment));
513
+	cli_dbgmsg("FileAlignment: 0x%x\n", EC32(optional_hdr64.FileAlignment));
502 514
 	cli_dbgmsg("MajorSubsystemVersion: %d\n", EC16(optional_hdr64.MajorSubsystemVersion));
503 515
 	cli_dbgmsg("MinorSubsystemVersion: %d\n", EC16(optional_hdr64.MinorSubsystemVersion));
504
-	cli_dbgmsg("SizeOfImage: %d\n", EC32(optional_hdr64.SizeOfImage));
505
-	cli_dbgmsg("SizeOfHeaders: %d\n", EC32(optional_hdr64.SizeOfHeaders));
516
+	cli_dbgmsg("SizeOfImage: 0x%x\n", EC32(optional_hdr64.SizeOfImage));
517
+	cli_dbgmsg("SizeOfHeaders: 0x%x\n", EC32(optional_hdr64.SizeOfHeaders));
506 518
 	cli_dbgmsg("NumberOfRvaAndSizes: %d\n", EC32(optional_hdr64.NumberOfRvaAndSizes));
507 519
     }
508 520
 
509 521
     if (DETECT_BROKEN && (!(pe_plus?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment)) || (pe_plus?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment))%0x1000)) {
510
-      cli_dbgmsg("Bad virtual alignemnt\n");
511
-      if(ctx->virname)
512
-	*ctx->virname = "Broken.Executable";
513
-      return CL_VIRUS;
522
+        cli_dbgmsg("Bad virtual alignemnt\n");
523
+        if(ctx->virname)
524
+	    *ctx->virname = "Broken.Executable";
525
+	return CL_VIRUS;
514 526
     }
515 527
 
516 528
     if (DETECT_BROKEN && (!(pe_plus?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment)) || (pe_plus?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment))%0x200)) {
517
-      cli_dbgmsg("Bad file alignemnt\n");
518
-      if(ctx->virname)
519
-	*ctx->virname = "Broken.Executable";
520
-      return CL_VIRUS;
529
+        cli_dbgmsg("Bad file alignemnt\n");
530
+	if(ctx->virname)
531
+	    *ctx->virname = "Broken.Executable";
532
+	return CL_VIRUS;
521 533
     }
522 534
 
523 535
     switch(pe_plus ? EC16(optional_hdr64.Subsystem) : EC16(optional_hdr32.Subsystem)) {
... ...
@@ -574,33 +594,60 @@ int cli_scanpe(int desc, cli_ctx *ctx)
574 574
 	return CL_EMEM;
575 575
     }
576 576
 
577
-    for(i = 0; i < nsections; i++) {
577
+    exe_sections = (struct cli_exe_section *) cli_calloc(nsections, sizeof(struct cli_exe_section));
578
+    
579
+    if(!exe_sections) {
580
+	cli_dbgmsg("Can't allocate memory for section headers\n");
581
+	free(section_hdr);
582
+	return CL_EMEM;
583
+    }
578 584
 
579
-	if(cli_readn(desc, &section_hdr[i], sizeof(struct pe_image_section_hdr)) != sizeof(struct pe_image_section_hdr)) {
580
-	    cli_dbgmsg("Can't read section header\n");
581
-	    cli_dbgmsg("Possibly broken PE file\n");
582
-	    free(section_hdr);
583
-	    if(DETECT_BROKEN) {
584
-		if(ctx->virname)
585
-		    *ctx->virname = "Broken.Executable";
586
-		return CL_VIRUS;
587
-	    }
588
-	    return CL_CLEAN;
585
+    valign = (pe_plus)?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment);
586
+    falign = (pe_plus)?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment);
587
+
588
+    if(cli_readn(desc, section_hdr, sizeof(struct pe_image_section_hdr)*nsections) != (int)(nsections*sizeof(struct pe_image_section_hdr))) {
589
+        cli_dbgmsg("Can't read section header\n");
590
+	cli_dbgmsg("Possibly broken PE file\n");
591
+	free(section_hdr);
592
+	free(exe_sections);
593
+	if(DETECT_BROKEN) {
594
+	    if(ctx->virname)
595
+		*ctx->virname = "Broken.Executable";
596
+	    return CL_VIRUS;
597
+	}
598
+	return CL_CLEAN;
599
+    }
600
+    
601
+    for(i = 0; falign!=0x200 && i<nsections; i++) {
602
+	/* file alignment fallback mode - blah */
603
+	if (section_hdr[i].SizeOfRawData && EC32(section_hdr[i].PointerToRawData)%falign && !(EC32(section_hdr[i].PointerToRawData)%0x200)) {
604
+	    cli_dbgmsg("Found misaligned section, using 0x200\n");
605
+	    falign = 0x200;
589 606
 	}
607
+    }
590 608
 
609
+    for(i = 0; i < nsections; i++) {
591 610
 	strncpy(sname, (char *) section_hdr[i].Name, 8);
592 611
 	sname[8] = 0;
612
+	exe_sections[i].rva = PEALIGN(EC32(section_hdr[i].VirtualAddress), valign);
613
+	exe_sections[i].vsz = PESALIGN(EC32(section_hdr[i].VirtualSize), valign);
614
+	exe_sections[i].raw = PEALIGN(EC32(section_hdr[i].PointerToRawData), falign);
615
+	exe_sections[i].rsz = PESALIGN(EC32(section_hdr[i].SizeOfRawData), falign);
616
+	if (exe_sections[i].rsz && fsize>exe_sections[i].raw && !CLI_ISCONTAINED(0, (uint32_t) fsize, exe_sections[i].raw, exe_sections[i].rsz))
617
+	    exe_sections[i].rsz = fsize - exe_sections[i].raw;
618
+	
593 619
 	cli_dbgmsg("Section %d\n", i);
594 620
 	cli_dbgmsg("Section name: %s\n", sname);
595
-	cli_dbgmsg("VirtualSize: %d\n", EC32(section_hdr[i].VirtualSize));
596
-	cli_dbgmsg("VirtualAddress: 0x%x\n", EC32(section_hdr[i].VirtualAddress));
597
-	cli_dbgmsg("SizeOfRawData: %d\n", EC32(section_hdr[i].SizeOfRawData));
598
-	cli_dbgmsg("PointerToRawData: 0x%x (%d)\n", EC32(section_hdr[i].PointerToRawData), EC32(section_hdr[i].PointerToRawData));
621
+	cli_dbgmsg("Section data (from headers - in memory)\n");
622
+	cli_dbgmsg("VirtualSize: 0x%x 0x%x\n", EC32(section_hdr[i].VirtualSize), exe_sections[i].vsz);
623
+	cli_dbgmsg("VirtualAddress: 0x%x 0x%x\n", EC32(section_hdr[i].VirtualAddress), exe_sections[i].rva);
624
+	cli_dbgmsg("SizeOfRawData: 0x%x 0x%x\n", EC32(section_hdr[i].SizeOfRawData), exe_sections[i].rsz);
625
+	cli_dbgmsg("PointerToRawData: 0x%x 0x%x\n", EC32(section_hdr[i].PointerToRawData), exe_sections[i].raw);
599 626
 
600 627
 	if(EC32(section_hdr[i].Characteristics) & 0x20) {
601 628
 	    cli_dbgmsg("Section contains executable code\n");
602 629
 
603
-	    if(EC32(section_hdr[i].VirtualSize) < EC32(section_hdr[i].SizeOfRawData)) {
630
+	    if(exe_sections[i].vsz < exe_sections[i].rsz) {
604 631
 		cli_dbgmsg("Section contains free space\n");
605 632
 		/*
606 633
 		cli_dbgmsg("Dumping %d bytes\n", section_hdr.SizeOfRawData - section_hdr.VirtualSize);
... ...
@@ -618,79 +665,81 @@ int cli_scanpe(int desc, cli_ctx *ctx)
618 618
 
619 619
 	cli_dbgmsg("------------------------------------\n");
620 620
 
621
-	if (DETECT_BROKEN && EC32(section_hdr[i].VirtualAddress)%((pe_plus)?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment))) { /* Bad virtual alignment */
621
+	if (DETECT_BROKEN && EC32(section_hdr[i].VirtualAddress)%valign) { /* Bad virtual alignment */
622 622
 	    cli_dbgmsg("VirtualAddress is misaligned\n");
623 623
 	    if(ctx->virname)
624 624
 	        *ctx->virname = "Broken.Executable";
625 625
 	    free(section_hdr);
626
+	    free(exe_sections);
626 627
 	    return CL_VIRUS;
627 628
 	}
628 629
 
629
-	if (EC32(section_hdr[i].SizeOfRawData)) { /* Don't bother with virtual only sections */
630
-	    if(!CLI_ISCONTAINED2(0, (uint32_t) fsize, EC32(section_hdr[i].PointerToRawData), EC32(section_hdr[i].SizeOfRawData)) || EC32(section_hdr[i].PointerToRawData) > fsize) {
631
-	        cli_dbgmsg("Possibly broken PE file - Section %d out of file (Offset@ %d, Rsize %d, Total filesize %d)\n", i, EC32(section_hdr[i].PointerToRawData), EC32(section_hdr[i].SizeOfRawData), fsize);
632
-		  if(DETECT_BROKEN) {
633
-		      if(ctx->virname)
634
-			  *ctx->virname = "Broken.Executable";
635
-		      free(section_hdr);
636
-		      return CL_VIRUS;
637
-		  }
638
-		  broken = 1;
639
-
640
-	    } else {
641
-	        /* check MD5 section sigs */
642
-	        md5_sect = ctx->engine->md5_sect;
643
-		while(md5_sect && md5_sect->size < EC32(section_hdr[i].SizeOfRawData))
644
-		    md5_sect = md5_sect->next;
645
-
646
-		if(md5_sect && md5_sect->size == EC32(section_hdr[i].SizeOfRawData)) {
647
-		    md5_dig = cli_md5sect(desc, EC32(section_hdr[i].PointerToRawData), EC32(section_hdr[i].SizeOfRawData));
648
-		    if(!md5_dig) {
649
-		        cli_errmsg("PE: Can't calculate MD5 for section %d\n", i);
650
-		    } else {
651
-		        while(md5_sect && md5_sect->size == EC32(section_hdr[i].SizeOfRawData)) {
652
-			    if(!memcmp(md5_dig, md5_sect->md5, 16)) {
653
-			        if(ctx->virname)
654
-				    *ctx->virname = md5_sect->virname;
655
-				free(md5_dig);
656
-				free(section_hdr);
657
-				return CL_VIRUS;
658
-			    }
659
-			    md5_sect = md5_sect->next;
630
+	if (exe_sections[i].rsz) { /* Don't bother with virtual only sections */
631
+	    unsigned char md5_dig[16];
632
+	    if (exe_sections[i].raw >= fsize) { /* really broken */
633
+	        cli_dbgmsg("Broken PE file - Section %d starts beyond the end of file (Offset@ %d, Total filesize %d)\n", i, exe_sections[i].raw, fsize);
634
+		free(section_hdr);
635
+		free(exe_sections);
636
+		if(DETECT_BROKEN) {
637
+		    if(ctx->virname)
638
+		        *ctx->virname = "Broken.Executable";
639
+		    return CL_VIRUS;
640
+		}
641
+		return CL_CLEAN; /* no ninjas to see here! move along! */
642
+	    }
643
+	    
644
+	    /* check MD5 section sigs */
645
+	    md5_sect = ctx->engine->md5_sect;
646
+	    while(md5_sect && md5_sect->size < exe_sections[i].rsz)
647
+	        md5_sect = md5_sect->next;
648
+
649
+	    if(md5_sect && md5_sect->size == exe_sections[i].rsz) {
650
+	        if(!cli_md5sect(desc, exe_sections[i].raw, exe_sections[i].rsz, md5_dig)) {
651
+		    cli_errmsg("PE: Can't calculate MD5 for section %d\n", i);
652
+		} else {
653
+		    while(md5_sect && md5_sect->size == exe_sections[i].rsz) {
654
+		        if(!memcmp(md5_dig, md5_sect->md5, 16)) {
655
+			    if(ctx->virname)
656
+			        *ctx->virname = md5_sect->virname;
657
+			    free(section_hdr);
658
+			    free(exe_sections);
659
+			    return CL_VIRUS;
660 660
 			}
661
-			free(md5_dig);
661
+			md5_sect = md5_sect->next;
662 662
 		    }
663 663
 		}
664 664
 	    }
665 665
 	}
666 666
 
667 667
 	if(!i) {
668
-	    if (DETECT_BROKEN && EC32(section_hdr[i].VirtualAddress)!=((pe_plus)?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment))) { /* Bad first section RVA */
668
+	    if (DETECT_BROKEN && EC32(section_hdr[i].VirtualAddress)!=valign) { /* Bad first section RVA */
669 669
 	        cli_dbgmsg("First section is in the wrong place\n");
670 670
 	        if(ctx->virname)
671 671
 		    *ctx->virname = md5_sect->virname;
672 672
 		free(section_hdr);
673
+		free(exe_sections);
673 674
 		return CL_VIRUS;
674 675
 	    }
675
-	    min = EC32(section_hdr[i].VirtualAddress);
676
-	    max = EC32(section_hdr[i].VirtualAddress) + EC32(section_hdr[i].SizeOfRawData);
676
+	    min = exe_sections[i].rva;
677
+	    max = exe_sections[i].rva + exe_sections[i].rsz;
677 678
 	} else {
678
-	    if (DETECT_BROKEN && EC32(section_hdr[i].VirtualAddress)-EC32(section_hdr[i-1].VirtualAddress)!=PESALIGN(EC32(section_hdr[i-1].VirtualSize), ((pe_plus)?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment)))) { /* No holes, no overlapping, no virtual disorder */
679
+	    if (DETECT_BROKEN && EC32(section_hdr[i].VirtualAddress)-EC32(section_hdr[i-1].VirtualAddress)!= exe_sections[i-1].vsz) { /* No holes, no overlapping, no virtual disorder */
679 680
 	        cli_dbgmsg("Virtually misplaced section (wrong order, overlapping, non contiguous)\n");
680 681
 	        if(ctx->virname)
681 682
 		    *ctx->virname = md5_sect->virname;
682 683
 		free(section_hdr);
684
+		free(exe_sections);
683 685
 		return CL_VIRUS;
684 686
 	    }
685
-	    if(EC32(section_hdr[i].VirtualAddress) < min)
686
-		min = EC32(section_hdr[i].VirtualAddress);
687
+	    if(exe_sections[i].rva < min)
688
+	        min = exe_sections[i].rva;
687 689
 
688
-	    if(EC32(section_hdr[i].VirtualAddress) + EC32(section_hdr[i].SizeOfRawData) > max)
689
-		max = EC32(section_hdr[i].VirtualAddress) + EC32(section_hdr[i].SizeOfRawData);
690
+	    if(exe_sections[i].rva + exe_sections[i].rsz > max)
691
+	        max = exe_sections[i].rva + exe_sections[i].rsz;
690 692
 	}
691 693
 
692 694
 	if(SCAN_ALGO && !strlen(sname)) {
693
-	    if(EC32(section_hdr[i].VirtualSize) > 40000 && EC32(section_hdr[i].VirtualSize) < 70000) {
695
+	    if(exe_sections[i].vsz > 40000 && exe_sections[i].vsz < 70000) {
694 696
 		if(EC32(section_hdr[i].Characteristics) == 0xe0000060) {
695 697
 		    polipos = i;
696 698
 		}
... ...
@@ -699,16 +748,10 @@ int cli_scanpe(int desc, cli_ctx *ctx)
699 699
 
700 700
     }
701 701
 
702
-
703
-
704
-    if(pe_plus)
705
-	ep = EC32(optional_hdr64.AddressOfEntryPoint);
706
-    else
707
-	ep = EC32(optional_hdr32.AddressOfEntryPoint);
708
-
709
-    if(ep >= min && !(ep = cli_rawaddr(ep, section_hdr, nsections, &err, 0, 0)) && err) {
710
-	cli_dbgmsg("Possibly broken PE file\n");
702
+    if(!(ep = cli_rawaddr(vep, exe_sections, nsections, &err, fsize)) && err) {
703
+	cli_dbgmsg("EntryPoint out of file\n");
711 704
 	free(section_hdr);
705
+	free(exe_sections);
712 706
 	if(DETECT_BROKEN) {
713 707
 	    if(ctx->virname)
714 708
 		*ctx->virname = "Broken.Executable";
... ...
@@ -721,13 +764,14 @@ int cli_scanpe(int desc, cli_ctx *ctx)
721 721
 
722 722
     if(pe_plus) { /* Do not continue for PE32+ files */
723 723
 	free(section_hdr);
724
+	free(exe_sections);
724 725
 	return CL_CLEAN;
725 726
     }
726 727
 
727 728
     /* Attempt to detect some popular polymorphic viruses */
728 729
 
729 730
     /* W32.Parite.B */
730
-    if(SCAN_ALGO && !dll && ep == EC32(section_hdr[nsections - 1].PointerToRawData)) {
731
+    if(SCAN_ALGO && !dll && ep == exe_sections[nsections - 1].raw) {
731 732
 	lseek(desc, ep, SEEK_SET);
732 733
 	if(cli_readn(desc, buff, 4096) == 4096) {
733 734
 		const char *pt = cli_memstr(buff, 4040, "\x47\x65\x74\x50\x72\x6f\x63\x41\x64\x64\x72\x65\x73\x73\x00", 15);
... ...
@@ -738,6 +782,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
738 738
 		if(((dw1 = cli_readint32(pt)) ^ (dw2 = cli_readint32(pt + 4))) == 0x505a4f && ((dw1 = cli_readint32(pt + 8)) ^ (dw2 = cli_readint32(pt + 12))) == 0xffffb && ((dw1 = cli_readint32(pt + 16)) ^ (dw2 = cli_readint32(pt + 20))) == 0xb8) {
739 739
 		    *ctx->virname = "W32.Parite.B";
740 740
 		    free(section_hdr);
741
+		    free(exe_sections);
741 742
 		    return CL_VIRUS;
742 743
 		}
743 744
 	    }
... ...
@@ -745,7 +790,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
745 745
     }
746 746
 
747 747
     /* Kriz */
748
-    if(SCAN_ALGO && CLI_ISCONTAINED(EC32(section_hdr[nsections - 1].PointerToRawData), EC32(section_hdr[nsections - 1].SizeOfRawData), ep, 0x0fd2)) {
748
+    if(SCAN_ALGO && CLI_ISCONTAINED(exe_sections[nsections - 1].raw, exe_sections[nsections - 1].rsz, ep, 0x0fd2)) {
749 749
 	cli_dbgmsg("in kriz\n");
750 750
 	lseek(desc, ep, SEEK_SET);
751 751
 	if(cli_readn(desc, buff, 200) == 200) {
... ...
@@ -800,6 +845,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
800 800
 			}
801 801
 			*ctx->virname = "Win32.Kriz";
802 802
 			free(section_hdr);
803
+			free(exe_sections);
803 804
 			return CL_VIRUS;
804 805
 		}
805 806
 	}
... ...
@@ -820,6 +866,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
820 820
 		if(cli_memstr(buff, 4091, "\xe8\x2c\x61\x00\x00", 5)) {
821 821
 		    *ctx->virname = "W32.Magistr.A";
822 822
 		    free(section_hdr);
823
+		    free(exe_sections);
823 824
 		    return CL_VIRUS;
824 825
 		} 
825 826
 	    }
... ...
@@ -832,6 +879,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
832 832
 		if(cli_memstr(buff, 4091, "\xe8\x04\x72\x00\x00", 5)) {
833 833
 		    *ctx->virname = "W32.Magistr.B";
834 834
 		    free(section_hdr);
835
+		    free(exe_sections);
835 836
 		    return CL_VIRUS;
836 837
 		} 
837 838
 	    }
... ...
@@ -840,7 +888,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
840 840
 
841 841
     /* W32.Polipos.A */
842 842
    if(polipos && !dll && nsections > 2 && nsections < 13 && e_lfanew <= 0x800 && (EC16(optional_hdr32.Subsystem) == 2 || EC16(optional_hdr32.Subsystem) == 3) && EC16(file_hdr.Machine) == 0x14c && optional_hdr32.SizeOfStackReserve >= 0x80000) {
843
-		uint32_t remaining = EC32(section_hdr[0].SizeOfRawData);
843
+		uint32_t remaining = exe_sections[0].rsz;
844 844
 		uint32_t chunk = sizeof(buff);
845 845
 		uint32_t val, shift, raddr, total = 0;
846 846
 		const char *jpt;
... ...
@@ -852,23 +900,24 @@ int cli_scanpe(int desc, cli_ctx *ctx)
852 852
 	if(remaining < chunk)
853 853
 	    chunk = remaining;
854 854
 
855
-	lseek(desc, EC32(section_hdr[0].PointerToRawData), SEEK_SET);
855
+	lseek(desc, exe_sections[0].raw, SEEK_SET);
856 856
 	while((bytes = cli_readn(desc, buff, chunk)) > 0) {
857 857
 	    shift = 0;
858
-	    while(bytes - 5 > shift) {
858
+	    while((uint32_t)bytes - 5 > shift) {
859 859
 		jpt = buff + shift;
860 860
 		if(*jpt!='\xe9' && *jpt!='\xe8') {
861 861
 		    shift++;
862 862
 		    continue;
863 863
 		}
864 864
 		val = cli_readint32(jpt + 1);
865
-		val += 5 + EC32(section_hdr[0].VirtualAddress) + total + shift;
866
-		raddr = cli_rawaddr(val, section_hdr, nsections, &err, 0, 0);
865
+		val += 5 + exe_sections[0].rva + total + shift;
866
+		raddr = cli_rawaddr(val, exe_sections, nsections, &err, fsize);
867 867
 
868
-		if(!err && (raddr >= EC32(section_hdr[polipos].PointerToRawData) && raddr < EC32(section_hdr[polipos].PointerToRawData) + EC32(section_hdr[polipos].SizeOfRawData)) && (!offlist || (raddr != offlist->offset))) {
868
+		if(!err && (raddr >= exe_sections[polipos].raw && raddr < exe_sections[polipos].raw + exe_sections[polipos].rsz) && (!offlist || (raddr != offlist->offset))) {
869 869
 		    offnode = (struct offset_list *) cli_malloc(sizeof(struct offset_list));
870 870
 		    if(!offnode) {
871 871
 			free(section_hdr);
872
+			free(exe_sections);
872 873
 			while(offlist) {
873 874
 			    offnode = offlist;
874 875
 			    offlist = offlist->next;
... ...
@@ -925,33 +974,30 @@ int cli_scanpe(int desc, cli_ctx *ctx)
925 925
 
926 926
 	if(ret == CL_VIRUS) {
927 927
 	    free(section_hdr);
928
+	    free(exe_sections);
928 929
 	    return CL_VIRUS;
929 930
 	}
930 931
     }
931 932
 
932 933
 
933
-    if(broken) {
934
-	free(section_hdr);
935
-	return CL_CLEAN;
936
-    }
937
-
938 934
 #ifdef CL_EXPERIMENTAL
939 935
     /* SUE */
940 936
     
941
-    if(nsections > 2 && EC32(optional_hdr32.AddressOfEntryPoint) == EC32(section_hdr[nsections - 1].VirtualAddress) && EC32(section_hdr[nsections - 1].SizeOfRawData) > 0x350 && EC32(section_hdr[nsections - 1].SizeOfRawData) < 0x292+0x350+1000) {
937
+    if(nsections > 2 && vep == exe_sections[nsections - 1].rva && exe_sections[nsections - 1].rsz > 0x350 && exe_sections[nsections - 1].rsz < 0x292+0x350+1000) {
942 938
   
943 939
       
944 940
       char *sue=buff+0x74;
945 941
       uint32_t key;
946 942
       
947 943
       if(lseek(desc, ep-4, SEEK_SET) == -1) {
948
-	cli_dbgmsg("SUE: lseek() failed - EP out of file\n");
944
+	cli_dbgmsg("SUE: lseek() failed\n");
949 945
 	free(section_hdr);
946
+	free(exe_sections);
950 947
 	return CL_EIO;
951 948
       }
952
-      if((unsigned int) cli_readn(desc, buff, EC32(section_hdr[nsections - 1].SizeOfRawData)+4) == EC32(section_hdr[nsections - 1].SizeOfRawData)+4) {
949
+      if((unsigned int) cli_readn(desc, buff, exe_sections[nsections - 1].rsz+4) == exe_sections[nsections - 1].rsz+4) {
953 950
 	found=0;
954
-	while(CLI_ISCONTAINED(buff+4, EC32(section_hdr[nsections - 1].SizeOfRawData), sue, 4*3)) {
951
+	while(CLI_ISCONTAINED(buff+4, exe_sections[nsections - 1].rsz, sue, 4*3)) {
955 952
 	  if((cli_readint32(sue)^cli_readint32(sue+4))==0x5c41090e && (cli_readint32(sue)^cli_readint32(sue+8))==0x021e0145) {
956 953
 	    found=1;
957 954
 	    key=(cli_readint32(sue)^0x6e72656b);
... ...
@@ -960,28 +1006,31 @@ int cli_scanpe(int desc, cli_ctx *ctx)
960 960
 	  sue++;
961 961
 	}
962 962
 	cli_dbgmsg("SUE: key(%x) found @%x\n", key, sue-buff);
963
-	if (found && CLI_ISCONTAINED(buff, EC32(section_hdr[nsections - 1].SizeOfRawData), sue-0x74, 0xbe) &&
964
-	    (sue=sudecrypt(desc, fsize, section_hdr, nsections-1, sue, key, cli_readint32(buff), e_lfanew))) {
963
+	if (found && CLI_ISCONTAINED(buff, exe_sections[nsections - 1].rsz, sue-0x74, 0xbe) &&
964
+	    (sue=sudecrypt(desc, fsize, exe_sections, nsections-1, sue, key, cli_readint32(buff), e_lfanew))) {
965 965
 	  if(!(tempfile = cli_gentemp(NULL))) {
966 966
 	    free(sue);
967 967
 	    free(section_hdr);
968
+	    free(exe_sections);
968 969
 	    return CL_EMEM;
969 970
 	  }
970
-	  
971
+
971 972
 	  if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
972 973
 	    cli_dbgmsg("sue: Can't create file %s\n", tempfile);
973 974
 	    free(tempfile);
974 975
 	    free(sue);
975 976
 	    free(section_hdr);
977
+	    free(exe_sections);
976 978
 	    return CL_EIO;
977 979
 	  }
978 980
 	  
979
-	  if((unsigned int) write(ndesc, sue, ep) != ep) {
981
+	  if((unsigned int) cli_writen(ndesc, sue, ep) != ep) {
980 982
 	    cli_dbgmsg("sue: Can't write %d bytes\n", ep);
981 983
 	    close(ndesc);
982 984
 	    free(tempfile);
983 985
 	    free(sue);
984 986
 	    free(section_hdr);
987
+	    free(exe_sections);
985 988
 	    return CL_EIO;
986 989
 	  }
987 990
 
... ...
@@ -995,6 +1044,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
995 995
 
996 996
 	  if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) {
997 997
 	    free(section_hdr);
998
+	    free(exe_sections);
998 999
 	    close(ndesc);
999 1000
 	    if(!cli_leavetemps_flag)
1000 1001
 	      unlink(tempfile);
... ...
@@ -1029,6 +1079,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1029 1029
 	if(lseek(desc, ep, SEEK_SET) == -1) {
1030 1030
 	    cli_dbgmsg("UPX/FSG: lseek() failed\n");
1031 1031
 	    free(section_hdr);
1032
+	    free(exe_sections);
1032 1033
 	    return CL_EIO;
1033 1034
 	}
1034 1035
 
... ...
@@ -1036,6 +1087,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1036 1036
 	    cli_dbgmsg("UPX/FSG: Can't read 168 bytes at 0x%x (%d)\n", ep, ep);
1037 1037
 	    cli_dbgmsg("UPX/FSG: Broken or not UPX/FSG compressed file\n");
1038 1038
             free(section_hdr);
1039
+	    free(exe_sections);
1039 1040
 	    return CL_CLEAN;
1040 1041
 	}
1041 1042
 
... ...
@@ -1043,8 +1095,8 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1043 1043
 
1044 1044
 	    /* FSG v2.0 support - thanks to aCaB ! */
1045 1045
 
1046
-	    ssize = EC32(section_hdr[i + 1].SizeOfRawData);
1047
-	    dsize = EC32(section_hdr[i].VirtualSize);
1046
+	    ssize = exe_sections[i + 1].rsz;
1047
+	    dsize = exe_sections[i].vsz;
1048 1048
 
1049 1049
 	    while(found) {
1050 1050
 		    uint32_t newesi, newedi, newebx, newedx;
... ...
@@ -1052,6 +1104,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1052 1052
 		if(ctx->limits && ctx->limits->maxfilesize && (ssize > ctx->limits->maxfilesize || dsize > ctx->limits->maxfilesize)) {
1053 1053
 		    cli_dbgmsg("FSG: Sizes exceeded (ssize: %u, dsize: %u, max: %lu)\n", ssize, dsize , ctx->limits->maxfilesize);
1054 1054
 		    free(section_hdr);
1055
+		    free(exe_sections);
1055 1056
 		    if(BLOCKMAX) {
1056 1057
 			*ctx->virname = "PE.FSG.ExceededFileSize";
1057 1058
 			return CL_VIRUS;
... ...
@@ -1063,40 +1116,47 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1063 1063
 		if(ssize <= 0x19 || dsize <= ssize) {
1064 1064
 		    cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize);
1065 1065
 		    free(section_hdr);
1066
+		    free(exe_sections);
1066 1067
 		    return CL_CLEAN;
1067 1068
 		}
1068 1069
 
1069
-		if((newedx = cli_readint32(buff + 2) - EC32(optional_hdr32.ImageBase)) < EC32(section_hdr[i + 1].VirtualAddress) || newedx >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 4) {
1070
+		newedx = cli_readint32(buff + 2) - EC32(optional_hdr32.ImageBase);
1071
+		if(!CLI_ISCONTAINED(exe_sections[i + 1].rva, exe_sections[i + 1].rsz, newedx, 4)) {
1070 1072
 		    cli_dbgmsg("FSG: xchg out of bounds (%x), giving up\n", newedx);
1071 1073
 		    break;
1072 1074
 		}
1073 1075
 
1074 1076
 		if((src = (char *) cli_malloc(ssize)) == NULL) {
1075 1077
 		    free(section_hdr);
1078
+		    free(exe_sections);
1076 1079
 		    return CL_EMEM;
1077 1080
 		}
1078 1081
 
1079
-		lseek(desc, EC32(section_hdr[i + 1].PointerToRawData), SEEK_SET);
1082
+		lseek(desc, exe_sections[i + 1].raw, SEEK_SET);
1080 1083
 		if((unsigned int) cli_readn(desc, src, ssize) != ssize) {
1081
-		    cli_dbgmsg("Can't read raw data of section %d\n", i);
1084
+		    cli_dbgmsg("Can't read raw data of section %d\n", i + 1);
1082 1085
 		    free(section_hdr);
1086
+		    free(exe_sections);
1083 1087
 		    free(src);
1084 1088
 		    return CL_EIO;
1085 1089
 		}
1086 1090
 
1087
-		if(newedx < EC32(section_hdr[i + 1].VirtualAddress) || ((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)) {
1091
+		dest = src + newedx - exe_sections[i + 1].rva;
1092
+		if(newedx < exe_sections[i + 1].rva || !CLI_ISCONTAINED(src, ssize, dest, 4)) {
1088 1093
 		    cli_dbgmsg("FSG: New ESP out of bounds\n");
1089 1094
 		    free(src);
1090 1095
 		    break;
1091 1096
 		}
1092 1097
 
1093
-		if((newedx = cli_readint32(dest) - EC32(optional_hdr32.ImageBase)) <= EC32(section_hdr[i + 1].VirtualAddress) || newedx >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 4) {
1098
+		newedx = cli_readint32(dest) - EC32(optional_hdr32.ImageBase);
1099
+		if(!CLI_ISCONTAINED(exe_sections[i + 1].rva, exe_sections[i + 1].rsz, newedx, 4)) {
1094 1100
 		    cli_dbgmsg("FSG: New ESP (%x) is wrong\n", newedx);
1095 1101
 		    free(src);
1096 1102
 		    break;
1097 1103
 		}
1098 1104
  
1099
-		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) {
1105
+		dest = src + newedx - exe_sections[i + 1].rva;
1106
+		if(!CLI_ISCONTAINED(src, ssize, dest, 32)) {
1100 1107
 		    cli_dbgmsg("FSG: New stack out of bounds\n");
1101 1108
 		    free(src);
1102 1109
 		    break;
... ...
@@ -1107,35 +1167,37 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1107 1107
 		newebx = cli_readint32(dest + 16) - EC32(optional_hdr32.ImageBase);
1108 1108
 		newedx = cli_readint32(dest + 20);
1109 1109
 
1110
-		if(newedi != EC32(section_hdr[i].VirtualAddress)) {
1111
-		    cli_dbgmsg("FSG: Bad destination buffer (edi is %x should be %x)\n", newedi, EC32(section_hdr[i].VirtualAddress));
1110
+		if(newedi != exe_sections[i].rva) {
1111
+		    cli_dbgmsg("FSG: Bad destination buffer (edi is %x should be %x)\n", newedi, exe_sections[i].rva);
1112 1112
 		    free(src);
1113 1113
 		    break;
1114 1114
 		}
1115 1115
 
1116
-		if(newesi < EC32(section_hdr[i + 1].VirtualAddress) || newesi >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData)) {
1116
+		if(newesi < exe_sections[i + 1].rva || newesi - exe_sections[i + 1].rva >= exe_sections[i + 1].rsz) {
1117 1117
 		    cli_dbgmsg("FSG: Source buffer out of section bounds\n");
1118 1118
 		    free(src);
1119 1119
 		    break;
1120 1120
 		}
1121 1121
 
1122
-		if(newebx < EC32(section_hdr[i + 1].VirtualAddress) || newebx >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 16) {
1122
+		if(!CLI_ISCONTAINED(exe_sections[i + 1].rva, exe_sections[i + 1].rsz, newebx, 16)) {
1123 1123
 		    cli_dbgmsg("FSG: Array of functions out of bounds\n");
1124 1124
 		    free(src);
1125 1125
 		    break;
1126 1126
 		}
1127 1127
 
1128
-		newedx=cli_readint32(newebx + 12 - EC32(section_hdr[i + 1].VirtualAddress) + src) - EC32(optional_hdr32.ImageBase);
1128
+		newedx=cli_readint32(newebx + 12 - exe_sections[i + 1].rva + src) - EC32(optional_hdr32.ImageBase);
1129 1129
 		cli_dbgmsg("FSG: found old EP @%x\n",newedx);
1130 1130
 
1131 1131
 		if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
1132 1132
 		    free(section_hdr);
1133
+		    free(exe_sections);
1133 1134
 		    free(src);
1134 1135
 		    return CL_EMEM;
1135 1136
 		}
1136 1137
 
1137 1138
 		if(!(tempfile = cli_gentemp(NULL))) {
1138 1139
 		    free(section_hdr);
1140
+		    free(exe_sections);
1139 1141
 		    free(src);
1140 1142
 		    return CL_EMEM;
1141 1143
 		}
... ...
@@ -1144,12 +1206,13 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1144 1144
 		    cli_dbgmsg("FSG: Can't create file %s\n", tempfile);
1145 1145
 		    free(tempfile);
1146 1146
 		    free(section_hdr);
1147
+		    free(exe_sections);
1147 1148
 		    free(src);
1148 1149
 		    free(dest);
1149 1150
 		    return CL_EIO;
1150 1151
 		}
1151 1152
 		
1152
-		switch (unfsg_200(newesi - EC32(section_hdr[i + 1].VirtualAddress) + src, dest, ssize + EC32(section_hdr[i + 1].VirtualAddress) - newesi, dsize, newedi, EC32(optional_hdr32.ImageBase), newedx, ndesc)) {
1153
+		switch (unfsg_200(newesi - exe_sections[i + 1].rva + src, dest, ssize + exe_sections[i + 1].rva - newesi, dsize, newedi, EC32(optional_hdr32.ImageBase), newedx, ndesc)) {
1153 1154
 		    case 1: /* Everything OK */
1154 1155
 			cli_dbgmsg("FSG: Unpacked and rebuilt executable saved in %s\n", tempfile);
1155 1156
 			free(src);
... ...
@@ -1160,6 +1223,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1160 1160
 			cli_dbgmsg("***** Scanning rebuilt PE file *****\n");
1161 1161
 			if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) {
1162 1162
 			    free(section_hdr);
1163
+			    free(exe_sections);
1163 1164
 			    close(ndesc);
1164 1165
 			    if(!cli_leavetemps_flag)
1165 1166
 				unlink(tempfile);
... ...
@@ -1172,10 +1236,11 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1172 1172
 			    unlink(tempfile);
1173 1173
 			free(tempfile);
1174 1174
 			free(section_hdr);
1175
+			free(exe_sections);
1175 1176
 			return CL_CLEAN;
1176 1177
 
1177 1178
 		    case 0: /* We've got an unpacked buffer, no exe though */
1178
-			cli_dbgmsg("FSG: FSG: Successfully decompressed\n");
1179
+			cli_dbgmsg("FSG: Successfully decompressed\n");
1179 1180
 			close(ndesc);
1180 1181
 			unlink(tempfile);
1181 1182
 			free(tempfile);
... ...
@@ -1201,19 +1266,20 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1201 1201
 
1202 1202
 	    /* FSG support - v. 1.33 (thx trog for the many samples) */
1203 1203
 
1204
-	    ssize = EC32(section_hdr[i + 1].SizeOfRawData);
1205
-	    dsize = EC32(section_hdr[i].VirtualSize);
1204
+	    ssize = exe_sections[i + 1].rsz;
1205
+	    dsize = exe_sections[i].vsz;
1206 1206
 
1207 1207
 	    while(found) {
1208
-	            int gp, t, sectcnt = 0;
1208
+	            int sectcnt = 0;
1209 1209
 		    char *support;
1210
-		    uint32_t newesi, newedi, newebx, oldep;
1211
-		    struct SECTION *sections;
1210
+		    uint32_t newesi, newedi, newebx, oldep, gp, t;
1211
+		    struct cli_exe_section *sections;
1212 1212
 
1213 1213
 
1214 1214
 		if(ctx->limits && ctx->limits->maxfilesize && (ssize > ctx->limits->maxfilesize || dsize > ctx->limits->maxfilesize)) {
1215 1215
 		    cli_dbgmsg("FSG: Sizes exceeded (ssize: %u, dsize: %u, max: %lu)\n", ssize, dsize, ctx->limits->maxfilesize);
1216 1216
 		    free(section_hdr);
1217
+		    free(exe_sections);
1217 1218
 		    if(BLOCKMAX) {
1218 1219
 			*ctx->virname = "PE.FSG.ExceededFileSize";
1219 1220
 			return CL_VIRUS;
... ...
@@ -1225,20 +1291,22 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1225 1225
 		if(ssize <= 0x19 || dsize <= ssize) {
1226 1226
 		    cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize);
1227 1227
 		    free(section_hdr);
1228
+		    free(exe_sections);
1228 1229
 		    return CL_CLEAN;
1229 1230
 		}
1230 1231
 
1231
-		if((gp = cli_readint32(buff + 1) - EC32(optional_hdr32.ImageBase)) >= (int) EC32(section_hdr[i + 1].PointerToRawData) || gp < 0) {
1232
-		    cli_dbgmsg("FSG: Support data out of padding area (vaddr: %d)\n", EC32(section_hdr[i].VirtualAddress));
1232
+		if(!(gp = cli_rawaddr(cli_readint32(buff + 1) - EC32(optional_hdr32.ImageBase), NULL, 0 , &err, fsize)) && err ) {
1233
+		    cli_dbgmsg("FSG: Support data out of padding area\n");
1233 1234
 		    break;
1234 1235
 		}
1235 1236
 
1236 1237
 		lseek(desc, gp, SEEK_SET);
1237
-		gp = EC32(section_hdr[i + 1].PointerToRawData) - gp;
1238
+		gp = exe_sections[i + 1].raw - gp;
1238 1239
 
1239 1240
 		if(ctx->limits && ctx->limits->maxfilesize && (unsigned int) gp > ctx->limits->maxfilesize) {
1240 1241
 		    cli_dbgmsg("FSG: Buffer size exceeded (size: %d, max: %lu)\n", gp, ctx->limits->maxfilesize);
1241 1242
 		    free(section_hdr);
1243
+		    free(exe_sections);
1242 1244
 		    if(BLOCKMAX) {
1243 1245
 			*ctx->virname = "PE.FSG.ExceededFileSize";
1244 1246
 			return CL_VIRUS;
... ...
@@ -1249,28 +1317,30 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1249 1249
 
1250 1250
 		if((support = (char *) cli_malloc(gp)) == NULL) {
1251 1251
 		    free(section_hdr);
1252
+		    free(exe_sections);
1252 1253
 		    return CL_EMEM;
1253 1254
 		}
1254 1255
 
1255
-		if(cli_readn(desc, support, gp) != gp) {
1256
+		if((int)cli_readn(desc, support, gp) != (int)gp) {
1256 1257
 		    cli_dbgmsg("Can't read %d bytes from padding area\n", gp); 
1257 1258
 		    free(section_hdr);
1259
+		    free(exe_sections);
1258 1260
 		    free(support);
1259 1261
 		    return CL_EIO;
1260 1262
 		}
1261 1263
 
1262
-		newebx = cli_readint32(support) - EC32(optional_hdr32.ImageBase); /* Unused */
1264
+		/* newebx = cli_readint32(support) - EC32(optional_hdr32.ImageBase);  Unused */
1263 1265
 		newedi = cli_readint32(support + 4) - EC32(optional_hdr32.ImageBase); /* 1st dest */
1264 1266
 		newesi = cli_readint32(support + 8) - EC32(optional_hdr32.ImageBase); /* Source */
1265 1267
 
1266
-		if(newesi < EC32(section_hdr[i + 1].VirtualAddress) || newesi >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData)) {
1268
+		if(newesi < exe_sections[i + 1].rva || newesi - exe_sections[i + 1].rva >= exe_sections[i + 1].rsz) {
1267 1269
 		    cli_dbgmsg("FSG: Source buffer out of section bounds\n");
1268 1270
 		    free(support);
1269 1271
 		    break;
1270 1272
 		}
1271 1273
 
1272
-		if(newedi != EC32(section_hdr[i].VirtualAddress)) {
1273
-		    cli_dbgmsg("FSG: Bad destination (is %x should be %x)\n", newedi, EC32(section_hdr[i].VirtualAddress));
1274
+		if(newedi != exe_sections[i].rva) {
1275
+		    cli_dbgmsg("FSG: Bad destination (is %x should be %x)\n", newedi, exe_sections[i].rva);
1274 1276
 		    free(support);
1275 1277
 		    break;
1276 1278
 		}
... ...
@@ -1289,7 +1359,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1289 1289
 			/* FIXME: really need to bother? */
1290 1290
 			cli_dbgmsg("FSG: Original section %d is misaligned\n", sectcnt);
1291 1291
 
1292
-		    if(rva < EC32(section_hdr[i].VirtualAddress) || rva >= EC32(section_hdr[i].VirtualAddress)+EC32(section_hdr[i].VirtualSize)) {
1292
+		    if(rva < exe_sections[i].rva || rva - exe_sections[i].rva >= exe_sections[i].vsz) {
1293 1293
 			cli_dbgmsg("FSG: Original section %d is out of bounds\n", sectcnt);
1294 1294
 			break;
1295 1295
 		    }
... ...
@@ -1300,28 +1370,31 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1300 1300
 		    break;
1301 1301
 		}
1302 1302
 
1303
-		if((sections = (struct SECTION *) cli_malloc((sectcnt + 1) * sizeof(struct SECTION))) == NULL) {
1303
+		if((sections = (struct cli_exe_section *) cli_malloc((sectcnt + 1) * sizeof(struct cli_exe_section))) == NULL) {
1304 1304
 		    free(section_hdr);
1305
+		    free(exe_sections);
1305 1306
 		    free(support);
1306 1307
 		    return CL_EMEM;
1307 1308
 		}
1308 1309
 
1309 1310
 		sections[0].rva = newedi;
1310
-		for(t = 1; t <= sectcnt; t++)
1311
-		    sections[t].rva = cli_readint32(support + 8 + t * 4) - 1 -EC32(optional_hdr32.ImageBase);
1311
+		for(t = 1; t <= (uint32_t)sectcnt; t++)
1312
+		    sections[t].rva = cli_readint32(support + 8 + t * 4) - 1 - EC32(optional_hdr32.ImageBase);
1312 1313
 
1313 1314
 		free(support);
1314 1315
 
1315 1316
 		if((src = (char *) cli_malloc(ssize)) == NULL) {
1316 1317
 		    free(section_hdr);
1318
+		    free(exe_sections);
1317 1319
 		    free(sections);
1318 1320
 		    return CL_EMEM;
1319 1321
 		}
1320 1322
 
1321
-		lseek(desc, EC32(section_hdr[i + 1].PointerToRawData), SEEK_SET);
1323
+		lseek(desc, exe_sections[i + 1].raw, SEEK_SET);
1322 1324
 		if((unsigned int) cli_readn(desc, src, ssize) != ssize) {
1323 1325
 		    cli_dbgmsg("Can't read raw data of section %d\n", i);
1324 1326
 		    free(section_hdr);
1327
+		    free(exe_sections);
1325 1328
 		    free(sections);
1326 1329
 		    free(src);
1327 1330
 		    return CL_EIO;
... ...
@@ -1329,16 +1402,18 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1329 1329
 
1330 1330
 		if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
1331 1331
 		    free(section_hdr);
1332
+		    free(exe_sections);
1332 1333
 		    free(src);
1333 1334
 		    free(sections);
1334 1335
 		    return CL_EMEM;
1335 1336
 		}
1336 1337
 
1337
-		oldep = EC32(optional_hdr32.AddressOfEntryPoint) + 161 + 6 + cli_readint32(buff+163);
1338
+		oldep = vep + 161 + 6 + cli_readint32(buff+163);
1338 1339
 		cli_dbgmsg("FSG: found old EP @%x\n", oldep);
1339 1340
 
1340 1341
 		if(!(tempfile = cli_gentemp(NULL))) {
1341 1342
 		    free(section_hdr);
1343
+		    free(exe_sections);
1342 1344
 		    free(src);
1343 1345
 		    free(dest);
1344 1346
 		    free(sections);
... ...
@@ -1349,13 +1424,14 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1349 1349
 		    cli_dbgmsg("FSG: Can't create file %s\n", tempfile);
1350 1350
 		    free(tempfile);
1351 1351
 		    free(section_hdr);
1352
+		    free(exe_sections);
1352 1353
 		    free(src);
1353 1354
 		    free(dest);
1354 1355
 		    free(sections);
1355 1356
 		    return CL_EIO;
1356 1357
 		}
1357 1358
 
1358
-		switch(unfsg_133(src + newesi - EC32(section_hdr[i + 1].VirtualAddress), dest, ssize + EC32(section_hdr[i + 1].VirtualAddress) - newesi, dsize, sections, sectcnt, EC32(optional_hdr32.ImageBase), oldep, ndesc)) {
1359
+		switch(unfsg_133(src + newesi - exe_sections[i + 1].rva, dest, ssize + exe_sections[i + 1].rva - newesi, dsize, sections, sectcnt, EC32(optional_hdr32.ImageBase), oldep, ndesc)) {
1359 1360
 		    case 1: /* Everything OK */
1360 1361
 			cli_dbgmsg("FSG: Unpacked and rebuilt executable saved in %s\n", tempfile);
1361 1362
 			free(src);
... ...
@@ -1367,6 +1443,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1367 1367
 			cli_dbgmsg("***** Scanning rebuilt PE file *****\n");
1368 1368
 			if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) {
1369 1369
 			    free(section_hdr);
1370
+			    free(exe_sections);
1370 1371
 			    close(ndesc);
1371 1372
 			    if(!cli_leavetemps_flag)
1372 1373
 				unlink(tempfile);
... ...
@@ -1379,10 +1456,11 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1379 1379
 			    unlink(tempfile);
1380 1380
 			free(tempfile);
1381 1381
 			free(section_hdr);
1382
+			free(exe_sections);
1382 1383
 			return CL_CLEAN;
1383 1384
 
1384 1385
 		    case 0: /* We've got an unpacked buffer, no exe though */
1385
-			cli_dbgmsg("FSG: FSG: Successfully decompressed\n");
1386
+			cli_dbgmsg("FSG: Successfully decompressed\n");
1386 1387
 			close(ndesc);
1387 1388
 			unlink(tempfile);
1388 1389
 			free(tempfile);
... ...
@@ -1407,40 +1485,42 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1407 1407
 	}
1408 1408
 
1409 1409
 	/* FIXME: easy 2 hack */
1410
- 	if(found && buff[0] == '\xbb' && cli_readint32(buff + 1) - EC32(optional_hdr32.ImageBase) < min && buff[5] == '\xbf' && buff[10] == '\xbe') {
1410
+ 	if(found && buff[0] == '\xbb' && cli_readint32(buff + 1) - EC32(optional_hdr32.ImageBase) < min && buff[5] == '\xbf' && buff[10] == '\xbe' && vep >= exe_sections[i + 1].rva && vep - exe_sections[i + 1].rva > exe_sections[i + 1].rva - 0xe0 ) {
1411 1411
 
1412 1412
 	    /* FSG support - v. 1.31 */
1413 1413
 
1414
-	    ssize = EC32(section_hdr[i + 1].SizeOfRawData);
1415
-	    dsize = EC32(section_hdr[i].VirtualSize);
1414
+	    ssize = exe_sections[i + 1].rsz;
1415
+	    dsize = exe_sections[i].vsz;
1416 1416
 
1417 1417
 	    while(found) {
1418
-		    int gp = cli_readint32(buff+1) - EC32(optional_hdr32.ImageBase), t, sectcnt = 0;
1418
+		    int sectcnt = 0;
1419
+		    uint32_t t;
1420
+		    uint32_t gp = cli_rawaddr(cli_readint32(buff+1) - EC32(optional_hdr32.ImageBase), NULL, 0 , &err, fsize);
1419 1421
 		    char *support;
1420 1422
 		    uint32_t newesi = cli_readint32(buff+11) - EC32(optional_hdr32.ImageBase);
1421 1423
 		    uint32_t newedi = cli_readint32(buff+6) - EC32(optional_hdr32.ImageBase);
1422
-		    uint32_t oldep = EC32(optional_hdr32.AddressOfEntryPoint);
1423
-		    struct SECTION *sections;
1424
+		    uint32_t oldep = vep - exe_sections[i + 1].rva;
1425
+		    struct cli_exe_section *sections;
1424 1426
 
1425
-	        if (oldep <= EC32(section_hdr[i + 1].VirtualAddress) || oldep > EC32(section_hdr[i + 1].VirtualAddress)+EC32(section_hdr[i + 1].SizeOfRawData) - 0xe0) {
1426
-		  cli_dbgmsg("FSG: EP not in section %d\n", i+1);
1427
-		  break;
1427
+		if(err) {
1428
+		    cli_dbgmsg("FSG: Support data out of padding area\n");
1429
+		    break;
1428 1430
 		}
1429
-		oldep -= EC32(section_hdr[i + 1].VirtualAddress);
1430 1431
 
1431
-		if(newesi < EC32(section_hdr[i + 1].VirtualAddress) || newesi >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData)) {
1432
+		if(newesi < exe_sections[i + 1].rva || newesi - exe_sections[i + 1].rva >= exe_sections[i + 1].raw) {
1432 1433
 		    cli_dbgmsg("FSG: Source buffer out of section bounds\n");
1433 1434
 		    break;
1434 1435
 		}
1435 1436
 
1436
-		if(newedi != EC32(section_hdr[i].VirtualAddress)) {
1437
-		    cli_dbgmsg("FSG: Bad destination (is %x should be %x)\n", newedi, EC32(section_hdr[i].VirtualAddress));
1437
+		if(newedi != exe_sections[i].rva) {
1438
+		    cli_dbgmsg("FSG: Bad destination (is %x should be %x)\n", newedi, exe_sections[i].rva);
1438 1439
 		    break;
1439 1440
 		}
1440 1441
 
1441 1442
 		if(ctx->limits && ctx->limits->maxfilesize && (ssize > ctx->limits->maxfilesize || dsize > ctx->limits->maxfilesize)) {
1442 1443
 		    cli_dbgmsg("FSG: Sizes exceeded (ssize: %u, dsize: %u, max: %lu)\n", ssize, dsize, ctx->limits->maxfilesize);
1443 1444
 		    free(section_hdr);
1445
+		    free(exe_sections);
1444 1446
 		    if(BLOCKMAX) {
1445 1447
 			*ctx->virname = "PE.FSG.ExceededFileSize";
1446 1448
 			return CL_VIRUS;
... ...
@@ -1452,20 +1532,17 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1452 1452
 		if(ssize <= 0x19 || dsize <= ssize) {
1453 1453
 		    cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize);
1454 1454
 		    free(section_hdr);
1455
+		    free(exe_sections);
1455 1456
 		    return CL_CLEAN;
1456 1457
 		}
1457 1458
 
1458
-		if(gp >= (int) EC32(section_hdr[i + 1].PointerToRawData) || gp < 0) {
1459
-		    cli_dbgmsg("FSG: Support data out of padding area (newedi: %d, vaddr: %d)\n", newedi, EC32(section_hdr[i].VirtualAddress));
1460
-		    break;
1461
-		}
1462
-
1463 1459
 		lseek(desc, gp, SEEK_SET);
1464
-		gp = EC32(section_hdr[i + 1].PointerToRawData) - gp;
1460
+		gp = exe_sections[i + 1].raw - gp;
1465 1461
 
1466
-		if(ctx->limits && ctx->limits->maxfilesize && (unsigned int) gp > ctx->limits->maxfilesize) {
1462
+		if(ctx->limits && ctx->limits->maxfilesize && gp > ctx->limits->maxfilesize) {
1467 1463
 		    cli_dbgmsg("FSG: Buffer size exceeded (size: %d, max: %lu)\n", gp, ctx->limits->maxfilesize);
1468 1464
 		    free(section_hdr);
1465
+		    free(exe_sections);
1469 1466
 		    if(BLOCKMAX) {
1470 1467
 			*ctx->virname = "PE.FSG.ExceededFileSize";
1471 1468
 			return CL_VIRUS;
... ...
@@ -1476,19 +1553,21 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1476 1476
 
1477 1477
 		if((support = (char *) cli_malloc(gp)) == NULL) {
1478 1478
 		    free(section_hdr);
1479
+		    free(exe_sections);
1479 1480
 		    return CL_EMEM;
1480 1481
 		}
1481 1482
 
1482
-		if(cli_readn(desc, support, gp) != gp) {
1483
+		if(cli_readn(desc, support, gp) != (int)gp) {
1483 1484
 		    cli_dbgmsg("Can't read %d bytes from padding area\n", gp); 
1484 1485
 		    free(section_hdr);
1486
+		    free(exe_sections);
1485 1487
 		    free(support);
1486 1488
 		    return CL_EIO;
1487 1489
 		}
1488 1490
 
1489 1491
 		/* Counting original sections */
1490 1492
 		for(t = 0; t < gp - 2; t += 2) {
1491
-		  uint32_t rva = support[t]+256*support[t+1];
1493
+		  uint32_t rva = support[t]|(support[t+1]<<8);
1492 1494
 		  
1493 1495
 		  if (rva == 2 || rva == 1)
1494 1496
 		    break;
... ...
@@ -1496,7 +1575,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1496 1496
 		  rva = ((rva-2)<<12) - EC32(optional_hdr32.ImageBase);
1497 1497
 		  sectcnt++;
1498 1498
 
1499
-		  if(rva < EC32(section_hdr[i].VirtualAddress) || rva >= EC32(section_hdr[i].VirtualAddress)+EC32(section_hdr[i].VirtualSize)) {
1499
+		  if(rva < exe_sections[i].rva || rva - exe_sections[i].rva >= exe_sections[i].vsz) {
1500 1500
 		    cli_dbgmsg("FSG: Original section %d is out of bounds\n", sectcnt);
1501 1501
 		    break;
1502 1502
 		  }
... ...
@@ -1507,29 +1586,32 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1507 1507
 		    break;
1508 1508
 		}
1509 1509
 
1510
-		if((sections = (struct SECTION *) cli_malloc((sectcnt + 1) * sizeof(struct SECTION))) == NULL) {
1510
+		if((sections = (struct cli_exe_section *) cli_malloc((sectcnt + 1) * sizeof(struct cli_exe_section))) == NULL) {
1511 1511
 		    free(section_hdr);
1512
+		    free(exe_sections);
1512 1513
 		    free(support);
1513 1514
 		    return CL_EMEM;
1514 1515
 		}
1515 1516
 
1516 1517
 		sections[0].rva = newedi;
1517
-		for(t = 0; t <= sectcnt - 1; t++) {
1518
-		  sections[t+1].rva = (((support[t*2]+256*support[t*2+1])-2)<<12)-EC32(optional_hdr32.ImageBase);
1518
+		for(t = 0; t <= (uint32_t)sectcnt - 1; t++) {
1519
+		  sections[t+1].rva = (((support[t*2]|(support[t*2+1]<<8))-2)<<12)-EC32(optional_hdr32.ImageBase);
1519 1520
 		}
1520 1521
 
1521 1522
 		free(support);
1522 1523
 
1523 1524
 		if((src = (char *) cli_malloc(ssize)) == NULL) {
1524 1525
 		    free(section_hdr);
1526
+		    free(exe_sections);
1525 1527
 		    free(sections);
1526 1528
 		    return CL_EMEM;
1527 1529
 		}
1528 1530
 
1529
-		lseek(desc, EC32(section_hdr[i + 1].PointerToRawData), SEEK_SET);
1531
+		lseek(desc, exe_sections[i + 1].raw, SEEK_SET);
1530 1532
 		if((unsigned int) cli_readn(desc, src, ssize) != ssize) {
1531
-		    cli_dbgmsg("Can't read raw data of section %d\n", i);
1533
+		    cli_dbgmsg("FSG: Can't read raw data of section %d\n", i);
1532 1534
 		    free(section_hdr);
1535
+		    free(exe_sections);
1533 1536
 		    free(sections);
1534 1537
 		    free(src);
1535 1538
 		    return CL_EIO;
... ...
@@ -1537,6 +1619,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1537 1537
 
1538 1538
 		if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
1539 1539
 		    free(section_hdr);
1540
+		    free(exe_sections);
1540 1541
 		    free(src);
1541 1542
 		    free(sections);
1542 1543
 		    return CL_EMEM;
... ...
@@ -1544,11 +1627,12 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1544 1544
 
1545 1545
 		/* Better not increasing buff size any further, let's go the hard way */
1546 1546
 		gp = 0xda + 6*(buff[16]=='\xe8');
1547
-		oldep = EC32(optional_hdr32.AddressOfEntryPoint) + gp + 6 + cli_readint32(src+gp+2+oldep);
1547
+		oldep = vep + gp + 6 + cli_readint32(src+gp+2+oldep);
1548 1548
 		cli_dbgmsg("FSG: found old EP @%x\n", oldep);
1549 1549
 
1550 1550
 		if(!(tempfile = cli_gentemp(NULL))) {
1551 1551
 		    free(section_hdr);
1552
+		    free(exe_sections);
1552 1553
 		    free(src);
1553 1554
 		    free(dest);
1554 1555
 		    free(sections);
... ...
@@ -1559,6 +1643,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1559 1559
 		    cli_dbgmsg("FSG: Can't create file %s\n", tempfile);
1560 1560
 		    free(tempfile);
1561 1561
 		    free(section_hdr);
1562
+		    free(exe_sections);
1562 1563
 		    free(src);
1563 1564
 		    free(dest);
1564 1565
 		    free(sections);
... ...
@@ -1577,6 +1662,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1577 1577
 			cli_dbgmsg("***** Scanning rebuilt PE file *****\n");
1578 1578
 			if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) {
1579 1579
 			    free(section_hdr);
1580
+			    free(exe_sections);
1580 1581
 			    close(ndesc);
1581 1582
 			    if(!cli_leavetemps_flag)
1582 1583
 				unlink(tempfile);
... ...
@@ -1589,6 +1675,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1589 1589
 			    unlink(tempfile);
1590 1590
 			free(tempfile);
1591 1591
 			free(section_hdr);
1592
+			free(exe_sections);
1592 1593
 			return CL_CLEAN;
1593 1594
 
1594 1595
 		    case 0: /* We've got an unpacked buffer, no exe though */
... ...
@@ -1632,12 +1719,13 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1632 1632
 		cli_dbgmsg("UPX: Possibly hacked UPX section headers\n");
1633 1633
 
1634 1634
 	    /* we assume (i + 1) is UPX1 */
1635
-	    ssize = EC32(section_hdr[i + 1].SizeOfRawData);
1636
-	    dsize = EC32(section_hdr[i].VirtualSize) + EC32(section_hdr[i + 1].VirtualSize);
1635
+	    ssize = exe_sections[i + 1].rsz;
1636
+	    dsize = exe_sections[i].vsz + exe_sections[i + 1].vsz;
1637 1637
 
1638 1638
 	    if(ctx->limits && ctx->limits->maxfilesize && (ssize > ctx->limits->maxfilesize || dsize > ctx->limits->maxfilesize)) {
1639 1639
 		cli_dbgmsg("UPX: Sizes exceeded (ssize: %u, dsize: %u, max: %lu)\n", ssize, dsize , ctx->limits->maxfilesize);
1640 1640
 		free(section_hdr);
1641
+		free(exe_sections);
1641 1642
 		if(BLOCKMAX) {
1642 1643
 		    *ctx->virname = "PE.UPX.ExceededFileSize";
1643 1644
 		    return CL_VIRUS;
... ...
@@ -1649,32 +1737,37 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1649 1649
 	    if(ssize <= 0x19 || dsize <= ssize) { /* FIXME: What are reasonable values? */
1650 1650
 		cli_dbgmsg("UPX: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize);
1651 1651
 		free(section_hdr);
1652
+		free(exe_sections);
1652 1653
 		return CL_CLEAN;
1653 1654
 	    }
1654 1655
 
1655 1656
 	    /* FIXME: use file operations in case of big files */
1656 1657
 	    if((src = (char *) cli_malloc(ssize)) == NULL) {
1657 1658
 		free(section_hdr);
1659
+		free(exe_sections);
1658 1660
 		return CL_EMEM;
1659 1661
 	    }
1660 1662
 
1661 1663
 	    if(dsize > CLI_MAX_ALLOCATION) {
1662 1664
 		cli_errmsg("UPX: Too big value of dsize\n");
1663 1665
 		free(section_hdr);
1666
+		free(exe_sections);
1664 1667
 		free(src);
1665 1668
 		return CL_EMEM;
1666 1669
 	    }
1667 1670
 
1668
-	    if((dest = (char *) cli_calloc(dsize + 1024 + nsections * 40, sizeof(char))) == NULL) {
1671
+	    if((dest = (char *) cli_calloc(dsize + 8192, sizeof(char))) == NULL) {
1669 1672
 		free(section_hdr);
1673
+		free(exe_sections);
1670 1674
 		free(src);
1671 1675
 		return CL_EMEM;
1672 1676
 	    }
1673 1677
 
1674
-	    lseek(desc, EC32(section_hdr[i + 1].PointerToRawData), SEEK_SET);
1678
+	    lseek(desc, exe_sections[i + 1].raw, SEEK_SET);
1675 1679
 	    if((unsigned int) cli_readn(desc, src, ssize) != ssize) {
1676
-		cli_dbgmsg("Can't read raw data of section %d\n", i);
1680
+		cli_dbgmsg("UPX: Can't read raw data of section %d\n", i+1);
1677 1681
 		free(section_hdr);
1682
+		free(exe_sections);
1678 1683
 		free(src);
1679 1684
 		free(dest);
1680 1685
 		return CL_EIO;
... ...
@@ -1683,8 +1776,9 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1683 1683
 	    /* try to detect UPX code */
1684 1684
 
1685 1685
 	    if(lseek(desc, ep, SEEK_SET) == -1) {
1686
-		cli_dbgmsg("lseek() failed\n");
1686
+		cli_dbgmsg("UPX: lseek() failed\n");
1687 1687
 		free(section_hdr);
1688
+		free(exe_sections);
1688 1689
 		free(src);
1689 1690
 		free(dest);
1690 1691
 		return CL_EIO;
... ...
@@ -1692,8 +1786,9 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1692 1692
 
1693 1693
 	    if(cli_readn(desc, buff, 126) != 126) { /* i.e. 0x69 + 13 + 8 */
1694 1694
 		cli_dbgmsg("UPX: Can't read 126 bytes at 0x%x (%d)\n", ep, ep);
1695
-		cli_dbgmsg("UPX/FSG: Broken or not UPX/FSG compressed file\n");
1695
+		cli_dbgmsg("UPX: Broken or not UPX compressed file\n");
1696 1696
 		free(section_hdr);
1697
+		free(exe_sections);
1697 1698
 		free(src);
1698 1699
 		free(dest);
1699 1700
 		return CL_CLEAN;
... ...
@@ -1711,27 +1806,27 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1711 1711
 	    }
1712 1712
 
1713 1713
 	    if(upxfn) {
1714
-		    int skew = cli_readint32(buff + 2) - EC32(optional_hdr32.ImageBase) - EC32(section_hdr[i + 1].VirtualAddress);
1714
+		    int skew = cli_readint32(buff + 2) - EC32(optional_hdr32.ImageBase) - exe_sections[i + 1].rva;
1715 1715
 
1716 1716
 		if(buff[1] != '\xbe' || skew <= 0 || skew > 0xfff) { /* FIXME: legit skews?? */
1717 1717
 		    skew = 0; 
1718
-		    if(upxfn(src, ssize, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr32.AddressOfEntryPoint)) >= 0)
1718
+		    if(upxfn(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) >= 0)
1719 1719
 			upx_success = 1;
1720 1720
 
1721 1721
 		} else {
1722 1722
 		    cli_dbgmsg("UPX: UPX1 seems skewed by %d bytes\n", skew);
1723
-                    if(upxfn(src + skew, ssize - skew, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr32.AddressOfEntryPoint)-skew) >= 0 || upxfn(src, ssize, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr32.AddressOfEntryPoint)) >= 0)
1723
+                    if(upxfn(src + skew, ssize - skew, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep-skew) >= 0 || upxfn(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) >= 0)
1724 1724
 			upx_success = 1;
1725 1725
 		}
1726 1726
 
1727 1727
 		if(upx_success)
1728 1728
 		    cli_dbgmsg("UPX: Successfully decompressed\n");
1729 1729
 		else
1730
-		    cli_dbgmsg("UPX: Prefered decompressor failed\n");
1730
+		    cli_dbgmsg("UPX: Preferred decompressor failed\n");
1731 1731
 	    }
1732 1732
 
1733 1733
 	    if(!upx_success && upxfn != upx_inflate2b) {
1734
-		if(upx_inflate2b(src, ssize, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr32.AddressOfEntryPoint)) == -1 && upx_inflate2b(src + 0x15, ssize - 0x15, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr32.AddressOfEntryPoint) - 0x15) == -1) {
1734
+		if(upx_inflate2b(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) == -1 && upx_inflate2b(src + 0x15, ssize - 0x15, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep - 0x15) == -1) {
1735 1735
 
1736 1736
 		    cli_dbgmsg("UPX: NRV2B decompressor failed\n");
1737 1737
 		} else {
... ...
@@ -1741,7 +1836,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1741 1741
 	    }
1742 1742
 
1743 1743
 	    if(!upx_success && upxfn != upx_inflate2d) {
1744
-		if(upx_inflate2d(src, ssize, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr32.AddressOfEntryPoint)) == -1 && upx_inflate2d(src + 0x15, ssize - 0x15, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr32.AddressOfEntryPoint) - 0x15) == -1) {
1744
+		if(upx_inflate2d(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) == -1 && upx_inflate2d(src + 0x15, ssize - 0x15, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep - 0x15) == -1) {
1745 1745
 
1746 1746
 		    cli_dbgmsg("UPX: NRV2D decompressor failed\n");
1747 1747
 		} else {
... ...
@@ -1751,7 +1846,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1751 1751
 	    }
1752 1752
 
1753 1753
 	    if(!upx_success && upxfn != upx_inflate2e) {
1754
-		if(upx_inflate2e(src, ssize, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr32.AddressOfEntryPoint)) == -1 && upx_inflate2e(src + 0x15, ssize - 0x15, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr32.AddressOfEntryPoint) - 0x15) == -1) {
1754
+		if(upx_inflate2e(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) == -1 && upx_inflate2e(src + 0x15, ssize - 0x15, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep - 0x15) == -1) {
1755 1755
 		    cli_dbgmsg("UPX: NRV2E decompressor failed\n");
1756 1756
 		} else {
1757 1757
 		    upx_success = 1;
... ...
@@ -1769,6 +1864,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1769 1769
 	if(upx_success) {
1770 1770
 	    free(src);
1771 1771
 	    free(section_hdr);
1772
+	    free(exe_sections);
1772 1773
 
1773 1774
 	    if(!(tempfile = cli_gentemp(NULL))) {
1774 1775
 	        free(dest);
... ...
@@ -1823,6 +1919,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1823 1823
     if(cli_readn(desc, buff, 200) == -1) {
1824 1824
 	cli_dbgmsg("cli_readn() failed\n");
1825 1825
 	free(section_hdr);
1826
+	free(exe_sections);
1826 1827
 	return CL_EIO;
1827 1828
     }
1828 1829
 
... ...
@@ -1844,6 +1941,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1844 1844
 	    if(ctx->limits && ctx->limits->maxfilesize && dsize > ctx->limits->maxfilesize) {
1845 1845
 		cli_dbgmsg("Petite: Size exceeded (dsize: %u, max: %lu)\n", dsize, ctx->limits->maxfilesize);
1846 1846
 		free(section_hdr);
1847
+		free(exe_sections);
1847 1848
 		if(BLOCKMAX) {
1848 1849
 		    *ctx->virname = "PE.Petite.ExceededFileSize";
1849 1850
 		    return CL_VIRUS;
... ...
@@ -1855,15 +1953,17 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1855 1855
 	    if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
1856 1856
 		cli_dbgmsg("Petite: Can't allocate %d bytes\n", dsize);
1857 1857
 		free(section_hdr);
1858
+		free(exe_sections);
1858 1859
 		return CL_EMEM;
1859 1860
 	    }
1860 1861
 
1861 1862
 	    for(i = 0 ; i < nsections; i++) {
1862 1863
 		if(section_hdr[i].SizeOfRawData) {
1863
-		  uint32_t offset = cli_rawaddr(EC32(section_hdr[i].VirtualAddress), section_hdr, nsections, &err, 0, 0);
1864
+		  uint32_t offset = cli_rawaddr(EC32(section_hdr[i].VirtualAddress), exe_sections, nsections, &err, fsize);
1864 1865
 
1865 1866
 		    if(err || lseek(desc, offset, SEEK_SET) == -1 || (unsigned int) cli_readn(desc, dest + EC32(section_hdr[i].VirtualAddress) - min, EC32(section_hdr[i].SizeOfRawData)) != EC32(section_hdr[i].SizeOfRawData)) {
1866 1867
 			free(section_hdr);
1868
+			free(exe_sections);
1867 1869
 			free(dest);
1868 1870
 			return CL_EIO;
1869 1871
 		    }
... ...
@@ -1873,6 +1973,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1873 1873
 	    if(!(tempfile = cli_gentemp(NULL))) {
1874 1874
 	      free(dest);
1875 1875
 	      free(section_hdr);
1876
+	      free(exe_sections);
1876 1877
 	      return CL_EMEM;
1877 1878
 	    }
1878 1879
 
... ...
@@ -1880,61 +1981,49 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1880 1880
 		cli_dbgmsg("Petite: Can't create file %s\n", tempfile);
1881 1881
 		free(tempfile);
1882 1882
 		free(section_hdr);
1883
+		free(exe_sections);
1883 1884
 		free(dest);
1884 1885
 		return CL_EIO;
1885 1886
 	    }
1886 1887
 
1887 1888
 	    /* aCaB: Fixed to allow petite v2.1 unpacking (last section is a ghost) */
1888
-	    switch(petite_inflate2x_1to9(dest, min, max - min, section_hdr,
1889
+	    if (!petite_inflate2x_1to9(dest, min, max - min, section_hdr,
1889 1890
 		    nsections - (found == 1 ? 1 : 0), EC32(optional_hdr32.ImageBase),
1890
-		    EC32(optional_hdr32.AddressOfEntryPoint), ndesc,
1891
-		    found, EC32(optional_hdr32.DataDirectory[2].VirtualAddress),
1891
+		    vep, ndesc, found, EC32(optional_hdr32.DataDirectory[2].VirtualAddress),
1892 1892
 		    EC32(optional_hdr32.DataDirectory[2].Size))) {
1893
-		case 1:
1894
-		    cli_dbgmsg("Petite: Unpacked and rebuilt executable saved in %s\n", tempfile);
1895
-		    cli_dbgmsg("***** Scanning rebuilt PE file *****\n");
1896
-		    break;
1897
-
1898
-		case 0:
1899
-		    cli_dbgmsg("Petite: Unpacked data saved in %s\n", tempfile);
1900
-		    break;
1901
-
1902
-		default:
1903
-		    cli_dbgmsg("Petite: Unpacking failed\n");
1904
-	    }
1905
-
1906
-	    free(dest);
1907
-	    fsync(ndesc);
1908
-	    lseek(ndesc, 0, SEEK_SET);
1909
-
1910
-	    if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) {
1911
-		free(section_hdr);
1912
-		close(ndesc);
1913
-		if(!cli_leavetemps_flag) {
1914
-		    unlink(tempfile);
1915
-		    free(tempfile);
1916
-		} else {
1893
+	        cli_dbgmsg("Petite: Unpacked and rebuilt executable saved in %s\n", tempfile);
1894
+		cli_dbgmsg("***** Scanning rebuilt PE file *****\n");
1895
+		free(dest);
1896
+		fsync(ndesc);
1897
+		lseek(ndesc, 0, SEEK_SET);
1898
+		if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) {
1899
+		    free(section_hdr);
1900
+		    free(exe_sections);
1901
+		    close(ndesc);
1902
+		    if(!cli_leavetemps_flag) {
1903
+		        unlink(tempfile);
1904
+		    }
1917 1905
 		    free(tempfile);
1906
+		    return CL_VIRUS;
1918 1907
 		}
1919
-		return CL_VIRUS;
1920
-	    }
1921 1908
 
1909
+	    } else {
1910
+	        cli_dbgmsg("Petite: Unpacking failed\n");
1911
+		free(dest);
1912
+	    }
1922 1913
 	    close(ndesc);
1923
-
1924 1914
 	    if(!cli_leavetemps_flag) {
1925
-		unlink(tempfile);
1926
-		free(tempfile);
1927
-	    } else {
1928
-		free(tempfile);
1915
+	        unlink(tempfile);
1929 1916
 	    }
1917
+	    free(tempfile);
1930 1918
 	}
1931 1919
     }
1932 1920
 
1933 1921
     /* PESpin 1.1 */
1934 1922
 
1935 1923
     if(nsections > 1 &&
1936
-       EC32(optional_hdr32.AddressOfEntryPoint) >= EC32(section_hdr[nsections - 1].VirtualAddress) &&
1937
-       EC32(optional_hdr32.AddressOfEntryPoint) < EC32(section_hdr[nsections - 1].VirtualAddress) + EC32(section_hdr[nsections - 1].SizeOfRawData) - 0x3217 - 4 &&
1924
+       vep >= EC32(section_hdr[nsections - 1].VirtualAddress) &&
1925
+       vep < EC32(section_hdr[nsections - 1].VirtualAddress) + EC32(section_hdr[nsections - 1].SizeOfRawData) - 0x3217 - 4 &&
1938 1926
        memcmp(buff+4, "\xe8\x00\x00\x00\x00\x8b\x1c\x24\x83\xc3", 10) == 0)  {
1939 1927
 
1940 1928
 	    char *spinned;
... ...
@@ -1942,6 +2031,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1942 1942
 	if(ctx->limits && ctx->limits->maxfilesize && fsize > ctx->limits->maxfilesize) {
1943 1943
 	    cli_dbgmsg("PEspin: Size exceeded (fsize: %u, max: %lu)\n", fsize, ctx->limits->maxfilesize);
1944 1944
             free(section_hdr);
1945
+	    free(exe_sections);
1945 1946
 	    if(BLOCKMAX) {
1946 1947
 		*ctx->virname = "PE.Pespin.ExceededFileSize";
1947 1948
 		return CL_VIRUS;
... ...
@@ -1952,6 +2042,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1952 1952
 
1953 1953
 	if((spinned = (char *) cli_malloc(fsize)) == NULL) {
1954 1954
 	    free(section_hdr);
1955
+	    free(exe_sections);
1955 1956
 	    return CL_EMEM;
1956 1957
 	}
1957 1958
 
... ...
@@ -1960,12 +2051,14 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1960 1960
 	    cli_dbgmsg("PESpin: Can't read %d bytes\n", fsize);
1961 1961
 	    free(spinned);
1962 1962
 	    free(section_hdr);
1963
+	    free(exe_sections);
1963 1964
 	    return CL_EIO;
1964 1965
 	}
1965 1966
 
1966 1967
 	if(!(tempfile = cli_gentemp(NULL))) {
1967 1968
 	  free(spinned);
1968 1969
 	  free(section_hdr);
1970
+	  free(exe_sections);
1969 1971
 	  return CL_EMEM;
1970 1972
 	}
1971 1973
 
... ...
@@ -1974,10 +2067,11 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1974 1974
 	    free(tempfile);
1975 1975
 	    free(spinned);
1976 1976
 	    free(section_hdr);
1977
+	    free(exe_sections);
1977 1978
 	    return CL_EIO;
1978 1979
 	}
1979 1980
 
1980
-	switch(unspin(spinned, fsize, section_hdr, nsections - 1, EC32(optional_hdr32.AddressOfEntryPoint), ndesc, ctx)) {
1981
+	switch(unspin(spinned, fsize, section_hdr, nsections - 1, vep, ndesc, ctx)) {
1981 1982
 	case 0:
1982 1983
 	    free(spinned);
1983 1984
 	    if(cli_leavetemps_flag)
... ...
@@ -1992,6 +2086,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1992 1992
 		    unlink(tempfile);
1993 1993
 	        free(tempfile);
1994 1994
 		free(section_hdr);
1995
+		free(exe_sections);
1995 1996
 		return CL_VIRUS;
1996 1997
 	    }
1997 1998
 	    close(ndesc);
... ...
@@ -2012,6 +2107,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
2012 2012
 	    if(BLOCKMAX) {
2013 2013
 		free(tempfile);
2014 2014
 		free(section_hdr);
2015
+		free(exe_sections);
2015 2016
 		*ctx->virname = "PE.Pespin.ExceededFileSize";
2016 2017
 		return CL_VIRUS;
2017 2018
 	    }
... ...
@@ -2032,6 +2128,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
2032 2032
 	if ( fsize >= EC32(section_hdr[nsections - 1].PointerToRawData) + 0xC6 + 0xb97 ) { /* size check on yC sect */
2033 2033
 	  if((spinned = (char *) cli_malloc(fsize)) == NULL) {
2034 2034
 	    free(section_hdr);
2035
+	    free(exe_sections);
2035 2036
 	    return CL_EMEM;
2036 2037
 	  }
2037 2038
 
... ...
@@ -2040,12 +2137,14 @@ int cli_scanpe(int desc, cli_ctx *ctx)
2040 2040
 	    cli_dbgmsg("yC: Can't read %d bytes\n", fsize);
2041 2041
 	    free(spinned);
2042 2042
 	    free(section_hdr);
2043
+	    free(exe_sections);
2043 2044
 	    return CL_EIO;
2044 2045
 	  }
2045 2046
 
2046 2047
 	  if(!(tempfile = cli_gentemp(NULL))) {
2047 2048
 	    free(spinned);
2048 2049
 	    free(section_hdr);
2050
+	    free(exe_sections);
2049 2051
 	    return CL_EMEM;
2050 2052
 	  }
2051 2053
 
... ...
@@ -2054,6 +2153,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
2054 2054
 	    free(tempfile);
2055 2055
 	    free(spinned);
2056 2056
 	    free(section_hdr);
2057
+	    free(exe_sections);
2057 2058
 	    return CL_EIO;
2058 2059
 	  }
2059 2060
 
... ...
@@ -2065,6 +2165,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
2065 2065
 	    
2066 2066
 	    if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) {
2067 2067
 	      free(section_hdr);
2068
+	      free(exe_sections);
2068 2069
 	      close(ndesc);
2069 2070
 	      if(!cli_leavetemps_flag) {
2070 2071
 		unlink(tempfile);
... ...
@@ -2095,24 +2196,23 @@ int cli_scanpe(int desc, cli_ctx *ctx)
2095 2095
     /* WWPack */
2096 2096
 
2097 2097
     if(nsections > 1 &&
2098
-       EC32(section_hdr[nsections-1].SizeOfRawData)>0x2b1 &&
2099
-       EC32(optional_hdr32.AddressOfEntryPoint) == EC32(section_hdr[nsections - 1].VirtualAddress) &&
2100
-       EC32(section_hdr[nsections - 1].VirtualAddress)+EC32(section_hdr[nsections - 1].SizeOfRawData) == max &&
2098
+       exe_sections[nsections-1].raw>0x2b1 &&
2099
+       vep == exe_sections[nsections - 1].rva &&
2100
+       exe_sections[nsections - 1].rva + exe_sections[nsections - 1].rsz == max &&
2101 2101
        memcmp(buff, "\x53\x55\x8b\xe8\x33\xdb\xeb", 7) == 0 &&
2102 2102
        memcmp(buff+0x68, "\xe8\x00\x00\x00\x00\x58\x2d\x6d\x00\x00\x00\x50\x60\x33\xc9\x50\x58\x50\x50", 19) == 0)  {
2103
-      uint32_t headsize=EC32(section_hdr[nsections - 1].PointerToRawData);
2103
+      uint32_t headsize=exe_sections[nsections - 1].raw;
2104 2104
       char *dest, *wwp;
2105 2105
 
2106
-      for(i = 0 ; i < (unsigned int)nsections-1; i++) {
2107
-	uint32_t offset = cli_rawaddr(EC32(section_hdr[i].VirtualAddress), section_hdr, nsections, &err, 0, 0);
2108
-	if (!err && offset<headsize) headsize=offset;
2109
-      }
2106
+      for(i = 0 ; i < (unsigned int)nsections-1; i++)
2107
+	if (!err && exe_sections[i].raw<headsize) headsize=exe_sections[i].raw;
2110 2108
       
2111
-      dsize = max-min+headsize-EC32(section_hdr[nsections - 1].SizeOfRawData);
2109
+      dsize = max-min+headsize-exe_sections[nsections - 1].rsz;
2112 2110
 
2113 2111
       if(ctx->limits && ctx->limits->maxfilesize && dsize > ctx->limits->maxfilesize) {
2114 2112
 	cli_dbgmsg("WWPack: Size exceeded (dsize: %u, max: %lu)\n", dsize, ctx->limits->maxfilesize);
2115 2113
 	free(section_hdr);
2114
+	free(exe_sections);
2116 2115
 	if(BLOCKMAX) {
2117 2116
 	  *ctx->virname = "PE.WWPack.ExceededFileSize";
2118 2117
 	  return CL_VIRUS;
... ...
@@ -2124,6 +2224,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
2124 2124
       if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
2125 2125
 	cli_dbgmsg("WWPack: Can't allocate %d bytes\n", dsize);
2126 2126
 	free(section_hdr);
2127
+	free(exe_sections);
2127 2128
 	return CL_EMEM;
2128 2129
       }
2129 2130
       memset(dest, 0, dsize);
... ...
@@ -2133,44 +2234,49 @@ int cli_scanpe(int desc, cli_ctx *ctx)
2133 2133
 	cli_dbgmsg("WWPack: Can't read %d bytes from headers\n", headsize);
2134 2134
 	free(dest);
2135 2135
 	free(section_hdr);
2136
+	free(exe_sections);
2136 2137
 	return CL_EIO;
2137 2138
       }
2138 2139
 
2139 2140
       for(i = 0 ; i < (unsigned int)nsections-1; i++) {
2140
-	if(section_hdr[i].SizeOfRawData) {
2141
-	  uint32_t offset = cli_rawaddr(EC32(section_hdr[i].VirtualAddress), section_hdr, nsections, &err, 0, 0);
2141
+	if(exe_sections[i].rsz) {
2142
+	  uint32_t offset = exe_sections[i].raw;
2142 2143
 	  
2143
-	  if(err || lseek(desc, offset, SEEK_SET) == -1 || (unsigned int) cli_readn(desc, dest + headsize + EC32(section_hdr[i].VirtualAddress) - min, EC32(section_hdr[i].SizeOfRawData)) != EC32(section_hdr[i].SizeOfRawData)) {
2144
+	  if(err || lseek(desc, offset, SEEK_SET) == -1 || (unsigned int) cli_readn(desc, dest + headsize + exe_sections[i].rva - min, exe_sections[i].rsz) != exe_sections[i].rsz) {
2144 2145
 	    free(dest);
2145 2146
 	    free(section_hdr);
2147
+	    free(exe_sections);
2146 2148
 	    return CL_EIO;
2147 2149
 	  }
2148 2150
 	}
2149 2151
       }
2150 2152
 
2151
-      if((wwp = (char *) cli_calloc(EC32(section_hdr[nsections - 1].SizeOfRawData), sizeof(char))) == NULL) {
2152
-	cli_dbgmsg("WWPack: Can't allocate %d bytes\n", EC32(section_hdr[nsections - 1].SizeOfRawData));
2153
+      if((wwp = (char *) cli_calloc(exe_sections[nsections - 1].rsz, sizeof(char))) == NULL) {
2154
+	cli_dbgmsg("WWPack: Can't allocate %d bytes\n", exe_sections[nsections - 1].rsz);
2153 2155
 	free(dest);
2154 2156
 	free(section_hdr);
2157
+	free(exe_sections);
2155 2158
 	return CL_EMEM;
2156 2159
       }
2157 2160
 
2158
-      lseek(desc, EC32(section_hdr[nsections - 1].PointerToRawData), SEEK_SET);      
2159
-      if((size_t) cli_readn(desc, wwp, EC32(section_hdr[nsections - 1].SizeOfRawData)) != EC32(section_hdr[nsections - 1].SizeOfRawData)) {
2160
-	cli_dbgmsg("WWPack: Can't read %d bytes from wwpack sect\n", EC32(section_hdr[nsections - 1].SizeOfRawData));
2161
+      lseek(desc, exe_sections[nsections - 1].raw, SEEK_SET);
2162
+      if((size_t) cli_readn(desc, wwp, exe_sections[nsections - 1].rsz) != exe_sections[nsections - 1].rsz) {
2163
+	cli_dbgmsg("WWPack: Can't read %d bytes from wwpack sect\n", exe_sections[nsections - 1].rsz);
2161 2164
 	free(dest);
2162 2165
 	free(wwp);
2163 2166
 	free(section_hdr);
2167
+	free(exe_sections);
2164 2168
 	return CL_EIO;
2165 2169
       }
2166 2170
 
2167
-      if (!wwunpack(dest, dsize, headsize, min, EC32(section_hdr[nsections-1].VirtualAddress),  e_lfanew, wwp, EC32(section_hdr[nsections - 1].SizeOfRawData), nsections-1)) {
2171
+      if (!wwunpack(dest, dsize, headsize, min, exe_sections[nsections-1].rva, e_lfanew, wwp, exe_sections[nsections - 1].rsz, nsections-1)) {
2168 2172
 	
2169 2173
 	free(wwp);
2170 2174
 
2171 2175
 	if(!(tempfile = cli_gentemp(NULL))) {
2172 2176
 	  free(dest);
2173 2177
 	  free(section_hdr);
2178
+	  free(exe_sections);
2174 2179
 	  return CL_EMEM;
2175 2180
 	}
2176 2181
 
... ...
@@ -2179,6 +2285,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
2179 2179
 	  free(tempfile);
2180 2180
 	  free(dest);
2181 2181
 	  free(section_hdr);
2182
+	  free(exe_sections);
2182 2183
 	  return CL_EIO;
2183 2184
 	}
2184 2185
 
... ...
@@ -2188,6 +2295,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
2188 2188
 	  free(tempfile);
2189 2189
 	  free(dest);
2190 2190
 	  free(section_hdr);
2191
+	  free(exe_sections);
2191 2192
 	  return CL_EIO;
2192 2193
 	}
2193 2194
 
... ...
@@ -2202,6 +2310,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
2202 2202
 
2203 2203
 	if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) {
2204 2204
 	  free(section_hdr);
2205
+	  free(exe_sections);
2205 2206
 	  close(ndesc);
2206 2207
 	  if(!cli_leavetemps_flag)
2207 2208
 	    unlink(tempfile);
... ...
@@ -2223,36 +2332,34 @@ int cli_scanpe(int desc, cli_ctx *ctx)
2223 2223
 #ifdef CL_EXPERIMENTAL
2224 2224
     /* NsPack */
2225 2225
 
2226
-    /* WATCH OUT: ep && buff destroyed!!! */
2227 2226
     while (1) {
2228
-      uint32_t eprva = EC32(optional_hdr32.AddressOfEntryPoint);
2229
-      uint32_t start_of_stuff, ssize, dsize;
2227
+      uint32_t eprva = vep;
2228
+      uint32_t start_of_stuff, ssize, dsize, rep = ep;
2230 2229
       unsigned int nowinldr;
2231
-      char *src, *dest;
2230
+      char nbuff[24];
2231
+      char *src=buff, *dest;
2232 2232
       FILE *asd;
2233 2233
 
2234
-      ep = cli_rawaddr(eprva , section_hdr, nsections, &err, EC32(optional_hdr32.SectionAlignment), EC32(optional_hdr32.FileAlignment));
2235
-      if (lseek(desc, ep, SEEK_SET)==-1) break;
2236
-      if (cli_readn(desc, buff, 13)!=13) break;
2237 2234
       if (*buff=='\xe9') { /* bitched headers */
2238
-	eprva = cli_readint32(buff+1)+EC32(optional_hdr32.AddressOfEntryPoint)+5;
2239
-	ep = cli_rawaddr(eprva, section_hdr, nsections, &err, EC32(optional_hdr32.SectionAlignment), EC32(optional_hdr32.FileAlignment));
2240
-	if (lseek(desc, ep, SEEK_SET)==-1) break;
2241
-	if (cli_readn(desc, buff, 24)!=24) break;
2235
+	eprva = cli_readint32(buff+1)+vep+5;
2236
+	if (!(rep = cli_rawaddr(eprva, exe_sections, nsections, &err, fsize)) && err) break;
2237
+	if (lseek(desc, rep, SEEK_SET)==-1) break;
2238
+	if (cli_readn(desc, nbuff, 24)!=24) break;
2239
+	src = nbuff;
2242 2240
       }
2243 2241
 
2244
-      if (memcmp(buff, "\x9c\x60\xe8\x00\x00\x00\x00\x5d\xb8\x07\x00\x00\x00", 13)) break;
2242
+      if (memcmp(src, "\x9c\x60\xe8\x00\x00\x00\x00\x5d\xb8\x07\x00\x00\x00", 13)) break;
2245 2243
 
2246
-      nowinldr = 0x54-cli_readint32(buff+17);
2244
+      nowinldr = 0x54-cli_readint32(src+17);
2247 2245
       cli_dbgmsg("NsPack: Found *start_of_stuff @delta-%x\n", nowinldr);
2248 2246
 
2249
-      if (lseek(desc, ep-nowinldr, SEEK_SET)==-1) break;
2250
-      if (cli_readn(desc, buff, 4)!=4) break;
2251
-      start_of_stuff=ep+cli_readint32(buff);
2247
+      if (lseek(desc, rep-nowinldr, SEEK_SET)==-1) break;
2248
+      if (cli_readn(desc, nbuff, 4)!=4) break;
2249
+      start_of_stuff=rep+cli_readint32(nbuff);
2252 2250
       if (lseek(desc, start_of_stuff, SEEK_SET)==-1) break;
2253
-      if (cli_readn(desc, buff, 20)!=20) break;
2254
-      src = buff;
2255
-      if (!cli_readint32(buff)) {
2251
+      if (cli_readn(desc, nbuff, 20)!=20) break;
2252
+      src = nbuff;
2253
+      if (!cli_readint32(nbuff)) {
2256 2254
 	start_of_stuff+=4; /* FIXME: more to do */
2257 2255
 	src+=4;
2258 2256
       }
... ...
@@ -2263,6 +2370,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
2263 2263
       if(ctx->limits && ctx->limits->maxfilesize && (ssize > ctx->limits->maxfilesize || dsize > ctx->limits->maxfilesize)) {
2264 2264
 	cli_dbgmsg("NsPack: Size exceeded\n");
2265 2265
 	free(section_hdr);
2266
+	free(exe_sections);
2266 2267
 	if(BLOCKMAX) {
2267 2268
 	  *ctx->virname = "PE.NsPack.ExceededFileSize";
2268 2269
 	  return CL_VIRUS;
... ...
@@ -2271,7 +2379,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
2271 2271
 	}
2272 2272
       }
2273 2273
 
2274
-      if ( !ssize || !dsize || dsize != (uint32_t)PESALIGN(EC32(section_hdr[0].VirtualSize), EC32(optional_hdr32.SectionAlignment))) break;
2274
+      if ( !ssize || !dsize || dsize != exe_sections[0].vsz) break;
2275 2275
       if (lseek(desc, start_of_stuff, SEEK_SET)==-1) break;
2276 2276
       if (!(dest=cli_malloc(dsize))) break;
2277 2277
       /* memset(dest, 0xfc, dsize); */
... ...
@@ -2284,16 +2392,17 @@ int cli_scanpe(int desc, cli_ctx *ctx)
2284 2284
       cli_readn(desc, src, ssize);
2285 2285
 
2286 2286
       eprva+=0x27a;
2287
-      ep = cli_rawaddr(eprva, section_hdr, nsections, &err, EC32(optional_hdr32.SectionAlignment), EC32(optional_hdr32.FileAlignment));
2288
-      if (lseek(desc, ep, SEEK_SET)==-1) break;
2289
-      if (cli_readn(desc, buff, 5)!=5) break;
2290
-      eprva=eprva+5+cli_readint32(buff+1);
2287
+      if (!(rep = cli_rawaddr(eprva, exe_sections, nsections, &err, fsize)) && err) break;
2288
+      if (lseek(desc, rep, SEEK_SET)==-1) break;
2289
+      if (cli_readn(desc, nbuff, 5)!=5) break;
2290
+      eprva=eprva+5+cli_readint32(nbuff+1);
2291 2291
       cli_dbgmsg("NsPack: OEP = %08x\n", eprva);
2292 2292
 
2293 2293
       if(!(tempfile = cli_gentemp(NULL))) {
2294 2294
 	free(src);
2295 2295
 	free(dest);
2296 2296
 	free(section_hdr);
2297
+	free(exe_sections);
2297 2298
 	return CL_EMEM;
2298 2299
       }
2299 2300
 
... ...
@@ -2303,10 +2412,11 @@ int cli_scanpe(int desc, cli_ctx *ctx)
2303 2303
 	free(src);
2304 2304
 	free(dest);
2305 2305
 	free(section_hdr);
2306
+	free(exe_sections);
2306 2307
 	return CL_EIO;
2307 2308
       }
2308 2309
 
2309
-      if (!unspack(src, dest, ctx, EC32(section_hdr[0].VirtualAddress), EC32(optional_hdr32.ImageBase), eprva, ndesc)) {
2310
+      if (!unspack(src, dest, ctx, exe_sections[0].rva, EC32(optional_hdr32.ImageBase), eprva, ndesc)) {
2310 2311
 	free(src);
2311 2312
 	free(dest);
2312 2313
 	if (cli_leavetemps_flag)
... ...
@@ -2318,6 +2428,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
2318 2318
 
2319 2319
 	if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) {
2320 2320
 	  free(section_hdr);
2321
+	  free(exe_sections);
2321 2322
 	  close(ndesc);
2322 2323
 	  if(!cli_leavetemps_flag) unlink(tempfile);
2323 2324
 	  free(tempfile);
... ...
@@ -2338,6 +2449,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
2338 2338
     /* to be continued ... */
2339 2339
 
2340 2340
     free(section_hdr);
2341
+    free(exe_sections);
2341 2342
     return CL_CLEAN;
2342 2343
 }
2343 2344
 
... ...
@@ -2345,18 +2457,32 @@ int cli_peheader(int desc, struct cli_exe_info *peinfo)
2345 2345
 {
2346 2346
 	uint16_t e_magic; /* DOS signature ("MZ") */
2347 2347
 	uint32_t e_lfanew; /* address of new exe header */
2348
-	uint32_t min = 0, max = 0;
2348
+	/* Obsolete - see below
2349
+	  uint32_t min = 0, max = 0;
2350
+	*/
2349 2351
 	struct pe_image_file_hdr file_hdr;
2350
-	struct pe_image_optional_hdr32 optional_hdr32;
2351
-	struct pe_image_optional_hdr64 optional_hdr64;
2352
+	union {
2353
+	    struct pe_image_optional_hdr64 opt64;
2354
+	    struct pe_image_optional_hdr32 opt32;
2355
+	} pe_opt;
2356
+	struct pe_image_optional_hdr64 optional_hdr64 = pe_opt.opt64;
2357
+	struct pe_image_optional_hdr32 optional_hdr32 = pe_opt.opt32;
2352 2358
 	struct pe_image_section_hdr *section_hdr;
2353 2359
 	struct stat sb;
2354 2360
 	int i;
2355 2361
 	unsigned int err, pe_plus = 0;
2356
-
2362
+	uint32_t valign, falign;
2363
+	size_t fsize;
2357 2364
 
2358 2365
     cli_dbgmsg("in cli_peheader\n");
2359 2366
 
2367
+    if(fstat(desc, &sb) == -1) {
2368
+	cli_dbgmsg("fstat failed\n");
2369
+	return -1;
2370
+    }
2371
+
2372
+    fsize = sb.st_size;
2373
+
2360 2374
     if(cli_readn(desc, &e_magic, sizeof(e_magic)) != sizeof(e_magic)) {
2361 2375
 	cli_dbgmsg("Can't read DOS signature\n");
2362 2376
 	return -1;
... ...
@@ -2400,32 +2526,49 @@ int cli_peheader(int desc, struct cli_exe_info *peinfo)
2400 2400
 
2401 2401
     peinfo->nsections = EC16(file_hdr.NumberOfSections);
2402 2402
 
2403
-    if(EC16(file_hdr.SizeOfOptionalHeader) != sizeof(struct pe_image_optional_hdr32)) {
2404
-	if(EC16(file_hdr.SizeOfOptionalHeader) == sizeof(struct pe_image_optional_hdr64)) {
2405
-	    pe_plus = 1;
2406
-	} else {
2407
-	    cli_dbgmsg("Incorrect value of SizeOfOptionalHeader\n");
2403
+    if (EC16(file_hdr.SizeOfOptionalHeader) < sizeof(struct pe_image_optional_hdr32)) {
2404
+        cli_dbgmsg("SizeOfOptionalHeader too small\n");
2405
+	return -1;
2406
+    }
2407
+
2408
+    if(cli_readn(desc, &optional_hdr32, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) {
2409
+        cli_dbgmsg("Can't read optional file header\n");
2410
+	return -1;
2411
+    }
2412
+
2413
+    if(EC32(optional_hdr64.Magic)==PE32P_SIGNATURE) {
2414
+        if(EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr64)) {
2415
+	    cli_dbgmsg("Incorrect SizeOfOptionalHeader for PE32+\n");
2408 2416
 	    return -1;
2409 2417
 	}
2418
+	pe_plus = 1;
2410 2419
     }
2411 2420
 
2412 2421
     if(!pe_plus) { /* PE */
2413 2422
 	cli_dbgmsg("File format: PE\n");
2414 2423
 
2415 2424
 	if(cli_readn(desc, &optional_hdr32, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) {
2416
-	    cli_dbgmsg("Can't optional file header\n");
2425
+	    cli_dbgmsg("Can't read optional file header\n");
2417 2426
 	    return -1;
2418 2427
 	}
2419 2428
 
2420
-    } else { /* PE+ */
2421
-	cli_dbgmsg("File format: PE32+\n");
2429
+	if (EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr32)) {
2430
+	    /* Seek to the end of the long header */
2431
+	    lseek(desc, (EC16(file_hdr.SizeOfOptionalHeader)-sizeof(struct pe_image_optional_hdr32)), SEEK_CUR);
2432
+	}
2422 2433
 
2423
-	if(cli_readn(desc, &optional_hdr64, sizeof(struct pe_image_optional_hdr64)) != sizeof(struct pe_image_optional_hdr64)) {
2424
-	    cli_dbgmsg("Can't optional file header\n");
2434
+    } else { /* PE+ */
2435
+        if(cli_readn(desc, &optional_hdr32 + 1, sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) {
2436
+	    cli_dbgmsg("Can't read optional file header\n");
2425 2437
 	    return -1;
2426 2438
 	}
2439
+
2440
+	cli_dbgmsg("File format: PE32+\n");
2427 2441
     }
2428 2442
 
2443
+    valign = (pe_plus)?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment);
2444
+    falign = (pe_plus)?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment);
2445
+
2429 2446
     peinfo->section = (struct cli_exe_section *) cli_calloc(peinfo->nsections, sizeof(struct cli_exe_section));
2430 2447
 
2431 2448
     if(!peinfo->section) {
... ...
@@ -2433,13 +2576,6 @@ int cli_peheader(int desc, struct cli_exe_info *peinfo)
2433 2433
 	return -1;
2434 2434
     }
2435 2435
 
2436
-    if(fstat(desc, &sb) == -1) {
2437
-	cli_dbgmsg("fstat failed\n");
2438
-	free(peinfo->section);
2439
-	peinfo->section = NULL;
2440
-	return -1;
2441
-    }
2442
-
2443 2436
     section_hdr = (struct pe_image_section_hdr *) cli_calloc(peinfo->nsections, sizeof(struct pe_image_section_hdr));
2444 2437
 
2445 2438
     if(!section_hdr) {
... ...
@@ -2460,14 +2596,18 @@ int cli_peheader(int desc, struct cli_exe_info *peinfo)
2460 2460
 	    return -1;
2461 2461
 	}
2462 2462
 
2463
-	peinfo->section[i].rva = EC32(section_hdr[i].VirtualAddress);
2464
-	peinfo->section[i].vsz = EC32(section_hdr[i].VirtualSize);
2465
-	peinfo->section[i].raw = EC32(section_hdr[i].PointerToRawData);
2466
-	peinfo->section[i].rsz = EC32(section_hdr[i].SizeOfRawData);
2463
+	peinfo->section[i].rva = PEALIGN(EC32(section_hdr[i].VirtualAddress), valign);
2464
+	peinfo->section[i].vsz = PESALIGN(EC32(section_hdr[i].VirtualSize), valign);
2465
+	peinfo->section[i].raw = PEALIGN(EC32(section_hdr[i].PointerToRawData), falign);
2466
+	peinfo->section[i].rsz = PESALIGN(EC32(section_hdr[i].SizeOfRawData), falign);
2467
+	if (peinfo->section[i].rsz && !CLI_ISCONTAINED(0, (uint32_t) fsize, peinfo->section[i].raw, peinfo->section[i].rsz))
2468
+	    peinfo->section[i].rsz = (fsize - peinfo->section[i].raw)*(fsize>peinfo->section[i].raw);
2467 2469
 
2470
+	/* cli_rawaddr now handles the whole process space
2471
+	 * TO BE REMOVED
2468 2472
 	if(!i) {
2469
-	    min = EC32(section_hdr[i].VirtualAddress);
2470
-	    max = EC32(section_hdr[i].VirtualAddress) + EC32(section_hdr[i].SizeOfRawData);
2473
+	    min = peinfo->section[i].rva;
2474
+	    max = peinfo->section[i].rva + peinfo->section[i].rsz;
2471 2475
 	} else {
2472 2476
 	    if(EC32(section_hdr[i].VirtualAddress) < min)
2473 2477
 		min = EC32(section_hdr[i].VirtualAddress);
... ...
@@ -2475,6 +2615,7 @@ int cli_peheader(int desc, struct cli_exe_info *peinfo)
2475 2475
 	    if(EC32(section_hdr[i].VirtualAddress) + EC32(section_hdr[i].SizeOfRawData) > max)
2476 2476
 		max = EC32(section_hdr[i].VirtualAddress) + EC32(section_hdr[i].SizeOfRawData);
2477 2477
 	}
2478
+	*/
2478 2479
     }
2479 2480
 
2480 2481
     if(pe_plus)
... ...
@@ -2482,12 +2623,16 @@ int cli_peheader(int desc, struct cli_exe_info *peinfo)
2482 2482
     else
2483 2483
 	peinfo->ep = EC32(optional_hdr32.AddressOfEntryPoint);
2484 2484
 
2485
-	if(peinfo->ep >= min && !(peinfo->ep = cli_rawaddr(peinfo->ep, section_hdr, peinfo->nsections, &err, 0, 0)) && err) {
2486
-	cli_dbgmsg("Possibly broken PE file\n");
2485
+    if(!(peinfo->ep = cli_rawaddr(peinfo->ep, peinfo->section, peinfo->nsections, &err, fsize)) && err) {
2486
+#ifdef ACAB_REGRESSION
2487
+	peinfo->ep = 0x7fffffff;
2488
+#else
2489
+	cli_dbgmsg("Broken PE file\n");
2487 2490
 	free(section_hdr);
2488 2491
 	free(peinfo->section);
2489 2492
 	peinfo->section = NULL;
2490 2493
 	return -1;
2494
+#endif /* ACAB_REGRESSION */
2491 2495
     }
2492 2496
 
2493 2497
     free(section_hdr);
... ...
@@ -54,6 +54,7 @@
54 54
 #include "cltypes.h"
55 55
 #include "pe.h"
56 56
 #include "rebuildpe.h"
57
+#include "execs.h"
57 58
 #include "others.h"
58 59
 
59 60
 #define EC32(x) le32_to_host(x) /* Convert little endian to host */
... ...
@@ -81,7 +82,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_
81 81
   char *packed = NULL;
82 82
   uint32_t thisrva=0, bottom = 0, enc_ep=0, irva=0, workdone=0, grown=0x355, skew=0x35;
83 83
   int j = 0, oob, mangled = 0, check4resources=0;
84
-  struct SECTION *usects = NULL;
84
+  struct cli_exe_section *usects = NULL;
85 85
   void *tmpsct = NULL;
86 86
 
87 87
   /*
... ...
@@ -111,7 +112,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_
111 111
     if ( ! CLI_ISCONTAINED(buf, bufsz, packed, 4)) {
112 112
       if (usects)
113 113
 	free(usects);
114
-      return -1;
114
+      return 1;
115 115
     }
116 116
     srva = cli_readint32(packed);
117 117
 
... ...
@@ -120,7 +121,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_
120 120
       int t, upd = 1;
121 121
 
122 122
       if ( j <= 0 ) /* Some non petite compressed files will get here */
123
-	return -1;
123
+	return 1;
124 124
     
125 125
       /* Select * from sections order by rva asc; */
126 126
       while ( upd ) {
... ...
@@ -202,10 +203,12 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_
202 202
 	} else 
203 203
 	  workdone = 1;
204 204
 	enc_ep = pep+5+enc_ep;
205
-	if ( workdone == 1 )
205
+	if ( workdone == 1 ) {
206 206
 	  cli_dbgmsg("Petite: Old EP: %x\n", enc_ep);
207
-	else
208
-	  cli_dbgmsg("Petite: In troubles while attempting to decrypt old EP\n");
207
+	} else {
208
+	  enc_ep = usects[0].rva;
209
+	  cli_dbgmsg("Petite: In troubles while attempting to decrypt old EP, using bogus %x\n", enc_ep);
210
+	}
209 211
       }
210 212
 
211 213
       /* Let's compact data */
... ...
@@ -219,18 +222,13 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_
219 219
       cli_dbgmsg("Petite: Sections dump:\n");
220 220
       for (t = 0; t < j ; t++)
221 221
 	cli_dbgmsg("Petite: .SECT%d RVA:%x VSize:%x ROffset: %x, RSize:% x\n", t, usects[t].rva, usects[t].vsz, usects[t].raw, usects[t].rsz);
222
-      if ( (ssrc = rebuildpe(buf, usects, j, Imagebase, enc_ep, ResRva, ResSize)) ) {
223
-	if (cli_writen(desc, ssrc, 0x148+0x80+0x28*j+usects[j-1].raw+usects[j-1].rsz)==-1) {
224
-	  free(ssrc);
225
-	  free(usects);
226
-	  return -1;
227
-	}
228
-	free(ssrc);
229
-      } else
222
+      if (! cli_rebuildpe(buf, usects, j, Imagebase, enc_ep, ResRva, ResSize, desc)) {
230 223
 	cli_dbgmsg("Petite: Rebuilding failed\n");
231
-
224
+	free(usects);
225
+	return 1;
226
+      }
232 227
       free(usects);
233
-      return workdone;
228
+      return 0;
234 229
     }
235 230
 
236 231
 
... ...
@@ -247,7 +245,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_
247 247
       if ( ! CLI_ISCONTAINED(buf, bufsz, packed+4, 8) ) {
248 248
 	if (usects)
249 249
 	  free(usects);
250
-	return -1;
250
+	return 1;
251 251
       }
252 252
       /* Save the end of current packed section for later use */
253 253
       bottom = cli_readint32(packed+8) + 4;
... ...
@@ -257,7 +255,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_
257 257
       if ( !CLI_ISCONTAINED(buf, bufsz, ssrc, size*4) || !CLI_ISCONTAINED(buf, bufsz, ddst, size*4) ) {
258 258
 	if (usects)
259 259
 	  free(usects);
260
-	return -1;
260
+	return 1;
261 261
       }
262 262
 
263 263
       /* Copy packed data to the end of the current packed section */
... ...
@@ -273,26 +271,26 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_
273 273
       if ( ! CLI_ISCONTAINED(buf, bufsz, packed+4, 8)) {
274 274
 	if (usects)
275 275
 	  free(usects);
276
-	return -1;
276
+	return 1;
277 277
       }
278 278
 
279 279
       size = cli_readint32(packed+4); /* How many bytes to unpack */
280 280
       thisrva=cli_readint32(packed+8); /* RVA of the original section */
281 281
       packed += 0x10;
282 282
 
283
-      if ( j >= 99 ) {
283
+      if ( j >= 96 ) {
284 284
 	cli_dbgmsg("Petite: maximum number of sections exceeded, giving up.\n");
285 285
 	free(usects);
286
-	return -1;
286
+	return 1;
287 287
       }
288 288
       /* Alloc 1 more struct */
289
-      if ( ! (tmpsct = cli_realloc(usects, sizeof(struct SECTION) * (j+1))) ) {
289
+      if ( ! (tmpsct = cli_realloc(usects, sizeof(struct cli_exe_section) * (j+1))) ) {
290 290
 	if (usects)
291 291
 	  free(usects);
292
-	return -1;
292
+	return 1;
293 293
       }
294 294
 
295
-      usects = (struct SECTION *) tmpsct;
295
+      usects = (struct cli_exe_section *) tmpsct;
296 296
       /* Save section spex for later rebuilding */
297 297
       usects[j].rva = thisrva;
298 298
       usects[j].rsz = size;
... ...
@@ -352,7 +350,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_
352 352
 
353 353
       if ( !CLI_ISCONTAINED(buf, bufsz, ssrc, 1) || !CLI_ISCONTAINED(buf, bufsz, ddst, 1)) {
354 354
 	free(usects);
355
-	return -1;
355
+	return 1;
356 356
       }
357 357
 
358 358
       size--;
... ...
@@ -365,12 +363,12 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_
365 365
 	oob = doubledl(&ssrc, &mydl, buf, bufsz);
366 366
 	if ( oob == -1 ) {
367 367
 	  free(usects);
368
-	  return -1;
368
+	  return 1;
369 369
 	}
370 370
 	if (!oob) {
371 371
 	  if ( !CLI_ISCONTAINED(buf, bufsz, ssrc, 1) || !CLI_ISCONTAINED(buf, bufsz, ddst, 1) ) {
372 372
 	    free(usects);
373
-	    return -1;
373
+	    return 1;
374 374
 	  }
375 375
 	  *ddst++ = (char)((*ssrc++)^(size & 0xff));
376 376
 	  size--;
... ...
@@ -380,12 +378,12 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_
380 380
 	  while (1) {
381 381
 	    if ( (oob = doubledl(&ssrc, &mydl, buf, bufsz)) == -1 ) {
382 382
 	      free(usects);
383
-	      return -1;
383
+	      return 1;
384 384
 	    }
385 385
 	    backbytes = backbytes*2 + oob;
386 386
 	    if ( (oob = doubledl(&ssrc, &mydl, buf, bufsz)) == -1 ) {
387 387
 	      free(usects);
388
-	      return -1;
388
+	      return 1;
389 389
 	    }
390 390
 	    if (!oob)
391 391
 	      break;
... ...
@@ -396,7 +394,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_
396 396
 	    do {
397 397
 	      if ( (oob = doubledl(&ssrc, &mydl, buf, bufsz)) == -1 ) {
398 398
 		free(usects);
399
-		return -1;
399
+		return 1;
400 400
 	      }
401 401
 	      backbytes = backbytes*2 + oob;
402 402
 	      backsize--;
... ...
@@ -411,12 +409,12 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_
411 411
 
412 412
 	  if ( (oob = doubledl(&ssrc, &mydl, buf, bufsz)) == -1 ) {
413 413
 	    free(usects);
414
-	    return -1;
414
+	    return 1;
415 415
 	  }
416 416
 	  backsize = backsize*2 + oob;
417 417
 	  if ( (oob = doubledl(&ssrc, &mydl, buf, bufsz)) == -1 ) {
418 418
 	    free(usects);
419
-	    return -1;
419
+	    return 1;
420 420
 	  }
421 421
 	  backsize = backsize*2 + oob;
422 422
 	  if (!backsize) {
... ...
@@ -424,12 +422,12 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_
424 424
 	    while (1) {
425 425
 	      if ( (oob = doubledl(&ssrc, &mydl, buf, bufsz)) == -1 ) {
426 426
 		free(usects);
427
-		return -1;
427
+		return 1;
428 428
 	      }
429 429
 	      backsize = backsize*2 + oob;
430 430
 	      if ( (oob = doubledl(&ssrc, &mydl, buf, bufsz)) == -1 ) {
431 431
 		free(usects);
432
-		return -1;
432
+		return 1;
433 433
 	      }
434 434
 	      if (!oob)
435 435
 		break;
... ...
@@ -440,7 +438,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_
440 440
 	  size-=backsize;
441 441
 	  if(!CLI_ISCONTAINED(buf, bufsz, ddst, backsize) || !CLI_ISCONTAINED(buf, bufsz, ddst+backbytes, backsize)) {
442 442
 	    free(usects);
443
-	    return -1;
443
+	    return 1;
444 444
 	  }
445 445
 	  while(backsize--) {
446 446
 	    *ddst=*(ddst+backbytes);
... ...
@@ -31,7 +31,6 @@
31 31
 ** lookalike PE & Optional headers, an array of structures and
32 32
 ** of course the real content.
33 33
 ** Sections characteristics will have all the bits set.
34
-** Raw alignment is a waste and therefore is not performed.
35 34
 */
36 35
 
37 36
 #if HAVE_CONFIG_H
... ...
@@ -45,6 +44,9 @@
45 45
 
46 46
 #define EC32(x) le32_to_host(x) /* Convert little endian to host */
47 47
 #define EC16(x) le16_to_host(x) /* Convert little endian to host */
48
+#define PEALIGN(o,a) (((a))?(((o)/(a))*(a)):(o))
49
+#define PESALIGN(o,a) (((a))?(((o)/(a)+((o)%(a)!=0))*(a)):(o))
50
+
48 51
 
49 52
 struct IMAGE_PE_HEADER {
50 53
     uint32_t Signature;
... ...
@@ -115,27 +117,29 @@ struct IMAGE_PE_HEADER {
115 115
 \x00\x00\x00\x00\x10\x00\x00\x00\
116 116
 "
117 117
 
118
-char *rebuildpe(char *buffer, struct SECTION *sections, int sects, uint32_t base, uint32_t ep, uint32_t ResRva, uint32_t ResSize)
118
+int cli_rebuildpe(char *buffer, struct cli_exe_section *sections, int sects, uint32_t base, uint32_t ep, uint32_t ResRva, uint32_t ResSize, int file)
119 119
 {
120 120
   int i;
121 121
   uint32_t datasize=0, rawbase;
122 122
   char *pefile=NULL, *curpe;
123 123
   struct IMAGE_PE_HEADER *fakepe;
124 124
 
125
-
126
-  if(sects > 90)
127
-    return NULL;
125
+  if(sects > 96)
126
+    return 0;
128 127
 
129 128
   for (i=0; i < sects; i++)
130
-      datasize+=sections[i].rsz;
129
+    datasize+=PESALIGN(sections[i].rsz, 0x200);
130
+
131
+  rawbase = PESALIGN(0x148+0x80+0x28*sects, 0x200);
131 132
 
132 133
   if(datasize > CLI_MAX_ALLOCATION)
133
-    return NULL;
134
+    return 0;
134 135
 
135
-  rawbase = 0x148+0x80+0x28*sects;
136
-  if((pefile = (char *) cli_malloc(rawbase+datasize))) {
136
+  if((pefile = (char *) cli_calloc(rawbase+datasize, 1))) {
137 137
     memcpy(pefile, HEADERS, 0x148);
138 138
 
139
+    datasize = 0x1000;
140
+
139 141
     fakepe = (struct IMAGE_PE_HEADER *)(pefile+0xd0);
140 142
     fakepe->NumberOfSections = EC16(sects);
141 143
     fakepe->AddressOfEntryPoint = EC32(ep);
... ...
@@ -150,17 +154,22 @@ char *rebuildpe(char *buffer, struct SECTION *sections, int sects, uint32_t base
150 150
       cli_writeint32(curpe+8, sections[i].vsz);
151 151
       cli_writeint32(curpe+12, sections[i].rva);
152 152
       cli_writeint32(curpe+16, sections[i].rsz);
153
-      cli_writeint32(curpe+20, sections[i].raw + rawbase);
153
+      cli_writeint32(curpe+20, rawbase);
154 154
       cli_writeint32(curpe+24, 0);
155 155
       cli_writeint32(curpe+28, 0);
156 156
       cli_writeint32(curpe+32, 0);
157 157
       cli_writeint32(curpe+0x24, 0xffffffff);
158
+      memcpy(pefile+rawbase, buffer+sections[i].raw, sections[i].rsz);
159
+      rawbase+=PESALIGN(sections[i].rsz, 0x200);
158 160
       curpe+=40;
161
+      datasize+=PESALIGN(sections[i].vsz, 0x1000);
159 162
     }
160
-    memcpy(curpe, buffer, datasize);
163
+    fakepe->SizeOfImage = EC32(datasize);
164
+  } else {
165
+    return 0;
161 166
   }
162 167
 
163
-  return pefile;
168
+  i = (cli_writen(file, pefile, rawbase)!=-1);
169
+  free(pefile);
170
+  return i;
164 171
 }
165
-
166
-
... ...
@@ -21,14 +21,8 @@
21 21
 #define __REBUILDPE_H
22 22
 
23 23
 #include "cltypes.h"
24
+#include "execs.h"
24 25
 
25
-struct SECTION {
26
-    uint32_t rva;
27
-    uint32_t vsz;
28
-    uint32_t raw;
29
-    uint32_t rsz;
30
-};
31
-
32
-char *rebuildpe(char *buffer, struct SECTION *sections, int sects, uint32_t base, uint32_t ep, uint32_t ResRva, uint32_t ResSize);
26
+int cli_rebuildpe(char *, struct cli_exe_section *, int, uint32_t, uint32_t, uint32_t, uint32_t, int);
33 27
 
34 28
 #endif
... ...
@@ -57,6 +57,7 @@
57 57
 #include "cltypes.h"
58 58
 #include "pe.h"
59 59
 #include "rebuildpe.h"
60
+#include "execs.h"
60 61
 #include "others.h"
61 62
 #include "packlibs.h"
62 63
 
... ...
@@ -466,8 +467,8 @@ int unspin(char *src, int ssize, struct pe_image_section_hdr *sections, int sect
466 466
   bitmap=bitman; /* save as a free() bitmap */
467 467
 
468 468
   if ( (ep = (char *) cli_malloc(blobsz)) != NULL ) {
469
-    struct SECTION *rebhlp;
470
-    if ( (rebhlp = (struct SECTION *) cli_malloc(sizeof(struct SECTION)*(sectcnt))) != NULL ) {
469
+    struct cli_exe_section *rebhlp;
470
+    if ( (rebhlp = (struct cli_exe_section *) cli_malloc(sizeof(struct cli_exe_section)*(sectcnt))) != NULL ) {
471 471
       char *to = ep;
472 472
       int retval = 0;
473 473
 
... ...
@@ -483,13 +484,7 @@ int unspin(char *src, int ssize, struct pe_image_section_hdr *sections, int sect
483 483
 	bitmap = bitmap >>1;
484 484
       }
485 485
 
486
-      if ( (to = rebuildpe(ep, rebhlp, sectcnt, 0x400000, 0x1000, 0, 0))) { /* can't be bothered fixing those values: the rebuilt exe is completely broken anyway. */
487
-	if (cli_writen(desc, to, 0x148+0x80+0x28*j+rebhlp[j-1].raw+rebhlp[j-1].rsz)==-1) {
488
-	  cli_dbgmsg("spin: Cannot write unpacked file\n");
489
-	  retval = 1;
490
-	}
491
-	free(to);
492
-      } else {
486
+      if (! cli_rebuildpe(ep, rebhlp, sectcnt, 0x400000, 0x1000, 0, 0, desc)) { /* can't be bothered fixing those values: the rebuilt exe is completely broken anyway. */
493 487
 	cli_dbgmsg("spin: Cannot write unpacked file\n");
494 488
 	retval = 1;
495 489
       }
... ...
@@ -37,14 +37,6 @@
37 37
 ** (*) some versions or maybe only some samples
38 38
 */
39 39
 
40
-
41
-/*
42
-** TODO:
43
-**
44
-** needs performance tests
45
-**
46
-*/
47
-
48 40
 #if HAVE_CONFIG_H
49 41
 #include "clamav-config.h"
50 42
 #endif
... ...
@@ -64,9 +56,8 @@
64 64
 
65 65
 #define EC32(x) le32_to_host(x) /* Convert little endian to host */
66 66
 #define EC16(x) le16_to_host(x)
67
-#define VAALIGN(s) (((s)/0x1000+((s)%0x1000!=0))*0x1000)
68 67
 
69
-char *sudecrypt(int desc, size_t fsize, struct pe_image_section_hdr *section_hdr, uint16_t sects, char *buff, uint32_t bkey, uint32_t pkey, uint32_t e_lfanew) {
68
+char *sudecrypt(int desc, size_t fsize, struct cli_exe_section *sections, uint16_t sects, char *buff, uint32_t bkey, uint32_t pkey, uint32_t e_lfanew) {
70 69
   char *file, *hunk;
71 70
   uint32_t va,sz,key;
72 71
   int i, j;
... ...
@@ -110,8 +101,8 @@ char *sudecrypt(int desc, size_t fsize, struct pe_image_section_hdr *section_hdr
110 110
     if (!va) break;
111 111
     cli_dbgmsg("SUE: Hunk #%d RVA:%x size:%d\n", i, va, sz);
112 112
     for (j=0; j<sects; j++) {
113
-      if(!CLI_ISCONTAINED(EC32(section_hdr[j].VirtualAddress), EC32(section_hdr[j].SizeOfRawData), va, sz)) continue;
114
-      hunk=file+EC32(section_hdr[j].VirtualAddress)-va+EC32(section_hdr[j].PointerToRawData);
113
+      if(!CLI_ISCONTAINED(sections[j].rva, sections[j].rsz, va, sz)) continue;
114
+      hunk=file+sections[j].rva-va+sections[j].raw;
115 115
       while(sz>=4) {
116 116
 	cli_writeint32(hunk, cli_readint32(hunk)^key);
117 117
 	hunk+=4;
... ...
@@ -24,7 +24,7 @@
24 24
 #include "cltypes.h"
25 25
 #include "rebuildpe.h"
26 26
 
27
-char *sudecrypt(int, size_t, struct pe_image_section_hdr *, uint16_t, char *, uint32_t, uint32_t, uint32_t);
27
+char *sudecrypt(int, size_t, struct cli_exe_section *, uint16_t, char *, uint32_t, uint32_t, uint32_t);
28 28
 
29 29
 #endif
30 30
 #endif
... ...
@@ -116,6 +116,7 @@ nsp1:00435A5A                 push    8000h
116 116
 #include "clamav.h"
117 117
 #include "others.h"
118 118
 #include "rebuildpe.h"
119
+#include "execs.h"
119 120
 #include "unsp.h"
120 121
 
121 122
 
... ...
@@ -126,7 +127,7 @@ uint32_t unspack(char *start_of_stuff, char *dest, cli_ctx *ctx, uint32_t rva, u
126 126
   uint16_t *table;
127 127
   char *dst = dest;
128 128
   char *src = start_of_stuff+0xd;
129
-  struct SECTION section;
129
+  struct cli_exe_section section;
130 130
   
131 131
   if (c>=0xe1) return 1;
132 132
 
... ...
@@ -162,14 +163,7 @@ uint32_t unspack(char *start_of_stuff, char *dest, cli_ctx *ctx, uint32_t rva, u
162 162
   section.rsz = dsize;
163 163
   section.vsz = dsize;
164 164
   section.rva = rva;
165
-  if ( (src = rebuildpe(dest, &section, 1, base, ep, 0, 0)) ) {
166
-    if (cli_writen(file, src, 0x148+0x80+0x28+dsize)!=-1) {
167
-      free(src);
168
-      return 0;
169
-    }
170
-    free(src);
171
-  }
172
-  return 1;
165
+  return !cli_rebuildpe(dest, &section, 1, base, ep, 0, 0, file);
173 166
 }
174 167
 
175 168
 
... ...
@@ -49,6 +49,9 @@
49 49
 #include "cltypes.h"
50 50
 #include "others.h"
51 51
 
52
+#define PEALIGN(o,a) (((a))?(((o)/(a))*(a)):(o))
53
+#define PESALIGN(o,a) (((a))?(((o)/(a)+((o)%(a)!=0))*(a)):(o))
54
+
52 55
 #define HEADERS "\
53 56
 \x4D\x5A\x90\x00\x02\x00\x00\x00\x04\x00\x0F\x00\xFF\xFF\x00\x00\
54 57
 \xB0\x00\x00\x00\x00\x00\x00\x00\x40\x00\x1A\x00\x00\x00\x00\x00\
... ...
@@ -71,7 +74,7 @@ int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0
71 71
 {
72 72
   char *imports, *sections, *pehdr, *newbuf;
73 73
   int sectcnt, upd=1;
74
-  uint32_t realstuffsz;
74
+  uint32_t realstuffsz, valign;
75 75
   uint32_t foffset=0xd0+0xf8;
76 76
 
77 77
   if((dst == NULL) || (src == NULL))
... ...
@@ -109,7 +112,7 @@ int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0
109 109
     return 0;
110 110
   }
111 111
   
112
-  if (! cli_readint32(pehdr+0x38)) {
112
+  if (!(valign=cli_readint32(pehdr+0x38))) {
113 113
     cli_dbgmsg("UPX: Cant align to a NULL bound - giving up rebuild\n");
114 114
     return 0;
115 115
   }
... ...
@@ -120,7 +123,7 @@ int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0
120 120
     return 0;
121 121
   }
122 122
   
123
-  foffset+=0x28*sectcnt;
123
+  foffset = PESALIGN(foffset+0x28*sectcnt, valign);
124 124
   
125 125
   if (!CLI_ISCONTAINED(dst, *dsize, sections, 0x28*sectcnt)) {
126 126
     cli_dbgmsg("UPX: Not enough space for all sects - giving up rebuild\n");
... ...
@@ -128,11 +131,8 @@ int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0
128 128
   }
129 129
   
130 130
   for (upd = 0; upd <sectcnt ; upd++) {
131
-    uint32_t vsize=cli_readint32(sections+8)-1;
132
-    uint32_t rsize=cli_readint32(sections+16);
133
-    uint32_t urva=cli_readint32(sections+12);
134
-    
135
-    vsize=(((vsize/0x1000)+1)*0x1000); /* FIXME: get bounds from header */
131
+    uint32_t vsize=PESALIGN(cli_readint32(sections+8), valign);
132
+    uint32_t urva=PEALIGN(cli_readint32(sections+12), valign);
136 133
     
137 134
     /* Within bounds ? */
138 135
     if (!CLI_ISCONTAINED(upx0, realstuffsz, urva, vsize)) {
... ...
@@ -140,28 +140,19 @@ int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0
140 140
       return 0;
141 141
     }
142 142
     
143
-    /* Rsize -gt Vsize ? */
144
-    if ( rsize > vsize ) {
145
-      cli_dbgmsg("UPX: Raw size for sect %d is greater than virtual (%x / %x) - giving up rebuild\n", upd, rsize, vsize);
146
-      return 0;
147
-    }
148
-    
149
-    /* Am i been fooled? There are better ways ;) */
150
-    if ( rsize+4 < vsize && cli_readint32(dst+urva-upx0+rsize) ) {
151
-      cli_dbgmsg("UPX: Am i been fooled? - giving up rebuild\n", upd);
152
-      return 0;
153
-    }
154
-    
155 143
     cli_writeint32(sections+8, vsize);
144
+    cli_writeint32(sections+12, urva);
145
+    cli_writeint32(sections+16, vsize);
156 146
     cli_writeint32(sections+20, foffset);
157
-    foffset+=rsize;
147
+    foffset+=vsize;
158 148
     
159 149
     sections+=0x28;
160 150
   }
161 151
 
162 152
   cli_writeint32(pehdr+8, 0x4d414c43);
153
+  cli_writeint32(pehdr+0x3c, valign);
163 154
 
164
-  if (!(newbuf = (char *) cli_malloc(foffset))) {
155
+  if (!(newbuf = (char *) cli_calloc(foffset, sizeof(char)))) {
165 156
     cli_dbgmsg("UPX: malloc failed - giving up rebuild\n", upd);
166 157
     return 0;
167 158
   }
... ...
@@ -177,7 +168,7 @@ int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0
177 177
   /* CBA restoring the imports they'll look different from the originals anyway... */
178 178
   /* ...and yeap i miss the icon too :P */
179 179
 
180
-  if (foffset > *dsize) {
180
+  if (foffset > *dsize + 8192) {
181 181
     cli_dbgmsg("UPX: wrong raw size - giving up rebuild\n");
182 182
     return 0;
183 183
   }
... ...
@@ -21,6 +21,7 @@
21 21
 #define __YC_H
22 22
 
23 23
 #include "pe.h"
24
+#include "execs.h"
24 25
 #include "cltypes.h"
25 26
 
26 27
 int yc_decrypt(char *, unsigned int, struct pe_image_section_hdr *, unsigned int, uint32_t, int);