OBJECT_HEADER_QUOTA_INFO

The OBJECT_HEADER_QUOTA_INFO structure (formally _OBJECT_HEADER_QUOTA_INFO) is one of several structures that may precede an OBJECT_HEADER in a memory block that contains an Object Manager object.

Access

The point to making a separate structure of the OBJECT_HEADER_QUOTA_INFO is, of course, that the object need not have charged any process. The object’s memory overhead is then reduced by having the OBJECT_HEADER record just that there is no quota.

This saving was first implemented in version 3.50. For this and many versions after, the key to locating the OBJECT_HEADER_QUOTA_INFO is the byte-sized QuotaInfoOffset member of the OBJECT_HEADER. If this is zero, then the object has no OBJECT_HEADER_QUOTA_INFO. Otherwise, it is the offset in bytes from the start of the OBJECT_HEADER_QUOTA_INFO to the start of the OBJECT_HEADER. A programmer might write this as

OBJECT_HEADER_QUOTA_INFO *
OBJECT_HEADER_TO_QUOTA_INFO_EXISTS (
    OBJECT_HEADER *ObjectHeader)
{
    return (OBJECT_HEADER_QUOTA_INFO *) 
        ((PCHAR) ObjectHeader - ObjectHeader -> QuotaInfoOffset);
}
OBJECT_HEADER_QUOTA_INFO *
OBJECT_HEADER_TO_QUOTA_INFO (
    OBJECT_HEADER *ObjectHeader)
{
    return ObjectHeader -> QuotaInfoOffset != 0
        ? OBJECT_HEADER_TO_QUOTA_INFO_EXISTS (ObjectHeader)
        : NULL;
}

This location algorithm changed ever so slightly for version 6.0. It had by the been realised that the alignment requirements of the object, its header and its header’s headers mean that the header’s single-byte offsets to the header’s headers are themselves wasteful because the offsets must all be multiples of eight (even on 32-bit Windows). The particular need for version 6.0 was to find two spare bits for tracing. For plausibly no particular reason, these were taken from the QuotaInfoOffset. The algorithm to use is then:

OBJECT_HEADER_QUOTA_INFO *
OBJECT_HEADER_TO_QUOTA_INFO_EXISTS (
    OBJECT_HEADER *ObjectHeader)
{
    return (OBJECT_HEADER_QUOTA_INFO *) 
        ((PCHAR) ObjectHeader - (ObjectHeader -> QuotaInfoOffset & ~0x03));
}
OBJECT_HEADER_QUOTA_INFO *
OBJECT_HEADER_TO_QUOTA_INFO (
    OBJECT_HEADER *ObjectHeader)
{
    return (ObjectHeader -> QuotaInfoOffset & ~0x03) != 0
        ? OBJECT_HEADER_TO_QUOTA_INFO_EXISTS (ObjectHeader)
        : NULL;
}

A larger change came with version 6.1 and the realisation 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_QUOTA_INFO is present is 0x08. The three other information structures that can sit between the OBJECT_HEADER_QUOTA_INFO and the OBJECT_HEADER are represented by the bits of 0x07. 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_QUOTA_INFO *
OBJECT_HEADER_TO_QUOTA_INFO_EXISTS (
    OBJECT_HEADER *ObjectHeader)
{
    return (OBJECT_HEADER_QUOTA_INFO *) ((PCHAR) ObjectHeader 
        - ObpInfoMaskToOffset [ObjectHeader -> InfoMask & 0x0F]);
}
OBJECT_HEADER_QUOTA_INFO *
OBJECT_HEADER_TO_QUOTA_INFO (
    OBJECT_HEADER *ObjectHeader)
{
    return ObjectHeader -> InfoMask & 0x08
        ? OBJECT_HEADER_TO_QUOTA_INFO_EXISTS (ObjectHeader)
        : NULL;
}

Layout

The OBJECT_HEADER_QUOTA_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 2003 SP1. That names apply at least as far back as version 4.0 is known with slightly less certainty 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
ULONG PagedPoolCharge;
3.50 and higher
0x04 0x04
ULONG NonPagedPoolCharge;
3.50 and higher
0x08 0x08
ULONG SecurityDescriptorCharge;
3.50 and higher
  0x0C
ULONG Reserved1;
1607 and higher
0x0C 0x10
EPROCESS *ExclusiveProcess;
3.50 to 6.0
PVOID SecurityDescriptorQuotaBlock;
6.1 and higher
  0x18
ULONGLONG Reserved;
late 5.2 and higher
ULONGLONG Reserved2;
1607 and higher