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


推荐阅读
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文介绍了Perl的测试框架Test::Base,它是一个数据驱动的测试框架,可以自动进行单元测试,省去手工编写测试程序的麻烦。与Test::More完全兼容,使用方法简单。以plural函数为例,展示了Test::Base的使用方法。 ... [详细]
  • 本文介绍了如何在Mac上使用Pillow库加载不同于默认字体和大小的字体,并提供了一个简单的示例代码。通过该示例,读者可以了解如何在Python中使用Pillow库来写入不同字体的文本。同时,本文也解决了在Mac上使用Pillow库加载字体时可能遇到的问题。读者可以根据本文提供的示例代码,轻松实现在Mac上使用Pillow库加载不同字体的功能。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 生成对抗式网络GAN及其衍生CGAN、DCGAN、WGAN、LSGAN、BEGAN介绍
    一、GAN原理介绍学习GAN的第一篇论文当然由是IanGoodfellow于2014年发表的GenerativeAdversarialNetworks(论文下载链接arxiv:[h ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了作者在开发过程中遇到的问题,即播放框架内容安全策略设置不起作用的错误。作者通过使用编译时依赖注入的方式解决了这个问题,并分享了解决方案。文章详细描述了问题的出现情况、错误输出内容以及解决方案的具体步骤。如果你也遇到了类似的问题,本文可能对你有一定的参考价值。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • Go语言实现堆排序的详细教程
    本文主要介绍了Go语言实现堆排序的详细教程,包括大根堆的定义和完全二叉树的概念。通过图解和算法描述,详细介绍了堆排序的实现过程。堆排序是一种效率很高的排序算法,时间复杂度为O(nlgn)。阅读本文大约需要15分钟。 ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
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社区 版权所有