Windows Handle 如何关联对应的对象类型?

问题描述 投票:0回答:1

有两个文件。一个是

LearnHanle.exe
(拼写错误,应该是
LearnHandle.exe
),另一个是
pop.exe

这些文件的源代码在这里:

// LearnHanle.cpp

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
int main() {

    STARTUPINFOW startup = { 0 };
    startup.cb = sizeof startup;
    PROCESS_INFORMATION pi = { 0 };
    BOOL createProcResult = FALSE;
    if (!CreateProcessW(L"C:\\pop.exe", NULL, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi))
        MessageBoxA(NULL, "Create Process Failed", "Alert", MB_OK);

    char handle[80] = { 0 };
    sprintf_s(handle, "Process Handle: %llu ProcessId: %llu", pi.hProcess, pi.dwProcessId);
    MessageBoxA(NULL, handle, "Process", MB_OK);
    sprintf_s(handle, "Thread Handle: %llu ThreadId: %llu", pi.hThread, pi.dwThreadId);
    MessageBoxA(NULL, handle, "Thread", MB_OK);
    system("pause");
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);
}
// pop.cpp

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
int main() {
    MessageBox(0, 0, 0, 0);
    // Just sleep
    Sleep(6000000);
}

LearnHanle.exe
只是创建
pop.exe
进程,然后自行挂起。

我用

LearnHanle.exe
查看了
Process Explorer
进程的详细信息,找到了与
pop.exe
进程关联的HANDLE,然后就得到了HANDLE地址,如下所示:

Basic Information
Name: pop.exe(9092)
Type: Process
Description: Contains threads, an address space, and handles.
Address: 0xFFFFE786E04AF080

我用WinDbg调试了Windows 11内核,我使用

!object
命令查看HANDLE地址。输出在这里:

0: kd> !object 0xffffe786e04af080
Object: ffffe786e04af080  Type: (ffffe786da2cfd20) Process
    ObjectHeader: ffffe786e04af050 (new version)
    HandleCount: 9  PointerCount: 293899

ObjectHeader
指针指向
_EPROCESS
进程的
pop.exe
的对象头:

0: kd> dt _OBJECT_HEADER ffffe786e04af050
nt!_OBJECT_HEADER
   +0x000 PointerCount     : 0n293899
   +0x008 HandleCount      : 0n9
   +0x008 NextToFree       : 0x00000000`00000009 Void
   +0x010 Lock             : _EX_PUSH_LOCK
   +0x018 TypeIndex        : 0x47 'G'
   +0x019 TraceFlags       : 0 ''
   +0x019 DbgRefTrace      : 0y0
   +0x019 DbgTracePermanent : 0y0
   +0x01a InfoMask         : 0x88 ''
   +0x01b Flags            : 0 ''
   +0x01b NewObject        : 0y0
   +0x01b KernelObject     : 0y0
   +0x01b KernelOnlyAccess : 0y0
   +0x01b ExclusiveObject  : 0y0
   +0x01b PermanentObject  : 0y0
   +0x01b DefaultSecurityQuota : 0y0
   +0x01b SingleHandleEntry : 0y0
   +0x01b DeletedInline    : 0y0
   +0x01c Reserved         : 0
   +0x020 ObjectCreateInfo : 0xffffe786`dca5ccc0 _OBJECT_CREATE_INFORMATION
   +0x020 QuotaBlockCharged : 0xffffe786`dca5ccc0 Void
   +0x028 SecurityDescriptor : 0xffffd705`63f2962f Void
   +0x030 Body             : _QUAD

但是,

0: kd> dq 0xffffe786e04af080
ffffe786`e04af080  00000000`00000003 ffffe786`e04af088
ffffe786`e04af090  ffffe786`e04af088 ffffe786`e04af098
ffffe786`e04af0a0  ffffe786`e04af098 00000000`9e0b9000
ffffe786`e04af0b0  ffffe786`df8ec378 ffffe786`df8ec378
ffffe786`e04af0c0  00000000`00000000 00000000`00000000
ffffe786`e04af0d0  00000000`00200001 00000000`0000000f
ffffe786`e04af0e0  00000000`00000000 00000000`00000000
ffffe786`e04af0f0  00000000`00000000 00000000`00000000

我不知道该地址存储什么,以及

!object
命令如何获取
pop.exe
进程的信息。

然后我使用

!process
命令查看主机进程
LearnHanle.exe

0: kd> !process 0 0 LearnHanle.exe
PROCESS ffffe786e04020c0
    SessionId: 1  Cid: 22a8    Peb: 0036b000  ParentCid: 1344
    DirBase: 999c2000  ObjectTable: ffffd70567953400  HandleCount: 121.
    Image: LearnHanle.exe

我看了

LearnHanle.exe
_HANDLE_TABLE。

0: kd> dt _HANDLE_TABLE ffffd70567953400
nt!_HANDLE_TABLE
   +0x000 NextHandleNeedingPool : 0x400
   +0x004 ExtraInfoPages   : 0n0
   +0x008 TableCode        : 0xffffd705`6645a000
   +0x010 QuotaProcess     : 0xffffe786`e04020c0 _EPROCESS
   +0x018 HandleTableList  : _LIST_ENTRY [ 0xffffd705`67953bd8 - 0xffffd705`67133918 ]
   +0x028 UniqueProcessId  : 0x22a8
   +0x02c Flags            : 0
   +0x02c StrictFIFO       : 0y0
   +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) 
0: kd> dt _HANDLE_TABLE_ENTRY
nt!_HANDLE_TABLE_ENTRY
   +0x000 VolatileLowValue : Int8B
   +0x000 LowValue         : Int8B
   +0x000 InfoTable        : Ptr64 _HANDLE_TABLE_ENTRY_INFO
   +0x008 HighValue        : Int8B
   +0x008 NextFreeHandleEntry : Ptr64 _HANDLE_TABLE_ENTRY
   +0x008 LeafHandleValue  : _EXHANDLE
   +0x000 RefCountField    : Int8B
   +0x000 Unlocked         : Pos 0, 1 Bit
   +0x000 RefCnt           : Pos 1, 16 Bits
   +0x000 Attributes       : Pos 17, 3 Bits
   +0x000 ObjectPointerBits : Pos 20, 44 Bits
   +0x008 GrantedAccessBits : Pos 0, 25 Bits
   +0x008 NoRightsUpgrade  : Pos 25, 1 Bit
   +0x008 Spare1           : Pos 26, 6 Bits
   +0x00c Spare2           : Uint4B

我想知道进程句柄表中的句柄表项如何与相应的对象类型关联。

而且我也想知道这两位成员的目的:

struct _HANDLE_TABLE_ENTRY::ObjectPointerBits
struct _OBJECT_HEADER::TypeIndex
struct _KPROCESS::Header
(_DISPATCHER_HEADER)。

windbg wdk windows-kernel
1个回答
0
投票

作为示例,我将从资源管理器进程 (6496) 获取文件句柄 (0x1c8):

1: kd> !handle 0x1c8 3 0n6496

PROCESS ffffe4856647a080
    SessionId: 2  Cid: 1960    Peb: 00238000  ParentCid: 1904
    DirBase: 1409e3002  ObjectTable: ffffd10029c47740  HandleCount: 2981.
    Image: explorer.exe

Handle table at ffffd10029c47740 with 2981 entries in use

01c8: Object: ffffe48565dd7110  GrantedAccess: 00100001 (Inherit) (Audit) Entry: ffffd10029ff9720
Object: ffffe48565dd7110  Type: (ffffe485608f7220) File
    ObjectHeader: ffffe48565dd70e0 (new version)
        HandleCount: 1  PointerCount: 32783
        Directory Object: 00000000  Name: \Windows\en-US\explorer.exe.mui {HarddiskVolume3}

_EPROCESS
的手柄表开始:

0: kd> dt nt!_eprocess ffffe4856647a080 -y ObjectTable
nt!_EPROCESS
   +0x570 ObjectTable : 0xffffd100`29c47740 _HANDLE_TABLE


0: kd> dt nt!_handle_table 0xffffd100`29c47740
nt!_HANDLE_TABLE
   +0x000 NextHandleNeedingPool : 0x3800
   +0x004 ExtraInfoPages   : 0n0
   +0x008 TableCode        : 0xffffd100`29ef4001
   +0x010 QuotaProcess     : 0xffffe485`6647a080 _EPROCESS
   +0x018 HandleTableList  : _LIST_ENTRY [ 0xffffd100`29c47418 - 0xffffd100`29c47d98 ]
   +0x028 UniqueProcessId  : 0x1960
   +0x02c Flags            : 0
   +0x02c StrictFIFO       : 0y0
   +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) 

TableCode
字段指向一个表数组,较低位决定应使用哪个表:

0: kd> dq 0xffffd100`29ef4000
ffffd100`29ef4000  ffffd100`29ff9000 ffffd100`29ef5000
ffffd100`29ef4010  ffffd100`255fd000 ffffd100`29d96000
ffffd100`29ef4020  ffffd100`2a1fd000 ffffd100`2a0f7000
ffffd100`29ef4030  ffffd100`258bc000 ffffd100`25b5a000
ffffd100`29ef4040  ffffd100`25bff000 ffffd100`25cfc000
ffffd100`29ef4050  ffffd100`25b57000 ffffd100`25dfe000
ffffd100`29ef4060  ffffd100`258c6000 ffffd100`2802c000
ffffd100`29ef4070  00000000`00000000 00000000`00000000 

nt!ExpLookupHandleTableEntry
中的代码有助于确定如何使用表数组(第一个参数是RCX中的
_HANDLE_TABLE*
,第二个参数是RDX中的句柄):

PAGE:00000001407427E0 ExpLookupHandleTableEntry proc near     ; CODE XREF: ObDuplicateObject+180↑p
PAGE:00000001407427E0                                         ; ExMapHandleToPointer+11↑p ...
PAGE:00000001407427E0
PAGE:00000001407427E0 ; FUNCTION CHUNK AT PAGE:0000000140895396 SIZE 00000022 BYTES
PAGE:00000001407427E0
PAGE:00000001407427E0                 mov     eax, [rcx+_HANDLE_TABLE.NextHandleNeedingPool]
PAGE:00000001407427E2                 and     rdx, 0FFFFFFFFFFFFFFFCh
PAGE:00000001407427E6                 cmp     rdx, rax
PAGE:00000001407427E9                 jnb     short loc_140742820
PAGE:00000001407427EB                 mov     r8, [rcx+_HANDLE_TABLE.TableCode]
PAGE:00000001407427EF                 mov     eax, r8d
PAGE:00000001407427F2                 and     eax, 3
PAGE:00000001407427F5                 cmp     eax, 1
PAGE:00000001407427F8                 jnz     short loc_140742812
PAGE:00000001407427FA                 mov     rax, rdx
PAGE:00000001407427FD                 shr     rax, 0Ah
PAGE:0000000140742801                 mov     rax, [r8+rax*8-1]
PAGE:0000000140742806
PAGE:0000000140742806 loc_140742806:                          ; CODE XREF: ExpLookupHandleTableEntry+152BD3↓j
PAGE:0000000140742806                 and     edx, 3FFh
PAGE:000000014074280C                 lea     rax, [rax+rdx*4]
PAGE:0000000140742810                 retn
PAGE:0000000140742810 ; ---------------------------------------------------------------------------
PAGE:0000000140742811                 align 2
PAGE:0000000140742812
PAGE:0000000140742812 loc_140742812:                          ; CODE XREF: ExpLookupHandleTableEntry+18↑j
PAGE:0000000140742812                 test    eax, eax
PAGE:0000000140742814                 jnz     loc_140895396
PAGE:000000014074281A                 lea     rax, [r8+rdx*4]
PAGE:000000014074281E                 retn
PAGE:000000014074281E ; ---------------------------------------------------------------------------
PAGE:000000014074281F                 align 20h
PAGE:0000000140742820
PAGE:0000000140742820 loc_140742820:                          ; CODE XREF: ExpLookupHandleTableEntry+9↑j
PAGE:0000000140742820                 xor     eax, eax
PAGE:0000000140742822                 retn
PAGE:0000000140742822 ExpLookupHandleTableEntry endp

在我的例子中,它只是数组中的第一个表,因此句柄条目位于

table_base + (handle * 4)
。尽管每个表条目都是
_HANDLE_TABLE_ENTRY
(大小为 0x10),但每个句柄都是 4 的倍数(因此 0x10 / 4 = 4):

1: kd> ? ffffd100`29ff9000 + (0x1c8 * 4)
Evaluate expression: -51676341889248 = ffffd100`29ff9720

表格条目:

1: kd> dt _handle_table_entry ffffd100`29ff9720
nt!_HANDLE_TABLE_ENTRY
   +0x000 VolatileLowValue : 0n-1980064459403493377
   +0x000 LowValue         : 0n-1980064459403493377
   +0x000 InfoTable        : 0xe48565dd`70e0ffff _HANDLE_TABLE_ENTRY_INFO
   +0x008 HighValue        : 0n1048577
   +0x008 NextFreeHandleEntry : 0x00000000`00100001 _HANDLE_TABLE_ENTRY
   +0x008 LeafHandleValue  : _EXHANDLE
   +0x000 RefCountField    : 0n-1980064459403493377
   +0x000 Unlocked         : 0y1
   +0x000 RefCnt           : 0y0111111111111111 (0x7fff)
   +0x000 Attributes       : 0y000
   +0x000 ObjectPointerBits : 0y11100100100001010110010111011101011100001110 (0xe48565dd70e)
   +0x008 GrantedAccessBits : 0y0000100000000000000000001 (0x100001)
   +0x008 NoRightsUpgrade  : 0y0
   +0x008 Spare1           : 0y000000 (0)
   +0x00c Spare2           : 0

这里至少有两个有趣的东西:

  • GrantedAccessBits
    :这是对象的授予访问掩码(这里有
    0x100001
    ,对于文件对象来说它只是
    SYNCHRONIZE (0x10000) | FILE_READ_DATA (0x1)

  • ObjectPointerBits
    :经过计算后将是指向对象
    _OBJECT_HEADER
    的指针。

根据

ObjectPointerBits
值,您需要执行以下操作来获取对象头地址:
(ObjectPointerBits << 4) | 0xffff000000000000

1: kd> ? (0xe48565dd70e << 4) | 0xffff000000000000
Evaluate expression: -30213385916192 = ffffe485`65dd70e0

1: kd> dt _object_header ffffe485`65dd70e0
nt!_OBJECT_HEADER
   +0x000 PointerCount     : 0n32783
   +0x008 HandleCount      : 0n1
   +0x008 NextToFree       : 0x00000000`00000001 Void
   +0x010 Lock             : _EX_PUSH_LOCK
   +0x018 TypeIndex        : 0x14 ''
   +0x019 TraceFlags       : 0 ''
   +0x019 DbgRefTrace      : 0y0
   +0x019 DbgTracePermanent : 0y0
   +0x01a InfoMask         : 0x4c 'L'
   +0x01b Flags            : 0 ''
   +0x01b NewObject        : 0y0
   +0x01b KernelObject     : 0y0
   +0x01b KernelOnlyAccess : 0y0
   +0x01b ExclusiveObject  : 0y0
   +0x01b PermanentObject  : 0y0
   +0x01b DefaultSecurityQuota : 0y0
   +0x01b SingleHandleEntry : 0y0
   +0x01b DeletedInline    : 0y0
   +0x01c Reserved         : 0
   +0x020 ObjectCreateInfo : 0xffffe485`62c5ecc0 _OBJECT_CREATE_INFORMATION
   +0x020 QuotaBlockCharged : 0xffffe485`62c5ecc0 Void
   +0x028 SecurityDescriptor : (null) 
   +0x030 Body             : _QUAD

从对象头中,您可以通过执行以下计算来获取对象类型:

  • *((BYTE*)nt!ObHeaderCookie) ^ second_byte_of_object_header_address ^ _OBJECT_HEADER.TypeIndex
1: kd> db nt!ObHeaderCookie L1
fffff800`7911ed74  4c      

1: kd> ? (ffffe485`65dd70e0 >> 8) & 0xff
Evaluate expression: 112 = 00000000`00000070

1: kd> dt _object_header ffffe485`65dd70e0 -y TypeIndex
nt!_OBJECT_HEADER
   +0x018 TypeIndex : 0x14 ''

1: kd> ? 0x4c ^ 0x70 ^ 0x14
Evaluate expression: 40 = 00000000`00000028

上面的结果(在本例中为 0x28)是内核类型数组的索引,该数组是一个名为

nt!ObTypeIndexTable
的全局变量(
_OBJECT_TYPE
的数组):

1: kd> dt _OBJECT_TYPE poi(nt!ObTypeIndexTable + (0x28 * 8))
nt!_OBJECT_TYPE
   +0x000 TypeList         : _LIST_ENTRY [ 0xffffe485`608f7220 - 0xffffe485`608f7220 ]
   +0x010 Name             : _UNICODE_STRING "File"
   +0x020 DefaultObject    : 0x00000000`0000009b Void
   +0x028 Index            : 0x28 '('
   +0x02c TotalNumberOfObjects : 0x27cc
   +0x030 TotalNumberOfHandles : 0xaae
   +0x034 HighWaterNumberOfObjects : 0x2a42
   +0x038 HighWaterNumberOfHandles : 0xd36
   +0x040 TypeInfo         : _OBJECT_TYPE_INITIALIZER
   +0x0b8 TypeLock         : _EX_PUSH_LOCK
   +0x0c0 Key              : 0x656c6946
   +0x0c8 CallbackList     : _LIST_ENTRY [ 0xffffe485`608f72e8 - 0xffffe485`608f72e8 ]

所以它是一个文件对象(由

nt!FILE_OBJECT
表示)。

_DISPATCHER_HEADER

如果一个对象是可等待的(即它的句柄可以传递给

WaitForSingleObject
WaitForMutipleObjects
),那么它有一个
_DISPATCH_HEADER

© www.soinside.com 2019 - 2024. All rights reserved.