自己根據網上的一篇Thunk技術改寫的Thunk通用類

template<typename CallFunctionType,typename ClassFunctionType>class Thunk
{
	//BYTE:unsigned char
	//DWORD:unsigned long
	BYTE*m_thunk=0;
public:
	operator CallFunctionType()
	{
		return (CallFunctionType)m_thunk;
	}
public:
	Thunk(void*_this, ClassFunctionType callBack)
	{
		DWORD FuncAddr;
		DWORD addr1, addr2;
		GetMemberFuncAddr_VC6(FuncAddr, callBack);
		ThunkTemplate(addr1, addr2, 0);
		m_thunk = (BYTE *)VirtualAlloc(NULL, sizeof(BYTE[100]), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
		memcpy(m_thunk, (void*)addr1, addr2 - addr1);
		ReplaceCodeBuf(m_thunk, addr2 - addr1, -1, (DWORD)((void*)_this));
		ReplaceCodeBuf(m_thunk, addr2 - addr1, -2, FuncAddr);
	}
	~Thunk()
	{
		VirtualFree(m_thunk, sizeof(BYTE[100]), MEM_RELEASE);
	}

	template <class ToType, class FromType>void GetMemberFuncAddr_VC6(ToType& addr, FromType f)
	{
		union
		{
			FromType _f;
			ToType   _t;
		}ut;

		ut._f = f;

		addr = ut._t;
	}

	void ThunkTemplate(DWORD& addr1, DWORD& addr2, int calltype = 0)
	{
		int flag = 0;
		DWORD x1, x2;

		if (flag)
		{
			__asm //__thiscall
			{
			thiscall_1:	mov   ecx, -1;   //-1佔位符,運行時將被替換爲this指針.
				mov   eax, -2;   //-2佔位符,運行時將被替換爲CTimer::CallBcak的地址.
				jmp   eax;
			thiscall_2:;
			}

			__asm //__stdcall
			{
			stdcall_1:	push  dword ptr[esp]; //保存(複製)返回地址到當前棧中
				mov   dword ptr[esp + 4], -1; //將this指針送入棧中,即原來的返回地址處
				mov   eax, -2;
				jmp   eax; //跳轉至目標消息處理函數(類成員函數)
			stdcall_2:;
			}
		}

		if (calltype == 0)//this_call
		{
			__asm
			{
				mov   x1, offset thiscall_1;  //取 Thunk代碼段 的地址範圍.
				mov   x2, offset thiscall_2;
			}
		}
		else
		{
			__asm
			{
				mov   x1, offset stdcall_1;
				mov   x2, offset stdcall_2;
			}
		}

		addr1 = x1;
		addr2 = x2;
	}

	void ReplaceCodeBuf(BYTE *code, int len, DWORD old, DWORD x)
	{
		int i = 0;

		for (i = 0; i<len - 4; ++i)
		{
			if (*((DWORD *)&code[i]) == old)
			{
				*((DWORD *)&code[i]) = x;

				return;
			}
		}
	}
};

使用例子:

class CTimer
{
private:

	int m_uElapse;
	int m_handle;
	typedef  Thunk<TIMERPROC, void (CTimer::*)(HWND hwnd, UINT uMsg, unsigned int  idEvent, DWORD dwTime)>TimerCallBackThunk;
	TimerCallBackThunk*m_timerCallbackFun = 0;
public:

	CTimer() :m_uElapse(20), m_handle(1), m_timerCallbackFun(new TimerCallBackThunk(this, &CTimer::TimerProc)){}
	~CTimer(){ delete m_timerCallbackFun; }
	void SetInterval(int uElapse)
	{
		m_uElapse = uElapse;
	}

	void Begin()
	{
		m_handle = SetTimer(NULL, 0, m_uElapse, *m_timerCallbackFun);
	}
	void End()
	{
		KillTimer(NULL, m_handle);
	}

	void TimerProc(HWND hwnd, UINT uMsg, unsigned int  idEvent, DWORD dwTime)
	{
		printf("回調轉換成功!當前時間計數:dwTime=%d\n",dwTime);
	}
};
int main(int argc, char* argv[])
{
	CTimer timer;
	timer.SetInterval(400);
	timer.Begin();

	MSG msg;
	BOOL bRet;

	while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
	{
		if (bRet == -1)
		{
			break;
		}
		else
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	return 0;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章