So far in the Windows GUI memory space, an area previously unexplored by forensic and malware analysis tools, you have seen sessions, window stations, desktops 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.
'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.
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.
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!
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?
ReplyDeleteOf course its possible (see the "Detecting USB insertions" section above). I suppose you mean in a more automated way?
ReplyDeleteBasically 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
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