http://bugs.winehq.org/show_bug.cgi?id=30536
Bug #: 30536 Summary: Avanquest PDF Experte Ultimate 7.0.x installer crashes with stack overflow because user32.dll AdjustWindowRect, AdjustWindowRectEx, SetWindowLongA are not hotpatchable (DECLSPEC_HOTPATCH) Product: Wine Version: 1.5.3 Platform: x86 OS/Version: Linux Status: NEW Severity: normal Priority: P2 Component: user32 AssignedTo: wine-bugs@winehq.org ReportedBy: focht@gmx.net Classification: Unclassified
Hello,
"Avanquest PDF Experte Ultimate 7.0.x" installer dies quickly with a stack overflow.
--- snip --- $ WINEDEBUG=+tid,+seh,+process wine ./PDF\ Experte\ 7\ Ultimate.exe 002d:trace:process:init_current_directory starting in L"Z:\home\focht\Downloads\Avanquest PDF Experte Ultimate 7.0.1370.0\" 0x4 002d:trace:process:__wine_kernel_init starting process name=L"Z:\home\focht\Downloads\Avanquest PDF Experte Ultimate 7.0.1370.0\PDF Experte 7 Ultimate.exe" argv[0]=L"Z:\home\focht\Downloads\Avanquest PDF Experte Ultimate 7.0.1370.0\PDF Experte 7 Ultimate.exe" ... 0030:fixme:exec:SHELL_execute flags ignored: 0x00000100 0030:trace:process:create_process_impl app (null) cmdline L"C:\users\focht\Temp\FCW2111.tmp\ISAdmin.exe /SETUPAQ:196646" 0030:trace:process:find_exe_file looking for L"C:\users\focht\Temp\FCW2111.tmp\ISAdmin.exe" 0030:trace:process:find_exe_file Trying native exe L"C:\users\focht\Temp\FCW2111.tmp\ISAdmin.exe" 0030:trace:process:create_process_impl starting L"C:\users\focht\Temp\FCW2111.tmp\ISAdmin.exe" as Win32 binary (0x400000-0x4b1000) 0032:trace:process:init_current_directory starting in L"C:\users\focht\Temp\FCW2111.tmp\" 0x1c 0032:trace:process:__wine_kernel_init starting process name=L"C:\users\focht\Temp\FCW2111.tmp\ISAdmin.exe" argv[0]=L"C:\users\focht\Temp\FCW2111.tmp\ISAdmin.exe" 0030:trace:process:create_process_impl started process pid 0031 tid 0032 ... 0032:err:rebar:REBAR_NotifyFormat wrong response to WM_NOTIFYFORMAT (0), assuming ANSI 0032:trace:seh:raise_exception code=c00000fd flags=0 addr=0xa252924 ip=0a252924 tid=0032 0032:trace:seh:raise_exception eax=0a29bc40 ebx=00000000 ecx=00000000 edx=000506f4 esi=0a2a064c edi=00000000 0032:trace:seh:raise_exception ebp=003258b4 esp=00242000 cs=0023 ds=002b es=002b fs=0063 gs=006b flags=00010246 0032:trace:seh:call_stack_handlers calling handler at 0xa2973ce code=c00000fd flags=0 0032:trace:seh:call_stack_handlers handler at 0xa2973ce returned 1 0032:trace:seh:call_stack_handlers calling handler at 0xa296ceb code=c00000fd flags=0 0032:trace:seh:call_stack_handlers handler at 0xa296ceb returned 1 0032:trace:seh:call_stack_handlers calling handler at 0xa296d18 code=c00000fd flags=0 0032:trace:seh:call_stack_handlers handler at 0xa296d18 returned 1 0032:trace:seh:call_stack_handlers calling handler at 0xb93220 code=c00000fd flags=0 0032:trace:seh:call_stack_handlers handler at 0xb93220 returned 1 0032:trace:seh:call_stack_handlers calling handler at 0xb931c0 code=c00000fd flags=0 0032:trace:seh:call_stack_handlers handler at 0xb931c0 returned 1 0032:trace:seh:call_stack_handlers calling handler at 0xb92ffa code=c00000fd flags=0 0032:trace:seh:call_stack_handlers handler at 0xb92ffa returned 1 0032:trace:seh:call_stack_handlers calling handler at 0x100c503e code=c00000fd flags=0 0032:err:seh:setup_exception_record stack overflow 1360 bytes in thread 0032 eip f747bac7 esp 00240de0 stack 0x240000-0x241000-0x340000 --- snip ---
"ISAdmin.exe" can be started from temp folder after extraction to reproduce/debug.
Adding WINEDEBUG=+relay works around.
By adding more debugging channels (without +relay) and comparing the trace logs, one can converge on certain code/addresses to start debugging.
--- snip --- 0025:Call user32.GetActiveWindow() ret=0a2718ad 0025:Ret user32.GetActiveWindow() retval=00000000 ret=0a2718ad 0025:Call user32.IsZoomed(00020092) ret=0a2718c7 0025:Ret user32.IsZoomed() retval=00000000 ret=0a2718c7 0025:Call KERNEL32.LoadLibraryA(0a28bc40 "UxTheme.dll") ret=0a285cb0 0025:Ret KERNEL32.LoadLibraryA() retval=7dd60000 ret=0a285cb0 0025:Call KERNEL32.InterlockedExchange(0a2981f8,7dd60000) ret=0a285d01 0025:Ret KERNEL32.InterlockedExchange() retval=00000000 ret=0a285d01 0025:Call KERNEL32.GetProcAddress(7dd60000,0a2906f6 "IsThemeActive") ret=0a285d87 0025:Ret KERNEL32.GetProcAddress() retval=7dd6af64 ret=0a285d87 0025:Call uxtheme.IsThemeActive() ret=0a271908 0025:Ret uxtheme.IsThemeActive() retval=00000000 ret=0a271908 --- snip ---
After user32.IsZoomed() it always goes berserk. The offending code is located in a dll "NewUI.dll":
--- snip --- 0025:trace:loaddll:load_native_dll Loaded L"C:\users\focht\Temp\{0105E420-3327-496D-95E0-756E345AEF72}\{FC279721-37A6-4777-AFD8-7A56681EBA14}\Tools.dll" at 0x9fb0000: native 0025:trace:loaddll:load_native_dll Loaded L"C:\users\focht\Temp\{0105E420-3327-496D-95E0-756E345AEF72}\{FC279721-37A6-4777-AFD8-7A56681EBA14}\SerialNumberWrapper.dll" at 0xa120000: native 0025:trace:loaddll:load_builtin_dll Loaded L"C:\windows\system32\msvfw32.dll" at 0x7d3a0000: builtin 0025:trace:loaddll:load_builtin_dll Loaded L"C:\windows\system32\gdiplus.dll" at 0x7d320000: builtin 0025:trace:loaddll:load_builtin_dll Loaded L"C:\windows\system32\imagehlp.dll" at 0x7d300000: builtin 0025:trace:loaddll:load_builtin_dll Loaded L"C:\windows\system32\dbghelp.dll" at 0x7d290000: builtin 0025:trace:loaddll:load_native_dll Loaded L"C:\users\focht\Temp\{0105E420-3327-496D-95E0-756E345AEF72}\{FC279721-37A6-4777-AFD8-7A56681EBA14}\NewUI.dll" at 0xa250000: native 0025:trace:loaddll:load_builtin_dll Loaded L"C:\windows\system32\windowscodecs.dll" at 0x7d1f0000: builtin --- snip ---
It seems the installer code hooks various user32 API to "skin" dialogs. Part of the hooker code (annotated):
--- snip --- ... 0A251C3B 66:813F 8BFF CMP WORD PTR DS:[EDI],0FF8B ; check for "MOV EDI, EDI" 0A251C40 75 39 JNE SHORT 0A251C7B 0A251C42 8A03 MOV AL,BYTE PTR DS:[EBX] ; EBX = [EDI-5] 0A251C44 3C 90 CMP AL,90 ; NOP padding? 0A251C46 75 09 JNE SHORT 0A251C51 0A251C48 817F FC 90909 CMP DWORD PTR DS:[EDI-4],90909090 ; NOP padding? 0A251C4F 74 0D JE SHORT 0A251C5E 0A251C51 3C CC CMP AL,0CC ; INT3 padding? 0A251C53 75 26 JNE SHORT 0A251C7B 0A251C55 817F FC CCCCC CMP DWORD PTR DS:[EDI-4],CCCCCCCC ; INT3 padding? 0A251C5C 75 1D JNE SHORT 0A251C7B 0A251C5E C603 E9 MOV BYTE PTR DS:[EBX],0E9 ; long jump opcode 0A251C61 8B4E 18 MOV ECX,DWORD PTR DS:[ESI+18] 0A251C64 2B4E 14 SUB ECX,DWORD PTR DS:[ESI+14] 0A251C67 894F FC MOV DWORD PTR DS:[EDI-4],ECX ; set address to API hook 0A251C6A 66:C707 EBF9 MOV WORD PTR DS:[EDI],0F9EB ; short jump to long jump 0A251C6F 8B56 14 MOV EDX,DWORD PTR DS:[ESI+14] 0A251C72 83C2 02 ADD EDX,2 0A251C75 8916 MOV DWORD PTR DS:[ESI],EDX ; save real entry addr 0A251C77 C646 20 01 MOV BYTE PTR DS:[ESI+20],1 ; set flag "hooked" 0A251C7B 8B4C24 10 MOV ECX,DWORD PTR SS:[LOCAL.0] 0A251C7F 8D4424 10 LEA EAX,[LOCAL.0] 0A251C83 50 PUSH EAX ; old protect 0A251C84 51 PUSH ECX ; new protect 0A251C85 6A 14 PUSH 14 ; size = 20 0A251C87 53 PUSH EBX ; address 0A251C88 FFD5 CALL EBP ; KERNEL32.VirtualProtect --- snip ---
The entry is patched if "hotpatch" prolog is detected: 2 byte relative short jump back to Windows-style long-jump area (which is located before the API using NOPs or INT3s).
Due to missing HOTPATCH area, setting hooks for following API fails as above code will not patch these API entries:
user32.dll "AdjustWindowRectEx" user32.dll "AdjustWindowRect" user32.dll "SetWindowLongA"
After failure a different code path is taken and several other API get patched:
kernel32.dll "LoadLibraryA" kernel32.dll "LoadLibraryW" all "Ex" variants.
I think that code path is actually bugged which has severe consequences.
Later delayed imports are resolved using the stubs:
--- snip --- ... 0A281902 FF15 407A2A0A CALL DWORD PTR DS:[0A2A7A40] ; delayed import IsThemeActive ... 0A289678 B8 407A2A0A MOV EAX,OFFSET 0A2A7A40 0A28967D E9 00000000 JMP 0A289682 0A289682 51 PUSH ECX 0A289683 52 PUSH EDX 0A289684 50 PUSH EAX 0A289685 68 4C062A0A PUSH OFFSET 0A2A064C 0A28968A E8 25C50000 CALL 0A295BB4 ; "resolver" code 0A28968F 5A POP EDX 0A289690 59 POP ECX 0A289691 FFE0 JMP EAX --- snip ---
The "resolver" code uses kernel32.LoadLibraryA API which got hooked.
--- snip --- 0A295CA7 FF75 C8 PUSH DWORD PTR SS:[LOCAL.14] ; filename 0A295CAA FF15 B092290A CALL DWORD PTR DS:[<&KERNEL32.LoadLibraryA>] 0A295CB0 8BF8 MOV EDI,EAX 0A295CB2 85FF TEST EDI,EDI --- snip ---
--- snip --- ... 7B8564AA CC INT3 7B8564AB CC INT3 7B8564AC E9 6FC49F8E JMP 0A252920 kernel32.LoadLibraryA: 7B8564B1 EB F9 JMP SHORT 7B8564AC ; LoadLibraryA hook 7B8564B3 55 PUSH EBP 7B8564B4 8BEC MOV EBP,ESP 7B8564B6 53 PUSH EBX ... --- snip ---
Out of insanity the wrapper calls kernel32.LoadLibraryA (straight IAT entry!)
--- snip --- 0A252920 8B4424 04 MOV EAX,DWORD PTR SS:[ARG.1] ; filename 0A252924 56 PUSH ESI 0A252925 50 PUSH EAX ; filename 0A252926 FF15 B092290A CALL DWORD PTR DS:[<&KERNEL32.LoadLibraryA>] 0A25292C 8BF0 MOV ESI,EAX 0A25292E 6A 00 PUSH 0 0A252930 56 PUSH ESI 0A252931 E8 FAFEFFFF CALL 0A252830 0A252936 8BC6 MOV EAX,ESI 0A252938 5E POP ESI 0A252939 C2 0400 RETN 4 --- snip ---
The original IAT entry contains the destination API address which points to first byte of entry (only makes sense *if* the API is *not* hooked).
For whatever reason the wrapper doesn't make use of the hook-data (see function that patches the API entries: the +2 address is also saved away to continue on real API).
This makes the recursion and subsequent stack overflow complete.
---
If you add DECLSPEC_HOTPATCH to all three mentioned user32 API those LoadLibraryX API which cause the recursion don't get hooked, no stack overflow occurs and the installer proceeds to show a dialog. Unfortunately the dialog (that ought to be skinned) isn't redrawn possibly due to other Wine bugs in user32. You can drag it around and if you're lucky you can hit/click "next" button in the dark.
$ du -sh PDF\ Experte\ 7\ Ultimate.exe 35M PDF Experte 7 Ultimate.exe
$ sha1sum PDF\ Experte\ 7\ Ultimate.exe a06cf16dc98941e333d94111372358ad07286aca PDF Experte 7 Ultimate.exe
$ wine --version wine-1.5.3
Regards