热门标签 | 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++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • 采用IKE方式建立IPsec安全隧道
    一、【组网和实验环境】按如上的接口ip先作配置,再作ipsec的相关配置,配置文本见文章最后本文实验采用的交换机是H3C模拟器,下载地址如 ... [详细]
  • 利用决策树预测NBA比赛胜负的Python数据挖掘实践
    本文通过使用2013-14赛季NBA赛程与结果数据集以及2013年NBA排名数据,结合《Python数据挖掘入门与实践》一书中的方法,展示如何应用决策树算法进行比赛胜负预测。我们将详细讲解数据预处理、特征工程及模型评估等关键步骤。 ... [详细]
  • 丽江客栈选择问题
    本文介绍了一道经典的算法题,题目涉及在丽江河边的n家特色客栈中选择住宿方案。两位游客希望住在色调相同的两家客栈,并在晚上选择一家最低消费不超过p元的咖啡店小聚。我们将详细探讨如何计算满足条件的住宿方案总数。 ... [详细]
  • 深入解析Java枚举及其高级特性
    本文详细介绍了Java枚举的概念、语法、使用规则和应用场景,并探讨了其在实际编程中的高级应用。所有相关内容已收录于GitHub仓库[JavaLearningmanual](https://github.com/Ziphtracks/JavaLearningmanual),欢迎Star并持续关注。 ... [详细]
  • 本文介绍了如何使用JavaScript的Fetch API与Express服务器进行交互,涵盖了GET、POST、PUT和DELETE请求的实现,并展示了如何处理JSON响应。 ... [详细]
  • 本文详细介绍了如何在Kendo UI for jQuery的数据管理组件中,将行标题字段呈现为锚点(即可点击链接),帮助开发人员更高效地实现这一功能。通过具体的代码示例和解释,即使是新手也能轻松掌握。 ... [详细]
  • 在尝试使用C# Windows Forms客户端通过SignalR连接到ASP.NET服务器时,遇到了内部服务器错误(500)。本文将详细探讨问题的原因及解决方案。 ... [详细]
  • 本文介绍如何在SQL Server中创建动态SQL存储过程,并提供详细的代码实例和解释。通过这种方式,可以更灵活地处理查询条件和参数。 ... [详细]
  • 方法:1 配置数据库basediros.path.abspath(os.path.dirname(__file__))  #获取当前文件的绝对路径appFlask(__name__ ... [详细]
  • 本问题探讨了在特定条件下排列儿童队伍的方法数量。题目要求计算满足条件的队伍排列总数,并使用递推算法和大数处理技术来解决这一问题。 ... [详细]
  • JavaScript 基础语法指南
    本文详细介绍了 JavaScript 的基础语法,包括变量、数据类型、运算符、语句和函数等内容,旨在为初学者提供全面的入门指导。 ... [详细]
  • Python处理Word文档的高效技巧
    本文详细介绍了如何使用Python处理Word文档,涵盖从基础操作到高级功能的各种技巧。我们将探讨如何生成文档、定义样式、提取表格数据以及处理超链接和图片等内容。 ... [详细]
  • JSOI2010 蔬菜庆典:树结构中的无限大权值问题
    本文探讨了 JSOI2010 的蔬菜庆典问题,主要关注如何处理非根非叶子节点的无限大权值情况。通过分析根节点及其子树的特性,提出了有效的解决方案,并详细解释了算法的实现过程。 ... [详细]
  • 目录一、salt-job管理#job存放数据目录#缓存时间设置#Others二、returns模块配置job数据入库#配置returns返回值信息#mysql安全设置#创建模块相关 ... [详细]
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社区 版权所有