RootKits——windows内核安全防护(2)

__declspec(naked) MyKiFastCallEntry()
{
	__asm {
		jmp [d_origKiFastCallEntry]
	}
}

NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
{
	theDriverObject->DriverUnload  = OnUnload; 

	__asm {
		mov ecx, 0x176				
		rdmsr                          // read the value of the IA32_SYSENTER_EIP register
		mov d_origKiFastCallEntry, eax
		mov eax, MyKiFastCallEntry     // Hook function address
		wrmsr                          // Write to the IA32_SYSENTER_EIP register
	}
	return STATUS_SUCCESS;
}

由于系统调用所需要的数据来自于三个寄存器,第一,需要CS——也就是代码段,第二需要EIP——指令指针,第三,需要ESP——用于传递参数以及系统运行。而快速调用则是在CPU中增加三个模式相关的寄存器,也就是所谓的MSR。我们所需要做的事将其中的SYSENTER_EIP_MSR改变为我们的函数的地址,并将原来的系统调用地址保存起来。由于SYSENTER_EIP_MSR在内部的编号是0X176,所以首先向ecx中存入SYSENTER_EIP_MSR的编号,然后利用rdmsr读取SYSENTER_EIP_MSR中的值到eax当中。而下面的保存过程则相反。然后在我们的函数当中执行原来的系统调用。这里加上__declspecnaked)是因为不能由返回值,并且需要我们自己处理寄存器的值。

char jump_template[] = { 
	0x90,										//nop, debug
	0x60,										//pushad
	0x9C,										//pushfd
	0xB8, 0xAA, 0x00, 0x00, 0x00,				//mov eax, AAh
	0x90,										//push eax
	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,	//call 08:44332211h
	0x90,										//pop eax
	0x9D,										//popfd
	0x61,										//popad
	0xEA, 0x11, 0x22, 0x33, 0x44, 0x08, 0x00	//jmp 08:44332211h
};
char * idt_detour_tablebase;
跳转模板利用指令码直接编码,看后面的注释就可以了。不过里面的08:44332211并不是真实的跳转地址,而是在函数调用过程中进行了处理。
#define MAKELONG(a, b) ((unsigned long) (((unsigned short) (a)) | ((unsigned long) ((unsigned short) (b))) << 16))
#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()

void __stdcall count_interrupts(unsigned long inumber)
{
	unsigned long *aCountP; 
	unsigned long aNumber;
	__asm mov eax, [ebp+0Ch]
	__asm mov aNumber, eax
	
	aNumber = aNumber & 0x000000FF;
	aCountP = &g_i_count[aNumber]; 
	InterlockedIncrement(aCountP);
}

程序主要实现对中断进行技术,传递进来的是中断号,利用中断号索引整个中断计数数组,并将其递增。首先__asm mov eax, [ebp+0Ch]将保存在堆栈当中的参数给提取出来,因为包含两个局部变量,所以函数开头EBP-8,这里加上12刚好等于保存在堆栈当中的数据的地址。然后下面将数据保存到aNumber当中。并和255进行与操作,保证索引范围在255内。


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; 

	for(count=START_IDT_OFFSET;count<MAX_IDT_ENTRIES;count++)
	{
		g_i_count[count]=0;
	}
	__asm	sidt	idt_info
	idt_entries = (IDTENTRY*) MAKELONG(idt_info.LowIDTbase,idt_info.HiIDTbase);

	for(count=START_IDT_OFFSET;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);
	
		old_ISR_pointers[count] = MAKELONG(idt_entries[count].LowOffset,idt_entries[count].HiOffset);
	}
	idt_detour_tablebase = ExAllocatePool(NonPagedPool, sizeof(jump_template)*256);

	for(count=START_IDT_OFFSET;count<MAX_IDT_ENTRIES;count++)
	{
		int offset = sizeof(jump_template)*count;	
		char *entry_ptr = idt_detour_tablebase + offset;
		memcpy(entry_ptr, jump_template, sizeof(jump_template));
		entry_ptr[4] = (char)count;
		*( (unsigned long *)(&entry_ptr[10]) ) = (unsigned long)count_interrupts;
		*( (unsigned long *)(&entry_ptr[20]) ) = old_ISR_pointers[count];

		__asm cli
		idt_entries[count].LowOffset = (unsigned short)entry_ptr;
		idt_entries[count].HiOffset = (unsigned short)((unsigned long)entry_ptr >> 16);
		__asm sti
	}

	DbgPrint("Hooking Interrupt complete");

	return STATUS_SUCCESS;
}

程序主要实现对中断进行技术,传递进来的是中断号,利用中断号索引整个中断计数数组,并将其递增。首先__asm mov eax, [ebp+0Ch]将保存在堆栈当中的参数给提取出来,因为包含两个局部变量,所以函数开头EBP-8,这里加上12刚好等于保存在堆栈当中的数据的地址。然后下面将数据保存到aNumber当中。并和255进行与操作,保证索引范围在255内。






你可能感兴趣的:(操作系统,内核)