Geoff Chappell - Software Analyst
The OBJECT_HEADER_NAME_INFO structure (formally _OBJECT_HEADER_NAME_INFO) is one of several structures that may precede an OBJECT_HEADER in a memory block that contains an Object Manager object. It is the definitive record of the object’s name and of where the object sits in the namespace.
The point to making a separate structure of the OBJECT_HEADER_NAME_INFO is, of course, that the object need not have a name. The object’s memory overhead is then reduced by having the OBJECT_HEADER record just the absence.
This saving was first implemented in version 3.50. For this and many versions after, the OBJECT_HEADER_NAME_INFO is located by the byte-sized NameInfoOffset member of the OBJECT_HEADER. If this is zero, then the object has no OBJECT_HEADER_NAME_INFO. Otherwise, it is the offset in bytes from the start of the OBJECT_HEADER_NAME_INFO to the start of the OBJECT_HEADER. A programmer might write this as
OBJECT_HEADER_NAME_INFO * OBJECT_HEADER_TO_NAME_INFO_EXISTS ( OBJECT_HEADER *ObjectHeader) { return (OBJECT_HEADER_NAME_INFO *) ((PCHAR) ObjectHeader - ObjectHeader -> NameInfoOffset); }
OBJECT_HEADER_NAME_INFO * OBJECT_HEADER_TO_NAME_INFO ( OBJECT_HEADER *ObjectHeader) { return ObjectHeader -> NameInfoOffset != 0 ? OBJECT_HEADER_TO_NAME_INFO_EXISTS (ObjectHeader) : NULL; }
The location algorithm changed for version 6.1. It had by then been realised that if the various information structures that can precede the OBJECT_HEADER are always laid out in the same order, then the offset to any one of them can be computed from knowing which others are present. This knowledge costs only one bit for each of the possible information structures. The OBJECT_HEADER has these bits as the single-byte InfoMask. The kernel has as an internal variable an array of pre-computed offsets for the possible combinations of InfoMask bits. The bit that tells if an OBJECT_HEADER_NAME_INFO is present is 0x02. The only information structure that can sit between the OBJECT_HEADER_NAME_INFO and the OBJECT_HEADER is the OBJECT_HEADER_CREATOR_INFO, whose presence is represented by the 0x01 bit. Public symbol files for the kernel, starting with Windows 8, suggest strongly that Microsoft’s programmers have the computation as something very like
OBJECT_HEADER_NAME_INFO * OBJECT_HEADER_TO_NAME_INFO_EXISTS ( OBJECT_HEADER *ObjectHeader) { return (OBJECT_HEADER_NAME_INFO *) ((PCHAR) ObjectHeader - ObpInfoMaskToOffset [ObjectHeader -> InfoMask & 0x03]); }
OBJECT_HEADER_NAME_INFO * OBJECT_HEADER_TO_NAME_INFO ( OBJECT_HEADER *ObjectHeader) { return ObjectHeader -> InfoMask & 0x02 ? OBJECT_HEADER_TO_NAME_INFO_EXISTS (ObjectHeader) : NULL; }
The OBJECT_HEADER_NAME_INFO structure is 0x10 or 0x20 bytes in 32-bit and 64-bit Windows, respectively. Microsoft’s names and types are known from type information in public symbol files for the kernel, starting with Windows 2000 SP3. Names are known with slightly less certainty as far back as version 4.0 from the output of the !dso command as implemented by the debugger extension USEREXTS.DLL from the Windows NT 4.0 Device Driver Kit (DDK).
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x00 | 0x00 |
OBJECT_DIRECTORY *Directory; |
3.50 and higher |
0x04 | 0x08 |
UNICODE_STRING Name; |
3.50 and higher |
0x0C | 0x18 |
ULONG Reserved; |
3.50 to early 5.0 |
ULONG QueryReferences; |
late 5.0 to 6.0 | ||
LONG ReferenceCount; |
6.1 and higher | ||
0x1C |
ULONG Reserved; |
1607 and higher |
The Directory and Name are previously at offsets 0x48 and 0x5C in the OBJECT_CREATE_INFORMATION structure (or whatever it was called in version 3.10). As with later versions, this structure’s address is in the OBJECT_HEADER as the ObjectCreateInfo. Version 3.10, however, keeps this structure for the life of the object.
Both the original Reserved and its addition for later releases of Windows 10 make explicit that the OBJECT_HEADER_NAME_INFO must be a multiple of 0x08 or 0x10 bytes for 32-bit and 64-bit Windows, respectively, as must all the object header’s headers.
The !dso command for Windows 2000 still labels the dword at offset 0x0C as Reserved. Use as QueryReferences is seen in the kernel for Windows 2000 SP3 but not in SP1. No kernel for Windows 2000 SP2 has been found for inspection.