{"id":205,"date":"2007-11-28T12:22:36","date_gmt":"2007-11-28T17:22:36","guid":{"rendered":"http:\/\/www.nynaeve.net\/?p=205"},"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-6-ldrinitializethunk","status":"publish","type":"post","link":"http:\/\/www.nynaeve.net\/?p=205","title":{"rendered":"A catalog of NTDLL kernel mode to user mode callbacks, part 6: LdrInitializeThunk"},"content":{"rendered":"<p><a title=\"A catalog of NTDLL kernel mode to user mode callbacks, part 5: KiUserCallbackDispatcher\" href=\"http:\/\/www.nynaeve.net\/?p=204\">Previously<\/a>, I described the mechanism by which the kernel mode to user mode callback dispatcher (<em>KiUserCallbackDispatcher<\/em>) operates, and how it is utilized by win32k.sys for various window manager related operations.<\/p>\n<p>The next special NTDLL kernel mode to user mode &#8220;callback&#8221; up on the list is <em>LdrInitializeThunk<\/em>, which is not so much a callback as <em>the<\/em> entry point at which all user mode threads begin their execution system-wide.  Although the Win32 <a title=\"CreateThread\" href=\"http:\/\/msdn2.microsoft.com\/En-US\/library\/ms682453.aspx\">CreateThread<\/a> API (and even the <em>NtCreateThread<\/em> system service that is used to implement the Win32 <em>CreateThread<\/em>) provide the illusion that a thread begins its execution at a specified start routine (or instruction pointer, in the case of NtCreateThread), this is not truly the case.<\/p>\n<p>CreateThread internally layers in a special kernel32 stub routine (<em>BaseThreadStart<\/em> or <em>BaseProcessStart<\/em>) in between the specified thread routine and the actual initial instruction of the thread.  The kernel32 stub routine wrappers the call to the user-supplied thread start routine to provide services such a &#8220;top-level&#8221; SEH frame for the support of <a title=\"UnhandledExceptionFilter\" href=\"http:\/\/msdn2.microsoft.com\/EN-US\/library\/ms681401.aspx\">UnhandledExceptionFilter<\/a>.<\/p>\n<p>However, there exists yet another layer of indirection before a thread begins its execution at the specified thread start routine, even beyond the kernel32 stub routine at the start of all Win32 threads (the way the kernel32 stub routine works changes slightly with Windows Vista, though that is outside the scope of this discussion).  The presence of this extra layer of indirection can be inferred by examining the documentation on MSDN for <a title=\"DllMain\" href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/ms682583.aspx\">DllMain<\/a>, which states that all threads call out to the <em>DllMain<\/em> routine at some point during thread start-up.  The kernel32 stub routine is not involved in this process, and obviously the user-supplied thread entry point does not have to explicitly attempt to call DllMain for every loaded DLL with <em>DLL_THREAD_ATTACH<\/em>.  This leaves us with the question of who actually arranges for these DllMain calls to happen when a thread begins.<\/p>\n<p>The answer to this question is, of course, the feature routine of this article, LdrInitializeThunk.  When a user mode thread is readied to begin initial execution after being created, the initial context that is realized is <em>not<\/em> the context value supplied to NtCreateThread (which would eventually end up in the user-supplied thread entry point).  Instead, execution really begins at LdrInitializeThunk within NTDLL, which is supplied a CONTEXT record that describes the initially requested state of the thread (as supplied to <em>NtCreateThread<\/em>, or as created by <em>NtCreateThreadEx<\/em> on Windows Vista).  This context record is provided as an argument to LdrInitializeThunk, in order to allow for control to (eventually) be transferred to the user-supplied thread entry point.<\/p>\n<p>When invoked by a new thread, LdrInitializeThunk invokes <em>LdrpInitialize<\/em> to perform the remainder of the initialization tasks, and then calls upon the <em>NtContinue<\/em> system service to restore the supplied context record.  I have made available a <a title=\"LdrInitializeThunk\" href=\"http:\/\/www.nynaeve.net\/Code\/LdrInitializeThunk.c\">C-like representation<\/a> of this process for illustration purposes.<\/p>\n<p>LdrpInitialize makes a determination as to whether the process has already been initialized (for the purposes of NTDLL).  This step is necessary as LdrInitializeThunk (and by extension, LdrpInitialize) is not only the actual entry point for a new thread in an already initialized process, but it is also the entry point for the initial thread in a completely new process (making it the first piece of code that is run in user mode in a new process).  If the process has not already been initialized, then LdrpInitialize <a title=\"What is the lpReserved parameter to DllMain, really?  (Or a crash course in the internals of user mode process initialization)\" href=\"http:\/\/www.nynaeve.net\/?p=127\">performs process initialization tasks<\/a> by invoking <em>LdrpInitializeProcess<\/em> (some process initialization is performed inline by LdrpInitialize in the process initialization case as well).  If the process is a Wow64 process, then the Wow64 NTDLL is loaded and invoked to initialize the 32-bit NTDLL&#8217;s per-process state.<\/p>\n<p>Otherwise, if the process is already initialized, then LdrpInitialize invokes <em>LdrpInitializeThread<\/em> to perform per-thread initialization, which primarily involves invoking <a title=\"Thread Local Storage, part 5: Loader support for __declspec(thread) variables (process initialization time)\" href=\"http:\/\/www.nynaeve.net\/?p=186\">DllMain and TLS callbacks<\/a> for loaded modules while the loader lock is held.  (This is the reason why it is not supported to wait on a new thread to run its thread initialization routine from DllMain, because the new thread will immediately become blocked upon the loader lock, waiting for the thread already in DllMain to complete its processing.)  If the process is a Wow64 process, then there is again support for making a call to the 32-bit NTDLL for purposes of running 32-bit per-thread initialization code.<\/p>\n<p>When the required process or thread initialization tasks have been completed, LdrpInitialize returns to LdrInitializeThunk, which then realizes the user-supplied thread start context with a call to the NtContinue system service.<\/p>\n<p>One consequence of this architecture for process and thread initialization is that it becomes (slightly) more difficult to step through process initialization, because the thread that initializes the process is not the first thread <em>created<\/em> in the process, but rather the first thread that <em>executes LdrInitializeThunk<\/em>.  This means that one cannot simply create a process as suspended and attach a debugger to the process in order to step through process initialization, as the debugger break-in thread will run the very process initialization code that one wishes to step through before executing the break-in thread breakpoint instruction!<\/p>\n<p>There is, fortunately, support for debugging this scenario built in to the Windows debugger package.  By setting the debugger to break on the &#8216;create process&#8217; event, it is possible to manually set a breakpoint on a new process (created by the debugger) or a child process (if child process debugging is enabled) before LdrInitializeThunk is run.  This support is activated by breaking on the <em>cpr<\/em> (<strong>C<\/strong>reate <strong>Pr<\/strong>ocess) event.  For example, using the following ntsd command line, it is possible to examine the target and set breakpoints before any user mode code runs:<\/p>\n<blockquote>\n<p>ntsd.exe -xe cpr C:\\windows\\system32\\cmd.exe<\/p>\n<\/blockquote>\n<p>Note that as the loaded module list will not have been initialized at this point, symbols will not be functional, so it is necessary to resolve the offset of LdrInitializeThunk manually in order to set a breakpoint.  The process can be continued with the typical &#8220;g&#8221; command.<\/p>\n<p><em>Update: <a title=\"Pavel Lebedinsky\" href=\"http:\/\/www.nynaeve.net\/?p=205#comment-20568\">Pavel Labedinsky<\/a> points out that you can use &#8220;<\/em>-xe ld:ntdll.dll<em>&#8221; to achieve the same effect, but with the benefit that symbols for NTDLL are available.  This is a better option as it alleviates the necessity to manually resolve the addresses of locations that you wish to set a breakpoint on.<\/em>.<\/p>\n<p>Next up: Examining <em>RtlUserThreadStart<\/em> (present on Windows Vista and beyond).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Previously, I described the mechanism by which the kernel mode to user mode callback dispatcher (KiUserCallbackDispatcher) operates, and how it is utilized by win32k.sys for various window manager related operations. The next special NTDLL kernel mode to user mode &#8220;callback&#8221; up on the list is LdrInitializeThunk, which is not so much a callback as the [&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],"_links":{"self":[{"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=\/wp\/v2\/posts\/205"}],"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=205"}],"version-history":[{"count":1,"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=\/wp\/v2\/posts\/205\/revisions"}],"predecessor-version":[{"id":516,"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=\/wp\/v2\/posts\/205\/revisions\/516"}],"wp:attachment":[{"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=205"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=205"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.nynaeve.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=205"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}