http://bugs.winehq.org/show_bug.cgi?id=34623
Bug #: 34623 Summary: NCsoft's Aion (MMORPG) crashes on startup (WinLicense software protection, avoid forwarding some msvcr80 API to msvcrt) Product: Wine Version: 1.7.3 Platform: x86 OS/Version: Linux Status: NEW Severity: normal Priority: P2 Component: msvcrt AssignedTo: wine-bugs@winehq.org ReportedBy: focht@gmx.net Classification: Unclassified
Hello folks,
continuation of bug 34470 We're still 'purist' here, no winetricks (VC++ runtimes).
With msvcp80 fordwards fixed, the dll entry points from crysystem.dll and friends are successfully passed (no more exceptions with loader lock held).
Crashes at this point now invoke the registered crash handler/debugger which is obviously more helpful ;-)
Besides Winedbg, AION's own crash tool "SendLogClient.exe" gives a bit of information:
--- snip --- ... Registers: EAX=0343e13c CS=0023 EIP=f348e160 EFLGS=00010246 EBX=5653ffd8 SS=002b ESP=0032c63c EBP=0032c6a0 ECX=0349a9c0 DS=002b ESI=564dff90 FS=0063 EDX=032fe560 ES=002b EDI=0349a9c0 GS=006b Bytes at CS:EIP: 6d 73 76 63 72 74 2e 3f 3f 39 74 79 70 65 5f 69 Stack dump: 0032C63C: 032FE5AD 0349A9C0 03455245 0343E13D 564DFF90 00000000 00000000 00000000 0032C65C: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 0032C67C: 00000000 00000000 00000000 00000000 F73EE680 00000000 00000000 00000000 ... Call Stack Information F348E160 0032C6A0 0002:00008160 C:\windows\system32\msvcr80.dll Params: 0343E13C 0349A9C0 5653FFD8 5649FE00 [msvcr80.dll] Bytes at CS:EIP: 6d 73 76 63 72 74 2e 3f 3f 39 74 79 70 65 5f 69
0338A3F1 0032C710 0001:000B93F1 C:\Program Files\NCSOFT\Aion\bin32\CrySystem.dll Params: 0343E13C 0349A9C0 5653FFD8 5653FFC0 [CrySystem.dll] Bytes at CS:EIP: 5f b0 01 5e 88 43 09 5b 8b e5 5d c2 0c 00 5f 5e ... --- snip ---
The protection actually detects certain debuggers when being attached at runtime/crash time and kills them off through watcher threads.
Using tools like Imprec and LordPE one can dissemble/dump from process address space without attaching to the actual process (non-invasive method).
Using last good return address -> 0x0338A3F1 (CrySystem.dll):
--- snip --- 0338A3DC 8B45 10 mov eax,[ebp+10] 0338A3DF 8B4D 0C mov ecx,[ebp+C] 0338A3E2 8B13 mov edx,[ebx] 0338A3E4 8B52 04 mov edx,[edx+4] 0338A3E7 50 push eax 0338A3E8 8B45 08 mov eax,[ebp+8] 0338A3EB 51 push ecx 0338A3EC 50 push eax 0338A3ED 8BCB mov ecx,ebx 0338A3EF FFD2 call edx 0338A3F1 5F pop edi 0338A3F2 B0 01 mov al,1 0338A3F4 5E pop esi 0338A3F5 8843 09 mov [ebx+9],al 0338A3F8 5B pop ebx 0338A3F9 8BE5 mov esp,ebp 0338A3FB 5D pop ebp 0338A3FC C2 0C00 retn C --- snip ---
"call edx" -> edx from faulting thread context = 0x032fe560 gets the callee address:
--- snip --- 032FE560 55 push ebp 032FE561 8BEC mov ebp,esp 032FE563 83EC 50 sub esp,50 032FE566 833D B00B4C03 00 cmp dword ptr [34C0BB0],0 032FE56D 53 push ebx 032FE56E 8B5D 10 mov ebx,[ebp+10] 032FE571 56 push esi 032FE572 57 push edi 032FE573 8B7D 0C mov edi,[ebp+C] 032FE576 8BF1 mov esi,ecx 032FE578 74 27 je short 032FE5A1 032FE57A 68 7CA54903 push 349A57C 032FE57F B9 C0A94903 mov ecx,349A9C0 032FE584 90 nop 032FE585 E8 B5FB18F0 call F348E13F 032FE58A 84C0 test al,al 032FE58C 74 13 je short 032FE5A1 032FE58E 8D46 10 lea eax,[esi+10] 032FE591 50 push eax 032FE592 53 push ebx 032FE593 57 push edi 032FE594 FF15 B00B4C03 call [34C0BB0] ... --- snip ---
The interesting call is at 0x032FE585 -> "call F348E13F"
No need to disassemble the call target as it's obvious from the backtrace that the fault is caused by executing ascii characters and not opcodes.
" Bytes at CS:EIP: 6d 73 76 63 72 74 2e 3f 3f 39 74 79 70 65 5f 69 "
Dump gives:
--- snip --- F348E13F 6D 73 76 63 72 74 2E 3F 3F 38 74 79 70 65 5F 69 msvcrt.??8type_i F348E14F 6E 66 6F 40 40 51 42 45 48 41 42 56 30 40 40 5A nfo@@QBEHABV0@@Z F348E15F 00 6D 73 76 63 72 74 2E 3F 3F 39 74 79 70 65 5F .msvcrt.??9type_ F348E16F 69 6E 66 6F 40 40 51 42 45 48 41 42 56 30 40 40 info@@QBEHABV0@@ F348E17F 5A 00 6D 73 76 63 72 74 2E 3F 3F 5F 37 5F 5F 6E Z.msvcrt.??_7__n F348E18F 6F 6E 5F 72 74 74 69 5F 6F 62 6A 65 63 74 40 40 on_rtti_object@@ --- snip ---
It wants msvcr80.dll "??8type_info@@QBE_NABV0@@Z" which is unfortunately forwarded to msvcrt.dll
Source: http://source.winehq.org/git/wine.git/blob/dadb2fdfa9f73ef49a71837c3a2148305...
--- snip --- 49 @ thiscall -arch=i386 ??8type_info@@QBE_NABV0@@Z(ptr ptr) msvcrt.??8type_info@@QBEHABV0@@Z --- snip ---
Source: http://source.winehq.org/git/wine.git/blob/e931b5d17ee481798a72de2bd3103ed2d...
--- quote --- 538 /****************************************************************** 539 * ??8type_info@@QBEHABV0@@Z (MSVCRT.@) 540 */ 541 DEFINE_THISCALL_WRAPPER(MSVCRT_type_info_opequals_equals,8) 542 int __thiscall MSVCRT_type_info_opequals_equals(type_info * _this, const type_info * rhs) 543 { 544 int ret = !strcmp(_this->mangled + 1, rhs->mangled + 1); 545 TRACE("(%p %p) returning %d\n", _this, rhs, ret); 546 return ret; 547 } --- quote ---
Figuring out the list imports that can't be forwarded to msvcrt is usually done using following approach (assuming no IAT/indirect calls)...
Basically you search the mapped range of unpacked dll code section(s), checking all call/jmp destinations that match the range of mapped system dll (all sections), throw away the ones that point to code section and analyse the ones that point to other (data) section(s).
The following APIs that should not be forwarded to msvcrt:
--- quote --- msvcr80.dll.??0exception@std@@QAE@ABQBD@Z msvcr80.dll.??0exception@std@@QAE@ABQBDH@Z msvcr80.dll.??0exception@std@@QAE@ABV01@@Z msvcr80.dll.??0exception@std@@QAE@XZ msvcr80.dll.??1exception@std@@UAE@XZ msvcr80.dll.??8type_info@@QBE_NABV0@@Z msvcr80.dll.??9type_info@@QBE_NABV0@@Z msvcr80.dll.?_name_internal_method@type_info@@QBEPBDPAU__type_info_node@@@Z --- quote ---
Regards