"Fossies" - the Fresh Open Source Software Archive

Member "VirtualBox-6.1.18/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp" (7 Jan 2021, 135556 Bytes) of package /linux/misc/VirtualBox-6.1.18.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "SUPHardenedVerifyImage-win.cpp": 6.1.14a_vs_6.1.16.

    1 /* $Id: SUPHardenedVerifyImage-win.cpp $ */
    2 /** @file
    3  * VirtualBox Support Library/Driver - Hardened Image Verification, Windows.
    4  */
    5 
    6 /*
    7  * Copyright (C) 2006-2020 Oracle Corporation
    8  *
    9  * This file is part of VirtualBox Open Source Edition (OSE), as
   10  * available from http://www.virtualbox.org. This file is free software;
   11  * you can redistribute it and/or modify it under the terms of the GNU
   12  * General Public License (GPL) as published by the Free Software
   13  * Foundation, in version 2 as it comes in the "COPYING" file of the
   14  * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
   15  * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
   16  *
   17  * The contents of this file may alternatively be used under the terms
   18  * of the Common Development and Distribution License Version 1.0
   19  * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
   20  * VirtualBox OSE distribution, in which case the provisions of the
   21  * CDDL are applicable instead of those of the GPL.
   22  *
   23  * You may elect to license modified versions of this file under the
   24  * terms and conditions of either the GPL or the CDDL or both.
   25  */
   26 
   27 
   28 /*********************************************************************************************************************************
   29 *   Header Files                                                                                                                 *
   30 *********************************************************************************************************************************/
   31 #ifdef IN_RING0
   32 # ifndef IPRT_NT_MAP_TO_ZW
   33 #  define IPRT_NT_MAP_TO_ZW
   34 # endif
   35 # include <iprt/nt/nt.h>
   36 # include <ntimage.h>
   37 #else
   38 # include <iprt/nt/nt-and-windows.h>
   39 # include "Wintrust.h"
   40 # include "Softpub.h"
   41 # include "mscat.h"
   42 # ifndef LOAD_LIBRARY_SEARCH_APPLICATION_DIR
   43 #  define LOAD_LIBRARY_SEARCH_SYSTEM32           0x800
   44 # endif
   45 #endif
   46 
   47 #include <VBox/sup.h>
   48 #include <VBox/err.h>
   49 #include <iprt/ctype.h>
   50 #include <iprt/ldr.h>
   51 #include <iprt/log.h>
   52 #include <iprt/path.h>
   53 #include <iprt/string.h>
   54 #include <iprt/utf16.h>
   55 #include <iprt/crypto/pkcs7.h>
   56 #include <iprt/crypto/store.h>
   57 
   58 #ifdef IN_RING0
   59 # include "SUPDrvInternal.h"
   60 #else
   61 # include "SUPLibInternal.h"
   62 #endif
   63 #include "win/SUPHardenedVerify-win.h"
   64 
   65 
   66 /*********************************************************************************************************************************
   67 *   Defined Constants And Macros                                                                                                 *
   68 *********************************************************************************************************************************/
   69 /** The size of static hash (output) buffers.
   70  * Avoids dynamic allocations and cleanups for of small buffers as well as extra
   71  * calls for getting the appropriate buffer size.  The largest digest in regular
   72  * use by current windows version is SHA-512, we double this and hope it's
   73  * enough a good while. */
   74 #define SUPHARDNTVI_MAX_CAT_HASH_SIZE   128
   75 
   76 
   77 #if defined(VBOX_PERMIT_EVEN_MORE) && !defined(VBOX_PERMIT_MORE)
   78 # error "VBOX_PERMIT_EVEN_MORE without VBOX_PERMIT_MORE!"
   79 #endif
   80 
   81 
   82 /*********************************************************************************************************************************
   83 *   Structures and Typedefs                                                                                                      *
   84 *********************************************************************************************************************************/
   85 
   86 #ifdef IN_RING3
   87 typedef LONG (WINAPI * PFNWINVERIFYTRUST)(HWND hwnd, GUID const *pgActionID, PVOID pWVTData);
   88 typedef BOOL (WINAPI * PFNCRYPTCATADMINACQUIRECONTEXT)(HCATADMIN *phCatAdmin, const GUID *pGuidSubsystem, DWORD dwFlags);
   89 typedef BOOL (WINAPI * PFNCRYPTCATADMINACQUIRECONTEXT2)(HCATADMIN *phCatAdmin, const GUID *pGuidSubsystem, PCWSTR pwszHashAlgorithm,
   90                                                         struct _CERT_STRONG_SIGN_PARA const *pStrongHashPolicy, DWORD dwFlags);
   91 typedef BOOL (WINAPI * PFNCRYPTCATADMINCALCHASHFROMFILEHANDLE)(HANDLE hFile, DWORD *pcbHash, BYTE *pbHash, DWORD dwFlags);
   92 typedef BOOL (WINAPI * PFNCRYPTCATADMINCALCHASHFROMFILEHANDLE2)(HCATADMIN hCatAdmin, HANDLE hFile, DWORD *pcbHash,
   93                                                                 BYTE *pbHash, DWORD dwFlags);
   94 typedef HCATINFO (WINAPI *PFNCRYPTCATADMINENUMCATALOGFROMHASH)(HCATADMIN hCatAdmin, BYTE *pbHash, DWORD cbHash,
   95                                                                DWORD dwFlags, HCATINFO *phPrevCatInfo);
   96 typedef BOOL (WINAPI * PFNCRYPTCATADMINRELEASECATALOGCONTEXT)(HCATADMIN hCatAdmin, HCATINFO hCatInfo, DWORD dwFlags);
   97 typedef BOOL (WINAPI * PFNCRYPTCATDADMINRELEASECONTEXT)(HCATADMIN hCatAdmin, DWORD dwFlags);
   98 typedef BOOL (WINAPI * PFNCRYPTCATCATALOGINFOFROMCONTEXT)(HCATINFO hCatInfo, CATALOG_INFO *psCatInfo, DWORD dwFlags);
   99 
  100 typedef HCERTSTORE (WINAPI *PFNCERTOPENSTORE)(PCSTR pszStoreProvider, DWORD dwEncodingType, HCRYPTPROV_LEGACY hCryptProv,
  101                                               DWORD dwFlags, const void *pvParam);
  102 typedef BOOL (WINAPI *PFNCERTCLOSESTORE)(HCERTSTORE hCertStore, DWORD dwFlags);
  103 typedef PCCERT_CONTEXT (WINAPI *PFNCERTENUMCERTIFICATESINSTORE)(HCERTSTORE hCertStore, PCCERT_CONTEXT pPrevCertContext);
  104 
  105 typedef NTSTATUS (WINAPI *PFNBCRYPTOPENALGORTIHMPROVIDER)(BCRYPT_ALG_HANDLE *phAlgo, PCWSTR pwszAlgoId,
  106                                                           PCWSTR pwszImpl, DWORD dwFlags);
  107 #endif
  108 
  109 
  110 /*********************************************************************************************************************************
  111 *   Global Variables                                                                                                             *
  112 *********************************************************************************************************************************/
  113 /** The build certificate. */
  114 static RTCRX509CERTIFICATE  g_BuildX509Cert;
  115 
  116 /** Store for root software publisher certificates. */
  117 static RTCRSTORE            g_hSpcRootStore = NIL_RTCRSTORE;
  118 /** Store for root NT kernel certificates. */
  119 static RTCRSTORE            g_hNtKernelRootStore = NIL_RTCRSTORE;
  120 
  121 /** Store containing SPC, NT kernel signing, and timestamp root certificates. */
  122 static RTCRSTORE            g_hSpcAndNtKernelRootStore = NIL_RTCRSTORE;
  123 /** Store for supplemental certificates for use with
  124  * g_hSpcAndNtKernelRootStore. */
  125 static RTCRSTORE            g_hSpcAndNtKernelSuppStore = NIL_RTCRSTORE;
  126 
  127 /** The full \\SystemRoot\\System32 path. */
  128 SUPSYSROOTDIRBUF            g_System32NtPath;
  129 /** The full \\SystemRoot\\WinSxS path. */
  130 SUPSYSROOTDIRBUF            g_WinSxSNtPath;
  131 #if defined(IN_RING3) && !defined(VBOX_PERMIT_EVEN_MORE)
  132 /** The full 'Program Files' path. */
  133 SUPSYSROOTDIRBUF            g_ProgramFilesNtPath;
  134 # ifdef RT_ARCH_AMD64
  135 /** The full 'Program Files (x86)' path. */
  136 SUPSYSROOTDIRBUF            g_ProgramFilesX86NtPath;
  137 # endif
  138 /** The full 'Common Files' path. */
  139 SUPSYSROOTDIRBUF            g_CommonFilesNtPath;
  140 # ifdef RT_ARCH_AMD64
  141 /** The full 'Common Files (x86)' path. */
  142 SUPSYSROOTDIRBUF            g_CommonFilesX86NtPath;
  143 # endif
  144 #endif /* IN_RING3 && !VBOX_PERMIT_MORE*/
  145 
  146 /**
  147  * Blacklisted DLL names.
  148  */
  149 const RTSTRTUPLE g_aSupNtViBlacklistedDlls[] =
  150 {
  151     { RT_STR_TUPLE("SCROBJ.dll") },
  152     { NULL, 0 } /* terminator entry */
  153 };
  154 
  155 
  156 static union
  157 {
  158     SID                     Sid;
  159     uint8_t                 abPadding[SECURITY_MAX_SID_SIZE];
  160 }
  161 /** The TrustedInstaller SID (Vista+). */
  162                             g_TrustedInstallerSid,
  163 /** Local system ID (S-1-5-21). */
  164                             g_LocalSystemSid,
  165 /** Builtin Administrators group alias (S-1-5-32-544). */
  166                             g_AdminsGroupSid;
  167 
  168 
  169 /** Set after we've retrived other SPC root certificates from the system. */
  170 static bool                 g_fHaveOtherRoots = false;
  171 
  172 #if defined(IN_RING3) && !defined(IN_SUP_HARDENED_R3)
  173 /** Combined windows NT version number.  See SUP_MAKE_NT_VER_COMBINED and
  174  *  SUP_MAKE_NT_VER_SIMPLE. */
  175 uint32_t                    g_uNtVerCombined;
  176 #endif
  177 
  178 #ifdef IN_RING3
  179 /** Timestamp hack working around issues with old DLLs that we ship.
  180  * See supHardenedWinVerifyImageByHandle() for details.  */
  181 static uint64_t             g_uBuildTimestampHack = 0;
  182 #endif
  183 
  184 #ifdef IN_RING3
  185 /** Pointer to WinVerifyTrust. */
  186 PFNWINVERIFYTRUST                       g_pfnWinVerifyTrust;
  187 /** Pointer to CryptCATAdminAcquireContext. */
  188 PFNCRYPTCATADMINACQUIRECONTEXT          g_pfnCryptCATAdminAcquireContext;
  189 /** Pointer to CryptCATAdminAcquireContext2 if available. */
  190 PFNCRYPTCATADMINACQUIRECONTEXT2         g_pfnCryptCATAdminAcquireContext2;
  191 /** Pointer to CryptCATAdminCalcHashFromFileHandle. */
  192 PFNCRYPTCATADMINCALCHASHFROMFILEHANDLE  g_pfnCryptCATAdminCalcHashFromFileHandle;
  193 /** Pointer to CryptCATAdminCalcHashFromFileHandle2. */
  194 PFNCRYPTCATADMINCALCHASHFROMFILEHANDLE2 g_pfnCryptCATAdminCalcHashFromFileHandle2;
  195 /** Pointer to CryptCATAdminEnumCatalogFromHash. */
  196 PFNCRYPTCATADMINENUMCATALOGFROMHASH     g_pfnCryptCATAdminEnumCatalogFromHash;
  197 /** Pointer to CryptCATAdminReleaseCatalogContext. */
  198 PFNCRYPTCATADMINRELEASECATALOGCONTEXT   g_pfnCryptCATAdminReleaseCatalogContext;
  199 /** Pointer to CryptCATAdminReleaseContext. */
  200 PFNCRYPTCATDADMINRELEASECONTEXT         g_pfnCryptCATAdminReleaseContext;
  201 /** Pointer to CryptCATCatalogInfoFromContext. */
  202 PFNCRYPTCATCATALOGINFOFROMCONTEXT       g_pfnCryptCATCatalogInfoFromContext;
  203 
  204 /** Where we store the TLS entry for detecting WinVerifyTrustRecursion. */
  205 static uint32_t                         g_iTlsWinVerifyTrustRecursion = UINT32_MAX;
  206 /** Fallback WinVerifyTrust recursion protection. */
  207 static uint32_t volatile                g_idActiveThread = UINT32_MAX;
  208 
  209 #endif
  210 
  211 
  212 /*********************************************************************************************************************************
  213 *   Internal Functions                                                                                                           *
  214 *********************************************************************************************************************************/
  215 #ifdef IN_RING3
  216 static int supR3HardNtViCallWinVerifyTrust(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PRTERRINFO pErrInfo,
  217                                            PFNWINVERIFYTRUST pfnWinVerifyTrust, HRESULT *phrcWinVerifyTrust);
  218 static int supR3HardNtViCallWinVerifyTrustCatFile(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PRTERRINFO pErrInfo,
  219                                                   PFNWINVERIFYTRUST pfnWinVerifyTrust);
  220 #endif
  221 
  222 
  223 
  224 
  225 /** @copydoc RTLDRREADER::pfnRead */
  226 static DECLCALLBACK(int) supHardNtViRdrRead(PRTLDRREADER pReader, void *pvBuf, size_t cb, RTFOFF off)
  227 {
  228     PSUPHNTVIRDR pNtViRdr = (PSUPHNTVIRDR)pReader;
  229     Assert(pNtViRdr->Core.uMagic == RTLDRREADER_MAGIC);
  230     NTSTATUS rcNt;
  231 
  232     /* Check for type overflow (paranoia). */
  233     if ((ULONG)cb != cb)
  234         return VERR_OUT_OF_RANGE;
  235 
  236 #ifdef IN_RING3
  237     /* Make sure the event semaphore is reset (normally we don't use one). */
  238     if (pNtViRdr->hEvent)
  239     {
  240         rcNt = NtClearEvent(pNtViRdr->hEvent);
  241         if (!NT_SUCCESS(rcNt))
  242             return RTErrConvertFromNtStatus(rcNt);
  243     }
  244 #endif
  245 
  246     /* Perform the read. */
  247     LARGE_INTEGER offNt;
  248     offNt.QuadPart = off;
  249 
  250     IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
  251     rcNt = NtReadFile(pNtViRdr->hFile,
  252                       pNtViRdr->hEvent,
  253                       NULL /*ApcRoutine*/,
  254                       NULL /*ApcContext*/,
  255                       &Ios,
  256                       pvBuf,
  257                       (ULONG)cb,
  258                       &offNt,
  259                       NULL);
  260 
  261 #ifdef IN_RING0
  262     /* In ring-0 the handles shall be synchronized and not alertable. */
  263     AssertMsg(rcNt == STATUS_SUCCESS || !NT_SUCCESS(rcNt), ("%#x\n", rcNt));
  264 #else
  265     /* In ring-3 we like our handles synchronized and non-alertable, but we
  266        sometimes have to take what we can get.  So, deal with pending I/O as
  267        best we can. */
  268     if (rcNt == STATUS_PENDING)
  269         rcNt = NtWaitForSingleObject(pNtViRdr->hEvent ? pNtViRdr->hEvent : pNtViRdr->hFile, FALSE /*Alertable*/, NULL);
  270 #endif
  271     if (NT_SUCCESS(rcNt))
  272         rcNt = Ios.Status;
  273     if (NT_SUCCESS(rcNt))
  274     {
  275         /* We require the caller to not read beyond the end of the file since
  276            we don't have any way to communicate that we've read less that
  277            requested. */
  278         if (Ios.Information == cb)
  279         {
  280             pNtViRdr->off = off + cb; /* (just for show) */
  281             return VINF_SUCCESS;
  282         }
  283 #ifdef IN_RING3
  284         supR3HardenedError(VERR_READ_ERROR, false,
  285                            "supHardNtViRdrRead: Only got %#zx bytes when requesting %#zx bytes at %#llx in '%s'.\n",
  286                            Ios.Information, off, cb, pNtViRdr->szFilename);
  287 #endif
  288     }
  289     pNtViRdr->off = -1;
  290     return VERR_READ_ERROR;
  291 }
  292 
  293 
  294 /** @copydoc RTLDRREADER::pfnTell */
  295 static DECLCALLBACK(RTFOFF) supHardNtViRdrTell(PRTLDRREADER pReader)
  296 {
  297     PSUPHNTVIRDR pNtViRdr = (PSUPHNTVIRDR)pReader;
  298     Assert(pNtViRdr->Core.uMagic == RTLDRREADER_MAGIC);
  299     return pNtViRdr->off;
  300 }
  301 
  302 
  303 /** @copydoc RTLDRREADER::pfnSize */
  304 static DECLCALLBACK(uint64_t) supHardNtViRdrSize(PRTLDRREADER pReader)
  305 {
  306     PSUPHNTVIRDR pNtViRdr = (PSUPHNTVIRDR)pReader;
  307     Assert(pNtViRdr->Core.uMagic == RTLDRREADER_MAGIC);
  308     return pNtViRdr->cbFile;
  309 }
  310 
  311 
  312 /** @copydoc RTLDRREADER::pfnLogName */
  313 static DECLCALLBACK(const char *) supHardNtViRdrLogName(PRTLDRREADER pReader)
  314 {
  315     PSUPHNTVIRDR pNtViRdr = (PSUPHNTVIRDR)pReader;
  316     return pNtViRdr->szFilename;
  317 }
  318 
  319 
  320 /** @copydoc RTLDRREADER::pfnMap */
  321 static DECLCALLBACK(int) supHardNtViRdrMap(PRTLDRREADER pReader, const void **ppvBits)
  322 {
  323     RT_NOREF2(pReader, ppvBits);
  324     return VERR_NOT_SUPPORTED;
  325 }
  326 
  327 
  328 /** @copydoc RTLDRREADER::pfnUnmap */
  329 static DECLCALLBACK(int) supHardNtViRdrUnmap(PRTLDRREADER pReader, const void *pvBits)
  330 {
  331     RT_NOREF2(pReader, pvBits);
  332     return VERR_NOT_SUPPORTED;
  333 }
  334 
  335 
  336 /** @copydoc RTLDRREADER::pfnDestroy */
  337 static DECLCALLBACK(int) supHardNtViRdrDestroy(PRTLDRREADER pReader)
  338 {
  339     PSUPHNTVIRDR pNtViRdr = (PSUPHNTVIRDR)pReader;
  340     Assert(pNtViRdr->Core.uMagic == RTLDRREADER_MAGIC);
  341 
  342     pNtViRdr->Core.uMagic = ~RTLDRREADER_MAGIC;
  343     pNtViRdr->hFile = NULL;
  344 #ifdef IN_RING3
  345     if (pNtViRdr->hEvent)
  346     {
  347         NtClose(pNtViRdr->hEvent);
  348         pNtViRdr->hEvent = NULL;
  349     }
  350 #endif
  351     RTMemFree(pNtViRdr);
  352     return VINF_SUCCESS;
  353 }
  354 
  355 
  356 /**
  357  * Creates a loader reader instance for the given NT file handle.
  358  *
  359  * @returns iprt status code.
  360  * @param   hFile           Native NT file handle.
  361  * @param   pwszName        Optional file name.
  362  * @param   fFlags          Flags, SUPHNTVI_F_XXX.
  363  * @param   ppNtViRdr       Where to store the reader instance on success.
  364  */
  365 DECLHIDDEN(int) supHardNtViRdrCreate(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PSUPHNTVIRDR *ppNtViRdr)
  366 {
  367     /*
  368      * Try determine the size of the file.
  369      */
  370     IO_STATUS_BLOCK             Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
  371     FILE_STANDARD_INFORMATION   StdInfo;
  372     NTSTATUS rcNt = NtQueryInformationFile(hFile, &Ios, &StdInfo, sizeof(StdInfo), FileStandardInformation);
  373     if (!NT_SUCCESS(rcNt) || !NT_SUCCESS(Ios.Status))
  374         return VERR_LDRVI_FILE_LENGTH_ERROR;
  375 
  376     /*
  377      * Figure the file mode so we can see whether we'll be needing an event
  378      * semaphore for waiting on reads.  This may happen in very unlikely
  379      * NtCreateSection scenarios.
  380      */
  381 #if defined(IN_RING3) || defined(VBOX_STRICT)
  382     Ios.Status = STATUS_UNSUCCESSFUL;
  383     ULONG fMode;
  384     rcNt = NtQueryInformationFile(hFile, &Ios, &fMode, sizeof(fMode), FileModeInformation);
  385     if (!NT_SUCCESS(rcNt) || !NT_SUCCESS(Ios.Status))
  386         return VERR_SUP_VP_FILE_MODE_ERROR;
  387 #endif
  388 
  389     HANDLE hEvent = NULL;
  390 #ifdef IN_RING3
  391     if (!(fMode & (FILE_SYNCHRONOUS_IO_NONALERT | FILE_SYNCHRONOUS_IO_ALERT)))
  392     {
  393         rcNt = NtCreateEvent(&hEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE);
  394         if (!NT_SUCCESS(rcNt))
  395             return VERR_SUP_VP_CREATE_READ_EVT_SEM_FAILED;
  396     }
  397 #else
  398     Assert(fMode & FILE_SYNCHRONOUS_IO_NONALERT);
  399 #endif
  400 
  401     /*
  402      * Calc the file name length and allocate memory for the reader instance.
  403      */
  404     size_t cchFilename = 0;
  405     if (pwszName)
  406         cchFilename = RTUtf16CalcUtf8Len(pwszName);
  407 
  408     int rc = VERR_NO_MEMORY;
  409     PSUPHNTVIRDR pNtViRdr = (PSUPHNTVIRDR)RTMemAllocZ(sizeof(*pNtViRdr) + cchFilename);
  410     if (!pNtViRdr)
  411     {
  412 #ifdef IN_RING3
  413         if (hEvent != NULL)
  414             NtClose(hEvent);
  415 #endif
  416         return VERR_NO_MEMORY;
  417     }
  418 
  419     /*
  420      * Initialize the structure.
  421      */
  422     if (cchFilename)
  423     {
  424         char *pszName = &pNtViRdr->szFilename[0];
  425         rc = RTUtf16ToUtf8Ex(pwszName, RTSTR_MAX, &pszName, cchFilename + 1, NULL);
  426         AssertStmt(RT_SUCCESS(rc), pNtViRdr->szFilename[0] = '\0');
  427     }
  428     else
  429         pNtViRdr->szFilename[0] = '\0';
  430 
  431     pNtViRdr->Core.uMagic     = RTLDRREADER_MAGIC;
  432     pNtViRdr->Core.pfnRead    = supHardNtViRdrRead;
  433     pNtViRdr->Core.pfnTell    = supHardNtViRdrTell;
  434     pNtViRdr->Core.pfnSize    = supHardNtViRdrSize;
  435     pNtViRdr->Core.pfnLogName = supHardNtViRdrLogName;
  436     pNtViRdr->Core.pfnMap     = supHardNtViRdrMap;
  437     pNtViRdr->Core.pfnUnmap   = supHardNtViRdrUnmap;
  438     pNtViRdr->Core.pfnDestroy = supHardNtViRdrDestroy;
  439     pNtViRdr->hFile           = hFile;
  440     pNtViRdr->hEvent          = hEvent;
  441     pNtViRdr->off             = 0;
  442     pNtViRdr->cbFile          = (uint64_t)StdInfo.EndOfFile.QuadPart;
  443     pNtViRdr->fFlags          = fFlags;
  444     *ppNtViRdr = pNtViRdr;
  445     return VINF_SUCCESS;
  446 }
  447 
  448 
  449 /**
  450  * Checks if the file is owned by TrustedInstaller (Vista+) or similar.
  451  *
  452  * @returns true if owned by TrustedInstaller of pre-Vista, false if not.
  453  *
  454  * @param   hFile               The handle to the file.
  455  * @param   pwszName            The name of the file.
  456  */
  457 static bool supHardNtViCheckIsOwnedByTrustedInstallerOrSimilar(HANDLE hFile, PCRTUTF16 pwszName)
  458 {
  459     if (g_uNtVerCombined < SUP_NT_VER_VISTA)
  460         return true;
  461 
  462     /*
  463      * Get the ownership information.
  464      */
  465     union
  466     {
  467         SECURITY_DESCRIPTOR_RELATIVE    Rel;
  468         SECURITY_DESCRIPTOR             Abs;
  469         uint8_t                         abView[256];
  470     } uBuf;
  471     ULONG cbActual;
  472     NTSTATUS rcNt = NtQuerySecurityObject(hFile, OWNER_SECURITY_INFORMATION, &uBuf.Abs, sizeof(uBuf), &cbActual);
  473     if (!NT_SUCCESS(rcNt))
  474     {
  475         SUP_DPRINTF(("NtQuerySecurityObject failed with rcNt=%#x on '%ls'\n", rcNt, pwszName));
  476         return false;
  477     }
  478 
  479     /*
  480      * Check the owner.
  481      *
  482      * Initially we wished to only allow TrustedInstaller.  But a Windows CAPI
  483      * plugin "Program Files\Tumbleweed\Desktop Validator\tmwdcapiclient.dll"
  484      * turned up owned by the local system user, and we cannot operate without
  485      * the plugin loaded once it's installed (WinVerityTrust fails).
  486      *
  487      * We'd like to avoid allowing Builtin\Administrators here since it's the
  488      * default owner of anything an admin user creates (at least when elevated).
  489      * Seems windows update or someone ends up installing or modifying system
  490      * DLL ownership to this group, so for system32 and winsxs it's unavoidable.
  491      * And, not surprise, a bunch of products, including AV, firewalls and similar
  492      * ends up with their files installed with this group as owner.  For instance
  493      * if we wish to have NAT continue working, we need to allow this.
  494      *
  495      * Hopefully, we can limit the allowed files to these owners though, so
  496      * we won't be subject to ordinary (non-admin, or not elevated) users
  497      * downloading or be tricked into putting evil DLLs around the place...
  498      */
  499     PSID pOwner = uBuf.Rel.Control & SE_SELF_RELATIVE ? &uBuf.abView[uBuf.Rel.Owner] : uBuf.Abs.Owner;
  500     Assert((uintptr_t)pOwner - (uintptr_t)&uBuf < sizeof(uBuf) - sizeof(SID));
  501     if (RtlEqualSid(pOwner, &g_TrustedInstallerSid))
  502         return true;
  503     if (RtlEqualSid(pOwner, &g_LocalSystemSid))
  504         return true;
  505     if (RtlEqualSid(pOwner, &g_AdminsGroupSid))
  506     {
  507         SUP_DPRINTF(("%ls: Owner is administrators group.\n", pwszName));
  508         return true;
  509     }
  510 
  511     SUP_DPRINTF(("%ls: Owner is not trusted installer (%.*Rhxs)\n",
  512                  pwszName, ((uint8_t *)pOwner)[1] /*SubAuthorityCount*/ * sizeof(ULONG) + 8, pOwner));
  513     RT_NOREF1(pwszName);
  514     return false;
  515 }
  516 
  517 
  518 /**
  519  * Simple case insensitive UTF-16 / ASCII path compare.
  520  *
  521  * @returns true if equal, false if not.
  522  * @param   pawcLeft            The UTF-16 path string, not necessarily null
  523  *                              terminated.
  524  * @param   cwcLeft             The number of chars in the left string,
  525  *                              RTSTR_MAX if unknown but terminated.
  526  * @param   pszRight            The ascii string.
  527  */
  528 DECLHIDDEN(bool) supHardViUtf16PathIsEqualEx(PCRTUTF16 pawcLeft, size_t cwcLeft, const char *pszRight)
  529 {
  530     for (;;)
  531     {
  532         RTUTF16 wc;
  533         if (cwcLeft-- > 0)
  534             wc =*pawcLeft++;
  535         else
  536             wc = 0;
  537         uint8_t b  = *pszRight++;
  538         if (b != wc)
  539         {
  540             if (wc >= 0x80)
  541                 return false;
  542             wc = RT_C_TO_LOWER(wc);
  543             if (wc != b)
  544             {
  545                 b = RT_C_TO_LOWER(b);
  546                 if (wc != b)
  547                 {
  548                     if (wc == '/')
  549                         wc = '\\';
  550                     if (b == '/')
  551                         b = '\\';
  552                     if (wc != b)
  553                         return false;
  554                 }
  555             }
  556         }
  557         if (!b)
  558             return true;
  559     }
  560 }
  561 
  562 
  563 /**
  564  * Simple case insensitive UTF-16 / ASCII path compare.
  565  *
  566  * @returns true if equal, false if not.
  567  * @param   pwszLeft            The UTF-16 path string.
  568  * @param   pszRight            The ascii string.
  569  */
  570 static bool supHardViUtf16PathIsEqual(PCRTUTF16 pwszLeft, const char *pszRight)
  571 {
  572     return supHardViUtf16PathIsEqualEx(pwszLeft, RTSTR_MAX, pszRight);
  573 }
  574 
  575 
  576 #if 0 /* unused */
  577 /**
  578  * Simple case insensitive UTF-16 / ASCII ends-with path predicate.
  579  *
  580  * @returns true if equal, false if not.
  581  * @param   pwsz                The UTF-16 path string.
  582  * @param   pszSuffix           The ascii suffix string.
  583  */
  584 static bool supHardViUtf16PathEndsWith(PCRTUTF16 pwsz, const char *pszSuffix)
  585 {
  586     size_t cwc       = RTUtf16Len(pwsz);
  587     size_t cchSuffix = strlen(pszSuffix);
  588     if (cwc >= cchSuffix)
  589         return supHardViUtf16PathIsEqual(pwsz + cwc - cchSuffix, pszSuffix);
  590     return false;
  591 }
  592 #endif
  593 
  594 
  595 /**
  596  * Simple case insensitive UTF-16 / ASCII starts-with path predicate.
  597  *
  598  * @returns true if starts with given string, false if not.
  599  * @param   pwszLeft            The UTF-16 path string.
  600  * @param   pszRight            The ascii prefix string.
  601  */
  602 static bool supHardViUtf16PathStartsWithAscii(PCRTUTF16 pwszLeft, const char *pszRight)
  603 {
  604     for (;;)
  605     {
  606         RTUTF16 wc = *pwszLeft++;
  607         uint8_t b  = *pszRight++;
  608         if (b != wc)
  609         {
  610             if (!b)
  611                 return true;
  612             if (wc >= 0x80 || wc == 0)
  613                 return false;
  614             wc = RT_C_TO_LOWER(wc);
  615             if (wc != b)
  616             {
  617                 b = RT_C_TO_LOWER(b);
  618                 if (wc != b)
  619                 {
  620                     if (wc == '/')
  621                         wc = '\\';
  622                     if (b == '/')
  623                         b = '\\';
  624                     if (wc != b)
  625                         return false;
  626                 }
  627             }
  628         }
  629     }
  630 }
  631 
  632 
  633 /**
  634  * Simple case insensitive UNICODE_STRING starts-with path predicate.
  635  *
  636  * @returns true if starts with given string, false if not.
  637  * @param   pwszLeft            The path to check.
  638  * @param   cwcLeft             The length of @a pwszLeft
  639  * @param   pwszRight           The starts-with path.
  640  * @param   cwcRight            The length of @a pwszRight.
  641  * @param   fCheckSlash         Check for a slash following the prefix.
  642  */
  643 DECLHIDDEN(bool) supHardViUtf16PathStartsWithEx(PCRTUTF16 pwszLeft, uint32_t cwcLeft,
  644                                                 PCRTUTF16 pwszRight, uint32_t cwcRight, bool fCheckSlash)
  645 {
  646     if (cwcLeft < cwcRight || !cwcRight || !pwszRight)
  647         return false;
  648 
  649     /* See if we can get away with a case sensitive compare first. */
  650     if (memcmp(pwszLeft, pwszRight, cwcRight * sizeof(RTUTF16)) == 0)
  651         pwszLeft += cwcRight;
  652     else
  653     {
  654         /* No luck, do a slow case insensitive comapre.  */
  655         uint32_t cLeft = cwcRight;
  656         while (cLeft-- > 0)
  657         {
  658             RTUTF16 wcLeft  = *pwszLeft++;
  659             RTUTF16 wcRight = *pwszRight++;
  660             if (wcLeft != wcRight)
  661             {
  662                 wcLeft  = wcLeft < 0x80  ? wcLeft  == '/' ? '\\' : RT_C_TO_LOWER(wcLeft)  : wcLeft;
  663                 wcRight = wcRight < 0x80 ? wcRight == '/' ? '\\' : RT_C_TO_LOWER(wcRight) : wcRight;
  664                 if (wcLeft != wcRight)
  665                     return false;
  666             }
  667         }
  668     }
  669 
  670     /* Check for slash following the prefix, if request. */
  671     if (   !fCheckSlash
  672         || *pwszLeft == '\\'
  673         || *pwszLeft == '/')
  674         return true;
  675     return false;
  676 }
  677 
  678 
  679 /**
  680  * Simple case insensitive UNICODE_STRING starts-with path predicate.
  681  *
  682  * @returns true if starts with given string, false if not.
  683  * @param   pUniStrLeft         The path to check.
  684  * @param   pUniStrRight        The starts-with path.
  685  * @param   fCheckSlash         Check for a slash following the prefix.
  686  */
  687 DECLHIDDEN(bool) supHardViUniStrPathStartsWithUniStr(UNICODE_STRING const *pUniStrLeft, UNICODE_STRING const *pUniStrRight,
  688                                                      bool fCheckSlash)
  689 {
  690     return supHardViUtf16PathStartsWithEx(pUniStrLeft->Buffer, pUniStrLeft->Length / sizeof(WCHAR),
  691                                           pUniStrRight->Buffer, pUniStrRight->Length / sizeof(WCHAR), fCheckSlash);
  692 }
  693 
  694 
  695 #ifndef IN_RING0
  696 /**
  697  * Counts slashes in the given UTF-8 path string.
  698  *
  699  * @returns Number of slashes.
  700  * @param   pwsz                The UTF-16 path string.
  701  */
  702 static uint32_t supHardViUtf16PathCountSlashes(PCRTUTF16 pwsz)
  703 {
  704     uint32_t cSlashes = 0;
  705     RTUTF16 wc;
  706     while ((wc = *pwsz++) != '\0')
  707         if (wc == '/' || wc == '\\')
  708             cSlashes++;
  709     return cSlashes;
  710 }
  711 #endif
  712 
  713 
  714 #ifdef VBOX_PERMIT_MORE
  715 /**
  716  * Checks if the path goes into %windir%\apppatch\.
  717  *
  718  * @returns true if apppatch, false if not.
  719  * @param   pwszPath        The path to examine.
  720  */
  721 DECLHIDDEN(bool) supHardViIsAppPatchDir(PCRTUTF16 pwszPath, uint32_t cwcName)
  722 {
  723     uint32_t cwcWinDir = (g_System32NtPath.UniStr.Length - sizeof(L"System32")) / sizeof(WCHAR);
  724 
  725     if (cwcName <= cwcWinDir + sizeof("AppPatch"))
  726         return false;
  727 
  728     if (memcmp(pwszPath, g_System32NtPath.UniStr.Buffer, cwcWinDir * sizeof(WCHAR)))
  729         return false;
  730 
  731     if (!supHardViUtf16PathStartsWithAscii(&pwszPath[cwcWinDir], "\\AppPatch\\"))
  732         return false;
  733 
  734     return g_uNtVerCombined >= SUP_NT_VER_VISTA;
  735 }
  736 #else
  737 # error should not get here..
  738 #endif
  739 
  740 
  741 
  742 /**
  743  * Checks if the unsigned DLL is fine or not.
  744  *
  745  * @returns VINF_LDRVI_NOT_SIGNED or @a rc.
  746  * @param   hLdrMod             The loader module handle.
  747  * @param   pwszName            The NT name of the DLL/EXE.
  748  * @param   fFlags              Flags.
  749  * @param   hFile               The file handle.
  750  * @param   rc                  The status code..
  751  */
  752 static int supHardNtViCheckIfNotSignedOk(RTLDRMOD hLdrMod, PCRTUTF16 pwszName, uint32_t fFlags, HANDLE hFile, int rc)
  753 {
  754     RT_NOREF1(hLdrMod);
  755 
  756     if (fFlags & (SUPHNTVI_F_REQUIRE_BUILD_CERT | SUPHNTVI_F_REQUIRE_KERNEL_CODE_SIGNING))
  757         return rc;
  758 
  759     /*
  760      * Version macros.
  761      */
  762     uint32_t const uNtVer = g_uNtVerCombined;
  763 #define IS_XP()    ( uNtVer >= SUP_MAKE_NT_VER_SIMPLE(5, 1) && uNtVer < SUP_MAKE_NT_VER_SIMPLE(5, 2) )
  764 #define IS_W2K3()  ( uNtVer >= SUP_MAKE_NT_VER_SIMPLE(5, 2) && uNtVer < SUP_MAKE_NT_VER_SIMPLE(5, 3) )
  765 #define IS_VISTA() ( uNtVer >= SUP_MAKE_NT_VER_SIMPLE(6, 0) && uNtVer < SUP_MAKE_NT_VER_SIMPLE(6, 1) )
  766 #define IS_W70()   ( uNtVer >= SUP_MAKE_NT_VER_SIMPLE(6, 1) && uNtVer < SUP_MAKE_NT_VER_SIMPLE(6, 2) )
  767 #define IS_W80()   ( uNtVer >= SUP_MAKE_NT_VER_SIMPLE(6, 2) && uNtVer < SUP_MAKE_NT_VER_SIMPLE(6, 3) )
  768 #define IS_W81()   ( uNtVer >= SUP_MAKE_NT_VER_SIMPLE(6, 3) && uNtVer < SUP_MAKE_NT_VER_SIMPLE(6, 4) )
  769 
  770     /*
  771      * The System32 directory.
  772      *
  773      * System32 is full of unsigned DLLs shipped by microsoft, graphics
  774      * hardware vendors, input device/method vendors and whatnot else that
  775      * actually needs to be loaded into a process for it to work correctly.
  776      * We have to ASSUME that anything our process attempts to load from
  777      * System32 is trustworthy and that the Windows system with the help of
  778      * anti-virus software make sure there is nothing evil lurking in System32
  779      * or being loaded from it.
  780      *
  781      * A small measure of protection is to list DLLs we know should be signed
  782      * and decline loading unsigned versions of them, assuming they have been
  783      * replaced by an adversary with evil intentions.
  784      */
  785     PCRTUTF16 pwsz;
  786     uint32_t cwcName = (uint32_t)RTUtf16Len(pwszName);
  787     uint32_t cwcOther = g_System32NtPath.UniStr.Length / sizeof(WCHAR);
  788     if (supHardViUtf16PathStartsWithEx(pwszName, cwcName, g_System32NtPath.UniStr.Buffer, cwcOther, true /*fCheckSlash*/))
  789     {
  790         pwsz = pwszName + cwcOther + 1;
  791 
  792         /* Must be owned by trusted installer. (This test is superfuous, thus no relaxation here.) */
  793         if (   !(fFlags & SUPHNTVI_F_TRUSTED_INSTALLER_OWNER)
  794             && !supHardNtViCheckIsOwnedByTrustedInstallerOrSimilar(hFile, pwszName))
  795             return rc;
  796 
  797         /* Core DLLs. */
  798         if (supHardViUtf16PathIsEqual(pwsz, "ntdll.dll"))
  799             return uNtVer < SUP_NT_VER_VISTA ? VINF_LDRVI_NOT_SIGNED : rc;
  800         if (supHardViUtf16PathIsEqual(pwsz, "kernel32.dll"))
  801             return uNtVer < SUP_NT_VER_W81 ? VINF_LDRVI_NOT_SIGNED : rc;
  802         if (supHardViUtf16PathIsEqual(pwsz, "kernelbase.dll"))
  803             return IS_W80() || IS_W70() ? VINF_LDRVI_NOT_SIGNED : rc;
  804         if (supHardViUtf16PathIsEqual(pwsz, "apisetschema.dll"))
  805             return IS_W70() ? VINF_LDRVI_NOT_SIGNED : rc;
  806         if (supHardViUtf16PathIsEqual(pwsz, "apphelp.dll"))
  807             return VINF_LDRVI_NOT_SIGNED; /* So far, never signed... */
  808 #ifdef VBOX_PERMIT_VERIFIER_DLL
  809         if (supHardViUtf16PathIsEqual(pwsz, "verifier.dll"))
  810             return uNtVer < SUP_NT_VER_W81 ? VINF_LDRVI_NOT_SIGNED : rc;
  811 #endif
  812 #ifdef VBOX_PERMIT_MORE
  813         if (uNtVer >= SUP_NT_VER_W70) /* hard limit: user32.dll is unwanted prior to w7. */
  814         {
  815             if (supHardViUtf16PathIsEqual(pwsz, "sfc.dll"))
  816                 return uNtVer < SUP_MAKE_NT_VER_SIMPLE(6, 4) ? VINF_LDRVI_NOT_SIGNED : rc;
  817             if (supHardViUtf16PathIsEqual(pwsz, "sfc_os.dll"))
  818                 return uNtVer < SUP_MAKE_NT_VER_SIMPLE(6, 4) ? VINF_LDRVI_NOT_SIGNED : rc;
  819             if (supHardViUtf16PathIsEqual(pwsz, "user32.dll"))
  820                 return uNtVer < SUP_NT_VER_W81 ? VINF_LDRVI_NOT_SIGNED : rc;
  821         }
  822 #endif
  823 
  824 #ifndef IN_RING0
  825         /* Check that this DLL isn't supposed to be signed on this windows
  826            version.  If it should, it's likely to be a fake. */
  827         /** @todo list of signed dlls for various windows versions.  */
  828         return VINF_LDRVI_NOT_SIGNED;
  829 #else
  830         return rc;
  831 #endif /* IN_RING0 */
  832     }
  833 
  834 
  835 #ifndef IN_RING0
  836     /*
  837      * The WinSxS white list.
  838      *
  839      * Just like with System32 there are potentially a number of DLLs that
  840      * could be required from WinSxS.
  841      */
  842     cwcOther = g_WinSxSNtPath.UniStr.Length / sizeof(WCHAR);
  843     if (supHardViUtf16PathStartsWithEx(pwszName, cwcName, g_WinSxSNtPath.UniStr.Buffer, cwcOther, true /*fCheckSlash*/))
  844     {
  845         pwsz = pwszName + cwcOther + 1;
  846         cwcName -= cwcOther + 1;
  847 
  848         /* The WinSxS layout means everything worth loading is exactly one level down. */
  849         uint32_t cSlashes = supHardViUtf16PathCountSlashes(pwsz);
  850         if (cSlashes != 1)
  851             return rc;
  852 
  853         /* Must be owned by trusted installer. */
  854         if (   !(fFlags & SUPHNTVI_F_TRUSTED_INSTALLER_OWNER)
  855             && !supHardNtViCheckIsOwnedByTrustedInstallerOrSimilar(hFile, pwszName))
  856             return rc;
  857         return VINF_LDRVI_NOT_SIGNED;
  858     }
  859 #endif /* !IN_RING0 */
  860 
  861 
  862 #ifdef VBOX_PERMIT_MORE
  863     /*
  864      * AppPatch whitelist.
  865      */
  866     if (supHardViIsAppPatchDir(pwszName, cwcName))
  867     {
  868         cwcOther = g_System32NtPath.UniStr.Length / sizeof(WCHAR); /* ASSUMES System32 is called System32. */
  869         pwsz = pwszName + cwcOther + 1;
  870 
  871         if (   !(fFlags & SUPHNTVI_F_TRUSTED_INSTALLER_OWNER)
  872             && !supHardNtViCheckIsOwnedByTrustedInstallerOrSimilar(hFile, pwszName))
  873             return rc;
  874 
  875 # ifndef VBOX_PERMIT_EVEN_MORE
  876         if (supHardViUtf16PathIsEqual(pwsz, "acres.dll"))
  877             return VINF_LDRVI_NOT_SIGNED;
  878 
  879 #  ifdef RT_ARCH_AMD64
  880         if (supHardViUtf16PathIsEqual(pwsz, "AppPatch64\\AcGenral.dll"))
  881             return VINF_LDRVI_NOT_SIGNED;
  882 #  elif defined(RT_ARCH_X86)
  883         if (supHardViUtf16PathIsEqual(pwsz, "AcGenral.dll"))
  884             return VINF_LDRVI_NOT_SIGNED;
  885 #  endif
  886 # endif /* !VBOX_PERMIT_EVEN_MORE */
  887 
  888 # ifdef IN_RING0
  889         return rc;
  890 # else
  891         return VINF_LDRVI_NOT_SIGNED;
  892 # endif
  893     }
  894 #endif /* VBOX_PERMIT_MORE */
  895 
  896 
  897 #ifndef IN_RING0
  898 # if defined(VBOX_PERMIT_MORE) && !defined(VBOX_PERMIT_EVEN_MORE)
  899     /*
  900      * Program files and common files.
  901      * Permit anything that's signed and correctly installed.
  902      */
  903     if (   supHardViUtf16PathStartsWithEx(pwszName, cwcName,
  904                                           g_ProgramFilesNtPath.UniStr.Buffer, g_ProgramFilesNtPath.UniStr.Length,
  905                                           true /*fCheckSlash*/)
  906         || supHardViUtf16PathStartsWithEx(pwszName, cwcName,
  907                                           g_CommonFilesNtPath.UniStr.Buffer, g_CommonFilesNtPath.UniStr.Length,
  908                                           true /*fCheckSlash*/)
  909 # ifdef RT_ARCH_AMD64
  910         || supHardViUtf16PathStartsWithEx(pwszName, cwcName,
  911                                           g_ProgramFilesX86NtPath.UniStr.Buffer, g_ProgramFilesX86NtPath.UniStr.Length,
  912                                           true /*fCheckSlash*/)
  913         || supHardViUtf16PathStartsWithEx(pwszName, cwcName,
  914                                           g_CommonFilesX86NtPath.UniStr.Buffer, g_CommonFilesX86NtPath.UniStr.Length,
  915                                           true /*fCheckSlash*/)
  916 # endif
  917        )
  918     {
  919         if (   !(fFlags & SUPHNTVI_F_TRUSTED_INSTALLER_OWNER)
  920             && !supHardNtViCheckIsOwnedByTrustedInstallerOrSimilar(hFile, pwszName))
  921             return rc;
  922         return VINF_LDRVI_NOT_SIGNED;
  923     }
  924 
  925 # elif defined(VBOX_PERMIT_MORE) && defined(VBOX_PERMIT_EVEN_MORE)
  926     /*
  927      * Anything that's owned by the trusted installer.
  928      */
  929     if (   (fFlags & SUPHNTVI_F_TRUSTED_INSTALLER_OWNER)
  930         || supHardNtViCheckIsOwnedByTrustedInstallerOrSimilar(hFile, pwszName))
  931         return VINF_LDRVI_NOT_SIGNED;
  932 
  933 # endif
  934 #endif /* !IN_RING0 */
  935 
  936     /*
  937      * Not permitted.
  938      */
  939     return rc;
  940 }
  941 
  942 
  943 /**
  944  * @callback_method_impl{FNRTDUMPPRINTFV, Formats into RTERRINFO. }
  945  */
  946 static DECLCALLBACK(void) supHardNtViAsn1DumpToErrInfo(void *pvUser, const char *pszFormat, va_list va)
  947 {
  948     PRTERRINFO pErrInfo = (PRTERRINFO)pvUser;
  949     RTErrInfoAddV(pErrInfo, pErrInfo->rc, pszFormat, va);
  950 }
  951 
  952 
  953 /**
  954  * Attempts to locate a root certificate in the specified store.
  955  *
  956  * @returns IPRT status code.
  957  * @retval  VINF_SUCCESS if found.
  958  * @retval  VWRN_NOT_FOUND if not found.
  959  *
  960  * @param   hRootStore      The root certificate store to search.
  961  * @param   pSubject        The root certificate subject.
  962  * @param   pPublicKeyInfo  The public key of the root certificate to find.
  963  */
  964 static int supHardNtViCertVerifyFindRootCert(RTCRSTORE hRootStore, PCRTCRX509NAME pSubject,
  965                                              PCRTCRX509SUBJECTPUBLICKEYINFO pPublicKeyInfo)
  966 {
  967     RTCRSTORECERTSEARCH Search;
  968     int rc = RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280(hRootStore, pSubject, &Search);
  969     AssertRCReturn(rc, rc);
  970 
  971     rc = VWRN_NOT_FOUND;
  972     PCRTCRCERTCTX pCertCtx;
  973     while ((pCertCtx = RTCrStoreCertSearchNext(hRootStore, &Search)) != NULL)
  974     {
  975         PCRTCRX509SUBJECTPUBLICKEYINFO pCertPubKeyInfo = NULL;
  976         if (pCertCtx->pCert)
  977             pCertPubKeyInfo = &pCertCtx->pCert->TbsCertificate.SubjectPublicKeyInfo;
  978         else if (pCertCtx->pTaInfo)
  979             pCertPubKeyInfo = &pCertCtx->pTaInfo->PubKey;
  980         else
  981             pCertPubKeyInfo = NULL;
  982         if (   pCertPubKeyInfo
  983             && RTCrX509SubjectPublicKeyInfo_Compare(pCertPubKeyInfo, pPublicKeyInfo) == 0)
  984         {
  985             RTCrCertCtxRelease(pCertCtx);
  986             rc = VINF_SUCCESS;
  987             break;
  988         }
  989         RTCrCertCtxRelease(pCertCtx);
  990     }
  991 
  992     int rc2 = RTCrStoreCertSearchDestroy(hRootStore, &Search);
  993     AssertRC(rc2);
  994     return rc;
  995 }
  996 
  997 
  998 /**
  999  * @callback_method_impl{FNRTCRPKCS7VERIFYCERTCALLBACK,
 1000  * Standard code signing.  Use this for Microsoft SPC.}
 1001  */
 1002 static DECLCALLBACK(int) supHardNtViCertVerifyCallback(PCRTCRX509CERTIFICATE pCert, RTCRX509CERTPATHS hCertPaths,
 1003                                                        uint32_t fFlags, void *pvUser, PRTERRINFO pErrInfo)
 1004 {
 1005     PSUPHNTVIRDR pNtViRdr = (PSUPHNTVIRDR)pvUser;
 1006     Assert(pNtViRdr->Core.uMagic == RTLDRREADER_MAGIC);
 1007 
 1008     /*
 1009      * If there is no certificate path build & validator associated with this
 1010      * callback, it must be because of the build certificate.  We trust the
 1011      * build certificate without any second thoughts.
 1012      */
 1013     if (hCertPaths == NIL_RTCRX509CERTPATHS)
 1014     {
 1015         if (RTCrX509Certificate_Compare(pCert, &g_BuildX509Cert) == 0) /* healthy paranoia */
 1016             return VINF_SUCCESS;
 1017         int rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_NOT_BUILD_CERT_IPE, "Not valid kernel code signature (fFlags=%#x).", fFlags);
 1018         if (pErrInfo)
 1019         {
 1020             RTErrInfoAdd(pErrInfo, rc, "\n\nExe cert:\n");
 1021             RTAsn1Dump(&pCert->SeqCore.Asn1Core, 0 /*fFlags*/, 0 /*uLevel*/, supHardNtViAsn1DumpToErrInfo, pErrInfo);
 1022             RTErrInfoAdd(pErrInfo, rc, "\n\nBuild cert:\n");
 1023             RTAsn1Dump(&g_BuildX509Cert.SeqCore.Asn1Core, 0 /*fFlags*/, 0 /*uLevel*/, supHardNtViAsn1DumpToErrInfo, pErrInfo);
 1024         }
 1025         return rc;
 1026     }
 1027 
 1028     /*
 1029      * Standard code signing capabilites required.
 1030      */
 1031     int rc = RTCrPkcs7VerifyCertCallbackCodeSigning(pCert, hCertPaths, fFlags, NULL, pErrInfo);
 1032     if (   RT_SUCCESS(rc)
 1033         && (fFlags & RTCRPKCS7VCC_F_SIGNED_DATA))
 1034     {
 1035         /*
 1036          * For kernel code signing there are two options for a valid certificate path:
 1037          *  1. Anchored by the microsoft kernel signing root certificate (g_hNtKernelRootStore).
 1038          *  2. Anchored by an SPC root and signing entity including a 1.3.6.1.4.1.311.10.3.5 (WHQL)
 1039          *     or 1.3.6.1.4.1.311.10.3.5.1 (WHQL attestation) extended usage key.
 1040          */
 1041         if (pNtViRdr->fFlags & SUPHNTVI_F_REQUIRE_KERNEL_CODE_SIGNING)
 1042         {
 1043             uint32_t cPaths = RTCrX509CertPathsGetPathCount(hCertPaths);
 1044             uint32_t cFound = 0;
 1045             uint32_t cValid = 0;
 1046             for (uint32_t iPath = 0; iPath < cPaths; iPath++)
 1047             {
 1048                 bool                            fTrusted;
 1049                 PCRTCRX509NAME                  pSubject;
 1050                 PCRTCRX509SUBJECTPUBLICKEYINFO  pPublicKeyInfo;
 1051                 int                             rcVerify;
 1052                 rc = RTCrX509CertPathsQueryPathInfo(hCertPaths, iPath, &fTrusted, NULL /*pcNodes*/, &pSubject, &pPublicKeyInfo,
 1053                                                     NULL, NULL /*pCertCtx*/, &rcVerify);
 1054                 AssertRCBreak(rc);
 1055 
 1056                 if (RT_SUCCESS(rcVerify))
 1057                 {
 1058                     Assert(fTrusted);
 1059                     cValid++;
 1060 
 1061                     /*
 1062                      * 1. Search the kernel signing root store for a matching anchor.
 1063                      */
 1064                     rc = supHardNtViCertVerifyFindRootCert(g_hNtKernelRootStore, pSubject, pPublicKeyInfo);
 1065                     if (rc == VINF_SUCCESS)
 1066                         cFound++;
 1067                     /*
 1068                      * 2. Check for WHQL EKU and make sure it has a SPC root.
 1069                      */
 1070                     else if (   rc == VWRN_NOT_FOUND
 1071                              && (  pCert->TbsCertificate.T3.fExtKeyUsage
 1072                                  & (RTCRX509CERT_EKU_F_MS_ATTEST_WHQL_CRYPTO | RTCRX509CERT_EKU_F_MS_WHQL_CRYPTO)))
 1073                     {
 1074                         rc = supHardNtViCertVerifyFindRootCert(g_hSpcRootStore, pSubject, pPublicKeyInfo);
 1075                         if (rc == VINF_SUCCESS)
 1076                             cFound++;
 1077                     }
 1078                     AssertRCBreak(rc);
 1079                 }
 1080             }
 1081             if (RT_SUCCESS(rc) && cFound == 0)
 1082                 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_NOT_VALID_KERNEL_CODE_SIGNATURE,
 1083                                    "Signature #%u/%u: Not valid kernel code signature.",
 1084                                    pNtViRdr->iCurSignature + 1, pNtViRdr->cTotalSignatures);
 1085 
 1086 
 1087             if (RT_SUCCESS(rc) && cValid < 2 && g_fHaveOtherRoots)
 1088                 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_UNEXPECTED_VALID_PATH_COUNT,
 1089                                    "Signature #%u/%u: Expected at least %u valid paths, not %u.",
 1090                                    pNtViRdr->iCurSignature + 1, pNtViRdr->cTotalSignatures, 2, cValid);
 1091             if (rc == VWRN_NOT_FOUND)
 1092                 rc = VINF_SUCCESS;
 1093         }
 1094     }
 1095 
 1096     /*
 1097      * More requirements? NT5 build lab?
 1098      */
 1099 
 1100     return rc;
 1101 }
 1102 
 1103 
 1104 /**
 1105  * RTTimeNow equivaltent that handles ring-3 where we cannot use it.
 1106  *
 1107  * @returns pNow
 1108  * @param   pNow                Where to return the current time.
 1109  */
 1110 static PRTTIMESPEC supHardNtTimeNow(PRTTIMESPEC pNow)
 1111 {
 1112 #ifdef IN_RING3
 1113     /*
 1114      * Just read system time.
 1115      */
 1116     KUSER_SHARED_DATA volatile *pUserSharedData = (KUSER_SHARED_DATA volatile *)MM_SHARED_USER_DATA_VA;
 1117 # ifdef RT_ARCH_AMD64
 1118     uint64_t uRet = *(uint64_t volatile *)&pUserSharedData->SystemTime; /* This is what KeQuerySystemTime does (missaligned). */
 1119     return RTTimeSpecSetNtTime(pNow, uRet);
 1120 # else
 1121 
 1122     LARGE_INTEGER NtTime;
 1123     do
 1124     {
 1125         NtTime.HighPart = pUserSharedData->SystemTime.High1Time;
 1126         NtTime.LowPart  = pUserSharedData->SystemTime.LowPart;
 1127     } while (pUserSharedData->SystemTime.High2Time != NtTime.HighPart);
 1128     return RTTimeSpecSetNtTime(pNow, NtTime.QuadPart);
 1129 # endif
 1130 #else  /* IN_RING0 */
 1131     return RTTimeNow(pNow);
 1132 #endif /* IN_RING0 */
 1133 }
 1134 
 1135 
 1136 /**
 1137  * @callback_method_impl{FNRTLDRVALIDATESIGNEDDATA}
 1138  */
 1139 static DECLCALLBACK(int) supHardNtViCallback(RTLDRMOD hLdrMod, PCRTLDRSIGNATUREINFO pInfo, PRTERRINFO pErrInfo, void *pvUser)
 1140 {
 1141     RT_NOREF(hLdrMod);
 1142 
 1143     /*
 1144      * Check out the input.
 1145      */
 1146     PSUPHNTVIRDR pNtViRdr = (PSUPHNTVIRDR)pvUser;
 1147     Assert(pNtViRdr->Core.uMagic == RTLDRREADER_MAGIC);
 1148     pNtViRdr->cTotalSignatures = pInfo->cSignatures;
 1149     pNtViRdr->iCurSignature    = pInfo->iSignature;
 1150 
 1151     AssertReturn(pInfo->enmType == RTLDRSIGNATURETYPE_PKCS7_SIGNED_DATA, VERR_INTERNAL_ERROR_5);
 1152     AssertReturn(!pInfo->pvExternalData, VERR_INTERNAL_ERROR_5);
 1153     AssertReturn(pInfo->cbSignature == sizeof(RTCRPKCS7CONTENTINFO), VERR_INTERNAL_ERROR_5);
 1154     PCRTCRPKCS7CONTENTINFO pContentInfo = (PCRTCRPKCS7CONTENTINFO)pInfo->pvSignature;
 1155     AssertReturn(RTCrPkcs7ContentInfo_IsSignedData(pContentInfo), VERR_INTERNAL_ERROR_5);
 1156     AssertReturn(pContentInfo->u.pSignedData->SignerInfos.cItems == 1, VERR_INTERNAL_ERROR_5);
 1157     PCRTCRPKCS7SIGNERINFO pSignerInfo = pContentInfo->u.pSignedData->SignerInfos.papItems[0];
 1158 
 1159 
 1160     /*
 1161      * If special certificate requirements, check them out before validating
 1162      * the signature.  These only apply to the first signature (for now).
 1163      */
 1164     if (   (pNtViRdr->fFlags & SUPHNTVI_F_REQUIRE_BUILD_CERT)
 1165         && pInfo->iSignature == 0)
 1166     {
 1167         if (!RTCrX509Certificate_MatchIssuerAndSerialNumber(&g_BuildX509Cert,
 1168                                                             &pSignerInfo->IssuerAndSerialNumber.Name,
 1169                                                             &pSignerInfo->IssuerAndSerialNumber.SerialNumber))
 1170             return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_NOT_SIGNED_WITH_BUILD_CERT,
 1171                                  "Signature #%u/%u: Not signed with the build certificate (serial %.*Rhxs, expected %.*Rhxs)",
 1172                                  pInfo->iSignature + 1, pInfo->cSignatures,
 1173                                  pSignerInfo->IssuerAndSerialNumber.SerialNumber.Asn1Core.cb,
 1174                                  pSignerInfo->IssuerAndSerialNumber.SerialNumber.Asn1Core.uData.pv,
 1175                                  g_BuildX509Cert.TbsCertificate.SerialNumber.Asn1Core.cb,
 1176                                  g_BuildX509Cert.TbsCertificate.SerialNumber.Asn1Core.uData.pv);
 1177     }
 1178 
 1179     /*
 1180      * We instruction the verifier to use the signing time counter signature
 1181      * when present, but provides the linker time then the current time as
 1182      * fallbacks should the timestamp be missing or unusable.
 1183      *
 1184      * Update: Save the first timestamp we validate with build cert and
 1185      *         use this as a minimum timestamp for further build cert
 1186      *         validations.  This works around issues with old DLLs that
 1187      *         we sign against with our certificate (crt, sdl, qt).
 1188      *
 1189      * Update: If the validation fails, retry with the current timestamp. This
 1190      *         is a workaround for NTDLL.DLL in build 14971 having a weird
 1191      *         timestamp: 0xDF1E957E (Sat Aug 14 14:05:18 2088).
 1192      */
 1193     uint32_t fFlags = RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_SIGNING_TIME_IF_PRESENT
 1194                     | RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_MS_TIMESTAMP_IF_PRESENT
 1195                     | RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE_SIGNING_TIME_ONLY;
 1196 
 1197     /* In ring-0 we don't have all the necessary timestamp server root certificate
 1198      * info, so we have to allow using counter signatures unverified there.
 1199      * Ditto for the early period of ring-3 hardened stub execution. */
 1200 #ifndef IN_RING0
 1201     if (!g_fHaveOtherRoots)
 1202 #endif
 1203         fFlags |= RTCRPKCS7VERIFY_SD_F_USE_SIGNING_TIME_UNVERIFIED | RTCRPKCS7VERIFY_SD_F_USE_MS_TIMESTAMP_UNVERIFIED;
 1204 
 1205     /* Fallback timestamps to try: */
 1206     struct { RTTIMESPEC TimeSpec; const char *pszDesc; } aTimes[2];
 1207     unsigned cTimes = 0;
 1208 
 1209     /* 1. The linking timestamp: */
 1210     uint64_t uTimestamp = 0;
 1211     int rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_TIMESTAMP_SECONDS, &uTimestamp, sizeof(uTimestamp));
 1212     if (RT_SUCCESS(rc))
 1213     {
 1214 #ifdef IN_RING3 /* Hack alert! (see above) */
 1215         if (   (pNtViRdr->fFlags & SUPHNTVI_F_REQUIRE_KERNEL_CODE_SIGNING)
 1216             && (pNtViRdr->fFlags & SUPHNTVI_F_REQUIRE_SIGNATURE_ENFORCEMENT)
 1217             && uTimestamp < g_uBuildTimestampHack)
 1218             uTimestamp = g_uBuildTimestampHack;
 1219 #endif
 1220         RTTimeSpecSetSeconds(&aTimes[0].TimeSpec, uTimestamp);
 1221         aTimes[0].pszDesc = "link";
 1222         cTimes++;
 1223     }
 1224     else
 1225         SUP_DPRINTF(("RTLdrQueryProp/RTLDRPROP_TIMESTAMP_SECONDS failed on %s: %Rrc", pNtViRdr->szFilename, rc));
 1226 
 1227     /* 2. Current time. */
 1228     supHardNtTimeNow(&aTimes[cTimes].TimeSpec);
 1229     aTimes[cTimes].pszDesc = "now";
 1230     cTimes++;
 1231 
 1232     /* Make the verfication attempts. */
 1233     for (unsigned i = 0; ; i++)
 1234     {
 1235         Assert(i < cTimes);
 1236         rc = RTCrPkcs7VerifySignedData(pContentInfo, fFlags, g_hSpcAndNtKernelSuppStore, g_hSpcAndNtKernelRootStore,
 1237                                        &aTimes[i].TimeSpec, supHardNtViCertVerifyCallback, pNtViRdr, pErrInfo);
 1238         if (RT_SUCCESS(rc))
 1239         {
 1240             if (rc != VINF_SUCCESS)
 1241             {
 1242                 SUP_DPRINTF(("%s: Signature #%u/%u: info status: %d\n", pNtViRdr->szFilename, pInfo->iSignature + 1, pInfo->cSignatures, rc));
 1243                 if (pNtViRdr->rcLastSignatureFailure == VINF_SUCCESS)
 1244                     pNtViRdr->rcLastSignatureFailure = rc;
 1245             }
 1246             pNtViRdr->cOkaySignatures++;
 1247 
 1248 #ifdef IN_RING3 /* Hack alert! (see above) */
 1249             if ((pNtViRdr->fFlags & SUPHNTVI_F_REQUIRE_BUILD_CERT) && g_uBuildTimestampHack == 0 && cTimes > 1)
 1250                 g_uBuildTimestampHack = uTimestamp;
 1251 #endif
 1252             return VINF_SUCCESS;
 1253         }
 1254 
 1255         if (rc == VERR_CR_X509_CPV_NOT_VALID_AT_TIME && i + 1 < cTimes)
 1256             SUP_DPRINTF(("%s: Signature #%u/%u: VERR_CR_X509_CPV_NOT_VALID_AT_TIME for %#RX64; retrying against current time: %#RX64.\n",
 1257                          pNtViRdr->szFilename, pInfo->iSignature + 1, pInfo->cSignatures,
 1258                          RTTimeSpecGetSeconds(&aTimes[0].TimeSpec), RTTimeSpecGetSeconds(&aTimes[1].TimeSpec)));
 1259         else
 1260         {
 1261             /* There are a couple of failures we can tollerate if there are more than
 1262                one signature and one of them works out fine.  The RTLdrVerifySignature
 1263                caller will have to check the failure counts though to make sure
 1264                something succeeded. */
 1265             pNtViRdr->rcLastSignatureFailure = rc;
 1266             if (   rc == VERR_CR_X509_CPV_NOT_VALID_AT_TIME
 1267                 || rc == VERR_CR_X509_CPV_NO_TRUSTED_PATHS)
 1268             {
 1269                 SUP_DPRINTF(("%s: Signature #%u/%u: %s (%d) w/ timestamp=%#RX64/%s.\n", pNtViRdr->szFilename, pInfo->iSignature + 1, pInfo->cSignatures,
 1270                              rc == VERR_CR_X509_CPV_NOT_VALID_AT_TIME ? "VERR_CR_X509_CPV_NOT_VALID_AT_TIME" : "VERR_CR_X509_CPV_NO_TRUSTED_PATHS", rc,
 1271                              RTTimeSpecGetSeconds(&aTimes[i].TimeSpec), aTimes[i].pszDesc));
 1272 
 1273                 /* This leniency is not applicable to build certificate requirements (signature #1 only). */
 1274                 if (  !(pNtViRdr->fFlags & SUPHNTVI_F_REQUIRE_BUILD_CERT)
 1275                     || pInfo->iSignature != 0)
 1276                 {
 1277                     pNtViRdr->cNokSignatures++;
 1278                     rc = VINF_SUCCESS;
 1279                 }
 1280             }
 1281             else
 1282                 SUP_DPRINTF(("%s: Signature #%u/%u: %Rrc w/ timestamp=%#RX64/%s.\n", pNtViRdr->szFilename, pInfo->iSignature + 1, pInfo->cSignatures,
 1283                              rc, RTTimeSpecGetSeconds(&aTimes[i].TimeSpec), aTimes[i].pszDesc));
 1284             return rc;
 1285         }
 1286     }
 1287 }
 1288 
 1289 
 1290 /**
 1291  * Verifies the given loader image.
 1292  *
 1293  * @returns IPRT status code.
 1294  * @param   hLdrMod             File handle to the executable file.
 1295  * @param   pwszName            Full NT path to the DLL in question, used for
 1296  *                              dealing with unsigned system dlls as well as for
 1297  *                              error/logging.
 1298  * @param   pNtViRdr            The reader instance /w flags.
 1299  * @param   fAvoidWinVerifyTrust Whether to avoid WinVerifyTrust because of
 1300  *                              deadlock or other loader related dangers.
 1301  * @param   pfWinVerifyTrust    Where to return whether WinVerifyTrust was used.
 1302  * @param   pErrInfo            Pointer to error info structure. Optional.
 1303  */
 1304 DECLHIDDEN(int) supHardenedWinVerifyImageByLdrMod(RTLDRMOD hLdrMod, PCRTUTF16 pwszName, PSUPHNTVIRDR pNtViRdr,
 1305                                                   bool fAvoidWinVerifyTrust, bool *pfWinVerifyTrust, PRTERRINFO pErrInfo)
 1306 {
 1307     if (pfWinVerifyTrust)
 1308         *pfWinVerifyTrust = false;
 1309 
 1310 #ifdef IN_RING3
 1311     /* Check that the caller has performed the necessary library initialization. */
 1312     if (!RTCrX509Certificate_IsPresent(&g_BuildX509Cert))
 1313         return RTErrInfoSet(pErrInfo, VERR_WRONG_ORDER,
 1314                             "supHardenedWinVerifyImageByHandle: supHardenedWinInitImageVerifier was not called.");
 1315 #endif
 1316 
 1317     /*
 1318      * Check the trusted installer bit first, if requested as it's somewhat
 1319      * cheaper than the rest.
 1320      *
 1321      * We relax this for system32 and a little for WinSxS, like we used to, as
 1322      * there are apparently  some systems out there where the user, admin, or
 1323      * someone has changed the ownership of core windows DLLs like user32.dll
 1324      * and comctl32.dll.  Since we need user32.dll  and will be checking it's
 1325      * digital signature, it's reasonably safe to let this thru. (The report
 1326      * was of SECURITY_BUILTIN_DOMAIN_RID + DOMAIN_ALIAS_RID_ADMINS
 1327      * owning user32.dll, see public ticket 13187, VBoxStartup.3.log.)
 1328      *
 1329      * We've also had problems with graphics driver components like ig75icd64.dll
 1330      * and atig6pxx.dll not being owned by TrustedInstaller, with the result
 1331      * that 3D got broken (mod by zero issue in test build 5).  These were also
 1332      * SECURITY_BUILTIN_DOMAIN_RID + DOMAIN_ALIAS_RID_ADMINS.
 1333      *
 1334      * In one report by 'thor' the WinSxS resident comctl32.dll was owned by
 1335      * SECURITY_BUILTIN_DOMAIN_RID + DOMAIN_ALIAS_RID_ADMINS (with 4.3.16).
 1336      */
 1337     /** @todo Since we're now allowing Builtin\\Administrators after all, perhaps we
 1338      *        could drop these system32 + winsxs hacks?? */
 1339     if (   (pNtViRdr->fFlags & SUPHNTVI_F_TRUSTED_INSTALLER_OWNER)
 1340         && !supHardNtViCheckIsOwnedByTrustedInstallerOrSimilar(pNtViRdr->hFile, pwszName))
 1341     {
 1342         if (supHardViUtf16PathStartsWithEx(pwszName, (uint32_t)RTUtf16Len(pwszName),
 1343                                            g_System32NtPath.UniStr.Buffer, g_System32NtPath.UniStr.Length / sizeof(WCHAR),
 1344                                            true /*fCheckSlash*/))
 1345             SUP_DPRINTF(("%ls: Relaxing the TrustedInstaller requirement for this DLL (it's in system32).\n", pwszName));
 1346         else if (supHardViUtf16PathStartsWithEx(pwszName, (uint32_t)RTUtf16Len(pwszName),
 1347                                                 g_WinSxSNtPath.UniStr.Buffer, g_WinSxSNtPath.UniStr.Length / sizeof(WCHAR),
 1348                                                 true /*fCheckSlash*/))
 1349             SUP_DPRINTF(("%ls: Relaxing the TrustedInstaller requirement for this DLL (it's in WinSxS).\n", pwszName));
 1350         else
 1351             return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_NOT_OWNED_BY_TRUSTED_INSTALLER,
 1352                                  "supHardenedWinVerifyImageByHandle: TrustedInstaller is not the owner of '%ls'.", pwszName);
 1353     }
 1354 
 1355     /*
 1356      * Verify it.
 1357      *
 1358      * The PKCS #7 SignedData signature is checked in the callback. Any
 1359      * signing certificate restrictions are also enforced there.
 1360      */
 1361     pNtViRdr->cOkaySignatures        = 0;
 1362     pNtViRdr->cNokSignatures         = 0;
 1363     pNtViRdr->cTotalSignatures       = 0;
 1364     pNtViRdr->rcLastSignatureFailure = VINF_SUCCESS;
 1365     int rc = RTLdrVerifySignature(hLdrMod, supHardNtViCallback, pNtViRdr, pErrInfo);
 1366     if (RT_SUCCESS(rc))
 1367     {
 1368         Assert(pNtViRdr->cOkaySignatures + pNtViRdr->cNokSignatures == pNtViRdr->cTotalSignatures);
 1369         if (   !pNtViRdr->cOkaySignatures
 1370             || pNtViRdr->cOkaySignatures + pNtViRdr->cNokSignatures < pNtViRdr->cTotalSignatures /* paranoia */)
 1371         {
 1372             rc = pNtViRdr->rcLastSignatureFailure;
 1373             AssertStmt(RT_FAILURE_NP(rc), rc = VERR_INTERNAL_ERROR_3);
 1374         }
 1375         else if (rc == VINF_SUCCESS && RT_SUCCESS(pNtViRdr->rcLastSignatureFailure))
 1376             rc = pNtViRdr->rcLastSignatureFailure;
 1377     }
 1378 
 1379     /*
 1380      * Microsoft doesn't sign a whole bunch of DLLs, so we have to
 1381      * ASSUME that a bunch of system DLLs are fine.
 1382      */
 1383     if (rc == VERR_LDRVI_NOT_SIGNED)
 1384         rc = supHardNtViCheckIfNotSignedOk(hLdrMod, pwszName, pNtViRdr->fFlags, pNtViRdr->hFile, rc);
 1385     if (RT_FAILURE(rc))
 1386         RTErrInfoAddF(pErrInfo, rc, ": %ls", pwszName);
 1387 
 1388     /*
 1389      * Check for the signature checking enforcement, if requested to do so.
 1390      */
 1391     if (RT_SUCCESS(rc) && (pNtViRdr->fFlags & SUPHNTVI_F_REQUIRE_SIGNATURE_ENFORCEMENT))
 1392     {
 1393         bool fEnforced = false;
 1394         int rc2 = RTLdrQueryProp(hLdrMod, RTLDRPROP_SIGNATURE_CHECKS_ENFORCED, &fEnforced, sizeof(fEnforced));
 1395         if (RT_FAILURE(rc2))
 1396             rc = RTErrInfoSetF(pErrInfo, rc2, "Querying RTLDRPROP_SIGNATURE_CHECKS_ENFORCED failed on %ls: %Rrc.",
 1397                                pwszName, rc2);
 1398         else if (!fEnforced)
 1399             rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_SIGNATURE_CHECKS_NOT_ENFORCED,
 1400                                "The image '%ls' was not linked with /IntegrityCheck.", pwszName);
 1401     }
 1402 
 1403 #ifdef IN_RING3
 1404     /*
 1405      * Pass it thru WinVerifyTrust when possible.
 1406      */
 1407     if (!fAvoidWinVerifyTrust)
 1408         rc = supHardenedWinVerifyImageTrust(pNtViRdr->hFile, pwszName, pNtViRdr->fFlags, rc, pfWinVerifyTrust, pErrInfo);
 1409 #else
 1410     RT_NOREF1(fAvoidWinVerifyTrust);
 1411 #endif
 1412 
 1413     /*
 1414      * Check for blacklisted DLLs, both internal name and filename.
 1415      */
 1416     if (RT_SUCCESS(rc))
 1417     {
 1418         size_t const cwcName = RTUtf16Len(pwszName);
 1419         char         szIntName[64];
 1420         int rc2 = RTLdrQueryProp(hLdrMod, RTLDRPROP_INTERNAL_NAME, szIntName, sizeof(szIntName));
 1421         if (RT_SUCCESS(rc2))
 1422         {
 1423             size_t const cchIntName = strlen(szIntName);
 1424             for (unsigned i = 0; g_aSupNtViBlacklistedDlls[i].psz != NULL; i++)
 1425                 if (   cchIntName == g_aSupNtViBlacklistedDlls[i].cch
 1426                     && RTStrICmpAscii(szIntName, g_aSupNtViBlacklistedDlls[i].psz) == 0)
 1427                 {
 1428                     rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_UNDESIRABLE_MODULE,
 1429                                        "The image '%ls' is listed as undesirable.", pwszName);
 1430                     break;
 1431                 }
 1432         }
 1433         if (RT_SUCCESS(rc))
 1434         {
 1435             for (unsigned i = 0; g_aSupNtViBlacklistedDlls[i].psz != NULL; i++)
 1436                 if (cwcName >= g_aSupNtViBlacklistedDlls[i].cch)
 1437                 {
 1438                     PCRTUTF16 pwszTmp = &pwszName[cwcName - g_aSupNtViBlacklistedDlls[i].cch];
 1439                     if (   (   cwcName == g_aSupNtViBlacklistedDlls[i].cch
 1440                             || pwszTmp[-1] == '\\'
 1441                             || pwszTmp[-1] == '/')
 1442                         && RTUtf16ICmpAscii(pwszTmp, g_aSupNtViBlacklistedDlls[i].psz) == 0)
 1443                     {
 1444                         rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_UNDESIRABLE_MODULE,
 1445                                            "The image '%ls' is listed as undesirable.", pwszName);
 1446                         break;
 1447                     }
 1448                 }
 1449         }
 1450     }
 1451 
 1452 #ifdef IN_SUP_HARDENED_R3
 1453     /*
 1454      * Hook for the LdrLoadDll code to schedule scanning of imports.
 1455      */
 1456     if (RT_SUCCESS(rc))
 1457         supR3HardenedWinVerifyCacheScheduleImports(hLdrMod, pwszName);
 1458 #endif
 1459 
 1460     return rc;
 1461 }
 1462 
 1463 
 1464 /**
 1465  * Verifies the given executable image.
 1466  *
 1467  * @returns IPRT status code.
 1468  * @param   hFile               File handle to the executable file.
 1469  * @param   pwszName            Full NT path to the DLL in question, used for
 1470  *                              dealing with unsigned system dlls as well as for
 1471  *                              error/logging.
 1472  * @param   fFlags              Flags, SUPHNTVI_F_XXX.
 1473  * @param   fAvoidWinVerifyTrust Whether to avoid WinVerifyTrust because of
 1474  *                              deadlock or other loader related dangers.
 1475  * @param   pfWinVerifyTrust    Where to return whether WinVerifyTrust was used.
 1476  * @param   pErrInfo            Pointer to error info structure. Optional.
 1477  */
 1478 DECLHIDDEN(int) supHardenedWinVerifyImageByHandle(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, bool fAvoidWinVerifyTrust,
 1479                                                   bool *pfWinVerifyTrust, PRTERRINFO pErrInfo)
 1480 {
 1481     /*
 1482      * Create a reader instance.
 1483      */
 1484     PSUPHNTVIRDR pNtViRdr;
 1485     int rc = supHardNtViRdrCreate(hFile, pwszName, fFlags, &pNtViRdr);
 1486     if (RT_SUCCESS(rc))
 1487     {
 1488         /*
 1489          * Open the image.
 1490          */
 1491         RTLDRMOD  hLdrMod;
 1492         RTLDRARCH enmArch   = fFlags & SUPHNTVI_F_RC_IMAGE ? RTLDRARCH_X86_32 : RTLDRARCH_HOST;
 1493         uint32_t  fLdrFlags = RTLDR_O_FOR_VALIDATION | RTLDR_O_IGNORE_ARCH_IF_NO_CODE;
 1494         if (fFlags & SUPHNTVI_F_IGNORE_ARCHITECTURE)
 1495             fLdrFlags |= RTLDR_O_IGNORE_ARCH_IF_NO_CODE;
 1496         rc = RTLdrOpenWithReader(&pNtViRdr->Core, fLdrFlags, enmArch, &hLdrMod, pErrInfo);
 1497         if (RT_SUCCESS(rc))
 1498         {
 1499             /*
 1500              * Verify it.
 1501              */
 1502             rc = supHardenedWinVerifyImageByLdrMod(hLdrMod, pwszName, pNtViRdr, fAvoidWinVerifyTrust, pfWinVerifyTrust, pErrInfo);
 1503             int rc2 = RTLdrClose(hLdrMod); AssertRC(rc2);
 1504         }
 1505         else
 1506             supHardNtViRdrDestroy(&pNtViRdr->Core);
 1507     }
 1508     SUP_DPRINTF(("supHardenedWinVerifyImageByHandle: -> %d (%ls)%s\n",
 1509                  rc, pwszName, pfWinVerifyTrust && *pfWinVerifyTrust ? " WinVerifyTrust" : ""));
 1510     return rc;
 1511 }
 1512 
 1513 
 1514 #ifdef IN_RING3
 1515 /**
 1516  * supHardenedWinVerifyImageByHandle version without the name.
 1517  *
 1518  * The name is derived from the handle.
 1519  *
 1520  * @returns IPRT status code.
 1521  * @param   hFile       File handle to the executable file.
 1522  * @param   fFlags      Flags, SUPHNTVI_F_XXX.
 1523  * @param   pErrInfo    Pointer to error info structure. Optional.
 1524  */
 1525 DECLHIDDEN(int) supHardenedWinVerifyImageByHandleNoName(HANDLE hFile, uint32_t fFlags, PRTERRINFO pErrInfo)
 1526 {
 1527     /*
 1528      * Determine the NT name and call the verification function.
 1529      */
 1530     union
 1531     {
 1532         UNICODE_STRING UniStr;
 1533         uint8_t abBuffer[(MAX_PATH + 8 + 1) * 2];
 1534     } uBuf;
 1535 
 1536     ULONG cbIgn;
 1537     NTSTATUS rcNt = NtQueryObject(hFile,
 1538                                   ObjectNameInformation,
 1539                                   &uBuf,
 1540                                   sizeof(uBuf) - sizeof(WCHAR),
 1541                                   &cbIgn);
 1542     if (NT_SUCCESS(rcNt))
 1543         uBuf.UniStr.Buffer[uBuf.UniStr.Length / sizeof(WCHAR)] = '\0';
 1544     else
 1545         uBuf.UniStr.Buffer = (WCHAR *)L"TODO3";
 1546 
 1547     return supHardenedWinVerifyImageByHandle(hFile, uBuf.UniStr.Buffer, fFlags, false /*fAvoidWinVerifyTrust*/,
 1548                                              NULL /*pfWinVerifyTrust*/, pErrInfo);
 1549 }
 1550 #endif /* IN_RING3 */
 1551 
 1552 
 1553 /**
 1554  * Retrieves the full official path to the system root or one of it's sub
 1555  * directories.
 1556  *
 1557  * This code is also used by the support driver.
 1558  *
 1559  * @returns VBox status code.
 1560  * @param   pvBuf               The output buffer.  This will contain a
 1561  *                              UNICODE_STRING followed (at the kernel's
 1562  *                              discretion) the string buffer.
 1563  * @param   cbBuf               The size of the buffer @a pvBuf points to.
 1564  * @param   enmDir              Which directory under the system root we're
 1565  *                              interested in.
 1566  * @param   pErrInfo            Pointer to error info structure. Optional.
 1567  */
 1568 DECLHIDDEN(int) supHardNtGetSystemRootDir(void *pvBuf, uint32_t cbBuf, SUPHARDNTSYSROOTDIR enmDir, PRTERRINFO pErrInfo)
 1569 {
 1570     HANDLE              hFile = RTNT_INVALID_HANDLE_VALUE;
 1571     IO_STATUS_BLOCK     Ios   = RTNT_IO_STATUS_BLOCK_INITIALIZER;
 1572 
 1573     UNICODE_STRING      NtName;
 1574     switch (enmDir)
 1575     {
 1576         case kSupHardNtSysRootDir_System32:
 1577         {
 1578             static const WCHAR  s_wszNameSystem32[] = L"\\SystemRoot\\System32\\";
 1579             NtName.Buffer        = (PWSTR)s_wszNameSystem32;
 1580             NtName.Length        = sizeof(s_wszNameSystem32) - sizeof(WCHAR);
 1581             NtName.MaximumLength = sizeof(s_wszNameSystem32);
 1582             break;
 1583         }
 1584         case kSupHardNtSysRootDir_WinSxS:
 1585         {
 1586             static const WCHAR  s_wszNameWinSxS[] = L"\\SystemRoot\\WinSxS\\";
 1587             NtName.Buffer        = (PWSTR)s_wszNameWinSxS;
 1588             NtName.Length        = sizeof(s_wszNameWinSxS) - sizeof(WCHAR);
 1589             NtName.MaximumLength = sizeof(s_wszNameWinSxS);
 1590             break;
 1591         }
 1592         default:
 1593             AssertFailed();
 1594             return VERR_INVALID_PARAMETER;
 1595     }
 1596 
 1597     OBJECT_ATTRIBUTES ObjAttr;
 1598     InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
 1599 
 1600     NTSTATUS rcNt = NtCreateFile(&hFile,
 1601                                  FILE_READ_DATA | SYNCHRONIZE,
 1602                                  &ObjAttr,
 1603                                  &Ios,
 1604                                  NULL /* Allocation Size*/,
 1605                                  FILE_ATTRIBUTE_NORMAL,
 1606                                  FILE_SHARE_READ | FILE_SHARE_WRITE,
 1607                                  FILE_OPEN,
 1608                                  FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
 1609                                  NULL /*EaBuffer*/,
 1610                                  0 /*EaLength*/);
 1611     if (NT_SUCCESS(rcNt))
 1612         rcNt = Ios.Status;
 1613     if (NT_SUCCESS(rcNt))
 1614     {
 1615         ULONG cbIgn;
 1616         rcNt = NtQueryObject(hFile,
 1617                              ObjectNameInformation,
 1618                              pvBuf,
 1619                              cbBuf - sizeof(WCHAR),
 1620                              &cbIgn);
 1621         NtClose(hFile);
 1622         if (NT_SUCCESS(rcNt))
 1623         {
 1624             PUNICODE_STRING pUniStr = (PUNICODE_STRING)pvBuf;
 1625             if (pUniStr->Length > 0)
 1626             {
 1627                 /* Make sure it's terminated so it can safely be printed.*/
 1628                 pUniStr->Buffer[pUniStr->Length / sizeof(WCHAR)] = '\0';
 1629                 return VINF_SUCCESS;
 1630             }
 1631 
 1632             return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_SYSTEM32_PATH,
 1633                                  "NtQueryObject returned an empty path for '%ls'", NtName.Buffer);
 1634         }
 1635         return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_SYSTEM32_PATH, "NtQueryObject failed on '%ls' dir: %#x", NtName.Buffer, rcNt);
 1636     }
 1637     return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_SYSTEM32_PATH, "Failure to open '%ls': %#x", NtName.Buffer, rcNt);
 1638 }
 1639 
 1640 
 1641 /**
 1642  * Initialize one certificate entry.
 1643  *
 1644  * @returns VBox status code.
 1645  * @param   pCert               The X.509 certificate representation to init.
 1646  * @param   pabCert             The raw DER encoded certificate.
 1647  * @param   cbCert              The size of the raw certificate.
 1648  * @param   pErrInfo            Where to return extended error info. Optional.
 1649  * @param   pszErrorTag         Error tag.
 1650  */
 1651 static int supHardNtViCertInit(PRTCRX509CERTIFICATE pCert, unsigned char const *pabCert, unsigned cbCert,
 1652                                PRTERRINFO pErrInfo, const char *pszErrorTag)
 1653 {
 1654     AssertReturn(cbCert > 16 && cbCert < _128K,
 1655                  RTErrInfoSetF(pErrInfo, VERR_INTERNAL_ERROR_3, "%s: cbCert=%#x out of range", pszErrorTag, cbCert));
 1656     AssertReturn(!RTCrX509Certificate_IsPresent(pCert),
 1657                  RTErrInfoSetF(pErrInfo, VERR_WRONG_ORDER, "%s: Certificate already decoded?", pszErrorTag));
 1658 
 1659     RTASN1CURSORPRIMARY PrimaryCursor;
 1660     RTAsn1CursorInitPrimary(&PrimaryCursor, pabCert, cbCert, pErrInfo, &g_RTAsn1DefaultAllocator, RTASN1CURSOR_FLAGS_DER, NULL);
 1661     int rc = RTCrX509Certificate_DecodeAsn1(&PrimaryCursor.Cursor, 0, pCert, pszErrorTag);
 1662     if (RT_SUCCESS(rc))
 1663         rc = RTCrX509Certificate_CheckSanity(pCert, 0, pErrInfo, pszErrorTag);
 1664     return rc;
 1665 }
 1666 
 1667 
 1668 static int supHardNtViCertStoreAddArray(RTCRSTORE hStore, PCSUPTAENTRY paCerts, unsigned cCerts, PRTERRINFO pErrInfo)
 1669 {
 1670     for (uint32_t i = 0; i < cCerts; i++)
 1671     {
 1672         int rc = RTCrStoreCertAddEncoded(hStore, RTCRCERTCTX_F_ENC_TAF_DER, paCerts[i].pch, paCerts[i].cb, pErrInfo);
 1673         if (RT_FAILURE(rc))
 1674             return rc;
 1675     }
 1676     return VINF_SUCCESS;
 1677 }
 1678 
 1679 
 1680 /**
 1681  * Initialize a certificate table.
 1682  *
 1683  * @param   phStore             Where to return the store pointer.
 1684  * @param   paCerts1            Pointer to the first certificate table.
 1685  * @param   cCerts1             Entries in the first certificate table.
 1686  * @param   paCerts2            Pointer to the second certificate table.
 1687  * @param   cCerts2             Entries in the second certificate table.
 1688  * @param   paCerts3            Pointer to the third certificate table.
 1689  * @param   cCerts3             Entries in the third certificate table.
 1690  * @param   pErrInfo            Where to return extended error info. Optional.
 1691  * @param   pszErrorTag         Error tag.
 1692  */
 1693 static int supHardNtViCertStoreInit(PRTCRSTORE phStore,
 1694                                     PCSUPTAENTRY paCerts1, unsigned cCerts1,
 1695                                     PCSUPTAENTRY paCerts2, unsigned cCerts2,
 1696                                     PCSUPTAENTRY paCerts3, unsigned cCerts3,
 1697                                     PRTERRINFO pErrInfo, const char *pszErrorTag)
 1698 {
 1699     AssertReturn(*phStore == NIL_RTCRSTORE, VERR_WRONG_ORDER);
 1700     RT_NOREF1(pszErrorTag);
 1701 
 1702     int rc = RTCrStoreCreateInMem(phStore, cCerts1 + cCerts2);
 1703     if (RT_FAILURE(rc))
 1704         return RTErrInfoSetF(pErrInfo, rc, "RTCrStoreCreateMemoryStore failed: %Rrc", rc);
 1705 
 1706     rc = supHardNtViCertStoreAddArray(*phStore, paCerts1, cCerts1, pErrInfo);
 1707     if (RT_SUCCESS(rc))
 1708         rc = supHardNtViCertStoreAddArray(*phStore, paCerts2, cCerts2, pErrInfo);
 1709     if (RT_SUCCESS(rc))
 1710         rc = supHardNtViCertStoreAddArray(*phStore, paCerts3, cCerts3, pErrInfo);
 1711     return rc;
 1712 }
 1713 
 1714 
 1715 #if defined(IN_RING3) && !defined(VBOX_PERMIT_EVEN_MORE)
 1716 /**
 1717  * Initializes the windows paths.
 1718  */
 1719 static void supHardenedWinInitImageVerifierWinPaths(void)
 1720 {
 1721     /*
 1722      * Windows paths that we're interested in.
 1723      */
 1724     static const struct
 1725     {
 1726         SUPSYSROOTDIRBUF   *pNtPath;
 1727         WCHAR const        *pwszRegValue;
 1728         const char         *pszLogName;
 1729     } s_aPaths[] =
 1730     {
 1731         { &g_ProgramFilesNtPath,    L"ProgramFilesDir",         "ProgDir" },
 1732         { &g_CommonFilesNtPath,     L"CommonFilesDir",          "ComDir" },
 1733 # ifdef RT_ARCH_AMD64
 1734         { &g_ProgramFilesX86NtPath, L"ProgramFilesDir (x86)",   "ProgDir32" },
 1735         { &g_CommonFilesX86NtPath,  L"CommonFilesDir (x86)",    "ComDir32" },
 1736 # endif
 1737     };
 1738 
 1739     /*
 1740      * Open the registry key containing the paths.
 1741      */
 1742     UNICODE_STRING NtName = RTNT_CONSTANT_UNISTR(L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion");
 1743     OBJECT_ATTRIBUTES ObjAttr;
 1744     InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
 1745     HANDLE hKey;
 1746     NTSTATUS rcNt = NtOpenKey(&hKey, KEY_QUERY_VALUE, &ObjAttr);
 1747     if (NT_SUCCESS(rcNt))
 1748     {
 1749         /*
 1750          * Loop over the paths and resolve their NT paths.
 1751          */
 1752         for (uint32_t i = 0; i < RT_ELEMENTS(s_aPaths); i++)
 1753         {
 1754             /*
 1755              * Query the value first.
 1756              */
 1757             UNICODE_STRING ValueName;
 1758             ValueName.Buffer = (WCHAR *)s_aPaths[i].pwszRegValue;
 1759             ValueName.Length = (USHORT)(RTUtf16Len(s_aPaths[i].pwszRegValue) * sizeof(WCHAR));
 1760             ValueName.MaximumLength = ValueName.Length + sizeof(WCHAR);
 1761 
 1762             union
 1763             {
 1764                 KEY_VALUE_PARTIAL_INFORMATION   PartialInfo;
 1765                 uint8_t                         abPadding[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(WCHAR) * 128];
 1766                 uint64_t                        uAlign;
 1767             } uBuf;
 1768 
 1769             ULONG cbActual = 0;
 1770             rcNt = NtQueryValueKey(hKey, &ValueName, KeyValuePartialInformation, &uBuf, sizeof(uBuf) - sizeof(WCHAR), &cbActual);
 1771             if (NT_SUCCESS(rcNt))
 1772             {
 1773                 /*
 1774                  * Must be a simple string value, terminate it.
 1775                  */
 1776                 if (   uBuf.PartialInfo.Type == REG_EXPAND_SZ
 1777                     || uBuf.PartialInfo.Type == REG_SZ)
 1778                 {
 1779                     /*
 1780                      * Expand any environment variable references before opening it.
 1781                      * We use the result buffer as storage for the expaneded path,
 1782                      * reserving space for the windows name space prefix.
 1783                      */
 1784                     UNICODE_STRING Src;
 1785                     Src.Buffer = (WCHAR *)uBuf.PartialInfo.Data;
 1786                     Src.Length = uBuf.PartialInfo.DataLength;
 1787                     if (Src.Length >= sizeof(WCHAR) && Src.Buffer[Src.Length / sizeof(WCHAR) - 1] == '\0')
 1788                         Src.Length -= sizeof(WCHAR);
 1789                     Src.MaximumLength = Src.Length + sizeof(WCHAR);
 1790                     Src.Buffer[uBuf.PartialInfo.DataLength / sizeof(WCHAR)] = '\0';
 1791 
 1792                     s_aPaths[i].pNtPath->awcBuffer[0] = '\\';
 1793                     s_aPaths[i].pNtPath->awcBuffer[1] = '?';
 1794                     s_aPaths[i].pNtPath->awcBuffer[2] = '?';
 1795                     s_aPaths[i].pNtPath->awcBuffer[3] = '\\';
 1796                     UNICODE_STRING Dst;
 1797                     Dst.Buffer = &s_aPaths[i].pNtPath->awcBuffer[4];
 1798                     Dst.MaximumLength = sizeof(s_aPaths[i].pNtPath->awcBuffer) - sizeof(WCHAR) * 5;
 1799                     Dst.Length = Dst.MaximumLength;
 1800 
 1801                     if (uBuf.PartialInfo.Type == REG_EXPAND_SZ)
 1802                         rcNt = RtlExpandEnvironmentStrings_U(NULL, &Src, &Dst, NULL);
 1803                     else
 1804                     {
 1805                         memcpy(Dst.Buffer, Src.Buffer, Src.Length);
 1806                         Dst.Length = Src.Length;
 1807                     }
 1808                     if (NT_SUCCESS(rcNt))
 1809                     {
 1810                         Dst.Buffer[Dst.Length / sizeof(WCHAR)] = '\0';
 1811 
 1812                         /*
 1813                          * Include the \\??\\ prefix in the result and open the path.
 1814                          */
 1815                         Dst.Buffer        -= 4;
 1816                         Dst.Length        += 4 * sizeof(WCHAR);
 1817                         Dst.MaximumLength += 4 * sizeof(WCHAR);
 1818                         InitializeObjectAttributes(&ObjAttr, &Dst, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
 1819                         HANDLE          hFile = INVALID_HANDLE_VALUE;
 1820                         IO_STATUS_BLOCK Ios   = RTNT_IO_STATUS_BLOCK_INITIALIZER;
 1821                         NTSTATUS rcNt = NtCreateFile(&hFile,
 1822                                                      FILE_READ_DATA | SYNCHRONIZE,
 1823                                                      &ObjAttr,
 1824                                                      &Ios,
 1825                                                      NULL /* Allocation Size*/,
 1826                                                      FILE_ATTRIBUTE_NORMAL,
 1827                                                      FILE_SHARE_READ | FILE_SHARE_WRITE,
 1828                                                      FILE_OPEN,
 1829                                                      FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT
 1830                                                      | FILE_SYNCHRONOUS_IO_NONALERT,
 1831                                                      NULL /*EaBuffer*/,
 1832                                                      0 /*EaLength*/);
 1833                         if (NT_SUCCESS(rcNt))
 1834                             rcNt = Ios.Status;
 1835                         if (NT_SUCCESS(rcNt))
 1836                         {
 1837                             /*
 1838                              * Query the real NT name.
 1839                              */
 1840                             ULONG cbIgn;
 1841                             rcNt = NtQueryObject(hFile,
 1842                                                  ObjectNameInformation,
 1843                                                  s_aPaths[i].pNtPath,
 1844                                                  sizeof(*s_aPaths[i].pNtPath) - sizeof(WCHAR),
 1845                                                  &cbIgn);
 1846                             if (NT_SUCCESS(rcNt))
 1847                             {
 1848                                 if (s_aPaths[i].pNtPath->UniStr.Length > 0)
 1849                                 {
 1850                                     /* Make sure it's terminated.*/
 1851                                     s_aPaths[i].pNtPath->UniStr.Buffer[s_aPaths[i].pNtPath->UniStr.Length / sizeof(WCHAR)] = '\0';
 1852                                     SUP_DPRINTF(("%s:%*s %ls\n", s_aPaths[i].pszLogName, 9 - strlen(s_aPaths[i].pszLogName), "",
 1853                                                  s_aPaths[i].pNtPath->UniStr.Buffer));
 1854                                 }
 1855                                 else
 1856                                 {
 1857                                     SUP_DPRINTF(("%s: NtQueryObject returned empty string\n", s_aPaths[i].pszLogName));
 1858                                     rcNt = STATUS_INVALID_PARAMETER;
 1859                                 }
 1860                             }
 1861                             else
 1862                                 SUP_DPRINTF(("%s: NtQueryObject failed: %#x\n", s_aPaths[i].pszLogName, rcNt));
 1863                             NtClose(hFile);
 1864                         }
 1865                         else
 1866                             SUP_DPRINTF(("%s: NtCreateFile failed: %#x (%ls)\n",
 1867                                          s_aPaths[i].pszLogName, rcNt, Dst.Buffer));
 1868                     }
 1869                     else
 1870                         SUP_DPRINTF(("%s: RtlExpandEnvironmentStrings_U failed: %#x (%ls)\n",
 1871                                      s_aPaths[i].pszLogName, rcNt, Src.Buffer));
 1872                 }
 1873                 else
 1874                 {
 1875                     SUP_DPRINTF(("%s: type mismatch: %#x\n", s_aPaths[i].pszLogName, uBuf.PartialInfo.Type));
 1876                     rcNt = STATUS_INVALID_PARAMETER;
 1877                 }
 1878             }
 1879             else
 1880                 SUP_DPRINTF(("%s: NtQueryValueKey failed: %#x\n", s_aPaths[i].pszLogName, rcNt));
 1881 
 1882             /* Stub the entry on failure. */
 1883             if (!NT_SUCCESS(rcNt))
 1884             {
 1885                 s_aPaths[i].pNtPath->UniStr.Length = 0;
 1886                 s_aPaths[i].pNtPath->UniStr.Buffer = NULL;
 1887             }
 1888         }
 1889         NtClose(hKey);
 1890     }
 1891     else
 1892     {
 1893         SUP_DPRINTF(("NtOpenKey(%ls) failed: %#x\n", NtName.Buffer, rcNt));
 1894 
 1895         /* Stub all the entries on failure. */
 1896         for (uint32_t i = 0; i < RT_ELEMENTS(s_aPaths); i++)
 1897         {
 1898             s_aPaths[i].pNtPath->UniStr.Length = 0;
 1899             s_aPaths[i].pNtPath->UniStr.Buffer = NULL;
 1900         }
 1901     }
 1902 }
 1903 #endif /* IN_RING3 && !VBOX_PERMIT_EVEN_MORE */
 1904 
 1905 
 1906 /**
 1907  * This initializes the certificates globals so we don't have to reparse them
 1908  * every time we need to verify an image.
 1909  *
 1910  * @returns IPRT status code.
 1911  * @param   pErrInfo            Where to return extended error info. Optional.
 1912  */
 1913 DECLHIDDEN(int) supHardenedWinInitImageVerifier(PRTERRINFO pErrInfo)
 1914 {
 1915     AssertReturn(!RTCrX509Certificate_IsPresent(&g_BuildX509Cert), VERR_WRONG_ORDER);
 1916 
 1917     /*
 1918      * Get the system root paths.
 1919      */
 1920     int rc = supHardNtGetSystemRootDir(&g_System32NtPath, sizeof(g_System32NtPath), kSupHardNtSysRootDir_System32, pErrInfo);
 1921     if (RT_SUCCESS(rc))
 1922         rc = supHardNtGetSystemRootDir(&g_WinSxSNtPath, sizeof(g_WinSxSNtPath), kSupHardNtSysRootDir_WinSxS, pErrInfo);
 1923     if (RT_SUCCESS(rc))
 1924     {
 1925         SUP_DPRINTF(("System32:  %ls\n", g_System32NtPath.UniStr.Buffer));
 1926         SUP_DPRINTF(("WinSxS:    %ls\n", g_WinSxSNtPath.UniStr.Buffer));
 1927 #if defined(IN_RING3) && !defined(VBOX_PERMIT_EVEN_MORE)
 1928         supHardenedWinInitImageVerifierWinPaths();
 1929 #endif
 1930 
 1931         /*
 1932          * Initialize it, leaving the cleanup to the termination call.
 1933          */
 1934         rc = supHardNtViCertInit(&g_BuildX509Cert, g_abSUPBuildCert, g_cbSUPBuildCert, pErrInfo, "BuildCertificate");
 1935         if (RT_SUCCESS(rc))
 1936             rc = supHardNtViCertStoreInit(&g_hSpcRootStore, g_aSUPSpcRootTAs, g_cSUPSpcRootTAs,
 1937                                           NULL, 0, NULL, 0, pErrInfo, "SpcRoot");
 1938         if (RT_SUCCESS(rc))
 1939             rc = supHardNtViCertStoreInit(&g_hNtKernelRootStore, g_aSUPNtKernelRootTAs, g_cSUPNtKernelRootTAs,
 1940                                           NULL, 0, NULL, 0, pErrInfo, "NtKernelRoot");
 1941         if (RT_SUCCESS(rc))
 1942             rc = supHardNtViCertStoreInit(&g_hSpcAndNtKernelRootStore,
 1943                                           g_aSUPSpcRootTAs, g_cSUPSpcRootTAs,
 1944                                           g_aSUPNtKernelRootTAs, g_cSUPNtKernelRootTAs,
 1945                                           g_aSUPTimestampTAs, g_cSUPTimestampTAs,
 1946                                           pErrInfo, "SpcAndNtKernelRoot");
 1947         if (RT_SUCCESS(rc))
 1948             rc = supHardNtViCertStoreInit(&g_hSpcAndNtKernelSuppStore,
 1949                                           NULL, 0, NULL, 0, NULL, 0,
 1950                                           pErrInfo, "SpcAndNtKernelSupplemental");
 1951 
 1952 #if 0 /* For the time being, always trust the build certificate. It bypasses the timestamp issues of CRT and SDL. */
 1953         /* If the build certificate is a test singing certificate, it must be a
 1954            trusted root or we'll fail to validate anything. */
 1955         if (   RT_SUCCESS(rc)
 1956             && RTCrX509Name_Compare(&g_BuildX509Cert.TbsCertificate.Subject, &g_BuildX509Cert.TbsCertificate.Issuer) == 0)
 1957 #else
 1958         if (RT_SUCCESS(rc))
 1959 #endif
 1960             rc = RTCrStoreCertAddEncoded(g_hSpcAndNtKernelRootStore, RTCRCERTCTX_F_ENC_X509_DER,
 1961                                          g_abSUPBuildCert, g_cbSUPBuildCert, pErrInfo);
 1962 
 1963         if (RT_SUCCESS(rc))
 1964         {
 1965             /*
 1966              * Finally initialize known SIDs that we use.
 1967              */
 1968             SID_IDENTIFIER_AUTHORITY s_NtAuth = SECURITY_NT_AUTHORITY;
 1969             NTSTATUS rcNt = RtlInitializeSid(&g_TrustedInstallerSid, &s_NtAuth, SECURITY_SERVICE_ID_RID_COUNT);
 1970             if (NT_SUCCESS(rcNt))
 1971             {
 1972                 *RtlSubAuthoritySid(&g_TrustedInstallerSid, 0) = SECURITY_SERVICE_ID_BASE_RID;
 1973                 *RtlSubAuthoritySid(&g_TrustedInstallerSid, 1) = 956008885;
 1974                 *RtlSubAuthoritySid(&g_TrustedInstallerSid, 2) = 3418522649;
 1975                 *RtlSubAuthoritySid(&g_TrustedInstallerSid, 3) = 1831038044;
 1976                 *RtlSubAuthoritySid(&g_TrustedInstallerSid, 4) = 1853292631;
 1977                 *RtlSubAuthoritySid(&g_TrustedInstallerSid, 5) = 2271478464;
 1978 
 1979                 rcNt = RtlInitializeSid(&g_LocalSystemSid, &s_NtAuth, 1);
 1980                 if (NT_SUCCESS(rcNt))
 1981                 {
 1982                     *RtlSubAuthoritySid(&g_LocalSystemSid, 0) = SECURITY_LOCAL_SYSTEM_RID;
 1983 
 1984                     rcNt = RtlInitializeSid(&g_AdminsGroupSid, &s_NtAuth, 2);
 1985                     if (NT_SUCCESS(rcNt))
 1986                     {
 1987                         *RtlSubAuthoritySid(&g_AdminsGroupSid, 0) = SECURITY_BUILTIN_DOMAIN_RID;
 1988                         *RtlSubAuthoritySid(&g_AdminsGroupSid, 1) = DOMAIN_ALIAS_RID_ADMINS;
 1989                         return VINF_SUCCESS;
 1990                     }
 1991                 }
 1992             }
 1993             rc = RTErrConvertFromNtStatus(rcNt);
 1994         }
 1995         supHardenedWinTermImageVerifier();
 1996     }
 1997     return rc;
 1998 }
 1999 
 2000 
 2001 /**
 2002  * Releases resources allocated by supHardenedWinInitImageVerifier.
 2003  */
 2004 DECLHIDDEN(void) supHardenedWinTermImageVerifier(void)
 2005 {
 2006     if (RTCrX509Certificate_IsPresent(&g_BuildX509Cert))
 2007         RTAsn1VtDelete(&g_BuildX509Cert.SeqCore.Asn1Core);
 2008 
 2009     RTCrStoreRelease(g_hSpcAndNtKernelSuppStore);
 2010     g_hSpcAndNtKernelSuppStore = NIL_RTCRSTORE;
 2011     RTCrStoreRelease(g_hSpcAndNtKernelRootStore);
 2012     g_hSpcAndNtKernelRootStore = NIL_RTCRSTORE;
 2013 
 2014     RTCrStoreRelease(g_hNtKernelRootStore);
 2015     g_hNtKernelRootStore = NIL_RTCRSTORE;
 2016     RTCrStoreRelease(g_hSpcRootStore);
 2017     g_hSpcRootStore = NIL_RTCRSTORE;
 2018 }
 2019 
 2020 #ifdef IN_RING3
 2021 
 2022 /**
 2023  * This is a hardcoded list of certificates we thing we might need.
 2024  *
 2025  * @returns true if wanted, false if not.
 2026  * @param   pCert               The certificate.
 2027  */
 2028 static bool supR3HardenedWinIsDesiredRootCA(PCRTCRX509CERTIFICATE pCert)
 2029 {
 2030     char szSubject[512];
 2031     szSubject[sizeof(szSubject) - 1] = '\0';
 2032     RTCrX509Name_FormatAsString(&pCert->TbsCertificate.Subject, szSubject, sizeof(szSubject) - 1, NULL);
 2033 
 2034     /*
 2035      * Check that it's a plausible root certificate.
 2036      */
 2037     if (!RTCrX509Certificate_IsSelfSigned(pCert))
 2038     {
 2039         SUP_DPRINTF(("supR3HardenedWinIsDesiredRootCA: skipping - not-self-signed: %s\n", szSubject));
 2040         return false;
 2041     }
 2042 
 2043     if (RTAsn1Integer_UnsignedCompareWithU32(&pCert->TbsCertificate.T0.Version, 3) > 0)
 2044     {
 2045         if (   !(pCert->TbsCertificate.T3.fExtKeyUsage & RTCRX509CERT_KEY_USAGE_F_KEY_CERT_SIGN)
 2046             && (pCert->TbsCertificate.T3.fFlags & RTCRX509TBSCERTIFICATE_F_PRESENT_KEY_USAGE) )
 2047         {
 2048             SUP_DPRINTF(("supR3HardenedWinIsDesiredRootCA: skipping - non-cert-sign: %s\n", szSubject));
 2049             return false;
 2050         }
 2051         if (   pCert->TbsCertificate.T3.pBasicConstraints
 2052             && !pCert->TbsCertificate.T3.pBasicConstraints->CA.fValue)
 2053         {
 2054             SUP_DPRINTF(("supR3HardenedWinIsDesiredRootCA: skipping - non-CA: %s\n", szSubject));
 2055             return false;
 2056         }
 2057     }
 2058     if (pCert->TbsCertificate.SubjectPublicKeyInfo.SubjectPublicKey.cBits < 256) /* mostly for u64KeyId reading. */
 2059     {
 2060         SUP_DPRINTF(("supR3HardenedWinIsDesiredRootCA: skipping - key too small: %u bits %s\n",
 2061                      pCert->TbsCertificate.SubjectPublicKeyInfo.SubjectPublicKey.cBits, szSubject));
 2062         return false;
 2063     }
 2064     uint64_t const u64KeyId = pCert->TbsCertificate.SubjectPublicKeyInfo.SubjectPublicKey.uBits.pu64[1];
 2065 
 2066 # if 0
 2067     /*
 2068      * Whitelist - Array of names and key clues of the certificates we want.
 2069      */
 2070     static struct
 2071     {
 2072         uint64_t    u64KeyId;
 2073         const char *pszName;
 2074     } const s_aWanted[] =
 2075     {
 2076         /* SPC */
 2077         { UINT64_C(0xffffffffffffffff), "C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority" },
 2078         { UINT64_C(0xffffffffffffffff), "L=Internet, O=VeriSign, Inc., OU=VeriSign Commercial Software Publishers CA" },
 2079         { UINT64_C(0x491857ead79dde00), "C=US, O=The Go Daddy Group, Inc., OU=Go Daddy Class 2 Certification Authority" },
 2080 
 2081         /* TS */
 2082         { UINT64_C(0xffffffffffffffff), "O=Microsoft Trust Network, OU=Microsoft Corporation, OU=Microsoft Time Stamping Service Root, OU=Copyright (c) 1997 Microsoft Corp." },
 2083         { UINT64_C(0xffffffffffffffff), "O=VeriSign Trust Network, OU=VeriSign, Inc., OU=VeriSign Time Stamping Service Root, OU=NO LIABILITY ACCEPTED, (c)97 VeriSign, Inc." },
 2084         { UINT64_C(0xffffffffffffffff), "C=ZA, ST=Western Cape, L=Durbanville, O=Thawte, OU=Thawte Certification, CN=Thawte Timestamping CA" },
 2085 
 2086         /* Additional Windows 8.1 list: */
 2087         { UINT64_C(0x5ad46780fa5df300), "DC=com, DC=microsoft, CN=Microsoft Root Certificate Authority" },
 2088         { UINT64_C(0x3be670c1bd02a900), "OU=Copyright (c) 1997 Microsoft Corp., OU=Microsoft Corporation, CN=Microsoft Root Authority" },
 2089         { UINT64_C(0x4d3835aa4180b200), "C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Root Certificate Authority 2011" },
 2090         { UINT64_C(0x646e3fe3ba08df00), "C=US, O=MSFT, CN=Microsoft Authenticode(tm) Root Authority" },
 2091         { UINT64_C(0xece4e4289e08b900), "C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Root Certificate Authority 2010" },
 2092         { UINT64_C(0x59faf1086271bf00), "C=US, ST=Arizona, L=Scottsdale, O=GoDaddy.com, Inc., CN=Go Daddy Root Certificate Authority - G2" },
 2093         { UINT64_C(0x3d98ab22bb04a300), "C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root" },
 2094         { UINT64_C(0x91e3728b8b40d000), "C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO Certification Authority" },
 2095         { UINT64_C(0x61a3a33f81aace00), "C=US, ST=UT, L=Salt Lake City, O=The USERTRUST Network, OU=http://www.usertrust.com, CN=UTN-USERFirst-Object" },
 2096         { UINT64_C(0x9e5bc2d78b6a3636), "C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Premium Server CA, Email=premium-server@thawte.com" },
 2097         { UINT64_C(0xf4fd306318ccda00), "C=US, O=GeoTrust Inc., CN=GeoTrust Global CA" },
 2098         { UINT64_C(0xa0ee62086758b15d), "C=US, O=Equifax, OU=Equifax Secure Certificate Authority" },
 2099         { UINT64_C(0x8ff6fc03c1edbd00), "C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Root Certificate Authority - G2" },
 2100         { UINT64_C(0xa3ce8d99e60eda00), "C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA" },
 2101         { UINT64_C(0xa671e9fec832b700), "C=US, O=Starfield Technologies, Inc., OU=Starfield Class 2 Certification Authority" },
 2102         { UINT64_C(0xa8de7211e13be200), "C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA" },
 2103         { UINT64_C(0x0ff3891b54348328), "C=US, O=Entrust.net, OU=www.entrust.net/CPS incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.netSecure Server Certification Authority" },
 2104         { UINT64_C(0x7ae89c50f0b6a00f), "C=US, O=GTE Corporation, OU=GTE CyberTrust Solutions, Inc., CN=GTE CyberTrust Global Root" },
 2105         { UINT64_C(0xd45980fbf0a0ac00), "C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2006 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA" },
 2106         { UINT64_C(0x9e5bc2d78b6a3636), "C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Premium Server CA, Email=premium-server@thawte.com" },
 2107         { UINT64_C(0x7c4fd32ec1b1ce00), "C=PL, O=Unizeto Sp. z o.o., CN=Certum CA" },
 2108         { UINT64_C(0xd4fbe673e5ccc600), "C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA" },
 2109         { UINT64_C(0x16e64d2a56ccf200), "C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., OU=http://certificates.starfieldtech.com/repository/, CN=Starfield Services Root Certificate Authority" },
 2110         { UINT64_C(0x6e2ba21058eedf00), "C=US, ST=UT, L=Salt Lake City, O=The USERTRUST Network, OU=http://www.usertrust.com, CN=UTN - DATACorp SGC" },
 2111         { UINT64_C(0xb28612a94b4dad00), "O=Entrust.net, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.netCertification Authority (2048)" },
 2112         { UINT64_C(0x357a29080824af00), "C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class3 Public Primary Certification Authority - G5" },
 2113         { UINT64_C(0x466cbc09db88c100), "C=IL, O=StartCom Ltd., OU=Secure Digital Certificate Signing, CN=StartCom Certification Authority" },
 2114         { UINT64_C(0x9259c8abe5ca713a), "L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 2 Policy Validation Authority, CN=http://www.valicert.com/, Email=info@valicert.com" },
 2115         { UINT64_C(0x1f78fc529cbacb00), "C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 1999 VeriSign, Inc. - For authorized use only, CN=VeriSign Class3 Public Primary Certification Authority - G3" },
 2116         { UINT64_C(0x8043e4ce150ead00), "C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Assured ID Root CA" },
 2117         { UINT64_C(0x00f2e6331af7b700), "C=SE, O=AddTrust AB, OU=AddTrust External TTP Network, CN=AddTrust External CA Root" },
 2118     };
 2119 
 2120 
 2121     uint32_t i = RT_ELEMENTS(s_aWanted);
 2122     while (i-- > 0)
 2123         if (   s_aWanted[i].u64KeyId == u64KeyId
 2124             || s_aWanted[i].u64KeyId == UINT64_MAX)
 2125             if (RTCrX509Name_MatchWithString(&pCert->TbsCertificate.Subject, s_aWanted[i].pszName))
 2126             {
 2127                 SUP_DPRINTF(("supR3HardenedWinIsDesiredRootCA: Adding %#llx %s\n", u64KeyId, szSubject));
 2128                 return true;
 2129             }
 2130 
 2131     SUP_DPRINTF(("supR3HardenedWinIsDesiredRootCA: skipping %#llx %s\n", u64KeyId, szSubject));
 2132     return false;
 2133 # else
 2134     /*
 2135      * Blacklist approach.
 2136      */
 2137     static struct
 2138     {
 2139         uint64_t    u64KeyId;
 2140         const char *pszName;
 2141     } const s_aUnwanted[] =
 2142     {
 2143         { UINT64_C(0xffffffffffffffff), "C=US, O=U.S. Robots and Mechanical Men, Inc., OU=V.I.K.I." }, /* dummy entry */
 2144     };
 2145 
 2146     uint32_t i = RT_ELEMENTS(s_aUnwanted);
 2147     while (i-- > 0)
 2148         if (   s_aUnwanted[i].u64KeyId == u64KeyId
 2149             || s_aUnwanted[i].u64KeyId == UINT64_MAX)
 2150             if (RTCrX509Name_MatchWithString(&pCert->TbsCertificate.Subject, s_aUnwanted[i].pszName))
 2151             {
 2152                 SUP_DPRINTF(("supR3HardenedWinIsDesiredRootCA: skipping - blacklisted: %#llx %s\n", u64KeyId, szSubject));
 2153                 return false;
 2154             }
 2155 
 2156     SUP_DPRINTF(("supR3HardenedWinIsDesiredRootCA: Adding %#llx %s\n", u64KeyId, szSubject));
 2157     return true;
 2158 # endif
 2159 }
 2160 
 2161 
 2162 /**
 2163  * Loads a module in the system32 directory.
 2164  *
 2165  * @returns Module handle on success. Won't return on failure if fMandatory = true.
 2166  * @param   pszName             The name of the DLL to load.
 2167  * @param   fMandatory          Whether the library is mandatory.
 2168  */
 2169 DECLHIDDEN(HMODULE) supR3HardenedWinLoadSystem32Dll(const char *pszName, bool fMandatory)
 2170 {
 2171     WCHAR wszName[200+60];
 2172     UINT cwcDir = GetSystemDirectoryW(wszName, RT_ELEMENTS(wszName) - 60);
 2173     wszName[cwcDir] = '\\';
 2174     RTUtf16CopyAscii(&wszName[cwcDir + 1], RT_ELEMENTS(wszName) - cwcDir, pszName);
 2175 
 2176     DWORD fFlags = 0;
 2177     if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0))
 2178        fFlags = LOAD_LIBRARY_SEARCH_SYSTEM32;
 2179     HMODULE hMod = LoadLibraryExW(wszName, NULL, fFlags);
 2180     if (   hMod == NULL
 2181         && fFlags
 2182         && g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 2)
 2183         && RtlGetLastWin32Error() == ERROR_INVALID_PARAMETER)
 2184     {
 2185         fFlags = 0;
 2186         hMod = LoadLibraryExW(wszName, NULL, fFlags);
 2187     }
 2188     if (   hMod == NULL
 2189         && fMandatory)
 2190         supR3HardenedFatal("Error loading '%s': %u [%ls]", pszName, RtlGetLastWin32Error(), wszName);
 2191     return hMod;
 2192 }
 2193 
 2194 
 2195 /**
 2196  * Called by supR3HardenedWinResolveVerifyTrustApiAndHookThreadCreation to
 2197  * import selected root CAs from the system certificate store.
 2198  *
 2199  * These certificates permits us to correctly validate third party DLLs.
 2200  */
 2201 static void supR3HardenedWinRetrieveTrustedRootCAs(void)
 2202 {
 2203     uint32_t cAdded = 0;
 2204 
 2205     /*
 2206      * Load crypt32.dll and resolve the APIs we need.
 2207      */
 2208     HMODULE hCrypt32 = supR3HardenedWinLoadSystem32Dll("crypt32.dll", true /*fMandatory*/);
 2209 
 2210 #define RESOLVE_CRYPT32_API(a_Name, a_pfnType) \
 2211     a_pfnType pfn##a_Name = (a_pfnType)GetProcAddress(hCrypt32, #a_Name); \
 2212     if (pfn##a_Name == NULL) supR3HardenedFatal("Error locating '" #a_Name "' in 'crypt32.dll': %u", RtlGetLastWin32Error())
 2213     RESOLVE_CRYPT32_API(CertOpenStore, PFNCERTOPENSTORE);
 2214     RESOLVE_CRYPT32_API(CertCloseStore, PFNCERTCLOSESTORE);
 2215     RESOLVE_CRYPT32_API(CertEnumCertificatesInStore, PFNCERTENUMCERTIFICATESINSTORE);
 2216 #undef RESOLVE_CRYPT32_API
 2217 
 2218     /*
 2219      * Open the root store and look for the certificates we wish to use.
 2220      */
 2221     DWORD fOpenStore = CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG;
 2222     HCERTSTORE hStore = pfnCertOpenStore(CERT_STORE_PROV_SYSTEM_W, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
 2223                                          NULL /* hCryptProv = default */, CERT_SYSTEM_STORE_LOCAL_MACHINE | fOpenStore, L"Root");
 2224     if (!hStore)
 2225         hStore = pfnCertOpenStore(CERT_STORE_PROV_SYSTEM_W, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
 2226                                   NULL /* hCryptProv = default */, CERT_SYSTEM_STORE_CURRENT_USER | fOpenStore, L"Root");
 2227     if (hStore)
 2228     {
 2229         PCCERT_CONTEXT pCurCtx  = NULL;
 2230         while ((pCurCtx = pfnCertEnumCertificatesInStore(hStore, pCurCtx)) != NULL)
 2231         {
 2232             if (pCurCtx->dwCertEncodingType & X509_ASN_ENCODING)
 2233             {
 2234                 RTERRINFOSTATIC StaticErrInfo;
 2235                 RTASN1CURSORPRIMARY PrimaryCursor;
 2236                 RTAsn1CursorInitPrimary(&PrimaryCursor, pCurCtx->pbCertEncoded, pCurCtx->cbCertEncoded,
 2237                                         RTErrInfoInitStatic(&StaticErrInfo),
 2238                                         &g_RTAsn1DefaultAllocator, RTASN1CURSOR_FLAGS_DER, "CurCtx");
 2239                 RTCRX509CERTIFICATE MyCert;
 2240                 int rc = RTCrX509Certificate_DecodeAsn1(&PrimaryCursor.Cursor, 0, &MyCert, "Cert");
 2241                 if (RT_SUCCESS(rc))
 2242                 {
 2243                     if (supR3HardenedWinIsDesiredRootCA(&MyCert))
 2244                     {
 2245                         rc = RTCrStoreCertAddEncoded(g_hSpcRootStore, RTCRCERTCTX_F_ENC_X509_DER,
 2246                                                      pCurCtx->pbCertEncoded, pCurCtx->cbCertEncoded, NULL /*pErrInfo*/);
 2247                         AssertRC(rc);
 2248 
 2249                         rc = RTCrStoreCertAddEncoded(g_hSpcAndNtKernelRootStore, RTCRCERTCTX_F_ENC_X509_DER,
 2250                                                      pCurCtx->pbCertEncoded, pCurCtx->cbCertEncoded, NULL /*pErrInfo*/);
 2251                         AssertRC(rc);
 2252                         cAdded++;
 2253                     }
 2254 
 2255                     RTCrX509Certificate_Delete(&MyCert);
 2256                 }
 2257                 /* XP root certificate "C&W HKT SecureNet CA SGC Root" has non-standard validity
 2258                    timestamps, the UTC formatting isn't Zulu time but specifies timezone offsets.
 2259                    Ignore these failures and certificates. */
 2260                 else if (rc != VERR_ASN1_INVALID_UTC_TIME_ENCODING)
 2261                     AssertMsgFailed(("RTCrX509Certificate_DecodeAsn1 failed: rc=%#x: %s\n", rc, StaticErrInfo.szMsg));
 2262             }
 2263         }
 2264         pfnCertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
 2265         g_fHaveOtherRoots = true;
 2266     }
 2267     SUP_DPRINTF(("supR3HardenedWinRetrieveTrustedRootCAs: cAdded=%u\n", cAdded));
 2268 }
 2269 
 2270 
 2271 /**
 2272  * Resolves the WinVerifyTrust API after the process has been verified and
 2273  * installs a thread creation hook.
 2274  *
 2275  * The WinVerifyTrust API is used in addition our own Authenticode verification
 2276  * code.  If the image has the IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY flag
 2277  * set, it will be checked again by the kernel.  All our image has this flag set
 2278  * and we require all VBox extensions to have it set as well.  In effect, the
 2279  * authenticode signature will be checked two or three times.
 2280  *
 2281  * @param   pszProgName     The program name.
 2282  */
 2283 DECLHIDDEN(void) supR3HardenedWinResolveVerifyTrustApiAndHookThreadCreation(const char *pszProgName)
 2284 {
 2285 # ifdef IN_SUP_HARDENED_R3
 2286     /*
 2287      * Load our the support library DLL that does the thread hooking as the
 2288      * security API may trigger the creation of COM worker threads (or
 2289      * whatever they are).
 2290      *
 2291      * The thread creation hook makes the threads very slippery to debuggers by
 2292      * irreversably disabling most (if not all) debug events for them.
 2293      */
 2294     char szPath[RTPATH_MAX];
 2295     supR3HardenedPathAppSharedLibs(szPath, sizeof(szPath) - sizeof("/VBoxSupLib.DLL"));
 2296     suplibHardenedStrCat(szPath, "/VBoxSupLib.DLL");
 2297     HMODULE hSupLibMod = (HMODULE)supR3HardenedWinLoadLibrary(szPath, true /*fSystem32Only*/, 0 /*fMainFlags*/);
 2298     if (hSupLibMod == NULL)
 2299         supR3HardenedFatal("Error loading '%s': %u", szPath, RtlGetLastWin32Error());
 2300 # endif
 2301 
 2302     /*
 2303      * Allocate TLS entry for WinVerifyTrust recursion prevention.
 2304      */
 2305     DWORD iTls = TlsAlloc();
 2306     if (iTls != TLS_OUT_OF_INDEXES)
 2307         g_iTlsWinVerifyTrustRecursion = iTls;
 2308     else
 2309         supR3HardenedError(RtlGetLastWin32Error(), false /*fFatal*/, "TlsAlloc failed");
 2310 
 2311     /*
 2312      * Resolve the imports we need.
 2313      */
 2314     HMODULE hWintrust = supR3HardenedWinLoadSystem32Dll("Wintrust.dll", true /*fMandatory*/);
 2315 #define RESOLVE_CRYPT_API(a_Name, a_pfnType, a_uMinWinVer) \
 2316     do { \
 2317         g_pfn##a_Name = (a_pfnType)GetProcAddress(hWintrust, #a_Name); \
 2318         if (g_pfn##a_Name == NULL && (a_uMinWinVer) < g_uNtVerCombined) \
 2319             supR3HardenedFatal("Error locating '" #a_Name "' in 'Wintrust.dll': %u", RtlGetLastWin32Error()); \
 2320     } while (0)
 2321 
 2322     PFNWINVERIFYTRUST pfnWinVerifyTrust = (PFNWINVERIFYTRUST)GetProcAddress(hWintrust, "WinVerifyTrust");
 2323     if (!pfnWinVerifyTrust)
 2324         supR3HardenedFatal("Error locating 'WinVerifyTrust' in 'Wintrust.dll': %u", RtlGetLastWin32Error());
 2325 
 2326     RESOLVE_CRYPT_API(CryptCATAdminAcquireContext,           PFNCRYPTCATADMINACQUIRECONTEXT,          0);
 2327     RESOLVE_CRYPT_API(CryptCATAdminCalcHashFromFileHandle,   PFNCRYPTCATADMINCALCHASHFROMFILEHANDLE,  0);
 2328     RESOLVE_CRYPT_API(CryptCATAdminEnumCatalogFromHash,      PFNCRYPTCATADMINENUMCATALOGFROMHASH,     0);
 2329     RESOLVE_CRYPT_API(CryptCATAdminReleaseCatalogContext,    PFNCRYPTCATADMINRELEASECATALOGCONTEXT,   0);
 2330     RESOLVE_CRYPT_API(CryptCATAdminReleaseContext,           PFNCRYPTCATDADMINRELEASECONTEXT,         0);
 2331     RESOLVE_CRYPT_API(CryptCATCatalogInfoFromContext,        PFNCRYPTCATCATALOGINFOFROMCONTEXT,       0);
 2332 
 2333     RESOLVE_CRYPT_API(CryptCATAdminAcquireContext2,          PFNCRYPTCATADMINACQUIRECONTEXT2,         SUP_NT_VER_W80);
 2334     RESOLVE_CRYPT_API(CryptCATAdminCalcHashFromFileHandle2,  PFNCRYPTCATADMINCALCHASHFROMFILEHANDLE2, SUP_NT_VER_W80);
 2335 
 2336 # ifdef IN_SUP_HARDENED_R3
 2337     /*
 2338      * Load bcrypt.dll and instantiate a few hashing and signing providers to
 2339      * make sure the providers are cached for later us.  Avoid recursion issues.
 2340      */
 2341     HMODULE hBCrypt = supR3HardenedWinLoadSystem32Dll("bcrypt.dll", false /*fMandatory*/);
 2342     if (hBCrypt)
 2343     {
 2344         PFNBCRYPTOPENALGORTIHMPROVIDER pfnOpenAlgoProvider;
 2345         pfnOpenAlgoProvider = (PFNBCRYPTOPENALGORTIHMPROVIDER)GetProcAddress(hBCrypt, "BCryptOpenAlgorithmProvider");
 2346         if (pfnOpenAlgoProvider)
 2347         {
 2348             SUP_DPRINTF(("bcrypt.dll loaded at %p, BCryptOpenAlgorithmProvider at %p, preloading providers:\n",
 2349                          hBCrypt, pfnOpenAlgoProvider));
 2350 #  define PRELOAD_ALGO_PROVIDER(a_Name) \
 2351                 do { \
 2352                     BCRYPT_ALG_HANDLE hAlgo = NULL; \
 2353                     NTSTATUS rcNt = pfnOpenAlgoProvider(&hAlgo, a_Name, NULL, 0); \
 2354                     SUP_DPRINTF(("%sBCryptOpenAlgorithmProvider(,'%ls',0,0) -> %#x (hAlgo=%p)\n", \
 2355                                  NT_SUCCESS(rcNt) ? "    " : "warning: ", a_Name, rcNt, hAlgo)); \
 2356                 } while (0)
 2357             PRELOAD_ALGO_PROVIDER(BCRYPT_MD2_ALGORITHM);
 2358             PRELOAD_ALGO_PROVIDER(BCRYPT_MD4_ALGORITHM);
 2359             PRELOAD_ALGO_PROVIDER(BCRYPT_MD5_ALGORITHM);
 2360             PRELOAD_ALGO_PROVIDER(BCRYPT_SHA1_ALGORITHM);
 2361             PRELOAD_ALGO_PROVIDER(BCRYPT_SHA256_ALGORITHM);
 2362             PRELOAD_ALGO_PROVIDER(BCRYPT_SHA512_ALGORITHM);
 2363             PRELOAD_ALGO_PROVIDER(BCRYPT_RSA_ALGORITHM);
 2364             PRELOAD_ALGO_PROVIDER(BCRYPT_DSA_ALGORITHM);
 2365 #  undef PRELOAD_ALGO_PROVIDER
 2366         }
 2367         else
 2368             SUP_DPRINTF(("Warning! Failed to find BCryptOpenAlgorithmProvider in bcrypt.dll\n"));
 2369     }
 2370     else
 2371         SUP_DPRINTF(("Warning! Failed to load bcrypt.dll\n"));
 2372 
 2373     /*
 2374      * Call the verification API on ourselves and ntdll to make sure it works
 2375      * and loads more stuff it needs, preventing any recursive fun we'd run
 2376      * into after we set g_pfnWinVerifyTrust.
 2377      */
 2378     RTERRINFOSTATIC ErrInfoStatic;
 2379     RTErrInfoInitStatic(&ErrInfoStatic);
 2380     int rc = supR3HardNtViCallWinVerifyTrust(NULL, g_SupLibHardenedExeNtPath.UniStr.Buffer, 0,
 2381                                              &ErrInfoStatic.Core, pfnWinVerifyTrust, NULL);
 2382     if (RT_FAILURE(rc))
 2383         supR3HardenedFatalMsg(pszProgName, kSupInitOp_Integrity, rc,
 2384                               "WinVerifyTrust failed on stub executable: %s", ErrInfoStatic.szMsg);
 2385 # else
 2386     RT_NOREF1(pszProgName);
 2387 # endif
 2388 
 2389     if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0)) /* ntdll isn't signed on XP, assuming this is the case on W2K3 for now. */
 2390         supR3HardNtViCallWinVerifyTrust(NULL, L"\\SystemRoot\\System32\\ntdll.dll", 0, NULL, pfnWinVerifyTrust, NULL);
 2391     supR3HardNtViCallWinVerifyTrustCatFile(NULL, L"\\SystemRoot\\System32\\ntdll.dll", 0, NULL, pfnWinVerifyTrust);
 2392 
 2393     g_pfnWinVerifyTrust = pfnWinVerifyTrust;
 2394     SUP_DPRINTF(("g_pfnWinVerifyTrust=%p\n", pfnWinVerifyTrust));
 2395 
 2396 # ifdef IN_SUP_HARDENED_R3
 2397     /*
 2398      * Load some problematic DLLs into the verifier cache to prevent
 2399      * recursion trouble.
 2400      */
 2401     supR3HardenedWinVerifyCachePreload(L"\\SystemRoot\\System32\\crypt32.dll");
 2402     supR3HardenedWinVerifyCachePreload(L"\\SystemRoot\\System32\\Wintrust.dll");
 2403 # endif
 2404 
 2405     /*
 2406      * Now, get trusted root CAs so we can verify a broader scope of signatures.
 2407      */
 2408     supR3HardenedWinRetrieveTrustedRootCAs();
 2409 }
 2410 
 2411 
 2412 static int supR3HardNtViNtToWinPath(PCRTUTF16 pwszNtName, PCRTUTF16 *ppwszWinPath,
 2413                                     PRTUTF16 pwszWinPathBuf, size_t cwcWinPathBuf)
 2414 {
 2415     static const RTUTF16 s_wszPrefix[] = L"\\\\.\\GLOBALROOT";
 2416 
 2417     if (*pwszNtName != '\\' && *pwszNtName != '/')
 2418         return VERR_PATH_DOES_NOT_START_WITH_ROOT;
 2419 
 2420     size_t cwcNtName = RTUtf16Len(pwszNtName);
 2421     if (RT_ELEMENTS(s_wszPrefix) + cwcNtName > cwcWinPathBuf)
 2422         return VERR_FILENAME_TOO_LONG;
 2423 
 2424     memcpy(pwszWinPathBuf, s_wszPrefix, sizeof(s_wszPrefix));
 2425     memcpy(&pwszWinPathBuf[sizeof(s_wszPrefix) / sizeof(RTUTF16) - 1], pwszNtName, (cwcNtName + 1) * sizeof(RTUTF16));
 2426     *ppwszWinPath = pwszWinPathBuf;
 2427     return VINF_SUCCESS;
 2428 }
 2429 
 2430 
 2431 /**
 2432  * Calls WinVerifyTrust to verify an PE image.
 2433  *
 2434  * @returns VBox status code.
 2435  * @param   hFile               File handle to the executable file.
 2436  * @param   pwszName            Full NT path to the DLL in question, used for
 2437  *                              dealing with unsigned system dlls as well as for
 2438  *                              error/logging.
 2439  * @param   fFlags              Flags, SUPHNTVI_F_XXX.
 2440  * @param   pErrInfo            Pointer to error info structure. Optional.
 2441  * @param   pfnWinVerifyTrust   Pointer to the API.
 2442  * @param   phrcWinVerifyTrust  Where to WinVerifyTrust error status on failure,
 2443  *                              optional.
 2444  */
 2445 static int supR3HardNtViCallWinVerifyTrust(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PRTERRINFO pErrInfo,
 2446                                            PFNWINVERIFYTRUST pfnWinVerifyTrust, HRESULT *phrcWinVerifyTrust)
 2447 {
 2448     RT_NOREF1(fFlags);
 2449     if (phrcWinVerifyTrust)
 2450         *phrcWinVerifyTrust = S_OK;
 2451 
 2452     /*
 2453      * Convert the name into a Windows name.
 2454      */
 2455     RTUTF16 wszWinPathBuf[MAX_PATH];
 2456     PCRTUTF16 pwszWinPath;
 2457     int rc = supR3HardNtViNtToWinPath(pwszName, &pwszWinPath, wszWinPathBuf, RT_ELEMENTS(wszWinPathBuf));
 2458     if (RT_FAILURE(rc))
 2459         return RTErrInfoSetF(pErrInfo, rc, "Bad path passed to supR3HardNtViCallWinVerifyTrust: rc=%Rrc '%ls'", rc, pwszName);
 2460 
 2461     /*
 2462      * Construct input parameters and call the API.
 2463      */
 2464     WINTRUST_FILE_INFO FileInfo;
 2465     RT_ZERO(FileInfo);
 2466     FileInfo.cbStruct = sizeof(FileInfo);
 2467     FileInfo.pcwszFilePath = pwszWinPath;
 2468     FileInfo.hFile = hFile;
 2469 
 2470     GUID PolicyActionGuid = WINTRUST_ACTION_GENERIC_VERIFY_V2;
 2471 
 2472     WINTRUST_DATA TrustData;
 2473     RT_ZERO(TrustData);
 2474     TrustData.cbStruct = sizeof(TrustData);
 2475     TrustData.fdwRevocationChecks = WTD_REVOKE_NONE;  /* Keep simple for now. */
 2476     TrustData.dwStateAction = WTD_STATEACTION_VERIFY;
 2477     TrustData.dwUIChoice = WTD_UI_NONE;
 2478     TrustData.dwProvFlags = 0;
 2479     if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0))
 2480         TrustData.dwProvFlags = WTD_CACHE_ONLY_URL_RETRIEVAL;
 2481     else
 2482         TrustData.dwProvFlags = WTD_REVOCATION_CHECK_NONE;
 2483     TrustData.dwUnionChoice = WTD_CHOICE_FILE;
 2484     TrustData.pFile = &FileInfo;
 2485 
 2486     HRESULT hrc = pfnWinVerifyTrust(NULL /*hwnd*/, &PolicyActionGuid, &TrustData);
 2487     if (hrc == S_OK)
 2488         rc = VINF_SUCCESS;
 2489     else
 2490     {
 2491         /*
 2492          * Failed. Format a nice error message.
 2493          */
 2494 # ifdef DEBUG_bird
 2495         if (hrc != CERT_E_CHAINING /* Un-updated vistas, XPs, ++ */)
 2496             __debugbreak();
 2497 # endif
 2498         const char *pszErrConst = NULL;
 2499         switch (hrc)
 2500         {
 2501             case TRUST_E_SYSTEM_ERROR:            pszErrConst = "TRUST_E_SYSTEM_ERROR";         break;
 2502             case TRUST_E_NO_SIGNER_CERT:          pszErrConst = "TRUST_E_NO_SIGNER_CERT";       break;
 2503             case TRUST_E_COUNTER_SIGNER:          pszErrConst = "TRUST_E_COUNTER_SIGNER";       break;
 2504             case TRUST_E_CERT_SIGNATURE:          pszErrConst = "TRUST_E_CERT_SIGNATURE";       break;
 2505             case TRUST_E_TIME_STAMP:              pszErrConst = "TRUST_E_TIME_STAMP";           break;
 2506             case TRUST_E_BAD_DIGEST:              pszErrConst = "TRUST_E_BAD_DIGEST";           break;
 2507             case TRUST_E_BASIC_CONSTRAINTS:       pszErrConst = "TRUST_E_BASIC_CONSTRAINTS";    break;
 2508             case TRUST_E_FINANCIAL_CRITERIA:      pszErrConst = "TRUST_E_FINANCIAL_CRITERIA";   break;
 2509             case TRUST_E_PROVIDER_UNKNOWN:        pszErrConst = "TRUST_E_PROVIDER_UNKNOWN";     break;
 2510             case TRUST_E_ACTION_UNKNOWN:          pszErrConst = "TRUST_E_ACTION_UNKNOWN";       break;
 2511             case TRUST_E_SUBJECT_FORM_UNKNOWN:    pszErrConst = "TRUST_E_SUBJECT_FORM_UNKNOWN"; break;
 2512             case TRUST_E_SUBJECT_NOT_TRUSTED:     pszErrConst = "TRUST_E_SUBJECT_NOT_TRUSTED";  break;
 2513             case TRUST_E_NOSIGNATURE:             pszErrConst = "TRUST_E_NOSIGNATURE";          break;
 2514             case TRUST_E_FAIL:                    pszErrConst = "TRUST_E_FAIL";                 break;
 2515             case TRUST_E_EXPLICIT_DISTRUST:       pszErrConst = "TRUST_E_EXPLICIT_DISTRUST";    break;
 2516             case CERT_E_EXPIRED:                  pszErrConst = "CERT_E_EXPIRED";               break;
 2517             case CERT_E_VALIDITYPERIODNESTING:    pszErrConst = "CERT_E_VALIDITYPERIODNESTING"; break;
 2518             case CERT_E_ROLE:                     pszErrConst = "CERT_E_ROLE";                  break;
 2519             case CERT_E_PATHLENCONST:             pszErrConst = "CERT_E_PATHLENCONST";          break;
 2520             case CERT_E_CRITICAL:                 pszErrConst = "CERT_E_CRITICAL";              break;
 2521             case CERT_E_PURPOSE:                  pszErrConst = "CERT_E_PURPOSE";               break;
 2522             case CERT_E_ISSUERCHAINING:           pszErrConst = "CERT_E_ISSUERCHAINING";        break;
 2523             case CERT_E_MALFORMED:                pszErrConst = "CERT_E_MALFORMED";             break;
 2524             case CERT_E_UNTRUSTEDROOT:            pszErrConst = "CERT_E_UNTRUSTEDROOT";         break;
 2525             case CERT_E_CHAINING:                 pszErrConst = "CERT_E_CHAINING";              break;
 2526             case CERT_E_REVOKED:                  pszErrConst = "CERT_E_REVOKED";               break;
 2527             case CERT_E_UNTRUSTEDTESTROOT:        pszErrConst = "CERT_E_UNTRUSTEDTESTROOT";     break;
 2528             case CERT_E_REVOCATION_FAILURE:       pszErrConst = "CERT_E_REVOCATION_FAILURE";    break;
 2529             case CERT_E_CN_NO_MATCH:              pszErrConst = "CERT_E_CN_NO_MATCH";           break;
 2530             case CERT_E_WRONG_USAGE:              pszErrConst = "CERT_E_WRONG_USAGE";           break;
 2531             case CERT_E_UNTRUSTEDCA:              pszErrConst = "CERT_E_UNTRUSTEDCA";           break;
 2532             case CERT_E_INVALID_POLICY:           pszErrConst = "CERT_E_INVALID_POLICY";        break;
 2533             case CERT_E_INVALID_NAME:             pszErrConst = "CERT_E_INVALID_NAME";          break;
 2534             case CRYPT_E_FILE_ERROR:              pszErrConst = "CRYPT_E_FILE_ERROR";           break;
 2535             case CRYPT_E_REVOKED:                 pszErrConst = "CRYPT_E_REVOKED";              break;
 2536         }
 2537         if (pszErrConst)
 2538             rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_UNSUPPORTED_ARCH,
 2539                                "WinVerifyTrust failed with hrc=%s on '%ls'", pszErrConst, pwszName);
 2540         else
 2541             rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_UNSUPPORTED_ARCH,
 2542                                "WinVerifyTrust failed with hrc=%Rhrc on '%ls'", hrc, pwszName);
 2543         SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrust: WinVerifyTrust failed with %#x (%s) on '%ls'\n",
 2544                      hrc, pszErrConst, pwszName));
 2545         if (phrcWinVerifyTrust)
 2546             *phrcWinVerifyTrust = hrc;
 2547     }
 2548 
 2549     /* clean up state data. */
 2550     TrustData.dwStateAction = WTD_STATEACTION_CLOSE;
 2551     FileInfo.hFile = NULL;
 2552     hrc = pfnWinVerifyTrust(NULL /*hwnd*/, &PolicyActionGuid, &TrustData);
 2553 
 2554     return rc;
 2555 }
 2556 
 2557 
 2558 /**
 2559  * Calls WinVerifyTrust to verify an PE image via catalog files.
 2560  *
 2561  * @returns VBox status code.
 2562  * @param   hFile               File handle to the executable file.
 2563  * @param   pwszName            Full NT path to the DLL in question, used for
 2564  *                              dealing with unsigned system dlls as well as for
 2565  *                              error/logging.
 2566  * @param   fFlags              Flags, SUPHNTVI_F_XXX.
 2567  * @param   pErrInfo            Pointer to error info structure. Optional.
 2568  * @param   pfnWinVerifyTrust   Pointer to the API.
 2569  */
 2570 static int supR3HardNtViCallWinVerifyTrustCatFile(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, PRTERRINFO pErrInfo,
 2571                                                   PFNWINVERIFYTRUST pfnWinVerifyTrust)
 2572 {
 2573     RT_NOREF1(fFlags);
 2574     SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: hFile=%p pwszName=%ls\n", hFile, pwszName));
 2575 
 2576     /*
 2577      * Convert the name into a Windows name.
 2578      */
 2579     RTUTF16 wszWinPathBuf[MAX_PATH];
 2580     PCRTUTF16 pwszWinPath;
 2581     int rc = supR3HardNtViNtToWinPath(pwszName, &pwszWinPath, wszWinPathBuf, RT_ELEMENTS(wszWinPathBuf));
 2582     if (RT_FAILURE(rc))
 2583         return RTErrInfoSetF(pErrInfo, rc, "Bad path passed to supR3HardNtViCallWinVerifyTrustCatFile: rc=%Rrc '%ls'", rc, pwszName);
 2584 
 2585     /*
 2586      * Open the file if we didn't get a handle.
 2587      */
 2588     HANDLE hFileClose = NULL;
 2589     if (hFile == RTNT_INVALID_HANDLE_VALUE || hFile == NULL)
 2590     {
 2591         hFile = RTNT_INVALID_HANDLE_VALUE;
 2592         IO_STATUS_BLOCK     Ios   = RTNT_IO_STATUS_BLOCK_INITIALIZER;
 2593 
 2594         UNICODE_STRING      NtName;
 2595         NtName.Buffer = (PWSTR)pwszName;
 2596         NtName.Length = (USHORT)(RTUtf16Len(pwszName) * sizeof(WCHAR));
 2597         NtName.MaximumLength = NtName.Length + sizeof(WCHAR);
 2598 
 2599         OBJECT_ATTRIBUTES ObjAttr;
 2600         InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
 2601 
 2602         NTSTATUS rcNt = NtCreateFile(&hFile,
 2603                                      FILE_READ_DATA | READ_CONTROL | SYNCHRONIZE,
 2604                                      &ObjAttr,
 2605                                      &Ios,
 2606                                      NULL /* Allocation Size*/,
 2607                                      FILE_ATTRIBUTE_NORMAL,
 2608                                      FILE_SHARE_READ,
 2609                                      FILE_OPEN,
 2610                                      FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
 2611                                      NULL /*EaBuffer*/,
 2612                                      0 /*EaLength*/);
 2613         if (NT_SUCCESS(rcNt))
 2614             rcNt = Ios.Status;
 2615         if (!NT_SUCCESS(rcNt))
 2616             return RTErrInfoSetF(pErrInfo, RTErrConvertFromNtStatus(rcNt),
 2617                                  "NtCreateFile returned %#x opening '%ls'.", rcNt, pwszName);
 2618         hFileClose = hFile;
 2619     }
 2620 
 2621     /*
 2622      * On Windows 8.0 and later there are more than one digest choice.
 2623      */
 2624     int fNoSignedCatalogFound = -1;
 2625     rc = VERR_LDRVI_NOT_SIGNED;
 2626     static struct
 2627     {
 2628         /** The digest algorithm name. */
 2629         const WCHAR        *pszAlgorithm;
 2630         /** Cached catalog admin handle. */
 2631         HCATADMIN volatile  hCachedCatAdmin;
 2632     } s_aHashes[] =
 2633     {
 2634         { NULL,      NULL },
 2635         { L"SHA256", NULL },
 2636     };
 2637     for (uint32_t i = 0; i < RT_ELEMENTS(s_aHashes); i++)
 2638     {
 2639         /*
 2640          * Another loop for dealing with different trust provider policies
 2641          * required for successfully validating different catalog signatures.
 2642          */
 2643         bool                fTryNextPolicy;
 2644         uint32_t            iPolicy = 0;
 2645         static const GUID   s_aPolicies[] =
 2646         {
 2647             DRIVER_ACTION_VERIFY,              /* Works with microsoft bits. Most frequently used, thus first. */
 2648             WINTRUST_ACTION_GENERIC_VERIFY_V2, /* Works with ATI and other SPC kernel-code signed stuff. */
 2649         };
 2650         do
 2651         {
 2652             /*
 2653              * Create a context.
 2654              */
 2655             fTryNextPolicy = false;
 2656             bool fFreshContext = false;
 2657             BOOL fRc;
 2658             HCATADMIN hCatAdmin = ASMAtomicXchgPtr(&s_aHashes[i].hCachedCatAdmin, NULL);
 2659             if (hCatAdmin)
 2660             {
 2661                 SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: Cached context %p\n", hCatAdmin));
 2662                 fFreshContext = false;
 2663                 fRc = TRUE;
 2664             }
 2665             else
 2666             {
 2667 l_fresh_context:
 2668                 fFreshContext = true;
 2669                 if (g_pfnCryptCATAdminAcquireContext2)
 2670                     fRc = g_pfnCryptCATAdminAcquireContext2(&hCatAdmin, &s_aPolicies[iPolicy], s_aHashes[i].pszAlgorithm,
 2671                                                             NULL /*pStrongHashPolicy*/, 0 /*dwFlags*/);
 2672                 else
 2673                     fRc = g_pfnCryptCATAdminAcquireContext(&hCatAdmin, &s_aPolicies[iPolicy], 0 /*dwFlags*/);
 2674                 SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: New context %p\n", hCatAdmin));
 2675             }
 2676             if (fRc)
 2677             {
 2678                 SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: hCatAdmin=%p\n", hCatAdmin));
 2679 
 2680                 /*
 2681                  * Hash the file.
 2682                  */
 2683                 BYTE  abHash[SUPHARDNTVI_MAX_CAT_HASH_SIZE];
 2684                 DWORD cbHash = sizeof(abHash);
 2685                 if (g_pfnCryptCATAdminCalcHashFromFileHandle2)
 2686                     fRc = g_pfnCryptCATAdminCalcHashFromFileHandle2(hCatAdmin, hFile, &cbHash, abHash, 0 /*dwFlags*/);
 2687                 else
 2688                     fRc = g_pfnCryptCATAdminCalcHashFromFileHandle(hFile, &cbHash, abHash, 0 /*dwFlags*/);
 2689                 if (fRc)
 2690                 {
 2691                     /* Produce a string version of it that we can pass to WinVerifyTrust. */
 2692                     RTUTF16 wszDigest[SUPHARDNTVI_MAX_CAT_HASH_SIZE * 2 + 1];
 2693                     int rc2 = RTUtf16PrintHexBytes(wszDigest, RT_ELEMENTS(wszDigest), abHash, cbHash, RTSTRPRINTHEXBYTES_F_UPPER);
 2694                     if (RT_SUCCESS(rc2))
 2695                     {
 2696                         SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: cbHash=%u wszDigest=%ls\n", cbHash, wszDigest));
 2697 
 2698                         /*
 2699                          * Enumerate catalog information that matches the hash.
 2700                          */
 2701                         uint32_t iCat = 0;
 2702                         HCATINFO hCatInfoPrev = NULL;
 2703                         do
 2704                         {
 2705                             /* Get the next match. */
 2706                             HCATINFO hCatInfo = g_pfnCryptCATAdminEnumCatalogFromHash(hCatAdmin, abHash, cbHash, 0, &hCatInfoPrev);
 2707                             if (!hCatInfo)
 2708                             {
 2709                                 if (!fFreshContext)
 2710                                 {
 2711                                     SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: Retrying with fresh context (CryptCATAdminEnumCatalogFromHash -> %u; iCat=%#x)\n", RtlGetLastWin32Error(), iCat));
 2712                                     if (hCatInfoPrev != NULL)
 2713                                         g_pfnCryptCATAdminReleaseCatalogContext(hCatAdmin, hCatInfoPrev, 0 /*dwFlags*/);
 2714                                     g_pfnCryptCATAdminReleaseContext(hCatAdmin, 0 /*dwFlags*/);
 2715                                     goto l_fresh_context;
 2716                                 }
 2717                                 ULONG ulErr = RtlGetLastWin32Error();
 2718                                 fNoSignedCatalogFound = ulErr == ERROR_NOT_FOUND && fNoSignedCatalogFound != 0;
 2719                                 if (iCat == 0)
 2720                                     SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: CryptCATAdminEnumCatalogFromHash failed ERROR_NOT_FOUND (%u)\n", ulErr));
 2721                                 else if (iCat == 0)
 2722                                     SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: CryptCATAdminEnumCatalogFromHash failed %u\n", ulErr));
 2723                                 break;
 2724                             }
 2725                             fNoSignedCatalogFound = 0;
 2726                             Assert(hCatInfoPrev == NULL);
 2727                             hCatInfoPrev = hCatInfo;
 2728 
 2729                             /*
 2730                              * Call WinVerifyTrust.
 2731                              */
 2732                             CATALOG_INFO CatInfo;
 2733                             CatInfo.cbStruct = sizeof(CatInfo);
 2734                             CatInfo.wszCatalogFile[0] = '\0';
 2735                             if (g_pfnCryptCATCatalogInfoFromContext(hCatInfo, &CatInfo, 0 /*dwFlags*/))
 2736                             {
 2737                                 WINTRUST_CATALOG_INFO WtCatInfo;
 2738                                 RT_ZERO(WtCatInfo);
 2739                                 WtCatInfo.cbStruct              = sizeof(WtCatInfo);
 2740                                 WtCatInfo.dwCatalogVersion      = 0;
 2741                                 WtCatInfo.pcwszCatalogFilePath  = CatInfo.wszCatalogFile;
 2742                                 WtCatInfo.pcwszMemberTag        = wszDigest;
 2743                                 WtCatInfo.pcwszMemberFilePath   = pwszWinPath;
 2744                                 WtCatInfo.pbCalculatedFileHash  = abHash;
 2745                                 WtCatInfo.cbCalculatedFileHash  = cbHash;
 2746                                 WtCatInfo.pcCatalogContext      = NULL;
 2747 
 2748                                 WINTRUST_DATA TrustData;
 2749                                 RT_ZERO(TrustData);
 2750                                 TrustData.cbStruct              = sizeof(TrustData);
 2751                                 TrustData.fdwRevocationChecks   = WTD_REVOKE_NONE;  /* Keep simple for now. */
 2752                                 TrustData.dwStateAction         = WTD_STATEACTION_VERIFY;
 2753                                 TrustData.dwUIChoice            = WTD_UI_NONE;
 2754                                 TrustData.dwProvFlags           = 0;
 2755                                 if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0))
 2756                                     TrustData.dwProvFlags       = WTD_CACHE_ONLY_URL_RETRIEVAL;
 2757                                 else
 2758                                     TrustData.dwProvFlags       = WTD_REVOCATION_CHECK_NONE;
 2759                                 TrustData.dwUnionChoice         = WTD_CHOICE_CATALOG;
 2760                                 TrustData.pCatalog              = &WtCatInfo;
 2761 
 2762                                 HRESULT hrc = pfnWinVerifyTrust(NULL /*hwnd*/, &s_aPolicies[iPolicy], &TrustData);
 2763                                 SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: WinVerifyTrust => %#x; cat='%ls'; file='%ls'\n",
 2764                                              hrc, CatInfo.wszCatalogFile, pwszName));
 2765 
 2766                                 if (SUCCEEDED(hrc))
 2767                                     rc = VINF_SUCCESS;
 2768                                 else if (hrc == TRUST_E_NOSIGNATURE)
 2769                                 { /* ignore because it's useless. */ }
 2770                                 else if (hrc == ERROR_INVALID_PARAMETER)
 2771                                 { /* This is returned if the given file isn't found in the catalog, it seems. */ }
 2772                                 else
 2773                                 {
 2774                                     rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_WINTRUST_CAT_FAILURE,
 2775                                                        "WinVerifyTrust failed with hrc=%#x on '%ls' and .cat-file='%ls'.",
 2776                                                        hrc, pwszWinPath, CatInfo.wszCatalogFile);
 2777                                     fTryNextPolicy |= (hrc == CERT_E_UNTRUSTEDROOT);
 2778                                 }
 2779 
 2780                                 /* clean up state data. */
 2781                                 TrustData.dwStateAction = WTD_STATEACTION_CLOSE;
 2782                                 hrc = pfnWinVerifyTrust(NULL /*hwnd*/, &s_aPolicies[iPolicy], &TrustData);
 2783                                 Assert(SUCCEEDED(hrc));
 2784                             }
 2785                             else
 2786                             {
 2787                                 rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromWin32(RtlGetLastWin32Error()),
 2788                                                    "CryptCATCatalogInfoFromContext failed: %d [file=%s]",
 2789                                                    RtlGetLastWin32Error(), pwszName);
 2790                                 SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: CryptCATCatalogInfoFromContext failed\n"));
 2791                             }
 2792                             iCat++;
 2793                         } while (rc == VERR_LDRVI_NOT_SIGNED && iCat < 128);
 2794 
 2795                         if (hCatInfoPrev != NULL)
 2796                             if (!g_pfnCryptCATAdminReleaseCatalogContext(hCatAdmin, hCatInfoPrev, 0 /*dwFlags*/))
 2797                                 AssertFailed();
 2798                     }
 2799                     else
 2800                         rc = RTErrInfoSetF(pErrInfo, rc2, "RTUtf16PrintHexBytes failed: %Rrc", rc);
 2801                 }
 2802                 else
 2803                     rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromWin32(RtlGetLastWin32Error()),
 2804                                        "CryptCATAdminCalcHashFromFileHandle[2] failed: %d [file=%s]", RtlGetLastWin32Error(), pwszName);
 2805 
 2806                 if (!ASMAtomicCmpXchgPtr(&s_aHashes[i].hCachedCatAdmin, hCatAdmin, NULL))
 2807                     if (!g_pfnCryptCATAdminReleaseContext(hCatAdmin, 0 /*dwFlags*/))
 2808                         AssertFailed();
 2809             }
 2810             else
 2811                 rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromWin32(RtlGetLastWin32Error()),
 2812                                    "CryptCATAdminAcquireContext[2] failed: %d [file=%s]", RtlGetLastWin32Error(), pwszName);
 2813              iPolicy++;
 2814         } while (   fTryNextPolicy
 2815                  && iPolicy < RT_ELEMENTS(s_aPolicies));
 2816 
 2817         /*
 2818          * Only repeat if we've got g_pfnCryptCATAdminAcquireContext2 and can specify the hash algorithm.
 2819          */
 2820         if (!g_pfnCryptCATAdminAcquireContext2)
 2821             break;
 2822         if (rc != VERR_LDRVI_NOT_SIGNED)
 2823             break;
 2824     }
 2825 
 2826     if (hFileClose != NULL)
 2827         NtClose(hFileClose);
 2828 
 2829     /*
 2830      * DLLs that are likely candidates for local modifications.
 2831      */
 2832     if (rc == VERR_LDRVI_NOT_SIGNED)
 2833     {
 2834         bool        fCoreSystemDll = false;
 2835         PCRTUTF16   pwsz;
 2836         uint32_t    cwcName  = (uint32_t)RTUtf16Len(pwszName);
 2837         uint32_t    cwcOther = g_System32NtPath.UniStr.Length / sizeof(WCHAR);
 2838         if (supHardViUtf16PathStartsWithEx(pwszName, cwcName, g_System32NtPath.UniStr.Buffer, cwcOther, true /*fCheckSlash*/))
 2839         {
 2840             pwsz = pwszName + cwcOther + 1;
 2841             if (   supHardViUtf16PathIsEqual(pwsz, "uxtheme.dll")
 2842                 || supHardViUtf16PathIsEqual(pwsz, "user32.dll")
 2843                 || supHardViUtf16PathIsEqual(pwsz, "gdi32.dll")
 2844                 || supHardViUtf16PathIsEqual(pwsz, "opengl32.dll")
 2845                 || (fCoreSystemDll = supHardViUtf16PathIsEqual(pwsz, "KernelBase.dll"))
 2846                 || (fCoreSystemDll = supHardViUtf16PathIsEqual(pwsz, "kernel32.dll"))
 2847                 || (fCoreSystemDll = supHardViUtf16PathIsEqual(pwsz, "ntdll.dll"))
 2848                 )
 2849             {
 2850                 if (RTErrInfoIsSet(pErrInfo))
 2851                     RTErrInfoAdd(pErrInfo, rc, "\n");
 2852                 RTErrInfoAddF(pErrInfo, rc, "'%ls' is most likely modified.", pwszName);
 2853             }
 2854         }
 2855 
 2856         /* Kludge for ancient windows versions we don't want to support but
 2857            users still wants to use.  Keep things as safe as possible without
 2858            unnecessary effort.  Problem is that 3rd party catalog files cannot
 2859            easily be found.  Showstopper for ATI users. */
 2860         if (   fNoSignedCatalogFound == 1
 2861             && g_uNtVerCombined < SUP_NT_VER_VISTA
 2862             && !fCoreSystemDll)
 2863         {
 2864             rc = VINF_LDRVI_NOT_SIGNED;
 2865         }
 2866     }
 2867 
 2868     return rc;
 2869 }
 2870 
 2871 
 2872 /**
 2873  * Verifies the given image using WinVerifyTrust in some way.
 2874  *
 2875  * This is used by supHardenedWinVerifyImageByLdrMod as well as
 2876  * supR3HardenedScreenImage.
 2877  *
 2878  * @returns IPRT status code, modified @a rc.
 2879  * @param   hFile               Handle of the file to verify.
 2880  * @param   pwszName            Full NT path to the DLL in question, used for
 2881  *                              dealing with unsigned system dlls as well as for
 2882  *                              error/logging.
 2883  * @param   fFlags              SUPHNTVI_F_XXX.
 2884  * @param   rc                  The current status code.
 2885  * @param   pfWinVerifyTrust    Where to return whether WinVerifyTrust was
 2886  *                              actually used.
 2887  * @param   pErrInfo            Pointer to error info structure. Optional.
 2888  */
 2889 DECLHIDDEN(int) supHardenedWinVerifyImageTrust(HANDLE hFile, PCRTUTF16 pwszName, uint32_t fFlags, int rc,
 2890                                                bool *pfWinVerifyTrust, PRTERRINFO pErrInfo)
 2891 {
 2892     if (pfWinVerifyTrust)
 2893         *pfWinVerifyTrust = false;
 2894 
 2895     /*
 2896      * Call the windows verify trust API if we've resolved it and aren't in
 2897      * some obvious recursion.
 2898      */
 2899     if (g_pfnWinVerifyTrust != NULL)
 2900     {
 2901         uint32_t const idCurrentThread = RTNtCurrentThreadId();
 2902 
 2903         /* Check if loader lock owner. */
 2904         struct _RTL_CRITICAL_SECTION volatile *pLoaderLock = NtCurrentPeb()->LoaderLock;
 2905         bool fOwnsLoaderLock = pLoaderLock
 2906                             && pLoaderLock->OwningThread == (HANDLE)(uintptr_t)idCurrentThread
 2907                             && pLoaderLock->RecursionCount > 0;
 2908         if (!fOwnsLoaderLock)
 2909         {
 2910             /* Check for recursion. */
 2911             bool fNoRecursion;
 2912             if (g_iTlsWinVerifyTrustRecursion != UINT32_MAX)
 2913             {
 2914                 fNoRecursion = TlsGetValue(g_iTlsWinVerifyTrustRecursion) == 0;
 2915                 if (fNoRecursion)
 2916                     TlsSetValue(g_iTlsWinVerifyTrustRecursion, (void *)1);
 2917             }
 2918             else
 2919                 fNoRecursion = ASMAtomicCmpXchgU32(&g_idActiveThread, idCurrentThread, UINT32_MAX);
 2920 
 2921             if (fNoRecursion && !fOwnsLoaderLock)
 2922             {
 2923                 /* We can call WinVerifyTrust. */
 2924                 if (pfWinVerifyTrust)
 2925                     *pfWinVerifyTrust = true;
 2926 
 2927                 if (rc != VERR_LDRVI_NOT_SIGNED)
 2928                 {
 2929                     if (rc == VINF_LDRVI_NOT_SIGNED)
 2930                     {
 2931                         if (fFlags & SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION)
 2932                         {
 2933                             int rc2 = supR3HardNtViCallWinVerifyTrustCatFile(hFile, pwszName, fFlags, pErrInfo,
 2934                                                                              g_pfnWinVerifyTrust);
 2935                             SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile -> %d (org %d)\n", rc2, rc));
 2936                             rc = rc2;
 2937                         }
 2938                         else
 2939                         {
 2940                             AssertFailed();
 2941                             rc = VERR_LDRVI_NOT_SIGNED;
 2942                         }
 2943                     }
 2944                     else if (RT_SUCCESS(rc))
 2945                     {
 2946                         HRESULT hrcWinVerifyTrust;
 2947                         rc = supR3HardNtViCallWinVerifyTrust(hFile, pwszName, fFlags, pErrInfo, g_pfnWinVerifyTrust,
 2948                                                              &hrcWinVerifyTrust);
 2949 
 2950                         /* DLLs signed with special roots, like "Microsoft Digital Media Authority 2005",
 2951                            may fail here because the root cert is not in the normal certificate stores
 2952                            (if any).  Our verification code has the basics of these certificates included
 2953                            and can verify them, which is why we end up here instead of in the
 2954                            VINF_LDRVI_NOT_SIGNED case above.  Current workaround is to do as above.
 2955                            (Intel graphics driver DLLs, like igdusc64.dll. */
 2956                         if (   RT_FAILURE(rc)
 2957                             && hrcWinVerifyTrust == CERT_E_CHAINING
 2958                             && (fFlags & SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION))
 2959                         {
 2960                             rc = supR3HardNtViCallWinVerifyTrustCatFile(hFile, pwszName, fFlags, pErrInfo, g_pfnWinVerifyTrust);
 2961                             SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile -> %d (was CERT_E_CHAINING)\n", rc));
 2962                         }
 2963                     }
 2964                     else
 2965                     {
 2966                         int rc2 = supR3HardNtViCallWinVerifyTrust(hFile, pwszName, fFlags, pErrInfo, g_pfnWinVerifyTrust, NULL);
 2967                         AssertMsg(RT_FAILURE_NP(rc2),
 2968                                   ("rc=%Rrc, rc2=%Rrc %s", rc, rc2, pErrInfo ? pErrInfo->pszMsg : "<no-err-info>"));
 2969                         RT_NOREF_PV(rc2);
 2970                     }
 2971                 }
 2972 
 2973                 /* Unwind recursion. */
 2974                 if (g_iTlsWinVerifyTrustRecursion != UINT32_MAX)
 2975                     TlsSetValue(g_iTlsWinVerifyTrustRecursion, (void *)0);
 2976                 else
 2977                     ASMAtomicWriteU32(&g_idActiveThread, UINT32_MAX);
 2978             }
 2979             /*
 2980              * No can do.
 2981              */
 2982             else
 2983                 SUP_DPRINTF(("Detected WinVerifyTrust recursion: rc=%Rrc '%ls'.\n", rc, pwszName));
 2984         }
 2985         else
 2986             SUP_DPRINTF(("Detected loader lock ownership: rc=%Rrc '%ls'.\n", rc, pwszName));
 2987     }
 2988     return rc;
 2989 }
 2990 
 2991 
 2992 /**
 2993  * Checks if WinVerifyTrust is callable on the current thread.
 2994  *
 2995  * Used by the main code to figure whether it makes sense to try revalidate an
 2996  * image that hasn't passed thru WinVerifyTrust yet.
 2997  *
 2998  * @returns true if callable on current thread, false if not.
 2999  */
 3000 DECLHIDDEN(bool) supHardenedWinIsWinVerifyTrustCallable(void)
 3001 {
 3002     return g_pfnWinVerifyTrust != NULL
 3003         && (   g_iTlsWinVerifyTrustRecursion != UINT32_MAX
 3004             ?  (uintptr_t)TlsGetValue(g_iTlsWinVerifyTrustRecursion) == 0
 3005             : g_idActiveThread != RTNtCurrentThreadId() );
 3006 }
 3007 
 3008 
 3009 
 3010 /**
 3011  * Initializes g_uNtVerCombined and g_NtVerInfo.
 3012  * Called from suplibHardenedWindowsMain and suplibOsInit.
 3013  */
 3014 DECLHIDDEN(void) supR3HardenedWinInitVersion(bool fEarly)
 3015 {
 3016     /*
 3017      * Get the windows version.  Use RtlGetVersion as GetVersionExW and
 3018      * GetVersion might not be telling the whole truth (8.0 on 8.1 depending on
 3019      * the application manifest).
 3020      *
 3021      * Note! Windows 10 build 14267+ touches BSS when calling RtlGetVersion, so we
 3022      *       have to use the fallback for the call from the early init code.
 3023      */
 3024     OSVERSIONINFOEXW NtVerInfo;
 3025 
 3026     RT_ZERO(NtVerInfo);
 3027     NtVerInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
 3028     if (   fEarly
 3029         || !NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&NtVerInfo)))
 3030     {
 3031         RT_ZERO(NtVerInfo);
 3032         PPEB pPeb = NtCurrentPeb();
 3033         NtVerInfo.dwMajorVersion = pPeb->OSMajorVersion;
 3034         NtVerInfo.dwMinorVersion = pPeb->OSMinorVersion;
 3035         NtVerInfo.dwBuildNumber  = pPeb->OSBuildNumber;
 3036     }
 3037 
 3038     g_uNtVerCombined = SUP_MAKE_NT_VER_COMBINED(NtVerInfo.dwMajorVersion, NtVerInfo.dwMinorVersion, NtVerInfo.dwBuildNumber,
 3039                                                 NtVerInfo.wServicePackMajor, NtVerInfo.wServicePackMinor);
 3040 }
 3041 
 3042 #endif /* IN_RING3 */
 3043