Windows 2000 Object Structures
This article is excerpted from Undocumented Windows Secrets: A Programmer's Cookbook (Addison Wesley, 2001, ISBN: 0201721872).
There is hardly anything more fascinating in the internals of Windows 2000 than the world of its objects. If the memory space of an operating system is viewed as the surface of a planet, the objects are the creatures living on it. Several types of objects exist—small and large ones, simple and complex ones—and they interact in various ways. Windows 2000 features a clever and well-structured object management mechanism that is almost completely undocumented.
The Object Header
The body of an object can assume any form suitable for the creator of the object. The Windows 2000 object manager doesn't impose any restrictions on the size and structure of the object body. Contrary to this, the header portion of an object has much less degrees of freedom. Figure 1 shows the memory layout of a full-featured object, equipped with the maximum number of header fields. Every object features at least a basic OBJECT_HEADER structure, immediately preceding the object body, plus up to four optional structures that supply additional information about the object. As already noted, an object pointer always refers to the object body, not to the header, so the header fields are accessed via negative offsets relative to the object pointer. The basic header contains information about the availability and location of additional header fields, which are stacked up on the OBJECT_HEADER structure in the order shown in Figure 1, if present. However, this sequence isn't mandatory, and your programs should never rely on it. The information in the OBJECT_HEADER is sufficient to locate all header fields regardless of their order, as will be shown in a moment. The only exception is the OBJECT_CREATOR_INFO structure that always precedes the OBJECT_HEADER immediately if it is included.
Figure 1 Memory layout of an object.
Listing 1 shows the definition of the OBJECT_HEADER structure. Its members serve the following purposes:
The PointerCount member indicates how many active pointer references to this object currently exist. This value is similar to the reference count maintained by Component Object Model (COM) objects. The ntoskrnl.exe API functions ObfReferenceObject(), ObReferenceObjectByHandle(), ObReferenceObjectByName(), and ObReferenceObjectByPointer() increment the PointerCount, while ObfDereferenceObject() and ObDereferenceObject() decrement it.
The HandleCount member indicates how many open handles currently refer to this object.
The ObjectType member points to an OBJECT_TYPE structure (described later) representing the type object that has been used in the creation of this object.
The NameOffset specifies the number of bytes to be subtracted from the OBJECT_HEADER address to locate the object header's OBJECT_NAME portion. If zero, this structure is not available.
The HandleDBOffset specifies the number of bytes to be subtracted from the OBJECT_HEADER address to locate the object header's OBJECT_HANDLE_DB portion. If zero, this structure is not available.
The QuotaChargesOffset specifies the number of bytes to be subtracted from the OBJECT_HEADER address to locate the object header's OBJECT_QUOTA_CHARGES portion. If zero, this structure is not available.
The ObjectFlags specify various binary properties of an object, as listed in the top section of Listing 1. If the OB_FLAG_CREATOR_INFO bit is set, the object header includes an OBJECT_CREATOR_INFO structure that immediately precedes the OBJECT_HEADER.
The QuotaBlock and ObjectCreateInfo members are mutually exclusive. If the ObjectFlags member has the OB_FLAG_CREATE_INFO flag set, this member contains a pointer to the OBJECT_CREATE_INFO structure (described later) used in the creation of this object. Otherwise, it points to a QUOTA_BLOCK that provides information about the usage of the paged and non-paged memory pools. Many objects have their QuotaBlock pointer set to the internal PspDefaultQuotaBlock structure. The value of this union can be NULL.
The SecurityDescriptor member points to a SECURITY_DESCRIPTOR structure if the OB_FLAG_SECURITY bit of the ObjectFlags is set. Otherwise, its value is NULL.
In the above list, several structures have been mentioned that weren't discussed in detail so far. Each of them will be introduced now, starting with the four optional header parts shown in Figure 1.
Listing 1 The OBJECT_HEADER Structure
#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 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, * POBJECT_HEADER, **PPOBJECT_HEADER;