SUPDrv-win.cpp revision b7b1edd6e178dde0f2f3ee63aa767c04fd7de40b
16a8d09569a2ebd598cef72fa605be6fb4563607vboxsync * VBoxDrv - The VirtualBox Support Driver - Windows NT specifics.
16a8d09569a2ebd598cef72fa605be6fb4563607vboxsync * Copyright (C) 2006-2012 Oracle Corporation
16a8d09569a2ebd598cef72fa605be6fb4563607vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
16a8d09569a2ebd598cef72fa605be6fb4563607vboxsync * available from http://www.virtualbox.org. This file is free software;
16a8d09569a2ebd598cef72fa605be6fb4563607vboxsync * you can redistribute it and/or modify it under the terms of the GNU
16a8d09569a2ebd598cef72fa605be6fb4563607vboxsync * General Public License (GPL) as published by the Free Software
16a8d09569a2ebd598cef72fa605be6fb4563607vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
16a8d09569a2ebd598cef72fa605be6fb4563607vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16a8d09569a2ebd598cef72fa605be6fb4563607vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16a8d09569a2ebd598cef72fa605be6fb4563607vboxsync * The contents of this file may alternatively be used under the terms
16a8d09569a2ebd598cef72fa605be6fb4563607vboxsync * of the Common Development and Distribution License Version 1.0
fa28a063d8ed660b9ae9aef07f417338b0efd8acvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
16a8d09569a2ebd598cef72fa605be6fb4563607vboxsync * VirtualBox OSE distribution, in which case the provisions of the
16a8d09569a2ebd598cef72fa605be6fb4563607vboxsync * CDDL are applicable instead of those of the GPL.
16a8d09569a2ebd598cef72fa605be6fb4563607vboxsync * You may elect to license modified versions of this file under the
16a8d09569a2ebd598cef72fa605be6fb4563607vboxsync * terms and conditions of either the GPL or the CDDL or both.
a7a0244227b5c1fb4410f6a1fa6cf7a462eaf4c1vboxsync/*******************************************************************************
a7a0244227b5c1fb4410f6a1fa6cf7a462eaf4c1vboxsync* Header Files *
a7a0244227b5c1fb4410f6a1fa6cf7a462eaf4c1vboxsync*******************************************************************************/
#ifdef VBOX_WITH_HARDENING
# include "SUPHardenedVerify-win.h"
#ifdef VBOX_WITH_HARDENING
do { if ((a_pDevObj) == g_pDevObjStub) supdrvNtCompleteRequest(STATUS_ACCESS_DENIED, a_pIrp); } while (0)
#define VBOXDRV_WITH_FAST_IO
typedef struct SUPDRVDEVEXTUSR
#ifdef VBOX_WITH_HARDENING
typedef struct SUPDRVDEVEXTSTUB
typedef enum SUPDRVNTPROTECTKIND
typedef struct SUPDRVNTPROTECT
typedef NTSTATUS (NTAPI *PFNPSSETCREATEPROCESSNOTIFYROUTINEEX)(PCREATE_PROCESS_NOTIFY_ROUTINE_EX, BOOLEAN);
#ifdef VBOXDRV_WITH_FAST_IO
static BOOLEAN _stdcall VBoxDrvNtFastIoDeviceControl(PFILE_OBJECT pFileObj, BOOLEAN fWait, PVOID pvInput, ULONG cbInput,
static int VBoxDrvNtDeviceControlSlow(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PIRP pIrp, PIO_STACK_LOCATION pStack);
static VOID _stdcall VBoxPowerDispatchCallback(PVOID pCallbackContext, PVOID pArgument1, PVOID pArgument2);
#ifdef VBOX_WITH_HARDENING
static void supdrvNtProtectTerm(void);
static bool supdrvNtIsDebuggerAttached(void);
#ifdef VBOXDRV_WITH_FAST_IO
#ifdef VBOX_WITH_HARDENING
# ifdef RT_ARCH_AMD64
NTSTATUS rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXT), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjSys);
rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXTUSR), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjUsr);
#ifdef VBOX_WITH_HARDENING
rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXTSTUB), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjStub);
return rcNt;
#ifdef VBOX_WITH_HARDENING
return rcNt;
static void vboxdrvNtDestroyDevices(void)
if (g_pDevObjUsr)
#ifdef VBOX_WITH_HARDENING
if (g_pDevObjStub)
#ifdef VBOX_WITH_HARDENING
#ifdef VBOXDRV_WITH_FAST_IO
return STATUS_INTERNAL_ERROR;
#ifdef VBOX_WITH_HARDENING
if (!vrc)
#ifdef VBOXDRV_WITH_FAST_IO
return STATUS_SUCCESS;
#ifdef VBOX_WITH_HARDENING
RTR0Term();
return rcNt;
#ifdef VBOX_WITH_HARDENING
RTR0Term();
return rcNt;
#ifdef VBOX_WITH_HARDENING
LogRel(("vboxdrv: Declined %p access to VBoxDrvStub: rc=%d\n", PsGetProcessId(PsGetCurrentProcess()), rc));
if (pNtProtect)
&pSession);
rc = supdrvCreateSession(pDevExt, true /*fUser*/, pDevObj == g_pDevObjSys /*fUnrestricted*/, &pSession);
return supdrvNtCompleteRequest(rcNt, pIrp); /* Note. the IoStatus is completely ignored on error. */
#ifdef VBOX_WITH_HARDENING
if (pNtProtect)
if (pSession)
#ifdef VBOX_WITH_HARDENING
if (pNtProtect)
if (pSession)
#ifdef VBOXDRV_WITH_FAST_IO
static BOOLEAN _stdcall VBoxDrvNtFastIoDeviceControl(PFILE_OBJECT pFileObj, BOOLEAN fWait, PVOID pvInput, ULONG cbInput,
if (!pSession)
return TRUE;
if (supdrvNtIsDebuggerAttached())
return TRUE;
return TRUE;
unsigned cbOut = 0;
int rc = 0;
Log2(("VBoxDrvNtFastIoDeviceControl(%p): ioctl=%#x pvIn=%p cbIn=%#x pvOut=%p cbOut=%#x pSession=%p\n",
# ifdef RT_ARCH_AMD64
if (pHdr)
if (cbOut)
# ifdef RT_ARCH_AMD64
if (supdrvNtIsDebuggerAttached())
int rc = supdrvIOCtlFast(ulCmd, (unsigned)(uintptr_t)pIrp->UserBuffer /* VMCPU id */, pDevExt, pSession);
static int VBoxDrvNtDeviceControlSlow(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PIRP pIrp, PIO_STACK_LOCATION pStack)
unsigned cbOut = 0;
int rc = 0;
#ifdef RT_ARCH_AMD64
if (!rc)
#ifdef RT_ARCH_AMD64
return rcNt;
unsigned cbOut = 0;
int rc = 0;
: !pSession
if (!rc)
return rcNt;
return STATUS_NOT_SUPPORTED;
if ((unsigned)pArgument2 == 0)
#ifdef VBOX_WITH_HARDENING
void VBOXCALL supdrvOSSessionHashTabInserted(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
void VBOXCALL supdrvOSSessionHashTabRemoved(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
typedef struct MYSYSTEMGDIDRIVERINFO
int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
# ifndef RT_ARCH_X86
return VERR_NOT_SUPPORTED;
return rc;
if (!pwcsFilename)
return VERR_NO_TMP_MEMORY;
NTSTATUS rcNt = ZwSetSystemInformation(MY_SystemLoadGdiDriverInSystemSpaceInformation, &Info, sizeof(Info));
Info.ImageAddress, Info.SectionPointer, Info.ImageLength, pImage->cbImageBits, rcNt, Info.Name.Buffer));
# ifdef DEBUG_bird
Info.ImageAddress, Info.SectionPointer, Info.ImageLength, pImage->cbImageBits, rcNt, Info.Name.Buffer);
rc = RTR0MemObjLockKernel(&pImage->hMemLock, pImage->pvImage, pImage->cbImageBits, RTMEM_PROT_READ);
switch (rcNt)
# ifdef RT_ARCH_AMD64
return rc;
int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, const uint8_t *pbImageBits)
return VINF_SUCCESS;
static int supdrvNtCompare(PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, uint32_t uRva, uint32_t cb)
if (iDiff)
return iDiff;
int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
return VINF_SUCCESS;
&& pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size >= sizeof(IMAGE_IMPORT_DESCRIPTOR)
&& pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress > sizeof(IMAGE_NT_HEADERS)
&& pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress < pImage->cbImageBits
struct MyRegion
unsigned cExcludeRgns = 0;
/ sizeof(IMAGE_IMPORT_DESCRIPTOR);
while ( cImpsLeft-- > 0
cThunks++;
for (; i < cExcludeRgns; i++)
if (i != cExcludeRgns)
cExcludeRgns++;
pImp++;
int iDiff = 0;
if (!iDiff)
return VINF_SUCCESS;
return VERR_LDR_MISMATCH_NATIVE;
return VERR_INTERNAL_ERROR_4;
#ifdef SUPDRV_WITH_MSR_PROBER
typedef struct SUPDRVNTMSPROBERARGS
bool fGp;
return rc;
return VERR_ACCESS_DENIED;
return VINF_SUCCESS;
return rc;
return VERR_ACCESS_DENIED;
return VINF_SUCCESS;
bool fBeforeGp = true;
bool fModifyGp = true;
bool fAfterGp = true;
bool fRestoreGp = true;
if (!fFaster)
fBeforeGp = false;
fBeforeGp = true;
if (!fBeforeGp)
fModifyGp = false;
fModifyGp = true;
fAfterGp = false;
fAfterGp = true;
fRestoreGp = false;
fRestoreGp = true;
if (!fFaster)
ASMReloadCR3();
ASMNopPause();
return VINF_SUCCESS;
switch (rc)
if (rc < 0)
return STATUS_UNSUCCESSFUL;
#ifdef VBOX_WITH_HARDENING
if (!pszImageFile)
} Buf;
if (!chRight)
int rc;
if (uSessionId == 0)
&pvApiPortObj);
return VERR_SUPDRV_APIPORT_OPEN_ERROR;
if (!pbBuf)
cbNeeded = 0;
if ( pbBuf
bool fThatsIt = false;
ppPortProc++;
fThatsIt = false;
if (fThatsIt)
return rc;
static bool supdrvNtProtectIsFrigginThemesService(PSUPDRVNTPROTECT pNtProtect, PEPROCESS pAnnoyingProcess)
static bool supdrvNtProtectIsSpawningStubProcess(PSUPDRVNTPROTECT pNtStub, HANDLE hParentPid, HANDLE hChildPid)
bool fRc = false;
return fRc;
int rc = supdrvNtProtectCreate(&pNtChild, hChildPid, kSupDrvNtProtectKind_VmProcessUnconfirmed, false /*fLink*/);
if (fSuccess)
return VINF_SUCCESS;
return rc;
if (pNtProtect)
if (g_pDevObjSys)
if (pSession)
static void supdrvNtProtectVerifyNewChildProtection(PSUPDRVNTPROTECT pNtStub, PSUPDRVNTPROTECT pNtVm, bool fCallerChecks)
if ( fCallerChecks
LogRel(("vboxdrv: Misdetected vm stub; hParentPid=%p hChildPid=%p\n", pNtStub->AvlCore.Key, pNtVm->AvlCore.Key));
if (fCreated)
if (pNtStub)
if (!pNtVm)
supdrvNtProtectCallback_ProcessCreateNotifyEx(PEPROCESS pNewProcess, HANDLE hNewPid, PPS_CREATE_NOTIFY_INFO pInfo)
if (pInfo)
pInfo->FileOpenNameAvailable && pInfo->ImageFileName ? (size_t)pInfo->ImageFileName->Length / 2 : 0,
if (pNtStub)
if (!pNtVm)
# define SUPDRV_NT_ALLOW_PROCESS_RIGHTS \
| PROCESS_VM_READ \
| DELETE \
| READ_CONTROL \
| SYNCHRONIZE)
# define SUPDRV_NT_EVIL_PROCESS_RIGHTS \
| PROCESS_VM_WRITE \
Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
if (!pNtProtect)
if (pNtStub)
if (pNtProtect)
&& pOpInfo->Parameters->CreateHandleInformation.DesiredAccess == 0x1478 /* 6.1.7600.16385 (win7_rtm.090713-1255) */
Log(("vboxdrv/ProcessHandlePre: ctx=%04zx/%p wants %#x to %p/pid=%04zx [%d], allow %#x => %#x; %s\n",
Log(("vboxdrv/ProcessHandlePre: ctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] %s\n",
Log(("vboxdrv/ProcessHandlePre: ctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] %s\n",
return OB_PREOP_SUCCESS;
Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
/* From ntifs.h */
# define SUPDRV_NT_ALLOWED_THREAD_RIGHTS \
( THREAD_TERMINATE \
| DELETE \
| READ_CONTROL \
| SYNCHRONIZE)
# define SUPDRV_NT_EVIL_THREAD_RIGHTS \
Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
if (pNtProtect)
Log(("vboxdrv/ThreadHandlePre: ctx=%04zx/%p wants %#x to %p in pid=%04zx [%d], allow %#x => %#x; %s\n",
Log(("vboxdrv/ThreadHandlePre: ctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] self\n",
Log(("vboxdrv/ThreadHandlePre: ctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d], allow %#x => %#x; %s\n",
return OB_PREOP_SUCCESS;
Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
fGrantedAccess, SUPDRV_NT_ALLOWED_THREAD_RIGHTS, fGrantedAccess & ~SUPDRV_NT_ALLOWED_THREAD_RIGHTS));
static int supdrvNtProtectCreate(PSUPDRVNTPROTECT *ppNtProtect, HANDLE hPid, SUPDRVNTPROTECTKIND enmProcessKind, bool fLink)
if (!pNtProtect)
return VERR_NO_MEMORY;
if (fLink)
if (!fSuccess)
return VERR_DUPLICATE;
return VINF_SUCCESS;
if (!pNtProtect)
if (cRefs != 0)
PSUPDRVNTPROTECT pRemoved = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pNtProtect->AvlCore.Key);
if (pChild)
if (!cChildRefs)
if (pChild)
if (pFound)
return pFound;
if (!pbBuf)
return VERR_NO_MEMORY;
const char *pszType;
# ifndef VBOX_WITH_VISTA_NO_SP
return rc;
AssertReturn(PsGetProcessId(PsGetCurrentProcess()) == pNtProtect->AvlCore.Key, VERR_INTERNAL_ERROR_3);
pNtProtect->enmProcessKind = RT_SUCCESS(rc) ? kSupDrvNtProtectKind_StubSpawning : kSupDrvNtProtectKind_StubDead;
return rc;
# ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
static bool supdrvNtIsDebuggerAttached(void)
static void supdrvNtProtectTerm(void)
rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
# ifdef RT_ARCH_X86
g_pfnPsSetCreateProcessNotifyRoutineEx = (PFNPSSETCREATEPROCESSNOTIFYROUTINEEX)MmGetSystemRoutineAddress(&RoutineName);
g_pfnPsReferenceProcessFilePointer = (PFNPSREFERENCEPROCESSFILEPOINTER)MmGetSystemRoutineAddress(&RoutineName);
g_pfnPsIsProtectedProcessLight = (PFNPSISPROTECTEDPROCESSLIGHT)MmGetSystemRoutineAddress(&RoutineName);
# ifdef RT_ARCH_X86
case 0xb0: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xAF; break; /* just in case */
case 0xb1: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB0; break; /* just in case */
case 0xb2: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB1; break; /* just in case */
case 0xb3: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB2; break; /* XP SP3 */
case 0xb4: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB2; break; /* just in case */
case 0xb5: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB3; break; /* just in case */
case 0xb6: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB4; break; /* just in case */
case 0xb7: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB5; break; /* just in case */
case 0xb8: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB6; break; /* just in case */
case 0xb9: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB7; break; /* just in case */
case 0xba: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB8; break; /* just in case */
case 0xbb: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBA; break; /* W2K3 R2 SP2 */
case 0xbc: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBB; break; /* just in case */
case 0xbd: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBC; break; /* just in case */
case 0xbe: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBD; break; /* just in case */
case 0xbf: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBE; break; /* just in case */
case 0x1e: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x1F; break;
case 0x1f: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x20; break;
case 0x20: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x21; break;
case 0x21: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x22; break;
case 0x22: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x23; break;
LogRel(("vboxdrv: Cannot locate ZwQueryVirtualMemory in ntoskrnl, nor were we able to cook up a replacement.\n"));
return STATUS_PROCEDURE_NOT_FOUND;
rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, FALSE /*fRemove*/);
rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, FALSE /*fRemove*/);
for (uint32_t i = 0; i < RT_ELEMENTS(s_apwszAltitudes) && rcNt == STATUS_FLT_INSTANCE_ALTITUDE_COLLISION; i++)
return STATUS_SUCCESS;
# ifndef VBOX_WITH_VISTA_NO_SP
DbgPrint("vboxdrv: ObRegisterCallbacks was not found. Please make sure you got the latest updates and service packs installed\n");
g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
return rcNt;