对进程句柄表的认识

首先是句柄表结构,在_EPROCESS结构的的Object_Table域(一个指向_HANDLE_TABLE结构的指针),

lkd> DT _HANDLE_TABLE
nt!_HANDLE_TABLE
   +0x000 TableCode        : Uint4B                                //指向句柄表存储结构
   +0x004 QuotaProcess     : Ptr32 _EPROCESS
   +0x008 UniqueProcessId  : Ptr32 Void                            //PID
   +0x00c HandleLock       : _EX_PUSH_LOCK
   +0x010 HandleTableList  : _LIST_ENTRY                           //所有的句柄表形成的一个链表,链表头为全局HandleTableListHead
   +0x018 HandleContentionEvent : _EX_PUSH_LOCK
   +0x01c DebugInfo        : Ptr32 _HANDLE_TRACE_DEBUG_INFO
   +0x020 ExtraInfoPages   : Int4B
   +0x024 Flags            : Uint4B
   +0x024 StrictFIFO       : Pos 0, 1 Bit
   +0x028 FirstFreeHandle  : Uint4B                                 //空闲链表的表头句柄索引
   +0x02c LastFreeHandleEntry : Ptr32 _HANDLE_TABLE_ENTRY
   +0x030 HandleCount      : Uint4B        
   +0x034 NextHandleNeedingPool : Uint4B                            //下一个空闲链表的表头空闲索引
   +0x038 HandleCountHighWatermark : Uint4B
_HANDLE_TABLE的第一个成员TableCode,它是指向句柄表的储存结构


一,查看只有单层句柄表的程序

这里通过自己写的一个Test程序显示CreateFile来打开的句柄值。

通过Windbg查看这个_EPROCESS结构:

lkd> !PROCESS 6B0 0
Searching for Process with Cid == 6b0
Cid handle table at 97801000 with 600 entries in use

PROCESS 86d18030  SessionId: 1  Cid: 06b0    Peb: 7ffdc000  ParentCid: 07c4
    DirBase: be8335a0  ObjectTable: a88abbb8  HandleCount:  37.
    Image: test.exe

可以看到ObjectTable地址为a88abbb8,指向一个_HANDLE_TABLE的结构,再通过windbg查看这个地址的_HANDLE_TABLE

lkd> dt _handle_table a88abbb8
nt!_HANDLE_TABLE
   +0x000 TableCode        : 0xada1c000
   +0x004 QuotaProcess     : 0x86d18030 _EPROCESS
   +0x008 UniqueProcessId  : 0x000006b0 Void
   +0x00c HandleLock       : _EX_PUSH_LOCK
   +0x010 HandleTableList  : _LIST_ENTRY [ 0xada0e180 - 0xa6be53a8 ]
   +0x018 HandleContentionEvent : _EX_PUSH_LOCK
   +0x01c DebugInfo        : (null) 
   +0x020 ExtraInfoPages   : 0n0
   +0x024 Flags            : 0
   +0x024 StrictFIFO       : 0y0
   +0x028 FirstFreeHandle  : 0x64
   +0x02c LastFreeHandleEntry : 0xada1cff8 _HANDLE_TABLE_ENTRY
   +0x030 HandleCount      : 0x25
   +0x034 NextHandleNeedingPool : 0x800
   +0x038 HandleCountHighWatermark : 0x29

可以看到TbaleCode最低两位为0,说明为单层句柄表,那么windbg打印这个0xada1c000地址的值看看

lkd> dd 0xada1c000
ada1c000  00000000 fffffffe 8d4dc029 00000003
ada1c010  86bb7771 00100020 86d86ac9 001f0003
ada1c020  a88b9419 00020019 86cd6a61 001f0001
ada1c030  86da57d1 001f0001 86e03579 001f0001
ada1c040  ada18cc9 000f003f 86dd82e9 001f0003
ada1c050  aa9e0571 00000001 86dc26d9 00000804
ada1c060  86d4e109 021f0003 8847e571 000f037f
ada1c070  884baf61 000f01ff 8847e571 000f037f

TableCode每项8个字节,都是一个_HANDLE_TABLE_ENTRY结构,第一句柄表项表示该页面的审计掩码,从第二项开始就是有效的句柄项了。这里我这个Test程序打开的文件的句柄为0x48,也就是TbaleCode + 0x48 / 4 * 8偏移处(因为句柄表第一项索引为4,第二项为8。。。以此类推,而每一项又是8个字节的_HANDLE_TABLE_ENTRY结构),那么用windbg查看这个句柄表项:

lkd> dt _HANDLE_TABLE_ENTRY ada1c000+0x48/4*8
nt!_HANDLE_TABLE_ENTRY
   +0x000 Object           : 0x86cbcef9 Void
   +0x000 ObAttributes     : 0x86cbcef9
   +0x000 InfoTable        : 0x86cbcef9 _HANDLE_TABLE_ENTRY_INFO
   +0x000 Value            : 0x86cbcef9
   +0x004 GrantedAccess    : 0x120089
   +0x004 GrantedAccessIndex : 0x89
   +0x006 CreatorBackTraceIndex : 0x12
   +0x004 NextFreeTableEntry : 0x120089

这里_HANDLE_TABLE_ENTRY也就是两个union组成,Object指针指向句柄所代表的内核对象,它的最低三位又特殊含义:

第0位OBJ_PROTECT_CLOSE表示调用者能否关闭这个句柄,第一位OBJ_INHERIT表示进程的子进程能否继承这个句柄,就是能否拷贝到子进程的句柄表中,第二位OBJ_AUDIT_OBJECT_CLOSE,指示关闭这个对象是否会产生一个审计对象。这里的Object为 86cbcef9 ,它只有最低位是1,所以要查看这个句柄所指向的对象的话就要将第三位变为0才能表示指向的一个对象,这里就改成 86CBCEF8 ,这个地址就是一个对象地址,用windbg查看

lkd> dt _object_header 86CBCEF8 
nt!_OBJECT_HEADER
   +0x000 PointerCount     : 0n1
   +0x004 HandleCount      : 0n1
   +0x004 NextToFree       : 0x00000001 Void
   +0x008 Lock             : _EX_PUSH_LOCK
   +0x00c TypeIndex        : 0x1c ''
   +0x00d TraceFlags       : 0 ''
   +0x00e InfoMask         : 0xc ''
   +0x00f Flags            : 0x40 '@'
   +0x010 ObjectCreateInfo : 0x887c7640 _OBJECT_CREATE_INFORMATION
   +0x010 QuotaBlockCharged : 0x887c7640 Void
   +0x014 SecurityDescriptor : (null) 
   +0x018 Body             : _QUAD

看到TypeIndex为0x1c,对应着看下在ObTypeIndexTable这个全局对象类型表中的0x1c项,

lkd> dt _object_type poi(ObTypeIndexTable+0x1C*4)  
nt!_OBJECT_TYPE
   +0x000 TypeList         : _LIST_ENTRY [ 0x86813c58 - 0x86813c58 ]
   +0x008 Name             : _UNICODE_STRING "File"
   +0x010 DefaultObject    : 0x0000005c Void
   +0x014 Index            : 0x1c ''
   +0x018 TotalNumberOfObjects : 0x1773
   +0x01c TotalNumberOfHandles : 0x3e1
   +0x020 HighWaterNumberOfObjects : 0x1ee6
   +0x024 HighWaterNumberOfHandles : 0x4f1
   +0x028 TypeInfo         : _OBJECT_TYPE_INITIALIZER
   +0x078 TypeLock         : _EX_PUSH_LOCK
   +0x07c Key              : 0x656c6946
   +0x080 CallbackList     : _LIST_ENTRY [ 0x86813cd8 - 0x86813cd8 ]

可以看到正是对应着File对象,我们再看下打开的对象路径名等信息。

lkd> !object 86CBCEF8+0x18
Object: 86cbcf10  Type: (86813c58) File
    ObjectHeader: 86cbcef8 (new version)
    HandleCount: 1  PointerCount: 1
    Directory Object: 00000000  Name: \Users\Administrator\Desktop\TestHook.vmp.exe {HarddiskVolume1}

OK,Right!

二,查看查有高层句柄表的程序

这里就查看system(PID = 4)进程,

lkd> !process 4 0
Searching for Process with Cid == 4
Cid handle table at 97801000 with 639 entries in use

PROCESS 867d48a8  SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 00185000  ObjectTable: 8d401b28  HandleCount: 502.
    Image: System
lkd> dt _handle_table 8d401b28  
ntdll!_HANDLE_TABLE
   +0x000 TableCode        : 0xa5f0b001
   +0x004 QuotaProcess     : (null) 
   +0x008 UniqueProcessId  : 0x00000004 Void
   +0x00c HandleLock       : _EX_PUSH_LOCK
   +0x010 HandleTableList  : _LIST_ENTRY [ 0x8fa40418 - 0x8413f768 ]
   +0x018 HandleContentionEvent : _EX_PUSH_LOCK
   +0x01c DebugInfo        : (null) 
   +0x020 ExtraInfoPages   : 0n0
   +0x024 Flags            : 0
   +0x024 StrictFIFO       : 0y0
   +0x028 FirstFreeHandle  : 0x9a4
   +0x02c LastFreeHandleEntry : 0xa5f08ff8 _HANDLE_TABLE_ENTRY
   +0x030 HandleCount      : 0x1f5
   +0x034 NextHandleNeedingPool : 0x1000
   +0x038 HandleCountHighWatermark : 0x282

这里TableCode是0xa5f0b001,低两位为1,说明有两层,我们查看TableCode时候就应该查看0xa5f0b000

lkd> dd a5f0b000
a5f0b000  8d403000 a5f08000 00000000 00000000
a5f0b010  00000000 00000000 00000000 00000000
a5f0b020  00000000 00000000 00000000 00000000
a5f0b030  00000000 00000000 00000000 00000000
a5f0b040  00000000 00000000 00000000 00000000
a5f0b050  00000000 00000000 00000000 00000000
a5f0b060  00000000 00000000 00000000 00000000
a5f0b070  00000000 00000000 00000000 00000000

开头的两个即是两个低层句柄表的地址,这就和之前查看的方法一样了。每一个低层句柄表项是512个,除去第一个还有511个

我们这里查看一个0x68索引的句柄。

lkd> dt _handle_table_entry 8d403000 + 0x68/4*8
ntdll!_HANDLE_TABLE_ENTRY
   +0x000 Object           : 0x867f6ea1 Void
   +0x000 ObAttributes     : 0x867f6ea1
   +0x000 InfoTable        : 0x867f6ea1 _HANDLE_TABLE_ENTRY_INFO
   +0x000 Value            : 0x867f6ea1
   +0x004 GrantedAccess    : 0x2020003
   +0x004 GrantedAccessIndex : 3
   +0x006 CreatorBackTraceIndex : 0x202
   +0x004 NextFreeTableEntry : 0x2020003
这里Object为867F6EA1,让第三位为0,则为867F6EA0,查看一下信息
lkd> dt _object_header 867F6EA0
nt!_OBJECT_HEADER
   +0x000 PointerCount     : 0n1
   +0x004 HandleCount      : 0n1
   +0x004 NextToFree       : 0x00000001 Void
   +0x008 Lock             : _EX_PUSH_LOCK
   +0x00c TypeIndex        : 0x1c ''
   +0x00d TraceFlags       : 0 ''
   +0x00e InfoMask         : 0xc ''
   +0x00f Flags            : 0x42 'B'
   +0x010 ObjectCreateInfo : 0x00000001 _OBJECT_CREATE_INFORMATION
   +0x010 QuotaBlockCharged : 0x00000001 Void
   +0x014 SecurityDescriptor : (null) 
   +0x018 Body             : _QUAD

同样也是0x1c,也就是File类型对象,再看看其他信息是否一样。

lkd> !object 867F6EA0+0x18
Object: 867f6eb8  Type: (86813c58) File
    ObjectHeader: 867f6ea0 (new version)
    HandleCount: 1  PointerCount: 1
    Directory Object: 00000000  Name: \Boot\BCD {HarddiskVolume1}
OK Right!





阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页