SUPHardenedVerifyProcess-win.cpp revision 1f64240a0fda7b4c7cc9fcd4ef610f26623485b8
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* $Id$ */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** @file
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * VirtualBox Support Library/Driver - Hardened Process Verification, Windows.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/*
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * Copyright (C) 2006-2014 Oracle Corporation
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
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 *
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 *
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/*******************************************************************************
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync* Header Files *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync*******************************************************************************/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef IN_RING0
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define IPRT_NT_MAP_TO_ZW
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync# include <iprt/nt/nt.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# include <ntimage.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#else
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync# include <iprt/nt/nt-and-windows.h>
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <VBox/sup.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <VBox/err.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <iprt/alloca.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <iprt/ctype.h>
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync#include <iprt/param.h>
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync#include <iprt/string.h>
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync#include <iprt/zero.h>
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef IN_RING0
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# include "SUPDrvInternal.h"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# include "SUPLibInternal.h"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include "win/SUPHardenedVerify-win.h"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/*******************************************************************************
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync* Structures and Typedefs *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync*******************************************************************************/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Virtual address space region.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef struct SUPHNTVPREGION
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The RVA of the region. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t uRva;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The size of the region. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cb;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The protection of the region. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t fProt;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync} SUPHNTVPREGION;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Pointer to a virtual address space region. */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsynctypedef SUPHNTVPREGION *PSUPHNTVPREGION;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Virtual address space image information.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsynctypedef struct SUPHNTVPIMAGE
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync{
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync /** The base address of the image. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uintptr_t uImageBase;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync /** The size of the image mapping. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uintptr_t cbImage;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The name from the allowed lists. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync const char *pszName;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Name structure for NtQueryVirtualMemory/MemorySectionName. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync struct
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The full unicode name. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync UNICODE_STRING UniStr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Buffer space. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync WCHAR awcBuffer[260];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync } Name;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The number of mapping regions. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cRegions;
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync /** Mapping regions. */
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync SUPHNTVPREGION aRegions[16];
0c4004948fca34f2db87e7b38013137e9472c306vboxsync
0c4004948fca34f2db87e7b38013137e9472c306vboxsync /** The image characteristics from the FileHeader. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync uint16_t fImageCharecteristics;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The DLL characteristics from the OptionalHeader. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint16_t fDllCharecteristics;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Set if this is the DLL. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fDll;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Set if the image is NTDLL an the verficiation code needs to watch out for
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * the NtCreateSection patch. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fNtCreateSectionPatch;
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 bool fApiSetSchemaOnlySection1;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** This may be a 32-bit resource DLL. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool f32bitResourceDll;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the loader cache entry for the image. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PSUPHNTLDRCACHEENTRY pCacheEntry;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef IN_RING0
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** In ring-0 we don't currently cache images, so put it here. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SUPHNTLDRCACHEENTRY CacheEntry;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync} SUPHNTVPIMAGE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Pointer to image info from the virtual address space scan. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef SUPHNTVPIMAGE *PSUPHNTVPIMAGE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Virtual address space scanning state.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef struct SUPHNTVPSTATE
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Type of verification to perform. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SUPHARDNTVPKIND enmKind;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Combination of SUPHARDNTVP_F_XXX. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t fFlags;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The result. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rcResult;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Number of fixes we've done.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Only applicable in the purification modes. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cFixes;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Number of images in aImages. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cImages;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The index of the last image we looked up. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t iImageHint;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The process handle. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync HANDLE hProcess;
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 SUPHNTVPIMAGE aImages[1 + 6 + 1
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef VBOX_PERMIT_VERIFIER_DLL
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync + 1
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef VBOX_PERMIT_MORE
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync + 5
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef VBOX_PERMIT_VISUAL_STUDIO_PROFILING
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync + 16
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Memory compare scratch buffer.*/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t abMemory[_4K];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** File compare scratch buffer.*/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t abFile[_4K];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Section headers for use when comparing file and loaded image. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync IMAGE_SECTION_HEADER aSecHdrs[16];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the error info. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PRTERRINFO pErrInfo;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync} SUPHNTVPSTATE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Pointer to stat information of a virtual address space scan. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef SUPHNTVPSTATE *PSUPHNTVPSTATE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/*******************************************************************************
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync* Global Variables *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync*******************************************************************************/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * System DLLs allowed to be loaded into the process.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @remarks supHardNtVpCheckDlls assumes these are lower case.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic const char *g_apszSupNtVpAllowedDlls[] =
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "ntdll.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "kernel32.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "kernelbase.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "apphelp.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "apisetschema.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef VBOX_PERMIT_VERIFIER_DLL
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "verifier.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef VBOX_PERMIT_MORE
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define VBOX_PERMIT_MORE_FIRST_IDX 5
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "sfc.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "sfc_os.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "user32.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "acres.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "acgenral.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef VBOX_PERMIT_VISUAL_STUDIO_PROFILING
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "psapi.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "msvcrt.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "advapi32.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "sechost.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "rpcrt4.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "SamplingRuntime.dll",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync};
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * VBox executables allowed to start VMs.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @remarks Remember to keep in sync with SUPR3HardenedVerify.cpp.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic const char *g_apszSupNtVpAllowedVmExes[] =
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "VBoxHeadless.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "VirtualBox.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "VBoxSDL.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "VBoxNetDHCP.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "VBoxNetNAT.exe",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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};
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Pointer to NtQueryVirtualMemory. Initialized by SUPDrv-win.cpp in
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * ring-0, in ring-3 it's just a slightly confusing define. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef IN_RING0
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncPFNNTQUERYVIRTUALMEMORY g_pfnNtQueryVirtualMemory = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define g_pfnNtQueryVirtualMemory NtQueryVirtualMemory
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef IN_RING3
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** The number of valid entries in the loader cache.. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic uint32_t g_cSupNtVpLdrCacheEntries = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** The loader cache entries. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic SUPHNTLDRCACHEENTRY g_aSupNtVpLdrCacheEntries[RT_ELEMENTS(g_apszSupNtVpAllowedDlls) + 1 + 3];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Fills in error information.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int supHardNtVpSetInfo1(PRTERRINFO pErrInfo, int rc, const char *pszMsg, ...)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync va_list va;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef IN_RING3
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync va_start(va, pszMsg);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync supR3HardenedError(rc, false /*fFatal*/, "%N\n", pszMsg, &va);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync va_end(va);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync va_start(va, pszMsg);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTErrInfoSetV(pErrInfo, rc, pszMsg, va);
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync va_end(va);
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync return rc;
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync}
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync/**
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync * Fills in error information.
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync *
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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int supHardNtVpSetInfo2(PSUPHNTVPSTATE pThis, int rc, const char *pszMsg, ...)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync va_list va;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef IN_RING3
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync va_start(va, pszMsg);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync supR3HardenedError(rc, false /*fFatal*/, "%N\n", pszMsg, &va);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync va_end(va);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync va_start(va, pszMsg);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef IN_RING0
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTErrInfoSetV(pThis->pErrInfo, rc, pszMsg, va);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->rcResult = rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_SUCCESS(pThis->rcResult))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTErrInfoSetV(pThis->pErrInfo, rc, pszMsg, va);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->rcResult = rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTErrInfoAddF(pThis->pErrInfo, rc, " \n[rc=%d] ", rc);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTErrInfoAddV(pThis->pErrInfo, rc, pszMsg, va);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync va_end(va);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return pThis->rcResult;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int supHardNtVpReadImage(PSUPHNTVPIMAGE pImage, uint64_t off, void *pvBuf, size_t cbRead)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return pImage->pCacheEntry->pNtViRdr->Core.pfnRead(&pImage->pCacheEntry->pNtViRdr->Core, pvBuf, cbRead, off);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic NTSTATUS supHardNtVpReadMem(HANDLE hProcess, uintptr_t uPtr, void *pvBuf, size_t cbRead)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef IN_RING0
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* ASSUMES hProcess is the current process. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** @todo use MmCopyVirtualMemory where available! */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = RTR0MemUserCopyFrom(pvBuf, uPtr, cbRead);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_SUCCESS(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return STATUS_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return STATUS_ACCESS_DENIED;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SIZE_T cbIgn;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NTSTATUS rcNt = NtReadVirtualMemory(hProcess, (PVOID)uPtr, pvBuf, cbRead, &cbIgn);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (NT_SUCCESS(rcNt) && cbIgn != cbRead)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rcNt = STATUS_IO_DEVICE_ERROR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rcNt;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef IN_RING3
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic NTSTATUS supHardNtVpFileMemRestore(PSUPHNTVPSTATE pThis, PVOID pvRestoreAddr, uint8_t const *pbFile, uint32_t cbToRestore,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t fCorrectProtection)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PVOID pvProt = pvRestoreAddr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SIZE_T cbProt = cbToRestore;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ULONG fOldProt = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NTSTATUS rcNt = NtProtectVirtualMemory(pThis->hProcess, &pvProt, &cbProt, PAGE_READWRITE, &fOldProt);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (NT_SUCCESS(rcNt))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SIZE_T cbIgnored;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rcNt = NtWriteVirtualMemory(pThis->hProcess, pvRestoreAddr, pbFile, cbToRestore, &cbIgnored);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pvProt = pvRestoreAddr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbProt = cbToRestore;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NTSTATUS rcNt2 = NtProtectVirtualMemory(pThis->hProcess, &pvProt, &cbProt, fCorrectProtection, &fOldProt);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (NT_SUCCESS(rcNt))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rcNt = rcNt2;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->cFixes++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rcNt;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif /* IN_RING3 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef struct SUPHNTVPSKIPAREA
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t uRva;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cb;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync} SUPHNTVPSKIPAREA;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef SUPHNTVPSKIPAREA *PSUPHNTVPSKIPAREA;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int supHardNtVpFileMemCompareSection(PSUPHNTVPSTATE pThis, PSUPHNTVPIMAGE pImage,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t uRva, uint32_t cb, const uint8_t *pbFile,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int32_t iSh, PSUPHNTVPSKIPAREA paSkipAreas, uint32_t cSkipAreas,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t fCorrectProtection)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
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 uint8_t * const pbMemory = &pThis->abMemory[0];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync while (cb > 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbThis = RT_MIN(cb, cbMemory);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Clipping. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t uNextRva = uRva + cbThis;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (cSkipAreas)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t uRvaEnd = uNextRva;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t i = cSkipAreas;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync while (i-- > 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t uSkipEnd = paSkipAreas[i].uRva + paSkipAreas[i].cb;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ( uRva < uSkipEnd
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && uRvaEnd > paSkipAreas[i].uRva)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (uRva < paSkipAreas[i].uRva)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbThis = paSkipAreas[i].uRva - uRva;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uRvaEnd = paSkipAreas[i].uRva;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uNextRva = uSkipEnd;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (uRvaEnd >= uSkipEnd)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbThis -= uSkipEnd - uRva;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uRva = uSkipEnd;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uNextRva = uSkipEnd;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbThis = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Read the memory. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NTSTATUS rcNt = supHardNtVpReadMem(pThis->hProcess, pImage->uImageBase + uRva, pbMemory, cbThis);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!NT_SUCCESS(rcNt))
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Do the compare. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (memcmp(pbFile, pbMemory, cbThis) != 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t off = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync while (off < cbThis && pbFile[off] == pbMemory[off])
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync off++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SUP_DPRINTF((" %p / %#09x: %02x != %02x\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage->uImageBase + uRva + off, uRva + off, pbFile[off], pbMemory[off]));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t offLast = off;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cDiffs = 1;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t off2 = off + 1; off2 < cbThis; off2++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pbFile[off2] != pbMemory[off2])
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SUP_DPRINTF((" %p / %#09x: %02x != %02x\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage->uImageBase + uRva + off2, uRva + off2, pbFile[off2], pbMemory[off2]));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cDiffs++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync offLast = off2;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef IN_RING3
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ( pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync || pThis->enmKind == SUPHARDNTVPKIND_SELF_PURIFICATION)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PVOID pvRestoreAddr = (uint8_t *)pImage->uImageBase + uRva;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rcNt = supHardNtVpFileMemRestore(pThis, pvRestoreAddr, pbFile, cbThis, fCorrectProtection);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (NT_SUCCESS(rcNt))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SUP_DPRINTF((" Restored %#x bytes of original file content at %p\n", cbThis, pvRestoreAddr));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
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 cDiffs, uRva + off);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
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 pachSectNm, pbFile[off], pbMemory[off]);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Advance. The clipping makes it a little bit complicated. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbThis = uNextRva - uRva;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (cbThis >= cb)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cb -= cbThis;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pbFile += cbThis;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uRva = uNextRva;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int supHardNtVpCheckSectionProtection(PSUPHNTVPSTATE pThis, PSUPHNTVPIMAGE pImage,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t uRva, uint32_t cb, uint32_t fProt)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t const cbOrg = cb;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!cb)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ( pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync || pThis->enmKind == SUPHARDNTVPKIND_SELF_PURIFICATION)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t i = 0; i < pImage->cRegions; i++)
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t offRegion = uRva - pImage->aRegions[i].uRva;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (offRegion < pImage->aRegions[i].cb)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbLeft = pImage->aRegions[i].cb - offRegion;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ( pImage->aRegions[i].fProt != fProt
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && ( fProt != PAGE_READWRITE
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync || pImage->aRegions[i].fProt != PAGE_WRITECOPY))
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 (cbLeft >= cb)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cb -= cbLeft;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uRva += cbLeft;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if 0 /* This shouldn't ever be necessary. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ( i + 1 < pImage->cRegions
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && uRva < pImage->aRegions[i + 1].uRva)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbLeft = pImage->aRegions[i + 1].uRva - uRva;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (cbLeft >= cb)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cb -= cbLeft;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uRva += cbLeft;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLINLINE(bool) supHardNtVpIsModuleNameMatch(PSUPHNTVPIMAGE pImage, const char *pszModule)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pImage->fDll)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync const char *pszImageNm = pImage->pszName;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (;;)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync char chLeft = *pszImageNm++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync char chRight = *pszModule++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (chLeft != chRight)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Assert(chLeft == RT_C_TO_LOWER(chLeft));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (chLeft != RT_C_TO_LOWER(chRight))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ( chRight == '\0'
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && chLeft == '.'
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && pszImageNm[0] == 'd'
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && pszImageNm[1] == 'l'
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && pszImageNm[2] == 'l'
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && pszImageNm[3] == '\0')
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (chLeft == '\0')
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Worker for supHardNtVpGetImport that looks up a module in the module table.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
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.
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync */
93540abbca1a7ac8de705de01b9fc04092294a39vboxsyncstatic PSUPHNTVPIMAGE supHardNtVpFindModule(PSUPHNTVPSTATE pThis, const char *pszModule)
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync{
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync /*
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync * Check out the hint first.
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync */
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync if ( pThis->iImageHint < pThis->cImages
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync && supHardNtVpIsModuleNameMatch(&pThis->aImages[pThis->iImageHint], pszModule))
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync return &pThis->aImages[pThis->iImageHint];
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync /*
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync * Linear array search next.
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync */
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync uint32_t i = pThis->cImages;
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync while (i-- > 0)
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync if (supHardNtVpIsModuleNameMatch(&pThis->aImages[i], pszModule))
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync {
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync pThis->iImageHint = i;
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync return &pThis->aImages[i];
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync }
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* No cigar. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @callback_method_impl{FNRTLDRIMPORT}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(int) supHardNtVpGetImport(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PRTLDRADDR pValue, void *pvUser)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*SUP_DPRINTF(("supHardNtVpGetImport: %s / %#x / %s.\n", pszModule, uSymbol, pszSymbol));*/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PSUPHNTVPSTATE pThis = (PSUPHNTVPSTATE)pvUser;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = VERR_MODULE_NOT_FOUND;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PSUPHNTVPIMAGE pImage = supHardNtVpFindModule(pThis, pszModule);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pImage)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pImage->pCacheEntry->pbBits,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage->uImageBase, uSymbol, pszSymbol, pValue);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_SUCCESS(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
710a6316a22868b04400caf79719f96c18163cd3vboxsync * API set hacks.
710a6316a22868b04400caf79719f96c18163cd3vboxsync */
710a6316a22868b04400caf79719f96c18163cd3vboxsync else if (!RTStrNICmp(pszModule, RT_STR_TUPLE("api-ms-win-")))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage = supHardNtVpFindModule(pThis, s_apszDlls[i]);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pImage)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pImage->pCacheEntry->pbBits,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage->uImageBase, uSymbol, pszSymbol, pValue);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_SUCCESS(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (rc != VERR_SYMBOL_NOT_FOUND)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Deal with forwarders.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * ASSUMES no forwarders thru any api-ms-win-core-*.dll.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * ASSUMES forwarders are resolved after one redirection.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (rc == VERR_LDR_FORWARDER)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
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 uSymbol, pszSymbol, pInfo, cbInfo);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_SUCCESS(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = VERR_MODULE_NOT_FOUND;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage = supHardNtVpFindModule(pThis, pInfo->szModule);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pImage)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pImage->pCacheEntry->pbBits,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage->uImageBase, pInfo->iOrdinal, pInfo->pszSymbol, pValue);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_SUCCESS(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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 if (rc == VERR_LDR_FORWARDER)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = VERR_LDR_FORWARDER_CHAIN_TOO_LONG;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
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 }
93540abbca1a7ac8de705de01b9fc04092294a39vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SUP_DPRINTF(("supHardNtVpGetImport: RTLdrQueryForwarderInfo failed on symbol %#x/'%s' in '%s': %Rrc\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uSymbol, pszSymbol, pszModule, rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SUP_DPRINTF(("supHardNtVpGetImport: Failed to find symbol %#x / '%s' in '%s': %Rrc\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uSymbol, pszSymbol, pszModule, rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync/**
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync * Compares process memory with the disk content.
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync *
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.
0c4004948fca34f2db87e7b38013137e9472c306vboxsync */
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsyncstatic int supHardNtVpVerifyImageMemoryCompare(PSUPHNTVPSTATE pThis, PSUPHNTVPIMAGE pImage, HANDLE hProcess, PRTERRINFO pErrInfo)
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync{
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read and find the file headers.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = supHardNtVpReadImage(pImage, 0 /*off*/, pThis->abFile, sizeof(pThis->abFile));
0c4004948fca34f2db87e7b38013137e9472c306vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_IMAGE_HDR_READ_ERROR,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: Error reading image header: %Rrc", pImage->pszName, rc);
0c4004948fca34f2db87e7b38013137e9472c306vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t offNtHdrs = 0;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)&pThis->abFile[0];
0c4004948fca34f2db87e7b38013137e9472c306vboxsync if (pDosHdr->e_magic == IMAGE_DOS_SIGNATURE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync offNtHdrs = pDosHdr->e_lfanew;
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 }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PIMAGE_NT_HEADERS pNtHdrs = (PIMAGE_NT_HEADERS)&pThis->abFile[offNtHdrs];
0c4004948fca34f2db87e7b38013137e9472c306vboxsync PIMAGE_NT_HEADERS32 pNtHdrs32 = (PIMAGE_NT_HEADERS32)pNtHdrs;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pNtHdrs->Signature != IMAGE_NT_SIGNATURE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_BAD_IMAGE_SIGNATURE,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: No PE signature at %#x: %#x", pImage->pszName, offNtHdrs, pNtHdrs->Signature);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Do basic header validation.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef RT_ARCH_AMD64
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pNtHdrs->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64 && !pImage->f32bitResourceDll)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pNtHdrs->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
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
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);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync uint32_t cDirs = (fIs32Bit ? pNtHdrs32->OptionalHeader.NumberOfRvaAndSizes : pNtHdrs->OptionalHeader.NumberOfRvaAndSizes);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync if (cDirs != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_BAD_OPTIONAL_HEADER,
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync "%s: Unexpected data dirs: %#x", pImage->pszName, cDirs);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync /*
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync * Before we start comparing things, store what we need to know from the headers.
8a339f91959bb7a3315b51a23461b68c7b0cb50evboxsync */
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync uint32_t const cSections = pNtHdrs->FileHeader.NumberOfSections;
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync if (cSections > RT_ELEMENTS(pThis->aSecHdrs))
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 cSections * sizeof(IMAGE_SECTION_HEADER));
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync uintptr_t const uImageBase = fIs32Bit ? pNtHdrs32->OptionalHeader.ImageBase : pNtHdrs->OptionalHeader.ImageBase;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (uImageBase & PAGE_OFFSET_MASK)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_BAD_IMAGE_BASE,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: Invalid image base: %p", pImage->pszName, uImageBase);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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 pImage->pszName, cbImage, pImage->cbImage);
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));
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync
0c4004948fca34f2db87e7b38013137e9472c306vboxsync uint32_t const cbSectAlign = fIs32Bit ? pNtHdrs32->OptionalHeader.SectionAlignment : pNtHdrs->OptionalHeader.SectionAlignment;
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync if ( !RT_IS_POWER_OF_TWO(cbSectAlign)
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync || cbSectAlign < PAGE_SIZE
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
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 pImage->pszName, cbFileAlign, cbSectAlign);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t const cbHeaders = fIs32Bit ? pNtHdrs32->OptionalHeader.SizeOfHeaders : pNtHdrs->OptionalHeader.SizeOfHeaders;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t const cbMinHdrs = offNtHdrs + (fIs32Bit ? sizeof(*pNtHdrs32) : sizeof(*pNtHdrs) )
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync + sizeof(IMAGE_SECTION_HEADER) * cSections;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (cbHeaders < cbMinHdrs)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_BAD_SIZE_OF_HEADERS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: Headers are too small: %#x < %#x (cSections=%#x)",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage->pszName, cbHeaders, cbMinHdrs, cSections);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t const cbHdrsFile = RT_ALIGN_32(cbHeaders, cbFileAlign);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (cbHdrsFile > sizeof(pThis->abFile))
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Save some header fields we might be using later on.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage->fImageCharecteristics = pNtHdrs->FileHeader.Characteristics;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pImage->fDllCharecteristics = fIs32Bit ? pNtHdrs32->OptionalHeader.DllCharacteristics : pNtHdrs->OptionalHeader.DllCharacteristics;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync /*
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * Correct the apisetschema image base, size and region rva.
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pImage->fApiSetSchemaOnlySection1)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync pImage->uImageBase -= pThis->aSecHdrs[0].VirtualAddress;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync pImage->cbImage += pThis->aSecHdrs[0].VirtualAddress;
a39ea3668b7019c23a68936259545f9b71bce1aavboxsync pImage->aRegions[0].uRva = pThis->aSecHdrs[0].VirtualAddress;
0db6a029780d9f9b347500e117320a8d5661efe5vboxsync }
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Get relocated bits.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync uint8_t *pbBits;
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync if (pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION)
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync rc = supHardNtLdrCacheEntryGetBits(pImage->pCacheEntry, &pbBits, pImage->uImageBase, NULL /*pfnGetImport*/, pThis,
0c4004948fca34f2db87e7b38013137e9472c306vboxsync pThis->pErrInfo);
0c4004948fca34f2db87e7b38013137e9472c306vboxsync else
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync rc = supHardNtLdrCacheEntryGetBits(pImage->pCacheEntry, &pbBits, pImage->uImageBase, supHardNtVpGetImport, pThis,
0c4004948fca34f2db87e7b38013137e9472c306vboxsync pThis->pErrInfo);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync if (RT_FAILURE(rc))
0c4004948fca34f2db87e7b38013137e9472c306vboxsync return rc;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync
0c4004948fca34f2db87e7b38013137e9472c306vboxsync /* XP SP3 does not set ImageBase to load address. It fixes up the image on load time though. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync if (g_uNtVerCombined >= SUP_NT_VER_VISTA)
0c4004948fca34f2db87e7b38013137e9472c306vboxsync {
0c4004948fca34f2db87e7b38013137e9472c306vboxsync if (fIs32Bit)
0c4004948fca34f2db87e7b38013137e9472c306vboxsync ((PIMAGE_NT_HEADERS32)&pbBits[offNtHdrs])->OptionalHeader.ImageBase = (uint32_t)pImage->uImageBase;
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync else
0c4004948fca34f2db87e7b38013137e9472c306vboxsync ((PIMAGE_NT_HEADERS)&pbBits[offNtHdrs])->OptionalHeader.ImageBase = pImage->uImageBase;
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync }
0c4004948fca34f2db87e7b38013137e9472c306vboxsync
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync /*
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync * Figure out areas we should skip during comparison.
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync uint32_t cSkipAreas = 0;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync SUPHNTVPSKIPAREA aSkipAreas[5];
0c4004948fca34f2db87e7b38013137e9472c306vboxsync if (pImage->fNtCreateSectionPatch)
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync {
0c4004948fca34f2db87e7b38013137e9472c306vboxsync RTLDRADDR uValue;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync if (pThis->enmKind == SUPHARDNTVPKIND_VERIFY_ONLY)
0c4004948fca34f2db87e7b38013137e9472c306vboxsync {
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync /* Ignore our NtCreateSection hack. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pbBits, 0, UINT32_MAX, "NtCreateSection", &uValue);
0c4004948fca34f2db87e7b38013137e9472c306vboxsync if (RT_FAILURE(rc))
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync return supHardNtVpSetInfo2(pThis, rc, "%s: Failed to find 'NtCreateSection': %Rrc", pImage->pszName, rc);
0c4004948fca34f2db87e7b38013137e9472c306vboxsync aSkipAreas[cSkipAreas].uRva = (uint32_t)uValue;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync aSkipAreas[cSkipAreas++].cb = ARCH_BITS == 32 ? 5 : 12;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync
0c4004948fca34f2db87e7b38013137e9472c306vboxsync /* Ignore our LdrLoadDll hack. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pbBits, 0, UINT32_MAX, "LdrLoadDll", &uValue);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync if (RT_FAILURE(rc))
0c4004948fca34f2db87e7b38013137e9472c306vboxsync return supHardNtVpSetInfo2(pThis, rc, "%s: Failed to find 'LdrLoadDll': %Rrc", pImage->pszName, rc);
0c4004948fca34f2db87e7b38013137e9472c306vboxsync aSkipAreas[cSkipAreas].uRva = (uint32_t)uValue;
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync aSkipAreas[cSkipAreas++].cb = ARCH_BITS == 32 ? 5 : 12;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync }
0c4004948fca34f2db87e7b38013137e9472c306vboxsync
0c4004948fca34f2db87e7b38013137e9472c306vboxsync /* Ignore our patched LdrInitializeThunk hack. */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pbBits, 0, UINT32_MAX, "LdrInitializeThunk", &uValue);
0c4004948fca34f2db87e7b38013137e9472c306vboxsync if (RT_FAILURE(rc))
0c4004948fca34f2db87e7b38013137e9472c306vboxsync return supHardNtVpSetInfo2(pThis, rc, "%s: Failed to find 'LdrInitializeThunk': %Rrc", pImage->pszName, rc);
0c4004948fca34f2db87e7b38013137e9472c306vboxsync aSkipAreas[cSkipAreas].uRva = (uint32_t)uValue;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync aSkipAreas[cSkipAreas++].cb = 14;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync
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 if (RT_SUCCESS(rc))
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync {
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync aSkipAreas[cSkipAreas].uRva = (uint32_t)uValue;
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync aSkipAreas[cSkipAreas++].cb = RT_MAX(pbBits[(uint32_t)uValue], 0x50);
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync }
0c4004948fca34f2db87e7b38013137e9472c306vboxsync
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync Assert(cSkipAreas <= RT_ELEMENTS(aSkipAreas));
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync }
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync /*
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 */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync if (!pImage->fApiSetSchemaOnlySection1)
0c4004948fca34f2db87e7b38013137e9472c306vboxsync {
0c4004948fca34f2db87e7b38013137e9472c306vboxsync rc = supHardNtVpFileMemCompareSection(pThis, pImage, 0 /*uRva*/, cbHdrsFile, pbBits, -1, NULL, 0, PAGE_READONLY);
0c4004948fca34f2db87e7b38013137e9472c306vboxsync if (RT_FAILURE(rc))
0c4004948fca34f2db87e7b38013137e9472c306vboxsync return rc;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync
0c4004948fca34f2db87e7b38013137e9472c306vboxsync rc = supHardNtVpCheckSectionProtection(pThis, pImage, 0 /*uRva*/, cbHdrsFile, PAGE_READONLY);
0c4004948fca34f2db87e7b38013137e9472c306vboxsync if (RT_FAILURE(rc))
0c4004948fca34f2db87e7b38013137e9472c306vboxsync return rc;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync }
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync /*
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * Validate sections:
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * - Check them against the mapping regions.
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * - Check section bits according to enmKind.
0c4004948fca34f2db87e7b38013137e9472c306vboxsync */
0c4004948fca34f2db87e7b38013137e9472c306vboxsync uint32_t fPrevProt = PAGE_READONLY;
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync uint32_t uRva = cbHdrsFile;
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync for (uint32_t i = 0; i < cSections; i++)
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync {
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 if (cbMap > cbImage || uRva + cbMap > cbImage)
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 pImage->pszName, i, cbFile, cbMap, uSectRva);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Validate the protection and bits. */
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync if (!pImage->fApiSetSchemaOnlySection1 || i == 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t fProt;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (pThis->aSecHdrs[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE))
8cd2f2e64725096acb682f34a5568b7fb816eda7vboxsync {
8cd2f2e64725096acb682f34a5568b7fb816eda7vboxsync case IMAGE_SCN_MEM_READ:
8cd2f2e64725096acb682f34a5568b7fb816eda7vboxsync fProt = PAGE_READONLY;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fProt = PAGE_READWRITE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ( pThis->enmKind != SUPHARDNTVPKIND_VERIFY_ONLY
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && pThis->enmKind != SUPHARDNTVPKIND_CHILD_PURIFICATION
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && !suplibHardenedMemComp(pThis->aSecHdrs[i].Name, ".mrdata", 8)) /* w8.1, ntdll. Changed by proc init. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fProt = PAGE_READONLY;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
cba6719bd64ec749967bbe931230452664109857vboxsync case IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fProt = PAGE_EXECUTE_READ;
cba6719bd64ec749967bbe931230452664109857vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case IMAGE_SCN_MEM_EXECUTE:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fProt = PAGE_EXECUTE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
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 (!pImage->fDll)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
a8139954a84d6e9090dd3a8371aa788351d45bc3vboxsync if (pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION)
a8139954a84d6e9090dd3a8371aa788351d45bc3vboxsync fProt = PAGE_EXECUTE_READWRITE;
a8139954a84d6e9090dd3a8371aa788351d45bc3vboxsync else
a8139954a84d6e9090dd3a8371aa788351d45bc3vboxsync fProt = PAGE_EXECUTE_READ;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default:
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 }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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)
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (uRva < uSectRva && !pImage->fApiSetSchemaOnlySection1) /* Any gap worth checking? */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = supHardNtVpFileMemCompareSection(pThis, pImage, uRva, uSectRva - uRva, pbBits + uRva,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync i - 1, NULL, 0, fPrevProt);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_SUCCESS(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = supHardNtVpFileMemCompareSection(pThis, pImage, uSectRva, cbMap, pbBits + uSectRva,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync i, aSkipAreas, cSkipAreas, fProt);
0db6a029780d9f9b347500e117320a8d5661efe5vboxsync if (RT_SUCCESS(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbMapAligned = i + 1 < cSections && !pImage->fApiSetSchemaOnlySection1
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync ? RT_ALIGN_32(cbMap, cbSectAlign) : RT_ALIGN_32(cbMap, PAGE_SIZE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (cbMapAligned > cbMap)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = supHardNtVpFileMemCompareSection(pThis, pImage, uSectRva + cbMap, cbMapAligned - cbMap,
0db6a029780d9f9b347500e117320a8d5661efe5vboxsync g_abRTZeroPage, i, NULL, 0, fProt);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* The protection (must be checked afterwards!). */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = supHardNtVpCheckSectionProtection(pThis, pImage, uSectRva, RT_ALIGN_32(cbMap, PAGE_SIZE), fProt);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fPrevProt = fProt;
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
cba6719bd64ec749967bbe931230452664109857vboxsync /* Advance the RVA. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uRva = uSectRva + RT_ALIGN_32(cbMap, cbSectAlign);
9b789c281103a2489742bf32f6ab500e38b2ecd5vboxsync }
9b789c281103a2489742bf32f6ab500e38b2ecd5vboxsync
9b789c281103a2489742bf32f6ab500e38b2ecd5vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Verifies the signature of the given image on disk, then checks if the memory
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * mapping matches what we verified.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
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.
c91345f92b829d3fba05ce7a97206d83c5183ce0vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int supHardNtVpVerifyImage(PSUPHNTVPSTATE pThis, PSUPHNTVPIMAGE pImage, HANDLE hProcess)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Validate the file signature first, then do the memory compare.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ( pImage->pCacheEntry != NULL
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && pImage->pCacheEntry->hLdrMod != NIL_RTLDRMOD)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = supHardNtLdrCacheEntryVerify(pImage->pCacheEntry, pImage->Name.UniStr.Buffer, pThis->pErrInfo);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_SUCCESS(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = supHardNtVpVerifyImageMemoryCompare(pThis, pImage, hProcess, pThis->pErrInfo);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = supHardNtVpSetInfo2(pThis, VERR_OPEN_FAILED, "pCacheEntry/hLdrMod is NIL! Impossible!");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync/**
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync * Verifies that there is only one thread in the process.
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param hProcess The process.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param hThread The thread.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pErrInfo Pointer to error info structure. Optional.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLHIDDEN(int) supHardNtVpThread(HANDLE hProcess, HANDLE hThread, PRTERRINFO pErrInfo)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
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?
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ULONG cbIgn = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ULONG fAmI = 0;
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync NTSTATUS rcNt = NtQueryInformationThread(hThread, ThreadAmILastThread, &fAmI, sizeof(fAmI), &cbIgn);
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync if (!NT_SUCCESS(rcNt))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_NT_QI_THREAD_ERROR,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "NtQueryInformationThread/ThreadAmILastThread -> %#x", rcNt);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!fAmI)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_THREAD_NOT_ALONE,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "More than one thread in process");
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** @todo Would be nice to verify the relation ship between hProcess and hThread
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync * as well... */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
cba6719bd64ec749967bbe931230452664109857vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
cba6719bd64ec749967bbe931230452664109857vboxsync/**
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync * Verifies that there isn't a debugger attached to the process.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync * @returns VBox status code.
cba6719bd64ec749967bbe931230452664109857vboxsync * @param hProcess The process.
cba6719bd64ec749967bbe931230452664109857vboxsync * @param pErrInfo Pointer to error info structure. Optional.
cba6719bd64ec749967bbe931230452664109857vboxsync */
cba6719bd64ec749967bbe931230452664109857vboxsyncDECLHIDDEN(int) supHardNtVpDebugger(HANDLE hProcess, PRTERRINFO pErrInfo)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
/*
* Use the ProcessDebugPort request to check there is no debugger
* currently attached to the process.
*/
ULONG cbIgn = 0;
uintptr_t uPtr = ~(uintptr_t)0;
NTSTATUS rcNt = NtQueryInformationProcess(hProcess,
ProcessDebugPort,
&uPtr, sizeof(uPtr), &cbIgn);
if (!NT_SUCCESS(rcNt))
return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_NT_QI_PROCESS_DBG_PORT_ERROR,
"NtQueryInformationProcess/ProcessDebugPort -> %#x", rcNt);
if (uPtr != 0)
return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_DEBUGGED,
"Debugger attached (%#zx)", uPtr);
#endif /* !VBOX_WITHOUT_DEBUGGER_CHECKS */
return VINF_SUCCESS;
}
/**
* Matches two UNICODE_STRING structures in a case sensitive fashion.
*
* @returns true if equal, false if not.
* @param pUniStr1 The first unicode string.
* @param pUniStr2 The first unicode string.
*/
static bool supHardNtVpAreUniStringsEqual(PCUNICODE_STRING pUniStr1, PCUNICODE_STRING pUniStr2)
{
if (pUniStr1->Length != pUniStr2->Length)
return false;
return suplibHardenedMemComp(pUniStr1->Buffer, pUniStr2->Buffer, pUniStr1->Length) == 0;
}
/**
* Performs a case insensitive comparison of an ASCII and an UTF-16 file name.
*
* @returns true / false
* @param pszName1 The ASCII name.
* @param pwszName2 The UTF-16 name.
*/
static bool supHardNtVpAreNamesEqual(const char *pszName1, PCRTUTF16 pwszName2)
{
for (;;)
{
char ch1 = *pszName1++;
RTUTF16 wc2 = *pwszName2++;
if (ch1 != wc2)
{
ch1 = RT_C_TO_LOWER(ch1);
wc2 = wc2 < 0x80 ? RT_C_TO_LOWER(wc2) : wc2;
if (ch1 != wc2)
return false;
}
if (!ch1)
return true;
}
}
/**
* Records an additional memory region for an image.
*
* @returns VBox status code.
* @retval VINF_OBJECT_DESTROYED if we've unmapped the image (child
* purification only).
* @param pThis The process scanning state structure.
* @param pImage The new image structure. Only the unicode name
* buffer is valid.
* @param pMemInfo The memory information for the image.
*/
static int supHardNtVpNewImage(PSUPHNTVPSTATE pThis, PSUPHNTVPIMAGE pImage, PMEMORY_BASIC_INFORMATION pMemInfo)
{
/*
* Extract the final component.
*/
unsigned cwcDirName = pImage->Name.UniStr.Length / sizeof(WCHAR);
PCRTUTF16 pwszFilename = &pImage->Name.UniStr.Buffer[cwcDirName];
while ( cwcDirName > 0
&& pwszFilename[-1] != '\\'
&& pwszFilename[-1] != '/'
&& pwszFilename[-1] != ':')
{
pwszFilename--;
cwcDirName--;
}
if (!*pwszFilename)
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NO_IMAGE_MAPPING_NAME,
"Empty filename (len=%u) for image at %p.", pImage->Name.UniStr.Length, pMemInfo->BaseAddress);
/*
* Drop trailing slashes from the directory name.
*/
while ( cwcDirName > 0
&& ( pImage->Name.UniStr.Buffer[cwcDirName - 1] == '\\'
|| pImage->Name.UniStr.Buffer[cwcDirName - 1] == '/'))
cwcDirName--;
/*
* Match it against known DLLs.
*/
pImage->pszName = NULL;
for (uint32_t i = 0; i < RT_ELEMENTS(g_apszSupNtVpAllowedDlls); i++)
if (supHardNtVpAreNamesEqual(g_apszSupNtVpAllowedDlls[i], pwszFilename))
{
pImage->pszName = g_apszSupNtVpAllowedDlls[i];
pImage->fDll = true;
#ifndef VBOX_PERMIT_VISUAL_STUDIO_PROFILING
/* The directory name must match the one we've got for System32. */
if ( ( cwcDirName * sizeof(WCHAR) != g_System32NtPath.UniStr.Length
|| suplibHardenedMemComp(pImage->Name.UniStr.Buffer,
g_System32NtPath.UniStr.Buffer,
cwcDirName * sizeof(WCHAR)) )
# ifdef VBOX_PERMIT_MORE
&& ( pImage->pszName[0] != 'a'
|| pImage->pszName[1] != 'c'
|| !supHardViIsAppPatchDir(pImage->Name.UniStr.Buffer, pImage->Name.UniStr.Length / sizeof(WCHAR)) )
# endif
)
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NON_SYSTEM32_DLL,
"Expected %ls to be loaded from %ls.",
pImage->Name.UniStr.Buffer, g_System32NtPath.UniStr.Buffer);
# ifdef VBOX_PERMIT_MORE
if (g_uNtVerCombined < SUP_NT_VER_W70 && i >= VBOX_PERMIT_MORE_FIRST_IDX)
pImage->pszName = NULL; /* hard limit: user32.dll is unwanted prior to w7. */
# endif
#endif /* VBOX_PERMIT_VISUAL_STUDIO_PROFILING */
break;
}
if (!pImage->pszName)
{
/*
* Not a known DLL, is it a known executable?
*/
for (uint32_t i = 0; i < RT_ELEMENTS(g_apszSupNtVpAllowedVmExes); i++)
if (supHardNtVpAreNamesEqual(g_apszSupNtVpAllowedVmExes[i], pwszFilename))
{
pImage->pszName = g_apszSupNtVpAllowedVmExes[i];
pImage->fDll = false;
break;
}
}
if (!pImage->pszName)
{
/*
* Unknown image.
*
* If we're cleaning up a child process, we can unmap the offending
* DLL... Might have interesting side effects, or at least interesting
* as in "may you live in interesting times".
*/
#ifdef IN_RING3
if ( pMemInfo->AllocationBase == pMemInfo->BaseAddress
&& pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION)
{
SUP_DPRINTF(("supHardNtVpScanVirtualMemory: Unmapping image mem at %p (%p LB %#zx) - '%ls'\n",
pMemInfo->AllocationBase, pMemInfo->BaseAddress, pMemInfo->RegionSize));
NTSTATUS rcNt = NtUnmapViewOfSection(pThis->hProcess, pMemInfo->AllocationBase);
if (NT_SUCCESS(rcNt))
return VINF_OBJECT_DESTROYED;
pThis->cFixes++;
SUP_DPRINTF(("supHardNtVpScanVirtualMemory: NtUnmapViewOfSection(,%p) failed: %#x\n", pMemInfo->AllocationBase, rcNt));
}
#endif
/*
* Special error message if we can.
*/
if ( pMemInfo->AllocationBase == pMemInfo->BaseAddress
&& ( supHardNtVpAreNamesEqual("sysfer.dll", pwszFilename)
|| supHardNtVpAreNamesEqual("sysfer32.dll", pwszFilename)
|| supHardNtVpAreNamesEqual("sysfer64.dll", pwszFilename)
|| supHardNtVpAreNamesEqual("sysfrethunk.dll", pwszFilename)) )
{
supHardNtVpSetInfo2(pThis, VERR_SUP_VP_SYSFER_DLL,
"Found %ls at %p - This is probably part of Symantec Endpoint Protection. \n"
"You or your admin need to add and exception to the Application and Device Control (ADC) "
"component (or disable it) to prevent ADC from injecting itself into the VirtualBox VM processes. "
"See http://www.symantec.com/connect/articles/creating-application-control-exclusions-symantec-endpoint-protection-121"
, pImage->Name.UniStr.Buffer, pMemInfo->BaseAddress);
return pThis->rcResult = VERR_SUP_VP_SYSFER_DLL; /* Try make sure this is what the user sees first! */
}
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NOT_KNOWN_DLL_OR_EXE,
"Unknown image file %ls at %p.", pImage->Name.UniStr.Buffer, pMemInfo->BaseAddress);
}
/*
* Checks for multiple mappings of the same DLL but with different image file paths.
*/
uint32_t i = pThis->cImages;
while (i-- > 1)
if (pImage->pszName == pThis->aImages[i].pszName)
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_DUPLICATE_DLL_MAPPING,
"Duplicate image entries for %s: %ls and %ls",
pImage->pszName, pImage->Name.UniStr.Buffer, pThis->aImages[i].Name.UniStr.Buffer);
/*
* Since it's a new image, we expect to be at the start of the mapping now.
*/
if (pMemInfo->AllocationBase != pMemInfo->BaseAddress)
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_IMAGE_MAPPING_BASE_ERROR,
"Invalid AllocationBase/BaseAddress for %s: %p vs %p.",
pImage->pszName, pMemInfo->AllocationBase, pMemInfo->BaseAddress);
/*
* Check for size/rva overflow.
*/
if (pMemInfo->RegionSize >= _2G)
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_TOO_LARGE_REGION,
"Region 0 of image %s is too large: %p.", pImage->pszName, pMemInfo->RegionSize);
/*
* Fill in details from the memory info.
*/
pImage->uImageBase = (uintptr_t)pMemInfo->AllocationBase;
pImage->cbImage = pMemInfo->RegionSize;
pImage->pCacheEntry= NULL;
pImage->cRegions = 1;
pImage->aRegions[0].uRva = 0;
pImage->aRegions[0].cb = (uint32_t)pMemInfo->RegionSize;
pImage->aRegions[0].fProt = pMemInfo->Protect;
if (suplibHardenedStrCmp(pImage->pszName, "ntdll.dll") == 0)
pImage->fNtCreateSectionPatch = true;
else if (suplibHardenedStrCmp(pImage->pszName, "apisetschema.dll") == 0)
pImage->fApiSetSchemaOnlySection1 = true; /** @todo Check the ApiSetMap field in the PEB. */
#ifdef VBOX_PERMIT_MORE
else if (suplibHardenedStrCmp(pImage->pszName, "acres.dll") == 0)
pImage->f32bitResourceDll = true;
#endif
return VINF_SUCCESS;
}
/**
* Records an additional memory region for an image.
*
* @returns VBox status code.
* @param pThis The process scanning state structure.
* @param pImage The image.
* @param pMemInfo The memory information for the region.
*/
static int supHardNtVpAddRegion(PSUPHNTVPSTATE pThis, PSUPHNTVPIMAGE pImage, PMEMORY_BASIC_INFORMATION pMemInfo)
{
/*
* Make sure the base address matches.
*/
if (pImage->uImageBase != (uintptr_t)pMemInfo->AllocationBase)
return supHardNtVpSetInfo2(pThis, VERR_SUPLIB_NT_PROCESS_UNTRUSTED_3,
"Base address mismatch for %s: have %p, found %p for region %p LB %#zx.",
pImage->pszName, pImage->uImageBase, pMemInfo->AllocationBase,
pMemInfo->BaseAddress, pMemInfo->RegionSize);
/*
* Check for size and rva overflows.
*/
uintptr_t uRva = (uintptr_t)pMemInfo->BaseAddress - pImage->uImageBase;
if (pMemInfo->RegionSize >= _2G)
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_TOO_LARGE_REGION,
"Region %u of image %s is too large: %p/%p.", pImage->pszName, pMemInfo->RegionSize, uRva);
if (uRva >= _2G)
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_TOO_HIGH_REGION_RVA,
"Region %u of image %s is too high: %p/%p.", pImage->pszName, pMemInfo->RegionSize, uRva);
/*
* Record the region.
*/
uint32_t iRegion = pImage->cRegions;
if (iRegion + 1 >= RT_ELEMENTS(pImage->aRegions))
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_TOO_MANY_IMAGE_REGIONS,
"Too many regions for %s.", pImage->pszName);
pImage->aRegions[iRegion].uRva = (uint32_t)uRva;
pImage->aRegions[iRegion].cb = (uint32_t)pMemInfo->RegionSize;
pImage->aRegions[iRegion].fProt = pMemInfo->Protect;
pImage->cbImage = pImage->aRegions[iRegion].uRva + pImage->aRegions[iRegion].cb;
pImage->cRegions++;
pImage->fApiSetSchemaOnlySection1 = false;
return VINF_SUCCESS;
}
/**
* Scans the virtual memory of the process.
*
* This collects the locations of DLLs and the EXE, and verifies that executable
* memory is only associated with these.
*
* @returns VBox status code.
* @param pThis The process scanning state structure. Details
* about images are added to this.
* @param hProcess The process to verify.
*/
static int supHardNtVpScanVirtualMemory(PSUPHNTVPSTATE pThis, HANDLE hProcess)
{
SUP_DPRINTF(("supHardNtVpScanVirtualMemory: enmKind=%s\n",
pThis->enmKind == SUPHARDNTVPKIND_VERIFY_ONLY ? "VERIFY_ONLY" :
pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION ? "CHILD_PURIFICATION" : "SELF_PURIFICATION"));
uint32_t cXpExceptions = 0;
uintptr_t cbAdvance = 0;
uintptr_t uPtrWhere = 0;
#ifdef VBOX_PERMIT_VERIFIER_DLL
for (uint32_t i = 0; i < 10240; i++)
#else
for (uint32_t i = 0; i < 1024; i++)
#endif
{
SIZE_T cbActual = 0;
MEMORY_BASIC_INFORMATION MemInfo = { 0, 0, 0, 0, 0, 0, 0 };
NTSTATUS rcNt = g_pfnNtQueryVirtualMemory(hProcess,
(void const *)uPtrWhere,
MemoryBasicInformation,
&MemInfo,
sizeof(MemInfo),
&cbActual);
if (!NT_SUCCESS(rcNt))
{
if (rcNt == STATUS_INVALID_PARAMETER)
return pThis->rcResult;
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NT_QI_VIRTUAL_MEMORY_ERROR,
"NtQueryVirtualMemory failed for %p: %#x", uPtrWhere, rcNt);
}
/*
* Record images.
*/
if ( MemInfo.Type == SEC_IMAGE
|| MemInfo.Type == SEC_PROTECTED_IMAGE
|| MemInfo.Type == (SEC_IMAGE | SEC_PROTECTED_IMAGE))
{
uint32_t iImg = pThis->cImages;
rcNt = g_pfnNtQueryVirtualMemory(hProcess,
(void const *)uPtrWhere,
MemorySectionName,
&pThis->aImages[iImg].Name,
sizeof(pThis->aImages[iImg].Name) - sizeof(WCHAR),
&cbActual);
if (!NT_SUCCESS(rcNt))
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NT_QI_VIRTUAL_MEMORY_NM_ERROR,
"NtQueryVirtualMemory/MemorySectionName failed for %p: %#x", uPtrWhere, rcNt);
pThis->aImages[iImg].Name.UniStr.Buffer[pThis->aImages[iImg].Name.UniStr.Length / sizeof(WCHAR)] = '\0';
SUP_DPRINTF((MemInfo.AllocationBase == MemInfo.BaseAddress
? " *%p-%p %#06x/%#06x %#09x %ls\n"
: " %p-%p %#06x/%#06x %#09x %ls\n",
MemInfo.BaseAddress, (uintptr_t)MemInfo.BaseAddress - MemInfo.RegionSize - 1, MemInfo.Protect,
MemInfo.AllocationProtect, MemInfo.Type, pThis->aImages[iImg].Name.UniStr.Buffer));
/* New or existing image? */
bool fNew = true;
uint32_t iSearch = iImg;
while (iSearch-- > 0)
if (supHardNtVpAreUniStringsEqual(&pThis->aImages[iSearch].Name.UniStr, &pThis->aImages[iImg].Name.UniStr))
{
int rc = supHardNtVpAddRegion(pThis, &pThis->aImages[iSearch], &MemInfo);
if (RT_FAILURE(rc))
return rc;
fNew = false;
break;
}
else if (pThis->aImages[iSearch].uImageBase == (uintptr_t)MemInfo.AllocationBase)
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NT_MAPPING_NAME_CHANGED,
"Unexpected base address match");
if (fNew)
{
int rc = supHardNtVpNewImage(pThis, &pThis->aImages[iImg], &MemInfo);
if (RT_SUCCESS(rc))
{
if (rc != VINF_OBJECT_DESTROYED)
{
pThis->cImages++;
if (pThis->cImages >= RT_ELEMENTS(pThis->aImages))
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_TOO_MANY_DLLS_LOADED,
"Internal error: aImages is full.\n");
}
}
#ifdef IN_RING3 /* Continue and add more information if unknown DLLs are found. */
else if (rc != VERR_SUP_VP_NOT_KNOWN_DLL_OR_EXE && rc != VERR_SUP_VP_NON_SYSTEM32_DLL)
return rc;
#else
else
return rc;
#endif
}
}
/*
* XP, W2K3: Ignore the CSRSS read-only region as best we can.
*/
else if ( (MemInfo.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY))
== PAGE_EXECUTE_READ
&& cXpExceptions == 0
&& (uintptr_t)MemInfo.BaseAddress >= UINT32_C(0x78000000)
/* && MemInfo.BaseAddress == pPeb->ReadOnlySharedMemoryBase */
&& g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 0) )
{
cXpExceptions++;
SUP_DPRINTF((" %p-%p %#06x/%#06x %#09x XP CSRSS read-only region\n", MemInfo.BaseAddress,
(uintptr_t)MemInfo.BaseAddress - MemInfo.RegionSize - 1, MemInfo.Protect,
MemInfo.AllocationProtect, MemInfo.Type));
}
/*
* Executable memory?
*/
#ifndef VBOX_PERMIT_VISUAL_STUDIO_PROFILING
else if (MemInfo.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY))
{
SUP_DPRINTF((MemInfo.AllocationBase == MemInfo.BaseAddress
? " *%p-%p %#06x/%#06x %#09x !!\n"
: " %p-%p %#06x/%#06x %#09x !!\n",
MemInfo.BaseAddress, (uintptr_t)MemInfo.BaseAddress - MemInfo.RegionSize - 1,
MemInfo.Protect, MemInfo.AllocationProtect, MemInfo.Type));
# ifdef IN_RING3
if (pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION)
{
/*
* Free any private executable memory (sysplant.sys allocates executable memory).
*/
if (MemInfo.Type == MEM_PRIVATE)
{
SUP_DPRINTF(("supHardNtVpScanVirtualMemory: Freeing exec mem at %p (%p LB %#zx)\n",
uPtrWhere, MemInfo.BaseAddress, MemInfo.RegionSize));
PVOID pvFree = MemInfo.BaseAddress;
SIZE_T cbFree = MemInfo.RegionSize;
rcNt = NtFreeVirtualMemory(pThis->hProcess, &pvFree, &cbFree, MEM_RELEASE);
if (!NT_SUCCESS(rcNt))
supHardNtVpSetInfo2(pThis, VERR_SUP_VP_FREE_VIRTUAL_MEMORY_FAILED,
"NtFreeVirtualMemory (%p LB %#zx) failed: %#x",
MemInfo.BaseAddress, MemInfo.RegionSize, rcNt);
/* The Trend Micro sakfile.sys BSOD kludge. */
if (pThis->fFlags & SUPHARDNTVP_F_EXEC_ALLOC_REPLACE_WITH_ZERO)
{
pvFree = MemInfo.BaseAddress;
cbFree = MemInfo.RegionSize;
rcNt = NtAllocateVirtualMemory(pThis->hProcess, &pvFree, 0, &cbFree, MEM_COMMIT, PAGE_READWRITE);
if (!NT_SUCCESS(rcNt))
supHardNtVpSetInfo2(pThis, VERR_SUP_VP_REPLACE_VIRTUAL_MEMORY_FAILED,
"NtAllocateVirtualMemory (%p LB %#zx) failed with rcNt=%#x allocating "
"replacement memory for working around buggy protection software. "
"See VBoxStartup.log for more details",
MemInfo.BaseAddress, MemInfo.RegionSize, rcNt);
if (pvFree != MemInfo.BaseAddress)
supHardNtVpSetInfo2(pThis, VERR_SUP_VP_REPLACE_VIRTUAL_MEMORY_FAILED,
"We wanted NtAllocateVirtualMemory to get us %p LB %#zx, but it returned %p LB %#zx.",
MemInfo.BaseAddress, MemInfo.RegionSize, pvFree, cbFree, rcNt);
}
}
/*
* Unmap mapped memory, failing that, drop exec privileges.
*/
else if (MemInfo.Type == MEM_MAPPED)
{
SUP_DPRINTF(("supHardNtVpScanVirtualMemory: Unmapping exec mem at %p (%p/%p LB %#zx)\n",
uPtrWhere, MemInfo.AllocationBase, MemInfo.BaseAddress, MemInfo.RegionSize));
rcNt = NtUnmapViewOfSection(pThis->hProcess, MemInfo.AllocationBase);
if (!NT_SUCCESS(rcNt))
{
PVOID pvCopy = MemInfo.BaseAddress;
SIZE_T cbCopy = MemInfo.RegionSize;
NTSTATUS rcNt2 = NtProtectVirtualMemory(pThis->hProcess, &pvCopy, &cbCopy, PAGE_NOACCESS, NULL);
if (!NT_SUCCESS(rcNt2))
rcNt2 = NtProtectVirtualMemory(pThis->hProcess, &pvCopy, &cbCopy, PAGE_READONLY, NULL);
if (!NT_SUCCESS(rcNt2))
supHardNtVpSetInfo2(pThis, VERR_SUP_VP_UNMAP_AND_PROTECT_FAILED,
"NtUnmapViewOfSection (%p/%p LB %#zx) failed: %#x (%#x)",
MemInfo.AllocationBase, MemInfo.BaseAddress, MemInfo.RegionSize, rcNt, rcNt2);
}
}
else
supHardNtVpSetInfo2(pThis, VERR_SUP_VP_UNKOWN_MEM_TYPE,
"Unknown executable memory type %#x at %p/%p LB %#zx",
MemInfo.Type, MemInfo.AllocationBase, MemInfo.BaseAddress, MemInfo.RegionSize);
pThis->cFixes++;
}
else
# endif /* IN_RING3 */
supHardNtVpSetInfo2(pThis, VERR_SUP_VP_FOUND_EXEC_MEMORY,
"Found executable memory at %p (%p LB %#zx): type=%#x prot=%#x state=%#x aprot=%#x abase=%p",
uPtrWhere, MemInfo.BaseAddress, MemInfo.RegionSize, MemInfo.Type, MemInfo.Protect,
MemInfo.State, MemInfo.AllocationBase, MemInfo.AllocationProtect);
# ifndef IN_RING3
if (RT_FAILURE(pThis->rcResult))
return pThis->rcResult;
# endif
/* Continue add more information about the problematic process. */
}
#endif /* VBOX_PERMIT_VISUAL_STUDIO_PROFILING */
else
SUP_DPRINTF((MemInfo.AllocationBase == MemInfo.BaseAddress
? " *%p-%p %#06x/%#06x %#09x\n"
: " %p-%p %#06x/%#06x %#09x\n",
MemInfo.BaseAddress, (uintptr_t)MemInfo.BaseAddress - MemInfo.RegionSize - 1,
MemInfo.Protect, MemInfo.AllocationProtect, MemInfo.Type));
/*
* Advance.
*/
cbAdvance = MemInfo.RegionSize;
if (uPtrWhere + cbAdvance <= uPtrWhere)
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_EMPTY_REGION_TOO_LARGE,
"Empty region at %p.", uPtrWhere);
uPtrWhere += MemInfo.RegionSize;
}
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_TOO_MANY_MEMORY_REGIONS,
"Too many virtual memory regions.\n");
}
/**
* Verifies the loader image, i.e. check cryptographic signatures if present.
*
* @returns VBox status code.
* @param pEntry The loader cache entry.
* @param pwszName The filename to use in error messages.
* @param pErRInfo Where to return extened error information.
*/
DECLHIDDEN(int) supHardNtLdrCacheEntryVerify(PSUPHNTLDRCACHEENTRY pEntry, PCRTUTF16 pwszName, PRTERRINFO pErrInfo)
{
int rc = VINF_SUCCESS;
if (!pEntry->fVerified)
{
rc = supHardenedWinVerifyImageByLdrMod(pEntry->hLdrMod, pwszName, pEntry->pNtViRdr,
false /*fAvoidWinVerifyTrust*/, NULL /*pfWinVerifyTrust*/, pErrInfo);
pEntry->fVerified = RT_SUCCESS(rc);
}
return rc;
}
/**
* Allocates a image bits buffer and calls RTLdrGetBits on them.
*
* An assumption here is that there won't ever be concurrent use of the cache.
* It's currently 104% single threaded, non-reentrant. Thus, we can't reuse the
* pbBits allocation.
*
* @returns VBox status code
* @param pEntry The loader cache entry.
* @param ppbBits Where to return the pointer to the allocation.
* @param uBaseAddress The image base address, see RTLdrGetBits.
* @param pfnGetImport Import getter, see RTLdrGetBits.
* @param pvUser The user argument for @a pfnGetImport.
* @param pErrInfo Where to return extened error information.
*/
DECLHIDDEN(int) supHardNtLdrCacheEntryGetBits(PSUPHNTLDRCACHEENTRY pEntry, uint8_t **ppbBits,
RTLDRADDR uBaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser,
PRTERRINFO pErrInfo)
{
int rc;
/*
* First time around we have to allocate memory before we can get the image bits.
*/
if (!pEntry->pbBits)
{
size_t cbBits = RTLdrSize(pEntry->hLdrMod);
if (cbBits >= _1M*32U)
return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_IMAGE_TOO_BIG, "Image %s is too large: %zu bytes (%#zx).",
pEntry->pszName, cbBits, cbBits);
pEntry->pbBits = (uint8_t *)RTMemAllocZ(cbBits);
if (!pEntry->pbBits)
return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_NO_MEMORY, "Failed to allocate %zu bytes for image %s.",
cbBits, pEntry->pszName);
pEntry->fValidBits = false; /* paranoia */
rc = RTLdrGetBits(pEntry->hLdrMod, pEntry->pbBits, uBaseAddress, pfnGetImport, pvUser);
if (RT_FAILURE(rc))
return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_NO_MEMORY, "RTLdrGetBits failed on image %s: %Rrc",
pEntry->pszName, rc);
pEntry->uImageBase = uBaseAddress;
pEntry->fValidBits = pfnGetImport == NULL;
}
/*
* Cache hit? No?
*
* Note! We cannot currently cache image bits for images with imports as we
* don't control the way they're resolved. Fortunately, NTDLL and
* the VM process images all have no imports.
*/
else if ( !pEntry->fValidBits
|| pEntry->uImageBase != uBaseAddress
|| pfnGetImport)
{
pEntry->fValidBits = false;
rc = RTLdrGetBits(pEntry->hLdrMod, pEntry->pbBits, uBaseAddress, pfnGetImport, pvUser);
if (RT_FAILURE(rc))
return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_NO_MEMORY, "RTLdrGetBits failed on image %s: %Rrc",
pEntry->pszName, rc);
pEntry->uImageBase = uBaseAddress;
pEntry->fValidBits = pfnGetImport == NULL;
}
*ppbBits = pEntry->pbBits;
return VINF_SUCCESS;
}
/**
* Frees all resources associated with a cache entry and wipes the members
* clean.
*
* @param pEntry The entry to delete.
*/
static void supHardNTLdrCacheDeleteEntry(PSUPHNTLDRCACHEENTRY pEntry)
{
if (pEntry->pbBits)
{
RTMemFree(pEntry->pbBits);
pEntry->pbBits = NULL;
}
if (pEntry->hLdrMod != NIL_RTLDRMOD)
{
RTLdrClose(pEntry->hLdrMod);
pEntry->hLdrMod = NIL_RTLDRMOD;
pEntry->pNtViRdr = NULL;
}
else if (pEntry->pNtViRdr)
{
pEntry->pNtViRdr->Core.pfnDestroy(&pEntry->pNtViRdr->Core);
pEntry->pNtViRdr = NULL;
}
if (pEntry->hFile)
{
NtClose(pEntry->hFile);
pEntry->hFile = NULL;
}
pEntry->pszName = NULL;
pEntry->fVerified = false;
pEntry->fValidBits = false;
pEntry->uImageBase = 0;
}
#ifdef IN_RING3
/**
* Flushes the cache.
*
* This is called from one of two points in the hardened main code, first is
* after respawning and the second is when we open the vboxdrv device for
* unrestricted access.
*/
DECLHIDDEN(void) supR3HardenedWinFlushLoaderCache(void)
{
uint32_t i = g_cSupNtVpLdrCacheEntries;
while (i-- > 0)
supHardNTLdrCacheDeleteEntry(&g_aSupNtVpLdrCacheEntries[i]);
g_cSupNtVpLdrCacheEntries = 0;
}
/**
* Searches the cache for a loader image.
*
* @returns Pointer to the cache entry if found, NULL if not.
* @param pszName The name (from g_apszSupNtVpAllowedVmExes or
* g_apszSupNtVpAllowedDlls).
*/
static PSUPHNTLDRCACHEENTRY supHardNtLdrCacheLookupEntry(const char *pszName)
{
/*
* Since the caller is supplying us a pszName from one of the two tables,
* we can dispense with string compare and simply compare string pointers.
*/
uint32_t i = g_cSupNtVpLdrCacheEntries;
while (i-- > 0)
if (g_aSupNtVpLdrCacheEntries[i].pszName == pszName)
return &g_aSupNtVpLdrCacheEntries[i];
return NULL;
}
#endif /* IN_RING3 */
static int supHardNtLdrCacheNewEntry(PSUPHNTLDRCACHEENTRY pEntry, const char *pszName, PUNICODE_STRING pUniStrPath,
bool fDll, bool f32bitResourceDll, PRTERRINFO pErrInfo)
{
/*
* Open the image file.
*/
HANDLE hFile = RTNT_INVALID_HANDLE_VALUE;
IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
OBJECT_ATTRIBUTES ObjAttr;
InitializeObjectAttributes(&ObjAttr, pUniStrPath, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
#ifdef IN_RING0
ObjAttr.Attributes |= OBJ_KERNEL_HANDLE;
#endif
NTSTATUS rcNt = NtCreateFile(&hFile,
GENERIC_READ,
&ObjAttr,
&Ios,
NULL /* Allocation Size*/,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE, /** @todo nonalert? */
NULL /*EaBuffer*/,
0 /*EaLength*/);
if (NT_SUCCESS(rcNt))
rcNt = Ios.Status;
if (!NT_SUCCESS(rcNt))
return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_IMAGE_FILE_OPEN_ERROR,
"Error opening image for scanning: %#x (name %ls)", rcNt, pUniStrPath->Buffer);
/*
* Figure out validation flags we'll be using and create the reader
* for this image.
*/
uint32_t fFlags = fDll
? SUPHNTVI_F_TRUSTED_INSTALLER_OWNER | SUPHNTVI_F_ALLOW_CAT_FILE_VERIFICATION
: SUPHNTVI_F_REQUIRE_BUILD_CERT;
if (f32bitResourceDll)
fFlags |= SUPHNTVI_F_RESOURCE_IMAGE;
PSUPHNTVIRDR pNtViRdr;
int rc = supHardNtViRdrCreate(hFile, pUniStrPath->Buffer, fFlags, &pNtViRdr);
if (RT_FAILURE(rc))
{
NtClose(hFile);
return rc;
}
/*
* Finally, open the image with the loader
*/
RTLDRMOD hLdrMod;
RTLDRARCH enmArch = fFlags & SUPHNTVI_F_RC_IMAGE ? RTLDRARCH_X86_32 : RTLDRARCH_HOST;
if (fFlags & SUPHNTVI_F_RESOURCE_IMAGE)
enmArch = RTLDRARCH_WHATEVER;
rc = RTLdrOpenWithReader(&pNtViRdr->Core, RTLDR_O_FOR_VALIDATION, enmArch, &hLdrMod, pErrInfo);
if (RT_FAILURE(rc))
return supHardNtVpSetInfo1(pErrInfo, rc, "RTLdrOpenWithReader failed: %Rrc (Image='%ls').",
rc, pUniStrPath->Buffer);
/*
* Fill in the cache entry.
*/
pEntry->pszName = pszName;
pEntry->hLdrMod = hLdrMod;
pEntry->pNtViRdr = pNtViRdr;
pEntry->hFile = hFile;
pEntry->pbBits = NULL;
pEntry->fVerified = false;
pEntry->fValidBits = false;
pEntry->uImageBase = ~(uintptr_t)0;
#ifdef IN_SUP_HARDENED_R3
/*
* Log the image timestamp when in the hardened exe.
*/
uint64_t uTimestamp = 0;
rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_TIMESTAMP_SECONDS, &uTimestamp, sizeof(uint64_t));
SUP_DPRINTF(("%s: timestamp %#llx (rc=%Rrc)\n", pszName, uTimestamp, rc));
#endif
return VINF_SUCCESS;
}
#ifdef IN_RING3
/**
* Opens a loader cache entry.
*
* Currently this is only used by the import code for getting NTDLL.
*
* @returns VBox status code.
* @param pszName The DLL name. Must be one from the
* g_apszSupNtVpAllowedDlls array.
* @param ppEntry Where to return the entry we've opened/found.
*/
DECLHIDDEN(int) supHardNtLdrCacheOpen(const char *pszName, PSUPHNTLDRCACHEENTRY *ppEntry)
{
/*
* Locate the dll.
*/
uint32_t i = 0;
while ( i < RT_ELEMENTS(g_apszSupNtVpAllowedDlls)
&& strcmp(pszName, g_apszSupNtVpAllowedDlls[i]))
i++;
if (i >= RT_ELEMENTS(g_apszSupNtVpAllowedDlls))
return VERR_FILE_NOT_FOUND;
pszName = g_apszSupNtVpAllowedDlls[i];
/*
* Try the cache.
*/
*ppEntry = supHardNtLdrCacheLookupEntry(pszName);
if (*ppEntry)
return VINF_SUCCESS;
/*
* Not in the cache, so open it.
* Note! We cannot assume that g_System32NtPath has been initialized at this point.
*/
if (g_cSupNtVpLdrCacheEntries >= RT_ELEMENTS(g_aSupNtVpLdrCacheEntries))
return VERR_INTERNAL_ERROR_3;
static WCHAR s_wszSystem32[] = L"\\SystemRoot\\System32\\";
WCHAR wszPath[64];
memcpy(wszPath, s_wszSystem32, sizeof(s_wszSystem32));
RTUtf16CatAscii(wszPath, sizeof(wszPath), pszName);
UNICODE_STRING UniStr;
UniStr.Buffer = wszPath;
UniStr.Length = (USHORT)(RTUtf16Len(wszPath) * sizeof(WCHAR));
UniStr.MaximumLength = UniStr.Length + sizeof(WCHAR);
int rc = supHardNtLdrCacheNewEntry(&g_aSupNtVpLdrCacheEntries[g_cSupNtVpLdrCacheEntries], pszName, &UniStr,
true /*fDll*/, false /*f32bitResourceDll*/, NULL /*pErrInfo*/);
if (RT_SUCCESS(rc))
{
*ppEntry = &g_aSupNtVpLdrCacheEntries[g_cSupNtVpLdrCacheEntries];
g_cSupNtVpLdrCacheEntries++;
return VINF_SUCCESS;
}
return rc;
}
#endif /* IN_RING3 */
/**
* Opens all the images with the IPRT loader, setting both, hFile, pNtViRdr and
* hLdrMod for each image.
*
* @returns VBox status code.
* @param pThis The process scanning state structure.
*/
static int supHardNtVpOpenImages(PSUPHNTVPSTATE pThis)
{
unsigned i = pThis->cImages;
while (i-- > 0)
{
PSUPHNTVPIMAGE pImage = &pThis->aImages[i];
#ifdef IN_RING3
/*
* Try the cache first.
*/
pImage->pCacheEntry = supHardNtLdrCacheLookupEntry(pImage->pszName);
if (pImage->pCacheEntry)
continue;
/*
* Not in the cache, so load it into the cache.
*/
if (g_cSupNtVpLdrCacheEntries >= RT_ELEMENTS(g_aSupNtVpLdrCacheEntries))
return supHardNtVpSetInfo2(pThis, VERR_INTERNAL_ERROR_3, "Loader cache overflow.");
pImage->pCacheEntry = &g_aSupNtVpLdrCacheEntries[g_cSupNtVpLdrCacheEntries];
#else
/*
* In ring-0 we don't have a cache at the moment (resource reasons), so
* we have a static cache entry in each image structure that we use instead.
*/
pImage->pCacheEntry = &pImage->CacheEntry;
#endif
int rc = supHardNtLdrCacheNewEntry(pImage->pCacheEntry, pImage->pszName, &pImage->Name.UniStr,
pImage->fDll, pImage->f32bitResourceDll, pThis->pErrInfo);
if (RT_FAILURE(rc))
return rc;
#ifdef IN_RING3
g_cSupNtVpLdrCacheEntries++;
#endif
}
return VINF_SUCCESS;
}
/**
* Check the integrity of the executable of the process.
*
* @returns VBox status code.
* @param pThis The process scanning state structure. Details
* about images are added to this.
* @param hProcess The process to verify.
*/
static int supHardNtVpCheckExe(PSUPHNTVPSTATE pThis, HANDLE hProcess)
{
/*
* Make sure there is exactly one executable image.
*/
unsigned cExecs = 0;
unsigned iExe = ~0U;
unsigned i = pThis->cImages;
while (i-- > 0)
{
if (!pThis->aImages[i].fDll)
{
cExecs++;
iExe = i;
}
}
if (cExecs == 0)
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NO_FOUND_NO_EXE_MAPPING,
"No executable mapping found in the virtual address space.");
if (cExecs != 1)
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_FOUND_MORE_THAN_ONE_EXE_MAPPING,
"Found more than one executable mapping in the virtual address space.");
PSUPHNTVPIMAGE pImage = &pThis->aImages[iExe];
/*
* Check that it matches the executable image of the process.
*/
int rc;
ULONG cbUniStr = sizeof(UNICODE_STRING) + RTPATH_MAX * sizeof(RTUTF16);
PUNICODE_STRING pUniStr = (PUNICODE_STRING)RTMemAllocZ(cbUniStr);
if (!pUniStr)
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NO_MEMORY,
"Error allocating %zu bytes for process name.", cbUniStr);
ULONG cbIgn = 0;
NTSTATUS rcNt = NtQueryInformationProcess(hProcess, ProcessImageFileName, pUniStr, cbUniStr - sizeof(WCHAR), &cbIgn);
if (NT_SUCCESS(rcNt))
{
if (supHardNtVpAreUniStringsEqual(pUniStr, &pImage->Name.UniStr))
rc = VINF_SUCCESS;
else
{
pUniStr->Buffer[pUniStr->Length / sizeof(WCHAR)] = '\0';
rc = supHardNtVpSetInfo2(pThis, VERR_SUP_VP_EXE_VS_PROC_NAME_MISMATCH,
"Process image name does not match the exectuable we found: %ls vs %ls.",
pUniStr->Buffer, pImage->Name.UniStr.Buffer);
}
}
else
rc = supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NT_QI_PROCESS_NM_ERROR,
"NtQueryInformationProcess/ProcessImageFileName failed: %#x", rcNt);
RTMemFree(pUniStr);
if (RT_FAILURE(rc))
return rc;
/*
* Validate the signing of the executable image.
* This will load the fDllCharecteristics and fImageCharecteristics members we use below.
*/
rc = supHardNtVpVerifyImage(pThis, pImage, hProcess);
if (RT_FAILURE(rc))
return rc;
/*
* Check linking requirements.
* This query is only available using the current process pseudo handle on
* older windows versions. The cut-off seems to be Vista.
*/
SECTION_IMAGE_INFORMATION ImageInfo;
rcNt = NtQueryInformationProcess(hProcess, ProcessImageInformation, &ImageInfo, sizeof(ImageInfo), NULL);
if (!NT_SUCCESS(rcNt))
{
if ( rcNt == STATUS_INVALID_PARAMETER
&& g_uNtVerCombined < SUP_NT_VER_VISTA
&& hProcess != NtCurrentProcess() )
return VINF_SUCCESS;
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NT_QI_PROCESS_IMG_INFO_ERROR,
"NtQueryInformationProcess/ProcessImageInformation failed: %#x hProcess=%#x", rcNt, hProcess);
}
if ( !(ImageInfo.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY))
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_EXE_MISSING_FORCE_INTEGRITY,
"EXE DllCharacteristics=%#x, expected IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY to be set.",
ImageInfo.DllCharacteristics);
if (!(ImageInfo.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE))
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_EXE_MISSING_DYNAMIC_BASE,
"EXE DllCharacteristics=%#x, expected IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE to be set.",
ImageInfo.DllCharacteristics);
if (!(ImageInfo.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT))
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_EXE_MISSING_NX_COMPAT,
"EXE DllCharacteristics=%#x, expected IMAGE_DLLCHARACTERISTICS_NX_COMPAT to be set.",
ImageInfo.DllCharacteristics);
if (pImage->fDllCharecteristics != ImageInfo.DllCharacteristics)
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_DLL_CHARECTERISTICS_MISMATCH,
"EXE Info.DllCharacteristics=%#x fDllCharecteristics=%#x.",
ImageInfo.DllCharacteristics, pImage->fDllCharecteristics);
if (pImage->fImageCharecteristics != ImageInfo.ImageCharacteristics)
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_DLL_CHARECTERISTICS_MISMATCH,
"EXE Info.ImageCharacteristics=%#x fImageCharecteristics=%#x.",
ImageInfo.ImageCharacteristics, pImage->fImageCharecteristics);
return VINF_SUCCESS;
}
/**
* Check the integrity of the DLLs found in the process.
*
* @returns VBox status code.
* @param pThis The process scanning state structure. Details
* about images are added to this.
* @param hProcess The process to verify.
*/
static int supHardNtVpCheckDlls(PSUPHNTVPSTATE pThis, HANDLE hProcess)
{
/*
* Check for duplicate entries (paranoia).
*/
uint32_t i = pThis->cImages;
while (i-- > 1)
{
const char *pszName = pThis->aImages[i].pszName;
uint32_t j = i;
while (j-- > 0)
if (pThis->aImages[j].pszName == pszName)
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_DUPLICATE_DLL_MAPPING,
"Duplicate image entries for %s: %ls and %ls",
pszName, pThis->aImages[i].Name.UniStr.Buffer, pThis->aImages[j].Name.UniStr.Buffer);
}
/*
* Check that both ntdll and kernel32 are present.
* ASSUMES the entries in g_apszSupNtVpAllowedDlls are all lower case.
*/
uint32_t iNtDll = UINT32_MAX;
uint32_t iKernel32 = UINT32_MAX;
i = pThis->cImages;
while (i-- > 0)
if (suplibHardenedStrCmp(pThis->aImages[i].pszName, "ntdll.dll") == 0)
iNtDll = i;
else if (suplibHardenedStrCmp(pThis->aImages[i].pszName, "kernel32.dll") == 0)
iKernel32 = i;
if (iNtDll == UINT32_MAX)
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NO_NTDLL_MAPPING,
"The process has no NTDLL.DLL.");
if (iKernel32 == UINT32_MAX && pThis->enmKind == SUPHARDNTVPKIND_SELF_PURIFICATION)
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NO_KERNEL32_MAPPING,
"The process has no KERNEL32.DLL.");
else if (iKernel32 != UINT32_MAX && pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION)
return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_KERNEL32_ALREADY_MAPPED,
"The process already has KERNEL32.DLL loaded.");
/*
* Verify that the DLLs are correctly signed (by MS).
*/
i = pThis->cImages;
while (i-- > 0)
{
int rc = supHardNtVpVerifyImage(pThis, &pThis->aImages[i], hProcess);
if (RT_FAILURE(rc))
return rc;
}
return VINF_SUCCESS;
}
/**
* Verifies the given process.
*
* The following requirements are checked:
* - The process only has one thread, the calling thread.
* - The process has no debugger attached.
* - The executable image of the process is verified to be signed with
* certificate known to this code at build time.
* - The executable image is one of a predefined set.
* - The process has only a very limited set of system DLLs loaded.
* - The system DLLs signatures check out fine.
* - The only executable memory in the process belongs to the system DLLs and
* the executable image.
*
* @returns VBox status code.
* @param hProcess The process to verify.
* @param hThread A thread in the process (the caller).
* @param enmKind The kind of process verification to perform.
* @param fFlags Valid combination of SUPHARDNTVP_F_XXX flags.
* @param pErrInfo Pointer to error info structure. Optional.
* @param pcFixes Where to return the number of fixes made during
* purification. Optional.
*/
DECLHIDDEN(int) supHardenedWinVerifyProcess(HANDLE hProcess, HANDLE hThread, SUPHARDNTVPKIND enmKind, uint32_t fFlags,
uint32_t *pcFixes, PRTERRINFO pErrInfo)
{
if (pcFixes)
*pcFixes = 0;
/*
* Some basic checks regarding threads and debuggers. We don't need
* allocate any state memory for these.
*/
int rc = VINF_SUCCESS;
if (enmKind != SUPHARDNTVPKIND_CHILD_PURIFICATION)
rc = supHardNtVpThread(hProcess, hThread, pErrInfo);
if (RT_SUCCESS(rc))
rc = supHardNtVpDebugger(hProcess, pErrInfo);
if (RT_SUCCESS(rc))
{
/*
* Allocate and initialize memory for the state.
*/
PSUPHNTVPSTATE pThis = (PSUPHNTVPSTATE)RTMemAllocZ(sizeof(*pThis));
if (pThis)
{
pThis->enmKind = enmKind;
pThis->fFlags = fFlags;
pThis->rcResult = VINF_SUCCESS;
pThis->hProcess = hProcess;
pThis->pErrInfo = pErrInfo;
/*
* Perform the verification.
*/
rc = supHardNtVpScanVirtualMemory(pThis, hProcess);
if (RT_SUCCESS(rc))
rc = supHardNtVpOpenImages(pThis);
if (RT_SUCCESS(rc))
rc = supHardNtVpCheckExe(pThis, hProcess);
if (RT_SUCCESS(rc))
rc = supHardNtVpCheckDlls(pThis, hProcess);
if (pcFixes)
*pcFixes = pThis->cFixes;
/*
* Clean up the state.
*/
#ifdef IN_RING0
for (uint32_t i = 0; i < pThis->cImages; i++)
supHardNTLdrCacheDeleteEntry(&pThis->aImages[i].CacheEntry);
#endif
RTMemFree(pThis);
}
else
rc = supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_NO_MEMORY_STATE,
"Failed to allocate %zu bytes for state structures.", sizeof(*pThis));
}
return rc;
}