{"id":204,"date":"2007-11-21T12:19:41","date_gmt":"2007-11-21T17:19:41","guid":{"rendered":"http:\/\/www.nynaeve.net\/?p=204"},"modified":"2019-12-13T17:43:58","modified_gmt":"2019-12-13T22:43:58","slug":"a-catalog-of-ntdll-kernel-mode-to-user-mode-callbacks-part-5-kiusercallbackdispatcher","status":"publish","type":"post","link":"http:\/\/www.nynaeve.net\/?p=204","title":{"rendered":"A catalog of NTDLL kernel mode to user mode callbacks, part 5: KiUserCallbackDispatcher"},"content":{"rendered":"<p><a title=\"A catalog of NTDLL kernel mode to user mode callbacks, part 4: KiRaiseUserExceptionDispatcher\" href=\"http:\/\/www.nynaeve.net\/?p=203\">Last time<\/a>, I briefly outlined the operation of <em>KiRaiseUserExceptionDispatcher<\/em>, and how it is used by the <em>NtClose<\/em> system service to report certain classes of handle misuse under the debugger.<\/p>\n<p>All of the NTDLL kernel mode to user mode &#8220;callbacks&#8221; that I have covered thus far have been, for the most part fairly &#8220;passive&#8221; in nature.  By this, I mean that the kernel does not explicitly <em>call<\/em> any of these callbacks, at least in the usual nature of making a function call.  Instead, all of the routines that we have discussed thus far are only invoked instead of the normal return procedure for a system call or interrupt, under certain conditions.  (Conceptually, this is similar in some respects to returning to a different location using <a title=\"longjmp\" href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/3ye15wsy(VS.71).aspx\">longjmp<\/a>.)<\/p>\n<p>In contrast to the other routines that we have discussed thus far, <em>KiUserCallbackDispatcher<\/em> breaks completely out of the passive callback model.  The user mode callback dispatcher is, as the name implies, a trampoline that is used to make full-fledged calls to user mode, <em>from kernel mode<\/em>.  (It is complemented by the <em>NtCallbackReturn<\/em> system service, which resumes execution in kernel mode following a user mode callback&#8217;s completion.  Note that this means that a user mode callback can make auxiliary calls into the kernel without &#8220;returning&#8221; back to the original kernel mode caller.)<\/p>\n<p>Calling user mode to kernel mode is a very non-traditional approach in the Windows world, and for good reason.  Such calls are typically dangerous and need to be implemented very carefully in order to avoid creating any number of system reliability or integrity issues.  Beyond simply validating any data returned to kernel mode from user mode, there are a far greater number of concerns with a direct kernel mode to user mode call model as supported by KiUserCallbackDispatcher.  For example, a thread running in user mode can be freely suspended, delayed for a very long period of time due to a high priority user thread, or even terminated.  These actions mean that any code spanning a call out to user mode must not hold locks, have acquired memory or other resources that might need to be released, or soforth.<\/p>\n<p>From a kernel mode perspective, the way a user mode callback using KiUserCallbackDispatcher works is that the kernel saves the current processor state on the current kernel stack, alters the view of the top of the current kernel stack to point <em>after<\/em> the saved register state, sets a field in the current thread (<em>CallbackStack<\/em>) to point to the stack frame containing the saved register state (the previous CallbackStack value is saved to allow for recursive callbacks), and then executes a return to user mode using the standard return mechanism.<\/p>\n<p>The user mode return address is, of course,  set to the feature NTDLL routine of this article, KiUserCallbackDispatcher.  The way the user mode callback dispatcher operates is fairly simple.  First, it indexes into an array stored in the PEB with an argument to the callback dispatcher that is used to select the function to be invoked.  Then, the callback routine located in the array is invoked, and provided with a single pointer-sized argument from kernel mode (this argument is typically a structure pointer containing several parameters packaged up into one contiguous block of memory).  The actual implementation of KiUserCallbackDispatcher is fairly simple, and I have posted a <a title=\"KiUserCallbackDispatcher\" href=\"http:\/\/www.nynaeve.net\/Code\/KiUserCallbackDispatcher.c\">C representation<\/a> of it.<\/p>\n<p>In Win32, kernel mode to user mode callbacks are used exclusively by User32 for windowing related aspects, such as calling a window procedure to send a <em>WM_NCCREATE<\/em> message during the creation of a new window on behalf of a user mode caller that has invoked  <em>NtUserCreateWindowEx<\/em>.  For example, during window creation processing, if we set a breakpoint on KiUserCallbackDispatcher, we might see the following:<\/p>\n<pre>\r\nBreakpoint 1 hit\r\nntdll!KiUserCallbackDispatch:\r\n00000000`77691ff7 488b4c2420  mov rcx,qword ptr [rsp+20h]\r\n0:000&gt; k\r\nRetAddr           Call Site\r\n<span style=\"color:#ff0000\">00000000`775851ca ntdll!KiUserCallbackDispatch<\/span>\r\n<span style=\"color:#0000ff\">00000000`7758514a USER32!ZwUserCreateWindowEx+0xa<\/span>\r\n00000000`775853f4 USER32!VerNtUserCreateWindowEx+0x27c\r\n00000000`77585550 USER32!CreateWindowEx+0x3fe\r\n000007fe`fddfa5b5 USER32!CreateWindowExW+0x70\r\n000007fe`fde221d3 ole32!InitMainThreadWnd+0x65\r\n000007fe`fde2150c ole32!wCoInitializeEx+0xfa\r\n00000000`ff7e6db0 ole32!CoInitializeEx+0x18c\r\n00000000`ff7ecf8b notepad!WinMain+0x5c\r\n00000000`7746cdcd notepad!IsTextUTF8+0x24f\r\n00000000`7768c6e1 kernel32!BaseThreadInitThunk+0xd\r\n00000000`00000000 ntdll!RtlUserThreadStart+0x1d\r\n<\/pre>\n<p>If we step through this call a bit more, we&#8217;ll see that it eventually ends up in a function by the name of <em>user32!_fnINLPCREATESTRUCT<\/em>, which eventually calls <em>user32!DispatchClientMessage<\/em> with the WM_NCCREATE window message, allowing the window procedure of the new window to participate in the window creation process, despite the fact that win32k.sys handles the creation of a window in kernel mode.<\/p>\n<p>Callbacks are, as previously mentioned, permitted to be nested (or even recursively made) as well.  For example, after watching calls to KiUserCallbackDispatcher for a time, we&#8217;ll probably see something akin to the following:<\/p>\n<pre>\r\nBreakpoint 1 hit\r\nntdll!KiUserCallbackDispatch:\r\n00000000`77691ff7 488b4c2420  mov rcx,qword ptr [rsp+20h]\r\n0:000&gt; k\r\nRetAddr           Call Site\r\n<span style=\"color:#ff0000\">00000000`7758b45a ntdll!KiUserCallbackDispatch<\/span>\r\n<span style=\"color:#0000ff\">00000000`7758b4a4 USER32!NtUserMessageCall+0xa<\/span>\r\n00000000`7758e55a USER32!RealDefWindowProcWorker+0xb1\r\n000007fe`fca62118 USER32!RealDefWindowProcW+0x5a\r\n000007fe`fca61fa1 uxtheme!_ThemeDefWindowProc+0x298\r\n00000000`7758b992 uxtheme!ThemeDefWindowProcW+0x11\r\n00000000`ff7e69ef USER32!DefWindowProcW+0xe6\r\n00000000`7758e25a notepad!NPWndProc+0x217\r\n00000000`7758cbaf USER32!UserCallWinProcCheckWow+0x1ad\r\n00000000`77584e1c USER32!DispatchClientMessage+0xc3\r\n00000000`77692016 USER32!_fnINOUTNCCALCSIZE+0x3c\r\n<span style=\"color:#ff0000\">00000000`775851ca ntdll!KiUserCallbackDispatcherContinue<\/span>\r\n<span style=\"color:#0000ff\">00000000`7758514a USER32!ZwUserCreateWindowEx+0xa<\/span>\r\n00000000`775853f4 USER32!VerNtUserCreateWindowEx+0x27c\r\n00000000`77585550 USER32!CreateWindowEx+0x3fe\r\n00000000`ff7e9525 USER32!CreateWindowExW+0x70\r\n00000000`ff7e6e12 notepad!NPInit+0x1f9\r\n00000000`ff7ecf8b notepad!WinMain+0xbe\r\n00000000`7746cdcd notepad!IsTextUTF8+0x24f\r\n00000000`7768c6e1 kernel32!BaseThreadInitThunk+0xd\r\n<\/pre>\n<p>This support for recursive callbacks is a large factor in why threads that talk to win32k.sys often have so-called &#8220;large kernel stacks&#8221;.  The kernel mode dispatcher for user mode calls will attempt to convert the thread to a large kernel stack when a call is made, as the typical sized kernel stack is not large enough to support the number of recursive kernel mode to user mode calls present in a many complicated window messaging calls.<\/p>\n<p>If the process is a Wow64 process, then the callback array in the PEB is prepointed to an array of conversion functions inside the Wow64 layer, which map the callback argument to a version compatible with the 32-bit user32.dll, as appropriate.<\/p>\n<p>Next up: Taking a look at <em>LdrInitializeThunk<\/em>, where all user mode threads <em>really<\/em> begin their execution.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last time, I briefly outlined the operation of KiRaiseUserExceptionDispatcher, and how it is used by the NtClose system service to report certain classes of handle misuse under the debugger. All of the NTDLL kernel mode to user mode &#8220;callbacks&#8221; that I have covered thus far have been, for the most part fairly &#8220;passive&#8221; in nature. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[10,5],"tags":[17,29,32],"_links":{"self":[{"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=\/wp\/v2\/posts\/204"}],"collection":[{"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=204"}],"version-history":[{"count":1,"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=\/wp\/v2\/posts\/204\/revisions"}],"predecessor-version":[{"id":517,"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=\/wp\/v2\/posts\/204\/revisions\/517"}],"wp:attachment":[{"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=204"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=204"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=204"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}