hyb1394
驱动牛犊
驱动牛犊
  • 注册日期2004-07-30
  • 最后登录2005-03-14
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:1030回复:4

问个基础的问题:什么是句柄,有什么用处?

楼主#
更多 发布于:2004-07-30 11:43
什么是句柄,有什么用处?
snowStart
驱动老牛
驱动老牛
  • 注册日期2004-04-06
  • 最后登录2011-06-02
  • 粉丝0
  • 关注0
  • 积分95分
  • 威望19点
  • 贡献值177点
  • 好评度1点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2004-07-30 12:48
句柄简单讲其实就是指针,用来标识对象
学习,关注,交流中... [email=fengyu@163.com]Email:snowstarth@163.com[/email] [url]http://bbs.zndev.com/?a=snowStart[/url]
escape
驱动老牛
驱动老牛
  • 注册日期2002-02-01
  • 最后登录2004-08-20
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2004-07-30 15:49
而且这个指针指向了内核的一段数据。你
在应用层是不可以去读写这段内存的。
wcq98
驱动牛犊
驱动牛犊
  • 注册日期2004-07-30
  • 最后登录2008-05-08
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地板#
发布于:2004-07-30 17:49
每个程序都有一个独立的运行空间0-ffffffff,句柄(handle)就是它在这个空间中的起始位置(绝大多数都是0x400000),在本进程中,每个被打开的win32物件(模糊的概念,来不及细说)都有一个句柄。可以推断,不同的进程会有相同的句柄。就是说,句柄只在本进程的虚拟空间中才有用。

还有一个与其易混淆的概念,就是processID,它是全局的,是系统用来标志不同的进程的,所以每个process都有一个唯一的ID,它是怎么来的呢?这是一个微软尚未公开的秘密。据我的跟踪调查,它是一个指针异或一个每次启动机器都会不同的随机数而得来(这个数保存在KERNEL32堆里的一个固定的地址)。而这个指针,指向的是本进程的process database(PDB) ,这些PDB是全局的。微软为什么不把PDB的地址直接拿来当作processID呢?这大概是微软不想让一般的程序员对系统作出“越轨”的行为吧。
初来乍到,请多关照!
lovedrvdev
驱动牛犊
驱动牛犊
  • 注册日期2004-07-11
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分4分
  • 威望42点
  • 贡献值0点
  • 好评度9点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2004-07-30 17:58
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 。

 

游客

返回顶部