驱动代码
#include "vad.h"
#include <ntifs.h>
//获取全部变量PspCidTable
//指向一张表,里面存储的是512个句柄表指针
VOID table_1(ULONG64 BaseAddr);
//遍历每个句柄表指针; 句柄表指针指向一个表,里面存储
//的是进程或线程对象地址;16个字节;1024/16 = 256个;
VOID table_2(ULONG64 BaseAddr, INT index1);
VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint("卸载成功 \n");
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
DbgPrint("进入l \n");
UNICODE_STRING uc_funcName;
RtlInitUnicodeString(&uc_funcName, L"PsLookupProcessByProcessId");
LONGLONG* ul_funcAddr = MmGetSystemRoutineAddress(&uc_funcName);
if (ul_funcAddr == NULL)
{
return FALSE;
}
DbgPrint("PsLookupProcessByProcessId addr = %p \n", ul_funcAddr);
LONG64 CidTable_entry = 0;
for (int i = 0; i < 120; i++)
{
//找E8 call
if ((*((PUCHAR)ul_funcAddr + i)) == 0xe8)
{
CidTable_entry = (LONG64)((PUCHAR)ul_funcAddr + i);
break;
}
}
PLONG64 pPspCidTable = NULL;
if (CidTable_entry != 0)
{
//求出JMP 地址:ul_entry + 5 + 偏移地址
int dwOffset = *(INT*)(CidTable_entry + 1);
ULONG64 CidTableEntry_callJmp = CidTable_entry + dwOffset + 5;
DbgPrint("CidTableEntry_callJmp addr = %p \n", CidTableEntry_callJmp);
for (INT i = 0; i < 200; i++)
{
// fffff802`0841d1a5 48 8b 0d 84 73 f5 ff mov rcx,qword ptr [nt!PspCidTable (fffff802`08374530)]
if (*(PUCHAR)(CidTableEntry_callJmp + i) == 0x48 && *(PUCHAR)(CidTableEntry_callJmp + i + 1) == 0x8b && *(PUCHAR)(CidTableEntry_callJmp + i + 2) == 0x05)
{
// 解析 mov 地址
INT movCode = *(INT*)(CidTableEntry_callJmp + i + 3);
DbgPrint("movCode = %p \n", movCode);
ULONG64 movJmp = CidTableEntry_callJmp + i + movCode + 7;
DbgPrint("movJmp = %p \n", movJmp);
// 得到 PspCidTable
pPspCidTable = (PLONG64)movJmp;
DbgPrint("pPspCidTable addr = %p \n", pPspCidTable);
}
}
}
if (pPspCidTable == NULL)
{
return STATUS_SUCCESS;
}
//判断是几级表
LONG64 Table_code = *((PLONG64)((*pPspCidTable) + 8));
INT Grade = Table_code & 3;
DbgPrint("Table_code = %p \n", Table_code);
DbgPrint("Grade = %X \n", Grade);
if (Grade == 0)
{
}
else if (Grade == 1)
{
table_1(Table_code & (~3));
}
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
VOID table_2(ULONG64 BaseAddr, INT index1)
{
// 遍历一级表(每个表项大小 16 ),表大小 4k,所以遍历 4096/16 = 256 次
PEPROCESS p_eprocess = NULL;
PETHREAD p_ethread = NULL;
INT p_id = 0;
for (INT i = 0; i < 256; i++)
{
if (!MmIsAddressValid((PVOID64)(BaseAddr + i * 16)))
{
DbgPrint("非法地址= %p \n", BaseAddr + i * 16);
continue;
}
ULONG64 Table1_code = *(PULONG64)(BaseAddr + i * 16);
// 换算 先右移16位 在与上0xfffffffffffffff0
ULONG64 Table1_decode = (LONG64)Table1_code >> 0x10;
Table1_decode &= 0xfffffffffffffff0;
//计算方式说明:i*4->windows规定。
//1024*index1-> 因为一个表有256个对象地址,那么256*4 = 1024;
//1024* index1代表第几个句柄指针索引
p_id = i * 4 + 1024 * index1;
// 判断是进程还是线程
if (PsLookupProcessByProcessId((HANDLE)p_id, &p_eprocess) == STATUS_SUCCESS)
{
DbgPrint("进程PID: %d | ID: %d | 对象: %p \n", p_id, i, Table1_decode);
}
else if (PsLookupThreadByThreadId((HANDLE)p_id, &p_ethread) == STATUS_SUCCESS)
{
DbgPrint("线程TID: %d | ID: %d | 对象: %p \n", p_id, i , Table1_decode);
}
}
}
VOID table_1(ULONG64 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("非法二级表指针(1):%p \n", BaseAddr + i * 8);
continue;
}
if (!MmIsAddressValid((PVOID64) * (PULONG64)(BaseAddr + i * 8)))
{
DbgPrint("非法二级表指针(2):%p \n", BaseAddr + i * 8);
continue;
}
ul_baseAddr_1 = *(PULONG64)(BaseAddr + i * 8);
table_2(ul_baseAddr_1, i);
}
}
总结
不懂可以私信我!!