SUPR3HardenedMain-win.cpp revision 4f2b002896072b0b5a7cb566341c8bac5e69392b
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync * VirtualBox Support Library - Hardened main(), windows bits.
c98fb3e16fcd571a790eab772c0c66173d225205vboxsync * Copyright (C) 2006-2014 Oracle Corporation
c98fb3e16fcd571a790eab772c0c66173d225205vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * available from http://www.virtualbox.org. This file is free software;
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync * The contents of this file may alternatively be used under the terms
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync * of the Common Development and Distribution License Version 1.0
897aeea81122648c298d7d059f8186ae6d6127cevboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
897aeea81122648c298d7d059f8186ae6d6127cevboxsync * VirtualBox OSE distribution, in which case the provisions of the
897aeea81122648c298d7d059f8186ae6d6127cevboxsync * CDDL are applicable instead of those of the GPL.
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync * You may elect to license modified versions of this file under the
6e40d94b3d9a8feb6d50df199c96370c72234170vboxsync * terms and conditions of either the GPL or the CDDL or both.
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync/*******************************************************************************
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync* Header Files *
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync*******************************************************************************/
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync/*******************************************************************************
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync* Defined Constants And Macros *
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync*******************************************************************************/
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync/** The first argument of a respawed stub argument.
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync * This just needs to be unique enough to avoid most confusion with real
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync * executable names, there are other checks in place to make sure we've respanwed. */
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync#define SUPR3_RESPAWN_ARG0 "81954AF5-4D2F-31EB-A142-B7AF187A1C41-suplib-2ndchild"
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync/** Unconditional assertion. */
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync supR3HardenedFatal("%s: %s", __FUNCTION__, #a_Expr); \
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync } while (0)
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync/** Unconditional assertion of NT_SUCCESS. */
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync supR3HardenedFatal("%s: %s -> %#x", __FUNCTION__, #a_Expr, rcNtAssert); \
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync } while (0)
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync/** Unconditional assertion of a WIN32 API returning non-FALSE. */
6e40d94b3d9a8feb6d50df199c96370c72234170vboxsync#define SUPR3HARDENED_ASSERT_WIN32_SUCCESS(a_Expr) \
6e40d94b3d9a8feb6d50df199c96370c72234170vboxsync supR3HardenedFatal("%s: %s -> %#x", __FUNCTION__, #a_Expr, GetLastError()); \
6e40d94b3d9a8feb6d50df199c96370c72234170vboxsync } while (0)
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync/*******************************************************************************
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync* Structures and Typedefs *
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync*******************************************************************************/
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync * Security descriptor cleanup structure.
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync/** Pointer to security cleanup structure. */
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync * Image verifier cache entry.
d467cc8ba02be8665f75ea7d9155af6ea3256862vboxsync /** Pointer to the next entry with the same hash value. */
d467cc8ba02be8665f75ea7d9155af6ea3256862vboxsync /** The file handle. */
d467cc8ba02be8665f75ea7d9155af6ea3256862vboxsync /** If fIndexNumber is set, this is an file system internal file identifier. */
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync /** The path hash value. */
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync /** The verification result. */
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync /** Whether IndexNumber is valid */
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync /** cwcPath * sizeof(RTUTF16). */
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync /** The full path of this entry (variable size). */
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync/** Pointer to an image verifier path entry. */
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync/*******************************************************************************
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync* Global Variables *
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync*******************************************************************************/
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync/** @name Global variables initialized by suplibHardenedWindowsMain.
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync/** Combined windows NT version number. See SUP_MAKE_NT_VER_COMBINED. */
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync/** Count calls to the special main function for linking santity checks. */
163ee37fba9247129f39302c37ca2db94c70dec6vboxsyncstatic uint32_t volatile g_cSuplibHardenedWindowsMainCalls;
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync/** The UTF-16 windows path to the executable. */
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync/** The NT path of the executable. */
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync/** The offset into g_SupLibHardenedExeNtPath of the executable name (WCHAR,
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync * not byte). This also gives the length of the exectuable directory path,
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync * including a trailing slash. */
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync/** @name Hook related variables.
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync/** The jump back address of the patched NtCreateSection. */
163ee37fba9247129f39302c37ca2db94c70dec6vboxsyncextern "C" PFNRT g_pfnNtCreateSectionJmpBack = NULL;
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync/** Pointer to the bit of assembly code that will perform the original
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync * NtCreateSection operation. */
163ee37fba9247129f39302c37ca2db94c70dec6vboxsyncstatic NTSTATUS (NTAPI * g_pfnNtCreateSectionReal)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES,
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync/** The hash table of verifier cache . */
163ee37fba9247129f39302c37ca2db94c70dec6vboxsyncstatic VERIFIERCACHEENTRY * volatile g_apVerifierCache[128];
163ee37fba9247129f39302c37ca2db94c70dec6vboxsync/** Static error info structure used during init. */
#ifdef RT_ARCH_AMD64
# include "NtCreateSection-template-amd64-syscall-type-1.h"
#ifdef RT_ARCH_X86
# include "NtCreateSection-template-x86-syscall-type-1.h"
return NULL;
pwszHaystack++;
pwszCur++;
if (!pv)
return pv;
if (!pvOld)
if (!pv)
return pv;
if (pv)
while (*pwszPath)
pwszPath++;
if (!fSystem32Only)
if ( !pvRet
&& fFlags
return pvRet;
return NULL;
NTSTATUS rcNt = NtQueryInformationFile(hFile, &Ios, pIndexNumber, sizeof(*pIndexNumber), FileInternalInformation);
#ifdef DEBUG_bird
__debugbreak();
while (cwcLeft-- > 0)
return uHash;
static void supR3HardenedWinVerifyCacheInsert(PCUNICODE_STRING pUniStr, HANDLE hFile, int rc, bool fCacheable)
&& fCacheable)
if (pEntry)
if (!pOther)
#ifdef DEBUG_bird
__debugbreak();
static PVERIFIERCACHEENTRY supR3HardenedWinVerifyCacheLookup(PCUNICODE_STRING pUniStr, HANDLE hFile)
while (pCur)
return pCur;
if ( fIndexNumberValid
return pCur;
#ifdef DEBUG_bird
__debugbreak();
return NULL;
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--;
supR3HardenedMonitor_NtCreateSection(PHANDLE phSection, ACCESS_MASK fAccess, POBJECT_ATTRIBUTES pObjAttribs,
bool const fExecProt = RT_BOOL(fProtect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_WRITECOPY
} uBuf;
NTSTATUS rcNt = NtQueryObject(hFile, ObjectNameInformation, &uBuf, sizeof(uBuf) - sizeof(WCHAR) - 128, &cbNameBuf);
"supR3HardenedMonitor_NtCreateSection: NtQueryObject -> %#x (fImage=%d fExecMap=%d fExecProt=%d)\n",
return rcNt;
if (pCacheHit)
SUP_DPRINTF(("supR3HardenedMonitor_NtCreateSection: cache hit (%Rrc) on %ls\n", pCacheHit->rc, pCacheHit->wszPath));
return g_pfnNtCreateSectionReal(phSection, fAccess, pObjAttribs, pcbSection, fProtect, fAttribs, hFile);
return STATUS_TRUST_FAILURE;
&hMyFile,
InitializeObjectAttributes(&ObjAttr, &uBuf.UniStr, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
&ObjAttr,
&Ios,
"supR3HardenedMonitor_NtCreateSection: Failed to duplicate and open the file: rcNt=%#x hFile=%p %ls\n",
return rcNt;
#ifdef DEBUG
supR3HardenedError(VINF_SUCCESS, false, "supR3HardenedMonitor_NtCreateSection: NtDuplicateObject(,%#x,) failed: %#x\n", hFile, rcNt);
if ( !fImage
PRTUTF16 pwszName = &uBuf.UniStr.Buffer[(g_System32NtPath.UniStr.Length - sizeof(L"System32") + sizeof(WCHAR)) / sizeof(WCHAR)];
SUP_DPRINTF(("supR3HardenedMonitor_NtCreateSection: Applying the drop-exec-kludge for '%ls'\n", uBuf.UniStr.Buffer));
return g_pfnNtCreateSectionReal(phSection, fAccess, pObjAttribs, pcbSection, fProtect, fAttribs, hFile);
bool fSystem32 = false;
fSystem32 = true;
#ifdef VBOX_PERMIT_MORE
&& memcmp(uBuf.UniStr.Buffer + (uBuf.UniStr.Length - sizeof(L"\\SamplingRuntime.dll") + sizeof(WCHAR)) / sizeof(WCHAR),
return g_pfnNtCreateSectionReal(phSection, fAccess, pObjAttribs, pcbSection, fProtect, fAttribs, hFile);
"supR3HardenedMonitor_NtCreateSection: Not a trusted location: '%ls' (fImage=%d fExecMap=%d fExecProt=%d)\n",
return STATUS_TRUST_FAILURE;
bool fCacheable = true;
int rc = supHardenedWinVerifyImageByHandle(hMyFile, uBuf.UniStr.Buffer, fFlags, &fCacheable, &ErrInfo);
return STATUS_TRUST_FAILURE;
return g_pfnNtCreateSectionReal(phSection, fAccess, pObjAttribs, pcbSection, fProtect, fAttribs, hFile);
#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));
void *pvMem = VirtualAllocEx(hProc, (void *)uCur, cbAlloc, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (pvMem)
if ( iDirection > 0
return pvMem;
if ( iDirection > 0
if (iDirection > 0)
return NULL;
#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
#ifdef RT_ARCH_AMD64
if (!pvMem)
if (!pvMem)
# 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 *)&pbNtCreateSection[2] = (uint32_t)((uintptr_t)puJmpTab - (uintptr_t)&pbNtCreateSection[2+4]);
# 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_X86
int rc = supHardenedWinVerifyProcess(GetCurrentProcess(), GetCurrentThread(), &g_ErrInfoStatic.Core);
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)
PSECURITY_DESCRIPTOR pSecDesc = (PSECURITY_DESCRIPTOR)suplibHardenedAllocZ(SECURITY_DESCRIPTOR_MIN_LENGTH);
SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCreateSecurityDescriptor(pSecDesc, SECURITY_DESCRIPTOR_REVISION));
SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlSetDaclSecurityDescriptor(pSecDesc, TRUE /*fDaclPresent*/, &pCleanup->Acl.AclHdr,
pwszArgs++;
int fQuoted = false;
pwszArgs++;
pwszArgs++;
unsigned cSlashes = 0;
cSlashes++;
pwszArgs++;
size_t cwcCmdLine = (sizeof(SUPR3_RESPAWN_ARG0) - 1) / sizeof(SUPR3_RESPAWN_ARG0[0]) /* Respawn exe name. */
PRTUTF16 pwszCmdLine = (PRTUTF16)HeapAlloc(GetProcessHeap(), 0 /* dwFlags*/, (cwcCmdLine + 1) * sizeof(RTUTF16));
if (cwcArgs)
return pwszCmdLine;
static int supR3HardenedWinDoReSpawn(void)
&ProcessInfo))
supR3HardenedError(dwErr, false /*fFatal*/, "DuplicateHandle failed on child process handle: %u\n", dwErr);
if (!fExitOk)
} while ( !fExitOk
if (fExitOk)
InitializeObjectAttributes(&ObjAttr, &NtDirName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
#ifdef VBOX_STRICT
bool fFound = true;
&cbActual);
fFound = true;
pObjDir++;
} while (!fFound);
return fFound;
InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
&ObjAttr,
&Ios,
/** @todo Consider starting the VBoxdrv.sys service. Requires 2nd process
const char *pszDefine;
switch (rcNt)
return supR3HardenedWinDoReSpawn();
#ifndef VBOX_WITH_VISTA_NO_SP
"Window Vista without any service pack installed is not supported. Please install the latest service pack.");
int cbNeeded = WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, pwszCmdLine, -1, NULL /*pszDst*/, 0 /*cbDst*/,
int cArgs = 0;
if (!ch)
bool fQuoted = false;
unsigned cSlashes = 0;
cSlashes++;
if (cSlashes)
pszSrc--;
while (cSlashes-- > 0)
if (!ch)
return papszArgs;
HANDLE hFile = CreateFileW(g_wszSupLibHardenedExePath, GENERIC_READ, FILE_SHARE_READ, NULL /*pSecurityAttributes*/,
supR3HardenedFatalMsg("suplibHardenedWindowsMain", kSupInitOp_Integrity, RTErrConvertFromWin32(GetLastError()),
supR3HardenedFatalMsg("suplibHardenedWindowsMain", kSupInitOp_Integrity, RTErrConvertFromNtStatus(rcNt),
int cArgs;