Windows Process Creation Internals & PEB

Objective: Deeply understand how Windows creates new processes, detailing the internal workings of the CreateProcess API, kernel object management, memory mapping, and the structure and role of the Process Environment Block (PEB). This is essential knowledge for analyzing and understanding malware behavior, reverse engineering, and advanced debugging.


Introduction

Process creation on Windows is a sophisticated, multi-step procedure involving extensive kernel and user-mode coordination. At the center of this operation is the CreateProcess() API, which initializes process structures, allocates memory, maps executables, and prepares environment variables.

Each Windows process also maintains a Process Environment Block (PEB), a crucial data structure that contains runtime information about the loaded modules, command-line arguments, and more. The PEB is frequently leveraged by attackers and defenders for various advanced techniques.

Windows-Process-Creation

High-Level CreateProcess Flow

The general steps when calling CreateProcess():

  1. User-mode API Call:
    Application invokes kernel32!CreateProcessW or similar.
  2. Kernel Transition (ntdll):
    CreateProcessW invokes ntdll!NtCreateUserProcess.
  3. Kernel Mode Initialization (ntoskrnl):
    • Kernel creates EPROCESS object.
    • Initializes Virtual Address Descriptor (VAD) structures.
    • Maps ntdll.dll into new process address space.
  4. PE File Loading:
    • PE loader maps executable image sections.
    • Resolves imports and relocations.
    • Sets initial execution context (thread, stack, registers).
  5. Subsystem Notification (CSRSS):
    • Subsystem server creates structures for console/GUI.
  6. Initial Thread Execution:
    • Execution begins at the AddressOfEntryPoint.

Detailed Step-by-Step Flow

Step 1: User-mode API Invocation

When an application wants to start a new process, it uses:

BOOL CreateProcessW(
  LPCWSTR lpApplicationName,
  LPWSTR  lpCommandLine,
  LPSECURITY_ATTRIBUTES lpProcessAttributes,
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
  BOOL    bInheritHandles,
  DWORD   dwCreationFlags,
  LPVOID  lpEnvironment,
  LPCWSTR lpCurrentDirectory,
  LPSTARTUPINFO lpStartupInfo,
  LPPROCESS_INFORMATION lpProcessInformation
);

This call eventually resolves down to an NTDLL syscall:

NtCreateUserProcess(&ProcessHandle, &ThreadHandle, ..., &ProcessParameters, ...);

Step 2: Kernel-side Initialization

Kernel (ntoskrnl) creates key kernel structures:

  • EPROCESS: Process kernel object
  • ETHREAD: Initial thread kernel object
  • VAD Tree: Virtual Address Descriptors for memory management
  • Initializes security tokens and handles

Step 3: PE Image Loading

Kernel PE loader:

  • Maps PE executable sections (.text, .data, etc.) into memory.
  • Handles relocations and import resolutions (IAT resolution).
  • Initializes the stack, heap, and default libraries (ntdll.dll).

Step 4: User-mode initialization (ntdll)

Upon kernel returning control, ntdll.dll runs user-mode initializations:

  • Executes TLS (Thread Local Storage) callbacks
  • Sets up user-mode stack and heap structures
  • Runs CRT (C Runtime) initialization (mainCRTStartup)

Step 5: Subsystem Initialization (CSRSS)

  • Windows subsystem (csrss.exe) notified to handle GUI or console session management.

Step 6: Main Thread Execution

  • Execution control transferred to the PE fileโ€™s AddressOfEntryPoint.

Process Environment Block (PEB)

The PEB is a crucial process structure located in user mode memory (fs:[0x30] on 32-bit, gs:[0x60] on 64-bit Windows).

typedef struct _PEB {
    BYTE Reserved1[2];
    BYTE BeingDebugged;
    BYTE Reserved2[1];
    PVOID Reserved3[2];
    PPEB_LDR_DATA Ldr;                // Loaded modules
    PRTL_USER_PROCESS_PARAMETERS ProcessParameters; // Command-line, env
    BYTE Reserved4[104];
    PVOID Reserved5[52];
    PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
    BYTE Reserved6[128];
    ULONG SessionId;
} PEB, *PPEB;

Key Fields:

  • BeingDebugged: Indicates if a debugger is attached.
  • Ldr: Contains loaded module information (PEB_LDR_DATA).
  • ProcessParameters: Command line, environment variables, startup directory, window settings.

PEB_LDR_DATA Structure

This structure points to the loaded modules (DLLs) in the process:

typedef struct _PEB_LDR_DATA {
  ULONG Length;
  BYTE Initialized;
  PVOID SsHandle;
  LIST_ENTRY InLoadOrderModuleList;
  LIST_ENTRY InMemoryOrderModuleList;
  LIST_ENTRY InInitializationOrderModuleList;
  PVOID EntryInProgress;
} PEB_LDR_DATA, *PPEB_LDR_DATA;

These linked lists (InLoadOrderModuleList, etc.) contain information about every DLL mapped into the process memory, crucial for module enumeration.


RTL_USER_PROCESS_PARAMETERS Structure

Contains the runtime parameters of the process:

typedef struct _RTL_USER_PROCESS_PARAMETERS {
    ULONG MaximumLength;
    ULONG Length;
    ULONG Flags;
    ULONG DebugFlags;
    HANDLE ConsoleHandle;
    ULONG ConsoleFlags;
    HANDLE StandardInput;
    HANDLE StandardOutput;
    HANDLE StandardError;
    UNICODE_STRING CurrentDirectoryPath;
    HANDLE CurrentDirectoryHandle;
    UNICODE_STRING DllPath;
    UNICODE_STRING ImagePathName;      // Path to the executable
    UNICODE_STRING CommandLine;        // Process arguments
    PVOID Environment;                 // Environment block
    ULONG StartingX;
    ULONG StartingY;
    ULONG CountX;
    ULONG CountY;
    ULONG CountCharsX;
    ULONG CountCharsY;
    ULONG FillAttribute;
    ULONG WindowFlags;
    ULONG ShowWindowFlags;
    UNICODE_STRING WindowTitle;
    UNICODE_STRING DesktopInfo;
    UNICODE_STRING ShellInfo;
    UNICODE_STRING RuntimeData;
    RTL_DRIVE_LETTER_CURDIR CurrentDirectories[32];
    ULONG EnvironmentSize;
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;

Common Malware & Defense Uses of PEB

Malware Uses:

  • Anti-debugging: Check BeingDebugged flag.
  • Module hiding: Manipulate PEB_LDR_DATA to hide loaded DLLs from tools like Process Explorer or debuggers.
  • Process injection: Read remote process PEB to locate modules and perform injection.

Defense Uses:

  • Forensics: Analyzing PEB structures to detect hidden modules or unusual command-line arguments.
  • Behavioral detection: Monitoring PEB accesses can indicate stealthy operations (like hiding loaded modules).

Practical Inspection of PEB

WinDbg Commands:

  • Inspect PEB:
!peb
  • View loaded modules:
lm
  • Dump PEB structure directly:
dt _PEB @$peb

Summary

  • Process creation (CreateProcess) is complex, involving kernel and user-mode coordination.
  • Key kernel objects (EPROCESS, ETHREAD) manage process lifecycle and resources.
  • The PEB contains vital runtime details and is heavily utilized by both malware and security tools.
  • Deep understanding aids in reverse engineering, malware analysis, and debugging.

0 0 votes
Article Rating
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments