Browse code

improve UPX detection

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

Tomasz Kojm authored on 2004/07/07 09:21:04
Showing 3 changed files
... ...
@@ -111,6 +111,7 @@ Masaki Ogawa <proc*mac.com>
111 111
 Phil Oleson <oz*nixil.net>
112 112
 Rudolph Pereira <r.pereira*isu.usyd.edu.au>
113 113
 Ed Phillips <ed*UDel.Edu>
114
+Pierre <pierrezero*fastmail.fm>
114 115
 Andreas Piesk <Andreas.Piesk*heise.de>
115 116
 Ant La Porte <ant*dvere.net>
116 117
 Thomas Quinot <thomas*cuivre.fr.eu.org>
... ...
@@ -1,3 +1,8 @@
1
+Wed Jul  7 02:17:00 CEST 2004 (tk)
2
+----------------------------------
3
+  * libclamav: pe: Improve UPX detection (thanks to aCaB). Ignore old "ZM"
4
+		   DOS executables (thanks to Pierre <pierrezero*fastmail.fm>)
5
+
1 6
 Tue Jul  6 17:46:39 CEST 2004 (tk)
2 7
 ----------------------------------
3 8
   * libclamav: disable quoted-printable decoder in HTML normaliser
... ...
@@ -38,12 +38,13 @@
38 38
 #include "upx.h"
39 39
 
40 40
 #define IMAGE_DOS_SIGNATURE	    0x5a4d	    /* MZ */
41
+#define IMAGE_DOS_SIGNATURE_OLD	    0x4d5a          /* ZM */
41 42
 #define IMAGE_NT_SIGNATURE	    0x00004550
42 43
 #define IMAGE_OPTIONAL_SIGNATURE    0x010b
43 44
 
44
-#define UPX_NRV2B "\x11\xc9\x75\x20\x41\x01\xdb\x75\x07\x8b\x1e\x83\xee\xfc\x11\xdb\x11\xc9\x01\xdb\x73\xef\x75\x09"
45
-#define UPX_NRV2D "\x8b\x1e\x83\xee\xfc\x11\xdb\x11\xc9\x01\xdb\x75\x07\x8b\x1e\x83\xee\xfc\x11\xdb\x11\xc9\x75\x20"
46
-#define UPX_NRV2E "\x83\xf0\xff\x74\x75\xd1\xf8\x89\xc5\xeb\x0b\x01\xdb\x75\x07\x8b\x1e\x83\xee\xfc\x11\xdb\x72\xcc"
45
+#define UPX_NRV2B "\x11\xdb\x11\xc9\x01\xdb\x75\x07\x8b\x1e\x83\xee\xfc\x11\xdb\x11\xc9\x11\xc9\x75\x20\x41\x01\xdb"
46
+#define UPX_NRV2D "\x83\xf0\xff\x74\x78\xd1\xf8\x89\xc5\xeb\x0b\x01\xdb\x75\x07\x8b\x1e\x83\xee\xfc\x11\xdb\x11\xc9"
47
+#define UPX_NRV2E "\xeb\x52\x31\xc9\x83\xe8\x03\x72\x11\xc1\xe0\x08\x8a\x06\x46\x83\xf0\xff\x74\x75\xd1\xf8\x89\xc5"
47 48
 
48 49
 #if WORDS_BIGENDIAN == 0
49 50
 #define EC16(v)	(v)
... ...
@@ -234,7 +235,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
234 234
 	struct pe_image_section_hdr *section_hdr;
235 235
 	struct stat sb;
236 236
 	char sname[9], buff[24], *tempfile;
237
-	int i, found, upx_success = 0;
237
+	int i, found, upx_success = 0, broken = 0;
238 238
 	int (*upxfn)(char *, int , char *, int) = NULL;
239 239
 
240 240
 
... ...
@@ -243,7 +244,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
243 243
 	return CL_EIO;
244 244
     }
245 245
 
246
-    if(EC16(e_magic) != IMAGE_DOS_SIGNATURE) {
246
+    if(EC16(e_magic) != IMAGE_DOS_SIGNATURE && EC16(e_magic) != IMAGE_DOS_SIGNATURE_OLD) {
247 247
 	cli_dbgmsg("Invalid DOS signature\n");
248 248
 	return CL_CLEAN;
249 249
     }
... ...
@@ -375,6 +376,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
375 375
 	strncpy(sname, section_hdr[i].Name, 8);
376 376
 	sname[8] = 0;
377 377
 	cli_dbgmsg("------------------------------------\n");
378
+	cli_dbgmsg("Section %d of %d\n", i, nsections);
378 379
 	cli_dbgmsg("Section name: %s\n", sname);
379 380
 	cli_dbgmsg("VirtualSize: %d\n", EC32(section_hdr[i].VirtualSize));
380 381
 	cli_dbgmsg("VirtualAddress: 0x%x\n", EC32(section_hdr[i].VirtualAddress));
... ...
@@ -414,11 +416,18 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
414 414
 	return CL_EIO;
415 415
     }
416 416
 
417
-    ep = cli_rawaddr(EC32(optional_hdr.AddressOfEntryPoint), section_hdr, nsections);
417
+    if((ep = cli_rawaddr(EC32(optional_hdr.AddressOfEntryPoint), section_hdr, nsections)) == -1) {
418
+	cli_dbgmsg("Possibly broken PE file - Entry Point @%d out of file.\n", ep);
419
+	broken = 1;
420
+    }
418 421
 
419 422
     /* simple sanity check */
420
-    if(EC32(section_hdr[nsections - 1].PointerToRawData) + EC32(section_hdr[nsections - 1].SizeOfRawData) > sb.st_size || ep == -1) {
421
-	cli_dbgmsg("Possibly broken PE file\n");
423
+    if(!broken && EC32(section_hdr[nsections - 1].PointerToRawData) + EC32(section_hdr[nsections - 1].SizeOfRawData) > sb.st_size) {
424
+	cli_dbgmsg("Possibly broken PE file - Section %d out of file (Offset@ %d, Rsize %d, Total filesize %d, EP@ %d)\n", i, EC32(section_hdr[i].PointerToRawData), EC32(section_hdr[i].SizeOfRawData), sb.st_size, ep);
425
+	broken = 1;
426
+    }
427
+
428
+    if(broken) {
422 429
 	free(section_hdr);
423 430
 	return CL_CLEAN;
424 431
     }
... ...
@@ -431,7 +440,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
431 431
     /* try to find the first section with physical size == 0 */
432 432
     found = 0;
433 433
     for(i = 0; i < nsections - 1; i++) {
434
-	if(!section_hdr[i].SizeOfRawData) {
434
+	if(!section_hdr[i].SizeOfRawData && section_hdr[i].VirtualSize && section_hdr[i+1].SizeOfRawData && section_hdr[i+1].VirtualSize) {
435 435
 	    found = 1;
436 436
 	    cli_dbgmsg("UPX: empty section found - assuming UPX compression\n");
437 437
 	    break;
... ...
@@ -484,23 +493,23 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
484 484
 
485 485
 	/* try to detect UPX code */
486 486
 
487
-	if(lseek(desc, ep + 0x78, SEEK_SET) == -1) {
487
+	if(lseek(desc, ep + 0x69, SEEK_SET) == -1) {
488 488
 	    cli_dbgmsg("lseek() failed\n");
489 489
 	    free(section_hdr);
490 490
 	    return CL_EIO;
491 491
 	}
492 492
 
493
-	if(read(desc, buff, 13) != 13) {
494
-	    cli_dbgmsg("UPX: Can't read 13 bytes at 0x%x (%d)\n", ep + 0x78, ep + 0x78);
493
+	if(read(desc, buff, 21) != 21) {
494
+	    cli_dbgmsg("UPX: Can't read 21 bytes at 0x%x (%d)\n", ep + 0x69, ep + 0x78);
495 495
 	    return CL_EIO;
496 496
 	} else {
497
-	    if(cli_memstr(UPX_NRV2B, 24, buff, 13)) {
497
+	    if(cli_memstr(UPX_NRV2B, 24, buff, 13) || cli_memstr(UPX_NRV2B, 24, buff + 8, 13)) {
498 498
 		cli_dbgmsg("UPX: Looks like a NRV2B decompression routine\n");
499 499
 		upxfn = upx_inflate2b;
500
-	    } else if(cli_memstr(UPX_NRV2D, 24, buff, 13)) {
500
+	    } else if(cli_memstr(UPX_NRV2D, 24, buff, 13) || cli_memstr(UPX_NRV2D, 24, buff + 8, 13)) {
501 501
 		cli_dbgmsg("UPX: Looks like a NRV2D decompression routine\n");
502 502
 		upxfn = upx_inflate2d;
503
-	    } else if(cli_memstr(UPX_NRV2E, 24, buff, 13)) {
503
+	    } else if(cli_memstr(UPX_NRV2E, 24, buff, 13) || cli_memstr(UPX_NRV2E, 24, buff + 8, 13)) {
504 504
 		cli_dbgmsg("UPX: Looks like a NRV2E decompression routine\n");
505 505
 		upxfn = upx_inflate2e;
506 506
 	    }
... ...
@@ -511,7 +520,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
511 511
 		cli_dbgmsg("UPX: Prefered decompressor failed\n");
512 512
 	    } else {
513 513
 		upx_success = 1;
514
-		cli_dbgmsg("UPX: Successfuly decompressed\n");
514
+		cli_dbgmsg("UPX: Successfully decompressed\n");
515 515
 	    }
516 516
 	}
517 517
 
... ...
@@ -520,7 +529,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
520 520
 		cli_dbgmsg("UPX: NRV2B decompressor failed\n");
521 521
 	    } else {
522 522
 		upx_success = 1;
523
-		cli_dbgmsg("UPX: Successfuly decompressed with NRV2B\n");
523
+		cli_dbgmsg("UPX: Successfully decompressed with NRV2B\n");
524 524
 	    }
525 525
 	}
526 526
 
... ...
@@ -529,7 +538,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
529 529
 		cli_dbgmsg("UPX: NRV2D decompressor failed\n");
530 530
 	    } else {
531 531
 		upx_success = 1;
532
-		cli_dbgmsg("UPX: Successfuly decompressed with NRV2D\n");
532
+		cli_dbgmsg("UPX: Successfully decompressed with NRV2D\n");
533 533
 	    }
534 534
 	}
535 535
 
... ...
@@ -538,7 +547,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
538 538
 		cli_dbgmsg("UPX: NRV2E decompressor failed\n");
539 539
 	    } else {
540 540
 		upx_success = 1;
541
-		cli_dbgmsg("UPX: Successfuly decompressed with NRV2E\n");
541
+		cli_dbgmsg("UPX: Successfully decompressed with NRV2E\n");
542 542
 	    }
543 543
 	}
544 544