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

原文地址:https://www.cnblogs.com/revercc/p/14701592.html