先放上一张Windows Object完整的结构图,其中OBJECT_HEADER取自Windows XP SP2 英文版。
+----------------------------------------------------------------+
+------->| ( OBJECT_HEADER_QUOTA_INFO ) |
| +---->| ( OBJECT_HEADER_HANDLE_INFO ) |
| | +->| ( OBJECT_HEADER_NAME_INFO ) |
| | | | ( OBJECT_HEADER_CREATOR_INFO ) |
| | | +------------------------[ Object Header ]-----------------------+
| | | | nt!_OBJECT_HEADER |
| | | | +0x000 PointerCount : Int4B |
| | | | +0x004 HandleCount : Int4B |
| | | | +0x004 NextToFree : Ptr32 Void |
| | | | +0x008 Type : Ptr32 _OBJECT_TYPE |
| | +--| +0x00c NameInfoOffset : UChar |
| +-----| +0x00d HandleInfoOffset : UChar |
+--------| +0x00e QuotaInfoOffset : UChar |
| +0x00f Flags : UChar |
| +0x010 ObjectCreateInfo : Ptr32 _OBJECT_CREATE_INFORMATION |
| +0x010 QuotaBlockCharged : Ptr32 Void |
| +0x014 SecurityDescriptor : Ptr32 Void |
| +0x018 Body : _QUAD |
+-------------------------[ Object Body ]------------------------+
| OBJECT_DIRECTORY, DRIVER_OBJECT, DEVICE_OBJECT, FILE_OBJECT... |
+----------------------------------------------------------------+
一个对象由三部分组成,在Object Header之前是一段变长的区域,由四个独立的结构体组成:
typedef struct _OBJECT_HEADER_QUOTA_INFO {
ULONG PagedPoolCharge;
ULONG NonPagedPoolCharge;
ULONG SecurityDescriptorCharge;
PEPROCESS ExclusiveProcess;
#ifdef _WIN64
ULONG64 Reserved; // Win64 requires these structures to be 16 byte aligned.
#endif
} OBJECT_HEADER_QUOTA_INFO, *POBJECT_HEADER_QUOTA_INFO;
union {
POBJECT_HANDLE_COUNT_DATABASE HandleCountDataBase;
OBJECT_HANDLE_COUNT_ENTRY SingleEntry;
};
} OBJECT_HEADER_HANDLE_INFO, *POBJECT_HEADER_HANDLE_INFO;
typedef struct _OBJECT_HEADER_NAME_INFO {
POBJECT_DIRECTORY Directory;
UNICODE_STRING Name;
ULONG QueryReferences;
#if DBG
ULONG Reserved2;
LONG DbgDereferenceCount;
#ifdef _WIN64
ULONG64 Reserved3; // Win64 requires these structures to be 16 byte aligned.
#endif
#endif
} OBJECT_HEADER_NAME_INFO, *POBJECT_HEADER_NAME_INFO;
// end_ntosp
LIST_ENTRY TypeList;
HANDLE CreatorUniqueProcess;
USHORT CreatorBackTraceIndex;
USHORT Reserved;
} OBJECT_HEADER_CREATOR_INFO, *POBJECT_HEADER_CREATOR_INFO;
一个对象可以包含全部四个结构,也可能只包含其中的某个,因此这段区域是变长的。
之后是OBJECT_HEADER结构,NameInfoOffset、HandleInfoOffset、QuotaInfoOffset分别为OBJECT_HEADER到OBJECT_HEADER_NAME_INFO、OBJECT_HEADER_HANDLE_INFO、OBJECT_HEADER_QUOTA_INFO这三个结构的偏移。
kd> !object \Driver\Disk
Object: 8985da08 Type: (898df3b0) Driver
ObjectHeader: 8985d9f0
HandleCount: 0 PointerCount: 6
Directory Object: e1005160 Name: Disk
继续看一下OBJECT_HEADER结构的信息:
kd> dt nt!_object_header 8985d9f0
nt!_OBJECT_HEADER
+0x000 PointerCount : 6
+0x004 HandleCount : 0
+0x004 NextToFree : (null)
+0x008 Type : 0x898df3b0 _OBJECT_TYPE
+0x00c NameInfoOffset : 0x10 ''
+0x00d HandleInfoOffset : 0 ''
+0x00e QuotaInfoOffset : 0 ''
+0x00f Flags : 0x32 '2'
+0x010 ObjectCreateInfo : 0x00000001 _OBJECT_CREATE_INFORMATION
+0x010 QuotaBlockCharged : 0x00000001
+0x014 SecurityDescriptor : 0xe100c843
+0x018 Body : _QUAD
在NameInfoOffset中指出OBJECT_HEADER_NAME_INFO的便宜量为0×10,它的地址为OBJECT_HEADER - OBJECT_HEADER.NameInfoOffset,即0×8985d9f0-0×10,继续来看:
kd> dt nt!_object_header_name_info 8985d9f0-0x10
nt!_OBJECT_HEADER_NAME_INFO
+0x000 Directory : 0xe1005160 _OBJECT_DIRECTORY
+0x004 Name : _UNICODE_STRING "Disk"
+0x00c QueryReferences : 1
kd> dt nt!_driver_object 8985da08
nt!_DRIVER_OBJECT
+0x000 Type : 4
+0x002 Size : 168
+0x004 DeviceObject : 0x89900c68 _DEVICE_OBJECT
+0x008 Flags : 0x12
+0x00c DriverStart : 0xf7627000
+0x010 DriverSize : 0x8e00
+0x014 DriverSection : 0x89927a70
+0x018 DriverExtension : 0x8985dab0 _DRIVER_EXTENSION
+0x01c DriverName : _UNICODE_STRING "\Driver\Disk"
+0x024 HardwareDatabase : 0x8068db10 _UNICODE_STRING "\REGISTRY\MACHINE\HARDWARE\DESCRIPTION\SYSTEM"
+0x028 FastIoDispatch : (null)
+0x02c DriverInit : 0xf762e8ab disk!GsDriverEntry+0
+0x030 DriverStartIo : (null)
+0x034 DriverUnload : 0xf763e53a CLASSPNP!ClassUnload+0
+0x038 MajorFunction : [28] 0xf763dc30 CLASSPNP!ClassCreateClose+0
Driver object (8985da08) is for:
\Driver\Disk
Driver Extension List: (id , addr)
(f763e3be 8985d8f0)
Device Object list:
89900c68 89896c68 8985ec68 8985cab8
OBJECT_HEADER的大小为0×18字节,因此Object Body = OBJECT_HEADER + 0×18,但是0×18是个硬编码值,如果OBJECT_HEADER在以后的系统中发生了变化,显然用这个0×18是不可靠的。
OBJECT_HEADER结构中有一个Body成员,如果执行“dt nt!_OBJECT_HEADER -b”会有以下的输出:
kd> dt nt!_OBJECT_HEADER -b
+0x000 PointerCount : Int4B
+0x004 HandleCount : Int4B
+0x004 NextToFree : Ptr32
+0x008 Type : Ptr32
+0x00c NameInfoOffset : UChar
+0x00d HandleInfoOffset : UChar
+0x00e QuotaInfoOffset : UChar
+0x00f Flags : UChar
+0x010 ObjectCreateInfo : Ptr32
+0x010 QuotaBlockCharged : Ptr32
+0x014 SecurityDescriptor : Ptr32
+0x018 Body : _QUAD
+0×000 DoNotUseThisField : Float
注意斜体字部分。Body成员在OBJECT_HEADER结构中的偏移量实际上就是Object Body到OBJECT_HEADER的偏移量(0×18),它只是作为定位偏移量来使用,因此会有“Do Not Use This Field”的提示。
在WRK的代码中定义了一个宏函数(见 %wrk%\base\ntos\inc\ob.h),用于从Object Body访问OBJECT_HEADER结构。
#define OBJECT_TO_OBJECT_HEADER( o ) \
CONTAINING_RECORD( (o), OBJECT_HEADER, Body )
// Calculate the address of the base of the structure given its type, and an
// address of a field within the structure.
//
#ifndef CONTAINING_RECORD
#define CONTAINING_RECORD(address, type, field) \
((type *)((PCHAR)(address) - (ULONG_PTR)(&((type *)0)->field)))
#endif
利用OBJECT_TO_OBJECT_HEADER()传递一个Object Body的地址给它(例如,Disk.sys的DriverObject),就可以轻松的得到这个对象的OBJECT_HEADER结构。
[url]http://www.phpfav.com[/url]