[Bug 47027] EA Origin client crashes on startup ( Origin IGO using madCodeHook 3.x engine can't cope with GOT/ PIC register load code within 15-byte range at API entry)

wine-bugs at winehq.org wine-bugs at winehq.org
Mon Apr 29 13:57:21 CDT 2019


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

Anastasius Focht <focht at gmx.net> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
            Summary|EA Origin client crashes on |EA Origin client crashes on
                   |startup (Origin IGO hook    |startup (Origin IGO using
                   |engine can't cope with      |madCodeHook 3.x engine
                   |GOT/PIC register load code  |can't cope with GOT/PIC
                   |at API entry, needs         |register load code within
                   |DECLSPEC_HOTPATCH for       |15-byte range at API entry)
                   |user32.SetForegroundWindow) |

--- Comment #12 from Anastasius Focht <focht at gmx.net> ---
Hello Louis,

yeah I see it now ... IGO uses madCodeHook 3.x (http://www.madshi.net/)

--- snip ---
; ASCII
"C:\jenkins\workspace\Client\build_release_win\origin\products\client\10.5.38\IGO\madCodeHook3\Sources\C++\ModuleTools.cpp"
--- snip ---

Reminds me of Chromium. It copies a whole range of opcodes (15 bytes) from API
entry into dynamically allocated trampoline. In addition it tries to be clever
and patches instructions that change code flow (calls) within first 15 bytes of
function entry (if their complete opcode fits in range).

Pure unhooked 'user32.SetForegroundWindow' with DECLSPEC_HOTPATCH applied:

--- snip ---
7E68A0C0  8BFF              MOV EDI,EDI
7E68A0C2  55                PUSH EBP
7E68A0C3  8BEC              MOV EBP,ESP
7E68A0C5  E8 77D9FCFF       CALL 7E657A41
7E68A0CA  05 366F0B00       ADD EAX,0B6F36
7E68A0CF  5D                POP EBP
7E68A0D0  8D4C24 04         LEA ECX,[ESP+4]
7E68A0D4  83E4 F0           AND ESP,FFFFFFF0
7E68A0D7  FF71 FC           PUSH DWORD PTR DS:[ECX-4]
7E68A0DA  55                PUSH EBP
7E68A0DB  89E5              MOV EBP,ESP
7E68A0DD  53                PUSH EBX
7E68A0DE  8B19              MOV EBX,DWORD PTR DS:[ECX]
7E68A0E0  51                PUSH ECX
7E68A0E1  F680 80B60E00 0   TEST BYTE PTR DS:[EAX+0EB680],08
7E68A0E8  75 26             JNE SHORT 7E68A110
...
--- snip ---

After hook:

--- snip ---
7E68A0C0  E9 0BEED091       JMP 10398ED0  ; first hook
7E68A0C5  8BE5              MOV ESP,EBP
7E68A0C7  5D                POP EBP
7E68A0C8  E9 03EED091       JMP 10398ED0  ; second hook, non-reachable though
7E68A0CD  0B00              OR EAX,DWORD PTR DS:[EAX]
7E68A0CF  5D                POP EBP       ; <--- trampoline continuation
7E68A0D0  8D4C24 04         LEA ECX,[ESP+4]
7E68A0D4  83E4 F0           AND ESP,FFFFFFF0
7E68A0D7  FF71 FC           PUSH DWORD PTR DS:[ECX-4]
7E68A0DA  55                PUSH EBP
7E68A0DB  89E5              MOV EBP,ESP
7E68A0DD  53                PUSH EBX
7E68A0DE  8B19              MOV EBX,DWORD PTR DS:[ECX]
7E68A0E0  51                PUSH ECX
7E68A0E1  F680 80B60E00 0   TEST BYTE PTR DS:[EAX+0EB680],08
7E68A0E8  75 26             JNE SHORT 7E68A110
...
--- snip ---

When the first hook is done (taking 5-bytes), the next instruction instruction
within 15-byte range is the call to load PIC register. IGO/madCodeHook3
considers it a code flow change and patches it as well, along with original
prologue chunk insertion. Questionable implementation if the code won't be
reachable at all due to first own(!) hook.

--- snip ---
7E68A0C0  E9 0BEED091      JMP 10398ED0 
7E68A0C5  E8 77D9FCFF      CALL 7E657A41   ; <-- will be patched in second pass
7E68A0CA  05 366F0B00      ADD EAX,0B6F36
7E68A0CF  5D               POP EBP
--- snip ---

The final trampoline with copied opcodes:

--- snip ---
7F000210  8BFF              MOV EDI,EDI
7F000212  55                PUSH EBP
7F000213  8BEC              MOV EBP,ESP
7F000215  E8 277865FF       CALL 7E657A41   ; PIC load, can't work
7F00021A  05 366F0B00       ADD EAX,0B6F36
7F00021F  E9 AB9E68FF       JMP 7E68A0CF
--- snip ---

In other cases it works because there is no call instruction in first 15-byte
range, example:

'DoDragDrop' hooked API entry which doesn't even have DECLSPEC_HOTPATCH:

--- snip ---
...
7E366710  E9 8B210392      JMP 103988A0
7E366715  E4 F0            IN AL,0F0
7E366717  FF71 FC          PUSH DWORD PTR DS:[ECX-4]
7E36671A  55               PUSH EBP
7E36671B  89E5             MOV EBP,ESP
7E36671D  57               PUSH EDI
7E36671E  56               PUSH ESI
7E36671F  53               PUSH EBX         ; <--- trampoline continuation
7E366720  E8 1BDDFBFF      CALL 7E324440    ; PIC load, will work
7E366725  81C3 DB280E00    ADD EBX,0E28DB
...
--- snip ---

Trampoline, has copy of first 15 bytes:

--- snip ---
7F000040  8D4C24 04        LEA ECX,[ESP+4]  ; original entry with no hotpatch
7F000044  83E4 F0          AND ESP,FFFFFFF0
7F000047  FF71 FC          PUSH DWORD PTR DS:[ECX-4]
7F00004A  55               PUSH EBP
7F00004B  89E5             MOV EBP,ESP
7F00004D  57               PUSH EDI
7F00004E  56               PUSH ESI
7F00004F  E9 CB6636FF      JMP 7E36671F
--- snip ---

Another example that doesn't work:

'user32.BringWindowToTop' has no DECLSPEC_HOTPATCH:

--- snip ---
7E6E9280  8D4C24 04       LEA ECX,[ARG.1]  ; original entry with no hotpatch    
7E6E9284  83E4 F0         AND ESP,FFFFFFF0
7E6E9287  FF71 FC         PUSH DWORD PTR DS:[ECX-4]
7E6E928A  55              PUSH EBP
7E6E928B  89E5            MOV EBP,ESP
7E6E928D  53              PUSH EBX
7E6E928E  E8 DD32F6FF     CALL 7E64C570
7E6E9293  81C3 6D7D0500   ADD EBX,57D6D
7E6E9299  51              PUSH ECX
...
--- snip ---

After hook:

--- snip ---
7E64C570  8B1C24          MOV EBX,DWORD PTR SS:[ESP]
7E64C573  C3              RETN

7E6E9280  E9 5BEECA91     JMP 103980E0
7E6E9285  E4 F0           IN AL,0F0
7E6E9287  FF71 FC         PUSH DWORD PTR DS:[ECX-4]
7E6E928A  55              PUSH EBP
7E6E928B  89E5            MOV EBP,ESP
7E6E928D  53              PUSH EBX
7E6E928E  E8 DD32F6FF     CALL 7E64C570
7E6E9293  81C3 6D7D0500   ADD EBX,57D6D     ; <--- trampoline continuation
7E6E9299  51              PUSH ECX
7E6E929A  83EC 04         SUB ESP,4
7E6E929D  6A 03           PUSH 3
7E6E929F  6A 00           PUSH 0
7E6E92A1  6A 00           PUSH 0
7E6E92A3  6A 00           PUSH 0
7E6E92A5  6A 00           PUSH 0
7E6E92A7  6A 00           PUSH 0
7E6E92A9  FF31            PUSH DWORD PTR DS:[ECX]
7E6E92AB  E8 50F6FFFF     CALL SetWindowPos
...
--- snip ---

Unfortunately the first byte of call instruction to load PIC reg is the 15th
byte, hence it's still considered part of "prologue".
The hook copies the whole call into trampoline.

--- snip ---
7F000210  8D4C24 04       LEA ECX,[ESP+4]    ; original entry with no hotpatch
7F000214  83E4 F0         AND ESP,FFFFFFF0
7F000217  FF71 FC         PUSH DWORD PTR DS:[ECX-4]
7F00021A  55              PUSH EBP
7F00021B  89E5            MOV EBP,ESP
7F00021D  53              PUSH EBX
7F00021E  E8 4DC364FF     CALL 7E64C570      ; PIC load, can't work
7F000223  E9 6B906EFF     JMP 7E6E9293
--- snip ---

DECLSPEC_HOTPATCH would help in this case.

There is not much to be done about it .. shuffling code around
(add/remove/dummy vars) has the risk of not working out as intended. The
compiler can optimize/re-arrange code at will, depending on used optimization
levels.

Honstely, I've already said it multiple times (bug 37540 and the like): the
usage of PIC for 32-bit is just harmful, I don't see any benefit at all. It's
just wasted time hacking around and clobbering Wine sources with
DECLSPEC_HOTPATCH which won't help in some cases as demonstrated here.

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