准备资料:
中断描述符表(Interrupt Descriptor Table,IDT)显然是用来处理中断的。IDT指定了如何处理诸如下一个键、发生页面错误或用户进程请求SSDT时所触发的中断。本文介绍HOOK IDT中的向量0x2E,该钩子在SSDT中的内核函数之前进行调用。
处理IDT时需要注意两点,每个处理器都有自己的IDT,需要钩住系统上的所有IDT。
当应用程序需要操作系统的支持时,NTDLL.DLL向EAX寄存器加载SSDT中系统调用的索引号,向EDX寄存器加载用户堆栈参数的指针。然后发出中断指令进入内核。
SIDT指令将在内存中为每个CPU寻找IDT。SIDT指令将中断描述符表寄存器IDTR(64bit,16-47bit存有中断描述表符IDT基地址)的内容存入指定地址单元。这个指令不是特权指令。
__asm { sidt Idt_info ; }
Idt_info实际上是IDTINFO结构。
IDTINFO结构:
typedef struct { WORD IDTLimit; WORD LowIDTbase; //IDT的低半地址 WORD HiIDTbase; //IDT的高半地址 } IDTINFO; #define MAKELONG(a, b)((LONG)(((WORD)(a))|((DWORD)((WORD)(b)))<< 16))
IDT划分为一个较低的WORD值和一个较高的WORD值,可以通过MAKELONG宏来获得正确的DWORD值,其中最高位WORD在前面。
IDT中每一项都具有自己的结构,长度为64位。每一项包含一个特定中断处理函数的地址。IDTENTRY结构中的LowOffset和HiOffset组成了中断处理程序的地址。
#pragma pack(1) typedef struct { unsigned short LowOffset; unsigned short selector; unsigned char unused_lo; unsigned char segment_type:4; //0x0E is an interrupt gate unsigned char system_segment_flag:1; unsigned char DPL:2; // descriptor privilege level unsigned char P:1; /* present */ unsigned short HiOffset; } IDTENTRY; /* sidt returns idt in this format */ typedef struct { unsigned short IDTLimit; unsigned short LowIDTbase; unsigned short HiIDTbase; } IDTINFO; #pragma pack()
参考代码:(copy from www.rootkit.com)
1 // --------------------------- 2 // BASIC INTERRUPT HOOK part 3 3 // this hooks the entire table 4 // --------------------------- 5 6 #include "ntddk.h" 7 #include <stdio.h> 8 9 //debuggering 10 //#define _DEBUG 11 12 #define MAKELONG(a, b) ((unsigned long) (((unsigned short) (a)) | ((unsigned long) ((unsigned short) (b))) << 16)) 13 14 // set this to the max int you want to hook 15 #define MAX_IDT_ENTRIES 0xFF 16 17 // the starting interrupt for patching 18 // to 'skip' some troublesome interrupts 19 // at the beginning of the table (TODO, find out why) 20 #define START_IDT_OFFSET 0x00 21 22 unsigned long g_i_count[MAX_IDT_ENTRIES]; 23 unsigned long old_ISR_pointers[MAX_IDT_ENTRIES]; // better save the old one!! 24 25 char jump_template[] = { 26 0x90, //nop, debug 27 0x60, //pushad 28 0x9C, //pushfd 29 0xB8, 0xAA, 0x00, 0x00, 0x00, //mov eax, AAh 30 0x50, //push eax 31 0x9A, 0x11, 0x22, 0x33, 0x44, 0x08, 0x00, //call 08:44332211h 32 0x58, //pop eax 33 0x9D, //popfd 34 0x61, //popad 35 0xEA, 0x11, 0x22, 0x33, 0x44, 0x08, 0x00 //jmp 08:44332211h 36 }; 37 38 char * idt_detour_tablebase; 39 40 41 /// 42 // IDT structures 43 /// 44 #pragma pack(1) 45 46 // entry in the IDT, this is sometimes called 47 // an "interrupt gate" 48 typedef struct 49 { 50 unsigned short LowOffset; 51 unsigned short selector; 52 unsigned char unused_lo; 53 unsigned char segment_type:4; //0x0E is an interrupt gate 54 unsigned char system_segment_flag:1; 55 unsigned char DPL:2; // descriptor privilege level 56 unsigned char P:1; /* present */ 57 unsigned short HiOffset; 58 } IDTENTRY; 59 60 /* sidt returns idt in this format */ 61 typedef struct 62 { 63 unsigned short IDTLimit; 64 unsigned short LowIDTbase; 65 unsigned short HiIDTbase; 66 } IDTINFO; 67 68 #pragma pack() 69 70 71 72 VOID OnUnload( IN PDRIVER_OBJECT DriverObject ) 73 { 74 int i; 75 IDTINFO idt_info; // this structure is obtained by calling STORE IDT (sidt) 76 IDTENTRY* idt_entries; // and then this pointer is obtained from idt_info 77 char _t[255]; 78 79 // load idt_info 80 __asm sidt idt_info 81 idt_entries = (IDTENTRY*) MAKELONG(idt_info.LowIDTbase,idt_info.HiIDTbase); 82 83 DbgPrint("ROOTKIT: OnUnload called\n"); 84 85 for(i=START_IDT_OFFSET;i<MAX_IDT_ENTRIES;i++) 86 { 87 _snprintf(_t, 253, "interrupt %d called %d times", i, g_i_count[i]); 88 DbgPrint(_t); 89 } 90 91 DbgPrint("UnHooking Interrupt..."); 92 93 for(i=START_IDT_OFFSET;i<MAX_IDT_ENTRIES;i++) 94 { 95 // restore the original interrupt handler 96 __asm cli 97 idt_entries[i].LowOffset = (unsigned short) old_ISR_pointers[i]; 98 idt_entries[i].HiOffset = (unsigned short)((unsigned long)old_ISR_pointers[i] >> 16); 99 __asm sti 100 } 101 102 103 DbgPrint("UnHooking Interrupt complete."); 104 } 105 106 NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath ) 107 { 108 IDTINFO idt_info; // this structure is obtained by calling STORE IDT (sidt) 109 IDTENTRY* idt_entries; // and then this pointer is obtained from idt_info 110 IDTENTRY* i; 111 unsigned long addr; 112 unsigned long count; 113 char _t[255]; 114 115 theDriverObject->DriverUnload = OnUnload; 116 117 for(count=START_IDT_OFFSET;count<MAX_IDT_ENTRIES;count++) 118 { 119 g_i_count[count]=0; 120 } 121 122 // load idt_info 123 __asm sidt idt_info 124 idt_entries = (IDTENTRY*) MAKELONG(idt_info.LowIDTbase,idt_info.HiIDTbase); 125 126 //// 127 // save old idt pointers 128 //// 129 for(count=START_IDT_OFFSET;count < MAX_IDT_ENTRIES;count++) 130 { 131 i = &idt_entries[count]; 132 addr = MAKELONG(i->LowOffset, i->HiOffset); 133 134 _snprintf(_t, 253, "Interrupt %d: ISR 0x%08X", count, addr); 135 DbgPrint(_t); 136 137 old_ISR_pointers[count] = MAKELONG(idt_entries[count].LowOffset,idt_entries[count].HiOffset); 138 } 139 140 141 /// 142 // setup the detour table 143 /// 144 idt_detour_tablebase = ExAllocatePool(NonPagedPool, sizeof(jump_template)*256); 145 146 for(count=START_IDT_OFFSET;count<MAX_IDT_ENTRIES;count++) 147 { 148 int offset = sizeof(jump_template)*count; 149 char *entry_ptr = idt_detour_tablebase + offset; 150 151 // entry_ptr points to the start of our jump code in the detour_table 152 153 // copy the starter code into the template location 154 memcpy(entry_ptr, jump_template, sizeof(jump_template)); 155 156 // stamp the far jump to the original ISR 157 *( (unsigned long *)(&entry_ptr[20]) ) = old_ISR_pointers[count]; 158 159 // finally, make the interrupt point to our template code 160 __asm cli 161 idt_entries[count].LowOffset = (unsigned short)entry_ptr; 162 idt_entries[count].HiOffset = (unsigned short)((unsigned long)entry_ptr >> 16); 163 __asm sti 164 } 165 166 DbgPrint("Hooking Interrupt complete"); 167 168 return STATUS_SUCCESS; 169 }
XP虚拟机加载该驱动后,贴出DbgView日志
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)