Detecting Window Stations and Clipboard Monitoring Malware with Volatility

Wednesday, September 19, 2012

Michael Ligh

Fd7e078e5bfb68a4be33cbfac76f4f70

In the Month of Volatility Plugins 1.1 post, we discussed sessions, which are containers for processes and other objects related to a Windows user's logon session.

Among those other objects are window stations, which act as security boundaries for processes and desktops. If you're not already familiar with these objects, see Sessions, Desktops, and Window Stations (Technet) or Window Stations and Desktops (MSDN).

From a forensic standpoint, by analyzing window stations objects, you can detect applications snooping on clipboard activity along with the frequency of clipboard usage and the available data formats.

Data Structures

The window station structure is tagWINDOWSTATION. A structure from Windows 7 64-bit is shown below.  

>>> dt("tagWINDOWSTATION") 'tagWINDOWSTATION' (152 bytes) 0x0   : dwSessionId                    ['unsigned long'] 0x8   : rpwinstaNext                   ['pointer64', ['tagWINDOWSTATION']] 0x10  : rpdeskList                     ['pointer64', ['tagDESKTOP']] 0x18  : pTerm                          ['pointer64', ['tagTERMINAL']] 0x20  : dwWSF_Flags                    ['unsigned long'] 0x28  : spklList                       ['pointer64', ['tagKL']] 0x30  : ptiClipLock                    ['pointer64', ['tagTHREADINFO']] 0x38  : ptiDrawingClipboard            ['pointer64', ['tagTHREADINFO']] 0x40  : spwndClipOpen                  ['pointer64', ['tagWND']] 0x48  : spwndClipViewer                ['pointer64', ['tagWND']] 0x50  : spwndClipOwner                 ['pointer64', ['tagWND']] 0x58  : pClipBase                      ['pointer', ['array', at 0x10195a848>, ['tagCLIP']]] 0x60  : cNumClipFormats                ['unsigned long'] 0x64  : iClipSerialNumber              ['unsigned long'] 0x68  : iClipSequenceNumber            ['unsigned long'] 0x70  : spwndClipboardListener         ['pointer64', ['tagWND']] 0x78  : pGlobalAtomTable               ['pointer64', ['void']] 0x80  : luidEndSession                 ['_LUID'] 0x88  : luidUser                       ['_LUID'] 0x90  : psidUser                       ['pointer64', ['void']]   

Key Points

  • dwSessionId can be used to link a window station to its owning session (it will match _MM_SESSION_SPACE.SessionId). 
  • rpwinstaNext can be used to enumerate all window stations in the same session as the current one. 
  • rpdeskList is a pointer to the window station’s first desktop.  
  • dwWSF_Flags can tell you if the window station is interactive or not (see the WSF_NOIO flag). 
  • Several of the fields can tell you which thread is viewing the clipboard, which thread owns the clipboard, and which thread (if any) may be listening to clipboard operations (i.e. snooping). 
  • pClipBase is a pointer to an array of tagCLIP structures that describe the available clipboard formats and contain handles to clipboard objects. The array size is taken from cNumClipFormats
  • iClipSequenceNumber increments by 1 for each object copied to the clipboard. By looking at this number, you can tell how frequently copy operations occur. 
  • pGlobalAtomTable points to the window station’s atom table.

The WndScan Plugin

Window stations (and desktops) are securable objects. That means they’re allocated, managed, and freed by the same executive object manager that handles processes, threads, mutants, and registry keys. Thus, they have a _POOL_HEADER and a _OBJECT_HEADER and can easily be located in physical memory by sub-classing Volatility’s built-in scan.PoolScanner class.  Alternately, if PDB symbols are available, you can walk the list of window stations for a given session using win32k!_grpWinStaList.   

Also note the tagWINDOWSTATION structure does not have a name field, yet window stations are referred to by their name (such as WinSta0). That’s because the name field is in the _OBJECT_HEADER.   

In the output below, the first window station found is WinSta0 for session 2. This window station’s atom table is located at 0xe7981648, it contains three desktops (Default, Disconnect, and Winlogon), and rdpclip.exe is current viewing the clipboard, which makes sense since that is the process that handles copy & paste operations over RDP. There are 4 supported clipboard formats (such as ASCII, Unicode, bitmap, etc.) and so far the user has copied 9 items to the clipboard.    

$ python vol.py -f rdp.mem --profile=Win2003SP2x86 wndscan Volatile Systems Volatility Framework 2.1_alpha ************************************************** WindowStation: 0x8581e40, Name: WinSta0, Next: 0x0 SessionId: 2, AtomTable: 0xe7981648, Interactive: True Desktops: Default, Disconnect, Winlogon ptiDrawingClipboard: pid - tid - spwndClipOpen: 0x0, spwndClipViewer: 0xbc6f2ca8 6772 rdpclip.exe cNumClipFormats: 4, iClipSerialNumber: 9 pClipBase: 0xe6fe8ec8, Formats: CF_UNICODETEXT,CF_LOCALE,CF_TEXT,CF_OEMTEXT  [snip]    

The next window station is named __X78B95_89_IW with a single desktop named __A8D9S1_42_ID. This is a standard naming convention used by inetinfo.exe, so you know the suspect system was running IIS at the time.  The last one shown in the example is WinSta0 for session 0. Although it’s interactive, the cNumClipFormats and iClipSerialNumber are both 0, meaning this window station’s clipboard has never been used.   

************************************************** WindowStation: 0x990c760, Name: __X78B95_89_IW, Next: 0x0 SessionId: 0, AtomTable: 0xe26c6a60, Interactive: False Desktops: __A8D9S1_42_ID ptiDrawingClipboard: pid - tid - spwndClipOpen: 0x0, spwndClipViewer: 0x0   cNumClipFormats: 0, iClipSerialNumber: 0 pClipBase: 0x0, Formats:  ************************************************** WindowStation: 0x9a0d148, Name: WinSta0, Next: 0x8a089c48 SessionId: 0, AtomTable: 0xe1b19b10, Interactive: True Desktops: Default, Disconnect, Winlogon ptiDrawingClipboard: pid - tid - spwndClipOpen: 0x0, spwndClipViewer: 0x0   cNumClipFormats: 0, iClipSerialNumber: 0 pClipBase: 0x0, Formats:  [snip]

Clipboard Snooping Malware

Many malware samples snoop on clipboard operations. One method is by hooking SetClipboardData and stealing the data as its placed into the clipboard, but that modifies the system in obvious ways. Another method, which you probably will never see is calling GetClipboardData at a fast-paced regular interval (i.e. in a loop with Sleep(100)). Why is this a bad idea? Because before requesting the clipboard data, you must call OpenClipboard, and only one window can have the clipboard open at a time. If malware opens the clipboard to check for data every 100ms, it could accidentally prevent (by blocking) legit applications from accessing the clipboard.  

The recommended way to access data as soon as its copied to the clipboard is to register as a clipboard viewer (SetClipboardViewer) or format listener (AddClipboardFormatListener). These functions allow applications to receive notifications (via WM_DRAWCLIPBOARD messages) whenever the content of the clipboard changes. They can then safely open the clipboard and query the data. As always, the most interesting part of all this is the laundry list of artifacts left in physical memory as a result of calling these APIs. The following example uses Nirsoft's clipboardic (you can also use InsideClipboard) to demonstrate. These tools use the same APIs that malware uses, and since they're not actually malicious, you can follow along on your own systems.  

To help illustrate the exact changes made from specific behaviors, we'll start with a fresh system just rebooted (i.e. no clipboard activity yet). Here's the wndscan output for the user's WinSta0:  

$ python vol.py -f memory.dmp --profile=Win7SP1x86 wndscan ************************************************** WindowStation: 0x7ea45d00, Name: WinSta0, Next: 0x0 SessionId: 1, AtomTable: 0x93b107f0, Interactive: True Desktops: Default, Disconnect, Winlogon ptiDrawingClipboard: pid - tid - spwndClipOpen: 0x0, spwndClipViewer: 0x0   cNumClipFormats: 0, iClipSerialNumber: 0 pClipBase: 0x0, Formats: 

Notice the clipboard base is NULL, there are no formats, no clipboard owners or viewers, and the serial number is zero. We can use the wintree plugin to grep for the initial windows of the class CLIPBRDWNDCLASS.  

$ python vol.py -f memory.dmp --profile=Win7SP1x86 wintree | grep CLIPBRDWNDCLASS Volatile Systems Volatility Framework 2.2_alpha .#10062  explorer.exe:372 CLIPBRDWNDCLASS .#100f0  explorer.exe:372 CLIPBRDWNDCLASS .#1011e  vmtoolsd.exe:2224 CLIPBRDWNDCLASS .#1014a  SnagIt32.exe:2300 CLIPBRDWNDCLASS

As you can see, explorer, vmtoolsd (VMware Tools), and SnagIt32 (a screen shot application that allows you to copy/paste images) have windows of this class. That all makes perfect sense. Do you see other applications on your system? If so, do they have a functional need to access the clipboard? These are questions you'll ask yourself when trying to determine if there are malicious processes snooping on your clipboard.  

Now, on my test VM, I opened Notepad++ and Nirsoft's clipboardic.exe program. I copied some data from my host OS and pasted it into the running VMware guest. I also copied some data from the Notepad++ release notes onto the clipboard. As you can see, the text was captured by clipboardic.exe as expected:  

Let's take a second look at the physical memory after those actions. Keep in mind, malware would use the exact same APIs and produce similar effects.  

$ python vol.py -f memory.dmp --profile=Win7SP1x86 wndscan ************************************************** WindowStation: 0x7ea45d00, Name: WinSta0, Next: 0x0 SessionId: 1, AtomTable: 0x93b107f0, Interactive: True Desktops: Default, Disconnect, Winlogon ptiDrawingClipboard: pid - tid - spwndClipOpen: 0x0, spwndClipViewer: 0xfea5db80 3616 Clipboardic.ex cNumClipFormats: 4, iClipSerialNumber: 11 pClipBase: 0xfccb2be8, Formats: CF_UNICODETEXT,Unknown choice 8192,CF_TEXT,Unknown choice 197569

What do you see? A new clipboard viewer has been registered by pid 3616 (Clipboardic.exe). There are four clipboard formats, among them are ANSI text and Unicode text (the others are probably OLE data - more on that in a future MoVP post). The serial number has now been increased to 11. Furthermore, there are several new windows of the clipboard class:  

$ python vol.py -f memory.dmp --profile=Win7SP1x86 wintree | grep CLIPBRDWNDCLASS Volatile Systems Volatility Framework 2.2_alpha .#10062  explorer.exe:372 CLIPBRDWNDCLASS .#100f0  explorer.exe:372 CLIPBRDWNDCLASS .#1011e  vmtoolsd.exe:2224 CLIPBRDWNDCLASS .#1014a  SnagIt32.exe:2300 CLIPBRDWNDCLASS .#4002c  vmtoolsd.exe:2224 CLIPBRDWNDCLASS .#10288  notepad++.exe:3140 CLIPBRDWNDCLASS .#1032c  Clipboardic.ex:3616 CLIPBRDWNDCLASS

Each application that's involved in the copy and paste operations is represented here. VMware Tools (vmtoolsd.exe) which was previously running has created a new window (#4002c) to pass the data from the host to the guest. Notepad++ has a window (#10288) to receive the data. Clipboardic.exe has a window (#1032c) to snoop on the data.   

Conclusion

By analyzing window station objects, you can get a better understanding of the GUI landscape at the time of a compromise or malware infection. Further more, you can easily enumerate desktops, locate atom tables, and determine which processes have registered to receive clipboard notifications. With Volatility, now you can detect which applications may be stealing clipboard data in entirely new ways!  

Cross-posted from http://volatility-labs.blogspot.com/2012/09/movp-12-window-stations-and-clipboard.html

Possibly Related Articles:
11414
Operating Systems Breaches
Information Security
malware Forensics Penetration Testing Intrusion Detection Network Security Monitoring Analysis Volatility Clipboard
Post Rating I Like this!
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.