thunk技术

Thunk : 将一段机器码对应的字节保存在一个连续内存结构里, 然后将其指针强制转换成函数. 即用作函数来执行,通常用来将对象的成员函数作为回调函数.

#include "stdafx.h"
#include <Windows.h>

namespace pri{

	typedef unsigned char u1byte;
	typedef unsigned short u2byte;
	typedef unsigned long u4byte;
	typedef void* pvoid;

	#define GETBYTE(b, n) ((u1byte)(b >> ((n - 1)* 8) & 0x 000000FF))

	class Thunk
	{
	public:
		Thunk()
		{
			m_pThis = (Thunk*)VirtualAlloc(nullptr, sizeof(Thunk),
				MEM_COMMIT, PAGE_EXECUTE_READWRITE);
		}

		~Thunk()
		{
			if (m_pThis) {
				VirtualFree(m_pThis, 0, MEM_RELEASE);
			}
		}

	public:
		void* ThisCall(void* pThis, u4byte addr)
		{
			/*
			__asm {
				mov exc,pThis;
				call Addr;
			}
			*/
			m_pThis->m_thisCall.Mov = 0xB9;				// mov exc,pThis;
			m_pThis->m_thisCall.This = (u4byte)pThis;
			m_pThis->m_thisCall.Jmp = 0xE9;				// call Addr;
			m_pThis->m_thisCall.Addr = addr - (u4byte)(&(m_pThis->m_thisCall)) - 
				sizeof(BYTECODE_THISCALL);

			FlushInstructionCache(GetCurrentProcess(), &(m_pThis->m_stdCall),
				sizeof(BYTECODE_THISCALL));
			return &(m_pThis->m_thisCall);
		}

		void* StdCall(void* pThis, u4byte addr)
		{
			/*
			__asm{
				push dword ptr [esp];
				mov dword ptr [esp+4],pThis;
				call Addr;
			}
			*/
			m_pThis->m_stdCall.Push[0] = 0xFF;		// push dword ptr [esp];
			m_pThis->m_stdCall.Push[1] = 0x34;			
			m_pThis->m_stdCall.Push[2] = 0x24;
			m_pThis->m_stdCall.Mov = 0x042444c7;		// mov dword ptr [esp+4],pThis;
			m_pThis->m_stdCall.This = (u4byte)pThis;
			m_pThis->m_stdCall.Jmp = 0xE9;			// call Addr;
			m_pThis->m_stdCall.Addr = addr - (u4byte)(&(m_pThis->m_stdCall)) -
				sizeof(BYTECODE_STDCALL);
			FlushInstructionCache(GetCurrentProcess(), &(m_pThis->m_stdCall),
				sizeof(BYTECODE_STDCALL));
			return &(m_pThis->m_stdCall);
		}

		template<typename T>
		static u4byte GetMemberAddr(T funcName)
		{
			union {
				T From;
				u4byte To;
			} union_cast;
			union_cast.From = funcName;
			return union_cast.To;
		}

		#pragma pack(push, 1)
		struct BYTECODE_THISCALL
		{
			u1byte Mov;	// 0xB0
			u4byte This;	// this
			u1byte Jmp;	// 0xE9
			u4byte Addr;	// addr
		};

		struct BYTECODE_STDCALL
		{
			u1byte Push[3];
			u4byte Mov;
			u4byte This;
			u1byte Jmp;
			u4byte Addr;
		};

		#pragma pack (pop)
		BYTECODE_THISCALL	m_thisCall;
		BYTECODE_STDCALL	m_stdCall;
		Thunk* m_pThis;
	};
}

class A
{
public:
	A() {}

	~A() {}

	// __thiscall调用约定 [12/28/2014]
	// 将this指针存入ecx寄存器进行参数传递
	void __thiscall fun1(HWND hwnd, UINT msg, UINT_PTR id, DWORD time)
	{
		hwnd = 0;
		msg = 1;
		id = 2;
		time = 3;
		m_index = 100;
	}

	// Win32API函数调用约定 [12/28/2014]
	// 将this指针压入栈进行参数传递
	void __stdcall fun2(HWND hwnd, UINT msg, UINT_PTR id, DWORD time)
	{
		hwnd = 0;
		msg = 1;
		id = 2;
		time = 3;
		m_index = 100;
	}

	// c++默认为__thiscall调用约定 [12/28/2014]
	void fun3(HWND hwnd, UINT msg, UINT_PTR id, DWORD time)
	{
		hwnd = 0;
		msg = 1;
		id = 2;
		time = 3;
		m_index = 100;
	}

private:
	int m_index;
};


int _tmain(int argc, _TCHAR* argv[])
{
	A* pa = new A();
	pa->fun1(0, 1, 2, 3);
	pa->fun2(0, 1, 2, 3);
	pa->fun3(0, 1, 2, 3);

	pri::Thunk thunk;
	void* thisAddr = thunk.ThisCall(pa, pri::Thunk::GetMemberAddr(&A::fun1));
	void* stdAddr = thunk.StdCall(pa, pri::Thunk::GetMemberAddr(&A::fun2));

	// 这里是非成员函数调用,只能为__stdcall [12/28/2014]
	//typedef void(__thiscall* ThisCall)(HWND, UINT, UINT_PTR, DWORD);
	typedef void(__stdcall* StdCall)(HWND, UINT, UINT_PTR, DWORD);
	StdCall pv0 = (StdCall)thisAddr;
	StdCall pv1 = (StdCall)stdAddr;
	pv0(0, 1, 2, 3);
	pv1(0, 1, 2, 3);

	// 执行成员函数回调 [12/28/2014]
	UINT_PTR id0 = SetTimer(nullptr, 100, 1000, (TIMERPROC)pv0);
	UINT_PTR id1 = SetTimer(nullptr, 101, 1000, (TIMERPROC)pv1);


	MSG   msg;  
	int   itemp; 
	while ( (itemp = GetMessage(&msg, NULL,NULL,NULL))&& (itemp!=0) &&  (-1 !=  itemp))   
	{     
		if   (msg.message   ==   WM_TIMER)     
		{     
			TranslateMessage(&msg);     
			DispatchMessage(&msg);       
		}     
	}     

	system("pause");

	return 0;
}


 

posted on 2015-01-18 16:05  dchao  阅读(269)  评论(0编辑  收藏  举报

导航