You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1087 lines
34 KiB
1087 lines
34 KiB
/*++
|
|
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
verifier.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the main entry points for
|
|
the base application verifier provider (verifier.dll).
|
|
|
|
Author:
|
|
|
|
Silviu Calinoiu (SilviuC) 2-Feb-2001
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
//
|
|
// IMPORTANT NOTE.
|
|
//
|
|
// This dll cannot contain non-ntdll dependencies. This way we can run
|
|
// verifier systemwide for any process (including smss and csrss).
|
|
//
|
|
|
|
|
|
#include "pch.h"
|
|
|
|
#include "verifier.h"
|
|
#include "support.h"
|
|
#include "settings.h"
|
|
#include "critsect.h"
|
|
#include "faults.h"
|
|
#include "deadlock.h"
|
|
#include "vspace.h"
|
|
#include "logging.h"
|
|
|
|
//
|
|
// ntdll.dll thunks
|
|
//
|
|
|
|
RTL_VERIFIER_THUNK_DESCRIPTOR AVrfpNtdllThunks [] =
|
|
{
|
|
{"NtAllocateVirtualMemory", NULL, AVrfpNtAllocateVirtualMemory},
|
|
{"NtFreeVirtualMemory", NULL, AVrfpNtFreeVirtualMemory},
|
|
{"NtMapViewOfSection", NULL, AVrfpNtMapViewOfSection},
|
|
{"NtUnmapViewOfSection", NULL, AVrfpNtUnmapViewOfSection},
|
|
{"NtCreateSection", NULL, AVrfpNtCreateSection},
|
|
{"NtOpenSection", NULL, AVrfpNtOpenSection},
|
|
{"NtCreateFile", NULL, AVrfpNtCreateFile},
|
|
{"NtOpenFile", NULL, AVrfpNtOpenFile},
|
|
{"NtCreateKey", NULL, AVrfpNtCreateKey},
|
|
{"NtOpenKey", NULL, AVrfpNtOpenKey},
|
|
{"LdrGetProcedureAddress", NULL, AVrfpLdrGetProcedureAddress},
|
|
|
|
{"RtlTryEnterCriticalSection", NULL, AVrfpRtlTryEnterCriticalSection},
|
|
{"RtlEnterCriticalSection", NULL, AVrfpRtlEnterCriticalSection},
|
|
{"RtlLeaveCriticalSection", NULL, AVrfpRtlLeaveCriticalSection},
|
|
{"RtlInitializeCriticalSection", NULL, AVrfpRtlInitializeCriticalSection},
|
|
{"RtlInitializeCriticalSectionAndSpinCount", NULL, AVrfpRtlInitializeCriticalSectionAndSpinCount},
|
|
{"RtlDeleteCriticalSection", NULL, AVrfpRtlDeleteCriticalSection},
|
|
{"RtlInitializeResource", NULL, AVrfpRtlInitializeResource},
|
|
{"RtlDeleteResource", NULL, AVrfpRtlDeleteResource},
|
|
{"RtlAcquireResourceShared", NULL, AVrfpRtlAcquireResourceShared},
|
|
{"RtlAcquireResourceExclusive", NULL, AVrfpRtlAcquireResourceExclusive},
|
|
{"RtlReleaseResource", NULL, AVrfpRtlReleaseResource},
|
|
{"RtlConvertSharedToExclusive", NULL, AVrfpRtlConvertSharedToExclusive},
|
|
{"RtlConvertExclusiveToShared", NULL, AVrfpRtlConvertExclusiveToShared},
|
|
|
|
{"NtCreateEvent", NULL, AVrfpNtCreateEvent },
|
|
{"NtClose", NULL, AVrfpNtClose},
|
|
|
|
{"RtlAllocateHeap", NULL, AVrfpRtlAllocateHeap },
|
|
{"RtlReAllocateHeap", NULL, AVrfpRtlReAllocateHeap },
|
|
{"RtlFreeHeap", NULL, AVrfpRtlFreeHeap },
|
|
|
|
{"NtReadFile", NULL, AVrfpNtReadFile},
|
|
{"NtReadFileScatter", NULL, AVrfpNtReadFileScatter},
|
|
{"NtWriteFile", NULL, AVrfpNtWriteFile},
|
|
{"NtWriteFileGather", NULL, AVrfpNtWriteFileGather},
|
|
|
|
{"NtWaitForSingleObject", NULL, AVrfpNtWaitForSingleObject},
|
|
{"NtWaitForMultipleObjects", NULL, AVrfpNtWaitForMultipleObjects},
|
|
|
|
{"RtlSetThreadPoolStartFunc", NULL, AVrfpRtlSetThreadPoolStartFunc},
|
|
|
|
{NULL, NULL, NULL}
|
|
};
|
|
|
|
//
|
|
// kernel32.dll thunks
|
|
//
|
|
|
|
RTL_VERIFIER_THUNK_DESCRIPTOR AVrfpKernel32Thunks [] =
|
|
{
|
|
{"HeapCreate", NULL, AVrfpHeapCreate},
|
|
{"HeapDestroy", NULL, AVrfpHeapDestroy},
|
|
{"CloseHandle", NULL, AVrfpCloseHandle},
|
|
{"ExitThread", NULL, AVrfpExitThread},
|
|
{"TerminateThread", NULL, AVrfpTerminateThread},
|
|
{"SuspendThread", NULL, AVrfpSuspendThread},
|
|
{"TlsAlloc", NULL, AVrfpTlsAlloc},
|
|
{"TlsFree", NULL, AVrfpTlsFree},
|
|
{"TlsGetValue", NULL, AVrfpTlsGetValue},
|
|
{"TlsSetValue", NULL, AVrfpTlsSetValue},
|
|
{"CreateThread", NULL, AVrfpCreateThread},
|
|
{"GetProcAddress", NULL, AVrfpGetProcAddress},
|
|
{"WaitForSingleObject", NULL, AVrfpWaitForSingleObject},
|
|
{"WaitForMultipleObjects", NULL, AVrfpWaitForMultipleObjects},
|
|
{"WaitForSingleObjectEx", NULL, AVrfpWaitForSingleObjectEx},
|
|
{"WaitForMultipleObjectsEx", NULL, AVrfpWaitForMultipleObjectsEx},
|
|
{"GlobalAlloc", NULL, AVrfpGlobalAlloc},
|
|
{"GlobalReAlloc", NULL, AVrfpGlobalReAlloc},
|
|
{"LocalAlloc", NULL, AVrfpLocalAlloc},
|
|
{"LocalReAlloc", NULL, AVrfpLocalReAlloc},
|
|
{"CreateFileA", NULL, AVrfpCreateFileA},
|
|
{"CreateFileW", NULL, AVrfpCreateFileW},
|
|
{"FreeLibraryAndExitThread", NULL, AVrfpFreeLibraryAndExitThread},
|
|
{"GetTickCount", NULL, AVrfpGetTickCount},
|
|
{"IsBadReadPtr", NULL, AVrfpIsBadReadPtr},
|
|
{"IsBadHugeReadPtr", NULL, AVrfpIsBadHugeReadPtr},
|
|
{"IsBadWritePtr", NULL, AVrfpIsBadWritePtr},
|
|
{"IsBadHugeWritePtr", NULL, AVrfpIsBadHugeWritePtr},
|
|
{"IsBadCodePtr", NULL, AVrfpIsBadCodePtr},
|
|
{"IsBadStringPtrA", NULL, AVrfpIsBadStringPtrA},
|
|
{"IsBadStringPtrW", NULL, AVrfpIsBadStringPtrW},
|
|
{"ExitProcess", NULL, AVrfpExitProcess},
|
|
{"VirtualFree", NULL, AVrfpVirtualFree},
|
|
{"VirtualFreeEx", NULL, AVrfpVirtualFreeEx},
|
|
|
|
{NULL, NULL, NULL}
|
|
};
|
|
|
|
//
|
|
// advapi32.dll thunks
|
|
//
|
|
|
|
RTL_VERIFIER_THUNK_DESCRIPTOR AVrfpAdvapi32Thunks [] =
|
|
{
|
|
{"RegCreateKeyA", NULL, AVrfpRegCreateKeyA},
|
|
{"RegCreateKeyW", NULL, AVrfpRegCreateKeyW},
|
|
{"RegCreateKeyExA", NULL, AVrfpRegCreateKeyExA},
|
|
{"RegCreateKeyExW", NULL, AVrfpRegCreateKeyExW},
|
|
{"RegOpenKeyA", NULL, AVrfpRegOpenKeyA},
|
|
{"RegOpenKeyW", NULL, AVrfpRegOpenKeyW},
|
|
{"RegOpenKeyExA", NULL, AVrfpRegOpenKeyExA},
|
|
{"RegOpenKeyExW", NULL, AVrfpRegOpenKeyExW},
|
|
|
|
{NULL, NULL, NULL}
|
|
};
|
|
|
|
//
|
|
// msvcrt.dll thunks
|
|
//
|
|
|
|
RTL_VERIFIER_THUNK_DESCRIPTOR AVrfpMsvcrtThunks [] =
|
|
{
|
|
{"malloc", NULL, AVrfp_malloc},
|
|
{"calloc", NULL, AVrfp_calloc},
|
|
{"realloc", NULL, AVrfp_realloc},
|
|
{"free", NULL, AVrfp_free},
|
|
#if defined(_X86_) // compilers for various architectures decorate slightly different
|
|
{"??2@YAPAXI@Z", NULL, AVrfp_new},
|
|
{"??3@YAXPAX@Z", NULL, AVrfp_delete},
|
|
{"??_U@YAPAXI@Z", NULL, AVrfp_newarray},
|
|
{"??_V@YAXPAX@Z", NULL, AVrfp_deletearray},
|
|
#elif defined(_IA64_)
|
|
{"??2@YAPEAX_K@Z", NULL, AVrfp_new},
|
|
{"??3@YAXPEAX@Z", NULL, AVrfp_delete},
|
|
{"??_U@YAPEAX_K@Z", NULL, AVrfp_newarray},
|
|
{"??_V@YAXPEAX@Z", NULL, AVrfp_deletearray},
|
|
#elif defined(_AMD64_)
|
|
{"??2@YAPAX_K@Z", NULL, AVrfp_new},
|
|
{"??3@YAXPAX@Z", NULL, AVrfp_delete},
|
|
{"??_U@YAPAX_K@Z", NULL, AVrfp_newarray},
|
|
{"??_V@YAXPAX@Z", NULL, AVrfp_deletearray},
|
|
#else
|
|
#error Unknown architecture
|
|
#endif
|
|
|
|
{NULL, NULL, NULL}
|
|
};
|
|
|
|
//
|
|
// oleaut32.dll thunks
|
|
//
|
|
|
|
RTL_VERIFIER_THUNK_DESCRIPTOR AVrfpOleaut32Thunks [] =
|
|
{
|
|
{"SysAllocString", NULL, AVrfpSysAllocString},
|
|
{"SysReAllocString", NULL, AVrfpSysReAllocString},
|
|
{"SysAllocStringLen", NULL, AVrfpSysAllocStringLen},
|
|
{"SysReAllocStringLen", NULL, AVrfpSysReAllocStringLen},
|
|
{"SysAllocStringByteLen", NULL, AVrfpSysAllocStringByteLen},
|
|
|
|
{NULL, NULL, NULL}
|
|
};
|
|
|
|
//
|
|
// dll's providing thunks verified.
|
|
//
|
|
|
|
RTL_VERIFIER_DLL_DESCRIPTOR AVrfpExportDlls [] =
|
|
{
|
|
{L"ntdll.dll", 0, NULL, AVrfpNtdllThunks},
|
|
{L"kernel32.dll", 0, NULL, AVrfpKernel32Thunks},
|
|
{L"advapi32.dll", 0, NULL, AVrfpAdvapi32Thunks},
|
|
{L"msvcrt.dll", 0, NULL, AVrfpMsvcrtThunks},
|
|
|
|
//
|
|
// Special care in what new dlls are added here. It is important
|
|
// when running in back compat mode. For instance oleaut32.dll
|
|
// cannot be hooked in WinXP due to a bug in ntdll\verifier.c
|
|
// that has been fixed. Unfortunately when we put the latest verifier
|
|
// on WinXP we need to workaround this.
|
|
//
|
|
|
|
{L"oleaut32.dll", 0, NULL, AVrfpOleaut32Thunks},
|
|
|
|
{NULL, 0, NULL, NULL}
|
|
};
|
|
|
|
|
|
RTL_VERIFIER_PROVIDER_DESCRIPTOR AVrfpProvider =
|
|
{
|
|
sizeof (RTL_VERIFIER_PROVIDER_DESCRIPTOR),
|
|
AVrfpExportDlls,
|
|
AVrfpDllLoadCallback, // callback for DLL load events
|
|
AVrfpDllUnloadCallback, // callback for DLL unload events
|
|
|
|
NULL, // image name (filled by verifier engine)
|
|
0, // verifier flags (filled by verifier engine)
|
|
0, // debug flags (filled by verifier engine)
|
|
|
|
NULL, // RtlpGetStackTraceAddress
|
|
NULL, // RtlpDebugPageHeapCreate
|
|
NULL, // RtlpDebugPageHeapDestroy
|
|
|
|
AVrfpNtdllHeapFreeCallback // callback for HeapFree events inside the ntdll code (e.g. HeapDestroy);
|
|
// the HeapFree calls from the other DLLs are already hooked using AVrfpRtlFreeHeap.
|
|
};
|
|
|
|
//
|
|
// Mark if we have been called with PROCESS_ATTACH once.
|
|
// In some cases the fusion code loads dynamically kernel32.dll and enforces
|
|
// the run of all initialization routines and causes us to get called
|
|
// twice.
|
|
//
|
|
|
|
BOOL AVrfpProcessAttachCalled;
|
|
BOOL AVrfpProcessAttachResult = TRUE;
|
|
|
|
//
|
|
// Global data.
|
|
//
|
|
|
|
const WCHAR AVrfpThreadName[] = L"Thread";
|
|
UNICODE_STRING AVrfpThreadObjectName;
|
|
|
|
//
|
|
// Provider descriptor from WinXP timeframe.
|
|
// Used to make verifier backwards compatible.
|
|
//
|
|
typedef struct _RTL_VERIFIER_PROVIDER_DESCRIPTOR_WINXP {
|
|
|
|
ULONG Length;
|
|
PRTL_VERIFIER_DLL_DESCRIPTOR ProviderDlls;
|
|
RTL_VERIFIER_DLL_LOAD_CALLBACK ProviderDllLoadCallback;
|
|
RTL_VERIFIER_DLL_UNLOAD_CALLBACK ProviderDllUnloadCallback;
|
|
|
|
PWSTR VerifierImage;
|
|
ULONG VerifierFlags;
|
|
ULONG VerifierDebug;
|
|
|
|
//PVOID RtlpGetStackTraceAddress;
|
|
//PVOID RtlpDebugPageHeapCreate;
|
|
//PVOID RtlpDebugPageHeapDestroy;
|
|
|
|
} RTL_VERIFIER_PROVIDER_DESCRIPTOR_WINXP, *PRTL_VERIFIER_PROVIDER_DESCRIPTOR_WINXP;
|
|
|
|
#define WINXP_BUILD_NUMBER 2600
|
|
ULONG AVrfpBuildNumber;
|
|
|
|
PVOID
|
|
AVrfpWinXPFakeGetStackTraceAddress (
|
|
USHORT Index
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(Index);
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// DllMain
|
|
//
|
|
|
|
BOOL
|
|
DllMainWithoutVerifierEnabled (
|
|
DWORD Reason
|
|
);
|
|
|
|
NTSTATUS
|
|
AVrfpRedirectNtdllStopFunction (
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
WINAPI
|
|
DllMain(
|
|
HINSTANCE hInstDll, // handle to the DLL module
|
|
DWORD fdwReason, // reason for calling function
|
|
LPVOID lpvReserved // reserved
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
UNREFERENCED_PARAMETER (hInstDll);
|
|
|
|
//
|
|
// This function will call a light version of DllMain that enables only
|
|
// the stop logic and logging logic for the cases where verifier.dll
|
|
// is dynamically loaded by verifier shims just for that functionality.
|
|
// For such cases the verifier flag will not be set.
|
|
//
|
|
|
|
if ((NtCurrentPeb()->NtGlobalFlag & FLG_APPLICATION_VERIFIER) == 0) {
|
|
return DllMainWithoutVerifierEnabled (fdwReason);
|
|
}
|
|
|
|
//
|
|
// DllMain code when verifier flag is set.
|
|
//
|
|
|
|
switch (fdwReason) {
|
|
|
|
case DLL_PROCESS_VERIFIER:
|
|
|
|
//
|
|
// DllMain gets called with this special reason by the verifier engine.
|
|
// Minimal code should execute here (e.g. passing back the provider
|
|
// descriptor). The rest should be postponed to PROCESS_ATTACH moment.
|
|
//
|
|
|
|
AVrfpBuildNumber = NtCurrentPeb()->OSBuildNumber;
|
|
|
|
if (lpvReserved) {
|
|
|
|
//
|
|
// If we are running on WinXP the latest verifier.dll then we change
|
|
// the length to the old one and we disable hooks for oleaut32. A bug
|
|
// in ntdll\verifier.c prevents this from being hooked correctly. The
|
|
// bug was fixed but we still need to workaround it when running in
|
|
// backcompat mode.
|
|
//
|
|
|
|
if (AVrfpBuildNumber == WINXP_BUILD_NUMBER) {
|
|
|
|
PRTL_VERIFIER_DLL_DESCRIPTOR Descriptor;
|
|
|
|
AVrfpProvider.Length = sizeof (RTL_VERIFIER_PROVIDER_DESCRIPTOR_WINXP);
|
|
|
|
Descriptor = &AVrfpExportDlls[0];
|
|
|
|
while (Descriptor->DllName != NULL) {
|
|
|
|
if (_wcsicmp (Descriptor->DllName, L"oleaut32.dll") == 0) {
|
|
|
|
RtlZeroMemory (Descriptor, sizeof *Descriptor);
|
|
break;
|
|
}
|
|
|
|
Descriptor += 1;
|
|
}
|
|
}
|
|
|
|
*((PRTL_VERIFIER_PROVIDER_DESCRIPTOR *)lpvReserved) = &AVrfpProvider;
|
|
|
|
Status = AVrfpDllInitialize ();
|
|
|
|
if (! NT_SUCCESS (Status)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Create private verifier heap. We need to do it here because in
|
|
// PROCESS_ATTACH it is too late. Verifier will receive a dll load
|
|
// notification for kernel32 before verifier DllMain is called
|
|
// with PROCESS_ATTACH.
|
|
//
|
|
|
|
AVrfpHeap = RtlCreateHeap (HEAP_CLASS_1 | HEAP_GROWABLE,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (AVrfpHeap == NULL) {
|
|
DbgPrint ("AVRF: failed to create verifier heap. \n");
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Initialize verifier stops and logging.
|
|
//
|
|
|
|
Status = AVrfpInitializeVerifierStops();
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint ("AVRF: failed to initialize verifier stop logic (%X). \n", Status);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Create call trackers.
|
|
//
|
|
|
|
Status = AVrfCreateTrackers ();
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint ("AVRF: failed to initialize call trackers (%X). \n", Status);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case DLL_PROCESS_ATTACH:
|
|
|
|
//
|
|
// Execute only minimal code here and avoid too many DLL dependencies.
|
|
//
|
|
|
|
if (! AVrfpProcessAttachCalled) {
|
|
|
|
AVrfpProcessAttachCalled = TRUE;
|
|
|
|
//
|
|
// Pickup private ntdll entrypoints required by verifier.
|
|
//
|
|
|
|
if (AVrfpBuildNumber == WINXP_BUILD_NUMBER) {
|
|
|
|
AVrfpGetStackTraceAddress = AVrfpWinXPFakeGetStackTraceAddress;
|
|
AVrfpRtlpDebugPageHeapCreate = NULL;
|
|
AVrfpRtlpDebugPageHeapDestroy = NULL;
|
|
}
|
|
else {
|
|
|
|
AVrfpGetStackTraceAddress = (PFN_RTLP_GET_STACK_TRACE_ADDRESS)(AVrfpProvider.RtlpGetStackTraceAddress);
|
|
AVrfpRtlpDebugPageHeapCreate = (PFN_RTLP_DEBUG_PAGE_HEAP_CREATE)(AVrfpProvider.RtlpDebugPageHeapCreate);
|
|
AVrfpRtlpDebugPageHeapDestroy = (PFN_RTLP_DEBUG_PAGE_HEAP_DESTROY)(AVrfpProvider.RtlpDebugPageHeapDestroy);
|
|
}
|
|
|
|
//
|
|
// Cache some basic system information for later use.
|
|
//
|
|
|
|
Status = NtQuerySystemInformation (SystemBasicInformation,
|
|
&AVrfpSysBasicInfo,
|
|
sizeof (AVrfpSysBasicInfo),
|
|
NULL);
|
|
|
|
if (! NT_SUCCESS (Status)) {
|
|
|
|
if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_GENERIC) != 0) {
|
|
|
|
DbgPrint ("AVRF: NtQuerySystemInformation (SystemBasicInformation) failed, status %#x\n",
|
|
Status);
|
|
}
|
|
|
|
AVrfpProcessAttachResult = FALSE;
|
|
return AVrfpProcessAttachResult;
|
|
}
|
|
|
|
//
|
|
// For XP client only try to patch old stop function from ntdll
|
|
// so that it jumps unconditionally into the better stop function
|
|
// from verifier.dll.
|
|
//
|
|
|
|
if (AVrfpBuildNumber == WINXP_BUILD_NUMBER) {
|
|
|
|
Status = AVrfpRedirectNtdllStopFunction ();
|
|
|
|
if (! NT_SUCCESS (Status)) {
|
|
|
|
DbgPrint ("AVRF: failed to patch old stop function (%X). \n", Status);
|
|
|
|
AVrfpProcessAttachResult = FALSE;
|
|
return AVrfpProcessAttachResult;
|
|
}
|
|
}
|
|
|
|
RtlInitUnicodeString(&AVrfpThreadObjectName,
|
|
AVrfpThreadName);
|
|
|
|
//
|
|
// Initialize various sub-modules.
|
|
//
|
|
|
|
if (AVrfpProvider.VerifierImage) {
|
|
|
|
try {
|
|
|
|
//
|
|
// Initialize exception checking support (logging etc.).
|
|
//
|
|
|
|
AVrfpInitializeExceptionChecking ();
|
|
|
|
//
|
|
// Reserve a TLS slot for verifier.
|
|
//
|
|
|
|
Status = AVrfpAllocateVerifierTlsSlot ();
|
|
|
|
if (! NT_SUCCESS (Status)) {
|
|
|
|
AVrfpProcessAttachResult = FALSE;
|
|
return AVrfpProcessAttachResult;
|
|
}
|
|
|
|
//
|
|
// Initialize the thread hash table.
|
|
//
|
|
|
|
Status = AVrfpThreadTableInitialize();
|
|
|
|
if (! NT_SUCCESS (Status)) {
|
|
|
|
AVrfpProcessAttachResult = FALSE;
|
|
return AVrfpProcessAttachResult;
|
|
}
|
|
|
|
//
|
|
// Initialize the fault injection support.
|
|
//
|
|
|
|
Status = AVrfpInitializeFaultInjectionSupport ();
|
|
|
|
if (! NT_SUCCESS (Status)) {
|
|
|
|
AVrfpProcessAttachResult = FALSE;
|
|
return AVrfpProcessAttachResult;
|
|
}
|
|
|
|
//
|
|
// Initialize the lock verifier package.
|
|
//
|
|
|
|
Status = CritSectInitialize ();
|
|
|
|
if (! NT_SUCCESS (Status)) {
|
|
|
|
AVrfpProcessAttachResult = FALSE;
|
|
return AVrfpProcessAttachResult;
|
|
}
|
|
|
|
//
|
|
// Initialize deadlock verifier. If anything goes
|
|
// wrong during initialization we clean up and
|
|
// verifier will march forward. Just deadlock verifier
|
|
// will be disabled.
|
|
//
|
|
|
|
if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_DEADLOCK_CHECKS) != 0) {
|
|
|
|
AVrfDeadlockDetectionInitialize ();
|
|
}
|
|
|
|
//
|
|
// Initialize the virtual space tracker.
|
|
//
|
|
|
|
if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_VIRTUAL_SPACE_TRACKING) != 0) {
|
|
|
|
Status = AVrfpVsTrackInitialize ();
|
|
|
|
if (! NT_SUCCESS (Status)) {
|
|
|
|
AVrfpProcessAttachResult = FALSE;
|
|
return AVrfpProcessAttachResult;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Enable logging logic. We do this here separate from the
|
|
// initialization done in PROCESS_VERIFIER for verifier
|
|
// stops because we need to check the verifier flags and
|
|
// verifier image name and these are passed from ntdll.dll to
|
|
// verifier.dll only during PROCESS_ATTACH.
|
|
//
|
|
// Note. If verifier is enabled system wide we do not enable
|
|
// logging. This is a special case for internal users where
|
|
// it is assumed you have a kernel debugger attached and you
|
|
// are ready to deal with failures this way.
|
|
//
|
|
|
|
if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_ENABLED_SYSTEM_WIDE) == 0) {
|
|
|
|
Status = AVrfpInitializeVerifierLogging();
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
//
|
|
// Failure to initialize logging is not fatal. This can happen
|
|
// in out of memory conditions or for early processes like smss.exe.
|
|
//
|
|
|
|
DbgPrint ("AVRF: failed to initialize verifier logging (%X). \n", Status);
|
|
}
|
|
}
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
AVrfpProcessAttachResult = FALSE;
|
|
return AVrfpProcessAttachResult;
|
|
}
|
|
|
|
//
|
|
// Print a successful message.
|
|
//
|
|
|
|
DbgPrint ("AVRF: verifier.dll provider initialized for %ws with flags 0x%X\n",
|
|
AVrfpProvider.VerifierImage,
|
|
AVrfpProvider.VerifierFlags);
|
|
}
|
|
}
|
|
else {
|
|
|
|
//
|
|
// This is the second time our DllMain (DLL_PROCESS_ATTACH) gets called.
|
|
// Return the same result as last time.
|
|
//
|
|
|
|
return AVrfpProcessAttachResult;
|
|
}
|
|
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
|
|
//
|
|
// Cleanup exception checking support.
|
|
//
|
|
|
|
AVrfpCleanupExceptionChecking ();
|
|
|
|
//
|
|
// Uninitialize the locks checking packages.
|
|
//
|
|
|
|
CritSectUninitialize ();
|
|
|
|
break;
|
|
|
|
case DLL_THREAD_ATTACH:
|
|
|
|
AvrfpThreadAttach ();
|
|
|
|
break;
|
|
|
|
case DLL_THREAD_DETACH:
|
|
|
|
AvrfpThreadDetach ();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
DllMainWithoutVerifierEnabled (
|
|
DWORD Reason
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
switch (Reason) {
|
|
|
|
case DLL_PROCESS_ATTACH:
|
|
|
|
//
|
|
// Create private verifier heap. Since we run in a mode where verifier.dll
|
|
// is used only for verifier stops and logging it is ok to create the
|
|
// verifier private heap so late. The heap is used by verifier stops
|
|
// to keep a list of stops that should be skipped.
|
|
//
|
|
|
|
AVrfpHeap = RtlCreateHeap (HEAP_CLASS_1 | HEAP_GROWABLE,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (AVrfpHeap == NULL) {
|
|
DbgPrint ("AVRF: failed to create verifier heap. \n");
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Initialize verifier stops and logging.
|
|
//
|
|
|
|
Status = AVrfpInitializeVerifierStops();
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint ("AVRF: failed to initialize verifier stop logic (%X). \n", Status);
|
|
return FALSE;
|
|
}
|
|
|
|
Status = AVrfpInitializeVerifierLogging();
|
|
|
|
if (! NT_SUCCESS(Status)) {
|
|
DbgPrint ("AVRF: failed to initialize verifier logging (%X). \n", Status);
|
|
return FALSE;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
PRTL_VERIFIER_THUNK_DESCRIPTOR
|
|
AVrfpGetThunkDescriptor (
|
|
PRTL_VERIFIER_THUNK_DESCRIPTOR DllThunks,
|
|
ULONG Index)
|
|
{
|
|
PRTL_VERIFIER_THUNK_DESCRIPTOR Thunk = NULL;
|
|
|
|
Thunk = &(DllThunks[Index]);
|
|
|
|
if (Thunk->ThunkNewAddress == NULL) {
|
|
|
|
DbgPrint ("AVRF: internal error: we do not have a replace for %s !!! \n",
|
|
Thunk->ThunkName);
|
|
DbgBreakPoint ();
|
|
}
|
|
|
|
return Thunk;
|
|
}
|
|
|
|
|
|
//WINBASEAPI
|
|
BOOL
|
|
WINAPI
|
|
AVrfpCloseHandle(
|
|
IN OUT HANDLE hObject
|
|
)
|
|
{
|
|
typedef BOOL (WINAPI * FUNCTION_TYPE) (HANDLE);
|
|
FUNCTION_TYPE Function;
|
|
|
|
Function = AVRFP_GET_ORIGINAL_EXPORT (AVrfpKernel32Thunks,
|
|
AVRF_INDEX_KERNEL32_CLOSEHANDLE);
|
|
|
|
if (hObject == NULL) {
|
|
BUMP_COUNTER(CNT_CLOSE_NULL_HANDLE_CALLS);
|
|
CHECK_BREAK(BRK_CLOSE_NULL_HANDLE);
|
|
}
|
|
else if (hObject == NtCurrentProcess() ||
|
|
hObject == NtCurrentThread()) {
|
|
BUMP_COUNTER(CNT_CLOSE_PSEUDO_HANDLE_CALLS);
|
|
CHECK_BREAK(BRK_CLOSE_PSEUDO_HANDLE);
|
|
}
|
|
|
|
return (* Function)(hObject);
|
|
}
|
|
|
|
|
|
//WINBASEAPI
|
|
FARPROC
|
|
WINAPI
|
|
AVrfpGetProcAddress(
|
|
IN HMODULE hModule,
|
|
IN LPCSTR lpProcName
|
|
)
|
|
{
|
|
typedef FARPROC (WINAPI * FUNCTION_TYPE) (HMODULE, LPCSTR);
|
|
FUNCTION_TYPE Function;
|
|
ULONG DllIndex;
|
|
ULONG ThunkIndex;
|
|
PRTL_VERIFIER_THUNK_DESCRIPTOR Thunks;
|
|
FARPROC ProcAddress;
|
|
|
|
if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_LOADLIBRARY_CALLS) != 0) {
|
|
|
|
DbgPrint ("AVRF: AVrfpGetProcAddress (%p, %s)\n",
|
|
hModule,
|
|
lpProcName);
|
|
}
|
|
|
|
//
|
|
// Call the original GetProcAddress from kernel32.
|
|
//
|
|
|
|
Function = AVRFP_GET_ORIGINAL_EXPORT (AVrfpKernel32Thunks,
|
|
AVRF_INDEX_KERNEL32_GETPROCADDRESS);
|
|
|
|
ProcAddress = (* Function)(hModule, lpProcName);
|
|
|
|
//
|
|
// Check if we want to thunk this export on the fly.
|
|
//
|
|
|
|
if (ProcAddress != NULL) {
|
|
|
|
//
|
|
// Parse all thunked DLLs.
|
|
//
|
|
// N.B.
|
|
//
|
|
// We cannot look only for thunked functions inside
|
|
// the hModule DLL because that can be forwarded to another thunked DLL.
|
|
// (e.g. kernel32!TryEnterCriticalSection is forwarded
|
|
// to ntdll!RtlTryEnterCriticalSection).
|
|
//
|
|
|
|
for (DllIndex = 0; AVrfpExportDlls[DllIndex].DllName != NULL; DllIndex += 1) {
|
|
|
|
//
|
|
// Parse all thunks for this DLL.
|
|
//
|
|
|
|
Thunks = AVrfpExportDlls[ DllIndex ].DllThunks;
|
|
|
|
for (ThunkIndex = 0; Thunks[ ThunkIndex ].ThunkName != NULL; ThunkIndex += 1) {
|
|
|
|
if (Thunks[ ThunkIndex ].ThunkOldAddress == ProcAddress) {
|
|
|
|
ProcAddress = Thunks[ ThunkIndex ].ThunkNewAddress;
|
|
|
|
if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_LOADLIBRARY_THUNKED) != 0) {
|
|
|
|
DbgPrint ("AVRF: AVrfpGetProcAddress (%p, %s) -> thunk address %p\n",
|
|
hModule,
|
|
lpProcName,
|
|
ProcAddress);
|
|
}
|
|
|
|
goto Done;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
Done:
|
|
|
|
return ProcAddress;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
AVrfpLdrGetProcedureAddress(
|
|
IN PVOID DllHandle,
|
|
IN CONST ANSI_STRING* ProcedureName OPTIONAL,
|
|
IN ULONG ProcedureNumber OPTIONAL,
|
|
OUT PVOID *ProcedureAddress
|
|
)
|
|
/*++
|
|
|
|
Routine description:
|
|
|
|
This routine is used to chain APIs hooked by other hook engines.
|
|
If the routine searched is one already hooked by verifier
|
|
then the verifier replacement is returned instead of the
|
|
original export.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG DllIndex;
|
|
ULONG ThunkIndex;
|
|
PRTL_VERIFIER_THUNK_DESCRIPTOR Thunks;
|
|
|
|
Status = LdrGetProcedureAddress (DllHandle,
|
|
ProcedureName,
|
|
ProcedureNumber,
|
|
ProcedureAddress);
|
|
|
|
if (! NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Parse all thunks with hooks for this DLL.
|
|
//
|
|
|
|
for (DllIndex = 0; AVrfpExportDlls[DllIndex].DllName != NULL; DllIndex += 1) {
|
|
|
|
Thunks = AVrfpExportDlls[DllIndex].DllThunks;
|
|
|
|
for (ThunkIndex = 0; Thunks[ThunkIndex].ThunkName != NULL; ThunkIndex += 1) {
|
|
|
|
if (Thunks[ThunkIndex].ThunkOldAddress == *ProcedureAddress) {
|
|
|
|
*ProcedureAddress = Thunks[ThunkIndex].ThunkNewAddress;
|
|
|
|
if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_LOADLIBRARY_THUNKED) != 0) {
|
|
|
|
DbgPrint ("AVRF: AVrfpLdrGetProcedureAddress (%p, %s) -> new address %p\n",
|
|
DllHandle,
|
|
Thunks[ThunkIndex].ThunkName,
|
|
*ProcedureAddress);
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
#define READ_POINTER(Address, Bias) (*((PLONG_PTR)((PBYTE)(LONG_PTR)(Address) + (Bias))))
|
|
|
|
NTSTATUS
|
|
AVrfpRedirectNtdllStopFunction (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine description:
|
|
|
|
This function is called only on XP client to patch RtlApplicationVerifierStop
|
|
so that it jumps unconditionally to the better VerifierStopMessage. For .NET
|
|
server and later this is not an issue but for XP client there is code in ntdll
|
|
(namely page heap) that calls this old function that is not flexible enough.
|
|
The main drawback is that it breaks into debugger no questions asked. The
|
|
newer function is more sophisticated (it logs, skips known stops, etc.).
|
|
Since verifier.dll can be refreshed on an XP client system through the
|
|
verifier package but ntdll.dll remains the one shipped with XP client
|
|
we need this patching solution.
|
|
|
|
The patching works by writing an unconditional jump at the start of
|
|
RtlApplicationVerifieStop to the better function VerifierStopMessage.
|
|
|
|
Parameters:
|
|
|
|
None.
|
|
|
|
Return value:
|
|
|
|
STATUS_SUCCESS or various failure codes.
|
|
|
|
--*/
|
|
{
|
|
#if defined(_X86_)
|
|
|
|
PVOID TargetAddress;
|
|
PVOID ThunkAddress;
|
|
PVOID SourceAddress;
|
|
PVOID ProtectAddress;
|
|
BYTE JumpCode[5];
|
|
LONG_PTR JumpAddress;
|
|
NTSTATUS Status;
|
|
ULONG OldProtection;
|
|
SIZE_T PageSize;
|
|
SIZE_T ProtectSize;
|
|
|
|
//
|
|
// Sanity check. The function should be called only for XP client.
|
|
//
|
|
|
|
if (AVrfpBuildNumber != WINXP_BUILD_NUMBER) {
|
|
|
|
ASSERT (AVrfpBuildNumber == WINXP_BUILD_NUMBER);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
//
|
|
// Prepare the code to be patched. The code layout is explained below.
|
|
//
|
|
// RtlApplicationVerifierStop points to 0xFF 0x25 THUNKADDRESS
|
|
// THUNKADDRESS points NTDLL_ADDRESS
|
|
//
|
|
|
|
|
|
ThunkAddress = (PVOID)READ_POINTER(RtlApplicationVerifierStop, 2); // FF 25 ADDRESS
|
|
SourceAddress = (PVOID)READ_POINTER(ThunkAddress, 0); // ADDRESS
|
|
|
|
TargetAddress = VerifierStopMessage;
|
|
JumpAddress = (LONG_PTR)TargetAddress - (LONG_PTR)SourceAddress - sizeof JumpCode;
|
|
|
|
JumpCode[0] = 0xE9; // unconditional jump X86 opcode
|
|
*((LONG_PTR *)(JumpCode + 1)) = JumpAddress;
|
|
|
|
PageSize = (SIZE_T)(AVrfpSysBasicInfo.PageSize);
|
|
|
|
if (PageSize == 0) {
|
|
|
|
ASSERT (PageSize != 0 && "AVrfpSysBasicInfo not initialized");
|
|
PageSize = 0x1000;
|
|
}
|
|
|
|
//
|
|
// Make R/W the start of the ntdll function to be patched.
|
|
//
|
|
|
|
ProtectAddress = SourceAddress;
|
|
ProtectSize = PageSize;
|
|
|
|
Status = NtProtectVirtualMemory (NtCurrentProcess(),
|
|
&ProtectAddress,
|
|
&ProtectSize,
|
|
PAGE_READWRITE,
|
|
&OldProtection);
|
|
|
|
if (! NT_SUCCESS(Status)) {
|
|
|
|
DbgPrint ("AVRF: failed to make R/W old verifier stop function @ %p (%X) \n",
|
|
SourceAddress,
|
|
Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Write patch code over old function.
|
|
//
|
|
|
|
RtlCopyMemory (SourceAddress, JumpCode, sizeof JumpCode);
|
|
|
|
//
|
|
// Change the protection back.
|
|
//
|
|
|
|
Status = NtProtectVirtualMemory (NtCurrentProcess(),
|
|
&ProtectAddress,
|
|
&ProtectSize,
|
|
OldProtection,
|
|
&OldProtection);
|
|
|
|
if (! NT_SUCCESS(Status)) {
|
|
|
|
DbgPrint ("AVRF: failed to revert protection of old verifier stop function @ %p (%X) \n",
|
|
SourceAddress,
|
|
Status);
|
|
|
|
//
|
|
// At this point we managed to patch the code so we will not fail the function
|
|
// since this will actually fail process startup.
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
return Status;
|
|
|
|
#else
|
|
|
|
//
|
|
// Just x86 for now. For other architectures the operation will be considered
|
|
// successful. The side-effect of not patching is that some verification code
|
|
// from ntdll will cause debugger breaks. So basically the verified process
|
|
// needs to be run under debugger for meaningful results.
|
|
//
|
|
// The only other architecture shipped for XP client is IA64 so eventually we
|
|
// will need to write code for that too.
|
|
//
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
#endif // #if defined(_X86_)
|
|
}
|