While performing some random research related to the WIN32K.SYS driver syscalls a few months ago, I stumbled on an interesting finding – when examining the full 32-bit (or in the case of the original research – 64) return values, some of the services seemed to return unusual numbers, for example 0xfffffa8000ea0000. After investigating the subject for a while, it turned out that a part of the WIN32K syscall interface indeed does not always return a value of the native CPU size (as opposed to the core NT kernel). Instead, some of the graphical services seem to be explicitly declared as:
VOID NtUserRandomService( ... )
USHORT NtUserRandomService( ... )
Funny enough to find such types of quirks in the Windows kernel, eh? A list of the flawed syscall names is as follows:
ETHREAD (full disclosure)
NtUserSetRipFlags(Windows XP only)
NtUserSetDbgTag(Windows XP only)
- Other (unknown?)
The above list was created based on the Windows 7 64-bit graphical system call table, although I do not guarantee it is by any means complete (system calls might have been added, removed, or altered since then). As can be seen, a user-mode application is primarily able to read the addresses of two, internal kernel-mode structures (assigned to the currently executed thread, thus no serious information disclosure is going on, here). These are:
ETHREAD– the very standard NT kernel structure, assigned to every single thread running in the system,
W32THREAD– an internal, and pretty much unexplored structure, allocated on demand (i.e. when the thread calls a win32k service for the first time). For more details, you’re advised to take a look at the Mysteries of win32k & GDI post on the Woodmann RCE Forums.
In order to confirm the story a little, let’s take a look at the example NtUserGetKeyState system call epilogue:
mov [ecx+48h], edx mov eax, [eax+70h] mov [ecx+4Ch], eax call _LeaveCrit@0 ; LeaveCrit() mov ax, di pop edi pop esi pop ebp retn 4
Clearly, the code doesn’t care about the upper 16 bits of the return value (leading to a partial disclosure) – that’s also the case for the rest of the aforementioned routines. A complete log from a Windows 7 64-bit instance of a Proof of Concept code follows:
--- 64bit Kernel-address disclosure: [+] [ETHREAD] NtUserAlterWindowStyle : 0xfffffa8000ea80b0 [+] [ETHREAD] NtUserSetThreadState : 0xfffffa8000ea80b0 [+] [ETHREAD] NtUserNotifyWinEvent : 0xfffffa8000ea80b0 [+] [ETHREAD] NtUserModifyUserStartupInfoFlags: 0xfffffa8000ea80b0 [+] [ETHREAD] NtUserSetThreadLayoutHandles : 0xfffffa8000ea80b0 [+] [ETHREAD] NtUserNotifyIMEStatus : 0xfffffa8000ea80b0 [+] [ETHREAD] NtUserSetThreadLayoutHandles : 0xfffffa8000ea80b0 [+] [W32THREAD] NtGdiEngUnlockSurface : 0xfffff900c216f010 [+] [W32THREAD] NtGdiPATHOBJ_vEnumStartClipLines: 0xfffff900c216f010 [+] [W32THREAD] NtGdiEngDeletePath : 0xfffff900c216f010 [+] [W32THREAD] NtGdiEngDeleteClip : 0xfffff900c216f010 [+] [W32THREAD] NtGdiFONTOBJ_vGetInfo : 0xfffff900c216f010 --- 48bit Kernel-address disclosure (the AX value is uncontrolled): [+] [ETHREAD] NtUserRegisterClassExWOW : 0xfffffa8000ea0000 [+] [ETHREAD] NtUserGetKeyState : 0xfffffa8000ea0000 [+] [ETHREAD] NtUserGetAsyncKeyState : 0xfffffa8000ea0000 [+] [ETHREAD] NtUserVkKeyScanEx : 0xfffffa8000ea0332 [+] [ETHREAD] NtUserSetWindowWord : 0xfffffa8000ea0000 [+] [ETHREAD] NtUserSetClassWord : 0xfffffa8000ea0000
Since the disclosed addresses do not pose a direct threat to the system security, the MSRC team did not consider the issue worth fixing. Well, although I do agree that it’s a minor issue, it is still amusing for me to find such peculiarities in the main Windows graphical kernel module ;) No source code this time, although I do encourage you to fire your IDA and verify the findings by yourself (Windows WIN32K.SYS System Call Table might come in handy).
PS. It seems that I wasn’t the only one coming across this matter – Tavis Ormandy has apparently tweeted about it a year ago, as well ;) Nice one.