概述
转载来源:https://blog.csdn.net/wzsy/article/details/6188554
为对象分配内存看完了, 这次我们看一个比较高层的函数。
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)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复