Analyzing Desktops, Heaps, and Ransomware with Volatility

This post introduces a new plugin for Volatility named deskscan - it enumerates desktops, desktop heap allocations, and associated threads. In the GUI landscape, a desktop is essentially a container for application windows and user interface objects.

Malware utilizes desktops in various ways, from launching applications in alternate desktops (i.e. so the current logged-on user doesn't see) to ransomware that locks users out of their own desktop.

We'll see some examples of both in this post. Before we begin, here is brief summary of the ways you might use the deskscan plugin in your forensic or malware investigations:

Find rogue desktops used to hide applications from logged-on users

Detect desktops created by ransomware

Link threads to their desktops

Analyze the desktop heap for memory corruptions

Profile dekstop heap allocations to locate USER objects

Data Structures

The tagDESKTOP structure represents desktops. Here is an example from Windows 7 x64:

Default is the default desktop for applications in the interactive window station. It is what you see 99.9% of the time you’re logged into a Windows system. Thus it makes sense that explorer.exe runs in this desktop (also note there are 6 different Explorer threads all running in this same desktop).

The number of windows in the Default desktop is also much higher than the others (238 compared to 25 in Disconnect and 6 in Winlogon). In order to allow the creation of so many more windows (and other objects), it makes sense that the Default desktop’s heap size is also much higher (0x300000 compared to 0x10000 and 0x20000).

The only threads in the Winlogon desktop actually belong to winlogon.exe.

The only desktop with global hooks is Default (fsHooks: 2128). This value can be parsed to report on installed windows message hooks.

If you pass the –v/--verbose option to the deskscan plugin, it will output details on the desktop’s heap allocations. As described in Windows Hook ofDeath: Kernel Attacks through Usermode Callbacks by Tarjei Mandt, the win32k!ghati symbol is an array of structures, one for each USER object type, telling you if the objects are allocated from the desktop heap, shared heap, or session pool.

Windows (tagWND) and hooks (tagHOOK) are two examples of objects you can find on the desktop heap. Thus, if you know the size of a tagWND (0x128 on Windows 7 x64) and the size of a heap header for that platform, you can walk the desktop heap allocations and narrow down the possible addresses of window structures.

$ python vol.py -f win7x64.dd --profile=Win7SP1x64 volshellVolatile Systems Volatility Framework 2.1_alphaCurrent context: process System, pid=4, ppid=0 DTB=0x187000Welcome to volshell! Current memory image is:file:///Users/Michael/Desktop/win7x64.ddTo get help, type 'hh()'# First switch into the context of a process in Session 1. >>> cc(pid = 880)Current context: process explorer.exe, pid=880, ppid=736 DTB=0x6c3e000# Acquire a process address space, which allows us to # instantiate objects and dereference pointers using # the right DTB for the _MM_SESSION_SPACE >>> session_space = self.eproc.get_process_address_space()# Determine the size of a heap entry header >>> header_size = session_space.profile.get_obj_size("_HEAP_ENTRY")# Determine the size of a tagWND structure for this platform # aligned to the heap granularity >>> import volatility.plugins.common as common>>> wnd_size = common.pool_align(session_space, "tagWND", header_size)# Create the heap object for WinSta0\Default >>> desktop_heap = obj.Object("_HEAP", \ offset = 0xfffff900c0600000, \ vm = session_space)# Walk the heap looking for appropriately sized allocations >>> for seg in desktop_heap.segments():... for entry in seg.heap_entries():... if (entry.Size - 1) * header_size == wnd_size:... print "? tagWND at", hex(entry.obj_offset + header_size)... ? tagWND at 0xfffff900c0600d90L? tagWND at 0xfffff900c06017a0L? tagWND at 0xfffff900c0601e10L? tagWND at 0xfffff900c0601f90L? tagWND at 0xfffff900c0602360L? tagWND at 0xfffff900c0602f80L[snip]
Of course, its possible to see false positives with this method, since all we’re matching on is the size of an allocation, especially if two or more objects were the same size. In fact, this is just a proof-of-concept explaining how the desktop heap can be leveraged if it became necessary. For example, later we’ll describe how the userhandles plugin can locate all USER objects, including tagWND, regardless of whether they’re allocated from the desktop heap, shared heap, or session pool. However, if the USER handle table is not accessible for some reason, at least we could use the heap allocations as a backup.

Tigger Malware

Tigger’s backdoor component accepts commands over the network. If the attacker wants to run applications on the victim machine, the malware creates a hidden desktop to run them in. You may notice that if you try to CreateProcess(“ipconfig.exe”, …) even if the SW_HIDE flag is set, a console window may flash instantaneously and alert the user that something suspicious is running in the background. Additionally, if an attacker opens a non-visible Internet Explorer instance (for example with COM APIs) in the logged on user’s Default desktop, the application’s threads (and thus its window messages) are subject to hooking and monitoring by any other tools in the desktop.

The code below is reverse-engineered from the DLL that Tigger injects into explorer.exe. It uses all the same flags, APIs, and variables that the real malware used. Here’s how it works:

Create a new desktop named system_temp_ if it doesn’t already exist

Generate a temporary file name that will be used to capture the redirected output of console commands

Set STARTUPINFO.lpDesktop to WinSta0\system_temp_

Set dwFlags to indicate the STARTUPINFO structure also has preferences for window visibility and standard output and standard error handles for the process to be created

Create the new process (full path to the process szCmd is passed into the function as an argument – originally from an attacker over the network)

Wait for the process to complete

Read the process’s output (if any) from the specified output file and return it in a buffer

At the end of the day, Tigger can covertly execute console and GUI applications without the user noticing and without being detected by security products that only monitor windows and window messages broadcasted in the user’s Default desktop. Of course, some of the more robust antivirus suites now monitor all desktops, but many of them still do not.

Unfortunately, since the function does call CloseDesktop at the end, this can cause the tagDESKTOP object in memory to be freed (unless other threads have references to it). That’s why Volatility leverages object scanning through physical memory to try and detect traces of past activity.

ACCDFISA Ransomware

The ACCDFISA malware (Anti Cyber Crime Department of Federal Internet Security Agency), described on the Emsisoft blog is a ransomware that creates a new desktop to display the ransom notice; and effectively locks users out of the system until they enter a special code. For example, one of the variants will display the message shown below after an infected system is booted:

With no obvious way to get back to the real desktop, users are forced to comply with the attacker’s demands, or figure out some other way around it. As shown in the next screenshot, to create this screen-lock effect, the malware uses CreateDesktopA to create a new desktop named My Desktop 2 and then switches to it with SwitchDesktop.

The artifacts this malware leaves in physical memory should not be surprising – a suspiciously named desktop with a single process (besides the typical csrss.exe) associated with the desktop. In the output below, notice the desktop is WinSta0\My Desktop 2 and the only thread attached to the desktop besides those from csrss.exe is thread ID 308 from svchost.exe. As you can imagine, a single thread running alone in a desktop is not typical.

Let’s view a tree of the windows in the suspicious desktop. This plugin will be introduced in a future post. So far we know svchost.exe is most likely the malware process, but we’ll need a bit more evidence to explicitly link it with the ransomware message.

As you can see, all of the windows for the ransom message are owned by svchost.exe with process ID 300. Now you can start your initial investigation based on this specific process. For example, using dlllist shows it’s not a real svchost.exe, rather its hosted out of the C:\wnhsmlud directory:

Using Volatility's deskscan command, you can analyze memory dumps in ways never seen before. Even better, this is just one of the new plugins in the win32k suite that will be released in Volatility 2.2.

The views expressed in this post are the opinions of the Infosec Island member that posted this content. Infosec Island is not responsible for the content or messaging of this post.

Unauthorized reproduction of this article (in part or in whole) is prohibited without the express written permission of Infosec Island and the Infosec Island member that posted this content--this includes using our RSS feed for any purpose other than personal use.