Chapter 2 System Architecture - Windows Internals Seventh Edition Part 1
Chapter 2 System Architecture - Windows Internals Seventh Edition Part 1
System architecture
Now that you’ve learned the terms, concepts, and tools you need to be fa-
miliar with, it’s time to start exploring the internal design goals and struc-
ture of the Microsoft Windows operating system (OS). This chapter ex-
plains the overall architecture of the system—the key components, how
they interact with each other, and the context in which they run. To pro-
vide a framework for understanding the internals of Windows, let’s first
review the requirements and goals that shaped the original design and
specification of the system.
Run most existing 16-bit MS-DOS and Microsoft Windows 3.1 applications.
Reliability and robustness The system should protect itself from both
internal malfunction and external tampering. Applications should not be
able to harm the OS or other applications.
Performance Within the constraints of the other design goals, the system
should be as fast and responsive as possible on each hardware platform.
All these OS components are, of course, fully protected from errant ap-
plications because applications don’t have direct access to the code and
data of the privileged part of the OS (although they can quickly call other
kernel services). This protection is one of the reasons that Windows has
the reputation for being both robust and stable as an application server
and as a workstation platform, yet fast and nimble from the perspective
of core OS services, such as virtual memory management, file I/O, net-
working, and file and print sharing.
With this brief overview of the design goals and packaging of Windows,
let’s take a look at the key system components that make up its architec-
ture. A simplified version of this architecture is shown in Figure 2-1. Keep
in mind that this diagram is basic. It doesn’t show everything. For exam-
ple, the networking components and the various types of device driver
layering are not shown.
In Figure 2-1, first notice the line dividing the user-mode and kernel-
mode parts of the Windows OS. The boxes above the line represent user-
mode processes, and the components below the line are kernel-mode OS
services. As mentioned in Chapter 1, user-mode threads execute in a pri-
vate process address space (although while they are executing in kernel
mode, they have access to system space). Thus, system processes, service
processes, user processes, and environment subsystems each have their
own private process address space. A second dividing line between ker-
nel-mode parts of Windows and the hypervisor is also visible. Strictly
speaking, the hypervisor still runs with the same CPU privilege level (0) as
the kernel, but because it uses specialized CPU instructions (VT-x on Intel,
SVM on AMD), it can both isolate itself from the kernel while also moni-
toring it (and applications). For these reasons, you may often hear the
term ring -1 thrown around (which is inaccurate).
Service processes These are processes that host Windows services, such
as the Task Scheduler and Print Spooler services. Services generally have
the requirement that they run independently of user logons. Many
Windows server applications, such as Microsoft SQL Server and Microsoft
Exchange Server, also include components that run as services. Chapter 9,
“Management mechanisms,” in Part 2 describes services in detail.
In Figure 2-1, notice the Subsystem DLLs box below the Service
Processes and User Processes boxes. Under Windows, user applications
don’t call the native Windows OS services directly. Rather, they go
through one or more subsystem dynamic-link libraries (DLLs). The role of
subsystem DLLs is to translate a documented function into the appropri-
ate internal (and generally undocumented) native system service calls im-
plemented mostly in Ntdll.dll. This translation might or might not involve
sending a message to the environment subsystem process that is serving
the user process.
Device drivers This includes both hardware device drivers, which trans-
late user I/O function calls into specific hardware device I/O requests, and
non-hardware device drivers, such as file system and network drivers.
The Hardware Abstraction Layer (HAL) This is a layer of code that iso-
lates the kernel, the device drivers, and the rest of the Windows executive
from platform-specific hardware differences (such as differences be-
tween motherboards).
Table 2-1 lists the file names of the core Windows OS components.
(You’ll need to know these file names because we’ll be referring to some
system files by name.) Each of these components is covered in greater de-
tail both later in this chapter and in the chapters that follow.
Before we dig into the details of these system components, though, let’s
examine some basics about the Windows kernel design, starting with
how Windows achieves portability across multiple hardware
architectures.
Portability
Symmetric multiprocessing
TABLE 2-2 Processor and memory limits for some Windows editions
Scalability
The scalability of the Windows kernel has evolved over time. For ex-
ample, Windows Server 2003 introduced per-CPU scheduling queues with
a fine-grained lock, permitting thread-scheduling decisions to occur in
parallel on multiple processors. Windows 7 and Windows Server 2008 R2
eliminated global scheduler locking during wait-dispatching operations.
This stepwise improvement of the granularity of locking has also oc-
curred in other areas, such as the memory manager, cache manager, and
object manager.
Windows ships in both client and server retail packages. There are six
desktop client versions of Windows 10: Windows 10 Home, Windows 10
Pro, Windows 10 Education, Windows 10 Pro Education, Windows 10
Enterprise, and Windows 10 Enterprise Long Term Servicing Branch
(LTSB). Other non-desktop editions include Windows 10 Mobile, Windows
10 Mobile Enterprise, and Windows 10 IoT Core, IoT Core Enterprise, and
IoT Mobile Enterprise. Still more variants exist that target world regions
with specific needs, such as the N series.
Layered services that come with Windows Server editions that don’t
come with the client editions (for example, directory services, Host
Guardian, Storage Spaces Direct, shielded virtual machines, and
clustering)
Table 2-2 lists the differences in memory and processor support for
some Windows 10, Windows Server 2012 R2, and Windows Server 2016
editions. For a detailed comparison chart of the different editions of
Windows Server 2012 R2, see https://www.microsoft.com/en-
us/download/details.aspx?id=41703. For Windows 10 and Server 2016 edi-
tions and earlier OS memory limits, see https://msdn.microsoft.com/en-
us/library/windows/desktop/aa366778.aspx.
Although there are several client and server retail packages of the
Windows OS, they share a common set of core system files, including the
kernel image, Ntoskrnl.exe (and the PAE version, Ntkrnlpa.exe), the HAL
libraries, the device drivers, and the base system utilities and DLLs.
With so many different editions of Windows and each having the same
kernel image, how does the system know which edition is booted? By
querying the registry values ProductType and ProductSuite under the
HKLM\SYSTEM\CurrentControlSet\Control\ProductOptions key.
ProductType is used to distinguish whether the system is a client system
or a server system (of any flavor). These values are loaded into the reg-
istry based on the licensing policy file described earlier. The valid values
are listed in Table 2-3. This can be queried from the user-mode
VerifyVersionInfo function or from a device driver using the kernel-
mode support function RtlGetVersion and RtlVerifyVersionInfo ,
both documented in the Windows Driver Kit (WDK).
So if the core files are essentially the same for the client and server
versions, how do the systems differ in operation? In short, server systems
are optimized by default for system throughput as high-performance ap-
plication servers, whereas the client version (although it has server capa-
bilities) is optimized for response time for interactive desktop use. For ex-
ample, based on the product type, several resource-allocation decisions
are made differently at system boot time, such as the size and number of
OS heaps (or pools), the number of internal system worker threads, and
the size of the system data cache. Also, run-time policy decisions, such as
the way the memory manager trades off system and process memory de-
mands, differ between the server and client editions. Even some thread-
scheduling details have different default behavior in the two families (the
default length of the time slice, or thread quantum; see Chapter 4 for de-
tails). Where there are significant operational differences in the two
products, these are highlighted in the pertinent chapters throughout the
rest of this book. Unless otherwise noted, everything in this book applies
to both the client and server versions.
EXPERIMENT: DETERMINING FEATURES ENABLED BY LICENSING POLICY
C:\>SlPolicy.exe -f
Software License Policy Viewer Version 1.0 (C)2016 by Pavel Yosifovich
Desktop Windows Manager
Explorer
Fax
Kernel
IIS
...
You can then add the name of any facility after the switch to display
the policy value for that facility. For example, to look at the limitations on
CPUs and available memory, use the Kernel facility. Here’s the expected
output on a machine running Windows 10 Pro:
C:\>SlPolicy.exe -f Kernel
Software License Policy Viewer Version 1.0 (C)2016 by Pavel Yosifovich
Kernel
------
Maximum allowed processor sockets: 2
Maximum memory allowed in MB (x86): 4096
Maximum memory allowed in MB (x64): 2097152
Maximum memory allowed in MB (ARM64): 2097152
Maximum physical page in bytes: 4096
Device Family ID: 3
Native VHD boot: Yes
Dynamic Partitioning supported: No
Virtual Dynamic Partitioning supported: No
Memory Mirroring supported: No
Persist defective memory list: No
As another example, the output for the kernel facility for a Windows
Server 2012 R2 Datacenter edition would look something like this:
Kernel
------
Maximum allowed processor sockets: 64
Maximum memory allowed in MB (x86): 4096
Maximum memory allowed in MB (x64): 4194304
Add physical memory allowed: Yes
Add VM physical memory allowed: Yes
Maximum physical page in bytes: 0
Native VHD boot: Yes
Dynamic Partitioning supported: Yes
Virtual Dynamic Partitioning supported: Yes
Memory Mirroring supported: Yes
Persist defective memory list: Yes
Checked build
The checked build was provided primarily to aid device driver devel-
opers because it performs more stringent error-checking on kernel-mode
functions called by device drivers or other system code. For example, if a
driver (or some other piece of kernel-mode code) makes an invalid call to
a system function that is checking parameters (such as acquiring a spin-
lock at the wrong interrupt request level), the system will stop execution
when the problem is detected rather than allow some data structure to be
corrupted and the system to possibly crash at a later time. Because a full
checked build was often unstable and impossible to run in most environ-
ments, Microsoft provides a checked kernel and HAL only for Windows
10 and later. This enables developers to obtain the same level of useful-
ness from the kernel and HAL code they interact with without dealing
with the issues that a full checked build would cause. This checked kernel
and HAL pair is freely available through the WDK, in the \Debug direc-
tory of the root installation path. For detailed instructions on how to do
this, see the section “Installing Just the Checked Operating System and
HAL” in the WDK documentation.
EXPERIMENT: DETERMINING IF YOU ARE RUNNING THE CHECKED BUILD
There is no built-in tool to display whether you are running the checked
build or the retail build (called the free build) of the kernel. However, this
information is available through the Debug property of the Windows
Management Instrumentation (WMI) Win32_OperatingSystem class. The
following PowerShell script displays this property. (You can try this by
opening a PowerShell script host.)
This system is not running the checked build, because the Debug prop-
erty shown here says False .
Finally, the checked build can also be useful for testing user-mode code
only because the timing of the system is different. (This is because of the
additional checking taking place within the kernel and the fact that the
components are compiled without optimizations.) Often, multithreaded
synchronization bugs are related to specific timing conditions. By run-
ning your tests on a system running the checked build (or at least the
checked kernel and HAL), the fact that the timing of the whole system is
different might cause latent timing bugs to surface that do not occur on a
normal retail system.
Virtualization-based security architecture overview
As you saw in Chapter 1 and again in this chapter, the separation be-
tween user mode and kernel mode provides protection for the OS from
user-mode code, whether malicious or not. However, if an unwanted
piece of kernel-mode code makes it into the system (because of some yet-
unpatched kernel or driver vulnerability or because the user was tricked
into installing a malicious or vulnerable driver), the system is essentially
compromised because all kernel-mode code has complete access to the
entire system. The technologies outlined in Chapter 1, which leverage the
hypervisor to provide additional guarantees against attacks, make up a
set of virtualization-based security (VBS) capabilities, extending the
processor’s natural privilege-based separation through the introduction
of Virtual Trust Levels (VTLs). Beyond simply introducing a new orthogo-
nal way of isolating access to memory, hardware, and processor re-
sources, VTLs also require new code and components to manage the
higher levels of trust. The regular kernel and drivers, running in VTL 0,
cannot be permitted to control and define VTL 1 resources; this would de-
feat the purpose.
In this architecture, the secure kernel is its own separate binary, which
is found under the name securekernel.exe on disk. As for IUM, it’s both an
environment that restricts the allowed system calls that regular user-
mode DLLs can make (thus limiting which of these DLLs can be loaded)
and a framework that adds special secure system calls that can execute
only under VTL 1. These additional system calls are exposed in a similar
way as regular system calls: through an internal system library named
Iumdll.dll (the VTL 1 version of Ntdll.dll) and a Windows subsystem–fac-
ing library named Iumbase.dll (the VTL 1 version of Kernelbase.dll). This
implementation of IUM, mostly sharing the same standard Win32 API li-
braries, allows for the reduction of the memory overhead of VTL 1 user-
mode applications because essentially, the same user-mode code is
present as in their VTL 0 counterparts. As an important note, copy-on-
write mechanisms, which you’ll learn more about in Chapter 5, prevent
VTL 0 applications from making changes to binaries used by VTL 1.
With VBS, the regular user versus kernel rules apply, but are now aug-
mented by VTL considerations. In other words, kernel-mode code run-
ning at VTL 0 cannot touch user mode running at VTL 1 because VTL 1 is
more privileged. Yet, user-mode code running at VTL 1 cannot touch ker-
nel mode running at VTL 0 either because user (ring 3) cannot touch ker-
nel (ring 0). Similarly, VTL 1 user-mode applications must still go through
regular Windows system calls and their respective access checks if they
wish to access resources.
The secure kernel however, by both running at VTL 1 and being in ker-
nel mode, does have complete access to VTL 0 memory and resources. It
can use the hypervisor to limit the VTL 0 OS access to certain memory lo-
cations by leveraging CPU hardware support known as Second Level
Address Translation (SLAT). SLAT is the basis of Credential Guard technol-
ogy, which can store secrets in such locations. Similarly, the secure kernel
can use SLAT technology to interdict and control execution of memory lo-
cations, a key covenant of Device Guard.
The addition of the secure kernel and VBS is an exciting step in modern
OS architecture. With additional hardware changes to various buses such
as PCI and USB, it will soon be possible to support an entire class of se-
cure devices, which, when combined with a minimalistic secure HAL, se-
cure Plug-and-Play manager, and secure User-Mode Device Framework,
could allow certain VTL 1 applications direct and segregated access to
specially designated devices, such as for biometric or smartcard input.
New versions of Windows 10 are likely to leverage such advances.
Key system components
Each executable image (.exe) is bound to one and only one subsystem.
When an image is run, the process creation code examines the subsystem
type code in the image header so that it can notify the proper subsystem
of the new process. This type code is specified with the /SUBSYSTEM
linker option of the Microsoft Visual Studio linker (or through the
SubSystem entry in the Linker/System property page in the project’s
properties).
You can see the image subsystem type by using the Dependency Walker
tool (Depends.exe). For example, notice the image types for two different
Windows images, Notepad.exe (the simple text editor) and Cmd.exe (the
Windows command prompt):
Subsystem startup
Windows subsystem
• Portions of the support for 16-bit virtual DOS machine (VDM) processes
(32-bit Windows only)
NOTE
The console host process (Conhost.exe), which provides support for con-
sole (character cell) applications
NOTE
With Windows 8 and later, the console architecture changed yet again.
The Conhost.exe process remains, but is now spawned from the console-
based process (rather than from Csrss.exe, as in Windows 7) by the con-
sole driver (\Windows\System32\Drivers\ConDrv.sys). The process in
question communicates with Conhost.exe using the console driver
(ConDrv.sys), by sending read, write, I/O control and other I/O request
types. Conhost.exe is designated as a server and the process using the
console is the client. This change obviates the need for Csrss.exe to re-
ceive keyboard input (as part of the raw input thread), send it through
Win32k.sys to Conhost.exe, and then use ALPC to send it to Cmd.exe.
Instead, the command-line application can directly receive input from the
console driver through read/write I/Os, avoiding needless context
switching.
Other subsystems
Finally, it’s also important to point out, that as the name says, the
POSIX subsystem/SUA was designed with POSIX/UNIX applications in
mind, which dominated the server market decades ago, not true Linux
applications, which are common today.
Under this model, the idea of a Pico provider is defined, which is a cus-
tom kernel-mode driver that receives access to specialized kernel inter-
faces through the PsRegisterPicoProvider API. The benefits of these
specialized interfaces are two-fold:
They allow the provider to create Pico processes and threads while cus-
tomizing their execution contexts, segments, and store data in their re-
spective EPROCESS and ETHREAD structures (see Chapter 3 and Chapter 4
for more on these structures).
As the feature is still officially in beta at the time of this writing and
subject to significant change, we won’t cover the actual internals of the
subsystem in this book. We will, however, take another look at Pico pro-
cesses in Chapter 3. When the subsystem matures beyond beta, you will
probably see official documentation on MSDN and stable APIs for inter-
acting with Linux processes from Windows.
Ntdll.dll
Ntdll.dll is a special system support library primarily for the use of sub-
system DLLs and native applications. (Native in this context refers to im-
ages that are not tied to any particular subsystem.) It contains two types
of functions:
The first group of functions provides the interface to the Windows ex-
ecutive system services that can be called from user mode. There are
more than 450 such functions, such as NtCreateFile , NtSetEvent , and
so on. As noted, most of the capabilities of these functions are accessible
through the Windows API. (A number are not, however, and are for use
only by specific OS-internal components.)
For each of these functions, Ntdll.dll contains an entry point with the
same name. The code inside the function contains the architecture-spe-
cific instruction that causes a transition into kernel mode to invoke the
system service dispatcher. (This is explained in more detail in Chapter 8
in Part 2.) After verifying some parameters, this system service dispatcher
calls the actual kernel-mode system service that contains the real code in-
side Ntoskrnl.exe. The following experiment shows what these functions
look like.
EXPERIMENT: VIEWING THE SYSTEM SERVICE DISPATCHER CODE
Notepad should launch and the debugger should break in the initial
breakpoint. This is very early in the life of the process, which you can wit-
ness by executing the k (call stack) command. You should see a few func-
tions starting with Ldr , which indicates the image loader. The main func-
tion for Notepad has not executed yet, which means you won’t see
Notepad’s window.
bp ntdll!ntcreatefile
Breakpoint 0 hit
ntdll!NtCreateFile:
00007ffa'9f4e5b10 4c8bd1 mov r10,rcx
The EAX register is set with the system service number (55 hex in this
case). This is the system service number on this OS (Windows 10 Pro x64).
Then notice the syscall instruction. This is the one causing the proces-
sor to transition to kernel mode, jumping to the system service dis-
patcher, where that EAX is used to select the NtCreateFile executive
service. You’ll also notice a check for a flag ( 1 ) at offset 0x308 in the
Shared User Data (more information on this structure is available in
Chapter 4). If this flag is set, execution will take another path, by using the
int 2Eh instruction instead. If you enable the specific Credential Guard
VBS feature that is described in Chapter 7, this flag will be set on your ma-
chine, because the hypervisor can react to the int instruction in a more
efficient fashion than the syscall instruction, and this behavior is bene-
ficial to Credential Guard.
0:000> u iumdll!IumCrypto
iumdll!IumCrypto:
00000001'8000113a c3 ret
Executive
Functions that are exported and callable from user mode These func-
tions are called system services and are exported via Ntdll.dll (such as
NtCreateFile from the previous experiment). Most of the services are
accessible through the Windows API or the APIs of another environment
subsystem. A few services, however, aren’t available through any docu-
mented subsystem function. (Examples include ALPC and various query
functions such as NtQuery-InformationProcess , specialized functions
such as NtCreatePagingFile , and so on.)
Device driver functions that are called through the DeviceIoControl
function This provides a general interface from user mode to kernel
mode to call functions in device drivers that are not associated with a
read or write. The driver used for Process Explorer and Process Monitor
from Sysinternals are good examples of that as is the console driver
(ConDrv.sys) mentioned earlier.
Functions that can be called only from kernel mode that are ex-
ported and documented in the WDK These include various support rou-
tines, such as the I/O manager (start with Io ), general executive func-
tions ( Ex ) and more, needed for device driver developers.
Functions that are exported and can be called from kernel mode but
are not documented in the WDK These include the functions called by
the boot video driver, which start with Inbv .
Functions that are defined as global symbols but are not exported
These include internal support functions called within Ntoskrnl.exe, such
as those that start with Iop (internal I/O manager support functions) or
Mi (internal memory management support functions).
Functions that are internal to a module that are not defined as global
symbols These functions are used exclusively by the executive and
kernel.
Plug and Play (PnP) manager The PnP manager, covered in Chapter 6,
determines which drivers are required to support a particular device and
loads those drivers. It retrieves the hardware resource requirements for
each device during enumeration. Based on the resource requirements of
each device, the PnP manager assigns the appropriate hardware re-
sources such as I/O ports, IRQs, DMA channels, and memory locations. It
is also responsible for sending proper event notification for device
changes (the addition or removal of a device) on the system.
Hypervisor library and VBS library These provide kernel support for
the secure virtual machine environment and optimize certain parts of the
code when the system knows it’s running in a client partition (virtual
environment).
Event Tracing for Windows (ETW) ETW provides helper routines for
system-wide event tracing for kernel-mode and user-mode components.
Kernel objects
Outside the kernel, the executive represents threads and other share-
able resources as objects. These objects require some policy overhead,
such as object handles to manipulate them, security checks to protect
them, and resource quotas to be deducted when they are created. This
overhead is eliminated in the kernel, which implements a set of simpler
objects, called kernel objects, that help the kernel control central process-
ing and support the creation of executive objects. Most executive-level ob-
jects encapsulate one or more kernel objects, incorporating their kernel-
defined attributes.
The kernel uses a data structure called the kernel processor control region
(KPCR) to store processor-specific data. The KPCR contains basic informa-
tion such as the processor’s interrupt dispatch table (IDT), task state seg-
ment (TSS), and global descriptor table (GDT). It also includes the inter-
rupt controller state, which it shares with other modules, such as the
ACPI driver and the HAL. To provide easy access to the KPCR, the kernel
stores a pointer to it in the fs register on 32-bit Windows and in the gs
register on an x64 Windows system.
The KPCR also contains an embedded data structure called the kernel
processor control block (KPRCB). Unlike the KPCR, which is documented
for third-party drivers and other internal Windows kernel components,
the KPRCB is a private structure used only by the kernel code in
Ntoskrnl.exe. It contains the following:
Scheduling information such as the current, next, and idle threads sched-
uled for execution on the processor
The dispatcher database for the processor, which includes the ready
queues for each priority level
CPU and NUMA topology, such as node information, cores per package,
logical processors per core, and so on
Cache sizes
The KPRCB also contains all the statistics for the processor, such as:
I/O statistics
DPC statistics
You can view the contents of the KPCR and KPRCB by using the !pcr and
!prcb kernel debugger commands. For the latter, if you don’t include
flags, the debugger will display information for CPU 0 by default.
Otherwise, you can specify a CPU by adding its number after the com-
mand—for example, !prcb 2 . The former command, on the other hand,
will always display information on the current processor, which you can
change in a remote debugging session. If doing local debugging, you can
obtain the address of the KPCR by using the !pcr extension, followed by
the CPU number, then replacing @$pcr with that address. Do not use any
of the other output shown in the !pcr command. This extension is depre-
cated and shows incorrect data. The following example shows what the
output of the dt nt!_KPCR @$pcr and !prcb commands looks like
(Windows 10 x64):
You can also use the dt command to directly dump the _KPRCB data
structures because the debugger command gives you the address of the
structure (shown in bold for clarity in the previous output). For example,
if you wanted to determine the speed of the processor as detected at boot,
you could look at the MHz field with the following command:
On this machine, the processor was running at about 2.2 GHz during
boot-up.
Hardware support
The other major job of the kernel is to abstract or isolate the executive
and device drivers from variations between the hardware architectures
supported by Windows. This job includes handling variations in functions
such as interrupt handling, exception dispatching, and multiprocessor
synchronization.
Even for these hardware-related functions, the design of the kernel at-
tempts to maximize the amount of common code. The kernel supports a
set of interfaces that are portable and semantically identical across archi-
tectures. Most of the code that implements these portable interfaces is
also identical across architectures.
The kernel also contains a small amount of code with x86-specific in-
terfaces needed to support old 16-bit MS-DOS programs (on 32-bit sys-
tems). These x86 interfaces aren’t portable in the sense that they can’t be
called on a machine based on any other architecture; they won’t be
present. This x86-specific code, for example, supports calls to use Virtual
8086 mode, required for the emulation of certain real-mode code on older
video cards.
On x64 and ARM machines, there is only one HAL image, called Hal.dll.
This results from all x64 machines having the same motherboard configu-
ration, because the processors require ACPI and APIC support. Therefore,
there is no need to support machines without ACPI or with a standard
PIC. Similarly, all ARM systems have ACPI and use interrupt controllers,
which are similar to a standard APIC. Once again, a single HAL can sup-
port this.
You can view the relationship of the kernel and HAL images by using the
Dependency Walker tool (Depends.exe) to examine their export and im-
port tables. To examine an image in the Dependency Walker, open the
File menu, choose Open, and select the desired image file.
Bootvid.dll The Boot Video Driver on x86 systems (Bootvid) provides sup-
port for the VGA commands required to display boot text and the boot
logo during startup.
Kdcom.dll This is the Kernel Debugger Protocol (KD) communications
library.
Ci.dll This is the integrity library. (See Chapter 8 in Part 2 for more infor-
mation on code integrity.)
Msrpc.sys The Microsoft Remote Procedure Call (RPC) client driver for
kernel mode allows the kernel (and other drivers) to communicate with
user-mode services through RPC or to marshal MES-encoded assets. For
example, the kernel uses this to marshal data to and from the user-mode
Plug-and-Play service.
Ksr contract This handles Kernel Soft Reboot (KSR) and the required per-
sistence of certain memory ranges to support it, specifically on certain
mobile and IoT platforms.
Ucode contract This is the microcode update library for platforms that
can support processor microcode updates, such as Intel and AMD.
Clfs contract This is the Common Log File System driver, used by (among
other things) the Transactional Registry (TxR). For more information on
TxR, see Chapter 8 in Part 2.
Ium Contract These are additional policies for IUM Trustlets running on
the system, which may be needed on certain SKUs, such as for providing
shielded VMs on Datacenter Server. Trustlets are described further in
Chapter 3.
Device drivers
In the context of the user thread that initiated an I/O function (such as a
read operation)
File system drivers These are Windows drivers that accept file-oriented
I/O requests and translate them into I/O requests bound for a particular
device.
File system filter drivers These include drivers that perform disk mir-
roring and encryption or scanning to locate viruses, intercept I/O re-
quests, and perform some added-value processing before passing the I/O
to the next layer (or in some cases rejecting the operation).
Network redirectors and servers These are file system drivers that
transmit file system I/O requests to a machine on the network and receive
such requests, respectively.
Protocol drivers These implement a networking protocol such as TCP/IP,
NetBEUI, and IPX/SPX.
Software drivers These are kernel modules that perform operations that
can only be done in kernel mode on behalf of some user-mode process.
Many utilities from Sysinternals such as Process Explorer and Process
Monitor use drivers to get information or perform operations that are not
possible to do from user-mode APIs.
The original driver model was created in the first NT version (3.1) and did
not support the concept of Plug and Play (PnP) because it was not yet
available. This remained the case until Windows 2000 came along (and
Windows 95/98 on the consumer Windows side).
Windows 2000 added support for PnP, Power Options, and an exten-
sion to the Windows NT driver model called the Windows Driver Model
(WDM). Windows 2000 and later can run legacy Windows NT 4 drivers,
but because these don’t support PnP and Power Options, systems running
these drivers will have reduced capabilities in these two areas.
Function drivers A function driver is the main device driver and pro-
vides the operational interface for its device. It is a required driver unless
the device is used raw, an implementation in which I/O is done by the bus
driver and any bus filter drivers, such as SCSI PassThru. A function driver
is by definition the driver that knows the most about a particular device,
and it is usually the only driver that accesses device-specific registers.
UMDF has two major versions: version 1.x is available for all OS ver-
sions that support UMDF, the latest and last being version 1.11, available
in Windows 10. This version uses C++ and COM for driver writing, which
is rather convenient for user-mode programmers, but it makes the UMDF
model different from KMDF. Version 2.0 of UMDF, introduced in
Windows 8.1, is based around the same object model as KMDF, making
the two frameworks very similar in their programming model. Finally,
WDF has been open-sourced by Microsoft, and at the time of this writing
is available on GitHub at https://github.com/Microsoft/Windows-Driver-
Frameworks.
Starting with Windows 10, the term Universal Windows drivers refers to
the ability to write device drivers once that share APIs and Device Driver
Interfaces (DDIs) provided by the Windows 10 common core. These driv-
ers are binary-compatible for a specific CPU architecture (x86, x64, ARM)
and can be used as is on a variety of form factors, from IoT devices, to
phones, to the HoloLens and Xbox One, to laptops and desktops. Universal
drivers can use KMDF, UMDF 2.x, or WDM as their driver model.
EXPERIMENT: VIEWING THE INSTALLED DEVICE DRIVERS
This window displays the list of device drivers defined in the registry,
their type, and their state (Running or Stopped). Device drivers and
Windows service processes are both defined in the same place:
HKLM\SYSTEM\CurrentControlSet\Services. However, they are distin-
guished by a type code. For example, type 1 is a kernel-mode device
driver. For a complete list of the information stored in the registry for de-
vice drivers, see Chapter 9 in Part 2.
Alternatively, you can list the currently loaded device drivers by select-
ing the System process in Process Explorer and opening the DLL view.
Here’s a sample output. (To get the extra columns, right-click a column
header and click Select Columns to see all the available columns for
modules in the DLL tab.)
PEERING INTO UNDOCUMENTED INTERFACES
Examining the names of the exported or global symbols in key system im-
ages (such as Ntoskrnl.exe, Hal.dll, or Ntdll.dll) can be enlightening—you
can get an idea of the kinds of things Windows can do versus what hap-
pens to be documented and supported today. Of course, just because you
know the names of these functions doesn’t mean that you can or should
call them—the interfaces are undocumented and are subject to change.
We suggest that you look at these functions purely to gain more insight
into the kinds of internal functions Windows performs, not to bypass sup-
ported interfaces.
For example, looking at the list of functions in Ntdll.dll gives you the
list of all the system services that Windows provides to user-mode subsys-
tem DLLs versus the subset that each subsystem exposes. Although many
of these functions map clearly to documented and supported Windows
functions, several are not exposed via the Windows API.
Table 2-5 lists most of the commonly used function name prefixes for
the executive components. Each of these major executive components
also uses a variation of the prefix to denote internal functions—either the
first letter of the prefix followed by an i (for internal) or the full prefix
followed by a p (for private). For example, Ki represents internal kernel
functions, and Psp refers to internal process support functions.
TABLE 2-5 Commonly Used Prefixes
You can decipher the names of these exported functions more easily if
you understand the naming convention for Windows system routines.
The general format is
<Prefix><Operation><Object>
In this format, Prefix is the internal component that exports the rou-
tine, Operation tells what is being done to the object or resource, and
Object identifies what is being operated on.
Idle process This contains one thread per CPU to account for idle CPU
time.
Secure System process This contains the address space of the secure ker-
nel in VTL 1, if running.
The next sections explain the key system processes shown in Figure 2-
6. Although these sections briefly indicate the order of process startup,
Chapter 11 in Part 2, contains a detailed description of the steps involved
in booting and starting Windows.
System idle process
The first process listed in Figure 2-6 is the Idle process. As discussed in
Chapter 3, processes are identified by their image name. However, this
process—as well as the System, Secure System, and Memory Compression
processes—isn’t running a real user-mode image. That is, there is no
“System Idle Process.exe” in the \Windows directory. In addition, because
of implementation details, the name shown for this process differs from
utility to utility. The Idle process accounts for idle time. That’s why the
number of “threads” in this “process” is the number of logical processors
on the system. Table 2-6 lists several of the names given to the Idle
process (process ID 0). The Idle process is explained in detail in Chapter 3.
Now let’s look at system threads and the purpose of each of the system
processes that are running real images.
The System process (process ID 4) is the home for a special kind of thread
that runs only in kernel mode: a kernel-mode system thread. System
threads have all the attributes and contexts of regular user-mode threads
such as a hardware context, priority, and so on, but differ in that they run
only in kernel-mode executing code loaded in system space, whether that
is in Ntoskrnl.exe or in any other loaded device driver. In addition, sys-
tem threads don’t have a user process address space and hence must allo-
cate any dynamic storage from OS memory heaps, such as a paged or
non-paged pool.
NOTE
By default, system threads are owned by the System process, but a de-
vice driver can create a system thread in any process. For example, the
Windows subsystem device driver (Win32k.sys) creates a system thread
inside the Canonical Display Driver (Cdd.dll) part of the Windows subsys-
tem process (Csrss.exe) so that it can easily access data in the user-mode
address space of that process.
The Secure System process (variable process ID) is technically the home
of the VTL 1 secure kernel address space, handles, and system threads.
That being said, because scheduling, object management, and memory
management are owned by the VTL 0 kernel, no such actual entities will
be associated with this process. Its only real use is to provide a visual in-
dicator to users (for example, in tools such as Task Manager and Process
Explorer) that VBS is currently active (providing at least one of the fea-
tures that leverages it).
Memory Compression process
Additionally, unlike the other System processes in this list, this process
actually stores its memory in the user-mode address space. This means it
is subject to working set trimming and will potentially have large visible
memory usage in system-monitoring tools. In fact, if you view the
Performance tab in Task Manager, which now shows both in-use and
compressed memory, you should see that the size of the Memory
Compression process’s working set is equal to the amount of compressed
memory.
Session Manager
9. It creates the initial process environment block and updates the Safe
Mode variable if needed.
12. It saves the program path listed in the S0InitialCommand value under
the HKLM\SYSTEM\ CurrentControlSet\Control\Session Manager key.
19. It reads and saves the KnownDlls value list stored in the
HKLM\SYSTEM\CurrentControlSet\Control\Session Manager key.
20. It creates system-wide environment variables as defined in
HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment.
24. It creates protected mailslot and named pipe prefixes to protect service
applications from spoofing attacks that could occur if a malicious user-
mode application executes before a service does.
26. It initializes the rest of the registry (HKLM software, SAM, and security
hives).
27. Unless disabled by the registry, it executes the Windows Platform Binary
Table (WPBT) binary registered in the respective ACPI table. This is often
used by anti-theft vendors to force the execution of a very early native
Windows binary that can call home or set up other services for execution,
even on a freshly installed system. These processes must link with
Ntdll.dll only (that is, belong to the native subsystem).
28. It processes pending file renames as specified in the registry keys seen
earlier unless this is a Windows Recovery Environment boot.
29. It initializes paging file(s) and dedicated dump file information based on
the HKLM\System\CurrentControlSet\Control\Session Manager\Memory
Management and HKLM\System\CurrentControlSet\Control\CrashControl
keys.
30. It checks the system’s compatibility with memory cooling technology,
used on NUMA systems.
31. It saves the old paging file, creates the dedicated crash dump file, and
creates new paging files as needed based on previous crash information.
35. It opens known DLLs and maps them as permanent sections (mapped
files) except those listed as exclusions in the earlier registry checks (none
listed by default).
After these steps have been completed, Smss.exe waits forever on the
handle to the session 0 instance of Csrss.exe. Because Csrss.exe is marked
as a critical process (and is also a protected process; see Chapter 3), if
Csrss.exe exits, this wait will never complete because the system will
crash.
It creates the subsystem process(es) for the session (by default, the
Windows subsystem Csrss.exe).
1. It marks itself and the main thread critical so that if it exits prematurely
and the system is booted in debugging mode, it will break into the debug-
ger. (Otherwise, the system will crash.)
6. It increases its own process base priority to high (13) and its main
thread’s priority to 15.
12. It creates the initial terminal, which is composed of a window station (al-
ways named Winsta0) and two desktops (Winlogon and Default) for pro-
cesses to run on in session 0.
13. It initializes the LSA machine encryption key, depending on whether it’s
stored locally or if it must be entered interactively. See Chapter 7 for more
information on how local authentication keys are stored.
14. It creates the Service Control Manager (SCM or Services.exe). See the up-
coming paragraphs for a brief description and Chapter 9 in Part 2 for
more details.
16. If Setup is currently pending (that is, if this is the first boot during a fresh
install or an update to a new major OS build or Insider Preview), it
launches the setup program.
17. It waits forever for a request for system shutdown or for one of the afore-
mentioned system processes to terminate (unless the
DontWatchSysProcs registry value is set in the Winlogon key mentioned
in step 7). In either case, it shuts down the system.
Recall that with Windows, services can refer to either a server process or
a device driver. This section deals with services that are user-mode pro-
cesses. Services are like Linux daemon processes in that they can be con-
figured to start automatically at system boot time without requiring an
interactive logon. They can also be started manually, such as by running
the Services administrative tool, using the sc.exe tool, or calling the
Windows StartService function. Typically, services do not interact with
the logged-on user, although there are special conditions when this is pos-
sible. Additionally, while most services run in special service accounts
(such as SYSTEM or LOCAL SERVICE), others can run with the same secu-
rity context as logged-in user accounts. (For more, see Chapter 9 in Part
2.)
Keep in mind that services have three names: the process name you
see running on the system, the internal name in the registry, and the dis-
play name shown in the Services administrative tool. (Not all services
have a display name—if a service doesn’t have a display name, the inter-
nal name is shown.) Services can also have a description field that further
details what the service does.
After the user name and password (or another information bundle as
the credential provider requires) have been captured, they are sent to the
Local Security Authentication Service process (Lsass.exe, described in
Chapter 7) to be authenticated. Lsass.exe calls the appropriate authentica-
tion package, implemented as a DLL, to perform the actual verification,
such as checking whether a password matches what is stored in the
Active Directory or the SAM (the part of the registry that contains the def-
inition of the local users and groups). If Credential Guard is enabled, and
this is a domain logon, Lsass.exe will communicate with the Isolated LSA
Trustlet (Lsaiso.exe, described in Chapter 7) to obtain the machine key re-
quired to authenticate the legitimacy of the authentication request.
Winlogon.exe is active not only during user logon and logoff, but also
whenever it intercepts the SAS from the keyboard. For example, when
you press Ctrl+Alt+Delete while logged on, the Windows Security screen
comes up, providing the options to log off, start the Task Manager, lock
the workstation, shut down the system, and so forth. Winlogon.exe and
LogonUI.exe are the processes that handle this interaction.