Windows对象 (Object) 的组织

来源:互联网 发布:淘宝网石龙二中校服 编辑:程序博客网 时间:2024/05/16 01:51

在《Windows对象(Object)结构》一文中简单的描述了Object的结构,其中一些结构的细节地方尚未提及。
这篇文章中,主要讨论对象管理器(Object Manager)如何组织系统中的各种对象。

与文件系统管理文件的方法类似,Windows对象管理器将系统中的对象按照树状结构进行存储。可以使用www.sysinternals.com的winobj来观察系统中的对象。

既然系统以树状结构存储对象,那就先从组成这棵树数据结构下手,看一下系统是如何将对象组织起来的。
Windows使用OBJECT_DIRECTORY和OBJECT_DIRECTORY_ENTRY结构作为“树干”,将 OBJECT_DIRECTORY结构的地址保存到位于Object Header之前的OBJECT_HEADER_NAME_INFO结构中。这些结构的定义如下:

//
// Object Directory Structure
//

#define NUMBER_HASH_BUCKETS 37
#define OBJ_INVALID_SESSION_ID 0xFFFFFFFF

typedef struct _OBJECT_DIRECTORY {
    struct _OBJECT_DIRECTORY_ENTRY *HashBuckets[ NUMBER_HASH_BUCKETS ];
    EX_PUSH_LOCK Lock;
    struct _DEVICE_MAP *DeviceMap;
    ULONG SessionId;
} OBJECT_DIRECTORY, *POBJECT_DIRECTORY;

//
// Object Directory Entry Structure
//
typedef struct _OBJECT_DIRECTORY_ENTRY {
    struct _OBJECT_DIRECTORY_ENTRY *ChainLink;
    PVOID Object;
    ULONG HashValue;
} OBJECT_DIRECTORY_ENTRY, *POBJECT_DIRECTORY_ENTRY;

typedef struct _OBJECT_HEADER_NAME_INFO {
    POBJECT_DIRECTORY Directory;
    UNICODE_STRING Name;
    ULONG QueryReferences;
} OBJECT_HEADER_NAME_INFO, *POBJECT_HEADER_NAME_INFO;

首先来看一下OBJECT_DIRECTORY结构,HashBuckets是一个有NUMBER_HASH_BUCKETS项数据的HASH表,类型为OBJECT_DIRECTORY_ENTRY结构指针数组,计算HASH的伪代码如下:

int CalcHash(WCHAR* ws)
{
    WcharLength = ws / sizeof( ws[0] );

    HashIndex = 0;

    while (WcharLength--) {
        Wchar = *ws++;
        HashIndex += (HashIndex << 1) + (HashIndex >> 1);

        if (Wchar < 'a') {

            HashIndex += Wchar;

        } else if (Wchar > 'z') {

            HashIndex += RtlUpcaseUnicodeChar( (WCHAR)Wchar );

        } else {

            HashIndex += (Wchar - ('a'-'A'));
        }
    }

    HashValue = HashIndex;
    HashIndex %= NUMBER_HASH_BUCKETS;

    return HashIndex;
}

这段代码的实现可以在ObpLookupDirectoryEntry()中找到(%wrk%/base/ntos/ob/Obdir.c)。

OBJECT_DIRECTORY结构正如它的名字一样——对象目录,对象管理器(Object Manager)将具有各个不同索引值的OBJECT_DIRECTORY_ENTRY结构保存在HashBuckets表中(索引值是这个指针数组的下标,范围从0-NUMBER_HASH_BUCKETS),而将各个具有相同索引值的OBJECT_DIRECTORY_ENTRY结构,依靠 OBJECT_DIRECTORY_ENTRY.ChainLink联系在一起,并将每一个对象(Object Body部分)保存在OBJECT_DIRECTORY_ENTRY.Object成员中。

我们将上面的文字描述实例化,最终形成了如下图的结构:
对象组织结构图-点击查看原始图片
这张图的信息全部来自于kd的输出,这里以“/Driver”为例,利用调试器看一下系统内部对象是如何组织的。

kd> !object /driver
Object: e1005160  Type: (899272c0) Directory
    ObjectHeader: e1005148
    HandleCount: 0  PointerCount: 117
    Directory Object: e1000118  Name: Driver

    Hash Address  Type          Name
    ---- -------  ----          ----
     00  897adc30 Driver        Beep
         8988df38 Driver        NDIS
         89885328 Driver        KSecDD
     01  8979b880 Driver        Raspti
         89690f38 Driver        Mouclass
     02  896a4418 Driver        TPInput
     03  896d79f0 Driver        Fips
         896a6d10 Driver        Kbdclass
        ...
     36  896c0658 Driver        Smapint
         896e1468 Driver        i8042prt
         897b04a8 Driver        CmBatt

“Object: e1005160”是“/Driver”对象的Object Body部分(OBJECT_DIRECTORY结构);“Type: (899272c0) Directory”表示“/Driver”对象是目录(Directory)类型;“Directory Object: e1000118”表示“/Driver”对象所在父目录(对象)的地址为0xe1000118(“/”目录对象)。
我们可以这样理解这个问题,文件系统会用两个特殊的目录来表示当前目录(“.”)和父目录(“..”),而对于一个目录(Directory)类型的对象,对象管理器使用Object Body部分来记录当前目录(对象)的信息,用OBJECT_HEADER_NAME_INFO的Directory成员保存父目录(对象)的地址。

OBJECT_HEADER_NAME_INFO是位于Object Header之前的一个结构,Directory成员记录了当前对象所在的目录(对象)的地址,Name成员保存对象名。
因此上面输出中的“Directory Object: e1000118”正是“/Driver”对象的OBJECT_HEADER_NAME_INFO.Directory所指向的目录(对象)——对象树的根节点“/”:

kd> dt nt!_object_header_name_info e1005148-0x10
nt!_OBJECT_HEADER_NAME_INFO
   +0x000 Directory        : 0xe1000118 _OBJECT_DIRECTORY
   +0x004 Name             : _UNICODE_STRING "Driver"
   +0x00c QueryReferences  : 1

kd> !object 0xe1000118
Object: e1000118  Type: (899272c0) Directory
    ObjectHeader: e1000100
    HandleCount: 0  PointerCount: 38
    Directory Object: 00000000  Name: /

“/”对象是目录类型,是整个对象数的树根,其OBJECT_HEADER_NAME_INFO.Directory的值为NULL。系统中将其地址保存在nt!ObpRootDirectoryObject中,如果使用“!object poi(nt!ObpRootDirectoryObject)”会得到与“!object 0xe1000118”相同的输出。
继续看“!object /driver”的输出,Hash一列是OBJECT_DIRECTORY.HashBuckets的数组下标(索引值),可以使用“!list ” -t nt!_OBJECT_DIRECTORY_ENTRY.ChainLink -e -x /”dd @$extret l4; !object poi(@$extret+0×4) /” 0xe15849d8 “”来查看具有相同索引值的OBJECT_DIRECTORY_ENTRY结构中的信息;Address一列表示对象地址(Object Body部分),保存在OBJECT_DIRECTORY_ENTRY.Object成员中;Type表示对象类型,可以看到“/Driver”目录(对象)中保存的对象为Driver类型(即Object Body部分使用DRIVER_OBJECT结构);Name是对象的名字,从OBJECT_DIRECTORY.Name中获得。
从上面的分析中可以看出,“!object”实际上是从OBJECT_HEADER以及Object Header之前的几个结构下手,从中取得系统内对象的信息。因此,Windows对象管理器在管理对象的时候,操作的是OBJECT_HEADER与 Object Header之前的几个结构,而并不关心Object Body的内容。Object Body之前的部分实际上是一个对象的“隐私”,这部分的“隐私”完全由对象管理器来维护,所以说,对象管理器的核心就是Object Body之前的这些结构,并利用ObXxx例程来对这些结构进行操作,从而实现对象管理的能力。


by CDrea

 
原创粉丝点击