A catalog of NTDLL kernel mode to user mode callbacks, part 1: Overview

As I previously mentioned, NTDLL maintains a set of special entrypoints that are used by the kernel to invoke certain functionality on the behalf of user mode.

In general, the functionality offered by these entrypoints is fairly simple, although having an understanding of how each are used provides useful insight into how certain features (such as user mode APCs) really work “under the hood”.

For the purposes of this discussion, the following are the NTDLL exported entrypoints that the kernel uses to communicate to user mode:

  1. KiUserExceptionDispatcher
  2. KiUserApcDispatcher
  3. KiRaiseUserExceptionDispatcher
  4. KiUserCallbackDispatcher
  5. LdrInitializeThunk
  6. RtlUserThreadStart
  7. EtwpNotificationThread
  8. LdrHotPatchRoutine

(There are other NTDLL exports used by the kernel, but not for direct user mode communication.)

These routines are generally used to inform user mode of a particular event occurring, though the specifics of how each routine is called vary somewhat.

KiUserExceptionDispatcher, KiUserApcDispatcher, and KiRaiseUserExceptionDispatcher are exclusively used when user mode has entered kernel mode, either implicitly, due to a processor interrupt (say, a page fault that will eventually trigger an access violation), or explicitly, due to a system call (such as NtWaitForSingleObject). The mechanism that the kernel uses to invoke these entrypoints is to alter the context that will be realized upon return from kernel mode to user mode. The return to user mode context information (a KTRAP_FRAME) is modified such that when kernel mode returns, instead of returning to the point upon which user mode invoked a kernel mode transition, control is transferred to one of the three dispatcher routines. Additional arguments are supplied to these dispatcher routines as necessary.

KiUserCallbackDispatcher is used to explicitly call out to user mode from kernel mode. This inverted mode of operation is typically discouraged in favor of models such as the pending IRP “inverted call model”. For historical design reasons, however, the Win32 subsystem (win32k.sys) uses this for a number of tasks (such as calling a user mode window procedure in response to a kernel mode window message operation). The user mode callout mechanism is not extensible to support arbitrary user mode callback destinations.

LdrInitializeThunk is the first instruction that any user mode thread runs, before the “actual” thread entrypoint. As such, it is the address at which every user mode thread system-wide begins execution.

RtlUserThreadStart is used on Windows Vista and Windows Server 2008 (and later OS’s) to form the initial entrypoint context for a thread started with NtCreateThreadEx (this is a marked departure from the approach taken by NtCreateThread, wherein the user mode caller supplies the initial thread context).

EtwpNotificationThread and LdrHotPatchRoutine both correspond to a standard thread entrypoint routine. These entrypoints are referenced by user mode threads that are created in the context of a particular process to carry out certain tasks on behalf of the kernel. As the latter two routines are generally only rarely encountered, this series does not describe them in detail.

Despite (or perhaps in spite of) the more or less completely unrealized promise of less reboots for hotfixes with Windows Server 2003, I think I’ve seen a grand total of one or two hotfixes in the entire lifetime of the OS that supported hotpatching. Knowing the effort that must have gone into developing hotpatching support, it is depressing to see security bulletin after security bulletin state “No, this hotfix does not support hotpatching. A reboot will be required.”. That is, however, a topic for another day.

Next up: Examining the operation of KiUserExceptionDispatcher in more detail.

Tags: ,

8 Responses to “A catalog of NTDLL kernel mode to user mode callbacks, part 1: Overview”

  1. LdrInitializeThunk is also the first instruction in process execution since it will be the first instruction for the main thread. One can use this knowledge to step through LdrpInitializeProcess to gain a better understanding of how programs start in Windows. My debugger employs a one-shot breakpoint on this address to catch process start (as opposed to a permanent breakpoint which would then catch subsequent thread starts).

  2. Skywing says:

    You can do similar with the DTW debuggers. For example:

    ntsd -xe cpr -c “bp <offset of ntdll!LdrInitializeThunk> ; g” C:\windows\system32\cmd.exe

    This will break in at the initial LdrInitializeThunk call (from there one can step into LdrpInitializeProcess if desired).

    (Note that symbols will not be available at this point in time so you will need to manually resolve the address manually.)

  3. It is actually pretty easy to resolve this particular address by taking advantage of your observation concerning NTDLL’s location in every process. Examine the exports for NTDLL and save the address for LdrpInitializeThunk in a pending breakpoint list. Then at the first opportunity – NTDLL’s load notification – apply the breakpoint.

  4. Skywing says:

    It is best to do this in a (separate) live process, or Vista’s ASLR will break it as the on-disk preferred base address of NTDLL doesn’t match with the in-memory system-wide address post-Windows Server 2003.

  5. Marc Sherman says:

    On my XP box, looks like system calls end up in:

    0:001> uf poi(SharedUserData!SystemCallStub)
    7c90eb8b 8bd4 mov edx,esp
    7c90eb8d 0f34 sysenter
    7c90eb8f 90 nop
    7c90eb90 90 nop
    7c90eb91 90 nop
    7c90eb92 90 nop
    7c90eb93 90 nop
    7c90eb94 c3 ret

    So are you saying that the instructions following the sysenter are never executed (including the ret instruction)?

  6. Skywing says:

    No. Most of the time, a return to user mode from kernel mode executes those instructions. In the case of (KiUserExceptionDispatcher, KiUserApcDispatcher, KiRaiseUserExceptionDispatcher) being activated, however, the kernel mode to user mode return address is not the instruction following sysenter but the first instruction in one of those three routines.

  7. […] Nynaeve Adventures in Windows debugging and reverse engineering. « A catalog of NTDLL kernel mode to user mode callbacks, part 1: Overview […]

  8. Yuhong Bao says:

    googling for “hotpatching site:http://microsoft.com/technet/security/bulletin/” reveals more patches that support hotpatching, some of them right on the search engine result page.