以前在别处写过类似的东西 什么是内联钩子技术?它到底有什么用 我们大概尽可能的授人以渔而不是鱼
那么先稍微了解这个技术到底有什么用
1、如果我想对消息框窗体进行美化(重绘)而不是使用系统默认的消息对话框 但很多时候你可能无法管理这些消息对话框窗体的弹出(管理泄露) 它可能是介于某个被调用第三方模块内部的行为 也可能是由于开发人员想快速的实现偷功减料
2、如果我需要去截获或修改自身程序网络层发送的数据包 那么在高层是无法做到的 当然你可以选择拦截.NET Socket类内的发出函数 但对.NET框架系统及.NET应用函数做拦截
不过对.NET函数拦截 它也会具备很多很多痛点 比如你需要拦截一个WebBrowser嵌入式控件向http应用服务器发送的协议请求报文(假设是抓包工具)它显然无法做到 为什么?WebBrowser作为一种OLE嵌入式的COM组件从AxHost派生 并高度封装成一个.NET用户控件(底层使用IE内核而注意IE内核是原生ATL程序 这意味着它不可能使用.NET上的函数)
内链钩子这种技术它谈不上新但足够使用 微软在自家系统中用的特别多 实际上HOOK是一种替换DOS下的中断机制但内敛钩子是比较特殊的一种它是替换被钩函数的执行行为(一是针对消息,另一个则是函数)
那么回到正题那么如何通过内敛钩子解决1、2的出现的问题呢?
对于第一题我们可以拦截MessageBoxA、MessageBoxW两个函数 然后替换它原来的行为 也就是说在上层只要调用了这两个函数 那么就会执行我们的替换这个方法的函数 在这个函数内部我们打开一个我们做好窗体美化的对话框 那么不论调用是通过.NET中的MessageBox::Show还是通过P/invoke调用或者是使用第三方插件使用了系统对话框的函数 那么就一定回弹出我们自定义美化的对话框(这个问题就解决了 而不必要大量调整代码)
对于第二题可以通过拦截send、recv、recvfrom、sendto、WSASend、WSARecv这些函数解决这类问题 而且它是健壮的 在很多问题上钩子的用途是非常的广泛 这里只是例举一些比较形象的问题 当然它可以被应用在一些安全事务的处理上
好了那么我们现在来看看它的原理图 只要理解了原理与思想至于如何实现就并不是那么需要去关注的问题了 因为本身并不是想象中的那么复杂
好,从图上看调用方调用了目标函数 目标函数由通过跳板把行为代理给钩子处理程序 可以说钩子技术是动态接口代理等技术的思想鼻主
从图上看对于跳板技术是作为打通调用方与钩子处理程序的核心之处 但函数本身并没有与钩子处理程序有任何代码或间接关联 那么需要完成上图的流程则必须要把跳板置入到函数内部去
从上图你可以看到有两个大方框这里表示函数头被修改前(origin)与修改后(jmp rva)那么需要先了解一下(jmp)在汇编中的作用它表示无条件的转移指令 而把它放置在函数头则意味着当调用方通过call指令调用函数时 那么最先则到达执行(jmp)转移到相对地址(RVA)那么此时并没有做入栈与部署堆栈等操作 如果我们把它转移到另一个函数的开始位置呢?
当调用方调用函数A时,但执行的确是函数B 因为函数A头部被修改成了类似于上面方式 但是在x86平台除了jmp rva还有另一种方式是通过call的 但这种处理上会比较麻烦
但考虑到jmp指令本身只支持在0x00000000~0x7FFFFFFF之间进行寻址 这很明显意味着在x64平台上使用这个指令作为函数的跳板层是会出问题的
对于x64平台上有几种方式比如通过push利用堆栈的方式
push rax
ret
当然我在开放的代码内是通过
mov rax, va
jmp rax
的方式(看雪论坛上有个牛人提供的C+代码便是这类)当然你可以选择使用如rdi、rdx寄存器托管函数的绝对地址(va)
开源代码示例代码的获取地址 https://github.com/liulilittle/NetHook 它包含了x64、x86下的内敛钩子工具的源代码你可以进行一些参考