As you can see, most of these tasks are critical to enabling an application to actually run its code; without them, everything from calling external functions to using the heap would immediately fail. After the process has been created, the loader calls a special native API to continue execution based on a context frame located on the stack. This context frame, built by the kernel, contains the actual entry point of the application. Therefore, because the loader doesn’t use a standard call or jump into the running application, you’ll never see the loader initialization functions as part of the call tree in a stack trace for a thread.
EXPERIMENT: Watching the Image Loader
In this experiment, you’ll use global flags to enable a debugging feature called
From the directory where you’ve installed WinDbg, launch the Gflags.exe application, and then click on the Image File tab.
In the Image field, type Notepad.exe, and then press the Tab key. This should enable the check boxes. Select the Show Loader Snaps option, and then click OK to dismiss the dialog box.
Now follow the steps in the EXPERIMENT: Viewing Debugger Objects section to start debugging the Notepad.exe application.
You should now see a couple of screens of debug information similar to that shown here:0924:0248 @ 116983652 - LdrpInitializeProcess - INFO: Initializing process 0x924 0924:0248 @ 116983652 - LdrpInitializeProcess - INFO: Beginning execution of notepad.exe (C:\Windows\notepad.exe) 0924:0248 @ 116983652 - LdrpLoadDll - INFO: Loading DLL "kernel32.dll" from path "C:\Windows;C:\Windows\system32;C:\Windows\system;C:\Windows; 0924:0248 @ 116983652 - LdrpMapDll - INFO: Mapped DLL "kernel32.dll" at address 76BD000 0924:0248 @ 116983652 - LdrGetProcedureAddressEx - INFO: Locating procedure "BaseThreadInitThunk" by name 0924:0248 @ 116983652 - LdrpRunInitializeRoutines - INFO: Calling init routine 76C14592 for DLL "C:\Windows\system32\kernel32.dll" 0924:0248 @ 116983652 - LdrGetProcedureAddressEx - INFO: Locating procedure "BaseQueryModuleData" by name
Eventually, the debugger breaks somewhere inside the loader code, at a special place where the image loader checks whether a debugger is attached and fires a breakpoint. If you press the G key to continue execution, you will see more messages from the loader, and Notepad will appear.
Try interacting with Notepad and see how certain operations invoke the loader. A good experiment is to open the Save/Open dialog. That demonstrates that the loader not only runs at startup, but continuously responds to thread requests that can cause
Early Process Initialization
Because the loader is present in Ntdll.dll, which is a native DLL that’s not associated with any particular subsystem, all processes are subject to the same loader behavior (with some minor differences). In Chapter 5, we’ll look in detail at the steps that lead to the creation of a process in kernel mode, as well as some of the work performed by the Windows function
Build the image path name for the application, and query the Image File Execution Options key for the application, as well as the DEP and SEH validation linker settings.
Look inside the executable’s header to see whether it is a .NET application (specified by the presence of a .NET-specific image directory).
Initialize the National Language Support (NLS for internationalization) tables for the process.
Initialize the Wow64 engine if the image is 32-bit and is running on 64-bit Windows.
Load any configuration options specified in the executable’s header. These options, which a developer can define when compiling the application, control the behavior of the executable.
Set the affinity mask if one was specified in the executable header.
Initialize FLS and TLS.
Initialize the heap manager for the process, and create the first process heap.
Allocate an SxS (Side-by-Side Assembly)/Fusion activation context for the process. This allows the system to use the appropriate DLL version file, instead of defaulting to the DLL that shipped with the operating system. (See Chapter 5 for more information.)
Open the \KnownDlls object directory, and build the known DLL path. For a Wow64 process, \KnownDlls32 is used instead.
Determine the process’ current directory and default load path (used when loading images and opening files).