https://git.reactos.org/?p=reactos.git;a=commitdiff;h=60a1006d0f8a0bb658c78…
commit 60a1006d0f8a0bb658c7881e48fc5ee8165a2c0c
Author: Mark Jansen <mark.jansen(a)reactos.org>
AuthorDate: Fri Apr 27 22:43:45 2018 +0200
Commit: Mark Jansen <mark.jansen(a)reactos.org>
CommitDate: Sat May 12 13:35:10 2018 +0200
[LDR] Initial verifier implementation
---
dll/ntdll/CMakeLists.txt | 1 +
dll/ntdll/include/ntdllp.h | 21 ++
dll/ntdll/ldr/ldrapi.c | 2 +-
dll/ntdll/ldr/ldrinit.c | 34 +--
dll/ntdll/ldr/ldrpe.c | 16 +-
dll/ntdll/ldr/verifier.c | 685 +++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 719 insertions(+), 40 deletions(-)
diff --git a/dll/ntdll/CMakeLists.txt b/dll/ntdll/CMakeLists.txt
index aefdaf5c40..e94db5c77a 100644
--- a/dll/ntdll/CMakeLists.txt
+++ b/dll/ntdll/CMakeLists.txt
@@ -19,6 +19,7 @@ list(APPEND SOURCE
ldr/ldrinit.c
ldr/ldrpe.c
ldr/ldrutils.c
+ ldr/verifier.c
rtl/libsupp.c
rtl/uilist.c
rtl/version.c
diff --git a/dll/ntdll/include/ntdllp.h b/dll/ntdll/include/ntdllp.h
index 4d6086730e..29ade67b45 100644
--- a/dll/ntdll/include/ntdllp.h
+++ b/dll/ntdll/include/ntdllp.h
@@ -46,6 +46,7 @@ extern ULONG LdrpActiveUnloadCount;
extern BOOLEAN LdrpShutdownInProgress;
extern UNICODE_STRING LdrpKnownDllPath;
extern PLDR_DATA_TABLE_ENTRY LdrpGetModuleHandleCache, LdrpLoadedDllHandleCache;
+extern BOOLEAN RtlpPageHeapEnabled;
extern ULONG RtlpDphGlobalFlags;
extern BOOLEAN g_ShimsEnabled;
extern PVOID g_pShimEngineModule;
@@ -158,6 +159,26 @@ LdrpLoadShimEngine(IN PWSTR ImageName,
VOID NTAPI
LdrpUnloadShimEngine(VOID);
+/* verifier.c */
+
+NTSTATUS NTAPI
+LdrpInitializeApplicationVerifierPackage(IN HANDLE KeyHandle,
+ IN PPEB Peb,
+ IN BOOLEAN SystemWide,
+ IN BOOLEAN ReadAdvancedOptions);
+
+NTSTATUS NTAPI
+AVrfInitializeVerifier(VOID);
+
+VOID NTAPI
+AVrfDllLoadNotification(IN PLDR_DATA_TABLE_ENTRY LdrEntry);
+
+VOID NTAPI
+AVrfDllUnloadNotification(IN PLDR_DATA_TABLE_ENTRY LdrEntry);
+
+VOID NTAPI
+AVrfPageHeapDllNotification(IN PLDR_DATA_TABLE_ENTRY LdrEntry);
+
/* FIXME: Cleanup this mess */
typedef NTSTATUS (NTAPI *PEPFUNC)(PPEB);
diff --git a/dll/ntdll/ldr/ldrapi.c b/dll/ntdll/ldr/ldrapi.c
index c33b21eff1..2f8cc68340 100644
--- a/dll/ntdll/ldr/ldrapi.c
+++ b/dll/ntdll/ldr/ldrapi.c
@@ -1503,7 +1503,7 @@ LdrUnloadDll(IN PVOID BaseAddress)
/* Notify Application Verifier */
if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAIL_CHECK)
{
- DPRINT1("We don't support Application Verifier yet\n");
+ AVrfDllUnloadNotification(LdrEntry);
}
/* Show message */
diff --git a/dll/ntdll/ldr/ldrinit.c b/dll/ntdll/ldr/ldrinit.c
index a5655eca41..902a797d15 100644
--- a/dll/ntdll/ldr/ldrinit.c
+++ b/dll/ntdll/ldr/ldrinit.c
@@ -82,7 +82,6 @@ ULONG LdrpActiveUnloadCount;
VOID NTAPI RtlpInitializeVectoredExceptionHandling(VOID);
VOID NTAPI RtlpInitDeferedCriticalSection(VOID);
VOID NTAPI RtlInitializeHeapManager(VOID);
-extern BOOLEAN RtlpPageHeapEnabled;
ULONG RtlpDisableHeapLookaside; // TODO: Move to heap.c
ULONG RtlpShutdownProcessFlags; // TODO: Use it
@@ -1311,26 +1310,6 @@ LdrpFreeTls(VOID)
TlsVector);
}
-NTSTATUS
-NTAPI
-LdrpInitializeApplicationVerifierPackage(PUNICODE_STRING ImagePathName, PPEB Peb, BOOLEAN
SystemWide, BOOLEAN ReadAdvancedOptions)
-{
- /* If global flags request DPH, perform some additional actions */
- if (Peb->NtGlobalFlag & FLG_HEAP_PAGE_ALLOCS)
- {
- // TODO: Read advanced DPH flags from the registry if requested
- if (ReadAdvancedOptions)
- {
- UNIMPLEMENTED;
- }
-
- /* Enable page heap */
- RtlpPageHeapEnabled = TRUE;
- }
-
- return STATUS_SUCCESS;
-}
-
NTSTATUS
NTAPI
LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName, PPEB Peb, PHANDLE
OptionsKey)
@@ -1426,7 +1405,7 @@ LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName, PPEB
Peb, PHANDLE
/* Call AVRF if necessary */
if (Peb->NtGlobalFlag & (FLG_APPLICATION_VERIFIER |
FLG_HEAP_PAGE_ALLOCS))
{
- Status = LdrpInitializeApplicationVerifierPackage(ImagePathName, Peb, TRUE,
FALSE);
+ Status = LdrpInitializeApplicationVerifierPackage(KeyHandle, Peb, TRUE,
FALSE);
if (!NT_SUCCESS(Status))
{
DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with
%08X\n", Status);
@@ -1439,7 +1418,7 @@ LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName, PPEB
Peb, PHANDLE
if (Peb->NtGlobalFlag & (FLG_APPLICATION_VERIFIER |
FLG_HEAP_PAGE_ALLOCS))
{
/* Initialize app verifier package */
- Status = LdrpInitializeApplicationVerifierPackage(ImagePathName, Peb, TRUE,
FALSE);
+ Status = LdrpInitializeApplicationVerifierPackage(KeyHandle, Peb, TRUE,
FALSE);
if (!NT_SUCCESS(Status))
{
DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with
%08X\n", Status);
@@ -2057,8 +2036,13 @@ LdrpInitializeProcess(IN PCONTEXT Context,
/* Check if the Application Verifier was enabled */
if (Peb->NtGlobalFlag & FLG_APPLICATION_VERIFIER)
{
- /* FIXME */
- DPRINT1("We don't support Application Verifier yet\n");
+ Status = AVrfInitializeVerifier();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("LDR: AVrfInitializeVerifier failed (ntstatus 0x%x)\n",
Status);
+ return Status;
+ }
+
}
if (IsDotNetImage)
diff --git a/dll/ntdll/ldr/ldrpe.c b/dll/ntdll/ldr/ldrpe.c
index fb217ed686..598e3e5477 100644
--- a/dll/ntdll/ldr/ldrpe.c
+++ b/dll/ntdll/ldr/ldrpe.c
@@ -20,17 +20,6 @@ ULONG LdrpNormalSnap;
/* FUNCTIONS *****************************************************************/
-VOID
-NTAPI
-AVrfPageHeapDllNotification(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
-{
- /* Check if page heap dll notification is turned on */
- if (!(RtlpDphGlobalFlags & DPH_FLAG_DLL_NOTIFY))
- return;
-
- /* We don't support this flag currently */
- UNIMPLEMENTED;
-}
NTSTATUS
NTAPI
@@ -795,10 +784,9 @@ LdrpWalkImportDescriptor(IN LPWSTR DllPath OPTIONAL,
}
/* Check if Application Verifier was enabled */
- if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAIL_CHECK)
+ if (Peb->NtGlobalFlag & FLG_APPLICATION_VERIFIER)
{
- /* FIXME */
- DPRINT1("We don't support Application Verifier yet!\n");
+ AVrfDllLoadNotification(LdrEntry);
}
/* Just to be safe */
diff --git a/dll/ntdll/ldr/verifier.c b/dll/ntdll/ldr/verifier.c
new file mode 100644
index 0000000000..6a44572a19
--- /dev/null
+++ b/dll/ntdll/ldr/verifier.c
@@ -0,0 +1,685 @@
+/*
+ * PROJECT: ReactOS NT User Mode Library
+ * LICENSE: GPL-2.0+ (
https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE: Verifier support routines
+ * COPYRIGHT: Copyright 2011 Aleksey Bragin (aleksey(a)reactos.org)
+ * Copyright 2018 Mark Jansen (mark.jansen(a)reactos.org)
+ */
+
+
+#include <ntdll.h>
+#include <reactos/verifier.h>
+
+#define NDEBUG
+#include <debug.h>
+
+extern PLDR_DATA_TABLE_ENTRY LdrpImageEntry;
+ULONG AVrfpVerifierFlags = 0;
+WCHAR AVrfpVerifierDllsString[256] = { 0 };
+ULONG AVrfpDebug = 0;
+BOOL AVrfpInitialized = FALSE;
+RTL_CRITICAL_SECTION AVrfpVerifierLock;
+LIST_ENTRY AVrfpVerifierProvidersList;
+
+#define VERIFIER_DLL_FLAGS_RESOLVED 1
+
+
+typedef struct _VERIFIER_PROVIDER
+{
+ LIST_ENTRY ListEntry;
+ UNICODE_STRING DllName;
+ PVOID BaseAddress;
+ PVOID EntryPoint;
+
+ // Provider data
+ PRTL_VERIFIER_DLL_DESCRIPTOR ProviderDlls;
+ RTL_VERIFIER_DLL_LOAD_CALLBACK ProviderDllLoadCallback;
+ RTL_VERIFIER_DLL_UNLOAD_CALLBACK ProviderDllUnloadCallback;
+ RTL_VERIFIER_NTDLLHEAPFREE_CALLBACK ProviderNtdllHeapFreeCallback;
+} VERIFIER_PROVIDER, *PVERIFIER_PROVIDER;
+
+
+
+
+VOID
+NTAPI
+AVrfReadIFEO(HANDLE KeyHandle)
+{
+ NTSTATUS Status;
+
+ Status = LdrQueryImageFileKeyOption(KeyHandle,
+ L"VerifierDlls",
+ REG_SZ,
+ AVrfpVerifierDllsString,
+ sizeof(AVrfpVerifierDllsString) - sizeof(WCHAR),
+ NULL);
+
+ if (!NT_SUCCESS(Status))
+ AVrfpVerifierDllsString[0] = UNICODE_NULL;
+
+ Status = LdrQueryImageFileKeyOption(KeyHandle,
+ L"VerifierFlags",
+ REG_DWORD,
+ &AVrfpVerifierFlags,
+ sizeof(AVrfpVerifierFlags),
+ NULL);
+ if (!NT_SUCCESS(Status))
+ AVrfpVerifierFlags = RTL_VRF_FLG_HANDLE_CHECKS | RTL_VRF_FLG_FAST_FILL_HEAP |
RTL_VRF_FLG_LOCK_CHECKS;
+
+ Status = LdrQueryImageFileKeyOption(KeyHandle,
+ L"VerifierDebug",
+ REG_DWORD,
+ &AVrfpDebug,
+ sizeof(AVrfpDebug),
+ NULL);
+ if (!NT_SUCCESS(Status))
+ AVrfpDebug = 0;
+}
+
+
+NTSTATUS
+NTAPI
+LdrpInitializeApplicationVerifierPackage(HANDLE KeyHandle, PPEB Peb, BOOLEAN SystemWide,
BOOLEAN ReadAdvancedOptions)
+{
+ /* If global flags request DPH, perform some additional actions */
+ if (Peb->NtGlobalFlag & FLG_HEAP_PAGE_ALLOCS)
+ {
+ // TODO: Read advanced DPH flags from the registry if requested
+ if (ReadAdvancedOptions)
+ {
+ UNIMPLEMENTED;
+ }
+
+ /* Enable page heap */
+ RtlpPageHeapEnabled = TRUE;
+ }
+
+ AVrfReadIFEO(KeyHandle);
+
+ return STATUS_SUCCESS;
+}
+
+BOOLEAN
+AVrfpIsVerifierProviderDll(PVOID BaseAddress)
+{
+ PLIST_ENTRY Entry;
+ PVERIFIER_PROVIDER Provider;
+
+ for (Entry = AVrfpVerifierProvidersList.Flink; Entry !=
&AVrfpVerifierProvidersList; Entry = Entry->Flink)
+ {
+ Provider = CONTAINING_RECORD(Entry, VERIFIER_PROVIDER, ListEntry);
+
+ if (BaseAddress == Provider->BaseAddress)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+SIZE_T
+AVrfpCountThunks(PIMAGE_THUNK_DATA Thunk)
+{
+ SIZE_T Count = 0;
+ while (Thunk[Count].u1.Function)
+ Count++;
+ return Count;
+}
+
+VOID
+AVrfpSnapDllImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
+{
+ ULONG Size;
+ PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
+ PBYTE DllBase = LdrEntry->DllBase;
+
+ ImportDescriptor = RtlImageDirectoryEntryToData(DllBase, TRUE,
IMAGE_DIRECTORY_ENTRY_IMPORT, &Size);
+ if (!ImportDescriptor)
+ {
+ //SHIMENG_INFO("Skipping module 0x%p \"%wZ\" due to no iat
found\n", LdrEntry->DllBase, &LdrEntry->BaseDllName);
+ return;
+ }
+
+ for (; ImportDescriptor->Name && ImportDescriptor->OriginalFirstThunk;
ImportDescriptor++)
+ {
+ PIMAGE_THUNK_DATA FirstThunk;
+ PVOID UnprotectedPtr = NULL;
+ SIZE_T UnprotectedSize = 0;
+ ULONG OldProtection = 0;
+ FirstThunk = (PIMAGE_THUNK_DATA)(DllBase + ImportDescriptor->FirstThunk);
+
+ /* Walk all imports */
+ for (;FirstThunk->u1.Function; FirstThunk++)
+ {
+ PLIST_ENTRY Entry;
+ PVERIFIER_PROVIDER Provider;
+
+ for (Entry = AVrfpVerifierProvidersList.Flink; Entry !=
&AVrfpVerifierProvidersList; Entry = Entry->Flink)
+ {
+ PRTL_VERIFIER_DLL_DESCRIPTOR DllDescriptor;
+
+ Provider = CONTAINING_RECORD(Entry, VERIFIER_PROVIDER, ListEntry);
+ for (DllDescriptor = Provider->ProviderDlls; DllDescriptor &&
DllDescriptor->DllName; ++DllDescriptor)
+ {
+ PRTL_VERIFIER_THUNK_DESCRIPTOR ThunkDescriptor;
+
+ for (ThunkDescriptor = DllDescriptor->DllThunks; ThunkDescriptor
&& ThunkDescriptor->ThunkName; ++ThunkDescriptor)
+ {
+ /* Just compare function addresses, the loader will have handled
forwarders and ordinals for us */
+ if ((PVOID)FirstThunk->u1.Function !=
ThunkDescriptor->ThunkOldAddress)
+ continue;
+
+ if (!UnprotectedPtr)
+ {
+ PVOID Ptr = &FirstThunk->u1.Function;
+ SIZE_T Size = sizeof(FirstThunk->u1.Function) *
AVrfpCountThunks(FirstThunk);
+ NTSTATUS Status;
+
+ UnprotectedPtr = Ptr;
+ UnprotectedSize = Size;
+
+ Status = NtProtectVirtualMemory(NtCurrentProcess(),
+ &Ptr,
+ &Size,
+ PAGE_EXECUTE_READWRITE,
+ &OldProtection);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint("AVRF: Unable to unprotect IAT to modify
thunks (status %08X).\n", Status);
+ UnprotectedPtr = NULL;
+ continue;
+ }
+ }
+
+ if (ThunkDescriptor->ThunkNewAddress == NULL)
+ {
+ DbgPrint("AVRF: internal error: New thunk for %s is
null.\n", ThunkDescriptor->ThunkName);
+ continue;
+ }
+ FirstThunk->u1.Function =
(SIZE_T)ThunkDescriptor->ThunkNewAddress;
+ if (AVrfpDebug & RTL_VRF_DBG_SHOWSNAPS)
+ DbgPrint("AVRF: Snapped (%wZ: %s) with (%wZ:
%p).\n",
+ &LdrEntry->BaseDllName,
+ ThunkDescriptor->ThunkName,
+ &Provider->DllName,
+ ThunkDescriptor->ThunkNewAddress);
+ }
+ }
+ }
+ }
+
+ if (UnprotectedPtr)
+ {
+ PVOID Ptr = UnprotectedPtr;
+ SIZE_T Size = UnprotectedSize;
+ NTSTATUS Status;
+
+ UnprotectedPtr = Ptr;
+ UnprotectedSize = Size;
+
+ Status = NtProtectVirtualMemory(NtCurrentProcess(),
+ &Ptr,
+ &Size,
+ OldProtection,
+ &OldProtection);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint("AVRF: Unable to reprotect IAT to modify thunks (status
%08X).\n", Status);
+ }
+ }
+ }
+}
+
+
+VOID
+AvrfpResolveThunks(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
+{
+ PLIST_ENTRY Entry;
+ PVERIFIER_PROVIDER Provider;
+
+ if (!AVrfpInitialized)
+ return;
+
+ for (Entry = AVrfpVerifierProvidersList.Flink; Entry !=
&AVrfpVerifierProvidersList; Entry = Entry->Flink)
+ {
+ PRTL_VERIFIER_DLL_DESCRIPTOR DllDescriptor;
+
+ Provider = CONTAINING_RECORD(Entry, VERIFIER_PROVIDER, ListEntry);
+
+ for (DllDescriptor = Provider->ProviderDlls; DllDescriptor &&
DllDescriptor->DllName; ++DllDescriptor)
+ {
+ PRTL_VERIFIER_THUNK_DESCRIPTOR ThunkDescriptor;
+
+ if ((DllDescriptor->DllFlags & VERIFIER_DLL_FLAGS_RESOLVED) ||
+ _wcsicmp(DllDescriptor->DllName, LdrEntry->BaseDllName.Buffer))
+ continue;
+
+ if (AVrfpDebug & RTL_VRF_DBG_SHOWVERIFIEDEXPORTS)
+ DbgPrint("AVRF: pid 0x%X: found dll descriptor for `%wZ' with
verified exports\n",
+ NtCurrentTeb()->ClientId.UniqueProcess,
+ &LdrEntry->BaseDllName);
+
+ for (ThunkDescriptor = DllDescriptor->DllThunks; ThunkDescriptor
&& ThunkDescriptor->ThunkName; ++ThunkDescriptor)
+ {
+ if (!ThunkDescriptor->ThunkOldAddress)
+ {
+ ANSI_STRING ThunkName;
+
+ RtlInitAnsiString(&ThunkName, ThunkDescriptor->ThunkName);
+ /* We cannot call the public api, because that would run init
routines! */
+ if (NT_SUCCESS(LdrpGetProcedureAddress(LdrEntry->DllBase,
&ThunkName, 0, &ThunkDescriptor->ThunkOldAddress, FALSE)))
+ {
+ if (AVrfpDebug & RTL_VRF_DBG_SHOWFOUNDEXPORTS)
+ DbgPrint("AVRF: (%wZ) %Z export found.\n",
&LdrEntry->BaseDllName, &ThunkName);
+ }
+ else
+ {
+ if (AVrfpDebug & RTL_VRF_DBG_SHOWFOUNDEXPORTS)
+ DbgPrint("AVRF: warning: did not find `%Z' export in
%wZ.\n", &ThunkName, &LdrEntry->BaseDllName);
+ }
+ }
+ }
+
+ DllDescriptor->DllFlags |= VERIFIER_DLL_FLAGS_RESOLVED;
+ }
+ }
+
+ AVrfpSnapDllImports(LdrEntry);
+}
+
+
+
+VOID
+NTAPI
+AVrfDllLoadNotification(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
+{
+ PLIST_ENTRY Entry;
+
+ if (!(NtCurrentPeb()->NtGlobalFlag & FLG_APPLICATION_VERIFIER))
+ return;
+
+ RtlEnterCriticalSection(&AVrfpVerifierLock);
+ if (!AVrfpIsVerifierProviderDll(LdrEntry->DllBase))
+ {
+ AvrfpResolveThunks(LdrEntry);
+
+ for (Entry = AVrfpVerifierProvidersList.Flink; Entry !=
&AVrfpVerifierProvidersList; Entry = Entry->Flink)
+ {
+ PVERIFIER_PROVIDER Provider;
+ RTL_VERIFIER_DLL_LOAD_CALLBACK ProviderDllLoadCallback;
+
+ Provider = CONTAINING_RECORD(Entry, VERIFIER_PROVIDER, ListEntry);
+
+ ProviderDllLoadCallback = Provider->ProviderDllLoadCallback;
+ if (ProviderDllLoadCallback)
+ {
+ ProviderDllLoadCallback(LdrEntry->BaseDllName.Buffer,
+ LdrEntry->DllBase,
+ LdrEntry->SizeOfImage,
+ LdrEntry);
+ }
+ }
+ }
+ RtlLeaveCriticalSection(&AVrfpVerifierLock);
+}
+
+VOID
+NTAPI
+AVrfDllUnloadNotification(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
+{
+ PLIST_ENTRY Entry;
+
+ if (!(NtCurrentPeb()->NtGlobalFlag & FLG_APPLICATION_VERIFIER))
+ return;
+
+ RtlEnterCriticalSection(&AVrfpVerifierLock);
+ if (!AVrfpIsVerifierProviderDll(LdrEntry->DllBase))
+ {
+ for (Entry = AVrfpVerifierProvidersList.Flink; Entry !=
&AVrfpVerifierProvidersList; Entry = Entry->Flink)
+ {
+ PVERIFIER_PROVIDER Provider;
+ RTL_VERIFIER_DLL_UNLOAD_CALLBACK ProviderDllUnloadCallback;
+
+ Provider = CONTAINING_RECORD(Entry, VERIFIER_PROVIDER, ListEntry);
+
+ ProviderDllUnloadCallback = Provider->ProviderDllUnloadCallback;
+ if (ProviderDllUnloadCallback)
+ {
+ ProviderDllUnloadCallback(LdrEntry->BaseDllName.Buffer,
+ LdrEntry->DllBase,
+ LdrEntry->SizeOfImage,
+ LdrEntry);
+ }
+ }
+ }
+ RtlLeaveCriticalSection(&AVrfpVerifierLock);
+}
+
+
+VOID
+NTAPI
+AVrfPageHeapDllNotification(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
+{
+ /* Check if page heap dll notification is turned on */
+ if (!(RtlpDphGlobalFlags & DPH_FLAG_DLL_NOTIFY))
+ return;
+
+ /* We don't support this flag currently */
+ UNIMPLEMENTED;
+}
+
+
+VOID
+NTAPI
+AVrfpResnapInitialModules(VOID)
+{
+ PLIST_ENTRY ListHead, ListEntry;
+
+ ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
+ for (ListEntry = ListHead->Flink; ListHead != ListEntry; ListEntry =
ListEntry->Flink)
+ {
+ PLDR_DATA_TABLE_ENTRY LdrEntry;
+
+ LdrEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
+
+ if (AVrfpIsVerifierProviderDll(LdrEntry->DllBase))
+ {
+ if (AVrfpDebug & RTL_VRF_DBG_SHOWSNAPS)
+ DbgPrint("AVRF: skipped resnapping provider %wZ ...\n",
&LdrEntry->BaseDllName);
+ }
+ else
+ {
+ if (AVrfpDebug & RTL_VRF_DBG_SHOWSNAPS)
+ DbgPrint("AVRF: resnapping %wZ ...\n",
&LdrEntry->BaseDllName);
+
+ AvrfpResolveThunks(LdrEntry);
+ }
+ }
+}
+
+PVOID
+NTAPI
+AvrfpFindDuplicateThunk(PLIST_ENTRY EndEntry, PWCHAR DllName, PCHAR ThunkName)
+{
+ PLIST_ENTRY Entry;
+
+ for (Entry = AVrfpVerifierProvidersList.Flink; Entry != EndEntry; Entry =
Entry->Flink)
+ {
+ PVERIFIER_PROVIDER Provider;
+ PRTL_VERIFIER_DLL_DESCRIPTOR DllDescriptor;
+
+ Provider = CONTAINING_RECORD(Entry, VERIFIER_PROVIDER, ListEntry);
+
+ if (AVrfpDebug & RTL_VRF_DBG_SHOWCHAINING_DEBUG)
+ DbgPrint("AVRF: chain: searching in %wZ\n",
&Provider->DllName);
+
+ for (DllDescriptor = Provider->ProviderDlls; DllDescriptor &&
DllDescriptor->DllName; ++DllDescriptor)
+ {
+ PRTL_VERIFIER_THUNK_DESCRIPTOR ThunkDescriptor;
+
+ if (AVrfpDebug & RTL_VRF_DBG_SHOWCHAINING_DEBUG)
+ DbgPrint("AVRF: chain: dll: %ws\n",
DllDescriptor->DllName);
+
+ if (_wcsicmp(DllDescriptor->DllName, DllName))
+ continue;
+
+ for (ThunkDescriptor = DllDescriptor->DllThunks; ThunkDescriptor
&& ThunkDescriptor->ThunkName; ++ThunkDescriptor)
+ {
+ if (AVrfpDebug & RTL_VRF_DBG_SHOWCHAINING_DEBUG)
+ DbgPrint("AVRF: chain: thunk: %s == %s ?\n",
ThunkDescriptor->ThunkName, ThunkName);
+
+ if (!_stricmp(ThunkDescriptor->ThunkName, ThunkName))
+ {
+ if (AVrfpDebug & RTL_VRF_DBG_SHOWCHAINING_DEBUG)
+ DbgPrint("AVRF: Found duplicate for (%ws: %s) in
%wZ\n",
+ DllDescriptor->DllName,
ThunkDescriptor->ThunkName, &Provider->DllName);
+
+ return ThunkDescriptor->ThunkNewAddress;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+
+VOID
+NTAPI
+AVrfpChainDuplicateThunks(VOID)
+{
+ PLIST_ENTRY Entry;
+ PVERIFIER_PROVIDER Provider;
+
+ for (Entry = AVrfpVerifierProvidersList.Flink; Entry !=
&AVrfpVerifierProvidersList; Entry = Entry->Flink)
+ {
+ PRTL_VERIFIER_DLL_DESCRIPTOR DllDescriptor;
+ PRTL_VERIFIER_THUNK_DESCRIPTOR ThunkDescriptor;
+
+ Provider = CONTAINING_RECORD(Entry, VERIFIER_PROVIDER, ListEntry);
+
+ for (DllDescriptor = Provider->ProviderDlls; DllDescriptor &&
DllDescriptor->DllName; ++DllDescriptor)
+ {
+ for (ThunkDescriptor = DllDescriptor->DllThunks; ThunkDescriptor
&& ThunkDescriptor->ThunkName; ++ThunkDescriptor)
+ {
+ PVOID Ptr;
+
+ if (AVrfpDebug & RTL_VRF_DBG_SHOWCHAINING_DEBUG)
+ DbgPrint("AVRF: Checking %wZ for duplicate (%ws: %s)\n",
+ &Provider->DllName, DllDescriptor->DllName,
ThunkDescriptor->ThunkName);
+
+ Ptr = AvrfpFindDuplicateThunk(Entry, DllDescriptor->DllName,
ThunkDescriptor->ThunkName);
+ if (Ptr)
+ {
+ if (AVrfpDebug & RTL_VRF_DBG_SHOWCHAINING)
+ DbgPrint("AVRF: Chaining (%ws: %s) to %wZ\n",
DllDescriptor->DllName, ThunkDescriptor->ThunkName, &Provider->DllName);
+
+ ThunkDescriptor->ThunkOldAddress = Ptr;
+ }
+ }
+ }
+ }
+}
+
+NTSTATUS
+NTAPI
+AVrfpLoadAndInitializeProvider(PVERIFIER_PROVIDER Provider)
+{
+ WCHAR StringBuffer[MAX_PATH + 11];
+ UNICODE_STRING DllPath;
+ PRTL_VERIFIER_PROVIDER_DESCRIPTOR Descriptor;
+ PIMAGE_NT_HEADERS ImageNtHeader;
+ NTSTATUS Status;
+
+ RtlInitEmptyUnicodeString(&DllPath, StringBuffer, sizeof(StringBuffer));
+ RtlAppendUnicodeToString(&DllPath, SharedUserData->NtSystemRoot);
+ RtlAppendUnicodeToString(&DllPath, L"\\System32\\");
+
+ if (AVrfpDebug & RTL_VRF_DBG_SHOWSNAPS)
+ DbgPrint("AVRF: verifier dll `%wZ'\n", &Provider->DllName);
+
+ Status = LdrLoadDll(DllPath.Buffer, NULL, &Provider->DllName,
&Provider->BaseAddress);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint("AVRF: %wZ: failed to load provider `%wZ' (status %08X) from
%wZ\n",
+ &LdrpImageEntry->BaseDllName,
+ &Provider->DllName,
+ Status,
+ &DllPath);
+ return Status;
+ }
+
+ /* Prevent someone funny from specifying his own application as provider */
+ ImageNtHeader = RtlImageNtHeader(Provider->BaseAddress);
+ if (!ImageNtHeader ||
+ !(ImageNtHeader->FileHeader.Characteristics & IMAGE_FILE_DLL))
+ {
+ DbgPrint("AVRF: provider %wZ is not a DLL image\n",
&Provider->DllName);
+ return STATUS_DLL_INIT_FAILED;
+ }
+
+ Provider->EntryPoint = LdrpFetchAddressOfEntryPoint(Provider->BaseAddress);
+ if (!Provider->EntryPoint)
+ {
+ DbgPrint("AVRF: cannot find an entry point for provider %wZ\n",
&Provider->DllName);
+ return STATUS_PROCEDURE_NOT_FOUND;
+ }
+
+ _SEH2_TRY
+ {
+ if (LdrpCallInitRoutine(Provider->EntryPoint,
+ Provider->BaseAddress,
+ DLL_PROCESS_VERIFIER,
+ &Descriptor))
+ {
+ if (Descriptor && Descriptor->Length ==
sizeof(RTL_VERIFIER_PROVIDER_DESCRIPTOR))
+ {
+ /* Copy the data */
+ Provider->ProviderDlls = Descriptor->ProviderDlls;
+ Provider->ProviderDllLoadCallback =
Descriptor->ProviderDllLoadCallback;
+ Provider->ProviderDllUnloadCallback =
Descriptor->ProviderDllUnloadCallback;
+ Provider->ProviderNtdllHeapFreeCallback =
Descriptor->ProviderNtdllHeapFreeCallback;
+
+ /* Update some info for the provider */
+ Descriptor->VerifierImage = LdrpImageEntry->BaseDllName.Buffer;
+ Descriptor->VerifierFlags = AVrfpVerifierFlags;
+ Descriptor->VerifierDebug = AVrfpDebug;
+
+ /* We don't have these yet */
+ DPRINT1("AVRF: RtlpGetStackTraceAddress MISSING\n");
+ DPRINT1("AVRF: RtlpDebugPageHeapCreate MISSING\n");
+ DPRINT1("AVRF: RtlpDebugPageHeapDestroy MISSING\n");
+ Descriptor->RtlpGetStackTraceAddress = NULL;
+ Descriptor->RtlpDebugPageHeapCreate = NULL;
+ Descriptor->RtlpDebugPageHeapDestroy = NULL;
+ Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ DbgPrint("AVRF: provider %wZ passed an invalid descriptor @
%p\n", &Provider->DllName, Descriptor);
+ Status = STATUS_INVALID_PARAMETER_4;
+ }
+ }
+ else
+ {
+ DbgPrint("AVRF: provider %wZ did not initialize correctly\n",
&Provider->DllName);
+ Status = STATUS_DLL_INIT_FAILED;
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ if (!NT_SUCCESS(Status))
+ return Status;
+
+
+ if (AVrfpDebug & RTL_VRF_DBG_LISTPROVIDERS)
+ DbgPrint("AVRF: initialized provider %wZ (descriptor @ %p)\n",
&Provider->DllName, Descriptor);
+
+ /* Done loading providers, allow dll notifications */
+ AVrfpInitialized = TRUE;
+
+ AVrfpChainDuplicateThunks();
+ AVrfpResnapInitialModules();
+
+ /* Manually call with DLL_PROCESS_ATTACH, since the process is not done initializing
*/
+ _SEH2_TRY
+ {
+ if (!LdrpCallInitRoutine(Provider->EntryPoint,
+ Provider->BaseAddress,
+ DLL_PROCESS_ATTACH,
+ NULL))
+ {
+ DbgPrint("AVRF: provider %wZ did not initialize correctly\n",
&Provider->DllName);
+ Status = STATUS_DLL_INIT_FAILED;
+ }
+
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ return Status;
+}
+
+
+NTSTATUS
+NTAPI
+AVrfInitializeVerifier(VOID)
+{
+ NTSTATUS Status;
+ PVERIFIER_PROVIDER Provider;
+ PLIST_ENTRY Entry;
+ WCHAR* Ptr, *Next;
+
+ Status = RtlInitializeCriticalSection(&AVrfpVerifierLock);
+ InitializeListHead(&AVrfpVerifierProvidersList);
+
+ if (!NT_SUCCESS(Status))
+ return Status;
+
+ DbgPrint("AVRF: %wZ: pid 0x%X: flags 0x%X: application verifier
enabled\n",
+ &LdrpImageEntry->BaseDllName,
NtCurrentTeb()->ClientId.UniqueProcess, AVrfpVerifierFlags);
+
+ Provider = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(VERIFIER_PROVIDER));
+ if (!Provider)
+ return STATUS_NO_MEMORY;
+
+ RtlInitUnicodeString(&Provider->DllName, L"verifier.dll");
+ InsertTailList(&AVrfpVerifierProvidersList, &Provider->ListEntry);
+
+ Next = AVrfpVerifierDllsString;
+
+ do
+ {
+ while (*Next == L' ' || *Next == L'\t')
+ Next++;
+
+ Ptr = Next;
+
+ while (*Next != ' ' && *Next != '\t' && *Next)
+ Next++;
+
+ if (*Next)
+ *(Next++) = '\0';
+ else
+ Next = NULL;
+
+ if (*Ptr)
+ {
+ Provider = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(VERIFIER_PROVIDER));
+ if (!Provider)
+ return STATUS_NO_MEMORY;
+ RtlInitUnicodeString(&Provider->DllName, Ptr);
+ InsertTailList(&AVrfpVerifierProvidersList,
&Provider->ListEntry);
+ }
+ } while (Next);
+
+ Entry = AVrfpVerifierProvidersList.Flink;
+ while (Entry != &AVrfpVerifierProvidersList)
+ {
+ Provider = CONTAINING_RECORD(Entry, VERIFIER_PROVIDER, ListEntry);
+ Entry = Entry->Flink;
+
+ Status = AVrfpLoadAndInitializeProvider(Provider);
+ if (!NT_SUCCESS(Status))
+ {
+ RemoveEntryList(&Provider->ListEntry);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, Provider);
+ }
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint("AVRF: %wZ: pid 0x%X: application verifier will be disabled due to
an initialization error.\n",
+ &LdrpImageEntry->BaseDllName,
NtCurrentTeb()->ClientId.UniqueProcess);
+ NtCurrentPeb()->NtGlobalFlag &= ~FLG_APPLICATION_VERIFIER;
+ }
+
+ return Status;
+}
+