在笔者上一篇文章《驱动开发:内核枚举SSDT表基址》实现了针对SSDT表的枚举功能,本章继续实现对SSSDT表的枚举,ShadowSSDT中文名影子系统服务描述表,SSSDT其主要的作用是管理系统中的图形化界面,其Win32子系统的内核实现是Win32k.sys驱动,属于GUI线程的一部分,其自身没有导出表,枚举SSSDT表其与SSDT原理基本一致。
如下是闭源ARK工具的枚举效果:

首先需要找到SSSDT表的位置,通过《Win10内核枚举SSDT表基址》文章中的分析可知,SSSDT就在SSDT的下面,只需要枚举4c8d1dde1e3a00特征即可,如果你找不到上一篇具体分析流程了,那么多半你是看到了转载文章。

先实现第一个功能,得到SSSDT表的基地址以及SSDT函数个数,完整代码如下所示。
#include <ntifs.h> #pragma intrinsic(__readmsr)
  typedef struct _SYSTEM_SERVICE_TABLE { 	PVOID          ServiceTableBase; 	PVOID          ServiceCounterTableBase; 	ULONGLONG      NumberOfServices; 	PVOID          ParamTableBase; } SYSTEM_SERVICE_TABLE, *PSYSTEM_SERVICE_TABLE;
  PSYSTEM_SERVICE_TABLE KeServiceDescriptorTableShadow = 0; ULONG64 ul64W32pServiceTable = 0;
 
  ULONGLONG GetKeServiceDescriptorTableShadow() { 	 	PUCHAR StartSearchAddress = (PUCHAR)__readmsr(0xC0000082) - 0x1808FE;
  	 	PUCHAR EndSearchAddress = StartSearchAddress + 0x8192; 	
  	PUCHAR ByteCode = NULL;
  	UCHAR OpCodeA = 0, OpCodeB = 0, OpCodeC = 0; 	ULONGLONG addr = 0; 	ULONG templong = 0;
  	for (ByteCode = StartSearchAddress; ByteCode < EndSearchAddress; ByteCode++) 	{ 		 		if (MmIsAddressValid(ByteCode) && MmIsAddressValid(ByteCode + 1) && MmIsAddressValid(ByteCode + 2)) 		{ 			OpCodeA = *ByteCode; 			OpCodeB = *(ByteCode + 1); 			OpCodeC = *(ByteCode + 2);
  			 			
 
 
 
 
 
 
 
 
 
 
  			if (OpCodeA == 0x4c && OpCodeB == 0x8d && OpCodeC == 0x1d) 			{ 				 				memcpy(&templong, ByteCode + 3, 4);
  				 				addr = (ULONGLONG)templong + (ULONGLONG)ByteCode + 7; 				return addr; 			} 		} 	} 	return  0; }
 
  ULONGLONG GetSSSDTCount() { 	PSYSTEM_SERVICE_TABLE pWin32k; 	ULONGLONG W32pServiceTable;
  	pWin32k = (PSYSTEM_SERVICE_TABLE)((ULONG64)KeServiceDescriptorTableShadow + sizeof(SYSTEM_SERVICE_TABLE)); 	W32pServiceTable = (ULONGLONG)(pWin32k->ServiceTableBase); 	
  	return pWin32k->NumberOfServices; }
  VOID UnDriver(PDRIVER_OBJECT driver) { 	DbgPrint(("驱动程序卸载成功! \n")); }
  NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { 	DbgPrint("hello lyshark.com \n");
  	KeServiceDescriptorTableShadow = (PSYSTEM_SERVICE_TABLE)GetKeServiceDescriptorTableShadow();
  	DbgPrint("[LyShark] SSSDT基地址 = 0x%p \n", KeServiceDescriptorTableShadow);
  	ULONGLONG count = GetSSSDTCount();
  	DbgPrint("[LyShark] SSSDT个数 = %d \n", count);
  	DriverObject->DriverUnload = UnDriver; 	return STATUS_SUCCESS; }
   | 
 
这段代码运行后即可得到SSSDT表基地址,以及该表中函数个数。

在此基础之上增加枚举计算过程即可,完整源代码如下所示。
SSSDT 函数起始index是0x1000,但W32pServiceTable是从基址开始记录的,这个误差则需要(index-0x1000)来得到,至于+4则是下一个元素与上一个元素的偏移。
计算公式:
- W32pServiceTable + 4 * (index-0x1000)
 
#include <ntifs.h> #pragma intrinsic(__readmsr)
  typedef struct _SYSTEM_SERVICE_TABLE { 	PVOID          ServiceTableBase; 	PVOID          ServiceCounterTableBase; 	ULONGLONG      NumberOfServices; 	PVOID          ParamTableBase; } SYSTEM_SERVICE_TABLE, *PSYSTEM_SERVICE_TABLE;
  PSYSTEM_SERVICE_TABLE KeServiceDescriptorTableShadow = 0; ULONG64 ul64W32pServiceTable = 0;
 
  ULONGLONG GetKeServiceDescriptorTableShadow() { 	 	PUCHAR StartSearchAddress = (PUCHAR)__readmsr(0xC0000082) - 0x1808FE;
  	 	PUCHAR EndSearchAddress = StartSearchAddress + 0x8192; 	
  	PUCHAR ByteCode = NULL;
  	UCHAR OpCodeA = 0, OpCodeB = 0, OpCodeC = 0; 	ULONGLONG addr = 0; 	ULONG templong = 0;
  	for (ByteCode = StartSearchAddress; ByteCode < EndSearchAddress; ByteCode++) 	{ 		 		if (MmIsAddressValid(ByteCode) && MmIsAddressValid(ByteCode + 1) && MmIsAddressValid(ByteCode + 2)) 		{ 			OpCodeA = *ByteCode; 			OpCodeB = *(ByteCode + 1); 			OpCodeC = *(ByteCode + 2);
  			 			
 
 
 
 
 
 
 
 
 
 
  			if (OpCodeA == 0x4c && OpCodeB == 0x8d && OpCodeC == 0x1d) 			{ 				 				memcpy(&templong, ByteCode + 3, 4);
  				 				addr = (ULONGLONG)templong + (ULONGLONG)ByteCode + 7; 				return addr; 			} 		} 	} 	return  0; }
 
  ULONGLONG GetSSSDTCount() { 	PSYSTEM_SERVICE_TABLE pWin32k; 	ULONGLONG W32pServiceTable;
  	pWin32k = (PSYSTEM_SERVICE_TABLE)((ULONG64)KeServiceDescriptorTableShadow + sizeof(SYSTEM_SERVICE_TABLE)); 	W32pServiceTable = (ULONGLONG)(pWin32k->ServiceTableBase); 	
  	return pWin32k->NumberOfServices; }
  VOID UnDriver(PDRIVER_OBJECT driver) { 	DbgPrint(("驱动程序卸载成功! \n")); }
  NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { 	DbgPrint("hello lyshark.com \n");
  	KeServiceDescriptorTableShadow = (PSYSTEM_SERVICE_TABLE)GetKeServiceDescriptorTableShadow();
  	DbgPrint("[LyShark] SSSDT基地址 = 0x%p \n", KeServiceDescriptorTableShadow);
  	ULONGLONG count = GetSSSDTCount();
  	DbgPrint("[LyShark] SSSDT个数 = %d \n", count);
  	 	for (size_t Index = 0; Index < count; Index++) 	{
  		PSYSTEM_SERVICE_TABLE pWin32k; 		ULONGLONG W32pServiceTable;
  		pWin32k = (PSYSTEM_SERVICE_TABLE)((ULONG64)KeServiceDescriptorTableShadow + sizeof(SYSTEM_SERVICE_TABLE)); 		W32pServiceTable = (ULONGLONG)(pWin32k->ServiceTableBase);
  		 		 		
  		 		 		
  		
  		ULONGLONG qword_temp = 0; 		LONG dw = 0;
  		 		 		qword_temp = W32pServiceTable + 4 * (Index - 0x1000); 		 		dw = *(PLONG)qword_temp; 		 		dw = dw >> 4; 		qword_temp = W32pServiceTable + (LONG64)dw;
  		DbgPrint("[LyShark] ID: %d | SSSDT: 0x%p \n", Index, qword_temp); 	}
  	DriverObject->DriverUnload = UnDriver; 	return STATUS_SUCCESS; }
   | 
 
枚举效果如下图所示所示,注意这一步必须要在GUI线程中执行,否则会异常,建议将枚举过程写成DLL文件,注入到explorer.exe进程内执行;
