VirtualBox

Ignore:
Timestamp:
Aug 14, 2014 1:25:12 AM (10 years ago)
Author:
vboxsync
Message:

SUP: Some cleanup and bug hacking.

Location:
trunk/src/VBox/HostDrivers/Support/win
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerify-win.h

    r52373 r52375  
    4343DECLHIDDEN(int)     supHardenedWinInitImageVerifier(PRTERRINFO pErrInfo);
    4444DECLHIDDEN(void)    supHardenedWinTermImageVerifier(void);
     45DECLHIDDEN(void)    supR3HardenedWinVerifyCachePreload(PCRTUTF16 pwszName);
    4546
    4647typedef enum SUPHARDNTVPKIND
     
    5859                                                PCRTUTF16 pwszRight, uint32_t cwcRight, bool fCheckSlash);
    5960DECLHIDDEN(bool)    supHardViIsAppPatchDir(PCRTUTF16 pwszPath, uint32_t cwcName);
     61
    6062
    6163/**
  • trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp

    r52366 r52375  
    954954
    955955/**
    956  * Checks if it's safe to call WinVerifyTrust or whether we might end up in an
    957  * infinite recursion.
    958  *
    959  * @returns true if ok, false if not.
    960  * @param   hFile               The file name.
    961  * @param   pwszName            The executable name.
    962  */
    963 static bool supR3HardNtViCanCallWinVerifyTrust(HANDLE hFile, PCRTUTF16 pwszName)
    964 {
    965      /*
    966       * Recursion preventions hacks:
    967       *  - Don't try call WinVerifyTrust on Wintrust.dll when called from the
    968       *    create section hook. CRYPT32.DLL tries to load WinTrust.DLL in some cases.
    969       */
    970      size_t cwcName = RTUtf16Len(pwszName);
    971      if (   hFile != NULL
    972          && cwcName > g_System32NtPath.UniStr.Length / sizeof(WCHAR)
    973          && !memcmp(pwszName, g_System32NtPath.UniStr.Buffer, g_System32NtPath.UniStr.Length)
    974          && supHardViUtf16PathIsEqual(&pwszName[g_System32NtPath.UniStr.Length / sizeof(WCHAR)], "\\wintrust.dll"))
    975          return false;
    976 
    977      return true;
    978 }
    979 
    980 
    981 /**
    982956 * Verifies the given loader image.
    983957 *
     
    10791053        static uint32_t volatile s_idActiveThread = UINT32_MAX;
    10801054        uint32_t const idCurrentThread = GetCurrentThreadId();
    1081         if (   s_idActiveThread != idCurrentThread
    1082             && supR3HardNtViCanCallWinVerifyTrust(pNtViRdr->hFile, pwszName) )
     1055        if (s_idActiveThread != idCurrentThread)
    10831056        {
    10841057            ASMAtomicCmpXchgU32(&s_idActiveThread, idCurrentThread, UINT32_MAX);
     
    11041077                }
    11051078                else if (RT_SUCCESS(rc))
     1079                {
     1080                    /** @todo having trouble with a 32-bit windows box when letting these calls thru */
    11061081                    rc = supR3HardNtViCallWinVerifyTrust(pNtViRdr->hFile, pwszName, pNtViRdr->fFlags, pErrInfo,
    11071082                                                         g_pfnWinVerifyTrust);
     1083                }
    11081084                else
    11091085                {
     
    11741150            supHardNtViRdrDestroy(&pNtViRdr->Core);
    11751151    }
    1176     SUP_DPRINTF(("supHardenedWinVerifyImageByHandle: -> %d (%ls)\n", rc, pwszName));
     1152    SUP_DPRINTF(("supHardenedWinVerifyImageByHandle: -> %d %s(%ls)\n", rc, pfCacheable && *pfCacheable ? "cacheable ": "", pwszName));
    11771153    return rc;
    11781154}
     
    17691745}
    17701746
     1747
     1748/**
     1749 * Loads a module in the system32 directory.
     1750 *
     1751 * @returns Module handle on success. Won't return on faliure.
     1752 * @param   pszName             The name of the DLL to load.
     1753 */
     1754DECLHIDDEN(HMODULE) supR3HardenedWinLoadSystem32Dll(const char *pszName)
     1755{
     1756    WCHAR wszName[200+60];
     1757    UINT cwcDir = GetSystemWindowsDirectoryW(wszName, RT_ELEMENTS(wszName) - 60);
     1758    memcpy(&wszName[cwcDir], RT_STR_TUPLE(L"\\System32\\"));
     1759    RTUtf16CopyAscii(&wszName[cwcDir + sizeof("\\System32\\") - 1], RT_ELEMENTS(wszName) - cwcDir, pszName);
     1760
     1761    DWORD fFlags = 0;
     1762    if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0))
     1763       fFlags = LOAD_LIBRARY_SEARCH_SYSTEM32;
     1764    HMODULE hMod = LoadLibraryExW(wszName, NULL, fFlags);
     1765    if (   hMod == NULL
     1766        && fFlags
     1767        && g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 2)
     1768        && GetLastError() == ERROR_INVALID_PARAMETER)
     1769    {
     1770        fFlags = 0;
     1771        hMod = LoadLibraryExW(wszName, NULL, fFlags);
     1772    }
     1773    if (hMod == NULL)
     1774        supR3HardenedFatal("Error loading '%s': %u [%ls]", pszName, GetLastError(), wszName);
     1775    return hMod;
     1776}
     1777
     1778
    17711779/**
    17721780 * Called by supR3HardenedWinResolveVerifyTrustApiAndHookThreadCreation to
     
    17741782 *
    17751783 * These certificates permits us to correctly validate third party DLLs.
    1776  *
    1777  * @param   fLoadLibraryFlags       The LoadLibraryExW flags that the caller
    1778  *                                  found to work.  Avoids us having to retry on
    1779  *                                  ERROR_INVALID_PARAMETER.
    1780  */
    1781 static void supR3HardenedWinRetrieveTrustedRootCAs(DWORD fLoadLibraryFlags)
     1784 */
     1785static void supR3HardenedWinRetrieveTrustedRootCAs(void)
    17821786{
    17831787    uint32_t cAdded = 0;
     
    17861790     * Load crypt32.dll and resolve the APIs we need.
    17871791     */
    1788     HMODULE hCrypt32 = LoadLibraryExW(L"\\\\.\\GLOBALROOT\\SystemRoot\\System32\\crypt32.dll", NULL, fLoadLibraryFlags);
    1789     if (!hCrypt32)
    1790         supR3HardenedFatal("Error loading 'crypt32.dll': %u", GetLastError());
     1792    HMODULE hCrypt32 = supR3HardenedWinLoadSystem32Dll("crypt32.dll");
    17911793
    17921794#define RESOLVE_CRYPT32_API(a_Name, a_pfnType) \
     
    18851887     * Resolve it.
    18861888     */
    1887     DWORD fFlags = 0;
    1888     if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0))
    1889        fFlags = LOAD_LIBRARY_SEARCH_SYSTEM32;
    1890     HMODULE hWintrust = LoadLibraryExW(L"\\\\.\\GLOBALROOT\\SystemRoot\\System32\\Wintrust.dll", NULL, fFlags);
    1891     if (   hWintrust == NULL
    1892         && fFlags
    1893         && g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 2)
    1894         && GetLastError() == ERROR_INVALID_PARAMETER)
    1895     {
    1896         fFlags = 0;
    1897         hWintrust = LoadLibraryExW(L"\\\\.\\GLOBALROOT\\SystemRoot\\System32\\Wintrust.dll", NULL, fFlags);
    1898     }
    1899     if (hWintrust == NULL)
    1900         supR3HardenedFatal("Error loading 'Wintrust.dll': %u", GetLastError());
    1901 
     1889    HMODULE hWintrust = supR3HardenedWinLoadSystem32Dll("Wintrust.dll");
    19021890#define RESOLVE_CRYPT_API(a_Name, a_pfnType, a_uMinWinVer) \
    19031891    do { \
     
    19431931    SUP_DPRINTF(("g_pfnWinVerifyTrust=%p\n", pfnWinVerifyTrust));
    19441932
     1933# ifdef IN_SUP_HARDENED_R3
     1934    /*
     1935     * Load some problematic DLLs into the verifier cache to prevent
     1936     * recursion trouble.
     1937     */
     1938    supR3HardenedWinVerifyCachePreload(L"\\SystemRoot\\System32\\crypt32.dll");
     1939    supR3HardenedWinVerifyCachePreload(L"\\SystemRoot\\System32\\Wintrust.dll");
     1940# endif
     1941
    19451942    /*
    19461943     * Now, get trusted root CAs so we can verify a broader scope of signatures.
    19471944     */
    1948     supR3HardenedWinRetrieveTrustedRootCAs(fFlags);
     1945    supR3HardenedWinRetrieveTrustedRootCAs();
     1946
     1947# ifdef IN_SUP_HARDENED_R3
     1948    /*
     1949     * Do some verify cache preloading.  The MS Visual C++ CRT DLLs works
     1950     * around recursion issues with WinVerifyTrust on 32-bit windows 7.
     1951     */
     1952    SUP_DPRINTF(("preloading part 2...\n"));
     1953#  if 0 /* Seeing if this helps with the later Win7/32 issue... apparently not :-/ */
     1954    supR3HardenedWinVerifyCachePreload(L"\\SystemRoot\\System32\\cfgmgr32.dll");
     1955    supR3HardenedWinVerifyCachePreload(L"\\SystemRoot\\System32\\devobj.dll");
     1956    supR3HardenedWinVerifyCachePreload(L"\\SystemRoot\\System32\\setupapi.dll");
     1957    supR3HardenedWinLoadSystem32Dll("setupapi.dll");
     1958    supR3HardenedWinVerifyCachePreload(L"\\SystemRoot\\System32\\rsaenh.dll");
     1959    supR3HardenedWinLoadSystem32Dll("rsaenh.dll");
     1960#  endif
     1961
     1962    WCHAR wszPath[260+16];
     1963    supR3HardenedWinVerifyCachePreload(L"\\SystemRoot\\System32\\apphelp.dll");
     1964    memcpy(wszPath, g_SupLibHardenedExeNtPath.UniStr.Buffer, g_SupLibHardenedExeNtPath.UniStr.Length);
     1965    static char const *s_apszAppDlls[] =
     1966    {
     1967        NULL,
     1968        "VBoxRT.dll",
     1969#  if _MSC_VER < 1600
     1970        "msvcr90.dll",  "msvcp90.dll",
     1971#  elif _MSC_VER < 1700
     1972        "msvcr100.dll", "msvcp100.dll",
     1973#  elif _MSC_VER < 1800
     1974        "msvcr110.dll", "msvcp110.dll",
     1975#  elif _MSC_VER < 1900
     1976        "msvcr120.dll", "msvcp120.dll",
     1977#  elif _MSC_VER < 1900
     1978        "msvcr130.dll", "msvcp130.dll",
     1979#  else
     1980#   error "Unsupported compiler version."
     1981#  endif
     1982    };
     1983    s_apszAppDlls[0] = pszProgName;
     1984    for (uint32_t i = 0; i < RT_ELEMENTS(s_apszAppDlls); i++)
     1985    {
     1986        RTUtf16CopyAscii(&wszPath[g_offSupLibHardenedExeNtName], 300 - g_offSupLibHardenedExeNtName, s_apszAppDlls[i]);
     1987        supR3HardenedWinVerifyCachePreload(wszPath);
     1988    }
     1989    SUP_DPRINTF(("preloading part 2 - done.\n"));
     1990# endif
    19491991}
    19501992
  • trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp

    r52373 r52375  
    381381 *                              here instead of being handled by the caller to
    382382 *                              save code duplication.
    383  */
    384 static void supR3HardenedWinVerifyCacheInsert(PCUNICODE_STRING pUniStr, HANDLE hFile, int rc, bool fCacheable)
     383 * @param   fForceCacheable     Overrides the main state and @a fCacheable.
     384 */
     385static void supR3HardenedWinVerifyCacheInsert(PCUNICODE_STRING pUniStr, HANDLE hFile, int rc, bool fCacheable,
     386                                              bool fForceCacheable)
    385387{
    386388    /*
    387389     * Don't cache anything until we've got the WinVerifyTrust API up and running.
    388390     */
    389     if (   g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_VERIFY_TRUST_READY
    390         && fCacheable)
     391    if (   (   g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_VERIFY_TRUST_READY
     392            && fCacheable)
     393        || fForceCacheable)
    391394    {
    392395        /*
     
    414417            {
    415418                if (ASMAtomicCmpXchgPtr(ppEntry, pEntry, NULL))
     419                {
     420                    SUP_DPRINTF(("supR3HardenedWinVerifyCacheInsert: %ls\n", pUniStr->Buffer));
    416421                    return;
     422                }
     423
    417424                PVERIFIERCACHEENTRY pOther = *ppEntry;
    418425                if (!pOther)
     
    618625
    619626
     627static NTSTATUS supR3HardenedScreenImage(HANDLE hFile, bool fImage, PULONG pfAccess, PULONG pfProtect, bool *pfCallRealApi,
     628                                         bool fForceCacheable)
     629{
     630    *pfCallRealApi = false;
     631
     632    /*
     633     * Query the name of the file, making sure to zero terminator the
     634     * string. (2nd half of buffer is used for error info, see below.)
     635     */
     636    union
     637    {
     638        UNICODE_STRING UniStr;
     639        uint8_t abBuffer[sizeof(UNICODE_STRING) + 2048 * sizeof(WCHAR)];
     640    } uBuf;
     641    RT_ZERO(uBuf);
     642    ULONG cbNameBuf;
     643    NTSTATUS rcNt = NtQueryObject(hFile, ObjectNameInformation, &uBuf, sizeof(uBuf) - sizeof(WCHAR) - 128, &cbNameBuf);
     644    if (!NT_SUCCESS(rcNt))
     645    {
     646        supR3HardenedError(VINF_SUCCESS, false, "NtCreateSection: NtQueryObject -> %#x (fImage=%d fProtect=%#x fAccess=%#x)\n",
     647                           fImage, *pfProtect, *pfAccess);
     648        return rcNt;
     649    }
     650
     651    if (supR3HardenedWinIsPossible8dot3Path(uBuf.UniStr.Buffer))
     652    {
     653        uBuf.UniStr.MaximumLength = sizeof(uBuf) - 128;
     654        supR3HardenedWinFix8dot3Path(hFile, &uBuf.UniStr);
     655    }
     656
     657    /*
     658     * Check the cache.
     659     */
     660    PVERIFIERCACHEENTRY pCacheHit = supR3HardenedWinVerifyCacheLookup(&uBuf.UniStr, hFile);
     661    if (pCacheHit)
     662    {
     663        SUP_DPRINTF(("NtCreateSection: cache hit (%Rrc) on %ls\n", pCacheHit->rc, pCacheHit->wszPath));
     664        if (RT_SUCCESS(pCacheHit->rc))
     665        {
     666            *pfCallRealApi = true;
     667            return STATUS_SUCCESS;
     668        }
     669        supR3HardenedError(VINF_SUCCESS, false, "NtCreateSection: cached rc=%Rrc fImage=%d fProtect=%#x fAccess=%#x %ls\n",
     670                           pCacheHit->rc, fImage, *pfProtect, *pfAccess, uBuf.UniStr.Buffer);
     671        return STATUS_TRUST_FAILURE;
     672    }
     673
     674    /*
     675     * On XP the loader might hand us handles with just FILE_EXECUTE and
     676     * SYNCHRONIZE, the means reading will fail later on.  Also, we need
     677     * READ_CONTROL access to check the file ownership later on, and non
     678     * of the OS versions seems be giving us that.  So, in effect we
     679     * more or less always reopen the file here.
     680     */
     681    HANDLE hMyFile = NULL;
     682    rcNt = NtDuplicateObject(NtCurrentProcess(), hFile, NtCurrentProcess(),
     683                             &hMyFile,
     684                             FILE_READ_DATA | READ_CONTROL | SYNCHRONIZE,
     685                             0 /* Handle attributes*/, 0 /* Options */);
     686    if (!NT_SUCCESS(rcNt))
     687    {
     688        if (rcNt == STATUS_ACCESS_DENIED)
     689        {
     690            IO_STATUS_BLOCK     Ios   = RTNT_IO_STATUS_BLOCK_INITIALIZER;
     691            OBJECT_ATTRIBUTES   ObjAttr;
     692            InitializeObjectAttributes(&ObjAttr, &uBuf.UniStr, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
     693
     694            rcNt = NtCreateFile(&hMyFile,
     695                                FILE_READ_DATA | READ_CONTROL | SYNCHRONIZE,
     696                                &ObjAttr,
     697                                &Ios,
     698                                NULL /* Allocation Size*/,
     699                                FILE_ATTRIBUTE_NORMAL,
     700                                FILE_SHARE_READ,
     701                                FILE_OPEN,
     702                                FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
     703                                NULL /*EaBuffer*/,
     704                                0 /*EaLength*/);
     705            if (NT_SUCCESS(rcNt))
     706                rcNt = Ios.Status;
     707            if (!NT_SUCCESS(rcNt))
     708            {
     709                supR3HardenedError(VINF_SUCCESS, false,
     710                                   "NtCreateSection: Failed to duplicate and open the file: rcNt=%#x hFile=%p %ls\n",
     711                                   rcNt, hFile, uBuf.UniStr.Buffer);
     712                return rcNt;
     713            }
     714
     715            /* Check that we've got the same file. */
     716            LARGE_INTEGER idMyFile, idInFile;
     717            bool fMyValid = supR3HardenedWinVerifyCacheGetIndexNumber(hMyFile, &idMyFile);
     718            bool fInValid = supR3HardenedWinVerifyCacheGetIndexNumber(hFile, &idInFile);
     719            if (   fMyValid
     720                && (   fMyValid != fInValid
     721                    || idMyFile.QuadPart != idInFile.QuadPart))
     722            {
     723                supR3HardenedError(VINF_SUCCESS, false,
     724                                   "NtCreateSection: Re-opened has different ID that input: %#llx vx %#llx (%ls)\n",
     725                                   rcNt, idMyFile.QuadPart, idInFile.QuadPart, uBuf.UniStr.Buffer);
     726                NtClose(hMyFile);
     727                return STATUS_TRUST_FAILURE;
     728            }
     729        }
     730        else
     731        {
     732            SUP_DPRINTF(("supR3HardenedMonitor_NtCreateSection: NtDuplicateObject -> %#x\n", rcNt));
     733#ifdef DEBUG
     734
     735            supR3HardenedError(VINF_SUCCESS, false, "supR3HardenedMonitor_NtCreateSection: NtDuplicateObject(,%#x,) failed: %#x\n", hFile, rcNt);
     736#endif
     737            hMyFile = hFile;
     738        }
     739    }
     740
     741    /*
     742     * Special Kludge for Windows XP and W2K3 and their stupid attempts
     743     * at mapping a hidden XML file called c:\Windows\WindowsShell.Manifest
     744     * with executable access.  The image bit isn't set, fortunately.
     745     */
     746    if (   !fImage
     747        && uBuf.UniStr.Length > g_System32NtPath.UniStr.Length - sizeof(L"System32") + sizeof(WCHAR)
     748        && memcmp(uBuf.UniStr.Buffer, g_System32NtPath.UniStr.Buffer,
     749                  g_System32NtPath.UniStr.Length - sizeof(L"System32") + sizeof(WCHAR)) == 0)
     750    {
     751        PRTUTF16 pwszName = &uBuf.UniStr.Buffer[(g_System32NtPath.UniStr.Length - sizeof(L"System32") + sizeof(WCHAR)) / sizeof(WCHAR)];
     752        if (RTUtf16ICmpAscii(pwszName, "WindowsShell.Manifest") == 0)
     753        {
     754            /*
     755             * Drop all executable access to the mapping and let it continue.
     756             */
     757            SUP_DPRINTF(("supR3HardenedMonitor_NtCreateSection: Applying the drop-exec-kludge for '%ls'\n", uBuf.UniStr.Buffer));
     758            if (*pfAccess & SECTION_MAP_EXECUTE)
     759                *pfAccess = (*pfAccess & ~SECTION_MAP_EXECUTE) | SECTION_MAP_READ;
     760            if (*pfProtect & PAGE_EXECUTE)
     761                *pfProtect = (*pfProtect & ~PAGE_EXECUTE) | PAGE_READONLY;
     762            *pfProtect = (*pfProtect & ~UINT32_C(0xf0)) | ((*pfProtect & UINT32_C(0xe0)) >> 4);
     763            if (hMyFile != hFile)
     764                NtClose(hMyFile);
     765            *pfCallRealApi = true;
     766            return STATUS_SUCCESS;
     767        }
     768    }
     769
     770    /*
     771     * Check the path.  We don't allow DLLs to be loaded from just anywhere:
     772     *      1. System32      - normal code or cat signing, owner TrustedInstaller.
     773     *      2. WinSxS        - normal code or cat signing, owner TrustedInstaller.
     774     *      3. VirtualBox    - kernel code signing and integrity checks.
     775     *      4. AppPatchDir   - normal code or cat signing, owner TrustedInstaller.
     776     *      5. Program Files - normal code or cat signing, owner TrustedInstaller.
     777     *      6. Common Files  - normal code or cat signing, owner TrustedInstaller.
     778     *      7. x86 variations of 4 & 5 - ditto.
     779     */
     780    bool fSystem32 = false;
     781    Assert(g_SupLibHardenedExeNtPath.UniStr.Buffer[g_offSupLibHardenedExeNtName - 1] == '\\');
     782    uint32_t fFlags = 0;
     783    if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_System32NtPath.UniStr, true /*fCheckSlash*/))
     784    {
     785        fSystem32 = true;
     786        fFlags |= SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION | SUPHNTVI_F_TRUSTED_INSTALLER_OWNER;
     787    }
     788    else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_WinSxSNtPath.UniStr, true /*fCheckSlash*/))
     789        fFlags |= SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION | SUPHNTVI_F_TRUSTED_INSTALLER_OWNER;
     790    else if (supHardViUtf16PathStartsWithEx(uBuf.UniStr.Buffer, uBuf.UniStr.Length / sizeof(WCHAR),
     791                                            g_SupLibHardenedExeNtPath.UniStr.Buffer,
     792                                            g_offSupLibHardenedExeNtName, false /*fCheckSlash*/))
     793        fFlags |= SUPHNTVI_F_REQUIRE_KERNEL_CODE_SIGNING | SUPHNTVI_F_REQUIRE_SIGNATURE_ENFORCEMENT;
     794#ifdef VBOX_PERMIT_MORE
     795    else if (supHardViIsAppPatchDir(uBuf.UniStr.Buffer, uBuf.UniStr.Length / sizeof(WCHAR)))
     796        fFlags |= SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION | SUPHNTVI_F_TRUSTED_INSTALLER_OWNER;
     797    else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_ProgramFilesNtPath.UniStr, true /*fCheckSlash*/))
     798        fFlags |= SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION | SUPHNTVI_F_TRUSTED_INSTALLER_OWNER;
     799    else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_CommonFilesNtPath.UniStr, true /*fCheckSlash*/))
     800        fFlags |= SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION | SUPHNTVI_F_TRUSTED_INSTALLER_OWNER;
     801# ifdef RT_ARCH_AMD64
     802    else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_ProgramFilesX86NtPath.UniStr, true /*fCheckSlash*/))
     803        fFlags |= SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION | SUPHNTVI_F_TRUSTED_INSTALLER_OWNER;
     804    else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_CommonFilesX86NtPath.UniStr, true /*fCheckSlash*/))
     805        fFlags |= SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION | SUPHNTVI_F_TRUSTED_INSTALLER_OWNER;
     806# endif
     807#endif
     808#ifdef VBOX_PERMIT_VISUAL_STUDIO_PROFILING
     809    /* Hack to allow profiling our code with Visual Studio. */
     810    else if (   uBuf.UniStr.Length > sizeof(L"\\SamplingRuntime.dll")
     811             && memcmp(uBuf.UniStr.Buffer + (uBuf.UniStr.Length - sizeof(L"\\SamplingRuntime.dll") + sizeof(WCHAR)) / sizeof(WCHAR),
     812                       L"\\SamplingRuntime.dll", sizeof(L"\\SamplingRuntime.dll") - sizeof(WCHAR)) == 0 )
     813    {
     814        if (hMyFile != hFile)
     815            NtClose(hMyFile);
     816        *pfCallRealApi = true;
     817        return STATUS_SUCCESS;
     818    }
     819#endif
     820    else
     821    {
     822        supR3HardenedError(VINF_SUCCESS, false,
     823                           "supR3HardenedMonitor_NtCreateSection: Not a trusted location: '%ls' (fImage=%d fProtect=%#x fAccess=%#x)",
     824                            uBuf.UniStr.Buffer, fImage, *pfAccess, *pfProtect);
     825        if (hMyFile != hFile)
     826            NtClose(hMyFile);
     827        return STATUS_TRUST_FAILURE;
     828    }
     829
     830    /*
     831     * Do the verification. For better error message we borrow what's
     832     * left of the path buffer for an RTERRINFO buffer.
     833     */
     834    RTERRINFO ErrInfo;
     835    RTErrInfoInit(&ErrInfo, (char *)&uBuf.abBuffer[cbNameBuf], sizeof(uBuf) - cbNameBuf);
     836
     837    bool fCacheable = true;
     838    int rc = supHardenedWinVerifyImageByHandle(hMyFile, uBuf.UniStr.Buffer, fFlags, &fCacheable, &ErrInfo);
     839    if (RT_FAILURE(rc))
     840    {
     841        supR3HardenedError(VINF_SUCCESS, false,
     842                           "supR3HardenedMonitor_NtCreateSection: rc=%Rrc fImage=%d fProtect=%#x fAccess=%#x %ls: %s\n",
     843                           rc, fImage, *pfAccess, *pfProtect, uBuf.UniStr.Buffer, ErrInfo.pszMsg);
     844        if (hMyFile != hFile)
     845            NtClose(hMyFile);
     846        return STATUS_TRUST_FAILURE;
     847    }
     848    if (hMyFile != hFile)
     849        supR3HardenedWinVerifyCacheInsert(&uBuf.UniStr, hMyFile, rc, fCacheable, fForceCacheable);
     850
     851    *pfCallRealApi = true;
     852    return STATUS_SUCCESS;
     853}
     854
     855
     856/**
     857 * Preloads a file into the verify cache if possible.
     858 *
     859 * This is used to avoid known cyclic LoadLibrary issues with WinVerifyTrust.
     860 *
     861 * @param   pwszName            The name of the DLL to verify.
     862 */
     863DECLHIDDEN(void) supR3HardenedWinVerifyCachePreload(PCRTUTF16 pwszName)
     864{
     865    HANDLE              hFile = RTNT_INVALID_HANDLE_VALUE;
     866    IO_STATUS_BLOCK     Ios   = RTNT_IO_STATUS_BLOCK_INITIALIZER;
     867
     868    UNICODE_STRING      UniStr;
     869    UniStr.Buffer = (PWCHAR)pwszName;
     870    UniStr.Length = (USHORT)(RTUtf16Len(pwszName) * sizeof(WCHAR));
     871    UniStr.MaximumLength = UniStr.Length + sizeof(WCHAR);
     872
     873    OBJECT_ATTRIBUTES   ObjAttr;
     874    InitializeObjectAttributes(&ObjAttr, &UniStr, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
     875
     876    NTSTATUS rcNt = NtCreateFile(&hFile,
     877                                 FILE_READ_DATA | READ_CONTROL | SYNCHRONIZE,
     878                                 &ObjAttr,
     879                                 &Ios,
     880                                 NULL /* Allocation Size*/,
     881                                 FILE_ATTRIBUTE_NORMAL,
     882                                 FILE_SHARE_READ,
     883                                 FILE_OPEN,
     884                                 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
     885                                 NULL /*EaBuffer*/,
     886                                 0 /*EaLength*/);
     887    if (NT_SUCCESS(rcNt))
     888        rcNt = Ios.Status;
     889    if (!NT_SUCCESS(rcNt))
     890    {
     891        SUP_DPRINTF(("supR3HardenedWinPreScreenImage: Error %#x opening '%ls'.\n", rcNt, pwszName));
     892        return;
     893    }
     894
     895    ULONG fAccess = 0;
     896    ULONG fProtect = 0;
     897    bool  fCallRealApi;
     898    //SUP_DPRINTF(("supR3HardenedWinVerifyCachePreload: scanning %ls\n", pwszName));
     899    supR3HardenedScreenImage(hFile, false, &fAccess, &fProtect, &fCallRealApi, true /* fForceCacheable */);
     900    //SUP_DPRINTF(("supR3HardenedWinVerifyCachePreload: done %ls\n", pwszName));
     901
     902    NtClose(hFile);
     903}
     904
     905
     906
    620907/**
    621908 * Hook that monitors NtCreateSection calls.
     
    643930        if (fImage || fExecMap || fExecProt)
    644931        {
    645             /*
    646              * Query the name of the file, making sure to zero terminator the
    647              * string. (2nd half of buffer is used for error info, see below.)
    648              */
    649             union
    650             {
    651                 UNICODE_STRING UniStr;
    652                 uint8_t abBuffer[sizeof(UNICODE_STRING) + 2048 * sizeof(WCHAR)];
    653             } uBuf;
    654             RT_ZERO(uBuf);
    655             ULONG cbNameBuf;
    656             NTSTATUS rcNt = NtQueryObject(hFile, ObjectNameInformation, &uBuf, sizeof(uBuf) - sizeof(WCHAR) - 128, &cbNameBuf);
     932            bool fCallRealApi;
     933            //SUP_DPRINTF(("supR3HardenedMonitor_NtCreateSection: 1\n"));
     934            NTSTATUS rcNt = supR3HardenedScreenImage(hFile, fImage, &fAccess, &fProtect, &fCallRealApi, false /*fForceCacheable*/);
     935            //SUP_DPRINTF(("supR3HardenedMonitor_NtCreateSection: 2 rcNt=%#x fCallRealApi=%#x\n", rcNt, fCallRealApi));
    657936            if (!NT_SUCCESS(rcNt))
    658             {
    659                 supR3HardenedError(VINF_SUCCESS, false,
    660                                    "NtCreateSection: NtQueryObject -> %#x (fImage=%d fExecMap=%d fExecProt=%d)\n",
    661                                    fImage, fExecMap, fExecProt);
    662937                return rcNt;
    663             }
    664 
    665             if (supR3HardenedWinIsPossible8dot3Path(uBuf.UniStr.Buffer))
    666             {
    667                 uBuf.UniStr.MaximumLength = sizeof(uBuf) - 128;
    668                 supR3HardenedWinFix8dot3Path(hFile, &uBuf.UniStr);
    669             }
    670 
    671             /*
    672              * Check the cache.
    673              */
    674             PVERIFIERCACHEENTRY pCacheHit = supR3HardenedWinVerifyCacheLookup(&uBuf.UniStr, hFile);
    675             if (pCacheHit)
    676             {
    677                 SUP_DPRINTF(("NtCreateSection: cache hit (%Rrc) on %ls\n", pCacheHit->rc, pCacheHit->wszPath));
    678                 if (RT_SUCCESS(pCacheHit->rc))
    679                     return g_pfnNtCreateSectionReal(phSection, fAccess, pObjAttribs, pcbSection, fProtect, fAttribs, hFile);
    680                 supR3HardenedError(VINF_SUCCESS, false,
    681                                    "NtCreateSection: cached rc=%Rrc fImage=%d fExecMap=%d fExecProt=%d %ls\n",
    682                                    pCacheHit->rc, fImage, fExecMap, fExecProt, uBuf.UniStr.Buffer);
     938            Assert(fCallRealApi);
     939            if (!fCallRealApi)
    683940                return STATUS_TRUST_FAILURE;
    684             }
    685 
    686             /*
    687              * On XP the loader might hand us handles with just FILE_EXECUTE and
    688              * SYNCHRONIZE, the means reading will fail later on.  Also, we need
    689              * READ_CONTROL access to check the file ownership later on, and non
    690              * of the OS versions seems be giving us that.  So, in effect we
    691              * more or less always reopen the file here.
    692              */
    693             HANDLE hMyFile = NULL;
    694             rcNt = NtDuplicateObject(NtCurrentProcess(), hFile, NtCurrentProcess(),
    695                                      &hMyFile,
    696                                      FILE_READ_DATA | READ_CONTROL | SYNCHRONIZE,
    697                                      0 /* Handle attributes*/, 0 /* Options */);
    698             if (!NT_SUCCESS(rcNt))
    699             {
    700                 if (rcNt == STATUS_ACCESS_DENIED)
    701                 {
    702                     IO_STATUS_BLOCK     Ios   = RTNT_IO_STATUS_BLOCK_INITIALIZER;
    703                     OBJECT_ATTRIBUTES   ObjAttr;
    704                     InitializeObjectAttributes(&ObjAttr, &uBuf.UniStr, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
    705 
    706                     rcNt = NtCreateFile(&hMyFile,
    707                                         FILE_READ_DATA | READ_CONTROL | SYNCHRONIZE,
    708                                         &ObjAttr,
    709                                         &Ios,
    710                                         NULL /* Allocation Size*/,
    711                                         FILE_ATTRIBUTE_NORMAL,
    712                                         FILE_SHARE_READ,
    713                                         FILE_OPEN,
    714                                         FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
    715                                         NULL /*EaBuffer*/,
    716                                         0 /*EaLength*/);
    717                     if (NT_SUCCESS(rcNt))
    718                         rcNt = Ios.Status;
    719                     if (!NT_SUCCESS(rcNt))
    720                     {
    721                         supR3HardenedError(VINF_SUCCESS, false,
    722                                            "NtCreateSection: Failed to duplicate and open the file: rcNt=%#x hFile=%p %ls\n",
    723                                            rcNt, hFile, uBuf.UniStr.Buffer);
    724                         return rcNt;
    725                     }
    726 
    727                     /* Check that we've got the same file. */
    728                     LARGE_INTEGER idMyFile, idInFile;
    729                     bool fMyValid = supR3HardenedWinVerifyCacheGetIndexNumber(hMyFile, &idMyFile);
    730                     bool fInValid = supR3HardenedWinVerifyCacheGetIndexNumber(hFile, &idInFile);
    731                     if (   fMyValid
    732                         && (   fMyValid != fInValid
    733                             || idMyFile.QuadPart != idInFile.QuadPart))
    734                     {
    735                         supR3HardenedError(VINF_SUCCESS, false,
    736                                            "NtCreateSection: Re-opened has different ID that input: %#llx vx %#llx (%ls)\n",
    737                                            rcNt, idMyFile.QuadPart, idInFile.QuadPart, uBuf.UniStr.Buffer);
    738                         NtClose(hMyFile);
    739                         return STATUS_TRUST_FAILURE;
    740                     }
    741                 }
    742                 else
    743                 {
    744                     SUP_DPRINTF(("supR3HardenedMonitor_NtCreateSection: NtDuplicateObject -> %#x\n", rcNt));
    745 #ifdef DEBUG
    746 
    747                     supR3HardenedError(VINF_SUCCESS, false, "supR3HardenedMonitor_NtCreateSection: NtDuplicateObject(,%#x,) failed: %#x\n", hFile, rcNt);
    748 #endif
    749                     hMyFile = hFile;
    750                 }
    751             }
    752 
    753             /*
    754              * Special Kludge for Windows XP and W2K3 and their stupid attempts
    755              * at mapping a hidden XML file called c:\Windows\WindowsShell.Manifest
    756              * with executable access.  The image bit isn't set, fortunately.
    757              */
    758             if (   !fImage
    759                 && uBuf.UniStr.Length > g_System32NtPath.UniStr.Length - sizeof(L"System32") + sizeof(WCHAR)
    760                 && memcmp(uBuf.UniStr.Buffer, g_System32NtPath.UniStr.Buffer,
    761                           g_System32NtPath.UniStr.Length - sizeof(L"System32") + sizeof(WCHAR)) == 0)
    762             {
    763                 PRTUTF16 pwszName = &uBuf.UniStr.Buffer[(g_System32NtPath.UniStr.Length - sizeof(L"System32") + sizeof(WCHAR)) / sizeof(WCHAR)];
    764                 if (RTUtf16ICmpAscii(pwszName, "WindowsShell.Manifest") == 0)
    765                 {
    766                     /*
    767                      * Drop all executable access to the mapping and let it continue.
    768                      */
    769                     SUP_DPRINTF(("supR3HardenedMonitor_NtCreateSection: Applying the drop-exec-kludge for '%ls'\n", uBuf.UniStr.Buffer));
    770                     if (fAccess & SECTION_MAP_EXECUTE)
    771                         fAccess = (fAccess & ~SECTION_MAP_EXECUTE) | SECTION_MAP_READ;
    772                     if (fProtect & PAGE_EXECUTE)
    773                         fProtect = (fProtect & ~PAGE_EXECUTE) | PAGE_READONLY;
    774                     fProtect = (fProtect & ~UINT32_C(0xf0)) | ((fProtect & UINT32_C(0xe0)) >> 4);
    775                     if (hMyFile != hFile)
    776                         NtClose(hMyFile);
    777                     return g_pfnNtCreateSectionReal(phSection, fAccess, pObjAttribs, pcbSection, fProtect, fAttribs, hFile);
    778                 }
    779             }
    780 
    781             /*
    782              * Check the path.  We don't allow DLLs to be loaded from just anywhere:
    783              *      1. System32      - normal code or cat signing, owner TrustedInstaller.
    784              *      2. WinSxS        - normal code or cat signing, owner TrustedInstaller.
    785              *      3. VirtualBox    - kernel code signing and integrity checks.
    786              *      4. AppPatchDir   - normal code or cat signing, owner TrustedInstaller.
    787              *      5. Program Files - normal code or cat signing, owner TrustedInstaller.
    788              *      6. Common Files  - normal code or cat signing, owner TrustedInstaller.
    789              *      7. x86 variations of 4 & 5 - ditto.
    790              */
    791             bool fSystem32 = false;
    792             Assert(g_SupLibHardenedExeNtPath.UniStr.Buffer[g_offSupLibHardenedExeNtName - 1] == '\\');
    793             uint32_t fFlags = 0;
    794             if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_System32NtPath.UniStr, true /*fCheckSlash*/))
    795             {
    796                 fSystem32 = true;
    797                 fFlags |= SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION | SUPHNTVI_F_TRUSTED_INSTALLER_OWNER;
    798             }
    799             else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_WinSxSNtPath.UniStr, true /*fCheckSlash*/))
    800                 fFlags |= SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION | SUPHNTVI_F_TRUSTED_INSTALLER_OWNER;
    801             else if (supHardViUtf16PathStartsWithEx(uBuf.UniStr.Buffer, uBuf.UniStr.Length / sizeof(WCHAR),
    802                                                     g_SupLibHardenedExeNtPath.UniStr.Buffer,
    803                                                     g_offSupLibHardenedExeNtName, false /*fCheckSlash*/))
    804                 fFlags |= SUPHNTVI_F_REQUIRE_KERNEL_CODE_SIGNING | SUPHNTVI_F_REQUIRE_SIGNATURE_ENFORCEMENT;
    805 #ifdef VBOX_PERMIT_MORE
    806             else if (supHardViIsAppPatchDir(uBuf.UniStr.Buffer, uBuf.UniStr.Length / sizeof(WCHAR)))
    807                 fFlags |= SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION | SUPHNTVI_F_TRUSTED_INSTALLER_OWNER;
    808             else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_ProgramFilesNtPath.UniStr, true /*fCheckSlash*/))
    809                 fFlags |= SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION | SUPHNTVI_F_TRUSTED_INSTALLER_OWNER;
    810             else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_CommonFilesNtPath.UniStr, true /*fCheckSlash*/))
    811                 fFlags |= SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION | SUPHNTVI_F_TRUSTED_INSTALLER_OWNER;
    812 # ifdef RT_ARCH_AMD64
    813             else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_ProgramFilesX86NtPath.UniStr, true /*fCheckSlash*/))
    814                 fFlags |= SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION | SUPHNTVI_F_TRUSTED_INSTALLER_OWNER;
    815             else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_CommonFilesX86NtPath.UniStr, true /*fCheckSlash*/))
    816                 fFlags |= SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION | SUPHNTVI_F_TRUSTED_INSTALLER_OWNER;
    817 # endif
    818 #endif
    819 #ifdef VBOX_PERMIT_VISUAL_STUDIO_PROFILING
    820             /* Hack to allow profiling our code with Visual Studio. */
    821             else if (   uBuf.UniStr.Length > sizeof(L"\\SamplingRuntime.dll")
    822                      && memcmp(uBuf.UniStr.Buffer + (uBuf.UniStr.Length - sizeof(L"\\SamplingRuntime.dll") + sizeof(WCHAR)) / sizeof(WCHAR),
    823                                L"\\SamplingRuntime.dll", sizeof(L"\\SamplingRuntime.dll") - sizeof(WCHAR)) == 0 )
    824             {
    825                 if (hMyFile != hFile)
    826                     NtClose(hMyFile);
    827                 return g_pfnNtCreateSectionReal(phSection, fAccess, pObjAttribs, pcbSection, fProtect, fAttribs, hFile);
    828             }
    829 #endif
    830             else
    831             {
    832                 supR3HardenedError(VINF_SUCCESS, false,
    833                                    "supR3HardenedMonitor_NtCreateSection: Not a trusted location: '%ls' (fImage=%d fExecMap=%d fExecProt=%d)",
    834                                     uBuf.UniStr.Buffer, fImage, fExecMap, fExecProt);
    835                 if (hMyFile != hFile)
    836                     NtClose(hMyFile);
    837                 return STATUS_TRUST_FAILURE;
    838             }
    839 
    840             /*
    841              * Do the verification. For better error message we borrow what's
    842              * left of the path buffer for an RTERRINFO buffer.
    843              */
    844             RTERRINFO ErrInfo;
    845             RTErrInfoInit(&ErrInfo, (char *)&uBuf.abBuffer[cbNameBuf], sizeof(uBuf) - cbNameBuf);
    846 
    847             bool fCacheable = true;
    848             int rc = supHardenedWinVerifyImageByHandle(hMyFile, uBuf.UniStr.Buffer, fFlags, &fCacheable, &ErrInfo);
    849             if (RT_FAILURE(rc))
    850             {
    851                 supR3HardenedError(VINF_SUCCESS, false,
    852                                    "supR3HardenedMonitor_NtCreateSection: rc=%Rrc fImage=%d fExecMap=%d fExecProt=%d %ls: %s\n",
    853                                    rc, fImage, fExecMap, fExecProt, uBuf.UniStr.Buffer, ErrInfo.pszMsg);
    854                 if (hMyFile != hFile)
    855                     NtClose(hMyFile);
    856                 return STATUS_TRUST_FAILURE;
    857             }
    858             if (hMyFile != hFile)
    859                 supR3HardenedWinVerifyCacheInsert(&uBuf.UniStr, hMyFile, rc, fCacheable);
    860941        }
    861942    }
  • trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainImports-win.cpp

    r52374 r52375  
    597597                                "%ls: supHardNtLdrCacheOpen failed: %Rrc '%s'.", g_aSupNtImpDlls[iDll].pwszName, rc);
    598598        }
     599
     600#if 0 /* Win7/32 ntdll!LdrpDebugFlags. */
     601    *(uint8_t *)&g_aSupNtImpDlls[0].pbImageBase[0xdd770] = 0x3;
     602#endif
    599603}
    600604
Note: See TracChangeset for help on using the changeset viewer.

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