http://bugs.winehq.org/show_bug.cgi?id=24081
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |focht@gmx.net Component|-unknown |ntoskrnl Summary|Garena crashes |Garena crashes (ntoskrnl: | |out buf length from driver | |ioctl dispatch used despite | |error condition)
--- Comment #4 from Anastasius Focht focht@gmx.net 2010-08-22 11:24:16 --- Hello,
looks like some anti-cheat software protection. There is a kernel service "GarenaPEngine" dynamically loaded and started:
--- snip --- 0016:Call KERNEL32.CreateProcessW(00000000,00118548 L"C:\windows\system32\winedevice.exe GarenaPEngine",00000000,00000000,00000000,00000000,00000000,00000000,0073e55c,0073e5a0) ret=68340f38 ... 0026:Call KERNEL32.LoadLibraryW(0011a610 L"C:\users\focht\Temp\HDR24d4.tmp") ret=6833c7f9 ... 0026:Ret KERNEL32.LoadLibraryW() retval=00540000 ret=6833c7f9 ... 0026:Call ntdll.RtlInitUnicodeString(0053e72c,005415bc L"\Device\GG_Protector") ret=005407f8 0026:Ret ntdll.RtlInitUnicodeString() retval=00000028 ret=005407f8 ... ntoskrnl.exe.IoCreateDevice(6833e5c0,00000100,0053e72c,00008fc7,00000000,00000000,0053e734) ret=00540823 ... 0026:Call ntoskrnl.exe.MmGetSystemRoutineAddress(0053e710) ret=00540914 ... 0026:Call KERNEL32.GetProcAddress(683a0000,0011d178 "PsGetProcessImageFileName") ret=683bb5b0 0026:Ret KERNEL32.GetProcAddress() retval=683b4294 ret=683bb5b0 ... 0026:Ret ntoskrnl.exe.MmGetSystemRoutineAddress() retval=683b4294 ret=00540914 ... 0026:Call ntoskrnl.exe.PsSetCreateProcessNotifyRoutine(00540614,00000000) ret=00540861 0026:fixme:ntoskrnl:PsSetCreateProcessNotifyRoutine stub: 0x540614 0 0026:Ret ntoskrnl.exe.PsSetCreateProcessNotifyRoutine() retval=00000000 ret=00540861 ... --- snip ---
Client opens the device link and issues initial ioctl (0x8FC7A244):
--- snip --- 0009:Call KERNEL32.CreateFileW(02b14700 L"\\.\GG_PROTECTOR",c0000000,00000000,00000000,00000003,00000004,00000000) ret=02b05af3 0009:Ret KERNEL32.CreateFileW() retval=0000013c ret=02b05af3 ... 0009:Call KERNEL32.DeviceIoControl(0000013c,8fc7a244,02b36c30,00000008,00000000,00000000,00328a14,00000000) ret=02b05c55 0026:Ret KERNEL32.WaitForMultipleObjects() retval=00000001 ret=683baf76 ... 0026:Call driver dispatch 0x540486 (device=0x11d558,irp=0x53e7e0) 0026:Call hal.KeGetCurrentIrql() ret=005404a3 0026:fixme:ntoskrnl:KeGetCurrentIrql stub! 0026:Ret hal.KeGetCurrentIrql() retval=00000000 ret=005404a3 0026:Call ntoskrnl.exe.KeWaitForSingleObject(005437e0,00000000,00000000,00000000,00000000) ret=00540a4f 0026:fixme:ntoskrnl:KeWaitForSingleObject stub: 0x5437e0, 0, 0, 0, (nil) 0026:Ret ntoskrnl.exe.KeWaitForSingleObject() retval=c0000002 ret=00540a4f 0026:trace:ntoskrnl:__regs_IofCompleteRequest 0x53e7e0 0 0026:trace:ntoskrnl:IoCompleteRequest 0x53e7e0 0 0026:Ret driver dispatch 0x540486 (device=0x11d558,irp=0x53e7e0) retval=00000000 0026: get_next_device_request( manager=003c, prev=0000, status=c0000005, prev_data={} ) 0026: get_next_device_request() = PENDING { next=0000, code=00000000, user_ptr=00000000, in_size=0, out_size=0, next_data={} } 0026:Call KERNEL32.WaitForMultipleObjects(00000002,0053e908,00000000,ffffffff) ret=68215f76 0026: select( flags=4, cookie=0053e4fc, signal=0000, prev_apc=0000, timeout=infinite, result={}, handles={0034,003c} ) 0026: select() = PENDING { timeout=infinite, call={APC_NONE}, apc_handle=0000 } 001d:err:ntdll:RtlpWaitForCriticalSection section 0x7bca2604 "../../../wine-git/dlls/ntdll/loader.c: loader_section" wait timed out in thread 001d, blocked by 0009, retrying (60 sec) --- snip ---
After return from driver dispatch, get_next_device_request() should unblock the waiting ioctl request from client. This fails, resulting in another get_next_device_request() round-trip (see the one with status=c0000005), finally getting stuck on STATUS_PENDING. Because the client never returns from device ioctl call (ioctl data not set -> pending request not satisfied), the whole thing hangs.
Took me a while to find out the cause .. this driver stuff isn't easy to debug because the client will continue to go further when the service start is delayed, not issuing device i/o controls (you have to attach fast and set bp into driver entry with some magic O_o).
The server call (the one with status=c0000005) after driver dispatch return is actually the result of an earlier server call failing. I noticed that when doing an strace on the whole thing. Ntdll's send_request() -> wineserver pipe write failed with -EFAULT. Going back I noticed the request header size had an insane value of 1431655765. Converting to hex gives: 0x55555555 ... ring a bell? Sure, its the IRP magic filler value.
--- snip dlls/ntoskrnl.exe/ntoskrnl.c --- static NTSTATUS process_ioctl( DEVICE_OBJECT *device, ULONG code, void *in_buff, ULONG in_size, void *out_buff, ULONG *out_size ) ... *out_size = (irp.IoStatus.u.Status >= 0) ? irp.IoStatus.Information : 0; ... --- snip dlls/ntoskrnl.exe/ntoskrnl.c ---
The driver returns ntstatus 0xc0000002 from its dispatcher (due to stubs). As you see in code snippet this results in unmodified out length field being taken for real (the driver did not touch it). This value is passed further, resulting in failing wine_server_call() finally ending up blocking the client.
With that problem fixed, the client starts up and gives login.
=========
From a quick glance at the driver code: technically this is not really going to
work (if client really depends on functional driver, answering ioctls with proper data). The driver supervises SSDT (watching for ring0 hookers) is something Wine's architecture doesn't support. Additionally it uses several _low_ level functionality to peek deeply into kernel structures (KPROCESS, KTHREAD).
=========
For a short workaround see appdb -> a user posted a script which just kills the service after start:
--- snip --- #!/bin/bash export WINEDEBUG=-all wine Garena.exe &
sleep 5 ret=`ps ax | grep GarenaPEngine` pid=${ret%% *} kill -9 $pid --- snip ---
Regards