Index: trunk/src/VBox/HostDrivers/Support/Makefile.kmk
===================================================================
--- trunk/src/VBox/HostDrivers/Support/Makefile.kmk	(revision 52192)
+++ trunk/src/VBox/HostDrivers/Support/Makefile.kmk	(revision 52204)
@@ -293,4 +293,5 @@
 	$(VBOX_PATH_RUNTIME_SRC)/common/misc/RTAssertMsg2WeakV.cpp \
 	$(VBOX_PATH_RUNTIME_SRC)/common/misc/zero.asm \
+	$(VBOX_PATH_RUNTIME_SRC)/common/path/RTPathFilename.cpp \
 	$(VBOX_PATH_RUNTIME_SRC)/common/string/memchr.asm \
 	$(VBOX_PATH_RUNTIME_SRC)/common/string/memcmp.asm \
Index: trunk/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp
===================================================================
--- trunk/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp	(revision 52192)
+++ trunk/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp	(revision 52204)
@@ -243,7 +243,12 @@
     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, cch, &cbWritten, NULL);
+# endif
     }
 #else
Index: trunk/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp
===================================================================
--- trunk/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp	(revision 52192)
+++ trunk/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp	(revision 52204)
@@ -3422,5 +3422,5 @@
         RTErrInfoInit(&ErrInfo, szErr, sizeof(szErr));
 
-        rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), &ErrInfo);
+        rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_VERIFY_ONLY, &ErrInfo);
         if (RT_FAILURE(rc))
             RTLogWriteDebugger(szErr, strlen(szErr));
Index: trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerify-win.h
===================================================================
--- trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerify-win.h	(revision 52192)
+++ trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerify-win.h	(revision 52204)
@@ -30,4 +30,10 @@
 #include <iprt/types.h>
 #include <iprt/crypto/x509.h>
+#ifndef SUP_CERTIFICATES_ONLY
+# ifdef RT_OS_WINDOWS
+#  include <iprt/ldr.h>
+# endif
+#endif
+
 
 RT_C_DECLS_BEGIN
@@ -37,9 +43,43 @@
 DECLHIDDEN(int)      supHardenedWinInitImageVerifier(PRTERRINFO pErrInfo);
 DECLHIDDEN(void)     supHardenedWinTermImageVerifier(void);
-DECLHIDDEN(int)      supHardenedWinVerifyProcess(HANDLE hProcess, HANDLE hThread, PRTERRINFO pErrInfo);
+
+typedef enum SUPHARDNTVPKIND
+{
+    SUPHARDNTVPKIND_VERIFY_ONLY = 1,
+    SUPHARDNTVPKIND_CHILD_PURIFICATION,
+    SUPHARDNTVPKIND_SELF_PURIFICATION,
+    SUPHARDNTVPKIND_32BIT_HACK = 0x7fffffff
+} SUPHARDNTVPKIND;
+DECLHIDDEN(int)      supHardenedWinVerifyProcess(HANDLE hProcess, HANDLE hThread, SUPHARDNTVPKIND enmKind, PRTERRINFO pErrInfo);
 
 DECLHIDDEN(bool)     supHardViIsAppPatchDir(PCRTUTF16 pwszPath, uint32_t cwcName);
-DECLHIDDEN(int)      supHardenedWinVerifyImageByHandle(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, bool *pfCacheable, PRTERRINFO pErrInfo);
-DECLHIDDEN(int)      supHardenedWinVerifyImageByHandleNoName(HANDLE hFile, uint32_t fFlags, PRTERRINFO pErrInfo);
+
+/**
+ * SUP image verifier loader reader instance.
+ */
+typedef struct SUPHNTVIRDR
+{
+    /** The core reader structure. */
+    RTLDRREADER Core;
+    /** The file handle . */
+    HANDLE      hFile;
+    /** Current file offset. */
+    RTFOFF      off;
+    /** The file size. */
+    RTFOFF      cbFile;
+    /** Flags for the verification callback, SUPHNTVI_F_XXX. */
+    uint32_t    fFlags;
+    /** The executable timstamp in second since unix epoch. */
+    uint64_t    uTimestamp;
+    /** Log name. */
+    char        szFilename[1];
+} SUPHNTVIRDR;
+/** Pointer to an SUP image verifier loader reader instance. */
+typedef SUPHNTVIRDR *PSUPHNTVIRDR;
+DECLHIDDEN(int) supHardNtViRdrCreate(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PSUPHNTVIRDR *ppNtViRdr);
+DECLHIDDEN(int) supHardenedWinVerifyImageByHandle(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, bool *pfCacheable, PRTERRINFO pErrInfo);
+DECLHIDDEN(int) supHardenedWinVerifyImageByHandleNoName(HANDLE hFile, uint32_t fFlags, PRTERRINFO pErrInfo);
+DECLHIDDEN(int) supHardenedWinVerifyImageByLdrMod(RTLDRMOD hLdrMod, PCRTUTF16 pwszName, PSUPHNTVIRDR pNtViRdr,
+                                                  bool *pfCacheable, PRTERRINFO pErrInfo);
 /** @name SUPHNTVI_F_XXX - Flags for supHardenedWinVerifyImageByHandle.
  * @{ */
Index: trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp
===================================================================
--- trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp	(revision 52192)
+++ trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp	(revision 52204)
@@ -74,27 +74,4 @@
 *   Structures and Typedefs                                                    *
 *******************************************************************************/
-/**
- * SUP image verifier loader reader instance.
- */
-typedef struct SUPHNTVIRDR
-{
-    /** The core reader structure. */
-    RTLDRREADER Core;
-    /** The file handle . */
-    HANDLE      hFile;
-    /** Current file offset. */
-    RTFOFF      off;
-    /** The file size. */
-    RTFOFF      cbFile;
-    /** Flags for the verification callback, SUPHNTVI_F_XXX. */
-    uint32_t    fFlags;
-    /** The executable timstamp in second since unix epoch. */
-    uint64_t    uTimestamp;
-    /** Log name. */
-    char        szFilename[1];
-} SUPHNTVIRDR;
-/** Pointer to an SUP image verifier loader reader instance. */
-typedef SUPHNTVIRDR *PSUPHNTVIRDR;
-
 
 #ifdef IN_RING3
@@ -349,5 +326,5 @@
  * @param   ppNtViRdr       Where to store the reader instance on success.
  */
-static int supHardNtViRdrCreate(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PSUPHNTVIRDR *ppNtViRdr)
+DECLHIDDEN(int) supHardNtViRdrCreate(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PSUPHNTVIRDR *ppNtViRdr)
 {
     /*
@@ -882,4 +859,132 @@
 
 /**
+ * Verifies the given loader image.
+ *
+ * @returns IPRT status code.
+ * @param   hLdrMod     File handle to the executable file.
+ * @param   pwszName    Full NT path to the DLL in question, used for dealing
+ *                      with unsigned system dlls as well as for error/logging.
+ * @param   pNtViRdr    The reader instance /w flags.
+ * @param   pfCacheable Where to return whether the result can be cached.  A
+ *                      valid value is always returned. Optional.
+ * @param   pErrInfo    Pointer to error info structure. Optional.
+ */
+DECLHIDDEN(int) supHardenedWinVerifyImageByLdrMod(RTLDRMOD hLdrMod, PCRTUTF16 pwszName, PSUPHNTVIRDR pNtViRdr,
+                                                  bool *pfCacheable, PRTERRINFO pErrInfo)
+{
+#ifdef IN_RING3
+    /* Check that the caller has performed the necessary library initialization. */
+    if (!RTCrX509Certificate_IsPresent(&g_BuildX509Cert))
+        return RTErrInfoSet(pErrInfo, VERR_WRONG_ORDER,
+                            "supHardenedWinVerifyImageByHandle: supHardenedWinInitImageVerifier was not called.");
+#endif
+
+    /*
+     * Verify it.
+     *
+     * The PKCS #7 SignedData signature is checked in the callback. Any
+     * signing certificate restrictions are also enforced there.
+     *
+     * For the time being, we use the executable timestamp as the
+     * certificate validation date.  We must query that first to avoid
+     * potential issues re-entering the loader code from the callback.
+     *
+     * Update: Save the first timestamp we validate with build cert and
+     *         use this as a minimum timestamp for further build cert
+     *         validations.  This works around issues with old DLLs that
+     *         we sign against with our certificate (crt, sdl, qt).
+     */
+    int rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_TIMESTAMP_SECONDS, &pNtViRdr->uTimestamp, sizeof(pNtViRdr->uTimestamp));
+    if (RT_SUCCESS(rc))
+    {
+#ifdef IN_RING3 /* Hack alert! (see above) */
+        if (   (pNtViRdr->fFlags & SUPHNTVI_F_REQUIRE_KERNEL_CODE_SIGNING)
+            && (pNtViRdr->fFlags & SUPHNTVI_F_REQUIRE_SIGNATURE_ENFORCEMENT)
+            && pNtViRdr->uTimestamp < g_uBuildTimestampHack)
+            pNtViRdr->uTimestamp = g_uBuildTimestampHack;
+#endif
+
+        rc = RTLdrVerifySignature(hLdrMod, supHardNtViCallback, pNtViRdr, pErrInfo);
+
+#ifdef IN_RING3 /* Hack alert! (see above) */
+        if ((pNtViRdr->fFlags & SUPHNTVI_F_REQUIRE_BUILD_CERT) && g_uBuildTimestampHack == 0 && RT_SUCCESS(rc))
+            g_uBuildTimestampHack = pNtViRdr->uTimestamp;
+#endif
+
+        /*
+         * Microsoft doesn't sign a whole bunch of DLLs, so we have to
+         * ASSUME that a bunch of system DLLs are fine.
+         */
+        if (rc == VERR_LDRVI_NOT_SIGNED)
+            rc = supHardNtViCheckIfNotSignedOk(hLdrMod, pwszName, pNtViRdr->fFlags, rc);
+        if (RT_FAILURE(rc))
+            RTErrInfoAddF(pErrInfo, rc, ": %ls", pwszName);
+
+        /*
+         * Check for the signature checking enforcement, if requested to do so.
+         */
+        if (RT_SUCCESS(rc) && (pNtViRdr->fFlags & SUPHNTVI_F_REQUIRE_SIGNATURE_ENFORCEMENT))
+        {
+            bool fEnforced = false;
+            int rc2 = RTLdrQueryProp(hLdrMod, RTLDRPROP_SIGNATURE_CHECKS_ENFORCED, &fEnforced, sizeof(fEnforced));
+            if (RT_FAILURE(rc2))
+                rc = RTErrInfoSetF(pErrInfo, rc2, "Querying RTLDRPROP_SIGNATURE_CHECKS_ENFORCED failed on %ls: %Rrc.",
+                                   pwszName, rc2);
+            else if (!fEnforced)
+                rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_SIGNATURE_CHECKS_NOT_ENFORCED,
+                                   "The image '%ls' was not linked with /IntegrityCheck.", pwszName);
+        }
+    }
+    else
+        RTErrInfoSetF(pErrInfo, rc, "RTLdrQueryProp/RTLDRPROP_TIMESTAMP_SECONDS failed on %ls: %Rrc", pwszName, rc);
+
+#ifdef IN_RING3
+     /*
+      * Call the windows verify trust API if we've resolved it.
+      */
+     if (   g_pfnWinVerifyTrust
+         && supR3HardNtViCanCallWinVerifyTrust(pNtViRdr->hFile, pwszName))
+     {
+         if (pfCacheable)
+             *pfCacheable = g_pfnWinVerifyTrust != NULL;
+         if (rc != VERR_LDRVI_NOT_SIGNED)
+         {
+             if (rc == VINF_LDRVI_NOT_SIGNED)
+             {
+                 if (pNtViRdr->fFlags & SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION)
+                 {
+                     int rc2 = supR3HardNtViCallWinVerifyTrustCatFile(pNtViRdr->hFile, pwszName, pNtViRdr->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))
+                 rc = supR3HardNtViCallWinVerifyTrust(pNtViRdr->hFile, pwszName, pNtViRdr->fFlags, pErrInfo,
+                                                      g_pfnWinVerifyTrust);
+             else
+             {
+                 int rc2 = supR3HardNtViCallWinVerifyTrust(pNtViRdr->hFile, pwszName, pNtViRdr->fFlags, pErrInfo,
+                                                           g_pfnWinVerifyTrust);
+                 AssertMsg(RT_FAILURE_NP(rc2),
+                           ("rc=%Rrc, rc2=%Rrc %s", rc, rc2, pErrInfo ? pErrInfo->pszMsg : "<no-err-info>"));
+             }
+         }
+     }
+#else  /* !IN_RING3 */
+     if (pfCacheable)
+         *pfCacheable = true;
+#endif /* !IN_RING3 */
+
+     return rc;
+}
+
+
+/**
  * Verifies the given executable image.
  *
@@ -899,11 +1004,4 @@
     if (pfCacheable)
         *pfCacheable = false;
-
-#ifdef IN_RING3
-    /* Check that the caller has performed the necessary library initialization. */
-    if (!RTCrX509Certificate_IsPresent(&g_BuildX509Cert))
-        return RTErrInfoSet(pErrInfo, VERR_WRONG_ORDER,
-                            "supHardenedWinVerifyImageByHandle: supHardenedWinInitImageVerifier was not called.");
-#endif
 
     /*
@@ -926,103 +1024,7 @@
             /*
              * Verify it.
-             *
-             * The PKCS #7 SignedData signature is checked in the callback. Any
-             * signing certificate restrictions are also enforced there.
-             *
-             * For the time being, we use the executable timestamp as the
-             * certificate validation date.  We must query that first to avoid
-             * potential issues re-entering the loader code from the callback.
-             *
-             * Update: Save the first timestamp we validate with build cert and
-             *         use this as a minimum timestamp for further build cert
-             *         validations.  This works around issues with old DLLs that
-             *         we sign against with our certificate (crt, sdl, qt).
              */
-            rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_TIMESTAMP_SECONDS, &pNtViRdr->uTimestamp, sizeof(pNtViRdr->uTimestamp));
-            if (RT_SUCCESS(rc))
-            {
-#ifdef IN_RING3 /* Hack alert! (see above) */
-                if (   (fFlags & SUPHNTVI_F_REQUIRE_KERNEL_CODE_SIGNING)
-                    && (fFlags & SUPHNTVI_F_REQUIRE_SIGNATURE_ENFORCEMENT)
-                    && pNtViRdr->uTimestamp < g_uBuildTimestampHack)
-                    pNtViRdr->uTimestamp = g_uBuildTimestampHack;
-#endif
-
-                rc = RTLdrVerifySignature(hLdrMod, supHardNtViCallback, pNtViRdr, pErrInfo);
-
-#ifdef IN_RING3 /* Hack alert! (see above) */
-                if ((fFlags & SUPHNTVI_F_REQUIRE_BUILD_CERT) && g_uBuildTimestampHack == 0 && RT_SUCCESS(rc))
-                    g_uBuildTimestampHack = pNtViRdr->uTimestamp;
-#endif
-
-                /*
-                 * Microsoft doesn't sign a whole bunch of DLLs, so we have to
-                 * ASSUME that a bunch of system DLLs are fine.
-                 */
-                if (rc == VERR_LDRVI_NOT_SIGNED)
-                    rc = supHardNtViCheckIfNotSignedOk(hLdrMod, pwszName, fFlags, rc);
-                if (RT_FAILURE(rc))
-                    RTErrInfoAddF(pErrInfo, rc, ": %ls", pwszName);
-
-                /*
-                 * Check for the signature checking enforcement, if requested to do so.
-                 */
-                if (RT_SUCCESS(rc) && (fFlags & SUPHNTVI_F_REQUIRE_SIGNATURE_ENFORCEMENT))
-                {
-                    bool fEnforced = false;
-                    int rc2 = RTLdrQueryProp(hLdrMod, RTLDRPROP_SIGNATURE_CHECKS_ENFORCED, &fEnforced, sizeof(fEnforced));
-                    if (RT_FAILURE(rc2))
-                        rc = RTErrInfoSetF(pErrInfo, rc2, "Querying RTLDRPROP_SIGNATURE_CHECKS_ENFORCED failed on %ls: %Rrc.",
-                                           pwszName, rc2);
-                    else if (!fEnforced)
-                        rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_SIGNATURE_CHECKS_NOT_ENFORCED,
-                                           "The image '%ls' was not linked with /IntegrityCheck.", pwszName);
-                }
-            }
-            else
-                RTErrInfoSetF(pErrInfo, rc, "RTLdrQueryProp/RTLDRPROP_TIMESTAMP_SECONDS failed on %ls: %Rrc", pwszName, rc);
-
-             int rc2 = RTLdrClose(hLdrMod); AssertRC(rc2);
-
-#ifdef IN_RING3
-             /*
-              * Call the windows verify trust API if we've resolved it.
-              */
-             if (   g_pfnWinVerifyTrust
-                 && supR3HardNtViCanCallWinVerifyTrust(hFile, pwszName))
-             {
-                 if (pfCacheable)
-                     *pfCacheable = g_pfnWinVerifyTrust != NULL;
-                 if (rc != VERR_LDRVI_NOT_SIGNED)
-                 {
-                     if (rc == VINF_LDRVI_NOT_SIGNED)
-                     {
-                         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))
-                         rc = supR3HardNtViCallWinVerifyTrust(hFile, pwszName, fFlags, pErrInfo, g_pfnWinVerifyTrust);
-                     else
-                     {
-                         int rc2 = supR3HardNtViCallWinVerifyTrust(hFile, pwszName, fFlags, pErrInfo, g_pfnWinVerifyTrust);
-                         AssertMsg(RT_FAILURE_NP(rc2),
-                                   ("rc=%Rrc, rc2=%Rrc %s", rc, rc2, pErrInfo ? pErrInfo->pszMsg : "<no-err-info>"));
-                     }
-                 }
-             }
-#else
-             if (pfCacheable)
-                 *pfCacheable = true;
-#endif /* IN_RING3 */
+            rc = supHardenedWinVerifyImageByLdrMod(hLdrMod, pwszName, pNtViRdr, pfCacheable, pErrInfo);
+            int rc2 = RTLdrClose(hLdrMod); AssertRC(rc2);
         }
         else
Index: trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyProcess-win.cpp
===================================================================
--- trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyProcess-win.cpp	(revision 52192)
+++ trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyProcess-win.cpp	(revision 52204)
@@ -39,4 +39,5 @@
 #include <VBox/err.h>
 #include <iprt/ctype.h>
+#include <iprt/zero.h>
 #include <iprt/param.h>
 
@@ -108,4 +109,11 @@
     /** This may be a 32-bit resource DLL. */
     bool            f32bitResourceDll;
+
+    /** Load module associated with the image during content verfication. */
+    RTLDRMOD        hLdrMod;
+    /** The file reader. */
+    PSUPHNTVIRDR    pNtViRdr;
+    /** Image bits for lazy cleanup. */
+    uint8_t        *pbBits;
 } SUPHNTVPIMAGE;
 /** Pointer to image info from the virtual address space scan. */
@@ -117,8 +125,12 @@
 typedef struct SUPHNTVPSTATE
 {
+    /** Type of verification to perform. */
+    SUPHARDNTVPKIND         enmKind;
     /** The result. */
     int                     rcResult;
     /** Number of images in aImages. */
     uint32_t                cImages;
+    /** The process handle. */
+    HANDLE                  hProcess;
     /** Images found in the process.
      * The array is large enough to hold the executable, all allowed DLLs, and one
@@ -284,22 +296,7 @@
 
 
-static NTSTATUS supHardNtVpReadFile(HANDLE hFile, uint64_t off, void *pvBuf, size_t cbRead)
-{
-    if ((ULONG)cbRead != cbRead)
-        return STATUS_INTEGER_OVERFLOW;
-
-    IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
-    NTSTATUS rcNt = NtReadFile(hFile,
-                               NULL /*hEvent*/,
-                               NULL /*ApcRoutine*/,
-                               NULL /*ApcContext*/,
-                               &Ios,
-                               pvBuf,
-                               (ULONG)cbRead,
-                               (PLARGE_INTEGER)&off,
-                               NULL);
-    if (NT_SUCCESS(rcNt))
-        rcNt = Ios.Status;
-    return rcNt;
+static int supHardNtVpReadImage(PSUPHNTVPIMAGE pImage, uint64_t off, void *pvBuf, size_t cbRead)
+{
+    return pImage->pNtViRdr->Core.pfnRead(&pImage->pNtViRdr->Core, pvBuf, cbRead, off);
 }
 
@@ -324,24 +321,144 @@
 
 
-static int supHardNtVpFileMemCompare(PSUPHNTVPSTATE pThis, const void *pvFile, const void *pvMemory, size_t cbToCompare,
-                                     PSUPHNTVPIMAGE pImage, uint32_t uRva)
-{
-    if (suplibHardenedMemComp(pvFile, pvMemory, cbToCompare) == 0)
-        return VINF_SUCCESS;
-
-    /* Find the exact location. */
-    const uint8_t *pbFile   = (const uint8_t *)pvFile;
-    const uint8_t *pbMemory = (const uint8_t *)pvMemory;
-    while (cbToCompare > 0 && *pbFile == *pbMemory)
-    {
-        cbToCompare--;
-        pbFile++;
-        pbMemory++;
-        uRva++;
-    }
-
-    return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_MEMORY_VS_FILE_MISMATCH,
-                               "%s: memory compare at %#x failed: %#x != %#x\n", pImage->pszName, uRva, *pbFile, *pbMemory);
-}
+#ifdef IN_RING3
+static NTSTATUS supHardNtVpFileMemRestore(PSUPHNTVPSTATE pThis, PVOID pvRestoreAddr, uint8_t const *pbFile, uint32_t cbToRestore,
+                                          uint32_t fCorrectProtection)
+{
+    PVOID  pvProt   = pvRestoreAddr;
+    SIZE_T cbProt   = cbToRestore;
+    ULONG  fOldProt = 0;
+    NTSTATUS rcNt = NtProtectVirtualMemory(pThis->hProcess, &pvProt, &cbProt, PAGE_READWRITE, &fOldProt);
+    if (NT_SUCCESS(rcNt))
+    {
+        SIZE_T cbIgnored;
+        rcNt = NtWriteVirtualMemory(pThis->hProcess, pvRestoreAddr, pbFile, cbToRestore, &cbIgnored);
+
+        pvProt = pvRestoreAddr;
+        cbProt = cbToRestore;
+        NTSTATUS rcNt2 = NtProtectVirtualMemory(pThis->hProcess, &pvProt, &cbProt, fCorrectProtection, &fOldProt);
+        if (NT_SUCCESS(rcNt))
+            rcNt = rcNt2;
+    }
+    return rcNt;
+}
+#endif /* IN_RING3 */
+
+
+typedef struct SUPHNTVPSKIPAREA
+{
+    uint32_t uRva;
+    uint32_t cb;
+} SUPHNTVPSKIPAREA;
+typedef SUPHNTVPSKIPAREA *PSUPHNTVPSKIPAREA;
+
+static int supHardNtVpFileMemCompareSection(PSUPHNTVPSTATE pThis, PSUPHNTVPIMAGE pImage,
+                                            uint32_t uRva, uint32_t cb, const uint8_t *pbFile,
+                                            int32_t iSh, PSUPHNTVPSKIPAREA paSkipAreas, uint32_t cSkipAreas,
+                                            uint32_t fCorrectProtection)
+{
+    AssertCompileAdjacentMembers(SUPHNTVPSTATE, abMemory, abFile); /* Use both the memory and file buffers here. Parfait might hate me for this... */
+    uint32_t  const cbMemory = sizeof(pThis->abMemory) + sizeof(pThis->abFile);
+    uint8_t * const pbMemory = &pThis->abMemory[0];
+
+    while (cb > 0)
+    {
+        uint32_t cbThis = RT_MIN(cb, cbMemory);
+
+        /* Clipping. */
+        uint32_t uNextRva = uRva + cbThis;
+        if (cSkipAreas)
+        {
+            uint32_t uRvaEnd = uNextRva;
+            uint32_t i = cSkipAreas;
+            while (i-- > 0)
+            {
+                uint32_t uSkipEnd = paSkipAreas[i].uRva + paSkipAreas[i].cb;
+                if (   uRva    < uSkipEnd
+                    && uRvaEnd > paSkipAreas[i].uRva)
+                {
+                    if (uRva < paSkipAreas[i].uRva)
+                    {
+                        cbThis   = paSkipAreas[i].uRva - uRva;
+                        uRvaEnd  = paSkipAreas[i].uRva;
+                        uNextRva = uSkipEnd;
+                    }
+                    else if (uRvaEnd >= uSkipEnd)
+                    {
+                        cbThis  -= uSkipEnd - uRva;
+                        uRva     = uSkipEnd;
+                    }
+                    else
+                    {
+                        uNextRva = uSkipEnd;
+                        cbThis   = 0;
+                        break;
+                    }
+                }
+            }
+        }
+
+        /* Read the memory. */
+        NTSTATUS rcNt = supHardNtVpReadMem(pThis->hProcess, pImage->uImageBase + uRva, pbMemory, cbThis);
+        if (!NT_SUCCESS(rcNt))
+            return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_MEMORY_READ_ERROR,
+                                       "%s: Error reading %#x bytes at %p (rva %#x, #%u, %.8s) from memory: %#x",
+                                       pImage->pszName, cbThis, pImage->uImageBase + uRva, uRva, iSh + 1,
+                                       iSh >= 0 ? (char *)pThis->aSecHdrs[iSh].Name : "headers", rcNt);
+
+        /* Do the compare. */
+        if (memcmp(pbFile, pbMemory, cbThis) != 0)
+        {
+            const char *pachSectNm = iSh >= 0 ? (char *)pThis->aSecHdrs[iSh].Name : "headers";
+            SUP_DPRINTF(("%s: Differences in section #%u (%s) between file and memory:\n", pImage->pszName, iSh + 1, pachSectNm));
+
+            uint32_t off = 0;
+            while (off < cbThis && pbFile[off] == pbMemory[off])
+                off++;
+            SUP_DPRINTF(("  %p / %#09x: %02x != %02x\n",
+                         pImage->uImageBase + uRva + off, uRva + off, pbFile[off], pbMemory[off]));
+            uint32_t offLast = off;
+            uint32_t cDiffs  = 1;
+            for (uint32_t off2 = off + 1; off2 < cbThis; off2++)
+                if (pbFile[off2] != pbMemory[off2])
+                {
+                    SUP_DPRINTF(("  %p / %#09x: %02x != %02x\n",
+                                 pImage->uImageBase + uRva + off2, uRva + off2, pbFile[off2], pbMemory[off2]));
+                    cDiffs++;
+                    offLast = off2;
+                }
+
+#ifdef IN_RING3
+            if (   pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION
+                || pThis->enmKind == SUPHARDNTVPKIND_SELF_PURIFICATION)
+            {
+                PVOID pvRestoreAddr = (uint8_t *)pImage->uImageBase + uRva;
+                rcNt = supHardNtVpFileMemRestore(pThis, pvRestoreAddr, pbFile, cbThis, fCorrectProtection);
+                if (NT_SUCCESS(rcNt))
+                    SUP_DPRINTF(("  Restored %#x bytes of original file content at %p\n", cbThis, pvRestoreAddr));
+                else
+                    return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_MEMORY_VS_FILE_MISMATCH,
+                                               "%s: Failed to restore %#x bytes at %p (%#x, #%u, %s): %#x (cDiffs=%#x, first=%#x)",
+                                               pImage->pszName, cbThis, pvRestoreAddr, uRva, iSh + 1, pachSectNm, rcNt,
+                                               cDiffs, uRva + off);
+            }
+            else
+#endif /* IN_RING3 */
+                return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_MEMORY_VS_FILE_MISMATCH,
+                                           "%s: %u differences between %#x and %#x in #%u (%.8s), first: %02x != %02x",
+                                           pImage->pszName, cDiffs, uRva + off, uRva + offLast, iSh + 1,
+                                           pachSectNm, pbFile[off], pbMemory[off]);
+        }
+
+        /* Advance. The clipping makes it a little bit complicated. */
+        cbThis  = uNextRva - uRva;
+        if (cbThis >= cb)
+            break;
+        cb     -= cbThis;
+        pbFile += cbThis;
+        uRva    = uNextRva;
+    }
+    return VINF_SUCCESS;
+}
+
 
 
@@ -351,4 +468,7 @@
     uint32_t const cbOrg = cb;
     if (!cb)
+        return VINF_SUCCESS;
+    if (   pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION
+        || pThis->enmKind == SUPHARDNTVPKIND_SELF_PURIFICATION)
         return VINF_SUCCESS;
 
@@ -398,17 +518,15 @@
  *                              space scan.
  * @param   hProcess            Handle to the process.
- * @param   hFile               Handle to the image file.
  * @param   pErrInfo            Pointer to error info structure. Optional.
  */
-static int supHardNtVpVerifyImageCompareMemory(PSUPHNTVPSTATE pThis, PSUPHNTVPIMAGE pImage, HANDLE hProcess, HANDLE hFile,
-                                               PRTERRINFO pErrInfo)
+static int supHardNtVpVerifyImageMemoryCompare(PSUPHNTVPSTATE pThis, PSUPHNTVPIMAGE pImage, HANDLE hProcess, PRTERRINFO pErrInfo)
 {
     /*
      * Read and find the file headers.
      */
-    NTSTATUS rcNt = supHardNtVpReadFile(hFile, 0, pThis->abFile, sizeof(pThis->abFile));
-    if (!NT_SUCCESS(rcNt))
+    int rc = supHardNtVpReadImage(pImage, 0 /*off*/, pThis->abFile, sizeof(pThis->abFile));
+    if (RT_FAILURE(rc))
         return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_IMAGE_HDR_READ_ERROR,
-                                   "%s: Error reading image header: %#x", pImage->pszName, rcNt);
+                                   "%s: Error reading image header: %Rrc", pImage->pszName, rc);
 
     uint32_t offNtHdrs = 0;
@@ -473,4 +591,8 @@
                                    "%s: SizeOfImage (%#x) isn't close enough to the mapping size (%#x)",
                                    pImage->pszName, cbImage, pImage->cbImage);
+    if (cbImage != RTLdrSize(pImage->hLdrMod))
+        return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_BAD_IMAGE_SIZE,
+                                   "%s: SizeOfImage (%#x) differs from what RTLdrSize returns (%#zx)",
+                                   pImage->pszName, cbImage, RTLdrSize(pImage->hLdrMod));
 
     uint32_t const cbSectAlign = fIs32Bit ? pNtHdrs32->OptionalHeader.SectionAlignment : pNtHdrs->OptionalHeader.SectionAlignment;
@@ -501,25 +623,74 @@
 
     /*
+     * Save some header fields we might be using later on.
+     */
+    pImage->fImageCharecteristics = pNtHdrs->FileHeader.Characteristics;
+    pImage->fDllCharecteristics   = fIs32Bit ? pNtHdrs32->OptionalHeader.DllCharacteristics : pNtHdrs->OptionalHeader.DllCharacteristics;
+
+    /*
+     * Correct the apisetschema image base, size and region rva.
+     */
+    if (pImage->fApiSetSchemaOnlySection1)
+    {
+        pImage->uImageBase      -= pThis->aSecHdrs[0].VirtualAddress;
+        pImage->cbImage         += pThis->aSecHdrs[0].VirtualAddress;
+        pImage->aRegions[0].uRva = pThis->aSecHdrs[0].VirtualAddress;
+    }
+
+    /*
+     * Get relocated bits.
+     */
+    pImage->pbBits = (uint8_t *)suplibHardenedAllocZ(cbImage);
+    if (RT_UNLIKELY(!pImage->pbBits))
+        return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NO_MEMORY,
+                                   "%s: Error allocating %#x bytes for fixed up image bits.", pImage->pszName, cbImage);
+    rc = RTLdrGetBits(pImage->hLdrMod, pImage->pbBits, pImage->uImageBase, NULL /*pfnGetImport*/, pThis);
+    /**@todo resolve import when not in SUPHARDNTVPKIND_CHILD_PURIFICATION mode. */
+    if (RT_FAILURE(rc))
+        return supHardNtVpSetInfo2(pThis, rc, "%s: RTLdrGetBits failed: %Rrc", pImage->pszName, rc);
+
+    /** @todo figure out if all windows versions do this... */
+    if (fIs32Bit)
+        ((PIMAGE_NT_HEADERS32)&pImage->pbBits[offNtHdrs])->OptionalHeader.ImageBase = (uint32_t)pImage->uImageBase;
+    else
+        ((PIMAGE_NT_HEADERS)&pImage->pbBits[offNtHdrs])->OptionalHeader.ImageBase   = pImage->uImageBase;
+
+    /*
+     * Figure out areas we should skip during comparison.
+     */
+    uint32_t         cSkipAreas = 0;
+    SUPHNTVPSKIPAREA aSkipAreas[2];
+    if (pImage->fNtCreateSectionPatch)
+    {
+        RTLDRADDR uValue;
+        if (pThis->enmKind == SUPHARDNTVPKIND_VERIFY_ONLY)
+        {
+            /* Ignore our NtCreateSection hack. */
+            rc = RTLdrGetSymbolEx(pImage->hLdrMod, pImage->pbBits, 0, "NtCreateSection", &uValue);
+            if (RT_FAILURE(rc))
+                return supHardNtVpSetInfo2(pThis, rc, "%s: Failed to find 'NtCreateSection': %Rrc", pImage->pszName, rc);
+            aSkipAreas[cSkipAreas].uRva = (uint32_t)uValue;
+            aSkipAreas[cSkipAreas++].cb = 16;
+        }
+
+        /* LdrSystemDllInitBlock is filled in by the kernel. It mainly contains addresses of 32-bit ntdll method for wow64. */
+        rc = RTLdrGetSymbolEx(pImage->hLdrMod, pImage->pbBits, 0, "LdrSystemDllInitBlock", &uValue);
+        if (RT_SUCCESS(rc))
+        {
+            aSkipAreas[cSkipAreas].uRva = (uint32_t)uValue;
+            aSkipAreas[cSkipAreas++].cb = RT_MAX(pImage->pbBits[(uint32_t)uValue], 0x50);
+        }
+    }
+
+    /*
      * Compare the file header with the loaded bits.  The loader will fiddle
      * with image base, changing it to the actual load address.
      */
-    int rc;
     if (!pImage->fApiSetSchemaOnlySection1)
     {
-        rcNt = supHardNtVpReadMem(hProcess, pImage->uImageBase, pThis->abMemory, cbHdrsFile);
-        if (!NT_SUCCESS(rcNt))
-            return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_MEMORY_READ_ERROR,
-                                       "%s: Error reading image header from memory: %#x", pImage->pszName, rcNt);
-        if (uImageBase != pImage->uImageBase)
-        {
-            if (fIs32Bit)
-                pNtHdrs32->OptionalHeader.ImageBase = (uint32_t)pImage->uImageBase;
-            else
-                pNtHdrs->OptionalHeader.ImageBase = pImage->uImageBase;
-        }
-
-        rc = supHardNtVpFileMemCompare(pThis, pThis->abFile, pThis->abMemory, cbHeaders, pImage, 0 /*uRva*/);
+        rc = supHardNtVpFileMemCompareSection(pThis, pImage, 0 /*uRva*/, cbHdrsFile, pImage->pbBits, -1, NULL, 0, PAGE_READONLY);
         if (RT_FAILURE(rc))
             return rc;
+
         rc = supHardNtVpCheckSectionProtection(pThis, pImage, 0 /*uRva*/, cbHdrsFile, PAGE_READONLY);
         if (RT_FAILURE(rc))
@@ -528,13 +699,10 @@
 
     /*
-     * Save some header fields we might be using later on.
-     */
-    pImage->fImageCharecteristics = pNtHdrs->FileHeader.Characteristics;
-    pImage->fDllCharecteristics   = fIs32Bit ? pNtHdrs32->OptionalHeader.DllCharacteristics : pNtHdrs->OptionalHeader.DllCharacteristics;
-
-    /*
-     * Validate sections and check them against the mapping regions.
-     */
-    uint32_t uRva = cbHdrsFile;
+     * Validate sections:
+     *      - Check them against the mapping regions.
+     *      - Check section bits according to enmKind.
+     */
+    uint32_t fPrevProt = PAGE_READONLY;
+    uint32_t uRva      = cbHdrsFile;
     for (uint32_t i = 0; i < cSections; i++)
     {
@@ -556,14 +724,7 @@
                                        pImage->pszName, i, cbFile, cbMap, uSectRva);
 
-        /* Validate the protection. */
+        /* Validate the protection and bits. */
         if (!pImage->fApiSetSchemaOnlySection1 || i == 0)
         {
-            if (pImage->fApiSetSchemaOnlySection1)
-            {
-                pImage->uImageBase -= uSectRva;
-                pImage->cbImage    += uSectRva;
-                pImage->aRegions[i].uRva = uSectRva;
-            }
-
             uint32_t fProt;
             switch (pThis->aSecHdrs[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE))
@@ -587,9 +748,35 @@
                                                "%s: Section %u: Unexpected characteristics: %#x (uSectRva=%#x, cbMap=%#x)",
                                                pImage->pszName, i, pThis->aSecHdrs[i].Characteristics, uSectRva, cbMap);
-
             }
+
+            /* The section bits, only child purification verifies all bits . */
+            if (   pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION
+                || (pThis->aSecHdrs[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE)) )
+            {
+                rc = VINF_SUCCESS;
+                if (uRva < uSectRva && !pImage->fApiSetSchemaOnlySection1) /* Any gap worth checking? */
+                    rc = supHardNtVpFileMemCompareSection(pThis, pImage, uRva, uSectRva - uRva, pImage->pbBits + uRva,
+                                                          i - 1, NULL, 0, fPrevProt);
+                if (RT_SUCCESS(rc))
+                    rc = supHardNtVpFileMemCompareSection(pThis, pImage, uSectRva, cbMap, pImage->pbBits + uSectRva,
+                                                          i, aSkipAreas, cSkipAreas, fProt);
+                if (RT_SUCCESS(rc))
+                {
+                    uint32_t cbMapAligned = i + 1 < cSections && !pImage->fApiSetSchemaOnlySection1
+                                          ? RT_ALIGN_32(cbMap, cbSectAlign) : RT_ALIGN_32(cbMap, PAGE_SIZE);
+                    if (cbMapAligned > cbMap)
+                        rc = supHardNtVpFileMemCompareSection(pThis, pImage, uSectRva + cbMap, cbMapAligned - cbMap,
+                                                              g_abRTZeroPage, i, NULL, 0, fProt);
+                }
+                if (RT_FAILURE(rc))
+                    return rc;
+            }
+
+            /* The protection (must be checked afterwards!). */
             rc = supHardNtVpCheckSectionProtection(pThis, pImage, uSectRva, RT_ALIGN_32(cbMap, PAGE_SIZE), fProt);
             if (RT_FAILURE(rc))
                 return rc;
+
+            fPrevProt = fProt;
         }
 
@@ -597,19 +784,4 @@
         uRva = uSectRva + RT_ALIGN_32(cbMap, cbSectAlign);
     }
-
-    /*
-     * Check the mapping regions with the image to make sure someone didn't
-     * fill executable code into some gap in the image.
-     */
-    /** @todo not vital. */
-
-
-    /*
-     * Compare executable code.  If we're not loaded at the link address, we
-     * need to load base relocations and apply them while making the compare.
-     * A special case
-     */
-    /** @todo not vital. */
-
 
     return VINF_SUCCESS;
@@ -632,50 +804,24 @@
 {
     /*
-     * Open the image.
-     */
-    HANDLE              hFile = RTNT_INVALID_HANDLE_VALUE;
-    IO_STATUS_BLOCK     Ios   = RTNT_IO_STATUS_BLOCK_INITIALIZER;
-
-    OBJECT_ATTRIBUTES   ObjAttr;
-    InitializeObjectAttributes(&ObjAttr, &pImage->Name.UniStr, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
-#ifdef IN_RING0
-    ObjAttr.Attributes |= OBJ_KERNEL_HANDLE;
-#endif
-
-    NTSTATUS rcNt = NtCreateFile(&hFile,
-                                 GENERIC_READ,
-                                 &ObjAttr,
-                                 &Ios,
-                                 NULL /* Allocation Size*/,
-                                 FILE_ATTRIBUTE_NORMAL,
-                                 FILE_SHARE_READ,
-                                 FILE_OPEN,
-                                 FILE_NON_DIRECTORY_FILE,
-                                 NULL /*EaBuffer*/,
-                                 0 /*EaLength*/);
-    if (NT_SUCCESS(rcNt))
-        rcNt = Ios.Status;
-    if (!NT_SUCCESS(rcNt))
-        return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_IMAGE_FILE_OPEN_ERROR,
-                                  "Error opening image for scanning: %#x (name %ls)", rcNt, pImage->Name.UniStr.Buffer);
-
-    /*
-     * Validate the signature, then make an attempt at comparing memory and
-     * disk content.
-     */
-    uint32_t fFlags = pImage->fDll ? 0 : SUPHNTVI_F_REQUIRE_BUILD_CERT;
-    if (pImage->f32bitResourceDll)
-        fFlags |= SUPHNTVI_F_RESOURCE_IMAGE;
-    int rc = supHardenedWinVerifyImageByHandle(hFile, pImage->Name.UniStr.Buffer, fFlags, NULL /*pfCacheable*/, pThis->pErrInfo);
-    if (RT_SUCCESS(rc))
-        rc = supHardNtVpVerifyImageCompareMemory(pThis, pImage, hProcess, hFile, pThis->pErrInfo);
-
-    /*
-     * Clean up and return.
-     */
-    rcNt = NtClose(hFile);
-    if (!NT_SUCCESS(rcNt) && RT_SUCCESS(rc))
-        rc = supHardNtVpSetInfo2(pThis, VERR_SUP_VP_IMAGE_FILE_CLOSE_ERROR,
-                                "Error closing image after scanning: %#x (name %ls)", rcNt, pImage->Name.UniStr.Buffer);
+     * Validate the file signature first, then do the memory compare.
+     */
+    int rc;
+    if (pImage->hLdrMod != NIL_RTLDRMOD)
+    {
+        rc = supHardenedWinVerifyImageByLdrMod(pImage->hLdrMod, pImage->Name.UniStr.Buffer, pImage->pNtViRdr,
+                                               NULL /*pfCacheable*/, pThis->pErrInfo);
+        if (RT_SUCCESS(rc))
+        {
+            rc = supHardNtVpVerifyImageMemoryCompare(pThis, pImage, hProcess, pThis->pErrInfo);
+
+            if (pImage->pbBits)
+            {
+                suplibHardenedFree(pImage->pbBits);
+                pImage->pbBits = NULL;
+            }
+        }
+    }
+    else
+        rc = supHardNtVpSetInfo2(pThis, VERR_OPEN_FAILED, "hLdrMod is NIL! Impossible!");
     return rc;
 }
@@ -740,28 +886,4 @@
 }
 #endif /* !VBOX_WITHOUT_DEBUGGER_CHECKS */
-
-
-/**
- * Allocates and initalizes a process stat structure for process virtual memory
- * scanning.
- *
- * @returns Pointer to the state structure on success, NULL on failure.
- * @param   pErrInfo            Pointer to error info structure. Optional.
- */
-static PSUPHNTVPSTATE supHardNtVpCreateState(PRTERRINFO pErrInfo)
-{
-    /*
-     * Allocate the memory.
-     */
-    PSUPHNTVPSTATE pThis = (PSUPHNTVPSTATE)suplibHardenedAllocZ(sizeof(*pThis));
-    if (pThis)
-    {
-        pThis->rcResult = VINF_SUCCESS;
-        pThis->pErrInfo = pErrInfo;
-        return pThis;
-    }
-    supHardNtVpSetInfo1(pErrInfo, VERR_NO_MEMORY, "Failed to allocate %zu bytes for state structures.", sizeof(*pThis));
-    return NULL;
-}
 
 
@@ -909,4 +1031,14 @@
 
     /*
+     * Checks for multiple mappings of the same DLL but with different image file paths.
+     */
+    uint32_t i = pThis->cImages;
+    while (i-- > 1)
+        if (pImage->pszName == pThis->aImages[i].pszName)
+            return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_DUPLICATE_DLL_MAPPING,
+                                       "Duplicate image entries for %s: %ls and %ls",
+                                       pImage->pszName, pImage->Name.UniStr.Buffer, pThis->aImages[i].Name.UniStr.Buffer);
+
+    /*
      * Since it's a new image, we expect to be at the start of the mapping now.
      */
@@ -928,8 +1060,19 @@
     pImage->uImageBase = (uintptr_t)pMemInfo->AllocationBase;
     pImage->cbImage    = pMemInfo->RegionSize;
+    pImage->hLdrMod    = NIL_RTLDRMOD;
+    pImage->pNtViRdr   = NULL;
     pImage->cRegions   = 1;
     pImage->aRegions[0].uRva    = 0;
     pImage->aRegions[0].cb      = (uint32_t)pMemInfo->RegionSize;
     pImage->aRegions[0].fProt   = pMemInfo->Protect;
+
+    if (suplibHardenedStrCmp(pImage->pszName, "ntdll.dll") == 0)
+        pImage->fNtCreateSectionPatch = true;
+    else if (suplibHardenedStrCmp(pImage->pszName, "apisetschema.dll") == 0)
+        pImage->fApiSetSchemaOnlySection1 = true; /** @todo Check the ApiSetMap field in the PEB. */
+#ifdef VBOX_PERMIT_MORE
+    else if (suplibHardenedStrCmp(pImage->pszName, "acres.dll") == 0)
+        pImage->f32bitResourceDll = true;
+#endif
 
     return VINF_SUCCESS;
@@ -980,4 +1123,5 @@
     pImage->cbImage = pImage->aRegions[iRegion].uRva + pImage->aRegions[iRegion].cb;
     pImage->cRegions++;
+    pImage->fApiSetSchemaOnlySection1 = false;
 
     return VINF_SUCCESS;
@@ -998,5 +1142,7 @@
 static int supHardNtVpScanVirtualMemory(PSUPHNTVPSTATE pThis, HANDLE hProcess)
 {
-    SUP_DPRINTF(("supHardNtVpScanVirtualMemory:\n"));
+    SUP_DPRINTF(("supHardNtVpScanVirtualMemory: enmKind=%s\n",
+                 pThis->enmKind == SUPHARDNTVPKIND_VERIFY_ONLY ? "VERIFY_ONLY" :
+                 pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION ? "CHILD_PURIFICATION" : "SELF_PURIFICATION"));
 
     uint32_t    cXpExceptions = 0;
@@ -1101,21 +1247,67 @@
         else if (MemInfo.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY))
         {
-            supHardNtVpSetInfo2(pThis, VERR_SUP_VP_FOUND_EXEC_MEMORY,
-                                "Found executable memory at %p (%p LB %#zx): type=%#x prot=%#x state=%#x aprot=%#x abase=%p",
-                                uPtrWhere,
-                                MemInfo.BaseAddress,
-                                MemInfo.RegionSize,
-                                MemInfo.Type,
-                                MemInfo.Protect,
-                                MemInfo.State,
-                                MemInfo.AllocationBase,
-                                MemInfo.AllocationProtect);
+            SUP_DPRINTF((MemInfo.AllocationBase == MemInfo.BaseAddress
+                         ? " *%p-%p %#06x/%#06x %#09x !!\n"
+                         : "  %p-%p %#06x/%#06x %#09x !!\n",
+                         MemInfo.BaseAddress, (uintptr_t)MemInfo.BaseAddress - MemInfo.RegionSize - 1,
+                         MemInfo.Protect, MemInfo.AllocationProtect, MemInfo.Type));
 # ifdef IN_RING3
+            if (pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION)
+            {
+                /*
+                 * Free any private executable memory (sysplant.sys allocates executable memory).
+                 */
+                if (MemInfo.Type == MEM_PRIVATE)
+                {
+                    SUP_DPRINTF(("supHardNtVpScanVirtualMemory: Freeing exec mem at %p (%p LB %#zx)\n",
+                                 uPtrWhere, MemInfo.BaseAddress, MemInfo.RegionSize));
+                    PVOID   pvFree = MemInfo.BaseAddress;
+                    SIZE_T  cbFree = MemInfo.RegionSize;
+                    rcNt = NtFreeVirtualMemory(pThis->hProcess, &pvFree, &cbFree, MEM_RELEASE);
+                    if (!NT_SUCCESS(rcNt))
+                        supHardNtVpSetInfo2(pThis, VERR_GENERAL_FAILURE,
+                                            "NtFreeVirtualMemory (%p LB %#zx) failed: %#x",
+                                            MemInfo.BaseAddress, MemInfo.RegionSize, rcNt);
+                }
+                /*
+                 * Unmap mapped memory, failing that, drop exec privileges.
+                 */
+                else if (MemInfo.Type == MEM_MAPPED)
+                {
+                    SUP_DPRINTF(("supHardNtVpScanVirtualMemory: Unmapping exec mem at %p (%p/%p LB %#zx)\n",
+                                 uPtrWhere, MemInfo.AllocationBase, MemInfo.BaseAddress, MemInfo.RegionSize));
+                    rcNt = NtUnmapViewOfSection(pThis->hProcess, MemInfo.AllocationBase);
+                    if (!NT_SUCCESS(rcNt))
+                    {
+                        PVOID  pvCopy = MemInfo.BaseAddress;
+                        SIZE_T cbCopy = MemInfo.RegionSize;
+                        NTSTATUS rcNt2 = NtProtectVirtualMemory(pThis->hProcess, &pvCopy, &cbCopy, PAGE_NOACCESS, NULL);
+                        if (!NT_SUCCESS(rcNt2))
+                            rcNt2 = NtProtectVirtualMemory(pThis->hProcess, &pvCopy, &cbCopy, PAGE_READONLY, NULL);
+                        if (!NT_SUCCESS(rcNt2))
+                            supHardNtVpSetInfo2(pThis, VERR_GENERAL_FAILURE,
+                                                "NtUnmapViewOfSection (%p/%p LB %#zx) failed: %#x (%#x)",
+                                                MemInfo.AllocationBase, MemInfo.BaseAddress, MemInfo.RegionSize, rcNt, rcNt2);
+                    }
+                }
+                else
+                    supHardNtVpSetInfo2(pThis, VERR_GENERAL_FAILURE,
+                                        "Unknown executable memory type %#x at %p/%p LB %#zx",
+                                        MemInfo.Type, MemInfo.AllocationBase, MemInfo.BaseAddress, MemInfo.RegionSize);
+            }
+            else
+# endif /* IN_RING3 */
+                supHardNtVpSetInfo2(pThis, VERR_SUP_VP_FOUND_EXEC_MEMORY,
+                                    "Found executable memory at %p (%p LB %#zx): type=%#x prot=%#x state=%#x aprot=%#x abase=%p",
+                                    uPtrWhere, MemInfo.BaseAddress, MemInfo.RegionSize, MemInfo.Type, MemInfo.Protect,
+                                    MemInfo.State, MemInfo.AllocationBase, MemInfo.AllocationProtect);
+
+# ifndef IN_RING3
+            if (RT_FAILURE(pThis->rcResult))
+                return pThis->rcResult;
+# endif
             /* Continue add more information about the problematic process. */
-# else
-            return pThis->rcResult;
-# endif
-        }
-#endif
+        }
+#endif /* VBOX_PERMIT_VISUAL_STUDIO_PROFILING */
         else
             SUP_DPRINTF((MemInfo.AllocationBase == MemInfo.BaseAddress
@@ -1137,4 +1329,82 @@
     return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_TOO_MANY_MEMORY_REGIONS,
                                "Too many virtual memory regions.\n");
+}
+
+/**
+ * Opens all the images with the IPRT loader, setting both pNtViRdr and hLdrMod
+ * for each image.
+ *
+ * @returns VBox status code.
+ * @param   pThis               The process scanning state structure.
+ */
+static int supHardNtVpOpenImages(PSUPHNTVPSTATE pThis)
+{
+    unsigned i = pThis->cImages;
+    while (i-- > 0)
+    {
+        PSUPHNTVPIMAGE pImage = &pThis->aImages[i];
+
+        /*
+         * Open the image file.
+         */
+        HANDLE              hFile = RTNT_INVALID_HANDLE_VALUE;
+        IO_STATUS_BLOCK     Ios   = RTNT_IO_STATUS_BLOCK_INITIALIZER;
+
+        OBJECT_ATTRIBUTES   ObjAttr;
+        InitializeObjectAttributes(&ObjAttr, &pImage->Name.UniStr, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
+#ifdef IN_RING0
+        ObjAttr.Attributes |= OBJ_KERNEL_HANDLE;
+#endif
+
+        NTSTATUS rcNt = NtCreateFile(&hFile,
+                                     GENERIC_READ,
+                                     &ObjAttr,
+                                     &Ios,
+                                     NULL /* Allocation Size*/,
+                                     FILE_ATTRIBUTE_NORMAL,
+                                     FILE_SHARE_READ,
+                                     FILE_OPEN,
+                                     FILE_NON_DIRECTORY_FILE,
+                                     NULL /*EaBuffer*/,
+                                     0 /*EaLength*/);
+        if (NT_SUCCESS(rcNt))
+            rcNt = Ios.Status;
+        if (!NT_SUCCESS(rcNt))
+            return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_IMAGE_FILE_OPEN_ERROR,
+                                      "Error opening image for scanning: %#x (name %ls)", rcNt, pImage->Name.UniStr.Buffer);
+
+        /*
+         * Figure out validation flags we'll be using and create the reader
+         * for this image.
+         */
+        uint32_t fFlags = pImage->fDll ? 0 : SUPHNTVI_F_REQUIRE_BUILD_CERT;
+        if (pImage->f32bitResourceDll)
+            fFlags |= SUPHNTVI_F_RESOURCE_IMAGE;
+
+        PSUPHNTVIRDR pNtViRdr;
+        int rc = supHardNtViRdrCreate(hFile, pImage->Name.UniStr.Buffer, fFlags, &pNtViRdr);
+        if (RT_FAILURE(rc))
+        {
+            NtClose(hFile);
+            return rc;
+        }
+        pImage->pNtViRdr = pNtViRdr;
+
+        /*
+         * Finally, open the image with the laoder.
+         */
+        RTLDRMOD hLdrMod;
+        RTLDRARCH enmArch = fFlags & SUPHNTVI_F_RC_IMAGE ? RTLDRARCH_X86_32 : RTLDRARCH_HOST;
+        if (fFlags & SUPHNTVI_F_RESOURCE_IMAGE)
+            enmArch = RTLDRARCH_WHATEVER;
+        rc = RTLdrOpenWithReader(&pNtViRdr->Core, RTLDR_O_FOR_VALIDATION, enmArch, &hLdrMod, pThis->pErrInfo);
+        if (RT_FAILURE(rc))
+            return supHardNtVpSetInfo2(pThis, rc, "RTLdrOpenWithReader failed: %Rrc (Image='%ls').",
+                                       rc, pImage->Name.UniStr.Buffer);
+
+        pImage->hLdrMod = hLdrMod;
+    }
+
+    return VINF_SUCCESS;
 }
 
@@ -1256,5 +1526,5 @@
 {
     /*
-     * Check for duplicate entries.
+     * Check for duplicate entries (paranoia).
      */
     uint32_t i = pThis->cImages;
@@ -1276,5 +1546,4 @@
     uint32_t iNtDll    = UINT32_MAX;
     uint32_t iKernel32 = UINT32_MAX;
-    uint32_t iApiSetSchema = UINT32_MAX;
     i = pThis->cImages;
     while (i-- > 0)
@@ -1283,17 +1552,13 @@
         else if (suplibHardenedStrCmp(pThis->aImages[i].pszName, "kernel32.dll") == 0)
             iKernel32 = i;
-        else if (suplibHardenedStrCmp(pThis->aImages[i].pszName, "apisetschema.dll") == 0)
-            iApiSetSchema = i;
-#ifdef VBOX_PERMIT_MORE
-        else if (suplibHardenedStrCmp(pThis->aImages[i].pszName, "acres.dll") == 0)
-            pThis->aImages[i].f32bitResourceDll = true;
-#endif
     if (iNtDll == UINT32_MAX)
         return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NO_NTDLL_MAPPING,
                                    "The process has no NTDLL.DLL.");
-    if (iKernel32 == UINT32_MAX)
+    if (iKernel32 == UINT32_MAX && pThis->enmKind != SUPHARDNTVPKIND_CHILD_PURIFICATION)
         return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NO_KERNEL32_MAPPING,
                                    "The process has no KERNEL32.DLL.");
-
+    else if (iKernel32 != UINT32_MAX && pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION)
+        return supHardNtVpSetInfo2(pThis, VERR_GENERAL_FAILURE,
+                                   "The process already has KERNEL32.DLL loaded.");
 
     /*
@@ -1303,7 +1568,4 @@
     while (i-- > 0)
     {
-        pThis->aImages[i].fNtCreateSectionPatch     = i == iNtDll;
-        pThis->aImages[i].fApiSetSchemaOnlySection1 = i == iApiSetSchema && pThis->aImages[i].cRegions == 1;
-
         int rc = supHardNtVpVerifyImage(pThis, &pThis->aImages[i], hProcess);
         if (RT_FAILURE(rc))
@@ -1332,8 +1594,13 @@
  * @param   hProcess            The process to verify.
  * @param   hThread             A thread in the process (the caller).
+ * @param   enmKind             The kind of process verification to perform.
  * @param   pErrInfo            Pointer to error info structure. Optional.
  */
-DECLHIDDEN(int) supHardenedWinVerifyProcess(HANDLE hProcess, HANDLE hThread, PRTERRINFO pErrInfo)
-{
+DECLHIDDEN(int) supHardenedWinVerifyProcess(HANDLE hProcess, HANDLE hThread, SUPHARDNTVPKIND enmKind, PRTERRINFO pErrInfo)
+{
+    /*
+     * Some basic checks regarding threads and debuggers. We don't need
+     * allocate any state memory for these.
+     */
     int rc = supHardNtVpThread(hProcess, hThread, pErrInfo);
 #ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
@@ -1343,8 +1610,21 @@
     if (RT_SUCCESS(rc))
     {
-        PSUPHNTVPSTATE pThis = supHardNtVpCreateState(pErrInfo);
+        /*
+         * Allocate and initialize memory for the state.
+         */
+        PSUPHNTVPSTATE pThis = (PSUPHNTVPSTATE)suplibHardenedAllocZ(sizeof(*pThis));
         if (pThis)
         {
+            pThis->enmKind  = enmKind;
+            pThis->rcResult = VINF_SUCCESS;
+            pThis->hProcess = hProcess;
+            pThis->pErrInfo = pErrInfo;
+
+            /*
+             * Perform the verification.
+             */
             rc = supHardNtVpScanVirtualMemory(pThis, hProcess);
+            if (RT_SUCCESS(rc))
+                rc = supHardNtVpOpenImages(pThis);
             if (RT_SUCCESS(rc))
                 rc = supHardNtVpCheckExe(pThis, hProcess);
@@ -1352,8 +1632,19 @@
                 rc = supHardNtVpCheckDlls(pThis, hProcess);
 
+            /*
+             * Clean up the state.
+             */
+            for (uint32_t i = 0; i < pThis->cImages; i++)
+            {
+                if (pThis->aImages[i].hLdrMod != NIL_RTLDRMOD)
+                    RTLdrClose(pThis->aImages[i].hLdrMod);
+                else if (pThis->aImages[i].pNtViRdr)
+                    pThis->aImages[i].pNtViRdr->Core.pfnDestroy(&pThis->aImages[i].pNtViRdr->Core);
+            }
             suplibHardenedFree(pThis);
         }
         else
-            rc = VERR_SUP_VP_NO_MEMORY_STATE;
+            rc = supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_NO_MEMORY_STATE,
+                                     "Failed to allocate %zu bytes for state structures.", sizeof(*pThis));
     }
     return rc;
Index: trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp
===================================================================
--- trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp	(revision 52192)
+++ trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp	(revision 52204)
@@ -45,4 +45,5 @@
 #include <iprt/initterm.h>
 #include <iprt/param.h>
+#include <iprt/path.h>
 #include <iprt/zero.h>
 
@@ -50,4 +51,8 @@
 #include "win/SUPHardenedVerify-win.h"
 #include "../SUPDrvIOC.h"
+
+#ifndef IMAGE_SCN_TYPE_NOLOAD
+# define IMAGE_SCN_TYPE_NOLOAD 0x00000002
+#endif
 
 
@@ -58,10 +63,10 @@
  * This just needs to be unique enough to avoid most confusion with real
  * executable names,  there are other checks in place to make sure we've respanwed. */
-#define SUPR3_RESPAWN_1_ARG0  "81954AF5-4D2F-31EB-A142-B7AF187A1C41-suplib-2ndchild"
+#define SUPR3_RESPAWN_1_ARG0  "0384ad8f-4f0c-d002-e3ae-5597cd55af98-suplib-2ndchild"
 
 /** The first argument of a respawed stub when respawned for the second time.
  * This just needs to be unique enough to avoid most confusion with real
  * executable names,  there are other checks in place to make sure we've respanwed. */
-#define SUPR3_RESPAWN_2_ARG0  "81954AF5-4D2F-31EB-A142-B7AF187A1C41-suplib-3rdchild"
+#define SUPR3_RESPAWN_2_ARG0  "0384ad8f-4f0c-d002-e3ae-5597cd55af98-suplib-3rdchild"
 
 /** Unconditional assertion. */
@@ -962,5 +967,6 @@
     /*
      * Install a anti debugging hack before we continue.  This prevents most
-     * notifications from ending up in the debugger.
+     * notifications from ending up in the debugger. (Also applied to the
+     * child process when respawning.)
      */
     rcNt = NtSetInformationThread(NtCurrentThread(), ThreadHideFromDebugger, NULL, 0);
@@ -1173,5 +1179,6 @@
 {
     RTErrInfoInitStatic(&g_ErrInfoStatic);
-    int rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), &g_ErrInfoStatic.Core);
+    int rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(),
+                                         SUPHARDNTVPKIND_VERIFY_ONLY, &g_ErrInfoStatic.Core);
     if (RT_FAILURE(rc))
         supR3HardenedFatalMsg("supR3HardenedWinVerifyProcess", kSupInitOp_Integrity, rc,
@@ -1730,305 +1737,4 @@
     if (!NT_SUCCESS(rcNt))
         return RTErrInfoSetF(pThis->pErrInfo, VERR_GENERAL_FAILURE, "NtWriteVirtualMemory/Peb failed: %#x", rcNt);
-
-    return VINF_SUCCESS;
-}
-
-
-DECLINLINE(PIMAGE_NT_HEADERS) supR3HardNtPuChFindNtHeaders(uint8_t *pbBuf, size_t cbBuf)
-{
-    PIMAGE_DOS_HEADER pMzHdr = (PIMAGE_DOS_HEADER)pbBuf;
-    if (cbBuf >= sizeof(*pMzHdr))
-    {
-        if (pMzHdr->e_magic == IMAGE_DOS_SIGNATURE)
-        {
-            if (pMzHdr->e_lfanew >= cbBuf)
-                return NULL;
-            cbBuf -= pMzHdr->e_lfanew;
-            pbBuf += pMzHdr->e_lfanew;
-        }
-    }
-
-    PIMAGE_NT_HEADERS pNtHdrs = (PIMAGE_NT_HEADERS)pbBuf;
-    if (cbBuf >= sizeof(IMAGE_NT_HEADERS))
-    {
-        if (pNtHdrs->Signature == IMAGE_NT_SIGNATURE)
-            return pNtHdrs;
-    }
-    return NULL;
-}
-
-
-static uint32_t supR3HardNtPuChFindFirstDiff(void const *pvBuf1, void const *pvBuf2, size_t cbBuf)
-{
-    uint8_t const *pabBuf1 = (uint8_t const *)pvBuf1;
-    uint8_t const *pabBuf2 = (uint8_t const *)pvBuf2;
-    uint32_t off = 0;
-    while (off < cbBuf && pabBuf1[off] == pabBuf2[off])
-        off++;
-    return off;
-}
-
-
-static NTSTATUS supR3HardNtPuChRestoreImageBits(PSUPR3HARDNTPUCH pThis, PVOID pvChildAddr,
-                                                void const *pvFileBits, size_t cbToRestore, uint32_t fCorrectProtection)
-{
-    PVOID  pvProt   = pvChildAddr;
-    SIZE_T cbProt   = cbToRestore;
-    ULONG  fOldProt = 0;
-    NTSTATUS rcNt = NtProtectVirtualMemory(pThis->hProcess, &pvProt, &cbProt, PAGE_READWRITE, &fOldProt);
-    if (NT_SUCCESS(rcNt))
-    {
-        SIZE_T cbIgnored;
-        rcNt = NtWriteVirtualMemory(pThis->hProcess, pvChildAddr, pvFileBits, cbToRestore, &cbIgnored);
-
-        pvProt = pvChildAddr;
-        cbProt = cbToRestore;
-        NTSTATUS rcNt2 = NtProtectVirtualMemory(pThis->hProcess, &pvProt, &cbProt, fCorrectProtection, &fOldProt);
-        if (NT_SUCCESS(rcNt))
-            rcNt = rcNt2;
-    }
-    return rcNt;
-}
-
-
-static int supR3HardNtPuChSanitizeImage(PSUPR3HARDNTPUCH pThis, PMEMORY_BASIC_INFORMATION pMemInfo)
-{
-    /*
-     * Get the image name.
-     */
-    union
-    {
-        UNICODE_STRING UniStr;
-        uint8_t abPadding[4096];
-    } uBuf;
-    SIZE_T cbActual;
-    NTSTATUS rcNt = NtQueryVirtualMemory(pThis->hProcess,
-                                         pMemInfo->BaseAddress,
-                                         MemorySectionName,
-                                         &uBuf,
-                                         sizeof(uBuf) - sizeof(WCHAR),
-                                         &cbActual);
-    if (!NT_SUCCESS(rcNt))
-        return RTErrInfoSetF(pThis->pErrInfo, VERR_GENERAL_FAILURE,
-                             "NtQueryVirtualMemory/MemorySectionName failed for %p: %#x", pMemInfo->BaseAddress, rcNt);
-    uBuf.UniStr.Buffer[uBuf.UniStr.Length / sizeof(WCHAR)] = '\0';
-    SUP_DPRINTF(("supR3HardNtPuChSanitizeImage: %p '%ls'\n", pMemInfo->BaseAddress, uBuf.UniStr.Buffer));
-
-
-    /*
-     * Open the file.
-     */
-    HANDLE              hFile = RTNT_INVALID_HANDLE_VALUE;
-    IO_STATUS_BLOCK     Ios   = RTNT_IO_STATUS_BLOCK_INITIALIZER;
-
-    OBJECT_ATTRIBUTES ObjAttr;
-    InitializeObjectAttributes(&ObjAttr, &uBuf.UniStr, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
-
-    rcNt = NtCreateFile(&hFile,
-                        FILE_READ_DATA | SYNCHRONIZE,
-                        &ObjAttr,
-                        &Ios,
-                        NULL /* Allocation Size*/,
-                        FILE_ATTRIBUTE_NORMAL,
-                        FILE_SHARE_READ,
-                        FILE_OPEN,
-                        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
-                        NULL /*EaBuffer*/,
-                        0 /*EaLength*/);
-    if (NT_SUCCESS(rcNt))
-        rcNt = Ios.Status;
-    if (!NT_SUCCESS(rcNt))
-        return RTErrInfoSetF(pThis->pErrInfo, RTErrConvertFromNtStatus(rcNt),
-                             "NtCreateFile returned %#x opening '%ls'.", rcNt, uBuf.UniStr.Buffer);
-
-    /*
-     * Read the headers, ASSUMES the stub isn't pushing the optional header out
-     * of a 4KB buffer.  Also ASSUMEs that the file is more than 4KB in size.
-     */
-    int             rc;
-    uint8_t         abFile[_4K];
-    LARGE_INTEGER   off;
-    off.QuadPart = 0;
-    rcNt = NtReadFile(hFile, NULL, NULL, NULL, &Ios, abFile, sizeof(abFile), &off, NULL);
-    if (NT_SUCCESS(rcNt))
-        rcNt = Ios.Status;
-    if (NT_SUCCESS(rcNt))
-    {
-        PIMAGE_NT_HEADERS pNtFile = supR3HardNtPuChFindNtHeaders(abFile, sizeof(abFile));
-        if (pNtFile)
-        {
-            /*
-             * Read the first 4KB of the process memory.
-             */
-            uint8_t abProc[_4K];
-            SIZE_T cbActualMem;
-            rcNt = NtReadVirtualMemory(pThis->hProcess, pMemInfo->BaseAddress, abProc, sizeof(abProc), &cbActualMem);
-            if (NT_SUCCESS(rcNt))
-            {
-                /*
-                 * Watch out for apisetschema.dll, it only has section #1
-                 * mapped into the process.
-                 */
-                if (   g_uNtVerCombined < SUP_NT_VER_W70
-                    || pThis->Peb.Diff3.W7.ApiSetMap != pMemInfo->BaseAddress
-                    || !supR3HardNtIsNamedSystem32Dll(&uBuf.UniStr, "apisetschema.dll"))
-                {
-                    PIMAGE_NT_HEADERS pNtProc = supR3HardNtPuChFindNtHeaders(abProc, sizeof(abProc));
-                    if ((uintptr_t)pNtProc - (uintptr_t)abProc == (uintptr_t)pNtFile - (uintptr_t)abFile)
-                    {
-                        pNtFile->OptionalHeader.ImageBase = pNtProc->OptionalHeader.ImageBase;
-
-                        size_t cbCompare = RT_MIN(pNtFile->OptionalHeader.SizeOfHeaders, sizeof(abProc));
-                        if (cbCompare < sizeof(abFile))
-                            RT_BZERO(&abFile[cbCompare], sizeof(abFile) - cbCompare);
-                        if (!memcmp(abFile, abProc, cbCompare))
-                            rc = VINF_SUCCESS;
-                        else
-                        {
-                            SUP_DPRINTF(("supR3HardNtPuChSanitizeImage: Header diff @%#x in ('%ls')\n",
-                                         supR3HardNtPuChFindFirstDiff(abFile, abProc, sizeof(abProc)), uBuf.UniStr.Buffer));
-                            rc = supR3HardNtPuChRestoreImageBits(pThis, pMemInfo->BaseAddress, abFile, cbCompare, PAGE_READONLY);
-                        }
-                    }
-                    else
-                        rc = RTErrInfoSetF(pThis->pErrInfo, VERR_GENERAL_FAILURE,
-                                           "PE header offset differs between file and memory: offProc=%p offFile=%p '%ls'\n",
-                                           (uintptr_t)pNtProc - (uintptr_t)abProc, (uintptr_t)pNtFile - (uintptr_t)abFile,
-                                           uBuf.UniStr.Buffer);
-                }
-                else
-                {
-                    /*
-                     * Validate the API set map.
-                     */
-                }
-            }
-            else
-                rc = RTErrInfoSetF(pThis->pErrInfo, RTErrConvertFromNtStatus(rcNt),
-                                   "NtReadVirtualMemory returned %#x read 4KB at %p ('%ls').", rcNt,
-                                   pMemInfo->BaseAddress, uBuf.UniStr.Buffer);
-        }
-        else
-            rc = RTErrInfoSetF(pThis->pErrInfo, RTErrConvertFromNtStatus(rcNt),
-                               "No PE header in the first 4KB of '%ls'.", rcNt, uBuf.UniStr.Buffer);
-    }
-    else
-        rc = RTErrInfoSetF(pThis->pErrInfo, RTErrConvertFromNtStatus(rcNt),
-                           "NtReadFile returned %#x reading the header of '%ls'.", rcNt, uBuf.UniStr.Buffer);
-
-    NtClose(hFile);
-
-    return rc;
-}
-
-
-static int supR3HardNtPuChSanitizeMemory(PSUPR3HARDNTPUCH pThis)
-{
-    /*
-     * Find and remove/disable any unwanted executable memory.
-     */
-    uint32_t    cXpExceptions = 0;
-    uintptr_t   cbAdvance = 0;
-    uintptr_t   uPtrWhere = 0;
-    for (uint32_t i = 0; i < 1024; i++)
-    {
-        SIZE_T                      cbActual = 0;
-        MEMORY_BASIC_INFORMATION    MemInfo  = { 0, 0, 0, 0, 0, 0, 0 };
-        NTSTATUS rcNt = NtQueryVirtualMemory(pThis->hProcess,
-                                             (void const *)uPtrWhere,
-                                             MemoryBasicInformation,
-                                             &MemInfo,
-                                             sizeof(MemInfo),
-                                             &cbActual);
-        if (!NT_SUCCESS(rcNt))
-            break;
-        //SUP_DPRINTF(("supR3HardNtPuChSanitizeMemory: %p (%p LB %#zx): type=%#010x prot=%#06x state=%#07x aprot=%#06x abase=%p\n",
-        //             uPtrWhere, MemInfo.BaseAddress, MemInfo.RegionSize,MemInfo.Type,
-        //             MemInfo.Protect, MemInfo.State, MemInfo.AllocationBase, MemInfo.AllocationProtect));
-
-        if (   MemInfo.Type == SEC_IMAGE
-            || MemInfo.Type == SEC_PROTECTED_IMAGE
-            || MemInfo.Type == (SEC_IMAGE | SEC_PROTECTED_IMAGE))
-        {
-            /*
-             * Restore modified parts of the image from file.
-             */
-            if (MemInfo.BaseAddress == MemInfo.AllocationBase)
-            {
-                int rc = supR3HardNtPuChSanitizeImage(pThis, &MemInfo);
-                if (RT_FAILURE(rc))
-                    return rc;
-            }
-        }
-        /*
-         * Executable memory outside an image is evil by definition.
-         */
-        else if (MemInfo.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY))
-        {
-            /*
-             * XP, W2K3 exception: Ignore the CSRSS read-only region as best we can.
-             */
-            if (   (MemInfo.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY))
-                   == PAGE_EXECUTE_READ
-                && cXpExceptions == 0
-                && (uintptr_t)MemInfo.BaseAddress >= UINT32_C(0x78000000)
-                /* && MemInfo.BaseAddress == pPeb->ReadOnlySharedMemoryBase */
-                && g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 0) )
-                cXpExceptions++;
-#ifndef VBOX_PERMIT_VISUAL_STUDIO_PROFILING
-            else
-            {
-                /*
-                 * Free any private executable memory (sysplant.sys allocates executable memory).
-                 */
-                if (MemInfo.Type == MEM_PRIVATE)
-                {
-                    SUP_DPRINTF(("supR3HardNtPuChSanitizeMemory: Freeing exec mem at %p (%p LB %#zx)\n",
-                                 uPtrWhere, MemInfo.BaseAddress, MemInfo.RegionSize));
-                    PVOID   pvFree = MemInfo.BaseAddress;
-                    SIZE_T  cbFree = MemInfo.RegionSize;
-                    rcNt = NtFreeVirtualMemory(pThis->hProcess, &pvFree, &cbFree, MEM_RELEASE);
-                    if (!NT_SUCCESS(rcNt))
-                        return RTErrInfoSetF(pThis->pErrInfo, VERR_GENERAL_FAILURE,
-                                             "NtFreeVirtualMemory (%p LB %#zx) failed: %#x",
-                                             MemInfo.BaseAddress, MemInfo.RegionSize, rcNt);
-                }
-                /*
-                 * Unmap mapped memory, failing that, drop exec privileges.
-                 */
-                else if (MemInfo.Type == MEM_MAPPED)
-                {
-                    SUP_DPRINTF(("supR3HardNtPuChSanitizeMemory: Unmapping exec mem at %p (%p/%p LB %#zx)\n",
-                                 uPtrWhere, MemInfo.AllocationBase, MemInfo.BaseAddress, MemInfo.RegionSize));
-                    rcNt = NtUnmapViewOfSection(pThis->hProcess, MemInfo.AllocationBase);
-                    if (!NT_SUCCESS(rcNt))
-                    {
-                        PVOID  pvCopy = MemInfo.BaseAddress;
-                        SIZE_T cbCopy = MemInfo.RegionSize;
-                        NTSTATUS rcNt2 = NtProtectVirtualMemory(pThis->hProcess, &pvCopy, &cbCopy, PAGE_NOACCESS, NULL);
-                        if (!NT_SUCCESS(rcNt2))
-                            rcNt2 = NtProtectVirtualMemory(pThis->hProcess, &pvCopy, &cbCopy, PAGE_READONLY, NULL);
-                        if (!NT_SUCCESS(rcNt2))
-                            return RTErrInfoSetF(pThis->pErrInfo, VERR_GENERAL_FAILURE,
-                                                 "NtUnmapViewOfSection (%p/%p LB %#zx) failed: %#x (%#x)",
-                                                 MemInfo.AllocationBase, MemInfo.BaseAddress, MemInfo.RegionSize, rcNt, rcNt2);
-                    }
-                }
-                else
-                    return RTErrInfoSetF(pThis->pErrInfo, VERR_GENERAL_FAILURE,
-                                         "Unknown executable memory type %#x at %p/%p LB %#zx",
-                                         MemInfo.Type, MemInfo.AllocationBase, MemInfo.BaseAddress, MemInfo.RegionSize);
-            }
-#endif
-        }
-
-        /*
-         * Advance.
-         */
-        cbAdvance = MemInfo.RegionSize;
-        if (uPtrWhere + cbAdvance <= uPtrWhere)
-            break;
-        uPtrWhere += MemInfo.RegionSize;
-    }
 
     return VINF_SUCCESS;
@@ -2153,5 +1859,5 @@
 
     /*
-     * Do the work.
+     * Do the work, the last bit we tag along with the process verfication code.
      */
     int rc = supR3HardNtPuChScrewUpPebForInitialImageEvents(&This);
@@ -2161,5 +1867,5 @@
         rc = supR3HardNtPuChSanitizePeb(&This);
     if (RT_SUCCESS(rc))
-        rc = supR3HardNtPuChSanitizeMemory(&This);
+        rc = supHardenedWinVerifyProcess(hProcess, hThread, SUPHARDNTVPKIND_CHILD_PURIFICATION, pErrInfo);
 
     return rc;
@@ -2301,4 +2007,16 @@
 #endif
 
+#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
+    /*
+     * Apply anti debugger notification trick to the thread.  (Also done in
+     * supR3HardenedWinInstallHooks.)
+     */
+    rcNt = NtSetInformationThread(NtCurrentThread(), ThreadHideFromDebugger, NULL, 0);
+    if (!NT_SUCCESS(rcNt))
+    {
+        NtTerminateProcess(hProcess, DBG_TERMINATE_PROCESS);
+        supR3HardenedError(rcNt, true /*fFatal*/, "NtSetInformationThread/ThreadHideFromDebugger failed: %#x\n", rcNt);
+    }
+#endif
 
     /*
@@ -2687,5 +2405,11 @@
 
     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. */
+        supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_SELF_PURIFICATION, NULL);
+
         supR3HardenedWinInstallHooks();
+    }
 
 #ifndef VBOX_WITH_VISTA_NO_SP
