x64驱动 遍历 PspCidTable 枚举隐进程和线程

本文深入探讨了PspCidTable的结构和工作原理,包括如何获取其地址,手动查询及解密过程,适用于Win7到Win10系统。通过代码示例展示了遍历进程和线程的方法。

介绍

PspCidTable 是一个内核句柄表,存放进程和线程的内核对象(EPROCESS 和 ETHREAD),并通过 PID 和 TID 进行索引(所以进程ID和线程ID不可能相同),ID 号以 4 递增。

获取 PspCidTable 地址

win7:

PsLookupProcessByProcessId(被导出) -> PspCidTable

win10:

PsLookupProcessByProcessId(被导出) -> PspReferenceCidTableEntry -> PspCidTable

手动查询 PspTable

打开 WinDbg,输入: dp PspCidTable
得到 PspTable 地址 ——
在这里插入图片描述
输入 dt _handle_table 0xffffc300d9016a80
在这里插入图片描述
TableCode 是指向句柄表的指针,低二位(二进制)记录句柄表的等级:0(00)表示一级表,1(01)表示二级表,2(10)表示三级表。这里的 0xffffc300`dda6f001 就说名它是一个二级表。

一级表里存放的就是进程和线程对象(加密过的,需要一些计算来解密),二级表里存放的是指向某个一级表的指针,同理三级表存放的是指向二级表的指针。

x64 系统中,每张表的大小是 0x1000(4096),一级表中存放的是 _handle_table_entry 结构(大小 = 16),二级表和三级表存放的是指针(大小 = 8)。

我们对 0xffffc300dda6f001 抹去低二位,输入 dp 0xffffc300dda6f000
在这里插入图片描述
可以看到我这张二级表中有 50个一级表指针。查看第一张一级表:dp 0xffffc300d901a000
在这里插入图片描述
我们知道一级句柄表是根据 进程或线程ID来索引的,且以 ‘4’ 累加,所以第一行对应 id = 0,第二行对应 id = 4。 根据尝试,PID = 4 的进程是 System:
在这里插入图片描述
所以 0x9888c5afd440d84f 解密后就应该是 System 进程的 EPROCESS。
解密算法:

系统版本 计算方法
win7 value & 0xfffffffffffffff0
win8 (value >> 0x13) & 0xfffffffffffffff0
win10 (value >> 0x10) & 0xfffffffffffffff0

我的系统是 win10,按照上面的计算方式得到的结果是 0xFFFF9888C5AFD440
输入 dt _eprocess 0xFFFF9888C5AFD440 验证:
在这里插入图片描述
成功!

代码

// 获取 PspCidTable
BOOLEAN get_PspCidTable(ULONG64* tableAddr) {
   
   

	// 获取 PsLookupProcessByProcessId 地址
	UNICODE_STRING uc_funcName;
	RtlInitUnicodeString(&uc_funcName, L"PsLookupProcessByProcessId");
	ULONG64 ul_funcAddr = MmGetSystemRoutineAddress(&uc_funcName);
	if (ul_funcAddr == NULL) {
   
   
		//DbgPrint("[LYSM] MmGetSystemRoutineAddress error.\n");
		return FALSE;
	}
	//DbgPrint("[LYSM] PsLookupProcessByProcessId:%p\n", ul_funcAddr);

	// 前 40 字节有 call(PspReferenceCidTableEntry)
	ULONG64 ul_entry = 0;
	for (INT i = 0; i < 40; i++) {
   
   
		if (*(PUCHAR)(ul_funcAddr + i) == 0xe8) {
   
   
			ul_entry = ul_funcAddr + i;
			break;
		}
	}
	if (ul_entry != 0) {
   
   
		// 解析 call 地址
		INT i_callCode = *(INT*)(ul_entry + 1);
		//DbgPrint("[LYSM] i_callCode:%X\n", i_callCode);
		ULONG64 ul_callJmp = ul_entry + i_callCode + 5;
		//DbgPrint("[LYSM] ul_callJmp:%p\n", ul_callJmp);
		// 来到 call(PspReferenceCidTableEntry) 内找 PspCidTable
		for (INT i = 0; i < 20; i++) {
   
   
			if (*(PUCHAR)(ul_callJmp + i) == 0x48 &&
				*(PUCHAR)(ul_callJmp + i + 1) == 0x8b &&
				*(PUCHAR)
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值