什么是 Thunk
Thunk 技术就是将一段机器码对应的字节保存在一个连续内存结构里,然后把其指针强制转换成函数, 即用作函数来执行。
什么是 DEP
说道Thunk,顺便介绍下DEP。数据执行保护 (DEP) 是一套软硬件技术,能够在内存上执行额外检查以帮助防止在系统上运行恶意代码。在 Microsoft Windows XP Service Pack 2 、 Microsoft Windows Server 2003 Service Pack 1 、Microsoft Windows XP Tablet PC Edition 2005 和 Microsoft Windows Vista 中,由硬件和软件一起强制实施 DEP 。 DEP 的主要优点是可以帮助防止数据页执行代码。通常情况下,不从默认堆和堆栈执行代码。硬件实施 DEP 检测从这些位置运行的代码,并在发现执行情况时引发异常。软件实施 DEP 可帮助阻止恶意代码利用 Windows 中的异常处理机制进行破坏。 硬件实施 DEP 是某些 DEP 兼容处理器的功能,可以防止在已标记为数据存储区的内存区域中执行代码。此功能也称为非执行和执行保护。 Windows XP SP2 还包括软件实施 DEP ,其目的在于减少利用 Windows 中的例外处理机制的情况。
在哪里查看DEP 设置呢?
我的电脑-> 属性-> 高级-> 性能-> 设置-> 数据执行保护。
在windows xp sp2 上默认是” 仅为基本 Windows 程序和服务启用 DEP “ 在Microsoft Windows Server 2003 Service Pack2 上默认是”为除下列选定程序之外的所有程序和服务启用 DEP “
WTL是怎样解决DEP问题:
WTL 也用了Thunk 技术, 如果在Microsoft Windows Server 2003 Service Pack2 上把DEP 设置成回默认的,然后运行一下WTL的 Dialog, 可以跑起来, 同样是用Thunk, 这是什么原因呢, 看ATL 代码, 可以发现如下代码:
thunkPage = (PATL_THUNK_ENTRY)VirtualAlloc(NULL,
PAGE_SIZE,
MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
原来WTL是用VirtualAlloc[PAGE_EXECUTE_READWRITE] 来分配Thunk 代码的内存。所以要是你的代码中使用的Thunk技术,请使用VirtualAlloc为Thunk分配内存。
下面给出一个使用Thunk改写窗口类回调函数为类成员函数的例子:
注意:
1. 这个例子从网上利用thunk技术封装窗口类改写过来,但是他的程序有些bug,下载下来直接编译会出错。
2. 利用thunk技术封装窗口类中使用的是静态变量传递窗口对象和窗口句柄,需要定义额外的变量,代码中使用RingSDK中的技术,在CreateWindow中将对象指针作为参数传递。
// TestTrunk.cpp : 定义应用程序的入口点。
//
#include "stdafx.h"
#include "TestTrunk.h"
#define MAX_LOADSTRING 100
#pragma pack(push,1)
typedef struct _StdCallThunk
{
DWORD m_mov; // = 0x042444C7
DWORD m_this; // = this
BYTE m_jmp; // = 0xe9
DWORD m_relproc; // = relative distance
} StdCallThunk;
#pragma pack(pop)
class CMyWindow
{
public:
CMyWindow():_hwnd(NULL){}
~CMyWindow(){VirtualFree(_pStdthunk, sizeof(StdCallThunk), MEM_RELEASE);}
bool Create();
protected:
LRESULT CALLBACK WndProc(UINT message, WPARAM wParam, LPARAM lParam);
MSG _msg;
HWND _hwnd;
StdCallThunk *_pStdthunk;
static LRESULT CALLBACK TempWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
};
bool CMyWindow::Create()
{
WNDCLASSEX wcex;
LPCTSTR lpszClassName = _T("ClassName");
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = CMyWindow::TempWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = GetModuleHandle(NULL);
wcex.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_TESTTRUNK));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_TESTTRUNK);
wcex.lpszClassName = lpszClassName;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
RegisterClassEx(&wcex);
_pStdthunk = (StdCallThunk *)VirtualAlloc(NULL, sizeof(StdCallThunk), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
_pStdthunk->m_mov = 0x042444c7;
_pStdthunk->m_jmp = 0xe9;
//CreateWindow的最后一个参数为this指针
CreateWindow(lpszClassName, NULL, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, GetModuleHandle(NULL),this);
if (_hwnd == NULL)
{
MessageBox(NULL,TEXT("Error"),NULL,NULL);
return FALSE;
}
ShowWindow(_hwnd, SW_SHOW);
UpdateWindow(_hwnd);
return TRUE;
}
LRESULT CALLBACK CMyWindow::TempWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_CREATE)//此处使用WM_NCCREATE消息也可以
{
//提取出对象指针
CMyWindow *w = NULL;
w = (CMyWindow*)((LPCREATESTRUCT)lParam)->lpCreateParams;
w->_hwnd = hWnd;
WNDPROC pWndProc = (WNDPROC)w->_pStdthunk;
w->_pStdthunk->m_this = (DWORD)w;
//计算跳转位置
w->_pStdthunk->m_relproc = (DWORD)&CMyWindow::StaticWndProc - ((DWORD)w->_pStdthunk + sizeof(StdCallThunk));
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)pWndProc);
return pWndProc( hWnd, message, wParam, lParam);
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
LRESULT CALLBACK CMyWindow::StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return ((CMyWindow *)hWnd)->WndProc(message, wParam, lParam);
}
LRESULT CALLBACK CMyWindow::WndProc(UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// 分析菜单选择:
switch (wmId)
{
case IDM_ABOUT:
MessageBox(NULL,TEXT("AboutDlg"),TEXT("关于"),NULL);
break;
case IDM_EXIT:
DestroyWindow(_hwnd);
break;
}
break;
case WM_PAINT:
hdc = BeginPaint(_hwnd, &ps);
// TODO: 在此添加任意绘图代码...
EndPaint(_hwnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(_hwnd, message, wParam, lParam);
break;
}
return TRUE;
}
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
CMyWindow pMyWindow;
pMyWindow.Create();
MSG msg;
HACCEL hAccelTable = LoadAccelerators(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_TESTTRUNK));
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
。