Windows Process Internals: A few Concepts to know before jumping on Memory Forensics [Part 5] — A Journey in to the Undocumented Process Handle Structures

imp hash
7 min readSep 13, 2020

In this series of articles of “Must know Process Internals for Memory Forensics” — we have traversed through ActiveProcessLinks (doubly-linked list) of EPROCESS in Part-1 to understand how memory manager keeps track of active processes on the system.

In Part-2, we have explored and traversed through Ldrmodules of _PEB structure that gave us insights how memory manager keeps track of all the loaded Dynamic Link Libraries (dlls) by a specific process.

In Part-3, we discussed about how system tracks loaded kernel modules by traversing and exploring nt!PsLoadedModuleList.

In the latest part, Part-4, we saw the details of Virtual Address Descriptors (VADs) and identified the details buried in to the VAD nodes.

This article would be Part-5 of the series and this would, most probably, be the last article (for now) of the series. In this Part-5, we will explore the kernel structures associated with Process Handles and how OS stores handle information for each process in the memory. The kernel structures related to handles have gone through a frequent change during each major version upgrade of the operating system. Windows 7, Windows 8, Windows 8.1 and now latest Windows 10 — all of these have different handle structures and a unique way to reference or to keep track of the handles in to the memory. I would say, Microsoft is introducing more and more complexity as they evolve hence from the forensics perspective, it has become harder to reverse these undocumented complex structures.

In this article, we will explore the kernel handle structures of Windows 10 (build 18362) via live kernel debugging. We will start with EPROCESS structure of one process and will follow through the cues provided by the handle kernel structures to reach to the actual Object and Object type that has been referred by a specific handle. Let us start the journey in to the kernel handle structures!!

What is a Handle, anyway?

If a process needs an access to any object such as a file, registry key, mutex, process, thread etc., it needs to get a hold of its handle first. Then the process can use this handle to get an access to the object referenced by this handle. The handle is a reference to a kernel structure that holds an information about the object that the handle refers to.

We will decode this jargon in the following sections. You may like to re-read this information after reading the entire article.

How Memory Manager keeps track of Process Objects & Handles?

Each process has a executive object structure called EPROCESS in the kernel memory. This EPROCESS structure has a field named “ObjectTable”. This ObjectTable is a _handle_table structure.

This structure has a field named “TableCode”. TableCode provides the reference to the base of the handle table entries (_handle_table_entries). You can see in the diagram below that there are indexes (0x04,0x08,0x0c and so on) are written to the adjacent to each handle_table_entry. When we say that process has got an access to the handle of an object — that essentially means that the process knows which index (represented by a handle) to go to in the handle_table_entries retrieve the pointer to the object that it needs an access to. Therefore, handle is nothing but the index in to this handle_table_entry. A process uses this index/handle to retrieve the information about the object that entry points to.

These entries are of _handle_table_entry structure. This structure contains the field named “ObjectPointerBits” that points to the object_header and we can get the address of the object from object_header.

The object_header contains a field named “IndexType” that points to the structure _object_type that gives us an information about the type of the object this header referring to OR in other words, what type of object (like file,mutex, directory, process etc.) structure to expect after the object_header. This is important because handle table entries are mix of all objects that process has open handle to and TypeIndex lets us know about the type of object refereed by a specific handle.

Please refer to the following diagram that helps us to understand how OS stores information related to process objects and its handles.

Figure 1. Logical view of pointers between various handle structures in memory

Exploring the handle structures through kernel debugging

Let us review all of these structures discussed above through live kernel debugging.

First of all, enumerate the active processes & pick any random process for our exploration. I have picked up a process that has its EPROCESS structure at 0xffffa703b3ebc080 address. Now, let us examine its ObjectTable by enumerating EPROECESS. Once, we get the ObjectTable, we can enumerate it and the get the address of the “TableCode” as “TableCode” is one of the fields in the ObjectTable. Please see following snippet for the same.

Figure 2. ObjectTable and TableCode
Figure 3. Mapping of the diagram with a debugger output — ObjectTable & TableCode

Now, let us enumerate what we have got at the TableCode. We expect to get the handle table entries at the address provided by the “TableCode”. We can derive base address of the handle table entries by ANDing the TableCode address with ~0x07.

Figure 4. deriving base address of handle table entries from TableCode

Please refer following snippets for the same. As expected, we have got the base address followed by handle table entries.

Figure 5. handle table entries starting with the base address derived earlier
Figure 6. Mapping of the diagram and a debugger output — handle table entries and indexes

We have got the handle table entries now. These are nothing but the handles to the actual object. As mentioned earlier, each handle table entry is of structure type _handle_table_entry. _handle_table_entry has got a field named “ObjectPointerBits” that points to the header of the object that is referred by that handle entry.

Let us take handle table entry at 0x14 index. The address at 0x14 index is 0xffffba8a1e3f1050. Let’s us enumerate this entry to get the pointer to the object.

Figure 7. Enumerating a handle table entry
Figure 8. Mapping of the diagram and a debugger output — ObjectPointerBits

We need to get object_header from “ObjectPointerBits”. The simple way of doing it add 0 at the end of the and ffff at the beginning of the “ObjectPointerBits” to complete 64bit pointer address.

Figure 9. Deriving a object_header address from ObjectPointerBits

I don’t know how it works but I could get the pointer to the object header by leftshift (<<4) and ORing the result with 0xffff000000000000. The derived hex number is a pointer to the object header. This is represented by _object_header structure.

Now, let us enumerate the _object_header and get the to the _object_type to identify the type of object followed by this object_header.

Figure 10. Enumerating a object_header
Figure 11. Mapping of the diagram and a debugger output — TypeIndex

As I said in the introduction of the article, Microsoft has made it more complex as they evolve with the operating systems. In earlier version of the Microsoft (like Windows 7) this TypeIndex is an index to the nt!ObTypeIndexTable,however, now this field does not refer to the direct index in to the ObType table. We need to derive the lookup index from the “TypeIndex” field and then use that index to lookup the type of the object in the nt!ObTypeIndexTable. To derive the lookup index from the: TypeIndex”, please perform following operations on the “TypeIndex”. We need to take the second least significant byte from the header. In our case,

object header is 0xffffa703`b2c47ae0 hence second least significant byte would be “7a”.

TypeIndex value is 0x68

Figure 12. Object_header & TypeIndex Values

Nt!ObHeaderCookie value is 0c

Figure 12. nt!ObHeaderCookie value

To derive lookup index, we need to XOR all these 3 values.

Figure 13. Deriving lookup index from TypeIndex value

Please refer to this amazing article at the link by Ashraf Abdalhalim to get more details about why we are doing this XOR to calculate the lookup index.

So, our lookup index is 1e. We can now enumerate object type by looking up in to the nt!ObTypeIndexTable.

Figure 14. Enumerating _object_type to get the object name/type

As we can see the object type is TpWorkerFactory.

Figure 15. Mapping of the diagram with a debugger output — Name in _object_type

We can verify the same by enumerating the same handle through !handle in the windbg.

Figure 16. !handle output from debugger

As expected, the all values are matching.

So, folks, we started with EPROCESS and reached to object_type by following cues provided by the various kernel structures. I hope you enjoy this reading.

That’s it for now, folks!! Happy hunting, fellas!!

by :
Kirtar Oza
Twitter : Krishna (@kirtar_oza)