https://bugs.winehq.org/show_bug.cgi?id=45936
Bug ID: 45936 Summary: IW4x crashes on keyboard input Product: Wine-staging Version: 3.17 Hardware: x86-64 OS: Linux Status: UNCONFIRMED Severity: normal Priority: P2 Component: -unknown Assignee: wine-bugs@winehq.org Reporter: huematrix@mailinator.com CC: leslie_alistair@hotmail.com, z.figura12@gmail.com Distribution: ---
Created attachment 62464 --> https://bugs.winehq.org/attachment.cgi?id=62464 Log
Upon pressing a key in IW4x (A Call of Duty: Modern Warfare 2 client), the program crashes. Full log below.
https://bugs.winehq.org/show_bug.cgi?id=45936
Louis Lenders xerox.xerox2000x@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |xerox.xerox2000x@gmail.com
--- Comment #1 from Louis Lenders xerox.xerox2000x@gmail.com --- (In reply to huematrix from comment #0)
Created attachment 62464 [details] Log
Upon pressing a key in IW4x (A Call of Duty: Modern Warfare 2 client), the program crashes. Full log below.
0009:err:module:DelayLoadFailureHook failed to delay load imm32.dll.ImmProcessKey wine: Call from 0x7b43d5bc to unimplemented function imm32.dll.ImmProcessKey, aborting 0009:err:module:DelayLoadFailureHook failed to delay load imm32.dll.ImmProcessKey
Something looks wrong with your configuration. Have set libraries to native in winecfg? And which ones? Thanks in advance for reporting back. Regards
https://bugs.winehq.org/show_bug.cgi?id=45936
--- Comment #2 from huematrix@mailinator.com --- (In reply to Louis Lenders from comment #1)
(In reply to huematrix from comment #0)
Created attachment 62464 [details] Log
Upon pressing a key in IW4x (A Call of Duty: Modern Warfare 2 client), the program crashes. Full log below.
0009:err:module:DelayLoadFailureHook failed to delay load imm32.dll.ImmProcessKey wine: Call from 0x7b43d5bc to unimplemented function imm32.dll.ImmProcessKey, aborting 0009:err:module:DelayLoadFailureHook failed to delay load imm32.dll.ImmProcessKey
Something looks wrong with your configuration. Have set libraries to native in winecfg? And which ones? Thanks in advance for reporting back. Regards
It's a fresh wine prefix, none of the configuration was changed.
https://bugs.winehq.org/show_bug.cgi?id=45936
--- Comment #3 from Louis Lenders xerox.xerox2000x@gmail.com --- (In reply to huematrix from comment #2)
0009:err:module:DelayLoadFailureHook failed to delay load imm32.dll.ImmProcessKey wine: Call from 0x7b43d5bc to unimplemented function imm32.dll.ImmProcessKey, aborting
It's a fresh wine prefix, none of the configuration was changed.
That`s strange then as that function ImmProcessKey is implemented... Maybe adding a WINEDEBUG=+loaddll log could reveal something? Could you run the app with that and attach terminal output here? thanks
https://bugs.winehq.org/show_bug.cgi?id=45936
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Ever confirmed|0 |1 URL| |https://github.com/Jawesome | |99/IW4x/releases/tag/0.5.4- | |dirty-client Component|-unknown |winecrt0 CC| |focht@gmx.net Status|UNCONFIRMED |NEW Summary|IW4x crashes on keyboard |IW4x 0.5.4 crashes on |input |keyboard input, failure to | |delay load | |'imm32.dll.ImmProcessKey' | |('kernel32.dll.LoadLibraryA | |' made no-op by protection | |scheme, breaks | |'__wine_spec_delay_load') Product|Wine-staging |Wine Keywords| |download, obfuscation
--- Comment #4 from Anastasius Focht focht@gmx.net --- Hello folks,
confirming.
Instructions for install:
https://iw4x.tumblr.com/post/161974206329/install-iw4x
NOTE: Although Wine-Staging is required for reproducing the issue (figure out which patchset is needed later), using vanilla Wine as product here. I want to have the traceability in mainline.
The problem is caused by one of the anti-hack/debug protection mechanisms used by the client. Relay tracing interferes with it too, hence it has to be debugged ;-)
Executable modules map (excerpt):
--- snip --- Base Size Name File version Path 00400000 06C71000 iw4x 4.2.0.0 C:\games\MW2\iw4x.exe 0A0A0000 00020000 mssmp3 C:\games\MW2\miles\mssmp3.asi 0A0C0000 0002A000 mssvoice C:\games\MW2\miles\mssvoice.asi 0A0F0000 0001D000 milesEq C:\games\MW2\miles\milesEq.flt 0A110000 00006000 mssds3d C:\games\MW2\miles\mssds3d.flt 0A120000 00012000 mssdsp 7.0w C:\games\MW2\miles\mssdsp.flt 0A140000 00011000 msseax C:\games\MW2\miles\msseax.flt 10000000 00521000 iw4x_1pi 0.5.4 C:\games\MW2\iw4x.dll 18000000 00033000 binkw32 1.8x C:\games\MW2\binkw32.dll 21100000 00097000 mss32 7.0w C:\games\MW2\mss32.dll 7A840000 00109000 opengl32 5.1.2600.2082 C:\windows\system32\opengl32.dll 7B420000 003D6000 KERNEL32 5.01.2600.2180 C:\windows\system32\KERNEL32.dll 7BC40000 000EC000 ntdll 6.1.7601.24059 C:\windows\system32\ntdll.dll ... --- snip ---
Relevant list of hooked API entry points:
--- snip --- Address Name Destination 7B46589B LoadLibraryA E9 B0FDDC94 JMP iw4x_1pi.10235650 7B465710 LoadLibraryExA E9 33FFDC94 JMP iw4x_1pi.10235648 7B4658DF LoadLibraryW E9 6CFDDC94 JMP iw4x_1pi.10235650 7B465779 LoadLibraryExW E9 CAFEDC94 JMP iw4x_1pi.10235648 --- snip ---
--- snip --- 10235648 33C0 XOR EAX,EAX 1023564A C2 0C00 RETN 0C ... 10235650 33C0 XOR EAX,EAX 10235652 C2 0400 RETN 4 --- snip ---
As you can see the protection scheme essentially no-ops LoadLibrary() after the hooks have been set up which harms Wine later.
https://source.winehq.org/git/wine.git/blob/HEAD:/dlls/user32/message.c#l239...
--- snip --- 2395 /*********************************************************************** 2396 * process_keyboard_message 2397 * 2398 * returns TRUE if the contents of 'msg' should be passed to the application 2399 */ 2400 static BOOL process_keyboard_message( MSG *msg, UINT hw_id, HWND hwnd_filter, 2401 UINT first, UINT last, BOOL remove ) 2402 { 2403 EVENTMSG event; ... 2466 accept_hardware_message( hw_id, remove ); 2467 msg->pt = point_phys_to_win_dpi( msg->hwnd, msg->pt ); 2468 2469 if ( remove && msg->message == WM_KEYDOWN ) 2470 if (ImmProcessKey(msg->hwnd, GetKeyboardLayout(0), msg->wParam, msg->lParam, 0) ) 2471 msg->wParam = VK_PROCESSKEY; 2472 2473 return TRUE; 2474 } --- snip ---
https://source.winehq.org/git/wine.git/blob/HEAD:/dlls/user32/Makefile.in
--- snip --- 6 DELAYIMPORTS = hid imm32 setupapi usp10 --- snip ---
https://source.winehq.org/git/wine.git/blob/HEAD:/dlls/winecrt0/delay_load.c...
--- snip --- 40 41 FARPROC WINAPI DECLSPEC_HIDDEN __wine_spec_delay_load( unsigned int id ) 42 { 43 struct ImgDelayDescr *descr = __wine_spec_delay_imports + HIWORD(id); 44 WORD func = LOWORD(id); 45 FARPROC proc; 46 47 if (!*descr->phmod) *descr->phmod = LoadLibraryA( descr->szName ); 48 if (!*descr->phmod || 49 !(proc = GetProcAddress( *descr->phmod, (LPCSTR)descr->pINT[func].u1.Function ))) 50 proc = DelayLoadFailureHook( descr->szName, (LPCSTR)descr->pINT[func].u1.Function ); 51 descr->pIAT[func].u1.Function = (ULONG_PTR)proc; 52 return proc; 53 } 54 55 #if defined(__GNUC__) && !defined(__APPLE__) /* we can't support destructors properly on Mac OS */ 56 static void free_delay_imports(void) __attribute__((destructor)); 57 static void free_delay_imports(void) 58 { 59 struct ImgDelayDescr *descr; 60 for (descr = __wine_spec_delay_imports; descr->szName; descr++) 61 if (*descr->phmod) FreeLibrary( *descr->phmod ); 62 } 63 #endif --- snip ---
Wine's delay load implementation uses LoadLibraryA() which has been made a no-op by the client protection, hence the failure.
There are multiple ways to fix this:
* don't delay load 'imm32.dll' from user32.dll' * use native API for loading the module * try GetModuleHandleExA() first before LoadLibraryA()
For quick testing I went for the third option. GetModuleHandleExA() has to be used which increments the module's reference count as free_delay_imports() uses FreeLibrary().
ProtectionID scan:
--- snip --- -=[ ProtectionID v0.6.9.0 DECEMBER]=- (c) 2003-2017 CDKiLLER & TippeX Build 24/12/17-21:05:42 Ready... Scanning -> C:\games\MW2\iw4x.exe File Type : 32-Bit Exe (Subsystem : Win CUI / 3), Size : 4186112 (03FE000h) Byte(s) | Machine: 0x14C (I386) Compilation TimeStamp : 0x00000000 -> Thu 01st Jan 1970 00:00:00 (GMT) [LoadConfig] Struct determined as v8 (Expected size 140 | Actual size 64) [!] Executable uses SEH Tables (/SAFESEH) (16 calculated 16 recorded... 0 invalid addresses) [LoadConfig] CodeIntegrity -> Flags 0x0 | Catalog 0x0 (0) | Catalog Offset 0x53445352 | Reserved 0x92C634B2 [LoadConfig] GuardAddressTakenIatEntryTable 0x4C7E25DE | Count 0xFC1760AC (4229390508) [LoadConfig] GuardLongJumpTargetTable 0x1DA6F819 | Count 0x0 (0) [LoadConfig] HybridMetadataPointer 0x5C5C785C | DynamicValueRelocTable 0x6D347769 [LoadConfig] FailFastIndirectProc 0x64702E70 | FailFastPointer 0x62 [LoadConfig] UnknownZero1 0x0 [File Heuristics] -> Flag #1 : 00000100000000001000000000000000 (0x04008000) [Entrypoint Section Entropy] : 6.71 (section #0) ".text " | Size : 0x2D531F (2970399) byte(s) [DllCharacteristics] -> Flag : (0x0000) -> NONE [SectionCount] 6 (0x6) | ImageSize 0x6C71000 (113709056) byte(s) [VersionInfo] Product Name : IW4x [VersionInfo] Product Version : 4.2.0.0 [VersionInfo] File Description : IW4x Multiplayer [VersionInfo] File Version : 4.2.0.0 [VersionInfo] Original FileName : iw4x.exe [VersionInfo] Internal Name : iw4x [VersionInfo] Legal Copyrights : No rights reserved. [ModuleReport] [IAT] Modules -> WINMM.dll | WSOCK32.dll | iw4x.dll | mss32.dll | binkw32.dll | d3d9.dll | DSOUND.dll | POWRPROF.dll | KERNEL32.dll | USER32.dll | GDI32.dll | ADVAPI32.dll | SHELL32.dll | ole32.dll | DDRAW.dll [Debug Info] (record 1 of 1) (file offset 0x339AD0) Characteristics : 0x0 | TimeDateStamp : 0x0 () | MajorVer : 0 / MinorVer : 0 -> (0.0) Type : 2 (0x2) -> CodeView | Size : 0x6B (107) AddressOfRawData : 0x390E18 | PointerToRawData : 0x390E18 CvSig : 0x53445352 | SigGuid 92C634B2-25DE-4C7E-AC6017FC19F8A61D Age : 0x0 (0) | Pdb : \x\iw4mp.pdb [i] additional feature : Valve CEG - Custom Executable Generation [.] CEG Build Version : 1, 1, 0, 1525 [.] CEG Product Version : 1, 1, 0, 1525 [.] CEG Build GUID : 3AE713D6-1855-4e8e-B3E7-8803674E1496 [.] CEG Build Machine : neilk2 [.] CEG Build Client Spec : neilk2_main2 [CdKeySerial] found "CDKey" @ VA: 0x002EEB9B / Offset: 0x002EEB9B [CdKeySerial] found "Unregistered" @ VA: 0x002F0B9D / Offset: 0x002F0B9D [CdKeySerial] found "Unregistered" @ VA: 0x00304BC6 / Offset: 0x00304BC6 [CdKeySerial] found "Unregistered" @ VA: 0x00306352 / Offset: 0x00306352 [CdKeySerial] found "Unregistered" @ VA: 0x0032BEAA / Offset: 0x0032BEAA [CompilerDetect] -> Visual C++ 8.0 (Visual Studio 2005) - Scan Took : 1.982 Second(s) [0000003FAh (1018) tick(s)] [506 of 580 scan(s) done]
Scanning -> C:\games\MW2\iw4x.dll File Type : 32-Bit Dll (Subsystem : Win GUI / 2), Size : 3061760 (02EB800h) Byte(s) | Machine: 0x14C (I386) Compilation TimeStamp : 0x5B7C4380 -> Tue 21st Aug 2018 16:53:20 (GMT) [TimeStamp] 0x5B7C4380 -> Tue 21st Aug 2018 16:53:20 (GMT) | PE Header | - | Offset: 0x00000120 | VA: 0x10000120 | - [TimeStamp] 0xFFFFFFFF -> Sun 07th Feb 2106 06:28:15 (GMT) | Export | - | Offset: 0x002C8A84 | VA: 0x104FC484 | - [!] Executable uses TLS callbacks (2 total... 0 invalid addresses) [LoadConfig] Struct determined as v8 (Expected size 140 | Actual size 64) [!] Executable uses SEH Tables (/SAFESEH) (2078 calculated 2062 recorded... 14 invalid addresses) [!] * table may be compressed / encrypted * [LoadConfig] CodeIntegrity -> Flags 0x0 | Catalog 0x0 (0) | Catalog Offset 0x0 | Reserved 0x0 [LoadConfig] GuardAddressTakenIatEntryTable 0x0 | Count 0x0 (0) [LoadConfig] GuardLongJumpTargetTable 0x0 | Count 0x0 (0) [LoadConfig] HybridMetadataPointer 0x0 | DynamicValueRelocTable 0x0 [LoadConfig] FailFastIndirectProc 0x0 | FailFastPointer 0x0 [LoadConfig] UnknownZero1 0x0 [File Heuristics] -> Flag #1 : 00000000000000001101000100000000 (0x0000D100) [Entrypoint Section Entropy] : 6.59 (section #0) ".UPX0 " | Size : 0x21FC60 (2227296) byte(s) [DllCharacteristics] -> Flag : (0x0140) -> ASLR | DEP [SectionCount] 5 (0x5) | ImageSize 0x521000 (5378048) byte(s) [Export] 100% of function(s) (65 of 65) are in file | 0 are forwarded | 64 code | 1 data | 0 uninit data | 0 unknown | [VersionInfo] Company Name : IW4x [VersionInfo] Product Name : IW4x [VersionInfo] Product Version : 0.5.4 [VersionInfo] File Description : IW4 client modification [VersionInfo] File Version : 0.5.4 [VersionInfo] Original FileName : iw4x.dll [VersionInfo] Internal Name : iw4x [VersionInfo] Legal Copyrights : Copyright 2017 The IW4x Team. All rights reserved. [ModuleReport] [IAT] Modules -> KERNEL32.DLL | ADVAPI32.dll | d3d9.dll | d3dx9_40.dll | dbghelp.dll | SHELL32.dll | SHLWAPI.dll | urlmon.dll | USER32.dll | WININET.dll | WINMM.dll | WS2_32.dll [Raw/Hidden Debug Record] (File Offset 0x292FA8) CvSig : 0x53445352 | SigGuid 83F25363-D6E3-4E6C-A99E39AA34FA867B Age : 0xD (13) | Pdb : F:\Git\iw4x\build\bin\Release\iw4x.pdb [CdKeySerial] found "Invalid code" @ VA: 0x004AD2A0 / Offset: 0x002798A0 [CdKeySerial] found "Invalid code" @ VA: 0x004AD2D8 / Offset: 0x002798D8 [!] File appears to have no protection or is using an unknown protection - Scan Took : 0.734 Second(s) [0000002DEh (734) tick(s)] [246 of 580 scan(s) done] --- snip ---
$ sha1sum * 5954d619517fd1db1fb8d3ea8a433e493f745fa5 installer_legacy.exe f82b22e39458212a4dbc3794624a967e28f24628 iw4x_files.zip 00b63831ed7b8abf5191fc308bd135a63d15a000 MW2.zip
$ du -sh * 2.4M installer_legacy.exe 99M iw4x_files.zip 12G MW2.zip
$ wine --version wine-3.17-74-gee206a3760
Regards
https://bugs.winehq.org/show_bug.cgi?id=45936
zzzzzyzz@hacari.org changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |zzzzzyzz@hacari.org
https://bugs.winehq.org/show_bug.cgi?id=45936
--- Comment #5 from huematrix@mailinator.com --- Still broken in 3.18-staging
https://bugs.winehq.org/show_bug.cgi?id=45936
--- Comment #6 from huematrix@mailinator.com --- There's a workaround for this, but you have to alt-tab while the game is loading, it works most of the time. Still worth checking out :)
https://bugs.winehq.org/show_bug.cgi?id=45936
huematrix@mailinator.com changed:
What |Removed |Added ---------------------------------------------------------------------------- Version|3.17 |3.21
https://bugs.winehq.org/show_bug.cgi?id=45936
Zebediah Figura z.figura12@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- Version|3.21 |3.17 CC|leslie_alistair@hotmail.com | |, z.figura12@gmail.com |
--- Comment #7 from Zebediah Figura z.figura12@gmail.com --- Please don't change the original reported version; a comment saying that the bug is still present is enough.
https://bugs.winehq.org/show_bug.cgi?id=45936
--- Comment #8 from Anastasius Focht focht@gmx.net --- Hello folks,
revisiting, obviously still present.
$ wine --version wine-4.7-98-gd48ffbdc01
Regards
https://bugs.winehq.org/show_bug.cgi?id=45936
mirh mirh@protonmail.ch changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |mirh@protonmail.ch
--- Comment #9 from mirh mirh@protonmail.ch --- So.. Like, the thing has gone open source just for the records. Not sure if it couldn't help.
https://github.com/IW4x/iw4x-client
https://bugs.winehq.org/show_bug.cgi?id=45936
--- Comment #10 from Anastasius Focht focht@gmx.net --- Hello mirh,
--- quote --- So.. Like, the thing has gone open source just for the records. Not sure if it couldn't help. --- quote ---
well, it essentially confirms my analysis for LoadLibrary{Ex}{A,W} hooks. The issue is obviously still present.
https://github.com/IW4x/iw4x-client/blob/23e9aa7ac0107a3a7a8c7cda2de4287f127...
--- snip --- void AntiCheat::InitLoadLibHook() { __VMProtectBeginUltra(""); static uint8_t kernel32Str[] = { 0xB4, 0x9A, 0x8D, 0xB1, 0x9A, 0x93, 0xCC, 0xCD, 0xD1, 0x9B, 0x93, 0x93 }; // KerNel32.dll static uint8_t loadLibAStr[] = { 0xB3, 0x90, 0x9E, 0x9B, 0xB3, 0x96, 0x9D, 0x8D, 0x9E, 0x8D, 0x86, 0xBE }; // LoadLibraryA static uint8_t loadLibWStr[] = { 0xB3, 0x90, 0x9E, 0x9B, 0xB3, 0x96, 0x9D, 0x8D, 0x9E, 0x8D, 0x86, 0xA8 }; // LoadLibraryW
HMODULE kernel32 = GetModuleHandleA(Utils::String::XOR(std::string(reinterpret_cast<char*>(kernel32Str), sizeof kernel32Str), -1).data()); if (kernel32) { FARPROC loadLibA = GetProcAddress(kernel32, Utils::String::XOR(std::string(reinterpret_cast<char*>(loadLibAStr), sizeof loadLibAStr), -1).data()); FARPROC loadLibW = GetProcAddress(kernel32, Utils::String::XOR(std::string(reinterpret_cast<char*>(loadLibWStr), sizeof loadLibWStr), -1).data());
std::string libExA = Utils::String::XOR(std::string(reinterpret_cast<char*>(loadLibAStr), sizeof loadLibAStr), -1); std::string libExW = Utils::String::XOR(std::string(reinterpret_cast<char*>(loadLibWStr), sizeof loadLibWStr), -1);
libExA.insert(libExA.end() - 1, 'E'); libExA.insert(libExA.end() - 1, 'x');
libExW.insert(libExW.end() - 1, 'E'); libExW.insert(libExW.end() - 1, 'x');
FARPROC loadLibExA = GetProcAddress(kernel32, libExA.data()); FARPROC loadLibExW = GetProcAddress(kernel32, libExW.data());
if (loadLibA && loadLibW && loadLibExA && loadLibExW) { #ifdef DEBUG_LOAD_LIBRARY AntiCheat::LoadLibHook[0].initialize(loadLibA, LoadLibaryAStub, HOOK_JUMP); AntiCheat::LoadLibHook[1].initialize(loadLibW, LoadLibaryWStub, HOOK_JUMP); AntiCheat::LoadLibHook[2].initialize(loadLibExA, LoadLibaryExAStub, HOOK_JUMP); AntiCheat::LoadLibHook[3].initialize(loadLibExW, LoadLibaryExWStub, HOOK_JUMP); #else static uint8_t loadLibStub[] = { 0x33, 0xC0, 0xC2, 0x04, 0x00 }; // xor eax, eax; retn 04h static uint8_t loadLibExStub[] = { 0x33, 0xC0, 0xC2, 0x0C, 0x00 }; // xor eax, eax; retn 0Ch AntiCheat::LoadLibHook[0].initialize(loadLibA, loadLibStub, HOOK_JUMP); AntiCheat::LoadLibHook[1].initialize(loadLibW, loadLibStub, HOOK_JUMP); AntiCheat::LoadLibHook[2].initialize(loadLibExA, loadLibExStub, HOOK_JUMP); AntiCheat::LoadLibHook[3].initialize(loadLibExW, loadLibExStub, HOOK_JUMP); #endif } }
static uint8_t ldrLoadDllStub[] = { 0x33, 0xC0, 0xC2, 0x10, 0x00 }; static uint8_t ldrLoadDll[] = { 0xB3, 0x9B, 0x8D, 0xB3, 0x90, 0x9E, 0x9B, 0xBB, 0x93, 0x93 }; // LdrLoadDll
HMODULE ntdll = Utils::GetNTDLL(); //AntiCheat::LoadLibHook[4].initialize(GetProcAddress(ntdll, Utils::String::XOR(std::string(reinterpret_cast<char*>(ldrLoadDll), sizeof ldrLoadDll), -1).data()), ldrLoadDllStub, HOOK_JUMP);
// Patch LdrpLoadDll Utils::Hook::Signature::Container container; container.signature = "\x8B\xFF\x55\x8B\xEC\x83\xE4\xF8\x81\xEC\x00\x00\x00\x00\xA1\x00\x00\x00\x00\x33\xC4\x89\x84\x24\x00\x00\x00\x00\x53\x8B\x5D\x10\x56\x57"; container.mask = "xxxxxxxxxx????x????xxxxx????xxxxxx"; container.callback = [](char* addr) { static uint8_t ldrpLoadDllStub[] = { 0x33, 0xC0, 0xC2, 0x0C, 0x00 }; AntiCheat::LoadLibHook[5].initialize(addr, ldrpLoadDllStub, HOOK_JUMP); };
Utils::Hook::Signature signature(ntdll, Utils::GetModuleSize(ntdll)); signature.add(container); //signature.process();
__VMProtectEnd; } --- snip ---
$ wine --version wine-5.6-299-gf65cfbfe9b
Regards