SUPHardenedVerifyProcess-win.cpp revision 2f9acd6c5608d79e003dda3b5ebbd511d7f6fdd0
10139N/A * available from http://www.virtualbox.org. This file is free software;
10139N/A# define IPRT_NT_MAP_TO_ZW
10139N/A# include "SUPDrvInternal.h"
10139N/A# include "SUPLibInternal.h"
10139N/A#include "win/SUPHardenedVerify-win.h"
10139N/Atypedef struct SUPHNTVPREGION
11248N/Atypedef struct SUPHNTVPIMAGE
10139N/A /** Name structure for NtQueryVirtualMemory/MemorySectionName. */
10139N/A bool f32bitResourceDll;
10139N/Atypedef struct SUPHNTVPSTATE
10985N/A#ifdef VBOX_PERMIT_MORE
10139N/Astatic const char *g_apszSupNtVpAllowedDlls[] =
10139N/A#ifdef VBOX_PERMIT_MORE
10139N/A * @remarks Remember to keep in sync with SUPR3HardenedVerify.cpp.
10139N/Astatic const char *g_apszSupNtVpAllowedVmExes[] =
10139N/A/** Pointer to NtQueryVirtualMemory. Initialized by SUPDrv-win.cpp in
10139N/Astatic int supHardNtVpReadImage(PSUPHNTVPIMAGE pImage, uint64_t off, void *pvBuf, size_t cbRead)
10139N/Astatic NTSTATUS supHardNtVpReadMem(HANDLE hProcess, uintptr_t uPtr, void *pvBuf, size_t cbRead)
10139N/A return STATUS_SUCCESS;
10139N/A return STATUS_ACCESS_DENIED;
return rcNt;
#ifdef IN_RING3
static NTSTATUS supHardNtVpFileMemRestore(PSUPHNTVPSTATE pThis, PVOID pvRestoreAddr, uint8_t const *pbFile, uint32_t cbToRestore,
NTSTATUS rcNt = NtProtectVirtualMemory(pThis->hProcess, &pvProt, &cbProt, PAGE_READWRITE, &fOldProt);
NTSTATUS rcNt2 = NtProtectVirtualMemory(pThis->hProcess, &pvProt, &cbProt, fCorrectProtection, &fOldProt);
return rcNt;
typedef struct SUPHNTVPSKIPAREA
AssertCompileAdjacentMembers(SUPHNTVPSTATE, abMemory, abFile); /* Use both the memory and file buffers here. Parfait might hate me for this... */
while (cb > 0)
if (cSkipAreas)
cbThis = 0;
SUP_DPRINTF(("%s: Differences in section #%u (%s) between file and memory:\n", pImage->pszName, iSh + 1, pachSectNm));
off++;
cDiffs++;
#ifdef IN_RING3
return VINF_SUCCESS;
if (!cb)
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return supHardNtVpSetInfo2(pThis, cbOrg == cb ? VERR_SUP_VP_SECTION_NOT_MAPPED : VERR_SUP_VP_SECTION_NOT_FULLY_MAPPED,
static int supHardNtVpVerifyImageMemoryCompare(PSUPHNTVPSTATE pThis, PSUPHNTVPIMAGE pImage, HANDLE hProcess, PRTERRINFO pErrInfo)
#ifdef RT_ARCH_AMD64
if (pNtHdrs->FileHeader.SizeOfOptionalHeader != (fIs32Bit ? sizeof(IMAGE_OPTIONAL_HEADER32) : sizeof(IMAGE_OPTIONAL_HEADER64)))
if (pNtHdrs->OptionalHeader.Magic != (fIs32Bit ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC))
uint32_t cDirs = (fIs32Bit ? pNtHdrs32->OptionalHeader.NumberOfRvaAndSizes : pNtHdrs->OptionalHeader.NumberOfRvaAndSizes);
suplibHardenedMemCopy(pThis->aSecHdrs, (fIs32Bit ? (void *)(pNtHdrs32 + 1) : (void *)(pNtHdrs + 1)),
uintptr_t const uImageBase = fIs32Bit ? pNtHdrs32->OptionalHeader.ImageBase : pNtHdrs->OptionalHeader.ImageBase;
uint32_t const cbImage = fIs32Bit ? pNtHdrs32->OptionalHeader.SizeOfImage : pNtHdrs->OptionalHeader.SizeOfImage;
if (RT_ALIGN_32(pImage->cbImage, PAGE_SIZE) != RT_ALIGN_32(cbImage, PAGE_SIZE) && !pImage->fApiSetSchemaOnlySection1)
uint32_t const cbSectAlign = fIs32Bit ? pNtHdrs32->OptionalHeader.SectionAlignment : pNtHdrs->OptionalHeader.SectionAlignment;
uint32_t const cbFileAlign = fIs32Bit ? pNtHdrs32->OptionalHeader.FileAlignment : pNtHdrs->OptionalHeader.FileAlignment;
if (!RT_IS_POWER_OF_TWO(cbFileAlign) || cbFileAlign < 512 || cbFileAlign > PAGE_SIZE || cbFileAlign > cbSectAlign)
uint32_t const cbHeaders = fIs32Bit ? pNtHdrs32->OptionalHeader.SizeOfHeaders : pNtHdrs->OptionalHeader.SizeOfHeaders;
pImage->fDllCharecteristics = fIs32Bit ? pNtHdrs32->OptionalHeader.DllCharacteristics : pNtHdrs->OptionalHeader.DllCharacteristics;
rc = RTLdrGetBits(pImage->hLdrMod, pImage->pbBits, pImage->uImageBase, NULL /*pfnGetImport*/, pThis);
if (fIs32Bit)
((PIMAGE_NT_HEADERS32)&pImage->pbBits[offNtHdrs])->OptionalHeader.ImageBase = (uint32_t)pImage->uImageBase;
return supHardNtVpSetInfo2(pThis, rc, "%s: Failed to find 'NtCreateSection': %Rrc", pImage->pszName, rc);
/* LdrSystemDllInitBlock is filled in by the kernel. It mainly contains addresses of 32-bit ntdll method for wow64. */
rc = supHardNtVpFileMemCompareSection(pThis, pImage, 0 /*uRva*/, cbHdrsFile, pImage->pbBits, -1, NULL, 0, PAGE_READONLY);
return rc;
return rc;
switch (pThis->aSecHdrs[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE))
case IMAGE_SCN_MEM_READ:
case IMAGE_SCN_MEM_EXECUTE:
return rc;
rc = supHardNtVpCheckSectionProtection(pThis, pImage, uSectRva, RT_ALIGN_32(cbMap, PAGE_SIZE), fProt);
return rc;
return VINF_SUCCESS;
int rc;
rc = supHardenedWinVerifyImageByLdrMod(pImage->hLdrMod, pImage->Name.UniStr.Buffer, pImage->pNtViRdr,
return rc;
NTSTATUS rcNt = NtQueryInformationThread(hThread, ThreadAmILastThread, &fAmI, sizeof(fAmI), &cbIgn);
if (!fAmI)
return VINF_SUCCESS;
#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
if (uPtr != 0)
return VINF_SUCCESS;
if (!ch1)
static int supHardNtVpNewImage(PSUPHNTVPSTATE pThis, PSUPHNTVPIMAGE pImage, PMEMORY_BASIC_INFORMATION pMemInfo)
while ( cwcDirName > 0
pwszFilename--;
cwcDirName--;
if (!*pwszFilename)
while ( cwcDirName > 0
cwcDirName--;
# ifdef VBOX_PERMIT_MORE
|| !supHardViIsAppPatchDir(pImage->Name.UniStr.Buffer, pImage->Name.UniStr.Length / sizeof(WCHAR)) )
# ifdef VBOX_PERMIT_MORE
"See http://www.symantec.com/connect/articles/creating-application-control-exclusions-symantec-endpoint-protection-121"
return pThis->rcResult = VERR_SUP_VP_SYSFER_DLL; /* Try make sure this is what the user sees first! */
"Invalid AllocationBase/BaseAddress for %s: %p vs %p.",
#ifdef VBOX_PERMIT_MORE
return VINF_SUCCESS;
static int supHardNtVpAddRegion(PSUPHNTVPSTATE pThis, PSUPHNTVPIMAGE pImage, PMEMORY_BASIC_INFORMATION pMemInfo)
return VINF_SUCCESS;
pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION ? "CHILD_PURIFICATION" : "SELF_PURIFICATION"));
(void const *)uPtrWhere,
&MemInfo,
sizeof(MemInfo),
&cbActual);
(void const *)uPtrWhere,
&cbActual);
pThis->aImages[iImg].Name.UniStr.Buffer[pThis->aImages[iImg].Name.UniStr.Length / sizeof(WCHAR)] = '\0';
bool fNew = true;
while (iSearch-- > 0)
if (supHardNtVpAreUniStringsEqual(&pThis->aImages[iSearch].Name.UniStr, &pThis->aImages[iImg].Name.UniStr))
return rc;
fNew = false;
if (fNew)
return rc;
return rc;
else if ( (MemInfo.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY))
&& cXpExceptions == 0
else if (MemInfo.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY))
# ifdef IN_RING3
* Free any private executable memory (sysplant.sys allocates executable memory).
# ifndef IN_RING3
InitializeObjectAttributes(&ObjAttr, &pImage->Name.UniStr, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
#ifdef IN_RING0
&ObjAttr,
&Ios,
return rc;
rc = RTLdrOpenWithReader(&pNtViRdr->Core, RTLDR_O_FOR_VALIDATION, enmArch, &hLdrMod, pThis->pErrInfo);
return VINF_SUCCESS;
unsigned cExecs = 0;
unsigned iExe = ~0U;
cExecs++;
iExe = i;
if (cExecs == 0)
int rc;
if (!pUniStr)
NTSTATUS rcNt = NtQueryInformationProcess(hProcess, ProcessImageFileName, pUniStr, cbUniStr - sizeof(WCHAR), &cbIgn);
return rc;
return rc;
rcNt = NtQueryInformationProcess(hProcess, ProcessImageInformation, &ImageInfo, sizeof(ImageInfo), NULL);
return VINF_SUCCESS;
return VINF_SUCCESS;
uint32_t j = i;
iNtDll = i;
iKernel32 = i;
return rc;
return VINF_SUCCESS;
DECLHIDDEN(int) supHardenedWinVerifyProcess(HANDLE hProcess, HANDLE hThread, SUPHARDNTVPKIND enmKind, PRTERRINFO pErrInfo)
#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
if (pThis)
return rc;