-
-
[原创]_HANDER_TABLE之我见
-
发表于:
2016-1-8 20:33
4221
-
实验平台: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不是数组开始地址了)
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)