Category: Windows Internals

  • Complete Roadmap to Mastering Windows Programming: Key Skills and Tools

    Becoming an expert in Windows programming requires mastering various areas, spanning from core operating system concepts to advanced application and system-level programming. Here’s a roadmap covering essential topics:

    1. Windows OS Fundamentals

    • Windows Architecture: Learn about the kernel, user mode, kernel mode, system processes, and Windows services.
    • System Calls and APIs: Understand how applications interact with the OS through system calls and the Windows API.

    2. Windows API (Win32 API)

    • Basic API Functions: Familiarize yourself with core Win32 functions like creating windows, handling messages, file I/O, and memory management.
    • Event Handling: Study the Windows message loop, message handling, and inter-process communication.
    • Threading and Synchronization: Learn about threading models, thread pools, and synchronization techniques (mutexes, events, semaphores).

    3. User Interface Programming

    • GDI and GDI+: Get to know the Graphics Device Interface (GDI) for rendering shapes, text, and images.
    • Direct2D and DirectWrite: For advanced graphics and text rendering, understand how to use Direct2D and DirectWrite.
    • Windows Forms and WPF: Learn about managed UI frameworks for building rich client applications.

    4. COM and COM+

    • Component Object Model (COM): COM is the basis for many Windows technologies, including ActiveX, OLE, and DirectX. Understand interfaces, IUnknown, and how COM objects are created and used.
    • COM Interoperability: For .NET applications, learn how to interact with COM objects and handle interop.

    5. Advanced Windows Programming Topics

    • DLLs and Static Libraries: Learn how to create and use dynamic-link libraries and static libraries in Windows applications.
    • Memory Management: Study virtual memory, heap management, and memory-mapped files.
    • Exception Handling: Familiarize yourself with Windows exception handling, SEH (Structured Exception Handling), and Vectored Exception Handling.

    6. Windows System Programming

    • File System and Registry Access: Understand how to interact with the Windows file system and registry for configuration and persistence.
    • Networking: Learn about Winsock and higher-level APIs for network communication.
    • Security: Explore Windows security mechanisms, access control lists (ACLs), privileges, and impersonation.

    7. PowerShell and Scripting

    • Automating Tasks: PowerShell is essential for automation on Windows. Learn to script and automate tasks, manage Windows services, and work with the registry and file system.

    8. Windows Driver Development

    • Kernel-Mode Programming: Explore Windows driver development for hardware-level programming and understand how user-mode applications interact with drivers.
    • WDK (Windows Driver Kit): Use the Windows Driver Kit for creating, testing, and debugging drivers.

    9. Multimedia Programming

    • DirectX: For game development or multimedia applications, learn about DirectX, including Direct3D for graphics, DirectSound for audio, and DirectInput.
    • Media Foundation: For handling video and audio playback, capture, and encoding, get to know the Media Foundation framework.

    10. Debugging and Profiling Tools

    • Visual Studio Debugger: Master breakpoints, watch windows, and various debugging techniques.
    • WinDbg and Debugging Tools for Windows: WinDbg is crucial for low-level debugging and analyzing memory dumps.
    • Performance Profiling: Learn how to profile applications with tools like Windows Performance Analyzer and Visual Studio Profiler.

    11. Cross-Platform Development

    • Windows Subsystem for Linux (WSL): Get comfortable with WSL for developing cross-platform applications on Windows.
    • Cross-Compilation with CMake: For cross-platform development, learn to use CMake for managing build processes.

    12. Windows UWP and WinUI

    • Universal Windows Platform (UWP): Study UWP for building applications that run across different Windows devices.
    • WinUI: Learn WinUI, the modern native UI framework, especially for Windows 10 and 11 applications.

    13. .NET Framework and .NET Core

    • C# and .NET APIs: If working with managed code, understand the .NET framework, including Windows-specific APIs and services.
    • Interoperability with Native Libraries: Learn P/Invoke for calling native functions from managed code.

    14. Windows Security and Hardening

    • App Containers and Sandboxing: Learn how to create secure applications that operate in a restricted environment.
    • Encryption and Certificates: Explore Windows Cryptography APIs for encrypting and securing sensitive data.
    • Windows Defender and Security Auditing: Familiarize yourself with Windows security tools and logs for auditing and threat detection.

    15. Windows Services and Background Tasks

    • Creating Windows Services: Learn how to create and manage services for background processing.
    • Task Scheduler: Understand how to schedule tasks to run at specified times or intervals.

    By focusing on these key areas, you’ll build the skills needed to develop, debug, and maintain powerful Windows applications and services. Let me know if you’d like detailed resources or code samples for any of these areas!

  • Windows Memory Monitoring

    For memory monitoring on Windows, especially targeting virtual memory allocations, page faults, and memory protection changes, there are several safer alternatives that don’t rely on hooking or unsupported mechanisms like ALPC. Below are some methods to achieve memory monitoring at the kernel level and provide user-mode notifications without performance bottlenecks.

    Key Approaches for Memory Monitoring

    1. Process and Thread Notifications: Use PsSetCreateProcessNotifyRoutineEx and PsSetCreateThreadNotifyRoutine to monitor process and thread creation events.
    2. Page Fault Monitoring: While page faults aren’t directly exposed via a kernel API, monitoring changes in memory protections (like NtProtectVirtualMemory) could serve as a way to track suspicious memory activities.
    3. Memory Region Monitoring: You can periodically check for virtual memory allocations by inspecting the memory regions of processes using functions like ZwQueryVirtualMemory.
    4. Filter Drivers: File system filter drivers can also be used to monitor specific file-related memory operations.

    Method 1: Virtual Memory Monitoring with Virtual Address Descriptors (VADs)

    While VADs (Virtual Address Descriptors) aren’t directly accessible through public APIs, you can inspect them indirectly in the kernel. This method requires deep knowledge of the Windows Memory Manager, but is the most efficient way to monitor memory changes.

    Method 2: Using PsSetLoadImageNotifyRoutine for Monitoring Memory-Mapped Files

    If you want to monitor memory allocations related to executable images or DLLs being loaded into memory, you can use the PsSetLoadImageNotifyRoutine function. This doesn’t give complete coverage of all memory operations but can be useful for monitoring memory-mapped files (like DLLs).

    VOID NTAPI LoadImageNotifyRoutine(
        PUNICODE_STRING FullImageName,
        HANDLE ProcessId,
        PIMAGE_INFO ImageInfo
    )
    {
        if (ImageInfo->SystemModeImage) {
            DbgPrint("System Mode Image Loaded: %wZ\n", FullImageName);
        } else {
            DbgPrint("User Mode Image Loaded: %wZ in Process %d\n", FullImageName, ProcessId);
        }
    }
    
    NTSTATUS DriverEntry(
        PDRIVER_OBJECT DriverObject,
        PUNICODE_STRING RegistryPath
    )
    {
        NTSTATUS status;
    
        // Register the image load notification routine
        status = PsSetLoadImageNotifyRoutine(LoadImageNotifyRoutine);
        if (!NT_SUCCESS(status)) {
            DbgPrint("Failed to register load image notify routine\n");
            return status;
        }
    
        DriverObject->DriverUnload = DriverUnload;
        return STATUS_SUCCESS;
    }
    
    VOID DriverUnload(PDRIVER_OBJECT DriverObject)
    {
        PsRemoveLoadImageNotifyRoutine(LoadImageNotifyRoutine);
        DbgPrint("Driver Unloaded\n");
    }

    Method 3: Periodic Virtual Memory Inspections

    You can use ZwQueryVirtualMemory to inspect the memory regions of a process periodically and gather information on virtual memory allocations, protection levels, and committed pages.

    Example of Using ZwQueryVirtualMemory:

    NTSTATUS QueryMemoryRegions(HANDLE ProcessHandle)
    {
        MEMORY_BASIC_INFORMATION memInfo;
        PVOID baseAddress = NULL;
        NTSTATUS status;
    
        while (NT_SUCCESS(status = ZwQueryVirtualMemory(
                ProcessHandle, baseAddress, MemoryBasicInformation, &memInfo, sizeof(memInfo), NULL)))
        {
            DbgPrint("BaseAddress: %p, RegionSize: %llu, State: %x, Protect: %x\n",
                     memInfo.BaseAddress, memInfo.RegionSize, memInfo.State, memInfo.Protect);
    
            // Move to the next memory region
            baseAddress = (PBYTE)baseAddress + memInfo.RegionSize;
        }
    
        return status;
    }

    Method 4: ETW (Event Tracing for Windows) for Page Faults and Memory Monitoring

    ETW is a powerful mechanism in Windows that can be used for tracing low-level system events, including memory-related operations such as page faults.

    1. Enable page fault and virtual memory event tracing using ETW.
    2. Collect and analyze ETW events for memory operations.

    Example of Setting Up ETW for Memory Operations:

    Using ETW, you can set up listeners for specific system events related to memory, such as:

    • Page faults
    • Memory allocations
    • Memory protection changes

    This requires using the Windows Performance Toolkit or programmatically setting up ETW sessions via the EventTrace APIs.

    Efficient Communication to User Mode

    To handle the high volume of kernel events without performance bottlenecks, you can use one of the following mechanisms for notifying user-mode applications:

    1. I/O Completion Ports: If you have a user-mode application that interacts with your driver, I/O completion ports are an efficient way to handle asynchronous notifications for memory changes.
    2. APCs (Asynchronous Procedure Calls): APCs allow you to execute code in the context of a user-mode thread. This is useful for delivering memory change notifications in a non-blocking manner.
    3. Shared Memory: If the volume of data is extremely high, you can create a shared memory region between your kernel-mode driver and user-mode application to pass information efficiently.

    Using APC for Memory Change Notifications

    In place of ALPC, you can use APC to notify user-mode applications about significant memory changes asynchronously. Here’s an outline of how to use APCs:

    1. Queue an APC to a user-mode thread when a memory protection change occurs.
    2. Execute APC in the user-mode thread context, passing memory-related information to user-mode.

    APC Example for Memory Change Notification

    VOID NTAPI MemoryChangeApcRoutine(
        PKAPC Apc,
        PKNORMAL_ROUTINE *NormalRoutine,
        PVOID *NormalContext,
        PVOID *SystemArgument1,
        PVOID *SystemArgument2
    )
    {
        // Log or notify about the memory change
        DbgPrint("Memory change APC triggered\n");
    
        // Cleanup APC
        ExFreePool(Apc);
    }
    
    VOID QueueMemoryChangeApc(PEPROCESS Process)
    {
        PKAPC Apc = (PKAPC)ExAllocatePool(NonPagedPool, sizeof(KAPC));
        if (!Apc) {
            return;
        }
    
        // Initialize and queue APC
        KeInitializeApc(Apc,
                        PsGetCurrentThread(), // Thread to queue the APC to
                        OriginalApcEnvironment,
                        (PKKERNEL_ROUTINE)MemoryChangeApcRoutine,
                        NULL, // Rundown routine
                        NULL, // Normal routine
                        KernelMode,
                        NULL);
    
        // Insert APC into the queue
        if (!KeInsertQueueApc(Apc, NULL, NULL, 0)) {
            ExFreePool(Apc);
        }
    }

    Conclusion

    For monitoring memory allocations, protection changes, and page faults in Windows 11, without using methods like SSDT hooking, you can:

    • Use PsSetCreateProcessNotifyRoutineEx and PsSetLoadImageNotifyRoutine for high-level monitoring of process and image loads.
    • Use ZwQueryVirtualMemory to inspect memory regions for allocation and protection changes.
    • Use APCs to asynchronously notify user-mode applications of memory changes without impacting performance.
    • Consider ETW for detailed tracing of memory events like page faults.

    These techniques help monitor memory efficiently without causing performance bottlenecks or violating Windows’ kernel integrity protections.For memory monitoring on Windows, especially targeting virtual memory allocations, page faults, and memory protection changes, there are several safer alternatives that don’t rely on hooking or unsupported mechanisms like ALPC. Below are some methods to achieve memory monitoring at the kernel level and provide user-mode notifications without performance bottlenecks.

    Key Approaches for Memory Monitoring

    1. Process and Thread Notifications: Use PsSetCreateProcessNotifyRoutineEx and PsSetCreateThreadNotifyRoutine to monitor process and thread creation events.
    2. Page Fault Monitoring: While page faults aren’t directly exposed via a kernel API, monitoring changes in memory protections (like NtProtectVirtualMemory) could serve as a way to track suspicious memory activities.
    3. Memory Region Monitoring: You can periodically check for virtual memory allocations by inspecting the memory regions of processes using functions like ZwQueryVirtualMemory.
    4. Filter Drivers: File system filter drivers can also be used to monitor specific file-related memory operations.

    Method 1: Virtual Memory Monitoring with Virtual Address Descriptors (VADs)

    While VADs (Virtual Address Descriptors) aren’t directly accessible through public APIs, you can inspect them indirectly in the kernel. This method requires deep knowledge of the Windows Memory Manager, but is the most efficient way to monitor memory changes.

    Method 2: Using PsSetLoadImageNotifyRoutine for Monitoring Memory-Mapped Files

    If you want to monitor memory allocations related to executable images or DLLs being loaded into memory, you can use the PsSetLoadImageNotifyRoutine function. This doesn’t give complete coverage of all memory operations but can be useful for monitoring memory-mapped files (like DLLs).

    VOID NTAPI LoadImageNotifyRoutine(
        PUNICODE_STRING FullImageName,
        HANDLE ProcessId,
        PIMAGE_INFO ImageInfo
    )
    {
        if (ImageInfo->SystemModeImage) {
            DbgPrint("System Mode Image Loaded: %wZ\n", FullImageName);
        } else {
            DbgPrint("User Mode Image Loaded: %wZ in Process %d\n", FullImageName, ProcessId);
        }
    }
    
    NTSTATUS DriverEntry(
        PDRIVER_OBJECT DriverObject,
        PUNICODE_STRING RegistryPath
    )
    {
        NTSTATUS status;
    
        // Register the image load notification routine
        status = PsSetLoadImageNotifyRoutine(LoadImageNotifyRoutine);
        if (!NT_SUCCESS(status)) {
            DbgPrint("Failed to register load image notify routine\n");
            return status;
        }
    
        DriverObject->DriverUnload = DriverUnload;
        return STATUS_SUCCESS;
    }
    
    VOID DriverUnload(PDRIVER_OBJECT DriverObject)
    {
        PsRemoveLoadImageNotifyRoutine(LoadImageNotifyRoutine);
        DbgPrint("Driver Unloaded\n");
    }

    Method 3: Periodic Virtual Memory Inspections

    You can use ZwQueryVirtualMemory to inspect the memory regions of a process periodically and gather information on virtual memory allocations, protection levels, and committed pages.

    Example of Using ZwQueryVirtualMemory:

    NTSTATUS QueryMemoryRegions(HANDLE ProcessHandle)
    {
        MEMORY_BASIC_INFORMATION memInfo;
        PVOID baseAddress = NULL;
        NTSTATUS status;
    
        while (NT_SUCCESS(status = ZwQueryVirtualMemory(
                ProcessHandle, baseAddress, MemoryBasicInformation, &memInfo, sizeof(memInfo), NULL)))
        {
            DbgPrint("BaseAddress: %p, RegionSize: %llu, State: %x, Protect: %x\n",
                     memInfo.BaseAddress, memInfo.RegionSize, memInfo.State, memInfo.Protect);
    
            // Move to the next memory region
            baseAddress = (PBYTE)baseAddress + memInfo.RegionSize;
        }
    
        return status;
    }

    Method 4: ETW (Event Tracing for Windows) for Page Faults and Memory Monitoring

    ETW is a powerful mechanism in Windows that can be used for tracing low-level system events, including memory-related operations such as page faults.

    1. Enable page fault and virtual memory event tracing using ETW.
    2. Collect and analyze ETW events for memory operations.

    Example of Setting Up ETW for Memory Operations:

    Using ETW, you can set up listeners for specific system events related to memory, such as:

    • Page faults
    • Memory allocations
    • Memory protection changes

    This requires using the Windows Performance Toolkit or programmatically setting up ETW sessions via the EventTrace APIs.

    Efficient Communication to User Mode

    To handle the high volume of kernel events without performance bottlenecks, you can use one of the following mechanisms for notifying user-mode applications:

    1. I/O Completion Ports: If you have a user-mode application that interacts with your driver, I/O completion ports are an efficient way to handle asynchronous notifications for memory changes.
    2. APCs (Asynchronous Procedure Calls): APCs allow you to execute code in the context of a user-mode thread. This is useful for delivering memory change notifications in a non-blocking manner.
    3. Shared Memory: If the volume of data is extremely high, you can create a shared memory region between your kernel-mode driver and user-mode application to pass information efficiently.

    Using APC for Memory Change Notifications

    In place of ALPC, you can use APC to notify user-mode applications about significant memory changes asynchronously. Here’s an outline of how to use APCs:

    1. Queue an APC to a user-mode thread when a memory protection change occurs.
    2. Execute APC in the user-mode thread context, passing memory-related information to user-mode.

    APC Example for Memory Change Notification

    VOID NTAPI MemoryChangeApcRoutine(
        PKAPC Apc,
        PKNORMAL_ROUTINE *NormalRoutine,
        PVOID *NormalContext,
        PVOID *SystemArgument1,
        PVOID *SystemArgument2
    )
    {
        // Log or notify about the memory change
        DbgPrint("Memory change APC triggered\n");
    
        // Cleanup APC
        ExFreePool(Apc);
    }
    
    VOID QueueMemoryChangeApc(PEPROCESS Process)
    {
        PKAPC Apc = (PKAPC)ExAllocatePool(NonPagedPool, sizeof(KAPC));
        if (!Apc) {
            return;
        }
    
        // Initialize and queue APC
        KeInitializeApc(Apc,
                        PsGetCurrentThread(), // Thread to queue the APC to
                        OriginalApcEnvironment,
                        (PKKERNEL_ROUTINE)MemoryChangeApcRoutine,
                        NULL, // Rundown routine
                        NULL, // Normal routine
                        KernelMode,
                        NULL);
    
        // Insert APC into the queue
        if (!KeInsertQueueApc(Apc, NULL, NULL, 0)) {
            ExFreePool(Apc);
        }
    }

    Conclusion

    For monitoring memory allocations, protection changes, and page faults in Windows 11, without using methods like SSDT hooking, you can:

    • Use PsSetCreateProcessNotifyRoutineEx and PsSetLoadImageNotifyRoutine for high-level monitoring of process and image loads.
    • Use ZwQueryVirtualMemory to inspect memory regions for allocation and protection changes.
    • Use APCs to asynchronously notify user-mode applications of memory changes without impacting performance.
    • Consider ETW for detailed tracing of memory events like page faults.

    These techniques help monitor memory efficiently without causing performance bottlenecks or violating Windows’ kernel integrity protections.

  • Windows PE Image Format details

    Windows Portable Executable (PE) format is a file format for executables, object code, DLLs, and others used in 32-bit and 64-bit versions of Windows operating systems. The Portable Executable format is a data structure that encapsulates the information necessary for the Windows OS loader to manage the wrapped executable code. It is a key component of the Windows operating system and plays a crucial role in the execution of applications.

    Key Components of the PE Format:

    1. DOS Header and Stub:
      • DOS Header (IMAGE_DOS_HEADER): The beginning of every PE file contains a DOS header. This header is primarily for compatibility reasons, so that older systems or tools can recognize the file. The DOS header contains the “MZ” signature, and a pointer (usually at offset 0x3C) to the PE header.
      • DOS Stub: After the DOS header, there is a small DOS program that typically outputs a message like “This program cannot be run in DOS mode” when run in a DOS environment.
    2. PE Header (IMAGE_NT_HEADERS):
      • Signature: The PE header starts with a signature, which is “PE\0\0”. This signature identifies the file as a PE format file.
      • File Header (IMAGE_FILE_HEADER): Contains information such as the target machine architecture, number of sections, and a time/date stamp.
      • Optional Header (IMAGE_OPTIONAL_HEADER): Despite its name, this header is not optional. It contains important information such as the entry point, image base, section alignment, and data directories (including import and export tables).
    3. Sections (IMAGE_SECTION_HEADER):
      • The PE file is divided into sections, each with a section header. Common sections include:
        • .text: Contains the executable code.
        • .data: Contains global variables and initialized data.
        • .rdata: Read-only data, such as string literals and constants.
        • .rsrc: Contains resources like icons, menus, and dialog boxes.
        • .reloc: Contains information used for base relocation, necessary if the image is not loaded at its preferred base address.
    4. Import and Export Tables:
      • Import Table: Lists functions and libraries that the executable will import at runtime. This allows dynamic linking to DLLs.
      • Export Table: Lists functions and variables that the executable exports for use by other modules.
    5. Relocation Information:
      • If the executable cannot be loaded at its preferred base address, the relocation information allows the loader to adjust addresses within the image accordingly.
    6. Debug Information:
      • Optional debug data can be included in the PE file, which is used by debugging tools to map addresses in the file back to the original source code.
    7. TLS (Thread Local Storage):
      • TLS is used for storing data that is unique to each thread in a multi-threaded environment. The PE format includes structures for managing TLS.
    8. Resource Section:
      • Contains resources such as icons, bitmaps, and version information that the application uses.

    Usage and Importance:

    • Executable and DLL Loading: The PE format is crucial for the OS loader to understand how to map an executable file into memory, resolve imports, and start execution.
    • Security and Integrity: The PE format includes features like digital signatures to verify the integrity and origin of the file.
    • Reverse Engineering: Understanding the PE format is vital for those involved in reverse engineering, as it provides insights into how executables are structured and how they function.

    Tools for Analyzing PE Files:

    • PE Explorer: A tool for inspecting the structure of PE files.
    • Dependency Walker: Used to analyze the DLL dependencies of a PE file.
    • Resource Hacker: Allows you to view and modify resources within a PE file.

    The PE format is central to the functioning of the Windows operating system, making it a critical topic for developers, system administrators, and security professionals alike.

  • What Happens When a Process is Launched in Windows: Key Components, DLLs, APIs, and Drivers Involved

    When a process is launched in Windows, a series of complex operations involving multiple components, APIs, DLLs, and drivers occurs to ensure the program is loaded and executed properly. Here’s a detailed breakdown:

    1. Process Creation Overview

    When you launch a process (e.g., double-clicking an .exe file), the following high-level steps take place:

    1. User Mode:
      • The request to create a process is initiated by a user-mode program (e.g., Windows Explorer or a command line).
      • API calls like CreateProcess or ShellExecute are invoked, depending on how the process is started.
    2. Kernel Mode:
      • The request is handed over to the Windows kernel, which handles low-level management like memory allocation, thread creation, and process scheduling.
      • The Windows NT Kernel (ntoskrnl.exe), along with specific drivers, is responsible for setting up the environment for the new process.

    2. Detailed Breakdown of Process Creation

    Step 1: User Mode – API Calls (CreateProcess)

    The process creation begins with a user-mode API call:

    • The most common API for creating a new process is CreateProcess (part of kernel32.dll).
    • CreateProcess is a wrapper for lower-level system calls, responsible for creating the process and the primary thread.

    Other involved DLLs:

    • kernel32.dll: Provides the core Windows API functions for process creation.
    • ntdll.dll: Contains the native Windows API functions that interact with the Windows kernel.
    • advapi32.dll: Used for processes launched with additional security requirements (e.g., for impersonation or privilege setting).

    Step 2: Kernel Transition (NtCreateProcess and NtCreateThread)

    Once the CreateProcess API is called, it invokes lower-level native system calls in ntdll.dll. These native calls are critical in transitioning from user-mode to kernel-mode to facilitate process creation.

    • NtCreateProcess and NtCreateThread are called, which communicate with the Windows kernel.

    Step 3: Kernel Mode Operations (Process Manager)

    After receiving the process creation request, the Windows Kernel (ntoskrnl.exe) and Process Manager are involved. The kernel carries out several key operations:

    1. Allocation of Process Object:
      • The Process Manager creates an internal process object, which represents the new process. This object includes details like the process ID (PID), handle table, and security descriptor.
    2. Virtual Memory Setup:
      • The kernel sets up a virtual address space for the new process. It creates the appropriate page tables for memory management.
    3. Thread Creation:
      • The primary thread for the process is created using the system call NtCreateThread.
      • The thread is placed in a ready state but doesn’t run yet.
    4. Handle and Security Setup:
      • The process’s security context (user permissions, tokens) is set up using SeAssignSecurity, and system resources (like file handles) are inherited from the parent process.

    Step 4: Image Loading (ntdll.dll, psapi.dll)

    Once the process object is created, the Image Loader loads the executable file into memory.

    1. Executable File Loading:
      • The Windows PE Loader (Part of ntoskrnl.exe) loads the executable (EXE) into the process’s virtual address space. The Portable Executable (PE) format is used to define the structure of the executable.
      • It maps sections of the EXE file into memory (code, data, etc.).
    2. Loading of Required DLLs:
      • The loader loads necessary DLLs (Dynamic Link Libraries) that the program depends on. This includes the Windows core libraries:
        • kernel32.dll: Provides APIs for memory management, file handling, and process control.
        • ntdll.dll: Provides the interface to the Windows kernel.
        • user32.dll: If the process is GUI-based, this is used for user interface elements.
        • gdi32.dll: For graphics-related functions in GUI applications.
        • Other Application-Specific DLLs: Any other DLLs specified by the application.
    3. Library Linking and Base Address Fixups:
      • The loader resolves dynamic linking by finding the addresses of functions in each loaded DLL and modifying the executable’s memory to call the correct functions.
      • Relocation of code may occur if libraries need to be loaded at different base addresses than expected.

    Step 5: Execution of the Process

    Once all required components are loaded and the process environment is set up:

    • The primary thread’s instruction pointer is set to the entry point of the executable (the start function defined in the PE header).
    • The process scheduler places the thread into the runnable state, and the process starts execution.

    3. Involved Drivers and Components

    Windows uses several low-level components and drivers during the process launch:

    File System Drivers (e.g., ntfs.sys, fltMgr.sys):

    • The file system drivers handle reading the executable and its dependencies (DLLs) from disk.
    • Filter drivers (such as antivirus drivers) may intercept the executable loading to scan for malicious code before execution.

    Memory Manager (Mm.sys):

    • The Memory Manager is responsible for allocating memory for the process. It loads the executable file into the process’s virtual memory space.

    I/O Manager (I/O subsystem):

    • The I/O Manager handles any input/output requests made by the process during startup. This includes file access, inter-process communication (IPC), and interaction with hardware devices.

    Security Subsystem (lsass.exe, sspicli.dll):

    • The Local Security Authority (LSASS) enforces security policies. It ensures that the process is running under the correct user security context (based on access tokens).
    • If the process requires elevated privileges (e.g., administrator), it prompts the user or verifies credentials.

    4. Other APIs and System Calls

    Several APIs and system calls are used throughout the process creation cycle:

    • RtlCreateUserProcess: A lower-level function used by CreateProcess to create a new process object.
    • ZwCreateProcess: A kernel-mode system call that is part of process creation.
    • PsCreateSystemThread: A kernel-mode function responsible for creating the initial system thread within a process.

    5. Execution Context Initialization

    Once the process starts executing, it initializes several components:

    1. Environment Variables:
      • The new process inherits the parent process’s environment variables or initializes its own.
    2. Loader Lock:
      • The loader uses a loader lock to ensure that the process only accesses shared libraries in a thread-safe way.
    3. Startup Code Execution:
      • After initialization, the C Runtime (CRT) startup code (_start function in C programs) is invoked, which eventually calls the main function.

    Conclusion

    When a process is launched in Windows, it involves several key components and operations, including user-mode API calls like CreateProcess, kernel-mode interactions with the process manager, memory manager, and I/O manager, and the loading of the executable and its dependencies by the PE loader. Kernel drivers (like ntfs.sys, fltMgr.sys) and core system DLLs (kernel32.dll, ntdll.dll) are also heavily involved in setting up the process environment and security context.