windows内核开发学习笔记四十一:内核对象管理机理

        对象管理器是执行体中的组件,主要管理执行体对象。在执行体对象也可能封装了一个或多个内核对象。对象管理器的基本功能是:

  • 为执行体的数据结构提供一种统一并且可扩展的定义和控制机制。
  • 提供统一的安全访问机制,保证系统的安全。
  • 在无须修改已有系统代码的情况下,加入新的对象类型。
  • 提供一组标准的API来对对象执行各种操作。
  • 提供一种命名机制,与文件系统的命名机制集成在一起。

每个对象都由两部分构成:对象头和对象体,所有对象都具有统一的格式,头格式如下:

typedef struct _OBJECT_HEADER{

       LONG_PTR PointerCount;                             //引用计数

        union{

             LONG_PTR  HandleCount;                   //指向该对象的句柄数

             PVOID  NextToFree;                          //对象被延迟删除时加入到一条链中

        };

        POBJECT_TYPE Type;                            //指向对象的类型信息

        UCHAR NameInfoOffset;                       //名称信息的内存偏移

        UCHAR HandleInfoOffset;                       //句柄信息的内存偏移

        UCHAR  QuotaInfoOffset;                    //配额信息的内存偏移

        UCHAR Flags;

        union {

                POBJECT_CREATE_INFOMATION ObjectCreateInfo;

                PVOID QuotaBlackChanrged;

        };

        PSECURITY_DESCRIPTOR securityDesciptor;   //安全描述符

        QUAD  Body;

}OBJECT_HEADER,*POBJECT_HEADER;

        对象头包含了对象管理所需要的基本信息:对象名称、类型、引用计数以及安全描述符等。在windows中,每一种对象都需要有一个对应的类型对象来说明其类型。

#define OBJECT_LOCK_COUNT  4

typedef struct _OBJECT_TYPE  {

        RESOURCE Mutex;

        LIST_ENTRY TypeList;

        UNICODE_STRING Name;              // 来自名称信息的内存偏移NameInfoOffset

        PVOID DefaultObject;

        ULONG Index;                               //此类型对象在全局数组中的索引

        ULONG TotalNumberOfObjects

        ULONG TotalNumberOfHandles;

        ULONG HighWaterNumberOfObjects;

         ULONG HighWaterNumberOfHandles;

        OBJECT_TYPE_INITIALIZER TypeInfo;

#ifdef POOL_TAGGING

        ULONG Key;

#endif                            //POOL_TAGGING

         RESOURCE ObjectLocks[OBJECT_LOCK_COUNT];

}OBJECT_TYPE,*POBJECT_TYPE;

        系统定义的对象种类时有限的,如WRK,就支持31种对象,都有一个全局的POBJECT_TYPE变量指向其类型对象。

        为了使每一种对象都可以在系统内部真正可用,系统通常后再初始化过程种调用ObCreateObjectType函数构建起这种对象类型、以完成相应全局变量的初始化。下面介绍ObCreateObjectType的函数:

NSTATUS ObCreateObjectType {

      __in FUNCTION_STRING TypeName;

      __in  POBJECT_TYPE_INITIALIZER ObjectTypeInitializer,

     __in_opt PSECURITY_DESCRIPTOR SecurityDescriptor,

      __out POBJECT_TYPE *ObjectType

};

        上面的输入参数ObjectTypeInitializer是指向POBJECT_TYPE_INITIALIZER的结构指针,其结构的定义如下:

typedef struct OBJECT_TYPE_INITIALIZER {

        USHORT Length;

        BOOLEAN useDefaultObject;

        BOOLEAN CaseInsensitive;

        ULONG InvalidAttributes;

        GENERIC_MAPPING GenericMapping;

        ULONG ValidAccessMask;

        BOOLEAN SecurityRequired;

        BOOLEAN MaintainTypeList;

        POOL_TYPE PoolType;

        ULONG DefaultPagedPoolCharge;

        ULONG DefaultNonPagedPoolCharge;

        OB_DUMP_METHOG DumpPrecedure;

        OB_OPEN_METHOD OpenProcedure;

        OB_CLOSE_METHOD CloseProcedure;

        OB_DELETE_METHOD DeleteProcedure;

        OB_PARSE_METHOD ParsePrecodure;

        OB_SECURITY_METHOD SecurityProcedure;

        OB_QUERYNAME_METHOD QueryNameProcedure;

        OB_OKAYTOCLOSE_METHOD OkayToCloseProcedure;

}OBJECT_TYPE_INITIALIZER,*POBJECT_TYPE_INITIALIZER;

        从上面看出,在调用ObCreateObjectType函数来构建一种新的对象类型时,调用者除了可以指定此种类型对象的一些数据特性外,还可以指定该类型对象的一些基本操作方法,包括Dump、Open、Close、Delete、Parse、Security、QueryName和OkayToClose。对象管理器正是通过这些方法来统一管理各种类型的对象的。系统有一个全局变量ObpObjectTypes数组记录了所有已创建的类型,这是一个静态数组,WRK限定不超过48种对象类型。OBJECT_TYPE 中的Index成员记录了一个类型对象在此数组中的索引。

        一旦类型对象已经被创建,后面的内核代码就可以调用ObCreateObject来创建此种类型的对象了,下面是ObCreateObject的函数的原型:

NTSTATUS ObCreateObject {

    __in KPROCESS_MODE ProbeMode,

    __in POBJECT_TYPE ObjectType,

    __in POJECT_ATTRIBUTES ObjectAttributes,

    __inout_opt PVOID ParseContext,

    __in ULONG ObjectBodySize,

    __in ULONG PagedPoolCharge.

  __out PVOID *Object

};

        注意,在创建对象时,ObjectType参数只是确定了对象头的部分,对象体部分的大小需要在ObjectBodySize参数中指定。该函数返回时,Object输出参数指向对象体起始位置。对象体的格式是特定于某种对象类型的,由相应类型对象的诸多过程来维护。

一是先建立类型对象:进程和线程对象在系统初始化的过程如下:

RtlZeroMemory(&ObjectTypeInitializer,sizeof(ObjectTypeInitializer));

ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);

ObjectTypeInitializer.SecurityRequired = TRUE;

ObjectTypeInitializer.PoolType = NonPagedPool;

ObjectTypeInitializer.InvalidAttributes = OBJ_PERMANENT

                                                        |OBJ_EXCLUSIVE

                                                        |OBJ_OPENIF;

RtlInitUnicodeString(&NameString,L“Process”);

ObjectTypeInitializer.DefaultPagedPoolCharge = PSP_PROCESS_PAGED_CHARGE;

ObjectTypeInitializer.DefaultNonPagedPoolCharge = PSP_PROCESS_NONPAGED_CHARGE;

ObjectTypeInitializer.DeletProcedure = PspProcedureDelete;

ObjectTypeInitializer.ValidAccessMask = PROCESS_ALL_ACCESS;

ObjectTypeInitializer.GenericMapping = PspProcessMapping;

if (!NT_SUCCESS(ObCreateObjectType(&NameString,

                                       &ObjectTypeInitializer,

                                        (PSECURITY_DESCRIPTOR)NULL,

                                        &PspProcessType))){

        return FALSE;

}

RtlInitUnicodeString(&NameString,L“Thread”);

ObjectTypeInitializer.DefaultPagedPoolCharge = PSP_THREAD_PAGED_CHARGE;

ObjectTypeInitializer.DefaultNonPagedPoolCharge = PSP_THREAD_NONPAGED_CHARGE;

ObjectTypeInitializer.DeletProcedure = PspThreadDelete;

ObjectTypeInitializer.ValidAccessMask = THREAD_ALL_ACCESS;

ObjectTypeInitializer.GenericMapping = PspThreadMapping;

if (!NT_SUCCESS(ObCreateObjectType(&NameString,

                                       &ObjectTypeInitializer,

                                        (PSECURITY_DESCRIPTOR)NULL,

                                        &PspThreadType))){

        return FALSE;

}

二是,在建立类型的基础上,由执行体建立进程和线程,建立进程时直接使用进程的类型对象PsProcessType:

Status = ObCreateObject(PreviousMode,

                                        PsProcessType,

                                        ObjectAttributes,

                                        PreviousMode,

                                        NULL,

                                        sizeof(EPROCESS),

                                        0,

                                        0,

                                        &Process);

if(!NT_SUCCESS(status)){

        goto exit_and_deref_parent;

}

建立线程时直接使用线程的类型对象PsThreadType:

Status = ObCreateObject(PreviousMode,

                                        PsThreadType,

                                        ObjectAttributes,

                                        PreviousMode,

                                        NULL,

                                        sizeof(ETHREAD),

                                        0,

                                        0,

                                        &Thread);

if(!NT_SUCCESS(status)){

       ObDereferenceObject(Process);

        return Status;

}

        对象管理器使用对象头中包含的信息来管理这些对象,在对象头中,除了对象名称和对象类型,还有指针计数和句柄数;指针计数记录了内核本身(也包括驱动程序)引用该对象的次数;句柄计数记录了有多少个句柄引用此对象。这些句柄可能出现在不同的进程中。

        类型对象并不需要为此种类类型的对象提供所有在OBJECT_TYPE_INITIALIZER定义中出现的方法。对象管理器提供了一些通用的服务,这些通用服务可以应用在任何类型的对象上。

  • OpenProcedure和CloseProcedure主要用于在已经创建的对象上的新建句柄,以指向此对象,这两个操作可以统一实现。
  • DeleteProcedure成员是显示指定的。
  • 针对所有类型的通信服务,加上特定于某种类型的实现,正好体现了面向对象程序设计中的多态性。

第三点是,对象的构造是由两部分来完成的:

(1)调用ObCreateObject,根据指定的类型对象来完成对象头的初始化,并且按照指定的大小来分配对象体的内存,可以统一完成。

(2)完成对象体的初始化,因为各种类型的对象有自己不同的初始化逻辑不可以统一完成。如,进程对象的构造是在PspCreateProcess函数中完成,而线程对象的构造是在PspCreateThread函数中完成的。

(3)前面两条介绍了通用服务和专用的初始化代码来管理对象,还提供了一些统一的机制来管理对象,如类型对象中可以跟踪记录当前所有此种类型的对象,因为所有的对象都是在ObpAllocateObject和ObpFreeObject中分配和释放的,可以自己在此函数完成此功能。

上面介绍了windows类型对象来管理对象的机理,除此以外,windows还允许以名称的方式来管理对象,这对于跨进程、跨模块的操作带来了极大方便,通过名称各自独立地创建或引用此对象,必须维护一套全局的名称查询机制,ObpDirectoryObjectiveType类型对象是实现这一机制的关键。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jyl_sh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值