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)
    • NtUserAlterWindowStyle
    • NtUserSetThreadState
    • NtUserNotifyWinEvent
    • NtUserModifyUserStartupInfoFlags
    • NtUserSetThreadLayoutHandles
    • NtUserNotifyIMEStatus
    • NtUserSetThreadLayoutHandles
    • NtUserSetRipFlags (Windows XP only)
    • NtUserSetDbgTag (Windows XP only)
  • ETHREAD (partial disclosure)
    • NtUserRegisterClassExWOW
    • NtUserGetKeyState
    • NtUserGetAsyncKeyState
    • NtUserVkKeyScanEx
    • NtUserSetWindowWord
    • NtUserSetClassWord
  • W32THREAD (full disclosure)
    • NtGdiEngUnlockSurface
    • NtGdiPATHOBJ_vEnumStartClipLines
    • NtGdiEngDeletePath
    • NtGdiEngDeleteClip
    • NtGdiFONTOBJ_vGetInfo
  • Other (unknown?)
    • NtGdiFlush
    • NtGdiEngUnlockSurface
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 exemplary 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).

Take care!

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.

PS2. I received the first, valid submission for Pimp CrackMe – a reversing challenge by Gynvael and me (see: link). Well done!