https://git.reactos.org/?p=reactos.git;a=commitdiff;h=60a1006d0f8a0bb658c7881e48fc5ee8165a2c0c

commit 60a1006d0f8a0bb658c7881e48fc5ee8165a2c0c
Author:     Mark Jansen <[email protected]>
AuthorDate: Fri Apr 27 22:43:45 2018 +0200
Commit:     Mark Jansen <[email protected]>
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 ([email protected])
+ *              Copyright 2018 Mark Jansen ([email protected])
+ */
+
+
+#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;
+}
+

Reply via email to