http://bugs.winehq.org/show_bug.cgi?id=28001
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|UNCONFIRMED |NEW CC| |focht@gmx.net Component|-unknown |wineserver Summary|World War One Gold demo |ExeCryptor protected |fails to start: 'Clock |apps/games complain with |manipulation detected!' |'Clock manipulation |[Exe Cryptor protection] |detected!' (World War One | |Gold demo, Universal | |Mechanic) Ever Confirmed|0 |1
--- Comment #3 from Anastasius Focht focht@gmx.net 2012-01-25 18:02:06 CST --- Hello,
lots of anti-debugging trickery. It seems the author of the protection really hates Ollydbg ;-)
The protection stores the trial/license data encrypted in registry (location depends on packaged app).
"bad" case = wineserver NOT running, everything gets bootstrapped through app start (services/winemenubuilder).
"good" case = wineserver and services already running, winemenubuilder process(es) exited.
--- snip --- ... 0039:Call TLS callback (proc=0x11b729f,module=0x400000,reason=THREAD_ATTACH,reserved=0) 0039:Ret TLS callback (proc=0x11b729f,module=0x400000,reason=THREAD_ATTACH,reserved=0) 0039:Starting thread proc 0xa0a450 (arg=0x32fc3c) 0039:Call KERNEL32.GetTickCount() ret=009f13a6 0039:Ret KERNEL32.GetTickCount() retval=00001022 ret=009f13a6 0039:Call KERNEL32.GetCurrentProcess() ret=009d50bc 0039:Ret KERNEL32.GetCurrentProcess() retval=ffffffff ret=009d50bc 0039:Call KERNEL32.GetProcessTimes(ffffffff,0032fca0,0032fc98,0032fc98,0032fc98) ret=009d50c2 0039:Ret KERNEL32.GetProcessTimes() retval=00000001 ret=009d50c2 0039:Call TLS callback (proc=0x11b729f,module=0x400000,reason=THREAD_DETACH,reserved=0) 0039:Ret TLS callback (proc=0x11b729f,module=0x400000,reason=THREAD_DETACH,reserved=0) ... 0024:Ret KERNEL32.WaitForSingleObject() retval=00000000 ret=009d8d2b 0024:Call KERNEL32.CloseHandle(00000050) ret=009d8d30 0024:Ret KERNEL32.CloseHandle() retval=00000001 ret=009d8d30 0024:Call KERNEL32.CreateThread(00000000,00000000,00a0a450,0032fc3c,00000000,0032fc38) ret=00df27fe 0024:Ret KERNEL32.CreateThread() retval=00000050 ret=00df27fe 0024:Call KERNEL32.WaitForSingleObject(00000050,ffffffff) ret=009d8d2b ... 003a:Call TLS callback (proc=0x11b729f,module=0x400000,reason=THREAD_ATTACH,reserved=0) 003a:Ret TLS callback (proc=0x11b729f,module=0x400000,reason=THREAD_ATTACH,reserved=0) 003a:Starting thread proc 0xa0a450 (arg=0x32fc3c) 003a:Call KERNEL32.FileTimeToLocalFileTime(0032fc8c,0032fc8c) ret=00df51ac 003a:Ret KERNEL32.FileTimeToLocalFileTime() retval=00000001 ret=00df51ac 003a:Call KERNEL32.FileTimeToDosDateTime(0032fc8c,0032fc76,0032fc74) ret=009d7b4b 003a:Ret KERNEL32.FileTimeToDosDateTime() retval=00000001 ret=009d7b4b 003a:Call TLS callback (proc=0x11b729f,module=0x400000,reason=THREAD_DETACH,reserved=0) 003a:Ret TLS callback (proc=0x11b729f,module=0x400000,reason=THREAD_DETACH,reserved=0) ... 0024:Call advapi32.RegOpenKeyExA(80000001,0032fb90 "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\{0AACAEAC-62E8-F4E5-C80B-4E70445C5704}",00000000,00000001,0032fca0) ret=00a03492 0024:Ret advapi32.RegOpenKeyExA() retval=00000000 ret=00a03492 0024:Call advapi32.RegQueryValueExA(00000050,0032fa90 "iaababkngnelnefogn",00000000,0032fc94,00000000,0032fc98) ret=009c776a 0024:Ret advapi32.RegQueryValueExA() retval=00000000 ret=009c776a 0024:Call advapi32.RegQueryValueExA(00000050,0032fa90 "iaababkngnelnefogn",00000000,0032fc94,0032f548,0032fc98) ret=009e222b 0024:Ret advapi32.RegQueryValueExA() retval=00000000 ret=009e222b ... 0024:Call advapi32.RegCreateKeyExA(80000001,0032fb98 "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\{0AACAEAC-62E8-F4E5-C80B-4E70445C5704}",00000000,00000000,00000000,00000002,00000000,0032fc9c,0032f520) ret=009e981b 0024:Ret advapi32.RegCreateKeyExA() retval=00000000 ret=009e981b 0024:Call advapi32.RegSetValueExA(00000050,0032fa98 "hacpgngcfdkfdnmm",00000000,00000003,0032f950,00000015) ret=009e3e55 0024:Ret advapi32.RegSetValueExA() retval=00000000 ret=009e3e55 --- snip ---
There are lots of threads created which execute short snippets of code (anti-debugging tricks/date/timing checks, etc.) These might not even call any Windows API (through obfuscated thunks).
Most likely the author wanted to prevent easy use of hardware breakpoints (per thread context). If the debugger supports break-on-thread-create event (halt in new thread entry) one can of course circumvent this technique easily (hooking Create(Remote)Thread and bpx on entry address parameter also works).
The culprit actually lies in the GetProcessTimes() API call, executed in one of these thread snippets.
I made a +server trace for both cases which gives better info:
"good" (wineserver prestarted):
--- snip --- ... 0039: init_thread( unix_pid=18227, unix_tid=18250, debug_level=1, teb=7ffd4000, entry=00a0a450, reply_fd=23, wait_fd=25, cpu=x86 ) 0039: init_thread() = 0 { pid=0023, tid=0039, server_start=1ccdbb19a715bb0 (-11.0328730), info_size=0, version=430, all_cpus=00000001 } 0024: select( flags=4, cookie=0032f99c, signal=0000, prev_apc=0000, timeout=infinite, result={}, handles={0050} ) 0024: select() = PENDING { timeout=infinite, call={APC_NONE}, apc_handle=0000 } 0039: get_process_info( handle=ffffffff ) 0039: get_process_info() = 0 { pid=0023, ppid=0000, affinity=0000000f, peb=7ffdf000, start_time=1ccdbb1a0bab52a (-0.4873940), end_time=0, exit_code=259, priority=2, cpu=x86, debugger_present=0 } ... 0039: *killed* exit_code=0 --- snip ---
"bad" (no wineserver prior, full bootstrap with app):
Even in this small snippet I had to filter out interleaving messages from different threads/processes due to parallel start of services/winemenubuilder.
--- snip --- ... 0037:Call KERNEL32.GetProcessTimes(ffffffff,0032fca0,0032fc98,0032fc98,0032fc98) ret=009d50c2 0037: get_process_info( handle=ffffffff ) 0037: get_process_info() = 0 { pid=0008, ppid=0000, affinity=0000000f, peb=7ffdf000, start_time=1ccdbb1f4271956 (-0.8753710), end_time=0, exit_code=259, priority=2, cpu=x86, debugger_present=0 } 0037:Ret KERNEL32.GetProcessTimes() retval=00000001 ret=009d50c2 0037:Call TLS callback (proc=0x11b729f,module=0x400000,reason=THREAD_DETACH,reserved=0) 0037:Ret TLS callback (proc=0x11b729f,module=0x400000,reason=THREAD_DETACH,reserved=0) ... 0037: *killed* exit_code=0 --- snip ---
The culprit is the process' "start_time" field: -0.4873940 vs. -0.8753710 Basically the time between recorded "birth" in wineserver and reaching that code snippet that retrieves the process start time is too long when fully bootstrapping (no wineserver running prior).
For testing purpose I moved the "process->start_time" field initialization (current_time) to "init_process_done" in wineserver (when the process is fully initialized). This helped. Even full bootstrap now displays the registration dialog.
--- snip --- 0037: get_process_info( handle=ffffffff ) 0037: get_process_info() = 0 { pid=0008, ppid=0000, affinity=0000000f, peb=7ffdf000, start_time=1ccdbb9cd1207a6 (-0.3414070), end_time=0, exit_code=259, priority=2, cpu=x86, debugger_present=0 } --- snip ---
-> -0.3414070
Maybe Alexandre can comment if such a change, that is setting "birth" time a bit later in wineserver might be feasible. This is all Wine internal process initialization hence the child doesn't really know what happened during "birth" and how long, before the first code in entry/tls callback is executed.
Otherwise this bug is basically a WONTFIX.
Workaround: start wineserver through other apps prior running the app/game to get a faster startup phase.
$ sha1sum um60.exe 245ee74f099671b25cdf4d50321d51cc63bea4e4 um60.exe
$ wine --version wine-1.3.37-413-g5f42f7d
Regards