[PATCH] kernel32: Call OutputDebugStringA when invalid heap is destroyed.
Rémi Bernon
rbernon at codeweavers.com
Wed Nov 18 12:23:21 CST 2020
And when PEB->BeingDebugged is set. Lords Of The Fallen anti-debug does
this and only succeeds if an OutputDebugStringA exception is received.
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
dlls/kernel32/heap.c | 5 +++
dlls/kernel32/tests/heap.c | 69 ++++++++++++++++++++++++++++++++++++++
2 files changed, 74 insertions(+)
diff --git a/dlls/kernel32/heap.c b/dlls/kernel32/heap.c
index b7bd6f5f91d..121cf931e43 100644
--- a/dlls/kernel32/heap.c
+++ b/dlls/kernel32/heap.c
@@ -135,6 +135,11 @@ BOOL WINAPI HeapDestroy( HANDLE heap /* [in] Handle of heap */ )
return TRUE;
}
if (!RtlDestroyHeap( heap )) return TRUE;
+ if (NtCurrentTeb()->Peb->BeingDebugged)
+ {
+ OutputDebugStringA( "Attempt to destroy an invalid heap\n" );
+ DbgBreakPoint();
+ }
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c
index fa372b14e21..63d294999d2 100644
--- a/dlls/kernel32/tests/heap.c
+++ b/dlls/kernel32/tests/heap.c
@@ -626,6 +626,74 @@ static void test_HeapCreate(void)
ok(HeapDestroy(heap),"HeapDestroy failed\n");
}
+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_HeapDestroy( 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;
+ PEB *Peb = NtCurrentTeb()->Peb;
+ BOOL ret, debugged;
+
+ AddVectoredExceptionHandler( TRUE, test_heap_destroy_except_handler );
+
+ SetLastError( 0xdeadbeef );
+ test_heap_destroy_dbgstr = FALSE;
+ test_heap_destroy_break = FALSE;
+ debugged = Peb->BeingDebugged;
+ Peb->BeingDebugged = TRUE;
+ ret = HeapDestroy( heap );
+ ok( !ret, "HeapDestroy with invalid heap succeeded\n" );
+ ok( GetLastError() == ERROR_INVALID_HANDLE,
+ "HeapDestroy error %u, expected ERROR_INVALID_HANDLE\n", GetLastError() );
+ 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;
+
+ RemoveVectoredExceptionHandler( test_heap_destroy_except_handler );
+}
static void test_GlobalAlloc(void)
{
@@ -1233,6 +1301,7 @@ START_TEST(heap)
test_heap();
test_obsolete_flags();
test_HeapCreate();
+ test_HeapDestroy();
test_GlobalAlloc();
test_LocalAlloc();
--
2.29.2
More information about the wine-devel
mailing list