Browse code

hacked cli_exe_sextions to allow for unaligned values and characteristics

TODO:
- check consistency in elf parser, packers and rebuildpe
- remove hardcoded header size
- fix check for 1st sect rva
- ...


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

aCaB authored on 2007/03/14 11:53:08
Showing 2 changed files
... ...
@@ -26,10 +26,14 @@
26 26
 struct cli_exe_section {
27 27
     uint32_t rva;
28 28
     uint32_t vsz;
29
-    uint32_t uvsz; /* unaligned vsz */
30 29
     uint32_t raw;
31 30
     uint32_t rsz;
32
-    uint32_t ursz;
31
+    uint32_t chr;
32
+    uint32_t urva; /* PE - unaligned VirtualAddress */
33
+    uint32_t uvsz; /* PE - unaligned VirtualSize */
34
+    uint32_t uraw; /* PE - unaligned PointerToRawData */
35
+    uint32_t ursz; /* PE - unaligned SizeOfRawData */
36
+
33 37
 };
34 38
 
35 39
 struct cli_exe_info {
... ...
@@ -235,7 +235,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
235 235
 	uint16_t nsections;
236 236
 	uint32_t e_lfanew; /* address of new exe header */
237 237
 	uint32_t ep, vep; /* entry point (raw, virtual) */
238
-	uint8_t polipos = 0, magistr;
238
+	uint8_t polipos = 0;
239 239
 	time_t timestamp;
240 240
 	struct pe_image_file_hdr file_hdr;
241 241
 	union {
... ...
@@ -639,13 +639,16 @@ int cli_scanpe(int desc, cli_ctx *ctx)
639 639
 	sname[8] = 0;
640 640
 	exe_sections[i].rva = PEALIGN(EC32(section_hdr[i].VirtualAddress), valign);
641 641
 	exe_sections[i].vsz = PESALIGN(EC32(section_hdr[i].VirtualSize), valign);
642
-	exe_sections[i].uvsz = EC32(section_hdr[i].VirtualSize);
643 642
 	exe_sections[i].raw = PEALIGN(EC32(section_hdr[i].PointerToRawData), falign);
644 643
 	exe_sections[i].rsz = PESALIGN(EC32(section_hdr[i].SizeOfRawData), falign);
644
+	exe_sections[i].chr = EC32(section_hdr[i].Characteristics);
645
+	exe_sections[i].urva = EC32(section_hdr[i].VirtualAddress); /* Just in case */
646
+	exe_sections[i].uvsz = EC32(section_hdr[i].VirtualSize);
647
+	exe_sections[i].uraw = EC32(section_hdr[i].PointerToRawData);
645 648
 	exe_sections[i].ursz = EC32(section_hdr[i].SizeOfRawData);
646 649
 
647 650
 	if (!exe_sections[i].vsz && exe_sections[i].rsz)
648
-	    exe_sections[i].vsz=PESALIGN(EC32(section_hdr[i].SizeOfRawData), valign);
651
+	    exe_sections[i].vsz=PESALIGN(exe_sections[i].ursz, valign);
649 652
 
650 653
 	if (exe_sections[i].rsz && fsize>exe_sections[i].raw && !CLI_ISCONTAINED(0, (uint32_t) fsize, exe_sections[i].raw, exe_sections[i].rsz))
651 654
 	    exe_sections[i].rsz = fsize - exe_sections[i].raw;
... ...
@@ -653,12 +656,12 @@ int cli_scanpe(int desc, cli_ctx *ctx)
653 653
 	cli_dbgmsg("Section %d\n", i);
654 654
 	cli_dbgmsg("Section name: %s\n", sname);
655 655
 	cli_dbgmsg("Section data (from headers - in memory)\n");
656
-	cli_dbgmsg("VirtualSize: 0x%x 0x%x\n", EC32(section_hdr[i].VirtualSize), exe_sections[i].vsz);
657
-	cli_dbgmsg("VirtualAddress: 0x%x 0x%x\n", EC32(section_hdr[i].VirtualAddress), exe_sections[i].rva);
658
-	cli_dbgmsg("SizeOfRawData: 0x%x 0x%x\n", EC32(section_hdr[i].SizeOfRawData), exe_sections[i].rsz);
659
-	cli_dbgmsg("PointerToRawData: 0x%x 0x%x\n", EC32(section_hdr[i].PointerToRawData), exe_sections[i].raw);
656
+	cli_dbgmsg("VirtualSize: 0x%x 0x%x\n", exe_sections[i].uvsz, exe_sections[i].vsz);
657
+	cli_dbgmsg("VirtualAddress: 0x%x 0x%x\n", exe_sections[i].urva, exe_sections[i].rva);
658
+	cli_dbgmsg("SizeOfRawData: 0x%x 0x%x\n", exe_sections[i].ursz, exe_sections[i].rsz);
659
+	cli_dbgmsg("PointerToRawData: 0x%x 0x%x\n", exe_sections[i].uraw, exe_sections[i].raw);
660 660
 
661
-	if(EC32(section_hdr[i].Characteristics) & 0x20) {
661
+	if(exe_sections[i].chr & 0x20) {
662 662
 	    cli_dbgmsg("Section contains executable code\n");
663 663
 
664 664
 	    if(exe_sections[i].vsz < exe_sections[i].rsz) {
... ...
@@ -671,15 +674,15 @@ int cli_scanpe(int desc, cli_ctx *ctx)
671 671
 	    }
672 672
 	}
673 673
 
674
-	if(EC32(section_hdr[i].Characteristics) & 0x20000000)
674
+	if(exe_sections[i].chr & 0x20000000)
675 675
 	    cli_dbgmsg("Section's memory is executable\n");
676 676
 
677
-	if(EC32(section_hdr[i].Characteristics) & 0x80000000)
677
+	if(exe_sections[i].chr & 0x80000000)
678 678
 	    cli_dbgmsg("Section's memory is writeable\n");
679 679
 
680 680
 	cli_dbgmsg("------------------------------------\n");
681 681
 
682
-	if (DETECT_BROKEN && EC32(section_hdr[i].VirtualAddress)%valign) { /* Bad virtual alignment */
682
+	if (DETECT_BROKEN && (exe_sections[i].urva % valign)) { /* Bad virtual alignment */
683 683
 	    cli_dbgmsg("VirtualAddress is misaligned\n");
684 684
 	    if(ctx->virname)
685 685
 	        *ctx->virname = "Broken.Executable";
... ...
@@ -730,7 +733,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
730 730
 	}
731 731
 
732 732
 	if(!i) {
733
-	    if (DETECT_BROKEN && (pe_plus?EC16(optional_hdr64.Subsystem):EC16(optional_hdr32.Subsystem))!= 1 && EC32(section_hdr[i].VirtualAddress)!=valign) { /* Bad first section RVA */
733
+	    if (DETECT_BROKEN && (pe_plus?EC16(optional_hdr64.Subsystem):EC16(optional_hdr32.Subsystem))!= 1 && exe_sections[i].urva!=valign) { /* Bad first section RVA */
734 734
 	        cli_dbgmsg("First section is in the wrong place\n");
735 735
 	        if(ctx->virname)
736 736
 		    *ctx->virname = "Broken.Executable";
... ...
@@ -741,7 +744,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
741 741
 	    min = exe_sections[i].rva;
742 742
 	    max = exe_sections[i].rva + exe_sections[i].rsz;
743 743
 	} else {
744
-	    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 */
744
+	    if (DETECT_BROKEN && exe_sections[i].urva - exe_sections[i-1].urva != exe_sections[i-1].vsz) { /* No holes, no overlapping, no virtual disorder */
745 745
 	        cli_dbgmsg("Virtually misplaced section (wrong order, overlapping, non contiguous)\n");
746 746
 	        if(ctx->virname)
747 747
 		    *ctx->virname = "Broken.Executable";
... ...
@@ -758,7 +761,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
758 758
 
759 759
 	if(SCAN_ALGO && (DCONF & PE_CONF_POLIPOS) && !strlen(sname)) {
760 760
 	    if(exe_sections[i].vsz > 40000 && exe_sections[i].vsz < 70000) {
761
-		if(EC32(section_hdr[i].Characteristics) == 0xe0000060) {
761
+		if(exe_sections[i].chr == 0xe0000060) {
762 762
 		    polipos = i;
763 763
 		}
764 764
 	    }
... ...
@@ -766,9 +769,10 @@ int cli_scanpe(int desc, cli_ctx *ctx)
766 766
 
767 767
     }
768 768
 
769
+    free(section_hdr);
770
+
769 771
     if(!(ep = cli_rawaddr(vep, exe_sections, nsections, &err, fsize)) && err) {
770 772
 	cli_dbgmsg("EntryPoint out of file\n");
771
-	free(section_hdr);
772 773
 	free(exe_sections);
773 774
 	if(DETECT_BROKEN) {
774 775
 	    if(ctx->virname)
... ...
@@ -781,22 +785,10 @@ int cli_scanpe(int desc, cli_ctx *ctx)
781 781
     cli_dbgmsg("EntryPoint offset: 0x%x (%d)\n", ep, ep);
782 782
 
783 783
     if(pe_plus) { /* Do not continue for PE32+ files */
784
-	free(section_hdr);
785 784
 	free(exe_sections);
786 785
 	return CL_CLEAN;
787 786
     }
788 787
 
789
-    magistr = (SCAN_ALGO && (DCONF & PE_CONF_MAGISTR) && !dll && (nsections>1) && (EC32(section_hdr[nsections - 1].Characteristics) & 0x80000000));
790
-
791
-    /*
792
-        - ENDPASS for section based heuristics -
793
-
794
-	past this line section names and
795
-	characteristics	are not availble
796
-    */
797
-    free(section_hdr);
798
-
799
-
800 788
 
801 789
     /* Attempt to detect some popular polymorphic viruses */
802 790
 
... ...
@@ -880,7 +872,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
880 880
     }
881 881
 
882 882
     /* W32.Magistr.A/B */
883
-    if(magistr) {
883
+    if(SCAN_ALGO && (DCONF & PE_CONF_MAGISTR) && !dll && (nsections>1) && (exe_sections[nsections - 1].chr & 0x80000000)) {
884 884
 	    uint32_t rsize, vsize, dam = 0;
885 885
 
886 886
 	vsize = exe_sections[nsections - 1].uvsz;
... ...
@@ -1244,7 +1236,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1244 1244
 	    }
1245 1245
 	} while (0);
1246 1246
     }
1247
-HERE!!!
1247
+
1248 1248
     if(found || upack) {
1249 1249
 	/* Check EP for UPX vs. FSG vs. Upack */
1250 1250
 	if(lseek(desc, ep, SEEK_SET) == -1) {
... ...
@@ -1305,30 +1297,29 @@ HERE!!!
1305 1305
 	    )
1306 1306
 	   ){ 
1307 1307
 		uint32_t vma, off;
1308
-		int a,b,c, file;
1308
+		int a,b,c;
1309 1309
 
1310 1310
 		cli_dbgmsg("Upack characteristics found.\n");
1311
-		a = EC32(section_hdr[0].VirtualSize);
1312
-		b = EC32(section_hdr[1].VirtualSize);
1311
+		a = exe_sections[0].vsz;
1312
+		b = exe_sections[1].vsz;
1313 1313
 		if (upack) {
1314
-			cli_dbgmsg("upack var set\n");
1315
-			c = EC32(section_hdr[2].VirtualSize);
1316
-			ssize = EC32(section_hdr[0].SizeOfRawData) + EC32(section_hdr[0].PointerToRawData);
1317
-			off = EC32(section_hdr[0].VirtualAddress);
1318
-			vma = EC32(optional_hdr32.ImageBase) + EC32(section_hdr[0].VirtualAddress);
1314
+			cli_dbgmsg("Upack: var set\n");
1315
+			c = exe_sections[2].vsz;
1316
+			ssize = exe_sections[0].ursz + exe_sections[0].uraw;
1317
+			off = exe_sections[0].rva;
1318
+			vma = EC32(optional_hdr32.ImageBase) + exe_sections[0].rva;
1319 1319
 		} else {
1320
-			cli_dbgmsg("upack var NOT set\n");
1321
-			c = EC32(section_hdr[1].VirtualAddress);
1322
-			ssize = EC32(section_hdr[1].PointerToRawData);
1320
+			cli_dbgmsg("Upack: var NOT set\n");
1321
+			c = exe_sections[1].rva;
1322
+			ssize = exe_sections[1].uraw;
1323 1323
 			off = 0;
1324
-			vma = EC32(section_hdr[1].VirtualAddress) - EC32(section_hdr[1].PointerToRawData);
1324
+			vma = exe_sections[1].rva - exe_sections[1].uraw;
1325 1325
 		}
1326 1326
 
1327 1327
 		dsize = a+b+c;
1328
-		if (ctx->limits && ctx->limits->maxfilesize && (dsize > ctx->limits->maxfilesize || ssize > ctx->limits->maxfilesize || EC32(section_hdr[1].SizeOfRawData) > ctx->limits->maxfilesize))
1328
+		if (ctx->limits && ctx->limits->maxfilesize && (dsize > ctx->limits->maxfilesize || ssize > ctx->limits->maxfilesize || exe_sections[1].ursz > ctx->limits->maxfilesize))
1329 1329
 		{
1330 1330
 		    cli_dbgmsg("Upack: Sizes exceeded (a: %u, b: %u, c: %ux, max: %lu)\n", a, b, c, ctx->limits->maxfilesize);
1331
-		    free(section_hdr);
1332 1331
 		    free(exe_sections);
1333 1332
 		    if(BLOCKMAX) {
1334 1333
 			*ctx->virname = "PE.Upack.ExceededFileSize";
... ...
@@ -1338,90 +1329,80 @@ HERE!!!
1338 1338
 		    }
1339 1339
 		}
1340 1340
 		/* these are unsigned so if vaddr - off < 0, it should be ok */
1341
-		if (EC32(section_hdr[1].VirtualAddress) - off > dsize || EC32(section_hdr[1].VirtualAddress) - off > dsize - EC32(section_hdr[1].SizeOfRawData) || (upack && (EC32(section_hdr[2].VirtualAddress) - EC32(section_hdr[0].VirtualAddress) > dsize || EC32(section_hdr[2].VirtualAddress) - EC32(section_hdr[0].VirtualAddress) > dsize - ssize)) || ssize > dsize)
1341
+		if (exe_sections[1].rva - off > dsize || exe_sections[1].rva - off > dsize - exe_sections[1].ursz || (upack && exe_sections[2].rva - exe_sections[0].rva > dsize || exe_sections[2].rva - exe_sections[0].rva > dsize - ssize) || ssize > dsize)
1342 1342
 		{
1343 1343
 		    cli_dbgmsg("Upack: probably malformed pe-header, skipping to next unpacker\n");
1344
-		    goto skip_upack_and_go_to_next_unpacker; /* I didn't want to add additional do while + break, can it be this way ? */
1344
+		    goto skip_upack_and_go_to_next_unpacker;
1345 1345
 		}
1346 1346
 			
1347 1347
 		if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
1348
-		    free(section_hdr);
1349 1348
 		    free(exe_sections);
1350 1349
 		    return CL_EMEM;
1351 1350
 		}
1352 1351
 		src = NULL;
1353
-		cli_dbgmsg("Upack: min: %08x %08x max: %08x\n", dest, a+b+c, dest+a+b+c);
1354 1352
 	
1355 1353
 		lseek(desc, 0, SEEK_SET);
1356
-		if(read(desc, dest, ssize) != ssize) { /* 2vGiM: i think this can be overflowed - should you check for ssize < dsize ?
1357
-		                                        * yup, I think you're right, added above
1358
-							*/
1354
+		if(read(desc, dest, ssize) != ssize) {
1359 1355
 		    cli_dbgmsg("Upack: Can't read raw data of section 0\n");
1360
-		    free(section_hdr);
1361 1356
 		    free(exe_sections);
1362 1357
 		    free(dest);
1363 1358
 		    return CL_EIO;
1364 1359
 		}
1365 1360
 
1366 1361
 		if (upack)
1367
-			memmove(dest + EC32(section_hdr[2].VirtualAddress) - EC32(section_hdr[0].VirtualAddress), dest, ssize);
1362
+		    memmove(dest + exe_sections[2].rva - exe_sections[0].rva, dest, ssize);
1368 1363
 
1369
-		lseek(desc, EC32(section_hdr[1].PointerToRawData), SEEK_SET);
1364
+		lseek(desc, exe_sections[1].uraw, SEEK_SET);
1370 1365
 
1371
-		if(read(desc, dest+EC32(section_hdr[1].VirtualAddress) - off, EC32(section_hdr[1].SizeOfRawData)) != EC32(section_hdr[1].SizeOfRawData)) {
1366
+		if(read(desc, dest + exe_sections[1].rva - off, exe_sections[1].uraw) != exe_sections[1].uraw) {
1372 1367
 		    cli_dbgmsg("Upack: Can't read raw data of section 1\n");
1373
-		    free(section_hdr);
1374 1368
 		    free(exe_sections);
1375 1369
 		    free(dest);
1376 1370
 		    return CL_EIO;
1377 1371
 		}
1378 1372
 
1379 1373
 		if(!(tempfile = cli_gentemp(NULL))) {
1380
-		    free(section_hdr);
1381 1374
 		    free(exe_sections);
1382 1375
 		    free(dest);
1383 1376
 		    return CL_EMEM;
1384 1377
 		}
1385 1378
 
1386
-		if((file = open(tempfile, O_RDWR|O_CREAT|O_TRUNC, S_IRWXU)) < 0) {
1379
+		if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC, S_IRWXU)) < 0) {
1387 1380
 		    cli_dbgmsg("Upack: Can't create file %s\n", tempfile);
1388 1381
 		    free(tempfile);
1389
-		    free(section_hdr);
1390 1382
 		    free(exe_sections);
1391 1383
 		    free(dest);
1392 1384
 		    return CL_EIO;
1393 1385
 		}
1394 1386
 
1395
-		switch (unupack(upack, dest, dsize, buff, vma, ep, EC32(optional_hdr32.ImageBase), EC32(section_hdr[0].VirtualAddress), file))
1387
+		switch (unupack(upack, dest, dsize, buff, vma, ep, EC32(optional_hdr32.ImageBase), exe_sections[0].rva, ndesc))
1396 1388
 		{
1397 1389
 			case 1: /* Everything OK */
1398 1390
 				cli_dbgmsg("Upack: Unpacked and rebuilt executable saved in %s\n", tempfile);
1399 1391
 				free(dest);
1400
-				fsync(file);
1401
-				lseek(file, 0, SEEK_SET);
1392
+				fsync(ndesc);
1393
+				lseek(ndesc, 0, SEEK_SET);
1402 1394
 
1403 1395
 				cli_dbgmsg("***** Scanning rebuilt PE file *****\n");
1404
-				if(cli_magic_scandesc(file, ctx) == CL_VIRUS) {
1405
-					free(section_hdr);
1396
+				if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) {
1406 1397
 					free(exe_sections);
1407
-					close(file);
1398
+					close(ndesc);
1408 1399
 					if(!cli_leavetemps_flag)
1409 1400
 						unlink(tempfile);
1410 1401
 					free(tempfile);
1411 1402
 					return CL_VIRUS;
1412 1403
 				}
1413 1404
 
1414
-				close(file);
1405
+				close(ndesc);
1415 1406
 				if(!cli_leavetemps_flag)
1416 1407
 					unlink(tempfile);
1417 1408
 				free(tempfile);
1418
-				free(section_hdr);
1419 1409
 				free(exe_sections);
1420 1410
 				return CL_CLEAN;
1421 1411
 
1422 1412
 			default: /* Everything gone wrong */
1423 1413
 				cli_dbgmsg("Upack: Unpacking failed\n");
1424
-				close(file);
1414
+				close(ndesc);
1425 1415
 				unlink(tempfile); /* It's empty anyway */
1426 1416
 				free(tempfile);
1427 1417
 				free(dest);
... ...
@@ -1429,7 +1410,7 @@ HERE!!!
1429 1429
 		}
1430 1430
 	}
1431 1431
 skip_upack_and_go_to_next_unpacker:
1432
-
1432
+HERE!!!
1433 1433
 	if((DCONF & PE_CONF_FSG) && buff[0] == '\x87' && buff[1] == '\x25') {
1434 1434
 
1435 1435
 	    /* FSG v2.0 support - thanks to aCaB ! */