现在有一些驱动保护对idt中断描述符表进行了一些处理,导致我们附加游戏的时候会直接重启或者蓝屏或者游戏退出的情况。那么本篇的内容实际是对教程中的知识点进行实践的内容,看本篇前希望你们明白第二十课的内容,不然会觉得莫名其妙。
好了,我们直接步入主题。
驱动保护既然hook了idt,自然会检测它hook的位置是否恢复,和对它自身函数做crc等等。那么我们直接恢复hook是没用的,就要另想方法了。
一般比较通用的方法有两种,对段基址进行处理和用vt,本篇就是用段基址处理hook后的idt。
在第二十课的时候我说过,windows中的虚拟地址是这样的:
段基址 + 段内偏移 = 虚拟地址
一般情况下段基址是0,所以段内偏移就相当于虚拟地址了。idt中所有中断函数的段基址也是默认为零的,而驱动保护就是对段内偏移进行修改,而达到hook的作用。由于段基址是零,所以修改段内偏移就等于修改了虚拟地址。我们要想办法绕过的话,就要对段基址动手脚,因为驱动保护基本没对段基址进行检测的,如果有的话,那这种办法就失灵了。但是我一般看到的都没有.......
怎么动手脚呢,我们可以这样处理:当段内偏移改变的时候,我们让段基址跟着改变。比如原始的段基址是0,段内偏移是0x1000,虚拟地址是0x1000,那就是:
0 + 0x1000 = 0x1000;
现在驱动保护修改了段内偏移,假如变成了0x500。那么:
0 + 0x500 = 0x500;
这样就实现了hook的目的。我们要绕过,就要这样做:
? + 0x500 = 0x1000;
就是段基址为多少的时候,使驱动保护提供的段内偏移和段基址相加还是等于以前的虚拟地址。
那么狠明显,0x1000 - 0x500 = 0x500;
段基址赋值为0x500就可以了。思路很简单的,但是由于概念本身就比较多,所以很多人被卡主了。
那好,现在问题解决了,只要发现改变了段内偏移,那我们就跟着改变段基址,使:
新段基址 + 新段内偏移 = 原始的虚拟地址
只要做到这样,就可以绕过游戏的hook。
但是另外一个问题来了,当驱动保护修改了段内偏移的时候,我们如何发现段内偏移给修改了呢?
一般最简单的方法是设置个定时器,要设置的尽量小点,不断的检测是否驱动保护修改了段内偏移,是的话就马上处理段基址。
还有其他的办法就是hook比较频繁被调用的函数,然后在过滤函数中对段内偏移做判断工作。系统中频繁被调用的函数有很多很多,大家可以根据需要去hook。
因为过驱动保护的时候我们为了简单,都会使用重载内核过掉内核hook,所以都会对kifastcallentry函数做手脚。而这个函数调用是非常非常频繁的,比定时器的最小周期还要频繁。如果你hook了kifastcallentry函数,又不想使代码量变多,你可以考虑在这个函数里面判断是够段内偏移被修改了。
我就是在kifastcallentry函数里面判断的,实际最好用定时器(思路清晰)!
下面我直接上代码把,实际这些代码都是写过的,我改动的地方不超过20行!由于我只为了表达思路,所以我简单的把以前的拼凑了一下,代码难看希望大家多多谅解。- #ifndef _PUBLIC_H_
- #define _PUBLIC_H_
-
- #include "ntddk.h"
-
- #define WORD USHORT
- #define DWORD ULONG
-
- #define MAKELONG(a, b) ((LONG)(((WORD)(((DWORD_PTR)(a)) & 0xffff)) \
- | ((DWORD)((WORD)(((DWORD_PTR)(b)) & 0xffff))) << 16))
-
- typedef struct _IDTR{
- USHORT IDT_limit;
- USHORT IDT_LOWbase;
- USHORT IDT_HIGbase;
- }IDTR,*PIDTR;
-
- //idt结构定义
- typedef struct _IDTENTRY
- {
- unsigned short LowOffset;
- unsigned short selector;
- unsigned char retention:5;
- unsigned char zero1:3;
- unsigned char gate_type:1;
- unsigned char zero2:1;
- unsigned char interrupt_gate_size:1;
- unsigned char zero3:1;
- unsigned char zero4:1;
- unsigned char DPL:2;
- unsigned char P:1;
- unsigned short HiOffset;
- } IDTENTRY,*PIDTENTRY;
-
- //gdt结构定义
- typedef struct _KGDTENTRY {
- USHORT LimitLow;
- USHORT BaseLow;
- union {
- struct {
- UCHAR BaseMid;
- UCHAR Flags1; // Declare as bytes to avoid alignment
- UCHAR Flags2; // Problems.
- UCHAR BaseHi;
- } Bytes;
- struct {
- ULONG BaseMid : 8;
- ULONG Type : 5;
- ULONG Dpl : 2;
- ULONG Pres : 1;
-
- ULONG LimitHi : 4;
- ULONG Sys : 1;
- ULONG Reserved_0 : 1;
- ULONG Default_Big : 1;
- ULONG Granularity : 1;
- ULONG BaseHi : 8;
- } Bits;
- } HighWord;
- } KGDTENTRY, *PKGDTENTRY;
-
- //系统服务描述表定义
- #pragma pack(1)
- typedef struct ServiceDescriptorEntry {
- unsigned int *ServiceTableBase;
- unsigned int *ServiceCounterTableBase; //仅适用于checked build版本
- unsigned int NumberOfServices;
- unsigned char *ParamTableBase;
- } ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
- #pragma pack()
-
- __declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
-
- //global
- USHORT g_FilterJmp[3];
- ULONG g_uOrigInterruptFunc;
-
- BOOLEAN g_bHookInterrupt;
- //global
- ULONG g_ntcreatefile;
- ULONG g_fastcall_hookpointer;
- ULONG g_goto_origfunc;
-
- //等会儿就用它做栈回溯吧
- typedef NTSTATUS
- (*NTCREATEFILE) (
- __out PHANDLE FileHandle,
- __in ACCESS_MASK DesiredAccess,
- __in POBJECT_ATTRIBUTES ObjectAttributes,
- __out PIO_STATUS_BLOCK IoStatusBlock,
- __in_opt PLARGE_INTEGER AllocationSize,
- __in ULONG FileAttributes,
- __in ULONG ShareAccess,
- __in ULONG CreateDisposition,
- __in ULONG CreateOptions,
- __in_bcount_opt(EaLength) PVOID EaBuffer,
- __in ULONG EaLength
- );
-
- //各种函数乱声明下:D
- void PageProtectOn();
- void PageProtectOff();
- ULONG SearchHookPointer(ULONG StartAddress);
- void __stdcall FilterInterruptFunc3();
- ULONG GetInterruptFuncAddress(ULONG InterruptIndex);
-
- VOID HookInterruptFunc(ULONG InterruptIndex,ULONG NewInterruptFunc);
-
- void NewInterrupt3();
-
- #endif
复制代码 以上是头文件,下面才是重点:- #include "public.h"
-
- void PageProtectOn()
- {
- __asm{//恢复内存保护
- mov eax,cr0
- or eax,10000h
- mov cr0,eax
- sti
- }
- }
-
- void PageProtectOff()
- {
- __asm{//去掉内存保护
- cli
- mov eax,cr0
- and eax,not 10000h
- mov cr0,eax
- }
- }
-
- ULONG SearchHookPointer(ULONG StartAddress)
- {
- ULONG u_index;
-
- UCHAR *p = (UCHAR*)StartAddress;
-
- for (u_index = 0;u_index < 200;u_index++)
- {
- if (*p==0x2B&&
- *(p+1)==0xE1&&
- *(p+2)==0xC1&&
- *(p+3)==0xE9&&
- *(p+4)==0x02)
- {
- return (ULONG)p;
- }
-
- p--;
- }
-
- return 0;
- }
-
- //过滤kifastcallentry函数
- void FilterKiFastCallEntry(ULONG ServiceTableBase,ULONG FuncIndex)
- {
- //这里就是不断的检测
- HookInterruptFunc(3,(ULONG)NewInterrupt3);
- }
-
- __declspec(naked)
- void NewKiFastCallEntry()
- {
- __asm{
- pushad
- pushfd
-
- push eax
- push edi
- call FilterKiFastCallEntry
-
- popfd
- popad
-
- sub esp,ecx
- shr ecx,2
- jmp g_goto_origfunc
- }
- }
-
- void UnHookKiFastCallEntry()
- {
- UCHAR str_origfuncode[5] = {0x2B,0xE1,0xC1,0xE9,0x02};
-
- if (g_fastcall_hookpointer==0)
- { return; }
-
- PageProtectOff();
- RtlCopyMemory((PVOID)g_fastcall_hookpointer,str_origfuncode,5);
- PageProtectOn();
- }
-
- void HookKiFastCallEntry(ULONG HookPointer)
- {
- ULONG u_temp;
- UCHAR str_jmp_code[5];
-
- str_jmp_code[0] = 0xE9;
-
- u_temp = (ULONG)NewKiFastCallEntry - HookPointer - 5;
- *(ULONG*)&str_jmp_code[1] = u_temp;
-
- PageProtectOff();
-
- RtlCopyMemory((PVOID)HookPointer,str_jmp_code,5);
-
- PageProtectOn();
-
- }
-
- NTSTATUS NewNtCreateFile (
- __out PHANDLE FileHandle,
- __in ACCESS_MASK DesiredAccess,
- __in POBJECT_ATTRIBUTES ObjectAttributes,
- __out PIO_STATUS_BLOCK IoStatusBlock,
- __in_opt PLARGE_INTEGER AllocationSize,
- __in ULONG FileAttributes,
- __in ULONG ShareAccess,
- __in ULONG CreateDisposition,
- __in ULONG CreateOptions,
- __in_bcount_opt(EaLength) PVOID EaBuffer,
- __in ULONG EaLength
- )
- {
- ULONG u_call_retaddr;
-
- __asm{
- pushad
- mov eax,[ebp+0x4]
- mov u_call_retaddr,eax
- popad
- }
-
- g_fastcall_hookpointer = SearchHookPointer(u_call_retaddr);
- if (g_fastcall_hookpointer==0)
- {
- KdPrint(("search failed."));
- }else{
- KdPrint(("search success."));
- }
-
- g_goto_origfunc = g_fastcall_hookpointer + 5;
- HookKiFastCallEntry(g_fastcall_hookpointer);
-
- PageProtectOff();
- KeServiceDescriptorTable.ServiceTableBase[66] = (unsigned int)g_ntcreatefile;
- PageProtectOn();
-
- return ((NTCREATEFILE)g_ntcreatefile)(
- FileHandle,\
- DesiredAccess,\
- ObjectAttributes,\
- IoStatusBlock,\
- AllocationSize,\
- FileAttributes,\
- ShareAccess,\
- CreateDisposition,\
- CreateOptions,\
- EaBuffer,\
- EaLength);
- }
-
-
- void SearchKiFastCallEntry()
- {
-
- g_ntcreatefile = KeServiceDescriptorTable.ServiceTableBase[66];
- PageProtectOff();
- KeServiceDescriptorTable.ServiceTableBase[66] = (unsigned int)NewNtCreateFile;
- PageProtectOn();
- }
-
- //////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////
-
- void __stdcall FilterInterrupt()
- {
- KdPrint(("%s",(char*)PsGetCurrentProcess()+0x16c));
- }
-
- __declspec(naked)
- void NewInterrupt3OfOrigBase()
- {
- __asm{
- pushad
- pushfd
-
- push fs
- push 0x30
- pop fs
-
- call FilterInterrupt
-
- pop fs
-
- popfd
- popad
-
- jmp g_uOrigInterruptFunc
- }
- }
-
- __declspec(naked)
- void NewInterrupt3()
- {
- __asm{
- jmp fword ptr[g_FilterJmp]
- }
- }
-
- //这个函数功能是输入一个下标,返回该下标对应的中断地址
- ULONG GetInterruptFuncAddress(ULONG InterruptIndex)
- {
- IDTR idtr;
- IDTENTRY *pIdtEntry;
-
- __asm SIDT idtr;
-
- pIdtEntry = (IDTENTRY *)MAKELONG(idtr.IDT_LOWbase,idtr.IDT_HIGbase);
-
- return MAKELONG(pIdtEntry[InterruptIndex].LowOffset,pIdtEntry[InterruptIndex].HiOffset);
- }
-
- ULONG GetNewBase(ULONG NewInterruptFunc,ULONG OrigInterruptOffset)
- {
- return (NewInterruptFunc - OrigInterruptOffset);
- }
-
- //这个函数负责具体的修改工作,实际这些函数我20课中都一个个写过一遍的
- VOID SetInterrupt(ULONG InterruptIndex,ULONG uNewBase,BOOLEAN bIsNew)
- {
- ULONG u_fnKeSetTimeIncrement;
- UNICODE_STRING usFuncName;
- ULONG u_index;
- ULONG *u_KiProcessorBlock;
-
- IDTENTRY *pIdtEntry;
- PKGDTENTRY pGdt;
-
- RtlInitUnicodeString(&usFuncName,L"KeSetTimeIncrement");
-
- u_fnKeSetTimeIncrement = (ULONG)MmGetSystemRoutineAddress(&usFuncName);
- if (!MmIsAddressValid((PVOID)u_fnKeSetTimeIncrement))
- {
- return;
- }
-
- u_KiProcessorBlock = *(ULONG**)(u_fnKeSetTimeIncrement + 44);
-
- u_index = 0;
- while (u_KiProcessorBlock[u_index])
- {
- pIdtEntry = *(IDTENTRY**)(u_KiProcessorBlock[u_index] - 0xE8);
- pGdt = *(PKGDTENTRY*)(u_KiProcessorBlock[u_index] - 0xE4);
-
- KdPrint(("%X-----%X",pIdtEntry,pGdt));
-
- PageProtectOff();
-
- if (bIsNew)
- {
- pIdtEntry[InterruptIndex].selector = 0xA8;
- RtlCopyMemory(&pGdt[21],&pGdt[1],sizeof(KGDTENTRY));
- pGdt[21].BaseLow = (USHORT)(uNewBase&0xffff);
- pGdt[21].HighWord.Bytes.BaseMid = (UCHAR)((uNewBase>>16)&0xff);
- pGdt[21].HighWord.Bytes.BaseHi = (UCHAR)(uNewBase>>24);
- }else{
- pIdtEntry[InterruptIndex].selector = 0x8;
- memset(&pGdt[21],0,sizeof(KGDTENTRY));
- }
-
- PageProtectOn();
-
- u_index++;
- }
- }
-
- //注意这个函数,我是判断段内偏移是否修改完成或者恢复完成。就是说防止修改了一半或者恢复了一半我们就进行干涉,那样会马上悲剧的......所以这个函数很重要
- BOOLEAN QueryInterruptIsModify(ULONG uInterruptFunc,BOOLEAN bIsOrig)
- {
- ULONG u_fnKeSetTimeIncrement;
- UNICODE_STRING usFuncName;
- ULONG u_index;
- ULONG *u_KiProcessorBlock;
-
- IDTENTRY *pIdtEntry;
- PKGDTENTRY pGdt;
-
- RtlInitUnicodeString(&usFuncName,L"KeSetTimeIncrement");
-
- u_fnKeSetTimeIncrement = (ULONG)MmGetSystemRoutineAddress(&usFuncName);
- if (!MmIsAddressValid((PVOID)u_fnKeSetTimeIncrement))
- {
- return FALSE;
- }
-
- u_KiProcessorBlock = *(ULONG**)(u_fnKeSetTimeIncrement + 44);
-
- u_index = 0;
- while (u_KiProcessorBlock[u_index])
- {
- pIdtEntry = *(IDTENTRY**)(u_KiProcessorBlock[u_index] - 0xE8);
- pGdt = *(PKGDTENTRY*)(u_KiProcessorBlock[u_index] - 0xE4);
-
- if (bIsOrig)
- {
- if ((uInterruptFunc>>16)!=pIdtEntry[3].HiOffset||
- (uInterruptFunc & 0xffff)!=pIdtEntry[3].LowOffset)
- {
- return FALSE;
- }
- }else{
- if ((uInterruptFunc>>16)==pIdtEntry[3].HiOffset||
- (uInterruptFunc & 0xffff)==pIdtEntry[3].LowOffset)
- {
- return FALSE;
- }
- }
- u_index++;
- }
-
- return TRUE;
- }
-
- //这个函数先进行查询是否被修改,段内偏移修改了的话我们就跟着修改,这里我们使用一个变量g_bHookInterrupt来标记我们是否修改过段基址
- VOID HookInterruptFunc(ULONG InterruptIndex,ULONG NewInterruptFunc)
- {
- ULONG uNewBase;
- ULONG uInterrupFunc;
-
- uInterrupFunc = GetInterruptFuncAddress(InterruptIndex);
-
- if (QueryInterruptIsModify(g_uOrigInterruptFunc,TRUE)&&
- g_bHookInterrupt==TRUE)
- {
- SetInterrupt(InterruptIndex,0,FALSE);
- g_bHookInterrupt = FALSE;
- }
-
- if (QueryInterruptIsModify(g_uOrigInterruptFunc,FALSE)&&
- g_bHookInterrupt==FALSE)
- {
- KdPrint(("hook!"));
- uNewBase = NewInterruptFunc - uInterrupFunc;
-
- *(ULONG*)g_FilterJmp = (ULONG)NewInterrupt3OfOrigBase;
- g_FilterJmp[2] = 0x8;
-
- SetInterrupt(InterruptIndex,uNewBase,TRUE);
- g_bHookInterrupt = TRUE;
- }
- }
-
- void UnHookInterruptFunc(ULONG InterruptIndex)
- {
- SetInterrupt(InterruptIndex,0,FALSE);
- }
-
- VOID MyUnload(PDRIVER_OBJECT pDriverObject)
- {
- UnHookInterruptFunc(3);
- UnHookKiFastCallEntry();
- }
-
- NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING Reg_Path)
- {
- g_bHookInterrupt = FALSE;
-
- g_uOrigInterruptFunc = GetInterruptFuncAddress(3);
-
- SearchKiFastCallEntry();
-
- SetInterrupt(3,0,FALSE);
-
- pDriverObject->DriverUnload = MyUnload;
- return STATUS_SUCCESS;
- }
-
- //////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////
复制代码 |