热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Windows内核中的对象管理

1Windows内核中的对象管理每个对象都分为对象头和对象体,定义如下:typedefstruct_OBJECT_HEADER{LONGPoint

1  Windows内核中的对象管理

每个对象都分为对象头和对象体,定义如下:

typedef struct _OBJECT_HEADER

{

     LONG PointerCount; //引用计数

     union

     {

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

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

     };

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

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

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

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

     UCHAR Flags;

     union

     {

          POBJECT_CREATE_INFORMATION ObjectCreateInfo;

          PVOID QuotaBlockCharged;

     };

     PVOID SecurityDescriptor;   //安全描述符

     QUAD Body;               //对象体开始

} OBJECT_HEADER, *POBJECT_HEADER;

每种对象都有一个对应的类型对象(OBJECT_TYPE),定义如下:

#define OBJECT_LOCK_COUNT 4

typedef struct _OBJECT_TYPE {

    ERESOURCE Mutex;

    LIST_ENTRY TypeList;

    UNICODE_STRING Name;            // Copy from object header for convenience

    PVOID DefaultObject;

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

    ULONG TotalNumberOfObjects;

    ULONG TotalNumberOfHandles;

    ULONG HighWaterNumberOfObjects;

    ULONG HighWaterNumberOfHandles;

    OBJECT_TYPE_INITIALIZER TypeInfo;

#ifdef POOL_TAGGING

    ULONG Key;

#endif //POOL_TAGGING

    ERESOURCE ObjectLocks[ OBJECT_LOCK_COUNT ];

} OBJECT_TYPE, *POBJECT_TYPE;

WRK中的全局类型对象变量,如下表:

CmpKeyObjectType

ExWindowStationObjectType

ObpDeviceMapObjectType

DbgkDebugObjectType

IoAdapterObjectType

ObpDirectoryObjectType

ExCallbackObjectType

IoCompletionObjectType

ObpSymbolicLinkObjectType

ExDesktopObjectType

IoControllerObjectType

ObpTypeObjectType

ExEventObjectType

IoDeviceHandlerObjectType

PsJobType

ExEventPairObjectType

IoDriviceObjectType

PsProcessType

ExMutantObjectType

IoDriverObjectType

PsThreadType

ExpKeyedEventObjectType

IoFileObjectType

SeTokenObjectType

ExProfileObjectType

LpcPortObjectType

WmipGuidObjectType

ExSemaphoreObjectType

LpcWaitablePortObjectType

 

ExTimerObjectType

MmSectionObjectType

 

通常在初始化过程调用ObCreateObjectType函数构建这种对象类型,完成相应全局变量的初始化。

NTKERNELAPI

NTSTATUS

ObCreateObjectType(

    __in PUNICODE_STRING TypeName,

    __in POBJECT_TYPE_INITIALIZER ObjectTypeInitializer,

    __in_opt PSECURITY_DESCRIPTOR SecurityDescriptor,

    __out POBJECT_TYPE *ObjectType

);

ObjectTypeInitializer值其类型为指向OBJECT_TYPE_INITIALIZER结构的指针,结构定义如下:

 typedef struct _OBJECT_TYPE_INITIALIZER {

    USHORT Length;

    BOOLEAN UseDefaultObject;

    BOOLEAN CaseInsensitive;

    ULONG InvalidAttributes;

    GENERIC_MAPPING GenericMapping;

    ULONG ValidAccessMask;

    BOOLEAN SecurityRequired;

    BOOLEAN MaintainHandleCount;

    BOOLEAN MaintainTypeList;

    POOL_TYPE PoolType;

    ULONG DefaultPagedPoolCharge;

    ULONG DefaultNonPagedPoolCharge;

    OB_DUMP_METHOD DumpProcedure;

    OB_OPEN_METHOD OpenProcedure;

    OB_CLOSE_METHOD CloseProcedure;

    OB_DELETE_METHOD DeleteProcedure;

    OB_PARSE_METHOD ParseProcedure;

    OB_SECURITY_METHOD SecurityProcedure;

    OB_QUERYNAME_METHOD QueryNameProcedure;

    OB_OKAYTOCLOSE_METHOD OkayToCloseProcedure;

} OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;

可以看到在调用ObCreateObjectType创建对象类型,除了数据,还指定了基本的增删改等基本操作。之后内核就可以调用ObCreateObject来创建此种对象了。系统有一个全局变量ObpObjectTypes数组记录了所有已创建的类型。

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                        // 接收对象体的指针

)

以进程和线程对象为例:

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.DeleteProcedure = PspProcessDelete;

ObjectTypeInitializer.ValidAccessMask = PROCESS_ALL_ACCESS;

ObjectTypeInitializer.GenericMapping = PspProcessMapping;

 

if (!NT_SUCCESS (ObCreateObjectType (&NameString,

                                     &ObjectTypeInitializer,

                                     (PSECURITY_DESCRIPTOR) NULL,

                                     &PsProcessType))) {

    return FALSE;

}

RtlInitUnicodeString (&NameString, L"Thread");

ObjectTypeInitializer.DefaultPagedPoolCharge = PSP_THREAD_PAGED_CHARGE;

ObjectTypeInitializer.DefaultNonPagedPoolCharge = PSP_THREAD_NONPAGED_CHARGE;

ObjectTypeInitializer.DeleteProcedure = PspThreadDelete;

ObjectTypeInitializer.ValidAccessMask = THREAD_ALL_ACCESS;

ObjectTypeInitializer.GenericMapping = PspThreadMapping;

 

if (!NT_SUCCESS (ObCreateObjectType (&NameString,

                                     &ObjectTypeInitializer,

                                     (PSECURITY_DESCRIPTOR) NULL,

                                     &PsThreadType))) {

    return FALSE;

}

创建进程:

Status = ObCreateObject (PreviousMode,

                         PsProcessType,

                         ObjectAttributes,

                         PreviousMode,

                         NULL,

                         sizeof (EPROCESS),

                         0,

                         0,

                         &Process);

创建线程:

Status = ObCreateObject (PreviousMode,

                        PsThreadType,

                        ObjectAttributes,

                        PreviousMode,

                        NULL,

                        sizeof(ETHREAD),

                        0,

                        0,

                        &Thread);

 

对象管理器使用的对象头中还有两个重要信息:

1.指针计数,记录了内核本身(也包括驱动程序)引用该对象的次数。

2.句柄计数,记录了有多少个句柄引用此对象。这些句柄可能出现在不同进程中。

对象构造由两部分完成

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

2. 完成对象体的初始化。

Windows允许以名称的方式管理对象。Windows维护一套全局的名称查询机制,ObpDirectoryObjectType类型对象就说实现这一机制的关键。

Windows内部维护了一个对象层次目录(系统全局名字空间),其根目录对象是由全局变量ObRootDirectoryObject来定义。

NTCreateDirectoryObject 可以查看Callback、ArcName、Device、Driver、FileSystem

、KernelObjects 等子目录创建的过程。

ObpLookupDirectoryEntry指定目录查找一个名称。

ObpInsertDirectoryEntry 把一个对象插入到一个目录中。

ObpDeleteDirectoryEntry 删除找到的某一项。

ObpLookupObjectName 从指定的目录或根目录,递归地根据名称来找到一个对象。

ObpLookupObjectName定义如下:

NTSTATUS

ObpLookupObjectName (

    IN HANDLE RootDirectoryHandle,

    IN PUNICODE_STRING ObjectName,

    IN ULONG Attributes,

    IN POBJECT_TYPE ObjectType,

    IN KPROCESSOR_MODE AccessMode,

    IN PVOID ParseContext OPTIONAL,

    IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,

    IN PVOID InsertObject OPTIONAL,

    IN OUT PACCESS_STATE AccessState,

    OUT POBP_LOOKUP_CONTEXT LookupContext,

    OUT PVOID *FoundObject

);

ObpLookupObjectName执行逻辑:

  1. 参数检查
  2. 如果调用者指定了RootDirectoryHandle参数,则利用RootDirectory的Parse方法来解析对象名称,直到解析成功或者不成功,或者指示从头解析。
  3. 如果没有指定RootDirectoryHandle,则系统从全局的根目录ObpRootDirectoryObject开始解析。这种情况下,传递进来的对象名称必须以”\”开始。如果待查找的名称仅仅是“\”,则执行特殊处理。否则,执行下面的逻辑:

  • a. 首先判断名称是否以”\??\”打头,如果是的话,需要拿到当前进程的DeviceMap(设备表),以进一步查询。

  • b. 如果名称正好是”\??”,则直接返回当前进程的DeviceMap 作为结果。

  • c. 调用ObpLookupDirectoryEntry 查询。

在ObpLookupObjectName的代码逻辑中,可以看到进程设备表(DeviceMap),而且在目录对象的数据结构OBJECT_DIRECTORY中也有一个名为DeviceMap的成员,指向一个DEVICE_MAP。DEVICE_MAP的含义是,它定义了一个DOS设备名字空间,比如驱动器字母(C:/D:)和一些外设(com1),当对象管理器看到一个以“\??\”这样的名称,它会利用进程DeviceMap来获得相应的对象目录,然后进一步解析剩余名称字符串。

对象管理器中的对象是执行体对象,位于系统地址空间中,所有进程都可以访问这些对象。用户模式代码是调用系统服务时通过句柄来引用执行体对象。在内核中通过ObReferenceObjectByHandle将一个句柄转换成对应的对象。该函数负责从当前进程环境或内核环境句柄表中获得指定的对象引用。

关于对象的内存结构和生命周期,对象分为对象头对象体,头部结构是OBJECT_HEADER,对象体因对象而异,所以看到很多函数在接受对象作为参数时,类型为PVOID,而对象头和体通过ObpAllocateObject函数可知在同一块内存中。

从对象体转换到对象头,可以通过

#define OBJECT_TO_OBJECT_HEADER( o ) \

    CONTAINING_RECORD( (o), OBJECT_HEADER, Body )

对象是通过引用计数实现管理生命周期,一旦计数为零,则生命周期结束,对象的引用计数来源于2个方面,第一个来源是内核中的指针引用,一旦内核中新增了一个对象的引用,则对象引用计数需要增1,如果不在引用,则减1。第二个来源是进程打开一个对象获取一个句柄,它以后通过此句柄来引用此对象。对象头信息中准确记录有多少个句柄指向该对象,当1句柄不再被使用时,句柄计数减一。两种作用是在函数ObpIncrementHandleCount/ObpDecrementHandleCount中完成的。


推荐阅读
  • 在金融和会计领域,准确无误地填写票据和结算凭证至关重要。这些文件不仅是支付结算和现金收付的重要依据,还直接关系到交易的安全性和准确性。本文介绍了一种使用C语言实现小写金额转换为大写金额的方法,确保数据的标准化和规范化。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • 从 .NET 转 Java 的自学之路:IO 流基础篇
    本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • DNN Community 和 Professional 版本的主要差异
    本文详细解析了 DotNetNuke (DNN) 的两种主要版本:Community 和 Professional。通过对比两者的功能和附加组件,帮助用户选择最适合其需求的版本。 ... [详细]
  • ImmutableX Poised to Pioneer Web3 Gaming Revolution
    ImmutableX is set to spearhead the evolution of Web3 gaming, with its innovative technologies and strategic partnerships driving significant advancements in the industry. ... [详细]
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • golang常用库:配置文件解析库/管理工具viper使用
    golang常用库:配置文件解析库管理工具-viper使用-一、viper简介viper配置管理解析库,是由大神SteveFrancia开发,他在google领导着golang的 ... [详细]
  • 在前两篇文章中,我们探讨了 ControllerDescriptor 和 ActionDescriptor 这两个描述对象,分别对应控制器和操作方法。本文将基于 MVC3 源码进一步分析 ParameterDescriptor,即用于描述 Action 方法参数的对象,并详细介绍其工作原理。 ... [详细]
  • 本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ... [详细]
  • 本文详细介绍了如何构建一个高效的UI管理系统,集中处理UI页面的打开、关闭、层级管理和页面跳转等问题。通过UIManager统一管理外部切换逻辑,实现功能逻辑分散化和代码复用,支持多人协作开发。 ... [详细]
  • JavaScript中属性节点的类型及应用
    本文深入探讨了JavaScript中属性节点的不同类型及其在实际开发中的应用,帮助开发者更好地理解和处理HTML元素的属性。通过具体的案例和代码示例,我们将详细解析如何操作这些属性节点。 ... [详细]
  • 在 Swift 编程中,遇到错误提示“一元运算符 '!' 不能应用于 '()' 类型的操作数”,通常是因为尝试对没有返回值的方法或函数应用逻辑非运算符。本文将详细解释该错误的原因,并提供解决方案。 ... [详细]
  • 本文详细介绍了 Apache Jena 库中的 Txn.executeWrite 方法,通过多个实际代码示例展示了其在不同场景下的应用,帮助开发者更好地理解和使用该方法。 ... [详细]
author-avatar
我只当你的千纸鹤
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有