SUPR3HardenedMain-win.cpp revision 100b161379af7255c69e27587cc746e5f76ff050
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * VirtualBox Support Library - Hardened main(), windows bits.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Copyright (C) 2006-2014 Oracle Corporation
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * available from http://www.virtualbox.org. This file is free software;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * you can redistribute it and/or modify it under the terms of the GNU
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * General Public License (GPL) as published by the Free Software
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * The contents of this file may alternatively be used under the terms
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * of the Common Development and Distribution License Version 1.0
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * VirtualBox OSE distribution, in which case the provisions of the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * CDDL are applicable instead of those of the GPL.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * You may elect to license modified versions of this file under the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * terms and conditions of either the GPL or the CDDL or both.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/*******************************************************************************
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync* Header Files *
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync*******************************************************************************/
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/*******************************************************************************
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync* Defined Constants And Macros *
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync*******************************************************************************/
edde275acba04aca58db4172a163741e3abadfbcvboxsync/** The first argument of a respawed stub when respawned for the first time.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * This just needs to be unique enough to avoid most confusion with real
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * executable names, there are other checks in place to make sure we've respanwed. */
a1d9d394b49969e730c5a8e037ea2d672a48dbf6vboxsync#define SUPR3_RESPAWN_1_ARG0 "60eaff78-4bdd-042d-2e72-669728efd737-suplib-2ndchild"
edde275acba04aca58db4172a163741e3abadfbcvboxsync/** The first argument of a respawed stub when respawned for the second time.
edde275acba04aca58db4172a163741e3abadfbcvboxsync * This just needs to be unique enough to avoid most confusion with real
edde275acba04aca58db4172a163741e3abadfbcvboxsync * executable names, there are other checks in place to make sure we've respanwed. */
a1d9d394b49969e730c5a8e037ea2d672a48dbf6vboxsync#define SUPR3_RESPAWN_2_ARG0 "60eaff78-4bdd-042d-2e72-669728efd737-suplib-3rdchild"
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/** Unconditional assertion. */
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync supR3HardenedFatal("%s: %s\n", __FUNCTION__, #a_Expr); \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync } while (0)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/** Unconditional assertion of NT_SUCCESS. */
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync supR3HardenedFatal("%s: %s -> %#x\n", __FUNCTION__, #a_Expr, rcNtAssert); \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync } while (0)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/** Unconditional assertion of a WIN32 API returning non-FALSE. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#define SUPR3HARDENED_ASSERT_WIN32_SUCCESS(a_Expr) \
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync supR3HardenedFatal("%s: %s -> %#x\n", __FUNCTION__, #a_Expr, GetLastError()); \
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync } while (0)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/*******************************************************************************
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync* Structures and Typedefs *
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync*******************************************************************************/
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Security descriptor cleanup structure.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/** Pointer to security cleanup structure. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Image verifier cache entry.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** Pointer to the next entry with the same hash value. */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync /** Next entry in the WinVerifyTrust todo list. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** The file handle. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** If fIndexNumber is set, this is an file system internal file identifier. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** The path hash value. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** The verification result. */
eb259de2a9eac4b4dda56e89f5004671f926bd9bvboxsync /** Used for shutting up errors after a while. */
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync /** The validation flags (for WinVerifyTrust retry). */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** Whether IndexNumber is valid */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync /** Whether verified by WinVerifyTrust. */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync bool volatile fWinVerifyTrust;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** cwcPath * sizeof(RTUTF16). */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** The full path of this entry (variable size). */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/** Pointer to an image verifier path entry. */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Name of an import DLL that we need to check out.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync /** Pointer to the next DLL in the list. */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync /** The length of pwszAltSearchDir if available. */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync /** This points the directory containing the DLL needing it, this will be
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * NULL for a System32 DLL. */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync /** The name of the import DLL (variable length). */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync/** Pointer to a import DLL that needs checking out. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/*******************************************************************************
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync* Global Variables *
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync*******************************************************************************/
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/** @name Global variables initialized by suplibHardenedWindowsMain.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/** Combined windows NT version number. See SUP_MAKE_NT_VER_COMBINED. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/** Count calls to the special main function for linking santity checks. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic uint32_t volatile g_cSuplibHardenedWindowsMainCalls;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/** The UTF-16 windows path to the executable. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/** The NT path of the executable. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/** The offset into g_SupLibHardenedExeNtPath of the executable name (WCHAR,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * not byte). This also gives the length of the exectuable directory path,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * including a trailing slash. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/** @name Hook related variables.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/** The jump back address of the patched NtCreateSection. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncextern "C" PFNRT g_pfnNtCreateSectionJmpBack = NULL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/** Pointer to the bit of assembly code that will perform the original
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * NtCreateSection operation. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic NTSTATUS (NTAPI * g_pfnNtCreateSectionReal)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES,
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync/** The jump back address of the patched LdrLoadDll. */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync/** Pointer to the bit of assembly code that will perform the original
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * LdrLoadDll operation. */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsyncstatic NTSTATUS (NTAPI * g_pfnLdrLoadDllReal)(PWSTR, PULONG, PUNICODE_STRING, PHANDLE);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/** The hash table of verifier cache . */
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsyncstatic PVERIFIERCACHEENTRY volatile g_apVerifierCache[128];
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync/** Queue of cached images which needs WinVerifyTrust to check them. */
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsyncstatic PVERIFIERCACHEENTRY volatile g_pVerifierCacheTodoWvt = NULL;
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync/** Queue of cached images which needs their imports checked. */
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsyncstatic PVERIFIERCACHEIMPORT volatile g_pVerifierCacheTodoImports = NULL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/** Static error info structure used during init. */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync/** In the assembly file. */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsyncextern "C" uint8_t g_abSupHardReadWriteExecPage[PAGE_SIZE];
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync/** Whether we've patched our own LdrInitializeThunk or not. We do this to
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * disable thread creation. */
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync/** The backup of our own LdrInitializeThunk code, for enabling and disabling
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * thread creation in this process. */
beed5fc4d17b85d6d05516ae63e6308af82ad96fvboxsync/** Mask of adversaries that we've detected (SUPHARDNT_ADVERSARY_XXX). */
beed5fc4d17b85d6d05516ae63e6308af82ad96fvboxsync/** @name SUPHARDNT_ADVERSARY_XXX - Adversaries
beed5fc4d17b85d6d05516ae63e6308af82ad96fvboxsync/** Symantec endpoint protection or similar including SysPlant.sys. */
beed5fc4d17b85d6d05516ae63e6308af82ad96fvboxsync#define SUPHARDNT_ADVERSARY_SYMANTEC_SYSPLANT RT_BIT_32(0)
100b161379af7255c69e27587cc746e5f76ff050vboxsync/** Symantec Norton 360. */
100b161379af7255c69e27587cc746e5f76ff050vboxsync#define SUPHARDNT_ADVERSARY_SYMANTEC_N360 RT_BIT_32(1)
beed5fc4d17b85d6d05516ae63e6308af82ad96fvboxsync/** Avast! */
100b161379af7255c69e27587cc746e5f76ff050vboxsync/** TrendMicro OfficeScan and probably others. */
100b161379af7255c69e27587cc746e5f76ff050vboxsync/** McAfee. */
100b161379af7255c69e27587cc746e5f76ff050vboxsync/** Kaspersky. */
100b161379af7255c69e27587cc746e5f76ff050vboxsync/** Malwarebytes Anti-Malware (MBAM). */
100b161379af7255c69e27587cc746e5f76ff050vboxsync/** AVG Internet Security. */
100b161379af7255c69e27587cc746e5f76ff050vboxsync/** Panda Security. */
100b161379af7255c69e27587cc746e5f76ff050vboxsync/** Microsoft Security Essentials. */
beed5fc4d17b85d6d05516ae63e6308af82ad96fvboxsync/** Unknown adversary detected while waiting on child. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/*******************************************************************************
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync* Internal Functions *
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync*******************************************************************************/
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsyncstatic NTSTATUS supR3HardenedScreenImage(HANDLE hFile, bool fImage, PULONG pfAccess, PULONG pfProtect,
eb259de2a9eac4b4dda56e89f5004671f926bd9bvboxsync bool *pfCallRealApi, const char *pszCaller, bool fAvoidWinVerifyTrust,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync# define SYSCALL(a_Num) DECLASM(void) RT_CONCAT(supR3HardenedJmpBack_NtCreateSection_,a_Num)(void)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync# include "NtCreateSection-template-amd64-syscall-type-1.h"
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync# define SYSCALL(a_Num) DECLASM(void) RT_CONCAT(supR3HardenedJmpBack_NtCreateSection_,a_Num)(void)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync# include "NtCreateSection-template-x86-syscall-type-1.h"
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Simple wide char search routine.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @returns Pointer to the first location of @a wcNeedle in @a pwszHaystack.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * NULL if not found.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param pwszHaystack Pointer to the string that should be searched.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param wcNeedle The character to search for.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic PRTUTF16 suplibHardenedWStrChr(PCRTUTF16 pwszHaystack, RTUTF16 wcNeedle)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Simple wide char string length routine.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @returns The number of characters in the given string. (Excludes the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * terminator.)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param pwsz The string.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Allocate zero filled memory on the heap.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @returns Pointer to the memory. Will never return NULL, triggers a fatal
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * error instead.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param cb The number of bytes to allocate.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync void *pv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync supR3HardenedFatal("HeapAlloc failed to allocate %zu bytes.\n", cb);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Reallocates memory on the heap.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @returns Pointer to the resized memory block. Will never return NULL,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * triggers a fatal error instead.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param pvOld The old memory block.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param cbNew The new block size.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncDECLHIDDEN(void *) suplibHardenedReAlloc(void *pvOld, size_t cbNew)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync void *pv = HeapReAlloc(GetProcessHeap(), 0 /*dwFlags*/, pvOld, cbNew);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync supR3HardenedFatal("HeapReAlloc failed to allocate %zu bytes.\n", cbNew);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Frees memory allocated by suplibHardenedAlloc, suplibHardenedAllocZ or
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * suplibHardenedReAlloc.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param pv Pointer to the memeory to be freed.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Wrapper around LoadLibraryEx that deals with the UTF-8 to UTF-16 conversion
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * and supplies the right flags.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @returns Module handle on success, NULL on failure.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param pszName The full path to the DLL.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param fSystem32Only Whether to only look for imports in the system32
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * directory. If set to false, the application
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * directory is also searched.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncDECLHIDDEN(void *) supR3HardenedWinLoadLibrary(const char *pszName, bool fSystem32Only)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync int rc = RTStrToUtf16Ex(pszName, RTSTR_MAX, &pwszPath, RT_ELEMENTS(wszPath), NULL);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync void *pvRet = (void *)LoadLibraryExW(wszPath, NULL /*hFile*/, fFlags);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Vista, W7, W2K8R might not work without KB2533623, so retry with no flags. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pvRet = (void *)LoadLibraryExW(wszPath, NULL /*hFile*/, 0);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync supR3HardenedFatal("RTStrToUtf16Ex failed on '%s': %Rrc", pszName, rc);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Gets the internal index number of the file.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @returns True if we got an index number, false if not.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param hFile The file in question.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param pIndexNumber where to return the index number.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic bool supR3HardenedWinVerifyCacheGetIndexNumber(HANDLE hFile, PLARGE_INTEGER pIndexNumber)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync NTSTATUS rcNt = NtQueryInformationFile(hFile, &Ios, pIndexNumber, sizeof(*pIndexNumber), FileInternalInformation);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return NT_SUCCESS(rcNt) && pIndexNumber->QuadPart != 0;
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Calculates the hash value for the given UTF-16 path string.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @returns Hash value.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param pUniStr String to hash.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic uint32_t supR3HardenedWinVerifyCacheHashPath(PCUNICODE_STRING pUniStr)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync unsigned cwcLeft = pUniStr->Length / sizeof(WCHAR);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync while (cwcLeft-- > 0)
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Calculates the hash value for a directory + filename combo as if they were
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * one single string.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * @returns Hash value.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * @param pawcDir The directory name.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * @param cwcDir The length of the directory name. RTSTR_MAX if
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * not available.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * @param pszName The import name (UTF-8).
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsyncstatic uint32_t supR3HardenedWinVerifyCacheHashDirAndFile(PCRTUTF16 pawcDir, uint32_t cwcDir, const char *pszName)
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync while (cwcDir-- > 0)
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Verify string cache compare function.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * @returns true if the strings match, false if not.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * @param pawcLeft The left hand string.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * @param pawcRight The right hand string.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * @param cwcToCompare The number of chars to compare.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsyncstatic bool supR3HardenedWinVerifyCacheIsMatch(PCRTUTF16 pawcLeft, PCRTUTF16 pawcRight, uint32_t cwcToCompare)
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync /* Try a quick memory compare first. */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync if (memcmp(pawcLeft, pawcRight, cwcToCompare * sizeof(RTUTF16)) == 0)
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync return true;
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync /* Slow char by char compare. */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync while (cwcToCompare-- > 0)
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync wcLeft = wcLeft != '/' ? RT_C_TO_LOWER(wcLeft) : '\\';
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync wcLeft = wcRight != '/' ? RT_C_TO_LOWER(wcRight) : '\\';
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync return false;
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync return true;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Inserts the given verifier result into the cache.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param pUniStr The full path of the image.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param hFile The file handle - must either be entered into
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * the cache or closed.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param rc The verifier result.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * @param fWinVerifyTrust Whether verified by WinVerifyTrust or not.
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync * @param fFlags The image verification flags.
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsyncstatic void supR3HardenedWinVerifyCacheInsert(PCUNICODE_STRING pUniStr, HANDLE hFile, int rc,
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Allocate and initalize a new entry.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync PVERIFIERCACHEENTRY pEntry = (PVERIFIERCACHEENTRY)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync pEntry->uHash = supR3HardenedWinVerifyCacheHashPath(pUniStr);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync memcpy(pEntry->wszPath, pUniStr->Buffer, pUniStr->Length);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync pEntry->wszPath[pUniStr->Length / sizeof(WCHAR)] = '\0';
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync pEntry->fIndexNumberValid = supR3HardenedWinVerifyCacheGetIndexNumber(hFile, &pEntry->IndexNumber);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Try insert it, careful with concurrent code as well as potential duplicates.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync uint32_t iHashTab = pEntry->uHash % RT_ELEMENTS(g_apVerifierCache);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync VERIFIERCACHEENTRY * volatile *ppEntry = &g_apVerifierCache[iHashTab];
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync while (!ASMAtomicCmpXchgPtr(&g_pVerifierCacheTodoWvt, pEntry, pEntry->pNextTodoWvt));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheInsert: %ls\n", pUniStr->Buffer));
e17f6f8a70a7709a9a6319d9a473596fb600b552vboxsync && supR3HardenedWinVerifyCacheIsMatch(pOther->wszPath, pEntry->wszPath, pEntry->cbPath / sizeof(RTUTF16)))
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync /* Duplicate entry (may happen due to races). */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync HeapFree(GetProcessHeap(), 0 /* dwFlags*/, pEntry);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Looks up an entry in the verifier hash table.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @return Pointer to the entry on if found, NULL if not.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param pUniStr The full path of the image.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param hFile The file handle.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic PVERIFIERCACHEENTRY supR3HardenedWinVerifyCacheLookup(PCUNICODE_STRING pUniStr, HANDLE hFile)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uint32_t uHash = supR3HardenedWinVerifyCacheHashPath(pUniStr);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uint32_t iHashTab = uHash % RT_ELEMENTS(g_apVerifierCache);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PVERIFIERCACHEENTRY pCur = g_apVerifierCache[iHashTab];
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync && supR3HardenedWinVerifyCacheIsMatch(pCur->wszPath, pwszPath, cbPath / sizeof(RTUTF16)))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync bool fIndexNumberValid = supR3HardenedWinVerifyCacheGetIndexNumber(hFile, &IndexNumber);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync && IndexNumber.QuadPart == pCur->IndexNumber.QuadPart)
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Looks up an import DLL in the verifier hash table.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * @return Pointer to the entry on if found, NULL if not.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * @param pawcDir The directory name.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * @param cwcDir The length of the directory name.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * @param pszName The import name (UTF-8).
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsyncstatic PVERIFIERCACHEENTRY supR3HardenedWinVerifyCacheLookupImport(PCRTUTF16 pawcDir, uint32_t cwcDir, const char *pszName)
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync uint32_t uHash = supR3HardenedWinVerifyCacheHashDirAndFile(pawcDir, cwcDir, pszName);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync uint32_t iHashTab = uHash % RT_ELEMENTS(g_apVerifierCache);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync uint32_t const cbPath = (uint32_t)((cwcDir + 1 + strlen(pszName)) * sizeof(RTUTF16));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync PVERIFIERCACHEENTRY pCur = g_apVerifierCache[iHashTab];
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync if (supR3HardenedWinVerifyCacheIsMatch(pCur->wszPath, pawcDir, cwcDir))
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync if (pCur->wszPath[cwcDir] == '\\' || pCur->wszPath[cwcDir] == '/')
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync if (RTUtf16ICmpAscii(&pCur->wszPath[cwcDir + 1], pszName))
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Schedules the import DLLs for verification and entry into the cache.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * @param hLdrMod The loader module which imports should be
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * scheduled for verification.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * @param pwszName The full NT path of the module.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsyncDECLHIDDEN(void) supR3HardenedWinVerifyCacheScheduleImports(RTLDRMOD hLdrMod, PCRTUTF16 pwszName)
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Any imports?
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync int rc = RTLdrQueryPropEx(hLdrMod, RTLDRPROP_IMPORT_COUNT, NULL /*pvBits*/, &cImports, sizeof(cImports), NULL);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Figure out the DLL directory from pwszName.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync if ((wc == '\\' || wc == '/' || wc == ':') && cwcDir + 2 != i)
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync if ( g_System32NtPath.UniStr.Length / sizeof(WCHAR) == cwcDir
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync && supR3HardenedWinVerifyCacheIsMatch(pawcDir, g_System32NtPath.UniStr.Buffer, cwcDir))
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Enumerate the imports.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync for (i = 0; i < cImports; i++)
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync rc = RTLdrQueryPropEx(hLdrMod, RTLDRPROP_IMPORT_MODULE, NULL /*pvBits*/, &uBuf, sizeof(uBuf), NULL);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Skip kernel32, ntdll and API set stuff.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync || RTStrNCmp(uBuf.szName, RT_STR_TUPLE("api-ms-win-")) == 0 )
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Skip to the next one if it's already in the cache.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync if (supR3HardenedWinVerifyCacheLookupImport(g_System32NtPath.UniStr.Buffer,
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheScheduleImports: '%s' cached for system32\n", uBuf.szName));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync if (supR3HardenedWinVerifyCacheLookupImport(g_SupLibHardenedExeNtPath.UniStr.Buffer,
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheScheduleImports: '%s' cached for appdir\n", uBuf.szName));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync if (pawcDir && supR3HardenedWinVerifyCacheLookupImport(pawcDir, cwcDir, uBuf.szName) != NULL)
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheScheduleImports: '%s' cached for dll dir\n", uBuf.szName));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync /* We could skip already scheduled modules, but that'll require serialization and extra work... */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Add it to the todo list.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheScheduleImports: Import todo: #%u '%s'.\n", i, uBuf.szName));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync uint32_t cbName = (uint32_t)strlen(uBuf.szName) + 1;
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync uint32_t cbNameAligned = RT_ALIGN_32(cbName, sizeof(RTUTF16));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync uint32_t cbNeeded = RT_OFFSETOF(VERIFIERCACHEIMPORT, szName[cbNameAligned])
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync PVERIFIERCACHEIMPORT pImport = (PVERIFIERCACHEIMPORT)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNeeded);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync /* Init it. */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync pImport->pwszAltSearchDir = (PRTUTF16)&pImport->szName[cbNameAligned];
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync memcpy(pImport->pwszAltSearchDir, pawcDir, cwcDir * sizeof(RTUTF16));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync /* Insert it. */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync while (!ASMAtomicCmpXchgPtr(&g_pVerifierCacheTodoImports, pImport, pImport->pNext));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUP_DPRINTF(("RTLDRPROP_IMPORT_MODULE failed with rc=%Rrc i=%#x on '%ls'\n", rc, i, pwszName));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUP_DPRINTF(("RTLDRPROP_IMPORT_COUNT failed with rc=%Rrc on '%ls'\n", rc, pwszName));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Processes the list of import todos.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsyncstatic void supR3HardenedWinVerifyCacheProcessImportTodos(void)
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Work until we've got nothing more todo.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync PVERIFIERCACHEIMPORT pTodo = ASMAtomicXchgPtrT(&g_pVerifierCacheTodoImports, NULL, PVERIFIERCACHEIMPORT);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Not in the cached already?
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync if ( !supR3HardenedWinVerifyCacheLookupImport(g_System32NtPath.UniStr.Buffer,
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync && !supR3HardenedWinVerifyCacheLookupImport(g_SupLibHardenedExeNtPath.UniStr.Buffer,
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync || !supR3HardenedWinVerifyCacheLookupImport(pCur->pwszAltSearchDir, pCur->cwcAltSearchDir, pCur->szName)) )
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Try locate the imported DLL and open it.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: Processing '%s'...\n", pCur->szName));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync RTUTF16 wszPath[260 + 260]; /* Assumes we've limited the import name length to 256. */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync AssertCompile(sizeof(wszPath) > sizeof(g_System32NtPath));
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync * Check for DLL isolation / redirection / mapping.
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync int rc = RTStrToUtf16Ex(pCur->szName, RTSTR_MAX, &pwszName, cwcName, &cwcName);
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync UniStrName.Length = (USHORT)cwcName * sizeof(WCHAR);
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync UniStrName.MaximumLength = UniStrName.Length + sizeof(WCHAR);
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync UniStrStatic.MaximumLength = (USHORT)(sizeof(wszPath) - cwcName * sizeof(WCHAR) - sizeof(WCHAR));
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync static UNICODE_STRING const s_DefaultSuffix = RTNT_CONSTANT_UNISTR(L".dll");
100b161379af7255c69e27587cc746e5f76ff050vboxsync rcNtRedir = RtlDosApplyFileIsolationRedirection_Ustr(1 /*fFlags*/,
100b161379af7255c69e27587cc746e5f76ff050vboxsync IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync InitializeObjectAttributes(&ObjAttr, pUniStrResult,
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync 0 /*EaLength*/);
100b161379af7255c69e27587cc746e5f76ff050vboxsync /* For accurate logging. */
100b161379af7255c69e27587cc746e5f76ff050vboxsync size_t cwcCopy = RT_MIN(pUniStrResult->Length / sizeof(RTUTF16), RT_ELEMENTS(wszPath) - 1);
100b161379af7255c69e27587cc746e5f76ff050vboxsync memcpy(wszPath, pUniStrResult->Buffer, cwcCopy * sizeof(RTUTF16));
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: RTStrToUtf16Ex #1 failed: %Rrc\n", rc));
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync * If not something that gets remapped, do the half normal searching we need.
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync { g_System32NtPath.UniStr.Buffer, g_System32NtPath.UniStr.Length / sizeof(WCHAR) },
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync { g_SupLibHardenedExeNtPath.UniStr.Buffer, g_offSupLibHardenedExeNtName - 1 },
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync /* Search System32 first, unless it's a 'V*' or 'm*' name, the latter for msvcrt. */
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync if (aDirs[i].pawcDir && aDirs[i].cwcDir && aDirs[i].cwcDir < RT_ELEMENTS(wszPath) / 3 * 2)
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync memcpy(wszPath, aDirs[i].pawcDir, aDirs[i].cwcDir * sizeof(RTUTF16));
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync rc = RTStrToUtf16Ex(pCur->szName, RTSTR_MAX, &pwszName, cwcName, &cwcName);
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync NtName.Length = (USHORT)((cwc + cwcName) * sizeof(WCHAR));
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync NtName.MaximumLength = NtName.Length + sizeof(WCHAR);
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync 0 /*EaLength*/);
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: RTStrToUtf16Ex #2 failed: %Rrc\n", rc));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * If we successfully opened it, verify it and cache the result.
100b161379af7255c69e27587cc746e5f76ff050vboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: '%s' -> '%ls' [rcNtRedir=%#x]\n",
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync bool fCallRealApi = false;
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync rcNt = supR3HardenedScreenImage(hFile, true /*fImage*/, &fAccess, &fProtect, &fCallRealApi,
eb259de2a9eac4b4dda56e89f5004671f926bd9bvboxsync "Imports", false /*fAvoidWinVerifyTrust*/, NULL /*pfQuietFailure*/);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: Failed to locate '%s'\n", pCur->szName));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: '%s' is in the cache.\n", pCur->szName));
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync * Processes the list of WinVerifyTrust todos.
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsyncstatic void supR3HardenedWinVerifyCacheProcessWvtTodos(void)
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync PVERIFIERCACHEENTRY volatile *ppReschedLastNext = NULL;
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync * Work until we've got nothing more todo.
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync PVERIFIERCACHEENTRY pTodo = ASMAtomicXchgPtrT(&g_pVerifierCacheTodoWvt, NULL, PVERIFIERCACHEENTRY);
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync int rc = supHardenedWinVerifyImageTrust(pCur->hFile, pCur->wszPath, pCur->fFlags, pCur->rc,
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessWvtTodos: %d (was %d) fWinVerifyTrust=%d for '%ls'\n",
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync /* Retry it at a later time. */
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessWvtTodos: %d (was %d) fWinVerifyTrust=%d for '%ls' [rescheduled]\n",
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync /* else: already processed. */
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync * Anything to reschedule.
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync while (!ASMAtomicCmpXchgPtr(&g_pVerifierCacheTodoWvt, pReschedule, *ppReschedLastNext));
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync * Checks whether the path could be containing alternative 8.3 names generated
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync * by NTFS, FAT, or other similar file systems.
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync * @returns Pointer to the first component that might be an 8.3 name, NULL if
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync * not 8.3 path.
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync * @param pwszPath The path to check.
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsyncstatic PRTUTF16 supR3HardenedWinIsPossible8dot3Path(PCRTUTF16 pwszPath)
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync /* Could check more here before jumping to conclusions... */
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync else if (wc == 0)
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync * Fixes up a path possibly containing one or more alternative 8-dot-3 style
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync * components.
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync * The path is fixed up in place. Errors are ignored.
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync * @param hFile The handle to the file which path we're fixing up.
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync * @param pUniStr The path to fix up. MaximumLength is the max buffer
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsyncstatic void supR3HardenedWinFix8dot3Path(HANDLE hFile, PUNICODE_STRING pUniStr)
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync * We could use FileNormalizedNameInformation here and slap the volume device
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync * path in front of the result, but it's only supported since windows 8.0
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync * according to some docs... So we expand all supicious names.
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync pwszFix = supR3HardenedWinIsPossible8dot3Path(pwszFix);
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync while ((wc = *pwszFixEnd) != '\0' && wc != '\\' && wc != '//')
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync NtDir.Length = NtDir.MaximumLength = (USHORT)((pwszFix - pUniStr->Buffer) * sizeof(WCHAR));
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync InitializeObjectAttributes(&ObjAttr, &NtDir, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync 0 /*EaLength*/);
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync uint8_t abBuffer[sizeof(FILE_BOTH_DIR_INFORMATION) + 2048 * sizeof(WCHAR)];
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync NtFilterStr.Length = (USHORT)((uintptr_t)pwszFixEnd - (uintptr_t)pwszFix);
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync if (NT_SUCCESS(rcNt) && uBuf.Info.NextEntryOffset == 0) /* There shall only be one entry matching... */
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync uint32_t offName = uBuf.Info.FileNameLength / sizeof(WCHAR);
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync while (offName > 0 && uBuf.Info.FileName[offName - 1] != '\\' && uBuf.Info.FileName[offName - 1] != '/')
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync uint32_t cwcNameNew = (uBuf.Info.FileNameLength / sizeof(WCHAR)) - offName;
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync memcpy(pwszFix, &uBuf.Info.FileName[offName], cwcNameNew * sizeof(WCHAR));
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync else if ( pUniStr->Length + cwcNameNew * sizeof(WCHAR) - cwcNameOld * sizeof(WCHAR) + sizeof(WCHAR)
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync size_t cwcLeft = pUniStr->Length - (pwszFixEnd - pUniStr->Buffer) * sizeof(WCHAR) + sizeof(WCHAR);
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync memmove(&pwszFix[cwcNameNew], pwszFixEnd, cwcLeft * sizeof(WCHAR));
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync pUniStr->Length -= (USHORT)(cwcNameOld * sizeof(WCHAR));
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync pUniStr->Length += (USHORT)(cwcNameNew * sizeof(WCHAR));
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync memcpy(pwszFix, &uBuf.Info.FileName[offName], cwcNameNew * sizeof(WCHAR));
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync /* else: ignore overflow. */
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync /* else: ignore failure. */
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync /* Advance */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsyncstatic NTSTATUS supR3HardenedScreenImage(HANDLE hFile, bool fImage, PULONG pfAccess, PULONG pfProtect,
eb259de2a9eac4b4dda56e89f5004671f926bd9bvboxsync bool *pfCallRealApi, const char *pszCaller, bool fAvoidWinVerifyTrust,
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * Query the name of the file, making sure to zero terminator the
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * string. (2nd half of buffer is used for error info, see below.)
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync uint8_t abBuffer[sizeof(UNICODE_STRING) + 2048 * sizeof(WCHAR)];
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync NTSTATUS rcNt = NtQueryObject(hFile, ObjectNameInformation, &uBuf, sizeof(uBuf) - sizeof(WCHAR) - 128, &cbNameBuf);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync "supR3HardenedScreenImage/%s: NtQueryObject -> %#x (fImage=%d fProtect=%#x fAccess=%#x)\n",
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync if (supR3HardenedWinIsPossible8dot3Path(uBuf.UniStr.Buffer))
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * Check the cache.
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync PVERIFIERCACHEENTRY pCacheHit = supR3HardenedWinVerifyCacheLookup(&uBuf.UniStr, hFile);
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync /* If we haven't done the WinVerifyTrust thing, do it if we can. */
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync SUP_DPRINTF(("supR3HardenedScreenImage/%s: cache hit (%Rrc) on %ls [redoing WinVerifyTrust]\n",
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync int rc = supHardenedWinVerifyImageTrust(pCacheHit->hFile, pCacheHit->wszPath, pCacheHit->fFlags, pCacheHit->rc,
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync SUP_DPRINTF(("supR3HardenedScreenImage/%s: %d (was %d) fWinVerifyTrust=%d for '%ls'\n",
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync pszCaller, rc, pCacheHit->rc, fWinVerifyTrust, pCacheHit->wszPath));
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync SUP_DPRINTF(("supR3HardenedScreenImage/%s: WinVerifyTrust not available, rescheduling %ls\n",
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync SUP_DPRINTF(("supR3HardenedScreenImage/%s: cache hit (%Rrc) on %ls [avoiding WinVerifyTrust]\n",
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync SUP_DPRINTF(("supR3HardenedScreenImage/%s: cache hit (%Rrc) on %ls%s\n",
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync pszCaller, pCacheHit->rc, pCacheHit->wszPath, pCacheHit->fWinVerifyTrust ? "" : " [lacks WinVerifyTrust]"));
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync /* Return the cached value. */
eb259de2a9eac4b4dda56e89f5004671f926bd9bvboxsync uint32_t cErrorHits = ASMAtomicIncU32(&pCacheHit->cErrorHits);
eb259de2a9eac4b4dda56e89f5004671f926bd9bvboxsync "supR3HardenedScreenImage/%s: cached rc=%Rrc fImage=%d fProtect=%#x fAccess=%#x cErrorHits=%u %ls\n",
eb259de2a9eac4b4dda56e89f5004671f926bd9bvboxsync pszCaller, pCacheHit->rc, fImage, *pfProtect, *pfAccess, cErrorHits, uBuf.UniStr.Buffer);
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * On XP the loader might hand us handles with just FILE_EXECUTE and
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * SYNCHRONIZE, the means reading will fail later on. Also, we need
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * READ_CONTROL access to check the file ownership later on, and non
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * of the OS versions seems be giving us that. So, in effect we
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * more or less always reopen the file here.
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync rcNt = NtDuplicateObject(NtCurrentProcess(), hFile, NtCurrentProcess(),
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync InitializeObjectAttributes(&ObjAttr, &uBuf.UniStr, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync 0 /*EaLength*/);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync "supR3HardenedScreenImage/%s: Failed to duplicate and open the file: rcNt=%#x hFile=%p %ls\n",
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync /* Check that we've got the same file. */
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync bool fMyValid = supR3HardenedWinVerifyCacheGetIndexNumber(hMyFile, &idMyFile);
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync bool fInValid = supR3HardenedWinVerifyCacheGetIndexNumber(hFile, &idInFile);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync "supR3HardenedScreenImage/%s: Re-opened has different ID that input: %#llx vx %#llx (%ls)\n",
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync pszCaller, rcNt, idMyFile.QuadPart, idInFile.QuadPart, uBuf.UniStr.Buffer);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUP_DPRINTF(("supR3HardenedScreenImage/%s: NtDuplicateObject -> %#x\n", pszCaller, rcNt));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync "supR3HardenedScreenImage/%s: NtDuplicateObject(,%#x,) failed: %#x\n", pszCaller, hFile, rcNt);
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * Special Kludge for Windows XP and W2K3 and their stupid attempts
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * at mapping a hidden XML file called c:\Windows\WindowsShell.Manifest
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * with executable access. The image bit isn't set, fortunately.
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync && uBuf.UniStr.Length > g_System32NtPath.UniStr.Length - sizeof(L"System32") + sizeof(WCHAR)
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync && memcmp(uBuf.UniStr.Buffer, g_System32NtPath.UniStr.Buffer,
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync g_System32NtPath.UniStr.Length - sizeof(L"System32") + sizeof(WCHAR)) == 0)
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync PRTUTF16 pwszName = &uBuf.UniStr.Buffer[(g_System32NtPath.UniStr.Length - sizeof(L"System32") + sizeof(WCHAR)) / sizeof(WCHAR)];
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync if (RTUtf16ICmpAscii(pwszName, "WindowsShell.Manifest") == 0)
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * Drop all executable access to the mapping and let it continue.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUP_DPRINTF(("supR3HardenedScreenImage/%s: Applying the drop-exec-kludge for '%ls'\n", pszCaller, uBuf.UniStr.Buffer));
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync *pfAccess = (*pfAccess & ~SECTION_MAP_EXECUTE) | SECTION_MAP_READ;
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync *pfProtect = (*pfProtect & ~PAGE_EXECUTE) | PAGE_READONLY;
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync *pfProtect = (*pfProtect & ~UINT32_C(0xf0)) | ((*pfProtect & UINT32_C(0xe0)) >> 4);
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * Check the path. We don't allow DLLs to be loaded from just anywhere:
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * 1. System32 - normal code or cat signing, owner TrustedInstaller.
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * 2. WinSxS - normal code or cat signing, owner TrustedInstaller.
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * 3. VirtualBox - kernel code signing and integrity checks.
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * 4. AppPatchDir - normal code or cat signing, owner TrustedInstaller.
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * 5. Program Files - normal code or cat signing, owner TrustedInstaller.
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * 6. Common Files - normal code or cat signing, owner TrustedInstaller.
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * 7. x86 variations of 4 & 5 - ditto.
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync Assert(g_SupLibHardenedExeNtPath.UniStr.Buffer[g_offSupLibHardenedExeNtName - 1] == '\\');
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_System32NtPath.UniStr, true /*fCheckSlash*/))
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync fFlags |= SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION | SUPHNTVI_F_TRUSTED_INSTALLER_OWNER;
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_WinSxSNtPath.UniStr, true /*fCheckSlash*/))
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync fFlags |= SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION | SUPHNTVI_F_TRUSTED_INSTALLER_OWNER;
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync else if (supHardViUtf16PathStartsWithEx(uBuf.UniStr.Buffer, uBuf.UniStr.Length / sizeof(WCHAR),
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync g_offSupLibHardenedExeNtName, false /*fCheckSlash*/))
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync fFlags |= SUPHNTVI_F_REQUIRE_KERNEL_CODE_SIGNING | SUPHNTVI_F_REQUIRE_SIGNATURE_ENFORCEMENT;
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync else if (supHardViIsAppPatchDir(uBuf.UniStr.Buffer, uBuf.UniStr.Length / sizeof(WCHAR)))
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync fFlags |= SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION | SUPHNTVI_F_TRUSTED_INSTALLER_OWNER;
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_ProgramFilesNtPath.UniStr, true /*fCheckSlash*/))
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync fFlags |= SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION | SUPHNTVI_F_TRUSTED_INSTALLER_OWNER;
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_CommonFilesNtPath.UniStr, true /*fCheckSlash*/))
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync fFlags |= SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION | SUPHNTVI_F_TRUSTED_INSTALLER_OWNER;
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_ProgramFilesX86NtPath.UniStr, true /*fCheckSlash*/))
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync fFlags |= SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION | SUPHNTVI_F_TRUSTED_INSTALLER_OWNER;
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_CommonFilesX86NtPath.UniStr, true /*fCheckSlash*/))
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync fFlags |= SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION | SUPHNTVI_F_TRUSTED_INSTALLER_OWNER;
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync /* Hack to allow profiling our code with Visual Studio. */
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync else if ( uBuf.UniStr.Length > sizeof(L"\\SamplingRuntime.dll")
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync && memcmp(uBuf.UniStr.Buffer + (uBuf.UniStr.Length - sizeof(L"\\SamplingRuntime.dll") + sizeof(WCHAR)) / sizeof(WCHAR),
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync L"\\SamplingRuntime.dll", sizeof(L"\\SamplingRuntime.dll") - sizeof(WCHAR)) == 0 )
90624af27b0e648b68167bd3b332d0e3b1d18ab1vboxsync "supR3HardenedScreenImage/%s: Not a trusted location: '%ls' (fImage=%d fProtect=%#x fAccess=%#x)\n",
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync pszCaller, uBuf.UniStr.Buffer, fImage, *pfAccess, *pfProtect);
cd2274c977e1b722b535e4f601a324e8029b5e43vboxsync#else /* VBOX_PERMIT_EVEN_MORE */
cd2274c977e1b722b535e4f601a324e8029b5e43vboxsync * Require trusted installer + some kind of signature on everything, except
cd2274c977e1b722b535e4f601a324e8029b5e43vboxsync * for the VBox bits where we require kernel code signing and special
cd2274c977e1b722b535e4f601a324e8029b5e43vboxsync * integrity checks.
cd2274c977e1b722b535e4f601a324e8029b5e43vboxsync Assert(g_SupLibHardenedExeNtPath.UniStr.Buffer[g_offSupLibHardenedExeNtName - 1] == '\\');
cd2274c977e1b722b535e4f601a324e8029b5e43vboxsync if (supHardViUtf16PathStartsWithEx(uBuf.UniStr.Buffer, uBuf.UniStr.Length / sizeof(WCHAR),
cd2274c977e1b722b535e4f601a324e8029b5e43vboxsync g_offSupLibHardenedExeNtName, false /*fCheckSlash*/))
cd2274c977e1b722b535e4f601a324e8029b5e43vboxsync fFlags |= SUPHNTVI_F_REQUIRE_KERNEL_CODE_SIGNING | SUPHNTVI_F_REQUIRE_SIGNATURE_ENFORCEMENT;
cd2274c977e1b722b535e4f601a324e8029b5e43vboxsync fFlags |= SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION | SUPHNTVI_F_TRUSTED_INSTALLER_OWNER;
cd2274c977e1b722b535e4f601a324e8029b5e43vboxsync#endif /* VBOX_PERMIT_EVEN_MORE */
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * Do the verification. For better error message we borrow what's
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * left of the path buffer for an RTERRINFO buffer.
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync RTErrInfoInit(&ErrInfo, (char *)&uBuf.abBuffer[cbNameBuf], sizeof(uBuf) - cbNameBuf);
cf0e96b2c5a08292c6d13e4fdcb2d9518d1983e8vboxsync rc = supHardenedWinVerifyImageByHandle(hMyFile, uBuf.UniStr.Buffer, fFlags, fAvoidWinVerifyTrust, &fWinVerifyTrust, &ErrInfo);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync "supR3HardenedScreenImage/%s: rc=%Rrc fImage=%d fProtect=%#x fAccess=%#x %ls: %s\n",
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync pszCaller, rc, fImage, *pfAccess, *pfProtect, uBuf.UniStr.Buffer, ErrInfo.pszMsg);
680c2aff33be2ee9340c8763a3cb5c218c352bcfvboxsync supR3HardenedWinVerifyCacheInsert(&uBuf.UniStr, hMyFile, rc, fWinVerifyTrust, fFlags);
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync * Insert into the cache.
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync supR3HardenedWinVerifyCacheInsert(&uBuf.UniStr, hMyFile, rc, fWinVerifyTrust, fFlags);
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * Preloads a file into the verify cache if possible.
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * This is used to avoid known cyclic LoadLibrary issues with WinVerifyTrust.
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * @param pwszName The name of the DLL to verify.
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsyncDECLHIDDEN(void) supR3HardenedWinVerifyCachePreload(PCRTUTF16 pwszName)
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync UniStr.Length = (USHORT)(RTUtf16Len(pwszName) * sizeof(WCHAR));
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync UniStr.MaximumLength = UniStr.Length + sizeof(WCHAR);
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync InitializeObjectAttributes(&ObjAttr, &UniStr, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync 0 /*EaLength*/);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCachePreload: Error %#x opening '%ls'.\n", rcNt, pwszName));
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync //SUP_DPRINTF(("supR3HardenedWinVerifyCachePreload: scanning %ls\n", pwszName));
eb259de2a9eac4b4dda56e89f5004671f926bd9bvboxsync supR3HardenedScreenImage(hFile, false, &fAccess, &fProtect, &fCallRealApi, "preload", false /*fAvoidWinVerifyTrust*/,
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync //SUP_DPRINTF(("supR3HardenedWinVerifyCachePreload: done %ls\n", pwszName));
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * Hook that monitors NtCreateSection calls.
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * @returns NT status code.
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * @param phSection Where to return the section handle.
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * @param fAccess The desired access.
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * @param pObjAttribs The object attributes (optional).
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * @param pcbSection The section size (optional).
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * @param fProtect The max section protection.
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * @param fAttribs The section attributes.
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync * @param hFile The file to create a section from (optional).
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsyncsupR3HardenedMonitor_NtCreateSection(PHANDLE phSection, ACCESS_MASK fAccess, POBJECT_ATTRIBUTES pObjAttribs,
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync PLARGE_INTEGER pcbSection, ULONG fProtect, ULONG fAttribs, HANDLE hFile)
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync bool const fImage = RT_BOOL(fAttribs & (SEC_IMAGE | SEC_PROTECTED_IMAGE));
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync bool const fExecMap = RT_BOOL(fAccess & SECTION_MAP_EXECUTE);
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync bool const fExecProt = RT_BOOL(fProtect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_WRITECOPY
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync //SUP_DPRINTF(("supR3HardenedMonitor_NtCreateSection: 1\n"));
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync NTSTATUS rcNt = supR3HardenedScreenImage(hFile, fImage, &fAccess, &fProtect, &fCallRealApi,
eb259de2a9eac4b4dda56e89f5004671f926bd9bvboxsync "NtCreateSection", true /*fAvoidWinVerifyTrust*/, NULL /*pfQuietFailure*/);
48e06e6a052c50ecf176f63f5537f80b544bf34avboxsync //SUP_DPRINTF(("supR3HardenedMonitor_NtCreateSection: 2 rcNt=%#x fCallRealApi=%#x\n", rcNt, fCallRealApi));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Call checked out OK, call the original.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return g_pfnNtCreateSectionReal(phSection, fAccess, pObjAttribs, pcbSection, fProtect, fAttribs, hFile);
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync * Helper for supR3HardenedMonitor_LdrLoadDll.
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync * @returns NT status code.
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync * @param pwszPath The path destination buffer.
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync * @param cwcPath The size of the path buffer.
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync * @param pUniStrResult The result string.
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync * @param pOrgName The orignal name (for errors).
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync * @param pcwc Where to return the actual length.
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsyncstatic NTSTATUS supR3HardenedCopyRedirectionResult(WCHAR *pwszPath, size_t cwcPath, PUNICODE_STRING pUniStrResult,
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync *pcwc = cwc = pUniStrResult->Length / sizeof(WCHAR);
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync "supR3HardenedMonitor_LdrLoadDll: Name too long: %.*ls -> %.*ls (RtlDosApplyFileIoslationRedirection_Ustr)\n",
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync pOrgName->Length / sizeof(WCHAR), pOrgName->Buffer,
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync pUniStrResult->Length / sizeof(WCHAR), pUniStrResult->Buffer);
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync memcpy(&pwszPath[0], pUniStrResult->Buffer, pUniStrResult->Length);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Hooks that intercepts LdrLoadDll calls.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Two purposes:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * -# Enforce our own search path restrictions.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * -# Prevalidate DLLs about to be loaded so we don't upset the loader data
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * by doing it from within the NtCreateSection hook (WinVerifyTrust
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * seems to be doing harm there on W7/32).
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * @param pwszSearchPath The search path to use.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * @param pfFlags Flags on input. DLL characteristics or something
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * on return?
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * @param pName The name of the module.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * @param phMod Where the handle of the loaded DLL is to be
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * returned to the caller.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsyncsupR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_STRING pName, PHANDLE phMod)
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync * Process WinVerifyTrust todo before and after.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Reject things we don't want to deal with.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync supR3HardenedError(VINF_SUCCESS, false, "supR3HardenedMonitor_LdrLoadDll: name is NULL or have a zero length.\n");
680c2aff33be2ee9340c8763a3cb5c218c352bcfvboxsync SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x (pName=%p)\n", STATUS_INVALID_PARAMETER, pName));
680c2aff33be2ee9340c8763a3cb5c218c352bcfvboxsync /*SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: pName=%.*ls *pfFlags=%#x pwszSearchPath=%p:%ls\n",
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync (unsigned)pName->Length / sizeof(WCHAR), pName->Buffer, pfFlags ? *pfFlags : UINT32_MAX, pwszSearchPath,
680c2aff33be2ee9340c8763a3cb5c218c352bcfvboxsync !((uintptr_t)pwszSearchPath & 1) && (uintptr_t)pwszSearchPath >= 0x2000U ? pwszSearchPath : L"<flags>"));*/
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Reject long paths that's close to the 260 limit without looking.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync supR3HardenedError(VINF_SUCCESS, false, "supR3HardenedMonitor_LdrLoadDll: too long name: %#x bytes\n", pName->Length);
90624af27b0e648b68167bd3b332d0e3b1d18ab1vboxsync SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", STATUS_NAME_TOO_LONG));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Absolute path?
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync static UNICODE_STRING const s_DefaultSuffix = RTNT_CONSTANT_UNISTR(L".dll");
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync UNICODE_STRING UniStrStatic = { 0, (USHORT)sizeof(wszPath) - sizeof(WCHAR), wszPath };
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync rcNt = RtlDosApplyFileIsolationRedirection_Ustr(1 /*fFlags*/,
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync rcNt = supR3HardenedCopyRedirectionResult(wszPath, RT_ELEMENTS(wszPath), pUniStrResult, pName, &cwc);
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", rcNt));
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync ResolvedName.Length = (USHORT)(cwc * sizeof(WCHAR));
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync ResolvedName.MaximumLength = ResolvedName.Length + sizeof(WCHAR);
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: '%.*ls' -> '%.*ls' [redir]\n",
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync (unsigned)pName->Length / sizeof(WCHAR), pName->Buffer,
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync ResolvedName.Length / sizeof(WCHAR), ResolvedName.Buffer, rcNt));
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync * Not an absolute path. Check if it's one of those special API set DLLs
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync * or something we're known to use but should be taken from WinSxS.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync else if (supHardViUtf16PathStartsWithEx(pName->Buffer, pName->Length / sizeof(WCHAR),
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Not an absolute path or special API set. There are two alternatives
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * now, either there is no path at all or there is a relative path. We
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * will resolve it to an absolute path in either case, failing the call
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync * if we can't.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync bool const fNeedDllSuffix = offLastDot == UINT32_MAX && offLastSlash == UINT32_MAX;
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync if (offLastDot != UINT32_MAX && offLastDot == cwcName - 1)
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Reject relative paths for now as they might be breakout attempts.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync "supR3HardenedMonitor_LdrLoadDll: relative name not permitted: %.*ls\n",
90624af27b0e648b68167bd3b332d0e3b1d18ab1vboxsync SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", STATUS_OBJECT_NAME_INVALID));
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync * Perform dll redirection to WinSxS such. We using an undocumented
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync * API here, which as always is a bit risky... ASSUMES that the API
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync * returns a full DOS path.
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync rcNt = RtlDosApplyFileIsolationRedirection_Ustr(1 /*fFlags*/,
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync rcNt = supR3HardenedCopyRedirectionResult(wszPath, RT_ELEMENTS(wszPath), pUniStrResult, pName, &cwc);
28a2653de6f80a4b1f000cfc52e1a04492d4c151vboxsync SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", rcNt));
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync * Search for the DLL. Only System32 is allowed as the target of
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync * a search on the API level, all VBox calls will have full paths.
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync cwc = GetSystemDirectoryW(wszPath, RT_ELEMENTS(wszPath) - 32);
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync "supR3HardenedMonitor_LdrLoadDll: GetSystemDirectoryW failed: %u\n", GetLastError());
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", STATUS_UNEXPECTED_IO_ERROR));
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync if (cwc + 1 + cwcName + fNeedDllSuffix * 4 >= RT_ELEMENTS(wszPath))
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync "supR3HardenedMonitor_LdrLoadDll: Name too long (system32): %.*ls\n", cwcName, pawcName);
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", STATUS_NAME_TOO_LONG));
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync memcpy(&wszPath[cwc], pawcName, cwcName * sizeof(WCHAR));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync ResolvedName.Length = (USHORT)(cwc * sizeof(WCHAR));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync ResolvedName.MaximumLength = ResolvedName.Length + sizeof(WCHAR);
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: '%.*ls' -> '%.*ls' [rcNt=%#x]\n",
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync (unsigned)pName->Length / sizeof(WCHAR), pName->Buffer,
817577d2c4d6dee709de7a92d3bb7d0aeedae9aevboxsync ResolvedName.Length / sizeof(WCHAR), ResolvedName.Buffer, rcNt));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Try open the file. If this fails, never mind, just pass it on to
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * the real API as we've replaced any searchable name with a full name
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * and the real API can come up with a fitting status code for it.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync HANDLE hFile = CreateFileW(wszPath, GENERIC_READ, FILE_SHARE_READ, NULL /*pSecurityAttributes*/,
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL /*hTemplateFile*/);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync bool fCallRealApi = false;
93e05ea894cefd56ca308d72372b4dd8045bd1eevboxsync rcNt = supR3HardenedScreenImage(hFile, true /*fImage*/, &fAccess, &fProtect, &fCallRealApi,
eb259de2a9eac4b4dda56e89f5004671f926bd9bvboxsync "LdrLoadDll", false /*fAvoidWinVerifyTrust*/, &fQuietFailure);
eb259de2a9eac4b4dda56e89f5004671f926bd9bvboxsync supR3HardenedError(VINF_SUCCESS, false, "supR3HardenedMonitor_LdrLoadDll: rejecting '%ls': rcNt=%#x\n",
eb259de2a9eac4b4dda56e89f5004671f926bd9bvboxsync SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x '%ls'\n", rcNt, wszPath));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: error opening '%ls': %u\n", wszPath, dwErr));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Screened successfully enough. Call the real thing.
680c2aff33be2ee9340c8763a3cb5c218c352bcfvboxsync SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: pName=%.*ls *pfFlags=%#x pwszSearchPath=%p:%ls [calling]\n",
680c2aff33be2ee9340c8763a3cb5c218c352bcfvboxsync (unsigned)pName->Length / sizeof(WCHAR), pName->Buffer, pfFlags ? *pfFlags : UINT32_MAX, pwszSearchPath,
680c2aff33be2ee9340c8763a3cb5c218c352bcfvboxsync !((uintptr_t)pwszSearchPath & 1) && (uintptr_t)pwszSearchPath >= 0x2000U ? pwszSearchPath : L"<flags>"));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync rcNt = g_pfnLdrLoadDllReal(pwszSearchPath, pfFlags, pName, phMod);
90624af27b0e648b68167bd3b332d0e3b1d18ab1vboxsync * Log the result and process pending WinVerifyTrust work if we can.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x hMod=%p '%ls'\n", rcNt, *phMod, wszPath));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x '%ls'\n", rcNt, wszPath));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Tries to allocate memory between @a uStart and @a uEnd.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @returns Pointer to the memory on success. NULL on failure.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param uStart The start address.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param uEnd The end address. This is lower than @a uStart
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * if @a iDirection is negative, and higher if
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * positive.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param iDirection The search direction.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param cbAlloc The number of bytes to allocate.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic void *supR3HardenedWinAllocHookMemory(uintptr_t uStart, uintptr_t uEnd, intptr_t iDirection, size_t cbAlloc)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync size_t const uAllocGranularityMask = ~(cbAllocGranularity - 1);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Make uEnd the last valid return address.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Search for free memory.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Examine the memory at this address, if it's free, try make the allocation here.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync SUPR3HARDENED_ASSERT_NT_SUCCESS(NtQueryVirtualMemory(hProc,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync SUPR3HARDENED_ASSERT((uintptr_t)MemInfo.BaseAddress <= uCur);
fd658895339cb48b2ba581b1a1141aea39009ff7vboxsync NTSTATUS rcNt = NtAllocateVirtualMemory(hProc, &pvMem, 0 /*ZeroBits*/, &cbAlloc,
fd658895339cb48b2ba581b1a1141aea39009ff7vboxsync NtFreeVirtualMemory(hProc, &pvMem, &cbMem, MEM_RELEASE);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Advance within the free area and try again? */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uintptr_t uNext = iDirection > 0 ? uCur + cbAllocGranularity : uCur - cbAllocGranularity;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync || uNext - (uintptr_t)MemInfo.BaseAddress > MemInfo.RegionSize
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync || MemInfo.RegionSize - (uNext - (uintptr_t)MemInfo.BaseAddress) < cbAlloc
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Advance to the next memory region.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uCur = (uintptr_t)MemInfo.BaseAddress + MemInfo.RegionSize;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uCur = (uintptr_t)(MemInfo.AllocationBase ? MemInfo.AllocationBase : MemInfo.BaseAddress);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsyncstatic void supR3HardenedWinHookFailed(const char *pszWhich, uint8_t const *pbPrologue)
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync supR3HardenedFatalMsg("supR3HardenedWinInstallHooks", kSupInitOp_Misc, VERR_NO_MEMORY,
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync "Failed to install %s monitor: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n "
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync "(It is also possible you are running 32-bit VirtualBox under 64-bit windows.)\n"
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync pbPrologue[0], pbPrologue[1], pbPrologue[2], pbPrologue[3],
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync pbPrologue[4], pbPrologue[5], pbPrologue[6], pbPrologue[7],
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync pbPrologue[8], pbPrologue[9], pbPrologue[10], pbPrologue[11],
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync pbPrologue[12], pbPrologue[13], pbPrologue[14], pbPrologue[15]);
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync * IPRT thread that waits for the parent process to terminate and reacts by
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync * exiting the current process.
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync * @returns VINF_SUCCESS
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync * @param hSelf The current thread. Ignored.
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync * @param pvUser The handle of the parent process.
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsyncstatic DECLCALLBACK(int) supR3HardenedWinParentWatcherThread(RTTHREAD hSelf, void *pvUser)
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync * Wait for the parent to terminate.
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync rcNt = NtWaitForSingleObject(hProcWait, TRUE /*Alertable*/, NULL /*pTimeout*/);
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync supR3HardenedFatal("NtWaitForSingleObject returned %#x\n", rcNt);
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync * Proxy the termination code of the child, if it exited already.
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync NTSTATUS rcNt2 = NtQueryInformationProcess(hProcWait, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync SUP_DPRINTF(("supR3HardenedWinParentWatcherThread: Quitting: ExitCode=%#x rcNt=%#x\n", BasicInfo.ExitStatus, rcNt));
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync suplibHardenedExit((RTEXITCODE)BasicInfo.ExitStatus);
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync * Creates the parent watcher thread that will make sure this process exits when
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync * the parent does.
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync * This is a necessary evil to make VBoxNetDhcp and VBoxNetNat termination from
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync * Main work without too much new magic. It also makes Ctrl-C or similar work
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync * in on the hardened processes in the windows console.
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync * @param hVBoxRT The VBoxRT.dll handle. We use RTThreadCreate to
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync * spawn the thread to avoid duplicating thread
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync * creation and thread naming code from IPRT.
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsyncDECLHIDDEN(void) supR3HardenedWinCreateParentWatcherThread(HMODULE hVBoxRT)
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync * Resolve runtime methods that we need.
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync PFNRTTHREADCREATE pfnRTThreadCreate = (PFNRTTHREADCREATE)GetProcAddress(hVBoxRT, "RTThreadCreate");
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync * Find the parent process ID.
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync NTSTATUS rcNt = NtQueryInformationProcess(NtCurrentProcess(), ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync supR3HardenedFatal("supR3HardenedWinCreateParentWatcherThread: NtQueryInformationProcess failed: %#x\n", rcNt);
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync * Open the parent process for waiting and exitcode query.
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync InitializeObjectAttributes(&ObjAttr, NULL, 0, NULL /*hRootDir*/, NULL /*pSecDesc*/);
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync ClientId.UniqueProcess = (HANDLE)BasicInfo.InheritedFromUniqueProcessId;
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync rcNt = NtOpenProcess(&hParent, SYNCHRONIZE | PROCESS_QUERY_INFORMATION, &ObjAttr, &ClientId);
0d73750f953d8569054777eab62f40ad88a66d88vboxsync supR3HardenedFatalMsg("supR3HardenedWinCreateParentWatcherThread", kSupInitOp_Misc, VERR_GENERAL_FAILURE,
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync "NtOpenProcess(%p.0) failed: %#x\n", ClientId.UniqueProcess, rcNt);
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync * Create the thread that should do the waiting.
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync int rc = pfnRTThreadCreate(NULL, supR3HardenedWinParentWatcherThread, hParent, _64K /* stack */,
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync RTTHREADTYPE_DEFAULT, 0 /*fFlags*/, "ParentWatcher");
2fce40121ae472df2fd959fbe19775ed43304a0bvboxsync supR3HardenedFatal("supR3HardenedWinCreateParentWatcherThread: RTThreadCreate failed: %Rrc\n", rc);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Install hooks for intercepting calls dealing with mapping shared libraries
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * into the process.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * This allows us to prevent undesirable shared libraries from being loaded.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @remarks We assume we're alone in this process, so no seralizing trickery is
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * necessary when installing the patch.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * @remarks We would normally just copy the prologue sequence somewhere and add
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * a jump back at the end of it. But because we wish to avoid
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * allocating executable memory, we need to have preprepared assembly
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * "copies". This makes the non-system call patching a little tedious
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * and inflexible.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Install a anti debugging hack before we continue. This prevents most
7d6ce198fd361f58bd1ebdeee7772f76b4e58966vboxsync * notifications from ending up in the debugger. (Also applied to the
7d6ce198fd361f58bd1ebdeee7772f76b4e58966vboxsync * child process when respawning.)
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync rcNt = NtSetInformationThread(NtCurrentThread(), ThreadHideFromDebugger, NULL, 0);
751a35d04fb11f94562583ad77bc0a1382957f49vboxsync supR3HardenedFatalMsg("supR3HardenedWinInstallHooks", kSupInitOp_Misc, VERR_GENERAL_FAILURE,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "NtSetInformationThread/ThreadHideFromDebugger failed: %#x\n", rcNt);
751a35d04fb11f94562583ad77bc0a1382957f49vboxsync * Disable hard error popups so we can quietly refuse images to be loaded.
751a35d04fb11f94562583ad77bc0a1382957f49vboxsync rcNt = NtQueryInformationProcess(NtCurrentProcess(), ProcessDefaultHardErrorMode, &fHardErr, sizeof(fHardErr), NULL);
751a35d04fb11f94562583ad77bc0a1382957f49vboxsync supR3HardenedFatalMsg("supR3HardenedWinInstallHooks", kSupInitOp_Misc, VERR_GENERAL_FAILURE,
751a35d04fb11f94562583ad77bc0a1382957f49vboxsync "NtQueryInformationProcess/ProcessDefaultHardErrorMode failed: %#x\n", rcNt);
751a35d04fb11f94562583ad77bc0a1382957f49vboxsync rcNt = NtSetInformationProcess(NtCurrentProcess(), ProcessDefaultHardErrorMode, &fHardErr, sizeof(fHardErr));
751a35d04fb11f94562583ad77bc0a1382957f49vboxsync supR3HardenedFatalMsg("supR3HardenedWinInstallHooks", kSupInitOp_Misc, VERR_GENERAL_FAILURE,
751a35d04fb11f94562583ad77bc0a1382957f49vboxsync "NtSetInformationProcess/ProcessDefaultHardErrorMode failed: %#x\n", rcNt);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Locate the routines first so we can allocate memory that's near enough.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync FARPROC pfnNtCreateSection = GetProcAddress(hmodNtDll, "NtCreateSection");
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync //SUPR3HARDENED_ASSERT(pfnNtCreateSection == (FARPROC)NtCreateSection);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync FARPROC pfnLdrLoadDll = GetProcAddress(hmodNtDll, "LdrLoadDll");
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync //SUPR3HARDENED_ASSERT(pfnLdrLoadDll == (FARPROC)LdrLoadDll);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * For 64-bit hosts we need some memory within a +/-2GB range of the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * actual function to be able to patch it.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync uintptr_t uStart = RT_MAX((uintptr_t)pfnNtCreateSection, (uintptr_t)pfnLdrLoadDll);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync void *pvMem = supR3HardenedWinAllocHookMemory(uStart, uStart - _2G + PAGE_SIZE, -1, cbMem);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync uintptr_t uStart = RT_MIN((uintptr_t)pfnNtCreateSection, (uintptr_t)pfnLdrLoadDll);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync pvMem = supR3HardenedWinAllocHookMemory(uStart, uStart + _2G - PAGE_SIZE, 1, cbMem);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync supR3HardenedFatalMsg("supR3HardenedWinInstallHooks", kSupInitOp_Misc, VERR_NO_MEMORY,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "Failed to allocate memory within the +/-2GB range from NTDLL.\n");
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Hook #1 - NtCreateSection.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Purpose: Validate everything that can be mapped into the process before
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * it's mapped and we still have a file handle to work with.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync uint8_t * const pbNtCreateSection = (uint8_t *)(uintptr_t)pfnNtCreateSection;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Patch 64-bit hosts.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Pattern #1: XP64/W2K3-64 thru Windows 8.1
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync 0:000> u ntdll!NtCreateSection
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync ntdll!NtCreateSection:
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync 00000000`779f1750 4c8bd1 mov r10,rcx
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync 00000000`779f1753 b847000000 mov eax,47h
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync 00000000`779f1758 0f05 syscall
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync 00000000`779f175a c3 ret
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync 00000000`779f175b 0f1f440000 nop dword ptr [rax+rax]
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync The variant is the value loaded into eax: W2K3=??, Vista=47h?, W7=47h, W80=48h, W81=49h */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if ( pbNtCreateSection[ 0] == 0x4c /* mov r10, rcx */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync && pbNtCreateSection[ 3] == 0xb8 /* mov eax, 000000xxh */
4f2b002896072b0b5a7cb566341c8bac5e69392bvboxsync/* b8 22 35 ed 0 48 63 c0 ff e0 c3 f 1f 44 0 0 - necros2 - agnitum firewall? */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync offJmpBack = 8; /* the 3rd instruction (syscall). */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync# define SYSCALL(a_Num) case a_Num: pfnCallReal = RT_CONCAT(supR3HardenedJmpBack_NtCreateSection_,a_Num); break;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync# include "NtCreateSection-template-amd64-syscall-type-1.h"
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync supR3HardenedWinHookFailed("NtCreateSection", pbNtCreateSection);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync g_pfnNtCreateSectionJmpBack = (PFNRT)(uintptr_t)(pbNtCreateSection + offJmpBack);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync *puJmpTab = (uintptr_t)supR3HardenedMonitor_NtCreateSection;
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbNtCreateSection, 16,
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync *(uint32_t *)&pbNtCreateSection[2] = (uint32_t)((uintptr_t)puJmpTab - (uintptr_t)&pbNtCreateSection[2+4]);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbNtCreateSection, 16,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Patch 32-bit hosts.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Pattern #1: XP thru Windows 7
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync kd> u ntdll!NtCreateSection
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync ntdll!NtCreateSection:
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync 7c90d160 b832000000 mov eax,32h
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync 7c90d165 ba0003fe7f mov edx,offset SharedUserData!SystemCallStub (7ffe0300)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync 7c90d16a ff12 call dword ptr [edx]
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync 7c90d16c c21c00 ret 1Ch
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync 7c90d16f 90 nop
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync The variable bit is the value loaded into eax: XP=32h, W2K3=34h, Vista=4bh, W7=54h
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync Pattern #2: Windows 8.1
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync 0:000:x86> u ntdll_6a0f0000!NtCreateSection
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync ntdll_6a0f0000!NtCreateSection:
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync 6a15eabc b854010000 mov eax,154h
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync 6a15eac1 e803000000 call ntdll_6a0f0000!NtCreateSection+0xd (6a15eac9)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync 6a15eac6 c21c00 ret 1Ch
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync 6a15eac9 8bd4 mov edx,esp
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync 6a15eacb 0f34 sysenter
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync 6a15eacd c3 ret
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync The variable bit is the value loaded into eax: W81=154h
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync Note! One nice thing here is that we can share code pattern #1. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if ( pbNtCreateSection[ 0] == 0xb8 /* mov eax, 000000xxh*/
1042ff61f0b8de217c7e694021be0b9a5b9b8468vboxsync && ( ( pbNtCreateSection[ 5] == 0xba /* mov edx, offset SharedUserData!SystemCallStub */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync || ( pbNtCreateSection[ 5] == 0xe8 /* call [$+3] */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync && RT_ABS(*(int32_t *)&pbNtCreateSection[6]) < 0x10
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync# define SYSCALL(a_Num) case a_Num: pfnCallReal = RT_CONCAT(supR3HardenedJmpBack_NtCreateSection_,a_Num); break;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync# include "NtCreateSection-template-x86-syscall-type-1.h"
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync supR3HardenedWinHookFailed("NtCreateSection", pbNtCreateSection);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync g_pfnNtCreateSectionJmpBack = (PFNRT)(uintptr_t)(pbNtCreateSection + offJmpBack);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbNtCreateSection, 16,
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync *(uint32_t *)&pbNtCreateSection[1] = (uintptr_t)supR3HardenedMonitor_NtCreateSection
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbNtCreateSection, 16,
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Hook #2 - LdrLoadDll
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Purpose: (a) Enforce LdrLoadDll search path constraints, and (b) pre-validate
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * DLLs so we can avoid calling WinVerifyTrust from the first hook,
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * and thus avoiding messing up the loader data on some installations.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * This differs from the above function in that is no a system call and
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * we're at the mercy of the compiler.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync uint8_t * const pbLdrLoadDll = (uint8_t *)(uintptr_t)pfnLdrLoadDll;
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync memset(g_abSupHardReadWriteExecPage, 0xcc, PAGE_SIZE);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Patch 64-bit hosts.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync /* Pattern #1:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync Windows 8.1:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 0:000> u ntdll!LdrLoadDll
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync ntdll!LdrLoadDll:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00007ffa`814ccd44 488bc4 mov rax,rsp
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00007ffa`814ccd47 48895808 mov qword ptr [rax+8],rbx
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00007ffa`814ccd4b 48896810 mov qword ptr [rax+10h],rbp
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00007ffa`814ccd4f 48897018 mov qword ptr [rax+18h],rsi
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00007ffa`814ccd53 48897820 mov qword ptr [rax+20h],rdi
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00007ffa`814ccd57 4156 push r14
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00007ffa`814ccd59 4883ec70 sub rsp,70h
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00007ffa`814ccd5d f6059cd2100009 test byte ptr [ntdll!LdrpDebugFlags (00007ffa`815da000)],9
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync && pbLdrLoadDll[3] == 0x48 /* mov qword ptr [rax+8],rbx */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type1;
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync Pattern #2:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync Windows 8.0:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 0:000> u ntdll_w8_64!LdrLoadDll
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync ntdll_w8_64!LdrLoadDll:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00007ffa`52ffa7c0 48895c2408 mov qword ptr [rsp+8],rbx
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00007ffa`52ffa7c5 4889742410 mov qword ptr [rsp+10h],rsi
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00007ffa`52ffa7ca 48897c2418 mov qword ptr [rsp+18h],rdi
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00007ffa`52ffa7cf 55 push rbp
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00007ffa`52ffa7d0 4156 push r14
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00007ffa`52ffa7d2 4157 push r15
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00007ffa`52ffa7d4 488bec mov rbp,rsp
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00007ffa`52ffa7d7 4883ec60 sub rsp,60h
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00007ffa`52ffa7db 8b05df321000 mov eax,dword ptr [ntdll_w8_64!LdrpDebugFlags (00007ffa`530fdac0)]
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00007ffa`52ffa7e1 4d8bf1 mov r14,r9
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync else if ( pbLdrLoadDll[0] == 0x48 /* mov qword ptr [rsp+8],rbx */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync && pbLdrLoadDll[5] == 0x48 /* mov qword ptr [rsp+10h],rsi */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type2;
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync Pattern #3:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync ntdll_w7_64!LdrLoadDll:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`58be4a20 48895c2410 mov qword ptr [rsp+10h],rbx
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`58be4a25 48896c2418 mov qword ptr [rsp+18h],rbp
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`58be4a2a 56 push rsi
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`58be4a2b 57 push rdi
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`58be4a2c 4154 push r12
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`58be4a2e 4883ec50 sub rsp,50h
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`58be4a32 f605976e100009 test byte ptr [ntdll_w7_64!ShowSnaps (00000000`58ceb8d0)],9
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`58be4a39 498bf1 mov rsi,r9
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync else if ( pbLdrLoadDll[0] == 0x48 /* mov qword ptr [rsp+10h],rbx */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type3;
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync Pattern #4:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync Windows Vista:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 0:000> u ntdll_vista_64!LdrLoadDll
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync ntdll_vista_64!LdrLoadDll:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`58c11f60 fff3 push rbx
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`58c11f62 56 push rsi
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`58c11f63 57 push rdi
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`58c11f64 4154 push r12
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`58c11f66 4155 push r13
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`58c11f68 4156 push r14
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`58c11f6a 4157 push r15
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`58c11f6c 4881ecb0020000 sub rsp,2B0h
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`58c11f73 488b05367b0e00 mov rax,qword ptr [ntdll_vista_64!_security_cookie (00000000`58cf9ab0)]
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`58c11f7a 4833c4 xor rax,rsp
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`58c11f7d 48898424a0020000 mov qword ptr [rsp+2A0h],rax
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type4;
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync Pattern #5:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync Windows XP64:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 0:000> u ntdll!LdrLoadDll
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync ntdll!LdrLoadDll:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`78efa580 4c8bdc mov r11,rsp
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`78efa583 4881ece8020000 sub rsp,2E8h
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`78efa58a 49895bf8 mov qword ptr [r11-8],rbx
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`78efa58e 498973f0 mov qword ptr [r11-10h],rsi
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`78efa592 49897be8 mov qword ptr [r11-18h],rdi
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`78efa596 4d8963e0 mov qword ptr [r11-20h],r12
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`78efa59a 4d896bd8 mov qword ptr [r11-28h],r13
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`78efa59e 4d8973d0 mov qword ptr [r11-30h],r14
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`78efa5a2 4d897bc8 mov qword ptr [r11-38h],r15
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`78efa5a6 488b051bd10a00 mov rax,qword ptr [ntdll!_security_cookie (00000000`78fa76c8)]
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`78efa5ad 48898424a0020000 mov qword ptr [rsp+2A0h],rax
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`78efa5b5 4d8bf9 mov r15,r9
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`78efa5b8 4c8bf2 mov r14,rdx
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`78efa5bb 4c8be9 mov r13,rcx
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`78efa5be 4c89442458 mov qword ptr [rsp+58h],r8
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 00000000`78efa5c3 66c74424680000 mov word ptr [rsp+68h],0
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync else if ( pbLdrLoadDll[0] == 0x4c /* mov r11,rsp */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type5;
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync supR3HardenedWinHookFailed("LdrLoadDll", pbLdrLoadDll);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync /* Just use the disassembler to skip 6 bytes or more. */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync int rc = DISInstr(pbLdrLoadDll + offJmpBack, DISCPUMODE_64BIT, &Dis, &cbInstr);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync || (Dis.pCurInstr->fOpType & (DISOPTYPE_CONTROLFLOW))
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync || (Dis.ModRM.Bits.Mod == 0 && Dis.ModRM.Bits.Rm == 5 /* wrt RIP */) )
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync supR3HardenedWinHookFailed("LdrLoadDll", pbLdrLoadDll);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync /* Assemble the code for resuming the call.*/
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync *(PFNRT *)&g_pfnLdrLoadDllReal = (PFNRT)(uintptr_t)&g_abSupHardReadWriteExecPage[offExecPage];
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync memcpy(&g_abSupHardReadWriteExecPage[offExecPage], pbLdrLoadDll, offJmpBack);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync g_abSupHardReadWriteExecPage[offExecPage++] = 0xff; /* jmp qword [$+8 wrt RIP] */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync g_abSupHardReadWriteExecPage[offExecPage++] = 0x25;
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync *(uint32_t *)&g_abSupHardReadWriteExecPage[offExecPage] = RT_ALIGN_32(offExecPage + 4, 8) - (offExecPage + 4);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync *(uint64_t *)&g_abSupHardReadWriteExecPage[offExecPage] = (uintptr_t)&pbLdrLoadDll[offJmpBack];
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync /* Patch the function. */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync *puJmpTab = (uintptr_t)supR3HardenedMonitor_LdrLoadDll;
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbLdrLoadDll, 16, PAGE_EXECUTE_READWRITE, &dwOldProt));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync *(uint32_t *)&pbLdrLoadDll[2] = (uint32_t)((uintptr_t)puJmpTab - (uintptr_t)&pbLdrLoadDll[2+4]);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbLdrLoadDll, 16, PAGE_EXECUTE_READ, &dwOldProt));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Patch 32-bit hosts.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync /* Pattern #1:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 0:000> u ntdll!LdrLoadDll
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync ntdll!LdrLoadDll:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 77aff585 8bff mov edi,edi
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 77aff587 55 push ebp
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 77aff588 8bec mov ebp,esp
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 77aff58a 51 push ecx
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 77aff58b 51 push ecx
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 77aff58c a1f8bdaf77 mov eax,dword ptr [ntdll!LdrpLogLevelStateTable+0x24 (77afbdf8)]
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync Windows 8 rtm:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 0:000:x86> u ntdll_67150000!LdrLoadDll
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync ntdll_67150000!LdrLoadDll:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 67189f3f 8bff mov edi,edi
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 67189f41 55 push ebp
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 67189f42 8bec mov ebp,esp
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 67189f44 8b0d10eb2467 mov ecx,dword ptr [ntdll_67150000!LdrpDebugFlags (6724eb10)]
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync Windows 8.1:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 0:000:x86> u ntdll_w81_32!LdrLoadDll
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync ntdll_w81_32!LdrLoadDll:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 6718aade 8bff mov edi,edi
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 6718aae0 55 push ebp
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 6718aae1 8bec mov ebp,esp
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 6718aae3 83ec14 sub esp,14h
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 6718aae6 f6050040246709 test byte ptr [ntdll_w81_32!LdrpDebugFlags (67244000)],9
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync Pattern #2:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync Windows XP:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 0:000:x86> u ntdll_xp!LdrLoadDll
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync ntdll_xp!LdrLoadDll:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 77f569d2 6858020000 push 258h
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 77f569d7 68d866f777 push offset ntdll_xp!`string'+0x12c (77f766d8)
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 77f569dc e83bb20200 call ntdll_xp!_SEH_prolog (77f81c1c)
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 77f569e1 33db xor ebx,ebx
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 77f569e3 66895de0 mov word ptr [ebp-20h],bx
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 77f569e7 33c0 xor eax,eax
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 77f569e9 8d7de2 lea edi,[ebp-1Eh]
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 77f569ec ab stos dword ptr es:[edi]
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync Windows Server 2003:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 0:000:x86> u ntdll_w2k3_32!LdrLoadDll
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync ntdll_w2k3_32!LdrLoadDll:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 7c833f63 6840020000 push 240h
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 7c833f68 68b040837c push offset ntdll_w2k3_32!`string'+0x12c (7c8340b0)
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 7c833f6d e8a942ffff call ntdll_w2k3_32!_SEH_prolog (7c82821b)
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 7c833f72 a13077887c mov eax,dword ptr [ntdll_w2k3_32!__security_cookie (7c887730)]
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 7c833f77 8945e4 mov dword ptr [ebp-1Ch],eax
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 7c833f7a 8b4508 mov eax,dword ptr [ebp+8]
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 7c833f7d 8985b0fdffff mov dword ptr [ebp-250h],eax
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 7c833f83 8b450c mov eax,dword ptr [ebp+0Ch]
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync Windows Vista SP0 & SP1:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 0:000:x86> u ntdll_vista_sp0_32!LdrLoadDll
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync ntdll_vista_sp0_32!LdrLoadDll:
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 69b0eb00 6844020000 push 244h
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 69b0eb05 6838e9b269 push offset ntdll_vista_sp0_32! ?? ::FNODOBFM::`string'+0x39e (69b2e938)
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 69b0eb0a e835420300 call ntdll_vista_sp0_32!_SEH_prolog4_GS (69b42d44)
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 69b0eb0f 8b4508 mov eax,dword ptr [ebp+8]
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 69b0eb12 8985acfdffff mov dword ptr [ebp-254h],eax
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 69b0eb18 8b450c mov eax,dword ptr [ebp+0Ch]
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 69b0eb1b 8985c0fdffff mov dword ptr [ebp-240h],eax
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync 69b0eb21 8b4510 mov eax,dword ptr [ebp+10h]
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync if ( pbLdrLoadDll[0] == 0x8b /* mov edi, edi - for hot patching */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type1;
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync else if (pbLdrLoadDll[0] == 0x68 /* push dword XXXXXXXX */)
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type2;
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync g_supR3HardenedJmpBack_LdrLoadDll_Type2_PushDword = *(uint32_t const *)&pbLdrLoadDll[1];
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync supR3HardenedWinHookFailed("LdrLoadDll", pbLdrLoadDll);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync g_pfnLdrLoadDllJmpBack = (PFNRT)(uintptr_t)(pbLdrLoadDll + offJmpBack);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync /* Just use the disassembler to skip 6 bytes or more. */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync int rc = DISInstr(pbLdrLoadDll + offJmpBack, DISCPUMODE_32BIT, &Dis, &cbInstr);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync || (Dis.pCurInstr->fOpType & (DISOPTYPE_CONTROLFLOW)) )
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync supR3HardenedWinHookFailed("LdrLoadDll", pbLdrLoadDll);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync /* Assemble the code for resuming the call.*/
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync *(PFNRT *)&g_pfnLdrLoadDllReal = (PFNRT)(uintptr_t)&g_abSupHardReadWriteExecPage[offExecPage];
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync memcpy(&g_abSupHardReadWriteExecPage[offExecPage], pbLdrLoadDll, offJmpBack);
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync g_abSupHardReadWriteExecPage[offExecPage++] = 0xe9;
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync *(uint32_t *)&g_abSupHardReadWriteExecPage[offExecPage] = (uintptr_t)&pbLdrLoadDll[offJmpBack]
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync - (uintptr_t)&g_abSupHardReadWriteExecPage[offExecPage + 4];
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync /* Patch LdrLoadDLl. */
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbLdrLoadDll, 16,
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync *(uint32_t *)&pbLdrLoadDll[1] = (uintptr_t)supR3HardenedMonitor_LdrLoadDll - (uintptr_t)&pbLdrLoadDll[1+4];
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbLdrLoadDll, 16, PAGE_EXECUTE_READ, &dwOldProt));
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync * Seal the rwx page.
a60be2c64ea23bb7ce4c9998bcd541c4db879fbavboxsync SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), g_abSupHardReadWriteExecPage, PAGE_SIZE,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Verifies the process integrity.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncDECLHIDDEN(void) supR3HardenedWinVerifyProcess(void)
7d6ce198fd361f58bd1ebdeee7772f76b4e58966vboxsync int rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(),
e352c25b01398e5503235fed02436cb2992f1021vboxsync SUPHARDNTVPKIND_VERIFY_ONLY, NULL /*pcFixes*/, &g_ErrInfoStatic.Core);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync supR3HardenedFatalMsg("supR3HardenedWinVerifyProcess", kSupInitOp_Integrity, rc,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "Failed to verify process integrity: %s", g_ErrInfoStatic.szMsg);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Gets the SID of the user associated with the process.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @returns @c true if we've got a login SID, @c false if not.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param pSidUser Where to return the user SID.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param cbSidUser The size of the user SID buffer.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param pSidLogin Where to return the login SID.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param cbSidLogin The size of the login SID buffer.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic bool supR3HardenedGetUserAndLogSids(PSID pSidUser, ULONG cbSidUser, PSID pSidLogin, ULONG cbSidLogin)
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync SUPR3HARDENED_ASSERT_NT_SUCCESS(NtOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &hToken));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync SUPR3HARDENED_ASSERT_NT_SUCCESS(NtQueryInformationToken(hToken, TokenUser, &uBuf, sizeof(uBuf), &cbRet));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCopySid(cbSidUser, pSidUser, uBuf.UserInfo.User.Sid));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync bool fLoginSid = false;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync NTSTATUS rcNt = NtQueryInformationToken(hToken, TokenLogonSid, &uBuf, sizeof(uBuf), &cbRet);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if ((uBuf.Groups.Groups[i].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCopySid(cbSidLogin, pSidLogin, uBuf.Groups.Groups[i].Sid));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Build security attributes for the process or the primary thread (@a fProcess)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Process DACLs can be bypassed using the SeDebugPrivilege (generally available
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * to admins, i.e. normal windows users), or by taking ownership and/or
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * modifying the DACL. However, it restricts
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param pSecAttrs Where to return the security attributes.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param pCleanup Cleanup record.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param fProcess Set if it's for the process, clear if it's for
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * the primary thread.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic void supR3HardenedInitSecAttrs(PSECURITY_ATTRIBUTES pSecAttrs, PMYSECURITYCLEANUP pCleanup, bool fProcess)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Safe return values.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync suplibHardenedMemSet(pCleanup, 0, sizeof(*pCleanup));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/** @todo This isn't at all complete, just sketches... */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Create an ACL detailing the access of the above groups.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCreateAcl(&pCleanup->Acl.AclHdr, sizeof(pCleanup->Acl), ACL_REVISION));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync fDeny |= PROCESS_CREATE_THREAD | PROCESS_SET_SESSIONID | PROCESS_VM_OPERATION | PROCESS_VM_WRITE
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync | PROCESS_CREATE_PROCESS | PROCESS_DUP_HANDLE | PROCESS_SET_QUOTA
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync | PROCESS_SET_INFORMATION | PROCESS_SUSPEND_RESUME;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync fAllow |= PROCESS_TERMINATE | PROCESS_VM_READ | PROCESS_QUERY_INFORMATION;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync fAllowLogin |= PROCESS_TERMINATE | PROCESS_VM_READ | PROCESS_QUERY_INFORMATION;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0)) /* Introduced in Vista. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3)) /* Introduced in Windows 8.1. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync fDeny |= THREAD_SUSPEND_RESUME | THREAD_SET_CONTEXT | THREAD_SET_INFORMATION | THREAD_SET_THREAD_TOKEN
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync | THREAD_IMPERSONATE | THREAD_DIRECT_IMPERSONATION;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync fAllow |= THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync fAllowLogin |= THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0)) /* Introduced in Vista. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync fAllow |= THREAD_QUERY_LIMITED_INFORMATION | THREAD_SET_LIMITED_INFORMATION;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync fDeny |= ~fAllow & (SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Deny everyone access to bad bits. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlInitializeSid(&pCleanup->Everyone.Sid, &SIDAuthWorld, 1));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *RtlSubAuthoritySid(&pCleanup->Everyone.Sid, 0) = SECURITY_WORLD_RID;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlAddAccessDeniedAce(&pCleanup->Acl.AclHdr, ACL_REVISION,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Grant some access to the owner - doesn't work. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync SID_IDENTIFIER_AUTHORITY SIDAuthCreator = SECURITY_CREATOR_SID_AUTHORITY;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlInitializeSid(&pCleanup->Owner.Sid, &SIDAuthCreator, 1));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *RtlSubAuthoritySid(&pCleanup->Owner.Sid, 0) = SECURITY_CREATOR_OWNER_RID;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlAddAccessDeniedAce(&pCleanup->Acl.AclHdr, ACL_REVISION,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlAddAccessAllowedAce(&pCleanup->Acl.AclHdr, ACL_REVISION,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync bool fHasLoginSid = supR3HardenedGetUserAndLogSids(&pCleanup->User.Sid, sizeof(pCleanup->User),
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Grant minimal access to the user. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlAddAccessDeniedAce(&pCleanup->Acl.AclHdr, ACL_REVISION,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlAddAccessAllowedAce(&pCleanup->Acl.AclHdr, ACL_REVISION,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Grant very limited access to the login sid. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlAddAccessAllowedAce(&pCleanup->Acl.AclHdr, ACL_REVISION,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Create a security descriptor with the above ACL.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PSECURITY_DESCRIPTOR pSecDesc = (PSECURITY_DESCRIPTOR)suplibHardenedAllocZ(SECURITY_DESCRIPTOR_MIN_LENGTH);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCreateSecurityDescriptor(pSecDesc, SECURITY_DESCRIPTOR_REVISION));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlSetDaclSecurityDescriptor(pSecDesc, TRUE /*fDaclPresent*/, &pCleanup->Acl.AclHdr,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Predicate function which tests whether @a ch is a argument separator
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * character.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param ch The character to examine.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncDECLINLINE(bool) suplibCommandLineIsArgSeparator(int ch)
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync * Construct the new command line.
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync * Since argc/argv are both derived from GetCommandLineW (see
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync * suplibHardenedWindowsMain), we skip the argument by argument UTF-8 -> UTF-16
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync * conversion and quoting by going to the original source.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * The executable name, though, is replaced in case it's not a fullly
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * qualified path.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * The re-spawn indicator is added immediately after the executable name
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * so that we don't get tripped up missing close quote chars in the last
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * argument.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @returns Pointer to a command line string (heap).
edde275acba04aca58db4172a163741e3abadfbcvboxsync * @param pUniStr Unicode string structure to initialize to the
edde275acba04aca58db4172a163741e3abadfbcvboxsync * command line. Optional.
edde275acba04aca58db4172a163741e3abadfbcvboxsync * @param iWhich Which respawn we're to check for, 1 being the first
edde275acba04aca58db4172a163741e3abadfbcvboxsync * one, and 2 the second and final.
edde275acba04aca58db4172a163741e3abadfbcvboxsyncstatic PRTUTF16 supR3HardenedWinConstructCmdLine(PUNICODE_STRING pString, int iWhich)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Get the command line and skip the executable name.
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync PUNICODE_STRING pCmdLineStr = &NtCurrentPeb()->ProcessParameters->CommandLine;
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync uint32_t cwcArgs = pCmdLineStr->Length / sizeof(WCHAR);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Skip leading space (shouldn't be any, but whatever). */
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync while (cwcArgs > 0 && suplibCommandLineIsArgSeparator(*pawcArgs) )
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync SUPR3HARDENED_ASSERT(cwcArgs > 0 && *pawcArgs != '\0');
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Walk to the end of it. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync int fQuoted = false;
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync else if (*pawcArgs != '\\' || (pawcArgs[1] != '\\' && pawcArgs[1] != '"'))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync unsigned cSlashes = 0;
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync if (cwcArgs > 0 && *pawcArgs == '"' && (cSlashes & 1))
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync cwcArgs--, pawcArgs++; /* odd number of slashes == escaped quote */
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync } while (cwcArgs > 0 && (fQuoted || !suplibCommandLineIsArgSeparator(*pawcArgs)));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Skip trailing spaces. */
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync while (cwcArgs > 0 && suplibCommandLineIsArgSeparator(*pawcArgs))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Allocate a new buffer.
edde275acba04aca58db4172a163741e3abadfbcvboxsync AssertCompile(sizeof(SUPR3_RESPAWN_1_ARG0) == sizeof(SUPR3_RESPAWN_2_ARG0));
edde275acba04aca58db4172a163741e3abadfbcvboxsync size_t cwcCmdLine = (sizeof(SUPR3_RESPAWN_1_ARG0) - 1) / sizeof(SUPR3_RESPAWN_1_ARG0[0]) /* Respawn exe name. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync + !!cwcArgs + cwcArgs; /* if arguments present, add space + arguments. */
edde275acba04aca58db4172a163741e3abadfbcvboxsync supR3HardenedFatalMsg("supR3HardenedWinConstructCmdLine", kSupInitOp_Misc, VERR_OUT_OF_RANGE,
edde275acba04aca58db4172a163741e3abadfbcvboxsync "Command line is too long (%u chars)!", cwcCmdLine);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PRTUTF16 pwszCmdLine = (PRTUTF16)HeapAlloc(GetProcessHeap(), 0 /* dwFlags*/, (cwcCmdLine + 1) * sizeof(RTUTF16));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Construct the new command line.
edde275acba04aca58db4172a163741e3abadfbcvboxsync for (const char *pszSrc = iWhich == 1 ? SUPR3_RESPAWN_1_ARG0 : SUPR3_RESPAWN_2_ARG0; *pszSrc; pszSrc++)
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync suplibHardenedMemCopy(pwszDst, pawcArgs, cwcArgs * sizeof(RTUTF16));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync SUPR3HARDENED_ASSERT(pwszDst - pwszCmdLine == cwcCmdLine);
edde275acba04aca58db4172a163741e3abadfbcvboxsync pString->Length = (USHORT)(cwcCmdLine * sizeof(WCHAR));
edde275acba04aca58db4172a163741e3abadfbcvboxsync pString->MaximumLength = pString->Length + sizeof(WCHAR);
dca3cdd56f38abf4257b94ff13268323ea52e0a7vboxsync * Check if the zero terminated NT unicode string is the path to the given
dca3cdd56f38abf4257b94ff13268323ea52e0a7vboxsync * system32 DLL.
dca3cdd56f38abf4257b94ff13268323ea52e0a7vboxsync * @returns true if it is, false if not.
dca3cdd56f38abf4257b94ff13268323ea52e0a7vboxsync * @param pUniStr The zero terminated NT unicode string path.
dca3cdd56f38abf4257b94ff13268323ea52e0a7vboxsync * @param pszName The name of the system32 DLL.
dca3cdd56f38abf4257b94ff13268323ea52e0a7vboxsyncstatic bool supR3HardNtIsNamedSystem32Dll(PUNICODE_STRING pUniStr, const char *pszName)
dca3cdd56f38abf4257b94ff13268323ea52e0a7vboxsync if (pUniStr->Length > g_System32NtPath.UniStr.Length)
dca3cdd56f38abf4257b94ff13268323ea52e0a7vboxsync if (memcmp(pUniStr->Buffer, g_System32NtPath.UniStr.Buffer, g_System32NtPath.UniStr.Length) == 0)
dca3cdd56f38abf4257b94ff13268323ea52e0a7vboxsync if (pUniStr->Buffer[g_System32NtPath.UniStr.Length / sizeof(WCHAR)] == '\\')
dca3cdd56f38abf4257b94ff13268323ea52e0a7vboxsync if (RTUtf16ICmpAscii(&pUniStr->Buffer[g_System32NtPath.UniStr.Length / sizeof(WCHAR) + 1], pszName) == 0)
dca3cdd56f38abf4257b94ff13268323ea52e0a7vboxsync return true;
dca3cdd56f38abf4257b94ff13268323ea52e0a7vboxsync return false;
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * Common code used for child and parent to make new threads exit immediately.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * This patches the LdrInitializeThunk code to call NtTerminateThread with
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * STATUS_SUCCESS instead of doing the NTDLL initialization.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * @returns VBox status code.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * @param hProcess The process to do this to.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * @param pvLdrInitThunk The address of the LdrInitializeThunk code to
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * override.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * @param pvNtTerminateThread The address of the NtTerminateThread function in
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * the NTDLL instance we're patching. (Must be +/-
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * 2GB from the thunk code.)
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * @param pabBackup Where to back up the original instruction bytes
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * at pvLdrInitThunk.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * @param cbBackup The size of the backup area. Must be 16 bytes.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * @param pErrInfo Where to return extended error information.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * Optional.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsyncstatic int supR3HardNtDisableThreadCreationEx(HANDLE hProcess, void *pvLdrInitThunk, void *pvNtTerminateThread,
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync uint8_t *pabBackup, size_t cbBackup, PRTERRINFO pErrInfo)
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync SUP_DPRINTF(("supR3HardNtDisableThreadCreation: pvLdrInitThunk=%p pvNtTerminateThread=%p\n", pvLdrInitThunk, pvNtTerminateThread));
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync SUPR3HARDENED_ASSERT(RT_ABS((intptr_t)pvLdrInitThunk - (intptr_t)pvNtTerminateThread) < 16*_1M);
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * Back up the thunk code.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync NTSTATUS rcNt = NtReadVirtualMemory(hProcess, pvLdrInitThunk, pabBackup, cbBackup, &cbIgnored);
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync "supR3HardNtDisableThreadCreation: NtReadVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * Cook up replacement code that calls NtTerminateThread.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync memcpy(abReplacement, pabBackup, sizeof(abReplacement));
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync abReplacement[4] = 0xe8; /* call near NtTerminateThread */
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync *(int32_t *)&abReplacement[5] = (int32_t)((uintptr_t)pvNtTerminateThread - ((uintptr_t)pvLdrInitThunk + 9));
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync abReplacement[4] = 0xe8; /* call near NtTerminateThread */
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync *(int32_t *)&abReplacement[5] = (int32_t)((uintptr_t)pvNtTerminateThread - ((uintptr_t)pvLdrInitThunk + 9));
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * Install the replacment code.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync rcNt = NtProtectVirtualMemory(hProcess, &pvProt, &cbProt, PAGE_EXECUTE_READWRITE, &fOldProt);
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync "supR3HardNtDisableThreadCreationEx: NtProtectVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync rcNt = NtWriteVirtualMemory(hProcess, pvLdrInitThunk, abReplacement, sizeof(abReplacement), &cbIgnored);
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync "supR3HardNtDisableThreadCreationEx: NtWriteVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync rcNt = NtProtectVirtualMemory(hProcess, &pvProt, &cbProt, fOldProt, &fOldProt);
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync "supR3HardNtDisableThreadCreationEx: NtProtectVirtualMemory/LdrInitializeThunk/2 failed: %#x", rcNt);
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * Undo the effects of supR3HardNtDisableThreadCreationEx.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * @returns VBox status code.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * @param hProcess The process to do this to.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * @param pvLdrInitThunk The address of the LdrInitializeThunk code to
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * override.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * @param pabBackup Where to back up the original instruction bytes
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * at pvLdrInitThunk.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * @param cbBackup The size of the backup area. Must be 16 bytes.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * @param pErrInfo Where to return extended error information.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * Optional.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsyncstatic int supR3HardNtEnableThreadCreationEx(HANDLE hProcess, void *pvLdrInitThunk, uint8_t const *pabBackup, size_t cbBackup,
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync SUP_DPRINTF(("supR3HardNtEnableThreadCreation:\n"));
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync NTSTATUS rcNt = NtProtectVirtualMemory(hProcess, &pvProt, &cbProt, PAGE_EXECUTE_READWRITE, &fOldProt);
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync "supR3HardNtDisableThreadCreationEx: NtProtectVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync rcNt = NtWriteVirtualMemory(hProcess, pvLdrInitThunk, pabBackup, cbBackup, &cbIgnored);
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync "supR3HardNtEnableThreadCreation: NtWriteVirtualMemory/LdrInitializeThunk[restore] failed: %#x",
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync rcNt = NtProtectVirtualMemory(hProcess, &pvProt, &cbProt, fOldProt, &fOldProt);
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync "supR3HardNtEnableThreadCreation: NtProtectVirtualMemory/LdrInitializeThunk[restore] failed: %#x",
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * Disable thread creation for the current process.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * @remarks Doesn't really disables it, just makes the threads exit immediately
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * without executing any real code.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsyncstatic void supR3HardenedWinDisableThreadCreation(void)
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync /* Cannot use the imported NtTerminateThread as it's pointing to our own
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync syscall assembly code. */
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync FARPROC pfnNtTerminateThread = GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtTerminateThread");
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync int rc = supR3HardNtDisableThreadCreationEx(NtCurrentProcess(),
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync g_abLdrInitThunkSelfBackup, sizeof(g_abLdrInitThunkSelfBackup),
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * Undoes the effects of supR3HardenedWinDisableThreadCreation.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsyncDECLHIDDEN(void) supR3HardenedWinEnableThreadCreation(void)
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync int rc = supR3HardNtEnableThreadCreationEx(NtCurrentProcess(),
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync g_abLdrInitThunkSelfBackup, sizeof(g_abLdrInitThunkSelfBackup),
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync supR3HardenedError(rc, true /*fFatal*/, "%s", g_ErrInfoStatic.szMsg);
edde275acba04aca58db4172a163741e3abadfbcvboxsync * Child-Process Purification - release it from dubious influences.
edde275acba04aca58db4172a163741e3abadfbcvboxsync * AV software and other things injecting themselves into the embryonic
edde275acba04aca58db4172a163741e3abadfbcvboxsync * and budding process to intercept API calls and what not. Unfortunately
edde275acba04aca58db4172a163741e3abadfbcvboxsync * this is also the behavior of viruses, malware and other unfriendly
edde275acba04aca58db4172a163741e3abadfbcvboxsync * software, so we won't stand for it. AV software can scan our image
edde275acba04aca58db4172a163741e3abadfbcvboxsync * as they are loaded via kernel hooks, that's sufficient. No need for
edde275acba04aca58db4172a163741e3abadfbcvboxsync * matching half of NTDLL or messing with the import table of the
edde275acba04aca58db4172a163741e3abadfbcvboxsync * process executable.
edde275acba04aca58db4172a163741e3abadfbcvboxsync /** Process handle. */
edde275acba04aca58db4172a163741e3abadfbcvboxsync /** Primary thread handle. */
edde275acba04aca58db4172a163741e3abadfbcvboxsync /** Error buffer. */
f3b077ba3204fcb9c310e3929340db83bc9b77cdvboxsync /** The address of NTDLL in the child. */
f3b077ba3204fcb9c310e3929340db83bc9b77cdvboxsync /** The address of NTDLL in this process. */
edde275acba04aca58db4172a163741e3abadfbcvboxsync /** The basic process info. */
edde275acba04aca58db4172a163741e3abadfbcvboxsync /** The probable size of the PEB. */
edde275acba04aca58db4172a163741e3abadfbcvboxsync /** The pristine process environment block. */
edde275acba04aca58db4172a163741e3abadfbcvboxsyncstatic int supR3HardNtPuChScrewUpPebForInitialImageEvents(PSUPR3HARDNTPUCH pThis)
edde275acba04aca58db4172a163741e3abadfbcvboxsync * Not sure if any of the cracker software uses the PEB at this point, but
edde275acba04aca58db4172a163741e3abadfbcvboxsync * just in case they do make some of the PEB fields a little less useful.
edde275acba04aca58db4172a163741e3abadfbcvboxsync /* Make ImageBaseAddress useless. */
edde275acba04aca58db4172a163741e3abadfbcvboxsync Peb.ImageBaseAddress = (PVOID)((uintptr_t)Peb.ImageBaseAddress ^ UINT32_C(0x5f139000));
edde275acba04aca58db4172a163741e3abadfbcvboxsync Peb.ImageBaseAddress = (PVOID)((uintptr_t)Peb.ImageBaseAddress | UINT64_C(0x0313000000000000));
edde275acba04aca58db4172a163741e3abadfbcvboxsync * Write the PEB.
edde275acba04aca58db4172a163741e3abadfbcvboxsync NTSTATUS rcNt = NtWriteVirtualMemory(pThis->hProcess, pThis->BasicInfo.PebBaseAddress, &Peb, pThis->cbPeb, &cbActualMem);
edde275acba04aca58db4172a163741e3abadfbcvboxsync return RTErrInfoSetF(pThis->pErrInfo, VERR_GENERAL_FAILURE, "NtWriteVirtualMemory/Peb failed: %#x", rcNt);
04f85536aa01b3e25cece11d2a094e2a362bcbfavboxsync * Unmaps a DLL from the child process that was previously mapped by
04f85536aa01b3e25cece11d2a094e2a362bcbfavboxsync * supR3HardNtPuChMapDllIntoChild.
04f85536aa01b3e25cece11d2a094e2a362bcbfavboxsync * @returns Pointer to the DLL mapping on success, NULL on failure.
04f85536aa01b3e25cece11d2a094e2a362bcbfavboxsync * @param pThis The child purification instance data.
04f85536aa01b3e25cece11d2a094e2a362bcbfavboxsync * @param pvBase The base address of the mapping. Nothing done
04f85536aa01b3e25cece11d2a094e2a362bcbfavboxsync * @param pszShort The short name (for logging).
04f85536aa01b3e25cece11d2a094e2a362bcbfavboxsyncstatic void supR3HardNtPuChUnmapDllFromChild(PSUPR3HARDNTPUCH pThis, PVOID pvBase, const char *pszShort)
aac9fef3cdbe06bd5f6c584c43ff88ba12f9fc7evboxsync /*SUP_DPRINTF(("supR3HardNtPuChUnmapDllFromChild: Calling NtUnmapViewOfSection on %p / %s\n", pvBase, pszShort));*/
04f85536aa01b3e25cece11d2a094e2a362bcbfavboxsync NTSTATUS rcNt = NtUnmapViewOfSection(pThis->hProcess, pvBase);
04f85536aa01b3e25cece11d2a094e2a362bcbfavboxsync SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: NtUnmapViewOfSection failed on %s: %#x (%p)\n",
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * Maps a DLL into the child process.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * @returns Pointer to the DLL mapping on success, NULL on failure.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * @param pThis The child purification instance data.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * @param pNtName The path to the DLL.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * @param pszShort The short name (for logging).
eca3ddadc12f677ac68395c5eab914d41fc8963avboxsyncstatic PVOID supR3HardNtPuChMapDllIntoChild(PSUPR3HARDNTPUCH pThis, PUNICODE_STRING pNtName, const char *pszShort)
eca3ddadc12f677ac68395c5eab914d41fc8963avboxsync IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
eca3ddadc12f677ac68395c5eab914d41fc8963avboxsync InitializeObjectAttributes(&ObjAttr, pNtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
eca3ddadc12f677ac68395c5eab914d41fc8963avboxsync 0 /*EaLength*/);
eca3ddadc12f677ac68395c5eab914d41fc8963avboxsync SECTION_MAP_EXECUTE | SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_QUERY,
aac9fef3cdbe06bd5f6c584c43ff88ba12f9fc7evboxsync SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: mapping view of %s\n", pszShort)); /* For SEP. */
eca3ddadc12f677ac68395c5eab914d41fc8963avboxsync rcNt = NtMapViewOfSection(hSection, pThis->hProcess, &pvRet, 0 /*ZeroBits*/, 0 /*CommitSize*/,
eca3ddadc12f677ac68395c5eab914d41fc8963avboxsync NULL /*pOffSect*/, &cbView, ViewShare, 0 /*AllocationType*/, PAGE_READWRITE);
eca3ddadc12f677ac68395c5eab914d41fc8963avboxsync SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: %s mapped at %p LB %#x\n", pszShort, pvRet, cbView));
eca3ddadc12f677ac68395c5eab914d41fc8963avboxsync SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: NtMapViewOfSection failed on %s: %#x\n", pszShort, rcNt));
eca3ddadc12f677ac68395c5eab914d41fc8963avboxsync SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: NtCreateSection failed on %s: %#x\n", pszShort, rcNt));
eca3ddadc12f677ac68395c5eab914d41fc8963avboxsync SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: Error opening %s: %#x\n", pszShort, rcNt));
edde275acba04aca58db4172a163741e3abadfbcvboxsync * Trigger the initial image events without actually initializing the process.
edde275acba04aca58db4172a163741e3abadfbcvboxsync * This is a trick to force sysplant.sys to call its hand by tripping the image
edde275acba04aca58db4172a163741e3abadfbcvboxsync * loaded event for the main executable and ntdll images. This will happen when
edde275acba04aca58db4172a163741e3abadfbcvboxsync * the first thread in a process starts executing in PspUserThreadStartup. We
edde275acba04aca58db4172a163741e3abadfbcvboxsync * create a second thread that quits immediately by means of temporarily
edde275acba04aca58db4172a163741e3abadfbcvboxsync * replacing ntdll!LdrInitializeThunk by a NtTerminateThread call.
edde275acba04aca58db4172a163741e3abadfbcvboxsync * (LdrInitializeThunk is called by way of an APC queued the thread is created,
edde275acba04aca58db4172a163741e3abadfbcvboxsync * thus NtSetContextThread is of no use.)
edde275acba04aca58db4172a163741e3abadfbcvboxsync * @returns VBox status code.
edde275acba04aca58db4172a163741e3abadfbcvboxsync * @param pThis The child cleanup
edde275acba04aca58db4172a163741e3abadfbcvboxsync * @param pErrInfo For extended error information.
edde275acba04aca58db4172a163741e3abadfbcvboxsyncstatic int supR3HardNtPuChTriggerInitialImageEvents(PSUPR3HARDNTPUCH pThis)
1042ff61f0b8de217c7e694021be0b9a5b9b8468vboxsync * Use the on-disk image for the ntdll entrypoints here.
1042ff61f0b8de217c7e694021be0b9a5b9b8468vboxsync int rc = supHardNtLdrCacheOpen("ntdll.dll", &pLdrEntry);
1042ff61f0b8de217c7e694021be0b9a5b9b8468vboxsync return RTErrInfoSetF(pThis->pErrInfo, rc, "supHardNtLdrCacheOpen failed on NTDLL: %Rrc", rc);
1042ff61f0b8de217c7e694021be0b9a5b9b8468vboxsync rc = RTLdrGetSymbolEx(pLdrEntry->hLdrMod, pLdrEntry->pbBits, pThis->uNtDllAddr, UINT32_MAX,
1042ff61f0b8de217c7e694021be0b9a5b9b8468vboxsync return RTErrInfoSetF(pThis->pErrInfo, rc, "Error locating LdrInitializeThunk in NTDLL: %Rrc", rc);
1042ff61f0b8de217c7e694021be0b9a5b9b8468vboxsync PVOID pvLdrInitThunk = (PVOID)(uintptr_t)uLdrInitThunk;
1042ff61f0b8de217c7e694021be0b9a5b9b8468vboxsync rc = RTLdrGetSymbolEx(pLdrEntry->hLdrMod, pLdrEntry->pbBits, pThis->uNtDllAddr, UINT32_MAX,
1042ff61f0b8de217c7e694021be0b9a5b9b8468vboxsync return RTErrInfoSetF(pThis->pErrInfo, rc, "Error locating NtTerminateThread in NTDLL: %Rrc", rc);
1042ff61f0b8de217c7e694021be0b9a5b9b8468vboxsync SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: uLdrInitThunk=%p uNtTerminateThread=%p\n",
1042ff61f0b8de217c7e694021be0b9a5b9b8468vboxsync (uintptr_t)uLdrInitThunk, (uintptr_t)uNtTerminateThread));
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * Patch the child's LdrInitializeThunk to exit the thread immediately.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync rc = supR3HardNtDisableThreadCreationEx(pThis->hProcess, pvLdrInitThunk, (void *)(uintptr_t)uNtTerminateThread,
04f85536aa01b3e25cece11d2a094e2a362bcbfavboxsync * To further muddle the waters, we map the executable image and ntdll.dll
04f85536aa01b3e25cece11d2a094e2a362bcbfavboxsync * a 2nd time into the process before we actually start executing the thread
04f85536aa01b3e25cece11d2a094e2a362bcbfavboxsync * and trigger the genuine image load events.
9564efb26e4be678018e90c7f18dfb06c8b23009vboxsync * Update #1 (after 4.3.15 build 7):
9564efb26e4be678018e90c7f18dfb06c8b23009vboxsync * Turns out Symantec Endpoint Protection deadlocks when we map the
9564efb26e4be678018e90c7f18dfb06c8b23009vboxsync * executable into the process like this. The system only works
9564efb26e4be678018e90c7f18dfb06c8b23009vboxsync * halfways after that Powerbutton, impossible to shutdown without
9564efb26e4be678018e90c7f18dfb06c8b23009vboxsync * using the power or reset button. The order of the two mappings
9564efb26e4be678018e90c7f18dfb06c8b23009vboxsync * below doesn't matter. Haven't had time to look at stack yet.
9564efb26e4be678018e90c7f18dfb06c8b23009vboxsync * Observed on W7/64, SEP v12.1.4112.4156.
9564efb26e4be678018e90c7f18dfb06c8b23009vboxsync * Update #2 (after 4.3.16):
9564efb26e4be678018e90c7f18dfb06c8b23009vboxsync * Some avast! users complain about a deadlock mapping ntdll.dll
9564efb26e4be678018e90c7f18dfb06c8b23009vboxsync * as well. Unfortunately not reproducible, so there may possibly be
9564efb26e4be678018e90c7f18dfb06c8b23009vboxsync * some other cause. Sad as it's really a serious bug in whichever
9564efb26e4be678018e90c7f18dfb06c8b23009vboxsync * software it is that is causing it, and we'd like to report it to
9564efb26e4be678018e90c7f18dfb06c8b23009vboxsync * the responsible party.
04f85536aa01b3e25cece11d2a094e2a362bcbfavboxsync PVOID pvExe2 = supR3HardNtPuChMapDllIntoChild(pThis, &g_SupLibHardenedExeNtPath.UniStr, "executable[2nd]");
04f85536aa01b3e25cece11d2a094e2a362bcbfavboxsync UNICODE_STRING NtName1 = RTNT_CONSTANT_UNISTR(L"\\SystemRoot\\System32\\ntdll.dll");
04f85536aa01b3e25cece11d2a094e2a362bcbfavboxsync PVOID pvNtDll2 = supR3HardNtPuChMapDllIntoChild(pThis, &NtName1, "ntdll.dll[2nd]");
edde275acba04aca58db4172a163741e3abadfbcvboxsync * Create the thread, waiting 10 seconds for it to complete.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync NTSTATUS rcNt = RtlCreateUserThread(pThis->hProcess,
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync 0 /* ZeroBits */,
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync 0 /* MaximumStackSize */,
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync 0 /* CommittedStackSize */,
edde275acba04aca58db4172a163741e3abadfbcvboxsync Timeout.QuadPart = -10 * 10000000; /* 10 seconds */
edde275acba04aca58db4172a163741e3abadfbcvboxsync NtWaitForSingleObject(hThread2, FALSE /* Alertable */, &Timeout);
eca3ddadc12f677ac68395c5eab914d41fc8963avboxsync * Map kernel32.dll and kernelbase.dll (if applicable) into the process.
eca3ddadc12f677ac68395c5eab914d41fc8963avboxsync * This triggers should image load events that may set of AV activities
eca3ddadc12f677ac68395c5eab914d41fc8963avboxsync * that we'd rather see early than later.
04f85536aa01b3e25cece11d2a094e2a362bcbfavboxsync UNICODE_STRING NtName2 = RTNT_CONSTANT_UNISTR(L"\\SystemRoot\\System32\\kernel32.dll");
04f85536aa01b3e25cece11d2a094e2a362bcbfavboxsync PVOID pvKernel32 = supR3HardNtPuChMapDllIntoChild(pThis, &NtName2, "kernel32.dll");
04f85536aa01b3e25cece11d2a094e2a362bcbfavboxsync UNICODE_STRING NtName3 = RTNT_CONSTANT_UNISTR(L"\\SystemRoot\\System32\\KernelBase.dll");
eca3ddadc12f677ac68395c5eab914d41fc8963avboxsync PVOID pvKernelBase = g_uNtVerCombined >= SUP_NT_VER_VISTA
04f85536aa01b3e25cece11d2a094e2a362bcbfavboxsync ? supR3HardNtPuChMapDllIntoChild(pThis, &NtName3, "KernelBase.dll")
5de281ea9954eecffbd1ba604603cc8e8347e700vboxsync * Fudge factor for letting kernel threads get a chance to mess up our
5de281ea9954eecffbd1ba604603cc8e8347e700vboxsync * process asynchronously.
beed5fc4d17b85d6d05516ae63e6308af82ad96fvboxsync uint32_t cMsKludge = (g_fSupAdversaries & SUPHARDNT_ADVERSARY_SYMANTEC_SYSPLANT) ? 256 : g_fSupAdversaries ? 64 : 16;
beed5fc4d17b85d6d05516ae63e6308af82ad96fvboxsync Time.QuadPart = -8000000 / 100; /* 8ms in 100ns units, relative time. */
5de281ea9954eecffbd1ba604603cc8e8347e700vboxsync SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: Startup delay kludge #1: %u ms\n", GetTickCount() - dwStart));
04f85536aa01b3e25cece11d2a094e2a362bcbfavboxsync * Unmap the image we mapped into the guest above.
beed5fc4d17b85d6d05516ae63e6308af82ad96fvboxsync * Experiment: Don't unmap for avast.
beed5fc4d17b85d6d05516ae63e6308af82ad96fvboxsync if (!(g_fSupAdversaries & SUPHARDNT_ADVERSARY_AVAST))
beed5fc4d17b85d6d05516ae63e6308af82ad96fvboxsync supR3HardNtPuChUnmapDllFromChild(pThis, pvKernel32, "kernel32.dll");
beed5fc4d17b85d6d05516ae63e6308af82ad96fvboxsync supR3HardNtPuChUnmapDllFromChild(pThis, pvKernelBase, "KernelBase.dll");
04f85536aa01b3e25cece11d2a094e2a362bcbfavboxsync supR3HardNtPuChUnmapDllFromChild(pThis, pvNtDll2, "ntdll.dll[2nd]");
04f85536aa01b3e25cece11d2a094e2a362bcbfavboxsync supR3HardNtPuChUnmapDllFromChild(pThis, pvExe2, "executable[2nd]");
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * Restore the original thunk code and protection.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * We do this after waiting as anyone trying to kick of threads in the
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * process will get nothing done as long as our patch is in place.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync rc = supR3HardNtEnableThreadCreationEx(pThis->hProcess, pvLdrInitThunk, abBackup, sizeof(abBackup), pThis->pErrInfo);
edde275acba04aca58db4172a163741e3abadfbcvboxsyncstatic int supR3HardenedWinScratchChildMemory(HANDLE hProcess, void *pv, size_t cb, const char *pszWhat, PRTERRINFO pErrInfo)
edde275acba04aca58db4172a163741e3abadfbcvboxsync SUP_DPRINTF(("supR3HardenedWinScratchChildMemory: %p %#x\n", pv, cb));
edde275acba04aca58db4172a163741e3abadfbcvboxsync NTSTATUS rcNt = NtProtectVirtualMemory(hProcess, &pvCopy, &cbCopy, PAGE_NOACCESS, NULL);
edde275acba04aca58db4172a163741e3abadfbcvboxsync return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, "NtProtectVirtualMemory/%s (%p LB %#zx) failed: %#x",
edde275acba04aca58db4172a163741e3abadfbcvboxsyncstatic int supR3HardNtPuChSanitizePeb(PSUPR3HARDNTPUCH pThis)
edde275acba04aca58db4172a163741e3abadfbcvboxsync * Make a copy of the pre-execution PEB.
edde275acba04aca58db4172a163741e3abadfbcvboxsync * There should not be any activation context, so if there is, we scratch the memory associated with it.
edde275acba04aca58db4172a163741e3abadfbcvboxsync if (RT_SUCCESS(rc) && Peb.pShimData && !((uintptr_t)Peb.pShimData & PAGE_OFFSET_MASK))
edde275acba04aca58db4172a163741e3abadfbcvboxsync rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.pShimData, PAGE_SIZE, "pShimData", pErrInfo);
edde275acba04aca58db4172a163741e3abadfbcvboxsync if (RT_SUCCESS(rc) && Peb.ActivationContextData && !((uintptr_t)Peb.ActivationContextData & PAGE_OFFSET_MASK))
edde275acba04aca58db4172a163741e3abadfbcvboxsync rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.ActivationContextData, PAGE_SIZE, "ActivationContextData", pErrInfo);
edde275acba04aca58db4172a163741e3abadfbcvboxsync if (RT_SUCCESS(rc) && Peb.ProcessAssemblyStorageMap && !((uintptr_t)Peb.ProcessAssemblyStorageMap & PAGE_OFFSET_MASK))
edde275acba04aca58db4172a163741e3abadfbcvboxsync rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.ProcessAssemblyStorageMap, PAGE_SIZE, "ProcessAssemblyStorageMap", pErrInfo);
edde275acba04aca58db4172a163741e3abadfbcvboxsync if (RT_SUCCESS(rc) && Peb.SystemDefaultActivationContextData && !((uintptr_t)Peb.SystemDefaultActivationContextData & PAGE_OFFSET_MASK))
edde275acba04aca58db4172a163741e3abadfbcvboxsync rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.ProcessAssemblyStorageMap, PAGE_SIZE, "SystemDefaultActivationContextData", pErrInfo);
edde275acba04aca58db4172a163741e3abadfbcvboxsync if (RT_SUCCESS(rc) && Peb.SystemAssemblyStorageMap && !((uintptr_t)Peb.SystemAssemblyStorageMap & PAGE_OFFSET_MASK))
edde275acba04aca58db4172a163741e3abadfbcvboxsync rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.SystemAssemblyStorageMap, PAGE_SIZE, "SystemAssemblyStorageMap", pErrInfo);
edde275acba04aca58db4172a163741e3abadfbcvboxsync * Clear compatibility and activation related fields.
edde275acba04aca58db4172a163741e3abadfbcvboxsync /*Peb.Diff0.W6.IsProtectedProcess = 1;*/
edde275acba04aca58db4172a163741e3abadfbcvboxsync * Write back the PEB.
edde275acba04aca58db4172a163741e3abadfbcvboxsync NTSTATUS rcNt = NtWriteVirtualMemory(pThis->hProcess, pThis->BasicInfo.PebBaseAddress, &Peb, pThis->cbPeb, &cbActualMem);
edde275acba04aca58db4172a163741e3abadfbcvboxsync return RTErrInfoSetF(pThis->pErrInfo, VERR_GENERAL_FAILURE, "NtWriteVirtualMemory/Peb failed: %#x", rcNt);
f3b077ba3204fcb9c310e3929340db83bc9b77cdvboxsyncstatic void supR3HardNtPuChFindNtdll(PSUPR3HARDNTPUCH pThis)
f3b077ba3204fcb9c310e3929340db83bc9b77cdvboxsync * Find NTDLL in this process first and take that as a starting point.
f3b077ba3204fcb9c310e3929340db83bc9b77cdvboxsync pThis->uNtDllParentAddr = (uintptr_t)GetModuleHandleW(L"ntdll.dll");
f3b077ba3204fcb9c310e3929340db83bc9b77cdvboxsync SUPR3HARDENED_ASSERT(pThis->uNtDllParentAddr != 0 && !(pThis->uNtDllParentAddr & PAGE_OFFSET_MASK));
f3b077ba3204fcb9c310e3929340db83bc9b77cdvboxsync * Scan the virtual memory of the child.
f3b077ba3204fcb9c310e3929340db83bc9b77cdvboxsync /* Query information. */
f3b077ba3204fcb9c310e3929340db83bc9b77cdvboxsync MEMORY_BASIC_INFORMATION MemInfo = { 0, 0, 0, 0, 0, 0, 0 };
f3b077ba3204fcb9c310e3929340db83bc9b77cdvboxsync NTSTATUS rcNt = NtQueryVirtualMemory(pThis->hProcess,
f3b077ba3204fcb9c310e3929340db83bc9b77cdvboxsync (void const *)uPtrWhere,
f3b077ba3204fcb9c310e3929340db83bc9b77cdvboxsync || MemInfo.Type == (SEC_IMAGE | SEC_PROTECTED_IMAGE))
f3b077ba3204fcb9c310e3929340db83bc9b77cdvboxsync /* Get the image name. */
f3b077ba3204fcb9c310e3929340db83bc9b77cdvboxsync NTSTATUS rcNt = NtQueryVirtualMemory(pThis->hProcess,
f3b077ba3204fcb9c310e3929340db83bc9b77cdvboxsync uBuf.UniStr.Buffer[uBuf.UniStr.Length / sizeof(WCHAR)] = '\0';
dca3cdd56f38abf4257b94ff13268323ea52e0a7vboxsync if (supR3HardNtIsNamedSystem32Dll(&uBuf.UniStr, "ntdll.dll"))
dca3cdd56f38abf4257b94ff13268323ea52e0a7vboxsync pThis->uNtDllAddr = (uintptr_t)MemInfo.AllocationBase;
dca3cdd56f38abf4257b94ff13268323ea52e0a7vboxsync SUP_DPRINTF(("supR3HardNtPuChFindNtdll: uNtDllParentAddr=%p uNtDllChildAddr=%p\n",
f3b077ba3204fcb9c310e3929340db83bc9b77cdvboxsync supR3HardenedFatal("%s: ntdll.dll not found in child.", __FUNCTION__);
edde275acba04aca58db4172a163741e3abadfbcvboxsyncstatic int supR3HardenedWinPurifyChild(HANDLE hProcess, HANDLE hThread, PRTERRINFO pErrInfo)
edde275acba04aca58db4172a163741e3abadfbcvboxsync * Initialize the purifier instance data.
edde275acba04aca58db4172a163741e3abadfbcvboxsync NTSTATUS rcNt = NtQueryInformationProcess(hProcess, ProcessBasicInformation,
edde275acba04aca58db4172a163741e3abadfbcvboxsync &This.BasicInfo, sizeof(This.BasicInfo), &cbActual);
edde275acba04aca58db4172a163741e3abadfbcvboxsync return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
edde275acba04aca58db4172a163741e3abadfbcvboxsync "NtQueryInformationProcess/ProcessBasicInformation failed: %#x", rcNt);
b2560fc359a998cb1002e5de6eba0ef716d48803vboxsync SUP_DPRINTF(("supR3HardenedWinPurifyChild: PebBaseAddress=%p cbPeb=%#x\n", This.BasicInfo.PebBaseAddress, This.cbPeb));
edde275acba04aca58db4172a163741e3abadfbcvboxsync rcNt = NtReadVirtualMemory(hProcess, This.BasicInfo.PebBaseAddress, &This.Peb, sizeof(This.Peb), &cbActualMem);
edde275acba04aca58db4172a163741e3abadfbcvboxsync return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, "NtReadVirtualMemory/Peb failed: %#x", rcNt);
7d6ce198fd361f58bd1ebdeee7772f76b4e58966vboxsync * Do the work, the last bit we tag along with the process verfication code.
edde275acba04aca58db4172a163741e3abadfbcvboxsync int rc = supR3HardNtPuChScrewUpPebForInitialImageEvents(&This);
edde275acba04aca58db4172a163741e3abadfbcvboxsync rc = supR3HardNtPuChTriggerInitialImageEvents(&This);
e352c25b01398e5503235fed02436cb2992f1021vboxsync rc = supHardenedWinVerifyProcess(hProcess, hThread, SUPHARDNTVPKIND_CHILD_PURIFICATION, NULL /*pcFixes*/, pErrInfo);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Does the actually respawning.
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync * @returns Never, will call exit or raise fatal error.
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync * @param iWhich Which respawn we're to check for, 1 being the
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync * first one, and 2 the second and final.
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync * @todo Split up this function.
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync PRTL_USER_PROCESS_PARAMETERS pParentProcParams = pPeb->ProcessParameters;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync SUPR3HARDENED_ASSERT(g_cSuplibHardenedWindowsMainCalls == 1);
edde275acba04aca58db4172a163741e3abadfbcvboxsync * Set up security descriptors.
edde275acba04aca58db4172a163741e3abadfbcvboxsync supR3HardenedInitSecAttrs(&ProcessSecAttrs, &ProcessSecAttrsCleanup, true /*fProcess*/);
edde275acba04aca58db4172a163741e3abadfbcvboxsync supR3HardenedInitSecAttrs(&ThreadSecAttrs, &ThreadSecAttrsCleanup, false /*fProcess*/);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Configure the startup info and creation flags.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** @todo experiment with protected process stuff later on. */
a505d18eaecf5f7faff58cc7c05397f8adaf6d71vboxsync SiEx.StartupInfo.dwFlags |= pParentProcParams->WindowFlags & STARTF_USESHOWWINDOW;
0aab9cd857ec35928a0e61c68d3f27a5b4d88a95vboxsync SiEx.StartupInfo.wShowWindow = (WORD)pParentProcParams->ShowWindowFlags;
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync SiEx.StartupInfo.hStdInput = pParentProcParams->StandardInput;
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync SiEx.StartupInfo.hStdOutput = pParentProcParams->StandardOutput;
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync SiEx.StartupInfo.hStdError = pParentProcParams->StandardError;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Construct the command line and launch the process.
edde275acba04aca58db4172a163741e3abadfbcvboxsync PRTUTF16 pwszCmdLine = supR3HardenedWinConstructCmdLine(NULL, iWhich);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Misc, VERR_INVALID_NAME,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "Error relaunching VirtualBox VM process: %u\n"
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "Command line: '%ls'",
b2560fc359a998cb1002e5de6eba0ef716d48803vboxsync SUP_DPRINTF(("supR3HardenedWinDoReSpawn(%d): New child %x.%x [kernel32].\n",
b2560fc359a998cb1002e5de6eba0ef716d48803vboxsync iWhich, ProcessInfoW32.dwProcessId, ProcessInfoW32.dwThreadId));
edde275acba04aca58db4172a163741e3abadfbcvboxsync * Construct the process parameters.
edde275acba04aca58db4172a163741e3abadfbcvboxsync W32ImageName.Buffer = g_wszSupLibHardenedExePath; /* Yes the windows name for the process parameters. */
edde275acba04aca58db4172a163741e3abadfbcvboxsync W32ImageName.Length = (USHORT)RTUtf16Len(g_wszSupLibHardenedExePath) * sizeof(WCHAR);
edde275acba04aca58db4172a163741e3abadfbcvboxsync W32ImageName.MaximumLength = W32ImageName.Length + sizeof(WCHAR);
edde275acba04aca58db4172a163741e3abadfbcvboxsync supR3HardenedWinConstructCmdLine(&CmdLine, iWhich);
edde275acba04aca58db4172a163741e3abadfbcvboxsync SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCreateProcessParameters(&pProcParams,
edde275acba04aca58db4172a163741e3abadfbcvboxsync NULL /* CurrentDirectory - inherit from this process */,
edde275acba04aca58db4172a163741e3abadfbcvboxsync NULL /* Environment - inherit from this process */,
edde275acba04aca58db4172a163741e3abadfbcvboxsync NULL /* RuntimeInfo - none (byte array for MSVCRT file info) */)
edde275acba04aca58db4172a163741e3abadfbcvboxsync /** @todo this doesn't work. :-( */
edde275acba04aca58db4172a163741e3abadfbcvboxsync pProcParams->ConsoleHandle = pParentProcParams->ConsoleHandle;
edde275acba04aca58db4172a163741e3abadfbcvboxsync pProcParams->ConsoleFlags = pParentProcParams->ConsoleFlags;
edde275acba04aca58db4172a163741e3abadfbcvboxsync pProcParams->StandardInput = pParentProcParams->StandardInput;
edde275acba04aca58db4172a163741e3abadfbcvboxsync pProcParams->StandardOutput = pParentProcParams->StandardOutput;
edde275acba04aca58db4172a163741e3abadfbcvboxsync pProcParams->StandardError = pParentProcParams->StandardError;
edde275acba04aca58db4172a163741e3abadfbcvboxsync RTL_USER_PROCESS_INFORMATION ProcessInfoNt = { sizeof(ProcessInfoNt) };
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync rcNt = RtlCreateUserProcess(&g_SupLibHardenedExeNtPath.UniStr,
edde275acba04aca58db4172a163741e3abadfbcvboxsync supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Misc, VERR_INVALID_NAME,
edde275acba04aca58db4172a163741e3abadfbcvboxsync "Error relaunching VirtualBox VM process: %#x\n"
edde275acba04aca58db4172a163741e3abadfbcvboxsync "Command line: '%ls'",
b2560fc359a998cb1002e5de6eba0ef716d48803vboxsync SUP_DPRINTF(("supR3HardenedWinDoReSpawn(%d): New child %x.%x [ntdll].\n",
b2560fc359a998cb1002e5de6eba0ef716d48803vboxsync iWhich, ProcessInfo.ClientId.UniqueProcess, ProcessInfo.ClientId.UniqueThread));
7d6ce198fd361f58bd1ebdeee7772f76b4e58966vboxsync * Apply anti debugger notification trick to the thread. (Also done in
7d6ce198fd361f58bd1ebdeee7772f76b4e58966vboxsync * supR3HardenedWinInstallHooks.)
7d6ce198fd361f58bd1ebdeee7772f76b4e58966vboxsync rcNt = NtSetInformationThread(NtCurrentThread(), ThreadHideFromDebugger, NULL, 0);
7d6ce198fd361f58bd1ebdeee7772f76b4e58966vboxsync NtTerminateProcess(hProcess, DBG_TERMINATE_PROCESS);
7d6ce198fd361f58bd1ebdeee7772f76b4e58966vboxsync supR3HardenedError(rcNt, true /*fFatal*/, "NtSetInformationThread/ThreadHideFromDebugger failed: %#x\n", rcNt);
edde275acba04aca58db4172a163741e3abadfbcvboxsync * Clean up the process.
edde275acba04aca58db4172a163741e3abadfbcvboxsync int rc = supR3HardenedWinPurifyChild(hProcess, hThread, RTErrInfoInitStatic(&g_ErrInfoStatic));
edde275acba04aca58db4172a163741e3abadfbcvboxsync NtTerminateProcess(hProcess, DBG_TERMINATE_PROCESS);
edde275acba04aca58db4172a163741e3abadfbcvboxsync supR3HardenedError(rc, true /*fFatal*/, "%s", g_ErrInfoStatic.szMsg);
edde275acba04aca58db4172a163741e3abadfbcvboxsync * Start the process execution.
edde275acba04aca58db4172a163741e3abadfbcvboxsync SUPR3HARDENED_ASSERT_NT_SUCCESS(NtResumeThread(hThread, &cSuspendCount));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Close the unrestricted access handles. Since we need to wait on the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * child process, we'll reopen the process with limited access before doing
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * away with the process handle returned by CreateProcess.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0)) /* Introduced in Vista. */
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync rcNt = NtDuplicateObject(NtCurrentProcess(), hProcess,
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync rcNt = NtDuplicateObject(NtCurrentProcess(), hProcess,
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync /* Failure is unacceptable, kill the process. */
b2560fc359a998cb1002e5de6eba0ef716d48803vboxsync supR3HardenedError(rcNt, false /*fFatal*/, "NtDuplicateObject failed on child process handle: %#x\n", rcNt);
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync NTSTATUS rcNtExit = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync bool fExitOk = NT_SUCCESS(rcNtExit) && BasicInfo.ExitStatus != STATUS_PENDING;
edde275acba04aca58db4172a163741e3abadfbcvboxsync NtTerminateProcess(hProcess, DBG_TERMINATE_PROCESS);
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync rcNtWait = NtWaitForSingleObject(hProcess, TRUE /*Alertable*/, &Timeout);
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync rcNtExit = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync fExitOk = NT_SUCCESS(rcNtExit) && BasicInfo.ExitStatus != STATUS_PENDING;
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync "NtDuplicateObject failed and we failed to kill child: rcNt=%u rcNtWait=%u hProcess=%p\n",
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Misc, VERR_INVALID_NAME,
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync "NtDuplicateObject failed on child process handle: %#x\n", rcNt);
edde275acba04aca58db4172a163741e3abadfbcvboxsync SUPR3HARDENED_ASSERT_NT_SUCCESS(NtClose(hProcess));
bfc39c8324b2a90c8cb3fedf883495d1ed92e724vboxsync * Ditch the loader cache so we don't sit on too much memory while waiting.
71e448b6623e801f76cb68355a28500169de5695vboxsync * Enable thread creation at this point so Ctrl-C and Ctrl-Break can be processed.
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync * If this is the middle process, wait for both parent and child to quit.
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync rcNt = NtQueryInformationProcess(NtCurrentProcess(), ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync InitializeObjectAttributes(&ObjAttr, NULL, 0, NULL /*hRootDir*/, NULL /*pSecDesc*/);
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync ClientId.UniqueProcess = (HANDLE)BasicInfo.InheritedFromUniqueProcessId;
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync rcNt = NtOpenProcess(&hParent, SYNCHRONIZE | PROCESS_QUERY_INFORMATION, &ObjAttr, &ClientId);
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync rcNt = NtWaitForMultipleObjects(2, &ahHandles[0], WaitAnyObject, TRUE /*Alertable*/, NULL /*pTimeout*/);
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync supR3HardenedFatal("NtWaitForMultipleObjects returned %#x\n", rcNt);
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync * Wait for the process to terminate.
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync rcNt = NtWaitForSingleObject(hProcWait, TRUE /*Alertable*/, NULL /*pTimeout*/);
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync supR3HardenedFatal("NtWaitForSingleObject returned %#x\n", rcNt);
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync * Proxy the termination code of the child, if it exited already.
b2560fc359a998cb1002e5de6eba0ef716d48803vboxsync NTSTATUS rcNt2 = NtQueryInformationProcess(hProcWait, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
dca3cdd56f38abf4257b94ff13268323ea52e0a7vboxsync SUP_DPRINTF(("supR3HardenedWinDoReSpawn(%d): Quitting: ExitCode=%#x rcNt=%#x\n", iWhich, BasicInfo.ExitStatus, rcNt));
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync suplibHardenedExit((RTEXITCODE)BasicInfo.ExitStatus);
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync * Logs the content of the given object directory.
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync * @returns true if it exists, false if not.
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync * @param pszDir The path of the directory to log (ASCII).
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsyncstatic void supR3HardenedWinLogObjDir(const char *pszDir)
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync * Open the driver object directory.
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync int rc = RTUtf16CopyAscii(wszDir, RT_ELEMENTS(wszDir), pszDir);
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync SUP_DPRINTF(("supR3HardenedWinLogObjDir: RTUtf16CopyAscii -> %Rrc on '%s'\n", rc, pszDir));
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync NtDirName.Length = (USHORT)(RTUtf16Len(wszDir) * sizeof(WCHAR));
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync NtDirName.MaximumLength = NtDirName.Length + sizeof(WCHAR);
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync InitializeObjectAttributes(&ObjAttr, &NtDirName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync NTSTATUS rcNt = NtOpenDirectoryObject(&hDir, DIRECTORY_QUERY | FILE_LIST_DIRECTORY, &ObjAttr);
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync SUP_DPRINTF(("supR3HardenedWinLogObjDir: %ls => %#x\n", wszDir, rcNt));
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync * Enumerate it, looking for the driver.
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync sizeof(abBuffer) - 4, /* minus four for string terminator space. */
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync if (!NT_SUCCESS(rcNt) || cbActual < sizeof(OBJECT_DIRECTORY_INFORMATION))
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync SUP_DPRINTF(("supR3HardenedWinLogObjDir: NtQueryDirectoryObject => rcNt=%#x cbActual=%#x\n", rcNt, cbActual));
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync POBJECT_DIRECTORY_INFORMATION pObjDir = (POBJECT_DIRECTORY_INFORMATION)abBuffer;
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync WCHAR wcSaved = pObjDir->Name.Buffer[pObjDir->Name.Length / sizeof(WCHAR)];
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync pObjDir->TypeName.Length / sizeof(WCHAR), pObjDir->TypeName.Buffer,
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync pObjDir->Name.Length / sizeof(WCHAR), pObjDir->Name.Buffer));
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync /* Next directory entry. */
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync * Clean up and return.
edde275acba04aca58db4172a163741e3abadfbcvboxsync * Checks if the driver exists.
edde275acba04aca58db4172a163741e3abadfbcvboxsync * This checks whether the driver is present in the /Driver object directory.
edde275acba04aca58db4172a163741e3abadfbcvboxsync * Drivers being initialized or terminated will have an object there
edde275acba04aca58db4172a163741e3abadfbcvboxsync * before/after their devices nodes are created/deleted.
edde275acba04aca58db4172a163741e3abadfbcvboxsync * @returns true if it exists, false if not.
edde275acba04aca58db4172a163741e3abadfbcvboxsync * @param pszDriver The driver name.
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsyncstatic bool supR3HardenedWinDriverExists(const char *pszDriver)
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync * Open the driver object directory.
eca3ddadc12f677ac68395c5eab914d41fc8963avboxsync UNICODE_STRING NtDirName = RTNT_CONSTANT_UNISTR(L"\\Driver");
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync InitializeObjectAttributes(&ObjAttr, &NtDirName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync NTSTATUS rcNt = NtOpenDirectoryObject(&hDir, DIRECTORY_QUERY | FILE_LIST_DIRECTORY, &ObjAttr);
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync return true;
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync * Enumerate it, looking for the driver.
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync bool fFound = true;
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync sizeof(abBuffer) - 4, /* minus four for string terminator space. */
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync if (!NT_SUCCESS(rcNt) || cbActual < sizeof(OBJECT_DIRECTORY_INFORMATION))
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync POBJECT_DIRECTORY_INFORMATION pObjDir = (POBJECT_DIRECTORY_INFORMATION)abBuffer;
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync WCHAR wcSaved = pObjDir->Name.Buffer[pObjDir->Name.Length / sizeof(WCHAR)];
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync pObjDir->Name.Buffer[pObjDir->Name.Length / sizeof(WCHAR)] = '\0';
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync && RTUtf16ICmpAscii(pObjDir->Name.Buffer, pszDriver) == 0)
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync pObjDir->Name.Buffer[pObjDir->Name.Length / sizeof(WCHAR)] = wcSaved;
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync /* Next directory entry. */
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync * Clean up and return.
edde275acba04aca58db4172a163741e3abadfbcvboxsync * Open the stub device before the 2nd respawn.
edde275acba04aca58db4172a163741e3abadfbcvboxsync * Retry if we think driver might still be initializing (STATUS_NO_SUCH_DEVICE + \Drivers\VBoxDrv).
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync static const WCHAR s_wszName[] = L"\\Device\\VBoxDrvStub";
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync 0 /*EaLength*/);
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync /* The STATUS_NO_SUCH_DEVICE might be returned if the device is not
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync completely initialized. Delay a little bit and try again. */
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync if (iTry > 0 && GetTickCount() - uStartTick > 5000) /* 5 sec, at least two tries */
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync /** @todo Consider starting the VBoxdrv.sys service. Requires 2nd process
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync * though, rather complicated actually as CreateProcess causes all
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync * kind of things to happen to this process which would make it hard to
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync * pass the process verification tests... :-/ */
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync Time.QuadPart = -1000000 / 100; /* 1ms in 100ns units, relative time. */
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync Time.QuadPart = -32000000 / 100; /* 32ms in 100ns units, relative time. */
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync * Report trouble (fatal). For some errors codes we try gather some
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync * extra information that goes into VBoxStartup.log so that we stand a
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync * better chance resolving the issue.
40839c441cb305d84420565f7ca25403d8177413vboxsync if (SUP_NT_STATUS_IS_VBOX(rcNt)) /* See VBoxDrvNtErr2NtStatus. */
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync * \Windows\ApiPort open trouble. So far only
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync * STATUS_OBJECT_TYPE_MISMATCH has been observed.
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync SUP_DPRINTF(("Error opening VBoxDrvStub: VERR_SUPDRV_APIPORT_OPEN_ERROR\n"));
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync RTStrPrintf(szDir, sizeof(szDir), "\\Sessions\\%u\\Windows", uSessionId);
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Misc, rc,
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync "NtCreateFile(%ls) failed: VERR_SUPDRV_APIPORT_OPEN_ERROR\n"
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync "Error getting %s\\ApiPort in the driver from vboxdrv.\n"
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync "Could be due to security software is redirecting access to it, so please include full "
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync "details of such software in a bug report. VBoxStartup.log may contain details important "
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync "to resolving the issue."
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync * Generic VBox failure message.
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Driver, rc,
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync "NtCreateFile(%ls) failed: %Rrc (rcNt=%#x)\n", s_wszName, rc, rcNt);
485f31dd3495c289f625c9c5b900cf0b95838ed6vboxsync case STATUS_NO_SUCH_DEVICE: pszDefine = " STATUS_NO_SUCH_DEVICE"; break;
485f31dd3495c289f625c9c5b900cf0b95838ed6vboxsync case STATUS_OBJECT_NAME_NOT_FOUND: pszDefine = " STATUS_OBJECT_NAME_NOT_FOUND"; break;
485f31dd3495c289f625c9c5b900cf0b95838ed6vboxsync case STATUS_ACCESS_DENIED: pszDefine = " STATUS_ACCESS_DENIED"; break;
485f31dd3495c289f625c9c5b900cf0b95838ed6vboxsync case STATUS_TRUST_FAILURE: pszDefine = " STATUS_TRUST_FAILURE"; break;
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync * Problems opening the device is generally due to driver load/
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync * unload issues. Check whether the driver is loaded and make
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync * suggestions accordingly.
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync SUP_DPRINTF(("Error opening VBoxDrvStub: %s\n", pszDefine));
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Driver, VERR_OPEN_FAILED,
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync "NtCreateFile(%ls) failed: %#x%s (%u retries)\n"
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync "Driver is probably stuck stopping/starting. Try 'sc.exe query vboxdrv' to get more "
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync "information about its state. Rebooting may actually help.\n"
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Driver, VERR_OPEN_FAILED,
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync "NtCreateFile(%ls) failed: %#x%s (%u retries)\n"
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync "Driver is does not appear to be loaded. Try 'sc.exe start vboxdrv', reinstall "
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync "VirtualBox or reboot.\n"
681f9c8332e6b5a57c59e898d1edcc150423223dvboxsync /* Generic NT failure message. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Driver, VERR_OPEN_FAILED,
4221c34ed2180fbc3a82504145c4a66c589e9e6avboxsync "NtCreateFile(%ls) failed: %#x%s (%u retries)\n", s_wszName, rcNt, pszDefine, iTry);
edde275acba04aca58db4172a163741e3abadfbcvboxsync * Called by the main code if supR3HardenedWinIsReSpawnNeeded returns @c true.
edde275acba04aca58db4172a163741e3abadfbcvboxsync * @returns Program exit code.
edde275acba04aca58db4172a163741e3abadfbcvboxsync * Before the 2nd respawn we set up a child protection deal with the
edde275acba04aca58db4172a163741e3abadfbcvboxsync * support driver via /Devices/VBoxDrvStub.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Respawn the process with kernel protection for the new process.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Checks if re-spawning is required, replacing the respawn argument if not.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @returns true if required, false if not. In the latter case, the first
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * argument in the vector is replaced.
edde275acba04aca58db4172a163741e3abadfbcvboxsync * @param iWhich Which respawn we're to check for, 1 being the
edde275acba04aca58db4172a163741e3abadfbcvboxsync * first one, and 2 the second and final.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param cArgs The number of arguments.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param papszArgs Pointer to the argument vector.
edde275acba04aca58db4172a163741e3abadfbcvboxsyncDECLHIDDEN(bool) supR3HardenedWinIsReSpawnNeeded(int iWhich, int cArgs, char **papszArgs)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync SUPR3HARDENED_ASSERT(g_cSuplibHardenedWindowsMainCalls == 1);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return true;
edde275acba04aca58db4172a163741e3abadfbcvboxsync if (suplibHardenedStrCmp(papszArgs[0], SUPR3_RESPAWN_1_ARG0) == 0)
edde275acba04aca58db4172a163741e3abadfbcvboxsync return true;
edde275acba04aca58db4172a163741e3abadfbcvboxsync else if (suplibHardenedStrCmp(papszArgs[0], SUPR3_RESPAWN_2_ARG0) == 0)
edde275acba04aca58db4172a163741e3abadfbcvboxsync return false;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return true;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Replace the argument. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return false;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Initializes the windows verficiation bits.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param fFlags The main flags.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncDECLHIDDEN(void) supR3HardenedWinInit(uint32_t fFlags)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync int rc = supHardenedWinInitImageVerifier(&g_ErrInfoStatic.Core);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync supR3HardenedFatalMsg("supR3HardenedWinInit", kSupInitOp_Misc, rc,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "supHardenedWinInitImageVerifier failed: %s", g_ErrInfoStatic.szMsg);
5de281ea9954eecffbd1ba604603cc8e8347e700vboxsync * Do a self purification to cure avast's weird NtOpenFile write-thru
5de281ea9954eecffbd1ba604603cc8e8347e700vboxsync * change in GetBinaryTypeW change in kernel32. Unfortunately, avast
5de281ea9954eecffbd1ba604603cc8e8347e700vboxsync * uses a system thread to perform the process modifications, which
5de281ea9954eecffbd1ba604603cc8e8347e700vboxsync * means it's hard to make sure it had the chance to make them...
5de281ea9954eecffbd1ba604603cc8e8347e700vboxsync * We have to resort to kludge doing yield and sleep fudging for a
5de281ea9954eecffbd1ba604603cc8e8347e700vboxsync * number of milliseconds and schedulings before we can hope that avast
e352c25b01398e5503235fed02436cb2992f1021vboxsync * and similar products have done what they need to do. If we do any
e352c25b01398e5503235fed02436cb2992f1021vboxsync * fixes, we wait for a while again and redo it until we're clean.
e352c25b01398e5503235fed02436cb2992f1021vboxsync * This is unfortunately kind of fragile.
e352c25b01398e5503235fed02436cb2992f1021vboxsync Time.QuadPart = -8000000 / 100; /* 8ms in 100ns units, relative time. */
e352c25b01398e5503235fed02436cb2992f1021vboxsync SUP_DPRINTF(("supR3HardenedWinInit: Startup delay kludge #2/%u: %u ms, %u sleeps\n",
e352c25b01398e5503235fed02436cb2992f1021vboxsync rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_SELF_PURIFICATION,
beed5fc4d17b85d6d05516ae63e6308af82ad96fvboxsync SUP_DPRINTF(("supR3HardenedWinInit: cFixes=%u g_fSupAdversaries=%#x\n", cFixes, g_fSupAdversaries));
5de281ea9954eecffbd1ba604603cc8e8347e700vboxsync * Install the hooks.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Complain about Vista w/o service pack if we're launching a VM.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync && g_uNtVerCombined < SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync supR3HardenedFatalMsg("supR3HardenedWinInit", kSupInitOp_Misc, VERR_NOT_SUPPORTED,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "Window Vista without any service pack installed is not supported. Please install the latest service pack.");
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Converts the Windows command line string (UTF-16) to an array of UTF-8
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * arguments suitable for passing to main().
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @returns Pointer to the argument array.
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync * @param pawcCmdLine The UTF-16 windows command line to parse.
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync * @param cwcCmdLine The length of the command line.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param pcArgs Where to return the number of arguments.
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsyncstatic char **suplibCommandLineToArgvWStub(PCRTUTF16 pawcCmdLine, size_t cwcCmdLine, int *pcArgs)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Convert the command line string to UTF-8.
3c520cf6887d9039d9aa7cf3bbe81fd7de1ffd4cvboxsync SUPR3HARDENED_ASSERT(RT_SUCCESS(RTUtf16ToUtf8Ex(pawcCmdLine, cwcCmdLine, &pszCmdLine, 0, NULL)));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Parse the command line, carving argument strings out of it.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync char **papszArgs = (char **)suplibHardenedAllocZ(sizeof(char *) * cArgsAllocated);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* skip leading blanks. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Add argument to the vector. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync papszArgs = (char **)suplibHardenedReAlloc(papszArgs, sizeof(char *) * cArgsAllocated);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Unquote and unescape the string. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync bool fQuoted = false;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else if (ch != '\\' || (*pszSrc != '\\' && *pszSrc != '"'))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync unsigned cSlashes = 0;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync while (cSlashes-- > 0)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync } while (ch != '\0' && (fQuoted || !suplibCommandLineIsArgSeparator(ch)));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Terminate the argument. */
100b161379af7255c69e27587cc746e5f76ff050vboxsync * Logs information about a file from a protection product.
100b161379af7255c69e27587cc746e5f76ff050vboxsync * The purpose here is to better see which version of the product is installed
100b161379af7255c69e27587cc746e5f76ff050vboxsync * and not needing to depend on the user supplying the correct information.
100b161379af7255c69e27587cc746e5f76ff050vboxsync * @param pwszFile The NT path to the file.
100b161379af7255c69e27587cc746e5f76ff050vboxsyncstatic void supR3HardenedLogAdversarialFile(PCRTUTF16 pwszFile)
100b161379af7255c69e27587cc746e5f76ff050vboxsync * Open the file.
100b161379af7255c69e27587cc746e5f76ff050vboxsync IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
100b161379af7255c69e27587cc746e5f76ff050vboxsync UniStrName.Length = (USHORT)(RTUtf16Len(pwszFile) * sizeof(WCHAR));
100b161379af7255c69e27587cc746e5f76ff050vboxsync UniStrName.MaximumLength = UniStrName.Length + sizeof(WCHAR);
100b161379af7255c69e27587cc746e5f76ff050vboxsync InitializeObjectAttributes(&ObjAttr, &UniStrName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
100b161379af7255c69e27587cc746e5f76ff050vboxsync 0 /*EaLength*/);
100b161379af7255c69e27587cc746e5f76ff050vboxsync * Print basic file information available via NtQueryInformationFile.
100b161379af7255c69e27587cc746e5f76ff050vboxsync IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
100b161379af7255c69e27587cc746e5f76ff050vboxsync rcNt = NtQueryInformationFile(hFile, &Ios, &u.BasicInfo, sizeof(u.BasicInfo), FileBasicInformation);
100b161379af7255c69e27587cc746e5f76ff050vboxsync SUP_DPRINTF((" CreationTime: %s\n", RTTimeSpecToString(RTTimeSpecSetNtTime(&TimeSpec, u.BasicInfo.CreationTime.QuadPart), szTmp, sizeof(szTmp))));
100b161379af7255c69e27587cc746e5f76ff050vboxsync /*SUP_DPRINTF((" LastAccessTime: %s\n", RTTimeSpecToString(RTTimeSpecSetNtTime(&TimeSpec, u.BasicInfo.LastAccessTime.QuadPart), szTmp, sizeof(szTmp))));*/
100b161379af7255c69e27587cc746e5f76ff050vboxsync SUP_DPRINTF((" LastWriteTime: %s\n", RTTimeSpecToString(RTTimeSpecSetNtTime(&TimeSpec, u.BasicInfo.LastWriteTime.QuadPart), szTmp, sizeof(szTmp))));
100b161379af7255c69e27587cc746e5f76ff050vboxsync SUP_DPRINTF((" ChangeTime: %s\n", RTTimeSpecToString(RTTimeSpecSetNtTime(&TimeSpec, u.BasicInfo.ChangeTime.QuadPart), szTmp, sizeof(szTmp))));
100b161379af7255c69e27587cc746e5f76ff050vboxsync SUP_DPRINTF((" FileAttributes: %#x\n", u.BasicInfo.FileAttributes));
100b161379af7255c69e27587cc746e5f76ff050vboxsync SUP_DPRINTF((" FileBasicInformation -> %#x %#x\n", rcNt, Ios.Status));
100b161379af7255c69e27587cc746e5f76ff050vboxsync rcNt = NtQueryInformationFile(hFile, &Ios, &u.StdInfo, sizeof(u.StdInfo), FileStandardInformation);
100b161379af7255c69e27587cc746e5f76ff050vboxsync SUP_DPRINTF((" Size: %#llx\n", u.StdInfo.EndOfFile.QuadPart));
100b161379af7255c69e27587cc746e5f76ff050vboxsync SUP_DPRINTF((" FileStandardInformation -> %#x %#x\n", rcNt, Ios.Status));
100b161379af7255c69e27587cc746e5f76ff050vboxsync * Read the image header and extract the timestamp and other useful info.
100b161379af7255c69e27587cc746e5f76ff050vboxsync rcNt = NtReadFile(hFile, NULL /*hEvent*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/, &Ios,
100b161379af7255c69e27587cc746e5f76ff050vboxsync if (offNtHdrs < sizeof(u) - sizeof(IMAGE_NT_HEADERS))
100b161379af7255c69e27587cc746e5f76ff050vboxsync PIMAGE_NT_HEADERS64 pNtHdrs64 = (PIMAGE_NT_HEADERS64)&u.abBuf[offNtHdrs];
100b161379af7255c69e27587cc746e5f76ff050vboxsync PIMAGE_NT_HEADERS32 pNtHdrs32 = (PIMAGE_NT_HEADERS32)&u.abBuf[offNtHdrs];
100b161379af7255c69e27587cc746e5f76ff050vboxsync SUP_DPRINTF((" Timestamp: %#x\n", pNtHdrs64->FileHeader.TimeDateStamp));
100b161379af7255c69e27587cc746e5f76ff050vboxsync SUP_DPRINTF((" Machine: %#x%s\n", pNtHdrs64->FileHeader.Machine,
100b161379af7255c69e27587cc746e5f76ff050vboxsync pNtHdrs64->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 ? " - i386"
100b161379af7255c69e27587cc746e5f76ff050vboxsync : pNtHdrs64->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64 ? " - amd64" : ""));
100b161379af7255c69e27587cc746e5f76ff050vboxsync SUP_DPRINTF((" Timestamp: %#x\n", pNtHdrs64->FileHeader.TimeDateStamp));
100b161379af7255c69e27587cc746e5f76ff050vboxsync pNtHdrs64->OptionalHeader.MajorImageVersion, pNtHdrs64->OptionalHeader.MinorImageVersion));
100b161379af7255c69e27587cc746e5f76ff050vboxsync SUP_DPRINTF((" SizeOfImage: %#x (%u)\n", pNtHdrs64->OptionalHeader.SizeOfImage, pNtHdrs64->OptionalHeader.SizeOfImage));
100b161379af7255c69e27587cc746e5f76ff050vboxsync * Very crude way to extract info from the file version resource.
100b161379af7255c69e27587cc746e5f76ff050vboxsync PIMAGE_SECTION_HEADER paSectHdrs = (PIMAGE_SECTION_HEADER)( (uintptr_t)&pNtHdrs64->OptionalHeader
100b161379af7255c69e27587cc746e5f76ff050vboxsync if ( pNtHdrs64->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64)
100b161379af7255c69e27587cc746e5f76ff050vboxsync && pNtHdrs64->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_RESOURCE)
100b161379af7255c69e27587cc746e5f76ff050vboxsync RsrcDir = pNtHdrs64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
100b161379af7255c69e27587cc746e5f76ff050vboxsync else if ( pNtHdrs64->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
100b161379af7255c69e27587cc746e5f76ff050vboxsync && pNtHdrs32->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_RESOURCE)
100b161379af7255c69e27587cc746e5f76ff050vboxsync RsrcDir = pNtHdrs32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
100b161379af7255c69e27587cc746e5f76ff050vboxsync SUP_DPRINTF((" Resource Dir: %#x LB %#x\n", RsrcDir.VirtualAddress, RsrcDir.Size));
100b161379af7255c69e27587cc746e5f76ff050vboxsync && (uintptr_t)&u + sizeof(u) - (uintptr_t)paSectHdrs
100b161379af7255c69e27587cc746e5f76ff050vboxsync >= pNtHdrs64->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER) )
100b161379af7255c69e27587cc746e5f76ff050vboxsync for (uint32_t i = 0; i < pNtHdrs64->FileHeader.NumberOfSections; i++)
100b161379af7255c69e27587cc746e5f76ff050vboxsync if ( paSectHdrs[i].VirtualAddress - RsrcDir.VirtualAddress < paSectHdrs[i].SizeOfRawData
100b161379af7255c69e27587cc746e5f76ff050vboxsync + (paSectHdrs[i].VirtualAddress - RsrcDir.VirtualAddress);
100b161379af7255c69e27587cc746e5f76ff050vboxsync rcNt = NtReadFile(hFile, NULL /*hEvent*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/, &Ios,
100b161379af7255c69e27587cc746e5f76ff050vboxsync static const struct { PCRTUTF16 pwsz; size_t cb; } s_abFields[] =
100b161379af7255c69e27587cc746e5f76ff050vboxsync#define MY_WIDE_STR_TUPLE(a_sz) { L ## a_sz, sizeof(L ## a_sz) - sizeof(RTUTF16) }
100b161379af7255c69e27587cc746e5f76ff050vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(s_abFields); i++)
100b161379af7255c69e27587cc746e5f76ff050vboxsync size_t cwcLeft = (sizeof(u) - s_abFields[i].cb - 10) / sizeof(RTUTF16);
100b161379af7255c69e27587cc746e5f76ff050vboxsync while (cwcLeft-- > 0)
100b161379af7255c69e27587cc746e5f76ff050vboxsync if (memcmp(pwc + 1, s_abFields[i].pwsz, s_abFields[i].cb + sizeof(RTUTF16)) == 0)
100b161379af7255c69e27587cc746e5f76ff050vboxsync size_t cwcField = s_abFields[i].cb / sizeof(RTUTF16);
100b161379af7255c69e27587cc746e5f76ff050vboxsync for (uint32_t iPadding = 0; iPadding < 3; iPadding++, pwc++, cwcLeft--)
100b161379af7255c69e27587cc746e5f76ff050vboxsync s_abFields[i].pwsz, cwcField < 15 ? 15 - cwcField : 0, "", pwc));
100b161379af7255c69e27587cc746e5f76ff050vboxsync s_abFields[i].pwsz, cwcField < 15 ? 15 - cwcField : 0, "", rc));
100b161379af7255c69e27587cc746e5f76ff050vboxsync SUP_DPRINTF((" NtReadFile @%#llx -> %#x %#x\n", offRead.QuadPart, rcNt, Ios.Status));
100b161379af7255c69e27587cc746e5f76ff050vboxsync SUP_DPRINTF((" Nt Headers @%#x: Invalid signature\n", offNtHdrs));
100b161379af7255c69e27587cc746e5f76ff050vboxsync SUP_DPRINTF((" Nt Headers @%#x: out side buffer\n", offNtHdrs));
100b161379af7255c69e27587cc746e5f76ff050vboxsync SUP_DPRINTF((" NtReadFile @0 -> %#x %#x\n", rcNt, Ios.Status));
beed5fc4d17b85d6d05516ae63e6308af82ad96fvboxsync * Scans the Driver directory for drivers which may invade our processes.
beed5fc4d17b85d6d05516ae63e6308af82ad96fvboxsync * @returns Mask of SUPHARDNT_ADVERSARY_XXX flags.
100b161379af7255c69e27587cc746e5f76ff050vboxsync * @remarks The enumeration of \Driver normally requires administrator
100b161379af7255c69e27587cc746e5f76ff050vboxsync * privileges. So, the detection we're doing here isn't always gonna
100b161379af7255c69e27587cc746e5f76ff050vboxsync * work just based on that.
100b161379af7255c69e27587cc746e5f76ff050vboxsync * @todo Find drivers in \FileSystems as well, then we could detect VrNsdDrv
100b161379af7255c69e27587cc746e5f76ff050vboxsync * from ViRobot APT Shield 2.0.
beed5fc4d17b85d6d05516ae63e6308af82ad96fvboxsyncstatic uint32_t supR3HardenedWinFindAdversaries(void)
100b161379af7255c69e27587cc746e5f76ff050vboxsync static const struct
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_TRENDMICRO, "tmebc64" }, /* Titanium internet security, not officescan. */
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_TRENDMICRO, "tmeevw" }, /* Titanium internet security, not officescan. */
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_TRENDMICRO, "tmciesc" }, /* Titanium internet security, not officescan. */
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_MBAM, "MBAMWebAccessControl" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync static const struct
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\SysPlant.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\sysfer.dll" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\sysferThunk.dll" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\ccsetx64.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\ironx64.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\srtsp64.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\srtspx64.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\symds64.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\symefa64.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\symelam.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\symnets.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\symevent64x86.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswHwid.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswMonFlt.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswRdr2.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswRvrt.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswSnx.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswsp.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswStm.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswVmm.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\tmcomm.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\tmactmon.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\tmevtmgr.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\tmtdi.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\tmebc64.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\tmeevw.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\tmciesc.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\cfwids.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\McPvDrv.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\mfeapfk.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\mfeavfk.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\mfefirek.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\mfehidk.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\mfencbdc.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\mfewfpk.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\kl1.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\klflt.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\klif.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\klim6.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\klkbdflt.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\klmouflt.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\kltdi.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\kneps.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\klfphc.dll" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_MBAM, L"\\SystemRoot\\System32\\drivers\\MBAMSwissArmy.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_MBAM, L"\\SystemRoot\\System32\\drivers\\mwac.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_MBAM, L"\\SystemRoot\\System32\\drivers\\mbamchameleon.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_MBAM, L"\\SystemRoot\\System32\\drivers\\mbam.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgrkx64.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgmfx64.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgidsdrivera.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgidsha.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgtdia.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgloga.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgldx64.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgdiska.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\PSINAflt.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\PSINFile.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\PSINKNC.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\PSINProc.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\PSINProt.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\PSINReg.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\PSKMAD.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSAlpc.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSHttp.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNShttps.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSIds.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSNAHSL.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSpicc.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSPihsw.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSPop3.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSProt.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSPrv.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSSmtp.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSStrm.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNStlsc.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_MSE, L"\\SystemRoot\\System32\\drivers\\MpFilter.sys" },
100b161379af7255c69e27587cc746e5f76ff050vboxsync { SUPHARDNT_ADVERSARY_MSE, L"\\SystemRoot\\System32\\drivers\\NisDrvWFP.sys" },
beed5fc4d17b85d6d05516ae63e6308af82ad96fvboxsync * Open the driver object directory.
beed5fc4d17b85d6d05516ae63e6308af82ad96fvboxsync UNICODE_STRING NtDirName = RTNT_CONSTANT_UNISTR(L"\\Driver");
beed5fc4d17b85d6d05516ae63e6308af82ad96fvboxsync InitializeObjectAttributes(&ObjAttr, &NtDirName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
beed5fc4d17b85d6d05516ae63e6308af82ad96fvboxsync NTSTATUS rcNt = NtOpenDirectoryObject(&hDir, DIRECTORY_QUERY | FILE_LIST_DIRECTORY, &ObjAttr);
100b161379af7255c69e27587cc746e5f76ff050vboxsync * Enumerate it, looking for the driver.
100b161379af7255c69e27587cc746e5f76ff050vboxsync sizeof(abBuffer) - 4, /* minus four for string terminator space. */
100b161379af7255c69e27587cc746e5f76ff050vboxsync if (!NT_SUCCESS(rcNt) || cbActual < sizeof(OBJECT_DIRECTORY_INFORMATION))
100b161379af7255c69e27587cc746e5f76ff050vboxsync POBJECT_DIRECTORY_INFORMATION pObjDir = (POBJECT_DIRECTORY_INFORMATION)abBuffer;
100b161379af7255c69e27587cc746e5f76ff050vboxsync WCHAR wcSaved = pObjDir->Name.Buffer[pObjDir->Name.Length / sizeof(WCHAR)];
100b161379af7255c69e27587cc746e5f76ff050vboxsync pObjDir->Name.Buffer[pObjDir->Name.Length / sizeof(WCHAR)] = '\0';
100b161379af7255c69e27587cc746e5f76ff050vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(s_aDrivers); i++)
100b161379af7255c69e27587cc746e5f76ff050vboxsync if (RTUtf16ICmpAscii(pObjDir->Name.Buffer, s_aDrivers[i].pszDriver) == 0)
100b161379af7255c69e27587cc746e5f76ff050vboxsync SUP_DPRINTF(("Found driver %s (%#x)\n", s_aDrivers[i].pszDriver, s_aDrivers[i].fAdversary));
100b161379af7255c69e27587cc746e5f76ff050vboxsync pObjDir->Name.Buffer[pObjDir->Name.Length / sizeof(WCHAR)] = wcSaved;
100b161379af7255c69e27587cc746e5f76ff050vboxsync /* Next directory entry. */
100b161379af7255c69e27587cc746e5f76ff050vboxsync SUP_DPRINTF(("NtOpenDirectoryObject failed on \\Driver: %#x\n", rcNt));
100b161379af7255c69e27587cc746e5f76ff050vboxsync * Look for files.
100b161379af7255c69e27587cc746e5f76ff050vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(s_aFiles); i++)
100b161379af7255c69e27587cc746e5f76ff050vboxsync IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
100b161379af7255c69e27587cc746e5f76ff050vboxsync UniStrName.Length = (USHORT)(RTUtf16Len(s_aFiles[i].pwszFile) * sizeof(WCHAR));
100b161379af7255c69e27587cc746e5f76ff050vboxsync UniStrName.MaximumLength = UniStrName.Length + sizeof(WCHAR);
100b161379af7255c69e27587cc746e5f76ff050vboxsync InitializeObjectAttributes(&ObjAttr, &UniStrName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
100b161379af7255c69e27587cc746e5f76ff050vboxsync rcNt = NtCreateFile(&hFile, GENERIC_READ, &ObjAttr, &Ios, NULL /* Allocation Size*/, FILE_ATTRIBUTE_NORMAL,
100b161379af7255c69e27587cc746e5f76ff050vboxsync FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE, NULL /*EaBuffer*/, 0 /*EaLength*/);
100b161379af7255c69e27587cc746e5f76ff050vboxsync * Log details.
100b161379af7255c69e27587cc746e5f76ff050vboxsync SUP_DPRINTF(("supR3HardenedWinFindAdversaries: %#x\n", fFound));
100b161379af7255c69e27587cc746e5f76ff050vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(s_aFiles); i++)
100b161379af7255c69e27587cc746e5f76ff050vboxsync supR3HardenedLogAdversarialFile(s_aFiles[i].pwszFile);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncextern "C" int main(int argc, char **argv, char **envp);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * The executable entry point.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * This is normally taken care of by the C runtime library, but we don't want to
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * get involved with anything as complicated like the CRT in this setup. So, we
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * it everything ourselves, including parameter parsing.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncextern "C" void __stdcall suplibHardenedWindowsMain(void)
d1e6154d21dcc739e31ac7d8b139ee0fdfe60d45vboxsync * Initialize the NTDLL API wrappers. This aims at bypassing patched NTDLL
d1e6154d21dcc739e31ac7d8b139ee0fdfe60d45vboxsync * in all the processes leading up the VM process.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * After having resolved imports we patch the LdrInitializeThunk code so
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * that it's more difficult to invade our privacy by CreateRemoteThread.
8302394f164acb4adb187954f6ac8ef7a9efa629vboxsync * We'll re-enable this after opening the driver or temporarily while respawning.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Init g_uNtVerCombined. (The code is shared with SUPR3.lib and lives in
b2560fc359a998cb1002e5de6eba0ef716d48803vboxsync * Convert the arguments to UTF-8 and open the log file if specified.
b2560fc359a998cb1002e5de6eba0ef716d48803vboxsync * This must be done as early as possible since the code below may fail.
b2560fc359a998cb1002e5de6eba0ef716d48803vboxsync PUNICODE_STRING pCmdLineStr = &NtCurrentPeb()->ProcessParameters->CommandLine;
b2560fc359a998cb1002e5de6eba0ef716d48803vboxsync char **papszArgs = suplibCommandLineToArgvWStub(pCmdLineStr->Buffer, pCmdLineStr->Length / sizeof(WCHAR), &cArgs);
beed5fc4d17b85d6d05516ae63e6308af82ad96fvboxsync * Scan the system for adversaries.
beed5fc4d17b85d6d05516ae63e6308af82ad96fvboxsync g_fSupAdversaries = supR3HardenedWinFindAdversaries();
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Get the executable name.
d1e6154d21dcc739e31ac7d8b139ee0fdfe60d45vboxsync DWORD cwcExecName = GetModuleFileNameW(GetModuleHandleW(NULL), g_wszSupLibHardenedExePath,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (cwcExecName >= RT_ELEMENTS(g_wszSupLibHardenedExePath))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync supR3HardenedFatalMsg("suplibHardenedWindowsMain", kSupInitOp_Integrity, VERR_BUFFER_OVERFLOW,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "The executable path is too long.");
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* The NT version. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync HANDLE hFile = CreateFileW(g_wszSupLibHardenedExePath, GENERIC_READ, FILE_SHARE_READ, NULL /*pSecurityAttributes*/,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL /*hTemplateFile*/);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (hFile == NULL || hFile == INVALID_HANDLE_VALUE)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync supR3HardenedFatalMsg("suplibHardenedWindowsMain", kSupInitOp_Integrity, RTErrConvertFromWin32(GetLastError()),
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "Error opening the executable: %u (%ls).", GetLastError());
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync NTSTATUS rcNt = NtQueryObject(hFile, ObjectNameInformation, &g_SupLibHardenedExeNtPath,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync sizeof(g_SupLibHardenedExeNtPath) - sizeof(WCHAR), &cbIgn);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync supR3HardenedFatalMsg("suplibHardenedWindowsMain", kSupInitOp_Integrity, RTErrConvertFromNtStatus(rcNt),
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "NtQueryObject -> %#x (on %ls)\n", rcNt, g_wszSupLibHardenedExePath);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* The NT executable name offset / dir path length. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync g_offSupLibHardenedExeNtName = g_SupLibHardenedExeNtPath.UniStr.Length / sizeof(WCHAR);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync && g_SupLibHardenedExeNtPath.UniStr.Buffer[g_offSupLibHardenedExeNtName - 1] != '\\' )
b2560fc359a998cb1002e5de6eba0ef716d48803vboxsync * Call the C/C++ main function.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Exit the process (never return).
b2560fc359a998cb1002e5de6eba0ef716d48803vboxsync SUP_DPRINTF(("Terminating the normal way: rcExit=%d\n", rcExit));