我是靠谱客的博主 大气楼房,最近开发中收集的这篇文章主要介绍三。对象创建(ObCreateObject)和对象删除(ObDereferenceObject、ObpRemoveObjectRoutine),觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
三。对象创建(ObCreateObject)和对象删除(ObDereferenceObject、ObpRemoveObjectRoutine)
2010年05月11日 星期二 11:20
为对象分配内存看完了, 这次我们看一个比较高层的函数。 ObCreateObject, 这是内核的导出函数, 所有模块都可以使用(虽然它没有被文档化....) 它的作用是创建指定类型(OBJECT_TYPE)的对象示例。(注意ObAllocateObject只是分配了空间, 这里可以看到后续的操作) 这个函数的参数还真多啊。微软函数的参数一直都和火车一样。我们只能淡定。。。 NTSTATUS ObCreateObject ( __in KPROCESSOR_MODE ProbeMode, // 决定是否要验证参数 __in POBJECT_TYPE ObjectType, // 对象类型指针 __in POBJECT_ATTRIBUTES ObjectAttributes, // 对象的属性, 最终会转化成ObAllocateObject需要的OBJECT_CREATE_INFORMATION结构 __in KPROCESSOR_MODE OwnershipMode, // 内核对象?用户对象? 同上 __inout_opt PVOID ParseContext, // 这参数没用 __in ULONG ObjectBodySize, // 对象体大小 __in ULONG PagedPoolCharge, // ... __in ULONG NonPagedPoolCharge, // ... __out PVOID *Object // 接收对象体的指针 ) { ...... // 由于ObAllocateObject是通过OBJECT_CREATE_INFORMATION结构控制生成对象的, 这里先生成一个这个结构 ObjectCreateInfo = ObpAllocateObjectCreateInfoBuffer(); if (ObjectCreateInfo == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; // 出错就退出了 } else { // 这个函数填写OBJECT_CREATE_INFORMATION结构, 里面只是一堆转换操作 Status = ObpCaptureObjectCreateInformation( ObjectType, ProbeMode, OwnershipMode, ObjectAttributes, &CapturedObjectName, ObjectCreateInfo, FALSE ); if (NT_SUCCESS(Status)) { // OBJECT_TYPE.TypeInfo.InvalidAttributes 包含了本类对象的非法属性 // 如果和用户请求的属性有冲突就退出 if (ObjectType->TypeInfo.InvalidAttributes & ObjectCreateInfo->Attributes) { Status = STATUS_INVALID_PARAMETER; } else { // 没有冲突, 填写Charge if (PagedPoolCharge == 0) { PagedPoolCharge = ObjectType->TypeInfo.DefaultPagedPoolCharge; } if (NonPagedPoolCharge == 0) { NonPagedPoolCharge = ObjectType->TypeInfo.DefaultNonPagedPoolCharge; } ObjectCreateInfo->PagedPoolCharge = PagedPoolCharge; ObjectCreateInfo->NonPagedPoolCharge = NonPagedPoolCharge; // 生成对象体, 已经看过这个函数了 Status = ObpAllocateObject( ObjectCreateInfo, OwnershipMode, ObjectType, &CapturedObjectName, ObjectBodySize, &ObjectHeader ); if (NT_SUCCESS(Status)) { // 生成成功检测权限 *Object = &ObjectHeader->Body; if (ObjectHeader->Flags & OB_FLAG_PERMANENT_OBJECT) { if (!SeSinglePrivilegeCheck( SeCreatePermanentPrivilege, ProbeMode)) { ObpFreeObject(*Object); Status = STATUS_PRIVILEGE_NOT_HELD; } } // 成功退出 return Status; } } //一下都是错误处理 ObpReleaseObjectCreateInformation(ObjectCreateInfo); if (CapturedObjectName.Buffer != NULL) { ObpFreeObjectNameBuffer(&CapturedObjectName); } } ObpFreeObjectCreateInfoBuffer(ObjectCreateInfo); } return Status; } 这个函数做的事情非常简单 1。 使用ObpCaptureObjectCreateInformation函数把用户传进来的参数转化为OBJECT_CREATE_INFORMATION结构 因为使用为对象ObAllocateObject非配内存时, 这个结构控制了非配的行为 2。 ObpAllocateObject为对象非配内存 3。 检测一下权限什么, 就完了 有创建就有删除, windows中对对象的引用包含两种, 使用指针和使用句柄。 这两种方式在OBJECT_HEADER中分别有两个域用作计数, 当这两个计数都到达0时, 对象被删除了。 kd> dt _OBJECT_HEADER nt!_OBJECT_HEADER +0x000 PointerCount : Int4B 指针计数 +0x004 HandleCount : Int4B 句柄计数 ....... 句柄的操作要涉及到进程的句柄表, 比较麻烦。先看看指针计数。 下面这个函数负责减少指针计数, 如果计数到达0就删除对象。这个函数的实现非常简单 LONG_PTR FASTCALL ObfDereferenceObject ( __in PVOID Object //对象体指针 ) { ...... // 直接在对象体的基础上减去 0x18就是对象头了 ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object ); // 获得Type指针 ObjectType = ReadForWriteAccess(&ObjectHeader->Type); // 简单的递减 PointerCount 域 Result = ObpDecrPointerCount( ObjectHeader ); // 递减到0就要删除啦 if (Result == 0) { OldIrql = KeGetCurrentIrql(); ASSERT(ObjectHeader->HandleCount == 0); if ( !KeAreAllApcsDisabled() ) { // 如果在PASSIVE Level调用ObpRemoveObjectRoutine删除 ObpRemoveObjectRoutine( Object, FALSE ); return Result; } else { // 否则调用 ObpDeferObjectDeletion 延迟删除 ObpDeferObjectDeletion (ObjectHeader); } } return Result; } ObpDeferObjectDeletion和ObpRemoveObjectRoutine的目的都是一样的。 只不过在中断级比较高时ObpDeferObjectDeletion通过把请求派遣到系统工作线程中来降低优先级。 它的调用路径是 ObpDeferObjectDeletion->ExQueueWorkItem->(工作线程中)ObpProcessRemoveObjectQueue->ObpRemoveObjectRoutine 所以它最终还是调用ObpRemoveObjectRoutine来执行删除操作。 来看看对象的删除 VOID ObpRemoveObjectRoutine ( IN PVOID Object, // 对象体 IN BOOLEAN CalledOnWorkerThread // 是否是工作线程调用 ) { // 获得OBJECT_HEADER、对象类型、CreatorInfo和NameInfo // 若CreatorInfo和NameInfo不存在则返回NULL ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object ); ObjectType = ObjectHeader->Type; CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO( ObjectHeader ); NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader ); // 如果CreatorInfo存在, 并且它在对象链表中, 摘链 if (CreatorInfo != NULL && !IsListEmpty( &CreatorInfo->TypeList )) { ObpEnterObjectTypeMutex( ObjectType ); RemoveEntryList( &CreatorInfo->TypeList ); ObpLeaveObjectTypeMutex( ObjectType ); } // 释放名字占用的空间, 还记得ObAllocateObject中对Name的直接赋值吗? 这里进行了释放 if (NameInfo != NULL && NameInfo->Name.Buffer != NULL) { ExFreePool( NameInfo->Name.Buffer ); NameInfo->Name.Buffer = NULL; NameInfo->Name.Length = 0; NameInfo->Name.MaximumLength = 0; } // 权限检查略过 if (ObjectHeader->SecurityDescriptor != NULL) { ...... } // 使用对象类型中的_OBJECT_TYPE_INITIALIZER结构中的DeleteProcedure删除对象 if (ObjectType->TypeInfo.DeleteProcedure) { ObpBeginTypeSpecificCallOut( SaveIrql ); if (!CalledOnWorkerThread) { ObjectHeader->Flags |= OB_FLAG_DELETED_INLINE; } (*(ObjectType->TypeInfo.DeleteProcedure))(Object); ObpEndTypeSpecificCallOut( SaveIrql, "Delete", ObjectType, Object ); } // 这个是ObAllocateObject的逆操作 ObpFreeObject( Object ); } 比较重要的是_OBJECT_TYPE_INITIALIZER结构, 在ObInitSystem()中的创建类型对象部分我们已经看到过。它包含了众多回调函数地址。 由于windows的对象是使用统一的函数管理的, 他们的接口都一样。但相同操作不同对象应该做的事情肯定是不一样的。 像打开文件和打开注册表就是完全不同的操作。 于是windows将类型与类型之间行为不同的操作放入_OBJECT_TYPE_INITIALIZER结构中。这样就可以使用相同的接口来操作了。 比如上面的ObpRemoveObjectRoutine就调用了其中的DeleteProcedure路径。 ObpRemoveObjectRoutine并不需要知道这个对象是什么, 它只知道要删除一个对象应该调用对应_OBJECT_TYPE_INITIALIZER中的DeleteProcedure函数就可以了。 如果系统中加入了新类型ObpRemoveObjectRoutine的代码完全不用修改。做到使用统一的接口管理不同的对象。 最后展示一下_OBJECT_TYPE_INITIALIZER kd> dt _OBJECT_TYPE_INITIALIZER nt!_OBJECT_TYPE_INITIALIZER +0x000 Length : Uint2B +0x002 UseDefaultObject : UChar +0x003 CaseInsensitive : UChar +0x004 InvalidAttributes : Uint4B 该类型的非法参数 +0x008 GenericMapping : _GENERIC_MAPPING +0x018 ValidAccessMask : Uint4B +0x01c SecurityRequired : UChar +0x01d MaintainHandleCount : UChar +0x01e MaintainTypeList : UChar +0x020 PoolType : _POOL_TYPE +0x024 DefaultPagedPoolCharge : Uint4B +0x028 DefaultNonPagedPoolCharge : Uint4B +0x02c DumpProcedure : Ptr32 void 以下就是不同功能的回调函数了 +0x030 OpenProcedure : Ptr32 long +0x034 CloseProcedure : Ptr32 void +0x038 DeleteProcedure : Ptr32 void +0x03c ParseProcedure : Ptr32 long +0x040 SecurityProcedure : Ptr32 long +0x044 QueryNameProcedure : Ptr32 long +0x048 OkayToCloseProcedure : Ptr32 unsigned char |
最后
以上就是大气楼房为你收集整理的三。对象创建(ObCreateObject)和对象删除(ObDereferenceObject、ObpRemoveObjectRoutine)的全部内容,希望文章能够帮你解决三。对象创建(ObCreateObject)和对象删除(ObDereferenceObject、ObpRemoveObjectRoutine)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复