自己根据网上的一篇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;
}




以下是一个使用Thunk技术和VirtualAlloc函数的示例代码,演示了如何在C++中创建可执行代码的内存块,并使用Thunk函数进行调用: ```cpp #include <iostream> #include <Windows.h> class ThunkClass { public: ThunkClass(void (*func)()) : m_func(func) {} void Call() { m_func(); } private: void (*m_func)(); }; // 示例函数 void MyFunc() { std::cout << "MyFunc called!" << std::endl; } int main() { // 分配可执行的内存块 LPVOID executableMemory = VirtualAlloc(NULL, sizeof(ThunkClass), MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (executableMemory == NULL) { std::cerr << "Failed to allocate executable memory!" << std::endl; return -1; } // 创建一个Thunk对象,并将目标函数传递给构造函数 ThunkClass* thunk = new (executableMemory) ThunkClass(MyFunc); // 调用Thunk对象的Call方法 thunk->Call(); // 释放内存 thunk->~ThunkClass(); VirtualFree(executableMemory, 0, MEM_RELEASE); return 0; } ``` 在这个示例中,我们定义了一个 `ThunkClass`,它接受一个函数指针作为构造函数参数,并提供了一个 `Call` 方法来调用该函数。我们使用 `VirtualAlloc` 函数在内存中分配了一块可执行的内存块。 然后,我们使用定位 new 运算符将 `ThunkClass` 对象构造在可执行内存中。传递给构造函数的函数指针是我们想要调用的目标函数。 接下来,我们通过调用 `Call` 方法来执行目标函数。这里, `ThunkClass` 内部的 `Call` 方法会调用存储在对象中的函数指针。 在使用完内存块后,我们首先显式调用 `ThunkClass` 对象的析构函数 `~ThunkClass()`,然后使用 `VirtualFree` 函数释放内存。 这个示例代码演示了如何使用Thunk技术和VirtualAlloc函数来创建可执行代码的内存块,并通过Thunk对象进行调用。请注意,这个示例仅供了解和学习Thunk技术使用,实际应用中需要谨慎考虑安全性和可移植性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值