首页
社区
课程
招聘
[原创] (x64)Windows 10下的句柄表解析
2023-5-14 13:42 6400

[原创] (x64)Windows 10下的句柄表解析

2023-5-14 13:42
6400


x86下的_HANDLE_TABLE_ENTRY长度为8B,其低4字节Object指针直接指向对象头(_OBJECT_HEADER)。

在全局句柄表PspCidTable中,其PVOID指针直接指向对象体(_EPROCESS/_ETHREAD)。


在x64的Windows 10中,_HANDLE_TABLE_ENTRY结构长度拓展为16字节,其结构体中指向对象头的PVOID指针也消失了。


通过对PsLookupProcessByProcessId函数进行分析,其函数栈如下:

PsLookupProcessByProcessId -> PspReferenceCidTableEntry -> ExpLookupHandleTableEntry



句柄与对象指针的关键转换代码如下:

----------------------------------------

nt!ExpLookupHandleTableEntry:

fffff805`78ca15d0 8b01            mov     eax,dword ptr [rcx]        ; rcx=*PspCidTable

fffff805`78ca15d2 4883e2fc        and     rdx,0FFFFFFFFFFFFFFFCh    ; rdx=pid/handle

fffff805`78ca15d6 483bd0          cmp     rdx,rax

fffff805`78ca15d9 7357            jae     nt!ExpLookupHandleTableEntry+0x62 (fffff805`78ca1632)

fffff805`78ca15db 4c8b4108        mov     r8,qword ptr [rcx+8]        ; r8将存储PspCidTable->TableCode

fffff805`78ca15df 418bc0          mov     eax,r8d

fffff805`78ca15e2 83e003          and     eax,3

fffff805`78ca15e5 83f801          cmp     eax,1                                    ; 判断是否为二级索引

fffff805`78ca15e8 7517            jne     nt!ExpLookupHandleTableEntry+0x31 (fffff805`78ca1601)

fffff805`78ca15ea 488bc2          mov     rax,rdx

fffff805`78ca15ed 48c1e80a        shr     rax,0Ah

fffff805`78ca15f1 81e2ff030000    and     edx,3FFh

fffff805`78ca15f7 498b44c0ff      mov     rax,qword ptr [r8+rax*8-1]

fffff805`78ca15fc 488d0490        lea     rax,[rax+rdx*4]

fffff805`78ca1600 c3              ret


nt!PspReferenceCidTableEntry+0x5d:

fffff805`78ccd0ed 488b5c2420      mov     rbx,qword ptr [rsp+20h]    ; rbx=句柄表项存储的低8字节值

fffff805`78ccd0f2 48c1fb10        sar     rbx,10h       ; 右移16bit

fffff805`78ccd0f6 4883e3f0        and     rbx,0FFFFFFFFFFFFFFF0h        ; rbx指向对象头/对象体

fffff805`78ccd0fa 0fb603          movzx   eax,byte ptr [rbx]

fffff805`78ccd0fd 247f            and     al,7Fh

----------------------------------------


每个PAGE_SIZE大小为4KB,可存储句柄表项数为2^8个,且由于句柄号是4的整数倍,因此计算句柄项的中间索引时需要右移10bit获得Mid.index,计算句柄项的Low.index时需要与上0x3ff。中间索引表的表项应该存储的是PHANDLE_TABLE_ENTRY,长度为8字节;在计算Low.offset时,由于HANDLE_TABLE_ENTRY长度为16B,其句柄号是4的整数倍(本身已经乘4),只需要句柄号再乘4即可。句柄表项中并不直接映射对象头,而是间接进行映射。

其转换方式为(*(__int64*)handle_table_entry >> 0x10) && 0xfffffffffffffff0.



如果是进程句柄表,则在句柄较少的情况下采用直接索引(取决于TableCode的低2bit),即在句柄表中直接进行索引。此时其句柄表项可直接通过 `句柄表基址+4*handle` 取低8字节获取,之后的转换与上边的一样。





如被测试进程LoadPE.exe的pid为0x700,通过测试程序调用OpenProcess获取目标进程的句柄,如下:

LoadPE.exe进程的内核对象地址为0xFFFFCE0EAA636080(指向对象体),句柄号为0xac.


通过windbg获取LoadPE.exe进程的句柄表地址为 0xffffb98041457800,其 TableCode=0xffffb9803c9ff000.

由于TableCode&2 = 0,即采用直接索引,其句柄表项为 ce0eaa63`60500001 00000000`001fffff,其低8B可转换为对象头指针。

(0xce0eaa6360500001 >> 0x10) & 0xfffffffffffffff0 = 0xFFFFCE0EAA636050 (指向对象头)



以同样的方式解析全局句柄表PspCidTable,如下:

PspCidTable=ffffb980`37006e00,其TableCode=0xffffb9803a978001,即采用2级索引。

由于被测试程序LoadPE.exe的pid=0x700,(0x700 >> a)& 0x3ff = 1,即 Mid.index=1, Mid.offset=1*8.

Low.index=0x700 & 0x3ff = 0x300, Low.offset=4*0x300.

将取出的值做如上的处理便可得到对象体指针。




[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

收藏
点赞3
打赏
分享
最新回复 (2)
雪    币: 113
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
goren 2024-1-22 23:02
2
0
大佬 这句汇编的作用是啥啊 and     rdx,0FFFFFFFFFFFFFFFCh
雪    币: 19103
活跃值: (28707)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
秋狝 2024-1-23 09:29
3
1
感谢分享
游客
登录 | 注册 方可回帖
返回