Home | Resources | Newsletters | VICE | VI20051005

Vice Newsletter - October 6, 2005

Welcome on behalf of the eEye Research team to another issue of VICE, a free technical newsletter featuring content from the team representing the foundation of eEye as a company and culture.

With this fourth issue, we offer another technical article from Derek Soeder. This time Derek will take us through a reverse engineering case study. This article walks through the reverse engineering of the Windows System Hotkeys as an example of how this sort of thing is done. This will be the first of other reverse engineering articles from Derek that should be very educational.

As always, we have reviewed the questions from the pool of responses and our research team has provided expert comments and answers. Email your questions, comments, and/or criticisms to: vice@eeye.com.

In our Etcetera column this month we will review the 2005 Blackhat Briefings in Las Vegas and discuss some of the more interesting talks.

Enjoy!
Christopher Imes, Editor

In This Issue

1.Vulnerability Exposed!
 • Reverse Engineering Case Study #1: Windows System Hotkeys
 
2.Ask Research
 • I saw the BootRoot presentation at the 2005 Blackhat Briefings. Can I download the associated files?
 • I saw your upcoming vulnerabilities page. At what point does a vulnerability become overdue?
 
3.Etcetera
 • Blackhat Briefings 2005 Roundup
 • Vulnerability Expert Forum: October Patch Tuesday



Vulnerability Exposed!

Reverse Engineering Case Study #1: Windows System Hotkeys

There is probably no person in the world that knows every aspect of Microsoft Windows in specific detail, and even Google's tremendous body of knowledge is often ignorant of Windows minutiae. Fortunately, this type of information is available on-demand to anyone with a debugger, a disassembler, an Internet connection, and enough patience to sleuth it out.

Recently I was trying to figure out how the "special" hotkeys get processed in Windows, when somewhere along the way I thought it might be interesting to write the experience down as a sort of reverse engineering "case study", and at the same time document a tiny bit more of the undocumented. For better or worse, this article is the result, case study number one in what may or may not become a series. Knowledge of x86 assembly, IDA, and SoftICE is recommended, but we refer to them only casually and instead focus on the methodologies used and "experiments" devised. The reader will benefit greatly from having moderate Windows programming experience, and from having disassemblies of the referenced modules available with symbols applied.

Before We Begin
When we started this project, all we had in the way of preparations were IDA (http://www.datarescue.com/idabase/) and SoftICE (http://www.compuware.com/products/driverstudio/softice.htm) installed. The reader can benefit from the ex post facto nature of this walkthrough by already having his environment tailored to what we "precognitively" know will be useful, namely the following:All of these files reside in "%SystemRoot%\system32", and opening them in IDA is self-explanatory, although a non-administrative user will want to copy these modules to a directory to which he has write access first.

IDA will perform an auto-analysis and produce a disassembly of each automatically upon opening; newer versions will even ask if the user would like to download and apply symbols (function and variable names and type descriptions, in the form of a .pdb or .dbg file) from Microsoft as part of the process. Alternatively, the SoftICE installation also includes a tool called "Symbol Retriever" that can download the symbols for arbitrary files from Microsoft. If neither option is viable, or if both fail to work, a last resort is always setting up a test system with a base Windows installation and the latest Service Pack - no hotfixes - and downloading the appropriate symbols package from the Microsoft symbols site (http://www.microsoft.com/whdc/devtools/debugging/symbolpkg.mspx). To load symbol files, simply select File -> Load File -> PDB file or DBG file in IDA, after copying the relevant symbol files to the same directory from which the executable module was opened.

What are the Windows System Hotkeys?
There are certain moments in Windows - such as when Explorer dies - where it can be observed that a system process must be handling some, but not all, special key sequences. The easiest way to compile this list is to actually terminate Explorer.exe and then try out hotkeys; we came up with the following set:Hotkeys like Control + Escape and Windows + R function only when Explorer is running, so chances are very good that it registers them (probably using USER32.DLL!RegisterHotKey, the Windows API designed to provide this functionality) and therefore we're not interested in those. What we want to know is how "non-application" hotkeys are handled closer to the operating system.

Probably the easiest way to begin this project is by spending some time in the debugger. At least a couple of these hotkeys boil down to some simple and easily isolated functionality, perfect opportunities to set breakpoints and backtrack. For Ctrl + Shift + Esc (open Task Manager) and Win + U (open Utility Manager), we can expect a process to be created; Ctrl + Alt + Del will switch to an alternate desktop; Alt + Tab will create the task switching window; and PrtScrn will grab a screenshot and store it in the clipboard. Flagging down process creation sounds easiest, so we'll start there.

Control + Shift + Escape, Windows + U, and Control + Alt + Delete
Going into SoftICE to set some breakpoints, it becomes apparent that we're not even sure what process is handling these hotkeys yet. As we're assuming that they are in the care of some system process, intuition suggests that the most likely candidates are CSRSS, LSASS, SERVICES, and WINLOGON. Experimentation could tell us which guess if any is correct, but because we're dealing with new processes in this specific case, we can just consult the Parent PID field from our favorite process viewer and find out directly. Pressing Ctrl + Shift + Esc gives us a Taskman.exe process with WINLOGON listed as the parent; Win + U presents a Utilman.exe spawned by SERVICES.

Since SERVICES.EXE hosts the Service Control Manager (an RPC server) in addition to a number of system services, it is possible that it's actually creating Utilman.exe on behalf of another process, or perhaps there is a hotkey-servicing service contained therein that starts Utilman in an alternate way. A quick registry search for "utilman.exe" casts doubt on the second hypothesis, revealing that the program is the UtilMan / "Utility Manager" service, registered under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\UtilMan.

At this point, the leading postulation is that we'll see a CreateProcess call to start both Taskmgr (from WINLOGON) and Utilman (from SERVICES), although the process that handles Win + U will probably call StartService to spawn Utilman by proxy. Now we can set some breakpoints.

Because SoftICE won't let us set multiple breakpoints at the same location in different processes, we set them at each function's entry point in WINLOGON (addr winlogon; bpx KERNEL32!CreateProcessA; bpx KERNEL32!CreateProcessW) and at the second instruction of each in SERVICES (addr services; bpx KERNEL32!CreateProcessA+1; bpx KERNEL32!CreateProcessW+1 for Windows 2000). Although CreateProcessW is reached in SERVICES, with a call stack indicating a SERVICES.EXE procedure invoked via RPCRT4.DLL like we expected, neither WINLOGON breakpoint fires. Why?

Something must have gone wrong, and although strange theories about PID spoofing or SoftICE malfunctioning should not necessarily be dismissed out of hand, the approach that's both easiest and most likely to succeed is our "secret weapon" of breakpointing the kernel process creation routine: bpx NTOSKRNL!NtCreateProcess. (Without symbols, "? (&NTDLL!ZwCreateProcess)->1; NTCALL" can be used to find the function instead.)

In fact, it does succeed, and shows us a call stack like the following, from within the WINLOGON process:

NTDLL.DLL!ZwCreateProcess
KERNEL32.DLL!CreateProcessInternalW
ADVAPI32.DLL!CreateProcessAsUserW
MSGINA.DLL!WlxStartApplication
WINLOGON.EXE!StartApplication
WINLOGON.EXE!SASWndProc
USER32.DLL!UserCallWndProc
USER32.DLL!DispatchMessageWorker
USER32.DLL!DispatchMessageW

Apparently we forgot to cover CreateProcessInternalW. Of course this call stack makes perfect sense in retrospect, because Taskmgr running as SYSTEM (which it would be if not started via CreateProcessAsUser) would have been a grievous security misstep, but of course it executes as the logged-in user instead.

On a hunch, we set "bpx ADVAPI32!StartServiceA; bpx ADVAPI32!StartServiceW" in WINLOGON and see if they catch the operations assumed to be associated with Win + U. As a matter of fact, they do, as shown in the following call stack:

ADVAPI32.DLL!StartServiceW
WINLOGON.EXE!UtilManStartThread
KERNEL32.DLL!BaseThreadStart

Although not a very impressive call stack, this does tell us that a separate thread is being tasked with starting Utility Manager (because of the function's name and the abrupt end of the call stack at BaseThreadStart). A CreateThread breakpoint or a bit of IDA work, however, provides a better view of where this execution path originated:

KERNEL32.DLL!CreateThread
WINLOGON.EXE!SasAccessNotify
WINLOGON.EXE!SASWndProc
USER32.DLL!UserCallWndProc
USER32.DLL!DispatchMessageWorker
USER32.DLL!DispatchMessageW

Apparently WINLOGON - more precisely SASWndProc - is where these hotkeys' behaviors are determined, so we should definitely take a look at the disassembly to get a more thorough understanding of how the function works.

The first thing we see in SASWndProc is a switch statement on the function's second argument, exactly what we would expect to see in any WindowProc-type function. Curiosity at this point inspires us to see what window messages are handled by this switch - and as it turns out, the information will come in handy later. Apparently there are cases for WM_CREATE (0x0001), WM_DESTROY (0x0002), an undocumented message type (0x004C), WM_TIMER (0x0113), WM_HOTKEY (0x0312), and a private message type (0x0659). (See "winuser.h", included with Visual Studio or the Platform SDK, for these constants and countless others.)

WM_HOTKEY sounds appropriate for further investigation, although it corroborates the more banal scenario where a "system" hotkey is in fact no different from any other hotkey. Continuing into the disassembly, we see that if wParam ('idHotKey') is 4, then WINLOGON will call StartApplication to run Taskmgr.exe on the "Default" desktop, as a cursory glance at the page's string references tells us. For any other hotkey ID, it will call CADNotify, which of course stands for Control + Alt + Delete.

Ctrl + Alt + Del, at least, is starting to look less special than it once seemed; perhaps it is registered like any other hotkey. Although we could cross-reference USER32.DLL!RegisterHotKey (which may be named __declspec(dllimport) RegisterHotKey by IDA if symbols are loaded), it might be more interesting to backtrack from SASWndProc and make more sense of the "Secure Attention Sequence" window in general. (The information might be useful later).

Following the cross-reference backwards from SASWndProc takes us to SASInit, which registers a classes called "SAS window class", creates a window titled "SAS window" – nothing interesting yet – and then calls USER32!SetLogonNotifyWindow. Unfortunately, Googling on this API and its alias NtUserSetLogonNotifyWindow turns up nothing, and the function code dispatches straight into WIN32K.SYS via a system call. Could it register these hotkeys specially from within the kernel? Before we leave WINLOGON, there is one other avenue to explore, in between SASInit and SASWndProc's WM_HOTKEY code.

We saw that SASWndProc handles WM_CREATE, and the disassembly shows us that it does so by calling SASCreate. We quickly see what we were expecting all along, two calls to RegisterHotKey, which can be represented as follows:

RegisterHotKey(hwnd, /*id*/ 0, MOD_CONTROL|MOD_ALT|0x8000, VK_DELETE)
RegisterHotKey(hwnd, /*id*/ 4, MOD_CONTROL|MOD_SHIFT, VK_ESCAPE)

The first call passes 'fsModifiers' = MOD_CONTROL|MOD_ALT|0x8000 and 'vk' = VK_DELETE, in order to register Control + Alt + Delete with an ID of 0 and a mystery modifier flag that perhaps designates it as the Secure Attention Sequence. The second designates the MOD_CONTROL|MOD_SHIFT modifiers and a virtual key of VK_ESCAPE, to register Control + Shift + Escape as hotkey ID 4.

This means that Ctrl + Alt + Del and Ctrl + Shift + Esc are truly normal hotkeys in every way, but apparently they are the only ones registered by WINLOGON. What about Win + U and the others?

Windows + U, Continued
We tracked Win + U down as far as SASWndProc, but there's something different about it because it's not handled like normal hotkeys, via WM_HOTKEY messages. However, we do already have a call stack, and it directs us to the SasAccessNotify function and the code path leading up to it. After arriving at the call in SASWndProc, our first hop back leads us past another switch statement inside the message type switch. The second cross-reference hop reveals that the former, inner switch is part of the handler code for the undocumented 0x004C message type, and thumbing through it shows off some of the diverse functionality it handles.

Case 'wParam' = 3, which invokes SasAccessNotify, is the one that concerns us. The function is apparently suited to process any accessibility hotkey, because the CreateThread call's 'lpStartAddress' parameter is pulled from a table that mentions every type of accessibility feature with a shortcut key combination. Although we now know how Win + U functions, what really interests us is how the keypress is identified as a hotkey - that is, where these special window messages originate.

A compulsive habit with anything window message-related is to run the Spy++ tool (included with Visual Studio) and "see" what a window's message traffic looks like. In this case, it reveals some interesting but unexpected information - the "SAS window" is apparently hidden from the list! Simple test programs will confirm that we cannot find the window by its known caption and class name, any attempt to access the window by its handle (which we can get with "bpx SASWndProc") yields an "Invalid window handle" error.

What next? Searching WINLOGON and MSGINA in IDA for "4Ch" (the textual representation of the value 0x004C as it will appear in IDA) turns up nothing useful, so it's likely that the kernel is directly involved. It's finally time to open WIN32K.SYS, although searching it for "4Ch" will probably be a tedious process because that particular value could appear in any number of contexts, not just as a window message type. For a lack of better ideas, however, we do exactly that, and serendipitously it pays off - out of 255 hits, we see a manageable number of PUSH 4Ch instructions, and unbelievably, the first half almost completely pertain to notifying WINLOGON, presenting us with seemingly appropriate code snippets such as "PUSH 4Ch / PUSH _gspwndLogonNotify / CALL __PostMessage@16".

Because a text search of the entire WIN32K.SYS disassembly takes too long on our system, we instead opt for cross-referencing _gspwndLogonNotify, which brings up a comfortable 28 matches and lets us quickly pinpoint calls with 'wParam' = 3 in xxxAccessTimeOutTimer, FKActivationTimer (FK is for "FilterKeys"), HighContrastHotKey, MouseKeys, xxxStickyKeys, xxxSystemParametersInfo, xxxToggleKeysTimer, and UtilityManager.

We now have plenty of routes to explore, so we'll just start with the most likely according to function name. UtilityManager leads us via the _aAccessibilityProc function table to AccessProceduresStream, which in turn takes us to the more enticing ProcessKeyboardInput. Once there, we can see some recognizable VK_* constants, specifically 0x5B (VK_LWIN), 0x5C (VK_RWIN), and the range (0x9F..0xA5], which encompasses the Shift, Control, and Alt virtual keys; however, the modifiers seem to be internal representations. For example, the VK_LWIN code block causes bit 6 (0x40) of _gCurrentModifierBit to be set, and the VK_RWIN code sets bit 7 (0x80), but the public modifier definitions in "winuser.h" indicate only that both Windows keys share the modifier value MOD_WIN = 0x0008.

Taking a step back, it becomes clear that basically all keyboard input is passed through all of the accessibility functions, by way of the loop in AccessProceduresStream. In that case, UtilityManager deserves a second look, and upon closer inspection we see something that makes perfect sense - a comparison against 0x55 (VK_U) and a test of bits 6 and 7 (internal LWIN and RWIN modifiers). If both conditions are satisfied, the SAS window (which is nothing more than just a host for a message queue, not a visible window) gets a 'uMsg' = 0x004C, 'wParam' = 3, 'lParam' = 6 window message.

Alt + Tab and Alt + Escape
Tracking down Ctrl + Shift + Esc unexpectedly led to Ctrl + Alt + Del, and with a little more effort than anticipated, Win + U, but now we have no leads for the remaining hotkeys, so we're mostly starting from scratch. Keeping in mind the functionality we expect Alt + Tab to use, it might be the easiest to track down using breakpoints, but settings CreateWindowExA and CreateWindowExW breakpoints in every conceivable process reveals nothing. (Note that CreateWindowA and CreateWindowW do not exist as function code; they are now just macros in "winuser.h" that call the corresponding extended function.)

On a whim, a text search of WIN32K.SYS for "alttab" eventually turns up some results, the most interesting of which are _gspwndAltTab and NtUserGetAltTabInfo / _GetAltTabInfo, a pair which sound like the kernel-side implementation of a user-mode API. Because _gspwndAltTab is referenced in a number of places, but is never modified directly according to the search results (it's probably written to by way of a register loaded with its offset), we consult the MSDN Library (http://msdn.microsoft.com/library/) for more information on GetAltTabInfo.

What we find is an API, USER32!GetAltTabInfo, that accepts a window handle to the "application-switching window", but little else. One can, however, create a test program to find the Alt + Tab window (by constantly enumerating windows while the user presses Alt + Tab) and get some information on it. We did, and came up with the following:

HWND 000303CC

7x1 icons, cursor at icon (1,0), first icon at window's (12,16)

Window Text = ""
Window Class = "#32771"
Window Rect = ( 475, 457)-( 805, 567)
Client Rect = ( 0, 0)-( 324, 104)

GCL_MENUNAME = 00000000
GCL_HBRBACKGROUND = 00000000
GCL_HCURSOR = 00010011
GCL_HICON = 00000000
GCL_HMODULE = A0000000
GCL_CBWNDEXTRA = 00000004
GCL_CBCLSEXTRA = 00000000
GCL_WNDPROC = 00000000
GCL_STYLE = 00000803
GCW_ATOM = 00008003

GWL_WNDPROC = 00000000
GWL_HINSTANCE = 00000000
GWL_HWNDPARENT = 00000000
GWL_ID = 00000000
GWL_STYLE = 9C800000
GWL_EXSTYLE = 00000189
GWL_USERDATA = 00000000


Most of the queries that returned 0 were accompanied by GetLastError() = 5, "Access is denied." Nevertheless, the attempt yielded a lot of interesting information, mostly in the form of unique constants for which we can search - style 0x9C800000, extended style 0x189, and the window class atom of #32771, or 0x8003. Although the window procedure address would have been the most helpful, seeing an HMODULE of 0xA0000000 (the WIN32K.SYS base address) reassures us that Alt + Tab support is provided entirely by the kernel.

Perhaps the style bitmasks are constructed in an unusual way, or perhaps they change between window creation and when our program runs, but searching for "9C800000h" and "189h" is a complete disappointment. The style value comprises WS_POPUP|WS_VISIBLE|WS_DISABLED|WS_CLIPSIBLINGS|WS_BORDER, and the extended style represents WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW|WS_EX_TOPMOST|WS_EX_DLGMODALFRAME. It's reasonable to suspect that WS_VISIBLE or WS_DISABLE may have been toggled following window creation, but rather than attempt a number of text searches, each with little chance of success, we have other, more likely constants to try to find.

As we hoped, a search for "8003h" leads us straight to two xxxCreateWindowEx calls, with arguments 'dwExStyle' = 0x181, 'lpClassName' = MAKEINTATOM(0x8003), and 'dwStyle' = 0x88800000, one in xxxNextWindow and the other in xxxOldNextWindow. We also see that the global variable _gspwndAltTab we were interested in takes on a pointer to the newly-created window object, through a call to HMAssignmentLock. If we had set a memory write breakpoint (BPMD WIN32K!_gspwndAltTab W) instead of the approach we did take, we would have needed to step out of HMAssignmentLock because it does not establish an EBP-based stack frame, so the call stack would not have indicated its immediate caller. (It's important that the breakpoint only trigger on write, because a quick test reveals that the variable is read quite often.)

Now we can breakpoint both functions and see which is used; xxxNextWindow is the clear winner so we need not even bother with the other. As it is only called in one place, we can backtrack to xxxKeyEvent and survey its Alt + Tab-relevant code. Once again, we see recognizable VK_* constants (9 is VK_TAB and 0x1B is VK_ESCAPE, both of which can be reasonably expected to merit special handling). A couple code cross-references back we see a check to ensure that bit 2 of CL is clear, then a comparison of BL to 9 (VK_TAB), leading to the xxxNextWindow call. The Tab comparison of course makes sense, but where is the Alt check?

There are some Alt virtual key constants (0x12 or VK_MENU) present that perhaps deserve some scrutiny. We can see a couple in xxxKeyEvent; the first apparently only pertains to an IsSAS check for identifying the "Secure Attention Sequence", while the second, which is only reached if _gspwndAltTab is non-NULL (Alt + Tab mode is in effect), will just call xxxCancelCoolSwitch (presumably to cancel the Alt + Tabbing) if a key besides Tab, Shift, or Alt is pressed. The third instance of VK_MENU, after the call to xxxDoHotKeyStuff, looks even less promising, except that it evaluates the same condition as the one upon which the code block that calls xxxNextWindow depends. Specifically, DL is loaded with the value of bit 4 from a global variable; the conditional branch is followed if the bit is set, or skipped if clear; and then the same value in DL is reused by the later conditional branch that eventually leads to the xxxNextWindow call.

Because the heart of the Alt + Tab code cannot be reached without it, this value in DL must be important, and we should therefore make sure we understand it. Cross-referencing the global variable where the value originates turns up a strange set of operations - and no writes that could set or clear bit 4. Immediately above it, however, we see a global variable named _gafAsyncKeyState, which sounds similar enough to what we're interested in that it would be worthwhile to check its cross-references. There are a number of other cues that pique our interest in this variable: the "af" prefix (which may stand for "array of flags"), the expanses of unlabeled space that follow it, the anonymous variables scattered at non-DWORD aligned offsets throughout that space, and of course its name. These observations lead us to suspect that it's actually an array of bit flags denoting virtual key state (down or up), and that the bytes and DWORDs within its bounds are actually accesses to hard-coded offsets within the array, misrepresented by IDA as separate variables. Browsing _gafAsyncKeyState's cross-references confirms this hunch, as we see its contents accessed as an array of bytes, and code from the function GetAsyncKeyState further reveals that each virtual key gets a two-bit field in the array (lower indices corresponding to lesser-significance bits).

With this in mind, we can revisit the DL condition leading up to xxxNextWindow and make perfect sense of the disassembly. The global variable that provides DL its value is really _gafAsyncKeyState + 4, at which location bit 4 is the bit of interest, so the code is checking the two-bit field with index number 0x12 - the value for VK_MENU. In other words, we had seen the Alt check from the beginning, but we just didn't recognize it at the time.

While we're in the area, it looks like we've found the support code for Alt + Esc as well. If BL isn't VK_TAB, then it's compared to VK_ESCAPE. Both paths lead to the xxxNextWindow call, which may seem confusing before noting that it contains its own virtual key code comparisons for Tab and Escape (and also F6), so that it can administer the appropriate behavior based on which key combination caused it to execute.

PrintScreen
The final hotkey we set out to investigate is PrintScreen, and once again we're starting from scratch. Although we could try searching for "2Ch" (VK_SNAPSHOT) in WIN32K.SYS, we'd prefer to try something different. Our guess is that its support is coded in WIN32K, and that it uses the kernel equivalent of SetClipboardData (a quick look in USER32.DLL suggests that the function's name will likely be NtUserSetClipboardData), so we go there in the WIN32K disassembly - and find no cross-references. Not too surprised though, we continue down a page and see that the core routine is actually _SetClipboardData, which is referenced by another function called xxxSnapWindow. That function is only invoked from xxxScanSysQueue, which sounds somewhat disconnected from the keyboard handling code in which we expected to find ourselves.

Maybe we can track down what mechanism brings us to this point by backtracking. At the top of the block of code that calls xxxSnapWindow is a cross-reference from another conditional jump, the deciding factor being a comparison to 0x2C, VK_SNAPSHOT. Continuing backwards, we see what looks like a compiled switch statement, and some more "magic" values: 0x23, 0x100, 0x101, 0x102, 0x104, 0x105, and 0x20A, which correspond to the window message types WM_QUEUESYNC, WM_KEYDOWN (this is the one that eventually leads to xxxSnapWindow), WM_KEYUP, WM_CHAR, WM_SYSKEYDOWN, WM_SYSKEYUP, and WM_MOUSEWHEEL.

Evidently PrtScrn is queued as a WM_KEYDOWN message like any other key, although Spy++ demonstrates that message loops in user-land never receive the WM_KEYDOWN message for VK_SNAPSHOT, only WM_KEYUP. Further code traversing clarifies the situation, however - rather than xxxScanSysQueue operating like the "default window proc" garbage disposal for leftover messages, it's actually where all window messages are held for later retrieval. The function is called by xxxInternalGetMessage, which in turn is used by NtUserGetMessage, NtUserPeekMessage, and WIN32K message loops to receive messages appropriate to the requester's context. Apparently PrtScrn key presses are processed as they are encountered in the system message queue, and are silently purged afterward.

Other Hotkeys
Although we were thorough in listing special Windows hotkeys, a few did sneak past us. We know this because the xxxDoHotKeyStuff function, which we were using as a landmark while disassembling for Alt + Tab support, makes use of the function IsHotKey, which in turn scans a linked list of hotkey entries (starting at *_gphkFirst) to see if a virtual key plus modifiers combination matches a registered hotkey. The format of a list entry is roughly as follows:

+00h  PTR     pointer to {*ETHREAD, ...} structure
+04h  PTR     pointer to {HWND, ...} structure
+08h  DWORD   MOD_* modifiers (0x80000000 = SAS?)
+0Ch  DWORD   VK_* virtual key code
+10h  DWORD   associated window message (-7, -6, -5 special)
+14h  PTR     pointer to next hotkey entry structure


Walking the list, we see all the hotkeys registered for Explorer.exe, and the two that WINLOGON uses, as the following dump from a Windows 2000 system demonstrates:

ModifierVKeyIDProcessHotkey
0x000000020x1B0xF130EXPLORERCtrl+Esc
0x000000080x440x01FEEXPLORERWin+D
0x000000080x130x01FDEXPLORERWin+Pause
0x0000000C0x090x01FCEXPLORERWin+Shift+Tab
0x000000080x090x01FBEXPLORERWin+Tab
0x0000000A0x460x01FAEXPLORERWin+Ctrl+F
0x000000080x460x01F9EXPLORERWin+F
0x000000080x450x01F8EXPLORERWin+E
0x000000080x700x01F7EXPLORERWin+F1
0x0000000C0x4D0x01F6EXPLORERWin+Shift+M
0x000000080x4D0x01F5EXPLORERWin+M
0x000000080x520x01F4EXPLORERWin+R
0x000000060x1B0x0004WINLOGONCtrl+Shift+Esc
0x800000030x2E0x0000WINLOGONCtrl+Alt+Del (SAS)
0x000000040x7B-6CSRSSShift+F12
0x000000000x7B-5CSRSSF12
0x000000080x00-7CSRSSWindows key


At the very end we see three hotkeys which we assume are special due to their "ID" fields: Shift + F12 (-6), F12 with no modifiers (-5), and Win + no virtual key, the Windows key pressed and released by itself (-7).

These special cases are handled directly within xxxDoHotKeyStuff, so we can easily disassemble the associated code. The Windows key will generate a WM_SYSCOMMAND message with 'wParam' = SC_TASKLIST (which brings up the Start menu); the code paths for F12 and Ctrl + F12 both arrive at xxxActivateDebugger. The former is well-known behavior, and the latter is mentioned in Microsoft's RegisterHotKey documentation, so this is as far as we'll research these.

Additionally, there may be as-yet unencountered special hotkeys hard-coded into WIN32K that we have also missed; please contact us if you are aware of any.

Conclusion
In this article, we've debugged, disassembled, Googled, and coded our way through a seemingly arbitrary project to understand the Windows hotkey handling machinery, an undertaking which spanned both user- and kernel-lands. We hope it's been an informative and interesting example of reverse engineering, and that it might be of use to others who are interested in the inner workings of how Windows processes hotkeys. Next time, we'll take what we've learned here and apply it to a very different sort of project - so stay tuned.

Source: Derek Soeder, Software Engineer, eEye Digital Security


Ask Research

Q: I saw the BootRoot presentation at the 2005 Blackhat Briefings. Can I download the associated files?

A: BootRoot is a study in NT boot sector compromise. Much like the boot sector viruses of the 1980's, BootRoot exploits the principle that the first loaded code can obfuscate and hide from later loaded code. It shows that the process of NT booting is vulnerable to attack, and that once attacked, all subsequent systems have a harder time detecting the compromise.

Many have emailed the eEye Research Team looking for a link to the material from Derek Soeder's and Ryan Permeh's BootRoot talk. We apologize for the delay in getting this material online, but the guys wanted to make sure it was perfect before releasing it to the general public. For those that missed Blackhat Vegas in 2005, you can find a copy of the presentation slides inside the ZIP file.

Without further adieu, here is the link:
http://www.eeye.com/html/resources/downloads/other/index.html


Q: I saw your upcoming vulnerabilities page. At what point does a vulnerability become overdue?

A: eEye's Upcoming Advisories page (http://www.eeye.com/html/research/upcoming/index.html) is a great way to see what our research team is working on and what patches you can expect to see in the future. While we keep the details to a minimum, we do publish the date that an issue is reported to the vendor and how many days the patch is overdue.

eEye designates a vulnerability's remediation (a patch or mitigation procedure) to be overdue 60 days after its details have been provided to the vendor. We feel that 60 days is adequate time for a software vendor to confirm the flaw, research its root cause, and provide some sort of remediation. We arrived at the 60 day figure as a maximum for even the largest vendors by considering company size, platform pervasiveness, and the fact that the vendor may already have a backlog of security issues when presented with a new one.

Have a question you would like answered? Send it to vice@eeye.com, and win an eEye t-shirt if we select your question for an upcoming newsletter.


Etcetera

Blackhat Briefings 2005 Roundup

This July the eEye Research Team descended on Las Vegas, Nevada to attend the Blackhat Briefings 2005. Aside from attending, Barnaby Jack, Derek Soeder, and Ryan Permeh from the eEye Research Team gave presentations. We wanted to take some space to talk about some of the other talks given by researchers outside of eEye that were very interesting and worth attending. Because of the large amount of talks on the schedule we did not get to hear every one, so if we miss one here that you feel was worthy of a mention please let us know and we will mention it in the next issue of VICE.

The first notable presentation was presented by Jamie Butler, the author of the recently released book Rootkits, and co-presented by Sherri sparks. The talk was entitled "Shadow Walker - Raising the Bar for Rootkit Detection" and was an excellent presentation on a method to hide a rootkit in memory, thereby making it more difficult to be detected.

You most probably have heard about the fiasco involving Cisco, ISS, and a researcher by the name of Michael Lynn. Politics aside, the presentation given by Lynn, containing "banned material" and the like, was an interesting look at previous work performed by FX of Phenoelit fame, as well as some other research that was floating around the Internet. The real bottom line of the presentation is that Cisco IOS can in fact be exploited.

The last talk that we feel is worth mentioning was presented by two members of the Metasploit project: "spoonm" and "skape". Their presentation discussed recent advancements in shellcode, evasion techniques, and post-exploitation systems. This was a complex talk that gave a good overview of what we can expect to see in future versions of Metasploit.

Archives of all the Blackhat talks are available at the Blackhat website here: http://www.blackhat.com/html/bh-media-archives/bh-multi-media-archives.html#USA-2005

Vulnerability Expert Forum: October Patch Tuesday

Microsoft has released their security bulletin advanced notification for October's installment of Patch Tuesday. After last month's non-event, Microsoft plans to release 9 total patches affecting the various Windows platforms. This should undoubtedly create a lot of work for security and operations professionals responsible the patching and maintenance of systems. As a service to the network security community, eEye Digital Security hosts the monthly Vulnerability Experts Forum, which explores the details of security patches released and their potential impact to your organization. Additionally, eEye is able to offer unique insight into the vulnerabilities discovered by eEye researchers which Microsoft addresses.

To register for the Vulnerability Expert Forum, a free online webinar, please visit the eEye Events page:
http://www.eeye.com/html/company/events/index.html


How to Subscribe
To subscribe to this and other eEye newsletters, please visit: http://www.eeye.com/html/resources/newsletters/subscribe.html

Feedback
The eEye newsletter staff welcomes any comments, questions or suggestions from our readers. We hope that you will not hesitate to contact us with any feedback you may have. Send all feedback to vice@eeye.com.

Disclaimer
The information within this newsletter may change without notice. Use of this information constitutes acceptance for use in an AS IS condition. There are NO warranties with regard to this information. In no event shall the author be liable for any damages whatsoever arising out of or in connection with the use or spread of this information. Any use of this information is at the user's own risk. Opinions expressed are not necessarily those of eEye Digital Security.

Notice
Permission is hereby granted for the redistribution of this newsletter electronically. It is not to be edited in any way without the express consent of eEye. If you wish to reprint the whole or any part of this newsletter in any other medium excluding electronic medium, please email vice@eeye.com for permission. Permission to reprint readers' comments or questions, and edit where necessary for length and clarity, is assumed unless explicitly forbidden.