HOOK原理
在并发的情况下要HOOK函数需要使用CMPXCHG8B 指令,该指令可以原子操作一次性的替换掉8字节的内存。
CMPXCHG8B 指令
该指令判断指定内存中的8字节内容和EDX:EAX (edx高32位,eax,低32位)中的64字节内容是否相同,
如果相同,就把ECX:EBX(ecx高32位,ebx,低32位)中的内容替换到指定内存。
如果不相同,就把指定内存中的值替换到ECX:EBX中。
#include"ntddk.h"
ULONG addr = 0x80546a98; //这是SwapContext+8的位置
_declspec(naked) void Swap()
{
__asm{
push eax
mov eax,0x8003f048 //记录切换的次数
inc dword ptr [eax]
pop eax
//下面开始恢复原函数的指令
or cl, cl
mov byte ptr es : [esi + 0x2d], 0x2
pushfd
jmp addr //在自己的hook函数处理完后,跳转到原函数+8的位置
}
}
VOID __stdcall UnLoad(PDRIVER_OBJECT pDriver)
{
DbgPrint("Driver 卸载成功");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pRegPath)
{
pDriver->DriverUnload = UnLoad;
ULONG JmpAddr = (ULONG)Swap - 0x80546a90 - 5;//0x80546a90是SwapContext函数的地址
ULONG des[2] = {0};
DbgPrint("JmpAddr=%x\n",JmpAddr);
//去掉最高的8位 然后+e9
des[0] = (JmpAddr<<8)+ 0xe9; //xxxxxx e9 000000xx
//保留最低的8位 并移到最高位
des[1] =(JmpAddr>>24);
DbgPrint("des[0]=%x\n", des[0]);
DbgPrint("des[1]=%x\n", des[1]);
//准备好写入的8字节数据
__asm{
//把 EDX : EAX设置为目标的值
mov esi, 0x80546a90
//eax=0xc626c90a
mov eax, [esi]
//edx=0x9c022d46
mov edx, [esi+4]
// 把ECX:EBX 设置为要写入的值
//ebx= xx2d029c
mov ebx, des[0]
//ecx=e8xxx
mov ecx, des[4]
lock CMPXCHG8B [esi] ;
}
DbgPrint("高并发hook成功");
return STATUS_SUCCESS;
}