[Bug 30543] Multiple apps crash/terminate because K32GetModuleFileNameExW overflows supplied buffer

wine-bugs at winehq.org wine-bugs at winehq.org
Tue May 1 07:01:11 CDT 2012


http://bugs.winehq.org/show_bug.cgi?id=30543

Anastasius Focht <focht at gmx.net> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |focht at gmx.net
            Summary|K32GetModuleFileNameExW     |Multiple apps
                   |segfault                    |crash/terminate because
                   |                            |K32GetModuleFileNameExW
                   |                            |overflows supplied buffer

--- Comment #7 from Anastasius Focht <focht at gmx.net> 2012-05-01 07:01:11 CDT ---
Hello,

I encountered this problem with another app which also indicates
K32GetModuleFileNameExW() needs some more fixing.

Download:
http://download.sonymediasoftware.com/current/cdarchitect52d-trial_enu.exe

(needs 'winetricks -q mfc42' prerequisite, ignore the other bugs from
installer)

The app collects process module information on startup using
EnumProcesses/EnumProcessModules/GetModuleFileNameExW sequence.
It fails and terminates silently with 0xC0000409 (stack overflow).
Winedbg doesn't have a chance to attach due to bug 24038

App code, showing the problem (annotated):

--- snip ---
005240F0  SUB ESP,234
005240F6  MOV EAX,DWORD PTR DS:[625C1C]      ; global security cookie
005240FB  XOR EAX,ESP
005240FD  MOV DWORD PTR SS:[ESP+230],EAX     ; store local canary on stack
00524104  MOV EAX,DWORD PTR SS:[ESP+238]
0052410B  MOV ECX,DWORD PTR SS:[ESP+23C]
...
00524143  PUSH EBX
00524144  PUSH EDI
00524145  MOV EDI,DWORD PTR DS:[<&KERNEL32.GetProcAddress>]
0052414B  PUSH OFFSET 005F65B4               ; Procname = "EnumProcesses"
00524150  PUSH EBP                           ; hModule
00524151  CALL EDI                           ; KERNEL32.GetProcAddress
00524153  PUSH OFFSET 005F65A0               ; "EnumProcessModules"
00524158  PUSH EBP
00524159  MOV DWORD PTR SS:[ESP+20],EAX      ; KERNEL32.EnumProcesses
0052415D  CALL EDI                           ; KERNEL32.GetProcAddress
0052415F  PUSH OFFSET 005F6588               ; "GetModuleFileNameExW"
00524164  MOV EBX,EAX
00524166  PUSH EBP
00524167  MOV DWORD PTR SS:[ESP+38],EBX      ; KERNEL32.EnumProcessModules
0052416B  CALL EDI                           ; KERNEL32.GetProcAddress
0052416D  CMP DWORD PTR SS:[ESP+18],ESI
00524171  MOV DWORD PTR SS:[ESP+28],EAX      ; KERNEL32.GetModuleFileNameExW
...
00524197  MOV EDI,400
...
005241D9  LEA EDX,[ESP+24]
005241DD  PUSH EDX
005241DE  PUSH EDI                           ; 0x400
005241DF  PUSH ESI                           ; heap buffer (GlobalAlloc)
005241E0  CALL DWORD PTR SS:[ESP+24]         ; KERNEL32.EnumProcesses
005241E4  TEST EAX,EAX
...
00524206  PUSH EAX                           ; ProcessID
00524207  PUSH 0                             ; InheritHandle = FALSE
00524209  PUSH 410     ; Access = PROCESS_VM_READ|PROCESS_QUERY_INFORMATION
0052420E  CALL DWORD PTR DS:[<&KERNEL32.OpenProcess>] ; KERNEL32.OpenProcess
00524214  MOV EBX,EAX
...
0052421E  LEA ECX,[ESP+34]
00524222  PUSH ECX
00524223  PUSH 4
00524225  LEA EDX,[ESP+20]
00524229  PUSH EDX
0052422A  PUSH EBX                           ; hProcess
0052422B  CALL DWORD PTR SS:[ESP+40]         ; KERNEL32.EnumProcessModules
0052422F  TEST EAX,EAX
...
00524233  MOV ECX,DWORD PTR SS:[ESP+18]
00524237  PUSH 104     ; 0x104 (size of the filename buffer, in characters)
0052423C  LEA EAX,[ESP+3C]
00524240  PUSH EAX                           ; stack buffer for filename
00524241  PUSH ECX                           ; hModule
00524242  PUSH EBX                           ; hProcess
00524243  CALL DWORD PTR SS:[ESP+38]         ; KERNEL32.GetModuleFileNameExW
00524247  TEST EAX,EAX                       ; 0x20
...
005242A0  MOV ECX,DWORD PTR SS:[ESP+238]     ; get local canary back
005242A7  XOR EAX,EAX
005242A9  CMP DWORD PTR SS:[ESP+8],EAX
...
<security cookie mismatch throw 0xC0000409 and terminate process>
--- snip ---

The problem is that the local canary is partly overwritten by Wine after return
from kernel32.GetModuleFileNameExW().

0033E370 - buffer start for filename
0033E578 - stack canary

0033E370 + 0x104*2 = 0033E578

Before the call:

$+0 = start of buffer for filename

--- snip ---
$+204      00000023
$+208      C1D9AC35
$+20C      00524384
--- snip ---

After the call: 

--- snip ---
$+0      003A0043   C:
$+4      0077005C   \w
$+8      006E0069   in
$+C      006F0064   do
$+10     00730077   ws
$+14     0073005C   \s
$+18     00730079   ys
$+1C     00650074   te
$+20     0033006D   m3
$+24     005C0032   2\
$+28     00650073   se
$+2C     00760072   rv
$+30     00630069   ic
$+34     00730065   es
$+38     0065002E   .e
$+3C     00650078   xe
$+40     003B0000   .;
...
<garbage data due to ReadProcessMemory reading more than needed>
...
$+204    00000010
$+208    C1D90000
$+20C    00524384
--- snip ---

The canary was touched by Wine with following code (line 1268):

Source:
http://source.winehq.org/git/wine.git/blob/d08f34cd8ecd883a0f0c6bd9b150d92407f0f7c9:/dlls/kernel32/module.c#l1246

--- quote ---
1246 DWORD WINAPI K32GetModuleFileNameExW(HANDLE process, HMODULE module,
1247                                      LPWSTR file_name, DWORD size)
1248 {
1249     LDR_MODULE ldr_module;
1250     DWORD len;
1251 
1252     if (!size) return 0;
1253 
1254     if(!get_ldr_module(process, module, &ldr_module))
1255         return 0;
1256 
1257     len = ldr_module.FullDllName.Length / sizeof(WCHAR);
1258     if (size <= len)
1259     {
1260         len = size;
1261         size--;
1262     }
1263 
1264     if (!ReadProcessMemory(process, ldr_module.FullDllName.Buffer,
1265                            file_name, size * sizeof(WCHAR), NULL))
1266         return 0;
1267 
1268     file_name[size] = 0;
1269     return len;
1270 }
--- quote ---

Alexandre partly fixed some overflow when the caller supplied buffer was too
small with:
http://source.winehq.org/git/wine.git/commitdiff/d08f34cd8ecd883a0f0c6bd9b150d92407f0f7c9

There is garbage written to the buffer following the module name if the
supplied buffer size exceeds "ldr_module.FullDllName.Length".
Not sure if this is intended...

At least line 1268 is wrong, it writes past the end of buffer, destroying the
stack canary for the app.
The module name/path which is much shorter than supplied buffer and is already
NULL-terminated in between (see dump).

$ du -sh cdarchitect52d-trial_enu.exe 
30M    cdarchitect52d-trial_enu.exe

$ sha1sum cdarchitect52d-trial_enu.exe 
045cfb932746810b2bfb52594f31926be11ebb73  cdarchitect52d-trial_enu.exe

$ wine --version
wine-1.5.3-40-g9080f3c

Regards

-- 
Configure bugmail: http://bugs.winehq.org/userprefs.cgi?tab=email
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