...
|
...
|
@@ -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);
|