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; }