全局句柄表是一个内核中存储进程线程内核对象引用的一个结构,句柄表是啥能干啥我就不说了,下面我们来看一下我们经常用的一个导出函数PsLookupProcessByProcessId
首先我们在导出表里找一下这个函数,跟进去

如果大家有xp下搜索全局句柄表的经验的话会记得在win732或xp时候我们要找的PspCidTable就在这个函数里被引用了,不过在我这个win10-22h2下面是如下的引用方式

跟进去

可以看到是在PspReferenceCidTableEntry这个函数中直接引用的全局句柄表结构体地址
我们也可以通过从PsCidTable反过来找引用位置来确定自己的特征码搜索位置和方式
根据上面的引用方式我们可以确定下来我们的一个搜索方法,这是最直观也最简单的搜索方法,方便大家理解这个过程
下面我们来了解一下全局句柄表的结构以及遍历方式
PspCidTable: 地址是一个结构体 HANDLE_TABLE—>TableCode指向一张全局句柄表。
TableCode:地址的低2位记录这个表是一级句柄表,还是二级或者三级;00表示一级,01表示二级,10表示三级;
如果是一级:那么TableCode指向的表直接是内核地址;
如果是二级:那么TableCode指向的是一个存储了句柄表地址的表,再由这个表指向的一个表这个表里存储的地址指向内核地址.
如果是三级:则一层一层下去。一般不会不存在三级。
下面我们到环境里找一个看看,我这边启动了一个dbgview他的pid是1824

我先来说一下win10-22h2和win7下的变化吧
在我这个环境上现在的句柄表是这样计算的
首先我们的pid是1824,跟win7时候一样我们拿1824/4 = 456(0x1c8)
456/256=1 456%256=200(0xc8)
说明我们在第二张表上的第c8个HANDLE_TABLE_ENTRY
可以看到ObjectPointerBits是0xe081b956e34
我们先是0xe081b956e34 << 4 = 0xe081b956e340
在0xe081b956e340 | 0xffff000000000000 = ffffe081b956e340
因为我们知道这是个process,所以直接dt一下看看0x5a8的位置

可以看到这就是我们的这个dbgview进程
下面我们用驱动代码的方式来实现一下这个过程
我这里只做了给了固定的pid解析到process对象,大家可以根据我的代码拓展一下写一个遍历全局句柄表的方法
注意:全局句柄表里不止存了进程还有线程对象,如何去区分他们两个可以根据OBJECT_HEADER来分辨

全局句柄表和私有句柄表的结构体是共用的,所以说结构是一模一样的,只不过私有句柄表里存储的不只是进程线程还有其他的例如事件、文件、管道等等
既然是私有句柄表根据我们平时的编码过程可以理解,这个表一定是跟进程相关,甚至是存储到了进程对象中
大家可以回到我们之前那篇进程对象的文章里看下,在0x570的位置有个ObjectTable,这就是我们私有句柄表的地址
可以在环境里找个进程看一下
解析这个表的过程跟解析我们全局句柄表是一模一样的
大家可以参考我们解析全局句柄表的过程写一个函数来解析目标进程的私有句柄表
第二大家看一下HandleTableList的位置,我们全局句柄表的这个位置指向的是自己,这里则是一个链,大家可以根据这个链看一下能够否遍历所有的进程出来
具体代码我后面找个时间推到git上大家拉下去看吧,距离上一篇已经隔了几周了,这几周太忙了估计后面也不会像国庆时候那样有充足的时间来整理博文,不过所有的内容最终都会有的,我会慢慢找时间一点一点写
1: kd> dq PspCidTable
fffff801`302fc5c8 ffffd08d`38a1ed00 ffffe081`b22bc920
fffff801`302fc5d8 ffffe081`b22b8f00 00000000`00000002
fffff801`302fc5e8 00000000`00000000 00010000`00001000
fffff801`302fc5f8 00000000`00000000 00009705`00000000
fffff801`302fc608 00000000`00000000 00000000`00000000
fffff801`302fc618 00000000`00000000 00000000`00000000
fffff801`302fc628 00000000`00000000 00000000`00000000
fffff801`302fc638 ffffe081`b22fdae0 fffff801`30646000
1: kd> dt _HANDLE_TABLE ffffd08d`38a1ed00
ntdll!_HANDLE_TABLE
+0x000 NextHandleNeedingPool : 0x3400
+0x004 ExtraInfoPages : 0n0
+0x008 TableCode : 0xffffd08d`3c3c6001
+0x010 QuotaProcess : (null)
+0x018 HandleTableList : _LIST_ENTRY [ 0xffffd08d`38a1ed18 - 0xffffd08d`38a1ed18 ]
+0x028 UniqueProcessId : 0
+0x02c Flags : 1
+0x02c StrictFIFO : 0y1
+0x02c EnableHandleExceptions : 0y0
+0x02c Rundown : 0y0
+0x02c Duplicated : 0y0
+0x02c RaiseUMExceptionOnInvalidHandleClose : 0y0
+0x030 HandleContentionEvent : _EX_PUSH_LOCK
+0x038 HandleTableLock : _EX_PUSH_LOCK
+0x040 FreeLists : [1] _HANDLE_TABLE_FREE_LIST
+0x040 ActualEntry : [32] ""
+0x060 DebugInfo : (null)
1: kd> dq ffffd08d`3c3c6000
ffffd08d`3c3c6000 ffffd08d`38ab2000 ffffd08d`3c3c7000
ffffd08d`3c3c6010 ffffd08d`3c8cb000 ffffd08d`3d1f9000
ffffd08d`3c3c6020 ffffd08d`3db2e000 ffffd08d`3e47b000
ffffd08d`3c3c6030 ffffd08d`3f129000 ffffd08d`3db2d000
ffffd08d`3c3c6040 ffffd08d`40efe000 ffffd08d`460d1000
ffffd08d`3c3c6050 ffffd08d`40cff000 ffffd08d`3d238000
ffffd08d`3c3c6060 ffffd08d`67cff000 00000000`00000000
ffffd08d`3c3c6070 00000000`00000000 00000000`00000000
1: kd> dt _HANDLE_TABLE_ENTRY ffffd08d`3c3c7000+0x10*0xc8
ntdll!_HANDLE_TABLE_ENTRY
+0x000 VolatileLowValue : 0n-2269328954387013655
+0x000 LowValue : 0n-2269328954387013655
+0x000 InfoTable : 0xe081b956`e340dfe9 _HANDLE_TABLE_ENTRY_INFO
+0x008 HighValue : 0n0
+0x008 NextFreeHandleEntry : (null)
+0x008 LeafHandleValue : _EXHANDLE
+0x000 RefCountField : 0n-2269328954387013655
+0x000 Unlocked : 0y1
+0x000 RefCnt : 0y0110111111110100 (0x6ff4)
+0x000 Attributes : 0y000
+0x000 ObjectPointerBits : 0y11100000100000011011100101010110111000110100 (0xe081b956e34)
+0x008 GrantedAccessBits : 0y0000000000000000000000000 (0)
+0x008 NoRightsUpgrade : 0y0
+0x008 Spare1 : 0y000000 (0)
+0x00c Spare2 : 0
1: kd> dq PspCidTable
fffff801`302fc5c8 ffffd08d`38a1ed00 ffffe081`b22bc920
fffff801`302fc5d8 ffffe081`b22b8f00 00000000`00000002
fffff801`302fc5e8 00000000`00000000 00010000`00001000
fffff801`302fc5f8 00000000`00000000 00009705`00000000
fffff801`302fc608 00000000`00000000 00000000`00000000
fffff801`302fc618 00000000`00000000 00000000`00000000
fffff801`302fc628 00000000`00000000 00000000`00000000
fffff801`302fc638 ffffe081`b22fdae0 fffff801`30646000
1: kd> dt _HANDLE_TABLE ffffd08d`38a1ed00
ntdll!_HANDLE_TABLE
+0x000 NextHandleNeedingPool : 0x3400
+0x004 ExtraInfoPages : 0n0
+0x008 TableCode : 0xffffd08d`3c3c6001
+0x010 QuotaProcess : (null)
+0x018 HandleTableList : _LIST_ENTRY [ 0xffffd08d`38a1ed18 - 0xffffd08d`38a1ed18 ]
+0x028 UniqueProcessId : 0
+0x02c Flags : 1
+0x02c StrictFIFO : 0y1
+0x02c EnableHandleExceptions : 0y0
+0x02c Rundown : 0y0
+0x02c Duplicated : 0y0
+0x02c RaiseUMExceptionOnInvalidHandleClose : 0y0
+0x030 HandleContentionEvent : _EX_PUSH_LOCK
+0x038 HandleTableLock : _EX_PUSH_LOCK
+0x040 FreeLists : [1] _HANDLE_TABLE_FREE_LIST
+0x040 ActualEntry : [32] ""
+0x060 DebugInfo : (null)
1: kd> dq ffffd08d`3c3c6000
ffffd08d`3c3c6000 ffffd08d`38ab2000 ffffd08d`3c3c7000
ffffd08d`3c3c6010 ffffd08d`3c8cb000 ffffd08d`3d1f9000
ffffd08d`3c3c6020 ffffd08d`3db2e000 ffffd08d`3e47b000
ffffd08d`3c3c6030 ffffd08d`3f129000 ffffd08d`3db2d000
ffffd08d`3c3c6040 ffffd08d`40efe000 ffffd08d`460d1000
ffffd08d`3c3c6050 ffffd08d`40cff000 ffffd08d`3d238000
ffffd08d`3c3c6060 ffffd08d`67cff000 00000000`00000000
ffffd08d`3c3c6070 00000000`00000000 00000000`00000000
1: kd> dt _HANDLE_TABLE_ENTRY ffffd08d`3c3c7000+0x10*0xc8
ntdll!_HANDLE_TABLE_ENTRY
+0x000 VolatileLowValue : 0n-2269328954387013655
+0x000 LowValue : 0n-2269328954387013655
+0x000 InfoTable : 0xe081b956`e340dfe9 _HANDLE_TABLE_ENTRY_INFO
+0x008 HighValue : 0n0
+0x008 NextFreeHandleEntry : (null)
+0x008 LeafHandleValue : _EXHANDLE
+0x000 RefCountField : 0n-2269328954387013655
+0x000 Unlocked : 0y1
+0x000 RefCnt : 0y0110111111110100 (0x6ff4)
+0x000 Attributes : 0y000
+0x000 ObjectPointerBits : 0y11100000100000011011100101010110111000110100 (0xe081b956e34)
+0x008 GrantedAccessBits : 0y0000000000000000000000000 (0)
+0x008 NoRightsUpgrade : 0y0
+0x008 Spare1 : 0y000000 (0)
+0x00c Spare2 : 0
typedef struct _HANDLE_TABLE_ENTRY
{
union
{
LONG_PTR VolatileLowValue;
LONG_PTR LowValue;
PVOID InfoTable;
LONG_PTR RefCountField;
struct
{
ULONG_PTR Unlocked : 1;
ULONG_PTR RefCnt : 16;
ULONG_PTR Attributes : 3;
ULONG_PTR ObjectPointerBits : 44;
};
};
/*union
{
LONG_PTR HighValue;
struct _HANDLE_TABLE_ENTRY* NextFreeHandleEntry;
EXHANDLE LeafHandleValue;
struct
{
ULONG32 GrantedAccessBits : 25;
ULONG32 NoRightsUpgrade : 1;
ULONG32 Spare1 : 6;
};
ULONG32 Spare2;
};*/
} HANDLE_TABLE_ENTRY, * PHANDLE_TABLE_ENTRY;
typedef struct _HANDLE_TABLE_FREE_LIST
{
ULONG_PTR FreeListLock;
PHANDLE_TABLE_ENTRY FirstFreeHandleEntry;
PHANDLE_TABLE_ENTRY lastFreeHandleEntry;
LONG32 HandleCount;
ULONG32 HighWaterMark;
ULONG32 Reserved[8];
} HANDLE_TABLE_FREE_LIST, * PHANDLE_TABLE_FREE_LIST;
typedef struct _HANDLE_TABLE
{
ULONG32 NextHandleNeedingPool;
LONG32 ExtraInfoPages;
ULONG_PTR TableCode;
PEPROCESS QuotaProcess;
LIST_ENTRY HandleTableList;
ULONG32 UniqueProcessId;
union
{
ULONG32 Flags;
struct
{
BOOLEAN StrictFIFO : 1;
BOOLEAN EnableHandleExceptions : 1;
BOOLEAN Rundown : 1;
BOOLEAN Duplicated : 1;
BOOLEAN RaiseUMExceptionOnInvalidHandleClose : 1;
};
};
ULONG_PTR HandleContentionEvent;
ULONG_PTR HandleTableLock;
union
{
HANDLE_TABLE_FREE_LIST FreeLists[1];
BOOLEAN ActualEntry[32];
};
PVOID DebugInfo;
} HANDLE_TABLE, * PHANDLE_TABLE;
BOOLEAN TestLookupHandleTable(ULONG64 pid) {
PUCHAR lookupAddr = (PUCHAR)PsLookupProcessByProcessId;
PVOID E8Addr = NULL;
ULONG32 offset = 0;
for (size_t i = 0; i < 0x100; i++)
{
if (lookupAddr[i] == 0xe8) {
E8Addr = &lookupAddr[i];
offset = *(PULONG32)(&lookupAddr[i + 1]);
break;
}
}
if (E8Addr == NULL) {
return FALSE;
}
PUCHAR PspReferenceCidTableEntryAddr = NULL;
PspReferenceCidTableEntryAddr = (PUCHAR)((ULONG64)E8Addr + 4 + offset);
PVOID X35Addr = NULL;
PLONG64 PsCidTable = NULL;
offset = 0;
for (size_t i = 0; i < 0x150; i++)
{
if (PspReferenceCidTableEntryAddr[i] == 0x4c &&
PspReferenceCidTableEntryAddr[i + 1] == 0x8b &&
PspReferenceCidTableEntryAddr[i + 2] == 0x35) {
offset = *(PULONG32)&PspReferenceCidTableEntryAddr[i + 3];
X35Addr = &PspReferenceCidTableEntryAddr[i + 3];
break;
}
}
if (offset == 0) {
return FALSE;
}
PsCidTable = (PLONG64)((ULONG64)X35Addr + 4 + offset);
KdPrint(("[PsCidTable Addr] %p\r\n", PsCidTable));
//我们这里只做演示所以默认就是二级句柄表
PHANDLE_TABLE handleTable = PsCidTable[0];
PULONG64 tableArr = (PULONG64)((ULONG64)handleTable->TableCode & 0xfffffffffffffff0);
KdPrint(("[HANDLE_TABLE_ENTRY Addr] %p\r\n", tableArr));
pid /= 4;
int pages = pid / 256;
int index = pid % 256;
KdPrint(("[attributes]pages:%d---index:%d\r\n", pages, index));
PHANDLE_TABLE_ENTRY handleTableEntry = (PHANDLE_TABLE_ENTRY)(tableArr[pages] + 0x10 * index);
KdPrint(("[HANDLE_TABLE_ENTRY Addr] %p\r\n", handleTableEntry));
ULONG64 pointer = handleTableEntry->ObjectPointerBits;
PUCHAR proc = ((pointer << 4) | 0xffff000000000000);
KdPrint(("[process name] %s\r\n", (PCHAR)(proc + 0x5a8)));
return TRUE;
}
typedef struct _HANDLE_TABLE_ENTRY
{
union
{
LONG_PTR VolatileLowValue;
LONG_PTR LowValue;
PVOID InfoTable;
LONG_PTR RefCountField;
struct
{
ULONG_PTR Unlocked : 1;
ULONG_PTR RefCnt : 16;
ULONG_PTR Attributes : 3;
ULONG_PTR ObjectPointerBits : 44;
};
};
/*union
{
LONG_PTR HighValue;
struct _HANDLE_TABLE_ENTRY* NextFreeHandleEntry;
EXHANDLE LeafHandleValue;
struct
{
ULONG32 GrantedAccessBits : 25;
ULONG32 NoRightsUpgrade : 1;
ULONG32 Spare1 : 6;
};
ULONG32 Spare2;
};*/
} HANDLE_TABLE_ENTRY, * PHANDLE_TABLE_ENTRY;
typedef struct _HANDLE_TABLE_FREE_LIST
{
ULONG_PTR FreeListLock;
PHANDLE_TABLE_ENTRY FirstFreeHandleEntry;
PHANDLE_TABLE_ENTRY lastFreeHandleEntry;
LONG32 HandleCount;
ULONG32 HighWaterMark;
ULONG32 Reserved[8];
} HANDLE_TABLE_FREE_LIST, * PHANDLE_TABLE_FREE_LIST;
typedef struct _HANDLE_TABLE
{
ULONG32 NextHandleNeedingPool;
LONG32 ExtraInfoPages;
ULONG_PTR TableCode;
传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!