Many API functions of fweWindows will create and use handles (incoming parameters). The handle represents the memory address of a kernel object. Each process has a handle table, which stores the handles owned by the process. The kernel also has a handle table PspCidTable, which stores A handle to the entire system.
ExpLookupHandleTableEntry windows kernel handle table structure analysis
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 ; If the pid is greater than the address of the handle table, it is considered an invalid 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 ; The lower two digits indicate the level of the handle surface PAGE:00000001405F93E8 jnz short loc_1405F9402 ; Determine whether it is a level 2 handle table PAGE:00000001405F93EA mov rax, rdx ; rax=process ID PAGE:00000001405F93ED shr rax, 0Ah ; Process ID shifted right by 0xA PAGE:00000001405F93F1 and edx, 3FFh ; Process ID & amp; 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 ; Level 1 handle table processing PAGE:00000001405F9404 jnz short loc_1405F940C PAGE:00000001405F9406 lea rax, [r8 + rdx*4] ; Process ID * 4 PAGE: 00000001405F940A retn PAGE:00000001405F940A ; ---------------------------------------------- ------------------
handle table structure
nt!_HANDLE_TABLE + 0x000 NextHandleNeedingPool : Uint4B + 0x004 ExtraInfoPages : Int4B + 0x008 TableCode : Uint8B The lower two bits of the address of the handle table indicate the level + 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
process handle table location
nt!_EPROCESS + 0x570 ObjectTable : Ptr64 _HANDLE_TABLE
Address of the handle table of the notepad.exe process
1: kd> dt _eprocess objecttable 0xffff9f8f1219b080 nt!_EPROCESS + 0x570 ObjectTable : 0xffff8d85`56370c40 _HANDLE_TABLE
0xffff8d85`570ff000 notepad.exe handle table address, the lower two bits are 0, which means it is a level 1 table
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
Parse this handle object 9f8f124d`14b0fff3
(handle item>>0x10) & 0xfffffffffffffff0 = object address (low order)
(0x9f8f124d14b0fff3>>0x10) & 0xfffffffffffffff0 = 0x9f8f124d14b0 plus high bit 0xffff equals 0xffff9f8f124d14b0
dt_object_header 0xffff9f8f124d14b0
+ 0x000 PointerCount : 0n32764 + 0x008 HandleCount: 0n1 + 0x008 NextToFree : 0x00000000`00000001 Void + 0x010 Lock : _EX_PUSH_LOCK + 0x018 TypeIndex : 0x2d '-' handle type + 0x019 TraceFlags : 0 '' + 0x019 DbgRefTrace : 0y0 + 0x019 DbgTracePermanent : 0y0
Calculate object type index
2d^ObHeaderCookie^ (the penultimate byte of the object address is 14)
1: kd> 0x2d^0x14^0x29 int 0n16
Reverse the kernel function ObGetObjectType to know the calculation method
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 ]
You can see that the handle type is Profile type
kernel handle table
The PspCidTable kernel variable stores the memory address of the kernel global handle table
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 The lower two bits are 1, which means it is a secondary table 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
Find the handle pid of notepad.exe is 6264 (0x1878)
It can be known from the reverse of the upper kernel function
Handle table address + (process ID>>0xa*8)-1
1: kd> dq 0xffff8d85`53efc001 + (6*8)-1 ffff8d85`53efc030 ffff8d85`565fb000 00000000`00000000
Get the address of the level 1 table where the process is located ffff8d85`565fb000
get kernel object handle entry
1: kd> dq ffff8d85`565fb000 + (0x78*4)
ffff8d85`565fb480 9f8f121a`3080fffd 00000000`00000000
Parse kernel object address from kernel handle entry
(0x9f8f121a`3080fffd>>0x10) & 0xfffffffffffffff0 = 0xffff9f8f1219b080
1: kd> dt _eprocess imagefilename 0xffff9f8f1219b080 nt!_EPROCESS + 0x5a8 ImageFileName : [15] "notepad.exe"