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 ...
随机推荐
- Redis Scan迭代器遍历操作原理(一)
Redis在2.8.0版本新增了众望所归的scan操作,从此再也不用担心敲入了keys*, 然后举起双手看着键盘等待漫长的系统卡死了··· 命令的官方介绍在这里, 中文版由huangz同学细心翻译了, ...
- scala(三)
一.面向对象编程——类 1.定义一个简单的类 class HelloWorld { private var name = "leo" def sayHello() { print( ...
- mybatis sql使用经验总结
1.where 后面如果有动态sql,可以添加一个1=1条件,然后在后面添加动态sql语句,里面添加AND 例如: <select id="queryBizMonitorHistory ...
- 我的emacs简易配置
;;------------语言环境字符集设置(utf-8)------------- (set-language-environment 'Chinese-GB) (set-keyboard-cod ...
- C语言基本类型的字节数
- thinkphp 5 where 组合条件map数组or
if($inviterId>0) { $arr = Db::table("tablename")-> where("pid=$inviterId") ...
- java面试梳理
自己整理的有关java面试过的问题,有错的请矫正. 1, Spring的核心思想 控制反转和面向切面的编程 2,Spring的核心模块 反向控制与依赖注入.Bean配置以及加载 3,Scope是什么 ...
- Cloudera 安装
参考网址: http://tcxiang.iteye.com/blog/2087597 http://archive.cloudera.com/cdh5/ http://archive.clouder ...
- c++ poco 使用mysql中文乱码问题
poco 是c++ 一个比较好的库,现在正在学习使用它,碰到一些问题记录在此. poco版本:poco-1.46-all ,带有数据库的支持模块 操作系统:ubuntu 1.使用poco的MySQL模 ...
- 【BZOJ】1355 [Baltic2009]Radio Transmission
[算法]KMP [题解]KMP中n-next[n]得到最小循环节的性质. 考虑一个循环串(最后一个循环节可能残缺),它最长的[后缀=前缀]一定是以第二个循环节为起始位置的后缀. 正着考虑的话假设后缀T ...