[Bug 35788] Planetside 2 crashes on launch (uninitialized/implausible MONITORINFOA.cbSize passed to GetMonitorInfoA, causing stack buffer overwrite)

wine-bugs at winehq.org wine-bugs at winehq.org
Sat Apr 12 10:41:23 CDT 2014


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

Anastasius Focht <focht at gmx.net> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |obfuscation
                 CC|                            |focht at gmx.net
          Component|-unknown                    |user32
         Depends on|                            |32342
            Summary|Planetside 2 crashes on     |Planetside 2 crashes on
                   |launch                      |launch
                   |                            |(uninitialized/implausible
                   |                            |MONITORINFOA.cbSize passed
                   |                            |to GetMonitorInfoA, causing
                   |                            |stack buffer overwrite)

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

confirming.

--- snip ---
$ pwd
/home/focht/.wine/drive_c/Program Files/Sony Online Entertainment/Installed
Games/PlanetSide 2

$ WINEDEBUG=+tid,+seh,+relay wine ./LaunchPad.exe >>log.txt 2>&1
...
004a:Call user32.CreateWindowExA(00040100,04ca729c "Planetside2 PlayClient
(Stage) x86",0c49a3fc "Planetside2 v0.133.17.273288
x86",10ca0000,00000000,00000000,00000780,00000438,00000000,00000000,00000000,0c4ac360)
ret=0094c712
...
004a:Call window proc 0x94e170
(hwnd=0x30088,msg=WM_CREATE,wp=00000000,lp=0033e450)
004a:Call user32.MonitorFromWindow(00030088,00000001) ret=0094e21d
004a:Call winex11.drv.EnumDisplayMonitors(00000000,00000000,7ecf9f30,0033dc04)
ret=7ecfa5e5
004a:Call winex11.drv.GetMonitorInfo(00000001,0033da84) ret=7ecfa515
004a:Ret  winex11.drv.GetMonitorInfo() retval=00000001 ret=7ecfa515
004a:Ret  winex11.drv.EnumDisplayMonitors() retval=00000001 ret=7ecfa5e5
004a:Ret  user32.MonitorFromWindow() retval=00000001 ret=0094e21d
004a:Call user32.GetMonitorInfoA(00000001,0033ddec) ret=0094e228
004a:Call winex11.drv.GetMonitorInfo(00000001,0033dc70) ret=7ecfa515
004a:Ret  winex11.drv.GetMonitorInfo() retval=00000001 ret=7ecfa515
004a:Ret  user32.GetMonitorInfoA() retval=00000001 ret=0094e228
004a:Call user32.DefWindowProcA(00030088,00000001,00000000,0033e450)
ret=0094e256
004a:Ret  user32.DefWindowProcA() retval=00000000 ret=0094e256
004a:Call KERNEL32.IsDebuggerPresent() ret=012586ed
004a:Ret  KERNEL32.IsDebuggerPresent() retval=00000000 ret=012586ed
004a:Call KERNEL32.SetUnhandledExceptionFilter(00000000) ret=01258702
004a:Ret  KERNEL32.SetUnhandledExceptionFilter() retval=0091cf00 ret=01258702
004a:Call KERNEL32.UnhandledExceptionFilter(0289d718) ret=0125870d
wine: Unhandled exception 0xc0000409 in thread 4a at address 0x94e263 (thread
004a), starting debugger...
004a:trace:seh:start_debugger Starting debugger "winedbg --auto 73 1388"
004a:trace:process:create_process_impl app (null) cmdline L"winedbg --auto 73
1388"
004a:trace:process:find_exe_file looking for L"winedbg"
004a:trace:process:find_exe_file Trying native exe
L"C:\\windows\\system32\\winedbg.exe"
004a:trace:process:create_process_impl starting
L"C:\\windows\\system32\\winedbg.exe" as Win32 binary (0x10000000-0x10017000,
arch 014c)
004a:trace:process:create_process_impl started process pid 0061 tid 0062
...
004a:Ret  KERNEL32.UnhandledExceptionFilter() retval=00000000 ret=0125870d
005f:Call KERNEL32.Sleep(00000064) ret=0092d4fd
004a:Call KERNEL32.TerminateProcess(ffffffff,c0000409) ret=01258730
004a:Call KERNEL32.FreeLibrary(f7270000) ret=f70a242a
004a:Call PE DLL (proc=0xf7285318,module=0xf7270000
L"uxtheme.dll",reason=PROCESS_DETACH,res=(nil))
004a:Ret  PE DLL (proc=0xf7285318,module=0xf7270000
L"uxtheme.dll",reason=PROCESS_DETACH,res=(nil)) retval=1
004a:trace:loaddll:free_modref Unloaded module
L"C:\\windows\\system32\\uxtheme.dll" : builtin
004a:Ret  KERNEL32.FreeLibrary() retval=00000001 ret=f70a242a
Process of pid=0049 has terminated
No process loaded, cannot execute 'echo Modules:'
Cannot get info on module while no process is loaded
No process loaded, cannot execute 'echo Threads:'
process  tid      prio (all id:s are in hex)
00000008 notepad.exe
    00000009    0
0000000e services.exe
    0000001d    0
    0000001c    0
    00000014    0
    00000010    0
    0000000f    0
00000012 winedevice.exe
    0000001b    0
    00000018    0
    00000017    0
    00000013    0
00000019 plugplay.exe
    0000001f    0
    0000001e    0
    0000001a    0
00000020 explorer.exe
    00000021    0
winedbg: Internal crash at 0x7edc33b7 
--- snip ---

First, the crash reporting suffers from bug 24038
In this case 'winedbg' races against the process termination hence the internal
crash.

Relevant disassembly after dumping the main executable from memory and
rebuilding the IAT (also annotated to depict the important variables):

--- snip ---
0094E170   push    ebp
0094E171   mov     ebp, esp
0094E173   sub     esp, 0D0h
0094E179   mov     eax, _stack_canary_magic
0094E17E   xor     eax, ebp
0094E180   mov     [ebp+stack_canary], eax
...
0094E207   mov     ecx, [ebp+hwnd]
0094E20D   mov     eax, [esi]
0094E20F   push    1                              ; dwFlags
0094E211   push    ecx                            ; hwnd
0094E212   mov     dword_2DA1730, eax
0094E217   call    ds:MonitorFromWindow
0094E21D   lea     edx, [ebp+mi]
0094E220   push    edx                            ; lpmi
0094E221   push    eax                            ; hMonitor
0094E222   call    ds:GetMonitorInfoA
0094E228   mov     eax, [ebp+mi.rcMonitor.bottom]
0094E22B   sub     eax, [ebp+mi.rcMonitor.top]
0094E22E   mov     edx, [ebp+mi.rcMonitor.right]
0094E231   mov     ecx, dword_2DA1730
0094E237   sub     edx, [ebp+mi.rcMonitor.left]
0094E23A   push    esi                            ; lParam
0094E23B   push    edi                            ; wParam
0094E23C   mov     [ecx+1303Ch], eax
0094E242   mov     eax, [ebp+hwnd]
0094E248   push    ebx                            ; Msg
0094E249   push    eax                            ; hWnd
0094E24A   mov     [ecx+13038h], edx
0094E250   call    ds:DefWindowProcA
0094E256   pop     edi
0094E257   pop     esi
0094E258   pop     ebx
0094E259   mov     ecx, [ebp+_stack_canary]
0094E25C   xor     ecx, ebp
0094E25E   call    _check_stack_canary
0094E263   mov     esp, ebp
0094E265   pop     ebp
0094E266   retn    10h
...
_check_stack_canary:
0124BC85   cmp     ecx, _stack_canary_magic
0124BC8B   jnz     short loc_124BC8F
0124BC8D   rep retn
0124BC8F   jmp     _exception_stack_buffer_overrun
--- snip ---

Stack layout:

--- snip ---
-000000DC
...
-000000D0
-000000CC
-000000C8 ; hwnd
-000000C4
-000000C3
-0000002C ; 'mi' -> MONITORINFO (sizeof=0x28)
-00000004 ; stack_canary
+00000000
+00000004 ; ret addr
+00000008 ; arg_0
+0000000C ; arg_4_Msg
+00000010 ; arg_8_wParam
+00000014 ; arg_C_lParam
--- snip ---

Well, to make story short: some 'genius' forgot to initialize the 'cbSize'
member of 'MONITORINFOA' struct passed to GetMonitorInfoA().

There is a stack canary living adjacent to 'MONITORINFO' struct which gets
overwritten by Wine.
This is detected in function epilog code hence the exception (stack buffer
overrun).

There are two calls to GetMonitorInfoA() during startup, I printed the values:

--- snip ---
GetMonitorInfoA lpMonitorInfo->cbSize = 0x48
GetMonitorInfoA lpMonitorInfo->cbSize = 0x7d9ae2fc
--- snip ---

Wine needs to check for maximum allowed size -> sizeof(MONITORINFOEXA) struct
to protect against stupid apps.

This is not 100% foolproof because the uninitialized 'cbSize' value could be
still within 'sizeof(MONITORINFOA)+[1..CCHDEVICENAME]' range, allowing to write
past the buffer.

Wine:
http://source.winehq.org/git/wine.git/blob/bd262c606a5dca79aa2ec0d863bad04e4b776087:/dlls/user32/misc.c#l416

--- snip ---
416 BOOL WINAPI GetMonitorInfoA(HMONITOR hMonitor, LPMONITORINFO lpMonitorInfo)
417 {
418     MONITORINFOEXW miW;
419     MONITORINFOEXA *miA = (MONITORINFOEXA*)lpMonitorInfo;
420     BOOL ret;
421
422     miW.cbSize = sizeof(miW);
423
424     ret = GetMonitorInfoW(hMonitor, (MONITORINFO*)&miW);
425     if(!ret) return ret;
426
427     miA->rcMonitor = miW.rcMonitor;
428     miA->rcWork = miW.rcWork;
429     miA->dwFlags = miW.dwFlags;
430     if(miA->cbSize >= offsetof(MONITORINFOEXA, szDevice) +
sizeof(miA->szDevice))
431     WideCharToMultiByte(CP_ACP, 0, miW.szDevice, -1, miA->szDevice,
sizeof(miA->szDevice), NULL, NULL);
432     return ret;
433 }
--- snip ---

The game starts successfully if you add the upper bound check, catching
implausible values (I reached the lobby).

$ sha1sum PS2_setup.exe 
acc50d2d6c70a1da8b5fc1315d53a639b55451b5  PS2_setup.exe

$ du -sh PS2_setup.exe 
7.8M    PS2_setup.exe

$ wine --version
wine-1.7.16-133-gd8ca8c2

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