SUPHardenedVerifyProcess-win.cpp revision b2560fc359a998cb1002e5de6eba0ef716d48803
/* $Id$ */
/** @file
*/
/*
* Copyright (C) 2006-2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#ifdef IN_RING0
# define IPRT_NT_MAP_TO_ZW
# include <ntimage.h>
#else
#endif
#ifdef IN_RING0
# include "SUPDrvInternal.h"
#else
# include "SUPLibInternal.h"
#endif
#include "win/SUPHardenedVerify-win.h"
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Virtual address space region.
*/
typedef struct SUPHNTVPREGION
{
/** The RVA of the region. */
/** The size of the region. */
/** The protection of the region. */
/** Pointer to a virtual address space region. */
typedef SUPHNTVPREGION *PSUPHNTVPREGION;
/**
* Virtual address space image information.
*/
typedef struct SUPHNTVPIMAGE
{
/** The base address of the image. */
/** The size of the image mapping. */
/** The name from the allowed lists. */
const char *pszName;
/** Name structure for NtQueryVirtualMemory/MemorySectionName. */
struct
{
/** The full unicode name. */
/** Buffer space. */
} Name;
/** The number of mapping regions. */
/** Mapping regions. */
/** The image characteristics from the FileHeader. */
/** The DLL characteristics from the OptionalHeader. */
/** Set if this is the DLL. */
bool fDll;
/** Set if the image is NTDLL an the verficiation code needs to watch out for
* the NtCreateSection patch. */
bool fNtCreateSectionPatch;
/** Whether the API set schema hack needs to be applied when verifying memory
* content. The hack means that we only check if the 1st section is mapped. */
/** This may be a 32-bit resource DLL. */
bool f32bitResourceDll;
/** Pointer to image info from the virtual address space scan. */
typedef SUPHNTVPIMAGE *PSUPHNTVPIMAGE;
/**
* Virtual address space scanning state.
*/
typedef struct SUPHNTVPSTATE
{
/** The result. */
int rcResult;
/** Number of images in aImages. */
/** Images found in the process.
* The array is large enough to hold the executable, all allowed DLLs, and one
* more so we can get the image name of the first unwanted DLL. */
#ifdef VBOX_PERMIT_MORE
+ 5
#endif
+ 16
#endif
];
/** Memory compare scratch buffer.*/
/** File compare scratch buffer.*/
/** Section headers for use when comparing file and loaded image. */
/** Pointer to the error info. */
/** Pointer to stat information of a virtual address space scan. */
typedef SUPHNTVPSTATE *PSUPHNTVPSTATE;
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/**
* System DLLs allowed to be loaded into the process.
* @remarks supHardNtVpCheckDlls assumes these are lower case.
*/
static const char *g_apszSupNtVpAllowedDlls[] =
{
"ntdll.dll",
"kernel32.dll",
"kernelbase.dll",
"apphelp.dll",
"apisetschema.dll",
#ifdef VBOX_PERMIT_MORE
# define VBOX_PERMIT_MORE_FIRST_IDX 5
"sfc.dll",
"sfc_os.dll",
"user32.dll",
"acres.dll",
"acgenral.dll",
#endif
"psapi.dll",
"msvcrt.dll",
"advapi32.dll",
"sechost.dll",
"rpcrt4.dll",
"SamplingRuntime.dll",
#endif
};
/**
* VBox executables allowed to start VMs.
* @remarks Remember to keep in sync with SUPR3HardenedVerify.cpp.
*/
static const char *g_apszSupNtVpAllowedVmExes[] =
{
"VBoxHeadless.exe",
"VirtualBox.exe",
"VBoxSDL.exe",
"VBoxNetDHCP.exe",
"VBoxNetNAT.exe",
"tstMicro.exe",
"tstPDMAsyncCompletion.exe",
"tstPDMAsyncCompletionStress.exe",
"tstVMM.exe",
"tstVMREQ.exe",
"tstCFGM.exe",
"tstIntNet-1.exe",
"tstMMHyperHeap.exe",
"tstR0ThreadPreemptionDriver.exe",
"tstRTR0MemUserKernelDriver.exe",
"tstRTR0SemMutexDriver.exe",
"tstRTR0TimerDriver.exe",
"tstSSM.exe",
};
/** Pointer to NtQueryVirtualMemory. Initialized by SUPDrv-win.cpp in
* ring-0, in ring-3 it's just a slightly confusing define. */
#ifdef IN_RING0
#else
#endif
/**
* Fills in error information.
*
* @returns @a rc.
* @param pErrInfo Pointer to the extended error info structure.
* Can be NULL.
* @param pszErr Where to return error details.
* @param cbErr Size of the buffer @a pszErr points to.
* @param rc The status to return.
* @param pszMsg The format string for the message.
* @param ... The arguments for the format string.
*/
{
#ifdef IN_RING3
#endif
return rc;
}
/**
* Fills in error information.
*
* @returns @a rc.
* @param pThis The process validator instance.
* @param pszErr Where to return error details.
* @param cbErr Size of the buffer @a pszErr points to.
* @param rc The status to return.
* @param pszMsg The format string for the message.
* @param ... The arguments for the format string.
*/
{
#ifdef IN_RING3
#endif
#ifdef IN_RING0
#else
{
}
else
{
}
#endif
}
{
return STATUS_INTEGER_OVERFLOW;
NULL /*hEvent*/,
NULL /*ApcRoutine*/,
NULL /*ApcContext*/,
&Ios,
NULL);
if (NT_SUCCESS(rcNt))
return rcNt;
}
{
#ifdef IN_RING0
/* ASSUMES hProcess is the current process. */
/** @todo use MmCopyVirtualMemory where available! */
if (RT_SUCCESS(rc))
return STATUS_SUCCESS;
return STATUS_ACCESS_DENIED;
#else
return rcNt;
#endif
}
static int supHardNtVpFileMemCompare(PSUPHNTVPSTATE pThis, const void *pvFile, const void *pvMemory, size_t cbToCompare,
{
return VINF_SUCCESS;
/* Find the exact location. */
{
cbToCompare--;
pbFile++;
pbMemory++;
uRva++;
}
}
{
if (!cb)
return VINF_SUCCESS;
{
{
&& ( fProt != PAGE_READWRITE
"%s: RVA range %#x-%#x protection is %#x, expected %#x. (cb=%#x)",
return VINF_SUCCESS;
#if 0 /* This shouldn't ever be necessary. */
{
return VINF_SUCCESS;
}
#endif
}
}
return supHardNtVpSetInfo2(pThis, cbOrg == cb ? VERR_SUP_VP_SECTION_NOT_MAPPED : VERR_SUP_VP_SECTION_NOT_FULLY_MAPPED,
}
/**
* Compares process memory with the disk content.
*
* @returns VBox status code.
* @param pThis The process scanning state structure (for the
* two scratch buffers).
* @param pImage The image data collected during the address
* space scan.
* @param hProcess Handle to the process.
* @param hFile Handle to the image file.
* @param pErrInfo Pointer to error info structure. Optional.
*/
static int supHardNtVpVerifyImageCompareMemory(PSUPHNTVPSTATE pThis, PSUPHNTVPIMAGE pImage, HANDLE hProcess, HANDLE hFile,
{
/*
* Read and find the file headers.
*/
if (!NT_SUCCESS(rcNt))
{
}
/*
* Do basic header validation.
*/
#ifdef RT_ARCH_AMD64
#else
#endif
if (pNtHdrs->FileHeader.SizeOfOptionalHeader != (fIs32Bit ? sizeof(IMAGE_OPTIONAL_HEADER32) : sizeof(IMAGE_OPTIONAL_HEADER64)))
"%s: Unexpected optional header size: %#x",
if (pNtHdrs->OptionalHeader.Magic != (fIs32Bit ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC))
uint32_t cDirs = (fIs32Bit ? pNtHdrs32->OptionalHeader.NumberOfRvaAndSizes : pNtHdrs->OptionalHeader.NumberOfRvaAndSizes);
/*
* Before we start comparing things, store what we need to know from the headers.
*/
suplibHardenedMemCopy(pThis->aSecHdrs, (fIs32Bit ? (void *)(pNtHdrs32 + 1) : (void *)(pNtHdrs + 1)),
cSections * sizeof(IMAGE_SECTION_HEADER));
uintptr_t const uImageBase = fIs32Bit ? pNtHdrs32->OptionalHeader.ImageBase : pNtHdrs->OptionalHeader.ImageBase;
if (uImageBase & PAGE_OFFSET_MASK)
uint32_t const cbImage = fIs32Bit ? pNtHdrs32->OptionalHeader.SizeOfImage : pNtHdrs->OptionalHeader.SizeOfImage;
if (RT_ALIGN_32(pImage->cbImage, PAGE_SIZE) != RT_ALIGN_32(cbImage, PAGE_SIZE) && !pImage->fApiSetSchemaOnlySection1)
"%s: SizeOfImage (%#x) isn't close enough to the mapping size (%#x)",
uint32_t const cbSectAlign = fIs32Bit ? pNtHdrs32->OptionalHeader.SectionAlignment : pNtHdrs->OptionalHeader.SectionAlignment;
if ( !RT_IS_POWER_OF_TWO(cbSectAlign)
|| cbSectAlign < PAGE_SIZE
uint32_t const cbFileAlign = fIs32Bit ? pNtHdrs32->OptionalHeader.FileAlignment : pNtHdrs->OptionalHeader.FileAlignment;
if (!RT_IS_POWER_OF_TWO(cbFileAlign) || cbFileAlign < 512 || cbFileAlign > PAGE_SIZE || cbFileAlign > cbSectAlign)
"%s: Unexpected FileAlignment value: %#x (cbSectAlign=%#x)",
uint32_t const cbHeaders = fIs32Bit ? pNtHdrs32->OptionalHeader.SizeOfHeaders : pNtHdrs->OptionalHeader.SizeOfHeaders;
+ sizeof(IMAGE_SECTION_HEADER) * cSections;
"%s: Headers are too small: %#x < %#x (cSections=%#x)",
"%s: Headers are larger than expected: %#x/%#x (expected max %zx)",
/*
* Compare the file header with the loaded bits. The loader will fiddle
* with image base, changing it to the actual load address.
*/
int rc;
if (!pImage->fApiSetSchemaOnlySection1)
{
if (!NT_SUCCESS(rcNt))
{
if (fIs32Bit)
else
}
rc = supHardNtVpFileMemCompare(pThis, pThis->abFile, pThis->abMemory, cbHeaders, pImage, 0 /*uRva*/);
if (RT_FAILURE(rc))
return rc;
if (RT_FAILURE(rc))
return rc;
}
/*
* Save some header fields we might be using later on.
*/
pImage->fDllCharecteristics = fIs32Bit ? pNtHdrs32->OptionalHeader.DllCharacteristics : pNtHdrs->OptionalHeader.DllCharacteristics;
/*
* Validate sections and check them against the mapping regions.
*/
{
/* Validate the section. */
"%s: Section %u: Invalid virtual address: %#x (uRva=%#x, cbImage=%#x, cbSectAlign=%#x)",
"%s: Section %u: Invalid virtual size: %#x (uSectRva=%#x, uRva=%#x, cbImage=%#x)",
"%s: Section %u: Invalid file size: %#x (cbMap=%#x, uSectRva=%#x)",
/* Validate the protection. */
if (!pImage->fApiSetSchemaOnlySection1 || i == 0)
{
{
}
switch (pThis->aSecHdrs[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE))
{
case IMAGE_SCN_MEM_READ:
break;
break;
break;
case IMAGE_SCN_MEM_EXECUTE:
break;
default:
"%s: Section %u: Unexpected characteristics: %#x (uSectRva=%#x, cbMap=%#x)",
}
rc = supHardNtVpCheckSectionProtection(pThis, pImage, uSectRva, RT_ALIGN_32(cbMap, PAGE_SIZE), fProt);
if (RT_FAILURE(rc))
return rc;
}
/* Advance the RVA. */
}
/*
* Check the mapping regions with the image to make sure someone didn't
* fill executable code into some gap in the image.
*/
/** @todo not vital. */
/*
* Compare executable code. If we're not loaded at the link address, we
* need to load base relocations and apply them while making the compare.
* A special case
*/
/** @todo not vital. */
return VINF_SUCCESS;
}
/**
* Verifies the signature of the given image on disk, then checks if the memory
* mapping matches what we verified.
*
* @returns VBox status code.
* @param pThis The process scanning state structure (for the
* two scratch buffers).
* @param pImage The image data collected during the address
* space scan.
* @param hProcess Handle to the process.
* @param hFile Handle to the image file.
*/
{
/*
* Open the image.
*/
InitializeObjectAttributes(&ObjAttr, &pImage->Name.UniStr, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
#ifdef IN_RING0
#endif
&ObjAttr,
&Ios,
NULL /* Allocation Size*/,
NULL /*EaBuffer*/,
0 /*EaLength*/);
if (NT_SUCCESS(rcNt))
if (!NT_SUCCESS(rcNt))
/*
* Validate the signature, then make an attempt at comparing memory and
* disk content.
*/
if (pImage->f32bitResourceDll)
int rc = supHardenedWinVerifyImageByHandle(hFile, pImage->Name.UniStr.Buffer, fFlags, NULL /*pfCacheable*/, pThis->pErrInfo);
if (RT_SUCCESS(rc))
/*
* Clean up and return.
*/
return rc;
}
/**
* Verifies that there is only one thread in the process.
*
* @returns VBox status code.
* @param hProcess The process.
* @param hThread The thread.
* @param pErrInfo Pointer to error info structure. Optional.
*/
{
/*
* Use the ThreadAmILastThread request to check that there is only one
* thread in the process.
*/
NTSTATUS rcNt = NtQueryInformationThread(hThread, ThreadAmILastThread, &fAmI, sizeof(fAmI), &cbIgn);
if (!NT_SUCCESS(rcNt))
"NtQueryInformationThread/ThreadAmILastThread -> %#x", rcNt);
if (!fAmI)
"More than one thread in process");
/** @todo Would be nice to verify the relation ship between hProcess and hThread
* as well... */
return VINF_SUCCESS;
}
#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
/**
* Verifies that there isn't a debugger attached to the process.
*
* @returns VBox status code.
* @param hProcess The process.
* @param pErrInfo Pointer to error info structure. Optional.
*/
{
/*
* Use the ProcessDebugPort request to check there is no debugger
* currently attached to the process.
*/
if (!NT_SUCCESS(rcNt))
"NtQueryInformationProcess/ProcessDebugPort -> %#x", rcNt);
if (uPtr != 0)
"Debugger attached (%#zx)", uPtr);
return VINF_SUCCESS;
}
#endif /* !VBOX_WITHOUT_DEBUGGER_CHECKS */
/**
* Allocates and initalizes a process stat structure for process virtual memory
* scanning.
*
* @returns Pointer to the state structure on success, NULL on failure.
* @param pErrInfo Pointer to error info structure. Optional.
*/
{
/*
* Allocate the memory.
*/
if (pThis)
{
return pThis;
}
supHardNtVpSetInfo1(pErrInfo, VERR_NO_MEMORY, "Failed to allocate %zu bytes for state structures.", sizeof(*pThis));
return NULL;
}
/**
* 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.
*/
{
return false;
}
/**
* 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.
*/
{
for (;;)
{
{
return false;
}
if (!ch1)
return true;
}
}
/**
* Records an additional memory region for an image.
*
* @returns VBox status code.
* @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.
*/
while ( cwcDirName > 0
{
pwszFilename--;
cwcDirName--;
}
if (!*pwszFilename)
/*
* Drop trailing slashes from the directory name.
*/
while ( cwcDirName > 0
cwcDirName--;
/*
* Match it against known DLLs.
*/
{
/* The directory name must match the one we've got for System32. */
cwcDirName * sizeof(WCHAR)) )
# ifdef VBOX_PERMIT_MORE
|| !supHardViIsAppPatchDir(pImage->Name.UniStr.Buffer, pImage->Name.UniStr.Length / sizeof(WCHAR)) )
# endif
)
"Expected %ls to be loaded from %ls.",
# ifdef VBOX_PERMIT_MORE
# endif
#endif /* VBOX_PERMIT_VISUAL_STUDIO_PROFILING */
break;
}
{
/*
* Not a known DLL, executable?
*/
{
break;
}
}
{
{
"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. "
return pThis->rcResult = VERR_SUP_VP_SYSFER_DLL; /* Try make sure this is what the user sees first! */
}
}
/*
* Since it's a new image, we expect to be at the start of the mapping now.
*/
"Invalid AllocationBase/BaseAddress for %s: %p vs %p.",
/*
*/
/*
* Fill in details from the memory info.
*/
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.
*/
"Base address mismatch for %s: have %p, found %p for region %p LB %#zx.",
/*
* Check for size and rva overflows.
*/
/*
* Record the region.
*/
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.
*/
{
SUP_DPRINTF(("supHardNtVpScanVirtualMemory:\n"));
uint32_t cXpExceptions = 0;
for (uint32_t i = 0; i < 1024; i++)
{
MEMORY_BASIC_INFORMATION MemInfo = { 0, 0, 0, 0, 0, 0, 0 };
(void const *)uPtrWhere,
&MemInfo,
sizeof(MemInfo),
&cbActual);
if (!NT_SUCCESS(rcNt))
{
if (rcNt == STATUS_INVALID_PARAMETER)
}
/*
* Record images.
*/
{
(void const *)uPtrWhere,
&cbActual);
if (!NT_SUCCESS(rcNt))
pThis->aImages[iImg].Name.UniStr.Buffer[pThis->aImages[iImg].Name.UniStr.Length / sizeof(WCHAR)] = '\0';
? " *%p-%p %#06x/%#06x %#09x %ls\n"
: " %p-%p %#06x/%#06x %#09x %ls\n",
/* New or existing image? */
bool fNew = true;
while (iSearch-- > 0)
if (supHardNtVpAreUniStringsEqual(&pThis->aImages[iSearch].Name.UniStr, &pThis->aImages[iImg].Name.UniStr))
{
if (RT_FAILURE(rc))
return rc;
fNew = false;
break;
}
"Unexpected base address match");
if (fNew)
{
if (RT_SUCCESS(rc))
{
"Internal error: aImages is full.\n");
}
#ifdef IN_RING3 /* Continue and add more information if unknown DLLs are found. */
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))
&& cXpExceptions == 0
/* && MemInfo.BaseAddress == pPeb->ReadOnlySharedMemoryBase */
{
}
/*
* Executable memory?
*/
else if (MemInfo.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY))
{
"Found executable memory at %p (%p LB %#zx): type=%#x prot=%#x state=%#x aprot=%#x abase=%p",
# ifdef IN_RING3
/* Continue add more information about the problematic process. */
# else
# endif
}
#endif
else
? " *%p-%p %#06x/%#06x %#09x\n"
: " %p-%p %#06x/%#06x %#09x\n",
/*
* Advance.
*/
"Empty region at %p.", uPtrWhere);
}
"Too many virtual memory regions.\n");
}
/**
* 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.
*/
{
/*
* Make sure there is exactly one executable image.
*/
unsigned cExecs = 0;
unsigned iExe = ~0U;
while (i-- > 0)
{
{
cExecs++;
iExe = i;
}
}
if (cExecs == 0)
"No executable mapping found in the virtual address space.");
if (cExecs != 1)
"Found more than one executable mapping in the virtual address space.");
/*
* Check that it matches the executable image of the process.
*/
int rc;
if (!pUniStr)
"Error allocating %zu bytes for process name.", cbUniStr);
NTSTATUS rcNt = NtQueryInformationProcess(hProcess, ProcessImageFileName, pUniStr, cbUniStr - sizeof(WCHAR), &cbIgn);
if (NT_SUCCESS(rcNt))
{
rc = VINF_SUCCESS;
else
{
"Process image name does not match the exectuable we found: %ls vs %ls.",
}
}
else
"NtQueryInformationProcess/ProcessImageFileName failed: %#x", rcNt);
if (RT_FAILURE(rc))
return rc;
/*
* Validate the signing of the executable image.
* This will load the fDllCharecteristics and fImageCharecteristics members we use below.
*/
if (RT_FAILURE(rc))
return rc;
/*
* Check linking requirements.
*/
rcNt = NtQueryInformationProcess(hProcess, ProcessImageInformation, &ImageInfo, sizeof(ImageInfo), NULL);
if (!NT_SUCCESS(rcNt))
"NtQueryInformationProcess/ProcessImageInformation failed: %#x", rcNt);
"EXE DllCharacteristics=%#x, expected IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY to be set.",
"EXE DllCharacteristics=%#x, expected IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE to be set.",
"EXE DllCharacteristics=%#x, expected IMAGE_DLLCHARACTERISTICS_NX_COMPAT to be set.",
"EXE Info.DllCharacteristics=%#x fDllCharecteristics=%#x.",
"EXE Info.ImageCharacteristics=%#x fImageCharecteristics=%#x.",
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.
*/
{
/*
* Check for duplicate entries.
*/
while (i-- > 1)
{
uint32_t j = i;
while (j-- > 0)
"Duplicate image entries for %s: %ls and %ls",
}
/*
* Check that both ntdll and kernel32 are present.
* ASSUMES the entries in g_apszSupNtVpAllowedDlls are all lower case.
*/
while (i-- > 0)
iNtDll = i;
iKernel32 = i;
iApiSetSchema = i;
#ifdef VBOX_PERMIT_MORE
#endif
if (iNtDll == UINT32_MAX)
"The process has no NTDLL.DLL.");
if (iKernel32 == UINT32_MAX)
"The process has no KERNEL32.DLL.");
/*
* Verify that the DLLs are correctly signed (by MS).
*/
while (i-- > 0)
{
pThis->aImages[i].fApiSetSchemaOnlySection1 = i == iApiSetSchema && pThis->aImages[i].cRegions == 1;
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 pErrInfo Pointer to error info structure. Optional.
*/
{
#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
if (RT_SUCCESS(rc))
#endif
if (RT_SUCCESS(rc))
{
if (pThis)
{
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
}
else
}
return rc;
}