Inline Hook需要注意的问题

指令碎片化

在Inline Hook时一般在需要HOOK的函数头部写入jmp指令,然后jmp指令跳转到Detour函数中。但是因为inline hook函数的头部代码形式多样,写入jmp指令需要5个字节,但是有可能修改5个字节后会出现指令碎屑。这样如果执行完Detour函数后接着hook后的代码执行就会使程序崩溃。

inline hook前

inline hook后,0x12345678为Detour函数地址,填充jmp指令后产生指令碎屑

使用反汇编引擎

在需要inline hook时,使用轻量级的反汇编引擎对函数头部的代码进行反汇编,修改完整的一条指令,碎屑用nop填充。
但是又产生了新的问题,如果需要修改的代码为jmp指令或者 call指令(0xE8)指令如果在Detour函数中调用原函数呢?因为需要解决jmp指令偏移的问题,需要进行重定位很麻烦
例如:下图中函数头部为jmp 0x77799933,对应的机器码偏移为0xFB。如果在Detour函数中执行jmp 0x77799933指令,那么偏移的机器码就得重新计算。

恢复hook修改的代码

为了解决指令碎屑所带来的一系列问题,可以在Detour函数调用原函数前将hook是修改的代码恢复,然后在调用完之后Detour函数在将hook设置好。
例如:下图中在MessageBox的Detour函数中在调用原MessageBox前,先将inline Hook修改的代码恢复,在调用原MessageBox函数后在重新设置inline hook。

HOOK操作的线程安全

inline hook操作需要修改大于机器最大处理长度的字节,这时就有可能在设置hook的过程中代码被执行从而造成程序crash。

应用层暂停其他无关线程

对于应用层的inline hook,为了防止hook操作外的其他线程执行hook的函数,可以将其他无关线程全部Suspend,hook操作完之后在Resume

内核层提升中断请求级别(IRQL)

因为内核中线程调度内核代码所在的IRQL为DpcLevel,而处理器不接受同等级别或低级别的请求。所以可以将inline hook操作代码的IRQL级别提升到DpcLevel级别。
另外如果存在多个CPU的话还需将其他cpu投递特定DPC,是其他CPU进入一种“准空转”状态。

用Lock xchg/cmpxchg

xchg为数据交换指令,加上lock前缀可以保证此指令是一个原子操作,对应的API函数为InterlockedExchange/64()。

堆栈平衡和环境保护

因为inline hook会使代码直接jmp到Detour函数中,所以需要保证Detour函数与hook的函数调用约定和参数一致从而保证堆栈平衡。在Detour函数中调用原函数前需要将寄存器环境还原以免影响原函数则正确调用。

避免重入

HOOK A函数
Detour函数调用B函数,B函数中又会调用A函数,(接着A函数又会调用Detour函数),如此会形成一个无限递归也就是重入问题。

还原A函数

在Detour函数调用B函数前先还原A函数,在B函数调用后,Detour函数再将设置A函数的inline hook。

加入特定标志

在A函数调用参数中加入特殊标记,可以在Detour函数头部进行判断,如果此次A函数调用参数中有我们的特殊标记就证明此次调用是我们的调用继续执行就好了,如果没有说明是系统调用的直接调用原函数就好了。

原文地址:https://www.cnblogs.com/revercc/p/15467745.html