0
点赞
收藏
分享

微信扫一扫

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

介绍

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

获取 PspCidTable 地址

win7:

PsLookupProcessByProcessId(被导出) -> PspCidTable

win10:

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

手动查询 PspTable

打开 WinDbg,输入: ​​dp PspCidTable​​ 得到 PspTable 地址 ——

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


输入 ​​dt _handle_table 0xffffc300d9016a80​

x64驱动 遍历 PspCidTable 枚举隐进程和线程_句柄_02


TableCode 是指向句柄表的指针,低二位(二进制)记录句柄表的等级:0(00)表示一级表,1(01)表示二级表,2(10)表示三级表。这里的 0xffffc300`dda6f001 就说名它是一个二级表。

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

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

我们对 0xffffc300dda6f001 抹去低二位,输入 ​​dp 0xffffc300dda6f000​

x64驱动 遍历 PspCidTable 枚举隐进程和线程_二级_03


可以看到我这张二级表中有 50个一级表指针。查看第一张一级表:​​dp 0xffffc300d901a000​

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


我们知道一级句柄表是根据 进程或线程ID来索引的,且以 ‘4’ 累加,所以第一行对应 id = 0,第二行对应 id = 4。 根据尝试,PID = 4 的进程是 System:

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


所以 0x9888c5afd440d84f 解密后就应该是 System 进程的 EPROCESS。

解密算法:

系统版本

计算方法

win7

value & 0xfffffffffffffff0

win8

(value >> 0x13) & 0xfffffffffffffff0

win10

(value >> 0x10) & 0xfffffffffffffff0

我的系统是 win10,按照上面的计算方式得到的结果是 ​​0xFFFF9888C5AFD440​​​ 输入 ​​dt _eprocess 0xFFFF9888C5AFD440​​ 验证:

x64驱动 遍历 PspCidTable 枚举隐进程和线程_句柄_06


成功!

代码

// 获取 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)(ul_callJmp + i + 2) == 0x05) {
// 解析 mov 地址
INT i_movCode = *(INT*)(ul_callJmp+i + 3);
//DbgPrint("[LYSM] i_movCode:%X\n", i_movCode);
ULONG64 ul_movJmp = ul_callJmp+i + i_movCode + 7;
//DbgPrint("[LYSM] ul_movJmp:%p\n", ul_movJmp);
// 得到 PspCidTable
*tableAddr = ul_movJmp;
return TRUE;
}
}
}

// 前 40字节没有 call
else {
// 直接在 PsLookupProcessByProcessId 找 PspCidTable
for (INT i = 0; i < 70; i++) {
if(*(PUCHAR)(ul_funcAddr + i) == 0x49 &&
*(PUCHAR)(ul_funcAddr + i + 1) == 0x8b &&
*(PUCHAR)(ul_funcAddr + i + 2) == 0xdc &&
*(PUCHAR)(ul_funcAddr + i + 3) == 0x48 &&
*(PUCHAR)(ul_funcAddr + i + 4) == 0x8b &&
*(PUCHAR)(ul_funcAddr + i + 5) == 0xd1 &&
*(PUCHAR)(ul_funcAddr + i + 6) == 0x48 &&
*(PUCHAR)(ul_funcAddr + i + 7) == 0x8b){
// 解析 mov 地址
INT i_movCode = *(INT*)(ul_funcAddr+i+6 + 3);
//DbgPrint("[LYSM] i_movCode:%X\n", i_movCode);
ULONG64 ul_movJmp = ul_funcAddr+i+6 + i_movCode + 7;
//DbgPrint("[LYSM] ul_movJmp:%p\n", ul_movJmp);
// 得到 PspCidTable
*tableAddr = ul_movJmp;
return TRUE;
}
}
}

return FALSE;
}

/* 解析一级表
BaseAddr:一级表的基地址
index1:第几个一级表
index2:第几个二级表
*/
VOID parse_table_1(ULONG64 BaseAddr,INT index1,INT index2) {

//DbgPrint("[LYSM] BaseAddr 1:%p\n", BaseAddr);

// 获取系统版本
RTL_OSVERSIONINFOEXW OSVersion = { 0 };
OSVersion.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
RtlGetVersion((PRTL_OSVERSIONINFOW)&OSVersion);

// 遍历一级表(每个表项大小 16 ),表大小 4k,所以遍历 4096/16 = 526 次
PEPROCESS p_eprocess = NULL;
PETHREAD p_ethread = NULL;
INT i_id = 0;
for (INT i = 0; i < 256; i++) {
if (!MmIsAddressValid((PVOID64)(BaseAddr + i * 16))) {
//DbgPrint("[LYSM] 非法地址:%p\n", BaseAddr + i * 16);
continue;
}
// win10
if (OSVersion.dwMajorVersion == 10 && OSVersion.dwMinorVersion == 0) {
ULONG64 ul_recode = *(PULONG64)(BaseAddr + i * 16);
// 解密
ULONG64 ul_decode = (LONG64)ul_recode >> 0x10;
ul_decode &= 0xfffffffffffffff0;
// 判断是进程还是线程
i_id = i*4 + 1024*index1 + 512*index2*1024;
if (PsLookupProcessByProcessId(i_id , &p_eprocess) == STATUS_SUCCESS) {
DbgPrint("[LYSM] PID:%d , i:%d , addr:%p , object:%p\n", i_id , i, BaseAddr + i*0x10, ul_decode);
}
else if (PsLookupThreadByThreadId(i_id , &p_ethread) == STATUS_SUCCESS) {
DbgPrint("[LYSM] TID:%d , i:%d , addr:%p , object:%p\n", i_id , i, BaseAddr + i*0x10, ul_decode);
}

}
// win7
if (OSVersion.dwMajorVersion == 6 && OSVersion.dwMinorVersion == 1) {
ULONG64 ul_recode = *(PULONG64)(BaseAddr + i * 16);
// 解密
ULONG64 ul_decode = ul_recode & 0xfffffffffffffff0;
// 判断是进程还是线程
i_id = i*4 + 1024*index1 + 512*index2*1024;
if (PsLookupProcessByProcessId(i_id , &p_eprocess) == STATUS_SUCCESS) {
DbgPrint("[LYSM] PID:%d , i:%d , addr:%p , object:%p\n", i_id , i, BaseAddr + i*0x10, ul_decode);
}
else if (PsLookupThreadByThreadId(i_id , &p_ethread) == STATUS_SUCCESS) {
DbgPrint("[LYSM] TID:%d , i:%d , addr:%p , object:%p\n", i_id , i, BaseAddr + i*0x10, ul_decode);
}
else { continue; }
}
}
}

/* 解析二级表
BaseAddr:二级表基地址
index2:第几个二级表
*/
VOID parse_table_2(ULONG64 BaseAddr, INT index2) {

//DbgPrint("[LYSM] BaseAddr 2:%p\n", BaseAddr);

// 遍历二级表(每个表项大小 8),表大小 4k,所以遍历 4096/8 = 512 次
ULONG64 ul_baseAddr_1 = 0;
for (INT i = 0; i < 512; i++) {
if (!MmIsAddressValid((PVOID64)(BaseAddr + i * 8))) {
//DbgPrint("[LYSM] 非法二级表指针(1):%p\n", BaseAddr + i * 8);
continue;
}
if (!MmIsAddressValid((PVOID64)*(PULONG64)(BaseAddr + i * 8))) {
//DbgPrint("[LYSM] 非法二级表指针(2):%p\n", BaseAddr + i * 8);
continue;
}
ul_baseAddr_1 = *(PULONG64)(BaseAddr + i * 8);
parse_table_1(ul_baseAddr_1, i, index2);
}
}

/* 解析三级表
BaseAddr:三级表基地址
*/
VOID parse_table_3(ULONG64 BaseAddr) {

//DbgPrint("[LYSM] BaseAddr 3:%p\n", BaseAddr);

// 遍历三级表(每个表项大小 8),表大小 4k,所以遍历 4096/8 = 512 次
ULONG64 ul_baseAddr_2 = 0;
for (INT i = 0; i < 512; i++) {
if (!MmIsAddressValid((PVOID64)(BaseAddr + i * 8))) { continue; }
if (!MmIsAddressValid((PVOID64) * (PULONG64)(BaseAddr + i * 8))) { continue; }
ul_baseAddr_2 = *(PULONG64)(BaseAddr + i * 8);
parse_table_2(ul_baseAddr_2, i);
}
}

/* 遍历进程和线程
cidTableAddr:PspCidTable 地址
*/
BOOLEAN enum_PspCidTable(ULONG64 cidTableAddr) {

// 获取 _HANDLE_TABLE 的 TableCode
ULONG64 ul_tableCode = *(PULONG64)(((ULONG64)*(PULONG64)cidTableAddr) + 8);
//DbgPrint("[LYSM] ul_tableCode:%p\n", ul_tableCode);

// 取低 2位(二级制11 = 3)
INT i_low2 = ul_tableCode & 3;
//DbgPrint("[LYSM] i_low2:%X\n", i_low2);

// 一级表
if (i_low2 == 0) {
// TableCode 低 2位抹零(二级制11 = 3)
parse_table_1(ul_tableCode & (~3),0,0);
}
// 二级表
else if (i_low2 == 1) {
// TableCode 低 2位抹零(二级制11 = 3)
parse_table_2(ul_tableCode & (~3),0);
}
// 三级表
else if (i_low2 == 2) {
// TableCode 低 2位抹零(二级制11 = 3)
parse_table_3(ul_tableCode & (~3));
}
else {
DbgPrint("[LYSM] i_low2 非法!\n");
return FALSE;
}

return TRUE;
}

调用:

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegistryString)
{
// 初始化省略...
// ...
// ...


// 测试
ULONG64 tableAddr = 0;
if (get_PspCidTable(&tableAddr) == FALSE) {
DbgPrint("[LYSM] get_PspCidTable error.\n");
}
else {
enum_PspCidTable(tableAddr);
}


return STATUS_SUCCESS;
}



举报

相关推荐

0 条评论