In this video we walk through how process trees are visualized in Windows, starting with what tools like Process Explorer display, then moving step by step into coding our own tree in C++. We discuss why some processes are shown without parents, how process IDs are reused, and why comparing creation times is essential.
Why This Matters for TrainSec Students
Being able to construct and analyze a process tree is a fundamental skill for students of Windows internals and security research. Malware often hides by altering its parent process or exploiting PID reuse. Forensics and reverse engineering rely heavily on understanding which process started another and how relationships are tracked. By building your own tree in code, you gain practical knowledge of how Windows handles process management, which is directly applicable in security investigations and debugging tasks.
Questions and Answers from the Video
What is a process tree?
A process tree is a structured way to represent the running processes in Windows as parent–child relationships. Instead of a flat list of processes, the tree shows which process created which. Tools such as Process Explorer provide this by default. At the top level there are several roots, such as System, Registry, and Winlogon. Each root has its own descendants, forming smaller subtrees. Understanding this structure is important because it reflects how processes inherit properties from other processes, hinting at which process may have created them.
Why are there multiple roots instead of one tree?
Unlike some systems where everything is connected to a single “init” process, Windows allows multiple roots. For example, System, Csrss, and Wininit appear side by side. One way to think about it is to imagine a hidden node that is the “super-parent” of all these roots. In practice, though, each root starts its own tree. This explains why process explorers show several left-justified processes at the top level.
What is the difference between a parent process and a creator process?
The creator is the process that actually called the API to start it. Usually the creator and parent are the same, but Windows does allow them to differ. When this happens, certain properties like the current working directory are inherited from the parent, not necessarily the creator. This distinction matters for analysts: a process may look like it belongs under one parent but was actually started by another.
Why do some processes appear left-justified with no parent?
When a process’s recorded parent no longer exists in the system, tools have no information to display, so they place the process at the root level. For example, Explorer may appear parentless because its parent process terminated long ago. The parent ID is still stored, but since that ID no longer points to a live process, the program must treat it as if the process has no parent.
Can a process ID be reused?
Yes. When a process ends, its ID can be recycled by Windows and given to another process. This creates the risk that a child process might reference a parent ID that has since been reassigned to a completely unrelated process. Without additional checks, tools would mistakenly connect the child to the wrong parent.
How do tools avoid confusion from reused process IDs?
Process Explorer and similar tools solve this by checking creation times. If the supposed parent’s creation time is later than the child’s, then the relationship is invalid, and the child must be treated as parentless. This ensures that ID reuse does not break the accuracy of the process tree.
How can we programmatically list processes?
In Windows, the ToolHelp API provides functions to take a snapshot of the current system processes. Using CreateToolhelp32Snapshot, Process32First, and Process32Next, a program can iterate through all processes and capture information such as process ID, parent process ID, and executable name. This snapshot is the foundation for building a custom tree.
What information should we store about each process?
Each process record should contain the process ID, the parent ID, and the executable name for identification. To represent the hierarchy, it should also hold a list of its children. In C++, this is conveniently expressed with a structure that contains these fields plus a vector for child pointers.
How do we safely manage these structures in C++?
Managing memory manually with new and delete is error-prone. Instead, Pavel uses unique_ptr, a smart pointer that automatically frees memory when it goes out of scope. This ensures that when a process structure is no longer needed, the memory is released, preventing leaks and dangling pointers.
$1300
$1040 or $104 X 10 payments
Windows Internals Master
Broadens and deepens your understanding of the inner workings of Windows.
How do we attach processes to their parents in code?
The program builds a map keyed by process IDs. Each new process is looked up by its parent ID in this map. If the parent is found, the process is added as a child of that parent. If no parent is found, the process is stored in the list of root nodes. This mirrors the logic of tools like Process Explorer.
How do we display the process tree?
The program defines a function DisplayTree that recursively prints each process with indentation based on its depth in the tree. The function first prints the current process name and ID, then calls itself on the list of children, increasing the indentation. This makes the output look like the familiar tree view shown in graphical tools.
How do we verify a real parent beyond checking IDs?
The program includes a function GetStartTime that queries the start time of a process using OpenProcess and GetProcessTimes. By comparing the start time of the supposed parent to that of the child, the program can confirm whether the relationship is valid. If the parent started later than the child, the link is rejected, and the child is considered a root.
What units are used for process start times?
Windows records times in 100-nanosecond intervals, measured since January 1, 1601. While the numbers are unusual, they are consistent across processes. For the purpose of verifying parent–child relationships, only the relative values matter.
What happens if OpenProcess fails for a process?
Sometimes a process cannot be opened, either because of security restrictions or because it terminated between snapshot and query. In that case, the program returns zero to indicate failure. When this happens, the program defaults to trusting the parent ID, though this may not be fully accurate.
Pick Your Path and Join the Elite

Provides the necessary knowledge, understanding, and tools to be a successful Windows OS researcher.
Why is recursion effective for this task?
Recursion naturally fits tree traversal. Each process displays itself, then recursively calls the function on its children. The call stack keeps track of indentation levels automatically. This allows the code to remain simple and elegant even when the tree has many nested levels.
What is the final outcome of the code?
The final program produces a process tree almost identical to Process Explorer’s view. It correctly shows roots and children, accounts for missing parents, and defends against PID reuse. This demonstrates that with only the ToolHelp API and some careful logic, you can replicate what advanced tools do under the hood.
Keep Learning with TrainSec
This content is part of the free TrainSec Knowledge Library, where students can deepen their understanding of Windows internals, malware analysis, and reverse engineering.Subscribe for free and continue learning with us: https://trainsec.net/library
Liked the content?
Subscribe to the free TrainSec knowledge library, and get insider access to new content, discounts and additional materials.