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

This commit is contained in:
Sebastian Lackner 2014-10-21 06:03:57 +02:00 committed by Alexandre Julliard
parent dcd2b0a366
commit 1c1e7ed016
2 changed files with 69 additions and 0 deletions

View File

@ -1889,6 +1889,23 @@ static inline DWORD send_message_excpt( HWND hWnd, UINT uMsg, WPARAM wParam, LPA
return ret; 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 ) static LRESULT CALLBACK jmp_test_func( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{ {
if (uMsg == WM_USER) if (uMsg == WM_USER)
@ -1907,6 +1924,11 @@ static LRESULT CALLBACK atl_test_func( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
return 43; return 43;
} }
static DWORD CALLBACK atl5_test_func( void )
{
return 44;
}
static void test_atl_thunk_emulation( ULONG dep_flags ) static void test_atl_thunk_emulation( ULONG dep_flags )
{ {
static const char code_jmp[] = {0xE9, 0x00, 0x00, 0x00, 0x00}; 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_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_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_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"; static const char cls_name[] = "atl_thunk_class";
DWORD ret, size, old_prot; DWORD ret, size, old_prot;
ULONG old_flags = MEM_EXECUTE_OPTION_ENABLE; ULONG old_flags = MEM_EXECUTE_OPTION_ENABLE;
@ -2133,6 +2156,24 @@ static void test_atl_thunk_emulation( ULONG dep_flags )
else else
ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls ); 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 */ /* Restore the JMP instruction, set to executable, and then destroy the Window */
memcpy( base, code_jmp, sizeof(code_jmp) ); memcpy( base, code_jmp, sizeof(code_jmp) );

View File

@ -1648,6 +1648,14 @@ union atl_thunk
DWORD func; DWORD func;
WORD jmp; /* jmp eax */ WORD jmp; /* jmp eax */
} t4; } t4;
struct
{
DWORD inst1; /* pop ecx
* pop eax
* push ecx
* jmp 4(%eax) */
WORD inst2;
} t5;
}; };
#include "poppack.h" #include "poppack.h"
@ -1708,6 +1716,26 @@ static BOOL check_atl_thunk( EXCEPTION_RECORD *rec, CONTEXT *context )
thunk, context->Eip, context->Eax, context->Ecx ); thunk, context->Eip, context->Eax, context->Ecx );
return TRUE; 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; return FALSE;
} }