Hook专题5-VEH hook
学一学 hook 专题,今天是 VEH hook。
学习笔记
今天学了比较新的一个 hook 的姿势:利用异常处理去hook。
前置芝士
SEH
SEH 即 结构化异常处理(Structure Exception Handler),是Windows操作系统提供的强大异常处理功能。当程序执行过程中发生异常时,零环会使用KiDispatchException
判断是否有内核调试器。如果没有调试器,零环转交给三环的KiDispatchException
,开始找是否有异常处理程序(SEH、VEH)。如果已安装,会调用异常处理程序进行处理
异常处理流程:异常产生->调试器->VEH->SEH->TopLevelEH->调试器
SEH有很多缺点(基于线程、基于栈、处理优先级低)等等。
VEH
向量化异常处理(Vectored Exception Handler),我们可以用AddVectoredExceptionHandler
函数注册自定义的VEH。当捕获到异常时,我们会拿到一个_EXCEPTION_POINTERS类型的参数。而这个参数的成员ContextRecord
保存着异常触发时CPU各种寄存器的值,这就意味着我们可以直接修改EIP/RIP寄存器,从而达到指令跳转的目的。
VEH hook
之前用的 inline hook,IAT hook,virtual hook 以及 hotfix hook,都是通过修改内存来劫持的控制流,因为都对内存进行了直接修改所以很容易被检测到。
而在 VEH hook 中,我们可以使用硬件断点搞出一个异常来,然后转入我们的异常处理函数,这个是后话了,我们先学 int 3 断点去进行 VEH hook。
之前看 《加密与解密》 的书也讲到了,int 3就是一个断点指令,在我们打普通断点的时候,会把指令的第一个字节改为 0xCC 也就是 int 3指令的字节码,继续执行的时候会把 0xCC 替换回原指令字节。原理就是 0xCC 指令在执行的时候会引发一个 BREAKPOINT_EXCEPTION,被调试器接收到了,调试器暂时挂起了这个程序然后把当前程序的状态展示给我们看。若没有调试器,则我们需要自己写处理函数去处理这个异常。
创建一个dll
1 |
|
在这里
- EXCEPTION_EXECUTE_HANDLER(1):表示该异常被处理,从异常处下一条指令继续执行
- EXCEPTION_CONTINUE_SEARCH(0):表示异常不能被处理,交给下一个SEH
- EXCEPTION_CONTINUE_EXECUTION(-1):表示异常被忽略,从异常处继续执行
这里还有一点需要注意一下,就是 程序的指令指针 eip 需要后移两个字节,不然它会一直循环被自己断住的。
运行程序,注入,成功!
在这里需要注意一点就是,几乎每个 winapi 开头都是 mov edi,edi,这个是为了进行一个 hotfix 的。没错,是专门为了这个而生的,而且附近一定有空内存可以让我们进行修改大跳转指令的内存。