Windows Internals
Published on 10 min read
Updated on
In this series27 min read in total
- Windows Internals
- EDR Internals
- EDR Neutralization
Follow a Windows operation from its user-mode API to kernel objects, managers, and execution constraints.
Windows Internals becomes tedious when presented as a list of structures. This article instead follows one operation: an application thread requests access to a resource, the system translates the request, validates its context, routes a request, and retains the state required to execute it.
At each layer, the path answers three questions:
- which component owns the contract;
- which data crosses the boundary;
- which conclusions are stable, and which depend on the observed build.
Crossing the user-mode and kernel-mode boundary
An application runs in user mode, inside an isolated address space. It uses libraries that expose Win32 or more specialized interfaces. Those interfaces can validate arguments, adapt formats, and, when the operation requires a kernel service, reach a Native API routine exported by ntdll.dll.
The system transition changes privilege level, but it does not turn the application into kernel code. ntoskrnl.exe resumes execution at a controlled entry point, validates arguments according to the requested service, and invokes the relevant manager: objects, processes, memory, input/output, or configuration.
The Hardware Abstraction Layer (HAL) isolates some platform details, especially around interrupts and hardware access. Drivers participate in device stacks or call supported kernel interfaces. Running in kernel mode gives them high impact, but does not exempt them from Interrupt Request Level (IRQL), memory, or object contracts.
This architecture establishes where privilege transitions occur. It does not yet describe the durable state on which the kernel operates. Following an operation over time requires separating process and thread objects from their accompanying user-mode structures.
Processes and threads: separating roles
EPROCESS is the opaque process object used by the kernel. Microsoft documents its role and supported routines that accept a pointer to it, but not a contract allowing drivers to modify its fields freely. Offsets displayed by a debugger are therefore observations specific to the loaded symbols and build.
Conceptually, EPROCESS carries executive-level process state and embeds a KPROCESS associated with dispatching and scheduling. A thread is represented by an ETHREAD object that embeds a KTHREAD for kernel execution state. These relations help explain the model; their layouts are not a stable driver ABI.
The Process Environment Block (PEB) and Thread Environment Block (TEB) reside in user mode. The PEB exposes information related to the process and loader; the TEB carries per-thread state. A security tool can read them in some contexts, but their user-mode location means they do not replace the authority of kernel objects.
Handles connect the process to objects such as files, events, sections, or registry keys. A handle is not the object itself: it is an entry in a handle space associated with granted rights. The process primary token also supplies security context for many access checks.
These structures describe who executes and which objects it can reach. They do not say when a thread actually obtains a processor. The next mechanism is therefore the scheduling lifecycle.
Scheduling: from ready thread to wait
Windows uses priority-based preemptive scheduling. A ready thread is eligible to execute. Once dispatched to a processor it runs; preemption can make it ready again. Waiting for I/O, a dispatcher object, or a timer removes it from the processor until the condition is satisfied.
Thread priority and current IRQL are different concepts. Priority helps the scheduler choose among ready threads. IRQL is a per-processor execution level that masks some interrupts and constrains permitted kernel operations. An ordinary thread runs at PASSIVE_LEVEL even when its scheduling priority is high.
Scheduling explains when code runs, but not where its instructions and data reside. Windows interposes a virtual address space and memory manager for that purpose.
Virtual memory: translating an address and recovering content
Each process operates on virtual addresses. Architecture-defined page tables translate those addresses into physical-memory frames while a page is resident. The Page Frame Number (PFN) database tracks physical-frame state; a process working set describes the pages currently resident for that process under memory-manager policy.
An invalid entry does not necessarily mean that the data is absent. A page fault can be satisfied from an in-memory list, a private page stored in the page file, or the bytes of a mapped file. The exact source depends on the mapping type and current state.
The memory manager therefore establishes how a buffer becomes available to the CPU. It does not by itself transport a request to the file system or hardware. That transport belongs to the input/output model.
Input/output: request down, completion up
To open a file, an application can call CreateFileW. The API is exported by Kernel32.dll, declared in fileapi.h, and linked through Kernel32.lib; depending on the build, the export can forward its implementation to KernelBase.dll. The corresponding Native API, NtCreateFile, is exported by ntdll.dll and declared in winternl.h.
After the system transition, the I/O manager in ntoskrnl.exe builds a request. In the Windows Driver Model (WDM), this is generally represented by an I/O Request Packet (IRP). An open operation carries the IRP_MJ_CREATE major code. Each driver in the stack receives parameters for its level and can process or pass the request downward.
A file path can traverse minifilters, the file system, volume drivers, and storage drivers. This list is conceptual: actual components depend on configuration, device type, and operation. The request travels toward the device; status, byte count, and any data return through completion routines.
Direct Memory Access (DMA) lets some devices transfer data without making the CPU copy every byte. Memory Descriptor Lists (MDL) and mapping mechanisms describe buffers according to driver and platform contracts.
The I/O model explains how a request reaches its provider. It is not enough to decide whether the caller has the required rights. Before returning a useful handle, Windows must compare caller security context with object policy.
Access checks: computing handle rights
An access token contains the user’s and groups’ Security Identifiers (SID), as well as privileges. A security descriptor identifies the owner of a securable object and can contain a Discretionary Access Control List (DACL), which allows or denies rights, and a System Access Control List (SACL), which configures auditing.
The check compares desired access with caller context and object rules. Other mechanisms can participate, including privileges, Mandatory Integrity Control, and object-type-specific checks. On success, the returned handle carries the rights actually granted; it does not automatically confer every possible right on the object.
WinDbg observation: an internal field is not a contract
The first view establishes the general WinDbg session context.
The !process 0 0 cmd.exe command recovers the process-object address for cmd.exe.
dt nt!_EPROCESS Token queries symbols for the current build. The visible offset must never be reused as a universal constant.
The same enumeration finds the System process object, used here only to compare two fields.
The field has type _EX_FAST_REF, an object reference combining an aligned pointer and reference-count bits. Reading only the address without understanding those bits produces an incorrect interpretation.
The next capture shows state after an experimental write. It demonstrates that a kernel debugger can modify the observed layout, not that the layout is a supported interface.
Execution then resumes so consequences can be measured on the target.
This case shows why an internal offset must not be confused with an API. One central configuration resource remains: the registry, whose logical names connect to hives and specialized callbacks.
Registry: from logical views to hives
The registry organizes keys and values into hierarchical views. A hive is a logical group of keys, subkeys, and values with supporting files loaded into memory. Major system hives use files under %SystemRoot%\System32\Config; user profiles have separate files.
Log files participate in consistency and recovery. Cells, indexes, and other internal structures explain a build’s implementation, but applications should use documented APIs instead of depending on their layout.
RegOpenKeyExW and RegSetValueExW are exposed by Advapi32.dll, declared in winreg.h, and linked through Advapi32.lib. They reach Native API services in ntdll.dll, then the Configuration Manager in ntoskrnl.exe.
A filtering driver can call CmRegisterCallbackEx. The routine executes from ntoskrnl.exe, is declared in wdm.h, and is linked through NtosKrnl.lib. It registers a driver-supplied function and altitude. The Configuration Manager then delivers distinct REG_NOTIFY_CLASS values before or after operations. Available data and permitted changes depend on the exact class.
The registry adds configuration state and telemetry. It does not remove the kernel-execution constraints that apply to the callback. Understanding which routines and memory remain safe at that moment requires IRQL.
IRQL and synchronization: context is part of the contract
Interrupt Request Level (IRQL) is per-processor state. Raising IRQL masks some interrupts at lower or equal levels and restricts safe operations. It does not measure a driver’s “power”; it describes execution context.
At PASSIVE_LEVEL, a routine can wait and access pageable memory when its own contract permits. At DISPATCH_LEVEL and above, it must not perform a blocking wait or cause a page fault. Device IRQLs (DIRQL) serve device-interrupt routines. Exact values depend on architecture; HIGH_LEVEL symbolically names the highest level.
KeAcquireSpinLock is a macro declared in wdm.h and linked through Hal.lib under the WDK requirements. It raises the processor to DISPATCH_LEVEL, acquires the spinlock, and returns the old IRQL to the caller. The protected section must remain nonpageable and very short.
An executive resource solves a different problem. ExAcquireResourceSharedLite and ExAcquireResourceExclusiveLite provide a reader-writer lock that can wait. These routines execute from ntoskrnl.exe, are declared in wdm.h, and are linked through NtosKrnl.lib; their contracts require a compatible IRQL and management of normal kernel APC delivery. They are not interchangeable with a spinlock at DISPATCH_LEVEL.
Conclusion
Windows internals form a chain of contracts. An API prepares a request, the Native API crosses the boundary, a manager selects objects and rights, requests move through stacks, and scheduling, memory, and IRQL constrain execution.
This foundation makes the next two articles readable without repeating the same definitions: the EDR internals technical review applies these contracts to sensors, while EDR Neutralization examines the gap between loading trust and authorization in a driver protocol.
References
- Microsoft, Windows kernel opaque structures and Thread Priorities.
- Microsoft, Memory management for Windows drivers and Map Registers.
- Microsoft,
CreateFileW,NtCreateFile, and Overview of the Windows I/O Model. - Microsoft, Parts of the Access Control Model.
- Microsoft, Registry Hives, Filtering Registry Calls, and
CmRegisterCallbackEx. - Microsoft, Managing hardware priorities,
KeAcquireSpinLock, andExAcquireResourceSharedLite. - Pavel Yosifovich, Mark Russinovich, David Solomon, and Alex Ionescu, Windows Internals, 7th edition, Microsoft Press.






