全局句柄表

全局句柄表

在这里插入图片描述
在这里插入图片描述

查找时需要把最低位清0

在这里插入图片描述
PspCidTable存的是 _HANDLE_TABLE结构体的指针。
最后通过索引找到的是_EPROCESS _ETHREAD 这种结构体本身,不需要+18h。最后的两个bit位要清0.

HANDLE 和PID的区别

HANDLE 是一个进程私有的,PID是全局的。
在这里插入图片描述

PID TID

PID TID就是全局句柄表的*索引 4

实验查找计算器

第一步 :通过全局变量找到全局句柄表的位置:
kd> dd pspcidtable
805649c0 e1003b00 00000002 00000004 00000000
805649d0 00000000 00000000 00000000 00000000
805649e0 e13bd587 e10376ff e163422f e17ade87
805649f0 00000000 00000000 00000000 00000000
80564a00 e1396737 e189d7cf 00000000 00000000
80564a10 00000000 00000000 00000000 00000000
80564a20 00000002 00000000 00000000 00000000
80564a30 00000000 00000000 00000000 00000000
kd> dt _HANDLE_TABLE e1003b00
nt!_HANDLE_TABLE
+0x000 TableCode : 0xe1334001
+0x004 QuotaProcess : (null)
+0x008 UniqueProcessId : (null)
+0x00c HandleTableLock : [4] _EX_PUSH_LOCK
+0x01c HandleTableList : _LIST_ENTRY [ 0xe1003b1c - 0xe1003b1c ]
+0x024 HandleContentionEvent : _EX_PUSH_LOCK
+0x028 DebugInfo : (null)
+0x02c ExtraInfoPages : 0n0
+0x030 FirstFree : 0x15c
+0x034 LastFree : 0xe7c
+0x038 NextHandleNeedingPool : 0x1000 这里是一级表的句柄界限。
+0x03c HandleCount : 0n423
+0x040 Flags : 1
+0x040 StrictFIFO : 0y1

第三步:_TABLE_CODE 的最后两个bit位要清0,表示是几级表,这里是两级
kd> dd e1334000
e1334000 e1005000 e1338000 00000000 00000000
e1334010 00000000 00000000 00000000 00000000
e1334020 00000000 00000000 00000000 00000000
e1334030 00000000 00000000 00000000 00000000
e1334040 00000000 00000000 00000000 00000000
e1334050 00000000 00000000 00000000 00000000
e1334060 00000000 00000000 00000000 00000000
e1334070 00000000 00000000 00000000 00000000

第四步:计算器的PID=1504*2=3008 =bc0h

kd> dq e1005000+bc0
e1005bc0 0000000089eda5e9 0000079c00000000
e1005bd0 0000088000000000 0000000089e3b319
e1005be0 0000000089f22b59 000000008a0fba79
e1005bf0 000000008a1b5da1 0000000089f407b9
e1005c00 0000000089e21501 000000008a1d9b59
e1005c10 0000026400000000 0000000089f78709
e1005c20 000000008a020991 000006b800000000
e1005c30 0000000089e9f5d1 0000000089e9f351
kd> dd _HANDLE_TABLE e1003b00

这里找到的89eda5e9 就是计算器的内核对象地址。89eda5e8(最后三个bit位清0)

在这里插入图片描述

如何判断找到的句柄类型是进程还是线程

把找到的值减去18h,通过_OBJECT_HEADER结构体的TYPE 判断。

kd> dt _OBJECT_HEADER 89eda5e8-18 (_EPROCESS的位置-18h)
nt!_OBJECT_HEADER
+0x000 PointerCount : 0n17
+0x004 HandleCount : 0n2
+0x004 NextToFree : 0x00000002 Void
+0x008 Type : 0x8a34e270 _OBJECT_TYPE
+0x00c NameInfoOffset : 0 ‘’
+0x00d HandleInfoOffset : 0 ‘’
+0x00e QuotaInfoOffset : 0 ‘’
+0x00f Flags : 0x20 ’ ’
+0x010 ObjectCreateInfo : 0x8a0b52f0 _OBJECT_CREATE_INFORMATION
+0x010 QuotaBlockCharged : 0x8a0b52f0 Void
+0x014 SecurityDescriptor : 0xe2514df9 Void
+0x018 Body : _QUAD
kd> dt _OBJECT_TYPE 0x8a34e270
nt!_OBJECT_TYPE
+0x000 Mutex : _ERESOURCE
+0x038 TypeList : _LIST_ENTRY [ 0x8a34e2a8 - 0x8a34e2a8 ]
+0x040 Name : _UNICODE_STRING “Process” (类型为进程)
+0x048 DefaultObject : (null)
+0x04c Index : 5
+0x050 TotalNumberOfObjects : 0x1a
+0x054 TotalNumberOfHandles : 0x6b
+0x058 HighWaterNumberOfObjects : 0x1a
+0x05c HighWaterNumberOfHandles : 0x72
+0x060 TypeInfo : _OBJECT_TYPE_INITIALIZER
+0x0ac Key : 0x636f7250
+0x0b0 ObjectLocks : [4] _ERESOURCE

练习2:根据PID 查找进程对象

ULONG  FindKernelObjectByHandle(ULONG Index)
{
	PULONG pFunc = NULL;
	UNICODE_STRING PsLookup;
	//句柄表有几层
	ULONG Tier=0;
	PVOID KeObject=NULL;
	PULONG pFirstTableBase=NULL;
	PULONG pSecondTableBase=NULL;
	//句柄表的全局变量是未导出的需要在已经到处的函数里面找
	ULONG PspCidTable = 0;
	ULONG TableCode=0;
	RtlInitUnicodeString(&PsLookup, L"PsLookupProcessByProcessId");
	pFunc = MmGetSystemRoutineAddress(&PsLookup);
	//PspCidTable在函数PsLookupProcessByProcessId+0x1a
	PspCidTable=*(PULONG)((ULONG)pFunc+0x1a);
	//得到PspCidTable的值
	PspCidTable=*(PULONG)PspCidTable;
	TableCode=*(PULONG)PspCidTable;
	//PspCidTable的低两位决定全局句柄表有几层
	
	Tier=TableCode&3;

	switch (Tier)
	{
	case 0:
		//句柄表只有一级,PspCidTable低两位清0 然后加上索引*4/8   低4字节的低2位清0 就是内核对象的头_OBJECT_HEADER  +0x18就是真正的内核对象_ETHREAD 或者_EPROCESS
		KeObject=(PVOID)(TableCode+Index*2);
		break;
	case 1:
		//找在第一级表的位置   一个表最大的HANDLE 是 512*4=2048  索引、2048 就找出第一级表中的偏移
		pFirstTableBase=(PULONG)(TableCode&0xFFFFFFFC)+Index/512/4;
		//在表中的偏移等于     e1003000 e1fc0000
		//低10位 是在一级表中的偏移
		KeObject=(PVOID)((*pFirstTableBase)+(Index%2048*2));
		break;
	}
	return (*(PULONG)KeObject)&0xfffffffe;
}

练习三:全局句柄表便利进程名

#include"ntddk.h"
ULONG FindTableCount()
{
	PULONG pFunc = NULL;
	UNICODE_STRING PsLookup;

	//总的句柄数

	//句柄表的全局变量是未导出的需要在已经到处的函数里面找
	ULONG PspCidTable = 0;
	ULONG TableCode = 0;

	RtlInitUnicodeString(&PsLookup, L"PsLookupProcessByProcessId");
	pFunc = MmGetSystemRoutineAddress(&PsLookup);
	//PspCidTable在函数PsLookupProcessByProcessId+0x1a
	PspCidTable = *(PULONG)((ULONG)pFunc + 0x1a);
	//得到PspCidTable的值

	PspCidTable = *(PULONG)PspCidTable;

	TableCode = *(PULONG)PspCidTable;


	return *((PULONG)PspCidTable + 0x3c/ 4);
	
}
ULONG  FindKernelObjectByHandle(ULONG Index)
{
	PULONG pFunc = NULL;
	UNICODE_STRING PsLookup;
	//句柄表有几层
	ULONG Tier = 0;
	PVOID KeObject = NULL;
	PULONG pFirstTableBase = NULL;
	PULONG pSecondTableBase = NULL;
	//句柄表的全局变量是未导出的需要在已经到处的函数里面找
	ULONG PspCidTable = 0;
	ULONG TableCode = 0;
	RtlInitUnicodeString(&PsLookup, L"PsLookupProcessByProcessId");
	pFunc = MmGetSystemRoutineAddress(&PsLookup);
	//PspCidTable在函数PsLookupProcessByProcessId+0x1a
	PspCidTable = *(PULONG)((ULONG)pFunc + 0x1a);
	//得到PspCidTable的值
	PspCidTable = *(PULONG)PspCidTable;
	TableCode = *(PULONG)PspCidTable;
	//PspCidTable的低两位决定全局句柄表有几层

	Tier = TableCode & 3;

	switch (Tier)
	{
	case 0:
		//句柄表只有一级,PspCidTable低两位清0 然后加上索引*4/8   低4字节的低2位清0 就是内核对象的头_OBJECT_HEADER  +0x18就是真正的内核对象_ETHREAD 或者_EPROCESS
		KeObject = (PVOID)(TableCode + Index * 2);
		break;
	case 1:
		//找在第一级表的位置   一个表最大的HANDLE 是 512*4=2048  索引、2048 就找出第一级表中的偏移
		pFirstTableBase = (PULONG)(TableCode & 0xFFFFFFFC) + Index / 512 / 4;
		//在表中的偏移等于     e1003000 e1fc0000
		//低10位 是在一级表中的偏移
		KeObject = (PVOID)((*pFirstTableBase) + (Index % 2048 * 2));
		break;
	}
	return (*(PULONG)KeObject) & 0xfffffffe;
}


VOID Kill360()
{	
	ULONG TableCount = 0;
	ULONG i = 0;
	ULONG KernelObject = 0;
	PUNICODE_STRING TypeName = NULL;
	UNICODE_STRING ImageFileName;
	TableCount=FindTableCount();
	RtlInitUnicodeString(&ImageFileName, L"Process");
	while (i<TableCount)
	{
		KernelObject=FindKernelObjectByHandle(i*4);
		//判断是不是进程,如果是进程就输出进程名
		//_OBJECT_HEADER
		//_OBJECT_TYPE
		if (KernelObject!=0)
		{
			TypeName = (PUNICODE_STRING)((*(PULONG)(KernelObject - 0x10)) + 0x40);
			
			//如果是进程,就输出进程名
			if (!RtlCompareUnicodeString(TypeName,&ImageFileName,TRUE))
			{
				DbgPrint("%s\n", (PUNICODE_STRING)(KernelObject+0x174));
			}
		}
		i++;
	}
}

VOID __stdcall UnLoad(PDRIVER_OBJECT pDriver)
{
	DbgPrint("Driver 卸载成功\n");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pRegPath)
{
	Kill360();
	pDriver->DriverUnload = UnLoad;
	return STATUS_SUCCESS;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值