Windows Security Internals
Windows Security Internals – Reference Notes
I'm reading the book Windows Security Internals by James Forshaw. Beside the reading I've also taken phyiscal notes, and then used AI to organize my notes before posting them here. The intended use-case is for qucikly reading up on a subject or a topic. It is not intended to replace the book for in-depth information about a topic/subject.
Chapter 1: The Windows Kernel Executive
Overview
The Windows Kernel Executive (NTOS Kernel) is the core of the Windows operating system. It:
- Provides all of the operating system's privileged functionality.
- Provides an interface for user-mode applications to communicate with hardware.
- Exposes APIs for other subsystems to call.
The kernel is divided into subsystems, each identified by an API prefix. The most important subsystem is the Security Reference Monitor, which handles all access control decisions in the OS.
Conceptual model of Windows ring levels:
- Ring 0 – The hardware layer.
- The Kernel – Security guards and elevator (permissions and scheduling only).
- The first layer – Where actual work happens (user applications, services).
API Prefix to Subsystem Mapping
When you see a Windows API function name, its prefix tells you which kernel subsystem it belongs to.
| Prefix | Subsystem | Example |
|---|---|---|
Nt or Zw |
System Call Interface | NtOpenFile
|
Se |
Security Reference Monitor | SeImpersonate
|
Ob |
Object Manager | ObReferenceObject
|
Ps |
Process and Thread Manager | PsGetCurrentProcess
|
Cm |
Configuration Manager | CmRegisterCallbackEx
|
Mm |
Memory Manager | MmMapIoSpace
|
Io |
Input/Output Manager | IoCreateFile
|
Ci |
Code Integrity | CiValidateFileObject
|
Security Reference Monitor (SRM)
The Security Reference Monitor is the most important kernel subsystem. It is responsible for deciding who can access what in the operating system.
How the SRM Works
When a user process tries to access a resource, the SRM performs an access check:
- The process presents its access token to the SRM.
- The SRM queries the resource's security descriptor.
- If the token grants the requested rights, access is granted.
Key facts:
- Every process on the system is assigned an access token when it is created.
- The token is managed by the SRM.
- The token defines the identity of the user associated with the process.
- The SRM can perform access checks and queries the resource's security descriptor to do so.
- Users and groups are represented to the SRM by a SID (Security Identifier).
Access Token
An access token is a kernel object assigned to every process at creation time. It defines the user identity and the rights held by that process. The SRM uses this token when performing access checks against a resource's security descriptor.
Security Identifiers (SIDs)
A SID is a binary structure that uniquely represents a user or group. The Local Security Authority Subsystem (LSASS) creates SIDs and provides them to the SRM.
SID String Format (SDDL)
Microsoft defines the Security Descriptor Definition Language (SDDL) format to represent a SID as a human-readable string.
Example: The built-in Users group has the SID S-1-5-32-545.
| Part | Meaning |
|---|---|
S |
Fixed prefix – identifies this as a SID |
1 |
Version of the SID (always 1) |
5 |
Security Authority (5 = NT Authority)
|
32 |
Sub-authority value (part of the RID chain) |
545 |
RID – Relative Identifier (identifies the specific group) |
Well-known SIDs (like built-in groups) are always the same across Windows systems.
Take-home: SIDs represent users and groups, and can be represented as strings.
Key Kernel Executive Subsystems
The I/O Manager
The I/O Manager is a kernel subsystem that coordinates how applications and drivers communicate to perform input and output operations (files, devices, networks).
Job: Provide access to I/O devices through device drivers. The purpose of these drivers is to implement a filesystem or device interface.
How to load a driver:
- Manually: via the
NtLoadDriversystem call. - Automatically: by the Plug and Play (PnP) Manager.
Driver directory in the OMNS: For every driver loaded, the I/O Manager creates an entry in a driver directory inside the Object Manager Namespace. Only administrators can list this directory.
How does a normal user access a driver?
They don't interact with the driver directory directly. Instead, they interact through a device object, which is normally created in the \Device OMNS directory.
Example: When a user-mode app opens a file, the request goes through the I/O Manager, which creates an Input/Output Request Packet (IRP) and routes it to the correct driver.
Networking: Windows uses the AFD (Ancillary Function Driver) to provide networking services (TCP/IP, etc.) to applications. There are no built-in system calls for core network protocols – everything goes through AFD. WinSock is the user-mode handle to AFD.
The Process and Thread Manager
The Process and Thread Manager is the kernel component that creates and manages processes and threads.
- A process is the container – it holds the address space, handle table, and resources.
- A thread is the actual unit of execution running inside a process.
It handles scheduling, creation, termination, and keeps track of what the CPU should run and when, so the CPU knows what to run at any given moment.
The Memory Manager
The Memory Manager controls the allocation of both physical and virtual memory. It handles paging, swapping, and keeps memory protected between processes so one process cannot read another's memory.
Memory Protection Levels
| Protection Level | Description |
|---|---|
ReadOnly |
Memory can only be read |
ReadWrite |
Memory can be read and written |
ExecuteRead |
Memory can be executed and read |
ExecuteReadWrite |
Memory can be executed, read, and written |
Memory States
| State | Meaning | Safe to use? |
|---|---|---|
| Commit | Virtual memory is allocated and has backing physical memory | Yes |
| Reserve | Address range is reserved but has no backing physical memory. Using it causes a crash. | No |
| Free | Virtual memory is unused and unmapped. Using it causes a crash. | No |
Allocating Virtual Memory
Two ways to allocate virtual memory:
NtAllocateVirtualMemory– direct virtual memory allocation syscall.- Through a Section Object – a kernel object type that implements memory-mapped files.
What is a Section Object? A Section Object is a kernel type that implements memory-mapped files. It allows a file or pagefile-backed region to be mapped into a process's address space.
How to map a section into another process:
Specify a process handle to NtMapViewOfSection. This lets you share memory between processes.
Code Integrity
Code Integrity is a kernel subsystem that verifies and restricts what files can execute in the kernel and in user mode, by checking code signatures.
- Authenticode is the mechanism used to digitally sign executables and drivers.
- If a file or driver has an invalid signature, the kernel can block the loading of that driver to preserve system integrity.
Advanced Local Procedure Call (ALPC)
ALPC allows transmission of discrete messages between a server and a client on the same machine. It is a kernel-level inter-process communication (IPC) mechanism.
| System Call | Purpose |
|---|---|
NtCreateAlpcPort |
Creates a server-side ALPC port |
NtConnectAlpcPort |
Connects a client to an existing ALPC port |
The Configuration Manager
The Configuration Manager is what most people know as the Windows Registry. It stores persistent configuration information for the OS, device drivers, and applications – similar to how a text editor stores your last cursor position.
Chapter 2: The Object Manager
Overview
In Unix-like systems, everything is a file. In Windows, everything is an object. The Object Manager treats all kernel resources uniformly – files, registry keys, processes, threads, mutexes, and so on.
Every object has three things:
- A name – its path in the OMNS.
- A type – what kind of object it is.
- A security descriptor – who can access it and how.
The Object Manager is the central authority that organises the entire OS into a searchable tree structure.
What does the Object Manager actually do? It translates a handle into a memory address in kernel space.
Object Manager Namespace (OMNS)
Underneath the user interface, Windows has a hidden filesystem for kernel objects. Access to this internal filesystem is through the Object Manager Namespace (OMNS). It is not well-documented.
Think of it like a hidden File Explorer that shows kernel objects instead of regular files.
The OMNS is built out of Directory objects. These act like folders in a filesystem – each directory can contain other objects (which you can think of as files).
A security descriptor on each directory controls:
- Which users can list its contents.
- Who can create new objects or subdirectories inside it.
To enumerate the OMNS: Use a PowerShell module such as NtObjectManager.
Symbolic Links in the OMNS
A Symbolic Link in the OMNS redirects one OMNS path to another. It contains a SymbolicLinkTarget property that holds the target path that the link should resolve to.
Example: Drive letters like C: are symbolic links stored under \GLOBAL?? pointing to the actual device path (e.g., \Device\HarddiskVolume3).
Pre-configured OMNS Directories
Windows pre-configures several important object directories at boot:
| Path | Description |
|---|---|
\BaseNamedObjects |
Global directory for named user-mode objects (mutexes, events, semaphores, etc.) |
\Device |
Contains device objects such as mounted filesystems and hardware devices |
\GLOBAL?? |
Global directory for symbolic links, including drive letter mappings (e.g., C:)
|
\KnownDlls |
Directory containing special, pre-loaded DLL mappings |
\ObjectTypes |
Directory containing all named kernel object types |
\Sessions |
Directory for separate console sessions |
\Windows |
Directory for objects related to the Windows Manager |
\RpcControl |
Directory for Remote Procedure Call (RPC) endpoints |
System Calls
A system call lets user-mode code invoke kernel-mode code using the system call interface.
Nt vs Zw Prefix
All system calls start with either the Nt or Zw prefix. When the same code is executed inside the kernel:
Zwprefix – changes the security checking process. It signals to the kernel that the caller is trusted (typically another kernel component), and bypasses certain user-mode security checks.Ntprefix – performs the full security check as if the call came from user mode.
After the prefix comes an operation verb that describes what the call does.
Example: In NtCreateMutant, the verb is Create.
Common System Call Operations
| Operation Verb | Description |
|---|---|
Create |
Creates a new kernel object |
Open |
Opens an existing kernel object |
QueryInformation |
Queries object information and properties |
SetInformation |
Sets object information and properties |
Example: NtCreateMutant
From Listing 2-6 in the book. This is a real system call that creates a Mutant (mutex) object.
NTSTATUS NtCreateMutant(
HANDLE* MutantHandle, // (1) Out-pointer: receives the new handle
ACCESS_MASK DesiredAccess, // (2) What operations we want to perform via this handle
OBJECT_ATTRIBUTES* ObjectAttributes, // (3) Struct defining the object's attributes (name, etc.)
BOOLEAN InitialOwner // (4) Is the Mutant owned by the caller on creation?
);
Parameter explanations:
- MutantHandle – An outbound pointer to a HANDLE. The kernel writes the newly created handle value here.
- DesiredAccess – An access mask specifying what operations we want to be able to perform on the Mutant using this handle.
- ObjectAttributes – A struct that defines attributes for the object (name, root directory, security descriptor, etc.). See Listing 2-7 in the book.
- InitialOwner – Determines whether the newly created Mutant is immediately owned by the calling thread (
TRUE) or not (FALSE).
What is a Mutant?
A Mutant is Windows's kernel-internal name for a mutex (mutual exclusion object). It ensures that only one thread can access a shared resource at a time.
NTSTATUS Codes
All system calls return a 32-bit NTSTATUS code. This tells the caller whether the operation succeeded and, if not, why it failed.
NTSTATUS Structure
| Field | Bits | Description |
|---|---|---|
| Severity | 31–30 | Indicates the severity of the status (Success, Info, Warning, Error) |
| Customer Code (C) | 29 | Is this code defined by Microsoft (0) or a third party (1)?
|
| Reserved (R) | 28 | Must always be set to 0
|
| Facility | 27–16 | The component or subsystem this code belongs to |
| Status Code | 15–0 | A 16-bit number unique within the facility |
Severity Values
| Severity Name | Value | Meaning |
|---|---|---|
STATUS_SEVERITY_SUCCESS |
0 | Operation succeeded |
STATUS_SEVERITY_INFORMATIONAL |
1 | Informational, not an error |
STATUS_SEVERITY_WARNING |
2 | Warning – something unexpected but not fatal |
STATUS_SEVERITY_ERROR |
3 | Error – operation failed |
Facility Values (selected)
There are approximately 50 defined facilities. The facility identifies which component or subsystem produced the status code.
| Facility Name | Value | Description |
|---|---|---|
FACILITY_DEFAULT |
0 | Used for common/generic status codes |
FACILITY_DEBUGGER |
1 | Codes associated with the debugger |
FACILITY_NTWIN32 |
7 | Codes that originated from the Win32 API layer |
The Status Code field (bits 15–0) is a 16-bit number chosen to be unique within its facility.
Object Handles
What is a Handle?
A handle is a number (an ID tag) that a process holds to reference a kernel object it does not have direct memory access to – like a file or a kernel mutex.
- It is like an ID tag the process holds instead of a real memory address.
- User-mode applications cannot directly read or write kernel memory, so handles are the abstraction layer.
- The Object Manager translates a handle into a kernel memory address when the syscall is executed.
Handle Table
Each running process has an associated handle table maintained by the kernel. Every entry in the table contains three pieces of information:
- The handle's numeric identifier – the number used in user-mode code.
- The granted access mask – what rights (e.g., Read, Write) were granted when this handle was opened.
- A pointer to the object structure in kernel memory.
Handle Lookup Process
When a user-mode process passes a handle to a system call, the kernel:
- Receives the handle value from the system call.
- Calls an internal API (e.g.,
ObReferenceObjectByHandle) to convert the handle to a kernel pointer by looking up the numeric value in the process's handle table. - Determines whether the access the user requested is permitted.
Why step 3 is crucial: It ensures that a user cannot perform an operation on a handle they don't have rights for.
Example: If a process has a file handle opened with read-only access, attempting to write to it via that handle will be denied – even if the underlying file is writable.
If the lookup and access check succeed, the syscall gets a pointer to the object and performs the requested operation.
Conversion operation = turning a handle value into an actual kernel pointer.
Access Masks
What is an Access Mask?
An access mask is a 32-bit bitfield that specifies which specific operations a user or program is allowed to perform on a file, folder, or kernel object.
- The granted access stored in each handle table entry is an access mask.
- When opening or creating a handle, the caller passes a DesiredAccess parameter in the same format.
Access Mask Structure
| Region | Bits | Name | Notes |
|---|---|---|---|
| 1 (most important) | 15–0 | Type-Specific Access | Operations specific to a particular kernel object type |
| 2 | 20–16 | Standard Access | Operations that apply to any kernel object type |
| 3 | 27–24 | Special Access | Special flags (system security, maximum allowed) |
| 4 | 31–28 | Generic Access | Only used when requesting access; SRM converts to type-specific access |
Type-Specific Access (Bits 15–0)
Defines the operations allowed on a particular object type. Each type defines its own bits independently.
Example: A file object has separate bits to specify whether the file can be read or written.
Standard Access Rights (Bits 20–16)
These operations apply to any kernel object type:
| Right | Description |
|---|---|
Delete |
Removes the object (e.g., deletes the file from disk or key from registry) |
ReadControl |
Reads the security descriptor information for the object |
WriteDac |
Writes the object's Discretionary Access Control (DAC) – modifies who can access it |
WriteOwner |
Writes the owner information to the object |
Synchronize |
Waits on the object; allows a process to block until the object signals (e.g., wait for a process to exit) |
Additionally, from the special access region:
| Right | Description |
|---|---|
AccessSystemSecurity |
Reads or writes audit (SACL) information on the object |
MaximumAllowed |
Requests the maximum access the caller is permitted when performing an access check |
Generic Access Rights (Bits 31–28)
Used only when requesting access via a system call's DesiredAccess parameter. The SRM converts these into the corresponding type-specific access rights for the object type being opened.
| Generic Right | Converts to |
|---|---|
GenericRead |
Type-specific read rights for that object type |
GenericWrite |
Type-specific write rights for that object type |
GenericExecute |
Type-specific execute rights for that object type |
GenericAll |
All type-specific rights for that object type |
Permanent Objects
What is a Permanent Object?
A permanent object is an object that the kernel marks to prevent it from being destroyed when all handles to it are closed. The object's name remains in the OMNS even after all handles close.
Contrast with normal objects: A normal object is destroyed automatically once all handles to it are closed.
Note: Files and registry keys cannot be permanent objects in the OMNS – they are not stored in the OMNS and need a system call (like a delete call) to be removed.
API Calls
| API | Description |
|---|---|
NtMakePermanentObject |
Makes an object permanent. Requires the SeCreatePermanentPrivilege privilege.
|
NtMakeTemporaryObject |
Reverse operation – allows the object to be destroyed. All handles must be closed first. |
Handle Duplication
What is Handle Duplication?
Handle duplication allows a process to take an additional reference to a kernel object by creating a new handle (in the same or another process) pointing to the same underlying object.
Example: Pass a file handle to a new process. You can grant the duplicated handle only read-only access, even if the original handle had full read-write access.
PowerShell command for handle duplication: Copy-NtObject
Query and Set Information System Calls
The kernel implements a generic Query and Set Information pattern that applies consistently to all kernel objects.
Use case: Query a kernel object about its state. Example: get the creation timestamp for a process.
| Purpose | System Call Example | PowerShell Equivalent |
|---|---|---|
| Query object information | NtQueryInformationProcess |
Get-NtObjectInformation
|
| Set object information | — | Set-NtObjectInformation
|
Usage notes:
- Specify the open object handle and an information class (the type of info you want).
- Some information classes require special privileges or admin access to query.
- A buffer must be provided to receive the queried data. The exact required buffer size is rarely documented – discover it by inspection or brute-force.
Glossary
- Access Mask
- A 32-bit bitfield specifying which operations are allowed on a kernel object. Used both in the handle table (granted access) and when requesting access (DesiredAccess parameter).
- Access Token
- A kernel object assigned to every process at creation. Defines the user identity and the rights held by that process. Managed and checked by the SRM during access checks.
- AFD (Ancillary Function Driver)
- The kernel driver that provides networking services (TCP/IP, etc.) to user-mode applications. WinSock is the user-mode interface to AFD. There are no direct system calls for core network protocols – everything routes through AFD.
- ALPC (Advanced Local Procedure Call)
- A kernel mechanism for passing discrete messages between a server process and a client process on the same machine. Uses
NtCreateAlpcPortandNtConnectAlpcPort.
- Authenticode
- Microsoft's mechanism for digitally signing executables and drivers. Used by the Code Integrity subsystem to verify signatures before loading.
- Code Integrity
- A kernel subsystem that verifies file and driver code signatures and can block the loading of unsigned or improperly signed drivers to preserve system integrity.
- Configuration Manager
- The kernel subsystem that manages the Windows Registry. Stores persistent configuration for the OS, drivers, and applications.
- Handle
- A numeric ID tag a process holds to reference a kernel object it cannot directly access in memory. The Object Manager translates it to a kernel memory address via the handle table.
- Handle Duplication
- The process of creating a new handle (in the same or a different process) that references the same kernel object as an existing handle, optionally with reduced access rights. PowerShell:
Copy-NtObject.
- Handle Table
- A per-process table maintained by the kernel. Each entry holds: (1) the handle number, (2) the granted access mask, and (3) a pointer to the kernel object in memory.
- I/O Manager
- The kernel subsystem that coordinates how applications and device drivers communicate for I/O operations such as file access, device interaction, and networking. Creates an IRP (I/O Request Packet) for each operation.
- LSASS (Local Security Authority Subsystem)
- The user-mode Windows service responsible for creating SIDs and providing them to the SRM. Manages authentication and local security policy.
- Memory Manager
- The kernel subsystem that controls the allocation and protection of physical and virtual memory. Manages paging, swapping, and memory isolation between processes.
- Mutant
- The Windows kernel's internal name for a mutex (mutual exclusion object). Ensures that only one thread can access a shared resource at a time.
- NTSTATUS
- A 32-bit status code returned by all system calls. Encodes: severity (bits 31–30), customer code (bit 29), reserved (bit 28), facility (bits 27–16), and a status code (bits 15–0).
- Object
- In Windows, everything is an object: files, registry keys, processes, threads, mutexes, etc. Every kernel object has a name, a type, and a security descriptor. Managed uniformly by the Object Manager.
- Object Manager
- The kernel component responsible for managing all kernel objects. Translates handles to kernel memory addresses, maintains the OMNS, and enforces naming and object lifetime rules.
- OMNS (Object Manager Namespace)
- A hidden, filesystem-like namespace for kernel objects. Built from Directory objects organised in a tree. Not well-documented. Can be explored with the NtObjectManager PowerShell module.
- Permanent Object
- A kernel object marked to persist in the OMNS even after all handles to it are closed. Requires
SeCreatePermanentPrivilegeto create viaNtMakePermanentObject.
- Process
- A container that holds an address space, handle table, and threads. Created and managed by the Process and Thread Manager.
- Process and Thread Manager
- The kernel subsystem responsible for creating, managing, scheduling, and terminating processes and threads.
- RID (Relative Identifier)
- The rightmost sub-authority value(s) in a SID that uniquely identify a user or group within a domain or local machine.
- SDDL (Security Descriptor Definition Language)
- A Microsoft-defined string format for representing SIDs and security descriptors in human-readable form. Example:
S-1-5-32-545.
- Section Object
- A kernel object type that implements memory-mapped files. Allows file or pagefile-backed memory regions to be shared across processes.
- Security Descriptor
- An object attached to every kernel resource that defines who can access it and in what way. Queried by the SRM during access checks.
- Security Reference Monitor (SRM)
- The most important kernel subsystem. Performs all access checks – deciding whether a user process can access a resource based on its access token and the resource's security descriptor.
- SID (Security Identifier)
- A binary structure that uniquely identifies a user or group. Represented as a string in the format
S-1-5-...using SDDL notation. Created by LSASS and used by the SRM.
- Symbolic Link (OMNS)
- An OMNS object that redirects one namespace path to another. Contains a SymbolicLinkTarget property pointing to the destination path. Used for drive letter mappings under
\GLOBAL??.
- System Call
- A mechanism that allows user-mode code to invoke kernel-mode functionality through the system call interface. Always prefixed with
NtorZw.
- Thread
- The actual unit of execution running inside a process. A single process can have many threads running concurrently.
- Windows Kernel Executive
- The core of the Windows OS (NTOS Kernel). Provides all privileged OS functionality and exposes APIs to subsystems and user-mode applications via kernel executive components.