[Bug 44585] Blizzard Diablo III v2. 6. 1. 49286+ crashes with setup_exception_record stack overflow (needs ntdll.LdrRegisterDllNotification/ LdrUnregisterDllNotification implementation)

wine-bugs at winehq.org wine-bugs at winehq.org
Fri Feb 23 18:47:44 CST 2018


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

Anastasius Focht <focht at gmx.net> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
    Staged patchset|                            |https://github.com/wine-sta
                   |                            |ging/wine-staging/tree/mast
                   |                            |er/patches/ntdll-LdrRegiste
                   |                            |rDllNotification
                URL|                            |https://eu.battle.net/accou
                   |                            |nt/download/
             Status|UNCONFIRMED                 |STAGED
           Keywords|                            |download, obfuscation
          Component|-unknown                    |ntdll
                 CC|                            |focht at gmx.net
            Summary|Diablo III doesn't launch,  |Blizzard Diablo III v2. 6.
                   |stops at                    |1. 49286+ crashes with
                   |"setup_exception_record     |setup_exception_record
                   |stack overflow ..."         |stack overflow (needs
                   |                            |ntdll.LdrRegisterDllNotific
                   |                            |ation/LdrUnregisterDllNotif
                   |                            |ication implementation)
     Ever confirmed|0                           |1

--- Comment #1 from Anastasius Focht <focht at gmx.net> ---
Hello folks,

confirming.

The game executable seems to be wrapped with some custom protection scheme.

TLS callback installs VEH to decrypt entry point code via privileged
instruction exception handling (HLT, UD2).

--- snip ---
$ pwd
/home/focht/wine-games/wineprefix64-bnet/drive_c/Program Files (x86)/Diablo III

$ WINEDEBUG=+seh,+relay wine ./Diablo\ III.exe -launch >>log.txt 2>&1
...
002e:Ret  TLS callback
(proc=0x6aa080,module=0x400000,reason=PROCESS_ATTACH,reserved=0)
002e:Call TLS callback
(proc=0x40d450,module=0x400000,reason=PROCESS_ATTACH,reserved=0)
002e:Call ntdll.RtlAddVectoredExceptionHandler(00000001,00422ae0) ret=0040bd2c
002e:Ret  ntdll.RtlAddVectoredExceptionHandler() retval=0012df98 ret=0040bd2c
002e:trace:seh:raise_exception code=c0000096 flags=0 addr=0x40bdc4 ip=0040bdc4
tid=002e
002e:trace:seh:raise_exception  eax=00000000 ebx=7bc30000 ecx=7bc37070
edx=7bcf7604 esi=7bcf07e8 edi=00000000
002e:trace:seh:raise_exception  ebp=0033e2a0 esp=0033e26c cs=0023 ds=002b
es=002b fs=0063 gs=006b flags=00010246
002e:trace:seh:call_vectored_handlers calling handler at 0x422ae0 code=c0000096
flags=0
002e:trace:seh:call_vectored_handlers handler at 0x422ae0 returned ffffffff
002e:trace:seh:raise_exception code=c0000096 flags=0 addr=0x40c0b1 ip=0040c0b1
tid=002e
002e:trace:seh:raise_exception  eax=7b42ea00 ebx=7b6416b0 ecx=0000ea60
edx=7b420000 esi=7b642a4c edi=00000000
002e:trace:seh:raise_exception  ebp=0033e2a0 esp=0033e26c cs=0023 ds=002b
es=002b fs=0063 gs=006b flags=00010246
002e:trace:seh:call_vectored_handlers calling handler at 0x422ae0 code=c0000096
flags=0 
...
002e:Call KERNEL32.VirtualAlloc(00000000,000111f8,00003000,00000040)
ret=0040e721
002e:Ret  KERNEL32.VirtualAlloc() retval=00340000 ret=0040e721
002e:Call
ntdll.NtCreateSection(0033e7f0,000f001f,00000000,0033e7c8,00000040,08400000,00000000)
ret=0040e820
002e:Ret  ntdll.NtCreateSection() retval=00000000 ret=0040e820
002e:Call
KERNEL32.MapViewOfFileEx(00000040,000f001f,00000000,00000000,00000000,00000000)
ret=0040e917
002e:Ret  KERNEL32.MapViewOfFileEx() retval=025e0000 ret=0040e917
002e:Call KERNEL32.VirtualProtect(00400000,021d7000,00000040,0033e7e8)
ret=0040e970
002e:Ret  KERNEL32.VirtualProtect() retval=00000001 ret=0040e970
002e:trace:seh:raise_exception code=c0000096 flags=0 addr=0x40ea2b ip=0040ea2b
tid=002e
002e:trace:seh:raise_exception  eax=5f703102 ebx=0033e954 ecx=00000000
edx=00000002 esi=025d7000 edi=0033e3c0
002e:trace:seh:raise_exception  ebp=0033e940 esp=0033e2b0 cs=0023 ds=002b
es=002b fs=0063 gs=006b flags=00010202
002e:trace:seh:call_vectored_handlers calling handler at 0x422ae0 code=c0000096
flags=0
002e:trace:seh:call_vectored_handlers handler at 0x422ae0 returned ffffffff
002e:Call KERNEL32.UnmapViewOfFile(00400000) ret=00351179
002e:Ret  KERNEL32.UnmapViewOfFile() retval=00000001 ret=00351179
002e:Call
KERNEL32.MapViewOfFileEx(00000040,00000024,00000000,00000000,01770000,00400000)
ret=003511d9
002e:Ret  KERNEL32.MapViewOfFileEx() retval=00400000 ret=003511d9
002e:Call
KERNEL32.MapViewOfFileEx(00000040,00000006,00000000,01770000,00420000,01b70000)
ret=003511d9
002e:Ret  KERNEL32.MapViewOfFileEx() retval=01b70000 ret=003511d9
002e:Call
KERNEL32.MapViewOfFileEx(00000040,00000004,00000000,01b90000,00000000,01f90000)
ret=003511d9
002e:Ret  KERNEL32.MapViewOfFileEx() retval=01f90000 ret=003511d9 
002e:trace:seh:raise_exception code=c0000096 flags=0 addr=0x40ebd1 ip=0040ebd1
tid=002e
002e:trace:seh:raise_exception  eax=00000003 ebx=0033e954 ecx=0033e144
edx=00000000 esi=00415960 edi=003511f8
002e:trace:seh:raise_exception  ebp=0033e940 esp=0033e2b0 cs=0023 ds=002b
es=002b fs=0063 gs=006b flags=00010213
002e:trace:seh:call_vectored_handlers calling handler at 0x422ae0 code=c0000096
flags=0
002e:trace:seh:call_vectored_handlers handler at 0x422ae0 returned ffffffff 
...
002e:Call ntdll.RtlRemoveVectoredExceptionHandler(0012df98) ret=004101e9
002e:Ret  ntdll.RtlRemoveVectoredExceptionHandler() retval=00000001
ret=004101e9
...
--- snip ---

Custom imports resolver, with dynamic thunk creation

--- snip ---
...
002e:Call KERNEL32.LoadLibraryA(0033dedc "KERNEL32.dll") ret=00418c89
002e:Ret  KERNEL32.LoadLibraryA() retval=7b420000 ret=00418c89
002e:Call KERNEL32.VirtualAlloc(00000000,00001000,00001000,00000040)
ret=00419133
002e:Ret  KERNEL32.VirtualAlloc() retval=00370000 ret=00419133
002e:Call KERNEL32.GetProcAddress(7b420000,0033d9ec "FlushViewOfFile")
ret=0041953e
002e:Ret  KERNEL32.GetProcAddress() retval=7b42fcd8 ret=0041953e
002e:Call KERNEL32.GetProcAddress(7b420000,0033d9ec "UnlockFileEx")
ret=0041953e
002e:Ret  KERNEL32.GetProcAddress() retval=7b433998 ret=0041953e 
...
--- snip ---

Example of win32 API call via generated thunk:

--- snip ---
...
0115AF01  FF75 0C        PUSH DWORD PTR SS:[EBP+C]
0115AF04  50             PUSH EAX                    ; thunk for
0115AF05  FF15 24157301  CALL DWORD PTR DS:[1731524] ; KERNEL32.GetProcAddress
0115AF0B  8BF0           MOV ESI,EAX
0115AF0D  85F6           TEST ESI,ESI
0115AF0F  74 13          JE SHORT 0115AF24

thunk:

--- snip ---
...
01731524  003F0A6E
...
003F0A6E  B8 1276EBCA    MOV EAX,CAEB7612
003F0A73  E9 B4FDFFFF    JMP 003F082C
...
003F082C  2D 413A9229    SUB EAX,29923A41
003F0831  05 0B7E7417    ADD EAX,17747E0B
003F0836  35 EBE9F83C    XOR EAX,3CF8E9EB
003F083B  E9 62060000    JMP 003F0EA2
...
003F0EA2  2D 93E96315    SUB EAX,1563E993
003F0EA7  E9 1CFFFFFF    JMP 003F0DC8
...
003F0DC8  05 9FD9740C    ADD EAX,0C74D99F
003F0DCD  FFE0           JMP EAX       ; -> real KERNEL32.GetProcAddress

Wine KERNEL32.GetProcAddress:

7B464043  8D4C24 04      LEA ECX,DWORD PTR SS:[ESP+4]
7B464047  83E4 F0        AND ESP,FFFFFFF0
7B46404A  FF71 FC        PUSH DWORD PTR DS:[ECX-4]
7B46404D  55             PUSH EBP
7B46404E  89E5           MOV EBP,ESP
7B464050  51             PUSH ECX
7B464051  83EC 04        SUB ESP,4
7B464054  89C8           MOV EAX,ECX
7B464056  83EC 08        SUB ESP,8
7B464059  FF70 04        PUSH DWORD PTR DS:[EAX+4]
7B46405C  FF30           PUSH DWORD PTR DS:[EAX]
7B46405E  E8 C7FFFFFF    CALL 7B46402A
...
--- snip ---

Mappings:

--- snip ---
00400000  00001000  Diablo_III          PE header     Map  R E      R E
00401000  01330000  Diablo_III .text    Code          Map  R E      R E
01731000  0043F000  Diablo_III .rdata   Imports       Map  R E      R E
01B70000  0000B000  Diablo_III .rdata   Exports       Map  RW       RW
01B7B000  00403000  Diablo_III .data    Data          Map  RW       RW
01F7E000  00001000  Diablo_III stkresv                Map  RW       RW
01F7F000  00001000  Diablo_III .gfids                 Map  RW       RW
01F80000  00001000  Diablo_III .tls                   Map  RW       RW
01F81000  0000A000  Diablo_III _RDATA                 Map  RW       RW
01F8B000  00005000  Diablo_III .rsrc    Resources     Map  RW       RW
01F90000  0052C000  Diablo_III .rsrc    Resources     Map  R        R
024BC000  0011B000  Diablo_III .reloc   Relocations   Map  R        R
--- snip ---

A few native API functions get directly resolved in memory by walking the
export table, with no visible 'GetProcAddress' calls.

--- snip ---
...
002e:Call KERNEL32.GetStartupInfoW(0033fe30) ret=0111c114
002e:Ret  KERNEL32.GetStartupInfoW() retval=00000011 ret=0111c114
002e:Call KERNEL32.VirtualQuery(0033fe34,0033fe38,0000001c) ret=006ad5db
002e:Ret  KERNEL32.VirtualQuery() retval=0000001c ret=006ad5db
002e:trace:seh:raise_exception code=c000001d flags=0 addr=0x6a2008 ip=006a2008
tid=002e
002e:trace:seh:raise_exception  eax=95a775b1 ebx=0033ff00 ecx=0033fe00
edx=0111b32f esi=0013703b edi=00340000
002e:trace:seh:raise_exception  ebp=0033fe1c esp=0033fde8 cs=0023 ds=002b
es=002b fs=0063 gs=006b flags=00010297
002e:trace:seh:call_stack_handlers calling handler at 0x111e8c8 code=c000001d
flags=0
002e:Call iphlpapi.GetAdaptersInfo(00339330,0033e438) ret=004f26c1
...
002e:Ret  iphlpapi.GetAdaptersInfo() retval=00000000 ret=004f26c1
002e:Call
KERNEL32.GetVolumeInformationW(00000000,00000000,00000000,0033e44c,00000000,00000000,00000000,00000000)
ret=004f28af
002e:Ret  KERNEL32.GetVolumeInformationW() retval=00000001 ret=004f28af
002e:trace:seh:raise_exception code=c0000005 flags=0 addr=(nil) ip=00000000
tid=002e
002e:trace:seh:raise_exception  info[0]=00000008
002e:trace:seh:raise_exception  info[1]=00000000
002e:trace:seh:raise_exception  eax=00000000 ebx=00000023 ecx=00000000
edx=0033f8f0 esi=0000002b edi=0000002b
002e:trace:seh:raise_exception  ebp=00000000 esp=0033f900 cs=0023 ds=002b
es=002b fs=0063 gs=006b flags=00010286
002e:trace:seh:call_stack_handlers calling handler at (nil) code=c0000005
flags=0
002e:trace:seh:raise_exception code=c0000005 flags=0 addr=(nil) ip=00000000
tid=002e
002e:trace:seh:raise_exception  info[0]=00000008
002e:trace:seh:raise_exception  info[1]=00000000
002e:trace:seh:raise_exception  eax=0033f49c ebx=00000023 ecx=00000000
edx=7bc8fecc esi=0000002b edi=0000002b
002e:trace:seh:raise_exception  ebp=0033f448 esp=0033f41c cs=0023 ds=002b
es=002b fs=0063 gs=006b flags=00010216
002e:trace:seh:call_stack_handlers calling handler at 0x7bc8fecc code=c0000005
flags=0
002e:trace:seh:call_stack_handlers handler at 0x7bc8fecc returned 2
002e:trace:seh:call_stack_handlers calling handler at (nil) code=c0000005
flags=10 
--- snip ---

The resolver doesn't handle the case properly when a native API function is
missing. It happily generates thunks that decrypt NULL pointers before the
jump.

The Wine-Staging 2.21 trace log reveals the missing native API:

--- snip ---
...
0009:Call
KERNEL32.GetVolumeInformationW(00000000,00000000,00000000,0033e3dc,00000000,00000000,00000000,00000000)
ret=004f28af
0009:Ret  KERNEL32.GetVolumeInformationW() retval=00000001 ret=004f28af
0009:Call ntdll.LdrRegisterDllNotification(00000000,006a0ce0,00000000,0033e5b8)
ret=004db5d0
0009:Ret  ntdll.LdrRegisterDllNotification() retval=00000000 ret=004db5d0
0009:Call
ntdll.NtCreateFile(0033e338,00120089,0033e2bc,0033e2b4,00000000,00000000,00000001,00000001,00000020,00000000,00000000)
ret=004e0a5f
0009:Ret  ntdll.NtCreateFile() retval=00000000 ret=004e0a5f
0009:Call
ntdll.NtQueryInformationFile(000000c0,0033e2ac,0033e294,00000018,00000005)
ret=004e0f91
0009:Ret  ntdll.NtQueryInformationFile() retval=00000000 ret=004e0f91
0009:Call
ntdll.NtAllocateVirtualMemory(ffffffff,0033e394,00000000,0033e304,00001000,00000040)
ret=004e143d
0009:Ret  ntdll.NtAllocateVirtualMemory() retval=00000000 ret=004e143d
0009:Call
ntdll.NtReadFile(000000c0,00000000,00000000,00000000,0033e2b4,05070000,00013000,00000000,00000000)
ret=004e1786
0009:Ret  ntdll.NtReadFile() retval=00000000 ret=004e1786
0009:Call
ntdll.NtAllocateVirtualMemory(ffffffff,0033e5c8,00000000,0033e628,00001000,00000004)
ret=004dbcee
0009:Ret  ntdll.NtAllocateVirtualMemory() retval=00000000 ret=004dbcee
0009:Call
user32.SetWinEventHook(00000001,7fffffff,00000000,006a3f20,00000000,00000000,00000002)
ret=004ddc86
0009:Ret  user32.SetWinEventHook() retval=0002004e ret=004ddc86 
...
--- snip ---

These are Vista+ native API:

* ntdll.LdrRegisterDllNotification
* ntdll.LdrUnregisterDllNotification

https://github.com/wine-staging/wine-staging/tree/master/patches/ntdll-LdrRegisterDllNotification

The callback is likely used for anti-cheat/hack protection to:

* filter for known/unwanted modules
* consistency check in combination with other module enumeration methods
* resolving API at very early stage/hooking
* pre-patching code before module attach/detach notifications are being sent
* replace/redirect the loaded module entry point
...
* profit!

ProtectionID scan for exact version:

--- snip ---
-=[ ProtectionID v0.6.9.0 DECEMBER]=-
(c) 2003-2017 CDKiLLER & TippeX
Build 24/12/17-21:05:42
Ready...
Scanning -> Z:\home\focht\wine-games\wineprefix64-bnet\drive_c\Program Files
(x86)\Diablo III\Diablo III.exe
File Type : 32-Bit Exe (Subsystem : Win GUI / 2), Size : 31663592 (01E325E8h)
Byte(s) | Machine: 0x14C (I386)
Compilation TimeStamp : 0x5A839757 -> Wed 14th Feb 2018 01:56:39 (GMT)
[TimeStamp] 0x5A839757 -> Wed 14th Feb 2018 01:56:39 (GMT) | PE Header | - |
Offset: 0x00000178 | VA: 0x00400178 | -
[TimeStamp] 0x5A83974F -> Wed 14th Feb 2018 01:56:31 (GMT) | Export | - |
Offset: 0x0176EC84 | VA: 0x01B70484 | -
[TimeStamp] 0x5A839757 -> Wed 14th Feb 2018 01:56:39 (GMT) | DebugDirectory | -
| Offset: 0x015380D4 | VA: 0x019398D4 | -
[TimeStamp] 0x5A839757 -> Wed 14th Feb 2018 01:56:39 (GMT) | DebugDirectory | -
| Offset: 0x015380F0 | VA: 0x019398F0 | -
[TimeStamp] 0x5A839757 -> Wed 14th Feb 2018 01:56:39 (GMT) | DebugDirectory | -
| Offset: 0x0153810C | VA: 0x0193990C | -
-> File Appears to be Digitally Signed @ Offset 01E30E00h, size : 017E8h /
06120 byte(s)
[!] Executable uses TLS callbacks (3 total... 0 invalid addresses)
[LoadConfig] Struct determined as v8 (Expected size 140 | Actual size 64)
[!] Executable uses SEH Tables (/SAFESEH) (33371 calculated 33199 recorded...
70 invalid addresses) 
[!]    * table may be compressed / encrypted *
[LoadConfig] CodeIntegrity -> Flags 0x7C34 | Catalog 0xBFD3 (49107) | Catalog
Offset 0x2FE93D5F | Reserved 0x49CB461F
[LoadConfig] GuardAddressTakenIatEntryTable 0x4F29FF9C | Count 0x992AA633
(2569709107)
[LoadConfig] GuardLongJumpTargetTable 0x12E9CCF3 | Count 0xB9F3D522
(3119764770)
[LoadConfig] HybridMetadataPointer 0x21CA7CB6 | DynamicValueRelocTable
0xF1654DDC
[LoadConfig] FailFastIndirectProc 0x64AE2974 | FailFastPointer 0xCA03C693
[LoadConfig] UnknownZero1 0x6B52C00
[!] Warning: Imports (+size) goes outside of the file
[File Heuristics] -> Flag #1 : 00000100000001001101000100110100 (0x0404D134)
[Entrypoint Section Entropy] : 8.00 (section #0) ".text   " | Size : 0x132F368
(20116328) byte(s)
[DllCharacteristics] -> Flag : (0x8140) -> ASLR | DEP | TSA
[SectionCount] 9 (0x9) | ImageSize 0x21D7000 (35483648) byte(s)
[Export] 96% of function(s) (357 of 369) are in file | 0 are forwarded | 343
code | 26 data | 0 uninit data | 0 unknown | 
[VersionInfo] Company Name : Blizzard Entertainment
[VersionInfo] Product Name : Diablo III
[VersionInfo] Product Version : Version 2.6
[VersionInfo] File Description : Diablo III Retail
[VersionInfo] File Version : 2. 6. 1. 49286
[VersionInfo] Original FileName : Diablo III.exe
[VersionInfo] Internal Name : Diablo III
[VersionInfo] Legal Copyrights : Copyright © 2011-2014
[ModuleReport] [IAT] Modules -> USER32.dll
[Debug Info] (record 1 of 3) (file offset 0x15380D0)
Characteristics : 0x0 | TimeDateStamp : 0x5A839757 (Wed 14th Feb 2018 01:56:39
(GMT)) | MajorVer : 0 / MinorVer : 0 -> (0.0)
Type : 2 (0x2) -> CodeView | Size : 0x53 (83) 
AddressOfRawData : 0x158C96C | PointerToRawData : 0x158B16C
CvSig : 0x53445352 | SigGuid E65D58F8-37DC-47BC-B32D251EF458F1F8
Age : 0x1 (1) | Pdb : D:\BuildServer\4\work\code\branches\Release\Diablo
III.pdb
[Debug Info] (record 2 of 3) (file offset 0x15380EC)
Characteristics : 0x0 | TimeDateStamp : 0x5A839757 (Wed 14th Feb 2018 01:56:39
(GMT)) | MajorVer : 0 / MinorVer : 0 -> (0.0)
Type : 12 (0xC) -> Undocumented | Size : 0x14 (20) 
AddressOfRawData : 0x158C9C0 | PointerToRawData : 0x158B1C0
[Debug Info] (record 3 of 3) (file offset 0x1538108)
Characteristics : 0x0 | TimeDateStamp : 0x5A839757 (Wed 14th Feb 2018 01:56:39
(GMT)) | MajorVer : 0 / MinorVer : 0 -> (0.0)
Type : 13 (0xD) -> Undocumented | Size : 0x828 (2088) 
AddressOfRawData : 0x158C9D4 | PointerToRawData : 0x158B1D4
[CdKeySerial] found "Invalid code" @ VA: 0x0133D078 / Offset: 0x0133B878
[CdKeySerial] found "SerialNumber" @ VA: 0x0147899F / Offset: 0x0147719F
[CdKeySerial] found "Invalid code" @ VA: 0x014C7980 / Offset: 0x014C6180
[CompilerDetect] -> Visual C++ 14.0 (Visual Studio 2015)
[!] File appears to have no protection or is using an unknown protection
- Scan Took : 5.583 Second(s) [000001529h (5417) tick(s)] [506 of 580 scan(s)
done]
--- snip ---

$ wine --version
wine-3.2-173-gea82a00a42

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