From 198c7874ccb79ce14c338b4e5d9f7b8b6ccb9f04 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Thu, 8 Apr 2021 23:31:24 +0200
Subject: Fortify access to the PE directories.

---
 plugins/pe/format.c | 21 ++++++++++++++++-----
 plugins/pe/pe-int.c | 20 ++++++++++++++++----
 2 files changed, 32 insertions(+), 9 deletions(-)

diff --git a/plugins/pe/format.c b/plugins/pe/format.c
index f5bdac1..3839063 100644
--- a/plugins/pe/format.c
+++ b/plugins/pe/format.c
@@ -722,14 +722,23 @@ const image_data_directory *g_pe_format_get_directories(const GPeFormat *format,
 {
     const image_data_directory *result;     /* Liste à retourner           */
 
-    if (count != NULL)
-        *count = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
-
     if (g_pe_format_get_is_32b(format))
+    {
         result = format->nt_headers.optional_header.header_32.data_directory;
+
+        if (count != NULL)
+            *count = format->nt_headers.optional_header.header_32.number_of_rva_and_sizes;
+
+    }
     else
+    {
         result = format->nt_headers.optional_header.header_64.data_directory;
 
+        if (count != NULL)
+            *count = format->nt_headers.optional_header.header_64.number_of_rva_and_sizes;
+
+    }
+
     return result;
 
 }
@@ -751,6 +760,7 @@ const image_data_directory *g_pe_format_get_directories(const GPeFormat *format,
 void *g_pe_format_get_directory(const GPeFormat *format, size_t index)
 {
     void *result;                           /* Données à retourner         */
+    size_t max;                             /* Quantité de répertoires     */
     const image_data_directory *dir;        /* Localisation du répertoire  */
     vmpa2t pos;                             /* Tête de lecture             */
     bool status;                            /* Bilan d'un traitement       */
@@ -760,10 +770,11 @@ void *g_pe_format_get_directory(const GPeFormat *format, size_t index)
 
     result = NULL;
 
-    if (index >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
+    dir = g_pe_format_get_directories(format, &max);
+
+    if (index >= max)
         goto exit;
 
-    dir = g_pe_format_get_directories(format, NULL);
     dir += index;
 
     status = g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), dir->virtual_address, &pos);
diff --git a/plugins/pe/pe-int.c b/plugins/pe/pe-int.c
index db09c15..4104ce1 100644
--- a/plugins/pe/pe-int.c
+++ b/plugins/pe/pe-int.c
@@ -27,7 +27,9 @@
 #include <malloc.h>
 #include <string.h>
 
+#include <i18n.h>
 #include <common/endianness.h>
+#include <core/logs.h>
 
 
 
@@ -145,7 +147,7 @@ bool read_pe_optional_header(const GPeFormat *format, vmpa2t *pos, image_optiona
     image_optional_header_32 *hdr32;        /* Version 32 bits             */
     image_optional_header_64 *hdr64;        /* Version 64 bits             */
     image_data_directory *directories;      /* Répertoires à charger       */
-    uint32_t number_of_rva_and_sizes;       /* Quantité de ces répertoires */
+    uint32_t *number_of_rva_and_sizes;      /* Quantité de ces répertoires */
     uint32_t i;                             /* Boucle de parcours          */
 
     content = G_KNOWN_FORMAT(format)->content;
@@ -194,7 +196,7 @@ bool read_pe_optional_header(const GPeFormat *format, vmpa2t *pos, image_optiona
         if (result) result = g_binary_content_read_u32(content, pos, SRE_LITTLE, &hdr32->number_of_rva_and_sizes);
 
         directories = hdr32->data_directory;
-        number_of_rva_and_sizes = hdr32->number_of_rva_and_sizes;
+        number_of_rva_and_sizes = &hdr32->number_of_rva_and_sizes;
 
     }
     else
@@ -235,11 +237,21 @@ bool read_pe_optional_header(const GPeFormat *format, vmpa2t *pos, image_optiona
         if (result) result = g_binary_content_read_u32(content, pos, SRE_LITTLE, &hdr64->number_of_rva_and_sizes);
 
         directories = hdr64->data_directory;
-        number_of_rva_and_sizes = hdr64->number_of_rva_and_sizes;
+        number_of_rva_and_sizes = &hdr64->number_of_rva_and_sizes;
 
     }
 
-    for (i = 0; i < number_of_rva_and_sizes && result; i++)
+    if (result && *number_of_rva_and_sizes > IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
+    {
+        log_variadic_message(LMT_BAD_BINARY,
+                             _("Corrupted number of directories (%u); fixed!"),
+                             *number_of_rva_and_sizes);
+
+        *number_of_rva_and_sizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
+
+    }
+
+    for (i = 0; i < *number_of_rva_and_sizes && result; i++)
     {
         result = g_binary_content_read_u32(content, pos, SRE_LITTLE, &directories[i].virtual_address);
         if (result) result = g_binary_content_read_u32(content, pos, SRE_LITTLE, &directories[i].size);
-- 
cgit v0.11.2-87-g4458