Index: /trunk/include/iprt/nt/nt.h
===================================================================
--- /trunk/include/iprt/nt/nt.h	(revision 52942)
+++ /trunk/include/iprt/nt/nt.h	(revision 52943)
@@ -1772,4 +1772,30 @@
 NTSYSAPI NTSTATUS NTAPI NtQuerySecurityObject(HANDLE, ULONG, PSECURITY_DESCRIPTOR, ULONG, PULONG);
 
+#ifdef IPRT_NT_USE_WINTERNL
+typedef enum _EVENT_TYPE
+{
+    /* Manual reset event. */
+    NotificationEvent = 0,
+    /* Automaitc reset event. */
+    SynchronizationEvent
+} EVENT_TYPE;
+#endif
+NTSYSAPI NTSTATUS NTAPI NtCreateEvent(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, EVENT_TYPE, BOOLEAN);
+NTSYSAPI NTSTATUS NTAPI NtOpenEvent(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
+NTSYSAPI NTSTATUS NTAPI NtClearEvent(HANDLE);
+NTSYSAPI NTSTATUS NTAPI NtResetEvent(HANDLE, PULONG);
+NTSYSAPI NTSTATUS NTAPI NtSetEvent(HANDLE, PULONG);
+typedef enum _EVENT_INFORMATION_CLASS
+{
+    EventBasicInformation = 0
+} EVENT_INFORMATION_CLASS;
+/** Data returned by NtQueryEvent + EventBasicInformation. */
+typedef struct EVENT_BASIC_INFORMATION
+{
+    EVENT_TYPE  EventType;
+    ULONG       EventState;
+} EVENT_BASIC_INFORMATION;
+typedef EVENT_BASIC_INFORMATION *PEVENT_BASIC_INFORMATION;
+NTSYSAPI NTSTATUS NTAPI NtQueryEvent(HANDLE, EVENT_INFORMATION_CLASS, PVOID, ULONG, PULONG);
 
 #ifdef IPRT_NT_USE_WINTERNL
Index: /trunk/src/VBox/HostDrivers/Support/SUPLibInternal.h
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/SUPLibInternal.h	(revision 52942)
+++ /trunk/src/VBox/HostDrivers/Support/SUPLibInternal.h	(revision 52943)
@@ -313,12 +313,17 @@
 {
     SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED = 0,
+    SUPR3HARDENEDMAINSTATE_WIN_VM_INIT_CALLED,
+    SUPR3HARDENEDMAINSTATE_WIN_EARLY_IMPORTS_RESOLVED,
+    SUPR3HARDENEDMAINSTATE_WIN_EARLY_DEVICE_OPENED,
     SUPR3HARDENEDMAINSTATE_WIN_EP_CALLED,
     SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED,
     SUPR3HARDENEDMAINSTATE_WIN_VERSION_INITIALIZED,
-    SUPR3HARDENEDMAINSTATE_VERIFY_TRUST_READY,
+    SUPR3HARDENEDMAINSTATE_WIN_VERIFY_TRUST_READY,
+    SUPR3HARDENEDMAINSTATE_HARDENED_MAIN_CALLED,
     SUPR3HARDENEDMAINSTATE_INIT_RUNTIME,
     SUPR3HARDENEDMAINSTATE_GET_TRUSTED_MAIN,
     SUPR3HARDENEDMAINSTATE_CALLED_TRUSTED_MAIN,
-    SUPR3HARDENEDMAINSTATE_END
+    SUPR3HARDENEDMAINSTATE_END,
+    SUPR3HARDENEDMAINSTATE_32BIT_HACK = 0x7fffffff
 } SUPR3HARDENEDMAINSTATE;
 
@@ -336,4 +341,7 @@
 #endif
 extern DECLHIDDEN(SUPR3HARDENEDMAINSTATE) g_enmSupR3HardenedMainState;
+#ifdef RT_OS_WINDOWS
+extern DECLHIDDEN(bool)                 g_fSupEarlyVmProcessInit;
+#endif
 
 
@@ -437,7 +445,8 @@
 
 #ifdef RT_OS_WINDOWS
-DECLHIDDEN(void)    supR3HardenedWinInit(uint32_t fFlags);
+DECLHIDDEN(void)    supR3HardenedWinInit(uint32_t fFlags, bool fAvastKludge);
 DECLHIDDEN(void)    supR3HardenedWinInitVersion(void);
 DECLHIDDEN(void)    supR3HardenedWinInitImports(void);
+DECLHIDDEN(void)    supR3HardenedWinInitImportsEarly(uintptr_t uNtDllAddr);
 DECLHIDDEN(PFNRT)   supR3HardenedWinGetRealDllSymbol(const char *pszDll, const char *pszProcedure);
 DECLHIDDEN(void)    supR3HardenedWinVerifyProcess(void);
@@ -456,4 +465,6 @@
 # endif
 DECLHIDDEN(void)    supR3HardenedWinCompactHeaps(void);
+DECLHIDDEN(void)    supR3HardenedMainOpenDevice(void);
+DECLHIDDEN(void)    supR3HardenedWinReportErrorToParent(int rc, const char *pszFormat, va_list va);
 #endif
 
Index: /trunk/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp	(revision 52942)
+++ /trunk/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp	(revision 52943)
@@ -159,4 +159,5 @@
 /** The current SUPR3HardenedMain state / location. */
 SUPR3HARDENEDMAINSTATE  g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED;
+AssertCompileSize(g_enmSupR3HardenedMainState, sizeof(uint32_t));
 
 
@@ -253,12 +254,16 @@
     if (hStdOut != NULL)
     {
-# if 0 /* Windows 7 and earlier uses fake handles, with the last two bits set ((hStdOut & 3) == 3). */
-        IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
-        NtWriteFile(hStdOut, NULL /*Event*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/,
-                    &Ios, (PVOID)pch, (ULONG)cch, NULL /*ByteOffset*/, NULL /*Key*/);
-# else
-        DWORD cbWritten;
-        WriteFile(hStdOut, pch, (DWORD)cch, &cbWritten, NULL);
-# endif
+        if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
+        {
+            DWORD cbWritten;
+            WriteFile(hStdOut, pch, (DWORD)cch, &cbWritten, NULL);
+        }
+        /* Windows 7 and earlier uses fake handles, with the last two bits set ((hStdOut & 3) == 3). */
+        else if (NtWriteFile != NULL && ((uintptr_t)hStdOut & 3) == 0)
+        {
+            IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
+            NtWriteFile(hStdOut, NULL /*Event*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/,
+                        &Ios, (PVOID)pch, (ULONG)cch, NULL /*ByteOffset*/, NULL /*Key*/);
+        }
     }
 #else
@@ -1095,35 +1100,49 @@
     }
 
+    /*
+     * Don't call TrustedError if it's too early.
+     */
+    if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
+    {
 #ifdef SUP_HARDENED_SUID
-    /*
-     * Drop any root privileges we might be holding, this won't return
-     * if it fails but end up calling supR3HardenedFatal[V].
-     */
-    supR3HardenedMainDropPrivileges();
-#endif /* SUP_HARDENED_SUID */
-
-    /*
-     * Now try resolve and call the TrustedError entry point if we can
-     * find it.  We'll fork before we attempt this because that way the
-     * session management in main will see us exiting immediately (if
-     * it's involved with us).
-     */
+        /*
+         * Drop any root privileges we might be holding, this won't return
+         * if it fails but end up calling supR3HardenedFatal[V].
+         */
+        supR3HardenedMainDropPrivileges();
+#endif
+
+        /*
+         * Now try resolve and call the TrustedError entry point if we can
+         * find it.  We'll fork before we attempt this because that way the
+         * session management in main will see us exiting immediately (if
+         * it's involved with us).
+         */
 #if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
-    int pid = fork();
-    if (pid <= 0)
-#endif
-    {
-        static volatile bool s_fRecursive = false; /* Loader hooks may cause recursion. */
-        if (!s_fRecursive)
+        int pid = fork();
+        if (pid <= 0)
+#endif
         {
-            s_fRecursive = true;
-
-            PFNSUPTRUSTEDERROR pfnTrustedError = supR3HardenedMainGetTrustedError(g_pszSupLibHardenedProgName);
-            if (pfnTrustedError)
-                pfnTrustedError(pszWhere, enmWhat, rc, pszMsgFmt, va);
-
-            s_fRecursive = false;
+            static volatile bool s_fRecursive = false; /* Loader hooks may cause recursion. */
+            if (!s_fRecursive)
+            {
+                s_fRecursive = true;
+
+                PFNSUPTRUSTEDERROR pfnTrustedError = supR3HardenedMainGetTrustedError(g_pszSupLibHardenedProgName);
+                if (pfnTrustedError)
+                    pfnTrustedError(pszWhere, enmWhat, rc, pszMsgFmt, va);
+
+                s_fRecursive = false;
+            }
         }
     }
+#if defined(RT_OS_WINDOWS)
+    /*
+     * Report the error to the parent if this happens during early VM init.
+     */
+    else if (   g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED
+             && g_enmSupR3HardenedMainState != SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED)
+        supR3HardenedWinReportErrorToParent(rc, pszMsgFmt, va);
+#endif
 
     /*
@@ -1151,6 +1170,18 @@
     va_end(vaCopy);
 
-    suplibHardenedPrintPrefix();
-    suplibHardenedPrintFV(pszFormat, va);
+#if defined(RT_OS_WINDOWS)
+    /*
+     * Report the error to the parent if this happens during early VM init.
+     */
+    if (   g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED
+        && g_enmSupR3HardenedMainState != SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED)
+        supR3HardenedWinReportErrorToParent(VERR_INTERNAL_ERROR, pszFormat, va);
+    else
+#endif
+    {
+        suplibHardenedPrintPrefix();
+        suplibHardenedPrintFV(pszFormat, va);
+    }
+
     suplibHardenedExit(RTEXITCODE_FAILURE);
 }
@@ -1199,5 +1230,5 @@
  * @remarks This function will not return on failure.
  */
-static void supR3HardenedMainOpenDevice(void)
+DECLHIDDEN(void) supR3HardenedMainOpenDevice(void)
 {
     int rc = suplibOsInit(&g_SupPreInitData.Data, false /*fPreInit*/, true /*fUnrestricted*/);
@@ -1671,4 +1702,5 @@
 {
     SUP_DPRINTF(("SUPR3HardenedMain: pszProgName=%s fFlags=%#x\n", pszProgName, fFlags));
+    g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_HARDENED_MAIN_CALLED;
 
     /*
@@ -1678,7 +1710,12 @@
     g_pszSupLibHardenedProgName = pszProgName;
     g_fSupHardenedMain          = fFlags;
-    g_SupPreInitData.u32Magic     = SUPPREINITDATA_MAGIC;
-    g_SupPreInitData.Data.hDevice = SUP_HDEVICE_NIL;
-    g_SupPreInitData.u32EndMagic  = SUPPREINITDATA_MAGIC;
+#ifdef RT_OS_WINDOWS
+    if (!g_fSupEarlyVmProcessInit)
+#endif
+    {
+        g_SupPreInitData.u32Magic     = SUPPREINITDATA_MAGIC;
+        g_SupPreInitData.Data.hDevice = SUP_HDEVICE_NIL;
+        g_SupPreInitData.u32EndMagic  = SUPPREINITDATA_MAGIC;
+    }
 
 #ifdef SUP_HARDENED_SUID
@@ -1689,5 +1726,4 @@
      */
     supR3HardenedGetFullExePath();
-
 # endif
 
@@ -1714,9 +1750,10 @@
      * at dropping compatibility layers and process "security" solutions.
      */
-    if (   !(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
+    if (   !g_fSupEarlyVmProcessInit
+        && !(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
         && supR3HardenedWinIsReSpawnNeeded(1 /*iWhich*/, argc, argv))
     {
         SUP_DPRINTF(("SUPR3HardenedMain: Respawn #1\n"));
-        supR3HardenedWinInit(SUPSECMAIN_FLAGS_DONT_OPEN_DEV);
+        supR3HardenedWinInit(SUPSECMAIN_FLAGS_DONT_OPEN_DEV, true /*fAvastKludge*/);
         supR3HardenedVerifyAll(true /* fFatal */, pszProgName);
         return supR3HardenedWinReSpawn(1 /*iWhich*/);
@@ -1726,7 +1763,9 @@
      * Windows: Initialize the image verification global data so we can verify the
      * signature of the process image and hook the core of the DLL loader API so we
-     * can check the signature of all DLLs mapped into the process.
-     */
-    supR3HardenedWinInit(fFlags);
+     * can check the signature of all DLLs mapped into the process.  (Already done
+     * by early VM process init.)
+     */
+    if (!g_fSupEarlyVmProcessInit)
+        supR3HardenedWinInit(fFlags, true /*fAvastKludge*/);
 #endif /* RT_OS_WINDOWS */
 
@@ -1738,32 +1777,35 @@
     /*
      * The next steps are only taken if we actually need to access the support
-     * driver.
-     */
-    if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
-    {
+     * driver.  (Already done by early VM process init.)
+     */
 #ifdef RT_OS_WINDOWS
-        /*
-         * Windows: Verify the process (repeated by the kernel later.
-         */
-        supR3HardenedWinVerifyProcess();
-
-        /*
-         * Windows: The second respawn.  This time we make a special arrangement
-         * with vboxdrv to monitor access to the new process from its inception.
-         */
-        if (supR3HardenedWinIsReSpawnNeeded(2 /* iWhich*/, argc, argv))
+    if (!g_fSupEarlyVmProcessInit)
+#endif
+        if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
         {
-            SUP_DPRINTF(("SUPR3HardenedMain: Respawn #2\n"));
-            return supR3HardenedWinReSpawn(2 /* iWhich*/);
+#ifdef RT_OS_WINDOWS
+            /*
+             * Windows: Verify the process (repeated by the kernel later.
+             */
+            supR3HardenedWinVerifyProcess();
+
+            /*
+             * Windows: The second respawn.  This time we make a special arrangement
+             * with vboxdrv to monitor access to the new process from its inception.
+             */
+            if (supR3HardenedWinIsReSpawnNeeded(2 /* iWhich*/, argc, argv))
+            {
+                SUP_DPRINTF(("SUPR3HardenedMain: Respawn #2\n"));
+                return supR3HardenedWinReSpawn(2 /* iWhich*/);
+            }
+            SUP_DPRINTF(("SUPR3HardenedMain: Final process, opening VBoxDrv...\n"));
+            supR3HardenedWinFlushLoaderCache();
+#endif /* RT_OS_WINDOWS */
+
+            /*
+             * Open the vboxdrv device.
+             */
+            supR3HardenedMainOpenDevice();
         }
-        SUP_DPRINTF(("SUPR3HardenedMain: Final process, opening VBoxDrv...\n"));
-        supR3HardenedWinFlushLoaderCache();
-#endif /* RT_OS_WINDOWS */
-
-        /*
-         * Open the vboxdrv device.
-         */
-        supR3HardenedMainOpenDevice();
-    }
 
 #ifdef RT_OS_WINDOWS
@@ -1774,5 +1816,5 @@
     supR3HardenedWinFlushLoaderCache();
     supR3HardenedWinResolveVerifyTrustApiAndHookThreadCreation(g_pszSupLibHardenedProgName);
-    g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_VERIFY_TRUST_READY;
+    g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_WIN_VERIFY_TRUST_READY;
 #endif
 
Index: /trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerify-win.h
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerify-win.h	(revision 52942)
+++ /trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerify-win.h	(revision 52943)
@@ -165,5 +165,5 @@
 extern SUPSYSROOTDIRBUF g_System32NtPath;
 extern SUPSYSROOTDIRBUF g_WinSxSNtPath;
-#ifdef IN_RING3
+#if defined(IN_RING3) && !defined(VBOX_PERMIT_EVEN_MORE)
 extern SUPSYSROOTDIRBUF g_ProgramFilesNtPath;
 extern SUPSYSROOTDIRBUF g_CommonFilesNtPath;
@@ -172,5 +172,5 @@
 extern SUPSYSROOTDIRBUF g_CommonFilesX86NtPath;
 # endif
-#endif
+#endif /* IN_RING3 && !VBOX_PERMIT_EVEN_MORE */
 extern SUPSYSROOTDIRBUF g_SupLibHardenedExeNtPath;
 extern uint32_t         g_offSupLibHardenedExeNtName;
Index: /trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp	(revision 52942)
+++ /trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp	(revision 52943)
@@ -122,5 +122,5 @@
 /** The full \\SystemRoot\\WinSxS path. */
 SUPSYSROOTDIRBUF            g_WinSxSNtPath;
-#ifdef IN_RING3
+#if defined(IN_RING3) && !defined(VBOX_PERMIT_EVEN_MORE)
 /** The full 'Program Files' path. */
 SUPSYSROOTDIRBUF            g_ProgramFilesNtPath;
@@ -135,5 +135,5 @@
 SUPSYSROOTDIRBUF            g_CommonFilesX86NtPath;
 # endif
-#endif /* IN_RING3 */
+#endif /* IN_RING3 && !VBOX_PERMIT_MORE*/
 
 static union
@@ -1443,6 +1443,5 @@
 
 
-
-#ifdef IN_RING3
+#if defined(IN_RING3) && !defined(VBOX_PERMIT_EVEN_MORE)
 /**
  * Initializes the windows paths.
@@ -1632,5 +1631,5 @@
     }
 }
-#endif /* IN_RING3 */
+#endif /* IN_RING3 && !VBOX_PERMIT_EVEN_MORE */
 
 
@@ -1656,5 +1655,5 @@
         SUP_DPRINTF(("System32:  %ls\n", g_System32NtPath.UniStr.Buffer));
         SUP_DPRINTF(("WinSxS:    %ls\n", g_WinSxSNtPath.UniStr.Buffer));
-#ifdef IN_RING3
+#if defined(IN_RING3) && !defined(VBOX_PERMIT_EVEN_MORE)
         supHardenedWinInitImageVerifierWinPaths();
 #endif
Index: /trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp	(revision 52942)
+++ /trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp	(revision 52943)
@@ -174,7 +174,33 @@
 
 
+/**
+ * VM process parameters.
+ */
+typedef struct SUPR3WINPROCPARAMS
+{
+    /** The event semaphore the child will be waiting on. */
+    HANDLE          hEvtChild;
+    /** The event semaphore the parent will be waiting on. */
+    HANDLE          hEvtParent;
+
+    /** The address of the NTDLL. */
+    uintptr_t       uNtDllAddr;
+
+    /** The last status. */
+    int32_t         rc;
+    /** Error message / path name string space. */
+    char            szErrorMsg[4096];
+} SUPR3WINPROCPARAMS;
+
+
 /*******************************************************************************
 *   Global Variables                                                           *
 *******************************************************************************/
+/** Process parameters.  Specified by parent if VM process, see
+ *  supR3HardenedVmProcessInit. */
+static SUPR3WINPROCPARAMS   g_ProcParams = { NULL, NULL, 0, 0 };
+/** Set if supR3HardenedVmProcessInit was invoked. */
+bool                        g_fSupEarlyVmProcessInit = false;
+
 /** @name Global variables initialized by suplibHardenedWindowsMain.
  * @{ */
@@ -4362,6 +4388,7 @@
  * Initializes the windows verficiation bits.
  * @param   fFlags          The main flags.
- */
-DECLHIDDEN(void) supR3HardenedWinInit(uint32_t fFlags)
+ * @param   fAvastKludge    Whether to apply the avast kludge.
+ */
+DECLHIDDEN(void) supR3HardenedWinInit(uint32_t fFlags, bool fAvastKludge)
 {
     RTErrInfoInitStatic(&g_ErrInfoStatic);
@@ -4373,54 +4400,57 @@
     if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
     {
-        /*
-         * Do a self purification to cure avast's weird NtOpenFile write-thru
-         * change in GetBinaryTypeW change in kernel32.  Unfortunately, avast
-         * uses a system thread to perform the process modifications, which
-         * means it's hard to make sure it had the chance to make them...
-         *
-         * We have to resort to kludge doing yield and sleep fudging for a
-         * number of milliseconds and schedulings before we can hope that avast
-         * and similar products have done what they need to do.  If we do any
-         * fixes, we wait for a while again and redo it until we're clean.
-         *
-         * This is unfortunately kind of fragile.
-         */
-        uint32_t cMsFudge = g_fSupAdversaries ? 512 : 128;
-        uint32_t cFixes;
-        for (uint32_t iLoop = 0; iLoop < 16; iLoop++)
-        {
-            uint32_t    cSleeps = 0;
-            DWORD       dwStart = GetTickCount();
-            do
+        if (fAvastKludge)
+        {
+            /*
+             * Do a self purification to cure avast's weird NtOpenFile write-thru
+             * change in GetBinaryTypeW change in kernel32.  Unfortunately, avast
+             * uses a system thread to perform the process modifications, which
+             * means it's hard to make sure it had the chance to make them...
+             *
+             * We have to resort to kludge doing yield and sleep fudging for a
+             * number of milliseconds and schedulings before we can hope that avast
+             * and similar products have done what they need to do.  If we do any
+             * fixes, we wait for a while again and redo it until we're clean.
+             *
+             * This is unfortunately kind of fragile.
+             */
+            uint32_t cMsFudge = g_fSupAdversaries ? 512 : 128;
+            uint32_t cFixes;
+            for (uint32_t iLoop = 0; iLoop < 16; iLoop++)
             {
-                NtYieldExecution();
-                LARGE_INTEGER Time;
-                Time.QuadPart = -8000000 / 100; /* 8ms in 100ns units, relative time. */
-                NtDelayExecution(FALSE, &Time);
-                cSleeps++;
-            } while (   GetTickCount() - dwStart <= cMsFudge
-                     || cSleeps < 8);
-            SUP_DPRINTF(("supR3HardenedWinInit: Startup delay kludge #2/%u: %u ms, %u sleeps\n",
-                         iLoop, GetTickCount() - dwStart, cSleeps));
-
-            cFixes = 0;
-            rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_SELF_PURIFICATION,
-                                             &cFixes, NULL /*pErrInfo*/);
-            if (RT_FAILURE(rc) || cFixes == 0)
-                break;
-
-            if (!g_fSupAdversaries)
-                g_fSupAdversaries |= SUPHARDNT_ADVERSARY_UNKNOWN;
-            cMsFudge = 512;
-
-            /* Log the KiOpPrefetchPatchCount value if available, hoping it might sched some light on spider38's case. */
-            ULONG cPatchCount = 0;
-            NTSTATUS rcNt = NtQuerySystemInformation(SystemInformation_KiOpPrefetchPatchCount,
-                                                     &cPatchCount, sizeof(cPatchCount), NULL);
-            if (NT_SUCCESS(rcNt))
-                SUP_DPRINTF(("supR3HardenedWinInit: cFixes=%u g_fSupAdversaries=%#x cPatchCount=%#u\n",
-                             cFixes, g_fSupAdversaries, cPatchCount));
-            else
-                SUP_DPRINTF(("supR3HardenedWinInit: cFixes=%u g_fSupAdversaries=%#x\n", cFixes, g_fSupAdversaries));
+                uint32_t    cSleeps = 0;
+                DWORD       dwStart = GetTickCount();
+                do
+                {
+                    NtYieldExecution();
+                    LARGE_INTEGER Time;
+                    Time.QuadPart = -8000000 / 100; /* 8ms in 100ns units, relative time. */
+                    NtDelayExecution(FALSE, &Time);
+                    cSleeps++;
+                } while (   GetTickCount() - dwStart <= cMsFudge
+                         || cSleeps < 8);
+                SUP_DPRINTF(("supR3HardenedWinInit: Startup delay kludge #2/%u: %u ms, %u sleeps\n",
+                             iLoop, GetTickCount() - dwStart, cSleeps));
+
+                cFixes = 0;
+                rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_SELF_PURIFICATION,
+                                                 &cFixes, NULL /*pErrInfo*/);
+                if (RT_FAILURE(rc) || cFixes == 0)
+                    break;
+
+                if (!g_fSupAdversaries)
+                    g_fSupAdversaries |= SUPHARDNT_ADVERSARY_UNKNOWN;
+                cMsFudge = 512;
+
+                /* Log the KiOpPrefetchPatchCount value if available, hoping it might sched some light on spider38's case. */
+                ULONG cPatchCount = 0;
+                NTSTATUS rcNt = NtQuerySystemInformation(SystemInformation_KiOpPrefetchPatchCount,
+                                                         &cPatchCount, sizeof(cPatchCount), NULL);
+                if (NT_SUCCESS(rcNt))
+                    SUP_DPRINTF(("supR3HardenedWinInit: cFixes=%u g_fSupAdversaries=%#x cPatchCount=%#u\n",
+                                 cFixes, g_fSupAdversaries, cPatchCount));
+                else
+                    SUP_DPRINTF(("supR3HardenedWinInit: cFixes=%u g_fSupAdversaries=%#x\n", cFixes, g_fSupAdversaries));
+            }
         }
 
@@ -5061,4 +5091,20 @@
 
     /*
+     * Notify the parent process that we're probably capable of reporting our
+     * own errors.
+     */
+    if (g_ProcParams.hEvtParent || g_ProcParams.hEvtChild)
+    {
+        SUPR3HARDENED_ASSERT(g_fSupEarlyVmProcessInit);
+        NtSetEvent(g_ProcParams.hEvtParent, NULL);
+        NtClose(g_ProcParams.hEvtParent);
+        NtClose(g_ProcParams.hEvtChild);
+        g_ProcParams.hEvtParent = NULL;
+        g_ProcParams.hEvtChild  = NULL;
+    }
+    else
+        SUPR3HARDENED_ASSERT(!g_fSupEarlyVmProcessInit);
+
+    /*
      * After having resolved imports we patch the LdrInitializeThunk code so
      * that it's more difficult to invade our privacy by CreateRemoteThread.
@@ -5140,2 +5186,140 @@
 }
 
+
+/**
+ * Reports an error to the parent process via the process parameter structure.
+ *
+ * @param   rc                  The status code to report.
+ * @param   pszFormat           The format string.
+ * @param   va                  The format arguments.
+ */
+DECLHIDDEN(void) supR3HardenedWinReportErrorToParent(int rc, const char *pszFormat, va_list va)
+{
+    RTStrPrintfV(g_ProcParams.szErrorMsg, sizeof(g_ProcParams.szErrorMsg), pszFormat, va);
+    g_ProcParams.rc = RT_SUCCESS(rc) ? VERR_INTERNAL_ERROR_2 : rc;
+
+    NTSTATUS rcNt = NtSetEvent(g_ProcParams.hEvtParent, NULL);
+    if (NT_SUCCESS(rcNt))
+    {
+        LARGE_INTEGER Timeout;
+        Timeout.QuadPart = -300000000; /* 30 second */
+        NTSTATUS rcNt = NtWaitForSingleObject(g_ProcParams.hEvtChild, FALSE /*Alertable*/, &Timeout);
+        NtClearEvent(g_ProcParams.hEvtChild);
+    }
+}
+
+
+/**
+ * Routine called by the supR3HardenedVmProcessInitThunk assembly routine when
+ * LdrInitializeThunk is executed in during process initialization.
+ *
+ * This initializes the VM process, hooking NTDLL APIs and opening the device
+ * driver before any other DLLs gets loaded into the process.  This greately
+ * reduces and controls the trusted code base of the process compared to the
+ * opening it from SUPR3HardenedMain, avoid issues with so call protection
+ * software that is in the habit of patching half of the ntdll and kernel32
+ * APIs in the process, making it almost indistinguishable from software that is
+ * up to no good.  Once we've opened vboxdrv, the process should be locked down
+ * so thighly that only kernel software and csrss can mess with the process.
+ */
+DECLASM(uintptr_t) supR3HardenedVmProcessInit(void)
+{
+    /*
+     * Only let the first thread thru.
+     */
+    if (!ASMAtomicCmpXchgU32((uint32_t volatile *)&g_enmSupR3HardenedMainState,
+                             SUPR3HARDENEDMAINSTATE_WIN_VM_INIT_CALLED,
+                             SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED))
+    {
+        NtTerminateThread(0, 0);
+        return 0x22;  /* crash */
+    }
+    g_fSupEarlyVmProcessInit = true;
+
+    /*
+     * Initialize the NTDLL imports that we consider usable before the
+     * process has been initialized.
+     */
+    supR3HardenedWinInitImportsEarly(g_ProcParams.uNtDllAddr);
+    g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_WIN_EARLY_IMPORTS_RESOLVED;
+
+    /*
+     * Init g_uNtVerCombined as well as we can at this point.
+     */
+    supR3HardenedWinInitVersion();
+
+    /*
+     * Wait on the parent process to dispose of the full access process handle.
+     */
+    LARGE_INTEGER Timeout;
+    Timeout.QuadPart = -600000000; /* 60 second */
+    NTSTATUS rcNt = NtWaitForSingleObject(g_ProcParams.hEvtChild, FALSE /*Alertable*/, &Timeout);
+    if (NT_SUCCESS(rcNt))
+        rcNt = NtClearEvent(g_ProcParams.hEvtChild);
+    if (!NT_SUCCESS(rcNt))
+    {
+        NtTerminateProcess(NtCurrentProcess(), 0x42);
+        return 0x42; /* crash */
+    }
+
+    /*
+     * Convert the arguments to UTF-8 so we can open the log file if specified.
+     * Note! This leaks memory at present.
+     */
+    PUNICODE_STRING pCmdLineStr = &NtCurrentPeb()->ProcessParameters->CommandLine;
+    int    cArgs;
+    char **papszArgs = suplibCommandLineToArgvWStub(pCmdLineStr->Buffer, pCmdLineStr->Length / sizeof(WCHAR), &cArgs);
+    supR3HardenedOpenLog(&cArgs, papszArgs);
+    SUP_DPRINTF(("supR3HardenedVmProcessInit: uNtDllAddr=%p\n", g_ProcParams.uNtDllAddr));
+
+    /*
+     * Determine the executable path and name.  Will NOT determine the windows style
+     * executable path here as we don't need it.
+     */
+    SIZE_T cbActual = 0;
+    rcNt = NtQueryVirtualMemory(NtCurrentProcess(), &g_ProcParams, MemorySectionName, &g_SupLibHardenedExeNtPath,
+                                sizeof(g_SupLibHardenedExeNtPath) - sizeof(WCHAR), &cbActual);
+    if (   !NT_SUCCESS(rcNt)
+        || g_SupLibHardenedExeNtPath.UniStr.Length == 0
+        || g_SupLibHardenedExeNtPath.UniStr.Length & 1)
+        supR3HardenedFatal("NtQueryVirtualMemory/MemorySectionName failed in supR3HardenedVmProcessInit: %#x\n", rcNt);
+
+    /* The NT executable name offset / dir path length. */
+    g_offSupLibHardenedExeNtName = g_SupLibHardenedExeNtPath.UniStr.Length / sizeof(WCHAR);
+    while (   g_offSupLibHardenedExeNtName > 1
+           && g_SupLibHardenedExeNtPath.UniStr.Buffer[g_offSupLibHardenedExeNtName - 1] != '\\' )
+        g_offSupLibHardenedExeNtName--;
+
+    /*
+     * Initialize the image verification stuff (hooks LdrLoadDll and NtCreateSection).
+     */
+    supR3HardenedWinInit(0, false /*fAvastKludge*/);
+
+    /*
+     * Open the driver.
+     */
+    supR3HardenedMainOpenDevice();
+    g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_WIN_EARLY_DEVICE_OPENED;
+
+    /*
+     * Restore the LdrInitializeThunk code so we can initialize the process
+     * normally when we return.
+     */
+    PSUPHNTLDRCACHEENTRY pLdrEntry;
+    int rc = supHardNtLdrCacheOpen("ntdll.dll", &pLdrEntry);
+    if (RT_FAILURE(rc))
+        supR3HardenedFatal("supR3HardenedVmProcessInit: supHardNtLdrCacheOpen failed on NTDLL: %Rrc\n", rc);
+
+    RTLDRADDR uValue;
+    rc = RTLdrGetSymbolEx(pLdrEntry->hLdrMod, pLdrEntry->pbBits, 0, UINT32_MAX, "LdrInitializeThunk", &uValue);
+    if (RT_FAILURE(rc))
+        supR3HardenedFatal("supR3HardenedVmProcessInit: Failed to find LdrInitializeThunk (%Rrc).\n", rc);
+
+    PVOID pvLdrInitThunk = (uint8_t *)g_ProcParams.uNtDllAddr + (uint32_t)uValue;
+    SUPR3HARDENED_ASSERT_NT_SUCCESS(supR3HardenedWinProtectMemory(pvLdrInitThunk, 16, PAGE_EXECUTE_READWRITE));
+    memcpy(pvLdrInitThunk, pLdrEntry->pbBits + (uint32_t)uValue, 16);
+    SUPR3HARDENED_ASSERT_NT_SUCCESS(supR3HardenedWinProtectMemory(pvLdrInitThunk, 16, PAGE_EXECUTE_READ));
+
+    return (uintptr_t)pvLdrInitThunk;
+}
+
Index: /trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainA-win.asm
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainA-win.asm	(revision 52942)
+++ /trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainA-win.asm	(revision 52943)
@@ -35,4 +35,7 @@
 extern NAME(g_pfnNtCreateSectionJmpBack)
 
+; External code.
+extern NAME(supR3HardenedVmProcessInit)
+
 
 BEGINCODE
@@ -76,4 +79,73 @@
 
 %endif
+
+
+
+;;
+; Alternative code for LdrInitializeThunk that performs the VM process startup.
+;
+; This does not concern itself with any arguments on stack or in registers that
+; may be passed to the LdrIntializeThunk routine as we just save and restore
+; them all before we restart the restored LdrInitializeThunk routine.
+;
+BEGINPROC supR3HardenedVmProcessInitThunk
+        ;
+        ; Prologue.
+        ;
+
+        ; Reserve space for the "return" address.
+        push    0
+
+        ; Create a stack frame, saving xBP.
+        push    xBP
+        SEH64_PUSH_xBP
+        mov     xBP, xSP
+        SEH64_SET_FRAME_xBP 0 ; probably wrong...
+
+        ; Save all volatile registers.
+        push    xAX
+        push    xCX
+        push    xDX
+%ifdef RT_ARCH_AMD64
+        push    r8
+        push    r9
+        push    r10
+        push    r11
+%endif
+
+        ; Reserve spill space and align the stack.
+        sub     xSP, 20h
+        and     xSP, ~0fh
+        SEH64_END_PROLOGUE
+
+        ;
+        ; Call the C/C++ code that does the actual work.  This returns the
+        ; resume address in xAX, which we put in the "return" stack position.
+        ;
+        call    NAME(supR3HardenedVmProcessInit)
+        mov     [xBP + xCB], xAX
+
+        ;
+        ; Restore volatile registers.
+        ;
+        mov     xAX, [xBP - xCB*1]
+        mov     xCX, [xBP - xCB*2]
+        mov     xDX, [xBP - xCB*3]
+%ifdef RT_ARCH_AMD64
+        mov     r8,  [xBP - xCB*4]
+        mov     r9,  [xBP - xCB*5]
+        mov     r10, [xBP - xCB*6]
+        mov     r11, [xBP - xCB*7]
+%endif
+        ;
+        ; Use the leave instruction to restore xBP and set up xSP to point at
+        ; the resume address. Then use the 'ret' instruction to resume process
+        ; initializaton.
+        ;
+        leave
+        ret
+ENDPROC   supR3HardenedVmProcessInitThunk
+
+
 
 ;;
Index: /trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainImports-win.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainImports-win.cpp	(revision 52942)
+++ /trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainImports-win.cpp	(revision 52943)
@@ -229,4 +229,5 @@
 /**
  * All the DLLs we import from.
+ * @remarks Code ASSUMES that ntdll is the first entry.
  */
 static SUPHNTIMPDLL g_aSupNtImpDlls[] =
@@ -546,4 +547,38 @@
 
 
+/**
+ * Resolves NtDll functions we can trust calling before process init.
+ *
+ * @param   uNtDllAddr          The address of the NTDLL.
+ */
+DECLHIDDEN(void) supR3HardenedWinInitImportsEarly(uintptr_t uNtDllAddr)
+{
+    /*
+     * NTDLL is the first entry in the list.
+     */
+    g_aSupNtImpDlls[0].pbImageBase = (uint8_t const *)uNtDllAddr;
+    supR3HardenedParseModule(&g_aSupNtImpDlls[0]);
+    for (uint32_t i = 0; i < g_aSupNtImpDlls[0].cImports; i++)
+        if (!g_aSupNtImpDlls[0].paImports[i].pfnEarlyDummy)
+        {
+            const char *pszForwarder = supR3HardenedResolveImport(&g_aSupNtImpDlls[0], &g_aSupNtImpDlls[0].paImports[i]);
+            if (pszForwarder)
+                SUPHNTIMP_ERROR(32, "supR3HardenedWinInitImports", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
+                                "ntdll: Failed to resolve forwarder '%s'.", pszForwarder);
+        }
+        else
+            *g_aSupNtImpDlls[0].paImports[i].ppfnImport = g_aSupNtImpDlls[0].paImports[i].pfnEarlyDummy;
+
+    /*
+     * Pointer the other imports at the early init stubs.
+     */
+    for (uint32_t iDll = 1; iDll < RT_ELEMENTS(g_aSupNtImpDlls); iDll++)
+        for (uint32_t i = 0; i < g_aSupNtImpDlls[iDll].cImports; i++)
+            if (!g_aSupNtImpDlls[iDll].paImports[i].fOptional)
+                *g_aSupNtImpDlls[iDll].paImports[i].ppfnImport = g_aSupNtImpDlls[iDll].paImports[i].pfnEarlyDummy;
+            else
+                *g_aSupNtImpDlls[iDll].paImports[i].ppfnImport = NULL;
+}
+
 
 /**
Index: /trunk/src/VBox/HostDrivers/Support/win/import-template-ntdll.h
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/win/import-template-ntdll.h	(revision 52942)
+++ /trunk/src/VBox/HostDrivers/Support/win/import-template-ntdll.h	(revision 52943)
@@ -1,4 +1,6 @@
 SUPHARNT_IMPORT_SYSCALL(NtAllocateVirtualMemory, 24)
+SUPHARNT_IMPORT_SYSCALL(NtClearEvent, 4)
 SUPHARNT_IMPORT_SYSCALL(NtClose, 4)
+SUPHARNT_IMPORT_SYSCALL(NtCreateEvent, 20)
 SUPHARNT_IMPORT_SYSCALL(NtCreateFile, 44)
 SUPHARNT_IMPORT_SYSCALL(NtDelayExecution, 8)
@@ -9,4 +11,5 @@
 SUPHARNT_IMPORT_SYSCALL(NtMapViewOfSection, 40)
 SUPHARNT_IMPORT_SYSCALL(NtOpenDirectoryObject, 12)
+SUPHARNT_IMPORT_SYSCALL(NtOpenEvent, 12)
 SUPHARNT_IMPORT_SYSCALL(NtOpenKey, 12)
 SUPHARNT_IMPORT_SYSCALL(NtOpenProcess, 16)
@@ -17,4 +20,5 @@
 SUPHARNT_IMPORT_SYSCALL(NtQueryDirectoryFile, 44)
 SUPHARNT_IMPORT_SYSCALL(NtQueryDirectoryObject, 28)
+SUPHARNT_IMPORT_SYSCALL(NtQueryEvent, 20)
 SUPHARNT_IMPORT_SYSCALL(NtQueryInformationFile, 20)
 SUPHARNT_IMPORT_SYSCALL(NtQueryInformationProcess, 20)
@@ -22,6 +26,6 @@
 SUPHARNT_IMPORT_SYSCALL(NtQueryInformationToken, 20)
 SUPHARNT_IMPORT_SYSCALL(NtQueryObject, 20)
+SUPHARNT_IMPORT_SYSCALL(NtQuerySecurityObject, 20)
 SUPHARNT_IMPORT_SYSCALL(NtQuerySystemInformation, 16)
-SUPHARNT_IMPORT_SYSCALL(NtQuerySecurityObject, 20)
 SUPHARNT_IMPORT_SYSCALL(NtQueryTimerResolution, 12)
 SUPHARNT_IMPORT_SYSCALL(NtQueryValueKey, 24)
@@ -29,7 +33,9 @@
 SUPHARNT_IMPORT_SYSCALL(NtReadFile, 36)
 SUPHARNT_IMPORT_SYSCALL(NtReadVirtualMemory, 20)
+SUPHARNT_IMPORT_SYSCALL(NtResetEvent, 8)
 SUPHARNT_IMPORT_SYSCALL(NtResumeProcess, 4)
 SUPHARNT_IMPORT_SYSCALL(NtResumeThread, 8)
 SUPHARNT_IMPORT_SYSCALL(NtSetContextThread, 8)
+SUPHARNT_IMPORT_SYSCALL(NtSetEvent, 8)
 SUPHARNT_IMPORT_SYSCALL(NtSetInformationFile, 20)
 SUPHARNT_IMPORT_SYSCALL(NtSetInformationObject, 16)
@@ -42,14 +48,15 @@
 SUPHARNT_IMPORT_SYSCALL(NtTerminateThread, 8)
 SUPHARNT_IMPORT_SYSCALL(NtUnmapViewOfSection, 8)
+SUPHARNT_IMPORT_SYSCALL(NtWaitForMultipleObjects, 20)
 SUPHARNT_IMPORT_SYSCALL(NtWaitForSingleObject, 12)
-SUPHARNT_IMPORT_SYSCALL(NtWaitForMultipleObjects, 20)
 SUPHARNT_IMPORT_SYSCALL(NtWriteFile, 36)
 SUPHARNT_IMPORT_SYSCALL(NtWriteVirtualMemory, 20)
 SUPHARNT_IMPORT_SYSCALL(NtYieldExecution, 0)
 
-
 SUPHARNT_IMPORT_STDCALL_EARLY(NtCreateSection, 28)
 SUPHARNT_IMPORT_STDCALL_EARLY(NtQueryVolumeInformationFile, 20)
+
 SUPHARNT_IMPORT_STDCALL_EARLY(LdrInitializeThunk, 12)
+
 SUPHARNT_IMPORT_STDCALL(RtlAddAccessAllowedAce, 16)
 SUPHARNT_IMPORT_STDCALL(RtlAddAccessDeniedAce, 16)
@@ -74,5 +81,5 @@
 SUPHARNT_IMPORT_STDCALL_EARLY(RtlGetLastWin32Error, 0)
 SUPHARNT_IMPORT_STDCALL_EARLY(RtlGetVersion, 4)
-SUPHARNT_IMPORT_STDCALL(RtlInitializeSid, 12)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlInitializeSid, 12)
 SUPHARNT_IMPORT_STDCALL_EARLY(RtlNtStatusToDosError, 4)
 SUPHARNT_IMPORT_STDCALL_EARLY(RtlReAllocateHeap, 16)
@@ -82,4 +89,4 @@
 SUPHARNT_IMPORT_STDCALL_EARLY(RtlSetLastWin32ErrorAndNtStatusFromNtStatus, 4)
 SUPHARNT_IMPORT_STDCALL_EARLY(RtlSizeHeap, 12)
-SUPHARNT_IMPORT_STDCALL(RtlSubAuthoritySid, 8)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlSubAuthoritySid, 8)
 
Index: /trunk/src/VBox/Runtime/r3/win/ntdll-mini-implib.def
===================================================================
--- /trunk/src/VBox/Runtime/r3/win/ntdll-mini-implib.def	(revision 52942)
+++ /trunk/src/VBox/Runtime/r3/win/ntdll-mini-implib.def	(revision 52943)
@@ -33,5 +33,7 @@
 
     NtAllocateVirtualMemory               ;;= _NtAllocateVirtualMemory@24
+    NtClearEvent                          ;;= _NtClearEvent@4
     NtClose                               ;;= _NtClose@4
+    NtCreateEvent                         ;;= _NtCreateEvent@20
     NtCreateFile                          ;;= _NtCreateFile@44
     NtCreateSection                       ;;= _NtCreateSection@28
@@ -43,4 +45,5 @@
     NtMapViewOfSection                    ;;= _NtMapViewOfSection@40
     NtOpenDirectoryObject                 ;;= _NtOpenDirectoryObject@12
+    NtOpenEvent                           ;;= _NtOpenEvent@12
     NtOpenKey                             ;;= _NtOpenKey@12
     NtOpenProcess                         ;;= _NtOpenProcess@16
@@ -51,4 +54,5 @@
     NtQueryDirectoryFile                  ;;= _NtQueryDirectoryFile@44
     NtQueryDirectoryObject                ;;= _NtQueryDirectoryObject@28
+    NtQueryEvent                          ;;= _NtQueryEvent@20
     NtQueryInformationFile                ;;= _NtQueryInformationFile@20
     NtQueryInformationProcess             ;;= _NtQueryInformationProcess@20
@@ -64,7 +68,9 @@
     NtReadFile                            ;;= _NtReadFile@36
     NtReadVirtualMemory                   ;;= _NtReadVirtualMemory@20
+    NtResetEvent                          ;;= _NtResetEvent@8
     NtResumeProcess                       ;;= _NtResumeProcess@4
     NtResumeThread                        ;;= _NtResumeThread@8
     NtSetContextThread                    ;;= _NtSetContextThread@8
+    NtSetEvent                            ;;= _NtSetEvent@8
     NtSetInformationFile                  ;;= _NtSetInformationFile@20
     NtSetInformationObject                ;;= _NtSetInformationObject@16
@@ -77,6 +83,6 @@
     NtTerminateThread                     ;;= _NtTerminateThread@8
     NtUnmapViewOfSection                  ;;= _NtUnmapViewOfSection@8
+    NtWaitForMultipleObjects              ;;= _NtWaitForMultipleObjects@20
     NtWaitForSingleObject                 ;;= _NtWaitForSingleObject@12
-    NtWaitForMultipleObjects              ;;= _NtWaitForMultipleObjects@20
     NtWriteFile                           ;;= _NtWriteFile@36
     NtWriteVirtualMemory                  ;;= _NtWriteVirtualMemory@20
