[Bug 45349] New: Multiple applications and games crash due to missing support for 64-bit syscall thunks (StreetFighter V)

wine-bugs at winehq.org wine-bugs at winehq.org
Tue Jun 19 03:28:35 CDT 2018


https://bugs.winehq.org/show_bug.cgi?id=45349

            Bug ID: 45349
           Summary: Multiple applications and games crash due to missing
                    support for 64-bit syscall thunks (StreetFighter V)
           Product: Wine
           Version: 3.10
          Hardware: x86-64
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P2
         Component: ntdll
          Assignee: wine-bugs at winehq.org
          Reporter: focht at gmx.net
      Distribution: ---

Hello folks,

had this one lying around for some time, sadly got distracted from further
analysis (there are more bugs).

The game is "StreetFighter V Arcade Edition" and was gifted to me by Valve for
investigation, thanks ;-)

https://store.steampowered.com/app/310950/Street_Fighter_V_Arcade_Edition/

It has some custom DRM/protection scheme which uses various 64-bit anti-debug
and obfuscation techniques. There are a lot of single-step (TF) exceptions in
the code which are there by design (decrypt continuations).
At one point it crashes with invalid instruction exception:

--- snip ---
...
002e:trace:seh:NtRaiseException code=80000004 flags=0 addr=0x143fc99e9
ip=143fc99e9 tid=002e
002e:trace:seh:NtRaiseException  rax=00000000006000aa rbx=000000000000005e
rcx=000000000000005f rdx=000000000000071c
002e:trace:seh:NtRaiseException  rsi=0000000143fcf826 rdi=0000000000000000
rbp=00000000005ffbd8 rsp=00000000005ffbd0
002e:trace:seh:NtRaiseException   r8=0000000143fd2240  r9=000000000000000c
r10=0000000143fd26f8 r11=0000000000000000
002e:trace:seh:NtRaiseException  r12=000000000000005f r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
002e:trace:seh:RtlVirtualUnwind type 1 rip 143fc99e9 rsp 5ffbd0
002e:trace:seh:dump_unwind_info **** func 3fc9980-3fca910
002e:trace:seh:dump_unwind_info unwind info at 0x143fd26f0 flags 1 prolog 0x0
bytes function 0x143fc9980-0x143fca910
002e:trace:seh:dump_unwind_info     handler 0x143fd2240 data at 0x143fd26f8
002e:trace:seh:call_handler calling handler 0x143fd2240 (rec=0x5ffa90,
frame=0x5ffbd0 context=0x5fed30, dispatch=0x5ff200)
002e:trace:seh:call_handler handler at 0x143fd2240 returned 0
002e:trace:module:LdrGetDllHandle L"Kernel32.dll" -> 0x7b460000 (load path
L"Z:\\home\\focht\\Downloads;C:\\windows\\system32;C:\\windows\\system;C:\\windows;.;C:\\windows\\system32;C:\\windows;C:\\windows\\system32\\wbem")
002e:trace:ntdll:NtQueryInformationProcess
(0xffffffffffffffff,0x00000007,0x5ffcb0,0x00000008,0x5ffcb0)
002e: get_process_info( handle=ffffffff )
002e: get_process_info() = 0 { pid=002d, ppid=0000, affinity=000000ff,
peb=7fffffeaf000, start_time=1d3e17d69097156 (-0.0309210), end_time=0,
exit_code=259, priority=2, cpu=x86_64, debugger_present=0, debug_children=1 }
002e:trace:module:LdrGetDllHandle L"Kernel32.dll" -> 0x7b460000 (load path
L"Z:\\home\\focht\\Downloads;C:\\windows\\system32;C:\\windows\\system;C:\\windows;.;C:\\windows\\system32;C:\\windows;C:\\windows\\system32\\wbem")
002e:trace:seh:NtRaiseException code=c0000096 flags=0 addr=0x143fca968
ip=143fca968 tid=002e
002e:trace:seh:NtRaiseException  rax=00000000564d5868 rbx=000000008685d465
rcx=000000000000000a rdx=0000000143fc5658
002e:trace:seh:NtRaiseException  rsi=00000000005ffd58 rdi=0000000143fd3344
rbp=00000000005ffc18 rsp=00000000005ffc08
002e:trace:seh:NtRaiseException   r8=0000000143fd26f8  r9=000000000000000c
r10=0000000143fd26f8 r11=0000000000000000
002e:trace:seh:NtRaiseException  r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
002e:trace:seh:RtlVirtualUnwind type 1 rip 143fca968 rsp 5ffc08
002e:trace:seh:dump_unwind_info **** func 3fca910-3fcfbbc
002e:trace:seh:dump_unwind_info unwind info at 0x143fd26f0 flags 1 prolog 0x0
bytes function 0x143fca910-0x143fcfbbc
002e:trace:seh:dump_unwind_info     handler 0x143fcbbe8 data at 0x143fd26f8
002e:trace:seh:call_handler calling handler 0x143fcbbe8 (rec=0x5ffac0,
frame=0x5ffc08 context=0x5fed60, dispatch=0x5ff230)
002e:trace:seh:call_handler handler at 0x143fcbbe8 returned 0 
...
--- snip ---

One has to debug it to see the mess.
For that you need to defeat a few anti-debug trickery ;-)

The game protection copies native API entry point code around and assumes
64-bit Windows API entries which have a distinct signature/sequence.
A similar problem is described in bug 21232 which is about 32-bit syscall
thunks.

Partial copy of 'ntdll.NtQueryInformationProcess' entry point:

--- snip ---
0000000143FCFA88 | 55                   | push    rbp                           
0000000143FCFA89 | 48 89 E5             | mov     rbp, rsp                      
0000000143FCFA8C | 57                   | push    rdi                           
0000000143FCFA8D | 56                   | push    rsi                           
0000000143FCFA8E | 48 81 EC A0 00 00 00 | sub     rsp, A0                       
0000000143FCFA95 | 48 83 E4 F0          | and     rsp, FFFFFFFFFFFFFFF0         
0000000143FCFA99 | 48 81 EC 40 03 00 00 | sub     rsp, 340                      
0000000143FCFAA0 | 0F 11 B5 50 FF FF FF | movups  xmmword ptr ss:[rbp - B0],
xmm6 
0000000143FCFAA7 | 0F C4 08 33          | pinsrw  mm1, word ptr ds:[rax], 33    
0000000143FCFAAB | C0 48 83 C4          | ror     byte ptr ds:[rax - 7D], C4    
0000000143FCFAAF | 28 C3                | sub     bl, al                        
0000000143FCFAB1 | CC                   | int3                                  
0000000143FCFAB2 | CC                   | int3                                  
0000000143FCFAB3 | CC                   | int3                                  
0000000143FCFAB4 | CC                   | int3                                  
0000000143FCFAB5 | CC                   | int3                                  
0000000143FCFAB6 | CC                   | int3                                  
0000000143FCFAB7 | CC                   | int3                                  
0000000143FCFAB8 | 48 89 5C 24 08       | mov     qword ptr ss:[rsp + 8], rbx   
0000000143FCFABD | 48 89 6C 24 10       | mov     qword ptr ss:[rsp + 10], rbp  
0000000143FCFAC2 | 48 89 74 24 18       | mov     qword ptr ss:[rsp + 18], rsi  
0000000143FCFAC7 | 57                   | push    rdi                           
0000000143FCFAC8 | 48 83 EC 30          | sub     rsp, 30                       
0000000143FCFACC | 41 8B D9             | mov     ebx, r9d                      
0000000143FCFACF | 49 8B F0             | mov     rsi, r8                       
0000000143FCFAD2 | 8B EA                | mov     ebp, edx                      
0000000143FCFAD4 | 48 8B F9             | mov     rdi, rcx                      
0000000143FCFAD7 | EB 02                | jmp     streetfighterv.143FCFADB      
0000000143FCFAD9 | 48 EB E8             | jmp     streetfighterv.143FCFAC4      
--- snip ---

This obviously can't work. On 64-bit Windows the native API entry code is much
smaller (< 16 bytes). Due to partial opcode copy a fault is triggered when
executing.

Original 64-bit Wine API entry code:

--- snip ---
000000007BCEF058 55                       push    rbp
000000007BCEF059 48 89 E5                 mov     rbp, rsp
000000007BCEF05C 57                       push    rdi
000000007BCEF05D 56                       push    rsi
000000007BCEF05E 48 81 EC A0 00 00 00     sub     rsp, 0A0h
000000007BCEF065 48 83 E4 F0              and     rsp, 0FFFFFFFFFFFFFFF0h
000000007BCEF069 48 81 EC 40 03 00 00     sub     rsp, 340h
000000007BCEF070 0F 11 B5 50 FF FF FF     movups  [rbp+var_B0], xmm6
000000007BCEF077 0F 11 BD 60 FF FF FF     movups  [rbp+var_A0], xmm7
000000007BCEF07E 44 0F 11 85 70 FF FF FF  movups  [rbp+var_90], xmm8
000000007BCEF086 44 0F 11 4D 80           movups  [rbp+var_80], xmm9
000000007BCEF08B 44 0F 11 55 90           movups  [rbp+var_70], xmm10
000000007BCEF090 44 0F 11 5D A0           movups  [rbp+var_60], xmm11
000000007BCEF095 44 0F 11 65 B0           movups  [rbp+var_50], xmm12
000000007BCEF09A 44 0F 11 6D C0           movups  [rbp+var_40], xmm13
000000007BCEF09F 44 0F 11 75 D0           movups  [rbp+var_30], xmm14
000000007BCEF0A4 44 0F 11 7D E0           movups  [rbp+var_20], xmm15
000000007BCEF0A9 48 89 4D 10              mov     [rbp+ProcessHandle], rcx
000000007BCEF0AD 89 55 18                 mov    
[rbp+ProcessInformationClass], edx
000000007BCEF0B0 4C 89 45 20              mov     [rbp+ProcessInformation], r8
000000007BCEF0B4 44 89 4D 28              mov    
[rbp+ProcessInformationLength], r9d
000000007BCEF0B8 C7 84 24 3C 03 00 00 00+ mov     dword ptr [rsp+3F0h+n+4], 0
000000007BCEF0C3 C7 84 24 38 03 00 00 00+ mov     dword ptr [rsp+3F0h+n], 0
000000007BCEF0CE 48 B8 70 CA D9 7B 00 00+ mov     rax, offset
__wine_dbch_ntdll_6
...
--- snip ---

Wine-Staging patchset:
https://github.com/wine-staging/wine-staging/tree/HEAD/patches/winebuild-Fake_Dlls

Relevant part:
https://github.com/wine-staging/wine-staging/blob/HEAD/patches/winebuild-Fake_Dlls/0010-tools-winebuild-Add-syscall-thunks-for-64-bit.patch
(+prerequisite).

Generated 64-bit thunks:

--- snip ---
...
0000000143FCFA88 | B8 70 00 00 00          | mov     eax, 70                
0000000143FCFA8D | 65 FF 14 25 00 01 00 00 | call    qword ptr gs:[100]     
0000000143FCFA95 | C3                      | ret                            
0000000143FCFA96 | 00 00                   | add     byte ptr ds:[rax], al 
0000000143FCFA98 | B8 71 00 00 00          | mov     eax, 71                
0000000143FCFA9D | 65 FF 14 25 00 01 00 00 | call    qword ptr gs:[100]     
0000000143FCFAA5 | C3                      | ret   
...
--- snip ---

NOTE: I wanted to keep a separate ticket for 64-bit syscall thunks to
track/validate it separately from 32-bit parts (bug 21232).

Regards

-- 
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.



More information about the wine-bugs mailing list