首页
社区
课程
招聘
[原创]利用Thunk技术改写窗口类回调函数例子
发表于: 2011-4-30 14:29 8808

[原创]利用Thunk技术改写窗口类回调函数例子

2011-4-30 14:29
8808
// 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;
}

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 7
支持
分享
最新回复 (5)
雪    币: 6075
活跃值: (2236)
能力值: (RANK:1060 )
在线值:
发帖
回帖
粉丝
2
我觉得应该叫stub, 跟thunk没什么关系
2011-4-30 17:05
0
雪    币: 367
活跃值: (20)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
3
就是构造跳板函数嘛
ATL/WTL的窗口过程就是这样子处理的.类名叫做什么 thunk
2011-5-1 16:43
0
雪    币: 242
活跃值: (473)
能力值: ( LV11,RANK:188 )
在线值:
发帖
回帖
粉丝
4
学习CALLBACK,原来声明成CALLBACK(__stdcall)类型的类成员变量就可以操作它的函数指针了。可以转换变量类型了。而且居然__stdcall类型的也可以被__thiscall那样的调用,this指针(ecx)也能使用。被当做__stdcall第一个参数压栈了。测试后发现
__cdecl的和__stdcall的类似,也是用的第一个参数的位置来压栈this指针的
有意思的是参数要在寄存器里传递的__fastcall,它也总是用堆栈里的第一个参数位置来压栈this指针的。
看来非默认函数类型的类成员函数,也是被支持的,只是this指针总在堆栈上占一个位置。

vs2005的测试结果。以后可以用来做inline类保存在自己里面的hook stub了! /:^)!
2011-5-1 17:06
0
雪    币: 1847
活跃值: (1806)
能力值: ( LV12,RANK:230 )
在线值:
发帖
回帖
粉丝
5
惊现morning
2011-5-1 17:19
0
雪    币: 191
活跃值: (55)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
6
1.由于建立项目时疏忽,把TestThunk建成了TestTrunk给大家带来阅读不便,请谅解。
   2.由于工作后很少研究底层东西了,除了在COM里面看到一些关于stub。在网上看到Thunk,姑且当做thunk吧。
   看到论坛里帖子http://bbs.pediy.com/showthread.php?t=76213&highlight=发现可以只用一个静态函数实现窗口类回调函数变为非静态成员函数。主要是在
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;
 [COLOR="Red"]  //在此直接使用非静态成员函数,this指针通过ecx传递。[/COLOR]
		void* pProc = w->m_PorcA.Thiscall(w, Thunk::GetMemberFxnAddr(&CMyWindow::WndProc));
		SetWindowLong(hWnd, GWL_WNDPROC, (LONG)pProc);
		
	}
	return DefWindowProc(hWnd, message, wParam, lParam);
}

做以上更改。
在此感谢zhangludu,这份代码中使用了他写的的thunk类,真的很好用。以前一直在想着怎样使用thunk实现非静态成员函数作为线程函数,没想到他早就实现了。希望大家继续多提意见,
上传的附件:
2011-5-2 10:17
0
游客
登录 | 注册 方可回帖
返回
//