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@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();
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=82100
Your paranoid android.
=== debiant (32 bit report) ===
kernel32: loader.c:3964: Test failed: kernel32.dll:0: wrong OptionalHeader.AddressOfEntryPoint 30bf0 / 30bc0 loader.c:3969: Test failed: kernel32.dll:1: wrong OptionalHeader.DataDirectory[i].Size 6f14 / 6ef8 loader.c:3969: Test failed: kernel32.dll:5: wrong OptionalHeader.DataDirectory[i].Size 2594 / 258c loader.c:3968: Test failed: kernel32.dll:12: wrong OptionalHeader.DataDirectory[i].VirtualAddress 4ad88 / 4ad84 loader.c:3969: Test failed: kernel32.dll:12: wrong OptionalHeader.DataDirectory[i].Size d4c / d48 loader.c:3974: Test failed: kernel32.dll: wrong section 0 loader.c:3974: Test failed: kernel32.dll: wrong section 3 loader.c:3974: Test failed: kernel32.dll: wrong section 6 loader.c:3974: Test failed: kernel32.dll: wrong section 8 loader.c:3974: Test failed: kernel32.dll: wrong section 10 loader.c:3974: Test failed: kernel32.dll: wrong section 12
=== debiant (32 bit Chinese:China report) ===
kernel32: loader.c:3964: Test failed: kernel32.dll:0: wrong OptionalHeader.AddressOfEntryPoint 30bf0 / 30bc0 loader.c:3969: Test failed: kernel32.dll:1: wrong OptionalHeader.DataDirectory[i].Size 6f14 / 6ef8 loader.c:3969: Test failed: kernel32.dll:5: wrong OptionalHeader.DataDirectory[i].Size 2594 / 258c loader.c:3968: Test failed: kernel32.dll:12: wrong OptionalHeader.DataDirectory[i].VirtualAddress 4ad88 / 4ad84 loader.c:3969: Test failed: kernel32.dll:12: wrong OptionalHeader.DataDirectory[i].Size d4c / d48 loader.c:3974: Test failed: kernel32.dll: wrong section 0 loader.c:3974: Test failed: kernel32.dll: wrong section 3 loader.c:3974: Test failed: kernel32.dll: wrong section 6 loader.c:3974: Test failed: kernel32.dll: wrong section 8 loader.c:3974: Test failed: kernel32.dll: wrong section 10 loader.c:3974: Test failed: kernel32.dll: wrong section 12
=== debiant (32 bit WoW report) ===
kernel32: loader.c:3964: Test failed: kernel32.dll:0: wrong OptionalHeader.AddressOfEntryPoint 30bf0 / 30bc0 loader.c:3969: Test failed: kernel32.dll:1: wrong OptionalHeader.DataDirectory[i].Size 6f14 / 6ef8 loader.c:3969: Test failed: kernel32.dll:5: wrong OptionalHeader.DataDirectory[i].Size 2594 / 258c loader.c:3968: Test failed: kernel32.dll:12: wrong OptionalHeader.DataDirectory[i].VirtualAddress 4ad88 / 4ad84 loader.c:3969: Test failed: kernel32.dll:12: wrong OptionalHeader.DataDirectory[i].Size d4c / d48 loader.c:3974: Test failed: kernel32.dll: wrong section 0 loader.c:3974: Test failed: kernel32.dll: wrong section 3 loader.c:3974: Test failed: kernel32.dll: wrong section 6 loader.c:3974: Test failed: kernel32.dll: wrong section 8 loader.c:3974: Test failed: kernel32.dll: wrong section 10 loader.c:3974: Test failed: kernel32.dll: wrong section 12
=== debiant (64 bit WoW report) ===
kernel32: change.c:320: Test failed: should be ready change.c:350: Test failed: should be ready loader.c:3964: Test failed: kernel32.dll:0: wrong OptionalHeader.AddressOfEntryPoint 30bf0 / 30bc0 loader.c:3969: Test failed: kernel32.dll:1: wrong OptionalHeader.DataDirectory[i].Size 6f14 / 6ef8 loader.c:3969: Test failed: kernel32.dll:5: wrong OptionalHeader.DataDirectory[i].Size 2594 / 258c loader.c:3968: Test failed: kernel32.dll:12: wrong OptionalHeader.DataDirectory[i].VirtualAddress 4ad88 / 4ad84 loader.c:3969: Test failed: kernel32.dll:12: wrong OptionalHeader.DataDirectory[i].Size d4c / d48 loader.c:3974: Test failed: kernel32.dll: wrong section 0 loader.c:3974: Test failed: kernel32.dll: wrong section 3 loader.c:3974: Test failed: kernel32.dll: wrong section 6 loader.c:3974: Test failed: kernel32.dll: wrong section 8 loader.c:3974: Test failed: kernel32.dll: wrong section 10 loader.c:3974: Test failed: kernel32.dll: wrong section 12