SUPHardenedVerifyProcess-win.cpp revision 1f64240a0fda7b4c7cc9fcd4ef610f26623485b8
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * VirtualBox Support Library/Driver - Hardened Process Verification, Windows.
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * Copyright (C) 2006-2014 Oracle Corporation
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * available from http://www.virtualbox.org. This file is free software;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * you can redistribute it and/or modify it under the terms of the GNU
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * General Public License (GPL) as published by the Free Software
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The contents of this file may alternatively be used under the terms
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * of the Common Development and Distribution License Version 1.0
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * VirtualBox OSE distribution, in which case the provisions of the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * CDDL are applicable instead of those of the GPL.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * You may elect to license modified versions of this file under the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * terms and conditions of either the GPL or the CDDL or both.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/*******************************************************************************
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync* Header Files *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync*******************************************************************************/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/*******************************************************************************
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync* Structures and Typedefs *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync*******************************************************************************/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Virtual address space region.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The RVA of the region. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The size of the region. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The protection of the region. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Pointer to a virtual address space region. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Virtual address space image information.
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync /** The base address of the image. */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync /** The size of the image mapping. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The name from the allowed lists. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync const char *pszName;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Name structure for NtQueryVirtualMemory/MemorySectionName. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The full unicode name. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Buffer space. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The number of mapping regions. */
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync /** Mapping regions. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync /** The image characteristics from the FileHeader. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The DLL characteristics from the OptionalHeader. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Set if this is the DLL. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Set if the image is NTDLL an the verficiation code needs to watch out for
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * the NtCreateSection patch. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Whether the API set schema hack needs to be applied when verifying memory
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * content. The hack means that we only check if the 1st section is mapped. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** This may be a 32-bit resource DLL. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the loader cache entry for the image. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** In ring-0 we don't currently cache images, so put it here. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Pointer to image info from the virtual address space scan. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Virtual address space scanning state.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Type of verification to perform. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Combination of SUPHARDNTVP_F_XXX. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The result. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Number of fixes we've done.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Only applicable in the purification modes. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Number of images in aImages. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The index of the last image we looked up. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The process handle. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Images found in the process.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The array is large enough to hold the executable, all allowed DLLs, and one
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * more so we can get the image name of the first unwanted DLL. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Memory compare scratch buffer.*/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** File compare scratch buffer.*/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Section headers for use when comparing file and loaded image. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the error info. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Pointer to stat information of a virtual address space scan. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/*******************************************************************************
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync* Global Variables *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync*******************************************************************************/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * System DLLs allowed to be loaded into the process.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @remarks supHardNtVpCheckDlls assumes these are lower case.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic const char *g_apszSupNtVpAllowedDlls[] =
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "ntdll.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "kernel32.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "kernelbase.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "apphelp.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "apisetschema.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "verifier.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "sfc_os.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "user32.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "acres.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "acgenral.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "psapi.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "msvcrt.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "advapi32.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "sechost.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "rpcrt4.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "SamplingRuntime.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * VBox executables allowed to start VMs.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @remarks Remember to keep in sync with SUPR3HardenedVerify.cpp.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic const char *g_apszSupNtVpAllowedVmExes[] =
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "VBoxHeadless.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "VirtualBox.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "VBoxSDL.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "VBoxNetDHCP.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "VBoxNetNAT.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "tstMicro.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "tstPDMAsyncCompletion.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "tstPDMAsyncCompletionStress.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "tstVMM.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "tstVMREQ.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "tstCFGM.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "tstIntNet-1.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "tstMMHyperHeap.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "tstR0ThreadPreemptionDriver.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "tstRTR0MemUserKernelDriver.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "tstRTR0SemMutexDriver.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "tstRTR0TimerDriver.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "tstSSM.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Pointer to NtQueryVirtualMemory. Initialized by SUPDrv-win.cpp in
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * ring-0, in ring-3 it's just a slightly confusing define. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncPFNNTQUERYVIRTUALMEMORY g_pfnNtQueryVirtualMemory = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define g_pfnNtQueryVirtualMemory NtQueryVirtualMemory
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** The number of valid entries in the loader cache.. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** The loader cache entries. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic SUPHNTLDRCACHEENTRY g_aSupNtVpLdrCacheEntries[RT_ELEMENTS(g_apszSupNtVpAllowedDlls) + 1 + 3];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Fills in error information.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns @a rc.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pErrInfo Pointer to the extended error info structure.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Can be NULL.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pszErr Where to return error details.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param cbErr Size of the buffer @a pszErr points to.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param rc The status to return.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pszMsg The format string for the message.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param ... The arguments for the format string.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int supHardNtVpSetInfo1(PRTERRINFO pErrInfo, int rc, const char *pszMsg, ...)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync supR3HardenedError(rc, false /*fFatal*/, "%N\n", pszMsg, &va);
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync * Fills in error information.
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync * @returns @a rc.
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync * @param pThis The process validator instance.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pszErr Where to return error details.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param cbErr Size of the buffer @a pszErr points to.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param rc The status to return.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pszMsg The format string for the message.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param ... The arguments for the format string.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int supHardNtVpSetInfo2(PSUPHNTVPSTATE pThis, int rc, const char *pszMsg, ...)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync supR3HardenedError(rc, false /*fFatal*/, "%N\n", pszMsg, &va);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTErrInfoAddF(pThis->pErrInfo, rc, " \n[rc=%d] ", rc);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int supHardNtVpReadImage(PSUPHNTVPIMAGE pImage, uint64_t off, void *pvBuf, size_t cbRead)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return pImage->pCacheEntry->pNtViRdr->Core.pfnRead(&pImage->pCacheEntry->pNtViRdr->Core, pvBuf, cbRead, off);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic NTSTATUS supHardNtVpReadMem(HANDLE hProcess, uintptr_t uPtr, void *pvBuf, size_t cbRead)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* ASSUMES hProcess is the current process. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** @todo use MmCopyVirtualMemory where available! */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NTSTATUS rcNt = NtReadVirtualMemory(hProcess, (PVOID)uPtr, pvBuf, cbRead, &cbIgn);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic NTSTATUS supHardNtVpFileMemRestore(PSUPHNTVPSTATE pThis, PVOID pvRestoreAddr, uint8_t const *pbFile, uint32_t cbToRestore,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NTSTATUS rcNt = NtProtectVirtualMemory(pThis->hProcess, &pvProt, &cbProt, PAGE_READWRITE, &fOldProt);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rcNt = NtWriteVirtualMemory(pThis->hProcess, pvRestoreAddr, pbFile, cbToRestore, &cbIgnored);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NTSTATUS rcNt2 = NtProtectVirtualMemory(pThis->hProcess, &pvProt, &cbProt, fCorrectProtection, &fOldProt);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif /* IN_RING3 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int supHardNtVpFileMemCompareSection(PSUPHNTVPSTATE pThis, PSUPHNTVPIMAGE pImage,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int32_t iSh, PSUPHNTVPSKIPAREA paSkipAreas, uint32_t cSkipAreas,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertCompileAdjacentMembers(SUPHNTVPSTATE, abMemory, abFile); /* Use both the memory and file buffers here. Parfait might hate me for this... */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t const cbMemory = sizeof(pThis->abMemory) + sizeof(pThis->abFile);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync while (cb > 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Clipping. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync while (i-- > 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t uSkipEnd = paSkipAreas[i].uRva + paSkipAreas[i].cb;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Read the memory. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NTSTATUS rcNt = supHardNtVpReadMem(pThis->hProcess, pImage->uImageBase + uRva, pbMemory, cbThis);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_MEMORY_READ_ERROR,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: Error reading %#x bytes at %p (rva %#x, #%u, %.8s) from memory: %#x",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage->pszName, cbThis, pImage->uImageBase + uRva, uRva, iSh + 1,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync iSh >= 0 ? (char *)pThis->aSecHdrs[iSh].Name : "headers", rcNt);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Do the compare. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync const char *pachSectNm = iSh >= 0 ? (char *)pThis->aSecHdrs[iSh].Name : "headers";
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SUP_DPRINTF(("%s: Differences in section #%u (%s) between file and memory:\n", pImage->pszName, iSh + 1, pachSectNm));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync while (off < cbThis && pbFile[off] == pbMemory[off])
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage->uImageBase + uRva + off, uRva + off, pbFile[off], pbMemory[off]));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t off2 = off + 1; off2 < cbThis; off2++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage->uImageBase + uRva + off2, uRva + off2, pbFile[off2], pbMemory[off2]));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ( pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync || pThis->enmKind == SUPHARDNTVPKIND_SELF_PURIFICATION)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PVOID pvRestoreAddr = (uint8_t *)pImage->uImageBase + uRva;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rcNt = supHardNtVpFileMemRestore(pThis, pvRestoreAddr, pbFile, cbThis, fCorrectProtection);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SUP_DPRINTF((" Restored %#x bytes of original file content at %p\n", cbThis, pvRestoreAddr));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_MEMORY_VS_FILE_MISMATCH,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: Failed to restore %#x bytes at %p (%#x, #%u, %s): %#x (cDiffs=%#x, first=%#x)",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage->pszName, cbThis, pvRestoreAddr, uRva, iSh + 1, pachSectNm, rcNt,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif /* IN_RING3 */
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_MEMORY_VS_FILE_MISMATCH,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: %u differences between %#x and %#x in #%u (%.8s), first: %02x != %02x",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage->pszName, cDiffs, uRva + off, uRva + offLast, iSh + 1,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Advance. The clipping makes it a little bit complicated. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int supHardNtVpCheckSectionProtection(PSUPHNTVPSTATE pThis, PSUPHNTVPIMAGE pImage,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ( pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync || pThis->enmKind == SUPHARDNTVPKIND_SELF_PURIFICATION)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t offRegion = uRva - pImage->aRegions[i].uRva;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbLeft = pImage->aRegions[i].cb - offRegion;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_SECTION_PROTECTION_MISMATCH,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: RVA range %#x-%#x protection is %#x, expected %#x. (cb=%#x)",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage->pszName, uRva, uRva + cbLeft - 1, pImage->aRegions[i].fProt, fProt, cb);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if 0 /* This shouldn't ever be necessary. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo2(pThis, cbOrg == cb ? VERR_SUP_VP_SECTION_NOT_MAPPED : VERR_SUP_VP_SECTION_NOT_FULLY_MAPPED,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: RVA range %#x-%#x is not mapped?", pImage->pszName, uRva, uRva + cb - 1);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLINLINE(bool) supHardNtVpIsModuleNameMatch(PSUPHNTVPIMAGE pImage, const char *pszModule)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Worker for supHardNtVpGetImport that looks up a module in the module table.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns Pointer to the module if found, NULL if not found.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pThis The process validator instance.
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync * @param pszModule The name of the module we're looking for.
93540abbca1a7ac8de705de01b9fc04092294a39vboxsyncstatic PSUPHNTVPIMAGE supHardNtVpFindModule(PSUPHNTVPSTATE pThis, const char *pszModule)
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync * Check out the hint first.
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync && supHardNtVpIsModuleNameMatch(&pThis->aImages[pThis->iImageHint], pszModule))
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync * Linear array search next.
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync while (i-- > 0)
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync if (supHardNtVpIsModuleNameMatch(&pThis->aImages[i], pszModule))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* No cigar. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @callback_method_impl{FNRTLDRIMPORT}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(int) supHardNtVpGetImport(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*SUP_DPRINTF(("supHardNtVpGetImport: %s / %#x / %s.\n", pszModule, uSymbol, pszSymbol));*/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PSUPHNTVPIMAGE pImage = supHardNtVpFindModule(pThis, pszModule);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pImage->pCacheEntry->pbBits,
710a6316a22868b04400caf79719f96c18163cd3vboxsync * API set hacks.
710a6316a22868b04400caf79719f96c18163cd3vboxsync else if (!RTStrNICmp(pszModule, RT_STR_TUPLE("api-ms-win-")))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync static const char * const s_apszDlls[] = { "ntdll.dll", "kernelbase.dll", "kernel32.dll" };
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(s_apszDlls); i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage = supHardNtVpFindModule(pThis, s_apszDlls[i]);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pImage->pCacheEntry->pbBits,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Deal with forwarders.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * ASSUMES no forwarders thru any api-ms-win-core-*.dll.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * ASSUMES forwarders are resolved after one redirection.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync size_t cbInfo = RT_MIN((uint32_t)*pValue, sizeof(RTLDRIMPORTINFO) + 32);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PRTLDRIMPORTINFO pInfo = (PRTLDRIMPORTINFO)alloca(cbInfo);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = RTLdrQueryForwarderInfo(pImage->pCacheEntry->hLdrMod, pImage->pCacheEntry->pbBits,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage = supHardNtVpFindModule(pThis, pInfo->szModule);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pImage->pCacheEntry->pbBits,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage->uImageBase, pInfo->iOrdinal, pInfo->pszSymbol, pValue);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SUP_DPRINTF(("supHardNtVpGetImport: Failed to find symbol '%s' in '%s' (forwarded from %s / %s): %Rrc\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pInfo->pszSymbol, pInfo->szModule, pszModule, pszSymbol, rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SUP_DPRINTF(("supHardNtVpGetImport: Failed to find forwarder module '%s' (%#x / %s; originally %s / %#x / %s): %Rrc\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pInfo->szModule, pInfo->iOrdinal, pInfo->pszSymbol, pszModule, uSymbol, pszSymbol, rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SUP_DPRINTF(("supHardNtVpGetImport: RTLdrQueryForwarderInfo failed on symbol %#x/'%s' in '%s': %Rrc\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SUP_DPRINTF(("supHardNtVpGetImport: Failed to find symbol %#x / '%s' in '%s': %Rrc\n",
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync * Compares process memory with the disk content.
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync * @returns VBox status code.
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * @param pThis The process scanning state structure (for the
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync * two scratch buffers).
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync * @param pImage The image data collected during the address
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * space scan.
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync * @param hProcess Handle to the process.
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * @param pErrInfo Pointer to error info structure. Optional.
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsyncstatic int supHardNtVpVerifyImageMemoryCompare(PSUPHNTVPSTATE pThis, PSUPHNTVPIMAGE pImage, HANDLE hProcess, PRTERRINFO pErrInfo)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read and find the file headers.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = supHardNtVpReadImage(pImage, 0 /*off*/, pThis->abFile, sizeof(pThis->abFile));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_IMAGE_HDR_READ_ERROR,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: Error reading image header: %Rrc", pImage->pszName, rc);
0c4004948fca34f2db87e7b38013137e9472c306vboxsync PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)&pThis->abFile[0];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (offNtHdrs > 512 || offNtHdrs < sizeof(*pDosHdr))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_BAD_MZ_OFFSET,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: Unexpected e_lfanew value: %#x", pImage->pszName, offNtHdrs);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PIMAGE_NT_HEADERS pNtHdrs = (PIMAGE_NT_HEADERS)&pThis->abFile[offNtHdrs];
0c4004948fca34f2db87e7b38013137e9472c306vboxsync PIMAGE_NT_HEADERS32 pNtHdrs32 = (PIMAGE_NT_HEADERS32)pNtHdrs;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_BAD_IMAGE_SIGNATURE,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: No PE signature at %#x: %#x", pImage->pszName, offNtHdrs, pNtHdrs->Signature);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Do basic header validation.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pNtHdrs->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64 && !pImage->f32bitResourceDll)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pNtHdrs->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_UNEXPECTED_IMAGE_MACHINE,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: Unexpected machine: %#x", pImage->pszName, pNtHdrs->FileHeader.Machine);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool const fIs32Bit = pNtHdrs->FileHeader.Machine == IMAGE_FILE_MACHINE_I386;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pNtHdrs->FileHeader.SizeOfOptionalHeader != (fIs32Bit ? sizeof(IMAGE_OPTIONAL_HEADER32) : sizeof(IMAGE_OPTIONAL_HEADER64)))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_BAD_OPTIONAL_HEADER,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: Unexpected optional header size: %#x",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage->pszName, pNtHdrs->FileHeader.SizeOfOptionalHeader);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync if (pNtHdrs->OptionalHeader.Magic != (fIs32Bit ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC))
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_BAD_OPTIONAL_HEADER,
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync "%s: Unexpected optional header magic: %#x", pImage->pszName, pNtHdrs->OptionalHeader.Magic);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync uint32_t cDirs = (fIs32Bit ? pNtHdrs32->OptionalHeader.NumberOfRvaAndSizes : pNtHdrs->OptionalHeader.NumberOfRvaAndSizes);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_BAD_OPTIONAL_HEADER,
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync "%s: Unexpected data dirs: %#x", pImage->pszName, cDirs);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync * Before we start comparing things, store what we need to know from the headers.
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync uint32_t const cSections = pNtHdrs->FileHeader.NumberOfSections;
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_TOO_MANY_SECTIONS,
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync "%s: Too many section headers: %#x", pImage->pszName, cSections);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync suplibHardenedMemCopy(pThis->aSecHdrs, (fIs32Bit ? (void *)(pNtHdrs32 + 1) : (void *)(pNtHdrs + 1)),
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync uintptr_t const uImageBase = fIs32Bit ? pNtHdrs32->OptionalHeader.ImageBase : pNtHdrs->OptionalHeader.ImageBase;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_BAD_IMAGE_BASE,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: Invalid image base: %p", pImage->pszName, uImageBase);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync uint32_t const cbImage = fIs32Bit ? pNtHdrs32->OptionalHeader.SizeOfImage : pNtHdrs->OptionalHeader.SizeOfImage;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_ALIGN_32(pImage->cbImage, PAGE_SIZE) != RT_ALIGN_32(cbImage, PAGE_SIZE) && !pImage->fApiSetSchemaOnlySection1)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_BAD_IMAGE_SIZE,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: SizeOfImage (%#x) isn't close enough to the mapping size (%#x)",
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync if (cbImage != RTLdrSize(pImage->pCacheEntry->hLdrMod))
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_BAD_IMAGE_SIZE,
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync "%s: SizeOfImage (%#x) differs from what RTLdrSize returns (%#zx)",
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync pImage->pszName, cbImage, RTLdrSize(pImage->pCacheEntry->hLdrMod));
0c4004948fca34f2db87e7b38013137e9472c306vboxsync uint32_t const cbSectAlign = fIs32Bit ? pNtHdrs32->OptionalHeader.SectionAlignment : pNtHdrs->OptionalHeader.SectionAlignment;
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync || cbSectAlign > (pImage->fApiSetSchemaOnlySection1 ? _64K : (uint32_t)PAGE_SIZE) )
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_BAD_SECTION_ALIGNMENT_VALUE,
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync "%s: Unexpected SectionAlignment value: %#x", pImage->pszName, cbSectAlign);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync uint32_t const cbFileAlign = fIs32Bit ? pNtHdrs32->OptionalHeader.FileAlignment : pNtHdrs->OptionalHeader.FileAlignment;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!RT_IS_POWER_OF_TWO(cbFileAlign) || cbFileAlign < 512 || cbFileAlign > PAGE_SIZE || cbFileAlign > cbSectAlign)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_BAD_FILE_ALIGNMENT_VALUE,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: Unexpected FileAlignment value: %#x (cbSectAlign=%#x)",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t const cbHeaders = fIs32Bit ? pNtHdrs32->OptionalHeader.SizeOfHeaders : pNtHdrs->OptionalHeader.SizeOfHeaders;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t const cbMinHdrs = offNtHdrs + (fIs32Bit ? sizeof(*pNtHdrs32) : sizeof(*pNtHdrs) )
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_BAD_SIZE_OF_HEADERS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: Headers are too small: %#x < %#x (cSections=%#x)",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t const cbHdrsFile = RT_ALIGN_32(cbHeaders, cbFileAlign);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_BAD_SIZE_OF_HEADERS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: Headers are larger than expected: %#x/%#x (expected max %zx)",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage->pszName, cbHeaders, cbHdrsFile, sizeof(pThis->abFile));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Save some header fields we might be using later on.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage->fImageCharecteristics = pNtHdrs->FileHeader.Characteristics;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage->fDllCharecteristics = fIs32Bit ? pNtHdrs32->OptionalHeader.DllCharacteristics : pNtHdrs->OptionalHeader.DllCharacteristics;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * Correct the apisetschema image base, size and region rva.
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync pImage->uImageBase -= pThis->aSecHdrs[0].VirtualAddress;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync pImage->cbImage += pThis->aSecHdrs[0].VirtualAddress;
a39ea3668b7019c23a68936259545f9b71bce1aavboxsync pImage->aRegions[0].uRva = pThis->aSecHdrs[0].VirtualAddress;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Get relocated bits.
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync if (pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION)
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync rc = supHardNtLdrCacheEntryGetBits(pImage->pCacheEntry, &pbBits, pImage->uImageBase, NULL /*pfnGetImport*/, pThis,
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync rc = supHardNtLdrCacheEntryGetBits(pImage->pCacheEntry, &pbBits, pImage->uImageBase, supHardNtVpGetImport, pThis,
0c4004948fca34f2db87e7b38013137e9472c306vboxsync /* XP SP3 does not set ImageBase to load address. It fixes up the image on load time though. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync ((PIMAGE_NT_HEADERS32)&pbBits[offNtHdrs])->OptionalHeader.ImageBase = (uint32_t)pImage->uImageBase;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync ((PIMAGE_NT_HEADERS)&pbBits[offNtHdrs])->OptionalHeader.ImageBase = pImage->uImageBase;
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync * Figure out areas we should skip during comparison.
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync /* Ignore our NtCreateSection hack. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pbBits, 0, UINT32_MAX, "NtCreateSection", &uValue);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync return supHardNtVpSetInfo2(pThis, rc, "%s: Failed to find 'NtCreateSection': %Rrc", pImage->pszName, rc);
0c4004948fca34f2db87e7b38013137e9472c306vboxsync aSkipAreas[cSkipAreas++].cb = ARCH_BITS == 32 ? 5 : 12;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync /* Ignore our LdrLoadDll hack. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pbBits, 0, UINT32_MAX, "LdrLoadDll", &uValue);
0c4004948fca34f2db87e7b38013137e9472c306vboxsync return supHardNtVpSetInfo2(pThis, rc, "%s: Failed to find 'LdrLoadDll': %Rrc", pImage->pszName, rc);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync aSkipAreas[cSkipAreas++].cb = ARCH_BITS == 32 ? 5 : 12;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync /* Ignore our patched LdrInitializeThunk hack. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pbBits, 0, UINT32_MAX, "LdrInitializeThunk", &uValue);
0c4004948fca34f2db87e7b38013137e9472c306vboxsync return supHardNtVpSetInfo2(pThis, rc, "%s: Failed to find 'LdrInitializeThunk': %Rrc", pImage->pszName, rc);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync /* LdrSystemDllInitBlock is filled in by the kernel. It mainly contains addresses of 32-bit ntdll method for wow64. */
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pbBits, 0, UINT32_MAX, "LdrSystemDllInitBlock", &uValue);
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync aSkipAreas[cSkipAreas++].cb = RT_MAX(pbBits[(uint32_t)uValue], 0x50);
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync * Compare the file header with the loaded bits. The loader will fiddle
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync * with image base, changing it to the actual load address.
0c4004948fca34f2db87e7b38013137e9472c306vboxsync rc = supHardNtVpFileMemCompareSection(pThis, pImage, 0 /*uRva*/, cbHdrsFile, pbBits, -1, NULL, 0, PAGE_READONLY);
0c4004948fca34f2db87e7b38013137e9472c306vboxsync rc = supHardNtVpCheckSectionProtection(pThis, pImage, 0 /*uRva*/, cbHdrsFile, PAGE_READONLY);
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * Validate sections:
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * - Check them against the mapping regions.
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * - Check section bits according to enmKind.
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync /* Validate the section. */
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync uint32_t uSectRva = pThis->aSecHdrs[i].VirtualAddress;
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync if (uSectRva < uRva || uSectRva > cbImage || RT_ALIGN_32(uSectRva, cbSectAlign) != uSectRva)
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_BAD_SECTION_RVA,
0c4004948fca34f2db87e7b38013137e9472c306vboxsync "%s: Section %u: Invalid virtual address: %#x (uRva=%#x, cbImage=%#x, cbSectAlign=%#x)",
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync pImage->pszName, i, uSectRva, uRva, cbImage, cbSectAlign);
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync uint32_t cbMap = pThis->aSecHdrs[i].Misc.VirtualSize;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_BAD_SECTION_VIRTUAL_SIZE,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: Section %u: Invalid virtual size: %#x (uSectRva=%#x, uRva=%#x, cbImage=%#x)",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage->pszName, i, cbMap, uSectRva, uRva, cbImage);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbFile = pThis->aSecHdrs[i].SizeOfRawData;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (cbFile != RT_ALIGN_32(cbFile, cbFileAlign) || cbFile > RT_ALIGN_32(cbMap, cbSectAlign))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_BAD_SECTION_FILE_SIZE,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: Section %u: Invalid file size: %#x (cbMap=%#x, uSectRva=%#x)",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Validate the protection and bits. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (pThis->aSecHdrs[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && pThis->enmKind != SUPHARDNTVPKIND_CHILD_PURIFICATION
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && !suplibHardenedMemComp(pThis->aSecHdrs[i].Name, ".mrdata", 8)) /* w8.1, ntdll. Changed by proc init. */
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Only the executable is allowed to have this section,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync and it's protected after we're done patching. */
a8139954a84d6e9090dd3a8371aa788351d45bc3vboxsync if (pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_UNEXPECTED_SECTION_FLAGS,
cba6719bd64ec749967bbe931230452664109857vboxsync "%s: Section %u: Unexpected characteristics: %#x (uSectRva=%#x, cbMap=%#x)",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage->pszName, i, pThis->aSecHdrs[i].Characteristics, uSectRva, cbMap);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* The section bits. Child purification verifies all, normal
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync verification verifies all except where the executable is
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync concerned (due to opening vboxdrv during early process init). */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ( ( (pThis->aSecHdrs[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && !(pThis->aSecHdrs[i].Characteristics & IMAGE_SCN_MEM_WRITE))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync || (pThis->aSecHdrs[i].Characteristics & (IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) == IMAGE_SCN_MEM_READ
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync || (pThis->enmKind == SUPHARDNTVPKIND_VERIFY_ONLY && pImage->fDll)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync || pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (uRva < uSectRva && !pImage->fApiSetSchemaOnlySection1) /* Any gap worth checking? */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = supHardNtVpFileMemCompareSection(pThis, pImage, uRva, uSectRva - uRva, pbBits + uRva,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = supHardNtVpFileMemCompareSection(pThis, pImage, uSectRva, cbMap, pbBits + uSectRva,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbMapAligned = i + 1 < cSections && !pImage->fApiSetSchemaOnlySection1
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync ? RT_ALIGN_32(cbMap, cbSectAlign) : RT_ALIGN_32(cbMap, PAGE_SIZE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = supHardNtVpFileMemCompareSection(pThis, pImage, uSectRva + cbMap, cbMapAligned - cbMap,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* The protection (must be checked afterwards!). */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = supHardNtVpCheckSectionProtection(pThis, pImage, uSectRva, RT_ALIGN_32(cbMap, PAGE_SIZE), fProt);
cba6719bd64ec749967bbe931230452664109857vboxsync /* Advance the RVA. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Verifies the signature of the given image on disk, then checks if the memory
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * mapping matches what we verified.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
9b789c281103a2489742bf32f6ab500e38b2ecd5vboxsync * @param pThis The process scanning state structure (for the
9b789c281103a2489742bf32f6ab500e38b2ecd5vboxsync * two scratch buffers).
9b789c281103a2489742bf32f6ab500e38b2ecd5vboxsync * @param pImage The image data collected during the address
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * space scan.
c91345f92b829d3fba05ce7a97206d83c5183ce0vboxsync * @param hProcess Handle to the process.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param hFile Handle to the image file.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int supHardNtVpVerifyImage(PSUPHNTVPSTATE pThis, PSUPHNTVPIMAGE pImage, HANDLE hProcess)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Validate the file signature first, then do the memory compare.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = supHardNtLdrCacheEntryVerify(pImage->pCacheEntry, pImage->Name.UniStr.Buffer, pThis->pErrInfo);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = supHardNtVpVerifyImageMemoryCompare(pThis, pImage, hProcess, pThis->pErrInfo);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = supHardNtVpSetInfo2(pThis, VERR_OPEN_FAILED, "pCacheEntry/hLdrMod is NIL! Impossible!");
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync * Verifies that there is only one thread in the process.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param hProcess The process.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param hThread The thread.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pErrInfo Pointer to error info structure. Optional.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLHIDDEN(int) supHardNtVpThread(HANDLE hProcess, HANDLE hThread, PRTERRINFO pErrInfo)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Use the ThreadAmILastThread request to check that there is only one
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * thread in the process.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Seems this isn't entirely reliable when hThread isn't the current thread?
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync NTSTATUS rcNt = NtQueryInformationThread(hThread, ThreadAmILastThread, &fAmI, sizeof(fAmI), &cbIgn);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_NT_QI_THREAD_ERROR,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "NtQueryInformationThread/ThreadAmILastThread -> %#x", rcNt);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_THREAD_NOT_ALONE,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "More than one thread in process");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** @todo Would be nice to verify the relation ship between hProcess and hThread
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync * as well... */
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync * Verifies that there isn't a debugger attached to the process.
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync * @returns VBox status code.
cba6719bd64ec749967bbe931230452664109857vboxsync * @param hProcess The process.
cba6719bd64ec749967bbe931230452664109857vboxsync * @param pErrInfo Pointer to error info structure. Optional.
cba6719bd64ec749967bbe931230452664109857vboxsyncDECLHIDDEN(int) supHardNtVpDebugger(HANDLE hProcess, PRTERRINFO pErrInfo)
#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
#ifdef IN_RING3
return VINF_OBJECT_DESTROYED;
SUP_DPRINTF(("supHardNtVpScanVirtualMemory: NtUnmapViewOfSection(,%p) failed: %#x\n", pMemInfo->AllocationBase, rcNt));
"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"));
#ifdef VBOX_PERMIT_VERIFIER_DLL
(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).
/* The Trend Micro sakfile.sys BSOD kludge. */
# ifndef IN_RING3
DECLHIDDEN(int) supHardNtLdrCacheEntryVerify(PSUPHNTLDRCACHEENTRY pEntry, PCRTUTF16 pwszName, PRTERRINFO pErrInfo)
return rc;
int rc;
return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_IMAGE_TOO_BIG, "Image %s is too large: %zu bytes (%#zx).",
return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_NO_MEMORY, "Failed to allocate %zu bytes for image %s.",
return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_NO_MEMORY, "RTLdrGetBits failed on image %s: %Rrc",
|| pfnGetImport)
return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_NO_MEMORY, "RTLdrGetBits failed on image %s: %Rrc",
return VINF_SUCCESS;
#ifdef IN_RING3
return &g_aSupNtVpLdrCacheEntries[i];
return NULL;
static int supHardNtLdrCacheNewEntry(PSUPHNTLDRCACHEENTRY pEntry, const char *pszName, PUNICODE_STRING pUniStrPath,
InitializeObjectAttributes(&ObjAttr, pUniStrPath, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
#ifdef IN_RING0
&ObjAttr,
&Ios,
if (f32bitResourceDll)
return rc;
#ifdef IN_SUP_HARDENED_R3
return VINF_SUCCESS;
#ifdef IN_RING3
uint32_t i = 0;
return VERR_FILE_NOT_FOUND;
if (*ppEntry)
return VINF_SUCCESS;
return VERR_INTERNAL_ERROR_3;
int rc = supHardNtLdrCacheNewEntry(&g_aSupNtVpLdrCacheEntries[g_cSupNtVpLdrCacheEntries], pszName, &UniStr,
return VINF_SUCCESS;
return rc;
#ifdef IN_RING3
return rc;
#ifdef IN_RING3
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, uint32_t fFlags,
if (pcFixes)
*pcFixes = 0;
if (pThis)
if (pcFixes)
#ifdef IN_RING0
return rc;