Windows Pool

Windows Pool is memory allocated in kernel mode for core system components like drivers, can operate their activities. There are

  • Paged Pool: stays temporarily in memory. It would be paged out to disk when system memory runs out of memory. When it needs, it pulls it back to memory.

  • Non Paged Pool: stays permanent in memory. It would be reserved for critical kernel objects or drivers that system cannot afford to page out.

Objects

  • Kernel Objects are fundamental components managed by Object Manager.

  • Represents physical and logical resources like processes, threads, files, devices and so on.

  • Every Object has general structure in a pool page.

  • It has

    • Pool Header
    • Optional Object Header -> there can be mulitple Optional object headers
    • Object header
    • Object Body
+---------------------+                           +---------------+
|  PsActiveProcessHead | -----------------------> |    _EPROCESS   |
+---------------------+                           +---------------+
                                                          ^
                                                          |              
                                                          v   
                                                    +------------+
                                                    |  _EPROCESS  | 
                                                    +------------+      
                                                          ^
                                                          |              
                                                          v              
                                                    +------------+       
                                                    |  _EPROCESS  | 
                                                    +------------+
                                                          .
                                                          .
                                                          .    

Pool Object Representation

    +-------------------------+
    |       Pool Header        |  <---- Contains metadata for pool (e.g., size, type)
    +-------------------------+
    |  Optional Object Header  |  <---- Contains additional headers
    +-------------------------+
    |      Object Header       |  <---- Key fields: Object Type, Object Size, Reference Count
    +-------------------------+
    |      Object Body         |  <---- Actual data; varies depending on the object type
    |  (Process, Thread, etc) |         (e.g., "Proc" for processes, "Thre" for threads, "File" for files)
    +-------------------------+
    

Inspecting cmd.exe

0: kd> !process 0 0 cmd.exe
PROCESS 	
    SessionId: 1  Cid: 1164    Peb: 72ce659000  ParentCid: 1148
    DirBase: 5e2bc002  ObjectTable: ffff99011473e500  HandleCount: 245.
    Image: cmd.exe


0: kd> dt nt!_EPROCESS ffffc509bf28b080 -y Image
   +0x464 ImageNotifyDone : 0y1
   +0x5a0 ImageFilePointer : 0xffffc509`c095e2b0 _FILE_OBJECT
   +0x5a8 ImageFileName : [15]  "cmd.exe"
   +0x5f4 ImagePathHash : 0xbd30981
0: kd> !object ffffc509bf28b080
Object: ffffc509bf28b080  Type: (ffffc509b88ab900) Process
    ObjectHeader: ffffc509bf28b050 (new version)
    HandleCount: 7  PointerCount: 261732
  • There are 7 active handles. PointerCount is a very large that represents the total number of objects referenced till time.

Open Handles

0: kd> !findhandle ffffc509bf28b080
                                                              
                   [ffffc509b8884040 System]
  18ac: Entry ffff99010d4662b0 Granted Access 102a (Protected) (Audit)
  2ab4: Entry ffff990112b41ad0 Granted Access 1fffff (Protected) (Audit)
  2c98: Entry ffff9901137fe260 Granted Access 102a (Protected) (Audit)
                                                              
                   [ffffc509bc16f080 csrss.exe]
   3a0: Entry ffff99010b5fce80 Granted Access 1fffff (Protected) (Audit)
                                                              
                   [ffffc509bd20d140 lsass.exe]
  1214: Entry ffff990112379850 Granted Access 1478 (Protected) (Audit)
                                                              
                   [ffffc509bd415300 svchost.exe]
  2768: Entry ffff9901139c2da0 Granted Access 1478 (Protected) (Audit)
                                                              
                   [ffffc509c0ed2080 conhost.exe]
   120: Entry ffff990112455480 Granted Access 1fffff (Protected) (Audit)
0: kd> !trueref ffffc509bf28b080
ffffc509bf28b080: HandleCount: 7 PointerCount: 261732 RealPointerCount: 153
  • HandleCount represents objects are accessed using a handle, which is standard way of accessing resources in windows.

  • Real Pointer Count, another way to access the kernel object is through pointers, done in kernel mode.

OBJECT_HEADER
0: kd> dt nt!_OBJECT_HEADER
   +0x000 PointerCount     : Int8B
   +0x008 HandleCount      : Int8B
   +0x008 NextToFree       : Ptr64 Void
   +0x010 Lock             : _EX_PUSH_LOCK
   +0x018 TypeIndex        : UChar
   +0x019 TraceFlags       : UChar
   +0x019 DbgRefTrace      : Pos 0, 1 Bit
   +0x019 DbgTracePermanent : Pos 1, 1 Bit
   +0x01a InfoMask         : UChar
   +0x01b Flags            : UChar
   +0x01b NewObject        : Pos 0, 1 Bit
   +0x01b KernelObject     : Pos 1, 1 Bit
   +0x01b KernelOnlyAccess : Pos 2, 1 Bit
   +0x01b ExclusiveObject  : Pos 3, 1 Bit
   +0x01b PermanentObject  : Pos 4, 1 Bit
   +0x01b DefaultSecurityQuota : Pos 5, 1 Bit
   +0x01b SingleHandleEntry : Pos 6, 1 Bit
   +0x01b DeletedInline    : Pos 7, 1 Bit
   +0x01c Reserved         : Uint4B
   +0x020 ObjectCreateInfo : Ptr64 _OBJECT_CREATE_INFORMATION
   +0x020 QuotaBlockCharged : Ptr64 Void
   +0x028 SecurityDescriptor : Ptr64 Void
   +0x030 Body             : _QUAD  
0: kd> dt nt!_QUAD
   +0x000 UseThisFieldToCopy : Int8B
   +0x000 DoNotUseThisField : Float


0: kd> ?? sizeof(_OBJECT_HEADER)
unsigned int64 0x38

The Body field is of type QUAD, which overlaps with the actual object’s data. So, subtract 0x8 from 0x38.

In a 64-bit architecture,_OBJECT_HEADER structure size is 0x30 bytes. To obtain the starting address of OBJECT_HEADER from OBJECT_BODY address, simply subtract 0x30 bytes from OBJECT_BODY address.

0: kd> dt nt!_OBJECT_HEADER ffffc509bf28b080-30
   +0x000 PointerCount     : 0n261732
   +0x008 HandleCount      : 0n7
   +0x008 NextToFree       : 0x00000000`00000007 Void
   +0x010 Lock             : _EX_PUSH_LOCK
   +0x018 TypeIndex        : 0xc ''
   +0x019 TraceFlags       : 0 ''
   +0x019 DbgRefTrace      : 0y0
   +0x019 DbgTracePermanent : 0y0
   +0x01a InfoMask         : 0x88 ''
   +0x01b Flags            : 0 ''
   +0x01b NewObject        : 0y0
   +0x01b KernelObject     : 0y0
   +0x01b KernelOnlyAccess : 0y0
   +0x01b ExclusiveObject  : 0y0
   +0x01b PermanentObject  : 0y0
   +0x01b DefaultSecurityQuota : 0y0
   +0x01b SingleHandleEntry : 0y0
   +0x01b DeletedInline    : 0y0
   +0x01c Reserved         : 0x7ffe
   +0x020 ObjectCreateInfo : 0xffffc509`bae86cc0 _OBJECT_CREATE_INFORMATION
   +0x020 QuotaBlockCharged : 0xffffc509`bae86cc0 Void
   +0x028 SecurityDescriptor : 0xffff9901`11fa936e Void
   +0x030 Body             : _QUAD
  • InfoMask is 0x88.

  • TraceFlags is an union of DbgRefTrace (0th bit) and DbgTracePermanent(1st bit). When the DbgRefTrace flag is set, it enables the tracking of reference count changes for the associated object. This allows developers and system administrators to monitor how many references exist to a particular object.

  • PermanentObject = 0, which means the process would be deleted once PointerCount and HandleCount reaches to 0. If PermanentObject=1, the object won’t be deleted the count drops to 0.

  • ObjectCreateInfo is a strucutre of _OBJECT_CREATE_INFORMATION, which maintains information about Process Creation Attributes, Namespace where it is created, Charged Paged (amount of memory allocated from the paged pool that is currently in use by the system), Non-Paged Pool and so on

  • In the older version of Windows, _OBJECT_HEADER->Type used to point to OBJECT_TYPE.

  • From Windows 7 onwards, it changed to 8 bit value and stored at _OBJECT_HEADER->TypeIndex. It points to index to a data structure nt!ObTypeIndexTable, which is an array of pointers of _OBJECT_TYPE.

OBJECT_HEADER Flags
#define OB_FLAG_NEW_OBJECT              0x01 // NewObject (New Object Created, not exists in Pool)
#define OB_FLAG_KERNEL_OBJECT           0x02 // KernelObject (Object can only have Kernel handles)
#define OB_FLAG_CREATOR_INFO            0x04 // KernelOnlyAccess (Kernel can only open & access handles)
#define OB_FLAG_EXCLUSIVE_OBJECT        0x08 // ExclusiveObject (Process who created can only open & access it)
#define OB_FLAG_PERMANENT_OBJECT        0x10 // PermanentObject (Persits even HandleCount & PointerCount drops to 0)
#define OB_FLAG_DEFAULT_SECURITY_QUOTA  0x20 // DefaultSecurityQuota (defines SecurityDescriptor)
#define OB_FLAG_SINGLE_HANDLE_ENTRY     0x40 // SingleHandleEntry (Only contains one entry OBJECT_HEADER_HANDLE_INFO )
#define OB_FLAG_DELETED_INLINE          0x80 // DeletedInline (Object in queue for deletion)
Optional ObjectHeader
Optional Object Header(ObpInfoMaskToOffset)
_OBJECT_HEADER_CREATOR_INFO0 = 0x1
_OBJECT_HEADER_NAME_INFOInfoMask & 0x3 = 0x2
_OBJECT_HEADER_HANDLE_INFOInfoMask & 0x7 = 0x4
_OBJECT_HEADER_QUOTA_INFOInfoMask & 0xF = 0x8
_OBJECT_HEADER_PROCESS_INFOInfoMask & 0x1F = 0x10
_OBJECT_HEADER_AUDIT_INFOInfoMask & 0x3F = 0x20
_OBJECT_HEADER_EXTENDED_INFOInfoMask & 0x7F = 0x40
_OBJECT_HEADER_PADDING_INFOInfoMask & 0xFF = 0x80

InfoMask : 0x88 -> _OBJECT_HEADER_QUOTA_INFO

Decoding InfoMask

  • Corresponding ResultBit for _OBJECT_HEADER_QUOTA_INFO is 0x08.
  • Subtract ResultBit from InfoMask i.e. InfoMask - ResultBit = 0x88 - 0x8 = 0x80
  • After subtraction, it points to the next Optional Header.
  • Again, Update the InfoMask Value and Calculate it. It will give _OBJECT_HEADER_PADDING_INFO
InfoMask = 0x88

OptionalHeaders = ["_OBJECT_HEADER_CREATOR_INFO", "_OBJECT_HEADER_NAME_INFO", "_OBJECT_HEADER_HANDLE_INFO", "_OBJECT_HEADER_QUOTA_INFO", "_OBJECT_HEADER_PROCESS_INFO", "_OBJECT_HEADER_AUDIT_INFO", "_OBJECT_HEADER_EXTENDED_INFO", "_OBJECT_HEADER_PADDING_INFO"]

MaskBit = [0x0, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF]

ResultBit = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80]

while InfoMask != 0:
   for _ in range(len(OptionalHeaders)):
      if(ResultBit[_] == MaskBit[_] & InfoMask):
         print(OptionalHeaders[_]) 
         InfoMask -= ResultBit[_]


# Output: 
#_OBJECT_HEADER_QUOTA_INFO
#_OBJECT_HEADER_PADDING_INFO
0: kd> db ffffc509bf28b080-80
ffffc509`bf28b000  00 00 d0 02 50 72 6f 63-00 00 00 00 00 00 00 00  ....Proc........
ffffc509`bf28b010  01 00 00 00 00 00 00 00-8e 01 00 00 00 00 00 00  ................
ffffc509`bf28b020  00 00 00 00 00 00 00 00-01 30 53 5e 20 00 00 00  .........0S^ ...
ffffc509`bf28b030  00 10 00 00 48 0c 00 00-78 00 00 00 fe 7f 00 00  ....H...x.......
ffffc509`bf28b040  c0 6c e8 ba 09 c5 ff ff-00 e0 05 5e fe 7f 00 00  .l.........^....
ffffc509`bf28b050  64 fe 03 00 00 00 00 00-07 00 00 00 00 00 00 00  d...............
ffffc509`bf28b060  00 00 00 00 00 00 00 00-0c 00 88 00 fe 7f 00 00  ................
ffffc509`bf28b070  c0 6c e8 ba 09 c5 ff ff-6e 93 fa 11 01 99 ff ff  .l......n.......
0: kd> dt ntkrnlmp!_OBJECT_HEADER_*
          ntkrnlmp!_OBJECT_HEADER_QUOTA_INFO
          ntkrnlmp!_OBJECT_HEADER_PROCESS_INFO
          ntkrnlmp!_OBJECT_HEADER_HANDLE_INFO
          ntkrnlmp!_OBJECT_HEADER_NAME_INFO
          ntkrnlmp!_OBJECT_HEADER_CREATOR_INFO
          ntkrnlmp!_OBJECT_HEADER_AUDIT_INFO
          ntkrnlmp!_OBJECT_HEADER_EXTENDED_INFO
          ntkrnlmp!_OBJECT_HEADER_PADDING_INFO
// OBJECT_BODY - OBJECT_HEADER_SIZE - _OBJECT_HEADER_QUOTA_INFO_SIZE
0: kd> ? ffffc509bf28b080-30-20
Evaluate expression: -64829324218320 = ffffc509`bf28b030

0: kd>  dt nt!_OBJECT_HEADER_QUOTA_INFO ffffc509`bf28b050-20
   +0x000 PagedPoolCharge  : 0x1000
   +0x004 NonPagedPoolCharge : 0xc48
   +0x008 SecurityDescriptorCharge : 0x78
   +0x00c Reserved1        : 0x7ffe
   +0x010 SecurityDescriptorQuotaBlock : 0xffffc509`bae86cc0 Void
   +0x018 Reserved2        : 0x00007ffe`5e05e000

Objects are always created with headers attached to the object body. However, the number of headers depends entirely on how the object is created. In Kernel, Windows maintains an array of all possible combinations of headers and stores the value in ObpInfoMaskToOffset. Just say, I used _OBJECT_HEADER_QUOTA_INFO, then size would be 0x20. If I used two different headers, then InfoMask value would be sum of size of both headers result bit.

Locating OBJECT_HEADER

The Optional Headers would appear before main OBJECT_HEADER and corresponding OptionalHeader result bit value would be stored in InfoMask.

// ObpInfoMaskToOffset + ResultBit Value of QUOTA_INFO
0: kd> db ObpInfoMaskToOffset + 0x8 L1
fffff807`1ec3de28  20   
  • Subtract it from _OBJECT_HEADER - _OBJECT_HEADER_QUOTA_INFO
0: kd> dt nt!_OBJECT_HEADER_QUOTA_INFO ffffc509`bf28b050-20
   +0x000 PagedPoolCharge  : 0x1000
   +0x004 NonPagedPoolCharge : 0xc48
   +0x008 SecurityDescriptorCharge : 0x78
   +0x00c Reserved1        : 0x7ffe
   +0x010 SecurityDescriptorQuotaBlock : 0xffffc509`bae86cc0 Void
   +0x018 Reserved2        : 0x00007ffe`5e05e000
  • When system opens any handles, it consumes system resources, and this keeps track of those for that given Object.
Optional Object Header Structures
0: kd> dt ntkrnlmp!_OBJECT_HEADER_PROCESS_INFO
   +0x000 ExclusiveProcess : Ptr64 _EPROCESS
   +0x008 Reserved         : Uint8B
0: kd> dt ntkrnlmp!_OBJECT_HEADER_HANDLE_INFO
   +0x000 HandleCountDataBase : Ptr64 _OBJECT_HANDLE_COUNT_DATABASE
   +0x000 SingleEntry      : _OBJECT_HANDLE_COUNT_ENTRY
0: kd> dt nt!_OBJECT_HANDLE_COUNT_DATABASE
   +0x000 CountEntries     : Uint4B
   +0x008 HandleCountEntries : [1] _OBJECT_HANDLE_COUNT_ENTRY
0: kd> dt nt!_OBJECT_HANDLE_COUNT_ENTRY
   +0x000 Process          : Ptr64 _EPROCESS
   +0x008 HandleCount      : Pos 0, 24 Bits
   +0x008 LockCount        : Pos 24, 8 Bits
  • Has entries of handles for per process
0: kd> dt ntkrnlmp!_OBJECT_HEADER_NAME_INFO
   +0x000 Directory        : Ptr64 _OBJECT_DIRECTORY
   +0x008 Name             : _UNICODE_STRING
   +0x018 ReferenceCount   : Int4B
   +0x01c Reserved         : Uint4B
  • Has Object name which makes it visible to other objects
0: kd> dt ntkrnlmp!_OBJECT_HEADER_CREATOR_INFO   
   +0x000 TypeList         : _LIST_ENTRY
   +0x010 CreatorUniqueProcess : Ptr64 Void
   +0x018 CreatorBackTraceIndex : Uint2B
   +0x01a Reserved1        : Uint2B
   +0x01c Reserved2        : Uint4B
  • Links same-type objects, tracks creating process, and captures backtrace.
0: kd> dt ntkrnlmp!_OBJECT_HEADER_AUDIT_INFO
   +0x000 SecurityDescriptor : Ptr64 Void
   +0x008 Reserved         : Uint8B
  • Has a pointer to Security Descriptor which was used while creating an Object. Used for File Objects to track audit.
0: kd> dt ntkrnlmp!_OBJECT_HEADER_EXTENDED_INFO
   +0x000 Footer           : Ptr64 _OBJECT_FOOTER   
   +0x008 Reserved         : Uint8B
  • Has a pointer to _OBJECT_FOOTER
0: kd> dt ntkrnlmp!_OBJECT_HEADER_PADDING_INFO
   +0x000 PaddingAmount    : Uint4B                  -
  • It’s just for alignment of object body.

alt text

OBJECT_HEADER TypeIndex

In older versions of Windows,Type field used to point to _OBJECT_TYPE structure. Starting with Windows 7, TypeIndex field is introduced, which stores an encoded value. When decoded, it provides an index that is used to locate _OBJECT_TYPE structure within ObTypeIndexTable array.

Now, Let’s look into TypeIndex

0: kd> dt nt!_OBJECT_HEADER ffffc509bf28b080-30
   +0x000 PointerCount     : 0n261732
   +0x008 HandleCount      : 0n7
   +0x008 NextToFree       : 0x00000000`00000007 Void
   +0x010 Lock             : _EX_PUSH_LOCK
   +0x018 TypeIndex        : 0xc ''
   +0x019 TraceFlags       : 0 ''
   +0x019 DbgRefTrace      : 0y0
   +0x019 DbgTracePermanent : 0y0
   +0x01a InfoMask         : 0x88 ''
   +0x01b Flags            : 0 ''
   ....
   ....

TypeIndex : 0x0c

0: kd> x nt!ObTypeIndexTable 
fffff807`1ed14e80 nt!ObTypeIndexTable = <no type information>
0: kd> x nt!ObGetObjectType
fffff807`1e6e7a50 nt!ObGetObjectType (ObGetObjectType)

0: kd> uf nt!ObGetObjectType
nt!ObGetObjectType:
fffff807`1e6e7a50 488d41d0        lea     rax,[rcx-30h]			 ; _OBJECT_HEADER 
fffff807`1e6e7a54 0fb649e8        movzx   ecx,byte ptr [rcx-18h] ; _OBJECT_HEADER->TypeIndex
fffff807`1e6e7a58 48c1e808        shr     rax,8					 ; _OBJECT_HEADER >> 8 
fffff807`1e6e7a5c 0fb6c0          movzx   eax,al				 ; (_OBJECT_HEADER >> 8) & 0xff
fffff807`1e6e7a5f 4833c1          xor     rax,rcx				 ;  ((_OBJECT_HEADER >> 8) & 0xff ) ^ (_OBJECT_HEADER->TypeIndex)
fffff807`1e6e7a62 0fb60dc3cc6200  movzx   ecx,byte ptr [nt!ObHeaderCookie (fffff807`1ed1472c)]
fffff807`1e6e7a69 4833c1          xor     rax,rcx				 ; ; (((_OBJECT_HEADER >> 8) & 0xff ) ^ (_OBJECT_HEADER->TypeIndex) ) ^ ((nt!ObHeaderCookie) & 0xff)
fffff807`1e6e7a6c 488d0d0dd46200  lea     rcx,[nt!ObTypeIndexTable (fffff807`1ed14e80)]
fffff807`1e6e7a73 488b04c1        mov     rax,qword ptr [rcx+rax*8]   ; Accessing the pointer to nt!ObTypeIndexTable
fffff807`1e6e7a77 c3              ret
  • ObHeaderCookie is a security mitigation in Windows kernel to enhance kernel object integrity. This cookie value is randomly generated when system boots up. This makes kernel objects less predictable and prevents the attackers to exploit these structures.

  • ObTypeIndexTable is an array which keeps track of each entry of _OBJECT_TYPE structure represents which specific type of object i.e. Thread, Process, Files and so on.

0: kd> db nt!ObHeaderCookie L1
fffff807`1ed1472c  bb                                               .   

(((_OBJECT_HEADER >> 0x8) & 0xff ) ^ (_OBJECT_HEADER->TypeIndex) ) ^ ((nt!ObHeaderCookie) & 0xff)

ObGetObjectType
nt!ObTypeIndexTable[
(   (((_OBJECT_HEADER >> 0x8) & 0xff ) ^ (_OBJECT_HEADER->TypeIndex) ) ^ ((nt!ObHeaderCookie) & 0xff)) * 0x08
   ]

(((0xffffc509bf28b080 » 0x08) & 0xff) ^ (0xbb) ^ ((0x0c) & 0xff)) = 0x7

0: kd> ? 0xb0 ^ 0xbb ^ 0x0c
Evaluate expression: 7 = 00000000`00000007
0: kd> dq nt!ObTypeIndexTable L8
fffff807`1ed14e80  00000000`00000000 ffffb000`adbac000
fffff807`1ed14e90  ffffc509`b88ab640 ffffc509`b88ab220
fffff807`1ed14ea0  ffffc509`b88abbc0 ffffc509`b88abd20
fffff807`1ed14eb0  ffffc509`b88ab7a0 ffffc509`b88ab900

0: kd> dq nt!ObTypeIndexTable + (0x8 * 0x7) L1
fffff807`1ed14eb8  ffffc509`b88ab900
0: kd> dt nt!_OBJECT_TYPE ffffc509`b88ab900
   +0x000 TypeList         : _LIST_ENTRY [ 0xffffc509`b88ab900 - 0xffffc509`b88ab900 ]
   +0x010 Name             : _UNICODE_STRING "Process"
   +0x020 DefaultObject    : (null) 
   +0x028 Index            : 0x7 ''
   +0x02c TotalNumberOfObjects : 0x68
   +0x030 TotalNumberOfHandles : 0x4e1
   +0x034 HighWaterNumberOfObjects : 0x6c
   +0x038 HighWaterNumberOfHandles : 0x55e
   +0x040 TypeInfo         : _OBJECT_TYPE_INITIALIZER
   +0x0b8 TypeLock         : _EX_PUSH_LOCK
   +0x0c0 Key              : 0x636f7250
   +0x0c8 CallbackList     : _LIST_ENTRY [ 0xffff9901`07feee00 - 0xffff9901`07feee00 ]

Pool Header

0: kd> dt nt!_POOL_HEADER ffffc509`bf28b000
   +0x000 PreviousSize     : 0y00000000 (0)
   +0x000 PoolIndex        : 0y00000000 (0)
   +0x002 BlockSize        : 0y11010000 (0xd0)
   +0x002 PoolType         : 0y00000010 (0x2) // NonPagedPoolMustSucceed
   +0x000 Ulong1           : 0x2d00000
   +0x004 PoolTag          : 0x636f7250
   +0x008 ProcessBilled    : (null) 
   +0x008 AllocatorBackTraceIndex : 0
   +0x00a PoolTagHash      : 0
  • PreviousSize : Size of Previous Chunk / 16
  • PoolIndex : Index to an array of PoolDescriptor
  • BlockSize : Size of Current Block / 16
  • PoolType : Information regarding the allocation tyoe
  • ProcessBilled: Pointer to _EPROCESS, which made this allocation. Only exists if PoolType is PoolQuota.
0: kd> dt nt!_POOL_TYPE
   NonPagedPool = 0n0
   NonPagedPoolExecute = 0n0
   PagedPool = 0n1
   NonPagedPoolMustSucceed = 0n2
   DontUseThisType = 0n3
   NonPagedPoolCacheAligned = 0n4
   PagedPoolCacheAligned = 0n5
   NonPagedPoolCacheAlignedMustS = 0n6
   MaxPoolType = 0n7
   NonPagedPoolBase = 0n0
   NonPagedPoolBaseMustSucceed = 0n2
   NonPagedPoolBaseCacheAligned = 0n4
   NonPagedPoolBaseCacheAlignedMustS = 0n6
   NonPagedPoolSession = 0n32
   PagedPoolSession = 0n33
   NonPagedPoolMustSucceedSession = 0n34
   DontUseThisTypeSession = 0n35
   NonPagedPoolCacheAlignedSession = 0n36
   PagedPoolCacheAlignedSession = 0n37
   NonPagedPoolCacheAlignedMustSSession = 0n38
   NonPagedPoolNx = 0n512
   NonPagedPoolNxCacheAligned = 0n516
   NonPagedPoolSessionNx = 0n544

Lets check it for some other process

Inspecting Notepad.exe

0: kd> !process 0 0 notepad.exe
PROCESS ffffc509c222c340
    SessionId: 1  Cid: 05a8    Peb: 74d112d000  ParentCid: 1148
    DirBase: 41f4c002  ObjectTable: ffff990111c26780  HandleCount: 482.
    Image: notepad.exe

0: kd> !object ffffc509c222c340
Object: ffffc509c222c340  Type: (ffffc509b88ab900) Process
    ObjectHeader: ffffc509c222c310 (new version)
    HandleCount: 6  PointerCount: 195153

0: kd> db ffffc509c222c340-90
ffffc509`c222c2b0  00 6f d0 02 50 72 6f 63-c8 14 c1 c1 09 c5 ff ff  .o..Proc........
ffffc509`c222c2c0  00 00 00 00 00 00 00 00-a8 0c 10 00 03 00 00 00  ................
ffffc509`c222c2d0  00 00 00 00 00 00 00 00-50 00 e3 c0 09 c5 ff ff  ........P.......
ffffc509`c222c2e0  00 00 46 09 01 99 ff ff-00 f0 18 00 30 00 00 00  ..F.........0...
ffffc509`c222c2f0  00 10 00 00 48 0c 00 00-78 00 00 00 00 00 00 00  ....H...x.......
ffffc509`c222c300  c0 6c e8 ba 09 c5 ff ff-95 61 07 00 00 00 00 00  .l.......a......
ffffc509`c222c310  51 fa 02 00 00 00 00 00-06 00 00 00 00 00 00 00  Q...............
ffffc509`c222c320  00 00 00 00 00 00 00 00-7f 00 88 00 00 00 00 00  ................

0: kd> dt nt!_OBJECT_HEADER ffffc509c222c340-30
   +0x000 PointerCount     : 0n195153
   +0x008 HandleCount      : 0n6
   +0x008 NextToFree       : 0x00000000`00000006 Void
   +0x010 Lock             : _EX_PUSH_LOCK
   +0x018 TypeIndex        : 0x7f ''
   +0x019 TraceFlags       : 0 ''
   +0x019 DbgRefTrace      : 0y0
   +0x019 DbgTracePermanent : 0y0
   +0x01a InfoMask         : 0x88 ''
   +0x01b Flags            : 0 ''
   +0x01b NewObject        : 0y0
   +0x01b KernelObject     : 0y0
   +0x01b KernelOnlyAccess : 0y0
   +0x01b ExclusiveObject  : 0y0
   +0x01b PermanentObject  : 0y0
   +0x01b DefaultSecurityQuota : 0y0
   +0x01b SingleHandleEntry : 0y0
   +0x01b DeletedInline    : 0y0
   +0x01c Reserved         : 0
   +0x020 ObjectCreateInfo : 0xffffc509`bae86cc0 _OBJECT_CREATE_INFORMATION
   +0x020 QuotaBlockCharged : 0xffffc509`bae86cc0 Void
   +0x028 SecurityDescriptor : 0xffff9901`11fa9365 Void
   +0x030 Body             : _QUAD


0: kd> db nt!ObHeaderCookie L1
fffff807`1ed1472c  bb                                               .

0: kd> ? (0xbb ^ 0x7f ^ c3)
Evaluate expression: 7 = 00000000`00000007

0: kd> ? nt!ObTypeIndexTable + ( 0x7 * @$ptrsize )
Evaluate expression: -8765511217480 = fffff807`1ed14eb8

0: kd> dq fffff807`1ed14eb8 L1
fffff807`1ed14eb8  ffffc509`b88ab900

0: kd> dt nt!_OBJECT_TYPE ffffc509`b88ab900
   +0x000 TypeList         : _LIST_ENTRY [ 0xffffc509`b88ab900 - 0xffffc509`b88ab900 ]
   +0x010 Name             : _UNICODE_STRING "Process"
   +0x020 DefaultObject    : (null) 
   +0x028 Index            : 0x7 ''
   +0x02c TotalNumberOfObjects : 0x68
   +0x030 TotalNumberOfHandles : 0x4e1
   +0x034 HighWaterNumberOfObjects : 0x6c
   +0x038 HighWaterNumberOfHandles : 0x55e
   +0x040 TypeInfo         : _OBJECT_TYPE_INITIALIZER
   +0x0b8 TypeLock         : _EX_PUSH_LOCK
   +0x0c0 Key              : 0x636f7250
   +0x0c8 CallbackList     : _LIST_ENTRY [ 0xffff9901`07feee00 - 0xffff9901`07feee00 ]

Inspecting csrss.exe


0: kd> !process csrss.exe
PROCESS ffff938cd7e86080
    SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 001aa000  ObjectTable: ffffc705c3015080  HandleCount: 2197.
    Image: System
    VadRoot ffff938cd7ea5560 Vads 6 Clone 0 Private 21. Modified 10228. Locked 0.
    DeviceMap ffffc705c304a540
....
....

0: kd> !pool ffff938cd7e86010
Pool page ffff938cd7e86010 region is Nonpaged pool
 ffff938cd7e86010 size:  e00 previous size:    0  (Allocated)  Proc
 ffff938cd7e86e10 size:  1f0 previous size:    0  (Free)       ..[U

0: kd> dt nt!_POOL_HEADER ffff938cd7e86080-70
   +0x000 PreviousSize     : 0y00000000 (0)
   +0x000 PoolIndex        : 0y11111111 (0xff)
   +0x002 BlockSize        : 0y11100000 (0xe0)
   +0x002 PoolType         : 0y00000010 (0x2)
   +0x000 Ulong1           : 0x2e0ff00
   +0x004 PoolTag          : 0x636f7250
   +0x008 ProcessBilled    : 0xffff938c`d7e4e9f8 _EPROCESS
   +0x008 AllocatorBackTraceIndex : 0xe9f8
   +0x00a PoolTagHash      : 0xd7e4
0: kd> !object ffff938cd7e86080
Object: ffff938cd7e86080  Type: (ffff938cd7eabbc0) Process
    ObjectHeader: ffff938cd7e86050 (new version)
    HandleCount: 4  PointerCount: 131200

0: kd> dt nt!_OBJECT_HEADER ffff938cd7e86080-30
   +0x000 PointerCount     : 0n131200
   +0x008 HandleCount      : 0n4
   +0x008 NextToFree       : 0x00000000`00000004 Void
   +0x010 Lock             : _EX_PUSH_LOCK
   +0x018 TypeIndex        : 0x7c '|'
   +0x019 TraceFlags       : 0 ''
   +0x019 DbgRefTrace      : 0y0
   +0x019 DbgTracePermanent : 0y0
   +0x01a InfoMask         : 0x80 ''
   +0x01b Flags            : 0x2 ''
   +0x01b NewObject        : 0y0
   +0x01b KernelObject     : 0y1
   +0x01b KernelOnlyAccess : 0y0
   +0x01b ExclusiveObject  : 0y0
   +0x01b PermanentObject  : 0y0
   +0x01b DefaultSecurityQuota : 0y0
   +0x01b SingleHandleEntry : 0y0
   +0x01b DeletedInline    : 0y0
   +0x01c Reserved         : 0xff938cd7
   +0x020 ObjectCreateInfo : 0xfffff806`7fe66a40 _OBJECT_CREATE_INFORMATION
   +0x020 QuotaBlockCharged : 0xfffff806`7fe66a40 Void
   +0x028 SecurityDescriptor : 0xffffc705`c30156a8 Void
   +0x030 Body             : _QUAD

InfoMask : 0x80 -> _OBJECT_HEADER_PADDING_INFO

0: kd> dt nt!_OBJECT_HEADER_PADDING_INFO
   +0x000 PaddingAmount    : Uint4B
  • There is one more way to find the offset
0: kd> db ObpInfoMaskToOffset + 80 L1
fffff806`7fe39020  04
  • Subtract 04 from the Header Offset
0: kd> dt nt!_OBJECT_HEADER_PADDING_INFO ffff938cd7e86080-30-4
   +0x000 PaddingAmount    : 0x30

alt text

References