分享
 
 
 

JIURL玩玩Win2k 对象

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

JIURL玩玩Win2k 对象

作者: JIURL

主页: http://jiurl.yeah.net

日期: 2003-7-30

Windows 2000 中有如下27种对象 Directory Thread Mutant Controller Type Profile Event SymbolicLink Section EventPair Desktop Timer File WindowStation Driver WmiGuid Token Device IoCompletion Process Adapter Key Job WaitablePort Port Callback Semaphore 。这27个名字就充分说明了对象对于Win2k有多么重要。

图1

先来看看对象的样子,如图1所示。对象至少由对象头和对象体组成,而在对象头之前(比对象头地址更低的地方)还可能有些相关的信息。对于不同类型的对象来说,对象头的定义是一样的,而对象体的大小,内容是完全不一样的。可选信息,对象头,对象体是紧紧的挨在一起的。

也可以使用以下工具,增加对对象的认识。http://www.sysinternals.com 中的 Winobj ,可以观察命名空间中的对象。《 Programming the Microsoft Windows Driver Model 》一书附书CD中的工具 DevView 。这两个工具功能差不多。

对象头及可选结构

OBJECT_HEADER 之前有四种可选结构,OBJECT_NAME,OBJECT_HANDLE_DB,OBJECT_QUOTA_CHARGES ,OBJECT_CREATOR_INFO。他们是否存在,都由 OBJECT_HEADER 中的相关域进行说明。前三种结构如果存在他们的相对于OBJECT_HEADER 的位置由 OBJECT_HEADER 中的相关域进行说明。只有 OBJECT_CREATOR_INFO 结构,如果存在,就位于 OBJECT_HEADER 之前,并紧挨着 OBJECT_HEADER。

OBJECT_HEADER 的定义如下,大小24(十进制)个字节,也就是6个DWORD。

(没有特别注明的话,本文所有的类型定义来自《Undocumented Windows 2000 Secrets: A Programmer's Cookbook》一书的部分章节及其附书源码。由于这部分没有什么官方文档,所以错误不可避免,大家对这些类型定义还是要有一点怀疑)

typedef struct _OBJECT_HEADER

{

/*000*/ DWORD PointerCount; // number of references

/*004*/ DWORD HandleCount; // number of open handles

/*008*/ POBJECT_TYPE ObjectType;

/*00C*/ BYTE NameOffset; // -> OBJECT_NAME

/*00D*/ BYTE HandleDBOffset; // -> OBJECT_HANDLE_DB

/*00E*/ BYTE QuotaChargesOffset; // -> OBJECT_QUOTA_CHARGES

/*00F*/ BYTE ObjectFlags; // OB_FLAG_*

/*010*/ union

{ // OB_FLAG_CREATE_INFO ? ObjectCreateInfo : QuotaBlock

/*010*/ PQUOTA_BLOCK QuotaBlock;

/*010*/ POBJECT_CREATE_INFO ObjectCreateInfo;

/*014*/ };

/*014*/ PSECURITY_DESCRIPTOR SecurityDescriptor;

/*018*/ }

OBJECT_HEADER;

.PointerCount

ntoskrnl.exe 中的 API ObfReferenceObject(), ObReferenceObjectByHandle(), ObReferenceObjectByName(), 和 ObReferenceObjectByPointer() 增加的就是这个PointerCount, ObfDereferenceObject() 和 ObDereferenceObject() 用来减少这个值。

.HandleCount

指明有多少个这个对象的打开句柄

.ObjectType

指向 OBJECT_TYPE 结构体的指针。

.NameOffset

用 OBJECT_HEADER 的地址减去 NameOffset 的值,来定位 OBJECT_NAME 部分。

如果 NameOffset 值为0,表示这个 OBJECT_HEADER 没有 OBJECT_NAME。

用来指出对象的名字,可选信息之一。

.HandleDBOffset

用 OBJECT_HEADER 的地址减去 HandleDBOffset 的值,来定位 OBJECT_HANDLE_DB 部分。

如果 HandleDBOffset 值为0,表示这个 OBJECT_HEADER 没有 OBJECT_HANDLE_DB。

可选信息之一。

.QuotaChargesOffset

用 OBJECT_HEADER 的地址减去 QuotaChargesOffset 的值,来定位 OBJECT_QUOTA_CHARGES 部分。

如果 QuotaChargesOffset 值为0,表示这个 OBJECT_HEADER 没有 OBJECT_QUOTA_CHARGES。

可选信息之一。

.ObjectFlags

#define OB_FLAG_CREATE_INFO 0x01 // has OBJECT_CREATE_INFO

#define OB_FLAG_KERNEL_MODE 0x02 // created by kernel

#define OB_FLAG_CREATOR_INFO 0x04 // has OBJECT_CREATOR_INFO

#define OB_FLAG_EXCLUSIVE 0x08 // OBJ_EXCLUSIVE

#define OB_FLAG_PERMANENT 0x10 // OBJ_PERMANENT

#define OB_FLAG_SECURITY 0x20 // has security descriptor

#define OB_FLAG_SINGLE_PROCESS 0x40 // no HandleDBList

也就是说,第0位,OB_FLAG_CREATE_INFO 位。第1位,OB_FLAG_KERNEL_MODE 位。第2位,OB_FLAG_CREATOR_INFO位。第3位,OB_FLAG_EXCLUSIVE 位。第4位,OB_FLAG_PERMANENT 位。第5位,OB_FLAG_SECURITY 位。第6位,OB_FLAG_SINGLE_PROCESS 位。

如果 OB_FLAG_CREATOR_INFO 位为1,则在 OBJECT_HEADER 之前,紧挨着一个 OBJECT_CREATOR_INFO 结构。

注意 OBJECT_CREATE_INFO 与 OBJECT_CREATOR_INFO 是不同的。

.QuotaBlock 或者 .ObjectCreateInfo

如果 ObjectFlags 的 OB_FLAG_CREATE_INFO 位为1,

则这里为 ObjectCreateInfo ,一个指针,指向一个 OBJECT_CREATE_INFO 结构。OBJECT_CREATE_INFO 为可选信息之一。

否则,这里为 QuotaBlock ,一个指针,指向一个 QUOTA_BLOCK 结构,

提供关于paged 和 non-paged 内存池使用情况的信息。PspDefaultQuotaBlock 一个全局变量,保存着 DefaultQuotaBlock。很多对象的 QuotaBlock 中的地址和 PspDefaultQuotaBlock 一样,指向DefaultQuotaBlock。这个 union 的值可以为 NULL。

.SecurityDescriptor

如果 ObjectFlags 的 OB_FLAG_SECURITY 位为1,

则 SecurityDescriptor 为一个指针,指向一个 SECURITY_DESCRIPTOR 结构。

如果 ObjectFlags 的 OB_FLAG_SECURITY 位为0,

则 SecurityDescriptor 值为 NULL。

OBJECT_NAME 定义如下

typedef struct _OBJECT_NAME

{

/*000*/ POBJECT_DIRECTORY Directory;

/*004*/ UNICODE_STRING Name;

/*00C*/ DWORD Reserved;

/*010*/ }

OBJECT_NAME;

.Directory

指向所在 Directory 对应的 Directory Object。可以为空。

.Name

对象的名字,是一个UNICODE_STRING结构,

UNICODE_STRING结构在ddk中定义如下。

typedef struct _UNICODE_STRING {

USHORT Length;

USHORT MaximumLength;

PWSTR Buffer;

} UNICODE_STRING *PUNICODE_STRING;

.Reserved

保留

其他的可选结构我们将在后面介绍。

下面我们看一个实际的例子,一个名字叫"\"的Directory 类型对象,它其实就是Directory的根对象。

kd> !object !object Object: 8141ecd0 Type: (81452820) Directory

ObjectHeader: 8141ecb8

HandleCount: 0 PointerCount: 34

Directory Object: 00000000 Name: 120 symbolic links snapped through this directory

HashBucket[ 00 ]: 8141b930 Directory 'ArcName'

HashBucket[ 01 ]: e2f7b600 Port 'SeLsaCommandPort'

HashBucket[ 03 ]: e1007390 Key '\REGISTRY'

HashBucket[ 07 ]: e2bb16e0 Port 'DbgUiApiPort'

HashBucket[ 09 ]: 810e7e00 Directory 'NLS'

HashBucket[ 10 ]: 8141ea50 SymbolicLink 'DosDevices'

HashBucket[ 13 ]: e14088a0 Port 'SeRmCommandPort'

HashBucket[ 14 ]: 810e8540 Mutant 'NlsCacheMutant'

e2fdb4c0 Port 'LsaAuthenticationPort'

81421450 Device 'Dfs'

810fc870 Event 'LanmanServerAnnounceEvent'

HashBucket[ 16 ]: 81416530 Directory 'Driver'

HashBucket[ 17 ]: e17c79c0 Port 'DbgSsApiPort'

HashBucket[ 18 ]: 81437d30 Directory 'WmiGuid'

HashBucket[ 19 ]: 8141b850 Directory 'Device'

HashBucket[ 20 ]: 810f68d0 Directory 'Windows'

HashBucket[ 21 ]: 810a7e70 Event 'SAM_SERVICE_STARTED'

HashBucket[ 22 ]: 810f67f0 Directory 'RPC Control'

e1408aa0 Port 'SmApiPort'

81422af0 Device 'Fat'

HashBucket[ 23 ]: 810e8730 Directory 'BaseNamedObjects'

HashBucket[ 24 ]: 8141eb10 Directory '??'

81416450 Directory 'FileSystem'

HashBucket[ 26 ]: 8141ebf0 Directory 'ObjectTypes'

HashBucket[ 27 ]: 8141ba10 Directory 'Security'

e302e6e0 Port 'ErrorLogPort'

HashBucket[ 31 ]: 8141bbb0 SymbolicLink 'SystemRoot'

HashBucket[ 32 ]: 8141d2d0 Directory 'Callback'

HashBucket[ 33 ]: 810ab330 Event 'EFSInitEvent'

810f7df0 Event 'SeLsaInitEvent'

810ec9d0 Event 'UniqueSessionIdEvent'

HashBucket[ 35 ]: 810f5f50 Directory 'KnownDlls'

\\ 从输出中我们可以看到 ObjectHeader: 8141ecb8 ,ObjectHeader结构大小为24个字节,也就是6个DWORD。

kd> dd 8141ecb8 l 6

dd 8141ecb8 l 6

8141ecb8 00000023 00000000 81452820 32000010

8141ecc8 00000001 e10010f8

\\ 分析一下这个 ObjectHeader 结构的每个域的值

/*000*/ DWORD PointerCount; // number of references

00000023

/*004*/ DWORD HandleCount; // number of open handles

00000000

/*008*/ POBJECT_TYPE ObjectType;

81452820

/*00C*/ BYTE NameOffset; // -> OBJECT_NAME

10

\\ 有 OBJECT_NAME

/*00D*/ BYTE HandleDBOffset; // -> OBJECT_HANDLE_DB

00

\\ 没有 OBJECT_HANDLE_DB

/*00E*/ BYTE QuotaChargesOffset; // -> OBJECT_QUOTA_CHARGES

00

\\ 没有 OBJECT_QUOTA_CHARGES

/*00F*/ BYTE ObjectFlags; // OB_FLAG_*

32

\\ 32(hex)=00110010(bin) ,即 OB_FLAG_KERNEL_MODE,OB_FLAG_PERMANENT,OB_FLAG_SECURITY 这3位被设立。

/*010*/ union

{ // OB_FLAG_CREATE_INFO ? ObjectCreateInfo : QuotaBlock

/*010*/ PQUOTA_BLOCK QuotaBlock;

/*010*/ POBJECT_CREATE_INFO ObjectCreateInfo;

/*014*/ };

00000001

\\ OB_FLAG_CREATE_INFO位没有被设立,但从值来看也不是一个 PQUOTA_BLOCK QuotaBlock。

/*014*/ PSECURITY_DESCRIPTOR SecurityDescriptor;

e10010f8

\\ OB_FLAG_SECURITY 标志位被设立说明了,SecurityDescriptor 不为空。这里是一个PSECURITY_DESCRIPTOR指针,我们将在后面进行讨论

ObjectHeader四个可选信息中 HandleDBOffset,QuotaChargesOffset 值都为0,表示没有相应的结构,NameOffset 值为 10,表示有相应的OBJECT_NAME结构,并且位于 ObjectHeader地址-0x10处。注意 OBJECT_NAME 结构长为0x10。可以看到 OBJECT_NAME 和 ObjectHeader 是紧挨着的。下面我们就来看看 OBJECT_NAME 中的内容。

kd> dd 8141ecb8-10 l 4

dd 8141ecb8-10 l 4

8141eca8 00000000 00040002 81452148 00000000

/*000*/ POBJECT_DIRECTORY Directory;

00000000

// 所在Directory的指针为0,是由于对象"\"是根,不在任何目录下。比如 directory对象\KnownDlls,它的这个值就不为0。我得到的值为 8141ecd0 ,正是 对象"\" 的 ObjectBody 的地址。

/*004*/ UNICODE_STRING Name;

0002 0004 81452148

// UNICODE_STRING 的 PWSTR Buffer 值为 81452148

kd> du 81452148

du 81452148

81452148 "\"

// 可以看到对象的名字叫"\"

/*00C*/ DWORD Reserved;

00000000

对象头的简单分析就到这里,对于不同类型的对象,对象头的格式是一样的。

Directory 类型的对象

现在我们继续分析Directory类型的对象体。不同类型的对象由于用途不同,对象体的结构是完全不一样的,就象图1中的情况那样。某种类型对象体的内容是由该类型的需要所决定的。对于 Directory 类型对象的用途是什么呢?这里的 Directory 指的不是文件系统目录,而是一个对象的目录,从 WinObj 这样的工具我们就能看到这一点。对象目录的组织使用和文件系统目录的组织相似的层次结构。从前面使用kd得到的输出,我们可以看到kd至少可以从Directory类型的对象体中得到下面的信息。

kd> !object !object Object: 8141ecd0 Type: (81452820) Directory

...

HashBucket[ 13 ]: e14088a0 Port 'SeRmCommandPort'

HashBucket[ 14 ]: 810e8540 Mutant 'NlsCacheMutant'

e2fdb4c0 Port 'LsaAuthenticationPort'

81421450 Device 'Dfs'

810fc870 Event 'LanmanServerAnnounceEvent'

HashBucket[ 16 ]: 81416530 Directory 'Driver'

HashBucket[ 17 ]: e17c79c0 Port 'DbgSsApiPort'

...

我们来看 Directory类型的对象体 OBJECT_DIRECTORY 的定义

#define OBJECT_HASH_TABLE_SIZE 37

typedef struct _OBJECT_DIRECTORY

{

/*000*/ POBJECT_DIRECTORY_ENTRY HashTable [OBJECT_HASH_TABLE_SIZE];

/*094*/ POBJECT_DIRECTORY_ENTRY CurrentEntry;

/*098*/ BOOLEAN CurrentEntryValid;

/*099*/ BYTE Reserved1;

/*09A*/ WORD Reserved2;

/*09C*/ DWORD Reserved3;

/*0A0*/ }

OBJECT_DIRECTORY;

typedef struct _OBJECT_DIRECTORY_ENTRY

{

/*000*/ struct _OBJECT_DIRECTORY_ENTRY *NextEntry;

/*004*/ POBJECT Object;

/*008*/ }

OBJECT_DIRECTORY_ENTRY;

从定义中我们看到 OBJECT_DIRECTORY 中主要是一个37项的哈希表。每项是一个指向 OBJECT_DIRECTORY_ENTRY 的指针。指向一个 OBJECT_DIRECTORY_ENTRY 组成的链。OBJECT_DIRECTORY_ENTRY 结构有两个域,第一个域是指向链的下一个OBJECT_DIRECTORY_ENTRY的指针,如果值为空的话,表明链已经结束了。第二域是指向一个某种类型对象的对象体的指针。比如上面例子中 HashBucket[ 16 ]: 81416530 Directory 'Driver' 的链上只有一项,该项的第二个域指向一个Directory类型对象。当有一个新的对象想要放入某个目录下,或者需要根据对象的名字查找对象时,通过哈希函数来确定对象该在哈希表的37个表目中的哪一个链上。这里所做的就是通过对对象名的每一个字符做一定的计算,最后得到一个数,用这个数除以37,取余数,得到了0-36 中的某个数,来确定所在的哈希表目。也就是用哈希函数对对象名计算来确定该对象应该在哈希表中的什么地方。如果想了解那个哈希函数具体算法,可以跟一下 ObpLookupDirectoryEntry 函数。使用 kd? ObpLookupDirectoryEntry 获得该函数的入口地址,然后用SoftICE断该地址。我用SoftICE大概跟了一下,这个函数有3个参数,第一个参数是一个指向OBJECT_DIRECTORY的指针,指定查找的目录。第二个参数是一个指向UNICODE_STRING的指针,指定要查找的名字。我就不详细叙述了。如果只是想找到某个名字的对象的话,可以遍历整个目录的每一个OBJECT_DIRECTORY_ENTRY,这样虽然慢一些,不过如果将来哈希函数有所变化的话,不会受到影响。 OBJECT_DIRECTORY 中使用哈希表的原因是为了加快查找速度。如果不使用哈希表的话,可以每个目录只维护一个对象链表,不过那样的话,根据对象名在某个目录下查找该对象的指针,有可能得遍历该目录下的每个对象。而使用了哈希表,利用哈希函数的计算,将很快确定只在该目录下的一部分对象中遍历。目前目录对象哈希表的项数为37。影响项数的一个因素是通常一个目录下可能会有多少对象,应该尽可能保证链上只有一项,或者链很短,来保证查找的速度。在 kd 中使用 !object 命令观察几个对象目录,可以看到Win2k使用的哈希函数,和37作为哈希表项数,效果还是不错的,对象比较均匀的分布在哈希表中,而且很多哈希表项对应的链上只有一个对象,有多个对象的链也都不是很长。

下面我们来看实际的例子,从前面 kd 的输出

kd> !object !object Object: 8141ecd0 Type: (81452820) Directory

ObjectHeader: 8141ecb8

...

我们看到对象"\"的对象头在 8141ecb8 ,对象体在 8141ecd0,对象头结构大小为0x18,也可以看出对象头和对象体是紧挨在一起的。下面我们来分析目录类型对象"\"的对象体。

kd> dd 8141ecd0 l a0/4

dd 8141ecd0 l a0/4

8141ecd0 e1008c68 e2f7c008 00000000 e10073c8

8141ece0 00000000 00000000 00000000 e2bac088

8141ecf0 00000000 e2bea1a8 e10001e8 00000000

8141ed00 00000000 e13891a8 e2bea328 00000000

8141ed10 e131eb08 e2baf188 e132f208 e1008ba8

8141ed20 e17b6708 e13d4268 e17b65e8 e135a768

8141ed30 e1007f28 00000000 e10004a8 e1007708

8141ed40 00000000 00000000 00000000 e1008b08

8141ed50 e10003a8 e2ffe508 00000000 e17bca68

8141ed60 00000000 8141ecf4 00780001 00000000

前面使用kd得到的输出是

HashBucket[ 00 ]: 8141b930 Directory 'ArcName'

...

HashBucket[ 14 ]: 810e8540 Mutant 'NlsCacheMutant'

e2fdb4c0 Port 'LsaAuthenticationPort'

81421450 Device 'Dfs'

810fc870 Event 'LanmanServerAnnounceEvent'

...

HashBucket[ 35 ]: 810f5f50 Directory 'KnownDlls'

哈希表的第0项值为 e1008c68,是个POBJECT_DIRECTORY_ENTRY

kd> dd e1008c68 l 2

dd e1008c68 l 2

e1008c68 00000000 8141b930

可以看到指向的OBJECT_DIRECTORY_ENTRY的.NextEntry为空,.Object 为 8141b930

用kd看到8141b930果然是一个对象,而且这个对象是一个目录类型的对象,通过它,又可以找到一些对象。

kd> !object 8141b930

!object 8141b930

Object: 8141b930 Type: (81452820) Directory

ObjectHeader: 8141b918

HandleCount: 0 PointerCount: 12

Directory Object: 8141ecd0 Name: ArcName

HashBucket[ 00 ]: 813c4c90 SymbolicLink 'multi(0)disk(0)rdisk(0)partition(3)'

814070d0 SymbolicLink 'multi(0)disk(0)rdisk(0)'

HashBucket[ 03 ]: 813c4c30 SymbolicLink 'multi(0)disk(0)rdisk(0)partition(4)'

HashBucket[ 07 ]: 813c4bd0 SymbolicLink 'multi(0)disk(0)rdisk(0)partition(5)'

HashBucket[ 10 ]: 813c4b70 SymbolicLink 'multi(0)disk(0)rdisk(0)partition(6)'

HashBucket[ 14 ]: 813c4b10 SymbolicLink 'multi(0)disk(0)rdisk(0)partition(7)'

HashBucket[ 17 ]: 813c4ab0 SymbolicLink 'multi(0)disk(0)rdisk(0)partition(8)'

HashBucket[ 21 ]: 813c4a50 SymbolicLink 'multi(0)disk(0)rdisk(0)partition(9)'

HashBucket[ 30 ]: 81420370 SymbolicLink 'multi(0)disk(0)rdisk(0)partition(1)'

HashBucket[ 33 ]: 813e7230 SymbolicLink 'multi(0)disk(0)rdisk(0)partition(2)'

813f9450 SymbolicLink 'multi(0)disk(0)fdisk(0)'

哈希表的第14项值为 e2bea328,是个POBJECT_DIRECTORY_ENTRY

kd> dd e2bea328 l 2

dd e2bea328 l 2

e2bea328 e13fee68 810e8540

kd> !object 810e8540

!object 810e8540

Object: 810e8540 Type: (8141ccc0) Mutant

ObjectHeader: 810e8528

HandleCount: 14 PointerCount: 15

Directory Object: 8141ecd0 Name: NlsCacheMutant

// 链表的第一项中,下一项地址为 e13fee68 ,对象地址为 810e8540

kd> dd e13fee68 l 2

dd e13fee68 l 2

e13fee68 e13c02e8 e2fdb4c0

kd> !object e2fdb4c0

!object e2fdb4c0

Object: e2fdb4c0 Type: (81416e80) Port

ObjectHeader: e2fdb4a8

HandleCount: 1 PointerCount: 29

Directory Object: 8141ecd0 Name: LsaAuthenticationPort

// 链表的第二项中,下一项地址为 e13c02e8 ,对象地址为 e2fdb4c0

kd> dd e13c02e8 l 2

dd e13c02e8 l 2

e13c02e8 e178c908 81421450

kd> !object 81421450

!object 81421450

Object: 81421450 Type: (81416920) Device

ObjectHeader: 81421438

HandleCount: 0 PointerCount: 2

Directory Object: 8141ecd0 Name: Dfs

// 链表的第三项中,下一项地址为 e178c908 ,对象地址为 81421450

kd> dd e178c908 l 2

dd e178c908 l 2

e178c908 00000000 810fc870

kd> !object 810fc870

!object 810fc870

Object: 810fc870 Type: (8141e460) Event

ObjectHeader: 810fc858

HandleCount: 1 PointerCount: 3

Directory Object: 8141ecd0 Name: LanmanServerAnnounceEvent

// 链表的第四项中,下一项地址为空,表示链表结束 ,对象地址为 810fc870

我们看到了目录类型对象中通过哈希表和链表来保存另一些对象的指针,包括目录对象。现在我们只要知道了目录类型对象"\"的地址("\"是根目录,它保存有下一级目录对象的指针)我们就可以找到所有目录下的对象。Win2k中全局变量 ObpRootDirectoryObject 中保存着目录对象"\"的地址。在 Win2k Build 2195 上,这个全局变量的地址为 8046ac24 。可以通过kd得到

kd> ? ObpRootDirectoryObject

? ObpRootDirectoryObject

Evaluate expression: -2142852060 = 8046ac24

dd 8046ac24 l 1

8046ac24 8141ecd0

我们前面已经看到了 8141ecd0 是目录对象"\"的对象体的地址。

我们在WinObj中,看不到任何的 Process, Thread 类型的对象。这是由于任何的 Directory Object 中都没有他们的对象指针。他们当然是存在的,否则就没必要弄个 Process, Thread 类型。他们其实就是 EPROCESS 和 ETHREAD。也就是说,EPROCESS,ETHREAD之前就有OBJECT_HEADER。

kd> !process 8 0

!process 8 0

Searching for Process with Cid == 8

PROCESS 8141e020 SessionId: 0 Cid: 0008 Peb: 00000000 ParentCid: 0000

DirBase: 00030000 ObjectTable: 81452a68 TableSize: 108.

Image: System

\\ System 进程的 EPROCESS 地址为 8141e020

kd> !object 8141e020

!object 8141e020

Object: 8141e020 Type: (814524e0) Process

ObjectHeader: 8141e008

HandleCount: 2 PointerCount: 36

kd> dd 8141e008 l 6

dd 8141e008 l 6

8141e008 00000024 00000002 814524e0 22000000

8141e018 804699c0 e1000618

很多的对象都不放在任何目录下。

关于 Directory Object 就介绍到这里。

Type 类型的对象

在前面介绍 OBJECT_HEADER 的时候,我们没有分析其中的 /*008*/ POBJECT_TYPE ObjectType; 这个域。这是一个非常重要的域,它是一个指针,指向包含对象类型的信息。前面例子中

kd> !object !object Object: 8141ecd0 Type: (81452820) Directory

...

kd> dd 8141ecb8 l 6

dd 8141ecb8 l 6

8141ecb8 00000023 00000000 81452820 32000010

8141ecc8 00000001 e10010f8

kd 可以知道"\"是 Directory 类型的对象,就是通过 POBJECT_TYPE ObjectType找到相关结构,获得的信息。

实际上 OBJECT_TYPE 也是一个对象,它就是 Type 类型的对象。它也象图1中显示的那样,有对象头,对象体和可选信息。

我们看到了"\"的 Type Object 地址为 81452820 ,我们现在先分析一下这个 Type Object 的头。

kd> !object 81452820

!object 81452820

Object: 81452820 Type: (81452920) Type

ObjectHeader: 81452808

HandleCount: 0 PointerCount: 1

Directory Object: 8141ebf0 Name: Directory

头部应该在 0x81452820-0x18=0x81452808 处(原因是头部紧挨着对象体,头部在前,头部大小0x18个字节)从 kd 的输出中,看到 kd 也是这么认为的。

kd> dd 81452808 l 6

dd 81452808 l 6

81452808 00000001 00000000 81452920 17000020

81452818 00000000 00000000

/*000*/ DWORD PointerCount; // number of references

00000001

/*004*/ DWORD HandleCount; // number of open handles

00000000

/*008*/ POBJECT_TYPE ObjectType;

81452920

/*00C*/ BYTE NameOffset; // -> OBJECT_NAME

20

/*00D*/ BYTE HandleDBOffset; // -> OBJECT_HANDLE_DB

00

/*00E*/ BYTE QuotaChargesOffset; // -> OBJECT_QUOTA_CHARGES

00

/*00F*/ BYTE ObjectFlags; // OB_FLAG_*

17

17(hex)=00010111(bin) OB_FLAG_CREATE_INFO OB_FLAG_KERNEL_MODE OB_FLAG_CREATOR_INFO OB_FLAG_PERMANENT

/*010*/ union

{ // OB_FLAG_CREATE_INFO ? ObjectCreateInfo : QuotaBlock

/*010*/ PQUOTA_BLOCK QuotaBlock;

/*010*/ POBJECT_CREATE_INFO ObjectCreateInfo;

/*014*/ };

00000000

/*014*/ PSECURITY_DESCRIPTOR SecurityDescriptor;

00000000

看到存在 OBJECT_NAME,并且在偏移20处,也就是0x81452808-0x20处。

kd> dd 81452808-20 l 4

dd 81452808-20 l 4

814527e8 8141ebf0 00140012 e1001948 00000000

// 所在目录的对象地址为 8141ebf0

kd> !object 8141ebf0

!object 8141ebf0

Object: 8141ebf0 Type: (81452820) Directory

...

// 和从WinObj 中看到的一样是Directory类型对象"Type"

kd> du e1001948

du e1001948

e1001948 "Directory"

// 类型对象的名字叫 "Directory"

OBJECT_HEADER中的标志OB_FLAG_CREATOR_INFO被设立,表明 OBJECT_CREATOR_INFO 结构存在,这个可选结构不像其他三个需要指明偏移,这个结构如果存在就一定位于 OBJECT_HEADER 之前,并紧挨着 OBJECT_HEADER。

OBJECT_CREATOR_INFO 结构定义如下

typedef struct _OBJECT_CREATOR_INFO

{

/*000*/ LIST_ENTRY ObjectList; // OBJECT_CREATOR_INFO

/*008*/ HANDLE UniqueProcessId;

/*00C*/ WORD Reserved1;

/*00E*/ WORD Reserved2;

/*010*/ }

OBJECT_CREATOR_INFO;

typedef struct _LIST_ENTRY {//from ntdef.h

struct _LIST_ENTRY *Flink;

struct _LIST_ENTRY *Blink;

} LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY;

.ObjectList 同一类型的对象被这个双向链表链在一起。

.UniqueProcessId 为创建这个对象的进程ID。

// 由于在对象头之前,并紧挨着对象头,大小为0x10字节,所以

kd> dd 81452808-10 l 4

dd 81452808-10 l 4

814527f8 814526f8 814528f8 00000000 00000000

/*000*/ LIST_ENTRY ObjectList; // OBJECT_CREATOR_INFO

814526f8 814528f8

/*008*/ HANDLE UniqueProcessId;

00000000

我们用 kd 遍历一下 ObjectList

kd> dd 814527f8 l 4

dd 814527f8 l 4

814527f8 814526f8 814528f8 00000000 00000000

// 814527f8 就是 81452808-10

kd> ? 814526f8+28

? 814526f8+28

Evaluate expression: -2126174432 = 81452720

// 由于 OBJECT_CREATOR_INFO 大小 0x10,紧跟着 OBJECT_HEADER 大小 0x18,紧跟着的才是对象体

而 !object 的参数是对象体的指针

kd> !object 81452720

!object 81452720

Object: 81452720 Type: (81452920) Type

ObjectHeader: 81452708

HandleCount: 0 PointerCount: 1

Directory Object: 8141ebf0 Name: SymbolicLink

// 可以看到链上的下一项是Type Object "SymbolicLink",可见ObjectList是同一类型的对象的链

kd> dd 814526f8 l 4

dd 814526f8 l 4

814526f8 814525f8 814527f8 00000000 00000000

// 我们顺着LIST_ENTRY 的Flink 一直走下去,直到遇到814527f8,表明已经循环了。

kd> dd 814525f8 l 4

dd 814525f8 l 4

814525f8 814524b8 814526f8 00000000 00000000

kd> dd 814524b8 l 4

dd 814524b8 l 4

814524b8 814523b8 814525f8 00000000 00000000

kd> dd 814523b8 l 4

dd 814523b8 l 4

814523b8 814522b8 814524b8 00000000 00000000

kd> dd 814522b8 l 4

dd 814522b8 l 4

814522b8 8141e438 814523b8 00000000 00000000

kd> dd 8141e438 l 4

dd 8141e438 l 4

8141e438 8141e338 814522b8 00000008 00000000

kd> dd 8141e338 l 4

dd 8141e338 l 4

8141e338 8141cc98 8141e438 00000008 00000000

kd> dd 8141cc98 l 4

dd 8141cc98 l 4

8141cc98 8141cb98 8141e338 00000008 00000000

kd> dd 8141cb98 l 4

dd 8141cb98 l 4

8141cb98 8141c878 8141cc98 00000008 00000000

kd> dd 8141c878 l 4

dd 8141c878 l 4

8141c878 8141c778 8141cb98 00000008 00000000

kd> dd 8141c778 l 4

dd 8141c778 l 4

8141c778 8141c678 8141c878 00000008 00000000

kd> dd 8141c678 l 4

dd 8141c678 l 4

8141c678 8141c578 8141c778 00000008 00000000

kd> dd 8141c578 l 4

dd 8141c578 l 4

8141c578 8141c478 8141c678 00000008 00000000

kd> dd 8141c478 l 4

dd 8141c478 l 4

8141c478 8141b738 8141c578 00000008 00000000

kd> dd 8141b738 l 4

dd 8141b738 l 4

8141b738 8141b098 8141c478 00000008 00000000

kd> dd 8141b098 l 4

dd 8141b098 l 4

8141b098 81416e58 8141b738 00000008 00000000

kd> dd 81416e58 l 4

dd 81416e58 l 4

81416e58 81416d58 8141b098 00000008 00000000

kd> dd 81416d58 l 4

dd 81416d58 l 4

81416d58 81416af8 81416e58 00000008 00000000

kd> dd 81416af8 l 4

dd 81416af8 l 4

81416af8 814169f8 81416d58 00000008 00000000

kd> dd 814169f8 l 4

dd 814169f8 l 4

814169f8 814168f8 81416af8 00000008 00000000

kd> dd 814168f8 l 4

dd 814168f8 l 4

814168f8 814167f8 814169f8 00000008 00000000

kd> dd 814167f8 l 4

dd 814167f8 l 4

814167f8 814166f8 814168f8 00000008 00000000

kd> dd 814166f8 l 4

dd 814166f8 l 4

814166f8 814165f8 814167f8 00000008 00000000

kd> dd 814165f8 l 4

dd 814165f8 l 4

814165f8 814379b8 814166f8 00000008 00000000

kd> dd 814379b8 l 4

dd 814379b8 l 4

814379b8 81452958 814165f8 00000008 003f0000

kd> dd 81452958 l 4

dd 81452958 l 4

81452958 814528f8 814379b8 000a0008 e1000ce8

kd> dd 814528f8 l 4

dd 814528f8 l 4

814528f8 814527f8 81452958 00000000 00000000

kd> dd 814527f8 l 4

dd 814527f8 l 4

814527f8 814526f8 814528f8 00000000 00000000

// 遇到814527f8,表明已经循环了。

下面我们看一下 Type Object 的对象体

typedef struct _OBJECT_TYPE

{

/*000*/ ERESOURCE Lock;

/*038*/ LIST_ENTRY ObjectListHead; // OBJECT_CREATOR_INFO

/*040*/ UNICODE_STRING ObjectTypeName; // see above

/*048*/ union

{

/*048*/ PVOID DefaultObject; // ObpDefaultObject

/*048*/ DWORD Code; // File: 5C, WaitablePort: A0

};

/*04C*/ DWORD ObjectTypeIndex; // OB_TYPE_INDEX_*

/*050*/ DWORD ObjectCount;

/*054*/ DWORD HandleCount;

/*058*/ DWORD PeakObjectCount;

/*05C*/ DWORD PeakHandleCount;

/*060*/ OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;

/*0AC*/ DWORD ObjectTypeTag; // OB_TYPE_TAG_*

/*0B0*/ }

OBJECT_TYPE;

// 地址 81452820,OBJECT_TYPE 结构长0xB0个字节

kd> dd 81452820 l b0/4

dd 81452820 l b0/4

81452820 81452720 81452920 00000000 00000000

81452830 00000000 00000000 00000000 00000000

81452840 00000000 00000000 00000000 00000000

81452850 00000000 00000000 81452858 81452858

81452860 00140012 e1001948 00000000 00000002

81452870 00000018 0000002d 00000018 00000032

81452880 0000004c 00000100 00020003 0002000c

81452890 00020003 000f000f 000f000f 00000000

814528a0 00000000 00000000 000000d0 00000000

814528b0 00000000 00000000 00000000 00000000

814528c0 804bfb34 00000000 00000000 65726944

/*000*/ ERESOURCE Lock;

81452820 81452720 81452920 00000000 00000000

81452830 00000000 00000000 00000000 00000000

81452840 00000000 00000000 00000000 00000000

81452850 00000000 00000000

/*038*/ LIST_ENTRY ObjectListHead; // OBJECT_CREATOR_INFO

81452858 81452858

/*040*/ UNICODE_STRING ObjectTypeName;

0012 0014 e1001948

// 看看 ObjectTypeName 中所指的字符串吧,

kd> du e1001948

du e1001948

e1001948 "Directory"

// 它是 "Directory"

/*048*/ PVOID DefaultObject; // ObpDefaultObject

/*048*/ DWORD Code; // File: 5C, WaitablePort: A0

00000000

/*04C*/ DWORD ObjectTypeIndex; // OB_TYPE_INDEX_*

00000002

// #define OB_TYPE_INDEX_DIRECTORY 2 // [Dire] "Directory"

系统应该是由这里来判断类型的,类型名只是给人看的。其他类型的定义将在后面列出。

/*050*/ DWORD ObjectCount;

00000018

/*054*/ DWORD HandleCount;

00000038

/*058*/ DWORD PeakObjectCount;

00000018

/*05C*/ DWORD PeakHandleCount;

00000044

/*060*/ OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;

81452880 0000004c 00000100 00020003 0002000c

81452890 00020003 000f000f 000f000f 00000000

814528a0 00000000 00000000 000000d0 00000000

814528b0 00000000 00000000 00000000 00000000

814528c0 804bfb34 00000000 00000000

/*0AC*/ DWORD ObjectTypeTag; // OB_TYPE_TAG_*

65726944

// 就是ascii的"eriD" ,#define OB_TYPE_TAG_DIRECTORY 'eriD' // [Dire] "Directory"

其他类型的定义将在后面列出。

OBJECT_TYPE_INITIALIZER 结构定义如下

typedef struct _OBJECT_TYPE_INITIALIZER

{

/*000*/ WORD Length; //0x004C

/*002*/ BOOLEAN UseDefaultObject;//OBJECT_TYPE.DefaultObject

/*003*/ BOOLEAN Reserved1;

/*004*/ DWORD InvalidAttributes;

/*008*/ GENERIC_MAPPING GenericMapping;

/*018*/ ACCESS_MASK ValidAccessMask;

/*01C*/ BOOLEAN SecurityRequired;

/*01D*/ BOOLEAN MaintainHandleCount; // OBJECT_HANDLE_DB

/*01E*/ BOOLEAN MaintainTypeList; // OBJECT_CREATOR_INFO

/*01F*/ BYTE Reserved2;

/*020*/ BOOL PagedPool;

/*024*/ DWORD DefaultPagedPoolCharge;

/*028*/ DWORD DefaultNonPagedPoolCharge;

/*02C*/ NTPROC DumpProcedure;

/*030*/ NTPROC OpenProcedure;

/*034*/ NTPROC CloseProcedure;

/*038*/ NTPROC DeleteProcedure;

/*03C*/ NTPROC_VOID ParseProcedure;

/*040*/ NTPROC_VOID SecurityProcedure; // SeDefaultObjectMethod

/*044*/ NTPROC_VOID QueryNameProcedure;

/*048*/ NTPROC_BOOLEAN OkayToCloseProcedure;

/*04C*/ }

OBJECT_TYPE_INITIALIZER;

/*000*/ WORD Length; //0x004C

004c

/*002*/ BOOLEAN UseDefaultObject;//OBJECT_TYPE.DefaultObject

00

/*003*/ BOOLEAN Reserved1;

00

/*004*/ DWORD InvalidAttributes;

00000100

/*008*/ GENERIC_MAPPING GenericMapping;

struct _GENERIC_MAPPING (sizeof=16)

+00 uint32 GenericRead

+04 uint32 GenericWrite

+08 uint32 GenericExecute

+0c uint32 GenericAll

00020003 0002000c

/*018*/ ACCESS_MASK ValidAccessMask;

typedef ULONG ACCESS_MASK;

00020003

/*01C*/ BOOLEAN SecurityRequired;

0f

/*01D*/ BOOLEAN MaintainHandleCount; // OBJECT_HANDLE_DB

00

/*01E*/ BOOLEAN MaintainTypeList; // OBJECT_CREATOR_INFO

0f

/*01F*/ BYTE Reserved2;

00

/*020*/ BOOL PagedPool;

00000000

/*024*/ DWORD DefaultPagedPoolCharge;

00000000

/*028*/ DWORD DefaultNonPagedPoolCharge;

000000d0

/*02C*/ NTPROC DumpProcedure;

00000000

/*030*/ NTPROC OpenProcedure;

00000000

/*034*/ NTPROC CloseProcedure;

00000000

/*038*/ NTPROC DeleteProcedure;

00000000

/*03C*/ NTPROC_VOID ParseProcedure;

00000000

/*040*/ NTPROC_VOID SecurityProcedure; // SeDefaultObjectMethod

804bfb34

kd> u 804bfb34

u 804bfb34

ntoskrnl!SeDefaultObjectMethod:

/*044*/ NTPROC_VOID QueryNameProcedure;

00000000

/*048*/ NTPROC_BOOLEAN OkayToCloseProcedure;

00000000

可以看到 Type Object 中的 OBJECT_TYPE_INITIALIZER 中有用于保存了函数例程的地方。

而关于这些函数概括性的介绍可以参考 《Inside Windows 2000 Third Edition》"Chapter 3 System Mechanisms" 中的 "Object Manager" 中的 Object Methods 部分。

Type Object 的对象体的描述就到这里。

对于 Type Object 还有几个问题需要注意

对于同一个类型的对象,他们的对象头中指向类型的指针,指到的是同一个地址。

比如,对于 Directory 类型的对象,他们指向类型的指针都指向 Type Object "Directory"

kd> !object \Device\Harddiskdmvolumes

!object \Device\Harddiskdmvolumes

Object: 813d2890 Type: (81452820) Directory

\\ 注意对象 \Device\Harddiskdmvolumes 的类型指针指向 81452820

kd> !object \Device\Harddiskdmvolumes\physicaldmvolumes

!object \Device\Harddiskdmvolumes\physicaldmvolumes

Object: 813d26d0 Type: (81452820) Directory

\\ 注意对象 \Device\Harddiskdmvolumes\physicaldmvolumes 的类型指针指向 81452820

所以,如果没有新的类型加入的话,类型对象一共就27个。

所有的 Type Object 的 OBJECT_HEADER 中的 ObjectType 都指向名字叫"Type"的 Type Object。

名字叫"Type"的 Type Object,也是Type Object,所以它的OBJECT_HEADER 中的 ObjectType 指向自己。

kd> !object 81452920

!object 81452920

Object: 81452920 Type: (81452920) Type

ObjectHeader: 81452908

HandleCount: 0 PointerCount: 1

Directory Object: 8141ebf0 Name: Type

就是说所有的类型对象的对象头中的 ObjectType 指针,指向27个类型对象中的叫"Type"的那个。而叫"Type"的那个类型对象的对象头中的 ObjectType 指针,指向自己。

所有的类型对象被放在了 \ObjectTypes\ 下,我们可以在"\"目录对象的结构中找"ObjectTypes"目录对象,来得到所有的类型对象的指针。也可以通过一个叫 ObpTypeDirectoryObject 的全局变量,这个全局变量中放着"ObjectTypes"目录对象的地址。使用第一种方法保险一些。

下面列出 ObjectTypeIndex 和 ObjectTypeTag

#define OB_TYPE_INDEX_TYPE 1 // [ObjT] "Type"

#define OB_TYPE_INDEX_DIRECTORY 2 // [Dire] "Directory"

#define OB_TYPE_INDEX_SYMBOLIC_LINK 3 // [Symb] "SymbolicLink"

#define OB_TYPE_INDEX_TOKEN 4 // [Toke] "Token"

#define OB_TYPE_INDEX_PROCESS 5 // [Proc] "Process"

#define OB_TYPE_INDEX_THREAD 6 // [Thre] "Thread"

#define OB_TYPE_INDEX_JOB 7 // [Job ] "Job"

#define OB_TYPE_INDEX_EVENT 8 // [Even] "Event"

#define OB_TYPE_INDEX_EVENT_PAIR 9 // [Even] "EventPair"

#define OB_TYPE_INDEX_MUTANT 10 // [Muta] "Mutant"

#define OB_TYPE_INDEX_CALLBACK 11 // [Call] "Callback"

#define OB_TYPE_INDEX_SEMAPHORE 12 // [Sema] "Semaphore"

#define OB_TYPE_INDEX_TIMER 13 // [Time] "Timer"

#define OB_TYPE_INDEX_PROFILE 14 // [Prof] "Profile"

#define OB_TYPE_INDEX_WINDOW_STATION 15 // [Wind] "WindowStation"

#define OB_TYPE_INDEX_DESKTOP 16 // [Desk] "Desktop"

#define OB_TYPE_INDEX_SECTION 17 // [Sect] "Section"

#define OB_TYPE_INDEX_KEY 18 // [Key ] "Key"

#define OB_TYPE_INDEX_PORT 19 // [Port] "Port"

#define OB_TYPE_INDEX_WAITABLE_PORT 20 // [Wait] "WaitablePort"

#define OB_TYPE_INDEX_ADAPTER 21 // [Adap] "Adapter"

#define OB_TYPE_INDEX_CONTROLLER 22 // [Cont] "Controller"

#define OB_TYPE_INDEX_DEVICE 23 // [Devi] "Device"

#define OB_TYPE_INDEX_DRIVER 24 // [Driv] "Driver"

#define OB_TYPE_INDEX_IO_COMPLETION 25 // [IoCo] "IoCompletion"

#define OB_TYPE_INDEX_FILE 26 // [File] "File"

#define OB_TYPE_INDEX_WMI_GUID 27 // [WmiG] "WmiGuid"

#define OB_TYPE_TAG_TYPE 'TjbO' // [ObjT] "Type"

#define OB_TYPE_TAG_DIRECTORY 'eriD' // [Dire] "Directory"

#define OB_TYPE_TAG_SYMBOLIC_LINK 'bmyS' // [Symb] "SymbolicLink"

#define OB_TYPE_TAG_TOKEN 'ekoT' // [Toke] "Token"

#define OB_TYPE_TAG_PROCESS 'corP' // [Proc] "Process"

#define OB_TYPE_TAG_THREAD 'erhT' // [Thre] "Thread"

#define OB_TYPE_TAG_JOB ' boJ' // [Job ] "Job"

#define OB_TYPE_TAG_EVENT 'nevE' // [Even] "Event"

#define OB_TYPE_TAG_EVENT_PAIR 'nevE' // [Even] "EventPair"

#define OB_TYPE_TAG_MUTANT 'atuM' // [Muta] "Mutant"

#define OB_TYPE_TAG_CALLBACK 'llaC' // [Call] "Callback"

#define OB_TYPE_TAG_SEMAPHORE 'ameS' // [Sema] "Semaphore"

#define OB_TYPE_TAG_TIMER 'emiT' // [Time] "Timer"

#define OB_TYPE_TAG_PROFILE 'forP' // [Prof] "Profile"

#define OB_TYPE_TAG_WINDOW_STATION 'dniW' // [Wind] "WindowStation"

#define OB_TYPE_TAG_DESKTOP 'kseD' // [Desk] "Desktop"

#define OB_TYPE_TAG_SECTION 'tceS' // [Sect] "Section"

#define OB_TYPE_TAG_KEY ' yeK' // [Key ] "Key"

#define OB_TYPE_TAG_PORT 'troP' // [Port] "Port"

#define OB_TYPE_TAG_WAITABLE_PORT 'tiaW' // [Wait] "WaitablePort"

#define OB_TYPE_TAG_ADAPTER 'padA' // [Adap] "Adapter"

#define OB_TYPE_TAG_CONTROLLER 'tnoC' // [Cont] "Controller"

#define OB_TYPE_TAG_DEVICE 'iveD' // [Devi] "Device"

#define OB_TYPE_TAG_DRIVER 'virD' // [Driv] "Driver"

#define OB_TYPE_TAG_IO_COMPLETION 'oCoI' // [IoCo] "IoCompletion"

#define OB_TYPE_TAG_FILE 'eliF' // [File] "File"

#define OB_TYPE_TAG_WMI_GUID 'GimW' // [WmiG] "WmiGuid"

对 Type 类型的对象就介绍到这里。

其他

可选结构之一的 OBJECT_HANDLE_DB

OBJECT_HANDLE_DB 结构定义如下

typedef struct _OBJECT_HANDLE_DB

{

/*000*/ union

{

/*000*/ struct _EPROCESS *Process;

/*000*/ struct _OBJECT_HANDLE_DB_LIST *HandleDBList;

/*004*/ };

/*004*/ DWORD HandleCount;

/*008*/ }

OBJECT_HANDLE_DB;

typedef struct _OBJECT_HANDLE_DB_LIST

{

/*000*/ DWORD Count;

/*004*/ OBJECT_HANDLE_DB Entries [];

/*???*/ };

如果头中的 OB_FLAG_SINGLE_PROCESS 标志位被设立,则 union 中的 .Process 有效,指向一个EPROCESS。如果有多个进程都拥有本对象的句柄(handle),那么OB_FLAG_SINGLE_PROCESS 标志位不会被设立,则 union 中的 .HandleDBList 有效。

kd> !object \Windows\WindowStations\WinSta0

!object \Windows\WindowStations\WinSta0

Object: 810c9398 Type: (8141c5a0) WindowStation

ObjectHeader: 810c9380

HandleCount: 29 PointerCount: 46

Directory Object: 810e5930 Name: WinSta0

\\ 对象头地址为 810c9380 ,对象头中 +c 开始的4个字节分别是 NameOffset HandleDBOffset \\ QuotaChargesOffset ObjectFlags

kd> db 810c9380+c l 4

db 810c9380+c l 4

810c938c 10 18 00 20

\\ HandleDBOffset 不为0,表明存在 OBJECT_HANDLE_DB ,并且偏移为 18,即810c9380-18=810c9368,大小为8个字节。NameOffset 不为0,偏移为10。ObjectFlags为 20(hex)=00100000(bin) 即 OB_FLAG_SECURITY, 标志位 OB_FLAG_SINGLE_PROCESS 没有被设立,表明 OBJECT_HANDLE_DB 的union 中的 .HandleDBList 有效。

kd> dd 810c9380-18 l 2

dd 810c9380-18 l 2

810c9368 e308ac48 00000002

/*000*/ struct _OBJECT_HANDLE_DB_LIST *HandleDBList;

e308ac48

/*004*/ DWORD HandleCount;

00000002

\\ OBJECT_HANDLE_DB_LIST 的 Count

kd> dd e308ac48 l 1

dd e308ac48 l 1

e308ac48 00000016

\\ 有0x16 项

kd> dd e308ac48+4 l 16*2

dd e308ac48+4 l 16*2

e308ac4c 810cc740 00000002 00000000 00000000

e308ac5c 81054020 00000002 833eb1c0 00000002

e308ac6c 81f9f020 00000002 824c65e0 00000002

e308ac7c 80e68100 00000002 00000000 00000000

e308ac8c 84f7a7e0 00000002 810e8020 00000002

e308ac9c 00000000 00000000 00000000 00000000

e308acac 00000000 00000000 00000000 00000000

e308acbc 8352a620 00000002 00000000 00000000

e308accc 8475f020 00000002 830f0a00 00000002

e308acdc 83084b00 00000002 817cb3c0 00000001

e308acec 83589020 00000002 8345a440 00000002

\\ 试一下第一项中的指向EPROCESS的指针。

kd> !process 810cc740 0

!process 810cc740 0

PROCESS 810cc740 SessionId: 0 Cid: 00bc Peb: 7ffdf000 ParentCid: 008c

DirBase: 075a7000 ObjectTable: 810cc6a8 TableSize: 357.

Image: winlogon.exe

\\ 确实是指向一个EPROCESS结构

可选结构之一的 OBJECT_QUOTA_CHARGES

OBJECT_QUOTA_CHARGES 结构定义如下

#define OB_SECURITY_CHARGE 0x00000800

typedef struct _OBJECT_QUOTA_CHARGES

{

/*000*/ DWORD PagedPoolCharge;

/*004*/ DWORD NonPagedPoolCharge;

/*008*/ DWORD SecurityCharge;

/*00C*/ DWORD Reserved;

/*010*/ }

OBJECT_QUOTA_CHARGES;

当对象头中的标志位 OB_FLAG_CREATE_INFO 为0时,头中的 PQUOTA_BLOCK QuotaBlock 有效。

struct _EPROCESS_QUOTA_BLOCK (sizeof=44)

+00 uint32 QuotaLock

+04 uint32 ReferenceCount

+08 uint32 QuotaPeakPoolUsage[2]

+10 uint32 QuotaPoolUsage[2]

+18 uint32 QuotaPoolLimit[2]

+20 uint32 PeakPagefileUsage

+24 uint32 PagefileUsage

+28 uint32 PagefileLimit

kd> !object \KnownDlls\user32.dll

!object \KnownDlls\user32.dll

Object: e17c29e0 Type: (8141b760) Section

ObjectHeader: e17c29c8

HandleCount: 0 PointerCount: 1

Directory Object: 810f63d0 Name: user32.dll

\\ 对象头地址为 e17c29c8 ,对象头中 +c 开始的4个字节分别是 NameOffset HandleDBOffset

\\ QuotaChargesOffset ObjectFlags

kd> db e17c29c8+c l 4

db e17c29c8+c l 4

e17c29d4 10 00 20 10

\\ QuotaChargesOffset 不为0,表明存在 OBJECT_QUOTA_CHARGES ,并且偏移为 20,即e17c29c8-20=e17c29a8,大小为8个字节。NameOffset 不为0,偏移为10。ObjectFlags为 10(hex)=00010000(bin) 即 OB_FLAG_PERMANENT,OB_FLAG_CREATE_INFO 位为0。

\\ OBJECT_QUOTA_CHARGES

kd> dd e17c29c8-20 l 4

dd e17c29c8-20 l 4

e17c29a8 000001b8 000000d8 00000800 00000000

/*000*/ DWORD PagedPoolCharge;

000001b8

/*004*/ DWORD NonPagedPoolCharge;

000000d8

/*008*/ DWORD SecurityCharge;

00000800

/*00C*/ DWORD Reserved;

00000000

\\ 头地址在 e17c29c8,头中 QuotaBlock 值为 804699c0

kd> dd e17c29c8 l 6

dd e17c29c8 l 6

e17c29c8 00000001 00000000 8141b760 10200010

e17c29d8 804699c0 e17bb8d8

\\EPROCESS_QUOTA_BLOCK

kd> dd 804699c0 l 2c/4

dd 804699c0 l 2c/4

804699c0 00000000 000006b9 0008395c 001499e0

804699d0 0007eebc 00139f6c ffffffff ffffffff

804699e0 0000106e 00000f16 ffffffff

+00 uint32 QuotaLock

00000000

+04 uint32 ReferenceCount

000006b9

+08 uint32 QuotaPeakPoolUsage[2]

0008395c 001499e0

+10 uint32 QuotaPoolUsage[2]

0007eebc 00139f6c

+18 uint32 QuotaPoolLimit[2]

ffffffff ffffffff

+20 uint32 PeakPagefileUsage

0000106e

+24 uint32 PagefileUsage

00000f16

+28 uint32 PagefileLimit

ffffffff

OBJECT_HEADER中的 /*014*/ PSECURITY_DESCRIPTOR ObjectCreateInfo

如果OBJECT_HEADER中的 OB_FLAG_SECURITY 标志被设立则 SecurityDescriptor 为指向 SECURITY_DESCRIPTOR 的指针。如果 OB_FLAG_SECURITY 标志没有被设立,则 SecurityDescriptor 为空。

SECURITY_DESCRIPTOR 结构定义如下

// kd 中使用 !strct 得到。

struct _SECURITY_DESCRIPTOR (sizeof=20)

+00 byte Revision

+01 byte Sbz1

+02 uint16 Control

+04 void *Owner

+08 void *Group

+0c struct _ACL *Sacl

+10 struct _ACL *Dacl

struct _SID (sizeof=12)

+0 byte Revision

+1 byte SubAuthorityCount

+2 struct _SID_IDENTIFIER_AUTHORITY IdentifierAuthority

+2 byte Value[6]

+8 uint32 SubAuthority[1]

struct _ACL (sizeof=8)

+0 byte AclRevision

+1 byte Sbz1

+2 uint16 AclSize

+4 uint16 AceCount

+6 uint16 Sbz2

\\ 以"\"为例

kd> !object !object Object: 8141ecd0 Type: (81452820) Directory

ObjectHeader: 8141ecb8

kd> dd 8141ecb8 l 6

dd 8141ecb8 l 6

8141ecb8 00000023 00000000 81452820 32000010

8141ecc8 00000001 e10010f8

\\ 32(hex)=00110010(bin) ,即 OB_FLAG_KERNEL_MODE,OB_FLAG_PERMANENT,OB_FLAG_SECURITY 这3位被设立。所以 e10010f8 为 SecurityDescriptor 指向 SECURITY_DESCRIPTOR。SECURITY_DESCRIPTOR 结构大小为20(dec)个字节。

kd> dd e10010f8 l 5

dd e10010f8 l 5

e10010f8 80040001 00000070 00000080 00000000

e1001108 00000014

+00 byte Revision

01

+01 byte Sbz1

00

+02 uint16 Control

8004

+04 void *Owner

00000070

+08 void *Group

00000080

+0c struct _ACL *Sacl

00000000

// 为空,表示不存在 Sacl

+10 struct _ACL *Dacl

00000014

// 不为空,表示存在 Dacl ,并且在从 SECURITY_DESCRIPTOR 开始处偏移为 14 的地方,

即 e10010f8+14

kd> db e10010f8+14 l 8

db e10010f8+14 l 8

e100110c 02 00 5c 00 04 00 00 00

+0 byte AclRevision

02

+1 byte Sbz1

00

+2 uint16 AclSize

005c

+4 uint16 AceCount

0004

+6 uint16 Sbz2

0000

// 使用 kd 的 !sd 命令来显示安全描述符

kd> !sd e10010f8

!sd e10010f8

->Revision: 0x1

->Sbz1 : 0x0

->Control : 0x8004

SE_DACL_PRESENT

SE_SELF_RELATIVE

->Owner : S-1-5-32-544

->Group : S-1-5-18

->Dacl :

->Dacl : ->AclRevision: 0x2

->Dacl : ->Sbz1 : 0x0

->Dacl : ->AclSize : 0x5c

->Dacl : ->AceCount : 0x4

->Dacl : ->Sbz2 : 0x0

->Dacl : ->Ace[0]: ->AceType: ACCESS_ALLOWED_ACE_TYPE

->Dacl : ->Ace[0]: ->AceFlags: 0x0

->Dacl : ->Ace[0]: ->AceSize: 0x14

->Dacl : ->Ace[0]: ->Mask : 0x00020003

->Dacl : ->Ace[0]: ->SID: S-1-1-0

->Dacl : ->Ace[1]: ->AceType: ACCESS_ALLOWED_ACE_TYPE

->Dacl : ->Ace[1]: ->AceFlags: 0x0

->Dacl : ->Ace[1]: ->AceSize: 0x14

->Dacl : ->Ace[1]: ->Mask : 0x000f000f

->Dacl : ->Ace[1]: ->SID: S-1-5-18

->Dacl : ->Ace[2]: ->AceType: ACCESS_ALLOWED_ACE_TYPE

->Dacl : ->Ace[2]: ->AceFlags: 0x0

->Dacl : ->Ace[2]: ->AceSize: 0x18

->Dacl : ->Ace[2]: ->Mask : 0x000f000f

->Dacl : ->Ace[2]: ->SID: S-1-5-32-544

->Dacl : ->Ace[3]: ->AceType: ACCESS_ALLOWED_ACE_TYPE

->Dacl : ->Ace[3]: ->AceFlags: 0x0

->Dacl : ->Ace[3]: ->AceSize: 0x14

->Dacl : ->Ace[3]: ->Mask : 0x00020003

->Dacl : ->Ace[3]: ->SID: S-1-5-12

->Sacl : is NULL

总结

最后我们来总结一下,从一个对象可以找到的信息。对象指针都是指向对象体的。

对象头:

使用计数

打开句柄计数

相应类型对象的指针

标志和偏移(指明存在哪些可选部分,对存在的部分指明在对象头之前的偏移)

安全描述符

对象头之前的可选信息(哪些存在由对象头中的标志和偏移决定):

OBJECT_NAME 名字,对象所在目录

OBJECT_HANDLE_DB 使用对象的进程

OBJECT_QUOTA_CHARGES PagedPool,NonPagedPool 的使用情况

OBJECT_CREATOR_INFO 打开进程ID,本类型对象链表

类型对象:

该类型对象链表头(绝大多数的类型,并不构造这个链)

类型名(Unicode字符串)

类型序号(用一个数表示的类型)

其他的信息

该类型的一些例程

前面对对象头及其相关结构做了介绍,并对 Directory 类型,Type 类型 对象的对象体也做了介绍。Process 类型,Thred 类型 对象将在其他地方做更多介绍。需要特别说明的是,通过 Directory 可以找到的对象只是系统存在的所有对象中的一小部分。很多对象是被进程使用的,在有关进程的介绍中,我们将看到如何找到更多的对象。

欢迎交流,欢迎交朋友,

欢迎访问 http://jiurl.yeah.net http://jiurl.cosoft.org.cn/forum

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有