原理:
段基址 + 偏移地址 = 函数地址
让idt不动的话, 就需要更改段基址
实例代码:
#include "ntddk.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{ //idt的表的地址 USHORT IDT_limit; USHORT IDT_LOWbase; USHORT IDT_HIGbase; }IDTR, *PIDTR; typedef struct _IDTENTRY //idt的表的元素地址 { unsigned short LowOffset; unsigned short selector;//16位 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; typedef struct _KGDTENTRY { //gdt表的元素的结构里 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; //global USHORT g_FilterJmp[3];//2字节 ULONG g_uOrigInterruptFunc;//保存老的3号中断的函数地址 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 } } USHORT g_u_cs; void __stdcall FilterInterrupt()//过滤函数 { KdPrint(("%s---%X", (char*)PsGetCurrentProcess() + 0x16c, g_u_cs)); } fa __declspec(naked) void NewInterrupt3OfOrigBase()//我的hook函数 { __asm{ pushad pushfd push fs push 0x30 pop fs call FilterInterrupt pop fs popfd popad jmp g_uOrigInterruptFunc } } __declspec(naked) void NewInterrupt3()//新3号中断函数 直接把基地址改成偏移了 就进入了我的hook函数 { __asm{ mov g_u_cs, cs jmp fword ptr[g_FilterJmp] //NewInterrupt3OfOrigBase 现实了远跳转 在原始的段基址 } } ULONG GetInterruptFuncAddress(ULONG InterruptIndex)//得到老3号中断的地址 保存 { IDTR idtr; IDTENTRY *pIdtEntry; __asm SIDT idtr; pIdtEntry = (IDTENTRY *)MAKELONG(idtr.IDT_LOWbase, idtr.IDT_HIGbase); KdPrint(("idt表地址%x\n", pIdtEntry)); return MAKELONG(pIdtEntry[InterruptIndex].LowOffset, pIdtEntry[InterruptIndex].HiOffset); } ULONG GetNewBase(ULONG NewInterruptFunc, ULONG OrigInterruptOffset) { return (NewInterruptFunc - OrigInterruptOffset); } VOID SetInterrupt(ULONG InterruptIndex, ULONG uNewBase, BOOLEAN bIsNew)//先 得到idt gdt 表地址 然后再改选择符 { 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);//得到idt表地址 pGdt = *(PKGDTENTRY*)(u_KiProcessorBlock[u_index] - 0xE4);//得到gdt表地址 KdPrint(("Idt段基址选择符%x\n", pIdtEntry[3].selector));//得到3号中断 段选择符 为8 KdPrint(("GDT表:%X--%X--%X--%X\n", pGdt, pGdt[1].BaseLow, pGdt[1].HighWord.Bits.BaseMid, pGdt[1].HighWord.Bits.BaseHi));//由8二进制1000得到内核层gdt表的数组1号元素的 段内偏移 PageProtectOff(); if (bIsNew) { pIdtEntry[InterruptIndex].selector = 0xa8;//10101000 第21元素 idt表的选择符8修改成了a8 1111000 //A8原来是 RtlCopyMemory(&pGdt[21], &pGdt[1], sizeof(KGDTENTRY));//把第2元素的地址复制给了 第21元素的地址 KdPrint(("新段基址%x\n", uNewBase)); pGdt[21].BaseLow = (USHORT)(uNewBase & 0xffff);//第21元素的内容修改 pGdt[21].HighWord.Bytes.BaseMid = (UCHAR)((uNewBase >> 16) & 0xff); pGdt[21].HighWord.Bytes.BaseHi = (UCHAR)(uNewBase >> 24); //直接把基地址改成偏移了 就进入了我的hook函数 } else{ pIdtEntry[InterruptIndex].selector = 0x8;//还原选择为8 memset(&pGdt[21], 0, sizeof(KGDTENTRY));//还原第21元素的地址修改为0 int3中断走正常的选择符 } PageProtectOn(); u_index++; } } VOID HookInterruptFunc(ULONG InterruptIndex, ULONG NewInterruptFunc) { //USHORT g_FilterJmp[3];//2字节 ULONG uNewBase; g_uOrigInterruptFunc = GetInterruptFuncAddress(InterruptIndex);//保存老的3号中断的函数地址 uNewBase = NewInterruptFunc - g_uOrigInterruptFunc;//新3号中断函数 - 老3号中断函数 = 新段基址 直接把基地址改成偏移了 就进入了我的hook函数 *(ULONG*)g_FilterJmp = (ULONG)NewInterrupt3OfOrigBase; //低1, 4的元素 赋值 我的hook函数 g_FilterJmp[2] = 0x8;//高5,6的元素 赋值 SetInterrupt(InterruptIndex, uNewBase, TRUE); } void UnHookInterruptFunc(ULONG InterruptIndex) { SetInterrupt(InterruptIndex, 0, FALSE); } VOID MyUnload(PDRIVER_OBJECT pDriverObject) { UnHookInterruptFunc(3); } NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING Reg_Path) { HookInterruptFunc(3, (ULONG)NewInterrupt3); pDriverObject->DriverUnload = MyUnload; return STATUS_SUCCESS; }
0则评论给“[驱动开发]隐藏idt HOOK”