https://bugs.winehq.org/show_bug.cgi?id=45377
Bug ID: 45377 Summary: StreetFighter V Arcade Edition (Steam) custom protection scheme fails to validate in-memory 'ntdll.dll' PE header against on-disk fake-dll Product: Wine Version: 3.11 Hardware: x86-64 OS: Linux Status: NEW Severity: normal Priority: P2 Component: ntdll Assignee: wine-bugs@winehq.org Reporter: focht@gmx.net Distribution: ---
Hello folks,
continuation of bug 45349
It's a similar problem domain as bug 15437 ("Multiple programs using madCodeHook crash (in-memory PE image of Wine builtins vs. ELF image on disk)") but unlike that one it can't be worked around by removing the placeholder/fake dll.
Trace log doesn't reveal much. It has to be debugged with 64-bit debuggers that are very unstable/fragile due to various Wine bugs #debugception
NOTE: relay thunks don't work here.
--- snip --- $ WINEDEBUG=+seh,+server,+ntdll wine ./StreetFighterV.exe >>log.txt 2>&1 ... 002e:trace:ntdll:FILE_CreateFile handle=0x5ff768 access=80100000 name=L"\??\C:\windows\system32\ntdll.dll" objattr=00000040 root=(nil) sec=(nil) io=0x5ff770 alloc_size=(nil) attr=00000000 sharing=00000001 disp=1 options=00000060 ea=(nil).0x00000000 002e:trace:file:nt_to_unix_file_name_internal L"\??\C:\windows\system32\ntdll.dll" -> "/home/focht/.wine/dosdevices/c:/windows/system32/ntdll.dll" 002e: create_file( access=80100000, sharing=00000001, create=1, options=00000060, attrs=00000000, objattr={rootdir=0000,attributes=00000040,sd={},name=L""}, filename="/home/focht/.wine/dosdevices/c:/windows/system32/ntdll.dll" ) 002e: create_file() = 0 { handle=0024 } 002e:trace:file:CreateFileW returning 0x24 002e: create_mapping( access=000f0005, flags=08000000, file_access=00000001, size=00000000, file_handle=0024, objattr={rootdir=0000,attributes=00000080,sd={},name=L""} ) 002e: create_mapping() = 0 { handle=0028 } 002e: get_mapping_info( handle=0028, access=00000004 ) 002e: get_mapping_info() = 0 { size=0000edac, flags=00800000, shared_file=0000, image={} } 002e: get_handle_fd( handle=0028 ) 002e: *fd* 0028 -> 31 002e: get_handle_fd() = 0 { type=1, cacheable=1, access=000f0005, options=00000020 } 002e: map_view( mapping=0028, access=00000004, base=00600000, size=0000f000, start=00000000 ) 002e: map_view() = 0 002e: unmap_view( base=00600000 ) 002e: unmap_view() = 0 002e: close_handle( handle=0028 ) 002e: close_handle() = 0 002e: close_handle( handle=0024 ) 002e: close_handle() = 0 002e:trace:ntdll:RtlSystemTimeToLocalTime (0x5ffb30, 0x5ffb28) 002e:trace:file:CreateFileW L"\\.\mailslot\ErrLog-Pec72FB" GENERIC_WRITE FILE_SHARE_READ FILE_SHARE_WRITE creation 3 attributes 0x0 002e:trace:file:RtlDosPathNameToNtPathName_U_WithStatus (L"\\.\mailslot\ErrLog-Pec72FB",0x5ff1f0,(nil),(nil)) 002e:trace:file:RtlGetFullPathName_U (L"\\.\mailslot\ErrLog-Pec72FB" 520 0x5fede0 (nil)) 002e:trace:ntdll:FILE_CreateFile handle=0x5ff1d8 access=40100000 name=L"\??\mailslot\ErrLog-Pec72FB" objattr=00000040 root=(nil) sec=(nil) io=0x5ff1e0 alloc_size=(nil) attr=00000000 sharing=00000003 disp=1 options=00000060 ea=(nil).0x00000000 002e: open_file_object( access=40100000, attributes=00000040, rootdir=0000, sharing=00000003, options=00000060, filename=L"\??\mailslot\ErrLog-Pec72FB" ) 002e: open_file_object() = OBJECT_NAME_NOT_FOUND { handle=0000 } 002e:warn:file:CreateFileW Unable to create file L"\\.\mailslot\ErrLog-Pec72FB" (status c0000034) 002e:trace:file:CreateFileW returning 0xffffffffffffffff 002e:trace:file:CreateFileW L"\\.\mailslot\ErrLog-Pec72FB" GENERIC_WRITE FILE_SHARE_READ FILE_SHARE_WRITE creation 3 attributes 0x0 002e:trace:file:RtlDosPathNameToNtPathName_U_WithStatus (L"\\.\mailslot\ErrLog-Pec72FB",0x5ff1f0,(nil),(nil)) 002e:trace:file:RtlGetFullPathName_U (L"\\.\mailslot\ErrLog-Pec72FB" 520 0x5fede0 (nil)) 002e:trace:ntdll:FILE_CreateFile handle=0x5ff1d8 access=40100000 name=L"\??\mailslot\ErrLog-Pec72FB" objattr=00000040 root=(nil) sec=(nil) io=0x5ff1e0 alloc_size=(nil) attr=00000000 sharing=00000003 disp=1 options=00000060 ea=(nil).0x00000000 002e: open_file_object( access=40100000, attributes=00000040, rootdir=0000, sharing=00000003, options=00000060, filename=L"\??\mailslot\ErrLog-Pec72FB" ) 002e: open_file_object() = OBJECT_NAME_NOT_FOUND { handle=0000 } 002e:warn:file:CreateFileW Unable to create file L"\\.\mailslot\ErrLog-Pec72FB" (status c0000034) 002e:trace:file:CreateFileW returning 0xffffffffffffffff 002e: terminate_process( handle=0000, exit_code=0 ) 002e: terminate_process() = 0 { self=1 } 002e:trace:module:LdrShutdownProcess () --- snip ---
Tidbit: The mailslot thing seems to belong to some internal error handling. It is interesting because such unique patterns help sometimes to identify the protection scheme/used 3rd party library code. Unfortunately a search of '\.\mailslot\ErrLog-Pec*' reveals not that much.
https://www.google.de/search?&q=%22%5C.%5Cmailslot%5CErrLog"
Some samples from malware analysis sites.
---
To come to this point one has to defeat some simple anti-debugging checks. Use of hardware breakpoints is mandatory due to code being dynamically unpacked.
=== #1 ===
--- snip --- 002e:Call KERNEL32.IsDebuggerPresent() ret=143fca16e 002e:Ret KERNEL32.IsDebuggerPresent() retval=00000000 ret=143fca16e --- snip ---
--- snip --- ... 0000000143FCA169 | 48 8B F8 | mov rdi, rax 0000000143FCA16C | FF D3 | call rbx 0000000143FCA16E | 48 8B 74 24 40 | mov rsi, qword ptr ss:[rsp+40] 0000000143FCA173 | 85 C0 | test eax, eax 0000000143FCA175 | 48 8B 5C 24 38 | mov rbx, qword ptr ss:[rsp+38] ; set ZF=1 0000000143FCA17A | 74 20 | je streetfighterv.143FCA19C ... --- snip ---
=== #2 ===
--- snip --- 002e:Call KERNEL32.CheckRemoteDebuggerPresent(ffffffffffffffff,005ffd00) ret=143fca1b4 002e:Call ntdll.NtQueryInformationProcess(ffffffffffffffff,00000007,005ffc38,00000008,00000000) ret=7b48d9e8 002e:trace:ntdll:NtQueryInformationProcess (0xffffffffffffffff,0x00000007,0x5ffc38,0x00000008,(nil)) 002e: get_process_info( handle=ffffffff ) 002e: get_process_info() = 0 { pid=002d, ppid=0000, affinity=000000ff, peb=7fffffeaf000, start_time=1d3e151f13af5a8 (-0.0174060), end_time=0, exit_code=259, priority=2, cpu=x86_64, debugger_present=0, debug_children=1 } 002e:Ret ntdll.NtQueryInformationProcess() retval=00000000 ret=7b48d9e8 002e:Ret KERNEL32.CheckRemoteDebuggerPresent() retval=00000001 ret=143fca1b4 --- snip ---
--- snip --- 0000000143FCA1A1 | 48 8D 54 24 30 | lea rdx, qword ptr ss:[rsp+30] 0000000143FCA1A6 | 48 83 C9 FF | or rcx, FFFFFFFFFFFFFFFF 0000000143FCA1AA | C7 44 24 30 01 00 00.| mov dword ptr ss:[rsp+30], 1 0000000143FCA1B2 | FF D7 | call rdi 0000000143FCA1B4 | 83 7C 24 30 00 | cmp dword ptr ss:[rsp+30], 0 ; set ZF=1 0000000143FCA1B9 | 75 04 | jne streetfighterv.143FCA1BF --- snip ---
=== #3 ===
Inlined variant of PEB debugger check
--- snip --- ; TEB 0000000143FCFA53 | 65 4C 8B 1C 25 30 00.| mov r11, qword ptr gs:[30] 0000000143FCFA5C | 33 DB | xor ebx, ebx ; PEB 0000000143FCFA5E | 49 8B 4B 60 | mov rcx, qword ptr ds:[r11 + 60] ; being debugged? 0000000143FCFA62 | 38 59 02 | cmp byte ptr ds:[rcx + 2], bl ; zero out BL 0000000143FCFA65 | 0F 95 C3 | setne bl 0000000143FCFA68 | EB 01 | jmp streetfighterv.143FCFA6B 0000000143FCFA6A | EB E8 | jmp streetfighterv.143FCFA54 --- snip ---
=== #4 ===
--- snip --- $ WINEDEBUG=+seh,+server,+ntdll wine ./StreetFighterV.exe >>log.txt 2>&1 ... 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 } ... --- snip ---
--- snip --- ; preset app flag 0000000143FCE79C | C7 44 24 30 01 | mov dword ptr ss:[rsp+30], 1 0000000143FCE7A4 | E8 9F 13 00 00 | call streetfighterv.143FCFB48 ... 0000000143FCFB71 | 48 8B CB | mov rcx, rbx 0000000143FCFB74 | 4C 89 5C 24 20 | mov qword ptr ss:[rsp+20], r11 ; NtQueryInformationProcess, ProcessDebugPort 0000000143FCFB79 | E8 0A FF FF FF | call streetfighterv.143FCFA88 0000000143FCFB7E | 85 C0 | test eax, eax 0000000143FCFB80 | 74 0D | je streetfighterv.143FCFB8F 0000000143FCFB82 | 33 C0 | xor eax, eax 0000000143FCFB84 | 48 8B 5C 24 40 | mov rbx, qword ptr ss:[rsp+40] 0000000143FCFB89 | 48 83 C4 30 | add rsp, 30 0000000143FCFB8D | 5F | pop rdi 0000000143FCFB8E | C3 | ret ; reset app flag NTSTATUS == STATUS_SUCCESS 0000000143FCFB8F | C7 07 00 00 00. | mov dword ptr ds:[rdi], 0 0000000143FCFB95 | EB 01 | jmp streetfighterv.143FCFB98 0000000143FCFB97 | EB E8 | jmp streetfighterv.143FCFB81 0000000143FCFB99 | 03 00 | add eax, dword ptr ds:[rax] 0000000143FCFB9B | 00 00 | add byte ptr ds:[rax], al 0000000143FCFB9D | 66 48 B9 48 83. | mov rcx, 245C8B4808C48348 ... 0000000143FCFBA0 | 48 83 C4 08 | add rsp, 8 0000000143FCFBA4 | 48 8B 5C 24 40 | mov rbx, qword ptr ss:[rsp+40] 0000000143FCFBA9 | B8 01 00 00 00 | mov eax, 1 0000000143FCFBAE | 48 83 C4 30 | add rsp, 30 0000000143FCFBB2 | 5F | pop rdi 0000000143FCFBB3 | C3 | ret ... ; app flag == 0? 0000000143FCE7A9 | 83 7C 24 30 00 | cmp dword ptr ss:[rsp+30], 0 0000000143FCE7AE | 75 33 | jne streetfighterv.143FCE7E3 0000000143FCE7B0 | 85 C0 | test eax, eax 0000000143FCE7B2 | 74 2F | je streetfighterv.143FCE7E3 --- snip ---
'ProcessDebugPort' -> anti-debug check, the call is made via a copy of 'ntdll.NtQueryInformationProcess' entry hence the 64-bit syscall thunks are needed -> bug 45349
The check here seems kinda pointless, the code doesn't look at 'ProcessDebugPort' return value at all. It only validates return status -> app bug?
=====================
And the final frontier ...
Caller code that maps the 'ntdll.dll' placeholder into memory to validate it with in-memory 'ntdll.dll' PE image.
--- snip --- ... 0000000143FED295 | mov r13, qword ptr ds:[r14] 0000000143FED298 | lea rcx, qword ptr ss:[rsp + 60] 0000000143FED29D | mov edx, 104 0000000143FED2A2 | xor esi, esi 0000000143FED2A4 | call <streetfighterv.GetSystemWindowsDirectoryA> ... 0000000143FED31E | mov qword ptr ss:[rsp + 30], rsi 0000000143FED323 | lea rcx, qword ptr ss:[rsp + 60] 0000000143FED328 | lea r8d, qword ptr ds:[r9 + 1] 0000000143FED32C | mov edx, 80000000 0000000143FED331 | mov dword ptr ss:[rsp + 28], esi 0000000143FED335 | mov dword ptr ss:[rsp + 20], 3 0000000143FED33D | call qword ptr ds:[<&CreateFileA>] 0000000143FED343 | mov edi, esi 0000000143FED345 | mov rbp, rsi 0000000143FED348 | cmp rax, FFFFFFFFFFFFFFFF 0000000143FED34C | mov r12, rax 0000000143FED34F | setne dil 0000000143FED353 | test edi, edi 0000000143FED355 | je streetfighterv.143FED38B 0000000143FED357 | xor edx, edx 0000000143FED359 | mov ecx, E3 0000000143FED35E | call qword ptr ds:[143FEEE50] 0000000143FED364 | xor r9d, r9d 0000000143FED367 | xor edx, edx 0000000143FED369 | lea r8d, qword ptr ds:[r9 + 2] 0000000143FED36D | mov rcx, r12 0000000143FED370 | mov qword ptr ss:[rsp + 28], rsi 0000000143FED375 | mov dword ptr ss:[rsp + 20], esi 0000000143FED379 | call qword ptr ds:[<&CreateFileMappingA>] 0000000143FED37F | mov edi, esi 0000000143FED381 | test rax, rax 0000000143FED384 | mov rbp, rax 0000000143FED387 | setne dil 0000000143FED38B | test edi, edi 0000000143FED38D | mov rbx, rsi 0000000143FED390 | je streetfighterv.143FED406 0000000143FED392 | xor edx, edx 0000000143FED394 | mov ecx, F3 0000000143FED399 | call qword ptr ds:[143FEEE50] 0000000143FED39F | xor r9d, r9d 0000000143FED3A2 | xor r8d, r8d 0000000143FED3A5 | lea edx, qword ptr ds:[r9 + 4] 0000000143FED3A9 | mov rcx, rbp 0000000143FED3AC | mov qword ptr ss:[rsp + 20], rsi ; map placeholder image 0000000143FED3B1 | call qword ptr ds:[<&MapViewOfFile>] 0000000143FED3B7 | mov edi, esi 0000000143FED3B9 | test rax, rax 0000000143FED3BC | mov rbx, rax 0000000143FED3BF | setne dil 0000000143FED3C3 | test edi, edi 0000000143FED3C5 | je streetfighterv.143FED406 0000000143FED3C7 | xor edx, edx 0000000143FED3C9 | mov ecx, 103 0000000143FED3CE | call qword ptr ds:[143FEEE50] 0000000143FED3D4 | mov rdx, rbx 0000000143FED3D7 | mov rcx, r15 ; check disk PE header vs. in-memory PE header (phase 1 validate) 0000000143FED3DA | call streetfighterv.143FECB30 0000000143FED3DF | test eax, eax 0000000143FED3E1 | mov edi, eax ; mismatch -> jump 0000000143FED3E3 | je streetfighterv.143FED406 0000000143FED3E5 | xor edx, edx 0000000143FED3E7 | mov ecx, 113 0000000143FED3EC | call qword ptr ds:[143FEEE50] 0000000143FED3F2 | mov rcx, rbx 0000000143FED3F5 | call streetfighterv.143FECA30 0000000143FED3FA | xor edi, edi 0000000143FED3FC | test rax, rax 0000000143FED3FF | mov rsi, rax 0000000143FED402 | setne dil 0000000143FED406 | test rbx, rbx 0000000143FED409 | je streetfighterv.143FED414 0000000143FED40B | mov rcx, rbx 0000000143FED40E | call qword ptr ds:[<&UnmapViewOfFile>] 0000000143FED414 | test rbp, rbp 0000000143FED417 | je streetfighterv.143FED422 0000000143FED419 | mov rcx, rbp 0000000143FED41C | call qword ptr ds:[<&CloseHandle>] 0000000143FED422 | cmp r12, FFFFFFFFFFFFFFFF 0000000143FED426 | je streetfighterv.143FED431 0000000143FED428 | mov rcx, r12 0000000143FED42B | call qword ptr ds:[<&CloseHandle>] 0000000143FED431 | test edi, edi 0000000143FED433 | je streetfighterv.143FED4CA ... --- snip ---
in-memory 'ntdll.dll' (sections = 2)
--- snip --- $ ==> 50 45 00 00 64 86 02 00 00 00 00 00 00 00 00 00 PE..d........... $+10 00 00 00 00 F0 00 22 20 0B 02 07 0A 00 60 10 00 ....ð." .....`.. $+20 00 00 02 00 00 00 00 00 F0 B8 0B 00 00 10 00 00 ........ð¸...... $+30 00 00 C4 7B 00 00 00 00 00 10 00 00 00 10 00 00 ..Ä{............ $+40 01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 ................ $+50 00 70 12 00 00 10 00 00 00 00 00 00 00 00 00 01 .p.............. $+60 00 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00 ................ $+70 00 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00 ................ $+80 00 00 00 00 10 00 00 00 40 7D 10 00 48 A1 00 00 ........@}..H¡.. $+90 00 00 00 00 00 00 00 00 B8 1E 11 00 AC 03 00 00 ........¸...¬... $+A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ $+B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ $+C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ $+D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ $+E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ $+F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ $+100 00 00 00 00 00 00 00 00 2E 74 65 78 74 00 00 00 .........text... --- snip ---
placedholder/fake-dll mapped disk view (sections = 4):
--- snip --- $ ==> 50 45 00 00 64 86 04 00 00 00 00 00 00 00 00 00 PE..d........... $+10 00 00 00 00 F0 00 22 20 0B 02 07 0A 97 CE 00 00 ....ð." .....Î.. $+20 00 00 00 00 00 00 00 00 70 50 00 00 00 10 00 00 ........pP...... $+30 00 00 00 10 00 00 00 00 00 10 00 00 00 02 00 00 ................ $+40 01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 ................ $+50 00 20 01 00 00 04 00 00 00 00 00 00 00 00 00 01 . .............. $+60 00 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00 ................ $+70 00 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00 ................ $+80 00 00 00 00 10 00 00 00 80 50 00 00 17 8E 00 00 .........P...... $+90 00 00 00 00 00 00 00 00 00 10 01 00 AC 03 00 00 ............¬... $+A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ $+B0 00 00 01 00 08 00 00 00 00 00 00 00 00 00 00 00 ................ $+C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ $+D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ $+E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ $+F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ $+100 00 00 00 00 00 00 00 00 2E 74 65 78 74 00 00 00 .........text... --- snip ---
Validation (phase 1):
--- snip --- ... ; e_magic 0000000143FE9D45 | 66 81 3B 4D 5A | cmp word ptr ds:[rbx], 5A4D 0000000143FE9D4A | 75 F1 | jne streetfighterv.143FE9D3D 0000000143FE9D4C | 48 89 7C 24 30 | mov qword ptr ss:[rsp+30], rdi ; DWORD e_lfanew 0000000143FE9D51 | 48 63 7B 3C | movsxd rdi, dword ptr ds:[rbx+3C] 0000000143FE9D55 | 48 03 FB | add rdi, rbx ; PE signature, 'PE' from in-memory image 0000000143FE9D58 | 81 3F 50 45 00 00 | cmp dword ptr ds:[rdi], 4550 0000000143FE9D5E | 74 0D | je streetfighterv.143FE9D6D 0000000143FE9D60 | 33 C0 | xor eax, eax 0000000143FE9D62 | 48 8B 7C 24 30 | mov rdi, qword ptr ss:[rsp+30] 0000000143FE9D67 | 48 83 C4 20 | add rsp, 20 0000000143FE9D6B | 5B | pop rbx 0000000143FE9D6C | C3 | ret 0000000143FE9D6D | EB 01 | jmp streetfighterv.143FE9D70 0000000143FE9D6F | EB E8 | jmp streetfighterv.143FE9D59 0000000143FE9D71 | 03 00 | add eax, dword ptr ds:[rax] 0000000143FE9D73 | 00 00 | add byte ptr ds:[rax], al 0000000143FE9D75 | 66 48 B9 48 83 C4.| mov rcx, 48C78B4808C48348 0000000143FE9D80 | 8B 7C 24 30 | mov edi, dword ptr ss:[rsp+30] 0000000143FE9D84 | 48 83 C4 20 | add rsp, 20 0000000143FE9D88 | 5B | pop rbx 0000000143FE9D89 | C3 | ret ... 0000000143FECB80 | 48 85 C0 | test rax, rax 0000000143FECB83 | 48 8B F8 | mov rdi, rax 0000000143FECB86 | 74 16 | je streetfighterv.143FECB9E ; DWORD AddressOfEntryPoint disk image (RVA: 0x5070) 0000000143FECB88 | 8B 40 28 | mov eax, dword ptr ds:[rax+28] ; dword ptr [rbx+28]=[ntdll.000000007BC40068]=BB8F0 0000000143FECB8B | 39 43 28 | cmp dword ptr ds:[rbx+28], eax 0000000143FECB8E | 75 0E | jne streetfighterv.143FECB9E ; DWORD size of Import Directory (array of IIDs) in-memory view: 0x10 0000000143FECB90 | 8B 83 84 00 00 00 | mov eax, dword ptr ds:[rbx+84] ; dword ptr [rdi+84]=[00000000006100E4]=10 0000000143FECB96 | 3B 87 84 00 00 00 | cmp eax, dword ptr ds:[rdi+84] 0000000143FECB9C | 74 12 | je streetfighterv.143FECBB0 0000000143FECB9E | 33 C0 | xor eax, eax 0000000143FECBA0 | 48 8B 6C 24 30 | mov rbp, qword ptr ss:[rsp+30] 0000000143FECBA5 | 48 8B 5C 24 40 | mov rbx, qword ptr ss:[rsp+40] 0000000143FECBAA | 48 83 C4 20 | add rsp, 20 0000000143FECBAE | 5F | pop rdi 0000000143FECBAF | C3 | ret ... 0000000143FECBB0 | 48 89 74 24 38 | mov qword ptr ss:[rsp+38], rsi ; WORD NumberOfSections ; word ptr [rbx+6]=[ntdll.000000007BC40046]=2 0000000143FECBB5 | 0F B7 73 06 | movzx esi, word ptr ds:[rbx+6] ; word ptr [rdi+6]=[0000000000610066]=4 0000000143FECBB9 | 66 3B 77 06 | cmp si, word ptr ds:[rdi+6] 0000000143FECBBD | 75 3E | jne streetfighterv.143FECBFD 0000000143FECBBF | 4C 8B C0 | mov r8, rax ; DWORD Resource Table / RVA of Resource Directory ; edx=00000000006100E8 0000000143FECBC2 | 48 8D 97 88 00 00.| lea rdx, qword ptr ds:[rdi+88] ; rcx=ntdll.000000007BC400C8 0000000143FECBC9 | 48 8D 8B 88 00 00.| lea rcx, qword ptr ds:[rbx+88] 0000000143FECBD0 | 49 C1 E0 03 | shl r8, 3 0000000143FECBD4 | E8 F7 1E 00 00 | call streetfighterv.143FEEAD0 0000000143FECBD9 | 85 C0 | test eax, eax 0000000143FECBDB | 75 20 | jne streetfighterv.143FECBFD 0000000143FECBDD | 0F B7 C6 | movzx eax, si 0000000143FECBE0 | 48 8B CD | mov rcx, rbp 0000000143FECBE3 | 4C 8D 04 80 | lea r8, qword ptr ds:[rax+rax*4] 0000000143FECBE7 | 0F B7 47 14 | movzx eax, word ptr ds:[rdi+14] 0000000143FECBEB | 48 8D 54 38 18 | lea rdx, qword ptr ds:[rax+rdi+1 0000000143FECBF0 | 49 C1 E0 03 | shl r8, 3 0000000143FECBF4 | E8 D7 1E 00 00 | call streetfighterv.143FEEAD0 0000000143FECBF9 | 85 C0 | test eax, eax 0000000143FECBFB | 74 04 | je streetfighterv.143FECC01 0000000143FECBFD | 33 C0 | xor eax, eax 0000000143FECBFF | EB 14 | jmp streetfighterv.143FECC15 0000000143FECC01 | EB 02 | jmp streetfighterv.143FECC05 0000000143FECC03 | 48 EB E8 | jmp streetfighterv.143FECBEE 0000000143FECC06 | 02 00 | add al, byte ptr ds:[rax] 0000000143FECC08 | 00 00 | add byte ptr ds:[rax], al 0000000143FECC0A | 48 B9 48 83 C4 08.| mov rcx, 1B808C48348 0000000143FECC14 | 00 48 8B | add byte ptr ds:[rax-75], cl 0000000143FECC17 | 74 24 | je streetfighterv.143FECC3D 0000000143FECC19 | 38 48 8B | cmp byte ptr ds:[rax-75], cl 0000000143FECC1C | 6C | insb 0000000143FECC1D | 24 30 | and al, 30 0000000143FECC1F | 48 8B 5C 24 40 | mov rbx, qword ptr ss:[rsp+40] 0000000143FECC24 | 48 83 C4 20 | add rsp, 20 0000000143FECC28 | 5F | pop rdi 0000000143FECC29 | C3 | ret ... --- snip ---
I've left out the actual data directory traversal (would be too much). This just shows it extensively validates to in-memory PE image against the disk image.
Regards
https://bugs.winehq.org/show_bug.cgi?id=45377
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- URL| |https://store.steampowered. | |com/app/310950/ Depends on| |45349 Keywords| |obfuscation, win64
https://bugs.winehq.org/show_bug.cgi?id=45377
soredake yuno@hitler.rocks changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |yuno@hitler.rocks
https://bugs.winehq.org/show_bug.cgi?id=45377
Rémi Bernon rbernon@codeweavers.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |rbernon@codeweavers.com
--- Comment #1 from Rémi Bernon rbernon@codeweavers.com --- I believe the game now works, with the staging fakedll and the user shared data updates patches, and the recently upstreamed ptids changes in:
* daa120309e1f server: Make sure pids/tids are multiples of four. * 8bb684c63e02 ntdll/tests: Test that ptids are multiples of four.
https://bugs.winehq.org/show_bug.cgi?id=45377
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Resolution|--- |FIXED Summary|StreetFighter V Arcade |StreetFighter V Arcade |Edition (Steam) custom |Edition (Steam) custom |protection scheme fails to |protection scheme requires |validate in-memory |pids/tids to be multiples |'ntdll.dll' PE header |of four |against on-disk fake-dll | Status|NEW |RESOLVED Component|ntdll |wineserver Fixed by SHA1| |daa120309e1f674a251497ff6a0 | |14168d339c90c
--- Comment #2 from Anastasius Focht focht@gmx.net --- Hello Rémi,
well, I didn't revisit this one for a long time since it was depending on Wine-Staging patchset(s) and potentially on the conversion of core dlls to PE format which is the proper way. Not all protection schemes need syscall-style entries/thunks.
In general I try to avoid analysing too much further to not let people cherry-pick things into mainline while Staging patches keep living on forever. Kind of putting some pressure to continue upstreaming things.
I will refine the ticket summary to target the specific issue you fixed. Good work! All other issues are already tracked in different tickets along with their Wine-Staging patchset(s).
https://source.winehq.org/git/wine.git/commitdiff/daa120309e1f674a251497ff6a... ("server: Make sure pids/tids are multiples of four.")
--- snip --- Street Fighter V unpacker relies on it when validating other processes for its anti-debug checks, it uses (PID&0xfffffffc)>>2 as an array index and then checks back indexes against PIDs, and terminates early if some PIDs do not match. --- snip ---
Thanks Rémi
Regards
https://bugs.winehq.org/show_bug.cgi?id=45377
Alexandre Julliard julliard@winehq.org changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|RESOLVED |CLOSED
--- Comment #3 from Alexandre Julliard julliard@winehq.org --- Closing bugs fixed in 5.8.
https://bugs.winehq.org/show_bug.cgi?id=45377 Bug 45377 depends on bug 45349, which changed state.
Bug 45349 Summary: Multiple applications and games crash due to missing support for 64-bit syscall thunks (StreetFighter V, World of Warcraft) https://bugs.winehq.org/show_bug.cgi?id=45349
What |Removed |Added ---------------------------------------------------------------------------- Status|STAGED |RESOLVED Resolution|--- |FIXED