OBJECT_HEADER_HANDLE_INFO

The OBJECT_HEADER_HANDLE_INFO structure (formally _OBJECT_HEADER_HANDLE_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 which processes have opened how many handles to the object.

Access

The point to making a separate structure of the OBJECT_HEADER_HANDLE_INFO is, of course, that the Object Manager does not maintain these handle counts for all types of object. For such objects, the memory overhead is 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_HANDLE_INFO is located by the byte-sized HandleInfoOffset member of the OBJECT_HEADER. If this is zero, then the object has no OBJECT_HEADER_HANDLE_INFO. Otherwise, it is the offset in bytes from the start of the OBJECT_HEADER_HANDLE_INFO to the start of the OBJECT_HEADER. A programmer might write this as

OBJECT_HEADER_HANDLE_INFO *
OBJECT_HEADER_TO_HANDLE_INFO_EXISTS (
    OBJECT_HEADER *ObjectHeader)
{
    return (OBJECT_HEADER_HANDLE_INFO *) 
        ((PCHAR) ObjectHeader - ObjectHeader -> HandleInfoOffset);
}
OBJECT_HEADER_HANDLE_INFO *
OBJECT_HEADER_TO_HANDLE_INFO (
    OBJECT_HEADER *ObjectHeader)
{
    return ObjectHeader -> HandleInfoOffset != 0
        ? OBJECT_HEADER_TO_HANDLE_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_HANDLE_INFO is present is 0x04. The only information structures that can sit between the OBJECT_HEADER_HANDLE_INFO and the OBJECT_HEADER are the OBJECT_HEADER_NAME_INFO and OBJECT_HEADER_CREATOR_INFO, which are represented by the 0x02 and 0x01 bits. 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_HANDLE_INFO *
OBJECT_HEADER_TO_HANDLE_INFO_EXISTS (
    OBJECT_HEADER *ObjectHeader)
{
    return (OBJECT_HEADER_HANDLE_INFO *) ((PCHAR) ObjectHeader 
        - ObpInfoMaskToOffset [ObjectHeader -> InfoMask & 0x07]);
}
OBJECT_HEADER_HANDLE_INFO *
OBJECT_HEADER_TO_HANDLE_INFO (
    OBJECT_HEADER *ObjectHeader)
{
    return ObjectHeader -> InfoMask & 0x04
        ? OBJECT_HEADER_TO_HANDLE_INFO_EXISTS (ObjectHeader)
        : NULL;
}

Layout

The OBJECT_HEADER_HANDLE_INFO structure is 0x08 or 0x10 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 these 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).

Though the OBJECT_HEADER_HANDLE_INFO is formally a structure, its one member is an unnamed union:

Offset (x86) Offset (x64) Definition Versions
0x00 0x00
union {
    OBJECT_HANDLE_COUNT_DATABASE *HandleCountDataBase;
    OBJECT_HANDLE_COUNT_ENTRY SingleEntry;
};
3.50 and higher

In general, the database is a separate memory allocation of a count of processes and an array of entries, one per process.

A frequent particular case, not least for being certain as an initial case, is that the object is opened by just one process. The database has just the one entry and might never need another. This is accommodated efficiently by making that the whole database is the SingleEntry. This state is indicated by a set OBJ_FLAG_SINGLE_HANDLE_ENTRY (0x40) in the Flags in the OBJECT_HEADER.