Browse code

add support for PE32+ executables

git-svn: trunk@1772

Tomasz Kojm authored on 2005/11/27 07:39:01
Showing 3 changed files
... ...
@@ -1,3 +1,7 @@
1
+Sat Nov 26 23:32:35 CET 2005 (tk)
2
+---------------------------------
3
+  * libclamav/pe.[ch]: add support for PE32+ executables (used on win64)
4
+
1 5
 Wed Nov 23 11:20:54 GMT 2005 (njh)
2 6
 ----------------------------------
3 7
   * libclamav/mbox.c:	Multipart headers: handle end of header lines that are
... ...
@@ -47,7 +47,8 @@
47 47
 #define IMAGE_DOS_SIGNATURE	    0x5a4d	    /* MZ */
48 48
 #define IMAGE_DOS_SIGNATURE_OLD	    0x4d5a          /* ZM */
49 49
 #define IMAGE_NT_SIGNATURE	    0x00004550
50
-#define IMAGE_OPTIONAL_SIGNATURE    0x010b
50
+#define PE32_SIGNATURE		    0x010b
51
+#define PE32P_SIGNATURE		    0x020b
51 52
 
52 53
 #define DETECT_BROKEN		    (options & CL_SCAN_BLOCKBROKEN)
53 54
 #define BLOCKMAX		    (options & CL_SCAN_BLOCKMAX)
... ...
@@ -155,14 +156,16 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
155 155
 	uint16_t nsections;
156 156
 	uint32_t e_lfanew; /* address of new exe header */
157 157
 	uint32_t ep; /* entry point (raw) */
158
+	uint32_t tmp;
158 159
 	time_t timestamp;
159 160
 	struct pe_image_file_hdr file_hdr;
160
-	struct pe_image_optional_hdr optional_hdr;
161
+	struct pe_image_optional_hdr32 optional_hdr32;
162
+	struct pe_image_optional_hdr64 optional_hdr64;
161 163
 	struct pe_image_section_hdr *section_hdr;
162 164
 	struct stat sb;
163 165
 	char sname[9], buff[4096], *tempfile;
164 166
 	unsigned int i, found, upx_success = 0, min = 0, max = 0, err, broken = 0;
165
-	unsigned int ssize = 0, dsize = 0, dll = 0;
167
+	unsigned int ssize = 0, dsize = 0, dll = 0, pe_plus = 0;
166 168
 	int (*upxfn)(char *, int , char *, int *, uint32_t, uint32_t, uint32_t) = NULL;
167 169
 	char *src = NULL, *dest = NULL;
168 170
 	int ndesc, ret;
... ...
@@ -334,40 +337,96 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
334 334
 
335 335
     cli_dbgmsg("SizeOfOptionalHeader: %d\n", EC16(file_hdr.SizeOfOptionalHeader));
336 336
 
337
-    if(EC16(file_hdr.SizeOfOptionalHeader) != sizeof(struct pe_image_optional_hdr)) {
338
-	cli_warnmsg("Broken PE header detected.\n");
339
-	if(DETECT_BROKEN) {
340
-	    if(virname)
341
-		*virname = "Broken.Executable";
342
-	    return CL_VIRUS;
337
+    if(EC16(file_hdr.SizeOfOptionalHeader) != sizeof(struct pe_image_optional_hdr32)) {
338
+	if(EC16(file_hdr.SizeOfOptionalHeader) == sizeof(struct pe_image_optional_hdr64)) {
339
+	    pe_plus = 1;
340
+	} else {
341
+	    cli_warnmsg("Broken PE header detected.\n");
342
+	    if(DETECT_BROKEN) {
343
+		if(virname)
344
+		    *virname = "Broken.Executable";
345
+		return CL_VIRUS;
346
+	    }
347
+	    return CL_CLEAN;
343 348
 	}
344
-	return CL_CLEAN;
345 349
     }
346 350
 
347
-    if(read(desc, &optional_hdr, sizeof(struct pe_image_optional_hdr)) != sizeof(struct pe_image_optional_hdr)) {
348
-	cli_dbgmsg("Can't optional file header\n");
349
-	if(DETECT_BROKEN) {
350
-	    if(virname)
351
-		*virname = "Broken.Executable";
352
-	    return CL_VIRUS;
351
+    if(!pe_plus) { /* PE */
352
+
353
+	if(read(desc, &optional_hdr32, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) {
354
+	    cli_dbgmsg("Can't optional file header\n");
355
+	    if(DETECT_BROKEN) {
356
+		if(virname)
357
+		    *virname = "Broken.Executable";
358
+		return CL_VIRUS;
359
+	    }
360
+	    return CL_CLEAN;
353 361
 	}
354
-	return CL_CLEAN;
362
+
363
+	if(EC16(optional_hdr32.Magic) != PE32_SIGNATURE) {
364
+	    cli_warnmsg("Incorrect magic number in optional header\n");
365
+	    if(DETECT_BROKEN) {
366
+		if(virname)
367
+		    *virname = "Broken.Executable";
368
+		return CL_VIRUS;
369
+	    }
370
+	}
371
+	cli_dbgmsg("File format: PE\n");
372
+
373
+	cli_dbgmsg("MajorLinkerVersion: %d\n", optional_hdr32.MajorLinkerVersion);
374
+	cli_dbgmsg("MinorLinkerVersion: %d\n", optional_hdr32.MinorLinkerVersion);
375
+	cli_dbgmsg("SizeOfCode: %d\n", EC32(optional_hdr32.SizeOfCode));
376
+	cli_dbgmsg("SizeOfInitializedData: %d\n", EC32(optional_hdr32.SizeOfInitializedData));
377
+	cli_dbgmsg("SizeOfUninitializedData: %d\n", EC32(optional_hdr32.SizeOfUninitializedData));
378
+	cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", EC32(optional_hdr32.AddressOfEntryPoint));
379
+	cli_dbgmsg("BaseOfCode: 0x%x\n", EC32(optional_hdr32.BaseOfCode));
380
+	cli_dbgmsg("SectionAlignment: %d\n", EC32(optional_hdr32.SectionAlignment));
381
+	cli_dbgmsg("FileAlignment: %d\n", EC32(optional_hdr32.FileAlignment));
382
+	cli_dbgmsg("MajorSubsystemVersion: %d\n", EC16(optional_hdr32.MajorSubsystemVersion));
383
+	cli_dbgmsg("MinorSubsystemVersion: %d\n", EC16(optional_hdr32.MinorSubsystemVersion));
384
+	cli_dbgmsg("SizeOfImage: %d\n", EC32(optional_hdr32.SizeOfImage));
385
+	cli_dbgmsg("SizeOfHeaders: %d\n", EC32(optional_hdr32.SizeOfHeaders));
386
+	cli_dbgmsg("NumberOfRvaAndSizes: %d\n", EC32(optional_hdr32.NumberOfRvaAndSizes));
387
+
388
+    } else { /* PE+ */
389
+
390
+	if(read(desc, &optional_hdr64, sizeof(struct pe_image_optional_hdr64)) != sizeof(struct pe_image_optional_hdr64)) {
391
+	    cli_dbgmsg("Can't optional file header\n");
392
+	    if(DETECT_BROKEN) {
393
+		if(virname)
394
+		    *virname = "Broken.Executable";
395
+		return CL_VIRUS;
396
+	    }
397
+	    return CL_CLEAN;
398
+	}
399
+
400
+	if(EC16(optional_hdr64.Magic) != PE32P_SIGNATURE) {
401
+	    cli_warnmsg("Incorrect magic number in optional header\n");
402
+	    if(DETECT_BROKEN) {
403
+		if(virname)
404
+		    *virname = "Broken.Executable";
405
+		return CL_VIRUS;
406
+	    }
407
+	}
408
+	cli_dbgmsg("File format: PE32+\n");
409
+
410
+	cli_dbgmsg("MajorLinkerVersion: %d\n", optional_hdr64.MajorLinkerVersion);
411
+	cli_dbgmsg("MinorLinkerVersion: %d\n", optional_hdr64.MinorLinkerVersion);
412
+	cli_dbgmsg("SizeOfCode: %d\n", EC32(optional_hdr64.SizeOfCode));
413
+	cli_dbgmsg("SizeOfInitializedData: %d\n", EC32(optional_hdr64.SizeOfInitializedData));
414
+	cli_dbgmsg("SizeOfUninitializedData: %d\n", EC32(optional_hdr64.SizeOfUninitializedData));
415
+	cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", EC32(optional_hdr64.AddressOfEntryPoint));
416
+	cli_dbgmsg("BaseOfCode: 0x%x\n", EC32(optional_hdr64.BaseOfCode));
417
+	cli_dbgmsg("SectionAlignment: %d\n", EC32(optional_hdr64.SectionAlignment));
418
+	cli_dbgmsg("FileAlignment: %d\n", EC32(optional_hdr64.FileAlignment));
419
+	cli_dbgmsg("MajorSubsystemVersion: %d\n", EC16(optional_hdr64.MajorSubsystemVersion));
420
+	cli_dbgmsg("MinorSubsystemVersion: %d\n", EC16(optional_hdr64.MinorSubsystemVersion));
421
+	cli_dbgmsg("SizeOfImage: %d\n", EC32(optional_hdr64.SizeOfImage));
422
+	cli_dbgmsg("SizeOfHeaders: %d\n", EC32(optional_hdr64.SizeOfHeaders));
423
+	cli_dbgmsg("NumberOfRvaAndSizes: %d\n", EC32(optional_hdr64.NumberOfRvaAndSizes));
355 424
     }
356 425
 
357
-    cli_dbgmsg("MajorLinkerVersion: %d\n", optional_hdr.MajorLinkerVersion);
358
-    cli_dbgmsg("MinorLinkerVersion: %d\n", optional_hdr.MinorLinkerVersion);
359
-    cli_dbgmsg("SizeOfCode: %d\n", EC32(optional_hdr.SizeOfCode));
360
-    cli_dbgmsg("SizeOfInitializedData: %d\n", EC32(optional_hdr.SizeOfInitializedData));
361
-    cli_dbgmsg("SizeOfUninitializedData: %d\n", EC32(optional_hdr.SizeOfUninitializedData));
362
-    cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", EC32(optional_hdr.AddressOfEntryPoint));
363
-    cli_dbgmsg("SectionAlignment: %d\n", EC32(optional_hdr.SectionAlignment));
364
-    cli_dbgmsg("FileAlignment: %d\n", EC32(optional_hdr.FileAlignment));
365
-    cli_dbgmsg("MajorSubsystemVersion: %d\n", EC16(optional_hdr.MajorSubsystemVersion));
366
-    cli_dbgmsg("MinorSubsystemVersion: %d\n", EC16(optional_hdr.MinorSubsystemVersion));
367
-    cli_dbgmsg("SizeOfImage: %d\n", EC32(optional_hdr.SizeOfImage));
368
-    cli_dbgmsg("SizeOfHeaders: %d\n", EC32(optional_hdr.SizeOfHeaders));
369
-
370
-    switch(EC16(optional_hdr.Subsystem)) {
426
+    switch(pe_plus ? EC16(optional_hdr64.Subsystem) : EC16(optional_hdr32.Subsystem)) {
371 427
 	case 0:
372 428
 	    cli_dbgmsg("Subsystem: Unknown\n");
373 429
 	    break;
... ...
@@ -402,10 +461,9 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
402 402
 	    cli_dbgmsg("Subsystem: EFI runtime driver\n");
403 403
 	    break;
404 404
 	default:
405
-	    cli_warnmsg("Unknown subsystem in PE header (0x%x)\n", EC16(optional_hdr.Subsystem));
405
+	    cli_warnmsg("Unknown subsystem in PE header (0x%x)\n", pe_plus ? EC16(optional_hdr64.Subsystem) : EC16(optional_hdr32.Subsystem));
406 406
     }
407 407
 
408
-    cli_dbgmsg("NumberOfRvaAndSizes: %d\n", EC32(optional_hdr.NumberOfRvaAndSizes));
409 408
     cli_dbgmsg("------------------------------------\n");
410 409
 
411 410
     if(fstat(desc, &sb) == -1) {
... ...
@@ -488,7 +546,12 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
488 488
 
489 489
     }
490 490
 
491
-    if((ep = EC32(optional_hdr.AddressOfEntryPoint)) >= min && !(ep = cli_rawaddr(EC32(optional_hdr.AddressOfEntryPoint), section_hdr, nsections, &err)) && err) {
491
+    if(pe_plus)
492
+	ep = EC32(optional_hdr64.AddressOfEntryPoint);
493
+    else
494
+	ep = EC32(optional_hdr32.AddressOfEntryPoint);
495
+
496
+    if(ep >= min && !(ep = cli_rawaddr(ep, section_hdr, nsections, &err)) && err) {
492 497
 	cli_dbgmsg("Possibly broken PE file\n");
493 498
 	free(section_hdr);
494 499
 	if(DETECT_BROKEN) {
... ...
@@ -559,6 +622,12 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
559 559
 	return CL_CLEAN;
560 560
     }
561 561
 
562
+    if(pe_plus) { /* Do not continue for PE32+ files */
563
+	free(section_hdr);
564
+	return CL_CLEAN;
565
+    }
566
+
567
+
562 568
     /* UPX & FSG support */
563 569
 
564 570
     /* try to find the first section with physical size == 0 */
... ...
@@ -614,7 +683,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
614 614
 		    return CL_CLEAN;
615 615
 		}
616 616
 
617
-		if((newedx = cli_readint32(buff + 2) - EC32(optional_hdr.ImageBase)) < EC32(section_hdr[i + 1].VirtualAddress) || newedx >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 4) {
617
+		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) {
618 618
 		    cli_dbgmsg("FSG: xchg out of bounds (%x), giving up\n", newedx);
619 619
 		    break;
620 620
 		}
... ...
@@ -638,7 +707,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
638 638
 		    break;
639 639
 		}
640 640
 
641
-		if((newedx = cli_readint32(dest) - EC32(optional_hdr.ImageBase)) <= EC32(section_hdr[i + 1].VirtualAddress) || newedx >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 4) {
641
+		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) {
642 642
 		    cli_dbgmsg("FSG: New ESP (%x) is wrong\n", newedx);
643 643
 		    free(src);
644 644
 		    break;
... ...
@@ -650,9 +719,9 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
650 650
 		    break;
651 651
 		}
652 652
 
653
-		newedi = cli_readint32(dest) - EC32(optional_hdr.ImageBase);
654
-		newesi = cli_readint32(dest + 4) - EC32(optional_hdr.ImageBase);
655
-		newebx = cli_readint32(dest + 16) - EC32(optional_hdr.ImageBase);
653
+		newedi = cli_readint32(dest) - EC32(optional_hdr32.ImageBase);
654
+		newesi = cli_readint32(dest + 4) - EC32(optional_hdr32.ImageBase);
655
+		newebx = cli_readint32(dest + 16) - EC32(optional_hdr32.ImageBase);
656 656
 		newedx = cli_readint32(dest + 20);
657 657
 
658 658
 		if(newedi != EC32(section_hdr[i].VirtualAddress)) {
... ...
@@ -673,7 +742,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
673 673
 		    break;
674 674
 		}
675 675
 
676
-		newedx=cli_readint32(newebx + 12 - EC32(section_hdr[i + 1].VirtualAddress) + src) - EC32(optional_hdr.ImageBase);
676
+		newedx=cli_readint32(newebx + 12 - EC32(section_hdr[i + 1].VirtualAddress) + src) - EC32(optional_hdr32.ImageBase);
677 677
 		cli_dbgmsg("FSG: found old EP @%x\n",newedx);
678 678
 
679 679
 		if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
... ...
@@ -692,7 +761,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
692 692
 		    return CL_EIO;
693 693
 		}
694 694
 		
695
-		switch (unfsg_200(newesi - EC32(section_hdr[i + 1].VirtualAddress) + src, dest, ssize + EC32(section_hdr[i + 1].VirtualAddress) - newesi, dsize, newedi, EC32(optional_hdr.ImageBase), newedx, ndesc)) {
695
+		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)) {
696 696
 		    case 1: /* Everything OK */
697 697
 			cli_dbgmsg("FSG: Unpacked and rebuilt executable saved in %s\n", tempfile);
698 698
 			free(src);
... ...
@@ -740,7 +809,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
740 740
 	    }
741 741
 	}
742 742
 
743
- 	if(found && buff[0] == '\xbe' && cli_readint32(buff + 1) - EC32(optional_hdr.ImageBase) < min) {
743
+ 	if(found && buff[0] == '\xbe' && cli_readint32(buff + 1) - EC32(optional_hdr32.ImageBase) < min) {
744 744
 
745 745
 	    /* FSG support - v. 1.33 (thx trog for the many samples) */
746 746
 
... ...
@@ -771,7 +840,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
771 771
 		    return CL_CLEAN;
772 772
 		}
773 773
 
774
-		if((gp = cli_readint32(buff + 1) - EC32(optional_hdr.ImageBase)) >= (int) EC32(section_hdr[i + 1].PointerToRawData) || gp < 0) {
774
+		if((gp = cli_readint32(buff + 1) - EC32(optional_hdr32.ImageBase)) >= (int) EC32(section_hdr[i + 1].PointerToRawData) || gp < 0) {
775 775
 		    cli_dbgmsg("FSG: Support data out of padding area (vaddr: %d)\n", EC32(section_hdr[i].VirtualAddress));
776 776
 		    break;
777 777
 		}
... ...
@@ -802,9 +871,9 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
802 802
 		    return CL_EIO;
803 803
 		}
804 804
 
805
-		newebx = cli_readint32(support) - EC32(optional_hdr.ImageBase); /* Unused */
806
-		newedi = cli_readint32(support + 4) - EC32(optional_hdr.ImageBase); /* 1st dest */
807
-		newesi = cli_readint32(support + 8) - EC32(optional_hdr.ImageBase); /* Source */
805
+		newebx = cli_readint32(support) - EC32(optional_hdr32.ImageBase); /* Unused */
806
+		newedi = cli_readint32(support + 4) - EC32(optional_hdr32.ImageBase); /* 1st dest */
807
+		newesi = cli_readint32(support + 8) - EC32(optional_hdr32.ImageBase); /* Source */
808 808
 
809 809
 		if(newesi < EC32(section_hdr[i + 1].VirtualAddress) || newesi >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData)) {
810 810
 		    cli_dbgmsg("FSG: Source buffer out of section bounds\n");
... ...
@@ -825,7 +894,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
825 825
 		    if(!rva)
826 826
 			break;
827 827
 
828
-		    rva -= EC32(optional_hdr.ImageBase)+1;
828
+		    rva -= EC32(optional_hdr32.ImageBase)+1;
829 829
 		    sectcnt++;
830 830
 
831 831
 		    if(rva % 0x1000)
... ...
@@ -851,7 +920,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
851 851
 
852 852
 		sections[0].rva = newedi;
853 853
 		for(t = 1; t <= sectcnt; t++)
854
-		    sections[t].rva = cli_readint32(support + 8 + t * 4) - 1 -EC32(optional_hdr.ImageBase);
854
+		    sections[t].rva = cli_readint32(support + 8 + t * 4) - 1 -EC32(optional_hdr32.ImageBase);
855 855
 
856 856
 		free(support);
857 857
 
... ...
@@ -877,7 +946,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
877 877
 		    return CL_EMEM;
878 878
 		}
879 879
 
880
-		oldep = EC32(optional_hdr.AddressOfEntryPoint) + 161 + 6 + cli_readint32(buff+163);
880
+		oldep = EC32(optional_hdr32.AddressOfEntryPoint) + 161 + 6 + cli_readint32(buff+163);
881 881
 		cli_dbgmsg("FSG: found old EP @%x\n", oldep);
882 882
 
883 883
 		tempfile = cli_gentemp(NULL);
... ...
@@ -891,7 +960,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
891 891
 		    return CL_EIO;
892 892
 		}
893 893
 
894
-		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_hdr.ImageBase), oldep, ndesc)) {
894
+		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)) {
895 895
 		    case 1: /* Everything OK */
896 896
 			cli_dbgmsg("FSG: Unpacked and rebuilt executable saved in %s\n", tempfile);
897 897
 			free(src);
... ...
@@ -943,7 +1012,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
943 943
 	}
944 944
 
945 945
 	/* FIXME: easy 2 hack */
946
- 	if(found && buff[0] == '\xbb' && cli_readint32(buff + 1) - EC32(optional_hdr.ImageBase) < min && buff[5] == '\xbf' && buff[10] == '\xbe') {
946
+ 	if(found && buff[0] == '\xbb' && cli_readint32(buff + 1) - EC32(optional_hdr32.ImageBase) < min && buff[5] == '\xbf' && buff[10] == '\xbe') {
947 947
 
948 948
 	    /* FSG support - v. 1.31 */
949 949
 
... ...
@@ -951,11 +1020,11 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
951 951
 	    dsize = EC32(section_hdr[i].VirtualSize);
952 952
 
953 953
 	    while(found) {
954
-		    int gp = cli_readint32(buff+1) - EC32(optional_hdr.ImageBase), t, sectcnt = 0;
954
+		    int gp = cli_readint32(buff+1) - EC32(optional_hdr32.ImageBase), t, sectcnt = 0;
955 955
 		    char *support;
956
-		    uint32_t newesi = cli_readint32(buff+11) - EC32(optional_hdr.ImageBase);
957
-		    uint32_t newedi = cli_readint32(buff+6) - EC32(optional_hdr.ImageBase);
958
-		    uint32_t oldep = EC32(optional_hdr.AddressOfEntryPoint);
956
+		    uint32_t newesi = cli_readint32(buff+11) - EC32(optional_hdr32.ImageBase);
957
+		    uint32_t newedi = cli_readint32(buff+6) - EC32(optional_hdr32.ImageBase);
958
+		    uint32_t oldep = EC32(optional_hdr32.AddressOfEntryPoint);
959 959
 		    struct SECTION *sections;
960 960
 
961 961
 	        if (oldep <= EC32(section_hdr[i + 1].VirtualAddress) || oldep > EC32(section_hdr[i + 1].VirtualAddress)+EC32(section_hdr[i + 1].SizeOfRawData) - 0xe0) {
... ...
@@ -1029,7 +1098,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
1029 1029
 		  if (rva == 2 || rva == 1)
1030 1030
 		    break;
1031 1031
 
1032
-		  rva = ((rva-2)<<12) - EC32(optional_hdr.ImageBase);
1032
+		  rva = ((rva-2)<<12) - EC32(optional_hdr32.ImageBase);
1033 1033
 		  sectcnt++;
1034 1034
 
1035 1035
 		  if(rva < EC32(section_hdr[i].VirtualAddress) || rva >= EC32(section_hdr[i].VirtualAddress)+EC32(section_hdr[i].VirtualSize)) {
... ...
@@ -1051,7 +1120,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
1051 1051
 
1052 1052
 		sections[0].rva = newedi;
1053 1053
 		for(t = 0; t <= sectcnt - 1; t++) {
1054
-		  sections[t+1].rva = (((support[t*2]+256*support[t*2+1])-2)<<12)-EC32(optional_hdr.ImageBase);
1054
+		  sections[t+1].rva = (((support[t*2]+256*support[t*2+1])-2)<<12)-EC32(optional_hdr32.ImageBase);
1055 1055
 		}
1056 1056
 
1057 1057
 		free(support);
... ...
@@ -1080,7 +1149,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
1080 1080
 
1081 1081
 		/* Better not increasing buff size any further, let's go the hard way */
1082 1082
 		gp = 0xda + 6*(buff[16]=='\xe8');
1083
-		oldep = EC32(optional_hdr.AddressOfEntryPoint) + gp + 6 + cli_readint32(src+gp+2+oldep);
1083
+		oldep = EC32(optional_hdr32.AddressOfEntryPoint) + gp + 6 + cli_readint32(src+gp+2+oldep);
1084 1084
 		cli_dbgmsg("FSG: found old EP @%x\n", oldep);
1085 1085
 
1086 1086
 		tempfile = cli_gentemp(NULL);
... ...
@@ -1094,7 +1163,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
1094 1094
 		    return CL_EIO;
1095 1095
 		}
1096 1096
 
1097
-		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_hdr.ImageBase), oldep, ndesc)) {
1097
+		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)) {
1098 1098
 		    case 1: /* Everything OK */
1099 1099
 			cli_dbgmsg("FSG: Unpacked and rebuilt executable saved in %s\n", tempfile);
1100 1100
 			free(src);
... ...
@@ -1233,16 +1302,16 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
1233 1233
 	    }
1234 1234
 
1235 1235
 	    if(upxfn) {
1236
-		    int skew = cli_readint32(buff + 2) - EC32(optional_hdr.ImageBase) - EC32(section_hdr[i + 1].VirtualAddress);
1236
+		    int skew = cli_readint32(buff + 2) - EC32(optional_hdr32.ImageBase) - EC32(section_hdr[i + 1].VirtualAddress);
1237 1237
 
1238 1238
 		if(buff[1] != '\xbe' || skew <= 0 || skew > 0xfff) { /* FIXME: legit skews?? */
1239 1239
 		    skew = 0; 
1240
-		    if(upxfn(src, ssize, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr.AddressOfEntryPoint)) >= 0)
1240
+		    if(upxfn(src, ssize, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr32.AddressOfEntryPoint)) >= 0)
1241 1241
 			upx_success = 1;
1242 1242
 
1243 1243
 		} else {
1244 1244
 		    cli_dbgmsg("UPX: UPX1 seems skewed by %d bytes\n", skew);
1245
-                    if(upxfn(src + skew, ssize - skew, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr.AddressOfEntryPoint)-skew) >= 0 || upxfn(src, ssize, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr.AddressOfEntryPoint)) >= 0)
1245
+                    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)
1246 1246
 			upx_success = 1;
1247 1247
 		}
1248 1248
 
... ...
@@ -1253,7 +1322,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
1253 1253
 	    }
1254 1254
 
1255 1255
 	    if(!upx_success && upxfn != upx_inflate2b) {
1256
-		if(upx_inflate2b(src, ssize, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr.AddressOfEntryPoint)) == -1 && upx_inflate2b(src + 0x15, ssize - 0x15, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr.AddressOfEntryPoint) - 0x15) == -1) {
1256
+		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) {
1257 1257
 
1258 1258
 		    cli_dbgmsg("UPX: NRV2B decompressor failed\n");
1259 1259
 		} else {
... ...
@@ -1263,7 +1332,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
1263 1263
 	    }
1264 1264
 
1265 1265
 	    if(!upx_success && upxfn != upx_inflate2d) {
1266
-		if(upx_inflate2d(src, ssize, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr.AddressOfEntryPoint)) == -1 && upx_inflate2d(src + 0x15, ssize - 0x15, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr.AddressOfEntryPoint) - 0x15) == -1) {
1266
+		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) {
1267 1267
 
1268 1268
 		    cli_dbgmsg("UPX: NRV2D decompressor failed\n");
1269 1269
 		} else {
... ...
@@ -1273,7 +1342,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
1273 1273
 	    }
1274 1274
 
1275 1275
 	    if(!upx_success && upxfn != upx_inflate2e) {
1276
-		if(upx_inflate2e(src, ssize, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr.AddressOfEntryPoint)) == -1 && upx_inflate2e(src + 0x15, ssize - 0x15, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr.AddressOfEntryPoint) - 0x15) == -1) {
1276
+		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) {
1277 1277
 		    cli_dbgmsg("UPX: NRV2E decompressor failed\n");
1278 1278
 		} else {
1279 1279
 		    upx_success = 1;
... ...
@@ -1343,8 +1412,8 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
1343 1343
 	return CL_EIO;
1344 1344
     }
1345 1345
 
1346
-    if(buff[0] != '\xb8' || (uint32_t) cli_readint32(buff + 1) != EC32(section_hdr[nsections - 1].VirtualAddress) + EC32(optional_hdr.ImageBase)) {
1347
-	if(nsections < 2 || buff[0] != '\xb8' || (uint32_t) cli_readint32(buff + 1) != EC32(section_hdr[nsections - 2].VirtualAddress) + EC32(optional_hdr.ImageBase))
1346
+    if(buff[0] != '\xb8' || (uint32_t) cli_readint32(buff + 1) != EC32(section_hdr[nsections - 1].VirtualAddress) + EC32(optional_hdr32.ImageBase)) {
1347
+	if(nsections < 2 || buff[0] != '\xb8' || (uint32_t) cli_readint32(buff + 1) != EC32(section_hdr[nsections - 2].VirtualAddress) + EC32(optional_hdr32.ImageBase))
1348 1348
 	    found = 0;
1349 1349
 	else
1350 1350
 	    found = 1;
... ...
@@ -1398,10 +1467,10 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
1398 1398
 
1399 1399
 	    /* aCaB: Fixed to allow petite v2.1 unpacking (last section is a ghost) */
1400 1400
 	    switch(petite_inflate2x_1to9(dest, min, max - min, section_hdr,
1401
-		    nsections - (found == 1 ? 1 : 0), EC32(optional_hdr.ImageBase),
1402
-		    EC32(optional_hdr.AddressOfEntryPoint), ndesc,
1403
-		    found, EC32(optional_hdr.DataDirectory[2].VirtualAddress),
1404
-		    EC32(optional_hdr.DataDirectory[2].Size))) {
1401
+		    nsections - (found == 1 ? 1 : 0), EC32(optional_hdr32.ImageBase),
1402
+		    EC32(optional_hdr32.AddressOfEntryPoint), ndesc,
1403
+		    found, EC32(optional_hdr32.DataDirectory[2].VirtualAddress),
1404
+		    EC32(optional_hdr32.DataDirectory[2].Size))) {
1405 1405
 		case 1:
1406 1406
 		    cli_dbgmsg("Petite: Unpacked and rebuilt executable saved in %s\n", tempfile);
1407 1407
 		    cli_dbgmsg("***** Scanning rebuilt PE file *****\n");
... ...
@@ -1445,8 +1514,8 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
1445 1445
     /* PESpin 1.1 */
1446 1446
 
1447 1447
     if(nsections > 1 &&
1448
-       EC32(optional_hdr.AddressOfEntryPoint) >= EC32(section_hdr[nsections - 1].VirtualAddress) &&
1449
-       EC32(optional_hdr.AddressOfEntryPoint) < EC32(section_hdr[nsections - 1].VirtualAddress) + EC32(section_hdr[nsections - 1].SizeOfRawData) - 0x3217 - 4 &&
1448
+       EC32(optional_hdr32.AddressOfEntryPoint) >= EC32(section_hdr[nsections - 1].VirtualAddress) &&
1449
+       EC32(optional_hdr32.AddressOfEntryPoint) < EC32(section_hdr[nsections - 1].VirtualAddress) + EC32(section_hdr[nsections - 1].SizeOfRawData) - 0x3217 - 4 &&
1450 1450
        memcmp(buff+4, "\xe8\x00\x00\x00\x00\x8b\x1c\x24\x83\xc3", 10) == 0)  {
1451 1451
 
1452 1452
 	    struct stat fstats;
... ...
@@ -1479,7 +1548,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
1479 1479
 	    return CL_EIO;
1480 1480
 	}
1481 1481
 
1482
-	if(!unspin(spinned, fstats.st_size, section_hdr, nsections - 1, EC32(optional_hdr.AddressOfEntryPoint), ndesc)) {
1482
+	if(!unspin(spinned, fstats.st_size, section_hdr, nsections - 1, EC32(optional_hdr32.AddressOfEntryPoint), ndesc)) {
1483 1483
 	    free(spinned);
1484 1484
 	    cli_dbgmsg("PESpin: Unpacked and rebuilt executable saved in %s\n", tempfile);
1485 1485
 	    fsync(ndesc);
... ...
@@ -1523,11 +1592,12 @@ int cli_peheader(int desc, struct cli_exe_info *peinfo)
1523 1523
 	uint32_t e_lfanew; /* address of new exe header */
1524 1524
 	uint32_t min, max;
1525 1525
 	struct pe_image_file_hdr file_hdr;
1526
-	struct pe_image_optional_hdr optional_hdr;
1526
+	struct pe_image_optional_hdr32 optional_hdr32;
1527
+	struct pe_image_optional_hdr64 optional_hdr64;
1527 1528
 	struct pe_image_section_hdr *section_hdr;
1528 1529
 	struct stat sb;
1529 1530
 	int i;
1530
-	unsigned int err;
1531
+	unsigned int err, pe_plus = 0;
1531 1532
 
1532 1533
 
1533 1534
     cli_dbgmsg("in cli_peheader\n");
... ...
@@ -1573,16 +1643,30 @@ int cli_peheader(int desc, struct cli_exe_info *peinfo)
1573 1573
 	return -1;
1574 1574
     }
1575 1575
 
1576
-    if(EC16(file_hdr.SizeOfOptionalHeader) != sizeof(struct pe_image_optional_hdr)) {
1577
-	cli_warnmsg("Broken PE header detected.\n");
1578
-	return -1;
1576
+    peinfo->nsections = EC16(file_hdr.NumberOfSections);
1577
+
1578
+    if(EC16(file_hdr.SizeOfOptionalHeader) != sizeof(struct pe_image_optional_hdr32)) {
1579
+	if(EC16(file_hdr.SizeOfOptionalHeader) == sizeof(struct pe_image_optional_hdr64)) {
1580
+	    pe_plus = 1;
1581
+	} else {
1582
+	    cli_warnmsg("Broken PE header detected\n");
1583
+	    return -1;
1584
+	}
1579 1585
     }
1580 1586
 
1581
-    peinfo->nsections = EC16(file_hdr.NumberOfSections);
1587
+    if(!pe_plus) { /* PE */
1582 1588
 
1583
-    if(read(desc, &optional_hdr, sizeof(struct pe_image_optional_hdr)) != sizeof(struct pe_image_optional_hdr)) {
1584
-	cli_dbgmsg("Can't optional file header\n");
1585
-	return -1;
1589
+	if(read(desc, &optional_hdr32, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) {
1590
+	    cli_dbgmsg("Can't optional file header\n");
1591
+	    return -1;
1592
+	}
1593
+
1594
+    } else { /* PE+ */
1595
+
1596
+	if(read(desc, &optional_hdr64, sizeof(struct pe_image_optional_hdr64)) != sizeof(struct pe_image_optional_hdr64)) {
1597
+	    cli_dbgmsg("Can't optional file header\n");
1598
+	    return -1;
1599
+	}
1586 1600
     }
1587 1601
 
1588 1602
     peinfo->section = (struct cli_exe_section *) cli_calloc(peinfo->nsections, sizeof(struct cli_exe_section));
... ...
@@ -1633,7 +1717,12 @@ int cli_peheader(int desc, struct cli_exe_info *peinfo)
1633 1633
 	}
1634 1634
     }
1635 1635
 
1636
-    if((peinfo->ep = EC32(optional_hdr.AddressOfEntryPoint)) >= min && !(peinfo->ep = cli_rawaddr(EC32(optional_hdr.AddressOfEntryPoint), section_hdr, peinfo->nsections, &err)) && err) {
1636
+    if(pe_plus)
1637
+	peinfo->ep = EC32(optional_hdr64.AddressOfEntryPoint);
1638
+    else
1639
+	peinfo->ep = EC32(optional_hdr32.AddressOfEntryPoint);
1640
+
1641
+    if(peinfo->ep >= min && !(peinfo->ep = cli_rawaddr(peinfo->ep, section_hdr, peinfo->nsections, &err)) && err) {
1637 1642
 	cli_dbgmsg("Possibly broken PE file\n");
1638 1643
 	free(section_hdr);
1639 1644
 	free(peinfo->section);
... ...
@@ -1,5 +1,5 @@
1 1
 /*
2
- *  Copyright (C) 2004 Tomasz Kojm <tkojm@clamav.net>
2
+ *  Copyright (C) 2004 - 2005 Tomasz Kojm <tkojm@clamav.net>
3 3
  *
4 4
  *  Implementation (header structures) based on the PE format description
5 5
  *  by B. Luevelsmeyer
... ...
@@ -41,7 +41,7 @@ struct pe_image_data_dir {
41 41
     uint32_t Size;
42 42
 };
43 43
 
44
-struct pe_image_optional_hdr {
44
+struct pe_image_optional_hdr32 {
45 45
     uint16_t Magic;
46 46
     uint8_t  MajorLinkerVersion;		    /* unreliable */
47 47
     uint8_t  MinorLinkerVersion;		    /* unreliable */
... ...
@@ -75,6 +75,39 @@ struct pe_image_optional_hdr {
75 75
     struct pe_image_data_dir DataDirectory[16];
76 76
 };
77 77
 
78
+struct pe_image_optional_hdr64 {
79
+    uint16_t Magic;
80
+    uint8_t  MajorLinkerVersion;		    /* unreliable */
81
+    uint8_t  MinorLinkerVersion;		    /* unreliable */
82
+    uint32_t SizeOfCode;			    /* unreliable */
83
+    uint32_t SizeOfInitializedData;		    /* unreliable */
84
+    uint32_t SizeOfUninitializedData;		    /* unreliable */
85
+    uint32_t AddressOfEntryPoint;
86
+    uint32_t BaseOfCode;
87
+    uint64_t ImageBase;				    /* multiple of 64 KB */
88
+    uint32_t SectionAlignment;			    /* usually 32 or 4096 */
89
+    uint32_t FileAlignment;			    /* usually 32 or 512 */
90
+    uint16_t MajorOperatingSystemVersion;	    /* not used */
91
+    uint16_t MinorOperatingSystemVersion;	    /* not used */
92
+    uint16_t MajorImageVersion;			    /* unreliable */
93
+    uint16_t MinorImageVersion;			    /* unreliable */
94
+    uint16_t MajorSubsystemVersion;
95
+    uint16_t MinorSubsystemVersion;
96
+    uint32_t Win32VersionValue;			    /* ? */
97
+    uint32_t SizeOfImage;
98
+    uint32_t SizeOfHeaders;
99
+    uint32_t CheckSum;				    /* NT drivers only */
100
+    uint16_t Subsystem;
101
+    uint16_t DllCharacteristics;
102
+    uint64_t SizeOfStackReserve;
103
+    uint64_t SizeOfStackCommit;
104
+    uint64_t SizeOfHeapReserve;
105
+    uint64_t SizeOfHeapCommit;
106
+    uint32_t LoaderFlags;			    /* ? */
107
+    uint32_t NumberOfRvaAndSizes;		    /* unreliable */
108
+    struct pe_image_data_dir DataDirectory[16];
109
+};
110
+
78 111
 struct pe_image_section_hdr {
79 112
     uint8_t Name[8];			    /* may not end with NULL */
80 113
     /*