Windows Memory Forensics Series — Part 03: Process Creation Internals
Parts 01 and 02 covered how to find processes and validate what’s loaded inside them. This part goes one level deeper: how a process actually comes into existence in the first place — from the double-click to the first executed instruction.
Understanding the creation flow in detail is what makes the forensic artifacts in Parts 01 and 02 make sense: why EPROCESS looks the way it does, why the PEB exists at all, and how the PE loading process, the VAD Tree, and memory paging all fit together.
1. What Happens When You Double-Click notepad.exe
Step 1: Request Execution (User Mode)
You double-click the file. The shell (e.g. explorer.exe) calls a function named CreateProcess.
Step 2: Create the EPROCESS (Kernel Mode)
The request drops into the kernel, which builds a data structure in its own memory called EPROCESS.
- Purpose: this is the process’s official record — it holds the Process ID (PID), the security structure (Access Token), and which process is the parent.
Step 3: Allocate the Virtual Address Space
Windows builds a virtual address space for the process (e.g. 4GB on a 32-bit system, or a vastly larger space on 64-bit).
- Purpose: give the process an empty address space, completely independent from every other process — without reserving any physical RAM yet.
Step 4: Read the PE Header and Map the Sections
Windows opens the .exe file on disk and reads its structure (the PE Header).
Step 5: Resolve Imports
Windows inspects the Imports section and loads the required DLLs (e.g. kernel32.dll), writing the real function addresses into a table called the IAT (Import Address Table).
Step 6: Create the Primary Thread and Start Execution
Windows creates an ETHREAD and sets up the CPU to begin executing code at the address written in AddressOfEntryPoint.
2. What Is EPROCESS, Exactly?
EPROCESS is a kernel data structure in Windows representing a process from the kernel’s point of view.
So when Windows creates a process such as:
notepad.exe
PID = 4200the kernel holds an object/structure roughly called:
EPROCESSrepresenting that process and holding the information Windows needs to manage it.
2.1 EPROCESS — The Full Picture
EPROCESS
│
├── Object / Kernel Management
│ ├── Process Object Header
│ ├── Object information
│ └── Reference / handle-related information
│
├── Process Identity
│ ├── UniqueProcessId
│ ├── Image/File information
│ ├── Process flags
│ └── Process state
│
├── Process Relationships
│ ├── ActiveProcessLinks
│ ├── Parent Process
│ ├── Session information
│ └── Job information
│
├── Security
│ ├── Token
│ ├── Security context
│ └── Privilege-related information
│
├── Execution
│ ├── Threads
│ ├── Thread list
│ ├── Scheduling information
│ └── Process state
│
├── Memory Management
│ ├── Process Address Space
│ ├── Directory Table Base
│ ├── VAD information
│ ├── Working Set information
│ └── Memory-management structures
│
├── Handles / Objects
│ ├── Handle table
│ └── Object-related information
│
├── I/O
│ ├── I/O-related information
│ └── Device / file interaction state
│
├── Loader / Image Information
│ ├── Image file information
│ ├── Section information
│ └── Image-related metadata
│
└── Accounting / Statistics
├── CPU time
├── Memory usage
├── Quotas
└── Other accounting informationEPROCESS structures are not isolated from each other. Windows links them together in a linked list inside the kernel, so it can walk from one process to the next — this is the same list pslist (Part 01) traverses.
2.2 The Idea, Simplified
Imagine three processes:
explorer.exe PID 1000
notepad.exe PID 2000
chrome.exe PID 3000Windows can keep them connected like this:
EPROCESS EPROCESS EPROCESS
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ explorer │ │ notepad │ │ chrome │
│ PID 1000 │ │ PID 2000 │ │ PID 3000 │
│ │ │ │ │ │
│ ActiveLinks │──────►│ ActiveLinks │──────►│ ActiveLinks │
└─────────────┘ └─────────────┘ └─────────────┘
▲ │
└──────────────────────────────────────────┘But in reality Windows uses a doubly linked list — every node has both:
Flink
Blink2.3 Flink and Blink
EPROCESS A
│
├── Flink ──────► EPROCESS B
│
└── Blink ◄───── EPROCESS previousSo every process can find:
- what comes after it, via
Flink - what comes before it, via
Blink
Flink
A ─────────────────► B
▲ │
│ │ Flink
│ ▼
└──────────────────── C Blink2.4 Which Field Connects Them?
In modern Windows, EPROCESS contains a field called:
ActiveProcessLinksof type:
LIST_ENTRYand LIST_ENTRY itself is:
typedef struct _LIST_ENTRY {
struct _LIST_ENTRY *Flink;
struct _LIST_ENTRY *Blink;
} LIST_ENTRY;So conceptually:
EPROCESS
│
├── UniqueProcessId
│
├── Token
│
├── ...
│
└── ActiveProcessLinks
├── Flink
└── BlinkActiveProcessLinks is exactly what places an EPROCESS into the Active Process List.
2.5 Where Does the Kernel Start?
There is a head for the list, from which Windows begins its traversal:
PsActiveProcessHead
│
▼
EPROCESS A
│
Flink
▼
EPROCESS B
│
Flink
▼
EPROCESS C
│
Flink
▼
PsActiveProcessHeadIn other words:
PsActiveProcessHead
↓
explorer
↓
notepad
↓
chrome
↓
...This is fundamental to understanding how pslist works (see Part 01).
3. What Is the PE Header?
Think of the PE Header as the program’s “ID card” or “specification sheet.” The moment you double-click an .exe, the OS reads this card to understand the file's dimensions, where to place it in RAM, and how to run it.
3.1 The DOS Header
The first data structure encountered at the very start of any Windows executable (.exe or .dll).
- Fixed size: 64 bytes (
0x40) - Located at offset
0x00 - Contains many legacy fields (used by old MS-DOS systems), but modern Windows only cares about two of them:
1. The Magic Signature: e_magic
- Location: the very start of the file, offset
0x00 - Value: always
0x5A4Din hex, equal to the charactersMZ(named after programmer Mark Zbikowski, who designed the format) - Purpose: Windows reads these two characters to confirm the file is actually a valid Windows executable; without
MZ, the system refuses to run it
2. The Golden Pointer: e_lfanew
- Location: at the end of the DOS Header, offset
0x3C - Purpose: holds a number (address/offset) pointing directly to the start of the real PE Header (the NT Headers) inside the file
- Why it matters: without this pointer, Windows wouldn’t know exactly where the PE Header begins, since the space between the DOS Header and the PE Header can vary in size from file to file
3.2 The NT Headers (The Beating Heart)
The most important structure, containing 3 parts:
- Signature — the PE-specific signature, the characters
PE\0\0 - File Header — basic information about the file itself:
- Processor architecture (32-bit or 64-bit?)
- Number of sections inside the file
- File creation date/time
- Optional Header — despite the name “optional,” it’s mandatory in
.exefiles: AddressOfEntryPoint— the address where the processor begins executing codeImageBase— the preferred address where the file wants to be loaded in memorySizeOfImage— the total size the file occupies once unfolded in memory
3.3 The Section Table
Works like a conversion map that tells Windows how to take the data written in the file on disk and place it correctly in memory (RAM). Think of the Section Table as containing a “data form” for each section (like .text or .data), with 4 key parameters:
The 4 Key Parameters Per Section
Get Reyadjr0x1’s stories in your inbox
Join Medium for free to get updates from this writer.
Parameter Technical Name Simple Function Location on disk PointerToRawData Where the section starts inside the .exe file on disk Size on disk SizeOfRawData The real size of the section's data on disk Location in memory VirtualAddress (RVA) The address the section will land at in memory (relative to the program's base address) Size in memory VirtualSize The size the section will occupy in virtual memory
3.4 How Windows Maps a Section Like .text Into Memory
Let’s apply the formula to a practical example:
- Program base address (ImageBase): suppose Windows decides to load the program at address
0x400000in memory - Reading section data from the table: Windows looks at the Section Table row for
.textand finds:
VirtualAddress = 0x1000PointerToRawData = 0x400
- The mapping process:
- Windows goes to the disk at location
0x400and reads the instruction code - To calculate its final location in memory, it does a simple addition
- As a result, Windows moves the code and places it at address
0x401000in memory
3.5 Security Permissions (Characteristics)
The Section Table doesn’t just define addresses — it also gives each section specific access permissions:
.textsection: gets Execute/Read permission (execute and read only), so the processor can execute the code, and no program can modify it.datasection: gets Read/Write permission, used to store variables
3.6 The Five Loading Stages
1. Headers Parsing
- What happens: the OS opens the file and reads the main parts in order: DOS Header → PE Header → Optional Header
- Goal: confirm the file is valid and intended for Windows, and learn the basic instructions for its size and location
2. Sections Table Parsing
- What happens: the system reads the Section Table to verify its validity and boundaries
- Goal: identify the sections present (like
.textand.data) and how much space and what permissions each needs
3. Mapping
- What happens: Windows builds the virtual address space and starts moving each section from disk into its appropriate address in memory, based on
ImageBaseandVirtualAddress - Goal: unfold the file’s parts inside RAM in an organized way
4. Imports Resolution
- What happens: Windows looks at the Imports section (e.g.
kernel32.dlloruser32.dll), loads these libraries into memory, and writes the real function addresses into a table called the IAT (Import Address Table) - Goal: connect the program to the helper functions it needs from the system (e.g. a function to open a window or show a message)
5. Execution
- What happens: the CPU jumps directly to the address written in
AddressOfEntryPointand executes the first instruction there - Result: the program starts running and its window appears
4. The PEB (Process Environment Block)
PEB stands for Process Environment Block — a data structure representing a process’s information in User Mode. Windows creates this structure for every running process so it can hold that process’s runtime information without constantly having to go back into Kernel Mode.
4.1 Key Elements of the PEB Structure
1. BeingDebugged
A one-byte field. Its value is 1 if the process is being traced by a debugger, and 0 if running normally. Attackers and malware check this field to apply Anti-Debugging techniques.
2. Ldr — PEB_LDR_DATA
A pointer to a structure containing a list of all modules and external DLLs loaded into the process. This list is a doubly linked list showing DLL addresses and their location in memory.
3. ProcessParameters — RTL_USER_PROCESS_PARAMETERS
A structure holding the process’s startup parameters, such as:
- Executable file path
- Command line
- Current directory
- Environment variables
4. ProcessHeap
A pointer to the process’s main heap, used for dynamic memory allocation.
5. ImageBaseAddress
A pointer to the address where the main .exe file is loaded within the process's virtual memory.
4.2 _EPROCESS Is Not a Direct "Container" of the PEB
The _EPROCESS object in the kernel does not contain the full PEB structure inside it — it only contains a pointer to the PEB's address in User Space:
- In Kernel Space: the
_EPROCESSstructure contains a field calledPeb, of type pointer (struct _PEB*) - In User Space: the actual memory where the PEB structure is built
6. The VAD Tree (Virtual Address Descriptor Tree) — In Depth
The VAD Tree is the fundamental data structure the kernel in Windows uses to track and count every memory region reserved inside a process’s Virtual Address Space.
Imagine the process’s Virtual Address Space is a huge piece of land. When the process wants to reserve a plot (carve out memory for Code, Stack, or Heap), the OS builds a land registry recording:
- Where does this plot start and where does it end, address-wise?
- What are this plot’s permissions? (Read-Only, Write, or Execute?)
That land registry, at the kernel level, is the VAD Tree.
6.1 Key Data Stored in Each Tree Node
Each node inside the VAD tree represents a reserved memory region and contains:
1. Addresses (Starting & Ending VPN)
Defines the start and end virtual memory address of the region reserved.
2. Allocation Type
Indicates whether the space is:
- Private Memory: memory private to this process only (like the Heap and Stack)
- Mapped File / Section: memory tied to a file on disk (like an
.exefile or DLL files)
3. Protection Flags
Define what’s permitted on this region, such as:
PAGE_READONLYPAGE_READWRITEPAGE_EXECUTE_READWRITE(a very dangerous permission, because it allows writing and executing code in the same region at the same time)
7. What Is a Page, Simply Put?
Windows and the CPU don’t treat RAM as a random sea of bytes, and they don’t reserve memory byte-by-byte. Instead, they divide both virtual and physical memory into small, fixed-size blocks.
- The standard size of a single Page on most systems is 4 Kilobytes (4096 bytes)
- The Page is the smallest building-block unit the CPU and OS can reserve, move, or apply security permissions to (Read, Write, Execute)
7.1 Analogy: Being Inside the RAM Giant
Imagine RAM as a giant notebook:
The Page (a page in the notebook): one sheet of the notebook (fixed size, 4KB)
- You can’t tear off half a sheet and write on it — you either use the whole sheet or leave it empty
The PTE (Page Table Entry): the index tag glued to the top of that sheet
- This tag says: “Where is this sheet actually located in real RAM? And is it allowed to be written to, or read-only?”
7.2 The Complete Architecture With the VAD Tree
To tie the whole picture together so it never gets confusing again:
- The VAD Node (tree node): represents a large space (e.g. a program requests 1 Megabyte). That space contains 256 pages
- The Pages: that 1 Megabyte gets split into 256 small chunks, each 4KB
- The PTE table (the tags): contains 256 entries (PTEs), each entry holding one page and responsible for translating its address and monitoring its current permissions in front of the CPU
8. Memory Management Mechanics
Imagine you want to reserve a table at a big restaurant:
8.1 Step One: Initial Reservation (MEM_RESERVE)
- What happens? You call the restaurant and say: “I want to reserve a table for 10 people at 8.”
- What does the restaurant do? It puts your name in the book: “Table 5 is reserved for so-and-so.”
- In memory: Windows records in the VAD Tree that this address range (e.g. from
0x1000to0x5000) is reserved for your program. - The reality: no food is put on the table, and no space was actually pulled from real RAM — just “a name on paper.”
8.2 Step Two: Commitment (MEM_COMMITTED)
- What happens? You confirm with the restaurant and say: “Prepare the order and the cost, we’re on our way.”
- What does the restaurant do? It ensures it has enough food in the kitchen for 10 people, but hasn’t plated the food yet!
- In memory: Windows checks RAM and the Page File and guarantees there’s enough free space for this page if you decide to use it, and sets the permissions (like Read/Write).
- The reality: real RAM still hasn’t had anything placed into it!
8.3 Step Three: Actual Access (Page Fault, then Demand Paging)
- What happens? The moment the guest sits down and reaches out to eat (i.e., the program tries to read or write to memory for the first time):
- The CPU: checks the PTE table and finds the page empty, with no code actually backed by real RAM!
- Reaction: the CPU raises an alarm called a Page Fault
- The Kernel steps in: the kernel hears the alarm, goes and opens RAM, grabs a real free physical frame, links it to that address, and updates the PTE to make it valid (
Valid = 1) - From this moment on: the data is actually inside RAM and you can use it directly!
Why This Matters for the Investigation
Everything explained in this part maps directly onto the forensic artifacts covered in Parts 01 and 02:
- The
EPROCESS/ActiveProcessLinkswalk is exactly whatpslisttraverses, and exactly what DKOM manipulates - The PEB’s
ImageBaseAddressfield is exactly the valueldrmodulescompares against the VAD - The VAD Tree’s
ProtectionandTypefields are exactly whatmalfindandldrmodulesinspect to flag suspicious memory regions





