对象管理器使用对象头中保存的数据来管理这些对象,而无需关注它们的类型,标准对象头中的属性
1.对象名称:使一个对象对于其他的进程也是可见的,便于共享
2.对象目录:提供了一个层次结构来存储对象名称
3.安全描述符:决定了谁可以使用该对象,以及允许它们如何使用它
4.配额花费:列出当一个进程打开一个指向该对象的句柄时,针对该进程收取的资源花费额
5.已打开的句柄计数:记录了“打开一个句柄来指向该对象”的次数
6.对象类型:指向一个类型对象,该对象包含了针对这种类型的对象都是公共的属性
7.引用计数:记录了一个内核模式组件引用该对象地址的次数
除了对象头以外,每个对象也有一个对象体,并且其格式和内容只有这种对象类型才有。
一个执行体组件通过创建一个对象类型,并且为它提供一些服务,就可以控制和维护所有这些类型的对象体中的数据。
对象管理器提供了少量的通用服务来操作对象头中保存的属性,并且可以用在任何类型对象上,windows子系统允许其中一些服务可以直接被windows应用程序使用。这些通用操作有
1.关闭:关闭一个指向某个对象的句柄
2.复制:通过先复制一个句柄,再将其交给另一个进程的方法来共享一个对象
3.查询对象:获得关于一个对象的标准属性信息
4.查询安全性:获取一个对象的安全描述符
5.设置安全性:改变一个对象上的保护设置
6.等待一个对象:用一个对象来同步一个线程的执行
7.等待多个对象:用多个对象来同步一个线程的执行
每个对象都有自己的创建、打开、查询服务(创建一个进程和创建一个文件需要初始化的数据是不同的)
winobj的ObjectTypes中可以看到对象管理器中声明的类型对象的列表
实验:查看对象头和类型对象
1.使用!process 0 0显示系统进程,例如我们选择其中显示的一项
*** NT ACTIVE PROCESS DUMP ****
PROCESS 821b9830 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000
DirBase: 00b18000 ObjectTable: e1000c98 HandleCount: 257.
Image: System
其中PROCESS就是进程内核对象的地址,System进程的进程内核对象地址为821b9830
2.使用!objcet命令显示进程内核系统对象的信息
lkd> !object 821b9830
Object: 821b9830 Type: (821b9e70) Process
ObjectHeader: 821b9818 (old version)
HandleCount: 2 PointerCount: 66
3.使用dt命令查看对象头和类型对象
lkd> dt _object_header 821b9818
nt!_OBJECT_HEADER
+0x000 PointerCount : 0n66
+0x004 HandleCount : 0n2
+0x004 NextToFree : 0x00000002 Void
+0x008 Type : 0x821b9e70 _OBJECT_TYPE
+0x00c NameInfoOffset : 0 ''
+0x00d HandleInfoOffset : 0 ''
+0x00e QuotaInfoOffset : 0 ''
+0x00f Flags : 0x22 '"'
+0x010 ObjectCreateInfo : 0x8055b200 _OBJECT_CREATE_INFORMATION
+0x010 QuotaBlockCharged : 0x8055b200 Void
+0x014 SecurityDescriptor : 0xe10003b3 Void
+0x018 Body : _QUAD
对象头的起始地址+0x18个字节就是对象体的起始地址(0x821b9818+0x18=0x821b9830)
lkd> dt _object_type 821b9e70
nt!_OBJECT_TYPE
+0x000 Mutex : _ERESOURCE
+0x038 TypeList : _LIST_ENTRY [ 0x821b9ea8 - 0x821b9ea8 ]
+0x040 Name : _UNICODE_STRING "Process"
+0x048 DefaultObject : (null)
+0x04c Index : 5
+0x050 TotalNumberOfObjects : 0x1a
+0x054 TotalNumberOfHandles : 0x6d
+0x058 HighWaterNumberOfObjects : 0x1b
+0x05c HighWaterNumberOfHandles : 0x74
+0x060 TypeInfo : _OBJECT_TYPE_INITIALIZER
+0x0ac Key : 0x636f7250
+0x0b0 ObjectLocks : [4] _ERESOURCE
上面的输出显示出:对象类型结构体包含了对象类型的名称(Name成员),记录了这种类型活动对象的总数,以及这种类型的句柄和对象的尖峰数目。TypeInfo成员保存了一个指针,该指针指向的数据结构保存了对于该对象类型的所有对象都公共的属性,以及一组指向该对象类型的方法的指针
lkd> dt _object_type_initializer 821b9e70+60
nt!_OBJECT_TYPE_INITIALIZER
+0x000 Length : 0x4c
+0x002 UseDefaultObject : 0 ''
+0x003 CaseInsensitive : 0 ''
+0x004 InvalidAttributes : 0xb0
+0x008 GenericMapping : _GENERIC_MAPPING
+0x018 ValidAccessMask : 0x1f0fff
+0x01c SecurityRequired : 0x1 ''
+0x01d MaintainHandleCount : 0 ''
+0x01e MaintainTypeList : 0 ''
+0x020 PoolType : 0 ( NonPagedPool )
+0x024 DefaultPagedPoolCharge : 0x1000
+0x028 DefaultNonPagedPoolCharge : 0x290
+0x02c DumpProcedure : (null)
+0x030 OpenProcedure : (null)
+0x034 CloseProcedure : (null)
+0x038 DeleteProcedure : 0x805c8f00 void nt!PspProcessDelete+0
+0x03c ParseProcedure : (null)
+0x040 SecurityProcedure : 0x805ef42e long nt!SeDefaultObjectMethod+0
+0x044 QueryNameProcedure : (null)
+0x048 OkayToCloseProcedure : (null)
在用户模式下不能操作类型对象,然而它们定义的某些属性可以通过特定的原生服务或者windows api例程是可见的
1.类型名称:此种类型对象的名称(process、event。。。)
2.池类型:指明了这种类型的对象是从换页的还是非换页的内存中分配
3.默认的配额花费:默认从进程配额中扣除的幻夜内存池值和非换页内存池值
4.访问类型:当一个线程打开某个指向该类型对象时可以请求的访问类型(读、写、终止、挂起)
5.通用访问权限的映射关系:在四种通用的访问权限(读、写、执行、全部)和特属于该类型的访问权限之间的映射关系
6.同步:指明了一个线程是否可以等待这种类型的对象
7.方法:在一个对象的生命期的特定点上,对象管理器自动调用的一个或者多个例程
同步是一个对于windows应用程序可见的属性,指的是一个线程通过等待某个对象从一种状态改变成另一种状态,从而达到同步其执行过程的能力。一个线程可以对执行体的作业、进程、线程、文件、事件、信号量、互斥体和定时器对象进行同步。其他的执行体对象不支持同步。一个对象是否有能力支持同步,取决于该对象是否包含了一个内嵌的分发器对象,这也是一种内核对象。
对象方法,是由一组内部例程构成的,这些例程类似于C++的构造函数和析构函数,当一个对象被创建或者销毁时自动被调用。这些方法有
1.Open:对象句柄被打开的时候
2.Close:对象句柄被关闭的时候
3.Delete:对象管理器删除一个对象的时候
4.Query Name:一个线程请求在一个从属名字空间中查询一个对象(比如一个文件对象)的名称时
5.Parse:对象管理器在一个从属名字空间中搜索一个对象名称的时候
6.Security:当一个进程读取或改变一个对象(比如文件对象)在其从属名字空间中的保护属性时