热门标签 | 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中完成的。


推荐阅读
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • DNN Community 和 Professional 版本的主要差异
    本文详细解析了 DotNetNuke (DNN) 的两种主要版本:Community 和 Professional。通过对比两者的功能和附加组件,帮助用户选择最适合其需求的版本。 ... [详细]
  • 本文介绍了在Windows环境下使用pydoc工具的方法,并详细解释了如何通过命令行和浏览器查看Python内置函数的文档。此外,还提供了关于raw_input和open函数的具体用法和功能说明。 ... [详细]
  • 本文介绍如何使用阿里云的fastjson库解析包含时间戳、IP地址和参数等信息的JSON格式文本,并进行数据处理和保存。 ... [详细]
  • 尽管使用TensorFlow和PyTorch等成熟框架可以显著降低实现递归神经网络(RNN)的门槛,但对于初学者来说,理解其底层原理至关重要。本文将引导您使用NumPy从头构建一个用于自然语言处理(NLP)的RNN模型。 ... [详细]
  • 本文详细介绍了IBM DB2数据库在大型应用系统中的应用,强调其卓越的可扩展性和多环境支持能力。文章深入分析了DB2在数据利用性、完整性、安全性和恢复性方面的优势,并提供了优化建议以提升其在不同规模应用程序中的表现。 ... [详细]
  • 本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • 本文介绍了一款用于自动化部署 Linux 服务的 Bash 脚本。该脚本不仅涵盖了基本的文件复制和目录创建,还处理了系统服务的配置和启动,确保在多种 Linux 发行版上都能顺利运行。 ... [详细]
  • 本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ... [详细]
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • 本文详细介绍了macOS系统的核心组件,包括如何管理其安全特性——系统完整性保护(SIP),并探讨了不同版本的更新亮点。对于使用macOS系统的用户来说,了解这些信息有助于更好地管理和优化系统性能。 ... [详细]
  • 本文介绍了如何通过 Maven 依赖引入 SQLiteJDBC 和 HikariCP 包,从而在 Java 应用中高效地连接和操作 SQLite 数据库。文章提供了详细的代码示例,并解释了每个步骤的实现细节。 ... [详细]
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社区 版权所有