驱动开发:Win10内核枚举SSDT表基址

三年前面朝黄土背朝天的我,写了一篇如何在Windows 7系统下枚举内核SSDT表的文章《驱动开发:内核读取SSDT表基址》三年过去了我还是个单身狗,开个玩笑,微软的Windows 10系统已经覆盖了大多数个人PC终端,以前的方法也该进行迭代更新了,或许在网上你能够找到类似的文章,但我可以百分百肯定都不能用,今天LyShark将带大家一起分析Win10 x64最新系统SSDT表的枚举实现 。
看一款闭源ARK工具的枚举效果:

驱动开发:Win10内核枚举SSDT表基址

文章插图
直接步入正题,首先SSDT表中文为系统服务描述符表,SSDT表的作用是把应用层与内核联系起来起到桥梁的作用,枚举SSDT表也是反内核工具最基本的功能,通常在64位系统中要想找到SSDT表,需要先找到KeServiceDescriptorTable这个函数,由于该函数没有被导出,所以只能动态的查找它的地址,庆幸的是我们可以通过查找msr(c0000082)这个特殊的寄存器来替代查找KeServiceDescriptorTable这一步,在新版系统中查找SSDT可以归纳为如下这几个步骤 。
  • rdmsr c0000082 -> KiSystemCall64Shadow -> KiSystemServiceUser -> SSDT
首先第一步通过rdmsr C0000082 MSR寄存器得到KiSystemCall64Shadow的函数地址,计算KiSystemCall64ShadowKiSystemServiceUser偏移量,如下图所示 。
  • 得到相对偏移6ed53180(KiSystemCall64Shadow) - 6ebd2a82(KiSystemServiceUser) = 1806FE
  • 也就是说 6ed53180(rdmsr) - 1806FE = KiSystemServiceUser

驱动开发:Win10内核枚举SSDT表基址

文章插图
如上当我们找到了KiSystemServiceUser的地址以后,在KiSystemServiceUser向下搜索可找到KiSystemServiceRepeat里面就是我们要找的SSDT表基址 。
其中fffff8036ef8c880则是SSDT表的基地址,紧随其后的fffff8036ef74a80则是SSSDT表的基地址 。
【驱动开发:Win10内核枚举SSDT表基址】
驱动开发:Win10内核枚举SSDT表基址

文章插图
那么如果将这个过程通过代码的方式来实现,我们还需要使用《驱动开发:内核枚举IoTimer定时器》中所使用的特征码定位技术,如下我们查找这段特征 。
// 署名权// right to sign one's name on a piece of work// PowerBy: LyShark// Email: me@lyshark.com#include <ntifs.h>#pragma intrinsic(__readmsr)ULONGLONG ssdt_address = 0;// 获取 KeServiceDescriptorTable 首地址ULONGLONG GetLySharkCOMKeServiceDescriptorTable(){ // 设置起始位置 PUCHAR StartSearchAddress = (PUCHAR)__readmsr(0xC0000082) - 0x1806FE; // 设置结束位置 PUCHAR EndSearchAddress = StartSearchAddress + 0x100000; DbgPrint("[LyShark Search] 扫描起始地址: %p --> 扫描结束地址: %p \n", StartSearchAddress, EndSearchAddress); PUCHAR ByteCode = NULL; UCHAR OpCodeA = 0, OpCodeB = 0, OpCodeC = 0; ULONGLONG addr = 0; ULONG templong = 0; for (ByteCode = StartSearchAddress; ByteCode < EndSearchAddress; ByteCode++) {// 使用MmIsAddressValid()函数检查地址是否有页面错误if (MmIsAddressValid(ByteCode) && MmIsAddressValid(ByteCode + 1) && MmIsAddressValid(ByteCode + 2)){OpCodeA = *ByteCode;OpCodeB = *(ByteCode + 1);OpCodeC = *(ByteCode + 2);// 对比特征值 寻找 nt!KeServiceDescriptorTable 函数地址/*nt!KiSystemServiceRepeat:fffff803`6ebd2b94 4c8d15e59c3b00lear10,[nt!KeServiceDescriptorTable (fffff803`6ef8c880)]fffff803`6ebd2b9b 4c8d1dde1e3a00lear11,[nt!KeServiceDescriptorTableShadow (fffff803`6ef74a80)]fffff803`6ebd2ba2 f7437880000000testdword ptr [rbx+78h],80hfffff803`6ebd2ba9 7413jent!KiSystemServiceRepeat+0x2a (fffff803`6ebd2bbe)Branch*/if (OpCodeA == 0x4c && OpCodeB == 0x8d && OpCodeC == 0x15){// 获取高位地址fffff802memcpy(&templong, ByteCode + 3, 4);// 与低位64da4880地址相加得到完整地址addr = (ULONGLONG)templong + (ULONGLONG)ByteCode + 7;return addr;}} } return0;}VOID UnDriver(PDRIVER_OBJECT driver){ DbgPrint(("驱动程序卸载成功! \n"));}NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath){ DbgPrint("hello lyshark.com"); ssdt_address = GetLySharkCOMKeServiceDescriptorTable(); DbgPrint("[LyShark] SSDT = %p \n", ssdt_address); DriverObject->DriverUnload = UnDriver; return STATUS_SUCCESS;}

经验总结扩展阅读