36
36
#ifndef DISABLE_VERIFIER
37
37
/*
38
38
TODO add fail fast mode
39
- TODO add PE32+ support
40
39
TODO verify the entry point RVA and content.
41
- TODO load_section_table and load_data_directories must take PE32+ into account
42
40
TODO add section relocation support
43
41
TODO verify the relocation table, since we really don't use, no need so far.
44
42
TODO do full PECOFF resources verification
@@ -231,9 +229,11 @@ typedef struct {
231
229
gboolean report_warning ;
232
230
int stage ;
233
231
232
+ // Mono really only requires 15 here, but verifies the extra is zeroed.
234
233
DataDirectory data_directories [16 ];
235
234
guint32 section_count ;
236
235
SectionHeader * sections ;
236
+ guint pe64 ; // short name for PE32+; actual PE64 proposal was rejected
237
237
238
238
OffsetAndSize metadata_streams [5 ]; //offset from begin of the image
239
239
} VerifyContext ;
@@ -441,8 +441,6 @@ verify_pe_header (VerifyContext *ctx)
441
441
442
442
if (offset > ctx -> size - 20 )
443
443
ADD_ERROR (ctx , g_strdup ("File with truncated pe header" ));
444
- if (read16 (pe_header ) != 0x14c )
445
- ADD_ERROR (ctx , g_strdup ("Invalid PE header Machine value" ));
446
444
}
447
445
448
446
static void
@@ -462,40 +460,58 @@ verify_pe_optional_header (VerifyContext *ctx)
462
460
if (offset > ctx -> size - header_size || header_size > ctx -> size )
463
461
ADD_ERROR (ctx , g_strdup ("Invalid PE optional header size" ));
464
462
465
- if (read16 (pe_optional_header ) == 0x10b ) {
466
- if (header_size != 224 )
467
- ADD_ERROR (ctx , g_strdup_printf ("Invalid optional header size %d" , header_size ));
468
-
469
- /* LAMESPEC MS plays around this value and ignore it during validation
470
- if (read32 (pe_optional_header + 28) != 0x400000)
471
- ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
472
- if (read32 (pe_optional_header + 32 ) != 0x2000 )
473
- ADD_ERROR (ctx , g_strdup_printf ("Invalid Section Aligmnent %x" , read32 (pe_optional_header + 32 )));
474
- file_alignment = read32 (pe_optional_header + 36 );
475
- if (file_alignment != 0x200 && file_alignment != 0x1000 )
476
- ADD_ERROR (ctx , g_strdup_printf ("Invalid file Aligmnent %x" , file_alignment ));
477
- /* All the junk in the middle is irrelevant, specially for mono. */
478
- if (read32 (pe_optional_header + 92 ) > 0x10 )
479
- ADD_ERROR (ctx , g_strdup_printf ("Too many data directories %x" , read32 (pe_optional_header + 92 )));
480
- } else {
481
- if (read16 (pe_optional_header ) == 0x20B )
482
- ADD_ERROR (ctx , g_strdup ("Metadata verifier doesn't handle PE32+" ));
483
- else
484
- ADD_ERROR (ctx , g_strdup_printf ("Invalid optional header magic %d" , read16 (pe_optional_header )));
485
- }
463
+ const guint16 magic = read16 (pe_optional_header );
464
+
465
+ if (magic == 0x20B ) {
466
+ // Some fields are the same location for PE32 and PE32+.
467
+ // A few are offset by 4, 8, or 12, but we do not use them.
468
+ // Others are offset by 16.
469
+ // Some are missing.
470
+ ctx -> pe64 = 16 ;
471
+ } else if (magic != 0x10b )
472
+ ADD_ERROR (ctx , g_strdup_printf ("Invalid optional header magic %d" , magic ));
473
+
474
+ // Much of this is over-verification.
475
+ //
476
+ // File align and section align do not matter to Mono.
477
+ //
478
+ // Mono requires at least 15 data directories. More than that are ignored,
479
+ // except to require zeros in the 16th.
480
+ //
481
+ // Mono requires at least 216 (or pe64:232) size.
482
+
483
+ /* LAMESPEC MS plays around this value and ignore it during validation
484
+ if (read32 (pe_optional_header + 28) != 0x400000)
485
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
486
+ if (read32 (pe_optional_header + 32 ) != 0x2000 )
487
+ ADD_ERROR (ctx , g_strdup_printf ("Invalid Section Aligmnent %x" , read32 (pe_optional_header + 32 )));
488
+ file_alignment = read32 (pe_optional_header + 36 );
489
+ if (file_alignment != 0x200 && file_alignment != 0x1000 )
490
+ ADD_ERROR (ctx , g_strdup_printf ("Invalid file Aligmnent %x" , file_alignment ));
491
+ /* All the junk in the middle is irrelevant, specially for mono. */
492
+
493
+ if (header_size != 224 + ctx -> pe64 )
494
+ ADD_ERROR (ctx , g_strdup_printf ("Invalid optional header size %d" , header_size ));
495
+
496
+ const guint number_of_rvas_and_sizes = read32 (pe_optional_header + 92 + ctx -> pe64 );
497
+
498
+ // Data directories beyond 15 do not matter to mono.
499
+ if (number_of_rvas_and_sizes > 0x10 )
500
+ ADD_ERROR (ctx , g_strdup_printf ("Too many data directories %x" , number_of_rvas_and_sizes ));
486
501
}
487
502
488
503
static void
489
504
load_section_table (VerifyContext * ctx )
490
505
{
491
506
int i ;
492
507
SectionHeader * sections ;
493
- guint32 offset = pe_header_offset (ctx );
508
+ guint32 offset = pe_header_offset (ctx );
494
509
const char * ptr = ctx -> data + offset ;
495
510
guint16 num_sections = ctx -> section_count = read16 (ptr + 2 );
496
511
497
- offset += 244 ;/*FIXME, this constant is different under PE32+*/
498
- ptr += 244 ;
512
+ const guint optional_header_size = read16 (ptr + 16 );
513
+ offset += optional_header_size + 20 ;
514
+ ptr += optional_header_size + 20 ;
499
515
500
516
if (num_sections * 40 > ctx -> size - offset )
501
517
ADD_ERROR (ctx , g_strdup ("Invalid PE optional header size" ));
@@ -549,19 +565,18 @@ is_valid_data_directory (int i)
549
565
static void
550
566
load_data_directories (VerifyContext * ctx )
551
567
{
552
- guint32 offset = pe_header_offset (ctx ) + 116 ; /*FIXME, this constant is different under PE32+*/
568
+ guint32 offset = pe_header_offset (ctx ) + 116 + ctx -> pe64 ;
553
569
const char * ptr = ctx -> data + offset ;
554
570
int i ;
555
571
556
- for (i = 0 ; i < 16 ; ++ i ) {
572
+ for (i = 0 ; i < 16 ; ++ i , ptr += 8 ) {
557
573
guint32 rva = read32 (ptr );
558
574
guint32 size = read32 (ptr + 4 );
559
575
560
576
/*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
561
- if (i == CERTIFICATE_TABLE_IDX ) {
562
- ptr += 8 ;
577
+ if (i == CERTIFICATE_TABLE_IDX )
563
578
continue ;
564
- }
579
+
565
580
if ((rva != 0 || size != 0 ) && !is_valid_data_directory (i ))
566
581
ADD_ERROR (ctx , g_strdup_printf ("Invalid data directory %d" , i ));
567
582
@@ -571,8 +586,6 @@ load_data_directories (VerifyContext *ctx)
571
586
ctx -> data_directories [i ].rva = rva ;
572
587
ctx -> data_directories [i ].size = size ;
573
588
ctx -> data_directories [i ].translated_offset = translate_rva (ctx , rva );
574
-
575
- ptr += 8 ;
576
589
}
577
590
}
578
591
@@ -597,12 +610,8 @@ verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *tabl
597
610
g_assert (hint_table_rva != INVALID_OFFSET );
598
611
ptr = ctx -> data + hint_table_rva + 2 ;
599
612
600
- if (memcmp ("_CorExeMain" , ptr , SIZE_OF_CORMAIN ) && memcmp ("_CorDllMain" , ptr , SIZE_OF_CORMAIN )) {
601
- char name [SIZE_OF_CORMAIN ];
602
- memcpy (name , ptr , SIZE_OF_CORMAIN );
603
- name [SIZE_OF_CORMAIN - 1 ] = 0 ;
604
- ADD_ERROR (ctx , g_strdup_printf ("Invalid Hint / Name: '%s'" , name ));
605
- }
613
+ if (memcmp ("_CorExeMain" , ptr , SIZE_OF_CORMAIN ) && memcmp ("_CorDllMain" , ptr , SIZE_OF_CORMAIN ))
614
+ ADD_ERROR (ctx , g_strdup_printf ("Invalid Hint / Name: '%s'" , ptr ));
606
615
}
607
616
608
617
static void
@@ -613,6 +622,10 @@ verify_import_table (VerifyContext *ctx)
613
622
const char * ptr = ctx -> data + offset ;
614
623
guint32 name_rva , ilt_rva , iat_rva ;
615
624
625
+ // Having no import table is structurally valid
626
+ if (it .rva == 0 && it .size == 0 )
627
+ return ;
628
+
616
629
g_assert (offset != INVALID_OFFSET );
617
630
618
631
if (it .size < 40 )
@@ -640,12 +653,8 @@ verify_import_table (VerifyContext *ctx)
640
653
g_assert (name_rva != INVALID_OFFSET );
641
654
ptr = ctx -> data + name_rva ;
642
655
643
- if (memcmp ("mscoree.dll" , ptr , SIZE_OF_MSCOREE )) {
644
- char name [SIZE_OF_MSCOREE ];
645
- memcpy (name , ptr , SIZE_OF_MSCOREE );
646
- name [SIZE_OF_MSCOREE - 1 ] = 0 ;
647
- ADD_ERROR (ctx , g_strdup_printf ("Invalid Import Table Name: '%s'" , name ));
648
- }
656
+ if (memcmp ("mscoree.dll" , ptr , SIZE_OF_MSCOREE ))
657
+ ADD_ERROR (ctx , g_strdup_printf ("Invalid Import Table Name: '%s'" , ptr ));
649
658
}
650
659
651
660
if (ilt_rva ) {
0 commit comments