[Bug 60514] New: ntdll: IL-only (.NET Framework) exe crashes when debugger injects thread into suspended process before main thread runs
http://bugs.winehq.org/show_bug.cgi?id=60514 Bug ID: 60514 Summary: ntdll: IL-only (.NET Framework) exe crashes when debugger injects thread into suspended process before main thread runs Product: Wine Version: 11.18 Hardware: x86-64 OS: MacOS Status: UNCONFIRMED Severity: normal Priority: P2 Component: ntdll Assignee: wine-bugs@list.winehq.org Reporter: promonteiro89@icloud.com Target Milestone: --- Summary: loader_init() (dlls/ntdll/loader.c) handles an IL-only main module with: status = fixup_imports_ilonly( wm, NULL, entry ); which overwrites the start address (context->Rcx on x86_64) of whichever thread is the first thread to run loader_init with mscoree's _CorExeMain. That is only correct if the first thread is the main thread. If a debugger creates the process suspended and injects a thread before the main thread is resumed, that injected thread is the first to initialize the process and gets redirected to _CorExeMain. The real main thread later takes the else (thread attach) path and starts at the image's original entry point. For a 32-bit IL-only image (the usual AnyCPU .NET Framework console app) that entry is the PE32 stub "jmp dword ptr [abs32 IAT]". In a 64-bit process the slot holds garbage, so the thread jumps to a random non-canonical address and the process dies with 0xc0000005 (EXCEPTION_ACCESS_VIOLATION). How it was observed: Debugging a .NET Framework 4.8 AnyCPU console app (FxDemo.exe, PE32, ILONLY, entry stub at RVA 0x2712, image base 0x400000) under a debugger (tested with Visual Studio / vsdebugeng). The same program runs fine standalone, because there the main thread initializes the process first. - Under the debugger the main thread started at the unmodified entry point ("Starting thread proc 0000000000402712 (arg=000000010002D000)" in a +relay trace) and then faulted immediately: rip was a random 64-bit garbage value that changed on every run, the registers were still the initial thread context, and the exception was EXCEPTION_ACCESS_VIOLATION, info[0] = 8 (execute). - A different thread of the same process had initialized the process first (its PROCESS_ATTACH for mscoree.dll carried the process-init context) and was started at _CorExeMain with thread parameter 0. By inference, this was a thread injected from the debugger side whose original start address was not the exe entry point. - The debuggee had been created with CREATE_SUSPENDED. Root cause: The redirect to _CorExeMain is applied per "first thread to run loader_init" instead of per "thread that starts at the executable's entry point". Note on implementation pitfall: Do not compare against OptionalHeader.AddressOfEntryPoint directly. For IL-only PE32 images convert_to_pe64() zeroes it in the in-memory header, so the original entry point needs to come from ProcessImageInformation (SECTION_IMAGE_INFORMATION.TransferAddress). Suggested approach: - Record _CorExeMain and the original entry point (from SECTION_IMAGE_INFORMATION.TransferAddress); - Redirect a thread only if its start address equals the original entry point, in both the first-initializer path and the thread-attach path; - Clear the stored redirect once used. -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
participants (1)
-
WineHQ Bugzilla