Index: /trunk/include/iprt/nt/nt.h
===================================================================
--- /trunk/include/iprt/nt/nt.h	(revision 54996)
+++ /trunk/include/iprt/nt/nt.h	(revision 54997)
@@ -2165,4 +2165,17 @@
                                             PFNRT, PVOID, PHANDLE, PCLIENT_ID);
 
+#ifndef RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO
+typedef struct _RTL_CRITICAL_SECTION
+{
+    struct _RTL_CRITICAL_SECTION_DEBUG *DebugInfo;
+    LONG            LockCount;
+    LONG            Recursioncount;
+    HANDLE          OwningThread;
+    HANDLE          LockSemaphore;
+    ULONG_PTR       SpinCount;
+} RTL_CRITICAL_SECTION;
+typedef RTL_CRITICAL_SECTION *PRTL_CRITICAL_SECTION;
+#endif
+
 RT_C_DECLS_END
 /** @} */
Index: /trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp	(revision 54996)
+++ /trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp	(revision 54997)
@@ -98,4 +98,7 @@
 typedef BOOL (WINAPI *PFNCERTCLOSESTORE)(HCERTSTORE hCertStore, DWORD dwFlags);
 typedef PCCERT_CONTEXT (WINAPI *PFNCERTENUMCERTIFICATESINSTORE)(HCERTSTORE hCertStore, PCCERT_CONTEXT pPrevCertContext);
+
+typedef NTSTATUS (WINAPI *PFNBCRYPTOPENALGORTIHMPROVIDER)(BCRYPT_ALG_HANDLE *phAlgo, PCWSTR pwszAlgoId,
+                                                          PCWSTR pwszImpl, DWORD dwFlags);
 #endif
 
@@ -2051,5 +2054,5 @@
 
     /*
-     * Resolve it.
+     * Resolve the imports we need.
      */
     HMODULE hWintrust = supR3HardenedWinLoadSystem32Dll("Wintrust.dll");
@@ -2075,10 +2078,46 @@
     RESOLVE_CRYPT_API(CryptCATAdminCalcHashFromFileHandle2,  PFNCRYPTCATADMINCALCHASHFROMFILEHANDLE2, SUP_NT_VER_W80);
 
-    /*
-     * Call it on ourselves and ntdll to make sure it loads all the providers
-     * now, we would otherwise geting into recursive trouble in the
-     * NtCreateSection hook.
-     */
 # ifdef IN_SUP_HARDENED_R3
+    /*
+     * Load bcrypt.dll and instantiate a few hashing and signing providers to
+     * make sure the providers are cached for later us.  Avoid recursion issues.
+     */
+    HMODULE hBCrypt = supR3HardenedWinLoadSystem32Dll("bcrypt.dll");
+    if (hBCrypt)
+    {
+        PFNBCRYPTOPENALGORTIHMPROVIDER pfnOpenAlgoProvider;
+        pfnOpenAlgoProvider = (PFNBCRYPTOPENALGORTIHMPROVIDER)GetProcAddress(hBCrypt, "BCryptOpenAlgorithmProvider");
+        if (pfnOpenAlgoProvider)
+        {
+            SUP_DPRINTF(("bcrypt.dll loaded at %p, BCryptOpenAlgorithmProvider at %p, preloading providers:\n",
+                         hBCrypt, pfnOpenAlgoProvider));
+#  define PRELOAD_ALGO_PROVIDER(a_Name) \
+                do { \
+                    BCRYPT_ALG_HANDLE hAlgo = NULL; \
+                    NTSTATUS rcNt = pfnOpenAlgoProvider(&hAlgo, a_Name, NULL, 0); \
+                    SUP_DPRINTF(("%sBCryptOpenAlgorithmProvider(,'%ls',0,0) -> %#x (hAlgo=%p)\n", \
+                                 NT_SUCCESS(rcNt) ? "    " : "warning: ", a_Name, rcNt, hAlgo)); \
+                } while (0)
+            PRELOAD_ALGO_PROVIDER(BCRYPT_MD2_ALGORITHM);
+            PRELOAD_ALGO_PROVIDER(BCRYPT_MD4_ALGORITHM);
+            PRELOAD_ALGO_PROVIDER(BCRYPT_MD5_ALGORITHM);
+            PRELOAD_ALGO_PROVIDER(BCRYPT_SHA1_ALGORITHM);
+            PRELOAD_ALGO_PROVIDER(BCRYPT_SHA256_ALGORITHM);
+            PRELOAD_ALGO_PROVIDER(BCRYPT_SHA512_ALGORITHM);
+            PRELOAD_ALGO_PROVIDER(BCRYPT_RSA_ALGORITHM);
+            PRELOAD_ALGO_PROVIDER(BCRYPT_DSA_ALGORITHM);
+#  undef PRELOAD_ALGO_PROVIDER
+        }
+        else
+            SUP_DPRINTF(("Warning! Failed to find BCryptOpenAlgorithmProvider in bcrypt.dll\n"));
+    }
+    else
+        SUP_DPRINTF(("Warning! Failed to load bcrypt.dll\n"));
+
+    /*
+     * Call the verification API on ourselves and ntdll to make sure it works
+     * and loads more stuff it needs, preventing any recursive fun we'd run
+     * into after we set g_pfnWinVerifyTrust.
+     */
     RTERRINFOSTATIC ErrInfoStatic;
     RTErrInfoInitStatic(&ErrInfoStatic);
@@ -2582,75 +2621,89 @@
     if (g_pfnWinVerifyTrust != NULL)
     {
-        /* Check for recursion. */
-        bool fNoRecursion;
-        if (g_iTlsWinVerifyTrustRecursion != UINT32_MAX)
+        uint32_t const idCurrentThread = RTNtCurrentThreadId();
+
+        /* Check if loader lock owner. */
+        struct _RTL_CRITICAL_SECTION volatile *pLoaderLock = NtCurrentPeb()->LoaderLock;
+        bool fOwnsLoaderLock = pLoaderLock
+                            && pLoaderLock->OwningThread == (HANDLE)(uintptr_t)idCurrentThread
+                            && pLoaderLock->LockCount >= 0;
+        if (!fOwnsLoaderLock)
         {
-            fNoRecursion = TlsGetValue(g_iTlsWinVerifyTrustRecursion) == 0;
-            if (fNoRecursion)
-                TlsSetValue(g_iTlsWinVerifyTrustRecursion, (void *)1);
-        }
-        else
-        {
-            uint32_t const idCurrentThread = RTNtCurrentThreadId();
-            fNoRecursion = ASMAtomicCmpXchgU32(&g_idActiveThread, idCurrentThread, UINT32_MAX);
-        }
-        if (fNoRecursion)
-        {
-            /* We can call WinVerifyTrust. */
-            if (pfWinVerifyTrust)
-                *pfWinVerifyTrust = true;
-
-            if (rc != VERR_LDRVI_NOT_SIGNED)
+            /* Check for recursion. */
+            bool fNoRecursion;
+            if (g_iTlsWinVerifyTrustRecursion != UINT32_MAX)
             {
-                if (rc == VINF_LDRVI_NOT_SIGNED)
+                fNoRecursion = TlsGetValue(g_iTlsWinVerifyTrustRecursion) == 0;
+                if (fNoRecursion)
+                    TlsSetValue(g_iTlsWinVerifyTrustRecursion, (void *)1);
+            }
+            else
+                fNoRecursion = ASMAtomicCmpXchgU32(&g_idActiveThread, idCurrentThread, UINT32_MAX);
+
+            if (fNoRecursion && !fOwnsLoaderLock)
+            {
+                /* We can call WinVerifyTrust. */
+                if (pfWinVerifyTrust)
+                    *pfWinVerifyTrust = true;
+
+                if (rc != VERR_LDRVI_NOT_SIGNED)
                 {
-                    if (fFlags & SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION)
+                    if (rc == VINF_LDRVI_NOT_SIGNED)
                     {
-                        int rc2 = supR3HardNtViCallWinVerifyTrustCatFile(hFile, pwszName, fFlags, pErrInfo, g_pfnWinVerifyTrust);
-                        SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile -> %d (org %d)\n", rc2, rc));
-                        rc = rc2;
+                        if (fFlags & SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION)
+                        {
+                            int rc2 = supR3HardNtViCallWinVerifyTrustCatFile(hFile, pwszName, fFlags, pErrInfo,
+                                                                             g_pfnWinVerifyTrust);
+                            SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile -> %d (org %d)\n", rc2, rc));
+                            rc = rc2;
+                        }
+                        else
+                        {
+                            AssertFailed();
+                            rc = VERR_LDRVI_NOT_SIGNED;
+                        }
+                    }
+                    else if (RT_SUCCESS(rc))
+                    {
+                        HRESULT hrcWinVerifyTrust;
+                        rc = supR3HardNtViCallWinVerifyTrust(hFile, pwszName, fFlags, pErrInfo, g_pfnWinVerifyTrust,
+                                                             &hrcWinVerifyTrust);
+
+                        /* DLLs signed with special roots, like "Microsoft Digital Media Authority 2005",
+                           may fail here because the root cert is not in the normal certificate stores
+                           (if any).  Our verification code has the basics of these certificates included
+                           and can verify them, which is why we end up here instead of in the
+                           VINF_LDRVI_NOT_SIGNED case above.  Current workaround is to do as above.
+                           (Intel graphics driver DLLs, like igdusc64.dll. */
+                        if (   RT_FAILURE(rc)
+                            && hrcWinVerifyTrust == CERT_E_CHAINING
+                            && (fFlags & SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION))
+                        {
+                            rc = supR3HardNtViCallWinVerifyTrustCatFile(hFile, pwszName, fFlags, pErrInfo, g_pfnWinVerifyTrust);
+                            SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile -> %d (was CERT_E_CHAINING)\n", rc));
+                        }
                     }
                     else
                     {
-                        AssertFailed();
-                        rc = VERR_LDRVI_NOT_SIGNED;
+                        int rc2 = supR3HardNtViCallWinVerifyTrust(hFile, pwszName, fFlags, pErrInfo, g_pfnWinVerifyTrust, NULL);
+                        AssertMsg(RT_FAILURE_NP(rc2),
+                                  ("rc=%Rrc, rc2=%Rrc %s", rc, rc2, pErrInfo ? pErrInfo->pszMsg : "<no-err-info>"));
                     }
                 }
-                else if (RT_SUCCESS(rc))
-                {
-                    HRESULT hrcWinVerifyTrust;
-                    rc = supR3HardNtViCallWinVerifyTrust(hFile, pwszName, fFlags, pErrInfo, g_pfnWinVerifyTrust,
-                                                         &hrcWinVerifyTrust);
-
-                    /* DLLs signed with special roots, like "Microsoft Digital Media Authority 2005",
-                       may fail here because the root cert is not in the normal certificate stores
-                       (if any).  Our verification code has the basics of these certificates included
-                       and can verify them, which is why we end up here instead of in the
-                       VINF_LDRVI_NOT_SIGNED case above.  Current workaround is to do as above.
-                       (Intel graphics driver DLLs, like igdusc64.dll. */
-                    if (   RT_FAILURE(rc)
-                        && hrcWinVerifyTrust == CERT_E_CHAINING
-                        && (fFlags & SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION))
-                    {
-                        rc = supR3HardNtViCallWinVerifyTrustCatFile(hFile, pwszName, fFlags, pErrInfo, g_pfnWinVerifyTrust);
-                        SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile -> %d (was CERT_E_CHAINING)\n", rc));
-                    }
-                }
+
+                /* Unwind recursion. */
+                if (g_iTlsWinVerifyTrustRecursion != UINT32_MAX)
+                    TlsSetValue(g_iTlsWinVerifyTrustRecursion, (void *)0);
                 else
-                {
-                    int rc2 = supR3HardNtViCallWinVerifyTrust(hFile, pwszName, fFlags, pErrInfo, g_pfnWinVerifyTrust, NULL);
-                    AssertMsg(RT_FAILURE_NP(rc2),
-                              ("rc=%Rrc, rc2=%Rrc %s", rc, rc2, pErrInfo ? pErrInfo->pszMsg : "<no-err-info>"));
-                }
+                    ASMAtomicWriteU32(&g_idActiveThread, UINT32_MAX);
             }
-
-            /* Unwind recursion. */
-            if (g_iTlsWinVerifyTrustRecursion != UINT32_MAX)
-                TlsSetValue(g_iTlsWinVerifyTrustRecursion, (void *)0);
+            /*
+             * No can do.
+             */
             else
-                ASMAtomicWriteU32(&g_idActiveThread, UINT32_MAX);
+                SUP_DPRINTF(("Detected WinVerifyTrust recursion: rc=%Rrc '%ls'.\n", rc, pwszName));
         }
         else
-            SUP_DPRINTF(("Detected WinVerifyTrust recursion: rc=%Rrc '%ls'.\n", rc, pwszName));
+            SUP_DPRINTF(("Detected loader lock ownership: rc=%Rrc '%ls'.\n", rc, pwszName));
     }
     return rc;
