Sebastian Lackner : ntdll: Add support for ATL thunk 'POP ecx; POP eax; PUSH ecx; JMP 4(%eax)'.

Alexandre Julliard julliard at wine.codeweavers.com
Tue Oct 21 09:49:44 CDT 2014


Module: wine
Branch: master
Commit: 1c1e7ed016c129dacc52e5f6432587270c91f681
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=1c1e7ed016c129dacc52e5f6432587270c91f681

Author: Sebastian Lackner <sebastian at fds-team.de>
Date:   Tue Oct 21 06:03:57 2014 +0200

ntdll: Add support for ATL thunk 'POP ecx; POP eax; PUSH ecx; JMP 4(%eax)'.

---

 dlls/kernel32/tests/virtual.c | 41 +++++++++++++++++++++++++++++++++++++++++
 dlls/ntdll/signal_i386.c      | 28 ++++++++++++++++++++++++++++
 2 files changed, 69 insertions(+)

diff --git a/dlls/kernel32/tests/virtual.c b/dlls/kernel32/tests/virtual.c
index ae0ede5..1592b87 100644
--- a/dlls/kernel32/tests/virtual.c
+++ b/dlls/kernel32/tests/virtual.c
@@ -1889,6 +1889,23 @@ static inline DWORD send_message_excpt( HWND hWnd, UINT uMsg, WPARAM wParam, LPA
     return ret;
 }
 
+static inline DWORD call_proc_excpt( DWORD (CALLBACK *code)(void *), void *arg )
+{
+    EXCEPTION_REGISTRATION_RECORD frame;
+    DWORD ret;
+
+    frame.Handler = execute_fault_seh_handler;
+    frame.Prev = pNtCurrentTeb()->Tib.ExceptionList;
+    pNtCurrentTeb()->Tib.ExceptionList = &frame;
+
+    num_guard_page_calls = num_execute_fault_calls = 0;
+    ret = code( arg );
+
+    pNtCurrentTeb()->Tib.ExceptionList = frame.Prev;
+
+    return ret;
+}
+
 static LRESULT CALLBACK jmp_test_func( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
 {
     if (uMsg == WM_USER)
@@ -1907,6 +1924,11 @@ static LRESULT CALLBACK atl_test_func( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
     return 43;
 }
 
+static DWORD CALLBACK atl5_test_func( void )
+{
+    return 44;
+}
+
 static void test_atl_thunk_emulation( ULONG dep_flags )
 {
     static const char code_jmp[] = {0xE9, 0x00, 0x00, 0x00, 0x00};
@@ -1914,6 +1936,7 @@ static void test_atl_thunk_emulation( ULONG dep_flags )
     static const char code_atl2[] = {0xB9, 0x44, 0x33, 0x22, 0x11, 0xE9, 0x00, 0x00, 0x00, 0x00};
     static const char code_atl3[] = {0xBA, 0x44, 0x33, 0x22, 0x11, 0xB9, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE1};
     static const char code_atl4[] = {0xB9, 0x44, 0x33, 0x22, 0x11, 0xB8, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0};
+    static const char code_atl5[] = {0x59, 0x58, 0x51, 0xFF, 0x60, 0x04};
     static const char cls_name[] = "atl_thunk_class";
     DWORD ret, size, old_prot;
     ULONG old_flags = MEM_EXECUTE_OPTION_ENABLE;
@@ -2133,6 +2156,24 @@ static void test_atl_thunk_emulation( ULONG dep_flags )
     else
         ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
 
+    memcpy( base, code_atl5, sizeof(code_atl5) );
+
+    success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot );
+    ok( success, "VirtualProtect failed %u\n", GetLastError() );
+
+    ret = (DWORD_PTR)atl5_test_func;
+    ret = call_proc_excpt( (void *)base, &ret - 1 );
+    /* FIXME: We don't check the content of the registers EAX/ECX yet */
+    ok( ret == 44, "call returned wrong result, expected 44, got %d\n", ret );
+    ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
+    if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION))
+        ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
+    else if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
+        ok( num_execute_fault_calls == 0 || broken(num_execute_fault_calls == 1) /* Windows XP */,
+            "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
+    else
+        ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
+
     /* Restore the JMP instruction, set to executable, and then destroy the Window */
 
     memcpy( base, code_jmp, sizeof(code_jmp) );
diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c
index b315e55..13df4bb 100644
--- a/dlls/ntdll/signal_i386.c
+++ b/dlls/ntdll/signal_i386.c
@@ -1648,6 +1648,14 @@ union atl_thunk
         DWORD func;
         WORD  jmp;   /* jmp eax */
     } t4;
+    struct
+    {
+        DWORD inst1; /* pop ecx
+                      * pop eax
+                      * push ecx
+                      * jmp 4(%eax) */
+        WORD  inst2;
+    } t5;
 };
 #include "poppack.h"
 
@@ -1708,6 +1716,26 @@ static BOOL check_atl_thunk( EXCEPTION_RECORD *rec, CONTEXT *context )
                thunk, context->Eip, context->Eax, context->Ecx );
         return TRUE;
     }
+    else if (thunk_len >= sizeof(thunk_copy.t5) && thunk_copy.t5.inst1 == 0xff515859 &&
+                                                   thunk_copy.t5.inst2 == 0x0460)
+    {
+        DWORD func, stack[2];
+        if (virtual_uninterrupted_read_memory( (DWORD *)context->Esp,
+            stack, sizeof(stack) ) == sizeof(stack) &&
+            virtual_uninterrupted_read_memory( (DWORD *)stack[1] + 1,
+            &func, sizeof(DWORD) ) == sizeof(DWORD) &&
+            virtual_uninterrupted_write_memory( (DWORD *)context->Esp + 1,
+            &stack[0], sizeof(stack[0]) ) == sizeof(stack[0]))
+        {
+            context->Ecx = stack[0];
+            context->Eax = stack[1];
+            context->Esp = context->Esp + sizeof(DWORD);
+            context->Eip = func;
+            TRACE( "emulating ATL thunk type 5 at %p, func=%08x eax=%08x ecx=%08x esp=%08x\n",
+                   thunk, context->Eip, context->Eax, context->Ecx, context->Esp );
+            return TRUE;
+        }
+    }
 
     return FALSE;
 }




More information about the wine-cvs mailing list