Desynchronization Issues in Windows Message Handling

This week, Microsoft issued MS11-012 to resolve yet another batch of vulnerabilities in win32k.sys. The bulletin addressed three elevation of privilege vulnerabilities in window class data handling (somewhat related to those patched in MS10-073) and an additional two in window message handling. The latter were quite interesting as they were not your typical vulnerability class, but rather subtle issues caused by the desynchronization of threads engaged in synchronous messaging (using SendMessage APIs). In this post, we’ll review some of the internals concerning window messages and detail the issues at hand.
Past Vulnerabilities

Besides additions such as User Interface Privilege Isolation (UIPI) in Vista [1] and touch and gesture support in Windows 7, the core messaging components have undergone little change over the years. In spite of this, vulnerabilities continue to be discovered. In MS08-025, several data validation vulnerabilities related to user-mode callbacks in the system message handlers were addressed [2]. MS10-098 also fixed a validation issue introduced in Windows 7 upon processing WM_GETTEXT messages that could be leveraged to corrupt the memory of a privileged process. Moreover, additional denial of service vulnerabilities have been reported in system message handlers such as SfnINSTRING and SfnLOGONNOTIFY.
Windows Messages

Windows-based applications are event driven and act upon messages sent to them. Thus, messages and the mechanisms that support them have always played an integral role in the user interface component of the Windows operating system. Each window, owned by a thread, has a window procedure (function) for processing input messages and dispatching them to the operating system. If a thread accesses any of the user interface or GDI system calls (handled by win32k.sys), the kernel creates a THREADINFO structure which holds three message queues used to process input. These are the input queue, the post queue, and the send queue. The input queue is primarily used for mouse and keyboard messages, while the send and post queues are used for synchronous (send) and asynchronous (post) window messages respectively.

typedef struct _tagTHREADINFO // 156 elements, 0x208 bytes (sizeof)
2 {
4 /*0x0BC*/ struct _tagQ* pq; // input queue
6 /*0x0E0*/ struct _tagSMS* psmsSent; // send queue (sent)
7 /*0x0E4*/ struct _tagSMS* psmsCurrent; // send queue (current)
8 /*0x0E8*/ struct _tagSMS* psmsReceiveList; // send queue (received)
10 /*0x174*/ struct _tagMLIST mlPost; // post queue

Asynchronous Messages

Asynchronous messages are used in one-way communication between window threads and are typically used to notify a window to perform a specific task. Asynchronous messages are handled by the PostMessage APIs and are sent to the post queue of the receiving thread. The sender does not wait for the processing to complete in the receiving thread and thus returns immediately. For this reason, asynchronous messages cannot be used with pointers and handles as there is no guarantee that the sender will exist by the time the receiver processes the data.
Synchronous Messages

Synchronous messages differ from asynchronous messages as the sender typically waits for a response to be provided or a timeout to occur before continuing execution. Thus, they require mechanisms to ensure that the threads are properly synchronized and in the expected state. Synchronous messages use the SendMessage APIs which in turn direct execution to the NtUserMessageCall system call in win32k.sys.
view source
1 NTSTATUS NtUserMessageCall (
2 HWND hWnd, // target window
3 UINT Msg, // message type
4 WPARAM wParam, // param1
5 LPARAM lParam, // param2
6 ULONG_PTR ResultInfo, // param3
7 DWORD dwType, // window procedure
8 BOOL bAnsi ) // ansi/unicode

The message type (Msg) is identified by a unique WM code such as WM_SETFOCUS, WM_CREATE, WM_ENABLE, etc. Applications may define their own message codes, but those less than WM_USER (0×400) are reserved by the operating system. Each reserved code denotes an index into win32k!MessageTable (byte array) in which the lower 6 bits of each byte entry defines the identifier (array index) of the associated system message handlers (discussed in the next section).
view source
1 kd> db win32k!MessageTable
2 822a42c8 00 c2 00 00 00 00 00 00-00 00 00 00 c3 c4 ec 00 ................
3 822a42d8 00 00 00 00 80 00 00 00-00 00 c3 c5 00 00 00 00 ................
4 822a42e8 00 00 00 00 86 00 00 80-00 00 00 87 88 89 00 4a ...............J
5 822a42f8 00 80 00 00 00 00 00 00-8b 8c 29 00 a9 00 00 00 ..........).....
6 822a4308 00 00 00 00 00 00 8d 8e-00 cf 90 00 00 00 00 00 ................
7 822a4318 00 00 00 91 00 00 00 00-00 00 00 00 00 00 00 00 ................
8 822a4328 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
9 822a4338 a9 00 00 00 00 00 00 00-00 00 00 00 92 92 00 00 ................

Inter-thread messages are stored in a send message structure (win32k!tagSMS) and appended to the send queue of the receiving thread. The buffer for this structure is allocated in win32k!AllocSMS upon initiating inter-thread messaging in win32k!xxxInterSendMsgEx. The SMS structure holds all the message parameters and information about the sending and receiving threads. The structure is defined as follows (from the Windows 7 public symbols).
view source
1 typedef struct _tagSMS // 15 elements, 0x3C bytes (sizeof)
2 {
3 /*0x000*/ struct _tagSMS* psmsNext;
4 /*0x004*/ struct _tagSMS* psmsReceiveNext;
5 /*0x008*/ struct _tagTHREADINFO* ptiSender;
6 /*0x00C*/ struct _tagTHREADINFO* ptiReceiver;
7 /*0x010*/ FUNCT_00A4_1106_lpResultCallBack* lpResultCallBack;
8 /*0x014*/ ULONG32 dwData;
9 /*0x018*/ struct _tagTHREADINFO* ptiCallBackSender;
10 /*0x01C*/ LONG32 lRet;
11 /*0x020*/ ULONG32 tSent;
12 /*0x024*/ UINT32 flags;
13 /*0x028*/ UINT32 wParam;
14 /*0x02C*/ LONG32 lParam;
15 /*0x030*/ UINT32 message;
16 /*0x034*/ struct _tagWND* spwnd;
17 /*0x038*/ VOID* pvCapture;
18 } tagSMS, *PtagSMS;
Client and Server Functions

The function id stored in the message table denotes an index into a client (gapfnMessageCall) or server (gapfnScSendMessage) function table. The client functions are used by threads sending a message while the server functions are used by threads processing a message. The client functions (prefixed by NtUserfn) are mostly used for probing and caching (copying to kernel memory) of user-mode data. Server functions (prefixed by Sfn) parse and process the content of the message and, if necessary, return data to the sending thread. The following tables show the first few functions of the client and server function tables as found in the data section of win32k.sys.
view source
1 .rdata:BF9F30C8 _gapfnScSendMessage dd offset _SfnDWORD@32
2 .rdata:BF9F30CC dd offset _SfnNCDESTROY@32
3 .rdata:BF9F30D0 dd offset _SfnINLPCREATESTRUCT@32
4 .rdata:BF9F30D4 dd offset _SfnINSTRINGNULL@32
5 .rdata:BF9F30D8 dd offset _SfnOUTSTRING@32
6 .rdata:BF9F30DC dd offset _SfnINSTRING@32
7 .rdata:BF9F30E0 dd offset _SfnINOUTLPPOINT5@32
view source
1 .rdata:BF9F31C8 _gapfnMessageCall dd offset _NtUserfnNCDESTROY@28
2 .rdata:BF9F31CC dd offset _NtUserfnNCDESTROY@28
3 .rdata:BF9F31D0 dd offset _NtUserfnINLPCREATESTRUCT@28
4 .rdata:BF9F31D4 dd offset _NtUserfnINSTRINGNULL@28
5 .rdata:BF9F31D8 dd offset _NtUserfnOUTSTRING@28
6 .rdata:BF9F31DC dd offset _NtUserfnINSTRING@28
7 .rdata:BF9F31E0 dd offset _NtUserfnINOUTLPPOINT5@28

In sending a WM_CREATE (0×1), the sending thread looks up the associated function id in win32k!MessageTable and calls gapfnMessageCall[0x2] = NtUserfnINLPCREATESTRUCT. This function probes and caches the user-mode values before it is sent off in win32k!xxxInterSendMessage and the receiving thread processes the message in gapfnScSendMessage[0x2] = SfnINLPCREATESTRUCT.

SendMessage/GetMessage Execution Flow

In order for send messages to function as intended, the kernel must implement mechanisms to ensure that the sending and receiving threads are synchronized. This is important as message parameters/variables can be stored on the kernel stack of the sending thread, and updates made to this thread stack must be done in a controlled manner. To ensure that either thread has not unexpectedly terminated, the send message kernel structure employs a flags field to keep track of the state of both threads. For instance, if a thread terminates, win32k!xxxDestroyThreadInfo calls win32k!SendMsgCleanup to update the flags field of the SMS structure accordingly. This field must be checked explicitly before updating any values in the stack of the opposite thread.
Thread Desynchronization Vulnerabilities

Several server functions (win32k!Sfn*) did not properly validate the state of the sender thread (client) before returning data to the sender’s thread stack. Consequently, the receiver thread could write to memory that had been freed or even worse, write to a desynchronized kernel thread stack. The latter could result in arbitrary kernel code execution, for instance in overwriting the return pointer of a stack frame. In win32k!SfnINLPDRAWITEMSTRUCT, we see that the device context value on the client thread stack (ESI) is updated without performing the necessary state checks.
view source
1 .text:BF93A9FC mov edi, [ebp+hdcOriginal]
2 .text:BF93A9FF test edi, edi
3 .text:BF93AA01 jz short loc_BF93AA11
4 .text:BF93AA03 mov esi, [ebp+pDrawItemStruct] // client stack
5 .text:BF93AA06 push [esi+tagDRAWITEMSTRUCT.hDC]
6 .text:BF93AA09 call __ReleaseDC@4 ; _ReleaseDC(x)
7 .text:BF93AA0E mov [esi+tagDRAWITEMSTRUCT.hDC], edi // restore hDC
8 .text:BF93AA11 mov eax, [ebp+var_2C]
9 .text:BF93AA14 jmp short loc_BF93AA4C
10 .text:BF93AA16 xor eax, eax
11 .text:BF93AA18 inc eax
12 .text:BF93AA19 retn

1. Edgar Barbosa – Windows Vista UIPI

Category Article

11 Responses to “c0decstuff”

What's on Your Mind...

Thank f' u C0mment