用 Thunk 实现 COM 的挂钩

本文深入探讨了COM挂钩技术,通过替换虚表中的函数指针来实现。文章详细介绍了使用VirtualProtect改变虚表页面属性的方法,并提供了实现代码示例。此外,还介绍了一种通过thunk技术解决类成员函数作为挂钩函数限制的方法。

 COM 的挂钩其实已经是一个很古老的话题了,其核心技术就是替换 COM 对象虚表中相应位置的函数指针,从而达到挂钩的效果。顺便说一句,这个方法和内核的 SSDT 挂钩是十分类似的。其相应的实现代码也十分简单,如下所示:

需要指出的是,这里要使用 VirtualProtect 改变虚表的页面属性,就像挂钩 SSDT 时要改变 cr0 的保护属性一样。
整个的挂钩过程及使用类似于这个样子:

这种挂钩的方式有一个局限性,就是挂钩函数 HookQueryInterface 不能作为一个非 static 的类成员函数来实现。与之类似,Win32 的 WNDPROC 也无法使用非 static 的类成员函数来封装,实乃一大憾事。

当然,我们可以通过非常规的方法来解决这个问题,比如 thunk。
在开始实现我的 thunk 之前,先来看看一个 COM 方法调用的过程,考虑如下代码:

这个调用过程所对应的汇编代码为:

   

也就是说,一个 COM 方法调用的压栈顺序为:

  1. 由右至左的各个参数,也就是 STDCALL 调用约定的压栈顺序;
  2. this 指针;
  3. 当然,还有 call 的返回地址,这个压栈是在 call 指令内部完成的。

从上面可以看出来,为了把一个 COM 调用重定向到我们自己的类成员函数中,需要做以下工作:

  1. 保留原 COM 方法的各个参数;
  2. 保留原 COM 对象的 this 指针;
  3. 加入我们自己类对象的 this 指针;
  4. 保留 call 原有的返回地址。

简单说来,这个重定向的过程是将堆栈中插入另外一个 this 指针,仅此而已。
明确了这个操作的步骤,我们可以写出如下的 thunk 代码,这段代码将被放到目标 COM 对象的虚表中。

相应地,我们为这个 thunk 定义一个结构:

以及一个用于保存挂钩信息的结构:

 

 

 最后,就可以实现这个升级版的挂钩函数了,如下:

测试代码如下,使用 B 类中的 hook_foo 挂钩了上文中的 A::foo。

其中 member_cast 用于非 static 成员的类型转换,可以参考《获取成员函数的指针》一文,再次感谢 likunkun 所提供的优雅解决方案。
全部示例代码见附件。

下载地址: http://www.titilima.cn/attachment.php?id=287

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值