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


     

  • 相关阅读:
    主流数据库连接池性能比较 hikari druid c3p0 dbcp jdbc
    Dubbo 分布式事务一致性实现
    微服务实现事务一致性实例
    微服务间保持事务一致性
    海量积分数据实时排名处理方式介绍二
    Java两种方法实现循环报数
    MySQL 千万级 数据库或大表优化
    Linux 中 Nginx 重启关闭
    Linux 中 Oracle dmp 文件导入导出
    Linux 中 Oracle 数据库启动和关闭
  • 原文地址:https://www.cnblogs.com/dongc/p/5225109.html
Copyright © 2020-2023  润新知