Windows 10 X64 内核对象句柄表解析

fweWindows 很多API函数都会创建和使用句柄(传入参数),句柄代表一个内核对象的内存地址,每个进程都有一个句柄表,它保存着进程拥有的句柄,内核也有一个句柄表 PspCidTable,它保存着整个系统的句柄。

ExpLookupHandleTableEntry windows内核句柄表结构解析

PAGE:00000001405F93D0 ExpLookupHandleTableEntry proc near     ; CODE XREF: ObpReferenceObjectByHandleWithTag+EA↑p
PAGE:00000001405F93D0                                         ; NtClose+B5↓p ...
PAGE:00000001405F93D0                 mov     eax, [rcx]
PAGE:00000001405F93D2                 and     rdx, 0FFFFFFFFFFFFFFFCh
PAGE:00000001405F93D6                 cmp     rdx, rax        ; 如果pid大于句柄表地址则认为是无效pid
PAGE:00000001405F93D9                 jnb     short loc_1405F9435
PAGE:00000001405F93DB                 mov     r8, [rcx+8]
PAGE:00000001405F93DF                 mov     eax, r8d
PAGE:00000001405F93E2                 and     eax, 3
PAGE:00000001405F93E5                 cmp     eax, 1          ; 低两位表示句柄表层数level
PAGE:00000001405F93E8                 jnz     short loc_1405F9402 ; 判断是否是2级句柄表
PAGE:00000001405F93EA                 mov     rax, rdx        ; rax=进程ID
PAGE:00000001405F93ED                 shr     rax, 0Ah        ; 进程ID右移0xA
PAGE:00000001405F93F1                 and     edx, 3FFh       ; 进程ID & 0x3ff
PAGE:00000001405F93F7                 mov     rax, [r8+rax*8-1]
PAGE:00000001405F93FC                 lea     rax, [rax+rdx*4]
PAGE:00000001405F9400                 retn
PAGE:00000001405F9400 ; ---------------------------------------------------------------------------
PAGE:00000001405F9401                 align 2
PAGE:00000001405F9402
PAGE:00000001405F9402 loc_1405F9402:                          ; CODE XREF: ExpLookupHandleTableEntry+18↑j
PAGE:00000001405F9402                 test    eax, eax        ; 1级句柄表处理
PAGE:00000001405F9404                 jnz     short loc_1405F940C
PAGE:00000001405F9406                 lea     rax, [r8+rdx*4] ; 进程ID * 4
PAGE:00000001405F940A                 retn
PAGE:00000001405F940A ; ----------------------------------------------------------------

句柄表结构

nt!_HANDLE_TABLE
   +0x000 NextHandleNeedingPool : Uint4B
   +0x004 ExtraInfoPages   : Int4B
   +0x008 TableCode        : Uint8B 句柄表地址低两位表示层级
   +0x010 QuotaProcess     : Ptr64 _EPROCESS
   +0x018 HandleTableList  : _LIST_ENTRY
   +0x028 UniqueProcessId  : Uint4B
   +0x02c Flags            : Uint4B
   +0x02c StrictFIFO       : Pos 0, 1 Bit
   +0x02c EnableHandleExceptions : Pos 1, 1 Bit
   +0x02c Rundown          : Pos 2, 1 Bit
   +0x02c Duplicated       : Pos 3, 1 Bit
   +0x02c RaiseUMExceptionOnInvalidHandleClose : Pos 4, 1 Bit
   +0x030 HandleContentionEvent : _EX_PUSH_LOCK
   +0x038 HandleTableLock  : _EX_PUSH_LOCK
   +0x040 FreeLists        : [1] _HANDLE_TABLE_FREE_LIST
   +0x040 ActualEntry      : [32] UChar
   +0x060 DebugInfo        : Ptr64 _HANDLE_TRACE_DEBUG_INFO

进程句柄表位置

nt!_EPROCESS
+0x570 ObjectTable      : Ptr64 _HANDLE_TABLE

notepad.exe进程的句柄表地址

1: kd> dt _eprocess objecttable 0xffff9f8f1219b080
nt!_EPROCESS
   +0x570 ObjectTable : 0xffff8d85`56370c40 _HANDLE_TABLE

0xffff8d85`570ff000 notepad.exe句柄表地址,低两位为0 表示是1级表

1: kd> dq 0xffff8d85`570ff000
ffff8d85`570ff000  00000000`00000000 00000000`00000000
ffff8d85`570ff010  9f8f124d`1d30ffff 00000000`001f0003
ffff8d85`570ff020  9f8f124d`14b0fff3 00000000`001f0003
ffff8d85`570ff030  9f8f1212`67b0fff5 00000000`00000001
ffff8d85`570ff040  9f8f1227`9290ffd7 00000000`001f0003
ffff8d85`570ff050  9f8f123d`39d0ff89 00000000`000f00ff
ffff8d85`570ff060  9f8f121f`2370ffff 00000000`00100002
ffff8d85`570ff070  9f8f1212`7990ffff 00000000`00000001

解析这个句柄对象 9f8f124d`14b0fff3

(句柄项>>0x10)&0xfffffffffffffff0 = 对象地址(低位)

(0x9f8f124d14b0fff3>>0x10)&0xfffffffffffffff0 =  0x9f8f124d14b0 加上高位 0xffff 等于 0xffff9f8f124d14b0

dt _object_header 0xffff9f8f124d14b0

+0x000 PointerCount     : 0n32764
   +0x008 HandleCount      : 0n1
   +0x008 NextToFree       : 0x00000000`00000001 Void
   +0x010 Lock             : _EX_PUSH_LOCK
   +0x018 TypeIndex        : 0x2d '-' 句柄类型
   +0x019 TraceFlags       : 0 ''
   +0x019 DbgRefTrace      : 0y0
   +0x019 DbgTracePermanent : 0y0

计算对象类型索引

2d^ObHeaderCookie^(对象地址倒数第二个字节14)

1: kd> ?? 0x2d^0x14^0x29
int 0n16

逆向内核函数 ObGetObjectType得知计算方式

PAGE:00000001406FD860 ObGetObjectType proc near               ; DATA XREF: .pdata:000000014010986C↑o
PAGE:00000001406FD860                 lea     rax, [rcx-30h]
PAGE:00000001406FD864                 movzx   ecx, byte ptr [rcx-18h]
PAGE:00000001406FD868                 shr     rax, 8
PAGE:00000001406FD86C                 movzx   eax, al
PAGE:00000001406FD86F                 xor     rax, rcx
PAGE:00000001406FD872                 movzx   ecx, byte ptr cs:ObHeaderCookie
PAGE:00000001406FD879                 xor     rax, rcx
PAGE:00000001406FD87C                 lea     rcx, ObTypeIndexTable
PAGE:00000001406FD883                 mov     rax, [rcx+rax*8]
PAGE:00000001406FD887                 retn
PAGE:00000001406FD887 ObGetObjectType endp

ObTypeIndexTable+(Index*8)
1: kd> dq fffff801`1af08e10+0x16*8
fffff801`1af08ec0  ffff9f8f`0ceca560 ffff9f8f`0cecac40
fffff801`1af08ed0  ffff9f8f`0ceca6c0 ffff9f8f`0cec97a0
fffff801`1af08ee0  ffff9f8f`0cecada0 ffff9f8f`0cec9a60
fffff801`1af08ef0  ffff9f8f`0cec9d20 ffff9f8f`0cee1e80
fffff801`1af08f00  ffff9f8f`0cee14e0 ffff9f8f`0cee1d20
fffff801`1af08f10  ffff9f8f`0cee1220 ffff9f8f`0cee2ae0
fffff801`1af08f20  ffff9f8f`0cee22a0 ffff9f8f`0cee2140
fffff801`1af08f30  ffff9f8f`0cee2f00 ffff9f8f`0cee17a0

1: kd> dt _object_type ffff9f8f`0ceca560
nt!_OBJECT_TYPE
   +0x000 TypeList         : _LIST_ENTRY [ 0xffff9f8f`0ceca560 - 0xffff9f8f`0ceca560 ]
   +0x010 Name             : _UNICODE_STRING "Profile"
   +0x020 DefaultObject    : (null) 
   +0x028 Index            : 0x16 ''
   +0x02c TotalNumberOfObjects : 0
   +0x030 TotalNumberOfHandles : 0
   +0x034 HighWaterNumberOfObjects : 0
   +0x038 HighWaterNumberOfHandles : 0
   +0x040 TypeInfo         : _OBJECT_TYPE_INITIALIZER
   +0x0b8 TypeLock         : _EX_PUSH_LOCK
   +0x0c0 Key              : 0x666f7250
   +0x0c8 CallbackList     : _LIST_ENTRY [ 0xffff9f8f`0ceca628 - 0xffff9f8f`0ceca628 ]

可以看到这个句柄类型是 Profile类型 

 
  
 
  

内核句柄表

PspCidTable 内核变量存储内核全局句柄表的内存地址

1: kd> dq PspCidTable 
fffff801`1af085c0  ffff8d85`50279dc0 ffff9f8f`0cef6d80
fffff801`1af085d0  ffff9f8f`0cee2140 00000000`00000002
fffff801`1af085e0  00000000`00000000 00001000`00010000
fffff801`1af085f0  00000000`00000000 00000000`00005000
fffff801`1af08600  00000000`00000000 000001db`00000000
fffff801`1af08610  00000000`00000000 00000000`00000000
fffff801`1af08620  00000000`00000000 00000000`00000000
fffff801`1af08630  ffff9f8f`0cfef900 fffff801`19d06000

0xffff8d85`53efc001 低两位为1 表示是一个二级表
1: kd> dt _handle_table ffff8d85`50279dc0
nt!_HANDLE_TABLE
   +0x000 NextHandleNeedingPool : 0x1c00
   +0x004 ExtraInfoPages   : 0n0
   +0x008 TableCode        : 0xffff8d85`53efc001
   +0x010 QuotaProcess     : (null) 
   +0x018 HandleTableList  : _LIST_ENTRY [ 0xffff8d85`50279dd8 - 0xffff8d85`50279dd8 ]
   +0x028 UniqueProcessId  : 0
   +0x02c Flags            : 1
   +0x02c StrictFIFO       : 0y1
   +0x02c EnableHandleExceptions : 0y0
   +0x02c Rundown          : 0y0

查找notepad.exe的句柄 pid 为  6264 (0x1878)

由上内核函数逆向可知

句柄表地址+(进程ID>>0xa*8)-1 

1: kd> dq 0xffff8d85`53efc001+(6*8)-1 ffff8d85`53efc030 ffff8d85`565fb000 00000000`00000000

 得到进程所在1级表地址  ffff8d85`565fb000

得到内核对象句柄项

1: kd> dq ffff8d85`565fb000+(0x78*4)

ffff8d85`565fb480 9f8f121a`3080fffd 00000000`00000000

从内核句柄项中解析出内核对象地址

 (0x9f8f121a`3080fffd>>0x10)&0xfffffffffffffff0 = 0xffff9f8f1219b080

1: kd> dt _eprocess imagefilename 0xffff9f8f1219b080
nt!_EPROCESS
   +0x5a8 ImageFileName : [15]  "notepad.exe"

 
  
 
  

你可能感兴趣的:(Windows,windows,windows内核)