Windows OS Architecture

By Debraj Basak·Apr 25, 2025 · Updated Aug 1, 2026·15 min readWindows Internals

Objective: Build an accurate mental model of the Windows NT stack – privilege rings, the HAL, ntoskrnl.exe, the Executive, the object model, the syscall path, and the user-mode subsystem layer – so you can place any piece of code, any attack primitive, and any defensive sensor exactly where it lives in the architecture, and understand why the user/kernel boundary is the only trust boundary that really matters.


1. The Big Picture: Windows as a Layered System

Everything you will ever attack or defend on a Windows box lives somewhere in a stack of rings, and the entire value of a mental model is that you stop guessing where. Calling the OS a “middleman between you and the hardware” is fine as a one-liner – it manages processes and memory, brokers file I/O, exposes APIs, drives devices – but that framing hides the part that actually pays your rent as an operator or defender: the layering is a security architecture, not just an engineering convenience.

Each layer exists to enforce isolation, enable portability, or mediate trust. User code can’t touch a device register. A web browser can’t read another process’s heap. A driver bug can corrupt the entire machine. Those are all consequences of where a layer sits.

Ring 3 (User Mode)     Applications (.exe)
                       Win32 API     kernel32.dll  user32.dll  advapi32.dll
                       KernelBase    kernelbase.dll
                       Native API    ntdll.dll  /  win32u.dll
─────────────────────  user/kernel boundary  ──  SYSCALL  ──────────────────
Ring 0 (Kernel Mode)   Executive     Obj / Mem / IO / Proc / SRM / Config  (ntoskrnl.exe)
                       Kernel        scheduling · interrupts · synchronization
                       Drivers       *.sys   (WDM / KMDF / UMDF)
                       HAL           hardware abstraction (now linked into ntoskrnl)
─────────────────────  ring −1  ────────────────────────────────────────────
                       Hypervisor    Hyper-V · Secure Kernel  (VBS / HVCI)
─────────────────────  hardware  ───────────────────────────────────────────
                       CPU · RAM · Disk · NIC · GPU

Read this diagram top-down and you have the whole tutorial in miniature. The rest is mechanism.


2. Privilege Rings and the User/Kernel Boundary

x86/x64 hardware exposes four privilege levels, CPL 0 through CPL 3, but Windows ignores rings 1 and 2 entirely. User-mode programs run at CPL 3 (Ring 3); the kernel and everything it loads run at CPL 0 (Ring 0). There is no middle ground.

That split is enforced by the page tables, not by memory segmentation. When a process launches, Windows gives it a private virtual address space and a private handle table, so one application physically cannot read or scribble on another’s memory through normal means. Kernel mode is the opposite: every driver shares one address space with the kernel and with every other driver. A single bad pointer write in a third-party .sys doesn’t crash that driver – it bugchecks the whole box.

FeatureUser ModeKernel Mode
Privilege levelRing 3 (CPL 3)Ring 0 (CPL 0)
Address spacePer-process privateOne shared space
x86 splitLow 2 GB (0x000000000x7FFFFFFF)High 2 GB (0x800000000xFFFFFFFF)
x64 split128 TB user range128 TB kernel range
Memory isolationPrivate VAS + private handle tableNone – all drivers share memory
Crash impactProcess diesBugcheck (BSOD), whole system
Hardware accessNone – must syscallDirect, via the HAL
Examplesexplorer.exe, chrome.exentoskrnl.exe, disk.sys

This is the boundary the entire defensive industry is built around. Get to Ring 0 and you are peer to the security software, not below it. That’s why kernel exploitation and signed-driver abuse are worth so much – and why Microsoft keeps stacking mitigations underneath the kernel (see §10).


Diagram showing Windows privilege rings from user-mode applications at Ring 3 down through the SYSCALL boundary into kernel-mode Executive and drivers at Ring 0, with the Hyper-V hypervisor layer below at Ring -1
The [user/kernel boundary](https://genxcyber.com/user-mode-vs-kernel-mode-privilege-rings-windows/) enforced by the SYSCALL instruction is the only hardware trust boundary Windows relies on – every layer above or below it inherits that split.

3. The HAL and Hardware Portability

Swap a server’s interrupt controller or move from one chipset generation to the next, and Windows still boots with the same kernel binary. That portability has a name: the Hardware Abstraction Layer, historically hal.dll. The HAL translates generic OS requests – “mask this interrupt,” “program this timer,” “talk to the bus” – into platform-specific instructions, so the kernel and drivers never hardcode chipset details.

The rule that matters operationally: drivers do not touch hardware directly. Every kernel-mode driver routes hardware access through HAL routines. That’s a portability win and a chokepoint.

One correction to the old folklore – people still draw hal.dll as its own box. It isn’t, not since Windows 10 version 2004, where the HAL was statically linked into ntoskrnl.exe. The hal.dll you still see on disk is a backwards-compatibility stub. If your mental diagram has a fat separate HAL layer, it’s about a decade out of date.


4. Inside ntoskrnl.exe: Kernel Layer and the Executive

The single most important binary in the OS is ntoskrnl.exe. It contains two distinct layers, and conflating them is a common rookie mistake.

The Executive is the upper layer – the policy and resource-management subsystems. The Kernel (often written “the kernel proper”) is the lower layer, doing the raw CPU-facing work: thread and interrupt scheduling and dispatching, trap handling, exception dispatching, multiprocessor synchronization, and bringing device drivers up at boot. The kernel layer knows nothing about “files” or “security” – it knows threads, DPCs, spinlocks, and trap frames. The Executive builds the meaningful abstractions on top.

ComponentFunction
Object ManagerCentral resource infrastructure – all named/shared resources are objects
Memory Manager (VMM)Implements per-process virtual address spaces; backs the Cache Manager
I/O ManagerBuilds and routes I/O Request Packets (IRPs) to drivers
Security Reference Monitor (SRM)Validates access tokens against object ACLs
Process ManagerCreates/terminates EPROCESS and ETHREAD objects
LPC / ALPC FacilityFast local inter-process communication between subsystems
Configuration ManagerThe registry implementation
Cache ManagerUnified file-system cache
PnP / Power ManagerHardware enumeration and power-state transitions

When you trace a syscall later in §7, you’re watching the kernel layer dispatch into an Executive routine. Keep the two separate in your head.


Hierarchy diagram of [ntoskrnl.exe](https://genxcyber.com/hal-ntoskrnl-windows-kernel-core-components/) showing the Executive subsystems including Object Manager, Memory Manager, I/O Manager, Security Reference Monitor, and Process Manager above the Kernel layer which contains the statically-linked HAL
The Executive subsystems handle policy and resource management while the Kernel layer beneath them handles raw CPU scheduling, interrupts, and trap handling – two distinct layers inside one binary.

5. The Windows Object Model

Here’s the rule that makes the whole system coherent: Windows is object-based. Almost every shareable system resource – processes, threads, files, registry keys, events, mutexes, sections, tokens, devices – is represented as an object managed by the Object Manager. Each object has a type (which defines its attributes and the methods that operate on it), a body of attributes, and a set of methods. This gives one consistent, security-checked path for naming, sharing, protecting, and reference-counting every resource.

The key access distinction maps straight onto the trust boundary from §2:

  • Kernel-mode code can hold direct pointers to objects.
  • User-mode code can only ever obtain handles – indices into the process’s private handle table that the Object Manager validates on every use.

Not everything is an object. Only data that needs to be shared, protected, named, or made visible to user mode is wrapped in an object; structures used purely internally by a single OS component (and there are many) are plain structures, never registered with the Object Manager.

Each object is fronted by an _OBJECT_HEADER that carries the type index, reference counts (PointerCount/HandleCount), and optional security descriptor. When HandleCount and PointerCount both drop to zero, the object is freed. This reference counting is exactly what attackers and defenders both watch: a leaked or duplicated handle to lsass.exe is a credential-theft tell (see §11-12).


6. Key Kernel Data Structures

If you only memorize one cluster of structures, make it these. Process injection, DKOM rootkits, token theft, and most of EDR’s telemetry all read or write the fields below.

_EPROCESS – Executive process object. The kernel represents every process (including the System Idle and System processes) with an EPROCESS. It holds the handle table, virtual-memory state, security context, debugging, and I/O/timing statistics. Fields worth knowing:

  • Pcb (_KPROCESS, offset +0x000) – the embedded kernel process control block.
  • UniqueProcessId – the PID.
  • ActiveProcessLinks (_LIST_ENTRY) – the doubly-linked list threading every process together; the list head is nt!PsActiveProcessHead. Unlinking your process here is classic DKOM process hiding.
  • Token (_EX_FAST_REF) – the primary access token; swapping this pointer is token-stealing privilege escalation.
  • VadRoot – root of the Virtual Address Descriptor tree.
  • ObjectTable (_HANDLE_TABLE) – the per-process handle table.

The System process’s EPROCESS pointer lives at nt!PsInitialSystemProcess – the canonical place to grab a SYSTEM token.

_KPROCESS – kernel process control block. Embedded inside EPROCESS at EPROCESS.Pcb. Used by the lower kernel layer for scheduling: thread list, quantum, base priority, and execution times.

_ETHREAD – Executive thread object. The opaque thread object; routines like PsIsSystemThread operate on it. It carries what the I/O Manager, SRM, Memory Manager, and ALPC Manager need to track per thread. Fields: Tcb (_KTHREAD, offset +0x000), ThreadListEntry, IrpList.

_KTHREAD – kernel thread control block. Embedded in ETHREAD at ETHREAD.Tcb. Holds the thread’s stacks, scheduling state, APC queues, system-call info, priority, and execution times.

_KPCR – Kernel Processor Control Region. On an SMP box each logical processor gets its own KPCR, carrying per-CPU data shared by kernel and HAL, with an embedded KPRCB (_KPRCB). The current CPU’s KPCR is reachable at FS:[0] in kernel mode on 32-bit Windows and at GS:[0] in kernel mode on x64. KPRCB.CurrentThread points to the KTHREAD currently running on that processor.

The whole chain links together like this:

KPCR.Prcb (KPRCB)
  └─ CurrentThread → KTHREAD
                        └─ embedded in ETHREAD.Tcb
                             └─ Process → KPROCESS
                                            └─ embedded in EPROCESS.Pcb

6.1 WinDbg lab: walking the live structures

Boot a Windows 10/11 VM with bcdedit /debug on plus kdnet (or VirtualKD-Redux) and attach a kernel debugger:

; List all processes via EPROCESS ActiveProcessLinks
!process 0 0

; Dump a full EPROCESS
dt nt!_EPROCESS <address>

; Dump the embedded KPROCESS (Pcb)
dt nt!_KPROCESS <address>

; Dump an ETHREAD
dt nt!_ETHREAD <address>

; Inspect the current processor's KPCR / KPRCB
dt nt!_KPCR @$pcr
dt nt!_KPRCB @$prcb

; Follow CurrentThread → KTHREAD
dt nt!_KPRCB @$prcb CurrentThread
dt nt!_KTHREAD <CurrentThread address>

; Locate the SSDT and inspect a routine
dps nt!KiServiceTable L100
u nt!NtCreateFile

Unlink an EPROCESS from ActiveProcessLinks and !process 0 0 stops showing it while the thread still runs – that is DKOM in one move, and the reason cross-referencing scheduler state against the process list is a rootkit-detection technique.


Hierarchy diagram linking the KPCR per-CPU structure through KPRCB and CurrentThread pointer to KTHREAD embedded in ETHREAD, then through the Process pointer to KPROCESS embedded in EPROCESS which holds the Token and handle table
This KPCR→KPRCB→KTHREAD→ETHREAD→KPROCESS→EPROCESS chain is the navigational spine of every process-injection, DKOM, and token-theft technique in Windows.

7. The Syscall Path: From WriteFile to the Kernel

A user-mode API call doesn’t “enter the kernel” magically; it walks a fixed chain and crosses the boundary at exactly one instruction.

kernel32!WriteFile  →  kernelbase!WriteFile  →  ntdll!NtWriteFile (syscall stub)
        →  SYSCALL  →  nt!KiSystemCall64  →  SSDT lookup  →  nt!NtWriteFile

The documented Win32 function in kernel32.dll/kernelbase.dll eventually calls the matching Nt* routine in ntdll.dll. ntdll is the last user-mode stop: it provides over 200 syscall stubs (NtCreateFile, NtSetEvent, …), and each stub just loads the System Service Number and executes the transition instruction.

The x64 stub pattern is tiny and worth recognizing on sight:

mov r10, rcx              ; SYSCALL clobbers RCX, so save arg0 in R10
mov eax, <SSN>            ; System Service Number → EAX
syscall                   ; transition to Ring 0
ret

On the kernel side, nt!KiSystemCall64 is the dispatcher. It uses the SSN in EAX to index the System Service Descriptor Table (SSDT) and calls the corresponding routine. On 64-bit Windows the SSDT stores relative offsets to the kernel routines, not absolute pointers. Two tables exist:

  • Native SSDT (KeServiceDescriptorTable) – core NT operations (process, thread, file, registry, memory).
  • Shadow SSDT (KeServiceDescriptorTableShadow) – GUI/Win32k operations, serviced by win32k.sys; the GUI-path stubs live in win32u.dll.

SSNs are not stable – they change between Windows builds, which is exactly why “direct syscall” tradecraft has to resolve them dynamically (and why hardcoding them breaks across updates).

7.1 C lab: observing the call chain

// Demonstrates the Win32 → ntdll → kernel call chain
#include <windows.h>
#include <stdio.h>

int main() {
    // Win32 API layer
    HANDLE hFile = CreateFile(
        L"C:\\test.txt",
        GENERIC_READ,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL
    );
    // Set a breakpoint on ntdll!NtCreateFile in WinDbg to observe
    // the syscall stub and SSN placed in EAX before the SYSCALL instruction
    if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
    return 0;
}

Break on bp ntdll!NtCreateFile and u ntdll!NtCreateFile to watch the mov r10, rcx / mov eax, <SSN> / syscall sequence. Confirm the SSN against your specific build – it varies.


Flow diagram tracing a WriteFile call from kernel32 through kernelbase and ntdll syscall stub, across the SYSCALL boundary into KiSystemCall64 which performs SSDT lookup to dispatch to the kernel NtWriteFile routine
Every Windows API call reaches the kernel through this fixed chain – the SYSCALL instruction carrying the System Service Number in EAX is the single crossing point between user and kernel mode.

8. User-Mode Subsystems and the API Stack

The user-mode side is layered just as deliberately as the kernel side:

LayerBinaryRole
Win32 application.exeYour code
Windows APIkernel32.dll, user32.dll, advapi32.dllDocumented high-level wrappers
KernelBasekernelbase.dllRefactored Win32 internals (Vista+)
Native APIntdll.dllSyscall stubs; Nt*/Zw* functions
Subsystem DLLwin32u.dllGUI-path syscall stubs to win32k.sys

The Windows personality is implemented by the Client/Server Runtime Subsystem, csrss.exe. At boot, once boot and system drivers are loaded, the kernel starts the Session Manager Subsystem (smss.exe), which in turn launches the crucial Win32 user- and kernel-mode services, including csrss.exe. The core system-process tree to memorize:

smss.exe  →  wininit.exe  →  lsass.exe, services.exe, csrss.exe

Knowing this tree is what lets you spot anomalies: a csrss.exe not parented by smss.exe, or an lsass.exe with a surprise child, is immediately suspicious.


9. Kernel-Mode Drivers and the I/O Model

Drivers are loadable kernel-mode modules – .sys files – that sit between the I/O Manager and hardware and call HAL routines to actually touch devices. I/O flows as I/O Request Packets (IRPs): the I/O Manager builds an IRP and routes it down the driver stack.

WDM (Windows Driver Model) is the original interface; KMDF (Kernel-Mode Driver Framework) and UMDF (User-Mode Driver Framework) wrap WDM with simpler, less error-prone interfaces. Because every loaded driver shares the kernel address space (§2), each .sys is also raw attack surface – a vulnerable signed driver is a ready-made Ring 0 primitive (BYOVD).


10. Virtualization-Based Security (VBS) and the Hypervisor Layer

Modern Windows adds a layer below the kernel – effectively ring −1. The hypervisor (Hyper-V) is the trust anchor. It carries no external drivers or modules; internally it runs its own memory manager, virtual-processor scheduler, interrupt/timer management, synchronization, and partition/IPC management.

This hypervisor underpins Virtualization-Based Security (VBS) and HVCI (Hypervisor-Protected Code Integrity). With HVCI, kernel code pages can’t be modified at runtime even from Ring 0, and the Secure Kernel isolates secrets (e.g., Credential Guard moves lsass.exe secrets into a VSM enclave). For an attacker this is the point: getting Ring 0 no longer means “game over for the whole machine” – the hypervisor still stands above you, which is what makes DKOM and SSDT/code patching dramatically harder.


11. Security Implications and the Attacker/Defender View per Layer

Each layer is both an attack target and a sensor location:

  • User-mode API layer – API hooking, IAT/inline patching; ntdll ETW patching (EtwEventWrite) to blind telemetry.
  • Native API / syscall boundary – direct syscalls bypass user-mode hooks; SSNs resolved dynamically.
  • Kernel drivers – BYOVD and driver CVEs for Ring 0; HVCI/KMCS raise the bar.
  • Kernel data structures – DKOM on EPROCESS.ActiveProcessLinks (hiding), Token swap (privesc).

Detection & Defense pairing

Sysmon event IDs by layer:

Event IDNameLayer monitored
1Process CreationUser-mode process creation (CreateProcessNtCreateProcess)
2File Creation Time ChangedObject Manager / NTFS
7Image LoadedModule/driver load (flag Signed=false)
10Process AccessOpenProcessNtOpenProcess (cross-process handle)
11File CreateI/O Manager path
13Registry Value SetConfiguration Manager
25Process TamperingImage hollowing / herpaderping

Audit policy (auditpol /set /subcategory:"Process Creation" /success:enable /failure:enable):

  • Process Creation4688 (full command line if enabled)
  • Audit Kernel Object4656/4663 (object handle requests/access)
  • Audit Handle Manipulation4658/4690
  • Audit Security State Change4608 (system start)
  • Audit Sensitive Privilege Use4673 (e.g. SeDebugPrivilege – key for kernel-targeting tools)

ETW providers: Microsoft-Windows-Kernel-Process ({22FB2CD6-...}), Microsoft-Windows-Kernel-File ({EDD08927-...}), Microsoft-Windows-Kernel-Registry ({70EB4F03-...}), Microsoft-Windows-Security-Auditing ({54849625-...}), and the high-fidelity ETWTI Microsoft-Windows-Threat-Intelligence ({F4E1897C-...}) – which surfaces NtAllocateVirtualMemory, NtMapViewOfSection, and remote-thread creation. ETWTI requires a PPL subscriber, which is why it’s the kernel sensor commercial EDRs lean on.

Sigma field patterns:

  • EventID: 7 + Signed: false + ImageLoaded contains \.sys → unsigned driver load
  • EventID: 10 + TargetImage: lsass.exe + GrantedAccess: 0x1010 → LSASS handle acquisition
  • EventID: 1 + ParentImage: smss.exe → unexpected child of Session Manager

Hardening:

  • KMCS – kernel driver signing enforced by default on x64; pair with UEFI Secure Boot + HVCI (bcdedit /set hypervisorlaunchtype auto) to block unsigned drivers and stop SSDT/IAT hooks.
  • HVCI (Memory Integrity) – blocks runtime kernel-code modification; makes DKOM-style attacks far harder.
  • ASR rules – stop Office/browser processes from triggering sensitive syscall chains.
  • Credential Guard – VBS-isolates lsass.exe secrets in the Secure Kernel.
  • LSA Protection (PPL) – runs lsass.exe as a Protected Process Light, blocking OpenProcess with PROCESS_VM_READ from unprivileged callers.

MITRE ATT&CK mapping

TechniqueNameArchitectural link
T1055Process InjectionOpenProcess / NtWriteVirtualMemory / NtCreateThreadEx; user/kernel boundary
T1055.001DLL InjectionOpenProcessWriteProcessMemoryCreateRemoteThread
T1055.012Process HollowingCreateProcess(SUSPENDED)NtUnmapViewOfSection → kernel object manipulation
T1014RootkitDKOM on EPROCESS.ActiveProcessLinks; SSDT hooking
T1562.001Impair Defenses: Disable/Modify ToolsETW patching, SSDT hook removal
T1562.006Impair Defenses: Indicator BlockingPatching ntdll.dll ETW functions (EtwEventWrite)
T1106Native APIDirect ntdll.dll Nt* calls, bypassing the Win32 layer
T1059Command and Scripting InterpreterExecution flows through the Win32 subsystem and csrss.exe

12. Recap

Read the stack top to bottom and the model holds:

  • Ring 3 vs Ring 0 is the only trust boundary that matters; the CPU enforces it via paging, and crossing it happens at exactly one SYSCALL instruction.
  • ntoskrnl.exe holds two layers – the Executive (Object/Memory/IO/Process/SRM/Config managers) on top, the Kernel (scheduling, interrupts, traps, synchronization) below – with the HAL statically linked in since Windows 10 2004.
  • Everything shareable is an object; user mode gets handles, kernel mode gets pointers.
  • The EPROCESS → KPROCESS / ETHREAD → KTHREAD / KPCR → KPRCB chain is where injection, DKOM, and token theft happen – and where WinDbg lets you watch them.
  • The syscall path (kernel32ntdllSYSCALLKiSystemCall64 → SSDT) is fixed, but SSNs drift per build.
  • VBS/HVCI/Hyper-V sit below the kernel and re-establish a trust anchor even against Ring 0.

Know where a primitive sits, and you know which sensor catches it and which mitigation breaks it. That mapping – layer to telemetry to hardening – is the whole point of carrying this model in your head.


Related Tutorials

References

Get new drops in your inbox

Windows internals, exploit dev, and red-team write-ups - no spam, unsubscribe anytime.