Wednesday, September 26, 2012

MoVP 3.3 Analyzing USER Handles and the Win32k.sys Gahti

Month of Volatility Plugins

Since the early days of memory forensics, tools have analyzed kernel/executive objects such as processes, threads, mutexes, open files, and registry keys. In fact, I would consider that a basic capability of any framework. One thing that sets Volatility apart from other tools, besides the 10 points on our wiki and the massive number of new features already discussed in MoVP posts, is the ability to enumerate and analyze USER objects and USER handle tables. Today we'll introduce a plugin named gahti that determines the various different types of USER objects on a system and another plugin named userhandles which traverses the handle table entries and associates them with the owning processes or threads. As you'll soon see, this is an important aspect of forensics that no other tools implement - not even those with pretty GUIs or Microsoft's own kernel debugger.

USER Objects

There are either 20 (Windows XP through Vista) or 22 (Windows 7) types of USER objects, including TYPE_FREE. From a malware and forensics perspective, the user handle tables are extremely valuable, because they provide an alternative method of finding evidence. For example, we already discussed how to find windows and message hooks (both by following pointers in the tagDESKTOP structures), but the same objects can be found by walking the USER handle table. Thus if an attacker tried to get creative and hide objects using DKOM, they’d have to hide in two places rather than one. Also, the handle tables can serve as a primary way of finding objects that we don’t locate in other ways, such as clipboard data (see a future MoVP post).

USER Object Types (Gahti)

The win32k!_gahti symbol is an array of tagHANDLETYPEINFO structures – one for each object type. These structures are similar in concept to nt!_OBJECT_TYPE for executive objects - they provide a reference of information about the various object types. In particular the handle type info structures tell you what pool tags (if any) are associated with each object, where the object is allocated (desktop heap, shared heap, session pool), and whether the object is thread owned or process owned. The structure for x64 is shown below:

fnDestroy member points to the deallocation/cleanup function for the object type

dwAllocTag is similar to a pool tag - a 32-bit value that can be used to find or identify the allocation in memory

bObjectCreateFlags can be used to determine if an object is thread-owned or process-owned, if its allocated from the shared or desktop heaps, etc

Before moving on, let’s take a quick look at the output of the gahti plugin on an x64 Windows 7 system. The first structure in the gahti is always for TYPE_FREE, whose members are all 0. You can then see TYPE_WINDOW objects have a tag Uswd, they are thread-owned and they’re allocated from the desktop heap (or failing that, the session pool). TYPE_TIMER (GDI timers) objects are process owned. TYPE_CLIPDATA (clipboard objects) are neither thread nor process owned – which makes sense because data copied to the clipboard is freely accessible by any process (in the same session) that calls GetClipboardData.

Now that you know what type of USER objects exist, we should discuss the critical tagSHAREDINFO structure - which can be found at win32k!_gSharedInfo. This structure contains a pointer to the USER handle table, which is basically a map to all USER objects in use on the system. The challenging part is finding this symbol and structure in a 10 GB (or however large your RAM is) memory dump. We cannot rely on calling APIs from dbghelp.dll because Volatility must work on non-Windows analysis systems. Although there is a Python PDB parser written by Brendan Dolan-Gavitt (a Volatility developer), its not integrated yet into the core code base. Furthermore, the structure we're looking for isn't allocated dynamically, thus there are no pool tags to scan for. We must overcome these challenges to find a method that is both accurate (i.e. it only finds one possibility - the correct one) and reliable (i.e. it works across all Windows versions, service packs and hardware architectures).

To find the needle in the haystack, start with what you know - the symbol is somewhere in win32k.sys. Already that clue narrows our search down to 3-5 MB. Then do a little digging - open win32k.sys in IDA Pro and use the Names pane to locate _gSharedInfo. As shown below, the symbol exists in the .data section of the PE file. Depending on the build of win32k.sys being analyzed, now the search can be narrowed to about 100 - 150 KB.

At this point, we can use some basic pattern/member matching to find the structure. Yet before we do that, you should know a little bit about the structure whose members you're trying to match. On a Windows 7 x64 system, the tagSHAREDINFO looks like this:

The psi member should point to a valid tagSERVERINFO structure. The aheList should point to an array of _HANDLEENTRY – one for each handle in the table. To determine how many handles are currently in use, you can look at tagSHAREDINFO.psi.cHandleEntries. The HeEntrySize is equal to sizeof(_HANDLEENTRY) for the current platform. The ulSharedDelta is a delta that usermode processes can use to determine the location of USER objects in kernel memory. With the information we've gathered so far, its possible to write code for Volatility that can in fact find this needle in a haystack. The procedure is as follows:

Determine the base address of win32k.sys as mapped into the session space

Locate the .data PE section. If the PE header is corrupt or paged (we've seen this happen in very busy large memory systems like 80 GB RAM Hyper-V cluster servers), then we just brute force our search using the 3-5 MB full length of win32k.sys instead of just the .data section.

Iterate over the data on a DWORD boundary and instantiate a tagSHAREDINFO object at the address - then determine if its valid using the class's is_valid method - this is where the sanity checks are performed.

Just to give you an idea of how that last step appears in Python within Volatility's architecture, here it is:

class tagSHAREDINFO(obj.CType):

"""A class for shared info blocks"""

def is_valid(self):

"""The sanity checks for tagSHAREDINFO structures"""

if not obj.CType.is_valid(self):

return False

# The kernel's version of tagSHAREDINFO should always have

# a zeroed-out shared delta member.

if self.ulSharedDelta != 0:

return False

# The pointer to our server information structure must be valid

if not self.psi.is_valid():

return False

# The pointer to the handle table must be valid

if not self.aheList.is_valid():

return False

# The final check is that the total size in bytes of the handle

# table is equal to the size of a _HANDLEENTRY multiplied by the

# number of _HANDLEENTRY structures.

return (self.psi.cbHandleTable /

self.obj_vm.profile.get_obj_size("_HANDLEENTRY")

== self.psi.cHandleEntries)

Now you should be able to find the tagSHAREDINFO structure on all versions of Windows without any problem. Tarjei Mandt’s Windows Hook of Death: Kernel Attacks through Usermode Callbacks describes two additional ways of finding tagSHAREDINFO, which can also be useful depending on your context. For example, you can use user32!_gSharedInfo – a symbol exported on Windows 7 (but only Windows 7); or on a live system you can call the CsrClientConnectToServer API function.

All USER objects start with one of the common headers, which are pointed to by the _HANDLEENTRY.phead member. The bType tells you what type of object the handle is for, and based on the information previously dumped from win32k!_gahti, you know which objects are thread-owned (they’ll begin with a _THRDESKHEAD) and which are process-owned (they’ll begin with a _PROCDESKHEAD). Objects like TYPE_CLIPBOARD begin with the generic _HEAD. Here are the three possibilities:

If an object in the handle table is thread-owned, you can identify the object’s owning thread using _THRDESKHEAD.pti, which is a pointer to tagTHREADINFO. From there, you can use the tagTHREADINFO.pEThread member which points to the execute thread object (_ETHREAD).

On the other hand, if an object is process-owned, the _HANDLEENTRY.pOwner field is a pointer to the owning tagPROCESSINFO. From there, tagPROCESSINFO.Process identifies the _EPROCESS.

Now, regardless of whether USER objects are thread- or process-owned, you can associate them with the executive _ETHREAD or _EPROCESS objects that everyone is familiar with. Bravo!

Guess what else this information can be useful for? Cross-referencing thread and process objects for rootkit detection ala psxview. You've heard of processes hiding by unlinking from PsActiveProcessHead. You've heard of them mangling their pool tags and non-critical members to hide from scanning techniques. I would be surprised if any rootkits exist, even in a proof-of-concept state that hide using both of those techniques, the 5-6 others that psxview already detects and removes all of the processes handles from the USER handle table.

The UserHandles Plugin

The userhandles plugin locates the shared information structure for each session, walks the handle table, and prints out the contents.

To only show USER objects owned by a particular process use --pid=PID. To filter by object type, use something like --type=TYPE_HOOK. Finally, if you want to include information on handles marked as freed, then use --free.

Although the output of this plugin
is not very verbose, it gives you an overview of the types of objects being
used by a particular thread or process. Furthermore, it can be used as an API
for other plugins to find specific object types and then go into detail about them. In fact this is exactly how the previously described eventhooks plugin works, and several other plugins which will be introduced in future MoVP posts.

Conclusion

What you've been learning over the past few weeks of MoVP posts is that there's entirely new and unexplored areas of kernel memory where malware lurks; and the evidence begs to be found. We enjoy focusing on challenging, innovative, and technical problems. Just because Microsoft doesn't document it, doesn't mean you can't analyze it with Volatility!