VirtualBox

Changeset 52204 in vbox for trunk/src/VBox/HostDrivers


Ignore:
Timestamp:
Jul 26, 2014 11:22:44 AM (10 years ago)
Author:
vboxsync
Message:

SUP,LDR: Changed RTLdrGetBits to allow not resolving imports. Combined the memory and image purification code with the process validation code, adding a validation kind/mode parameter. The process verfication code now checks that code sections are unmodified. Had to add a self purification run before hooking NtCreateSection to undo a weird kernel32 change that avast made (making GetBinaryTypeW specify write thru when opening a file). So, VM startup is now even slower thanks to avast.

Location:
trunk/src/VBox/HostDrivers/Support
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostDrivers/Support/Makefile.kmk

    r52169 r52204  
    293293        $(VBOX_PATH_RUNTIME_SRC)/common/misc/RTAssertMsg2WeakV.cpp \
    294294        $(VBOX_PATH_RUNTIME_SRC)/common/misc/zero.asm \
     295        $(VBOX_PATH_RUNTIME_SRC)/common/path/RTPathFilename.cpp \
    295296        $(VBOX_PATH_RUNTIME_SRC)/common/string/memchr.asm \
    296297        $(VBOX_PATH_RUNTIME_SRC)/common/string/memcmp.asm \
  • trunk/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp

    r52169 r52204  
    243243    if (hStdOut != NULL)
    244244    {
     245# if 0 /* Windows 7 and earlier uses fake handles, with the last two bits set ((hStdOut & 3) == 3). */
    245246        IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
    246247        NtWriteFile(hStdOut, NULL /*Event*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/,
    247248                    &Ios, (PVOID)pch, (ULONG)cch, NULL /*ByteOffset*/, NULL /*Key*/);
     249# else
     250        DWORD cbWritten;
     251        WriteFile(hStdOut, pch, cch, &cbWritten, NULL);
     252# endif
    248253    }
    249254#else
  • trunk/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp

    r52192 r52204  
    34223422        RTErrInfoInit(&ErrInfo, szErr, sizeof(szErr));
    34233423
    3424         rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), &ErrInfo);
     3424        rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_VERIFY_ONLY, &ErrInfo);
    34253425        if (RT_FAILURE(rc))
    34263426            RTLogWriteDebugger(szErr, strlen(szErr));
  • trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerify-win.h

    r52160 r52204  
    3030#include <iprt/types.h>
    3131#include <iprt/crypto/x509.h>
     32#ifndef SUP_CERTIFICATES_ONLY
     33# ifdef RT_OS_WINDOWS
     34#  include <iprt/ldr.h>
     35# endif
     36#endif
     37
    3238
    3339RT_C_DECLS_BEGIN
     
    3743DECLHIDDEN(int)      supHardenedWinInitImageVerifier(PRTERRINFO pErrInfo);
    3844DECLHIDDEN(void)     supHardenedWinTermImageVerifier(void);
    39 DECLHIDDEN(int)      supHardenedWinVerifyProcess(HANDLE hProcess, HANDLE hThread, PRTERRINFO pErrInfo);
     45
     46typedef enum SUPHARDNTVPKIND
     47{
     48    SUPHARDNTVPKIND_VERIFY_ONLY = 1,
     49    SUPHARDNTVPKIND_CHILD_PURIFICATION,
     50    SUPHARDNTVPKIND_SELF_PURIFICATION,
     51    SUPHARDNTVPKIND_32BIT_HACK = 0x7fffffff
     52} SUPHARDNTVPKIND;
     53DECLHIDDEN(int)      supHardenedWinVerifyProcess(HANDLE hProcess, HANDLE hThread, SUPHARDNTVPKIND enmKind, PRTERRINFO pErrInfo);
    4054
    4155DECLHIDDEN(bool)     supHardViIsAppPatchDir(PCRTUTF16 pwszPath, uint32_t cwcName);
    42 DECLHIDDEN(int)      supHardenedWinVerifyImageByHandle(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, bool *pfCacheable, PRTERRINFO pErrInfo);
    43 DECLHIDDEN(int)      supHardenedWinVerifyImageByHandleNoName(HANDLE hFile, uint32_t fFlags, PRTERRINFO pErrInfo);
     56
     57/**
     58 * SUP image verifier loader reader instance.
     59 */
     60typedef struct SUPHNTVIRDR
     61{
     62    /** The core reader structure. */
     63    RTLDRREADER Core;
     64    /** The file handle . */
     65    HANDLE      hFile;
     66    /** Current file offset. */
     67    RTFOFF      off;
     68    /** The file size. */
     69    RTFOFF      cbFile;
     70    /** Flags for the verification callback, SUPHNTVI_F_XXX. */
     71    uint32_t    fFlags;
     72    /** The executable timstamp in second since unix epoch. */
     73    uint64_t    uTimestamp;
     74    /** Log name. */
     75    char        szFilename[1];
     76} SUPHNTVIRDR;
     77/** Pointer to an SUP image verifier loader reader instance. */
     78typedef SUPHNTVIRDR *PSUPHNTVIRDR;
     79DECLHIDDEN(int) supHardNtViRdrCreate(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PSUPHNTVIRDR *ppNtViRdr);
     80DECLHIDDEN(int) supHardenedWinVerifyImageByHandle(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, bool *pfCacheable, PRTERRINFO pErrInfo);
     81DECLHIDDEN(int) supHardenedWinVerifyImageByHandleNoName(HANDLE hFile, uint32_t fFlags, PRTERRINFO pErrInfo);
     82DECLHIDDEN(int) supHardenedWinVerifyImageByLdrMod(RTLDRMOD hLdrMod, PCRTUTF16 pwszName, PSUPHNTVIRDR pNtViRdr,
     83                                                  bool *pfCacheable, PRTERRINFO pErrInfo);
    4484/** @name SUPHNTVI_F_XXX - Flags for supHardenedWinVerifyImageByHandle.
    4585 * @{ */
  • trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp

    r52160 r52204  
    7474*   Structures and Typedefs                                                    *
    7575*******************************************************************************/
    76 /**
    77  * SUP image verifier loader reader instance.
    78  */
    79 typedef struct SUPHNTVIRDR
    80 {
    81     /** The core reader structure. */
    82     RTLDRREADER Core;
    83     /** The file handle . */
    84     HANDLE      hFile;
    85     /** Current file offset. */
    86     RTFOFF      off;
    87     /** The file size. */
    88     RTFOFF      cbFile;
    89     /** Flags for the verification callback, SUPHNTVI_F_XXX. */
    90     uint32_t    fFlags;
    91     /** The executable timstamp in second since unix epoch. */
    92     uint64_t    uTimestamp;
    93     /** Log name. */
    94     char        szFilename[1];
    95 } SUPHNTVIRDR;
    96 /** Pointer to an SUP image verifier loader reader instance. */
    97 typedef SUPHNTVIRDR *PSUPHNTVIRDR;
    98 
    9976
    10077#ifdef IN_RING3
     
    349326 * @param   ppNtViRdr       Where to store the reader instance on success.
    350327 */
    351 static int supHardNtViRdrCreate(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PSUPHNTVIRDR *ppNtViRdr)
     328DECLHIDDEN(int) supHardNtViRdrCreate(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PSUPHNTVIRDR *ppNtViRdr)
    352329{
    353330    /*
     
    882859
    883860/**
     861 * Verifies the given loader image.
     862 *
     863 * @returns IPRT status code.
     864 * @param   hLdrMod     File handle to the executable file.
     865 * @param   pwszName    Full NT path to the DLL in question, used for dealing
     866 *                      with unsigned system dlls as well as for error/logging.
     867 * @param   pNtViRdr    The reader instance /w flags.
     868 * @param   pfCacheable Where to return whether the result can be cached.  A
     869 *                      valid value is always returned. Optional.
     870 * @param   pErrInfo    Pointer to error info structure. Optional.
     871 */
     872DECLHIDDEN(int) supHardenedWinVerifyImageByLdrMod(RTLDRMOD hLdrMod, PCRTUTF16 pwszName, PSUPHNTVIRDR pNtViRdr,
     873                                                  bool *pfCacheable, PRTERRINFO pErrInfo)
     874{
     875#ifdef IN_RING3
     876    /* Check that the caller has performed the necessary library initialization. */
     877    if (!RTCrX509Certificate_IsPresent(&g_BuildX509Cert))
     878        return RTErrInfoSet(pErrInfo, VERR_WRONG_ORDER,
     879                            "supHardenedWinVerifyImageByHandle: supHardenedWinInitImageVerifier was not called.");
     880#endif
     881
     882    /*
     883     * Verify it.
     884     *
     885     * The PKCS #7 SignedData signature is checked in the callback. Any
     886     * signing certificate restrictions are also enforced there.
     887     *
     888     * For the time being, we use the executable timestamp as the
     889     * certificate validation date.  We must query that first to avoid
     890     * potential issues re-entering the loader code from the callback.
     891     *
     892     * Update: Save the first timestamp we validate with build cert and
     893     *         use this as a minimum timestamp for further build cert
     894     *         validations.  This works around issues with old DLLs that
     895     *         we sign against with our certificate (crt, sdl, qt).
     896     */
     897    int rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_TIMESTAMP_SECONDS, &pNtViRdr->uTimestamp, sizeof(pNtViRdr->uTimestamp));
     898    if (RT_SUCCESS(rc))
     899    {
     900#ifdef IN_RING3 /* Hack alert! (see above) */
     901        if (   (pNtViRdr->fFlags & SUPHNTVI_F_REQUIRE_KERNEL_CODE_SIGNING)
     902            && (pNtViRdr->fFlags & SUPHNTVI_F_REQUIRE_SIGNATURE_ENFORCEMENT)
     903            && pNtViRdr->uTimestamp < g_uBuildTimestampHack)
     904            pNtViRdr->uTimestamp = g_uBuildTimestampHack;
     905#endif
     906
     907        rc = RTLdrVerifySignature(hLdrMod, supHardNtViCallback, pNtViRdr, pErrInfo);
     908
     909#ifdef IN_RING3 /* Hack alert! (see above) */
     910        if ((pNtViRdr->fFlags & SUPHNTVI_F_REQUIRE_BUILD_CERT) && g_uBuildTimestampHack == 0 && RT_SUCCESS(rc))
     911            g_uBuildTimestampHack = pNtViRdr->uTimestamp;
     912#endif
     913
     914        /*
     915         * Microsoft doesn't sign a whole bunch of DLLs, so we have to
     916         * ASSUME that a bunch of system DLLs are fine.
     917         */
     918        if (rc == VERR_LDRVI_NOT_SIGNED)
     919            rc = supHardNtViCheckIfNotSignedOk(hLdrMod, pwszName, pNtViRdr->fFlags, rc);
     920        if (RT_FAILURE(rc))
     921            RTErrInfoAddF(pErrInfo, rc, ": %ls", pwszName);
     922
     923        /*
     924         * Check for the signature checking enforcement, if requested to do so.
     925         */
     926        if (RT_SUCCESS(rc) && (pNtViRdr->fFlags & SUPHNTVI_F_REQUIRE_SIGNATURE_ENFORCEMENT))
     927        {
     928            bool fEnforced = false;
     929            int rc2 = RTLdrQueryProp(hLdrMod, RTLDRPROP_SIGNATURE_CHECKS_ENFORCED, &fEnforced, sizeof(fEnforced));
     930            if (RT_FAILURE(rc2))
     931                rc = RTErrInfoSetF(pErrInfo, rc2, "Querying RTLDRPROP_SIGNATURE_CHECKS_ENFORCED failed on %ls: %Rrc.",
     932                                   pwszName, rc2);
     933            else if (!fEnforced)
     934                rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_SIGNATURE_CHECKS_NOT_ENFORCED,
     935                                   "The image '%ls' was not linked with /IntegrityCheck.", pwszName);
     936        }
     937    }
     938    else
     939        RTErrInfoSetF(pErrInfo, rc, "RTLdrQueryProp/RTLDRPROP_TIMESTAMP_SECONDS failed on %ls: %Rrc", pwszName, rc);
     940
     941#ifdef IN_RING3
     942     /*
     943      * Call the windows verify trust API if we've resolved it.
     944      */
     945     if (   g_pfnWinVerifyTrust
     946         && supR3HardNtViCanCallWinVerifyTrust(pNtViRdr->hFile, pwszName))
     947     {
     948         if (pfCacheable)
     949             *pfCacheable = g_pfnWinVerifyTrust != NULL;
     950         if (rc != VERR_LDRVI_NOT_SIGNED)
     951         {
     952             if (rc == VINF_LDRVI_NOT_SIGNED)
     953             {
     954                 if (pNtViRdr->fFlags & SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION)
     955                 {
     956                     int rc2 = supR3HardNtViCallWinVerifyTrustCatFile(pNtViRdr->hFile, pwszName, pNtViRdr->fFlags, pErrInfo,
     957                                                                      g_pfnWinVerifyTrust);
     958                     SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile -> %d (org %d)\n", rc2, rc));
     959                     rc = rc2;
     960                 }
     961                 else
     962                 {
     963                     AssertFailed();
     964                     rc = VERR_LDRVI_NOT_SIGNED;
     965                 }
     966             }
     967             else if (RT_SUCCESS(rc))
     968                 rc = supR3HardNtViCallWinVerifyTrust(pNtViRdr->hFile, pwszName, pNtViRdr->fFlags, pErrInfo,
     969                                                      g_pfnWinVerifyTrust);
     970             else
     971             {
     972                 int rc2 = supR3HardNtViCallWinVerifyTrust(pNtViRdr->hFile, pwszName, pNtViRdr->fFlags, pErrInfo,
     973                                                           g_pfnWinVerifyTrust);
     974                 AssertMsg(RT_FAILURE_NP(rc2),
     975                           ("rc=%Rrc, rc2=%Rrc %s", rc, rc2, pErrInfo ? pErrInfo->pszMsg : "<no-err-info>"));
     976             }
     977         }
     978     }
     979#else  /* !IN_RING3 */
     980     if (pfCacheable)
     981         *pfCacheable = true;
     982#endif /* !IN_RING3 */
     983
     984     return rc;
     985}
     986
     987
     988/**
    884989 * Verifies the given executable image.
    885990 *
     
    8991004    if (pfCacheable)
    9001005        *pfCacheable = false;
    901 
    902 #ifdef IN_RING3
    903     /* Check that the caller has performed the necessary library initialization. */
    904     if (!RTCrX509Certificate_IsPresent(&g_BuildX509Cert))
    905         return RTErrInfoSet(pErrInfo, VERR_WRONG_ORDER,
    906                             "supHardenedWinVerifyImageByHandle: supHardenedWinInitImageVerifier was not called.");
    907 #endif
    9081006
    9091007    /*
     
    9261024            /*
    9271025             * Verify it.
    928              *
    929              * The PKCS #7 SignedData signature is checked in the callback. Any
    930              * signing certificate restrictions are also enforced there.
    931              *
    932              * For the time being, we use the executable timestamp as the
    933              * certificate validation date.  We must query that first to avoid
    934              * potential issues re-entering the loader code from the callback.
    935              *
    936              * Update: Save the first timestamp we validate with build cert and
    937              *         use this as a minimum timestamp for further build cert
    938              *         validations.  This works around issues with old DLLs that
    939              *         we sign against with our certificate (crt, sdl, qt).
    9401026             */
    941             rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_TIMESTAMP_SECONDS, &pNtViRdr->uTimestamp, sizeof(pNtViRdr->uTimestamp));
    942             if (RT_SUCCESS(rc))
    943             {
    944 #ifdef IN_RING3 /* Hack alert! (see above) */
    945                 if (   (fFlags & SUPHNTVI_F_REQUIRE_KERNEL_CODE_SIGNING)
    946                     && (fFlags & SUPHNTVI_F_REQUIRE_SIGNATURE_ENFORCEMENT)
    947                     && pNtViRdr->uTimestamp < g_uBuildTimestampHack)
    948                     pNtViRdr->uTimestamp = g_uBuildTimestampHack;
    949 #endif
    950 
    951                 rc = RTLdrVerifySignature(hLdrMod, supHardNtViCallback, pNtViRdr, pErrInfo);
    952 
    953 #ifdef IN_RING3 /* Hack alert! (see above) */
    954                 if ((fFlags & SUPHNTVI_F_REQUIRE_BUILD_CERT) && g_uBuildTimestampHack == 0 && RT_SUCCESS(rc))
    955                     g_uBuildTimestampHack = pNtViRdr->uTimestamp;
    956 #endif
    957 
    958                 /*
    959                  * Microsoft doesn't sign a whole bunch of DLLs, so we have to
    960                  * ASSUME that a bunch of system DLLs are fine.
    961                  */
    962                 if (rc == VERR_LDRVI_NOT_SIGNED)
    963                     rc = supHardNtViCheckIfNotSignedOk(hLdrMod, pwszName, fFlags, rc);
    964                 if (RT_FAILURE(rc))
    965                     RTErrInfoAddF(pErrInfo, rc, ": %ls", pwszName);
    966 
    967                 /*
    968                  * Check for the signature checking enforcement, if requested to do so.
    969                  */
    970                 if (RT_SUCCESS(rc) && (fFlags & SUPHNTVI_F_REQUIRE_SIGNATURE_ENFORCEMENT))
    971                 {
    972                     bool fEnforced = false;
    973                     int rc2 = RTLdrQueryProp(hLdrMod, RTLDRPROP_SIGNATURE_CHECKS_ENFORCED, &fEnforced, sizeof(fEnforced));
    974                     if (RT_FAILURE(rc2))
    975                         rc = RTErrInfoSetF(pErrInfo, rc2, "Querying RTLDRPROP_SIGNATURE_CHECKS_ENFORCED failed on %ls: %Rrc.",
    976                                            pwszName, rc2);
    977                     else if (!fEnforced)
    978                         rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_SIGNATURE_CHECKS_NOT_ENFORCED,
    979                                            "The image '%ls' was not linked with /IntegrityCheck.", pwszName);
    980                 }
    981             }
    982             else
    983                 RTErrInfoSetF(pErrInfo, rc, "RTLdrQueryProp/RTLDRPROP_TIMESTAMP_SECONDS failed on %ls: %Rrc", pwszName, rc);
    984 
    985              int rc2 = RTLdrClose(hLdrMod); AssertRC(rc2);
    986 
    987 #ifdef IN_RING3
    988              /*
    989               * Call the windows verify trust API if we've resolved it.
    990               */
    991              if (   g_pfnWinVerifyTrust
    992                  && supR3HardNtViCanCallWinVerifyTrust(hFile, pwszName))
    993              {
    994                  if (pfCacheable)
    995                      *pfCacheable = g_pfnWinVerifyTrust != NULL;
    996                  if (rc != VERR_LDRVI_NOT_SIGNED)
    997                  {
    998                      if (rc == VINF_LDRVI_NOT_SIGNED)
    999                      {
    1000                          if (fFlags & SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION)
    1001                          {
    1002                              int rc2 = supR3HardNtViCallWinVerifyTrustCatFile(hFile, pwszName, fFlags, pErrInfo,
    1003                                                                               g_pfnWinVerifyTrust);
    1004                              SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile -> %d (org %d)\n", rc2, rc));
    1005                              rc = rc2;
    1006                          }
    1007                          else
    1008                          {
    1009                              AssertFailed();
    1010                              rc = VERR_LDRVI_NOT_SIGNED;
    1011                          }
    1012                      }
    1013                      else if (RT_SUCCESS(rc))
    1014                          rc = supR3HardNtViCallWinVerifyTrust(hFile, pwszName, fFlags, pErrInfo, g_pfnWinVerifyTrust);
    1015                      else
    1016                      {
    1017                          int rc2 = supR3HardNtViCallWinVerifyTrust(hFile, pwszName, fFlags, pErrInfo, g_pfnWinVerifyTrust);
    1018                          AssertMsg(RT_FAILURE_NP(rc2),
    1019                                    ("rc=%Rrc, rc2=%Rrc %s", rc, rc2, pErrInfo ? pErrInfo->pszMsg : "<no-err-info>"));
    1020                      }
    1021                  }
    1022              }
    1023 #else
    1024              if (pfCacheable)
    1025                  *pfCacheable = true;
    1026 #endif /* IN_RING3 */
     1027            rc = supHardenedWinVerifyImageByLdrMod(hLdrMod, pwszName, pNtViRdr, pfCacheable, pErrInfo);
     1028            int rc2 = RTLdrClose(hLdrMod); AssertRC(rc2);
    10271029        }
    10281030        else
  • trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyProcess-win.cpp

    r52169 r52204  
    3939#include <VBox/err.h>
    4040#include <iprt/ctype.h>
     41#include <iprt/zero.h>
    4142#include <iprt/param.h>
    4243
     
    108109    /** This may be a 32-bit resource DLL. */
    109110    bool            f32bitResourceDll;
     111
     112    /** Load module associated with the image during content verfication. */
     113    RTLDRMOD        hLdrMod;
     114    /** The file reader. */
     115    PSUPHNTVIRDR    pNtViRdr;
     116    /** Image bits for lazy cleanup. */
     117    uint8_t        *pbBits;
    110118} SUPHNTVPIMAGE;
    111119/** Pointer to image info from the virtual address space scan. */
     
    117125typedef struct SUPHNTVPSTATE
    118126{
     127    /** Type of verification to perform. */
     128    SUPHARDNTVPKIND         enmKind;
    119129    /** The result. */
    120130    int                     rcResult;
    121131    /** Number of images in aImages. */
    122132    uint32_t                cImages;
     133    /** The process handle. */
     134    HANDLE                  hProcess;
    123135    /** Images found in the process.
    124136     * The array is large enough to hold the executable, all allowed DLLs, and one
     
    284296
    285297
    286 static NTSTATUS supHardNtVpReadFile(HANDLE hFile, uint64_t off, void *pvBuf, size_t cbRead)
    287 {
    288     if ((ULONG)cbRead != cbRead)
    289         return STATUS_INTEGER_OVERFLOW;
    290 
    291     IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
    292     NTSTATUS rcNt = NtReadFile(hFile,
    293                                NULL /*hEvent*/,
    294                                NULL /*ApcRoutine*/,
    295                                NULL /*ApcContext*/,
    296                                &Ios,
    297                                pvBuf,
    298                                (ULONG)cbRead,
    299                                (PLARGE_INTEGER)&off,
    300                                NULL);
    301     if (NT_SUCCESS(rcNt))
    302         rcNt = Ios.Status;
    303     return rcNt;
     298static int supHardNtVpReadImage(PSUPHNTVPIMAGE pImage, uint64_t off, void *pvBuf, size_t cbRead)
     299{
     300    return pImage->pNtViRdr->Core.pfnRead(&pImage->pNtViRdr->Core, pvBuf, cbRead, off);
    304301}
    305302
     
    324321
    325322
    326 static int supHardNtVpFileMemCompare(PSUPHNTVPSTATE pThis, const void *pvFile, const void *pvMemory, size_t cbToCompare,
    327                                      PSUPHNTVPIMAGE pImage, uint32_t uRva)
    328 {
    329     if (suplibHardenedMemComp(pvFile, pvMemory, cbToCompare) == 0)
    330         return VINF_SUCCESS;
    331 
    332     /* Find the exact location. */
    333     const uint8_t *pbFile   = (const uint8_t *)pvFile;
    334     const uint8_t *pbMemory = (const uint8_t *)pvMemory;
    335     while (cbToCompare > 0 && *pbFile == *pbMemory)
    336     {
    337         cbToCompare--;
    338         pbFile++;
    339         pbMemory++;
    340         uRva++;
    341     }
    342 
    343     return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_MEMORY_VS_FILE_MISMATCH,
    344                                "%s: memory compare at %#x failed: %#x != %#x\n", pImage->pszName, uRva, *pbFile, *pbMemory);
    345 }
     323#ifdef IN_RING3
     324static NTSTATUS supHardNtVpFileMemRestore(PSUPHNTVPSTATE pThis, PVOID pvRestoreAddr, uint8_t const *pbFile, uint32_t cbToRestore,
     325                                          uint32_t fCorrectProtection)
     326{
     327    PVOID  pvProt   = pvRestoreAddr;
     328    SIZE_T cbProt   = cbToRestore;
     329    ULONG  fOldProt = 0;
     330    NTSTATUS rcNt = NtProtectVirtualMemory(pThis->hProcess, &pvProt, &cbProt, PAGE_READWRITE, &fOldProt);
     331    if (NT_SUCCESS(rcNt))
     332    {
     333        SIZE_T cbIgnored;
     334        rcNt = NtWriteVirtualMemory(pThis->hProcess, pvRestoreAddr, pbFile, cbToRestore, &cbIgnored);
     335
     336        pvProt = pvRestoreAddr;
     337        cbProt = cbToRestore;
     338        NTSTATUS rcNt2 = NtProtectVirtualMemory(pThis->hProcess, &pvProt, &cbProt, fCorrectProtection, &fOldProt);
     339        if (NT_SUCCESS(rcNt))
     340            rcNt = rcNt2;
     341    }
     342    return rcNt;
     343}
     344#endif /* IN_RING3 */
     345
     346
     347typedef struct SUPHNTVPSKIPAREA
     348{
     349    uint32_t uRva;
     350    uint32_t cb;
     351} SUPHNTVPSKIPAREA;
     352typedef SUPHNTVPSKIPAREA *PSUPHNTVPSKIPAREA;
     353
     354static int supHardNtVpFileMemCompareSection(PSUPHNTVPSTATE pThis, PSUPHNTVPIMAGE pImage,
     355                                            uint32_t uRva, uint32_t cb, const uint8_t *pbFile,
     356                                            int32_t iSh, PSUPHNTVPSKIPAREA paSkipAreas, uint32_t cSkipAreas,
     357                                            uint32_t fCorrectProtection)
     358{
     359    AssertCompileAdjacentMembers(SUPHNTVPSTATE, abMemory, abFile); /* Use both the memory and file buffers here. Parfait might hate me for this... */
     360    uint32_t  const cbMemory = sizeof(pThis->abMemory) + sizeof(pThis->abFile);
     361    uint8_t * const pbMemory = &pThis->abMemory[0];
     362
     363    while (cb > 0)
     364    {
     365        uint32_t cbThis = RT_MIN(cb, cbMemory);
     366
     367        /* Clipping. */
     368        uint32_t uNextRva = uRva + cbThis;
     369        if (cSkipAreas)
     370        {
     371            uint32_t uRvaEnd = uNextRva;
     372            uint32_t i = cSkipAreas;
     373            while (i-- > 0)
     374            {
     375                uint32_t uSkipEnd = paSkipAreas[i].uRva + paSkipAreas[i].cb;
     376                if (   uRva    < uSkipEnd
     377                    && uRvaEnd > paSkipAreas[i].uRva)
     378                {
     379                    if (uRva < paSkipAreas[i].uRva)
     380                    {
     381                        cbThis   = paSkipAreas[i].uRva - uRva;
     382                        uRvaEnd  = paSkipAreas[i].uRva;
     383                        uNextRva = uSkipEnd;
     384                    }
     385                    else if (uRvaEnd >= uSkipEnd)
     386                    {
     387                        cbThis  -= uSkipEnd - uRva;
     388                        uRva     = uSkipEnd;
     389                    }
     390                    else
     391                    {
     392                        uNextRva = uSkipEnd;
     393                        cbThis   = 0;
     394                        break;
     395                    }
     396                }
     397            }
     398        }
     399
     400        /* Read the memory. */
     401        NTSTATUS rcNt = supHardNtVpReadMem(pThis->hProcess, pImage->uImageBase + uRva, pbMemory, cbThis);
     402        if (!NT_SUCCESS(rcNt))
     403            return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_MEMORY_READ_ERROR,
     404                                       "%s: Error reading %#x bytes at %p (rva %#x, #%u, %.8s) from memory: %#x",
     405                                       pImage->pszName, cbThis, pImage->uImageBase + uRva, uRva, iSh + 1,
     406                                       iSh >= 0 ? (char *)pThis->aSecHdrs[iSh].Name : "headers", rcNt);
     407
     408        /* Do the compare. */
     409        if (memcmp(pbFile, pbMemory, cbThis) != 0)
     410        {
     411            const char *pachSectNm = iSh >= 0 ? (char *)pThis->aSecHdrs[iSh].Name : "headers";
     412            SUP_DPRINTF(("%s: Differences in section #%u (%s) between file and memory:\n", pImage->pszName, iSh + 1, pachSectNm));
     413
     414            uint32_t off = 0;
     415            while (off < cbThis && pbFile[off] == pbMemory[off])
     416                off++;
     417            SUP_DPRINTF(("  %p / %#09x: %02x != %02x\n",
     418                         pImage->uImageBase + uRva + off, uRva + off, pbFile[off], pbMemory[off]));
     419            uint32_t offLast = off;
     420            uint32_t cDiffs  = 1;
     421            for (uint32_t off2 = off + 1; off2 < cbThis; off2++)
     422                if (pbFile[off2] != pbMemory[off2])
     423                {
     424                    SUP_DPRINTF(("  %p / %#09x: %02x != %02x\n",
     425                                 pImage->uImageBase + uRva + off2, uRva + off2, pbFile[off2], pbMemory[off2]));
     426                    cDiffs++;
     427                    offLast = off2;
     428                }
     429
     430#ifdef IN_RING3
     431            if (   pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION
     432                || pThis->enmKind == SUPHARDNTVPKIND_SELF_PURIFICATION)
     433            {
     434                PVOID pvRestoreAddr = (uint8_t *)pImage->uImageBase + uRva;
     435                rcNt = supHardNtVpFileMemRestore(pThis, pvRestoreAddr, pbFile, cbThis, fCorrectProtection);
     436                if (NT_SUCCESS(rcNt))
     437                    SUP_DPRINTF(("  Restored %#x bytes of original file content at %p\n", cbThis, pvRestoreAddr));
     438                else
     439                    return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_MEMORY_VS_FILE_MISMATCH,
     440                                               "%s: Failed to restore %#x bytes at %p (%#x, #%u, %s): %#x (cDiffs=%#x, first=%#x)",
     441                                               pImage->pszName, cbThis, pvRestoreAddr, uRva, iSh + 1, pachSectNm, rcNt,
     442                                               cDiffs, uRva + off);
     443            }
     444            else
     445#endif /* IN_RING3 */
     446                return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_MEMORY_VS_FILE_MISMATCH,
     447                                           "%s: %u differences between %#x and %#x in #%u (%.8s), first: %02x != %02x",
     448                                           pImage->pszName, cDiffs, uRva + off, uRva + offLast, iSh + 1,
     449                                           pachSectNm, pbFile[off], pbMemory[off]);
     450        }
     451
     452        /* Advance. The clipping makes it a little bit complicated. */
     453        cbThis  = uNextRva - uRva;
     454        if (cbThis >= cb)
     455            break;
     456        cb     -= cbThis;
     457        pbFile += cbThis;
     458        uRva    = uNextRva;
     459    }
     460    return VINF_SUCCESS;
     461}
     462
    346463
    347464
     
    351468    uint32_t const cbOrg = cb;
    352469    if (!cb)
     470        return VINF_SUCCESS;
     471    if (   pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION
     472        || pThis->enmKind == SUPHARDNTVPKIND_SELF_PURIFICATION)
    353473        return VINF_SUCCESS;
    354474
     
    398518 *                              space scan.
    399519 * @param   hProcess            Handle to the process.
    400  * @param   hFile               Handle to the image file.
    401520 * @param   pErrInfo            Pointer to error info structure. Optional.
    402521 */
    403 static int supHardNtVpVerifyImageCompareMemory(PSUPHNTVPSTATE pThis, PSUPHNTVPIMAGE pImage, HANDLE hProcess, HANDLE hFile,
    404                                                PRTERRINFO pErrInfo)
     522static int supHardNtVpVerifyImageMemoryCompare(PSUPHNTVPSTATE pThis, PSUPHNTVPIMAGE pImage, HANDLE hProcess, PRTERRINFO pErrInfo)
    405523{
    406524    /*
    407525     * Read and find the file headers.
    408526     */
    409     NTSTATUS rcNt = supHardNtVpReadFile(hFile, 0, pThis->abFile, sizeof(pThis->abFile));
    410     if (!NT_SUCCESS(rcNt))
     527    int rc = supHardNtVpReadImage(pImage, 0 /*off*/, pThis->abFile, sizeof(pThis->abFile));
     528    if (RT_FAILURE(rc))
    411529        return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_IMAGE_HDR_READ_ERROR,
    412                                    "%s: Error reading image header: %#x", pImage->pszName, rcNt);
     530                                   "%s: Error reading image header: %Rrc", pImage->pszName, rc);
    413531
    414532    uint32_t offNtHdrs = 0;
     
    473591                                   "%s: SizeOfImage (%#x) isn't close enough to the mapping size (%#x)",
    474592                                   pImage->pszName, cbImage, pImage->cbImage);
     593    if (cbImage != RTLdrSize(pImage->hLdrMod))
     594        return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_BAD_IMAGE_SIZE,
     595                                   "%s: SizeOfImage (%#x) differs from what RTLdrSize returns (%#zx)",
     596                                   pImage->pszName, cbImage, RTLdrSize(pImage->hLdrMod));
    475597
    476598    uint32_t const cbSectAlign = fIs32Bit ? pNtHdrs32->OptionalHeader.SectionAlignment : pNtHdrs->OptionalHeader.SectionAlignment;
     
    501623
    502624    /*
     625     * Save some header fields we might be using later on.
     626     */
     627    pImage->fImageCharecteristics = pNtHdrs->FileHeader.Characteristics;
     628    pImage->fDllCharecteristics   = fIs32Bit ? pNtHdrs32->OptionalHeader.DllCharacteristics : pNtHdrs->OptionalHeader.DllCharacteristics;
     629
     630    /*
     631     * Correct the apisetschema image base, size and region rva.
     632     */
     633    if (pImage->fApiSetSchemaOnlySection1)
     634    {
     635        pImage->uImageBase      -= pThis->aSecHdrs[0].VirtualAddress;
     636        pImage->cbImage         += pThis->aSecHdrs[0].VirtualAddress;
     637        pImage->aRegions[0].uRva = pThis->aSecHdrs[0].VirtualAddress;
     638    }
     639
     640    /*
     641     * Get relocated bits.
     642     */
     643    pImage->pbBits = (uint8_t *)suplibHardenedAllocZ(cbImage);
     644    if (RT_UNLIKELY(!pImage->pbBits))
     645        return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NO_MEMORY,
     646                                   "%s: Error allocating %#x bytes for fixed up image bits.", pImage->pszName, cbImage);
     647    rc = RTLdrGetBits(pImage->hLdrMod, pImage->pbBits, pImage->uImageBase, NULL /*pfnGetImport*/, pThis);
     648    /**@todo resolve import when not in SUPHARDNTVPKIND_CHILD_PURIFICATION mode. */
     649    if (RT_FAILURE(rc))
     650        return supHardNtVpSetInfo2(pThis, rc, "%s: RTLdrGetBits failed: %Rrc", pImage->pszName, rc);
     651
     652    /** @todo figure out if all windows versions do this... */
     653    if (fIs32Bit)
     654        ((PIMAGE_NT_HEADERS32)&pImage->pbBits[offNtHdrs])->OptionalHeader.ImageBase = (uint32_t)pImage->uImageBase;
     655    else
     656        ((PIMAGE_NT_HEADERS)&pImage->pbBits[offNtHdrs])->OptionalHeader.ImageBase   = pImage->uImageBase;
     657
     658    /*
     659     * Figure out areas we should skip during comparison.
     660     */
     661    uint32_t         cSkipAreas = 0;
     662    SUPHNTVPSKIPAREA aSkipAreas[2];
     663    if (pImage->fNtCreateSectionPatch)
     664    {
     665        RTLDRADDR uValue;
     666        if (pThis->enmKind == SUPHARDNTVPKIND_VERIFY_ONLY)
     667        {
     668            /* Ignore our NtCreateSection hack. */
     669            rc = RTLdrGetSymbolEx(pImage->hLdrMod, pImage->pbBits, 0, "NtCreateSection", &uValue);
     670            if (RT_FAILURE(rc))
     671                return supHardNtVpSetInfo2(pThis, rc, "%s: Failed to find 'NtCreateSection': %Rrc", pImage->pszName, rc);
     672            aSkipAreas[cSkipAreas].uRva = (uint32_t)uValue;
     673            aSkipAreas[cSkipAreas++].cb = 16;
     674        }
     675
     676        /* LdrSystemDllInitBlock is filled in by the kernel. It mainly contains addresses of 32-bit ntdll method for wow64. */
     677        rc = RTLdrGetSymbolEx(pImage->hLdrMod, pImage->pbBits, 0, "LdrSystemDllInitBlock", &uValue);
     678        if (RT_SUCCESS(rc))
     679        {
     680            aSkipAreas[cSkipAreas].uRva = (uint32_t)uValue;
     681            aSkipAreas[cSkipAreas++].cb = RT_MAX(pImage->pbBits[(uint32_t)uValue], 0x50);
     682        }
     683    }
     684
     685    /*
    503686     * Compare the file header with the loaded bits.  The loader will fiddle
    504687     * with image base, changing it to the actual load address.
    505688     */
    506     int rc;
    507689    if (!pImage->fApiSetSchemaOnlySection1)
    508690    {
    509         rcNt = supHardNtVpReadMem(hProcess, pImage->uImageBase, pThis->abMemory, cbHdrsFile);
    510         if (!NT_SUCCESS(rcNt))
    511             return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_MEMORY_READ_ERROR,
    512                                        "%s: Error reading image header from memory: %#x", pImage->pszName, rcNt);
    513         if (uImageBase != pImage->uImageBase)
    514         {
    515             if (fIs32Bit)
    516                 pNtHdrs32->OptionalHeader.ImageBase = (uint32_t)pImage->uImageBase;
    517             else
    518                 pNtHdrs->OptionalHeader.ImageBase = pImage->uImageBase;
    519         }
    520 
    521         rc = supHardNtVpFileMemCompare(pThis, pThis->abFile, pThis->abMemory, cbHeaders, pImage, 0 /*uRva*/);
     691        rc = supHardNtVpFileMemCompareSection(pThis, pImage, 0 /*uRva*/, cbHdrsFile, pImage->pbBits, -1, NULL, 0, PAGE_READONLY);
    522692        if (RT_FAILURE(rc))
    523693            return rc;
     694
    524695        rc = supHardNtVpCheckSectionProtection(pThis, pImage, 0 /*uRva*/, cbHdrsFile, PAGE_READONLY);
    525696        if (RT_FAILURE(rc))
     
    528699
    529700    /*
    530      * Save some header fields we might be using later on.
    531      */
    532     pImage->fImageCharecteristics = pNtHdrs->FileHeader.Characteristics;
    533     pImage->fDllCharecteristics   = fIs32Bit ? pNtHdrs32->OptionalHeader.DllCharacteristics : pNtHdrs->OptionalHeader.DllCharacteristics;
    534 
    535     /*
    536      * Validate sections and check them against the mapping regions.
    537      */
    538     uint32_t uRva = cbHdrsFile;
     701     * Validate sections:
     702     *      - Check them against the mapping regions.
     703     *      - Check section bits according to enmKind.
     704     */
     705    uint32_t fPrevProt = PAGE_READONLY;
     706    uint32_t uRva      = cbHdrsFile;
    539707    for (uint32_t i = 0; i < cSections; i++)
    540708    {
     
    556724                                       pImage->pszName, i, cbFile, cbMap, uSectRva);
    557725
    558         /* Validate the protection. */
     726        /* Validate the protection and bits. */
    559727        if (!pImage->fApiSetSchemaOnlySection1 || i == 0)
    560728        {
    561             if (pImage->fApiSetSchemaOnlySection1)
    562             {
    563                 pImage->uImageBase -= uSectRva;
    564                 pImage->cbImage    += uSectRva;
    565                 pImage->aRegions[i].uRva = uSectRva;
    566             }
    567 
    568729            uint32_t fProt;
    569730            switch (pThis->aSecHdrs[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE))
     
    587748                                               "%s: Section %u: Unexpected characteristics: %#x (uSectRva=%#x, cbMap=%#x)",
    588749                                               pImage->pszName, i, pThis->aSecHdrs[i].Characteristics, uSectRva, cbMap);
    589 
    590750            }
     751
     752            /* The section bits, only child purification verifies all bits . */
     753            if (   pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION
     754                || (pThis->aSecHdrs[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE)) )
     755            {
     756                rc = VINF_SUCCESS;
     757                if (uRva < uSectRva && !pImage->fApiSetSchemaOnlySection1) /* Any gap worth checking? */
     758                    rc = supHardNtVpFileMemCompareSection(pThis, pImage, uRva, uSectRva - uRva, pImage->pbBits + uRva,
     759                                                          i - 1, NULL, 0, fPrevProt);
     760                if (RT_SUCCESS(rc))
     761                    rc = supHardNtVpFileMemCompareSection(pThis, pImage, uSectRva, cbMap, pImage->pbBits + uSectRva,
     762                                                          i, aSkipAreas, cSkipAreas, fProt);
     763                if (RT_SUCCESS(rc))
     764                {
     765                    uint32_t cbMapAligned = i + 1 < cSections && !pImage->fApiSetSchemaOnlySection1
     766                                          ? RT_ALIGN_32(cbMap, cbSectAlign) : RT_ALIGN_32(cbMap, PAGE_SIZE);
     767                    if (cbMapAligned > cbMap)
     768                        rc = supHardNtVpFileMemCompareSection(pThis, pImage, uSectRva + cbMap, cbMapAligned - cbMap,
     769                                                              g_abRTZeroPage, i, NULL, 0, fProt);
     770                }
     771                if (RT_FAILURE(rc))
     772                    return rc;
     773            }
     774
     775            /* The protection (must be checked afterwards!). */
    591776            rc = supHardNtVpCheckSectionProtection(pThis, pImage, uSectRva, RT_ALIGN_32(cbMap, PAGE_SIZE), fProt);
    592777            if (RT_FAILURE(rc))
    593778                return rc;
     779
     780            fPrevProt = fProt;
    594781        }
    595782
     
    597784        uRva = uSectRva + RT_ALIGN_32(cbMap, cbSectAlign);
    598785    }
    599 
    600     /*
    601      * Check the mapping regions with the image to make sure someone didn't
    602      * fill executable code into some gap in the image.
    603      */
    604     /** @todo not vital. */
    605 
    606 
    607     /*
    608      * Compare executable code.  If we're not loaded at the link address, we
    609      * need to load base relocations and apply them while making the compare.
    610      * A special case
    611      */
    612     /** @todo not vital. */
    613 
    614786
    615787    return VINF_SUCCESS;
     
    632804{
    633805    /*
    634      * Open the image.
    635      */
    636     HANDLE              hFile = RTNT_INVALID_HANDLE_VALUE;
    637     IO_STATUS_BLOCK     Ios   = RTNT_IO_STATUS_BLOCK_INITIALIZER;
    638 
    639     OBJECT_ATTRIBUTES   ObjAttr;
    640     InitializeObjectAttributes(&ObjAttr, &pImage->Name.UniStr, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
    641 #ifdef IN_RING0
    642     ObjAttr.Attributes |= OBJ_KERNEL_HANDLE;
    643 #endif
    644 
    645     NTSTATUS rcNt = NtCreateFile(&hFile,
    646                                  GENERIC_READ,
    647                                  &ObjAttr,
    648                                  &Ios,
    649                                  NULL /* Allocation Size*/,
    650                                  FILE_ATTRIBUTE_NORMAL,
    651                                  FILE_SHARE_READ,
    652                                  FILE_OPEN,
    653                                  FILE_NON_DIRECTORY_FILE,
    654                                  NULL /*EaBuffer*/,
    655                                  0 /*EaLength*/);
    656     if (NT_SUCCESS(rcNt))
    657         rcNt = Ios.Status;
    658     if (!NT_SUCCESS(rcNt))
    659         return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_IMAGE_FILE_OPEN_ERROR,
    660                                   "Error opening image for scanning: %#x (name %ls)", rcNt, pImage->Name.UniStr.Buffer);
    661 
    662     /*
    663      * Validate the signature, then make an attempt at comparing memory and
    664      * disk content.
    665      */
    666     uint32_t fFlags = pImage->fDll ? 0 : SUPHNTVI_F_REQUIRE_BUILD_CERT;
    667     if (pImage->f32bitResourceDll)
    668         fFlags |= SUPHNTVI_F_RESOURCE_IMAGE;
    669     int rc = supHardenedWinVerifyImageByHandle(hFile, pImage->Name.UniStr.Buffer, fFlags, NULL /*pfCacheable*/, pThis->pErrInfo);
    670     if (RT_SUCCESS(rc))
    671         rc = supHardNtVpVerifyImageCompareMemory(pThis, pImage, hProcess, hFile, pThis->pErrInfo);
    672 
    673     /*
    674      * Clean up and return.
    675      */
    676     rcNt = NtClose(hFile);
    677     if (!NT_SUCCESS(rcNt) && RT_SUCCESS(rc))
    678         rc = supHardNtVpSetInfo2(pThis, VERR_SUP_VP_IMAGE_FILE_CLOSE_ERROR,
    679                                 "Error closing image after scanning: %#x (name %ls)", rcNt, pImage->Name.UniStr.Buffer);
     806     * Validate the file signature first, then do the memory compare.
     807     */
     808    int rc;
     809    if (pImage->hLdrMod != NIL_RTLDRMOD)
     810    {
     811        rc = supHardenedWinVerifyImageByLdrMod(pImage->hLdrMod, pImage->Name.UniStr.Buffer, pImage->pNtViRdr,
     812                                               NULL /*pfCacheable*/, pThis->pErrInfo);
     813        if (RT_SUCCESS(rc))
     814        {
     815            rc = supHardNtVpVerifyImageMemoryCompare(pThis, pImage, hProcess, pThis->pErrInfo);
     816
     817            if (pImage->pbBits)
     818            {
     819                suplibHardenedFree(pImage->pbBits);
     820                pImage->pbBits = NULL;
     821            }
     822        }
     823    }
     824    else
     825        rc = supHardNtVpSetInfo2(pThis, VERR_OPEN_FAILED, "hLdrMod is NIL! Impossible!");
    680826    return rc;
    681827}
     
    740886}
    741887#endif /* !VBOX_WITHOUT_DEBUGGER_CHECKS */
    742 
    743 
    744 /**
    745  * Allocates and initalizes a process stat structure for process virtual memory
    746  * scanning.
    747  *
    748  * @returns Pointer to the state structure on success, NULL on failure.
    749  * @param   pErrInfo            Pointer to error info structure. Optional.
    750  */
    751 static PSUPHNTVPSTATE supHardNtVpCreateState(PRTERRINFO pErrInfo)
    752 {
    753     /*
    754      * Allocate the memory.
    755      */
    756     PSUPHNTVPSTATE pThis = (PSUPHNTVPSTATE)suplibHardenedAllocZ(sizeof(*pThis));
    757     if (pThis)
    758     {
    759         pThis->rcResult = VINF_SUCCESS;
    760         pThis->pErrInfo = pErrInfo;
    761         return pThis;
    762     }
    763     supHardNtVpSetInfo1(pErrInfo, VERR_NO_MEMORY, "Failed to allocate %zu bytes for state structures.", sizeof(*pThis));
    764     return NULL;
    765 }
    766888
    767889
     
    9091031
    9101032    /*
     1033     * Checks for multiple mappings of the same DLL but with different image file paths.
     1034     */
     1035    uint32_t i = pThis->cImages;
     1036    while (i-- > 1)
     1037        if (pImage->pszName == pThis->aImages[i].pszName)
     1038            return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_DUPLICATE_DLL_MAPPING,
     1039                                       "Duplicate image entries for %s: %ls and %ls",
     1040                                       pImage->pszName, pImage->Name.UniStr.Buffer, pThis->aImages[i].Name.UniStr.Buffer);
     1041
     1042    /*
    9111043     * Since it's a new image, we expect to be at the start of the mapping now.
    9121044     */
     
    9281060    pImage->uImageBase = (uintptr_t)pMemInfo->AllocationBase;
    9291061    pImage->cbImage    = pMemInfo->RegionSize;
     1062    pImage->hLdrMod    = NIL_RTLDRMOD;
     1063    pImage->pNtViRdr   = NULL;
    9301064    pImage->cRegions   = 1;
    9311065    pImage->aRegions[0].uRva    = 0;
    9321066    pImage->aRegions[0].cb      = (uint32_t)pMemInfo->RegionSize;
    9331067    pImage->aRegions[0].fProt   = pMemInfo->Protect;
     1068
     1069    if (suplibHardenedStrCmp(pImage->pszName, "ntdll.dll") == 0)
     1070        pImage->fNtCreateSectionPatch = true;
     1071    else if (suplibHardenedStrCmp(pImage->pszName, "apisetschema.dll") == 0)
     1072        pImage->fApiSetSchemaOnlySection1 = true; /** @todo Check the ApiSetMap field in the PEB. */
     1073#ifdef VBOX_PERMIT_MORE
     1074    else if (suplibHardenedStrCmp(pImage->pszName, "acres.dll") == 0)
     1075        pImage->f32bitResourceDll = true;
     1076#endif
    9341077
    9351078    return VINF_SUCCESS;
     
    9801123    pImage->cbImage = pImage->aRegions[iRegion].uRva + pImage->aRegions[iRegion].cb;
    9811124    pImage->cRegions++;
     1125    pImage->fApiSetSchemaOnlySection1 = false;
    9821126
    9831127    return VINF_SUCCESS;
     
    9981142static int supHardNtVpScanVirtualMemory(PSUPHNTVPSTATE pThis, HANDLE hProcess)
    9991143{
    1000     SUP_DPRINTF(("supHardNtVpScanVirtualMemory:\n"));
     1144    SUP_DPRINTF(("supHardNtVpScanVirtualMemory: enmKind=%s\n",
     1145                 pThis->enmKind == SUPHARDNTVPKIND_VERIFY_ONLY ? "VERIFY_ONLY" :
     1146                 pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION ? "CHILD_PURIFICATION" : "SELF_PURIFICATION"));
    10011147
    10021148    uint32_t    cXpExceptions = 0;
     
    11011247        else if (MemInfo.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY))
    11021248        {
    1103             supHardNtVpSetInfo2(pThis, VERR_SUP_VP_FOUND_EXEC_MEMORY,
    1104                                 "Found executable memory at %p (%p LB %#zx): type=%#x prot=%#x state=%#x aprot=%#x abase=%p",
    1105                                 uPtrWhere,
    1106                                 MemInfo.BaseAddress,
    1107                                 MemInfo.RegionSize,
    1108                                 MemInfo.Type,
    1109                                 MemInfo.Protect,
    1110                                 MemInfo.State,
    1111                                 MemInfo.AllocationBase,
    1112                                 MemInfo.AllocationProtect);
     1249            SUP_DPRINTF((MemInfo.AllocationBase == MemInfo.BaseAddress
     1250                         ? " *%p-%p %#06x/%#06x %#09x !!\n"
     1251                         : "  %p-%p %#06x/%#06x %#09x !!\n",
     1252                         MemInfo.BaseAddress, (uintptr_t)MemInfo.BaseAddress - MemInfo.RegionSize - 1,
     1253                         MemInfo.Protect, MemInfo.AllocationProtect, MemInfo.Type));
    11131254# ifdef IN_RING3
     1255            if (pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION)
     1256            {
     1257                /*
     1258                 * Free any private executable memory (sysplant.sys allocates executable memory).
     1259                 */
     1260                if (MemInfo.Type == MEM_PRIVATE)
     1261                {
     1262                    SUP_DPRINTF(("supHardNtVpScanVirtualMemory: Freeing exec mem at %p (%p LB %#zx)\n",
     1263                                 uPtrWhere, MemInfo.BaseAddress, MemInfo.RegionSize));
     1264                    PVOID   pvFree = MemInfo.BaseAddress;
     1265                    SIZE_T  cbFree = MemInfo.RegionSize;
     1266                    rcNt = NtFreeVirtualMemory(pThis->hProcess, &pvFree, &cbFree, MEM_RELEASE);
     1267                    if (!NT_SUCCESS(rcNt))
     1268                        supHardNtVpSetInfo2(pThis, VERR_GENERAL_FAILURE,
     1269                                            "NtFreeVirtualMemory (%p LB %#zx) failed: %#x",
     1270                                            MemInfo.BaseAddress, MemInfo.RegionSize, rcNt);
     1271                }
     1272                /*
     1273                 * Unmap mapped memory, failing that, drop exec privileges.
     1274                 */
     1275                else if (MemInfo.Type == MEM_MAPPED)
     1276                {
     1277                    SUP_DPRINTF(("supHardNtVpScanVirtualMemory: Unmapping exec mem at %p (%p/%p LB %#zx)\n",
     1278                                 uPtrWhere, MemInfo.AllocationBase, MemInfo.BaseAddress, MemInfo.RegionSize));
     1279                    rcNt = NtUnmapViewOfSection(pThis->hProcess, MemInfo.AllocationBase);
     1280                    if (!NT_SUCCESS(rcNt))
     1281                    {
     1282                        PVOID  pvCopy = MemInfo.BaseAddress;
     1283                        SIZE_T cbCopy = MemInfo.RegionSize;
     1284                        NTSTATUS rcNt2 = NtProtectVirtualMemory(pThis->hProcess, &pvCopy, &cbCopy, PAGE_NOACCESS, NULL);
     1285                        if (!NT_SUCCESS(rcNt2))
     1286                            rcNt2 = NtProtectVirtualMemory(pThis->hProcess, &pvCopy, &cbCopy, PAGE_READONLY, NULL);
     1287                        if (!NT_SUCCESS(rcNt2))
     1288                            supHardNtVpSetInfo2(pThis, VERR_GENERAL_FAILURE,
     1289                                                "NtUnmapViewOfSection (%p/%p LB %#zx) failed: %#x (%#x)",
     1290                                                MemInfo.AllocationBase, MemInfo.BaseAddress, MemInfo.RegionSize, rcNt, rcNt2);
     1291                    }
     1292                }
     1293                else
     1294                    supHardNtVpSetInfo2(pThis, VERR_GENERAL_FAILURE,
     1295                                        "Unknown executable memory type %#x at %p/%p LB %#zx",
     1296                                        MemInfo.Type, MemInfo.AllocationBase, MemInfo.BaseAddress, MemInfo.RegionSize);
     1297            }
     1298            else
     1299# endif /* IN_RING3 */
     1300                supHardNtVpSetInfo2(pThis, VERR_SUP_VP_FOUND_EXEC_MEMORY,
     1301                                    "Found executable memory at %p (%p LB %#zx): type=%#x prot=%#x state=%#x aprot=%#x abase=%p",
     1302                                    uPtrWhere, MemInfo.BaseAddress, MemInfo.RegionSize, MemInfo.Type, MemInfo.Protect,
     1303                                    MemInfo.State, MemInfo.AllocationBase, MemInfo.AllocationProtect);
     1304
     1305# ifndef IN_RING3
     1306            if (RT_FAILURE(pThis->rcResult))
     1307                return pThis->rcResult;
     1308# endif
    11141309            /* Continue add more information about the problematic process. */
    1115 # else
    1116             return pThis->rcResult;
    1117 # endif
    1118         }
    1119 #endif
     1310        }
     1311#endif /* VBOX_PERMIT_VISUAL_STUDIO_PROFILING */
    11201312        else
    11211313            SUP_DPRINTF((MemInfo.AllocationBase == MemInfo.BaseAddress
     
    11371329    return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_TOO_MANY_MEMORY_REGIONS,
    11381330                               "Too many virtual memory regions.\n");
     1331}
     1332
     1333/**
     1334 * Opens all the images with the IPRT loader, setting both pNtViRdr and hLdrMod
     1335 * for each image.
     1336 *
     1337 * @returns VBox status code.
     1338 * @param   pThis               The process scanning state structure.
     1339 */
     1340static int supHardNtVpOpenImages(PSUPHNTVPSTATE pThis)
     1341{
     1342    unsigned i = pThis->cImages;
     1343    while (i-- > 0)
     1344    {
     1345        PSUPHNTVPIMAGE pImage = &pThis->aImages[i];
     1346
     1347        /*
     1348         * Open the image file.
     1349         */
     1350        HANDLE              hFile = RTNT_INVALID_HANDLE_VALUE;
     1351        IO_STATUS_BLOCK     Ios   = RTNT_IO_STATUS_BLOCK_INITIALIZER;
     1352
     1353        OBJECT_ATTRIBUTES   ObjAttr;
     1354        InitializeObjectAttributes(&ObjAttr, &pImage->Name.UniStr, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
     1355#ifdef IN_RING0
     1356        ObjAttr.Attributes |= OBJ_KERNEL_HANDLE;
     1357#endif
     1358
     1359        NTSTATUS rcNt = NtCreateFile(&hFile,
     1360                                     GENERIC_READ,
     1361                                     &ObjAttr,
     1362                                     &Ios,
     1363                                     NULL /* Allocation Size*/,
     1364                                     FILE_ATTRIBUTE_NORMAL,
     1365                                     FILE_SHARE_READ,
     1366                                     FILE_OPEN,
     1367                                     FILE_NON_DIRECTORY_FILE,
     1368                                     NULL /*EaBuffer*/,
     1369                                     0 /*EaLength*/);
     1370        if (NT_SUCCESS(rcNt))
     1371            rcNt = Ios.Status;
     1372        if (!NT_SUCCESS(rcNt))
     1373            return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_IMAGE_FILE_OPEN_ERROR,
     1374                                      "Error opening image for scanning: %#x (name %ls)", rcNt, pImage->Name.UniStr.Buffer);
     1375
     1376        /*
     1377         * Figure out validation flags we'll be using and create the reader
     1378         * for this image.
     1379         */
     1380        uint32_t fFlags = pImage->fDll ? 0 : SUPHNTVI_F_REQUIRE_BUILD_CERT;
     1381        if (pImage->f32bitResourceDll)
     1382            fFlags |= SUPHNTVI_F_RESOURCE_IMAGE;
     1383
     1384        PSUPHNTVIRDR pNtViRdr;
     1385        int rc = supHardNtViRdrCreate(hFile, pImage->Name.UniStr.Buffer, fFlags, &pNtViRdr);
     1386        if (RT_FAILURE(rc))
     1387        {
     1388            NtClose(hFile);
     1389            return rc;
     1390        }
     1391        pImage->pNtViRdr = pNtViRdr;
     1392
     1393        /*
     1394         * Finally, open the image with the laoder.
     1395         */
     1396        RTLDRMOD hLdrMod;
     1397        RTLDRARCH enmArch = fFlags & SUPHNTVI_F_RC_IMAGE ? RTLDRARCH_X86_32 : RTLDRARCH_HOST;
     1398        if (fFlags & SUPHNTVI_F_RESOURCE_IMAGE)
     1399            enmArch = RTLDRARCH_WHATEVER;
     1400        rc = RTLdrOpenWithReader(&pNtViRdr->Core, RTLDR_O_FOR_VALIDATION, enmArch, &hLdrMod, pThis->pErrInfo);
     1401        if (RT_FAILURE(rc))
     1402            return supHardNtVpSetInfo2(pThis, rc, "RTLdrOpenWithReader failed: %Rrc (Image='%ls').",
     1403                                       rc, pImage->Name.UniStr.Buffer);
     1404
     1405        pImage->hLdrMod = hLdrMod;
     1406    }
     1407
     1408    return VINF_SUCCESS;
    11391409}
    11401410
     
    12561526{
    12571527    /*
    1258      * Check for duplicate entries.
     1528     * Check for duplicate entries (paranoia).
    12591529     */
    12601530    uint32_t i = pThis->cImages;
     
    12761546    uint32_t iNtDll    = UINT32_MAX;
    12771547    uint32_t iKernel32 = UINT32_MAX;
    1278     uint32_t iApiSetSchema = UINT32_MAX;
    12791548    i = pThis->cImages;
    12801549    while (i-- > 0)
     
    12831552        else if (suplibHardenedStrCmp(pThis->aImages[i].pszName, "kernel32.dll") == 0)
    12841553            iKernel32 = i;
    1285         else if (suplibHardenedStrCmp(pThis->aImages[i].pszName, "apisetschema.dll") == 0)
    1286             iApiSetSchema = i;
    1287 #ifdef VBOX_PERMIT_MORE
    1288         else if (suplibHardenedStrCmp(pThis->aImages[i].pszName, "acres.dll") == 0)
    1289             pThis->aImages[i].f32bitResourceDll = true;
    1290 #endif
    12911554    if (iNtDll == UINT32_MAX)
    12921555        return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NO_NTDLL_MAPPING,
    12931556                                   "The process has no NTDLL.DLL.");
    1294     if (iKernel32 == UINT32_MAX)
     1557    if (iKernel32 == UINT32_MAX && pThis->enmKind != SUPHARDNTVPKIND_CHILD_PURIFICATION)
    12951558        return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NO_KERNEL32_MAPPING,
    12961559                                   "The process has no KERNEL32.DLL.");
    1297 
     1560    else if (iKernel32 != UINT32_MAX && pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION)
     1561        return supHardNtVpSetInfo2(pThis, VERR_GENERAL_FAILURE,
     1562                                   "The process already has KERNEL32.DLL loaded.");
    12981563
    12991564    /*
     
    13031568    while (i-- > 0)
    13041569    {
    1305         pThis->aImages[i].fNtCreateSectionPatch     = i == iNtDll;
    1306         pThis->aImages[i].fApiSetSchemaOnlySection1 = i == iApiSetSchema && pThis->aImages[i].cRegions == 1;
    1307 
    13081570        int rc = supHardNtVpVerifyImage(pThis, &pThis->aImages[i], hProcess);
    13091571        if (RT_FAILURE(rc))
     
    13321594 * @param   hProcess            The process to verify.
    13331595 * @param   hThread             A thread in the process (the caller).
     1596 * @param   enmKind             The kind of process verification to perform.
    13341597 * @param   pErrInfo            Pointer to error info structure. Optional.
    13351598 */
    1336 DECLHIDDEN(int) supHardenedWinVerifyProcess(HANDLE hProcess, HANDLE hThread, PRTERRINFO pErrInfo)
    1337 {
     1599DECLHIDDEN(int) supHardenedWinVerifyProcess(HANDLE hProcess, HANDLE hThread, SUPHARDNTVPKIND enmKind, PRTERRINFO pErrInfo)
     1600{
     1601    /*
     1602     * Some basic checks regarding threads and debuggers. We don't need
     1603     * allocate any state memory for these.
     1604     */
    13381605    int rc = supHardNtVpThread(hProcess, hThread, pErrInfo);
    13391606#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
     
    13431610    if (RT_SUCCESS(rc))
    13441611    {
    1345         PSUPHNTVPSTATE pThis = supHardNtVpCreateState(pErrInfo);
     1612        /*
     1613         * Allocate and initialize memory for the state.
     1614         */
     1615        PSUPHNTVPSTATE pThis = (PSUPHNTVPSTATE)suplibHardenedAllocZ(sizeof(*pThis));
    13461616        if (pThis)
    13471617        {
     1618            pThis->enmKind  = enmKind;
     1619            pThis->rcResult = VINF_SUCCESS;
     1620            pThis->hProcess = hProcess;
     1621            pThis->pErrInfo = pErrInfo;
     1622
     1623            /*
     1624             * Perform the verification.
     1625             */
    13481626            rc = supHardNtVpScanVirtualMemory(pThis, hProcess);
     1627            if (RT_SUCCESS(rc))
     1628                rc = supHardNtVpOpenImages(pThis);
    13491629            if (RT_SUCCESS(rc))
    13501630                rc = supHardNtVpCheckExe(pThis, hProcess);
     
    13521632                rc = supHardNtVpCheckDlls(pThis, hProcess);
    13531633
     1634            /*
     1635             * Clean up the state.
     1636             */
     1637            for (uint32_t i = 0; i < pThis->cImages; i++)
     1638            {
     1639                if (pThis->aImages[i].hLdrMod != NIL_RTLDRMOD)
     1640                    RTLdrClose(pThis->aImages[i].hLdrMod);
     1641                else if (pThis->aImages[i].pNtViRdr)
     1642                    pThis->aImages[i].pNtViRdr->Core.pfnDestroy(&pThis->aImages[i].pNtViRdr->Core);
     1643            }
    13541644            suplibHardenedFree(pThis);
    13551645        }
    13561646        else
    1357             rc = VERR_SUP_VP_NO_MEMORY_STATE;
     1647            rc = supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_NO_MEMORY_STATE,
     1648                                     "Failed to allocate %zu bytes for state structures.", sizeof(*pThis));
    13581649    }
    13591650    return rc;
  • trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp

    r52176 r52204  
    4545#include <iprt/initterm.h>
    4646#include <iprt/param.h>
     47#include <iprt/path.h>
    4748#include <iprt/zero.h>
    4849
     
    5051#include "win/SUPHardenedVerify-win.h"
    5152#include "../SUPDrvIOC.h"
     53
     54#ifndef IMAGE_SCN_TYPE_NOLOAD
     55# define IMAGE_SCN_TYPE_NOLOAD 0x00000002
     56#endif
    5257
    5358
     
    5863 * This just needs to be unique enough to avoid most confusion with real
    5964 * executable names,  there are other checks in place to make sure we've respanwed. */
    60 #define SUPR3_RESPAWN_1_ARG0  "81954AF5-4D2F-31EB-A142-B7AF187A1C41-suplib-2ndchild"
     65#define SUPR3_RESPAWN_1_ARG0  "0384ad8f-4f0c-d002-e3ae-5597cd55af98-suplib-2ndchild"
    6166
    6267/** The first argument of a respawed stub when respawned for the second time.
    6368 * This just needs to be unique enough to avoid most confusion with real
    6469 * executable names,  there are other checks in place to make sure we've respanwed. */
    65 #define SUPR3_RESPAWN_2_ARG0  "81954AF5-4D2F-31EB-A142-B7AF187A1C41-suplib-3rdchild"
     70#define SUPR3_RESPAWN_2_ARG0  "0384ad8f-4f0c-d002-e3ae-5597cd55af98-suplib-3rdchild"
    6671
    6772/** Unconditional assertion. */
     
    962967    /*
    963968     * Install a anti debugging hack before we continue.  This prevents most
    964      * notifications from ending up in the debugger.
     969     * notifications from ending up in the debugger. (Also applied to the
     970     * child process when respawning.)
    965971     */
    966972    rcNt = NtSetInformationThread(NtCurrentThread(), ThreadHideFromDebugger, NULL, 0);
     
    11731179{
    11741180    RTErrInfoInitStatic(&g_ErrInfoStatic);
    1175     int rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), &g_ErrInfoStatic.Core);
     1181    int rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(),
     1182                                         SUPHARDNTVPKIND_VERIFY_ONLY, &g_ErrInfoStatic.Core);
    11761183    if (RT_FAILURE(rc))
    11771184        supR3HardenedFatalMsg("supR3HardenedWinVerifyProcess", kSupInitOp_Integrity, rc,
     
    17301737    if (!NT_SUCCESS(rcNt))
    17311738        return RTErrInfoSetF(pThis->pErrInfo, VERR_GENERAL_FAILURE, "NtWriteVirtualMemory/Peb failed: %#x", rcNt);
    1732 
    1733     return VINF_SUCCESS;
    1734 }
    1735 
    1736 
    1737 DECLINLINE(PIMAGE_NT_HEADERS) supR3HardNtPuChFindNtHeaders(uint8_t *pbBuf, size_t cbBuf)
    1738 {
    1739     PIMAGE_DOS_HEADER pMzHdr = (PIMAGE_DOS_HEADER)pbBuf;
    1740     if (cbBuf >= sizeof(*pMzHdr))
    1741     {
    1742         if (pMzHdr->e_magic == IMAGE_DOS_SIGNATURE)
    1743         {
    1744             if (pMzHdr->e_lfanew >= cbBuf)
    1745                 return NULL;
    1746             cbBuf -= pMzHdr->e_lfanew;
    1747             pbBuf += pMzHdr->e_lfanew;
    1748         }
    1749     }
    1750 
    1751     PIMAGE_NT_HEADERS pNtHdrs = (PIMAGE_NT_HEADERS)pbBuf;
    1752     if (cbBuf >= sizeof(IMAGE_NT_HEADERS))
    1753     {
    1754         if (pNtHdrs->Signature == IMAGE_NT_SIGNATURE)
    1755             return pNtHdrs;
    1756     }
    1757     return NULL;
    1758 }
    1759 
    1760 
    1761 static uint32_t supR3HardNtPuChFindFirstDiff(void const *pvBuf1, void const *pvBuf2, size_t cbBuf)
    1762 {
    1763     uint8_t const *pabBuf1 = (uint8_t const *)pvBuf1;
    1764     uint8_t const *pabBuf2 = (uint8_t const *)pvBuf2;
    1765     uint32_t off = 0;
    1766     while (off < cbBuf && pabBuf1[off] == pabBuf2[off])
    1767         off++;
    1768     return off;
    1769 }
    1770 
    1771 
    1772 static NTSTATUS supR3HardNtPuChRestoreImageBits(PSUPR3HARDNTPUCH pThis, PVOID pvChildAddr,
    1773                                                 void const *pvFileBits, size_t cbToRestore, uint32_t fCorrectProtection)
    1774 {
    1775     PVOID  pvProt   = pvChildAddr;
    1776     SIZE_T cbProt   = cbToRestore;
    1777     ULONG  fOldProt = 0;
    1778     NTSTATUS rcNt = NtProtectVirtualMemory(pThis->hProcess, &pvProt, &cbProt, PAGE_READWRITE, &fOldProt);
    1779     if (NT_SUCCESS(rcNt))
    1780     {
    1781         SIZE_T cbIgnored;
    1782         rcNt = NtWriteVirtualMemory(pThis->hProcess, pvChildAddr, pvFileBits, cbToRestore, &cbIgnored);
    1783 
    1784         pvProt = pvChildAddr;
    1785         cbProt = cbToRestore;
    1786         NTSTATUS rcNt2 = NtProtectVirtualMemory(pThis->hProcess, &pvProt, &cbProt, fCorrectProtection, &fOldProt);
    1787         if (NT_SUCCESS(rcNt))
    1788             rcNt = rcNt2;
    1789     }
    1790     return rcNt;
    1791 }
    1792 
    1793 
    1794 static int supR3HardNtPuChSanitizeImage(PSUPR3HARDNTPUCH pThis, PMEMORY_BASIC_INFORMATION pMemInfo)
    1795 {
    1796     /*
    1797      * Get the image name.
    1798      */
    1799     union
    1800     {
    1801         UNICODE_STRING UniStr;
    1802         uint8_t abPadding[4096];
    1803     } uBuf;
    1804     SIZE_T cbActual;
    1805     NTSTATUS rcNt = NtQueryVirtualMemory(pThis->hProcess,
    1806                                          pMemInfo->BaseAddress,
    1807                                          MemorySectionName,
    1808                                          &uBuf,
    1809                                          sizeof(uBuf) - sizeof(WCHAR),
    1810                                          &cbActual);
    1811     if (!NT_SUCCESS(rcNt))
    1812         return RTErrInfoSetF(pThis->pErrInfo, VERR_GENERAL_FAILURE,
    1813                              "NtQueryVirtualMemory/MemorySectionName failed for %p: %#x", pMemInfo->BaseAddress, rcNt);
    1814     uBuf.UniStr.Buffer[uBuf.UniStr.Length / sizeof(WCHAR)] = '\0';
    1815     SUP_DPRINTF(("supR3HardNtPuChSanitizeImage: %p '%ls'\n", pMemInfo->BaseAddress, uBuf.UniStr.Buffer));
    1816 
    1817 
    1818     /*
    1819      * Open the file.
    1820      */
    1821     HANDLE              hFile = RTNT_INVALID_HANDLE_VALUE;
    1822     IO_STATUS_BLOCK     Ios   = RTNT_IO_STATUS_BLOCK_INITIALIZER;
    1823 
    1824     OBJECT_ATTRIBUTES ObjAttr;
    1825     InitializeObjectAttributes(&ObjAttr, &uBuf.UniStr, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
    1826 
    1827     rcNt = NtCreateFile(&hFile,
    1828                         FILE_READ_DATA | SYNCHRONIZE,
    1829                         &ObjAttr,
    1830                         &Ios,
    1831                         NULL /* Allocation Size*/,
    1832                         FILE_ATTRIBUTE_NORMAL,
    1833                         FILE_SHARE_READ,
    1834                         FILE_OPEN,
    1835                         FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
    1836                         NULL /*EaBuffer*/,
    1837                         0 /*EaLength*/);
    1838     if (NT_SUCCESS(rcNt))
    1839         rcNt = Ios.Status;
    1840     if (!NT_SUCCESS(rcNt))
    1841         return RTErrInfoSetF(pThis->pErrInfo, RTErrConvertFromNtStatus(rcNt),
    1842                              "NtCreateFile returned %#x opening '%ls'.", rcNt, uBuf.UniStr.Buffer);
    1843 
    1844     /*
    1845      * Read the headers, ASSUMES the stub isn't pushing the optional header out
    1846      * of a 4KB buffer.  Also ASSUMEs that the file is more than 4KB in size.
    1847      */
    1848     int             rc;
    1849     uint8_t         abFile[_4K];
    1850     LARGE_INTEGER   off;
    1851     off.QuadPart = 0;
    1852     rcNt = NtReadFile(hFile, NULL, NULL, NULL, &Ios, abFile, sizeof(abFile), &off, NULL);
    1853     if (NT_SUCCESS(rcNt))
    1854         rcNt = Ios.Status;
    1855     if (NT_SUCCESS(rcNt))
    1856     {
    1857         PIMAGE_NT_HEADERS pNtFile = supR3HardNtPuChFindNtHeaders(abFile, sizeof(abFile));
    1858         if (pNtFile)
    1859         {
    1860             /*
    1861              * Read the first 4KB of the process memory.
    1862              */
    1863             uint8_t abProc[_4K];
    1864             SIZE_T cbActualMem;
    1865             rcNt = NtReadVirtualMemory(pThis->hProcess, pMemInfo->BaseAddress, abProc, sizeof(abProc), &cbActualMem);
    1866             if (NT_SUCCESS(rcNt))
    1867             {
    1868                 /*
    1869                  * Watch out for apisetschema.dll, it only has section #1
    1870                  * mapped into the process.
    1871                  */
    1872                 if (   g_uNtVerCombined < SUP_NT_VER_W70
    1873                     || pThis->Peb.Diff3.W7.ApiSetMap != pMemInfo->BaseAddress
    1874                     || !supR3HardNtIsNamedSystem32Dll(&uBuf.UniStr, "apisetschema.dll"))
    1875                 {
    1876                     PIMAGE_NT_HEADERS pNtProc = supR3HardNtPuChFindNtHeaders(abProc, sizeof(abProc));
    1877                     if ((uintptr_t)pNtProc - (uintptr_t)abProc == (uintptr_t)pNtFile - (uintptr_t)abFile)
    1878                     {
    1879                         pNtFile->OptionalHeader.ImageBase = pNtProc->OptionalHeader.ImageBase;
    1880 
    1881                         size_t cbCompare = RT_MIN(pNtFile->OptionalHeader.SizeOfHeaders, sizeof(abProc));
    1882                         if (cbCompare < sizeof(abFile))
    1883                             RT_BZERO(&abFile[cbCompare], sizeof(abFile) - cbCompare);
    1884                         if (!memcmp(abFile, abProc, cbCompare))
    1885                             rc = VINF_SUCCESS;
    1886                         else
    1887                         {
    1888                             SUP_DPRINTF(("supR3HardNtPuChSanitizeImage: Header diff @%#x in ('%ls')\n",
    1889                                          supR3HardNtPuChFindFirstDiff(abFile, abProc, sizeof(abProc)), uBuf.UniStr.Buffer));
    1890                             rc = supR3HardNtPuChRestoreImageBits(pThis, pMemInfo->BaseAddress, abFile, cbCompare, PAGE_READONLY);
    1891                         }
    1892                     }
    1893                     else
    1894                         rc = RTErrInfoSetF(pThis->pErrInfo, VERR_GENERAL_FAILURE,
    1895                                            "PE header offset differs between file and memory: offProc=%p offFile=%p '%ls'\n",
    1896                                            (uintptr_t)pNtProc - (uintptr_t)abProc, (uintptr_t)pNtFile - (uintptr_t)abFile,
    1897                                            uBuf.UniStr.Buffer);
    1898                 }
    1899                 else
    1900                 {
    1901                     /*
    1902                      * Validate the API set map.
    1903                      */
    1904                 }
    1905             }
    1906             else
    1907                 rc = RTErrInfoSetF(pThis->pErrInfo, RTErrConvertFromNtStatus(rcNt),
    1908                                    "NtReadVirtualMemory returned %#x read 4KB at %p ('%ls').", rcNt,
    1909                                    pMemInfo->BaseAddress, uBuf.UniStr.Buffer);
    1910         }
    1911         else
    1912             rc = RTErrInfoSetF(pThis->pErrInfo, RTErrConvertFromNtStatus(rcNt),
    1913                                "No PE header in the first 4KB of '%ls'.", rcNt, uBuf.UniStr.Buffer);
    1914     }
    1915     else
    1916         rc = RTErrInfoSetF(pThis->pErrInfo, RTErrConvertFromNtStatus(rcNt),
    1917                            "NtReadFile returned %#x reading the header of '%ls'.", rcNt, uBuf.UniStr.Buffer);
    1918 
    1919     NtClose(hFile);
    1920 
    1921     return rc;
    1922 }
    1923 
    1924 
    1925 static int supR3HardNtPuChSanitizeMemory(PSUPR3HARDNTPUCH pThis)
    1926 {
    1927     /*
    1928      * Find and remove/disable any unwanted executable memory.
    1929      */
    1930     uint32_t    cXpExceptions = 0;
    1931     uintptr_t   cbAdvance = 0;
    1932     uintptr_t   uPtrWhere = 0;
    1933     for (uint32_t i = 0; i < 1024; i++)
    1934     {
    1935         SIZE_T                      cbActual = 0;
    1936         MEMORY_BASIC_INFORMATION    MemInfo  = { 0, 0, 0, 0, 0, 0, 0 };
    1937         NTSTATUS rcNt = NtQueryVirtualMemory(pThis->hProcess,
    1938                                              (void const *)uPtrWhere,
    1939                                              MemoryBasicInformation,
    1940                                              &MemInfo,
    1941                                              sizeof(MemInfo),
    1942                                              &cbActual);
    1943         if (!NT_SUCCESS(rcNt))
    1944             break;
    1945         //SUP_DPRINTF(("supR3HardNtPuChSanitizeMemory: %p (%p LB %#zx): type=%#010x prot=%#06x state=%#07x aprot=%#06x abase=%p\n",
    1946         //             uPtrWhere, MemInfo.BaseAddress, MemInfo.RegionSize,MemInfo.Type,
    1947         //             MemInfo.Protect, MemInfo.State, MemInfo.AllocationBase, MemInfo.AllocationProtect));
    1948 
    1949         if (   MemInfo.Type == SEC_IMAGE
    1950             || MemInfo.Type == SEC_PROTECTED_IMAGE
    1951             || MemInfo.Type == (SEC_IMAGE | SEC_PROTECTED_IMAGE))
    1952         {
    1953             /*
    1954              * Restore modified parts of the image from file.
    1955              */
    1956             if (MemInfo.BaseAddress == MemInfo.AllocationBase)
    1957             {
    1958                 int rc = supR3HardNtPuChSanitizeImage(pThis, &MemInfo);
    1959                 if (RT_FAILURE(rc))
    1960                     return rc;
    1961             }
    1962         }
    1963         /*
    1964          * Executable memory outside an image is evil by definition.
    1965          */
    1966         else if (MemInfo.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY))
    1967         {
    1968             /*
    1969              * XP, W2K3 exception: Ignore the CSRSS read-only region as best we can.
    1970              */
    1971             if (   (MemInfo.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY))
    1972                    == PAGE_EXECUTE_READ
    1973                 && cXpExceptions == 0
    1974                 && (uintptr_t)MemInfo.BaseAddress >= UINT32_C(0x78000000)
    1975                 /* && MemInfo.BaseAddress == pPeb->ReadOnlySharedMemoryBase */
    1976                 && g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 0) )
    1977                 cXpExceptions++;
    1978 #ifndef VBOX_PERMIT_VISUAL_STUDIO_PROFILING
    1979             else
    1980             {
    1981                 /*
    1982                  * Free any private executable memory (sysplant.sys allocates executable memory).
    1983                  */
    1984                 if (MemInfo.Type == MEM_PRIVATE)
    1985                 {
    1986                     SUP_DPRINTF(("supR3HardNtPuChSanitizeMemory: Freeing exec mem at %p (%p LB %#zx)\n",
    1987                                  uPtrWhere, MemInfo.BaseAddress, MemInfo.RegionSize));
    1988                     PVOID   pvFree = MemInfo.BaseAddress;
    1989                     SIZE_T  cbFree = MemInfo.RegionSize;
    1990                     rcNt = NtFreeVirtualMemory(pThis->hProcess, &pvFree, &cbFree, MEM_RELEASE);
    1991                     if (!NT_SUCCESS(rcNt))
    1992                         return RTErrInfoSetF(pThis->pErrInfo, VERR_GENERAL_FAILURE,
    1993                                              "NtFreeVirtualMemory (%p LB %#zx) failed: %#x",
    1994                                              MemInfo.BaseAddress, MemInfo.RegionSize, rcNt);
    1995                 }
    1996                 /*
    1997                  * Unmap mapped memory, failing that, drop exec privileges.
    1998                  */
    1999                 else if (MemInfo.Type == MEM_MAPPED)
    2000                 {
    2001                     SUP_DPRINTF(("supR3HardNtPuChSanitizeMemory: Unmapping exec mem at %p (%p/%p LB %#zx)\n",
    2002                                  uPtrWhere, MemInfo.AllocationBase, MemInfo.BaseAddress, MemInfo.RegionSize));
    2003                     rcNt = NtUnmapViewOfSection(pThis->hProcess, MemInfo.AllocationBase);
    2004                     if (!NT_SUCCESS(rcNt))
    2005                     {
    2006                         PVOID  pvCopy = MemInfo.BaseAddress;
    2007                         SIZE_T cbCopy = MemInfo.RegionSize;
    2008                         NTSTATUS rcNt2 = NtProtectVirtualMemory(pThis->hProcess, &pvCopy, &cbCopy, PAGE_NOACCESS, NULL);
    2009                         if (!NT_SUCCESS(rcNt2))
    2010                             rcNt2 = NtProtectVirtualMemory(pThis->hProcess, &pvCopy, &cbCopy, PAGE_READONLY, NULL);
    2011                         if (!NT_SUCCESS(rcNt2))
    2012                             return RTErrInfoSetF(pThis->pErrInfo, VERR_GENERAL_FAILURE,
    2013                                                  "NtUnmapViewOfSection (%p/%p LB %#zx) failed: %#x (%#x)",
    2014                                                  MemInfo.AllocationBase, MemInfo.BaseAddress, MemInfo.RegionSize, rcNt, rcNt2);
    2015                     }
    2016                 }
    2017                 else
    2018                     return RTErrInfoSetF(pThis->pErrInfo, VERR_GENERAL_FAILURE,
    2019                                          "Unknown executable memory type %#x at %p/%p LB %#zx",
    2020                                          MemInfo.Type, MemInfo.AllocationBase, MemInfo.BaseAddress, MemInfo.RegionSize);
    2021             }
    2022 #endif
    2023         }
    2024 
    2025         /*
    2026          * Advance.
    2027          */
    2028         cbAdvance = MemInfo.RegionSize;
    2029         if (uPtrWhere + cbAdvance <= uPtrWhere)
    2030             break;
    2031         uPtrWhere += MemInfo.RegionSize;
    2032     }
    20331739
    20341740    return VINF_SUCCESS;
     
    21531859
    21541860    /*
    2155      * Do the work.
     1861     * Do the work, the last bit we tag along with the process verfication code.
    21561862     */
    21571863    int rc = supR3HardNtPuChScrewUpPebForInitialImageEvents(&This);
     
    21611867        rc = supR3HardNtPuChSanitizePeb(&This);
    21621868    if (RT_SUCCESS(rc))
    2163         rc = supR3HardNtPuChSanitizeMemory(&This);
     1869        rc = supHardenedWinVerifyProcess(hProcess, hThread, SUPHARDNTVPKIND_CHILD_PURIFICATION, pErrInfo);
    21641870
    21651871    return rc;
     
    23012007#endif
    23022008
     2009#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
     2010    /*
     2011     * Apply anti debugger notification trick to the thread.  (Also done in
     2012     * supR3HardenedWinInstallHooks.)
     2013     */
     2014    rcNt = NtSetInformationThread(NtCurrentThread(), ThreadHideFromDebugger, NULL, 0);
     2015    if (!NT_SUCCESS(rcNt))
     2016    {
     2017        NtTerminateProcess(hProcess, DBG_TERMINATE_PROCESS);
     2018        supR3HardenedError(rcNt, true /*fFatal*/, "NtSetInformationThread/ThreadHideFromDebugger failed: %#x\n", rcNt);
     2019    }
     2020#endif
    23032021
    23042022    /*
     
    26872405
    26882406    if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
     2407    {
     2408        /* Do a self purification to cure avast's weird NtOpenFile write-thru
     2409           change in GetBinaryTypeW change in kernel32. */
     2410        supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_SELF_PURIFICATION, NULL);
     2411
    26892412        supR3HardenedWinInstallHooks();
     2413    }
    26902414
    26912415#ifndef VBOX_WITH_VISTA_NO_SP
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette