VOID KiUserCallbackDispatcher( __in PVOID CallbackArgument __in ULONG CallbackIndex ) { NTSTATUS Status; ULONG ReturnStatus; PPEB Peb; // // Note that a custom calling convention is used, such that all arguments are // passed on the stack, starting at [rsp+20] (on x64). No register arguments // are used on x64 platforms. // // // Make the call to the specified kernel mode to user mode callback. The set // of callback routines is stored in an array pointed to by the // "KernelCallbackTable" member of the PEB. // // Each callback takes a single argument, which is typically a structure // pointer. Most callbacks are in fact actually sub-dispatchers for several // different callbacks that share the same calling convention after the // callback arguments are unpacked from the structure pointer. // // In the case of a Wow64 process, the Wow64 layer will have installed a set // of shadow trampoline function pointers in the PEB to facilitate the // necessary conversion of the callback argument. // Peb = NtCurrentPeb(); ReturnStatus = Peb->KernelCallbackTable[ CallbackIndex ]( CallbackArgument ); // // If the callback did not explicitly return to kernel mode, then do so now. // Note that this is not the typical case, as all User32 callbacks should // call NtCallbackReturn directly. // Status = NtCallbackReturn( 0, 0, ReturnStatus ); // // NtCallbackReturn should never return to us. If it did so, then something // has gone very wrong. // for (;;) RtlRaiseStatus( Status ); }