From d7d0e1917534ef784bb37b4c5dbbca58c9d8a300 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Tue, 25 Aug 2015 11:31:34 +0200
Subject: mscoree: Implement semi-stub for _CorValidateImage.

This is required in order to implement "proper" loader support for .NET executables.
(Yes, its intentional that both NTSTATUS and HRESULT values are returned, don't ask...)
---
 dlls/mscoree/mscoree_main.c | 75 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 73 insertions(+), 2 deletions(-)

diff --git a/dlls/mscoree/mscoree_main.c b/dlls/mscoree/mscoree_main.c
index 8b46fd5..8ec8ffe 100644
--- a/dlls/mscoree/mscoree_main.c
+++ b/dlls/mscoree/mscoree_main.c
@@ -21,11 +21,14 @@
 
 #include <stdarg.h>
 
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
 #define COBJMACROS
 #include "wine/unicode.h"
 #include "wine/library.h"
 #include "windef.h"
 #include "winbase.h"
+#include "winternl.h"
 #include "winuser.h"
 #include "winnls.h"
 #include "winreg.h"
@@ -259,8 +262,76 @@ VOID WINAPI _CorImageUnloading(PVOID imageBase)
 
 HRESULT WINAPI _CorValidateImage(PVOID* imageBase, LPCWSTR imageName)
 {
-    TRACE("(%p, %s): stub\n", imageBase, debugstr_w(imageName));
-    return E_FAIL;
+    IMAGE_COR20_HEADER *cliheader;
+    IMAGE_NT_HEADERS *nt;
+    ULONG size;
+
+    TRACE("(%p, %s)\n", imageBase, debugstr_w(imageName));
+
+    if (!imageBase)
+        return E_INVALIDARG;
+
+    nt = RtlImageNtHeader(*imageBase);
+    if (!nt)
+        return STATUS_INVALID_IMAGE_FORMAT;
+
+    cliheader = RtlImageDirectoryEntryToData(*imageBase, TRUE, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, &size);
+    if (!cliheader || size < sizeof(*cliheader))
+        return STATUS_INVALID_IMAGE_FORMAT;
+
+#ifdef _WIN64
+    if (cliheader->Flags & COMIMAGE_FLAGS_32BITREQUIRED)
+        return STATUS_INVALID_IMAGE_FORMAT;
+
+    if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
+    {
+        if (cliheader->Flags & COMIMAGE_FLAGS_ILONLY)
+        {
+            DWORD *entry = &nt->OptionalHeader.AddressOfEntryPoint;
+            DWORD old_protect;
+
+            if (!VirtualProtect(entry, sizeof(*entry), PAGE_READWRITE, &old_protect))
+                return E_UNEXPECTED;
+            *entry = 0;
+            if (!VirtualProtect(entry, sizeof(*entry), old_protect, &old_protect))
+                return E_UNEXPECTED;
+        }
+
+        return STATUS_SUCCESS;
+    }
+
+    if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
+    {
+        if (!(cliheader->Flags & COMIMAGE_FLAGS_ILONLY))
+            return STATUS_INVALID_IMAGE_FORMAT;
+
+        FIXME("conversion of IMAGE_NT_HEADERS32 -> IMAGE_NT_HEADERS64 not implemented\n");
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+#else
+    if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
+    {
+        if (cliheader->Flags & COMIMAGE_FLAGS_ILONLY)
+        {
+            DWORD *entry = &nt->OptionalHeader.AddressOfEntryPoint;
+            DWORD old_protect;
+
+            if (!VirtualProtect(entry, sizeof(*entry), PAGE_READWRITE, &old_protect))
+                return E_UNEXPECTED;
+            *entry = (nt->FileHeader.Characteristics & IMAGE_FILE_DLL) ?
+                ((DWORD_PTR)&_CorDllMain - (DWORD_PTR)*imageBase) :
+                ((DWORD_PTR)&_CorExeMain - (DWORD_PTR)*imageBase);
+            if (!VirtualProtect(entry, sizeof(*entry), old_protect, &old_protect))
+                return E_UNEXPECTED;
+        }
+
+        return STATUS_SUCCESS;
+    }
+
+#endif
+
+    return STATUS_INVALID_IMAGE_FORMAT;
 }
 
 HRESULT WINAPI GetCORSystemDirectory(LPWSTR pbuffer, DWORD cchBuffer, DWORD *dwLength)
-- 
2.5.0

