首页
社区
课程
招聘
[原创]_HANDER_TABLE之我见
发表于: 2016-1-8 20:33 4220

[原创]_HANDER_TABLE之我见

2016-1-8 20:33
4220

实验平台:win7 x64
lkd> dt _handle_table
nt!_HANDLE_TABLE
   +0x000 TableCode        : Uint8B
   +0x008 QuotaProcess     : Ptr64 _EPROCESS
   +0x010 UniqueProcessId  : Ptr64 Void
   +0x018 HandleLock       : _EX_PUSH_LOCK
   +0x020 HandleTableList  : _LIST_ENTRY
   +0x030 HandleContentionEvent : _EX_PUSH_LOCK
   +0x038 DebugInfo        : Ptr64 _HANDLE_TRACE_DEBUG_INFO
   +0x040 ExtraInfoPages   : Int4B
   +0x044 Flags            : Uint4B
   +0x044 StrictFIFO       : Pos 0, 1 Bit
   +0x048 FirstFreeHandle  : Uint4B
   +0x050 LastFreeHandleEntry : Ptr64 _HANDLE_TABLE_ENTRY
   +0x058 HandleCount      : Uint4B
   +0x05c NextHandleNeedingPool : Uint4B
   +0x060 HandleCountHighWatermark : Uint4B

成员TableCode是_HANDLE_TABLE_ENTRY数组开始地址 也有可能是一个指向第一个数组的指针
具体看TableCode的最低位,为0则是数组开始地址 为1置0后则是一个指向第一个数组开始地址的指针
我是这么理解的 如果TableCode最低位为1 则说明两件事
1.有多个数组
2.此时TableCode的值不是数组开始地址,而是指向数组开始地址的指针.
那怎么知道有多少个数组呢?
_HANDER_TABLE下的HandleCount说明了一个有多少个句柄 一个数组最多只能保存255个HANDLE_TABLE_ENTRY (一页是4096K ,而一个HANDLE_TABLE_ENTRY的大小是16字节)
如果HandleCount的值<0xff 则一个数组 <0xff*2 则两个数组 以此类推

找一个小于255个句柄的进程实验下:
PROCESS fffffa801058f160
    SessionId: 1  Cid: 11c8    Peb: 7efdf000  ParentCid: 114c
    DirBase: 0aeb4000  ObjectTable: fffff8a01c1ed770  HandleCount: 118.
    Image: NT6LKD.exe

lkd> dt _handle_table fffff8a01c1ed770
ntdll!_HANDLE_TABLE
   +0x000 TableCode        : 0xfffff8a0`25581000
   +0x008 QuotaProcess     : 0xfffffa80`1058f160 _EPROCESS
   +0x010 UniqueProcessId  : 0x00000000`000011c8 Void
   +0x018 HandleLock       : _EX_PUSH_LOCK
   +0x020 HandleTableList  : _LIST_ENTRY [ 0xfffff8a0`2153e4e0 - 0xfffff8a0`16e87710 ]
   +0x030 HandleContentionEvent : _EX_PUSH_LOCK
   +0x038 DebugInfo        : (null)
   +0x040 ExtraInfoPages   : 0n0
   +0x044 Flags            : 0
   +0x044 StrictFIFO       : 0y0
   +0x048 FirstFreeHandle  : 0x1dc
   +0x050 LastFreeHandleEntry : 0xfffff8a0`25581ff0 _HANDLE_TABLE_ENTRY
   +0x058 HandleCount      : 0x76
   +0x05c NextHandleNeedingPool : 0x400
   +0x060 HandleCountHighWatermark : 0x77

HandleCount小于255 说明只有一个数组,那么TableCode的值就是数组开始地址
lkd> dq 0xfffff8a0`25581000
fffff8a0`25581000  00000000`00000000 00000000`fffffffe
fffff8a0`25581010  fffff8a0`17f00911 00000000`00000009
fffff8a0`25581020  fffff8a0`025ecb81 00000000`00000003
fffff8a0`25581030  fffff8a0`03b12d71 00000000`00000003
fffff8a0`25581040  fffffa80`107e6041 00000000`00100020
fffff8a0`25581050  fffff8a0`255499a1 00000000`00000009
fffff8a0`25581060  fffff8a0`03b12d71 00000000`00000003
fffff8a0`25581070  fffffa80`075f6311 00000000`00100020
前16字节是无关的值 忽略
看看fffff8a0`25581010 它是第二个元素 这个第二个元素应该说是句柄 句柄都是4的倍数 第一个元素是无效的 忽略 handle/4*0x10 + 数组开始地址
lkd> dt _handle_table_entry fffff8a0`25581010
ntdll!_HANDLE_TABLE_ENTRY
   +0x000 Object           : 0xfffff8a0`17f00911 Void
   +0x000 ObAttributes     : 0x17f00911
   +0x000 InfoTable        : 0xfffff8a0`17f00911 _HANDLE_TABLE_ENTRY_INFO
   +0x000 Value            : 0xfffff8a0`17f00911
   +0x008 GrantedAccess    : 9
   +0x008 GrantedAccessIndex : 9
   +0x00a CreatorBackTraceIndex : 0
   +0x008 NextFreeTableEntry : 9
只关心Object
这个Object是一个_OBJECT_HEADER 最后三位需要置0 貌似跟继承性有关什么的..
lkd> dt _object_header fffff8a0`17f00910
nt!_OBJECT_HEADER
   +0x000 PointerCount     : 0n1
   +0x008 HandleCount      : 0n1
   +0x008 NextToFree       : 0x00000000`00000001 Void
   +0x010 Lock             : _EX_PUSH_LOCK
   +0x018 TypeIndex        : 0x23 '#'
   +0x019 TraceFlags       : 0 ''
   +0x01a InfoMask         : 0x8 ''
   +0x01b Flags            : 0 ''
   +0x020 ObjectCreateInfo : 0xfffffa80`0dd64600 _OBJECT_CREATE_INFORMATION
   +0x020 QuotaBlockCharged : 0xfffffa80`0dd64600 Void
   +0x028 SecurityDescriptor : (null)
   +0x030 Body             : _QUAD
Type 0x23 那应该是Key对象
lkd> !object fffff8a0`17f00910+0x30
Object: fffff8a017f00940  Type: (fffffa8006a39300) Key
    ObjectHeader: fffff8a017f00910 (new version)
    HandleCount: 1  PointerCount: 1
    Directory Object: 00000000  Name: \REGISTRY\MACHINE\SOFTWARE\MICROSOFT\WINDOWS NT\CURRENTVERSION\IMAGE FILE EXECUTION OPTIONS
没错 这个就是这个进程的第一个句柄 句柄为4 Key对象

_OBJECT_HEADER 后是这个对象的具体数据(身体) 是个KEY对象 那么这个身体就是_CM_KEY_BODY
lkd> dt _CM_KEY_BODY fffff8a0`17f00910+0x30
nt!_CM_KEY_BODY
   +0x000 Type             : 0x6b793032
   +0x008 KeyControlBlock  : 0xfffff8a0`0040c4a8 _CM_KEY_CONTROL_BLOCK
   +0x010 NotifyBlock      : (null)
   +0x018 ProcessID        : 0x00000000`000011c8 Void
   +0x020 KeyBodyList      : _LIST_ENTRY [ 0xfffff8a0`255499f0 - 0xfffff8a0`22d90e00 ]
   +0x030 Flags            : 0y0000000000000000 (0)
   +0x030 HandleTags       : 0y0000000000000000 (0)
   +0x038 KtmTrans         : (null)
   +0x040 KtmUow           : (null)
   +0x048 ContextListHead  : _LIST_ENTRY [ 0xfffff8a0`17f00988 - 0xfffff8a0`17f00988 ]
lkd> dt _CM_KEY_CONTROL_BLOCK 0xfffff8a0`0040c4a8
nt!_CM_KEY_CONTROL_BLOCK
   +0x000 RefCount         : 0x5e
   +0x004 ExtFlags         : 0y0000000000000000 (0)
   +0x004 PrivateAlloc     : 0y1
   +0x004 Delete           : 0y0
   +0x004 HiveUnloaded     : 0y0
   +0x004 Decommissioned   : 0y0
   +0x004 LockTablePresent : 0y0
   +0x004 TotalLevels      : 0y0000000111 (0x7)
   +0x008 DelayedDeref     : 0y0
   +0x008 DelayedClose     : 0y0
   +0x008 Parking          : 0y0
   +0x010 KeyHash          : _CM_KEY_HASH
   +0x010 ConvKey          : 0x984c4bc
   +0x018 NextHash         : (null)
   +0x020 KeyHive          : 0xfffff8a0`02b7d010 _HHIVE
   +0x028 KeyCell          : 0x2d90020
   +0x030 KcbPushlock      : _EX_PUSH_LOCK
   +0x038 Owner            : (null)
   +0x038 SharedCount      : 0n0
   +0x040 SlotHint         : 0
   +0x048 ParentKcb        : 0xfffff8a0`0040cde8 _CM_KEY_CONTROL_BLOCK
   +0x050 NameBlock        : 0xfffff8a0`0a683260 _CM_NAME_CONTROL_BLOCK
   +0x058 CachedSecurity   : 0xfffff8a0`0a667600 _CM_KEY_SECURITY_CACHE
   +0x060 ValueCache       : _CACHED_CHILD_LIST
   +0x070 IndexHint        : 0x00000000`00000012 _CM_INDEX_HINT_BLOCK
   +0x070 HashKey          : 0x12
   +0x070 SubKeyCount      : 0x12
   +0x078 KeyBodyListHead  : _LIST_ENTRY [ 0xfffff8a0`037cc9a0 - 0xfffff8a0`1bbf7550 ]
   +0x078 FreeListEntry    : _LIST_ENTRY [ 0xfffff8a0`037cc9a0 - 0xfffff8a0`1bbf7550 ]
   +0x088 KeyBodyArray     : [4] 0xfffff8a0`0a67a710 _CM_KEY_BODY
   +0x0a8 KcbLastWriteTime : _LARGE_INTEGER 0x01d11893`9eb89f9c
   +0x0b0 KcbMaxNameLen    : 0x48
   +0x0b2 KcbMaxValueNameLen : 0
   +0x0b4 KcbMaxValueDataLen : 0
   +0x0b8 KcbUserFlags     : 0y0001
   +0x0b8 KcbVirtControlFlags : 0y1010
   +0x0b8 KcbDebug         : 0y00000000 (0)
   +0x0b8 Flags            : 0y0000000000100000 (0x20)
   +0x0c0 RealKeyName      : 0xfffff8a0`0380d310  "Image File Execution Options"
   +0x0c8 KCBUoWListHead   : _LIST_ENTRY [ 0xfffff8a0`0040c570 - 0xfffff8a0`0040c570 ]
   +0x0d8 DelayQueueEntry  : _LIST_ENTRY [ 0xfffff8a0`0040c580 - 0xfffff8a0`0040c580 ]
   +0x0d8 Stolen           : 0xfffff8a0`0040c580  "???"
   +0x0e8 TransKCBOwner    : (null)
   +0x0f0 KCBLock          : _CM_INTENT_LOCK
   +0x100 KeyLock          : _CM_INTENT_LOCK
   +0x110 TransValueCache  : _CHILD_LIST
   +0x118 TransValueListOwner : (null)
   +0x120 FullKCBName      : (null)

在_CM_KEY_CONTROL_BLOCK 偏移0x0c0 RealKeyName给出了名字 跟上面的相比,后面是对的 说明正确
   
找一个句柄大于255小于512的实验下:
lkd> dt _HANDLE_TABLE 0xfffff8a0`1742d090
nt!_HANDLE_TABLE
   +0x000 TableCode        : 0xfffff8a0`17ed4001
   +0x008 QuotaProcess     : 0xfffffa80`09ebf4d0 _EPROCESS
   +0x010 UniqueProcessId  : 0x00000000`00000c60 Void
   +0x018 HandleLock       : _EX_PUSH_LOCK
   +0x020 HandleTableList  : _LIST_ENTRY [ 0xfffff8a0`00d06a00 - 0xfffff8a0`1555fa60 ]
   +0x030 HandleContentionEvent : _EX_PUSH_LOCK
   +0x038 DebugInfo        : (null)
   +0x040 ExtraInfoPages   : 0n0
   +0x044 Flags            : 0
   +0x044 StrictFIFO       : 0y0
   +0x048 FirstFreeHandle  : 0x174
   +0x050 LastFreeHandleEntry : 0xfffff8a0`17ed5ff0 _HANDLE_TABLE_ENTRY
   +0x058 HandleCount      : 0x185
   +0x05c NextHandleNeedingPool : 0x800
   +0x060 HandleCountHighWatermark : 0x1a2
HandleCount>255h
此时TableCode最低位为1 置0后指向第一个数组
lkd> dq 0xfffff8a0`17ed4000
fffff8a0`17ed4000  fffff8a0`17d8d000 fffff8a0`17ed5000
fffff8a0`17ed4010  00000000`00000000 00000000`00000000
fffff8a0`17ed4020  00000000`00000000 00000000`00000000
fffff8a0`17ed4030  00000000`00000000 00000000`00000000
fffff8a0`17ed4040  00000000`00000000 00000000`00000000
fffff8a0`17ed4050  00000000`00000000 00000000`00000000
fffff8a0`17ed4060  00000000`00000000 00000000`00000000
fffff8a0`17ed4070  00000000`00000000 00000000`00000000
可以看到有两个数组
看下第一个数组
lkd> dq 0xfffff8a0`17d8d000
fffff8a0`17d8d000  00000000`00000000 00000000`fffffffe
fffff8a0`17d8d010  fffff8a0`16aeff71 00000000`00000009
fffff8a0`17d8d020  fffff8a0`0cc2b961 00000000`00000003
fffff8a0`17d8d030  fffff8a0`05bb4a71 00000000`00000003
fffff8a0`17d8d040  fffffa80`09f45371 00000000`00100020
fffff8a0`17d8d050  fffff8a0`174a26c1 00000000`00000009
fffff8a0`17d8d060  fffff8a0`05bb4a71 00000000`00000003
fffff8a0`17d8d070  fffffa80`09e8bef1 00000000`00100020
看下第二个数组
lkd> dq 0xfffff8a0`17ed5000
fffff8a0`17ed5000  00000000`00000000 00000000`fffffffe
fffff8a0`17ed5010  fffffa80`06f841e1 00000000`00000804
fffff8a0`17ed5020  fffffa80`0746d7f1 00000000`00000804
fffff8a0`17ed5030  fffffa80`0758b4b1 00000000`00000804
fffff8a0`17ed5040  fffffa80`074f0041 00000000`00000804
fffff8a0`17ed5050  fffffa80`06daabe1 00000000`00100003
fffff8a0`17ed5060  fffffa80`09ec5511 00000000`00100003
fffff8a0`17ed5070  fffffa80`06db4601 00000000`001f0003

看下第一个数组的最后一个元素
lkd>
fffff8a0`17d8df80  fffff8a0`17bc66c1 00000000`000f0003
fffff8a0`17d8df90  fffffa80`0e958df1 00000000`00100002
fffff8a0`17d8dfa0  fffffa80`0e889c21 00000000`001f0003
fffff8a0`17d8dfb0  fffffa80`07505031 00000000`001fffff
fffff8a0`17d8dfc0  fffffa80`07505031 00000000`001fffff
fffff8a0`17d8dfd0  fffffa80`09f4cd71 00000000`00100002
fffff8a0`17d8dfe0  fffffa80`09ffae31 00000000`00000804
fffff8a0`17d8dff0  fffffa80`09f92491 00000000`00000804   <-----这个
跟基地址相差ff0 0xff0/0x10=0xff=255h  再加上它本身的16字节为0x1000 刚好是4096K一页的大小

找个>512<768的 没有找到,那就找个<768的吧
PROCESS fffffa800e651b30
    SessionId: 1  Cid: 06e8    Peb: 7fffffda000  ParentCid: 0684
    DirBase: 1e5325000  ObjectTable: fffff8a005f89be0  HandleCount: 835.
    Image: explorer.exe
    lkd> dt _handle_table fffff8a005f89be0
nt!_HANDLE_TABLE
   +0x000 TableCode        : 0xfffff8a0`056dc001
   +0x008 QuotaProcess     : 0xfffffa80`0e651b30 _EPROCESS
   +0x010 UniqueProcessId  : 0x00000000`000006e8 Void
   +0x018 HandleLock       : _EX_PUSH_LOCK
   +0x020 HandleTableList  : _LIST_ENTRY [ 0xfffff8a0`04b8b530 - 0xfffff8a0`05ea03a0 ]
   +0x030 HandleContentionEvent : _EX_PUSH_LOCK
   +0x038 DebugInfo        : (null)
   +0x040 ExtraInfoPages   : 0n0
   +0x044 Flags            : 0
   +0x044 StrictFIFO       : 0y0
   +0x048 FirstFreeHandle  : 0xc24
   +0x050 LastFreeHandleEntry : 0xfffff8a0`08f29ff0 _HANDLE_TABLE_ENTRY
   +0x058 HandleCount      : 0x344
   +0x05c NextHandleNeedingPool : 0x1000
   +0x060 HandleCountHighWatermark : 0x386
835/255 > 3 也就是说有4个数组
lkd> dq 0xfffff8a0`056dc000
fffff8a0`056dc000  fffff8a0`05f7c000 fffff8a0`056e0000
fffff8a0`056dc010  fffff8a0`055d7000 fffff8a0`08f29000
fffff8a0`056dc020  00000000`00000000 00000000`00000000
fffff8a0`056dc030  00000000`00000000 00000000`00000000
fffff8a0`056dc040  00000000`00000000 00000000`00000000
fffff8a0`056dc050  00000000`00000000 00000000`00000000
fffff8a0`056dc060  00000000`00000000 00000000`00000000
fffff8a0`056dc070  00000000`00000000 00000000`00000000
搞好4个地址
至于网上很多说什么TableCode低三位 低两位决定几级表 看不懂 有人还说分级是怕装不下句柄 那好吧 一级就说是TableCode就是数组开始地址 二级说明什么? 三级呢?不过就是想告诉你TableCode不是开始地址了
可能是实验中没出现TableCode低两位为10 才得出此结论
怕装不下句柄 那好办,看看呗 最大的HANDLE_TABLE 莫过于PspCidTable了 查看之后发现低两位也只有1
以实验说话..反正我没看见低两位为10 也就是所谓的三级表 可能是太年轻了,以后遇到看看.
写到这里的时候突然发现好像懂了那些人说的表的分级,二级是指向一级的指针,那三级就是指向一级的指针的指针.
额,实验没发现三级表,我还是先按我自己的理论来理解吧 (TableCode最低位为1 则告诉使用者这个TableCode不是数组开始地址了)


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 3
支持
分享
最新回复 (2)
雪    币: 256
活跃值: (48)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
2
TableCode最低位为1 则告诉使用者这个TableCode不是数组开始地址了 而是保存数组开始地址的数组 这个数组大小由句柄数决定 句柄数/255 取整+1
2016-1-8 20:40
0
雪    币: 99
活跃值: (110)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
支持楼主,分析的很详细
2016-1-8 23:59
0
游客
登录 | 注册 方可回帖
返回
//