Windows内核执行体对象管理器的操作过程与分析
我之前写过一个有关于对象管理的读书笔记。但是这篇文章与前面的不同,这是我个人对对象管理器到底是什么的一个分析,而且也是直接对WRK代码进行的阅读。
执行体对象即我们通常所言的内核对象,我们知道Windows内核中有许多“管理器”,然而管理器并不是一个实体的存在而是一个抽象的概念。它更像是一系列相关函数和数据结构的集合。
《Windows Internals》中如此定义对象管理器:“本节将介绍Windows的对象管理器,即执行体内部负责创建、删除、保护和跟踪对象的组件”。
我们先从创建对象开始。依次是:创建对象、删除对象、引用对象、解除引用对象、控制对象访问、查找对象、
一.创建对象
对象创建操作肯定从r3传来。
针对每个对象类型都有各自的创建内核对象的函数。举个例子,
NtCreateFile()
NtCreateEvent()
NtCreateTimer()
NtCreateKey()
NtCreateProcess()
NtCreateThread()
这些函数都是由相应的Zw版本对应而来的。
这些函数内部都是用了ObCreateObject()这个函数来创建对象。
ObCreateObject()函数主要做了两件事
1.解析传入的OBJECT_ATTRIBUTES结构到对象的OBJECT_CREATE_INFORMATION结构以及其他结构中。
2.调用ObpAllocateObject()函数创建对象。
我们主要关注ObpAllocateObject()函数怎么创建的对象。
NTSTATUS
ObpAllocateObject (
IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
IN KPROCESSOR_MODE OwnershipMode,
IN POBJECT_TYPE ObjectType OPTIONAL,
IN PUNICODE_STRING ObjectName,
IN ULONG ObjectBodySize,
OUT POBJECT_HEADER *ReturnedObjectHeader
) /*++ Routine Description: This routine allocates a new object including the object header
and body from pool and fill in the appropriate fields. Arguments: ObjectCreateInfo - Supplies the create information for the new object OwnershipMode - Supplies the processor mode of who is going to own
the object ObjectType - Optionally supplies the object type of the object being
created. If the object create info not null then this field must
be supplied. ObjectName - Supplies the name of the object being created ObjectBodySize - Specifies the size, in bytes, of the body of the object
being created ReturnedObjectHeader - Receives a pointer to the object header for the
newly created objet. Return Value: An appropriate status value. --*/ {
ULONG HeaderSize;
POBJECT_HEADER ObjectHeader;
ULONG QuotaInfoSize;
ULONG HandleInfoSize;
ULONG NameInfoSize;
ULONG CreatorInfoSize;
POBJECT_HEADER_QUOTA_INFO QuotaInfo;
POBJECT_HEADER_HANDLE_INFO HandleInfo;
POBJECT_HEADER_NAME_INFO NameInfo;
POBJECT_HEADER_CREATOR_INFO CreatorInfo;
POOL_TYPE PoolType; PAGED_CODE(); //
// Compute the sizes of the optional object header components.
// if (ObjectCreateInfo == NULL) { QuotaInfoSize = ;
HandleInfoSize = ;
NameInfoSize = sizeof( OBJECT_HEADER_NAME_INFO );
CreatorInfoSize = sizeof( OBJECT_HEADER_CREATOR_INFO );//OBJECT_HEADER_CREATOR_INFO一定存在 } else { //
// The caller specified some additional object create info
//
// First check to see if we need to set the quota
// if (((ObjectCreateInfo->PagedPoolCharge != ObjectType->TypeInfo.DefaultPagedPoolCharge ||
ObjectCreateInfo->NonPagedPoolCharge != ObjectType->TypeInfo.DefaultNonPagedPoolCharge ||
ObjectCreateInfo->SecurityDescriptorCharge > SE_DEFAULT_SECURITY_QUOTA) &&
PsGetCurrentProcess() != PsInitialSystemProcess) ||
(ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE)) {
//这时,配额头才是存在的
QuotaInfoSize = sizeof( OBJECT_HEADER_QUOTA_INFO ); } else { QuotaInfoSize = ;
} //
// Check if we are to allocate space to maintain handle counts
// if (ObjectType->TypeInfo.MaintainHandleCount) {
//这时,句柄头才是存在的
HandleInfoSize = sizeof( OBJECT_HEADER_HANDLE_INFO ); } else { HandleInfoSize = ;
} //
// Check if we are to allocate space for the name
// if (ObjectName->Buffer != NULL) {
//这时,名字头才是存在的
NameInfoSize = sizeof( OBJECT_HEADER_NAME_INFO ); } else { NameInfoSize = ;
} //
// Finally check if we are to maintain the creator info
// if (ObjectType->TypeInfo.MaintainTypeList) { CreatorInfoSize = sizeof( OBJECT_HEADER_CREATOR_INFO ); } else { CreatorInfoSize = ;
}
} //
// Now compute the total header size
//
//计算整个头的大小
HeaderSize = QuotaInfoSize +
HandleInfoSize +
NameInfoSize +
CreatorInfoSize +
FIELD_OFFSET( OBJECT_HEADER, Body ); //
// Allocate and initialize the object.
//
// If the object type is not specified or specifies nonpaged pool,
// then allocate the object from nonpaged pool.
// Otherwise, allocate the object from paged pool.
// if ((ObjectType == NULL) || (ObjectType->TypeInfo.PoolType == NonPagedPool)) {
//为啥等于空时要用非分页池?
PoolType = NonPagedPool; } else { PoolType = PagedPool;
} ObjectHeader = ExAllocatePoolWithTag( PoolType,
HeaderSize + ObjectBodySize,
(ObjectType == NULL ? 'TjbO' : ObjectType->Key) |//这里体现了对象类型中国Key字段的作用
PROTECTED_POOL ); if (ObjectHeader == NULL) { return STATUS_INSUFFICIENT_RESOURCES;
} //
// Now based on if we are to put in the quota, handle, name, or creator info we
// will do the extra work. This order is very important because we rely on
// it to free the object.
// if (QuotaInfoSize != ) {
//设置配额头OBJECT_HEADER_QUOTA_INFO
QuotaInfo = (POBJECT_HEADER_QUOTA_INFO)ObjectHeader;
QuotaInfo->PagedPoolCharge = ObjectCreateInfo->PagedPoolCharge;
QuotaInfo->NonPagedPoolCharge = ObjectCreateInfo->NonPagedPoolCharge;
QuotaInfo->SecurityDescriptorCharge = ObjectCreateInfo->SecurityDescriptorCharge;
QuotaInfo->ExclusiveProcess = NULL;
ObjectHeader = (POBJECT_HEADER)(QuotaInfo + );
} if (HandleInfoSize != ) {
//设置Handle头OBJECT_HEADER_HANDLE_INFO
HandleInfo = (POBJECT_HEADER_HANDLE_INFO)ObjectHeader;
HandleInfo->SingleEntry.HandleCount = ;
ObjectHeader = (POBJECT_HEADER)(HandleInfo + );
} if (NameInfoSize != ) {
//设置Name头OBJECT_HEADER_NAME_INFO
NameInfo = (POBJECT_HEADER_NAME_INFO)ObjectHeader;
NameInfo->Name = *ObjectName;
NameInfo->Directory = NULL;
NameInfo->QueryReferences = ; if ( (OwnershipMode == KernelMode)
&&
(ObjectCreateInfo != NULL)
&&
(ObjectCreateInfo->Attributes & OBJ_KERNEL_EXCLUSIVE) ) { NameInfo->QueryReferences |= OBP_NAME_KERNEL_PROTECTED;
} ObjectHeader = (POBJECT_HEADER)(NameInfo + );
} if (CreatorInfoSize != ) {
//设置创建信息头OBJECT_HEADER_CREATOR_INFO
CreatorInfo = (POBJECT_HEADER_CREATOR_INFO)ObjectHeader;
CreatorInfo->CreatorBackTraceIndex = ;
CreatorInfo->CreatorUniqueProcess = PsGetCurrentProcess()->UniqueProcessId;//把创建对象的进程的信息存在创建信息头中
InitializeListHead( &CreatorInfo->TypeList );//加入到同一类型的内核对象的列表 PERFINFO_ADD_OBJECT_TO_ALLOCATED_TYPE_LIST(CreatorInfo, ObjectType); ObjectHeader = (POBJECT_HEADER)(CreatorInfo + );
} //
// Compute the proper offsets based on what we have
// //设置OBJECT_HEADER中几个可选头的偏移值
if (QuotaInfoSize != ) { ObjectHeader->QuotaInfoOffset = (UCHAR)(QuotaInfoSize + HandleInfoSize + NameInfoSize + CreatorInfoSize); } else { ObjectHeader->QuotaInfoOffset = ;
} if (HandleInfoSize != ) { ObjectHeader->HandleInfoOffset = (UCHAR)(HandleInfoSize + NameInfoSize + CreatorInfoSize); } else { ObjectHeader->HandleInfoOffset = ;
} if (NameInfoSize != ) { ObjectHeader->NameInfoOffset = (UCHAR)(NameInfoSize + CreatorInfoSize); } else { ObjectHeader->NameInfoOffset = ;
} //
// Say that this is a new object, and conditionally set the other flags
//
//添加标志位
ObjectHeader->Flags = OB_FLAG_NEW_OBJECT; if (CreatorInfoSize != ) { ObjectHeader->Flags |= OB_FLAG_CREATOR_INFO;
} if (HandleInfoSize != ) { ObjectHeader->Flags |= OB_FLAG_SINGLE_HANDLE_ENTRY;
} //
// Set the counters and its type
// ObjectHeader->PointerCount = ;//引用数
ObjectHeader->HandleCount = ;//句柄引用数
ObjectHeader->Type = ObjectType; //
// Initialize the object header.
//
// N.B. The initialization of the object header is done field by
// field rather than zeroing the memory and then initializing
// the pertinent fields.
//
// N.B. It is assumed that the caller will initialize the object
// attributes, object ownership, and parse context.
// //根据用户传入的参数设置OBJECT_HEADER的Flags值
if (OwnershipMode == KernelMode) { ObjectHeader->Flags |= OB_FLAG_KERNEL_OBJECT;
} if (ObjectCreateInfo != NULL &&
ObjectCreateInfo->Attributes & OBJ_PERMANENT ) { ObjectHeader->Flags |= OB_FLAG_PERMANENT_OBJECT;
} if ((ObjectCreateInfo != NULL) &&
(ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE)) { ObjectHeader->Flags |= OB_FLAG_EXCLUSIVE_OBJECT;
} ObjectHeader->ObjectCreateInfo = ObjectCreateInfo;
ObjectHeader->SecurityDescriptor = NULL; if (ObjectType != NULL) { InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfObjects); if (ObjectType->TotalNumberOfObjects > ObjectType->HighWaterNumberOfObjects) { ObjectType->HighWaterNumberOfObjects = ObjectType->TotalNumberOfObjects;
}
} //返回的值
*ReturnedObjectHeader = ObjectHeader; return STATUS_SUCCESS;
}
我们可以看到实质上内核对象就是用ExAllocatePoolWithTag分配的一块内存。
这个是OBJECT_HEADER,大量的操作都针对这个位进行。
看以看到对象头和所有可选头的填充都在这个函数中完成。
typedef struct _OBJECT_HEADER
{
LONG PointerCount;//引用计数
union
{
LONG HandleCount;//句柄计数
PVOID NextToFree;
};
POBJECT_TYPE Type;//对象类型
UCHAR NameInfoOffset;//OBJECT_HEADER_NAME_INFO偏移
UCHAR HandleInfoOffset;//OBJECT_HEADER_HANDLE_INFO偏移
UCHAR QuotaInfoOffset;//OBJECT_HEADER_QUOTA_INFO偏移
UCHAR Flags;//标明此对象各种的属性的标识符
union
{
POBJECT_CREATE_INFORMATION ObjectCreateInfo;//OBJECT_CREATE_INFORMATION结构地址
PVOID QuotaBlockCharged;
};
PVOID SecurityDescriptor;//安全描述符结构地址
QUAD Body;//对象体地址
} OBJECT_HEADER, *POBJECT_HEADER;
前面说ObCreateObject()函数“解析传入的OBJECT_ATTRIBUTES结构到对象的OBJECT_CREATE_INFORMATION结构以及其他结构中。”
在ObCreateObject()中的解析,在ObpAllocateObject()中派上了用途。ObpAllocateObject()不再有OBJECT_ATTRIBUTES结构作为参数。
二.删除对象
在ObDereferenceObject()中,会判断OBJECT_HEADER中的PointerCount值,如果为0就调用ObpDeleteObject()函数来进行删除。
ObpDeleteObject函数先把对象从OBJECT_HEADER_CREATOR_INFO.TypeList列表中删除,然后释放名字UNICODE_STRING的缓冲区,最后调用OBJECT_TYPE中定义的DeleteProcedure函数。
三.引用对象和解除引用对象
比如函数ObReferenceObjectByPointer()
引用和解除引用对象是在获取了OBJECT指针后,用OBJECT_TO_OBJECT_HEADER宏转换成OBJECT_HEADER指针,然后用InterlockedIncrement()加锁修改这个值。
四.控制对象访问
在打开一个对象时,参数中要填写预期的操作以申请权限。
Windows内核执行体对象管理器的操作过程与分析的更多相关文章
- Linux内核笔记——进程管理之执行体
内核版本:linux-2.6.11 在Linux中,有多种执行体(指令流.执行单位),它们是CPU调度和分配资源的基本单位,它们是内核态可见的,即内核态下,每一种执行体都有对应的唯一数据结构task_ ...
- [Windows内核分析]KPCR结构体介绍 (CPU控制区 Processor Control Region)
Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html 逆向分析操作系统内核代码至少需要具备两项技能: 段页汇编代码非常懂 ...
- windows内核窥探
windows是一个非常优秀的OS,从今天开始,我要和大家共同分享windows给我们带来的快乐!本人只所以将自己的学习笔记与大家分享,一是让自己更深入的理解windows,再就是有什么疏漏之处,望大 ...
- Windows 内核(WRK)编译
引子 WRK 是微软于 2006 年针对教育和学术界开放的 Windows 内核的部分源码, WRK(Windows Research Kernel)也就是 Windows 研究内核, 在 WRK 中 ...
- Windows内核驱动中操作文件
本页主题:如何在windows内核驱动中对文件操作,实现对文件的拷贝.粘贴.删除.查询信息等,这是很常用也是很简单的方法. 部分内容参考:http://www.cppblog.com/aurain/a ...
- Windows 内核(WRK)简介
引子 WRK 是微软于 2006 年针对教育和学术界开放的 Windows 内核的部分源码,WRK(Windows Research Kernel)也就是 Windows 研究内核,在 WRK 中不仅 ...
- 第一章 Windows内核概述
第一章 Windows内核概述 这一章节描述了Windows内核知识中最重要的几个概念,这些话题在这本书之后会有更详细的描述,那些会与当前的主题密切相关.要确保你理解这个章节的概念,因为这些概念构成了 ...
- Windows内核开发-Windows内部概述-2-
Windows内部概述-2- 线程: 执行代码的实体是线程.一个线程的包含在进程里面的,线程使用进程提供的资源来运行代码. 一个线程拥有以下的内容: 1:明确的运行模式,用户态或者内核态. 2:执行的 ...
- Windows内核开发-4-内核编程基础
Windows内核开发-4-内核编程基础 这里会构建一个简单但是完整的驱动程序和一个客户端,部署内核执行一些平时user下无法执行的操作. 将通过以下内容进行讲解: 1 介绍 2 驱动初始化 3 Cr ...
随机推荐
- 排座位&&Little Elephant And Permutation——排列dp的处理
排列的问题,就是要把序列排个序,使之达到某种最优值或者统计方案数 dp可以解决部分排列问题. 通常的解决方案是,按照编号(优先级)排序决策,从左到右决策两种. 这里主要是第一个. 排座位• 有
- 关于JBoss基本说明文档及基本使用安装
关于JBoss JBoss是全世界开发者共同努力的成果,一个基于J2EE的开放源代码的应用服务器.在不 到12个月的时间里有一百万以上的拷贝被下载.JBoss是第一位的J2EE应用服务器. J ...
- lua和C++的交互(1)
/* 以前听的一个故事,当年Java的创造者讲课的时候,一开始先拿一个简单的不能简单的小例子, 不断的扩展,最后成为一个复杂而完美的程序. 一个重要之重要的概念,就是栈.Lua与别的语言交互以及交换数 ...
- Linux常用网络工具:hping高级主机扫描
之前介绍了主机扫描工具fping,可以参考我写的<Linux常用网络工具:fping主机扫描>. hping是一款更高级的主机扫描工具,它支持TCP/IP数据包构造.分析,在某些防火墙配置 ...
- Mac(Linux)上安装memcached步骤
Mac上安装memcached类似于在Linux平台上安装memcached. 主要需要做两块: 一.安装libevent库: 二.安装memcached; 一.安装libevent库 libeven ...
- 前端PHP入门-030-文件函数API
bool file_exists ( $指定文件名或者文件路径) 功能:文件是否存在. bool is_readable ( $指定文件名或者文件路径) 功能:文件是否可读 bool is_write ...
- 如何卸载掉eclipse中的插件
First-->Help->About Eclipse Second--> Third-->
- MyBatis操作oracle的一些问题加载
mybatis在更新数据或者插入数据为空的时候必须指定jdbcType类型 1:传入的参数是对象类型 User user =new User(); INSERT INTO t_user ( id, u ...
- 【Android】完善Android学习(七:API 4.0.3)
备注:之前Android入门学习的书籍使用的是杨丰盛的<Android应用开发揭秘>,这本书是基于Android 2.2API的,目前Android已经到4.4了,更新了很多的API,也增 ...
- DLL初试
环境: VC++6.0 步骤: 1.建立一个WIN32 DYNAMIC-LINK LIBRARY工程,编写CPP文件,文件内容例如: #include "stdafx.h" #in ...