现在的位置: 首页 > 综合 > 正文

多CPU下安全inline hook

2014年02月22日 ⁄ 综合 ⁄ 共 2337字 ⁄ 字号 评论关闭

去師父神牛的空間里看了下關於内核安全inline hook的討論,感覺受益匪淺,查閲資料后,得知了一種CPU中較爲安全的安裝鈎子的方法。
該代碼來自《Rootkits:Subverting the Windows Kernel》一書,原理是通過向所有非當前的CPU插入DPC,並且在DPC例程中實現忙等待,這是一種比較可愛的方法(PS:雖然我還是糾結于,如果其他CPU當前就已經在執行DPC那不是情況會非常複雜嗎。。。)
Windows使用軟件中斷優先級,稱爲IRQL(Interrupt Request Level,中斷請求級別),Windows定義IRQL的範圍是0~31,數字越大,優先級越高。處理器執行時,擁有一個當前的IRQL,當發生中斷時,如果中斷的IRQL大於當前IRQL,當前執行會被打斷,處理器轉向執行中斷代碼,然後再根據需要繼續執行。IRQL最低是PASSIVE_LEVEL(0),也就是被動級別,普通的綫程都運行于這個級別,正因為這個級別最低,所以可以被所有更高的IRQL的例程打斷。比PASSIVE_LEVEL高的是APC_LEVEL(1),通常是APC(Asynchronous
Procedure Call,異步過程調用)的等級。然後是DISPATCH_LEVEL(2),,通常被用於DPC(Deferred Procedure Call,延遲過程調用)或者綫程的調度。3~26是設備IRQL,27-31是一些硬件的中斷。DPC一般用於處理一些需要高優先級,但是又不是非常緊急的事務,而APC一般適用於綫程異步通知。

 

下面是來自書上的代碼以及我寫的一些:

//Source code from <Rootkits:Subverting the Windows Kernel>, Chapter 7

PKDPC GainExclusivity()
{
	NTSTATUS ns;
	ULONG u_currentCPU;
	CCHAR i;
	PKDPC pkdpc, temp_pkdpc;
	if (KeGetCurrentIrql() != DISPATCH_LEVEL)
		return NULL;
	InterlockedAnd(&AllCPURaised, 0); //AllCPURaised = 0
	InterlockedAnd(&NumberOfRaisedCPU, 0); //NumberOfRaisedCPU = 0

	temp_pkdpc = (PKDPC) ExAllocatePool(NonPagedPool, KeNumberProcessors *
			sizeof(KDPC)); //分配處理器對應數量的
	if (temp_pkdpc == NULL)
		return NULL;
	u_currentCPU = KeGetCurrentProcessorNumber(); //獲取當前CPU號
	pkdpc = temp_pkdpc;
	for (i = 0; i < KeNumberProcessors; i++, *temp_pkdpc++)
	{
		if (i != u_currentCPU)
		{
			KeInitializeDpc(temp_pkdpc,
					RaiseCPUIrqlAndWait,
					NULL);

			KeSetTargetProcessorDpc(temp_pkdpc, i);
			KeInsertQueueDpc(temp_pkdpc, NULL, NULL); //對所有非當前CPU插入一個dpc
		}
	}
	while (InterlockedCompareExchange(&NumberOfRaisedCPU,
			KeNumberProcessors - 1, KeNumberProcessors - 1) !=
			KeNumberProcessors - 1) //所有CPU都在忙等待
	{
		__asm nop;
	}
	return pkdpc;//返回分配的内存等待釋放
}

//DPC例程
VOID RaiseCPUIrqlAndWait(IN PKDPC Dpc,
		IN PVOID DeferredContext,
		IN PVOID SystemArgument1,
		IN PVOID SystemArgument2)
{
	InterlockedIncrement(&NumberOfRaisedCPU); //宣佈挂起
	while (!InterlockedCompareExchange(&AllCPURaised, 1, 1))
	{
		__asm nop;
	}
	InterlockedDecrement(&NumberOfRaisedCPU); //宣佈釋放
}

NTSTATUS ReleaseExclusivity(PVOID pkdpc)
{
	InterlockedIncrement(&AllCPURaised); //釋放所有CPU
	while (InterlockedCompareExchange(&NumberOfRaisedCPU, 0, 0)) //等待所有CPU都被釋放
	{
		__asm nop;
	}
	if (pkdpc != NULL)
	{
		ExFreePool(pkdpc); //釋放内存
		pkdpc = NULL;
	}
	return STATUS_SUCCESS;
}

NTSTATUS InstallHook(PVOID pTarget,PVOID pSource,LONG nSize)
{
	PKDPC pkdpc;
	
	if(pkdpc = GainExclusivity()) {
		//關閉寫保護
		__asm {
			cli
			mov eax,cr0
			push eax
			xor eax,0x10000
			mov cr0,eax
		}
		RtlCopyMemory(pTarget,pSource,nSize);
		//開啓寫保護
		__asm {
			pop eax
			mov cr0,eax
			sti
		}
		ReleaseExclusivity(pkdpc);
	}
	return STATUS_SUCCESS;
}

 

抱歉!评论已关闭.