In a previous post I wrote about the newly documented POBJECT_TYPE variables for Vista. You can pass these exports to ObReferenceObjectByHandle, ObReferenceObjectByPointer, or ObOpenObjectByPointer. Talking about the new exports without talking about the type itself was a little bit of putting the cart before the horse and I wanted to fix that ;).
So, what is the type and what purpose does it serve?
The POBJECT_TYPE represents the attributes (which are internal to the kernel and can change from version to version) of an NT object. An NT object is nothing special based on outward appearances, it is just a pointer afterall. But how do you know which pointers are NT objects and which are not? One rule of thumb is that you never allocate the memory for the object directly, rather you are calling an API (such as IoCreateDevice) to do the allocation on your behalf. Another rule of thumb is that if you can call ObReferenceObject on the pointer, it is an NT object. For instance, PDRIVER_OBJECT, PDEVICE_OBJECT, and PFILE_OBJECT are all NT objects. On the other hand, a PIRP is not an NT object, it fails both rules (you can allocate one directly and then initialize it using IoSizeOfIrp and IoInitializeIrp and you cannot call ObReferenceObject on it).
Let’s look at the type and export itself in ntddk.h, typedef struct _OBJECT_TYPE *POBJECT_TYPE;. It is an anonymous type (by C standards at least), the actual definition of the _OBJECT_TYPE structure is not publicly exposed (this same pattern is repeated for other types like _KINTERRUPT or _ETHREAD). Furthermore, it is exported as a POBJECT_TYPE*, not a POBJECT_TYPE. It is exported indirectly as a double pointer because the address of the POBJECT_TYPE is used to check the type in the above mentioned calls. This means that there can one and only one PBOJECT_TYPE value for each object type in the system, if it was exported as POBJECT_TYPE the address would be different from driver to driver since the memory manager would map the export into a driver relative address..
Next time I will write about why you want to use these types when converting handles and pointers to their respective NT objects.