[PATCH] ntdll: Raise debug exceptions when invalid heap is destroyed.

Rémi Bernon rbernon at codeweavers.com
Wed Nov 18 14:09:35 CST 2020


And when PEB->BeingDebugged is set to 1. Lords Of The Fallen anti-tamper
does this and only continues if a DBG_PRINTEXCEPTION_C is received.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---

Moved this to ntdll instead as it seems to be happening there as well.

This is also more convenient to check the heap flags, but it then makes
it not possible to call OutputDebugStrA anymore (I suppose?), so raise
a raw DBG_PRINTEXCEPTION_C exception instead.

Supersedes: 196174

 dlls/ntdll/heap.c      | 14 +++++++++
 dlls/ntdll/tests/rtl.c | 66 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 80 insertions(+)

diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c
index 1ac0cb24806..b47ed003ce3 100644
--- a/dlls/ntdll/heap.c
+++ b/dlls/ntdll/heap.c
@@ -1589,6 +1589,20 @@ HANDLE WINAPI RtlDestroyHeap( HANDLE heap )
     void *addr;
 
     TRACE("%p\n", heap );
+    if (!heapPtr && heap && (((HEAP *)heap)->flags & HEAP_VALIDATE_PARAMS) &&
+        NtCurrentTeb()->Peb->BeingDebugged)
+    {
+        EXCEPTION_RECORD record;
+        record.ExceptionCode    = DBG_PRINTEXCEPTION_C;
+        record.ExceptionFlags   = 0;
+        record.ExceptionRecord  = NULL;
+        record.ExceptionAddress = RtlDestroyHeap;
+        record.NumberParameters = 2;
+        record.ExceptionInformation[1] = (ULONG_PTR)"Attempt to destroy an invalid heap\n";
+        record.ExceptionInformation[0] = strlen( (char *)record.ExceptionInformation[1] ) + 1;
+        RtlRaiseException( &record );
+        DbgBreakPoint();
+    }
     if (!heapPtr) return heap;
 
     if (heap == processHeap) return heap; /* cannot delete the main process heap */
diff --git a/dlls/ntdll/tests/rtl.c b/dlls/ntdll/tests/rtl.c
index 7a62670ea05..9f822704d98 100644
--- a/dlls/ntdll/tests/rtl.c
+++ b/dlls/ntdll/tests/rtl.c
@@ -3483,6 +3483,71 @@ static void test_LdrRegisterDllNotification(void)
     pLdrUnregisterDllNotification(cookie);
 }
 
+static BOOL test_heap_destroy_dbgstr = FALSE;
+static BOOL test_heap_destroy_break = FALSE;
+
+static LONG CALLBACK test_heap_destroy_except_handler( EXCEPTION_POINTERS *eptrs )
+{
+    if (eptrs->ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT)
+    {
+#if defined( __i386__ )
+        eptrs->ContextRecord->Eip += 1;
+        test_heap_destroy_break = TRUE;
+        return (LONG)EXCEPTION_CONTINUE_EXECUTION;
+#elif defined( __x86_64__ )
+        eptrs->ContextRecord->Rip += 1;
+        test_heap_destroy_break = TRUE;
+        return (LONG)EXCEPTION_CONTINUE_EXECUTION;
+#endif
+    }
+
+    if (eptrs->ExceptionRecord->ExceptionCode == DBG_PRINTEXCEPTION_C)
+    {
+        test_heap_destroy_dbgstr = TRUE;
+        return (LONG)EXCEPTION_CONTINUE_EXECUTION;
+    }
+
+    return (LONG)EXCEPTION_CONTINUE_SEARCH;
+}
+
+/* partially copied from ntdll/heap.c */
+#define HEAP_VALIDATE_PARAMS 0x40000000
+
+struct heap
+{
+    DWORD_PTR unknown1[2];
+    DWORD     unknown2[2];
+    DWORD_PTR unknown3[4];
+    DWORD     unknown4;
+    DWORD_PTR unknown5[2];
+    DWORD     unknown6[3];
+    DWORD_PTR unknown7[2];
+    DWORD     flags;
+    DWORD     force_flags;
+    DWORD_PTR unknown8[6];
+};
+
+static void test_RtlDestroyHeap(void)
+{
+    const struct heap invalid = {{0, 0}, {0, HEAP_VALIDATE_PARAMS}, {0, 0, 0, 0}, 0, {0, 0}, {0, 0, 0}, {0, 0}, HEAP_VALIDATE_PARAMS, 0, {0}};
+    HANDLE heap = (HANDLE)&invalid, ret;
+    PEB *Peb = NtCurrentTeb()->Peb;
+    BOOL debugged;
+    void *handler = RtlAddVectoredExceptionHandler( TRUE, test_heap_destroy_except_handler );
+
+    test_heap_destroy_dbgstr = FALSE;
+    test_heap_destroy_break = FALSE;
+    debugged = Peb->BeingDebugged;
+    Peb->BeingDebugged = TRUE;
+    ret = RtlDestroyHeap( heap );
+    ok( ret == heap, "RtlDestroyHeap(%p) returned %p\n", heap, ret );
+    ok( test_heap_destroy_dbgstr, "HeapDestroy didn't call OutputDebugStrA\n" );
+    ok( test_heap_destroy_break, "HeapDestroy didn't call DbgBreakPoint\n" );
+    Peb->BeingDebugged = debugged;
+
+    RtlRemoveVectoredExceptionHandler( handler );
+}
+
 START_TEST(rtl)
 {
     InitFunctionPtrs();
@@ -3523,4 +3588,5 @@ START_TEST(rtl)
     test_LdrEnumerateLoadedModules();
     test_RtlMakeSelfRelativeSD();
     test_LdrRegisterDllNotification();
+    test_RtlDestroyHeap();
 }
-- 
2.29.2




More information about the wine-devel mailing list