PE format allows to have variable length of Data Directories in PE Optional
Header. The exact number of Data Directories is stored in NumberOfRvaAndSizes
field. Size of the optional header depends on the number of Data Directories.

Constants IMAGE_SIZEOF_NT_OPTIONAL32_HEADER and 
IMAGE_SIZEOF_NT_OPTIONAL64_HEADER
are for PE images with all 16 Data Directories. And so cannot be used for
checking validity of SizeOfOptionalHeader.

Older PE linkers were generating PE binaries with less number of Data
Directories than 16 if trailing entries were empty. And gendef cannot
recognize such PE binaries.

Relax check for PE SizeOfOptionalHeader field. Allow any number of Data
Directories in PE Optional Header, including zero.

At the same time add checks for NumberOfRvaAndSizes member before
dereferencing DataDirectory[] array, which ensures that the entry is present.
---
 mingw-w64-tools/gendef/src/gendef.c | 55 +++++++++++++++++++++--------
 1 file changed, 41 insertions(+), 14 deletions(-)

diff --git a/mingw-w64-tools/gendef/src/gendef.c 
b/mingw-w64-tools/gendef/src/gendef.c
index 7440d60f35df..1f34edea2f07 100644
--- a/mingw-w64-tools/gendef/src/gendef.c
+++ b/mingw-w64-tools/gendef/src/gendef.c
@@ -18,6 +18,7 @@
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
+#include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <memory.h>
@@ -313,19 +314,19 @@ load_pep (void)
       gPEDta = NULL;
       return 0;
     }
-  if (gPEDta->FileHeader.SizeOfOptionalHeader == 
IMAGE_SIZEOF_NT_OPTIONAL32_HEADER
+  if (gPEDta->FileHeader.SizeOfOptionalHeader >= 
offsetof(IMAGE_OPTIONAL_HEADER32, DataDirectory)
       && gPEDta->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
     {
       gPEPDta = NULL;
       fprintf (stderr, " * [%s] Found PE image\n", fninput);
     }
-  else if (gPEDta->FileHeader.SizeOfOptionalHeader == 
IMAGE_SIZEOF_NT_OPTIONAL32_HEADER
+  else if (gPEDta->FileHeader.SizeOfOptionalHeader >= 
offsetof(IMAGE_OPTIONAL_HEADER32, DataDirectory)
       && gPEDta->OptionalHeader.Magic == 0 && gPEDta->FileHeader.Machine == 
0x014c /* IMAGE_FILE_MACHINE_I386 */)
     {
       gPEPDta = NULL;
       fprintf (stderr, " * [%s] Found PE image for I386 with zeroed NT 
magic\n", fninput);
     }
-  else if (gPEPDta->FileHeader.SizeOfOptionalHeader == 
IMAGE_SIZEOF_NT_OPTIONAL64_HEADER
+  else if (gPEPDta->FileHeader.SizeOfOptionalHeader >= 
offsetof(IMAGE_OPTIONAL_HEADER64, DataDirectory)
     && gPEPDta->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
     {
       gPEDta = NULL;
@@ -386,19 +387,27 @@ is_data (uint32_t va)
 static int
 is_reloc (uint32_t va)
 {
-  uint32_t va_rel, sz_rel, pos;
+  uint32_t va_rel = 0;
+  uint32_t sz_rel = 0;
+  uint32_t pos;
   unsigned char *p;
   PIMAGE_BASE_RELOCATION brel;
 
   if (gPEDta)
     {
-      va_rel = 
gPEDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
-      sz_rel = 
gPEDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
+      if (gPEDta->OptionalHeader.NumberOfRvaAndSizes > 
IMAGE_DIRECTORY_ENTRY_BASERELOC)
+        {
+          va_rel = 
gPEDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
+          sz_rel = 
gPEDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
+        }
     }
   else
     {
-      va_rel = 
gPEPDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
-      sz_rel = 
gPEPDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
+      if (gPEPDta->OptionalHeader.NumberOfRvaAndSizes > 
IMAGE_DIRECTORY_ENTRY_BASERELOC)
+        {
+          va_rel = 
gPEPDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
+          sz_rel = 
gPEPDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
+        }
     }
   if (va_rel == 0 || sz_rel < IMAGE_SIZEOF_BASE_RELOCATION)
     return 0;
@@ -476,8 +485,14 @@ map_va (uint32_t va)
 static void
 do_pepdef (void)
 {
-  uint32_t va_exp = 
gPEPDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
-  uint32_t sz_exp = 
gPEPDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
+  uint32_t va_exp = 0;
+  uint32_t sz_exp = 0;
+
+  if (gPEPDta->OptionalHeader.NumberOfRvaAndSizes > 
IMAGE_DIRECTORY_ENTRY_EXPORT)
+    {
+      va_exp = 
gPEPDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
+      sz_exp = 
gPEPDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
+    }
 
   do_export_read (va_exp, sz_exp, 1);
 }
@@ -485,10 +500,22 @@ do_pepdef (void)
 static void
 do_pedef (void)
 {
-  uint32_t va_exp = 
gPEDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
-  uint32_t sz_exp = 
gPEDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
-  uint32_t va_imp = 
gPEDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
-  uint32_t sz_imp = 
gPEDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
+  uint32_t va_exp = 0;
+  uint32_t sz_exp = 0;
+  uint32_t va_imp = 0;
+  uint32_t sz_imp = 0;
+
+  if (gPEDta->OptionalHeader.NumberOfRvaAndSizes > 
IMAGE_DIRECTORY_ENTRY_EXPORT)
+    {
+      va_exp = 
gPEDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
+      sz_exp = 
gPEDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
+    }
+
+  if (gPEDta->OptionalHeader.NumberOfRvaAndSizes > 
IMAGE_DIRECTORY_ENTRY_IMPORT)
+    {
+      va_imp = 
gPEDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
+      sz_imp = 
gPEDta->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
+    }
 
   imp32_free ();
   do_import_read32 (va_imp, sz_imp);
-- 
2.20.1



_______________________________________________
Mingw-w64-public mailing list
Mingw-w64-public@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to