SUPR3HardenedMain-win.cpp revision 5b6c1ebab7273734a475e2e3b850b16ccbdf788c
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * VirtualBox Support Library - Hardened main(), windows bits.
b72d3233df38e3122eda39b39a27b35c27209615vboxsync * Copyright (C) 2006-2014 Oracle Corporation
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * available from http://www.virtualbox.org. This file is free software;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * you can redistribute it and/or modify it under the terms of the GNU
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * General Public License (GPL) as published by the Free Software
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * The contents of this file may alternatively be used under the terms
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * of the Common Development and Distribution License Version 1.0
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * VirtualBox OSE distribution, in which case the provisions of the
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * CDDL are applicable instead of those of the GPL.
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * You may elect to license modified versions of this file under the
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * terms and conditions of either the GPL or the CDDL or both.
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync/*******************************************************************************
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync* Header Files *
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync*******************************************************************************/
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync/*******************************************************************************
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync* Defined Constants And Macros *
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync*******************************************************************************/
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync/** The first argument of a respawed stub when respawned for the first time.
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync * This just needs to be unique enough to avoid most confusion with real
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync * executable names, there are other checks in place to make sure we've respanwed. */
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync#define SUPR3_RESPAWN_1_ARG0 "60eaff78-4bdd-042d-2e72-669728efd737-suplib-2ndchild"
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync/** The first argument of a respawed stub when respawned for the second time.
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * This just needs to be unique enough to avoid most confusion with real
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * executable names, there are other checks in place to make sure we've respanwed. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync#define SUPR3_RESPAWN_2_ARG0 "60eaff78-4bdd-042d-2e72-669728efd737-suplib-3rdchild"
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync/** Unconditional assertion. */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync supR3HardenedFatal("%s: %s\n", __FUNCTION__, #a_Expr); \
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync } while (0)
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync/** Unconditional assertion of NT_SUCCESS. */
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync supR3HardenedFatal("%s: %s -> %#x\n", __FUNCTION__, #a_Expr, rcNtAssert); \
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync } while (0)
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync/** Unconditional assertion of a WIN32 API returning non-FALSE. */
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync#define SUPR3HARDENED_ASSERT_WIN32_SUCCESS(a_Expr) \
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync supR3HardenedFatal("%s: %s -> %#x\n", __FUNCTION__, #a_Expr, RtlGetLastWin32Error()); \
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync } while (0)
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync/*******************************************************************************
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync* Structures and Typedefs *
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync*******************************************************************************/
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * Security descriptor cleanup structure.
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync/** Pointer to security cleanup structure. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * Image verifier cache entry.
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync /** Pointer to the next entry with the same hash value. */
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync /** Next entry in the WinVerifyTrust todo list. */
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync /** The file handle. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** If fIndexNumber is set, this is an file system internal file identifier. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** The path hash value. */
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync /** The verification result. */
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync /** Used for shutting up errors after a while. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** The validation flags (for WinVerifyTrust retry). */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** Whether IndexNumber is valid */
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync /** Whether verified by WinVerifyTrust. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync bool volatile fWinVerifyTrust;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** cwcPath * sizeof(RTUTF16). */
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync /** The full path of this entry (variable size). */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync/** Pointer to an image verifier path entry. */
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync * Name of an import DLL that we need to check out.
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync /** Pointer to the next DLL in the list. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** The length of pwszAltSearchDir if available. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** This points the directory containing the DLL needing it, this will be
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * NULL for a System32 DLL. */
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync /** The name of the import DLL (variable length). */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync/** Pointer to a import DLL that needs checking out. */
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync * VM process parameters.
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** The event semaphore the child will be waiting on. */
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync /** The event semaphore the parent will be waiting on. */
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync /** The address of the NTDLL. */
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync /** The last status. */
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync /** Error message / path name string space. */
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync/*******************************************************************************
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync* Global Variables *
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync*******************************************************************************/
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync/** Process parameters. Specified by parent if VM process, see
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync * supR3HardenedVmProcessInit. */
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsyncstatic SUPR3WINPROCPARAMS g_ProcParams = { NULL, NULL, 0, 0 };
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync/** Set if supR3HardenedEarlyProcessInit was invoked. */
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync/** Set if the stub device has been opened (stub process only). */
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync/** @name Global variables initialized by suplibHardenedWindowsMain.
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync/** Combined windows NT version number. See SUP_MAKE_NT_VER_COMBINED. */
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync/** Count calls to the special main function for linking santity checks. */
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsyncstatic uint32_t volatile g_cSuplibHardenedWindowsMainCalls;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync/** The UTF-16 windows path to the executable. */
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync/** The NT path of the executable. */
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync/** The offset into g_SupLibHardenedExeNtPath of the executable name (WCHAR,
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync * not byte). This also gives the length of the exectuable directory path,
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync * including a trailing slash. */
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync/** @name Hook related variables.
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync/** The jump back address of the patched NtCreateSection. */
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsyncextern "C" PFNRT g_pfnNtCreateSectionJmpBack = NULL;
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync/** Pointer to the bit of assembly code that will perform the original
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync * NtCreateSection operation. */
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsyncstatic NTSTATUS (NTAPI * g_pfnNtCreateSectionReal)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES,
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync/** Pointer to the NtCreateSection function in NtDll (for patching purposes). */
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync/** The patched NtCreateSection bytes (for restoring). */
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync/** The jump back address of the patched LdrLoadDll. */
5981e6935987b08737b730b63a41acc1dd696377vboxsync/** Pointer to the bit of assembly code that will perform the original
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync * LdrLoadDll operation. */
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsyncstatic NTSTATUS (NTAPI * g_pfnLdrLoadDllReal)(PWSTR, PULONG, PUNICODE_STRING, PHANDLE);
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync/** Pointer to the LdrLoadDll function in NtDll (for patching purposes). */
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync/** The patched LdrLoadDll bytes (for restoring). */
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync/** The hash table of verifier cache . */
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsyncstatic PVERIFIERCACHEENTRY volatile g_apVerifierCache[128];
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync/** Queue of cached images which needs WinVerifyTrust to check them. */
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsyncstatic PVERIFIERCACHEENTRY volatile g_pVerifierCacheTodoWvt = NULL;
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync/** Queue of cached images which needs their imports checked. */
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsyncstatic PVERIFIERCACHEIMPORT volatile g_pVerifierCacheTodoImports = NULL;
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync/** The windows path to dir \\SystemRoot\\System32 directory (technically
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync * this whatever \KnownDlls\KnownDllPath points to). */
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync/** Positive if the DLL notification callback has been registered, counts
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync * registration attempts as negative. */
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync/** The registration cookie of the DLL notification callback. */
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync/** Static error info structure used during init. */
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync/** In the assembly file. */
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsyncextern "C" uint8_t g_abSupHardReadWriteExecPage[PAGE_SIZE];
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync/** Whether we've patched our own LdrInitializeThunk or not. We do this to
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync * disable thread creation. */
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync/** The backup of our own LdrInitializeThunk code, for enabling and disabling
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync * thread creation in this process. */
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync/** Mask of adversaries that we've detected (SUPHARDNT_ADVERSARY_XXX). */
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync/** @name SUPHARDNT_ADVERSARY_XXX - Adversaries
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync/** Symantec endpoint protection or similar including SysPlant.sys. */
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync#define SUPHARDNT_ADVERSARY_SYMANTEC_SYSPLANT RT_BIT_32(0)
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync/** Symantec Norton 360. */
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync#define SUPHARDNT_ADVERSARY_SYMANTEC_N360 RT_BIT_32(1)
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync/** Avast! */
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync/** TrendMicro OfficeScan and probably others. */
683eff3070b1b86fe71b71af7fda82766ea19d17vboxsync/** McAfee. */
683eff3070b1b86fe71b71af7fda82766ea19d17vboxsync/** Kaspersky or OEMs of it. */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync/** Malwarebytes Anti-Malware (MBAM). */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync/** AVG Internet Security. */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync/** Panda Security. */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync/** Microsoft Security Essentials. */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync/** Comodo. */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync/** Check Point's Zone Alarm (may include Kaspersky). */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync#define SUPHARDNT_ADVERSARY_ZONE_ALARM RT_BIT_32(11)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync/** Unknown adversary detected while waiting on child. */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync/*******************************************************************************
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync* Internal Functions *
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync*******************************************************************************/
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsyncstatic NTSTATUS supR3HardenedScreenImage(HANDLE hFile, bool fImage, PULONG pfAccess, PULONG pfProtect,
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync bool *pfCallRealApi, const char *pszCaller, bool fAvoidWinVerifyTrust,
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsyncstatic void supR3HardenedWinRegisterDllNotificationCallback(void);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsyncstatic void supR3HardenedWinReInstallHooks(bool fFirst);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync# define SYSCALL(a_Num) DECLASM(void) RT_CONCAT(supR3HardenedJmpBack_NtCreateSection_,a_Num)(void)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync# include "NtCreateSection-template-amd64-syscall-type-1.h"
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync# define SYSCALL(a_Num) DECLASM(void) RT_CONCAT(supR3HardenedJmpBack_NtCreateSection_,a_Num)(void)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync# include "NtCreateSection-template-x86-syscall-type-1.h"
683eff3070b1b86fe71b71af7fda82766ea19d17vboxsyncDECLASM(void) supR3HardenedEarlyProcessInitThunk(void);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * Simple wide char search routine.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @returns Pointer to the first location of @a wcNeedle in @a pwszHaystack.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * NULL if not found.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @param pwszHaystack Pointer to the string that should be searched.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @param wcNeedle The character to search for.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsyncstatic PRTUTF16 suplibHardenedWStrChr(PCRTUTF16 pwszHaystack, RTUTF16 wcNeedle)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * Simple wide char string length routine.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @returns The number of characters in the given string. (Excludes the
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * terminator.)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @param pwsz The string.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * Our version of GetTickCount.
683eff3070b1b86fe71b71af7fda82766ea19d17vboxsync * @returns Millisecond timestamp.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync PKUSER_SHARED_DATA pUserSharedData = (PKUSER_SHARED_DATA)(uintptr_t)0x7ffe0000;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /* use interrupt time */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync Time.HighPart = pUserSharedData->InterruptTime.High1Time;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync Time.LowPart = pUserSharedData->InterruptTime.LowPart;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync } while (pUserSharedData->InterruptTime.High2Time != Time.HighPart);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * Wrapper around LoadLibraryEx that deals with the UTF-8 to UTF-16 conversion
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * and supplies the right flags.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @returns Module handle on success, NULL on failure.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @param pszName The full path to the DLL.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @param fSystem32Only Whether to only look for imports in the system32
aace59ca7fd1b66174593c5a564878cfac89e11evboxsync * directory. If set to false, the application
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * directory is also searched.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsyncDECLHIDDEN(void *) supR3HardenedWinLoadLibrary(const char *pszName, bool fSystem32Only)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync int rc = RTStrToUtf16Ex(pszName, RTSTR_MAX, &pwszPath, RT_ELEMENTS(wszPath), NULL);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0))
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync void *pvRet = (void *)LoadLibraryExW(wszPath, NULL /*hFile*/, fFlags);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /* Vista, W7, W2K8R might not work without KB2533623, so retry with no flags. */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync && RtlGetLastWin32Error() == ERROR_INVALID_PARAMETER)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pvRet = (void *)LoadLibraryExW(wszPath, NULL /*hFile*/, 0);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync supR3HardenedFatal("RTStrToUtf16Ex failed on '%s': %Rrc", pszName, rc);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * Gets the internal index number of the file.
aace59ca7fd1b66174593c5a564878cfac89e11evboxsync * @returns True if we got an index number, false if not.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @param hFile The file in question.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @param pIndexNumber where to return the index number.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsyncstatic bool supR3HardenedWinVerifyCacheGetIndexNumber(HANDLE hFile, PLARGE_INTEGER pIndexNumber)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync NTSTATUS rcNt = NtQueryInformationFile(hFile, &Ios, pIndexNumber, sizeof(*pIndexNumber), FileInternalInformation);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync return NT_SUCCESS(rcNt) && pIndexNumber->QuadPart != 0;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * Calculates the hash value for the given UTF-16 path string.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @returns Hash value.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @param pUniStr String to hash.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsyncstatic uint32_t supR3HardenedWinVerifyCacheHashPath(PCUNICODE_STRING pUniStr)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync unsigned cwcLeft = pUniStr->Length / sizeof(WCHAR);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync while (cwcLeft-- > 0)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * Calculates the hash value for a directory + filename combo as if they were
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * one single string.
aace59ca7fd1b66174593c5a564878cfac89e11evboxsync * @returns Hash value.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @param pawcDir The directory name.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @param cwcDir The length of the directory name. RTSTR_MAX if
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * not available.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @param pszName The import name (UTF-8).
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsyncstatic uint32_t supR3HardenedWinVerifyCacheHashDirAndFile(PCRTUTF16 pawcDir, uint32_t cwcDir, const char *pszName)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync while (cwcDir-- > 0)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * Verify string cache compare function.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @returns true if the strings match, false if not.
b72d3233df38e3122eda39b39a27b35c27209615vboxsync * @param pawcLeft The left hand string.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @param pawcRight The right hand string.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @param cwcToCompare The number of chars to compare.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsyncstatic bool supR3HardenedWinVerifyCacheIsMatch(PCRTUTF16 pawcLeft, PCRTUTF16 pawcRight, uint32_t cwcToCompare)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /* Try a quick memory compare first. */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (memcmp(pawcLeft, pawcRight, cwcToCompare * sizeof(RTUTF16)) == 0)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync return true;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /* Slow char by char compare. */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync while (cwcToCompare-- > 0)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync wcLeft = wcLeft != '/' ? RT_C_TO_LOWER(wcLeft) : '\\';
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync wcRight = wcRight != '/' ? RT_C_TO_LOWER(wcRight) : '\\';
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync return false;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync return true;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * Inserts the given verifier result into the cache.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @param pUniStr The full path of the image.
b72d3233df38e3122eda39b39a27b35c27209615vboxsync * @param hFile The file handle - must either be entered into
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * the cache or closed.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync * @param rc The verifier result.
b72d3233df38e3122eda39b39a27b35c27209615vboxsync * @param fWinVerifyTrust Whether verified by WinVerifyTrust or not.
b72d3233df38e3122eda39b39a27b35c27209615vboxsync * @param fFlags The image verification flags.
b72d3233df38e3122eda39b39a27b35c27209615vboxsyncstatic void supR3HardenedWinVerifyCacheInsert(PCUNICODE_STRING pUniStr, HANDLE hFile, int rc,
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * Allocate and initalize a new entry.
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync PVERIFIERCACHEENTRY pEntry = (PVERIFIERCACHEENTRY)RTMemAllocZ(sizeof(VERIFIERCACHEENTRY) + pUniStr->Length);
if (!fWinVerifyTrust)
if (!pOther)
&& supR3HardenedWinVerifyCacheIsMatch(pOther->wszPath, pEntry->wszPath, pEntry->cbPath / sizeof(RTUTF16)))
static PVERIFIERCACHEENTRY supR3HardenedWinVerifyCacheLookup(PCUNICODE_STRING pUniStr, HANDLE hFile)
while (pCur)
return pCur;
if ( fIndexNumberValid
return pCur;
#ifdef DEBUG_bird
__debugbreak();
return NULL;
static PVERIFIERCACHEENTRY supR3HardenedWinVerifyCacheLookupImport(PCRTUTF16 pawcDir, uint32_t cwcDir, const char *pszName)
while (pCur)
return pCur;
return NULL;
int rc = RTLdrQueryPropEx(hLdrMod, RTLDRPROP_IMPORT_COUNT, NULL /*pvBits*/, &cImports, sizeof(cImports), NULL);
if (cImports)
uint32_t i = 0;
for (i = 0; i < cImports; i++)
} uBuf;
rc = RTLdrQueryPropEx(hLdrMod, RTLDRPROP_IMPORT_MODULE, NULL /*pvBits*/, &uBuf, sizeof(uBuf), NULL);
SUP_DPRINTF(("supR3HardenedWinVerifyCacheScheduleImports: '%s' cached for system32\n", uBuf.szName));
SUP_DPRINTF(("supR3HardenedWinVerifyCacheScheduleImports: '%s' cached for dll dir\n", uBuf.szName));
SUP_DPRINTF(("supR3HardenedWinVerifyCacheScheduleImports: Import todo: #%u '%s'.\n", i, uBuf.szName));
if (pImport)
if (!pawcDir)
static void supR3HardenedWinVerifyCacheProcessImportTodos(void)
PVERIFIERCACHEIMPORT pTodo = ASMAtomicXchgPtrT(&g_pVerifierCacheTodoImports, NULL, PVERIFIERCACHEIMPORT);
if (!pTodo)
|| !supR3HardenedWinVerifyCacheLookupImport(pCur->pwszAltSearchDir, pCur->cwcAltSearchDir, pCur->szName)) )
&ObjAttr,
&Ios,
SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: RTStrToUtf16Ex #1 failed: %Rrc\n", rc));
InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
&ObjAttr,
&Ios,
SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: RTStrToUtf16Ex #2 failed: %Rrc\n", rc));
bool fCallRealApi = false;
SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: Failed to locate '%s'\n", pCur->szName));
SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: '%s' is in the cache.\n", pCur->szName));
} while (pTodo);
static void supR3HardenedWinVerifyCacheProcessWvtTodos(void)
if (!pTodo)
bool fWinVerifyTrust = false;
SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessWvtTodos: %d (was %d) fWinVerifyTrust=%d for '%ls'\n",
SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessWvtTodos: %d (was %d) fWinVerifyTrust=%d for '%ls' [rescheduled]\n",
if (!pReschedule)
} while (pTodo);
if (pReschedule)
else if (wc == 0)
return NULL;
while (*pwszFix)
pwszFixEnd++;
InitializeObjectAttributes(&ObjAttr, &NtDir, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
&ObjAttr,
&Ios,
} uBuf;
&Ios,
&uBuf,
if (NT_SUCCESS(rcNt) && uBuf.Info.NextEntryOffset == 0) /* There shall only be one entry matching... */
while (offName > 0 && uBuf.Info.FileName[offName - 1] != '\\' && uBuf.Info.FileName[offName - 1] != '/')
offName--;
static NTSTATUS supR3HardenedScreenImage(HANDLE hFile, bool fImage, PULONG pfAccess, PULONG pfProtect,
bool *pfQuietFailure)
*pfCallRealApi = false;
if (pfQuietFailure)
*pfQuietFailure = false;
} uBuf;
NTSTATUS rcNt = NtQueryObject(hFile, ObjectNameInformation, &uBuf, sizeof(uBuf) - sizeof(WCHAR) - 128, &cbNameBuf);
return rcNt;
if (pCacheHit)
if (!fAvoidWinVerifyTrust)
bool fWinVerifyTrust = false;
int rc = supHardenedWinVerifyImageTrust(pCacheHit->hFile, pCacheHit->wszPath, pCacheHit->fFlags, pCacheHit->rc,
pszCaller, pCacheHit->rc, pCacheHit->wszPath, pCacheHit->fWinVerifyTrust ? "" : " [lacks WinVerifyTrust]"));
*pfCallRealApi = true;
return STATUS_SUCCESS;
"supR3HardenedScreenImage/%s: cached rc=%Rrc fImage=%d fProtect=%#x fAccess=%#x cErrorHits=%u %ls\n",
else if (pfQuietFailure)
*pfQuietFailure = true;
return STATUS_TRUST_FAILURE;
&hMyFile,
InitializeObjectAttributes(&ObjAttr, &uBuf.UniStr, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
&ObjAttr,
&Ios,
return rcNt;
if ( fMyValid
return STATUS_TRUST_FAILURE;
#ifdef DEBUG
if ( !fImage
PRTUTF16 pwszName = &uBuf.UniStr.Buffer[(g_System32NtPath.UniStr.Length - sizeof(L"System32") + sizeof(WCHAR)) / sizeof(WCHAR)];
SUP_DPRINTF(("supR3HardenedScreenImage/%s: Applying the drop-exec-kludge for '%ls'\n", pszCaller, uBuf.UniStr.Buffer));
*pfCallRealApi = true;
return STATUS_SUCCESS;
#ifndef VBOX_PERMIT_EVEN_MORE
if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_System32NtPath.UniStr, true /*fCheckSlash*/))
else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_WinSxSNtPath.UniStr, true /*fCheckSlash*/))
# ifdef VBOX_PERMIT_MORE
else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_ProgramFilesNtPath.UniStr, true /*fCheckSlash*/))
else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_CommonFilesNtPath.UniStr, true /*fCheckSlash*/))
# ifdef RT_ARCH_AMD64
else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_ProgramFilesX86NtPath.UniStr, true /*fCheckSlash*/))
else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_CommonFilesX86NtPath.UniStr, true /*fCheckSlash*/))
&& memcmp(uBuf.UniStr.Buffer + (uBuf.UniStr.Length - sizeof(L"\\SamplingRuntime.dll") + sizeof(WCHAR)) / sizeof(WCHAR),
*pfCallRealApi = true;
return STATUS_SUCCESS;
"supR3HardenedScreenImage/%s: Not a trusted location: '%ls' (fImage=%d fProtect=%#x fAccess=%#x)\n",
return STATUS_TRUST_FAILURE;
int rc;
bool fWinVerifyTrust = false;
rc = supHardenedWinVerifyImageByHandle(hMyFile, uBuf.UniStr.Buffer, fFlags, fAvoidWinVerifyTrust, &fWinVerifyTrust, &ErrInfo);
return STATUS_TRUST_FAILURE;
*pfCallRealApi = true;
return STATUS_SUCCESS;
InitializeObjectAttributes(&ObjAttr, &UniStr, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
&ObjAttr,
&Ios,
bool fCallRealApi;
supR3HardenedScreenImage(hFile, false, &fAccess, &fProtect, &fCallRealApi, "preload", false /*fAvoidWinVerifyTrust*/,
supR3HardenedMonitor_NtCreateSection(PHANDLE phSection, ACCESS_MASK fAccess, POBJECT_ATTRIBUTES pObjAttribs,
bool const fExecProt = RT_BOOL(fProtect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_WRITECOPY
bool fCallRealApi;
//SUP_DPRINTF(("supR3HardenedMonitor_NtCreateSection: 2 rcNt=%#x fCallRealApi=%#x\n", rcNt, fCallRealApi));
return rcNt;
if (!fCallRealApi)
return STATUS_TRUST_FAILURE;
return g_pfnNtCreateSectionReal(phSection, fAccess, pObjAttribs, pcbSection, fProtect, fAttribs, hFile);
static NTSTATUS supR3HardenedCopyRedirectionResult(WCHAR *pwszPath, size_t cwcPath, PUNICODE_STRING pUniStrResult,
"supR3HardenedMonitor_LdrLoadDll: Name too long: %.*ls -> %.*ls (RtlDosApplyFileIoslationRedirection_Ustr)\n",
return STATUS_NAME_TOO_LONG;
return STATUS_SUCCESS;
supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_STRING pName, PHANDLE phMod)
supR3HardenedError(VINF_SUCCESS, false, "supR3HardenedMonitor_LdrLoadDll: name is NULL or have a zero length.\n");
SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x (pName=%p)\n", STATUS_INVALID_PARAMETER, pName));
return STATUS_INVALID_PARAMETER;
(unsigned)pName->Length / sizeof(WCHAR), pName->Buffer, pfFlags ? *pfFlags : UINT32_MAX, pwszSearchPath,
!((uintptr_t)pwszSearchPath & 1) && (uintptr_t)pwszSearchPath >= 0x2000U ? pwszSearchPath : L"<flags>"));*/
supR3HardenedError(VINF_SUCCESS, false, "supR3HardenedMonitor_LdrLoadDll: too long name: %#x bytes\n", pName->Length);
return STATUS_NAME_TOO_LONG;
bool fSkipValidation = false;
rcNt = supR3HardenedCopyRedirectionResult(wszPath, RT_ELEMENTS(wszPath), pUniStrResult, pName, &cwc);
return rcNt;
fSkipValidation = true;
switch (pawcName[i])
offLastSlash = i;
offLastDot = i;
cwcName--;
return STATUS_OBJECT_NAME_INVALID;
rcNt = supR3HardenedCopyRedirectionResult(wszPath, RT_ELEMENTS(wszPath), pUniStrResult, pName, &cwc);
return rcNt;
return STATUS_NAME_TOO_LONG;
if (!fNeedDllSuffix)
if (!fSkipValidation)
return STATUS_OBJECT_NAME_INVALID;
InitializeObjectAttributes(&ObjAttr, &NtPathUniStr, OBJ_CASE_INSENSITIVE, hRootDir, NULL /*pSecDesc*/);
&ObjAttr,
&Ios,
bool fCallRealApi = false;
bool fQuietFailure = false;
if (!fQuietFailure)
supR3HardenedError(VINF_SUCCESS, false, "supR3HardenedMonitor_LdrLoadDll: rejecting '%ls': rcNt=%#x\n",
return rcNt;
SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: pName=%.*ls *pfFlags=%#x pwszSearchPath=%p:%ls [calling]\n",
(unsigned)pName->Length / sizeof(WCHAR), pName->Buffer, pfFlags ? *pfFlags : UINT32_MAX, pwszSearchPath,
!((uintptr_t)pwszSearchPath & 1) && (uintptr_t)pwszSearchPath >= 0x2000U ? pwszSearchPath : L"<flags>"));
SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x hMod=%p '%ls'\n", rcNt, *phMod, wszPath));
return rcNt;
static VOID CALLBACK supR3HardenedDllNotificationCallback(ULONG ulReason, PCLDR_DLL_NOTIFICATION_DATA pData, PVOID pvUser)
supR3HardenedFatal("supR3HardenedDllNotificationCallback: RTNtPathFromWinUtf16Ex failed on '%.*ls': %Rrc\n",
InitializeObjectAttributes(&ObjAttr, &NtPathUniStr, OBJ_CASE_INSENSITIVE, hRootDir, NULL /*pSecDesc*/);
&ObjAttr,
&Ios,
supR3HardenedFatal("supR3HardenedDllNotificationCallback: NtCreateFile failed on '%.*ls' / '%.*ls': %#x\n",
bool fCallRealApi = false;
bool fQuietFailure = false;
supR3HardenedFatal("supR3HardenedDllNotificationCallback: supR3HardenedScreenImage failed on '%.*ls' / '%.*ls': %#x\n",
static void supR3HardenedWinRegisterDllNotificationCallback(void)
&& g_cDllNotificationRegistered <= 0
NTSTATUS rcNt = LdrRegisterDllNotification(0, supR3HardenedDllNotificationCallback, NULL, &g_pvDllNotificationCookie);
#ifdef RT_ARCH_AMD64
static void *supR3HardenedWinAllocHookMemory(uintptr_t uStart, uintptr_t uEnd, intptr_t iDirection, size_t cbAlloc)
if (iDirection > 0)
(void *)uCur,
&MemInfo,
sizeof(MemInfo),
&cbIgn));
if ( iDirection > 0
return pvMem;
if ( iDirection > 0
if (iDirection > 0)
return NULL;
#ifdef RT_ARCH_X86
NTSTATUS rcNt2 = NtQueryInformationProcess(hProcWait, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
SUP_DPRINTF(("supR3HardenedWinParentWatcherThread: Quitting: ExitCode=%#x rcNt=%#x\n", BasicInfo.ExitStatus, rcNt));
NTSTATUS rcNt = NtQueryInformationProcess(NtCurrentProcess(), ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
supR3HardenedFatal("supR3HardenedWinCreateParentWatcherThread: NtQueryInformationProcess failed: %#x\n", rcNt);
supR3HardenedFatalMsg("supR3HardenedWinCreateParentWatcherThread", kSupInitOp_Misc, VERR_GENERAL_FAILURE,
static bool supR3HardenedWinAmIAlone(void)
NTSTATUS rcNt = NtQueryInformationThread(NtCurrentThread(), ThreadAmILastThread, &fAmIAlone, sizeof(fAmIAlone), &cbIgn);
const char *pszName;
} const s_aPatches[] =
{ sizeof(g_abNtCreateSectionPatch), g_abNtCreateSectionPatch, &g_pbNtCreateSection, "NtCreateSection" },
s_cTimes++;
SUPR3HARDENED_ASSERT_NT_SUCCESS(supR3HardenedWinProtectMemory(pbApi, s_aPatches[i].cbPatch, PAGE_EXECUTE_READWRITE));
if (fAmIAlone)
SUPR3HARDENED_ASSERT_NT_SUCCESS(supR3HardenedWinProtectMemory(pbApi, s_aPatches[i].cbPatch, PAGE_EXECUTE_READ));
static void supR3HardenedWinInstallHooks(void)
rcNt = NtQueryInformationProcess(NtCurrentProcess(), ProcessDefaultHardErrorMode, &fHardErr, sizeof(fHardErr), NULL);
rcNt = NtSetInformationProcess(NtCurrentProcess(), ProcessDefaultHardErrorMode, &fHardErr, sizeof(fHardErr));
#ifdef RT_ARCH_AMD64
if (!pvMem)
if (!pvMem)
#ifdef RT_ARCH_AMD64
# define SYSCALL(a_Num) case a_Num: pfnCallReal = RT_CONCAT(supR3HardenedJmpBack_NtCreateSection_,a_Num); break;
# include "NtCreateSection-template-amd64-syscall-type-1.h"
if (!pfnCallReal)
*(uint32_t *)&g_abNtCreateSectionPatch[2] = (uint32_t)((uintptr_t)puJmpTab - (uintptr_t)&pbNtCreateSection[2+4]);
puJmpTab++;
# define SYSCALL(a_Num) case a_Num: pfnCallReal = RT_CONCAT(supR3HardenedJmpBack_NtCreateSection_,a_Num); break;
# include "NtCreateSection-template-x86-syscall-type-1.h"
if (!pfnCallReal)
#ifdef RT_ARCH_AMD64
offJmpBack = 0;
*(uint32_t *)&g_abSupHardReadWriteExecPage[offExecPage] = RT_ALIGN_32(offExecPage + 4, 8) - (offExecPage + 4);
*(uint32_t *)&g_abLdrLoadDllPatch[2] = (uint32_t)((uintptr_t)puJmpTab - (uintptr_t)&pbLdrLoadDll[2+4]);
puJmpTab++;
offJmpBack = 0;
*(uint32_t *)&g_abLdrLoadDllPatch[1] = (uintptr_t)supR3HardenedMonitor_LdrLoadDll - (uintptr_t)&pbLdrLoadDll[1+4];
SUPR3HARDENED_ASSERT_NT_SUCCESS(supR3HardenedWinProtectMemory(g_abSupHardReadWriteExecPage, PAGE_SIZE, PAGE_EXECUTE_READ));
static bool supR3HardenedGetUserAndLogSids(PSID pSidUser, ULONG cbSidUser, PSID pSidLogin, ULONG cbSidLogin)
} uBuf;
SUPR3HARDENED_ASSERT_NT_SUCCESS(NtQueryInformationToken(hToken, TokenUser, &uBuf, sizeof(uBuf), &cbRet));
bool fLoginSid = false;
fLoginSid = true;
return fLoginSid;
static void supR3HardenedInitSecAttrs(PSECURITY_ATTRIBUTES pSecAttrs, PMYSECURITYCLEANUP pCleanup, bool fProcess)
SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCreateAcl(&pCleanup->Acl.AclHdr, sizeof(pCleanup->Acl), ACL_REVISION));
if (fProcess)
fDeny |= THREAD_SUSPEND_RESUME | THREAD_SET_CONTEXT | THREAD_SET_INFORMATION | THREAD_SET_THREAD_TOKEN
if (fHasLoginSid)
SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCreateSecurityDescriptor(pSecDesc, SECURITY_DESCRIPTOR_REVISION));
SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlSetDaclSecurityDescriptor(pSecDesc, TRUE /*fDaclPresent*/, &pCleanup->Acl.AclHdr,
int fQuoted = false;
unsigned cSlashes = 0;
cSlashes++;
cwcArgs--;
pawcArgs++;
size_t cwcCmdLine = (sizeof(SUPR3_RESPAWN_1_ARG0) - 1) / sizeof(SUPR3_RESPAWN_1_ARG0[0]) /* Respawn exe name. */
for (const char *pszSrc = iWhich == 1 ? SUPR3_RESPAWN_1_ARG0 : SUPR3_RESPAWN_2_ARG0; *pszSrc; pszSrc++)
if (cwcArgs)
if (pString)
return pwszCmdLine;
if (RTUtf16ICmpAscii(&pUniStr->Buffer[g_System32NtPath.UniStr.Length / sizeof(WCHAR) + 1], pszName) == 0)
static int supR3HardNtDisableThreadCreationEx(HANDLE hProcess, void *pvLdrInitThunk, void *pvNtTerminateThread,
SUP_DPRINTF(("supR3HardNtDisableThreadCreation: pvLdrInitThunk=%p pvNtTerminateThread=%p\n", pvLdrInitThunk, pvNtTerminateThread));
#ifdef RT_ARCH_AMD64
*(int32_t *)&abReplacement[5] = (int32_t)((uintptr_t)pvNtTerminateThread - ((uintptr_t)pvLdrInitThunk + 9));
*(int32_t *)&abReplacement[5] = (int32_t)((uintptr_t)pvNtTerminateThread - ((uintptr_t)pvLdrInitThunk + 9));
rcNt = NtWriteVirtualMemory(hProcess, pvLdrInitThunk, abReplacement, sizeof(abReplacement), &cbIgnored);
"supR3HardNtDisableThreadCreationEx: NtProtectVirtualMemory/LdrInitializeThunk/2 failed: %#x", rcNt);
return VINF_SUCCESS;
static int supR3HardNtEnableThreadCreationEx(HANDLE hProcess, void *pvLdrInitThunk, uint8_t const *pabBackup, size_t cbBackup,
NTSTATUS rcNt = NtProtectVirtualMemory(hProcess, &pvProt, &cbProt, PAGE_EXECUTE_READWRITE, &fOldProt);
"supR3HardNtEnableThreadCreation: NtWriteVirtualMemory/LdrInitializeThunk[restore] failed: %#x",
rcNt);
"supR3HardNtEnableThreadCreation: NtProtectVirtualMemory/LdrInitializeThunk[restore] failed: %#x",
rcNt);
return VINF_SUCCESS;
static void supR3HardenedWinDisableThreadCreation(void)
g_fSupInitThunkSelfPatched = false;
typedef struct SUPR3HARDNTPUCH
#ifdef RT_ARCH_AMD64
NTSTATUS rcNt = NtWriteVirtualMemory(pThis->hProcess, pThis->BasicInfo.PebBaseAddress, &Peb, pThis->cbPeb, &cbActualMem);
return RTErrInfoSetF(pThis->pErrInfo, VERR_GENERAL_FAILURE, "NtWriteVirtualMemory/Peb failed: %#x", rcNt);
return VINF_SUCCESS;
static void supR3HardNtPuChUnmapDllFromChild(PSUPR3HARDNTPUCH pThis, PVOID pvBase, const char *pszShort)
if (pvBase)
/*SUP_DPRINTF(("supR3HardNtPuChUnmapDllFromChild: Calling NtUnmapViewOfSection on %p / %s\n", pvBase, pszShort));*/
SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: NtUnmapViewOfSection failed on %s: %#x (%p)\n",
static PVOID supR3HardNtPuChMapDllIntoChild(PSUPR3HARDNTPUCH pThis, PUNICODE_STRING pNtName, const char *pszShort)
InitializeObjectAttributes(&ObjAttr, pNtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
&ObjAttr,
&Ios,
SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: mapping view of %s\n", pszShort)); /* For SEP. */
SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: %s mapped at %p LB %#x\n", pszShort, pvRet, cbView));
SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: NtMapViewOfSection failed on %s: %#x\n", pszShort, rcNt));
SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: NtCreateSection failed on %s: %#x\n", pszShort, rcNt));
return pvRet;
* This is a trick to force sysplant.sys to call its hand by tripping the image
rc = supR3HardNtDisableThreadCreationEx(pThis->hProcess, pvLdrInitThunk, (void *)(uintptr_t)uNtTerminateThread,
return rc;
PVOID pvExe2 = supR3HardNtPuChMapDllIntoChild(pThis, &g_SupLibHardenedExeNtPath.UniStr, "executable[2nd]");
&hThread2,
&Thread2Id);
: NULL;
uint32_t cMsKludge = (g_fSupAdversaries & SUPHARDNT_ADVERSARY_SYMANTEC_SYSPLANT) ? 256 : g_fSupAdversaries ? 64 : 16;
rc = supR3HardNtEnableThreadCreationEx(pThis->hProcess, pvLdrInitThunk, abBackup, sizeof(abBackup), pThis->pErrInfo);
return rc;
return VINF_SUCCESS;
static int supR3HardenedWinScratchChildMemory(HANDLE hProcess, void *pv, size_t cb, const char *pszWhat, PRTERRINFO pErrInfo)
return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, "NtProtectVirtualMemory/%s (%p LB %#zx) failed: %#x",
return VINF_SUCCESS;
* There should not be any activation context, so if there is, we scratch the memory associated with it.
int rc = 0;
if (RT_SUCCESS(rc) && Peb.ActivationContextData && !((uintptr_t)Peb.ActivationContextData & PAGE_OFFSET_MASK))
rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.ActivationContextData, PAGE_SIZE, "ActivationContextData", pErrInfo);
if (RT_SUCCESS(rc) && Peb.ProcessAssemblyStorageMap && !((uintptr_t)Peb.ProcessAssemblyStorageMap & PAGE_OFFSET_MASK))
rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.ProcessAssemblyStorageMap, PAGE_SIZE, "ProcessAssemblyStorageMap", pErrInfo);
if (RT_SUCCESS(rc) && Peb.SystemDefaultActivationContextData && !((uintptr_t)Peb.SystemDefaultActivationContextData & PAGE_OFFSET_MASK))
rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.ProcessAssemblyStorageMap, PAGE_SIZE, "SystemDefaultActivationContextData", pErrInfo);
if (RT_SUCCESS(rc) && Peb.SystemAssemblyStorageMap && !((uintptr_t)Peb.SystemAssemblyStorageMap & PAGE_OFFSET_MASK))
rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.SystemAssemblyStorageMap, PAGE_SIZE, "SystemAssemblyStorageMap", pErrInfo);
return rc;
/*Peb.Diff0.W6.IsProtectedProcess = 1;*/
NTSTATUS rcNt = NtWriteVirtualMemory(pThis->hProcess, pThis->BasicInfo.PebBaseAddress, &Peb, pThis->cbPeb, &cbActualMem);
return RTErrInfoSetF(pThis->pErrInfo, VERR_GENERAL_FAILURE, "NtWriteVirtualMemory/Peb failed: %#x", rcNt);
return VINF_SUCCESS;
SUPR3HARDENED_ASSERT(pThis->uNtDllParentAddr != 0 && !(pThis->uNtDllParentAddr & PAGE_OFFSET_MASK));
(void const *)uPtrWhere,
&MemInfo,
sizeof(MemInfo),
&cbActual);
} uBuf;
&uBuf,
&cbActual);
#ifdef DEBUG
static int supR3HardenedWinPurifyChild(HANDLE hProcess, HANDLE hThread, uintptr_t *puChildNtDllAddr, uintptr_t *puChildExeAddr,
*puChildNtDllAddr = 0;
*puChildExeAddr = 0;
SUP_DPRINTF(("supR3HardenedWinPurifyChild: PebBaseAddress=%p cbPeb=%#x\n", This.BasicInfo.PebBaseAddress, This.cbPeb));
rcNt = NtReadVirtualMemory(hProcess, This.BasicInfo.PebBaseAddress, &This.Peb, sizeof(This.Peb), &cbActualMem);
rc = supHardenedWinVerifyProcess(hProcess, hThread, SUPHARDNTVPKIND_CHILD_PURIFICATION, NULL /*pcFixes*/, pErrInfo);
return rc;
static void supR3HardenedWinKillChild(HANDLE hProcess, const char *pszWhere, int rc, const char *pszFormat, ...)
NTSTATUS rcNtExit = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
if (!fExitOk)
rcNtExit = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
} while ( !fExitOk
if (fExitOk)
static void supR3HardenedWinCheckChild(HANDLE hProcWait, uintptr_t uChildExeAddr, HANDLE *phEvtParent, HANDLE *phEvtChild)
uintptr_t uChildAddr = uChildExeAddr + ((uintptr_t)&g_ProcParams - (uintptr_t)NtCurrentPeb()->ImageBaseAddress);
NTSTATUS rcNt = NtReadVirtualMemory(hProcWait, (PVOID)uChildAddr, &ChildProcParams, sizeof(ChildProcParams), &cbIgnored);
supR3HardenedWinKillChild(hProcWait, "supR3HardenedWinCheckChild", rcNt, "NtSetEvent failed: %#x\n", rcNt);
supR3HardenedWinKillChild(hProcWait, "supR3HardenedWinCheckChild", rcNt, "NtClose failed on event sem: %#x\n", rcNt);
supR3HardenedFatalMsg("supR3HardenedWinCheckChild", kSupInitOp_Misc, ChildProcParams.rc, "%s", ChildProcParams.szErrorMsg);
static void supR3HardenedWinSetupChildInit(HANDLE hProcess, HANDLE hThread, uintptr_t uChildNtDllAddr, uintptr_t uChildExeAddr,
uintptr_t uChildAddr = uChildExeAddr + ((uintptr_t)&g_ProcParams - (uintptr_t)NtCurrentPeb()->ImageBaseAddress);
NTSTATUS rcNt = NtWriteVirtualMemory(hProcess, (PVOID)uChildAddr, &ChildProcParams, sizeof(ChildProcParams), &cbIgnored);
rc = supHardNtLdrCacheEntryGetBits(pLdrEntry, &pbChildNtDllBits, uChildNtDllAddr, NULL, NULL, NULL /*pErrInfo*/);
#ifdef RT_ARCH_AMD64
InitializeObjectAttributes(&ObjAttrs, NULL /*pName*/, OBJ_INHERIT, NULL /*hRootDir*/, NULL /*pSecDesc*/);
SUPR3HARDENED_ASSERT_NT_SUCCESS(NtCreateEvent(&hEvtChild, EVENT_ALL_ACCESS, &ObjAttrs, NotificationEvent, FALSE));
InitializeObjectAttributes(&ObjAttrs, NULL /*pName*/, OBJ_INHERIT, NULL /*hRootDir*/, NULL /*pSecDesc*/);
SUPR3HARDENED_ASSERT_NT_SUCCESS(NtCreateEvent(&hEvtParent, EVENT_ALL_ACCESS, &ObjAttrs, NotificationEvent, FALSE));
W32ImageName.Buffer = g_wszSupLibHardenedExePath; /* Yes the windows name for the process parameters. */
&CmdLine,
#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
supR3HardenedWinSetupChildInit(hProcess, hThread, uChildNtDllAddr, uChildExeAddr, hEvtChild, hEvtParent);
rcNt = NtQueryInformationProcess(NtCurrentProcess(), ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
#ifdef DEBUG
rcNt = NtWaitForMultipleObjects(cHandles, &ahHandles[0], WaitAnyObject, TRUE /*Alertable*/, NULL /*pTimeout*/);
NTSTATUS rcNt2 = NtQueryInformationProcess(hProcWait, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
if (hEvtParent)
SUP_DPRINTF(("supR3HardenedWinDoReSpawn(%d): Quitting: ExitCode=%#x rcNt=%#x\n", iWhich, BasicInfo.ExitStatus, rcNt));
InitializeObjectAttributes(&ObjAttr, &NtDirName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
&cbActual);
SUP_DPRINTF(("supR3HardenedWinLogObjDir: NtQueryDirectoryObject => rcNt=%#x cbActual=%#x\n", rcNt, cbActual));
pObjDir++;
InitializeObjectAttributes(&ObjAttr, &NtDirName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
#ifdef VBOX_STRICT
bool fFound = true;
&cbActual);
fFound = true;
pObjDir++;
} while (!fFound);
return fFound;
static void supR3HardenedWinOpenStubDevice(void)
if (g_fSupStubOpened)
InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
&ObjAttr,
&Ios,
/** @todo Consider starting the VBoxdrv.sys service. Requires 2nd process
g_fSupStubOpened = true;
if (uSessionId == 0)
const char *pszDefine;
switch (rcNt)
/** @todo don't fail during early init, wait till later and try load the driver if missing or at least query the service manager for additional information. */
* support driver via /Devices/VBoxDrvStub. (We tried to do this
rc = supHardNtVpThread(NtCurrentProcess(), NtCurrentThread(), RTErrInfoInitStatic(&g_ErrInfoStatic));
supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Integrity, rc, "%s", g_ErrInfoStatic.szMsg);
#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
InitializeObjectAttributes(&ObjAttrs, &UniStr, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
supR3HardenedFatalMsg("supR3HardenedWinInit", kSupInitOp_Misc, rcNt, "Error opening '%ls': %#x", UniStr.Buffer, rcNt);
supR3HardenedFatalMsg("supR3HardenedWinInit", kSupInitOp_Misc, rcNt, "Error querying '%ls': %#x", UniStr.Buffer, rcNt);
if (fAvastKludge)
cSleeps++;
cFixes = 0;
rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_SELF_PURIFICATION,
if (!g_fSupAdversaries)
/* Log the KiOpPrefetchPatchCount value if available, hoping it might sched some light on spider38's case. */
SUP_DPRINTF(("supR3HardenedWinInit: cFixes=%u g_fSupAdversaries=%#x\n", cFixes, g_fSupAdversaries));
#ifndef VBOX_WITH_VISTA_NO_SP
"Window Vista without any service pack installed is not supported. Please install the latest service pack.");
int cArgs = 0;
if (!ch)
bool fQuoted = false;
unsigned cSlashes = 0;
cSlashes++;
if (cSlashes)
pszSrc--;
while (cSlashes-- > 0)
if (!ch)
return papszArgs;
InitializeObjectAttributes(&ObjAttr, &UniStrName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
&ObjAttr,
&Ios,
rcNt = NtQueryInformationFile(hFile, &Ios, &u.BasicInfo, sizeof(u.BasicInfo), FileBasicInformation);
SUP_DPRINTF((" CreationTime: %s\n", RTTimeSpecToString(RTTimeSpecSetNtTime(&TimeSpec, u.BasicInfo.CreationTime.QuadPart), szTmp, sizeof(szTmp))));
/*SUP_DPRINTF((" LastAccessTime: %s\n", RTTimeSpecToString(RTTimeSpecSetNtTime(&TimeSpec, u.BasicInfo.LastAccessTime.QuadPart), szTmp, sizeof(szTmp))));*/
SUP_DPRINTF((" LastWriteTime: %s\n", RTTimeSpecToString(RTTimeSpecSetNtTime(&TimeSpec, u.BasicInfo.LastWriteTime.QuadPart), szTmp, sizeof(szTmp))));
SUP_DPRINTF((" ChangeTime: %s\n", RTTimeSpecToString(RTTimeSpecSetNtTime(&TimeSpec, u.BasicInfo.ChangeTime.QuadPart), szTmp, sizeof(szTmp))));
RT_ZERO(u);
SUP_DPRINTF((" SizeOfImage: %#x (%u)\n", pNtHdrs64->OptionalHeader.SizeOfImage, pNtHdrs64->OptionalHeader.SizeOfImage));
RT_ZERO(u);
while (cwcLeft-- > 0)
if (*pwc)
pwc++;
const char *pszDriver;
} s_aDrivers[] =
} s_aFiles[] =
{ SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\ccsetx64.sys" },
{ SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\ironx64.sys" },
{ SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\srtsp64.sys" },
{ SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\srtspx64.sys" },
{ SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\symds64.sys" },
{ SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\symefa64.sys" },
{ SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\symelam.sys" },
{ SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\symnets.sys" },
InitializeObjectAttributes(&ObjAttr, &NtDirName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
#ifdef VBOX_STRICT
&cbActual);
pObjDir++;
InitializeObjectAttributes(&ObjAttr, &UniStrName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
rcNt = NtCreateFile(&hFile, GENERIC_READ, &ObjAttr, &Ios, NULL /* Allocation Size*/, FILE_ATTRIBUTE_NORMAL,
return fFound;
int cArgs;
char **papszArgs = suplibCommandLineToArgvWStub(pCmdLineStr->Buffer, pCmdLineStr->Length / sizeof(WCHAR), &cArgs);
HANDLE hFile = CreateFileW(g_wszSupLibHardenedExePath, GENERIC_READ, FILE_SHARE_READ, NULL /*pSecurityAttributes*/,
supR3HardenedFatalMsg("suplibHardenedWindowsMain", kSupInitOp_Integrity, RTErrConvertFromWin32(RtlGetLastWin32Error()),
supR3HardenedFatalMsg("suplibHardenedWindowsMain", kSupInitOp_Integrity, RTErrConvertFromNtStatus(rcNt),
NtTerminateThread(0, 0);
g_fSupEarlyProcessInit = true;
int cArgs;
char **papszArgs = suplibCommandLineToArgvWStub(pCmdLineStr->Buffer, pCmdLineStr->Length / sizeof(WCHAR), &cArgs);
rcNt = NtQueryVirtualMemory(NtCurrentProcess(), &g_ProcParams, MemorySectionName, &g_SupLibHardenedExeNtPath,
supR3HardenedFatal("NtQueryVirtualMemory/MemorySectionName failed in supR3HardenedVmProcessInit: %#x\n", rcNt);
supR3HardenedFatal("supR3HardenedVmProcessInit: supHardNtLdrCacheOpen failed on NTDLL: %Rrc\n", rc);
rc = supHardNtLdrCacheEntryGetBits(pLdrEntry, &pbBits, g_ProcParams.uNtDllAddr, NULL, NULL, NULL /*pErrInfo*/);
supR3HardenedFatal("supR3HardenedVmProcessInit: supHardNtLdrCacheEntryGetBits failed on NTDLL: %Rrc\n", rc);
rc = RTLdrGetSymbolEx(pLdrEntry->hLdrMod, pbBits, g_ProcParams.uNtDllAddr, UINT32_MAX, "LdrInitializeThunk", &uValue);
SUPR3HARDENED_ASSERT_NT_SUCCESS(supR3HardenedWinProtectMemory(pvLdrInitThunk, 16, PAGE_EXECUTE_READWRITE));