Tuesday, September 18, 2012

MoVP 2.2 Malware In Your Windows

Month of Volatility Plugins

So far in the Windows GUI memory space, an area previously unexplored by forensic and malware analysis tools, you have seen sessions, window stationsdesktops and atoms. Today's MoVP 2.2 post is about windows. Windows are containers for buttons, scroll bars, text/edit areas, and so on. They have titles, coordinates, and visibility properties (like minimized, maximized, transparent or overlapped). They play such a massive role in UI, its no surprise that malware and attackers have found numerous ways to abuse windows and the window messaging architecture. For example, its common to see windows being used for inter-process communication, environmental awareness (i.e. detecting security/monitoring tools), disabling antivirus, defeating debuggers, simulating user interactions (like mouse clicks and keystrokes), and monitoring USB insertions.

Data Structures

The data structure for a window object is tagWND. Due to its large size, only a few select members are shown.

 >>> dt("tagWND")
'tagWND' (296 bytes)
0x0   : head                           ['_THRDESKHEAD']
[snip]
0x30  : ExStyle                        ['unsigned long']
0x34  : style                          ['unsigned long']
[snip]
0x48  : spwndNext                      ['pointer64', ['tagWND']]
0x50  : spwndPrev                      ['pointer64', ['tagWND']]
0x58  : spwndParent                    ['pointer64', ['tagWND']]
0x60  : spwndChild                     ['pointer64', ['tagWND']]
0x68  : spwndOwner                     ['pointer64', ['tagWND']]
0x70  : rcWindow                       ['tagRECT']
0x80  : rcClient                       ['tagRECT']
0x90  : lpfnWndProc                    ['pointer64', ['void']]
0x98  : pcls                           ['pointer64', ['tagCLS']]
[snip]
0xd8  : strName                        ['_LARGE_UNICODE_STRING']
[snip]
0x118 : spwndClipboardListenerNext     ['pointer64', ['tagWND']]
0x120 : ExStyle2                       ['unsigned long']
0x120 : bChildNoActivate               ['BitField', {'end_bit': 12, 'start_bit': 11, 'native_type': 'long'}]
0x120 : bClipboardListener             ['BitField', {'end_bit': 1, 'start_bit': 0, 'native_type': 'long'}]
[snip]

Key Points 
  • ExStyle is a combination of extended style flags (the dwExStyle parameter to CreateWindowEx). For example, WS_EX_ACCEPTFILES if the window accepts drag-drop files or WS_EX_TRANSPARENT to achieve transparency. 
  • style is a combination of style flags such as WS_VISIBLE. This tells you if the window was initially visible.  
  • The various spwnd fields such as spwndParent and spwndChild can be used to reconstruct the Z-order relationship of windows on a desktop. 
  • rcWindow and rcClient are tagRECT structures which have a left, right, bottom and top value. Together, the values indicate the position of the window within the desktop. 
  • lpfnWndProc is the window procedure function. Typically, all windows of a given class have the same window procedure, but that can be changed with window sub-classing (for example to customize the behavior of a button or form).
  • pcls is a pointer to the tagCLS which identifies the window’s class. 
  • strName is the window’s name/title (the lpWindowName argument to CreateWindowEx). 
The Windows Plugin 


The plugin enumerates windows in all desktops – even desktops in non-interactive window stations. It starts at tagDESKTOP.pDeskInfo.spwnd (a tagWND for the foreground window) and walks the Z-order. There are a number of interesting things you can see with this plugin. For example, with a basic process listing, you could see iexplore.exe and determine a browser was open, but with the windows plugin, you could drill down to any windows of the IEFrame class and see the title of the page being viewed:

$ python vol.py -f win7x64.dd --profile=Win7SP1x64 windows
Volatile Systems Volatility Framework 2.1_alpha
**************************************************
Window context: 1\WinSta0\Default

Window Handle: #40170 at 0xfffff900c06258a0, Name: Download: Microsoft Windows SDK 7.1 - Microsoft Download Center - Confirmation - Windows Internet Explorer
ClassAtom: 0xc193, Class: IEFrame
SuperClassAtom: 0xc193, SuperClass: IEFrame
pti: 0xfffff900c24c4c30, Tid: 680 at 0xfffffa8002007060
ppi: 0xfffff900c28c2320, Process: iexplore.exe, Pid: 2328
Visible: Yes
Left: -32000, Top: -32000, Bottom: -32000, Right: -32000
Style Flags: WS_MINIMIZE,WS_MINIMIZEBOX,WS_TABSTOP,WS_DLGFRAME,WS_BORDER,WS_THICKFRAME,WS_CAPTION,WS_CLIPCHILDREN,WS_SYSMENU,WS_MAXIMIZEBOX,WS_GROUP,WS_OVERLAPPED,WS_VISIBLE,WS_CLIPSIBLINGS
ExStyle Flags: WS_EX_LTRREADING,WS_EX_RIGHTSCROLLBAR,WS_EX_WINDOWEDGE,WS_EX_LEFT
Window procedure: 0x714f6f7a

To some extent, you can also view commands typed into cmd.exe prompts, because the title of the window changes. This is by no means equivalent to pulling command histories like cmdscan and consoles, but you never know when you'll get lucky - just search for ConsoleWindowClass during your investigations. 

Window Handle: #50294 at 0xfffff900c06219c0, Name: Administrator: Command Prompt - livekd  -w
ClassAtom: 0xc1d8, Class: ConsoleWindowClass
SuperClassAtom: 0xc1d8, SuperClass: ConsoleWindowClass
pti: 0xfffff900c28c09a0, Tid: 3020 at 0xfffffa8001f11b60
ppi: 0xfffff900c1c43010, Process: conhost.exe, Pid: 2476
Visible: Yes
[snip]

An old delivery mechanism for malware involved bundling an executable inside compressed windows help files (.chm). The standard chm viewer is hh.exe that you may see in a process list, but as shown below, you can also extract the name of the page being viewed. In this case, it’s just the help for Windbg, but if it was something like “Congrats you won 10 million dollars” then it might give you an idea of how a machine initially became infected (a gullible user / social engineering victim).


Window Handle: #e01ea at 0xfffff900c06428b0, Name: Debugging Tools for Windows
ClassAtom: 0xc1c2, Class: HH Parent
SuperClassAtom: 0xc1c2, SuperClass: HH Parent
pti: 0xfffff900c1f863a0, Tid: 2840 at 0xfffffa8003dfbb60
ppi: 0xfffff900c297e2a0, Process: hh.exe, Pid: 1952
Visible: Yes
[snip]

As shown in the following output, windows of the class TrayClockWClass will typically display the current local time of the computer.  Likewise, windows of the class Desktop User Picture will reveal the current logged on user’s name.

Window Handle: #3004e at 0xfffff900c0606d60, Name: 12:34 PM

ClassAtom: 0xc0e8, Class: TrayClockWClass
SuperClassAtom: 0xc0e8, SuperClass: TrayClockWClass
[snip]

Window Handle: #70268 at 0xfffff900c06352d0, Name: Sam
ClassAtom: 0xc0d8, Class: Desktop User Picture
SuperClassAtom: 0xc0d8, SuperClass: Desktop User Picture
[snip]


The WinTree Plugin 


The wintree plugin is less verbose than the windows plugin. It exists to show you the parent/child relationship between windows in the desktop. Here is a preview of the hh.exe window tree – you can see that all windows are visible, starting with the HH Parent, then HH Child, and including various Buttons, ComboBoxes, Edits, Toolbars, and an embedded Shell DocObject View with Internet Explorer_Server (this is why .chm files used to be so dangerous – their content is rendered with IE).

$ python vol.py -f win7x64.dd --profile=Win7SP1x64 wintree
[snip]
.Debugging Tools for Windows (visible) hh.exe:1952 HH Parent
..#70422 (visible) hh.exe:1952 HH Child
...#90452 (visible) hh.exe:1952 SysTabControl32
....#a0202 (visible) hh.exe:1952 -
.....Found: 62 (visible) hh.exe:1952 Static
.....Select &topic: (visible) hh.exe:1952 Static
.....Type in the &word(s) to search for: (visible) hh.exe:1952 Static
.....Sea&rch titles only (visible) hh.exe:1952 Button
.....&Match similar words (visible) hh.exe:1952 Button
.....Search previous res&ults (visible) hh.exe:1952 Button
.....List1 (visible) hh.exe:1952 SysListView32
......#50164 (visible) hh.exe:1952 SysHeader32
.....&Display (visible) hh.exe:1952 Button
.....&List Topics (visible) hh.exe:1952 Button
.....#70424 (visible) hh.exe:1952 Button
.....#702cc (visible) hh.exe:1952 ComboBox
......#f038e (visible) hh.exe:1952 Edit
..#702ba (visible) hh.exe:1952 HH SizeBar
..#70420 (visible) hh.exe:1952 HH Child
...#a0478 (visible) hh.exe:1952 Shell Embedding
....#36029e (visible) hh.exe:1952 Shell DocObject View
.....#9013e (visible) hh.exe:1952 Internet Explorer_Server
..#18029a (visible) hh.exe:1952 ToolbarWindow32

Malware Abusing Windows

Most of the situations we'll describe in the rest of this post can fit into one of two categories:

  • Malware that leverages existing windows on the system, for example to detect a running security application, insert keystrokes or mouse movements into a browser's message queue, or carry out some attack against the window operations (think Shatter Attack)
  • Malware that creates its own windows for inter-process communication, monitoring USB insertions, etc.
Window name detection (anti-RCE). Many malware families scan for window names created by antivirus, monitoring, and other security applications for use as an anti-RCE tactic. For example, they may call FindWindow or EnumWindows looking for “Process Monitor – Sysinternals: www.sysinternals.com” and then use GetWindowThreadProcessId to obtain the PID of procexp.exe from the window handle…then attempt to TerminateProcess. Or they may query for windows related to Wireshark and simply refuse to execute if any exist. Be aware of this if you're running samples on a VM or sandbox with familiar tools running at the same time. Also note that the malware thread must be running in the same desktop as the window its trying to detect. If you see malware enumerating desktops (EnumDesktops) and using SetThreadDesktop or SwitchDesktop, its trying to find windows system-wide and not just in the active desktop. 

Killing KAV with rogue window messages. Older versions of Kaspersky Antivirus were vulnerable to a shatter attack. In other words, lesser-privileged threads could send the antivirus engine’s “__AVP.Root” window a specially formed window message and cause the engine to stop scanning/protecting the system - this effectively disabled antivirus. Tigger delivered the message with PostMessageA as shown below. The special values are WPARAM 0x466 and LPARAM 0x10001. 


Dismissing alerts/prompts before users see. After disabling Windows File Protection and overwriting kernel32.dll, wininet.dll, and other system DLLs, Bankpatch calls ExitWindowsEx to reboot the machine. This is so the malicious DLLs are loaded into all target processes as soon as possible. Then the malware uses the window messaging architecture to dismiss any prompts that the operating system generates due to the reboot request (such as “You have unsaved work, do you really want to reboot?”). As shown below, the malware does this by calling EnumWindows in a loop, until the system shuts down – passing control to the EnumFunc callback.



That's only half the story. For the rest, take a look at the next image. It shows that EnumFunc uses GetWindowTextA to scan for text displayed inside the prompt window. If it begins with the string “Windows” then it uses GetDlgItem, likely to select the “OK” button and then posts a BM_CLICK message to the window thread’s message queue. This simulates a user clicking “OK” – the system has no idea it all happened automatically. In the end, Bankpatch was able to reboot the system without any user interaction required. 


Simulating keystrokes and mouse movements. Some malware may not only want to observe/record user actions, but it may want to perform actions on its own. For example, to log in, open a browser, and visit a specific web page (Koobface did this, but using IE's COM interface rather than synthesizing UI interactions). Blazgel is an example of malware with the ability to open the Winlogon desktop and simulate a user pressing CTRL+ALT+DEL to access a login prompt (in case the screen saver with automatic lock turned on).  To do this, you can broadcast a WM_HOTKEY message with number 0x2E0003 (MOD_ALT | MOD_CTRL | MOD_DEL) as shown below:


The next screen shot shows how the malware tunnels mouse movements over the command and control channel. One packet sends a string “EVENTMOUSE” if the attackers want to simulate a mouse movement. The next packet, read by Recv_Data, specifies the X and Y coordinates, which are then applied with SetCursorPos and triggered by mouse_event.  


Simple anti-debugging with WndProc callbacks. Most people who have never debugged a message loop will place breakpoints in the wrong place. For example, if you step over a call to CreateWindowEx without first placing a breakpoint on the window procedure passed to RegisterClassEx, then functions could execute unexpectedly. Consider the example below. If you compile it and start debugging the wmain function, most likely you'll see some GUI related APIs and think "oh that's boring" and step right over CreateWindowEx. Before that returns, however, you'll be presented with a message box that says "Gotcha." Why? WindowProcedure is never explicitly called in the code, but the API calls it internally. 

LRESULT WindowProcedure(HWND hwnd, UINT i, 
                        WPARAM wparam, LPARAM lparam)
{
    MessageBox(NULL, L"Gotcha", L"Gotcha", 0);
    return 0;
}

void wmain(int argc, WCHAR *argv[])
{
    WNDCLASSEX wndcls;

    ZeroMemory(&wndcls, sizeof(WNDCLASSEX));
    wndcls.cbSize = sizeof(WNDCLASSEX);
    wndcls.lpszClassName = L"Testing";
    wndcls.lpfnWndProc = (WNDPROC) WindowProcedure;

    ATOM ClassAtom = RegisterClassEx(&wndcls);
    HWND hWnd = CreateWindowEx(0, (LPCWSTR)ClassAtom, 
                       L"WindowName", 0, 0, 0, 0, 
                               0, 0, 0, 0, NULL);
    
    //The WindowProcedure will execute before this
}


Detecting USB insertions. Both Conficker and Stuxnet spread by infecting USB sticks with autorun files. Conficker generated a random string for use as the window class name, then created a window with CreateWindowExA and configured it to monitor for WM_DEVICECHANGE notifications. In this manner, the malware was able to detect immediately when new USB devices were inserted, and it could proceed with infection. The disassembly below shows the code from Conficker's binary that sets up the new window:



Likewise, Stuxnet registers a class named AFX64c313 (this is hard-coded unlike Conficker's) and creates a window of that class with the exact same name. As described in Stuxnet’s Footprint In Memory with Volatility 2.0, here is the view of this artifact from atomscan - the plugin discussed in yesterday's MoVP 2.1 post.  

$ python vol.py –f stuxnet.vmem atomscan
AtomOfs(V)       Atom Refs   Pinned Name
---------- ---------- ------ ------ ----

[snip]
0xe1f05ad0     0xc084     19      0 MSWHEEL_ROLLMSG
0xe1f3dcd0     0xc0d1      2      0 C:\WINDOWS\system32\SHDOCVW.dll
0xe1fee430     0xc0e1      1      0 image/jpeg
0xe20514d8     0xc118      2      0 AFX64c313
0xe20e0de0     0xc090      4      0 OLE_MESSAHE
0xe20e23d8     0xc115      2      0 ShImgVw:CPreviewWnd
0xe20f0208     0xc100      2      0 SysFader
[snip]

Here is a view of the CreateWindowEx artifact. Note the window is owned by services.exe, because that’s one of stuxnet’s code injection targets. The window's visibility is set to False and the window procedure is located at 0x13fe695 in the memory of services.exe. 

$ python vol.py –f stuxnet.vmem windows

[snip]
Window Handle: #e00e8 at 0xbc940720, Name: AFX64c313
ClassAtom: 0xc118, Class: AFX64c313
SuperClassAtom: 0xc118, SuperClass: AFX64c313
pti: 0xe1e81380, Tid: 1420 at 0x82126bf0
ppi: 0xe163f008, Process: services.exe, Pid: 668
Visible: No
Left: 92, Top: 146, Bottom: 923, Right: 695
Style Flags: WS_MINIMIZEBOX,WS_TABSTOP,WS_DLGFRAME,WS_BORDER,WS_THICKFRAME,WS_CAPTION,WS_SYSMENU,WS_MAXIMIZEBOX,WS_GROUP,WS_OVERLAPPED,WS_CLIPSIBLINGS
ExStyle Flags: WS_EX_LTRREADING,WS_EX_RIGHTSCROLLBAR,WS_EX_WINDOWEDGE,WS_EX_LEFT
Window procedure: 0x13fe695
[snip]

Taking the analysis one step further, you can disassemble the window procedure and see exactly which window messages it handles. Note instead of actually being interactive with volshell, you can pass commands via standard input.


$ echo "cc(pid = 668); dis(0x13fe695)" | ./vol.py -f stuxnet.vmem volshell

0x13fe695 55               PUSH EBP
0x13fe696 8bec             MOV EBP, ESP
0x13fe698 817d0c19020000   CMP DWORD [EBP+0xc], 0x219; WM_DEVICE_CHANGE
0x13fe69f 7514             JNZ 0x13fe6b5
0x13fe6a1 ff7514           PUSH DWORD [EBP+0x14]
0x13fe6a4 ff7510           PUSH DWORD [EBP+0x10]
0x13fe6a7 e810000000       CALL 0x13fe6bc
0x13fe6ac 59               POP ECX
0x13fe6ad 33c0             XOR EAX, EAX
0x13fe6af 59               POP ECX
0x13fe6b0 40               INC EAX
0x13fe6b1 5d               POP EBP
0x13fe6b2 c21000           RET 0x10
0x13fe6b5 5d               POP EBP
0x13fe6b6 ff25c4534401     JMP DWORD [0x14453c4]
0x13fe6bc 55               PUSH EBP
0x13fe6bd 8bec             MOV EBP, ESP
0x13fe6bf 83e4f8           AND ESP, -0x8
0x13fe6c2 64a100000000     MOV EAX, [FS:0x0]
0x13fe6c8 6aff              PUSH -0x1
0x13fe6ca 68893d4401        PUSH DWORD 0x1443d89
0x13fe6cf 50                PUSH EAX
0x13fe6d0 64892500000000    MOV [FS:0x0], ESP
0x13fe6d7 83ec6c            SUB ESP, 0x6c
0x13fe6da 817d0800800000    CMP DWORD [EBP+0x8], 0x8000; DBT_DEVICEARRIVAL
0x13fe6e1 53                PUSH EBX
0x13fe6e2 56                PUSH ESI
0x13fe6e3 0f8542010000      JNZ 0x13fe82b

Conclusion

This post discussed the importance of windows in not only the UI subsystem but in malware analysis and digital forensics. There's more to this that meets the eye (no puns intended), we didn't even touch on intercepting key strokes and mouse movements, malicious window subclassing, and detecting hidden or phony processes by cross-referencing window classes. As you keep these things in mind, remember that Volatility opens the door to possibilities that are not only unavailable in other memory analysis frameworks, but most people have never thought about them. That's what Volatility is all about!

3 comments:

  1. A very informative read. Do you know if there is an easy way to scan a memory image for processes that look for WM_DEVICEHANGE notifications? this would hopefully catch malware waiting for USB insertions. If its not possible, what the best way to write plugin for volatility to do it?

    ReplyDelete
  2. Of course its possible (see the "Detecting USB insertions" section above). I suppose you mean in a more automated way?

    Basically you'd enumerate all windows in all desktops in all window stations using the same code windows and wintree use (and can be seen here: http://code.google.com/p/volatility/source/browse/trunk/volatility/plugins/gui/windows.py). For each window, disassemble its lpfnWndProc with the built-in distorm3 python bindings and look for instructions that compare the function's 2nd argument (typically EBP+12) with 0x219 which is WM_DEVICECHANGE.

    The caveat is you're disassembling and not emulating so tricks like MOV EDX, 0x218; INC EDX, followed by a CMP DWORD [EBP+12], EDX would still check for WM_DEVICECHANGE but it would require you to handle extra cases (and that could get annoying real fast bc there's so many possibilities). However, most likely malware won't do that unless they're specifically trying to evade your tool.

    Here's an example I threw up on pastebin: http://pastebin.com/9q3KdTxB

    ReplyDelete
    Replies
    1. That's exactly what I was thinking - thanks for your reply and the code! I had some malware that was waiting for 0x219, and this is a great automated way to quickly check for this type of malware. Brilliant stuff!

      Delete