首页 > 其他分享 >驱动开发:内核枚举ShadowSSDT基址

驱动开发:内核枚举ShadowSSDT基址

时间:2022-10-20 08:47:42浏览次数:54  
标签:ULONGLONG SERVICE W32pServiceTable 枚举 内核 fffff802 TABLE ShadowSSDT ByteCode

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

如下是闭源ARK工具的枚举效果:

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

先实现第一个功能,得到SSSDT表的基地址以及SSDT函数个数,完整代码如下所示。

// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: [email protected]

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

// 获取 KeServiceDescriptorTableShadow 首地址
ULONGLONG GetKeServiceDescriptorTableShadow()
{
	// 设置起始位置
	PUCHAR StartSearchAddress = (PUCHAR)__readmsr(0xC0000082) - 0x1808FE;

	// 设置结束位置
	PUCHAR EndSearchAddress = StartSearchAddress + 0x8192;
	// DbgPrint("扫描起始地址: %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 函数地址
			/*
			lyshark.com kd> u KiSystemServiceRepeat
				nt!KiSystemServiceRepeat:
				fffff802`7c1d2b94 4c8d15e59c3b00  lea     r10,[nt!KeServiceDescriptorTable (fffff802`7c58c880)]
				fffff802`7c1d2b9b 4c8d1dde1e3a00  lea     r11,[nt!KeServiceDescriptorTableShadow (fffff802`7c574a80)]
				fffff802`7c1d2ba2 f7437880000000  test    dword ptr [rbx+78h],80h
				fffff802`7c1d2ba9 7413            je      nt!KiSystemServiceRepeat+0x2a (fffff802`7c1d2bbe)
				fffff802`7c1d2bab f7437800002000  test    dword ptr [rbx+78h],200000h
				fffff802`7c1d2bb2 7407            je      nt!KiSystemServiceRepeat+0x27 (fffff802`7c1d2bbb)
				fffff802`7c1d2bb4 4c8d1d051f3a00  lea     r11,[nt!KeServiceDescriptorTableFilter (fffff802`7c574ac0)]
				fffff802`7c1d2bbb 4d8bd3          mov     r10,r11
			*/
			if (OpCodeA == 0x4c && OpCodeB == 0x8d && OpCodeC == 0x1d)
			{
				// 获取高位地址fffff802
				memcpy(&templong, ByteCode + 3, 4);

				// 与低位64da4880地址相加得到完整地址
				addr = (ULONGLONG)templong + (ULONGLONG)ByteCode + 7;
				return addr;
			}
		}
	}
	return  0;
}

// 得到SSSDT个数
ULONGLONG GetSSSDTCount()
{
	PSYSTEM_SERVICE_TABLE pWin32k;
	ULONGLONG W32pServiceTable;

	pWin32k = (PSYSTEM_SERVICE_TABLE)((ULONG64)KeServiceDescriptorTableShadow + sizeof(SYSTEM_SERVICE_TABLE));
	W32pServiceTable = (ULONGLONG)(pWin32k->ServiceTableBase);
	// DbgPrint("Count => %d \n", pWin32k->NumberOfServices);

	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)
// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: [email protected]

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

// 获取 KeServiceDescriptorTableShadow 首地址
ULONGLONG GetKeServiceDescriptorTableShadow()
{
	// 设置起始位置
	PUCHAR StartSearchAddress = (PUCHAR)__readmsr(0xC0000082) - 0x1808FE;

	// 设置结束位置
	PUCHAR EndSearchAddress = StartSearchAddress + 0x8192;
	// DbgPrint("扫描起始地址: %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 函数地址
			/*
			lyshark.com kd> u KiSystemServiceRepeat
			nt!KiSystemServiceRepeat:
			fffff802`7c1d2b94 4c8d15e59c3b00  lea     r10,[nt!KeServiceDescriptorTable (fffff802`7c58c880)]
			fffff802`7c1d2b9b 4c8d1dde1e3a00  lea     r11,[nt!KeServiceDescriptorTableShadow (fffff802`7c574a80)]
			fffff802`7c1d2ba2 f7437880000000  test    dword ptr [rbx+78h],80h
			fffff802`7c1d2ba9 7413            je      nt!KiSystemServiceRepeat+0x2a (fffff802`7c1d2bbe)
			fffff802`7c1d2bab f7437800002000  test    dword ptr [rbx+78h],200000h
			fffff802`7c1d2bb2 7407            je      nt!KiSystemServiceRepeat+0x27 (fffff802`7c1d2bbb)
			fffff802`7c1d2bb4 4c8d1d051f3a00  lea     r11,[nt!KeServiceDescriptorTableFilter (fffff802`7c574ac0)]
			fffff802`7c1d2bbb 4d8bd3          mov     r10,r11
			*/
			if (OpCodeA == 0x4c && OpCodeB == 0x8d && OpCodeC == 0x1d)
			{
				// 获取高位地址fffff802
				memcpy(&templong, ByteCode + 3, 4);

				// 与低位64da4880地址相加得到完整地址
				addr = (ULONGLONG)templong + (ULONGLONG)ByteCode + 7;
				return addr;
			}
		}
	}
	return  0;
}

// 得到SSSDT个数
ULONGLONG GetSSSDTCount()
{
	PSYSTEM_SERVICE_TABLE pWin32k;
	ULONGLONG W32pServiceTable;

	pWin32k = (PSYSTEM_SERVICE_TABLE)((ULONG64)KeServiceDescriptorTableShadow + sizeof(SYSTEM_SERVICE_TABLE));
	W32pServiceTable = (ULONGLONG)(pWin32k->ServiceTableBase);
	// DbgPrint("Count => %d \n", pWin32k->NumberOfServices);

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

	// 循环枚举SSSDT
	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);

		// 获取SSSDT地址
		//ln win32k!W32pServiceTable+((poi(win32k!W32pServiceTable+4*(1-1000))&0x00000000`ffffffff)>>4)-10000000
		//u win32k!W32pServiceTable+((poi(win32k!W32pServiceTable+4*(Index-0x1000))&0x00000000`ffffffff)>>4)-0x10000000

		//u poi(win32k!W32pServiceTable+4*(1-0x1000))
		//u poi(win32k!W32pServiceTable+4*(1-0x1000))&0x00000000`ffffffff
		//u (poi(win32k!W32pServiceTable+4*(1-0x1000))&0x00000000`ffffffff)>>4

		//u win32k!W32pServiceTable+((poi(win32k!W32pServiceTable+4*(1-0x1000))&0x00000000`ffffffff)>>4)-0x10000000

		ULONGLONG qword_temp = 0;
		LONG dw = 0;

		// SSSDT 下标从1000开始,而W32pServiceTable是从0开始
		// + 4 则是每次向下4字节就是下一个地址
		qword_temp = W32pServiceTable + 4 * (Index - 0x1000);
		
		dw = *(PLONG)qword_temp;
		// dw = qword_temp & 0x00000000ffffffff;
		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进程内执行。

标签:ULONGLONG,SERVICE,W32pServiceTable,枚举,内核,fffff802,TABLE,ShadowSSDT,ByteCode
From: https://www.cnblogs.com/LyShark/p/16807522.html

相关文章

  • ubuntu20.04内核升级,增加kvm模块
    ubuntu20.04内核升级,增加kvm模块原创 南哥小白 南小白攻防 2022-03-3115:43    本操作主要是升级内核,体验一下源码编译内核的操作步骤。准备虚拟机以及......
  • 驱动开发:Win10枚举完整SSDT地址表
    在前面的博文《驱动开发:Win10内核枚举SSDT表基址》中已经教大家如何寻找SSDT表基地址了,找到后我们可根据序号获取到指定SSDT函数的原始地址,而如果需要输出所有SSDT表信息,则......
  • 同样的内核,为何linux干净稳定,而android臃肿又乌烟瘴气
    众所周知,现在智能手机操作系统主要有两大类:Android、iOS,采用Android系统的智能机品牌厂商很多(如:华为、Oppo、小米、魅族、三星、还有一些杂牌机等等),而iOS系统只有苹果的iPho......
  • 驱动开发:Win10内核枚举SSDT表基址
    三年前面朝黄土背朝天的我,写了一篇如何在Windows7系统下枚举内核SSDT表的文章《驱动开发:内核读取SSDT表基址》三年过去了我还是个单身狗,开个玩笑,微软的Windows10系统已经......
  • 驱动开发:Win10内核枚举SSDT表基址
    三年前面朝黄土背朝天的我,写了一篇如何在Windows7系统下枚举内核SSDT表的文章《驱动开发:内核读取SSDT表基址》三年过去了我还是个单身狗,开个玩笑,微软的Windows10系统已经......
  • Python中的枚举类enum
    0.本文来历上一篇文章,我写了Pytest插件pytest-order指定用例顺序我当时就比较好奇它的顺序和英文的对应关系,肯定是写死的,找了下就发现在源码sorter.py中定义了一......
  • 驱动开发:内核枚举Minifilter微过滤驱动
    Minifilter是一种文件过滤驱动,该驱动简称为微过滤驱动,相对于传统的sfilter文件过滤驱动来说,微过滤驱动编写时更简单,其不需要考虑底层RIP如何派发且无需要考虑兼容性问题,微......
  • 浅谈C语言中的常量(字面常量、const修饰的常变量、#define定义的标识符常量、枚举常量
    一.常量不会变的量就是常量,比如性别,血型等;二.常量的分类1.字面常量2.const修饰的常变量3.#define定义的标识符常量4.枚举常量1.字面常量2.const修饰的常变量    在......
  • 结构体,枚举,联合体
    为什么有自定义类型?   C语言中的数据类型有int,float,double,short,char等,但是对于一些复杂的结构体我们还是不能用我们已有的类型来进行定义。比如说你想要描述一个人,你可......
  • linux 内核编译问题汇总
    一、编译设备树时找不到设备树包含的头文件设备树包中包含的头文件会到kernel/scripts/dtc/include-prefixes/dt-bindings目录下去查找(新版本内核),而dt-bindings目录......