利用Thunk让C++成员函数变回调函数

  Windows API经常需要回调函数,而在C++开发中面向对象当行其道,若能让C++类的成员函数成为回调函数,简直就是大善!但是C++成员函数都隐含了一个this指针用于指向当前的对象。要实现回调确实不容易。

   我大约一年前就接触到Thunk技术,甚至也看过利用Thunk实现将成员函数变成回调函数的例子。但是我实在没了解过C++汇编后的样子,很容易钻了 牛角尖,看都看不懂,直接用他们的程序又不敢,毕竟出错后不好处理。前端时间偶尔想起Thunk技术,对未懂技术老这样悬着很可能影响自己的程序员生涯 的,于是决心闭关参悟(没办法 ,资质差啊),终于弄明白了。那种感觉啊,就像诚信礼佛的人突然见到如来一样,或者换了贴近自己的比喻:就像千年色鬼见到美女一样的兴奋。 我忍不住的模仿小说中的修真人士突悟大道后的感叹:原来如此!

  下面的分享一下我的收获,基本上是出入门径的写给初学者的,大侠千万要止步,小弟皮薄!

   稍微研究了一下C++汇编后的代码,一般调用C++的成员函数之前,都是使用ECX寄存器保存对象的指针,好在C++成员函数的调用约定 __thiscall的参数压栈顺序和堆栈平衡的维护都是和回调函数的调用约定__stdcall一样,所以只需要构造汇编将对象指针保存在ECX寄存器 后JMP到成员函数的执行地址就可以了。先写个C++结构拼凑这两条汇编码:
  #pragma pack( push, 1 )
  struct  MemFunToStdCallThunk
  {
  BYTE       m_mov;
  DWORD     m_this;
  BYTE       m_jmp;
  DWORD     m_relproc;
  BOOL  Init( DWORD_PTR proc, void* pThis )
  {
  m_mov = 0xB9;
  m_this = PtrToUlong(pThis);
  m_jmp = 0xe9;
  m_relproc = DWORD((INT_PTR)proc - ((INT_PTR)this+sizeof(MemFunToStdCallThunk)));
  ::FlushInstructionCache( ::GetCurrentProcess(), this, sizeof(MemFunToStdCallThunk) );
  return TRUE;
  }
  void* GetCodeAddress()
  {
  return this;
  }
  };
  #pragma  pack( pop )
  这个结构相当于两条汇编语句:
  mov ecx, pThis
  jmp [偏移地址]
  使用:
  class  CTestClass
  {
  private:
  int  m_nBase;
  MemFunToStdCallThunk  m_thunk;
  void  memFun( int m, int n )
  {
  int  nSun = m_nBase + m + n;
  CString str;
  str.Format( _T("%d"), nSun );
  AtlMessageBox( NULL, _U_STRINGorID( str ) );
  }
  public:
  CTestClass()
  {
  m_nBase  = 10;
  }
  void  Test()
  {
  //UnionCastType:利用联合将函数指针转换成DWORD_PTR
  m_thunk.Init( UnionCastType<DWORD_PTR>(&CTestClass::memFun), this );
  StdCallFun fun = (StdCallFun)m_thunk.GetCodeAddress();
  ATLASSERT( fun != NULL );
  fun( 1, 3 );
  }
  };
  MemFunToStdCallThunk的Init方法接受成员函数指针和对象指针后就构造成2条汇编码,当调用fun(1,3)时,
  首先将参数3和1压入堆栈,之后跳转到m_thunk处,也就是那构造的2条汇编码处,将对象指针保存到ECX寄存器,之后跳转到指定的成员函数处执行。一切OK了。
  UnionCastType方法的代码如下:
  template< typename TDst, typename TSrc >
  TDst  UnionCastType( TSrc src )
  {
  union
  {
  TDst  uDst;
  TSrc  uSrc;
  }uMedia;
  uMedia.uSrc  =  src;
  return uMedia.uDst;
  }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值