[Bug 30536] New: Avanquest PDF Experte Ultimate 7.0.x installer crashes with stack overflow because user32.dll AdjustWindowRect, AdjustWindowRectEx, SetWindowLongA are not hotpatchable (DECLSPEC_HOTPATCH)

wine-bugs at winehq.org wine-bugs at winehq.org
Sat Apr 28 15:39:36 CDT 2012


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 at winehq.org
        ReportedBy: focht at 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

-- 
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