JIURL玩玩Win2k进程线程篇 HANDLE_TABLE
作者: JIURL
日期: 2003-7-30
Win2k Build 2195 中 EPROCESS 偏移+128 处的 struct HANDLE_TABLE *ObjectTable ,就是指向该进程 HANDLE_TABLE 结构的指针。通过一个进程的 HANDLE_TABLE 结构,我们可以找到这个进程打开的所有对象。我们在程序中获得的各种句柄,就是对象在句柄表中的索引。例如,在程序中打开文件,获得的是一个句柄(HANDLE)。接下来通过这个句柄来对这个文件进行操作。句柄是该文件对象在句柄表中的索引,通过句柄,就可以在句柄表中找到相应的文件对象的指针。就可以对该文件对象进行相应的操作。
通过 EPROCESS 的 +128 struct HANDLE_TABLE *ObjectTable 我们可以找到一个进程的 HANDLE_TABLE 结构,通过 HANDLE_TABLE 结构的 +08 struct _HANDLE_TABLE_ENTRY ***Table 我们可以找到这个进程的句柄表。这个表中放着进程的所有对象的指针。句柄表分三层,最上层表是一个大小为1KB的数组,共有256个元素,每个元素4个字节长,每个元素是一个指向中层表的指针。中层表也是一个大小为1KB的数组,共有256个元素,每个元素4个字节长,每个元素是一个指向下层表的指针。下层表是一个 HANDLE_TABLE_ENTRY 数组,整个数组大小为2KB,共有256个元素,每个元素8个字节长,是一个 HANDLE_TABLE_ENTRY ,HANDLE_TABLE_ENTRY 中保存着指向对象的指针。一个进程有一个上层表,一个上层表最多可以有256个中层表。每个中层表最多可以有256个下层表。每个下层表最多可以有256个对象的指针。
一个句柄被分为三部分,分别做这三个表中的索引,最低10bit(bits0-9)的值乘以2,就得到了在下层表中的偏移。bits10-17这8bit,为中层表的索引,乘以4得到在中层表中的偏移。bits18-25这8bit,为高层表的索引,乘以4得到在高层表中的偏移。
对于一个句柄,我们最后可以在一个下层表中找到对应的 HANDLE_TABLE_ENTRY。HANDLE_TABLE_ENTRY 大小为 8 个字节,由2个32bit组成。如果第一个32bit值不为0,那么第一个32bit就可以转换成一个指向对象头的指针。由于对象头总是32bit对齐的,所以一个对象头的指针的低3bit总是0。所以 HANDLE_TABLE_ENTRY 第一个32bit 的低3bit,被用作标志。由于所有的对象都在系统地址空间(0x80000000-0xFFFFFFFF)中,所以一个对象头的指针的最高位总是1。所以 HANDLE_TABLE_ENTRY 第一个32bit 的最高位也被用作标志。当我们把一个
HANDLE_TABLE_ENTRY 第一个32bit 转换成对象头的指针时,需要把低3bit设为0,最高位设为1。对象指针总是指的对象体的指针,由于对象头在对象体之前,大小为0x18字节,所以对象指针等于对象头指针加0x18。
HANDLE_TABLE 结构在 Win2k Build 2195 中定义如下
kd> !strct HANDLE_TABLE
!strct HANDLE_TABLE
struct _HANDLE_TABLE (sizeof=108)
+00 uint32 Flags
+04 int32 HandleCount
+08 struct _HANDLE_TABLE_ENTRY ***Table
+0c struct _EPROCESS *QuotaProcess
+10 void *UniqueProcessId
+14 int32 FirstFreeTableEntry
+18 int32 NextIndexNeedingPool
+1c struct _ERESOURCE HandleTableLock
+1c struct _LIST_ENTRY SystemResourcesList
+1c struct _LIST_ENTRY *Flink
+20 struct _LIST_ENTRY *Blink
+24 struct _OWNER_ENTRY *OwnerTable
+28 int16 ActiveCount
+2a uint16 Flag
+2c struct _KSEMAPHORE *SharedWaiters
+30 struct _KEVENT *ExclusiveWaiters
+34 struct _OWNER_ENTRY OwnerThreads[2]
uint32 OwnerThread
int32 OwnerCount
uint32 TableSize
+44 uint32 ContentionCount
+48 uint16 NumberOfSharedWaiters
+4a uint16 NumberOfExclusiveWaiters
+4c void *Address
+4c uint32 CreatorBackTraceIndex
+50 uint32 SpinLock
+54 struct _LIST_ENTRY HandleTableList
+54 struct _LIST_ENTRY *Flink
+58 struct _LIST_ENTRY *Blink
+5c struct _KEVENT HandleContentionEvent
+5c struct _DISPATCHER_HEADER Header
+5c byte Type
+5d byte Absolute
+5e byte Size
+5f byte Inserted
+60 int32 SignalState
+64 struct _LIST_ENTRY WaitListHead
+64 struct _LIST_ENTRY *Flink
+68 struct _LIST_ENTRY *Blink
kd> !strct HANDLE_TABLE_ENTRY
!strct HANDLE_TABLE_ENTRY
struct _HANDLE_TABLE_ENTRY (sizeof=8)
+0 void *Object
+0 uint32 ObAttributes
+4 uint32 GrantedAccess
+4 uint16 GrantedAccessIndex
+6 uint16 CreatorBackTraceIndex
+4 int32 NextFreeTableEntry
下面我们使用 kd 来进行说明
kd> !process 0 0
!process 0 0
**** NT ACTIVE PROCESS DUMP ****
...
PROCESS 82592ae0 SessionId: 0 Cid: 0254 Peb: 7ffdf000 ParentCid: 0240
DirBase: 02611000 ObjectTable: 824e08e8 TableSize: 31.
Image: internat.exe
...
// 我们就以进程 internat.exe 为例,注意 ObjectTable: 824e08e8 TableSize: 31
// 使用 !handle 命令,查看 PID为254 的进程的句柄表中的对象
kd> !handle 0 3 254
!handle 0 3 254
processor number 0
Searching for Process with Cid == 254
PROCESS 82592ae0 SessionId: 0 Cid: 0254 Peb: 7ffdf000 ParentCid: 0240
DirBase: 02611000 ObjectTable: 824e08e8 TableSize: 31.
Image: internat.exe
Handle Table at e3073000 with 31 Entries in use
0004: Object: e13d7c10 GrantedAccess: 000f001f
Object: e13d7c10 Type: (8141b760) Section
ObjectHeader: e13d7bf8
HandleCount: 1 PointerCount: 1
0008: Object: 8236a400 GrantedAccess: 00100003
Object: 8236a400 Type: (8141e460) Event
ObjectHeader: 8236a3e8
HandleCount: 1 PointerCount: 1
...
0044: Object: e139af20 GrantedAccess: 000f003f
Object: e139af20 Type: (8141b0c0) Key
ObjectHeader: e139af08
HandleCount: 1 PointerCount: 1
Directory Object: 00000000 Name: \REGISTRY\MACHINE
\\ 进程句柄为 0044 的对象,下面我们将自己通过句柄表找到句柄为44的对象
\\ 记住对象的名字 Name: \REGISTRY\MACHINE
...
00ac: Object: e3065800 GrantedAccess: 00020019
Object: e3065800 Type: (8141b0c0) Key
ObjectHeader: e30657e8
HandleCount: 1 PointerCount: 1
Directory Object: 00000000 Name: \REGISTRY\MACHINE\SYSTEM\ControlSet001
\Control\Nls\Language Groups
\\ 首先从进程的 EPROCESS 结构中获得 HANDLE_TABLE 结构的地址
kd> !strct eprocess 82592ae0
!strct eprocess 82592ae0
struct _EPROCESS (sizeof=648)
...
+128 struct _HANDLE_TABLE *ObjectTable = 824E08E8
...
\\ 从 HANDLE_TABLE 结构中的 +08 struct _HANDLE_TABLE_ENTRY ***Table 找到句柄表
kd> !strct handle_table 824E08E8
!strct handle_table 824E08E8
struct _HANDLE_TABLE (sizeof=108)
+00 uint32 Flags = 00000000
+04 int32 HandleCount = 0000001f
+08 struct _HANDLE_TABLE_ENTRY ***Table = E3073000
+0c struct _EPROCESS *QuotaProcess = 82592AE0
+10 void *UniqueProcessId = 00000254
+14 int32 FirstFreeTableEntry = 00000021
+18 int32 NextIndexNeedingPool = 00000100
...
+54 struct _LIST_ENTRY HandleTableList
+54 struct _LIST_ENTRY *Flink = 835CC9DC
+58 struct _LIST_ENTRY *Blink = 8105449C
+5c struct _KEVENT HandleContentionEvent
...
+68 struct _LIST_ENTRY *Blink = 824E094C
句柄表的上层表地址为 E3073000,现在我们开始寻找句柄为 0x44 对应的对象
// 句柄 0x44,的上层索引,bits18-25的值为0,偏移为0*4。
// 对应的中层表的地址为 e3073400
kd> dd E3073000+0*4 l 4
dd E3073000+0*4 l 4
e3073000 e3073400 00000000 00000000 00000000
// 句柄 0x44,的中层索引,bits10-17的值为0,偏移为0*4。
// 对应的下层表的地址为 e3073800
kd> dd e3073400+0*4 l 4
dd e3073400+0*4 l 4
e3073400 e3073800 00000000 00000000 00000000
// 句柄 0x44,bits0-9的值为0x44, HANDLE_TABLE_ENTRY 在下层表中的偏移为 0x44*2
kd> dd e3073800+44*2 l 8
dd e3073800+44*2 l 8
e3073888 6139af08 000f003f 62beecc8 000f003f
e3073898 010e86b8 0002000f 010c9cf8 001f0003
我们找到了句柄 0x44 对应的 HANDLE_TABLE_ENTRY,它的第一个32bit,值为 6139af08 ,不空。
我们把它转换为对象指针。
// 转换成对象头的指针,把低3bit设为0,最高位设为1。
// 由于 6139af08 低三位为0,所以不用设置。最高位不为1,通过加 80000000 ,来设置成1。
kd> ? 80000000+6139af08
? 80000000+6139af08
Evaluate expression: -516313336 = e139af08
// 对象指针是对象体的指针,等于对象头指针加0x18
kd> ? e139af08+18
? e139af08+18
Evaluate expression: -516313312 = e139af20
得到了对象指针 e139af20
// 使用 !object 命令,来分析对象。
kd> !object e139af20
!object e139af20
Object: e139af20 Type: (8141b0c0) Key
ObjectHeader: e139af08
HandleCount: 1 PointerCount: 1
Directory Object: 00000000 Name: \REGISTRY\MACHINE
可以看到这个对象就是前面使用 !handle 命令时,看到的那个对象。
通过句柄 0x44 我们找到了相应的对象。
句柄表所消耗的内存
当进程打开的对象不超过大约256个时,系统只为句柄表分配一个上层表,大小为1KB。一个中层表,大小为1KB。一个下层表,大小为2KB。正好可以放在同一个物理页中。当进程打开的对象超过大约256个时,系统会再分配2个下层表,放在同一个物理页,并把这2个下层表的地址,填入中层表的相应项,这样就可以存放大约256*3=768 个对象的对象头指针。绝大多数情况下,这就够用了。
所以绝大多数情况下,进程的句柄表消耗的物理内存为4K(打开的对象不超过大约256个时)或者8K(打开的对象不超过大约768个时)。
下面我们来看一下刚才进程 internat.exe 的句柄表的情况
上层表地址为 e3073000,上层表第一项对应的中层表地址为 e3073400,
上层表第一项对应的中层表的第一项对应的下层表地址为 e3073800
正是在同一页上,我们显示这一页中的全部内容
kd> dd e3073000 l 400
dd e3073000 l 400
e3073000 e3073400 00000000 00000000 00000000
e3073010 00000000 00000000 00000000 00000000
...
e30733f0 00000000 00000000 00000000 00000000
e3073400 e3073800 00000000 00000000 00000000
e3073410 00000000 00000000 00000000 00000000
...
e30737e0 00000000 00000000 00000000 00000000
e30737f0 00000000 00000000 00000000 00000000
e3073800 00000000 00000001 613d7bf8 000f001f
e3073810 0236a3e8 00100003 01092948 00100003
e3073820 02244748 00100003 010f5f18 00000003
e3073830 0132a7b2 00100020 010f6878 000f000f
e3073840 021fb2a8 00100003 613b3e19 001f0001
e3073850 010e84c8 00000001 61390498 000f001f
e3073860 0108a529 001f0003 010c9220 000f037f
e3073870 010c3dc0 000f01ff 010c9220 000f037f
e3073880 02469968 00100003 6139af08 000f003f
e3073890 62beecc8 000f003f 010e86b8 0002000f
e30738a0 010c9cf8 001f0003 02469d28 001f0003
e30738b0 02469ce8 001f0001 02469ca8 001f0003
e30738c0 02469c68 001f0001 61371d88 000f003f
e30738d0 6139a508 000f003f 63418e08 000f003f
e30738e0 00000000 0000002c 613d20c8 000f0007
e30738f0 00000000 0000001c 00000000 00000020
e3073900 00000000 00000023 00000000 00000022
e3073910 00000000 00000025 00000000 00000024
e3073920 00000000 0000001e 00000000 00000026
e3073930 00000000 00000027 00000000 00000028
e3073940 00000000 0000001f 613c75c8 00020019
e3073950 61325c28 00020019 630657e8 00020019
e3073960 00000000 0000002d 00000000 0000002e
...
e3073fe0 00000000 000000fd 00000000 000000fe
e3073ff0 00000000 000000ff 00000000 ffffffff
HANDLE_TABLE 链
在 Win2k Build 2195 中,所有进程(包括 Idle 进程 )的 HANDLE_TABLE 结构通过 HANDLE_TABLE 结构偏移 +54 处的 LIST_ENTRY HandleTableList 链在一起。
+54 struct _LIST_ENTRY HandleTableList
+54 struct _LIST_ENTRY *Flink
+58 struct _LIST_ENTRY *Blink
通过全局变量 HandleTableListHead 可以找到这个链。
对于 Win2k Build 2195 ,HandleTableListHead 地址为 8046a140,该地址开始处为一个 LIST_ENTRY 结构。
Win2k 中还有一个特殊的 HANDLE_TABLE ,可以叫做 KernelHandleTable 。它不属于任何进程,也通过 HANDLE_TABLE 结构偏移 +54 处的 LIST_ENTRY HandleTableList 链在 HANDLE_TABLE 链上。可以通过全局变量 ObpKernelHandleTable 找到它。对于 Win2k Build 2195 ,ObpKernelHandleTable 地址为 8046a694 ,是一个 HANDLE_TABLE 结构的指针。
进程线程 HANDLE_TABLE
Win2k 中还有一个特殊的 HANDLE_TABLE,可以叫做 PspCidTable 。这个 HANDLE_TABLE 的句柄表中,保存着所有进程和线程对象的指针。PID(进程ID)和 ThreadID(线程ID)就是在这个句柄表中的索引。这个 HANDLE_TABLE 不属于任何进程,也没有链在 HANDLE_TABLE 链上。全局变量 PspCidTable 中是指向这个 HANDLE_TABLE 的指针。这个 HANDLE_TABLE 还有一点和别的 HANDLE_TABLE 都不同,就是它的 HANDLE_TABLE_ENTRY 中的第一个32bit 放着的是对象体指针(当然需要转换)而不是对象头指针(对象指针就是对象体指针)。
下面我们看实际的例子
// PspCidTable 中是 HANDLE_TABLE 的地址
kd> dd PspCidTable l 1
dd PspCidTable l 1
80469a28 81452228
kd> !strct HANDLE_TABLE 81452228
!strct HANDLE_TABLE 81452228
struct _HANDLE_TABLE (sizeof=108)
+00 uint32 Flags = 00000000
+04 int32 HandleCount = 000000d1
+08 struct _HANDLE_TABLE_ENTRY ***Table = E1004000
+0c struct _EPROCESS *QuotaProcess = 00000000
+10 void *UniqueProcessId = 00000000
+14 int32 FirstFreeTableEntry = 0000008a
+18 int32 NextIndexNeedingPool = 00000100
+1c struct _ERESOURCE HandleTableLock
+1c struct _LIST_ENTRY SystemResourcesList
+1c struct _LIST_ENTRY *Flink = 80480020
+20 struct _LIST_ENTRY *Blink = 814522E0
+24 struct _OWNER_ENTRY *OwnerTable = 00000000
+28 int16 ActiveCount = 0000
+2a uint16 Flag = 0000
+2c struct _KSEMAPHORE *SharedWaiters = 00000000
+30 struct _KEVENT *ExclusiveWaiters = 00000000
+34 struct _OWNER_ENTRY OwnerThreads[2]
+34 OwnerThreads[0]
+34 uint32 OwnerThread = 00000000
+38 int32 OwnerCount = 00000000
+38 uint32 TableSize = 00000000
+3c OwnerThreads[1]
+3c uint32 OwnerThread = 00000000
+40 int32 OwnerCount = 00000000
+40 uint32 TableSize = 00000000
+44 uint32 ContentionCount = 00000000
+48 uint16 NumberOfSharedWaiters = 0000
+4a uint16 NumberOfExclusiveWaiters = 0000
+4c void *Address = 00000000
+4c uint32 CreatorBackTraceIndex = 00000000
+50 uint32 SpinLock = 00000000
+54 struct _LIST_ENTRY HandleTableList
+54 struct _LIST_ENTRY *Flink = 8145227C
+58 struct _LIST_ENTRY *Blink = 8145227C
+5c struct _KEVENT HandleContentionEvent
+5c struct _DISPATCHER_HEADER Header
+5c byte Type = 00 .
+5d byte Absolute = 00 .
+5e byte Size = 04 .
+5f byte Inserted = 00 .
+60 int32 SignalState = 00000000
+64 struct _LIST_ENTRY WaitListHead
+64 struct _LIST_ENTRY *Flink = 8145228C
+68 struct _LIST_ENTRY *Blink = 8145228C
// 句柄表的上层表地址为 E1004000
// 第0个中层表地址为 e1004400
kd> dd E1004000 l 4
dd E1004000 l 4
e1004000 e1004400 00000000 00000000 00000000
// 第0个中层表的第0个下层表地址为 e1004800
kd> dd E1004400 l 4
dd E1004400 l 4
e1004400 e1004800 00000000 00000000 00000000
// 第0个中层表的第0个下层表的内容
kd> dd E1004800 l 200
dd E1004800 l 200
e1004800 00000000 00000001 0141eda0 00000000
e1004810 0141e020 00000000 0141e7c0 00000000
e1004820 0141e540 00000000 0141d020 00000000
e1004830 0141dda0 00000000 0141db20 00000000
e1004840 0141d8a0 00000000 0141d620 00000000
e1004850 0141d3a0 00000000 0141c020 00000000
e1004860 0141cda0 00000000 0141b4c0 00000000
e1004870 0141b240 00000000 0141a020 00000000
e1004880 0141ada0 00000000 0141a660 00000000
e1004890 0141a3e0 00000000 01411020 00000000
e10048a0 013f7240 00000000 013d1b80 00000000
e10048b0 01421660 00000000 01350c20 00000000
e10048c0 012a7b20 00000000 011017c0 00000000
e10048d0 012a78a0 00000000 012663a0 00000000
e10048e0 0114cda0 00000000 01101540 00000000
e10048f0 011012c0 00000000 010fc020 00000000
e1004900 02000000 00000000 010f7a60 00000000
e1004910 010f7340 00000000 010f7760 00000000
e1004920 010f6c00 00000000 010f6960 00000000
e1004930 010e9860 00000000 010e9b00 00000000
e1004940 010e9520 00000000 010cb020 00000000
e1004950 010e8020 00000000 010ce220 00000000
e1004960 010cc020 00000000 010ccce0 00000000
e1004970 010cc9a0 00000000 010cc660 00000000
e1004980 010ca020 00000000 010c2020 00000000
e1004990 010c2b00 00000000 010c3340 00000000
e10049a0 010c1020 00000000 01089700 00000000
e10049b0 010c19c0 00000000 010c12c0 00000000
e10049c0 02000000 00000000 010bf020 00000000
e10049d0 010bd580 00000000 010bb980 00000000
e10049e0 010bb2c0 00000000 010ba420 00000000
e10049f0 010b9020 00000000 010b9d60 00000000
e1004a00 039beae0 00000000 010b8c00 00000000
e1004a10 01099020 00000000 010ae180 00000000
e1004a20 010ac020 00000000 010acda0 00000000
e1004a30 00000000 000000b5 043c2da0 00000000
e1004a40 01090d80 00000000 010ab420 00000000
e1004a50 03518a80 00000000 02fac920 00000000
e1004a60 010aa020 00000000 010a9d40 00000000
e1004a70 010a8740 00000000 06b02020 00000000
e1004a80 02000000 00000000 00000000 000000b0
e1004a90 010a5da0 00000000 010a4020 00000000
e1004aa0 010a7b20 00000000 010a5b20 00000000
e1004ab0 010a46e0 00000000 010a2d00 00000000
e1004ac0 010a2a80 00000000 04859da0 00000000
e1004ad0 0109f020 00000000 010a3900 00000000
e1004ae0 0109e020 00000000 010a6d20 00000000
e1004af0 0109c360 00000000 03518580 00000000
e1004b00 01099da0 00000000 01097020 00000000
e1004b10 010926c0 00000000 01092940 00000000
e1004b20 03425c20 00000000 010915c0 00000000
e1004b30 0108dc00 00000000 034aa860 00000000
e1004b40 0108a020 00000000 0108cd00 00000000
e1004b50 0108c020 00000000 0108b6c0 00000000
e1004b60 01089020 00000000 0484e020 00000000
e1004b70 047d6480 00000000 07b3f700 00000000
e1004b80 01086020 00000000 05b1b020 00000000
e1004b90 039bed60 00000000 05938cc0 00000000
e1004ba0 01065940 00000000 01063580 00000000
e1004bb0 0105cca0 00000000 0105a980 00000000
e1004bc0 01059580 00000000 0105a320 00000000
e1004bd0 043c2020 00000000 01056280 00000000
e1004be0 047f8560 00000000 0639c1c0 00000000
e1004bf0 03555340 00000000 02151940 00000000
e1004c00 010555a0 00000000 01055820 00000000
e1004c10 0104a700 00000000 01052b80 00000000
e1004c20 05b9b480 00000000 0689f020 00000000
e1004c30 01045a20 00000000 01042c20 00000000
e1004c40 0767d800 00000000 069c3020 00000000
e1004c50 0767d020 00000000 035007e0 00000000
e1004c60 021a2680 00000000 022d6ac0 00000000
e1004c70 01fac020 00000000 01089da0 00000000
e1004c80 022fd020 00000000 022fdda0 00000000
e1004c90 022fd320 00000000 022fd6e0 00000000
e1004ca0 0243bda0 00000000 02000000 00000000
e1004cb0 05938a40 00000000 027e4460 00000000
e1004cc0 0104cb00 00000000 01c15860 00000000
e1004cd0 0786d020 00000000 02b83560 00000000
e1004ce0 02c305e0 00000000 0349e3e0 00000000
e1004cf0 02daf020 00000000 02e0c740 00000000
e1004d00 02def020 00000000 02ded760 00000000
e1004d10 02eb9b20 00000000 02eb98a0 00000000
e1004d20 010a3120 00000000 03309020 00000000
e1004d30 06d00020 00000000 047fb7e0 00000000
e1004d40 010cdaa0 00000000 0323c400 00000000
e1004d50 019a5900 00000000 048217a0 00000000
e1004d60 0489e2e0 00000000 02000000 00000000
e1004d70 038fada0 00000000 01c153c0 00000000
e1004d80 00000000 000000b8 0639cda0 00000000
e1004d90 008bcda0 00000000 07a5d740 00000000
e1004da0 0344c020 00000000 00000000 000000de
e1004db0 02389380 00000000 0108a8e0 00000000
e1004dc0 00000000 000000d0 03375020 00000000
e1004dd0 034aace0 00000000 0767d300 00000000
e1004de0 04029900 00000000 0712fda0 00000000
e1004df0 06a594c0 00000000 01079da0 00000000
e1004e00 035a4d60 00000000 04977340 00000000
e1004e10 0786d600 00000000 009c46c0 00000000
e1004e20 01eefbc0 00000000 03210520 00000000
e1004e30 0788c020 00000000 035c3da0 00000000
e1004e40 02000000 00000000 06b8db60 00000000
e1004e50 0492dc80 00000000 063eada0 00000000
e1004e60 00000000 000000da 035a43e0 00000000
e1004e70 034e0020 00000000 019a5020 00000000
e1004e80 00000000 000000cc 02eb9620 00000000
e1004e90 034e03a0 00000000 04fdf4a0 00000000
e1004ea0 0349f980 00000000 04a4ec20 00000000
e1004eb0 00000000 000000e0 049e9020 00000000
e1004ec0 00000000 000000d6 01055020 00000000
e1004ed0 00000000 00000046 04029b80 00000000
e1004ee0 00000000 000000df 00000000 000000dc
e1004ef0 00000000 000000d8 00000000 000000e1
e1004f00 00000000 000000dd 00000000 000000e2
e1004f10 00000000 000000e3 00000000 000000e4
e1004f20 00000000 000000e5 00000000 000000e6
e1004f30 00000000 000000e7 00000000 000000e8
e1004f40 00000000 000000e9 00000000 000000ea
e1004f50 00000000 000000eb 00000000 000000ec
e1004f60 00000000 000000ed 00000000 000000ee
e1004f70 00000000 000000ef 00000000 000000f0
e1004f80 00000000 000000f1 00000000 000000f2
e1004f90 00000000 000000f3 00000000 000000f4
e1004fa0 00000000 000000f5 00000000 000000f6
e1004fb0 00000000 000000f7 00000000 000000f8
e1004fc0 00000000 000000f9 00000000 000000fa
e1004fd0 00000000 000000fb 00000000 000000fc
e1004fe0 00000000 000000fd 00000000 000000fe
e1004ff0 00000000 000000ff 00000000 ffffffff
// PID为0x8的进程是System进程
kd> !process 8 0
!process 8 0
Searching for Process with Cid == 8
PROCESS 8141e020 SessionId: 0 Cid: 0008 Peb: 00000000 ParentCid: 0000
DirBase: 00030000 ObjectTable: 81452a68 TableSize: 108.
Image: System
下面我们要找 0x8 对应的对象
// PID为0x8。0x8对应的上层表索引为0,中层表索引为0
// 下层表中的偏移为 0x8*2。所以0x8对应的 HANDLE_TABLE_ENTRY 地址为 e1004800+8*2。
kd> dd e1004800+8*2 l 2
dd e1004800+8*2 l 2
e1004810 0141e020 00000000
// HANDLE_TABLE_ENTRY 中第一个32bit不空。
// 把 HANDLE_TABLE_ENTRY 第一个32bit转换成对象指针。
// 低3bit本身是0,把最高位设为1。
kd> ? 0141e020+80000000
? 0141e020+80000000
Evaluate expression: -2126389216 = 8141e020
// 注意这里转换得到的直接是对象指针(对象体指针)。
// 用 !object 命令获得这个对象的信息
kd> !object 8141e020
!object 8141e020
Object: 8141e020 Type: (814524e0) Process
ObjectHeader: 8141e008
HandleCount: 2 PointerCount: 36
// 是进程类型的对象,我们可以用 !process 命令获得这个进程的信息
kd> !process 8141e020 0
!process 8141e020 0
PROCESS 8141e020 SessionId: 0 Cid: 0008 Peb: 00000000 ParentCid: 0000
DirBase: 00030000 ObjectTable: 81452a68 TableSize: 108.
Image: System
进程信息显示是 PID 为 8 的 System 进程。
我们通过PID在 PspCidTable 中,找到了该PID的进程对象。
我们可以算出地址 e1004808 处的 HANDLE_TABLE_ENTRY 对应的句柄值为 0x4。
我们看看 e1004808 处的 HANDLE_TABLE_ENTRY 找到的对象的句柄值(PID 或者 ThreadID)是否为0x4。
// 转换成对象指针
kd> ? 0141eda0+80000000
? 0141eda0+80000000
Evaluate expression: -2126385760 = 8141eda0
// 用 !object 命令分析
kd> !object 8141eda0
!object 8141eda0
Object: 8141eda0 Type: (814523e0) Thread
ObjectHeader: 8141ed88
HandleCount: 0 PointerCount: 3
// 是一个 Thread 类型对象
// 用 !thread 命令分析
kd> !thread 8141eda0 0
!thread 8141eda0 0
THREAD 8141eda0 Cid 8.4 Teb: 00000000 Win32Thread: 00000000 WAIT
// Cid 8.4 说明 ThreadID 为 0x4 。线程所在进程 PID 为 0x8 。
欢迎交流,欢迎交朋友,