HOOK技術之SSDT hook(x86/x64)


x86 SSDT Hook

32位下進行SSDT Hook比較簡單,通過修改SSDT表中需要hook的系統服務為自己的函數,在自己的函數中進行過濾判斷達到hook的目的。

獲取KeServiceDescriptorTable基地址

要想進行ssdt hook,首先需要獲得SSDT表的基地址。
因為KeServiceDescriptorTable是ntoskrnl.exe導出的,所以我們可以直接在程序中聲明導入符號得到KeServiceDescriptorTable的值。

typedef struct ServiceDescriptorEntry {
	unsigned int *ServiceTableBase;
	unsigned int *ServiceCounterTableBase;
	unsigned int NumberOfServices;
	unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;

extern "C" __declspec(dllimport)  ServiceDescriptorTableEntry_t  KeServiceDescriptorTable;

可以通過ntoskrnl.exe的EAT導出表得到KeServiceDescriptorTable的值。

還可以通過搜索KeAddSystemServiceTable進行硬編碼0xB883得到KeServiceDescriptorTable的值

獲取KeServiceDescriptorTableShadow基地址

因為KiServiceDescriptorTableShadow並未被win32k.sys導出,所以只能通過硬編碼搜索KeAddSystemServiceTable/KeRemoteSystemServiceTable得到

基地址差法,一般KiServiceDescriptorTableShadow就在KiServiceDescriptorTable附近如果xp就是 KeServiceDescriptorTableShadow=KeServiceDescriptorTable-0×40。如果是win7:KeServiceDescriptorTableShadow=KeServiceDescriptorTable+0×40;

注意KeServiceDescriptorTableShadow表中包含了KeServiceDescriptorTable表的內容

x64 SSDT Hook

HOOK思路

因為x64位中ssdt表是加密的,ssdt中的每一項占4個字節但並不是對應的系統服務的地址,因為x64中地址為64位而ssdt每一項只有4個字節32位所以無法直接存放服務的地址。其實際存儲的4個字節的前28位表示的是對應的系統服務相對於SSDT表基地址的偏移,而后4位如果對應的服務的參數個數小於4則其值為0,不小於4則為參數個數減去4。所以我們在ssdt hook時向ssdt表項中填入的函數得在ntoskrnl.exe模塊中,原因是因為函數到SSDT表基地址的偏移大小小於4個字節。所以我們選取一個ntoskrnl.exe中很少使用的函數KeBugCheckEx作為中轉函數,將需要hook的ssdt項的改為KeBugCheckEx函數,然后在inlinehook KeBugCheck函數,jmp到我們的函數中進行過濾。

PatchGard

64系統增加了內核哨兵機制(PatchGard),一旦發現內核關鍵代碼被篡改就會直接藍屏。所以在64位系統上進行SSDT Hook需要繞過PatchGard。

獲取KeServiceDescriptorTable和KeServiceDescriptorTableShadow基地址

64位系統調用過程為 syscall --》nt!KiSystemCall64--》nt!KiSystemServiceStart--》nt!KiSystemServiceRepeat--》call r10調用對應的系統服務。

我們可以通過獲取nt!KiSystemCall64函數的地址,然后找到nt!KiSystemServiceRepeat函數通過硬編碼得到KeServiceDescriptorTable和KeServiceDescriptorTableShadow的基地址。因為MSR寄存器的0xC0000082被設置為nt!KiSystemCall64函數的地址,所以我們可以通過讀取MSR寄存器得到此函數地址。

ULONGLONG MyGetKeServiceDescriptorTable64()
{
	PUCHAR StartSearchAddress = (PUCHAR)__readmsr(0xC0000082);
	PUCHAR EndSearchAddress = StartSearchAddress + 0x500;
	PUCHAR i = NULL;
	UCHAR b1 = 0, b2 = 0, b3 = 0;
	ULONG templong = 0;
	ULONGLONG addr = 0;
	for (i = StartSearchAddress;i < EndSearchAddress;i++)
	{
		if (MmIsAddressValid(i) && MmIsAddressValid(i + 1) && MmIsAddressValid(i + 2))
		{
			b1 = *i;
			b2 = *(i + 1);
			b3 = *(i + 2);
			if (b1 == 0x4c && b2 == 0x8d && b3 == 0x15) //4c8d15
			{
				memcpy(&templong, i + 3, 4);
				addr = (ULONGLONG)templong + (ULONGLONG)i + 7;
				return addr;
			}
		}
	}
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM