Sebastian Lackner : ntdll: Add support for ATL thunk 'MOV this,ecx; JMP func'.

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


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

Author: Sebastian Lackner <sebastian at fds-team.de>
Date:   Tue Oct 21 05:55:27 2014 +0200

ntdll: Add support for ATL thunk 'MOV this,ecx; JMP func'.

---

 dlls/kernel32/tests/virtual.c | 31 +++++++++++++++++++++----
 dlls/ntdll/signal_i386.c      | 54 +++++++++++++++++++++++++++++--------------
 2 files changed, 63 insertions(+), 22 deletions(-)

diff --git a/dlls/kernel32/tests/virtual.c b/dlls/kernel32/tests/virtual.c
index 73b753e..5f83ead 100644
--- a/dlls/kernel32/tests/virtual.c
+++ b/dlls/kernel32/tests/virtual.c
@@ -1882,7 +1882,7 @@ static inline DWORD send_message_excpt( HWND hWnd, UINT uMsg, WPARAM wParam, LPA
     pNtCurrentTeb()->Tib.ExceptionList = &frame;
 
     num_guard_page_calls = num_execute_fault_calls = 0;
-    ret = SendMessageA( hWnd, WM_USER, 0, 0 );
+    ret = SendMessageA( hWnd, uMsg, wParam, lParam );
 
     pNtCurrentTeb()->Tib.ExceptionList = frame.Prev;
 
@@ -1900,14 +1900,18 @@ static LRESULT CALLBACK jmp_test_func( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
 static LRESULT CALLBACK atl_test_func( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
 {
     DWORD arg = (DWORD)hWnd;
-    ok( arg == 0x11223344, "arg is 0x%08x instead of 0x11223344\n", arg );
+    if (uMsg == WM_USER)
+        ok( arg == 0x11223344, "arg is 0x%08x instead of 0x11223344\n", arg );
+    else
+        ok( arg != 0x11223344, "arg is unexpectedly 0x11223344\n" );
     return 43;
 }
 
 static void test_atl_thunk_emulation( ULONG dep_flags )
 {
     static const char code_jmp[] = {0xE9, 0x00, 0x00, 0x00, 0x00};
-    static const char code_atl[] = {0xC7, 0x44, 0x24, 0x04, 0x44, 0x33, 0x22, 0x11, 0xE9, 0x00, 0x00, 0x00, 0x00};
+    static const char code_atl1[] = {0xC7, 0x44, 0x24, 0x04, 0x44, 0x33, 0x22, 0x11, 0xE9, 0x00, 0x00, 0x00, 0x00};
+    static const char code_atl2[] = {0xB9, 0x44, 0x33, 0x22, 0x11, 0xE9, 0x00, 0x00, 0x00, 0x00};
     static const char cls_name[] = "atl_thunk_class";
     DWORD ret, size, old_prot;
     ULONG old_flags = MEM_EXECUTE_OPTION_ENABLE;
@@ -2008,7 +2012,7 @@ static void test_atl_thunk_emulation( ULONG dep_flags )
 
     /* Now test with a proper ATL thunk instruction. */
 
-    memcpy( base, code_atl, sizeof(code_atl) );
+    memcpy( base, code_atl1, sizeof(code_atl1) );
     *(DWORD *)(base + 9) = (DWORD_PTR)atl_test_func - (DWORD_PTR)(base + 13);
 
     success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot );
@@ -2077,6 +2081,23 @@ static void test_atl_thunk_emulation( ULONG dep_flags )
             win_skip( "RtlAddVectoredExceptionHandler or RtlRemoveVectoredExceptionHandler not found\n" );
     }
 
+    /* Test alternative ATL thunk instructions. */
+
+    memcpy( base, code_atl2, sizeof(code_atl2) );
+    *(DWORD *)(base + 6) = (DWORD_PTR)atl_test_func - (DWORD_PTR)(base + 10);
+
+    success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot );
+    ok( success, "VirtualProtect failed %u\n", GetLastError() );
+
+    ret = send_message_excpt( hWnd, WM_USER + 1, 0, 0 );
+    /* FIXME: we don't check the content of the register ECX yet */
+    ok( ret == 43, "call returned wrong result, expected 43, 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
+        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) );
@@ -2194,7 +2215,7 @@ static void test_atl_thunk_emulation( ULONG dep_flags )
 
     /* Now test with a proper ATL thunk instruction. */
 
-    memcpy( base, code_atl, sizeof(code_atl) );
+    memcpy( base, code_atl1, sizeof(code_atl1) );
     *(DWORD *)(base + 9) = (DWORD_PTR)atl_test_func - (DWORD_PTR)(base + 13);
 
     count = 64;
diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c
index f97799c..dde4e2d 100644
--- a/dlls/ntdll/signal_i386.c
+++ b/dlls/ntdll/signal_i386.c
@@ -1616,12 +1616,22 @@ static inline BOOL check_invalid_gs( CONTEXT *context )
 
 
 #include "pshpack1.h"
-struct atl_thunk
+union atl_thunk
 {
-    DWORD movl;  /* movl this,4(%esp) */
-    DWORD this;
-    BYTE  jmp;   /* jmp func */
-    int   func;
+    struct
+    {
+        DWORD movl;  /* movl this,4(%esp) */
+        DWORD this;
+        BYTE  jmp;   /* jmp func */
+        int   func;
+    } t1;
+    struct
+    {
+        BYTE  movl;  /* movl this,ecx */
+        DWORD this;
+        BYTE  jmp;   /* jmp func */
+        int   func;
+    } t2;
 };
 #include "poppack.h"
 
@@ -1632,26 +1642,36 @@ struct atl_thunk
  */
 static BOOL check_atl_thunk( EXCEPTION_RECORD *rec, CONTEXT *context )
 {
-    const struct atl_thunk *thunk = (const struct atl_thunk *)rec->ExceptionInformation[1];
-    struct atl_thunk thunk_copy;
-    BOOL ret = FALSE;
+    const union atl_thunk *thunk = (const union atl_thunk *)rec->ExceptionInformation[1];
+    union atl_thunk thunk_copy;
+    SIZE_T thunk_len;
 
-    if (virtual_uninterrupted_read_memory( thunk, &thunk_copy, sizeof(*thunk) ) != sizeof(*thunk))
-        return FALSE;
+    thunk_len = virtual_uninterrupted_read_memory( thunk, &thunk_copy, sizeof(*thunk) );
+    if (!thunk_len) return FALSE;
 
-    if (thunk_copy.movl == 0x042444c7 && thunk_copy.jmp == 0xe9)
+    if (thunk_len >= sizeof(thunk_copy.t1) && thunk_copy.t1.movl == 0x042444c7 &&
+                                              thunk_copy.t1.jmp == 0xe9)
     {
         if (virtual_uninterrupted_write_memory( (DWORD *)context->Esp + 1,
-            &thunk_copy.this, sizeof(DWORD) ) == sizeof(DWORD))
+            &thunk_copy.t1.this, sizeof(DWORD) ) == sizeof(DWORD))
         {
-            context->Eip = (DWORD_PTR)(&thunk->func + 1) + thunk_copy.func;
-            TRACE( "emulating ATL thunk at %p, func=%08x arg=%08x\n",
-                   thunk, context->Eip, thunk_copy.this );
-            ret = TRUE;
+            context->Eip = (DWORD_PTR)(&thunk->t1.func + 1) + thunk_copy.t1.func;
+            TRACE( "emulating ATL thunk type 1 at %p, func=%08x arg=%08x\n",
+                   thunk, context->Eip, thunk_copy.t1.this );
+            return TRUE;
         }
     }
+    else if (thunk_len >= sizeof(thunk_copy.t2) && thunk_copy.t2.movl == 0xb9 &&
+                                                   thunk_copy.t2.jmp == 0xe9)
+    {
+        context->Ecx = thunk_copy.t2.this;
+        context->Eip = (DWORD_PTR)(&thunk->t2.func + 1) + thunk_copy.t2.func;
+        TRACE( "emulating ATL thunk type 2 at %p, func=%08x ecx=%08x\n",
+               thunk, context->Eip, context->Ecx );
+        return TRUE;
+    }
 
-    return ret;
+    return FALSE;
 }
 
 




More information about the wine-cvs mailing list