[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