[NDK]: Add missing RtlImageNtHeaderEx flags.
authorAlex Ionescu <aionescu@gmail.com>
Sun, 10 Jul 2011 21:55:55 +0000 (21:55 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Sun, 10 Jul 2011 21:55:55 +0000 (21:55 +0000)
[RTL]: Implement RtlImageNtHeaderEx and make RtlImageNtHeader call it. This will result in much stricter (and correct) PE loading by default, and enable a flag which can do even stricter checks.
[NTDLL]: Export RtlImageNtHeaderEx (maybe NTOS should export it too, not sure).

svn path=/trunk/; revision=52618

reactos/dll/ntdll/def/ntdll.pspec
reactos/include/ndk/rtltypes.h
reactos/lib/rtl/image.c

index e87b71c..d9ca50e 100644 (file)
 @ stdcall RtlIdentifierAuthoritySid(ptr)
 @ stdcall RtlImageDirectoryEntryToData(long long long ptr)
 @ stdcall RtlImageNtHeader(long)
-//@ stdcall RtlImageNtHeaderEx
+@ stdcall RtlImageNtHeaderEx(long ptr double ptr)
 @ stdcall RtlImageRvaToSection(ptr long long)
 @ stdcall RtlImageRvaToVa(ptr long long ptr)
 @ stdcall RtlImpersonateSelf(long)
index 3b93237..738a61e 100644 (file)
@@ -244,6 +244,11 @@ C_ASSERT(HEAP_CREATE_VALID_MASK == 0x0007F0FF);
 //
 #define RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE    4
 
+//
+// RtlImageNtHeaderEx Flags
+//
+#define RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK          0x00000001
+
 //
 // Codepages
 //
index ce54a6b..5ce0e74 100644 (file)
@@ -120,6 +120,13 @@ LdrVerifyMappedImageMatchesChecksum(
 
     return (BOOLEAN)(CalcSum == HeaderSum);
 #else
+    /*
+     * FIXME: Warning, this violates the PE standard and makes ReactOS drivers
+     * and other system code when normally on Windows they would not, since
+     * we do not write the checksum in them.
+     * Our compilers should be made to write out the checksum and this function
+     * should be enabled as to reject badly checksummed code.
+     */
     return TRUE;
 #endif
 }
@@ -127,28 +134,122 @@ LdrVerifyMappedImageMatchesChecksum(
 /*
  * @implemented
  */
-PIMAGE_NT_HEADERS
+NTSTATUS
 NTAPI
-RtlImageNtHeader(IN PVOID BaseAddress)
+RtlImageNtHeaderEx(IN ULONG Flags,
+                   IN PVOID Base,
+                   IN ULONG64 Size,
+                   OUT PIMAGE_NT_HEADERS *OutHeaders)
 {
-    PIMAGE_NT_HEADERS NtHeader;
-    PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)BaseAddress;
+    PIMAGE_NT_HEADERS NtHeaders;
+    PIMAGE_DOS_HEADER DosHeader;
+
+    /* You must want NT Headers, no? */
+    if (!OutHeaders) return STATUS_INVALID_PARAMETER;
+
+    /* Assume failure */
+    *OutHeaders = NULL;
 
-    if (DosHeader && SWAPW(DosHeader->e_magic) != IMAGE_DOS_SIGNATURE)
+    /* Validate Flags */
+    if (Flags &~ RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK)
     {
-        DPRINT1("DosHeader->e_magic %x\n", SWAPW(DosHeader->e_magic));
-        DPRINT1("NtHeader 0x%lx\n", ((ULONG_PTR)BaseAddress + SWAPD(DosHeader->e_lfanew)));
+        DPRINT1("Invalid flag combination... check for new API flags?\n");
+        return STATUS_INVALID_PARAMETER;
     }
-    else
+
+    /* Validate base */
+    if (!(Base) || (Base == (PVOID)-1)) return STATUS_INVALID_PARAMETER;
+
+    /* Check if the caller wants validation */
+    if (Flags & RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK)
     {
-        NtHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)BaseAddress + SWAPD(DosHeader->e_lfanew));
-        if (SWAPD(NtHeader->Signature) == IMAGE_NT_SIGNATURE)
-            return NtHeader;
+        /* Make sure the image size is at least big enough for the DOS header */
+        if (Size < sizeof(IMAGE_DOS_HEADER))
+        {
+            DPRINT1("Size too small\n");
+            return STATUS_INVALID_IMAGE_FORMAT;
+        }
     }
 
-    return NULL;
+    /* Check if the DOS Signature matches */
+    DosHeader = Base;
+    if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
+    {
+        /* Not a valid COFF */
+        DPRINT1("Not an MZ file\n");
+        return STATUS_INVALID_IMAGE_FORMAT;
+    }
+
+    /* Check if the caller wants validation */
+    if (Flags & RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK)
+    {
+        /* The offset should fit in the passsed-in size */
+        if (DosHeader->e_lfanew >= Size)
+        {
+            /* Fail */
+            DPRINT1("e_lfanew is larger than PE file\n");
+            return STATUS_INVALID_IMAGE_FORMAT;
+        }
+        
+        /* It shouldn't be past 4GB either */
+        if (DosHeader->e_lfanew >=
+            (MAXULONG - sizeof(IMAGE_DOS_SIGNATURE) - sizeof(IMAGE_FILE_HEADER)))
+        {
+            /* Fail */
+            DPRINT1("e_lfanew is larger than 4GB\n");
+            return STATUS_INVALID_IMAGE_FORMAT;
+        }
+        
+        /* And the whole file shouldn't overflow past 4GB */
+        if ((DosHeader->e_lfanew +
+            sizeof(IMAGE_DOS_SIGNATURE) - sizeof(IMAGE_FILE_HEADER)) >= Size)
+        {
+            /* Fail */
+            DPRINT1("PE is larger than 4GB\n");
+            return STATUS_INVALID_IMAGE_FORMAT;
+        }
+    }
+    
+    /* The offset also can't be larger than 256MB, as a hard-coded check */
+    if (DosHeader->e_lfanew >= (256 * 1024 * 1024))
+    {
+        /* Fail */
+        DPRINT1("PE offset is larger than 256MB\n");
+        return STATUS_INVALID_IMAGE_FORMAT;
+    }
+
+    /* Now it's safe to get the NT Headers */
+    NtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)Base + DosHeader->e_lfanew);
+
+    /* Verify the PE Signature */
+    if (NtHeaders->Signature != IMAGE_NT_SIGNATURE)
+    {
+        /* Fail */
+        DPRINT1("PE signature missing\n");
+        return STATUS_INVALID_IMAGE_FORMAT;
+    }
+
+    /* Now return success and the NT header */
+    *OutHeaders = NtHeaders;
+    return STATUS_SUCCESS;
 }
+    
+/*
+ * @implemented
+ */
+PIMAGE_NT_HEADERS
+NTAPI
+RtlImageNtHeader(IN PVOID Base)
+{
+    PIMAGE_NT_HEADERS NtHeader;
 
+    /* Call the new API */
+    RtlImageNtHeaderEx(RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK,
+                       Base,
+                       0,
+                       &NtHeader);
+    return NtHeader;
+}
 
 /*
  * @implemented