话说来看雪注册已半个月有余了,可是天天在线也不见KX增长。
老话说狗急了跳墙,人急了就会自己动手了。
说一个恢复InlineHook的方法,但是比较猥琐。而且高手直接飘过吧~~~~~~
咱就以某个游戏的保护措施为列吧,看好了这里不是讲如何过这个保护的,而是对她猥琐一下。
这个游戏在内核中HOOK了很多函数,就以KeAttachProcess为例。
在没运行游戏之前
代码:
kd> u KeAttachProcess nt!KeAttachProcess: 804f88cc 8bff mov edi,edi 804f88ce 55 push ebp 804f88cf 8bec mov ebp,esp 804f88d1 56 push esi 804f88d2 57 push edi
很明显它是在KeAttachProcess函数开头进行了HOOK并且转到的地址仍然是一条
JMP语句跳到另外一个地方,至于它为什么这么做。我分析可能是用一条线程不停的写
最后那条JMP语句比较方便。扯远了……
那么我们怎么恢复KeAttachProcess呢,正常的情况下只要将它头部的几条重新写进去就可以了
可我们今天要猥琐一点,偏要脱裤子放屁。 有时候脱裤子放屁也是一种艺术。
不废话了,图解它的HOOK原理
而我们要做的呢,看下图
好了,整个原理都看过图了。下面上代码就OK了
代码:
//Driver.c #include <ntddk.h> #include <wdm.h> #include <windef.h> #define NAKED __declspec(naked) //定义裸体函数 #define PAGEDCODE code_seg("PAGE") //分页 #define LOCKEDCODE code_seg() //非分页 #define INITCODE code_seg("INIT") //初始化时载入内存而后卸载 //保存被HOOK函数开头的前5条指令 #pragma pack(1) typedef struct _TOP5CODE { UCHAR instruction; //指令 ULONG address; //地址 }TOP5CODE,*PTOP5CODE; #pragma pack( ) BYTE *KeAttachProcessAddress = NULL; //AttachProcess函数地址 //卸载函数 VOID DriverUnload(IN PDRIVER_OBJECT pDriverObject) { KdPrint(("Enter DriverUnload\n")); } //获取函数地址 ULONG MyGetFunAddress( IN PCWSTR FunctionName) { UNICODE_STRING UniCodeFunctionName; RtlInitUnicodeString( &UniCodeFunctionName, FunctionName ); return (ULONG)MmGetSystemRoutineAddress( &UniCodeFunctionName ); } //中继函数 #pragma LOCKEDCODE static NAKED VOID MyKeAttachProcessRelay() { __asm { mov edi,edi push ebp mov ebp,esp push esi mov eax,KeAttachProcessAddress add eax,6 jmp eax } } //入口函数 NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { TOP5CODE *top5code = NULL; BYTE *jmpAddress = NULL; //保存GPK修改内容的地址 BYTE JmpMyAttachProcess[5] = {0xE9,0,0,0,0}; //跳转到HOOK函数的地址 KIRQL Irql; //获取函数地址 KeAttachProcessAddress = (BYTE*)MyGetFunAddress(L"KeAttachProcess"); //将指针指向AttachProcessAddress函数头部 top5code = (TOP5CODE*)KeAttachProcessAddress; jmpAddress = (BYTE*)top5code->address; //计算jmpAddress与MyKeAttachProcess的相对地址 *(ULONG *)(JmpMyAttachProcess+1)=(ULONG)MyKeAttachProcessRelay-((ULONG)jmpAddress+5); __asm { cli mov eax,cr0 and eax,not 10000h mov cr0,eax } //提升IRQL中断级 Irql=KeRaiseIrqlToDpcLevel(); //写入JMP语句 RtlCopyMemory((BYTE*)jmpAddress,JmpMyAttachProcess,5); //恢复Irql KeLowerIrql(Irql); __asm { mov eax,cr0 or eax,10000h mov cr0,eax sti } //设置卸载函数 DriverObject->DriverUnload = DriverUnload; return STATUS_SUCCESS; }
当然这种猥琐也可以用在SSDT HOOK 上面。
就是到被修改的地址开始出写一句JMP 跳转回原始函数的开始处。