http://bugs.winehq.org/show_bug.cgi?id=11344
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Keywords| |obfuscation Status|NEW |RESOLVED URL| |http://client.cdn.gamigo.co | |m/lc/de/LastChaos_DE_Setup. | |exe CC| |focht@gmx.net Resolution|--- |WONTFIX Summary|XTrap crashes |All XTrap (Online Game | |Security Solution) bundled | |games crash on startup | |(Windows 'sysenter' | |trampoline/setup has | |incompatible semantics on | |Linux)
--- Comment #34 from Anastasius Focht focht@gmx.net --- Hello folks,
I had a look at this, confirming.
There are various MMORPGs bundled with this online game protection scheme.
'AIKA online' -> http://aika.t3fun.com/Download/Client.aspx
--- snip --- -=[ ProtectionID v0.6.5.5 OCTOBER]=- (c) 2003-2013 CDKiLLER & TippeX Build 31/10/13-21:09:09 Ready... Scanning -> C:\T3fun\AikaOnline\AIKAEN.exe File Type : 32-Bit Exe (Subsystem : Win GUI / 2), Size : 2117632 (0205000h) Byte(s) [File Heuristics] -> Flag : 00000000000000001100000000110011 (0x0000C033) [Entrypoint Section Entropy] : 0.56 [!] Themida v2.0.1.0 - v2.1.8.0 (or newer) detected ! [i] Hide PE Scanner Option used - Scan Took : 0.348 Second(s) [00000015Ch tick(s)] [533 scan(s) done]
Scanning -> C:\T3fun\AikaOnline\AIKALauncher.exe File Type : 32-Bit Exe (Subsystem : Win GUI / 2), Size : 2609152 (027D000h) Byte(s) [File Heuristics] -> Flag : 00000000000000000000000000000000 (0x00000000) [Entrypoint Section Entropy] : 6.68 [!] X-Trap Online Game Security Solution references detected ! [CompilerDetect] -> Visual C++ 6.0 - Scan Took : 0.445 Second(s) [0000001BDh tick(s)] [533 scan(s) done] --- snip ---
'ElsWord Online' -> http://myaccount.elswordonline.com/Elsword/Download
--- snip --- -=[ ProtectionID v0.6.5.5 OCTOBER]=- (c) 2003-2013 CDKiLLER & TippeX Build 31/10/13-21:09:09 Ready... Scanning -> C:\Program Files\Kill3rCombo\Elsword\elsword.exe File Type : 32-Bit Exe (Subsystem : Win GUI / 2), Size : 2809240 (02ADD98h) Byte(s) -> File Appears to be Digitally Signed @ Offset 02ACA00h, size : 01398h / 05016 byte(s) [File Heuristics] -> Flag : 00000000000001001101000000000100 (0x0004D004) [Entrypoint Section Entropy] : 6.58 [!] X-Trap Online Game Security Solution references detected ! [!] Possible CD/DVD-Key or Serial Check -> Unregistered [CompilerDetect] -> Visual C++ 10.0 (Visual Studio 2010) - Scan Took : 0.450 Second(s) [0000001C2h tick(s)] [533 scan(s) done]
Scanning -> C:\Program Files\Kill3rCombo\Elsword\data\x2.exe File Type : 32-Bit Exe (Subsystem : Win GUI / 2), Size : 6748056 (066F798h) Byte(s) -> File Appears to be Digitally Signed @ Offset 066E400h, size : 01398h / 05016 byte(s) [File Heuristics] -> Flag : 00000000000001001100000000110111 (0x0004C037) [Entrypoint Section Entropy] : 7.26 [!] Themida v2.0.1.0 - v2.1.8.0 (or newer) detected ! [i] Hide PE Scanner Option used - Scan Took : 0.558 Second(s) [00000022Eh tick(s)] [533 scan(s) done] --- snip ---
'Knight Online World Client v2.025' -> http://us3cdn.ausgamers.com/downloads/1404038335/KnightOnlineSetup_v2025.exe
--- snip --- -=[ ProtectionID v0.6.5.5 OCTOBER]=- (c) 2003-2013 CDKiLLER & TippeX Build 31/10/13-21:09:09 Ready... Scanning -> C:\NTTGame\KnightOnlineEn\KnightOnLine.exe File Type : 32-Bit Exe (Subsystem : Win GUI / 2), Size : 4493752 (04491B8h) Byte(s) -> File Appears to be Digitally Signed @ Offset 0447000h, size : 021B8h / 08632 byte(s) [File Heuristics] -> Flag : 00000000000000001100000000110111 (0x0000C037) [Entrypoint Section Entropy] : 7.88 [!] Themida v2.0.1.0 - v2.1.8.0 (or newer) detected ! [i] Hide PE Scanner Option used - Scan Took : 0.435 Second(s) [0000001B3h tick(s)] [533 scan(s) done]
Scanning -> C:\NTTGame\KnightOnlineEn\Launcher.exe File Type : 32-Bit Exe (Subsystem : Win GUI / 2), Size : 2232320 (0221000h) Byte(s) [File Heuristics] -> Flag : 00000000000000001000000000000000 (0x00008000) [Entrypoint Section Entropy] : 6.66 [CompilerDetect] -> Visual C++ 8.0 (Visual Studio 2005) [!] File appears to have no protection or is using an unknown protection - Scan Took : 0.379 Second(s) [00000017Bh tick(s)] [533 scan(s) done] --- snip ---
'Last Chaos' -> http://client.cdn.gamigo.com/lc/de/LastChaos_DE_Setup.exe
--- snip --- -=[ ProtectionID v0.6.5.5 OCTOBER]=- (c) 2003-2013 CDKiLLER & TippeX Build 31/10/13-21:09:09 Ready... Scanning -> C:\GAMIGO\LastChaosGER\LC.exe File Type : 32-Bit Exe (Subsystem : Win GUI / 2), Size : 4117504 (03ED400h) Byte(s) [File Heuristics] -> Flag : 00000000000001001101001000000011 (0x0004D203) [Entrypoint Section Entropy] : 7.91 [!] VM Protect v1.60 - v2.05 detected ! - Scan Took : 0.527 Second(s) [00000020Fh tick(s)] [533 scan(s) done]
Scanning -> C:\GAMIGO\LastChaosGER\Bin\Nksp.exe File Type : 32-Bit Exe (Subsystem : Win GUI / 2), Size : 706048 (0AC600h) Byte(s) [File Heuristics] -> Flag : 00000000000001001100001100000011 (0x0004C303) [Entrypoint Section Entropy] : 7.93 [!] VM Protect v1.60 - v2.05 detected ! [CompilerDetect] -> Visual C++ 10.0 (Visual Studio 2010) - Scan Took : 0.329 Second(s) [000000149h tick(s)] [533 scan(s) done] --- snip ---
The analysis of those is difficult because all XTrap enabled games are additionally wrapped with intrusive protection schemes, that actively prevent debugging/reverse engineering.
Continuous scan of windows, processes, module lists, watchers for remote thread creation/dll injection and many more trickery is employed to thwart attempts to debug/attach debuggers to processes.
Additionally, "default" relay tracing and snooping is not possible due to the way the DRM schemes work. One has to carefully craft "custom" relay modules/function exclusion list.
I chose 'Last Chaos' as target, the information can be applied to other games too.
--- snip --- $ pwd /home/focht/wine-games/wineprefix-lc-xtrap/wineprefix/drive_c/GAMIGO/LastChaosGER
$ wine ./Bin/Nksp.exe ... 0023:Call KERNEL32.LoadLibraryA(0033ec54 "C:\GAMIGO\LastChaosGER\Bin\Xtrap\XTrapVa.dll") ret=004136c0 ... 0023:Ret PE DLL (proc=0x40c10044,module=0x40400000 L"XTrapVa.dll",reason=PROCESS_ATTACH,res=(nil)) retval=1 0023:Ret KERNEL32.LoadLibraryA() retval=40400000 ret=004136c0 ... 0023:Call KERNEL32.CreateEventA(00000000,00000000,00000000,00000000) ret=4044f01c 0023:Ret KERNEL32.CreateEventA() retval=00000148 ret=4044f01c 0023:Call KERNEL32.CreateThread(00000000,00000000,40413c00,406f1990,00000000,0033e240) ret=4044f066 0023:Ret KERNEL32.CreateThread() retval=00000158 ret=4044f066 0023:Call KERNEL32.GetThreadTimes(00000158,0033e244,0033e264,0033e25c,0033e254) ret=4044560f ... 002c:Starting thread proc 0x40413c00 (arg=0x406f1990) 002c:Call KERNEL32.GetTickCount() ret=40450257 002c:Ret KERNEL32.GetTickCount() retval=00c9add3 ret=40450257 002c:Call KERNEL32.GetTickCount() ret=4044d47c 002c:Ret KERNEL32.GetTickCount() retval=00c9add3 ret=4044d47c 002c:Call KERNEL32.WaitForSingleObjectEx(00000148,00002ee0,00000000) ret=404504f4 0023:fixme:thread:NtQueryInformationThread Cannot get kerneltime or usertime of other threads 0023:Ret KERNEL32.GetThreadTimes() retval=00000001 ret=4044560f 0023:Call KERNEL32.GetTickCount() ret=0033de5c 0023:Ret KERNEL32.GetTickCount() retval=00c9add4 ret=0033de5c 0023:trace:seh:raise_exception code=c0000005 flags=0 addr=0x33de5c ip=0033de5c tid=0023 0023:trace:seh:raise_exception info[0]=00000001 0023:trace:seh:raise_exception info[1]=00c9add4 0023:trace:seh:raise_exception eax=00c9add4 ebx=00000009 ecx=ffffffff edx=00000000 esi=406dd0f0 edi=406dd0fc 0023:trace:seh:raise_exception ebp=40673008 esp=0033de28 cs=0023 ds=002b es=002b fs=0063 gs=006b flags=00010206 0023:trace:seh:call_stack_handlers calling handler at 0x42644b code=c0000005 flags=0 0023:trace:seh:call_stack_handlers handler at 0x42644b returned 1 0023:trace:seh:call_stack_handlers calling handler at 0x40e194 code=c0000005 flags=0 ... --- snip ---
Before the crash one arrives at this location (after defeating various anti-debugging mechanisms):
--- snip --- 4058CEE0 56 PUSH ESI 4058CEE1 8BF1 MOV ESI,ECX 4058CEE3 8B0D 90326D40 MOV ECX,DWORD PTR DS:[406D3290] ; KERNEL32.GetTickCount 4058CEE9 8B06 MOV EAX,DWORD PTR DS:[ESI] 4058CEEB 51 PUSH ECX 4058CEEC 6A 59 PUSH 59 4058CEEE 8BCE MOV ECX,ESI 4058CEF0 FF90 80000000 CALL DWORD PTR DS:[EAX+80] 4058CEF6 A1 94326D40 MOV EAX,DWORD PTR DS:[406D3294] 4058CEFB 8B16 MOV EDX,DWORD PTR DS:[ESI] 4058CEFD 50 PUSH EAX 4058CEFE 6A 60 PUSH 60 4058CF00 8BCE MOV ECX,ESI 4058CF02 FF92 84000000 CALL DWORD PTR DS:[EDX+84] 4058CF08 5E POP ESI 4058CF09 C3 RETN --- snip ---
--- snip --- ... 40444DB7 50 PUSH EAX 40444DB8 52 PUSH EDX 40444DB9 FF75 F4 PUSH DWORD PTR SS:[EBP-C] 40444DBC FF75 14 PUSH DWORD PTR SS:[EBP+14] 40444DBF FF75 10 PUSH DWORD PTR SS:[EBP+10] 40444DC2 6A 00 PUSH 0 40444DC4 FF75 0C PUSH DWORD PTR SS:[EBP+C] 40444DC7 FF75 08 PUSH DWORD PTR SS:[EBP+8] 40444DCA 6A 00 PUSH 0 40444DCC B8 B2000000 MOV EAX,0B2 ; syscall # 0xB2 40444DD1 E8 DA010000 CALL 40444FB0 ; xtrap sysenter trampoline 40444DD6 83C4 1C ADD ESP,1C 40444DD9 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX 40444DDC 5A POP EDX 40444DDD 58 POP EAX 40444DDE 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-8] 40444DE1 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4] 40444DE4 F7D8 NEG EAX 40444DE6 1BC0 SBB EAX,EAX 40444DE8 F7D0 NOT EAX 40444DEA 23C1 AND EAX,ECX 40444DEC 5F POP EDI 40444DED 5E POP ESI 40444DEE 5B POP EBX 40444DEF 8BE5 MOV ESP,EBP 40444DF1 5D POP EBP 40444DF2 C2 1000 RETN 10 ...
; xtrap sysenter trampoline
40444FB0 8BD4 MOV EDX,ESP 40444FB2 0F34 SYSENTER 40444FB4 90 NOP 40444FB5 90 NOP 40444FB6 90 NOP 40444FB7 90 NOP ... --- snip ---
Some refresh how 'sysenter' works on Windows and Linux:
Windows: http://www.geoffchappell.com/studies/windows/km/cpu/sep.htm
Linux: https://reverseengineering.stackexchange.com/questions/2869/how-does-sysente...
Win32 stack layout for 'sysenter':
--- snip --- ESP+0x00 address of 'ret mm' or 'ret' in system call stub ESP+0x04 caller of system call stub ESP+0x08 1st NT syscall argument ESP+0x0c 2nd NT syscall argument ... --- snip ---
Linux stack layout for 'sysenter':
--- snip --- ESP+0x00 saved 'EBP' (pop %ebp) ESP+0x04 saved 'EDX' (pop %edx) ESP+0x08 saved 'ECX' (pop %ecx) ESP+0x0C saved 'EIP' (ret) --- snip ---
How 'XTrap' sets up the stack before 'sysenter':
EDX = ESP = 0x0033DDD4
--- snip --- 0033DDD4 40444DD6 ; return to 0x40444DD6 from 0x40444FB0 0033DDD8 00000000 0033DDDC FFFFFFFF 0033DDE0 7B848298 ; API entry of kernel32.GetTickCount 0033DDE4 00000000 0033DDE8 0033DE5C 0033DDEC 0000001C 0033DDF0 0033DE10 0033DDF4 00000009 0033DDF8 00000009 0033DDFC 0033DE78 0033DE00 FFFFFFFF 0033DE04 7B848298 0033DE08 0033DE10 0033DE0C 00000000 0033DE10 00000000 0033DE14 40673008 --- snip ---
With the 'sysenter' instruction executed, the transition to kernel mode is made.
Linux fast syscall layout dictates that the return address to userspace will be 0x7B848298 -> 'GetTickCount' entry.
--- snip --- GetTickCount: 7B848298 55 PUSH EBP 7B848299 89E5 MOV EBP,ESP 7B84829B 53 PUSH EBX 7B84829C 83E4 F0 AND ESP,FFFFFFF0 7B84829F E8 2C74FDFF CALL 7B81F6D0 7B8482A4 81C3 5C2D0700 ADD EBX,72D5C 7B8482AA E8 72FFFFFF CALL 7B848221 7B8482AF 8B5D FC MOV EBX,DWORD PTR SS:[EBP-4] 7B8482B2 C9 LEAVE 7B8482B3 C3 RETN --- snip ---
Since the 'sysenter' instruction can't be trapped by Wine there is no way to emulate it, avoiding the stack imbalance due to different fundamental design of the fast syscall facility.
This makes it a 'WONTFIX'.
$ sha1sum LastChaos_DE_Setup.exe 0e15713b80833f826c7c84be3c0f95ae85964df5 LastChaos_DE_Setup.exe
$ du -sh LastChaos_DE_Setup.exe 1.5G LastChaos_DE_Setup.exe
$ wine --version wine-1.7.21-3-gbf72c67
Regards