SlideShare a Scribd company logo
Full download ebooks at ebookmeta.com
Windows Kernel Programming Second Edition Pavel
Yosifovich
https://ebookmeta.com/product/windows-kernel-programming-
second-edition-pavel-yosifovich/
OR CLICK BUTTON
DOWLOAD NOW
Download more ebook from https://ebookmeta.com
More products digital (pdf, epub, mobi) instant
download maybe you interests ...
Windows Kernel Programming 2nd Edition Pavel Yosifovich
https://ebookmeta.com/product/windows-kernel-programming-2nd-
edition-pavel-yosifovich/
Windows 10 System Programming Part 2 Pavel Yosifovich
https://ebookmeta.com/product/windows-10-system-programming-
part-2-pavel-yosifovich/
Windows registry forensics advanced digital forensic
analysis of the Windows registry Second Edition Carvey
https://ebookmeta.com/product/windows-registry-forensics-
advanced-digital-forensic-analysis-of-the-windows-registry-
second-edition-carvey/
Mastering Linux Kernel Development A kernel developer s
reference manual 1st Edition Raghu Bharadwaj
https://ebookmeta.com/product/mastering-linux-kernel-development-
a-kernel-developer-s-reference-manual-1st-edition-raghu-
bharadwaj/
Expert Python Programming - Second Edition Micha■
Jaworski
https://ebookmeta.com/product/expert-python-programming-second-
edition-michal-jaworski/
Beginning Windows Mixed Reality Programming: For
HoloLens and Mixed Reality Headsets, 2nd Edition Sean
Ong
https://ebookmeta.com/product/beginning-windows-mixed-reality-
programming-for-hololens-and-mixed-reality-headsets-2nd-edition-
sean-ong/
Functional Programming in C Second Edition Enrico
Buonanno
https://ebookmeta.com/product/functional-programming-in-c-second-
edition-enrico-buonanno/
The Rust Programming Language, Second Edition Steve
Klabnik
https://ebookmeta.com/product/the-rust-programming-language-
second-edition-steve-klabnik/
Communication And Libertarianism 1st Edition Pavel
Slutskiy
https://ebookmeta.com/product/communication-and-
libertarianism-1st-edition-pavel-slutskiy/
Instant Access to Windows Kernel Programming Second Edition Pavel Yosifovich ebook Full Chapters
Windows Kernel Programming,
Second Edition
Pavel Yosifovich
This book is for sale at
http://leanpub.com/windowskernelprogrammingsecondedition
This version was published on 2022-01-22
* * * * *
This is a Leanpub book. Leanpub empowers authors and publishers
with the Lean Publishing process. Lean Publishing is the act of
publishing an in-progress ebook using lightweight tools and many
iterations to get reader feedback, pivot until you have the right book
and build traction once you do.
* * * * *
© 2020 - 2022 Pavel Yosifovich
Table of Contents
Introduction
Who Should Read This Book
What You Should Know to Use This Book
Book Contents
Sample Code
Chapter 1: Windows Internals Overview
Processes
Virtual Memory
Page States
System Memory
Threads
Thread Stacks
System Services (a.k.a. System Calls)
General System Architecture
Handles and Objects
Object Names
Accessing Existing Objects
Chapter 2: Getting Started with Kernel
Development
Installing the Tools
Creating a Driver Project
The DriverEntry and Unload Routines
Deploying the Driver
Simple Tracing
Summary
Chapter 3: Kernel Programming Basics
General Kernel Programming Guidelines
Unhandled Exceptions
Termination
Function Return Values
IRQL
C++ Usage
Testing and Debugging
Debug vs. Release Builds
The Kernel API
Functions and Error Codes
Strings
Dynamic Memory Allocation
Linked Lists
The Driver Object
Object Attributes
Device Objects
Opening Devices Directly
Summary
Chapter 4: Driver from Start to Finish
Introduction
Driver Initialization
Passing Information to the Driver
Client / Driver Communication Protocol
Creating the Device Object
Client Code
The Create and Close Dispatch Routines
The Write Dispatch Routine
Installing and Testing
Summary
Chapter 5: Debugging and Tracing
Debugging Tools for Windows
Introduction to WinDbg
Tutorial: User mode debugging basics
Kernel Debugging
Local Kernel Debugging
Local kernel Debugging Tutorial
Full Kernel Debugging
Using a Virtual Serial Port
Using the Network
Kernel Driver Debugging Tutorial
Asserts and Tracing
Asserts
Extended DbgPrint
Other Debugging Functions
Trace Logging
Viewing ETW Traces
Summary
Chapter 6: Kernel Mechanisms
Interrupt Request Level (IRQL)
Raising and Lowering IRQL
Thread Priorities vs. IRQLs
Deferred Procedure Calls
Using DPC with a Timer
Asynchronous Procedure Calls
Critical Regions and Guarded Regions
Structured Exception Handling
Using __try/__except
Using __try/__finally
Using C++ RAII Instead of __try / __finally
System Crash
Crash Dump Information
Analyzing a Dump File
System Hang
Thread Synchronization
Interlocked Operations
Dispatcher Objects
Mutex
Fast Mutex
Semaphore
Event
Named Events
Executive Resource
High IRQL Synchronization
The Spin Lock
Queued Spin Locks
Work Items
Summary
Chapter 7: The I/O Request Packet
Introduction to IRPs
Device Nodes
IRP Flow
IRP and I/O Stack Location
Viewing IRP Information
Dispatch Routines
Completing a Request
Accessing User Buffers
Buffered I/O
Direct I/O
User Buffers for IRP_MJ_DEVICE_CONTROL
Putting it All Together: The Zero Driver
Using a Precompiled Header
The DriverEntry Routine
The Create and Close Dispatch Routines
The Read Dispatch Routine
The Write Dispatch Routine
Test Application
Read/Write Statistics
Summary
Chapter 8: Advanced Programming Techniques
(Part 1)
Driver Created Threads
Memory Management
Pool Allocations
Secure Pools
Overloading the new and delete Operators
Lookaside Lists
The “Classic” Lookaside API
The Newer Lookaside API
Calling Other Drivers
Putting it All Together: The Melody Driver
Client Code
Invoking System Services
Example: Enumerating Processes
Summary
Chapter 9: Process and Thread Notifications
Process Notifications
Implementing Process Notifications
The DriverEntry Routine
Handling Process Exit Notifications
Handling Process Create Notifications
Providing Data to User Mode
The User Mode Client
Thread Notifications
Image Load Notifications
Final Client Code
Remote Thread Detection
The Detector Client
Summary
Introduction
Windows kernel programming is considered by many a dark art,
available to select few that manage to somehow unlock the
mysteries of the Windows kernel. Kernel development, however, is
no different than user-mode development, at least in general terms.
In both cases, a good understanding of the platform is essential for
producing high quality code.
The book is a guide to programming within the Windows kernel,
using the well-known Visual Studio integrated development
environment (IDE). This environment is familiar to many developers
in the Microsoft space, so that the learning curve is restricted to
kernel understanding, coding and debugging, with less friction from
the development tools.
The book targets software device drivers, a term I use to refer to
drivers that do not deal with hardware. Software kernel drivers have
full access to the kernel, allowing these to perform any operation
allowed by the kernel. Some software drivers are more specific, such
as file system mini filters, also described in the book.
Who Should Read This Book
The book is intended for software developers that target the
Windows kernel, and need to write kernel drivers to achieve their
goals. Common scenarios where kernel drivers are employed are in
the Cyber Security space, where kernel drivers are the chief
mechanism to get notified of important events, with the power to
intercept certain operations. The book uses C and C++ for code
examples, as the kernel API is all C. C++ is used where it makes
sense, where its advantages are obvious in terms of maintenance,
clarity, resource management, or any combination of these. The
book does not use complex C++ constructs, such as template
metaprogramming. The book is not about C++, it’s about Windows
kernel drivers.
What You Should Know to Use This
Book
Readers should be very comfortable with the C programming
language, especially with pointers, structures, and its standard
library, as these occur very frequently when working with kernel
APIs. Basic C++ knowledge is highly recommended, although it is
possible to traverse the book with C proficiency only.
Book Contents
Here is a quick rundown of the chapters in the book:
Chapter 1 (“Windows Internals Overview) provides the
fundamentals of the internal workings of the Windows OS at a
high level, enough to get the fundamentals without being
bogged down by too many details.
Chapter 2 (“Getting Started with Kernel Development”)
describes the tools and procedures needed to set up a
development environment for developing kernel drivers. A very
simple driver is created to make sure all the tools and
procedures are working correctly.
Chapter 3 (“Kernel Programming Basics) looks at the
fundamentals of writing drivers, including bssic kernel APIs,
handling of common programming tasks involving strings, linked
lists, dynamic memory allocations, and more.
Chapter 4 (“Driver from Start to Finish”) shows how to build a
complete driver that performs some useful functionality, along
with a client application to drive it.
If you are new to Windows kernel development, you should read
chapters 1 to 7 in order. Chapter 8 contains some advanced material
you may want to go back to after you have built a few simple
drivers. Chapters 9 onward describe specialized techniques, and in
theory at least, can be read in any order.
Sample Code
All the sample code from the book is freely available on the book’s
Github repository at
https://github.com/zodiacon/windowskernelprogrammingbook2e.
Updates to the code samples will be pushed to this repository. It’s
recommended the reader clone the repository to the local machine,
so it’s easy to experiment with the code directly.
All code samples have been compiled with Visual Studio 2019. It’s
possible to compile most code samples with earlier versions of Visual
Studio if desired. There might be few features of the latest C++
standards that may not be supported in earlier versions, but these
should be easy to fix.
Happy reading!
Pavel Yosifovich
June 2022
Chapter 1: Windows Internals
Overview
This chapter describes the most important concepts in the internal
workings of Windows. Some of the topics will be described in greater
detail later in the book, where it’s closely related to the topic at hand.
Make sure you understand the concepts in this chapter, as these make
the foundations upon any driver and even user mode low-level code, is
built.
In this chapter:
Processes
Virtual Memory
Threads
System Services
System Architecture
Handles and Objects
Processes
A process is a containment and management object that represents a
running instance of a program. The term “process runs” which is used
fairly often, is inaccurate. Processes don’t run – processes manage.
Threads are the ones that execute code and technically run. From a
high-level perspective, a process owns the following:
An executable program, which contains the initial code and data
used to execute code within the process. This is true for most
processes, but some special ones don’t have an executable image
(created directly by the kernel).
A private virtual address space, used for allocating memory for
whatever purposes the code within the process needs it.
An access token (called primary token), which is an object that
stores the security context of the process, used by threads
executing in the process (unless a thread assumes a different token
by using impersonation).
A private handle table to executive objects, such as events,
semaphores, and files.
One or more threads of execution. A normal user-mode process is
created with one thread (executing the classic main/WinMain
function). A user mode process without threads is mostly useless,
and under normal circumstances will be destroyed by the kernel.
These elements of a process are depicted in figure 1-1.
Figure 1-1: Important ingredients of a process
A process is uniquely identified by its Process ID, which remains unique
as long as the kernel process object exists. Once it’s destroyed, the
same ID may be reused for new processes. It’s important to realize that
the executable file itself is not a unique identifier of a process. For
example, there may be five instances of notepad.exe running at the
same time. Each of these Notepad instances has its own address space,
threads, handle table, process ID, etc. All those five processes are using
the same image file (notepad.exe) as their initial code and data. Figure
1-2 shows a screenshot of Task Manager’s Details tab showing five
instances of Notepad.exe, each with its own attributes.
Figure 1-2: Five instances of notepad
Virtual Memory
Every process has its own virtual, private, linear address space. This
address space starts out empty (or close to empty, since the executable
image and NtDll.Dll are the first to be mapped, followed by more
subsystem DLLs). Once execution of the main (first) thread begins,
memory is likely to be allocated, more DLLs loaded, etc. This address
space is private, which means other processes cannot access it directly.
The address space range starts at zero (technically the first and last
64KB of the address space cannot be committed), and goes all the way
to a maximum which depends on the process “bitness” (32 or 64 bit)
and the operating system “bitness” as follows:
For 32-bit processes on 32-bit Windows systems, the process
address space size is 2 GB by default.
For 32-bit processes on 32-bit Windows systems that use the
increase user virtual address space setting, can be configured to
have up to 3GB of address space per process. To get the extended
address space, the executable from which the process was created
must have been marked with the LARGEADDRESSAWARE linker flag in its
PE header. If it was not, it would still be limited to 2 GB.
For 64-bit processes (on a 64-bit Windows system, naturally), the
address space size is 8 TB (Windows 8 and earlier) or 128 TB
(Windows 8.1 and later).
For 32-bit processes on a 64-bit Windows system, the address
space size is 4 GB if the executable image has the
LARGEADDRESSAWARE flag in its PE header. Otherwise, the size remains
at 2 GB.
The requirement of the LARGEADDRESSAWARE flag stems from the fact that a 2 GB
address range requires 31 bits only, leaving the most significant bit (MSB) free
for application use. Specifying this flag indicates that the program is not using
bit 31 for anything and so having that bit set (which would happen for
addresses larger than 2 GB) is not an issue.
Each process has its own address space, which makes any process
address relative, rather than absolute. For example, when trying to
determine what lies in address 0x20000, the address itself is not
enough; the process to which this address relates to must be specified.
The memory itself is called virtual, which means there is an indirect
relationship between an address and the exact location where it’s found
in physical memory (RAM). A buffer within a process may be mapped to
physical memory, or it may temporarily reside in a file (such as a page
file). The term virtual refers to the fact that from an execution
perspective, there is no need to know if the memory about to be
accessed is in RAM or not; if the memory is indeed mapped to RAM, the
CPU will perform the virtual-to-physical translation before accessing the
data. if the memory is not resident (specified by a flag in the translation
table entry), the CPU will raise a page fault exception that causes the
memory manager’s page fault handler to fetch the data from the
appropriate file (if indeed it’s a valid page fault), copy it to RAM, make
the required changes in the page table entries that map the buffer, and
instruct the CPU to try again. Figure 1-3 shows this conceptual mapping
from virtual to physical memory for two processes.
Figure 1-3: virtual memory mapping
The unit of memory management is called a page. Every attribute
related to memory is always at a page’s granularity, such as its
protection or state. The size of a page is determined by CPU type (and
on some processors, may be configurable), and in any case, the memory
manager must follow suit. Normal (sometimes called small) page size is
4 KB on all Windows-supported architectures.
Apart from the normal (small) page size, Windows also supports large
pages. The size of a large page is 2 MB (x86/x64/ARM64) or 4 MB
(ARM). This is based on using the Page Directory Entry (PDE) to map the
large page without using a page table. This results in quicker translation,
but most importantly better use of the Translation Lookaside Buffer
(TLB) – a cache of recently translated pages maintained by the CPU. In
the case of a large page, a single TLB entry maps significantly more
memory than a small page.
The downside of large pages is the need to have the memory contiguous in
RAM, which can fail if memory is tight or very fragmented. Also, large pages
are always non-pageable and can only use read/write protection.
Huge pages of 1 GB in size are supported on Windows 10 and Server
2016 and later. These are used automatically with large pages if an
allocation is at least 1 GB in size, and that size can be located as
contiguous in RAM.
Page States
Each page in virtual memory can be in one of three states:
Free – the page is not allocated in any way; there is nothing there.
Any attempt to access that page would cause an access violation
exception. Most pages in a newly created process are free.
Committed – the reverse of free; an allocated page that can be
accessed successfully (assuming non-conflicting protection
attributes; for example, writing to a read-only page causes an
access violation). Committed pages are mapped to RAM or to a file
(such as a page file).
Reserved – the page is not committed, but the address range is
reserved for possible future commitment. From the CPU’s
perspective, it’s the same as Free – any access attempt raises an
access violation exception. However, new allocation attempts using
the VirtualAlloc function (or NtAllocateVirtualMemory, the related
native API) that does not specify a specific address would not
allocate in the reserved region. A classic example of using reserved
memory to maintain contiguous virtual address space while
conserving committed memory usage is described later in this
chapter in the section “Thread Stacks”.
System Memory
The lower part of the address space is for user-mode processes use.
While a particular thread is executing, its associated process address
space is visible from address zero to the upper limit as described in the
previous section. The operating system, however, must also reside
somewhere – and that somewhere is the upper address range that’s
supported on the system, as follows:
On 32-bit systems running without the increase user virtual address
space setting, the operating system resides in the upper 2 GB of
virtual address space, from address 0x80000000 to 0xFFFFFFFF.
On 32-bit systems configured with the increase user virtual address
space setting, the operating system resides in the address space
left. For example, if the system is configured with 3 GB user address
space per process (the maximum), the OS takes the upper 1 GB
(from address 0xC0000000 to 0xFFFFFFFF). The component that
suffers mostly from this address space reduction is the file system
cache.
On 64-bit systems running Windows 8, Server 2012 and earlier, the
OS takes the upper 8 TB of virtual address space.
On 64-bit systems running Windows 8.1, Server 2012 R2 and later,
the OS takes the upper 128 TB of virtual address space.
Figure 1-4 shows the virtual memory layout for the two “extreme” cases:
32-bit process on a 32-bit system (left) and a 64-bit process on a 64-bit
system (right).
Figure 1-4: virtual memory layout
System space is not process-relative – after all, it’s the same system, the
same kernel, the same drivers that service every process on the system
(the exception is some system memory that is on a per-session basis but
is not important for this discussion). It follows that any address in
system space is absolute rather than relative, since it “looks” the same
from every process context. Of course, actual access from user mode
into system space results in an access violation exception.
System space is where the kernel itself, the Hardware Abstraction Layer
(HAL), and kernel drivers reside once loaded. Thus, kernel drivers are
automatically protected from direct user mode access. It also means
they have a potentially system-wide impact. For example, if a kernel
driver leaks memory, that memory will not be freed even after the driver
unloads. User-mode processes, on the other hand, can never leak
anything beyond their lifetime. The kernel is responsible for closing and
freeing everything private to a dead process (all handles are closed and
all private memory is freed).
Threads
The actual entities that execute code are threads. A Thread is contained
within a process, using the resources exposed by the process to do work
(such as virtual memory and handles to kernel objects). The most
important information a thread owns is the following:
Current access mode, either user or kernel.
Execution context, including processor registers and execution state.
One or two stacks, used for local variable allocations and call
management.
Thread Local Storage (TLS) array, which provides a way to store
thread-private data with uniform access semantics.
Base priority and a current (dynamic) priority.
Processor affinity, indicating on which processors the thread is
allowed to run on.
The most common states a thread can be in are:
Running – currently executing code on a (logical) processor.
Ready – waiting to be scheduled for execution because all relevant
processors are busy or unavailable.
Waiting – waiting for some event to occur before proceeding. Once
the event occurs, the thread goes to the Ready state.
Figure 1-5 shows the state diagram for these states. The numbers in
parenthesis indicate the state numbers, as can be viewed by tools such
as Performance Monitor. Note that the Ready state has a sibling state
called Deferred Ready, which is similar, and exists to minimize internal
locking.
Figure 1-5: Common thread states
Thread Stacks
Each thread has a stack it uses while executing, used to store local
variables, parameters passed to functions (in some cases), and where
return addresses are stored prior to making function calls. A thread has
at least one stack residing in system (kernel) space, and it’s pretty small
(default is 12 KB on 32-bit systems and 24 KB on 64-bit systems). A
user-mode thread has a second stack in its process user-space address
range and is considerably larger (by default can grow to 1 MB). An
example with three user-mode threads and their stacks is shown in
figure 1-6. In the figure, threads 1 and 2 are in process A and thread 3
is in process B.
The kernel stack always resides in RAM while the thread is in the
Running or Ready states. The reason for this is subtle and will be
discussed later in this chapter. The user-mode stack, on the other hand,
may be paged out, just like any other user-mode memory.
The user-mode stack is handled differently than the kernel-mode stack
in terms of its size. It starts out with a certain amount of committed
memory (could be as small as a single page), where the next page is
committed with a PAGE_GUARD attribute. The rest of the stack address
space memory is reserved, thus not wasting memory. The idea is to
grow the stack in case the thread’s code needs to use more stack space.
If the thread needs more stack space it would access the guard page
which would throw a page-guard exception. The memory manager then
removes the guard protection, and commits an additional page, marking
it with a PAGE_GUARD attribute. This way, the stack grows as needed,
avoiding the entire stack memory being committed upfront. Figure 1-7
shows this layout.
Figure 1-6: User mode threads
and their stacks
Technically, Windows uses 3 guard pages rather than one in most cases.
Figure 1-7: Thread’s stack in user space
The sizes of a thread’s user-mode stack are determined as follows:
The executable image has a stack commit and reserved values in its
Portable Executable (PE) header. These are taken as defaults if a
thread does not specify alternative values. These are always used
for the first thread in the process.
When a thread is created with CreateThread (or similar functions),
the caller can specify its required stack size, either the upfront
committed size or the reserved size (but not both), depending on a
flag provided to the function; specifying zero uses the defaults set in
the PE header.
Curiously enough, the functions CreateThread and CreateRemoteThread(Ex) only
allow specifying a single value for the stack size and can be the committed or
the reserved size, but not both. The native (undocumented) function,
NtCreateThreadEx allows specifying both values.
System Services (a.k.a. System Calls)
Applications need to perform various operations that are not purely
computational, such as allocating memory, opening files, creating
threads, etc. These operations can only be ultimately performed by code
running in kernel mode. So how would user-mode code be able to
perform such operations?
Let’s take a common (simple) example: a user running a Notepad
process uses the File / Open menu to request opening a file. Notepad’s
code responds by calling the CreateFile documented Windows API
function. CreateFile is documented as implemented in kernel32.Dll,
one of the Windows subsystem DLLs. This function still runs in user
mode, so there is no way it can directly open a file. After some error
checking, it calls NtCreateFile, a function implemented in NTDLL.dll, a
foundational DLL that implements the API known as the Native API, and
is the lowest layer of code which is still in user mode. This function
(documented in the Windows Driver Kit for device driver developers) is
the one that makes the transition to kernel mode. Before the actual
transition, it puts a number, called system service number, into a CPU
register (EAX on Intel/AMD architectures). Then it issues a special CPU
instruction (syscall on x64 or sysenter on x86) that makes the actual
transition to kernel mode while jumping to a predefined routine called
the system service dispatcher.
The system service dispatcher, in turn, uses the value in that EAX register
as an index into a System Service Dispatch Table (SSDT). Using this
table, the code jumps to the system service (system call) itself. For our
Notepad example, the SSDT entry would point to the NtCreateFile
function, implemented by the kernel’s I/O manager. Notice the function
has the same name as the one in NTDLL.dll, and has the same
parameters as well. On the kernel side is the real implementation. Once
the system service is complete, the thread returns to user mode to
execute the instruction following sysenter/syscall. This sequence of
calls is depicted in figure 1-8.
Figure 1-8: System service function call flow
General System Architecture
Figure 1-9 shows the general architecture of Windows, comprising of
user-mode and kernel-mode components.
Figure 1-9: Windows system architecture
Here’s a quick rundown of the named boxes appearing in figure 1-9:
User processes
These are normal processes based on image files, executing on the
system, such as instances of Notepad.exe, cmd.exe, explorer.exe,
and so on.
Subsystem DLLs
Subsystem DLLs are dynamic link libraries (DLLs) that implement
the API of a subsystem. A subsystem is a particular view of the
capabilities exposed by the kernel. Technically, starting from
Windows 8.1, there is only a single subsystem – the Windows
Subsystem. The subsystem DLLs include well-known files, such as
kernel32.dll, user32.dll, gdi32.dll, advapi32.dll, combase.dll, and
many others. These include mostly the officially documented API of
Windows.
NTDLL.DLL
A system-wide DLL, implementing the Windows native API. This is
the lowest layer of code which is still in user mode. Its most
important role is to make the transition to kernel mode for system
call invocation. NTDLL also implements the Heap Manager, the
Image Loader and some part of the user mode thread pool.
Service Processes
Service processes are normal Windows processes that communicate
with the Service Control Manager (SCM, implemented in
services.exe) and allow some control over their lifetime. The SCM
can start, stop, pause, resume and send other messages to
services. Services typically execute under one of the special
Windows accounts – local system, network service or local service.
Executive
The Executive is the upper layer of NtOskrnl.exe (the “kernel”). It
hosts most of the code that is in kernel mode. It includes mostly the
various “managers”: Object Manager, Memory Manager, I/O
Manager, Plug & Play Manager, Power Manager, Configuration
Manager, etc. It’s by far larger than the lower Kernel layer.
Kernel
The Kernel layer implements the most fundamental and time-
sensitive parts of kernel-mode OS code. This includes thread
scheduling, interrupt and exception dispatching, and implementation
of various kernel primitives such as mutexes and semaphores. Some
of the kernel code is written in CPU-specific machine language for
efficiency and for getting direct access to CPU-specific details.
Device Drivers
Device drivers are loadable kernel modules. Their code executes in
kernel mode and so has the full power of the kernel. This book is
dedicated to writing certain types of kernel drivers.
Win32k.sys
This is the kernel-mode component of the Windows subsystem.
Essentially, it’s a kernel module (driver) that handles the user
interface part of Windows and the classic Graphics Device Interface
(GDI) APIs. This means that all windowing operations
(CreateWindowEx, GetMessage, PostMessage, etc.) are handled by this
component. The rest of the system has little-to-none knowledge of
UI.
Hardware Abstraction Layer (HAL)
The HAL is a software abstraction layer over the hardware closest to
the CPU. It allows device drivers to use APIs that do not require
detailed and specific knowledge of things like Interrupt Controllers
or DMA controller. Naturally, this layer is mostly useful for device
drivers written to handle hardware devices.
System Processes
System processes is an umbrella term used to describe processes
that are typically “just there”, doing their thing where normally
these processes are not communicated with directly. They are
important nonetheless, and some in fact, critical to the system’s
well-being. Terminating some of them is fatal and causes a system
crash. Some of the system processes are native processes, meaning
they use the native API only (the API implemented by NTDLL).
Example system processes include Smss.exe, Lsass.exe,
Winlogon.exe, and Services.exe.
Subsystem Process
The Windows subsystem process, running the image Csrss.exe, can
be viewed as a helper to the kernel for managing processes running
under the Windows subsystem. It is a critical process, meaning if
killed, the system would crash. There is one Csrss.exe instance per
session, so on a standard system two instances would exist – one
for session 0 and one for the logged-on user session (typically 1).
Although Csrss.exe is the “manager” of the Windows subsystem
(the only one left these days), its importance goes beyond just this
role.
Hyper-V Hypervisor
The Hyper-V hypervisor exists on Windows 10 and server 2016 (and
later) systems if they support Virtualization Based Security (VBS).
VBS provides an extra layer of security, where the normal OS is a
virtual machine controlled by Hyper-V. Two distinct Virtual Trust
Levels (VTLs) are defined, where VTL 0 consists of the normal user-
mode/kernel-mode we know of, and VTL 1 contains the secure
kernel and Isolated User Mode (IUM). VBS is beyond the scope of
this book. For more information, check out the Windows Internals
book and/or the Microsoft documentation.
Windows 10 version 1607 introduced the Windows Subsystem for Linux (WSL).
Although this may look like yet another subsystem, like the old POSIX and
OS/2 subsystems supported by Windows, it is not like that at all. The old
subsystems were able to execute POSIX and OS/2 apps if these were compiled
using a Windows compiler to use the PE format and Windows system calls.
WSL, on the other hand, has no such requirement. Existing executables from
Linux (stored in ELF format) can be run as-is on Windows, without any
recompilation.
To make something like this work, a new process type was created – the Pico
process together with a Pico provider. Briefly, a Pico process is an empty
address space (minimal process) that is used for WSL processes, where every
system call (Linux system call) must be intercepted and translated to the
Windows system call(s) equivalent using that Pico provider (a device driver).
There is a true Linux (the user-mode part) installed on the Windows machine.
The above description is for WSL version 1. Starting with Windows 10 version
2004, Windows supports a new version of WSL known as WSL 2. WSL 2 is not
based on pico processes anymore. Instead, it’s based on a hybrid virtual
machine technology that allows installing a full Linux system (including the
Linux kernel), but still see and share the Windows machine’s resources, such as
the file system. WSL 2 is faster than WSL 1 and solves some edge cases that
didn’t work well in WSL 1, thanks to the real Linux kernel handling Linux
system calls.
Handles and Objects
The Windows kernel exposes various types of objects for use by user-
mode processes, the kernel itself and kernel-mode drivers. Instances of
these types are data structures in system space, created by the Object
Manager (part of the executive) when requested to do so by user-mode
or kernel-mode code. Objects are reference counted – only when the
last reference to the object is released will the object be destroyed and
freed from memory.
Since these object instances reside in system space, they cannot be
accessed directly by user mode. User mode must use an indirect access
mechanism, known as handles. A handle is an index to an entry in a
table maintained on a process by process basis, stored in kernel space,
that points to a kernel object residing in system space. There are various
Create* and Open* functions to create/open objects and retrieve back
handles to these objects. For example, the CreateMutex user-mode
function allows creating or opening a mutex (depending on whether the
object is named and exists). If successful, the function returns a handle
to the object. A return value of zero means an invalid handle (and a
function call failure). The OpenMutex function, on the other hand, tries to
open a handle to a named mutex. If the mutex with that name does not
exist, the function fails and returns null (0).
Kernel (and driver) code can use either a handle or a direct pointer to an
object. The choice is usually based on the API the code wants to call. In
some cases, a handle given by user mode to the driver must be turned
into a pointer with the ObReferenceObjectByHandle function. We’ll discuss
these details in a later chapter.
Most functions return null (zero) on failure, but some do not. Most notably, the
CreateFile function returns INVALID_HANDLE_VALUE (-1) if it fails.
Handle values are multiples of 4, where the first valid handle is 4; Zero is
never a valid handle value.
Kernel-mode code can use handles when creating/opening objects, but
they can also use direct pointers to kernel objects. This is typically done
when a certain API demands it. Kernel code can get a pointer to an
object given a valid handle using the ObReferenceObjectByHandle
function. If successful, the reference count on the object is incremented,
so there is no danger that if the user-mode client holding the handle
decided to close it while kernel code holds a pointer to the object would
now hold a dangling pointer. The object is safe to access regardless of
the handle-holder until the kernel code calls ObDerefenceObject, which
decrements the reference count; if the kernel code missed this call,
that’s a resource leak which will only be resolved in the next system
boot.
All objects are reference counted. The object manager maintains a
handle count and total reference count for objects. Once an object is no
longer needed, its client should close the handle (if a handle was used to
access the object) or dereference the object (if kernel client using a
pointer). From that point on, the code should consider its handle/pointer
to be invalid. The Object Manager will destroy the object if its reference
count reaches zero.
Each object points to an object type, which holds information on the
type itself, meaning there is a single type object for each type of object.
These are also exposed as exported global kernel variables, some of
which are defined in the kernel headers and are needed in certain cases,
as we’ll see in later chapters.
Object Names
Some types of objects can have names. These names can be used to
open objects by name with a suitable Open function. Note that not all
objects have names; for example, processes and threads don’t have
names – they have IDs. That’s why the OpenProcess and OpenThread
functions require a process/thread identifier (a number) rather than a
string-base name. Another somewhat weird case of an object that does
not have a name is a file. The file name is not the object’s name – these
are different concepts.
Threads appear to have a name (starting from Windows 10), that can be set
with the user-mode API SetThreadDescription. This is not, however, a true
name, but rather a friendly name/description most useful in debugging, as
Visual Studio shows a thread’s description, if there is any.
From user-mode code, calling a Create function with a name creates the
object with that name if an object with that name does not exist, but if it
exists it just opens the existing object. In the latter case, calling
GetLastError returns ERROR_ALREADY_EXISTS, indicating this is not a new
object, and the returned handle is yet another handle to an existing
object.
The name provided to a Create function is not actually the final name of
the object. It’s prepended with SessionsxBaseNamedObjects where x
is the session ID of the caller. If the session is zero, the name is
prepended with BaseNamedObjects. If the caller happens to be
running in an AppContainer (typically a Universal Windows Platform
process), then the prepended string is more complex and consists of the
unique AppContainer SID: SessionsxAppContainerNamedObjects
{AppContainerSID}.
All the above means is that object names are session-relative (and in the
case of AppContainer – package relative). If an object must be shared
across sessions it can be created in session 0 by prepending the object
name with Global; for example, creating a mutex with the CreateMutex
function named GlobalMyMutex will create it under
BaseNamedObjects. Note that AppContainers do not have the power to
use session 0 object namespace.
This hierarchy can be viewed with the Sysinternals WinObj tool (run
elevated) as shown in figure 1-10.
Figure 1-10: Sysinternals WinObj tool
The view shown in figure 1-9 is the object manager namespace,
comprising of a hierarchy of named objects. This entire structure is held
in memory and manipulated by the Object Manager (part of the
Executive) as required. Note that unnamed objects are not part of this
structure, meaning the objects seen in WinObj do not comprise all the
existing objects, but rather all the objects that were created with a
name.
Every process has a private handle table to kernel objects (whether
named or not), which can be viewed with the Process Explorer and/or
Handles Sysinternals tools. A screenshot of Process Explorer showing
handles in some process is shown in figure 1-11. The default columns
shown in the handles view are the object type and name only. However,
there are other columns available, as shown in figure 1-11.
Figure 1-11: Viewing handles in processes with
Process Explorer
By default, Process Explorer shows only handles for objects, which have
names (according to Process Explorer’s definition of a name, discussed
shortly). To view all handles in a process, select Show Unnamed Handles
and Mappings from Process Explorer’s View menu.
The various columns in the handle view provide more information for
each handle. The handle value and the object type are self explanatory.
The name column is tricky. It shows true object names for Mutexes
(Mutants), Semaphores, Events, Sections, ALPC Ports, Jobs, Timers,
Directory (object manager Directories, not file system directories), and
other, less used object types. Yet others are shown with a name that has
a different meaning than a true named object:
Process and Thread objects, the name is shown as their unique ID.
For File objects, it shows the file name (or device name) pointed to
by the file object. It’s not the same as an object’s name, as there is
no way to get a handle to a file object given the file name - only a
new file object may be created that accesses the same underlying
file or device (assuming sharing settings for the original file object
allow it).
(Registry) Key objects names are shown with the path to the
registry key. This is not a name, for the same reasoning as for file
objects.
Token object names are shown with the user name stored in the
token.
Accessing Existing Objects
The Access column in Process Explorer’s handles view shows the access
mask which was used to open or create the handle. This access mask is
key to what operations are allowed to be performed with a specific
handle. For example, if client code wants to terminate a process, it must
call the OpenProcess function first, to obtain a handle to the required
process with an access mask of (at least) PROCESS_TERMINATE, otherwise
there is no way to terminate the process with that handle. If the call
succeeds, then the call to TerminateProcess is bound to succeed.
Here’s a user-mode example for terminating a process given a process
ID:
bool KillProcess(DWORD pid) {
//
// open a powerful-enough handle to the process
//
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
if (!hProcess)
return false;
//
// now kill it with some arbitrary exit code
//
BOOL success = TerminateProcess(hProcess, 1);
//
// close the handle
//
CloseHandle(hProcess);
return success != FALSE;
}
The Decoded Access column provides a textual description of the access
mask (for some object types), making it easier to identify the exact
access allowed for a particular handle.
Double-clicking a handle entry (or right-clicking and selecting Properties)
shows some of the object’s properties. Figure 1-12 shows a screenshot
of an example event object properties.
Figure 1-12: Object properties in Process Explorer
Notice that the dialog shown in figure 1-12 is for the object’s properties,
rather than the handle’s. In other words, looking at an object’s properties
from any handle that points to the same object shows the same
information.
The properties in figure 1-12 include the object’s name (if any), its type,
a short description, its address in kernel memory, the number of open
handles, and some specific object information, such as the state and
type of the event object shown. Note that the References shown do not
indicate the actual number of outstanding references to the object (it
does prior to Windows 8.1). A proper way to see the actual reference
count for the object is to use the kernel debugger’s !trueref command,
as shown here:
lkd> !object 0xFFFFA08F948AC0B0
Object: ffffa08f948ac0b0 Type: (ffffa08f684df140) Event
ObjectHeader: ffffa08f948ac080 (new version)
HandleCount: 2 PointerCount: 65535
Directory Object: ffff90839b63a700 Name: ShellDesktopSwitchEvent
lkd> !trueref ffffa08f948ac0b0
ffffa08f948ac0b0: HandleCount: 2 PointerCount: 65535 RealPointerCount: 3
We’ll take a closer look at the attributes of objects and the kernel
debugger in later chapters.
In the next chapter, we’ll start writing a very simple driver to show and
use many of the tools we’ll need later in this book.
Chapter 2: Getting Started with
Kernel Development
This chapter deals with the fundamentals needed to get up and running
with kernel driver development. During the course of this chapter, you’ll
install the necessary tools and write a very basic driver that can be
loaded and unloaded.
In this chapter:
Installing the Tools
Creating a Driver Project
The DriverEntry and Unload routines
Deploying the Driver
Simple Tracing
Installing the Tools
In the old days (pre-2012), the process of developing and building
drivers included using a dedicated build tool from the Device Driver Kit
(DDK), without having an integrated development experience developers
were used to when developing user-mode applications. There were
some workarounds, but none of them was perfect nor officially
supported by Microsoft.
Fortunately, starting with Visual Studio 2012 and Windows Driver Kit 8,
Microsoft officially supports building drivers with Visual Studio (with
msbuild), without the need to use a separate compiler and build tools.
To get started with driver development, the following tools must be
installed (in this order) on your development machine:
Visual Studio 2019 with the latest updates. Make sure the C++
workload is selected during installation. Note that any SKU will do,
including the free Community edition.
Windows 11 SDK (generally, the latest is recommended). Make sure
at least the Debugging Tools for Windows item is selected during
installation.
Windows 11 Driver Kit (WDK) - it supports building drivers for
Windows 7 and later versions of Windows. Make sure the wizard
installs the project templates for Visual Studio at the end of the
installation.
The Sysinternals tools, which are invaluable in any “internals” work,
can be downloaded for free from http://www.sysinternals.com. Click
on Sysinternals Suite on the left of that web page and download the
Sysinternals Suite zip file. Unzip to any folder, and the tools are
ready to go.
The SDK and WDK versions must match. Follow the guidelines in the WDK
download page to load the corresponding SDK with the WDK.
A quick way to make sure the WDK templates are installed correctly is to open
Visual Studio and select New Project and look for driver projects, such as
“Empty WDM Driver”.
Creating a Driver Project
With the above installations in place, a new driver project can be
created. The template you’ll use in this section is “WDM Empty Driver”.
Figure 2-1 shows what the New Project dialog looks like for this type of
driver in Visual Studio 2019. Figure 2-2 shows the same initial wizard
with Visual Studio 2019 if the Classic Project Dialog extension is installed
and enabled. The project in both figures is named “Sample”.
Figure 2-1: New WDM Driver Project in Visual Studio
2019
Figure 2-2: New WDM Driver Project in Visual Studio
2019 with the Classic Project Dialog extension
Once the project is created, the Solution Explorer shows a single file
within the Driver Files filter - Sample.inf. You won’t need this file in this
example, so simply delete it (right-click and select Remove or press the
Del key).
Now it’s time to add a source file. Right-click the Source Files node in
Solution Explorer and select Add / New Item… from the File menu.
Select a C++ source file and name it Sample.cpp. Click OK to create it.
The DriverEntry and Unload Routines
Every driver has an entry point called DriverEntry by default. This can
be considered the “main” function of the driver, comparable to the
classic main of a user-mode application. This function is called by a
system thread at IRQL PASSIVE_LEVEL (0). (IRQLs are discussed in detail
in chapter 8.)
DriverEntry has a predefined prototype, shown here:
NTSTATUS
DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING
RegistryPath
);
The _In_ annotations are part of the Source (Code) Annotation
Language (SAL). These annotations are transparent to the compiler, but
provide metadata useful for human readers and static analysis tools. I
may remove these annotations in code samples to make it easier to
read, but you should use SAL annotations whenever possible.
A minimal DriverEntry routine could just return a successful status, like
so:
NTSTATUS
DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath) {
return STATUS_SUCCESS;
}
This code would not yet compile. First, you’ll need to include a header
that has the required definitions for the types present in DriverEntry.
Here’s one possibility:
#include <ntddk.h>
Now the code has a better chance of compiling, but would still fail. One
reason is that by default, the compiler is set to treat warnings as errors,
and the function does not make use of its given arguments. Removing
treat warnings as errors from the compiler’s options is not
recommended, as some warnings may be errors in disguise. These
warnings can be resolved by removing the argument names entirely (or
commenting them out), which is fine for C++ files. There is another,
more “classic” way to solve this, which is to use the
UNREFERENCED_PARAMETER macro:
NTSTATUS
DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
UNREFERENCED_PARAMETER(DriverObject);
UNREFERENCED_PARAMETER(RegistryPath);
return STATUS_SUCCESS;
}
As it turns out, this macro actually references the argument given just
by writing its value as is, and this shuts the compiler up, making the
argument technically “referenced”.
Building the project now compiles fine, but causes a linker error. The
DriverEntry function must have C-linkage, which is not the default in
C++ compilation. Here’s the final version of a successful build of the
driver consisting of a DriverEntry function only:
extern "C" NTSTATUS
DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
UNREFERENCED_PARAMETER(DriverObject);
UNREFERENCED_PARAMETER(RegistryPath);
return STATUS_SUCCESS;
}
At some point, the driver may be unloaded. At that time, anything done
in the DriverEntry function must be undone. Failure to do so creates a
leak, which the kernel will not clean up until the next reboot. Drivers can
have an Unload routine that is automatically called before the driver is
unloaded from memory. Its pointer must be set using the DriverUnload
member of the driver object:
DriverObject->DriverUnload = SampleUnload;
The unload routine accepts the driver object (the same one passed to
DriverEntry) and returns void. As our sample driver has done nothing in
terms of resource allocation in DriverEntry, there is nothing to do in the
Unload routine, so we can leave it empty for now:
void SampleUnload(_In_ PDRIVER_OBJECT DriverObject) {
UNREFERENCED_PARAMETER(DriverObject);
}
Here is the complete driver source at this point:
#include <ntddk.h>
void SampleUnload(_In_ PDRIVER_OBJECT DriverObject) {
UNREFERENCED_PARAMETER(DriverObject);
}
extern "C" NTSTATUS
DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
UNREFERENCED_PARAMETER(RegistryPath);
DriverObject->DriverUnload = SampleUnload;
return STATUS_SUCCESS;
}
Deploying the Driver
Now that we have a successfully compiled Sample.sys driver file, let’s
install it on a system and then load it. Normally, you would install and
load a driver on a virtual machine, to remove the risk of crashing your
primary machine. Feel free to do so, or take the slight risk with this
minimalist driver.
Installing a software driver, just like installing a user-mode service,
requires calling the CreateService API with proper arguments, or using a
comparable tool. One of the well-known tools for this purpose is Sc.exe
(short for Service Control), a built-in Windows tool for managing
services. We’ll use this tool to install and then load the driver. Note that
installation and loading of drivers is a privileged operation, normally
available for administrators.
Open an elevated command window and type the following (the last part
should be the path on your system where the SYS file resides):
sc create sample type= kernel binPath= c:devsamplex64debugsample.sys
Note there is no space between type and the equal sign, and there is a
space between the equal sign and kernel; same goes for the second
part.
If all goes well, the output should indicate success. To test the
installation, you can open the registry editor (regedit.exe) and look for
the driver details at HKLMSystemCurrentControlSetServicesSample.
Figure 2-3 shows a screenshot of the registry editor after the previous
command.
Figure 2-3: Registry for an installed driver
To load the driver, we can use the Sc.exe tool again, this time with the
start option, which uses the StartService API to load the driver (the
same API used to load services). However, on 64 bit systems drivers
must be signed, and so normally the following command would fail:
sc start sample
Since it’s inconvenient to sign a driver during development (maybe even
not possible if you don’t have a proper certificate), a better option is to
put the system into test signing mode. In this mode, unsigned drivers
can be loaded without a hitch.
With an elevated command window, test signing can be turned on like
so:
bcdedit /set testsigning on
Unfortunately, this command requires a reboot to take effect. Once
rebooted, the previous start command should succeed.
If you are testing on a Windows 10 (or later) system with Secure Boot enabled,
changing the test signing mode will fail. This is one of the settings protected by
Secure Boot (local kernel debugging is also protected by Secure Boot). If you
can’t disable Secure Boot through BIOS setting, because of IT policy or some
other reason, your best option is to test on a virtual machine.
There is yet another setting that you may need to specify if you intend
to test the driver on pre-Windows 10 machine. In this case, you have to
set the target OS version in the project properties dialog, as shown in
figure 2-4. Notice that I have selected all configurations and all
platforms, so that when switching configurations (Debug/Release) or
platforms (x86/x64/ARM/ARM64), the setting is maintained.
Figure 2-4: Setting Target OS Platform in the project
properties
Once test signing mode is on, and the driver is loaded, this is the output
you should see:
c:/>sc start sample
SERVICE_NAME: sample
TYPE : 1 KERNEL_DRIVER
STATE : 4 RUNNING
(STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
PID : 0
FLAGS :
This means everything is well, and the driver is loaded. To confirm, we
can open Process Explorer and find the Sample.Sys driver image file.
Figure 2-5 shows the details of the sample driver image loaded into
system space.
Other documents randomly have
different content
Nu, ’k leer u, neef, den duivel te bezweren.
Heetspoor.
En ik u, neef, den duivel weg te bannen
Door waarheid; roep hem waarheid toe, hij vlucht.—
Vermoogt gij hem te roepen, breng hem hier,
Ik zweer, ik overmag hem, spot hem weg.
’t Gaat door; zeg hem de waarheid, en hij vlucht!
Mortimer.
Kom, kom;
Staakt dit gepraat, dat ons niet verder brengt.
Glendower.
Driemaal heeft Hendrik Bolingbroke den strijd
Met mijne macht gewaagd, en driemaal zond ik
Hem van de Wye en ’t zandig bed des Severns,
Bij storm, de kousen op den kop, naar huis.
Heetspoor.
Wat! ongeschoeid! en dat bij storm en onweer!
Hoe blijft hij vrij van koorts, in ’s duivels naam?
Glendower.
Komt, neemt de kaart nu. Willen we ons gebied
Alsnu naar ons verdrag in drieën deelen?
Mortimer.
De aartsdeken heeft voor ons het land alreeds
Gedeeld in drie geheel gelijke stukken.
England, van Trent en Severn tot hiertoe,
Naar ’t zuiden en naar ’t oosten, is voor mij;
Het westen, Wales, aan gene zij der Severns,
En al het vruchtbre land, aldus begrensd,
Aan Owen Glendower;—aan u, mijn waarde neef,
Al ’t oov’rige, ten noorden van de Trent.
Drievoudig zijn de stukken opgemaakt;
En hebben wij die wederzijds bezegeld,—
Wat heden avond nog gebeuren kan,—
Dan trekken wij, neef Percy, gij en ik
Alsook mylord van Worcester, morgen op,
Om uwen vader en het Schotsche leger
Te Shrewsbury, naar afspraak, aan te treffen.
Mijn vader hier is nog wel niet gereed,
Doch veertien dagen is zijn hulp te missen.—
En in dien tijd hebt gij toch uw vazallen,
Uw vrienden en uw magen wel bijeen?
Glendower.
Een korter tijd brengt mij, mylords, tot u;
En onder mijn geleide ook uwe vrouwen.
Nu sluipt gij weg en zegt haar geen vaarwel;
Want anders zou een vloed van tranen stroomen,
Bij ’t afscheid, dat gij van uw vrouwen neemt.
Heetspoor.
Mij dunkt, dat mijn deel, noord’lijk hier van Burton,
Niet een der uwe in omvang evenaart. 97
Ziet, hoe de stroom, hier in mijn land zich kronk’lend,
Een groote halve maan, een reuzenbrok,
En dat van de’ allerbesten grond, er uit snijdt.
Ik wil, dat hier de stroom worde afgedamd;
En in een nieuwe bedding vloeie hier
Dan vrij en recht de heldre, zilv’ren Trent;
Met zulk een bocht zal die zich hier niet krommen,
Dat zij mij zulk een rijken grond ontkaapt.
Glendower.
Niet krommen? ’t Moet en zal; gij ziet, zij doet het.
Mortimer.
Ja, maar ziet,
Hoe hier de stroom zijn richting neemt, bij mij
In ’t land dringt en geheel ten uwen bate
Van ’t overland zoo veel aan mij ontfutselt,
Als hij aan de’ andren kant aan u ontneemt.
Worcester.
Men graaft hem hier met weinig kosten door
En wint in ’t noorden lichtlijk deze landtong;
Dan zijn de scherpe bochten weg.
Heetspoor.
Ik wil ’t; met weinig kosten is ’t gedaan.
Glendower.
’k Wil niets veranderd hebben.
Heetspoor.
Wilt gij ’t niet?
Glendower.
Neen, en gij doet het niet.
Heetspoor.
Wie zal ’t verbieden?
Glendower.
Nu, dat zal ik.
Heetspoor.
Laat mij u niet verstaan,
En zeg het in het Welsch.
Glendower.
Ik spreek, heer, Engelsch, even goed als gij,
En werd zelfs opgevoed aan ’t Engelsch hof,
Waar ik, nog jong, voor menig Engelsch lied
Een lieflijk tokk’len van de harp ontwierp,
En aan de tong een hulprijk siersel schonk;
Nooit heeft men zulk een gave in u herkend.
Heetspoor.
Daarover, neef, verheug ik mij van harte,
’k Waar’ liever nog een katje en riep miaauw,
Dan een van die kling-klang-balladekramers;
’k Wil liever koop’ren luchters hooren draaien,
Of ongesmeerde wagenraadren knarsen;
Daar klemde ik zoo mijn tanden niet van saâm,
Als van die lisp’lend zoete poëzie;
Die is me, als ’t draven van een stijven knol.
Glendower.
Nu goed, verleg de Trent dan maar.
Heetspoor.
’t Is me onverschillig; driemaal zooveel land
Geef ik den eersten, besten, trouwen vriend;
Maar geldt het een verdrag of koop, let wel,
Dan twist ik om het tiende van een haar.
Zijn onze stukken klaar? en gaan we op weg?
Glendower.
’t Is held’re maan, gij kunt van nacht nog gaan;
Ik zal den schrijver haasten en ga tevens
De vrouwen op uw afreis voorbereiden.
Want, o, ik ducht, mijn dochter wordt waanzinnig
Zoozeer is ze aan haar Mortimer gehecht. 146
(Glendower af.)
Mortimer.
Neef Percy, foei, wat dwarsboomt gij mijn vader!
Heetspoor.
Ik kan ’t niet laten; soms maakt hij mij toornig
Door wat hij mij vertelt, van mier en mol,
Van droomer Merlin en zijn profetieën,
Van draken, van een vinnenloozen visch,
Een raaf, die ruit, een grijp, geknot van wieken,
Een leeuw, die rust, een kat, die sluipt en springt,
En zooveel wirrelwarrig tuig, dat ik
Geheel verheidend word. Denk,—gistren avond
Hield hij mij vast, ten minste negen uren,
Met al de duivels op te noemen, die
Hem dienstbaar zijn; ’k riep: “Hum!” en “goed, ga voort”,
Doch lette op niet één woord. Men wordt hem moede,
Meer dan een struik’lig paard, een kijvend wijf,
Een rook’rig huis. O veel, veel liever zou ik
Op kaas en knoflook zitten, in een molen,
Dan lekker smullen en zijn praatjes hooren
In eenig lustslot van de christenheid.
Mortimer.
Hij is, geloof me, een waardig edelman,
Van veel belezenheid en door-ervaren
In diepe kunsten, dapper als een leeuw,
Gezellig en in mildheid onuitputt’lijk
Als Indiës mijnen. Moet ik ’t zeggen, neef?
Hij koestert eerbied voor uw fieren geest,
En doet zijn eigen aard, als gij zijn wenschen
Zoo dwarsboomt, veel geweld aan, ja, dat doet hij.
’k Verzeker u, op aarde leeft geen mensch,
Die zoo hem tarten mocht, als gij het deedt,
En niet gevaarlijk wierd te recht gewezen;
Doch waag het niet te vaak, dit smeek ik u.
Worcester.
Voorwaar, mylord, uw hoofdigheid is laakbaar;
Gij hebt sinds uwe komst genoeg gedaan,
Om zijn geduld volkomen uit te putten.
Die fout, heer, moet gij leeren overmeest’ren;
Zij geev’ soms blijk van fierheid, adel, moed,—
In zoo ver kan zij u tot sieraad zijn,—
Doch al te vaak verraadt zij felle woede,
Ruwheid van doen, gebrek aan zelfbeheersching,
Trots, nederzien op and’ren, eigenwijsheid;
En zij zelfs met het kleinst gebrek uit deze
Een edelman behept, dit rooft hem steeds
Der menschen hart, en werpt ook op den glans
Van al zijn verd’re deugd een booze vlek,
Die haar van welverdienden lof versteekt. 189
Heetspoor.
Nu, ’k heb mijn les; geluk met hofmanieren!
Ziet, onze vrouwen; laat ons afscheid nemen.
(Glendower komt terug, met de Vrouwen.)
Mortimer.
Dit is voor mij een dood’lijk grievend leed:
Mijn vrouw verstaat geen Engelsch, ik geen Welsch.
Glendower.
Mijn dochter weent; zij wil van u niet scheiden;
Zij wil soldaat zijn, wil met u in ’t veld.
Mortimer.
Mijn vader, zeg haar, dat zij met nicht Percy
Ons onder uw geleide weldra volgt.
(Glendower spreekt met zijn dochter in het Welsch, en zij antwoordt in
dezelfde taal.)
Glendower.
Zij is als dol, een lastig, koppig schepsel,
Dat voor geen overreding vatbaar is.
(Zij spreekt tot Mortimer in het Welsch.)
Mortimer.
O, ik versta uw blik, dat lieflijk Welsch,
Dat uit uw zwaar bewolkte heem’len stroomt,
Ken ik te goed; en als ik mij niet schaamde,
Gaf ik u antwoord in dezelfde taal.
(Zij spreekt weder.)
’k Versta ook uwen kus, als gij den mijnen,
En dat is een gevoelvol onderhoud;
Doch nimmer wil ik ledigloopen, lieve,
Eer ik uw taal geleerd heb; want uw tong
Maakt Welsch zoo zoet als hooggestemde lied’ren,
Die bij haar luit een schoone koningin
Verrukk’lijk zingt in ’t zomer-lustprieel.
K o n i n g H e n d r i k I V , Eerste Gedeelte, Derde Bedrijf,
Tweede Tooneel.
Glendower.
Als gij ook wegsmelt, wordt zij gansch waanzinnig.
(Zij spreekt weder.)
Mortimer.
Die taal! ’k ben één en al onwetendheid!
Glendower.
Zij wenscht, gij vlijt u op het weeld’rig bies;
En legt uw dierbaar hoofd in haren schoot,
Dan wil zij u uw liev’lingsliedjes zingen,
Den god des slaaps bekronen op uw oogleên,
Uw bloed betoov’rend met een zoete loomheid,
Zóó lieflijk slaap en waken bij u scheiden,
Als tusschen dag en nacht de scheiding is,
Het uur, voordat des hemels zonnespan
In ’t oosten zijnen gouden tocht begint.
Mortimer.
Van harte gaarne zit ik neer en luister;
In dien tijd, hoop ik, komt ons stuk gereed.
Glendower.
Doe dat; de muzikanten,
Die voor u spelen zullen, zweven thans
Op duizend mijlen afstands in de lucht,
Doch zullen daad’lijk hier zijn. Zit en luister.
Heetspoor.
Kom, Kaatje, gij verstaat de kunst
om u neer te vlijen ook; kom, vlug, vlug! ik
wil mijn hoofd in uw schoot leggen. 231
Lady Percy.
Loop, gij malle gans!
(Muziek laat zich hooren.)
Heetspoor.
Nu merk ik, dat de duivel Welsch verstaat;
En ’t is geen wonder, dat hij luimen heeft;
Hij is, bij God, een goede muzikant.
Lady Percy.
Dan moet gij door en door muzikaal wezen, want gij wordt geheel
door uw luimen geregeerd. Lig stil, gij schelm, en hoor hoe de Lady
Welsch zingt.
Heetspoor.
Ik hoorde liever Lady, mijn brak, Iersch huilen.
Lady Percy.
Wilt gij een gat in uw hoofd hebben?
Heetspoor.
Neen.
Lady Percy.
Wees dan stil.
Heetspoor.
Ook niet; dit is een vrouwengebrek.
Lady Percy.
Nu, God help’ u!
Heetspoor.
In het bed der Welsche Lady?
Lady Percy.
Wat zegt gij?
Heetspoor.
Stil! zij zingt.
(Lady Mortimer zingt een Welsch lied.)
Kom, Kaatje, nu moet gij eens voor mij zingen.
Lady Percy.
Ik niet, in vollen ernst niet.
Heetspoor.
“Ik niet, in vollen ernst niet!” Mijn hartje, gij zweert als een
banketbakkersvrouw: “Gij niet, in vollen ernst niet!” en “Zoo waar
ik leef!” en “Zoo waar mij God helpe!” en “Zoo waar de lieve zon
schijnt!”
En geeft zoo taffen eedwaarborg, als waart gij
Nooit verder weg geweest dan Finsbury.
Zweer als een edelvrouw, zooals gij zijt,
Een vollen eed, die klinkt,—en laat “In ernst”
En zulke peperkoekbetuigingen
Aan fulpgalons en zondagsburgers over.
Kom, zing!
Lady Percy.
Ik wil niet zingen.
Heetspoor.
’t Is de naaste weg naar het snijderworden of roodborstjes africhten.
—Als de stukken klaar zijn, wil ik binnen twee uren weg; kom dus
binnen, als ge wilt.
(Heetspoor af.)
Glendower.
Kom, kom, lord Mortimer, gij gaat zoo traag,
Als deze heethoofd Percy vurig ijlt.
De stukken zijn nu wis gereed; wij zeeg’len
En dan terstond te paard!
Mortimer.
Van ganscher harte.
(Allen af.)
TWEEDE TOONEEL.
L o n d e n . Een vertrek in het paleis.
Koning Hendrik, Prins Hendrik en Lords komen op.
Koning Hendrik.
Verlaat ons, Lords; de prins van Wales en ik
Wij hebben een vertrouw’lijk onderhoud;
Doch blijft nabij, straks zullen we u behoeven.
(De Lords af.)
Ik weet niet, of het God zoo heeft beschikt
Voor ongevall’ge diensten, die ik deed,
Dat hij, naar zijn verborgen raad, een geesel
En straf mij uit mijn eigen bloed verwekt;
Doch gij doet mij, door heel uw levenswandel,
Gelooven, dat gij uitgelezen zijt
Tot heete wraak, als strenge roê, des hemels,
Om mijne schuld te straffen. Zeg mij anders,
Hoe zulke bandelooze, lage driften,
Een zoo armzalig, voos, onwaardig streven,
Een zoo onvruchtb’re lust en woest verkeer,
Als waar gij aan verknocht zijt, mee vergroeid,
De hoogheid van uw bloed verzellen konden,
Ooit konden reiken tot uw vorstenhart?
Prins Hendrik.
Veroorloof, uwe hoogheid! ’k Wenschte, dat ik
Van iedre smet mij zoo bevrijden kon,
Als ik mij buiten twijfel rein kan wasschen
Van meen’ge zonde, mij te last gelegd;
Doch laat mij toch om die verschooning smeeken,
Dat ik, eerst tal van sprookjes logenstraffend,—
Zooals het oor van grootheid vaak moet hooren
Van plasdankzoekers en van nieuwtjesventers,—
Voor enkle ware zaken, die mijn jeugd
Loszinnig, buiten ’t spoor geraakt, beging,
Vergiff’nis vind om mijn oprechte erkenning.
Koning Hendrik.
Vergeve u God!—doch ik verbaas mij, Hendrik,
Dat uw begeerten zoo de wieken uitslaan,
Ver van de vlucht van heel uw voorgeslacht.
Door ruwheid hebt ge uw zetel in den staatsraad
Verbeurd; uw jong’re broeder nam dien in;
Een vreemdling zijt gij schier voor alle harten
Van ’t hof en van de prinsen van mijn bloed.
De hoop en de verwachting van uw tijd,
Vervlogen zijn ze, en iedre menschenziel
Voorspelt zichzelf profetisch uwen val.
Was ik met mijn aanwezigheid zoo gul,
Zoo uitgestald voor ieders oog, zoo glansloos
En voor gemeen verkeer te koop geweest,—
Die meening, die de kroon mij heeft verschaft,
Ware aan het troonbezit getrouw gebleven,
Had mij een roemloos balling laten blijven,
Als een, die niets was, niets verwachten liet.
Ik kwam zeer zelden voor den dag, maar dan
Werd ik ook aangegaapt als een komeet;
Dan riep de vader tot zijn kroost: “Dat is hij!”
Een ander vroeg: “Waar, wie is Bolingbroke?”
Dan was de hoflijkheid des hemels mijn, 50
En kleedde ik mij in zulk een need’righeid,
Dat ik verknochtheid afdwong van hun hart,
En groet en jubelkreten aan hun mond,
Zelfs aan de zijde des gekroonden konings.
Zoo hield ik mijn persoon steeds frisch en nieuw;
Zij werd, gelijk een hoogepriesterskleed,
Bewond’rend slechts aanschouwd; en heel mijn praal,
Zeldzaam, doch kostbaar, was gelijk een feest,
En zoo, door ongewoonte, een plechtigheid.
De koning was een spring-in-’t-veld, verzelschapt
Van dwaze fratsenmakers, strooien geesten,
Snel vlammend, snel verbrand; zijn waardigheid
Versneed hij, mengde ’t hooge koningschap
Met luchtsprongnarren, liet zijn grooten naam
Ontheil’gen door hun spot, en gaf zijn aanzien,
Zijn naam ten trots, den lach van knapen prijs,
Den moedwil van elk ijdel, baardloos gekje;
Hij werd een klant der openbare straat,
En maakte zich tot leenman van de volksgunst,
Totdat, wijl de oogen daag’lijks hem verslonden,
Het volk van honing was verzaad, de smaak
Hun tegenstond van ’t zoet, waarvan een weinig
Meer dan een weinig veel te veel reeds is.
Kwam nu een dag, dat hij zich moest vertoonen,
Dan werd hij, als de koekoek is in Juni,
Gehoord, niet opgemerkt; gezien, met oogen,
Die, door gewoonte stomp en moe, niet meer
Voor ’t staren vatbaar zijn, dat met bewondring
Den zonneschijn der majesteit begroet,
Haar zelden zichtbren glans eerbiedig huldigt;
Zij knikkebolden met geloken oogleên,
Recht voor zijn oog, en gunden hem een blik,
Als wreev’le mannen aan hun vijand doen,
Van overdaad, die walgde van zijn bijzijn.
En, Hendrik, op diezelfde lijn staat gij,
Want gij ook hebt uw vorstlijkheid versmeten,
Door laakbaar, laag verkeer. Geen enkel oog,
Dat niet, te vaak u ziend, u moede werd;
Alleen het mijne wenschte u meer te zien,
En doet nu iets, wat ik mijzelf verwijt,
Het maakt zich blind door dwaze teederheid.
Prins Hendrik.
Ik wil voortaan, genadig heer en vader,
Mijzelf meer zijn.
Koning Hendrik.
In ieder opzicht zijt gij,
Voorwaar, te dezer stond, wat Richard was,
Toen ik te Ravenspurg uit Frankrijk landde;
En juist wat ik toen was, is Percy nu.
Ja, bij mijn scepter en mijn zieleheil,
Hij heeft veel hooger aanspraak op den troon,
Dan gij hebt door de schaduw van uw erfrecht;
Want zonder recht, ja zonder zweem van recht,
Vult hij ’s rijks velden met zijn wapenmacht,
Houdt stand voor de’ open muil des leeuws, en brengt, 102
Niet meer dan gij zijn jaren dankend, achtb’re
Bisschoppen en vergrijsde lords in ’t veld,
Tot schilden-splijten en tot bloedig strijden.
En wat onsterfelijken roem verwierf hij
Zich tegen Douglas, dien geprezen held,
Wiens stoute tochten, grootsche wapenfeiten
Bij elken krijger hem den eersten rang,
Den hoogsten oorlogsroem verworven hadden,
In alle rijken, waar men Christus eert!
Driemaal heeft deze Heetspoor, Mars in winds’len,
Die zuig’lingheld, in ’t veld den grooten Douglas
Verslagen, ééns gevangen hem gemaakt,
Hem weer geslaakt en toen als vriend gewonnen,
Om diepe vijandschap den mond te stoppen,
En onzen troon te schokken, dat hij vall’.
En hoor nu toe: “Percy, Northumberland,
Yorks hooge kerkvoogd, Douglas, Mortimer,
Zijn tegen ons verbonden, staan in ’t veld.”
Doch wat heb ik die tijding u te melden,
U, Hendrik, u mijn vijanden te noemen,
U, die mijn naaste en ergste vijand zijt?
U, die wellicht uit onderdaan’ge vrees,
Uit lagen lust, of als een luim u drijft,
Mij zult bevechten in soldij van Percy,
Den voet hem likken, voor zijn fronsblik kruipen,
Om recht te toonen, hoe ontaard gij zijt.
Prins Hendrik.
Neen, denk dit niet, gij zult het zoo niet vinden;
Vergeev’ God hun, die bij uw majesteit
Mij zoo van uwen goeden dunk beroofden!
Ik maak dit alles goed op Percy’s hoofd,
En zal aan ’t einde van een dag vol roems
Met fierheid tot u zeggen: “’k ben uw zoon”;
Als ik in een gewaad van bloed u nader,
Mijn trekken met een masker kleur van bloed,
Dat, weggewasschen, ook mijn schande wegspoelt.
Dat zal de dag zijn,—koom’ hij als hij wil!—
Waarop eenmaal dat kind van eer en roem,
De dapp’re Heetspoor, de geprezen ridder,
En uw vergeten Hendrik samentreffen.
O waar’ elke eer, die op zijn helmet troont,
Een menigt’, en op mijn hoofd elke schimp
Verdubbeld! want de dag genaakt, hij komt,
Dat ik dien noordschen jong’ling dwing, zijn schat
Van roem te ruilen voor mijn oogst van schande.
Percy, mijn vorst, is slechts mijn zaakwaarnemer;
Zijn heldendaden stapelt hij voor mij;
En dra roep ik hem op tot rekenschap;
Uitleev’ren zal hij mij zijn ganschen roem,
Ja, ook het nietigst eerbetoon der wereld,
Of ik rijt hem de reek’ning uit zijn hart.
Dit zweer ik plechtig, bij den naam van God;
En als het Hem behaagt, dat ik ’t volbreng,
Dan heele dit, zoo smeek ik uwe hoogheid,
Elke oude wond van mijn losbandigheid;
Zoo niet, dan delgt de dood toch alle schuld;
En ik wil honderdduizend dooden sterven,
Eer ik een adem van deze’ eed verbreek. 159
Koning Hendrik.
Dit doodt een honderdduizendtal verraders;
Nu zij bevel en alles u vertrouwd.
(Blunt komt op.)
Spreek, wakkre Blunt! uw blikken zijn vol haast.
Blunt.
Dien heeft de zaak, die ik u melden kom.
Lord Mortimer van Schotland zond bericht,
Dat Douglas zich met de Engelsche oproerlingen
Den elfden heeft vereend te Shrewsbury.
Het wordt een zoo verschrikk’lijk machtig heer,
Indien elk hunner zijn beloften houdt,
Als ooit een staat met onheil heeft gedreigd.
Koning Hendrik.
De graaf van Westmoreland trok heden op,
Met hem mijn zoon, lord John van Lancaster;
“Want dit bericht, vijf dagen is het oud.—
Aanstaanden Woensdag, Hendrik, breekt gij op;
Wijzelf op Donderdag; verzamelplaats
Zal Bridg’north zijn; gij, Hendrik, neemt uw weg
Door Glostershire; naar deze reek’ning zal,
Is alles goed geordend, in twaalf dagen
Te Bridg’north onze macht vereenigd zijn.
Van hier! veel is te doen en haast is goed;
’t Geluk wordt loom, als zich de mensch niet spoedt.
(Allen af.)
DERDE TOONEEL.
E a s t c h e a p . Een vertrek in de herberg “Het Zwijnshoofd.”
Falstaff en Bardolf komen op.
Falstaff.
Bardolf, ben ik niet schandelijk afgevallen na die laatste
geschiedenis? vermager ik niet? slink ik niet weg? Verduiveld, mijn
vel hangt om mij heen als het huiskleed van een oude madam; ik
ben zoo verschrompeld als een goudpippeling. Nu, ik wil tot mijzelf
inkeeren, maar dan terstond, terwijl ik nog wat goed in ’t vleesch
ben; binnenkort zal ik zoo min wezen, dat ik de kracht niet heb, om
tot mijzelf in te keeren. Als ik niet vergeten ben, hoe een kerk er van
binnen uitziet, ben ik een peperkorrel, een brouwerspaard! Een kerk
van binnen! Mijn omgang, mijn nietswaardige omgang heeft mij
bedorven.
Bardolf.
Sir John, gij zijt zoo neerslachtig, gij hebt niet lang meer te leven.
Falstaff.
Ja, zoo is het.—Kom, zing mij eens een schuinsch liedje, vroolijk
mij wat op. Ik was zoo deugdzaam gezind, als een man van stand
behoeft te zijn, deugdzaam genoeg; vloekte weinig, dobbelde niet
boven de zeven keer in de week, ging in slechte huizen niet meer
dan eens in een vierendeel—uurs; betaalde het geld, dat ik borgde,
drie- of viervoudig; leefde ordelijk en hield behoorlijk maat,—en nu
leef ik recht ordeloos en buiten alle maat. 23
Bardolf.
Nu, ge zijt zoo dik, Sir John, dat ge wel buiten alle maat moet zijn,
buiten alle redelijke maat, Sir John.
Falstaff.
Verbeter jij je gezicht, en ik wil mijn leven beteren. Je bent onze
admiraal, je draagt de lantaren aan den achtersteven,—neen, ze zit
bij je in den neus; je bent de Ridder van de brandende Lamp.
Bardolf.
Kom, Sir John, mijn gezicht doet u geen kwaad.
Falstaff.
Neen, dat wil ik je wel bezweren, ik maak er een even goed gebruik
van, als menigeen van een doodshoofd of een memento mori. Ik zie
nooit je gelaat, of ik denk aan het helsche vuur en aan den rijken
man, die in purper leefde; want daar zit hij al in zijn praal en brandt
en brandt. Was je eenigermate aan de deugd verkleefd, dan zou ik
zweren bij je gezicht; mijn eed zou wezen: “Bij die vuurvlam, die de
engel Gods is.” Maar je bent gansch en al aan de zonde verslaafd, en
zoudt inderdaad, zonder dien gloed op je gezicht, de zoon wezen
van de buitenste duisternis. Toen je bij Gadshill den heuvel opliept
om mijn paard te vangen,—als ik toen niet dacht, dat je een
dwaallicht of een bliksemvuurbol waart, dan is er voor geld niets
meer te koop. O, je bent een eeuwigdurende fakkeloptocht, een
onuitblusschelijk vreugdevuur. Je hebt mij een duizend marken aan
toortsen en kaarsen uitgehaald, als ik ’s nachts met je wandelde, de
eene herberg uit, de andere in; maar voor de sek, die je mij hebt
opgedronken, had ik bij den duursten kaarsenmaker in Europa even
zoo goedkoop kaarsen kunnen hebben. Ik heb dien salamander van
je nu al twee en dertig jaren van vuur voorzien, God loone ’t mij!
Bardolf.
Verduiveld, ik wenschte, dat mijn gezicht in uw buik zat!
Falstaff.
God beware me! dan had ik den brand in mijn ingewanden.
(De Waardin komt op.)
Hoe is het, mevrouw Koekeloer? Ben je er achter, wie mijn zakken
geleegd heeft?
Waardin.
Wel, Sir John, wat denkt ge, Sir John? Denkt ge, dat ik dieven in
mijn huis heb? Ik heb gezocht, ik heb gevraagd, en mijn man ook,
man voor man, jongen voor jongen, meid voor meid; geen tiende
van een haar is er ooit in mijn huis zoek geraakt. 67
Falstaff.
Gelogen, waardin; Bardolf is er geschoren geworden en heeft er
menig haar verloren; en ik durf zweren, dat mijn zakken geleêgd
zijn. Loop heen, je bent een vrouwmensch; ga!
Waardin.
Wie, ik? Neen, zeg dat nog eens! God in den hemel! zoo heeft mij
nog niemand in mijn eigen huis genoemd.
Falstaff.
Loop heen, ik ken je door en door.
Waardin.
Neen, Sir John; ge kent mij niet, Sir John; ik ken u, Sir John; ge zijt
me geld schuldig, Sir John; en nu zoekt ge twist om van mij af te
komen. Ik heb u een dozijn hemden op het lijf gekocht.
Falstaff.
Paklinnen, voddig paklinnen; ik heb ze aan bakkersvrouwen
weggegeven en die hebben er builen van gemaakt.
Waardin.
Wat! zoowaar ik een eerlijke vrouw ben, Hollandsch linnen van acht
schellingen de el! Bovendien zijt gij hier ook nog geld schuldig, Sir
John, voor uw eten, en het tusschen in drinken, en geleend geld, vier
en twintig pond.
Falstaff
(op Bardolf wijzend). Hij heeft ook zijn deel er van gehad, laat
hem betalen!
Waardin.
Hij? lieve, God, hij is arm, hij heeft niets.
Falstaff.
Wat! hij arm? Zie zijn gezicht eens aan; wat noem je dan rijk? laat
hem munt slaan uit zijn neus, munt slaan uit zijn wangen. Ik betaal
geen duit. Wat, wil je een grasgroenen jonker van mij maken? Zou
ik mijn gemak niet kunnen nemen in mijn eigen herberg, zonder dat
men mij de zakken leêgt? Ik ben er een zegelring van mijn
grootvader mee kwijt geraakt, die zijn veertig marken waard is.
Waardin.
O Jezus! ik heb den prins ik weet niet hoe dikwijls tegen hem
hooren zeggen, dat die ring van koper was.
Falstaff.
Wat! de prins is een weerhaan, een uitknijper; verduiveld! als hij
hier was, zou ik hem afrossen als een hond, zoo hij dat zeide.
(Prins Hendrik en Poins komen op, marcheerend; Falstaff gaat den Prins,
die op zijn commandostaf als op een fluit speelt, te gemoet.)
Falstaff.
Hoe is het, mijn jongen? Waait de wind uit dien hoek? Waarachtig?
moeten wij allen marcheeren?
Bardolf.
Ja, twee aan twee, als gevangenen naar Newgate. 104
Waardin.
Mylord, ik bid u, hoor mij.
Prins Hendrik.
Wat is er, vrouw Haastig? Hoe maakt uw man het? Ik mag hem wel;
hij is een eerlijke kerel.
Waardin.
Beste mylord, hoor mij aan!
Falstaff.
Ik bid u, laat haar loopen en luister naar mij.
Prins Hendrik.
Wat wil je dan, Hans?
Falstaff.
Kort geleden ben ik ’s avonds hier in slaap gevallen, daar achter het
tapijt, en toen zijn mij de zakken geleêgd; dit huis is een spelonk
geworden; zij leêgen er iemand de zakken.
Prins Hendrik.
Wat ben je er meê kwijt geraakt, Hans?
Falstaff.
Wil je wel gelooven, Hein, drie of vier schuldbekentenissen van
veertig pond elk, en een zegelring van mijn grootvader.
Prins Hendrik.
Een bagatel, een ding van acht stuivers.
Waardin.
Dat heb ik hem ook gezegd, mylord; en ik zeide, dat ik het uwe
genade had hooren zeggen; en, mylord, hij spreekt allerschandelijkst
van u, zoo’n vuilbek als hij is, en zeide, dat hij u zou afrossen.
Prins Hendrik.
Wat! dat zeide hij toch niet?
Waardin.
Als het niet waar is, is er geen waarachtigheid of eerlijkheid of
vrouwelijkheid in mij.
Falstaff.
Je bent niet waarachtiger dan gestoofde pruimen, niet eerlijker dan
een opgejaagde vos, en wat de vrouwelijkheid betreft, kan bij
vergelijking juffer Marianne van den moorendans voor een
buurtmeestersvrouw doorgaan. Loop, schepsel, loop rondom!
Waardin.
Zeg, wat voor een schepsel? wat voor een schepsel?
Falstaff.
Wat voor een schepsel? wel een schepsel, om God voor te danken.
Waardin.
Ik ben geen schepsel, om God voor te danken, onthoud dat maar; ik
ben een eerlijken mans vrouw; en, je ridderschap er buiten gelaten,
je bent een schelm, dat je mij zoo noemt.
Falstaff.
En, je vrouwelijkheid er buiten gelaten, je bent een beest, dat je het
beter wilt weten.
Waardin.
Zeg eens, wat voor een beest, jij schelm? 141
Falstaff.
Wat voor een beest? wel, een otter.
Prins Hendrik.
Een otter, Sir John! waarom een otter?
Falstaff.
Waarom? Wel, zij is nòch vleesch nòch visch; een mensch weet niet,
waar haar toe te brengen.
Waardin.
Je bent een lasteraar, als je dat zegt; gij en iedereen weet, dat ik
nergens toe te brengen ben, jij schelm, jij!
Prins Hendrik.
Je hebt gelijk, waardin; en hij belastert je op afschuwelijke manier.
Waardin.
Dat doet hij u ook, mylord; en hij zeide nog kort geleden, dat gij
hem duizend pond schuldig waart.
Prins Hendrik.
Wat, man! ik je duizend pond schuldig?
Falstaff.
Duizend pond, Hein! een millioen; je vriendschap is een millioen
waard; en je vriendschap ben je mij schuldig.
Waardin.
Neen, maar mylord, hij noemde u een weêrhaan, en zeide, dat hij u
zou afrossen.
Falstaff.
Heb ik dat gezegd, Bardolf?
Bardolf.
Zeker, Sir John, dat hebt ge gezegd.
Falstaff.
Ja, als hij zeide, dat mijn ring van koper was.
Prins Hendrik.
Ik zeg, hij is van koper; durft ge zoo goed als je woord nu wezen?
Falstaff.
Wel, Hein, je weet, voor zoover je slechts een man bent, durf ik;
maar voor zoover je een prins bent, vrees ik je, als het gebrul van
een leeuwenwelp.
Prins Hendrik.
En waarom niet als de leeuw?
Falstaff.
De koning zelf is te vreezen als de leeuw. Denk je, dat ik je zal
vreezen, zooals ik je vader vrees? Neen, als ik dat doe, straff’ mij
God en moge mijn gordel bersten!
Prins Hendrik.
O, als dat gebeurde, hoe zou je pens om je knieën flodderen! Maar,
kerel! voor waarheid, eerlijkheid en oprechtheid is er in je lijf geen
plaats; het is volgepropt met darmen en vet. Een eerlijke vrouw van
zakkenrollerij te beschuldigen! Wel, jij liederlijke, onbeschaamde,
opgezwollen schelm, als er iets in je zak zat dan
herbergiersrekeningen, nota’s uit knippen, en voor een armzaligen
stuiver kandijsuiker om de keel glad te houden,—als je zakken
gevuld waren met andere ongerechtigheden dan deze, dan ben ik
een schurk. En toch durf je volhouden, dat je geen onrecht zoudt
opsteken! Schaam je je niet? 184
Falstaff.
Laat ik je zeggen, Hein: je weet, in den staat van onschuld is Adam
gevallen; wat zou dan de arme Hans Falstaff doen in de dagen der
verdorvenheid? Je ziet, ik heb meer vleesch dan andere menschen
en daarom ook meer zwakheid. Je erkent dus, dat je mij de zakken
geleêgd hebt?
Prins Hendrik.
Dit schijnt wel te blijken.
Falstaff.
Waardin, ik vergeef je. Ga, maak het ontbijt gereed; bemin je man,
ga je bedienden na, zorg goed voor je gasten; je zult mij voor alle
gezonde redenen toegankelijk vinden; je ziet, ik ben bevredigd.—
Nog iets?—Neen, ik bid u, ga heen. (De Waardin af.) Nu, Hein, nu
van het nieuws aan het hof; die straatrooverij, jongen,—hoe is dat in
het effen gebracht?
Prins Hendrik.
O, mijn lieve rollènde, ik moet altijd je goede engel zijn.—Het geld
is terugbetaald.
Falstaff.
Hm! ik houd niet van dat terugbetalen; ’t is dubbel werk.
Prins Hendrik.
Ik ben met mijn vader op goeden voet en kan alles doen.
Falstaff.
Plunder dan vóór alles de schatkist, en wel zonder omslag te maken.
Bardolf.
Ja, doe dat, mylord.
Prins Hendrik.
Ik heb je een commando te voet verschaft, Hans.
Falstaff.
Te paard zou mij liever geweest zijn. Waar kan ik er een vinden, die
behoorlijk kan stelen? O, zoo’n knappen dief van twee-en-twintig of
daaromtrent! Ik ben schandelijk aan lager wal. Nu, God zij gedankt
voor die opstandelingen; zij doen niemand kwaad dan de braven; ik
prijs, ik loof hen.
Prins Hendrik.
Bardolf!
Bardolf.
Mylord?
Prins Hendrik.
Breng dit stuk aan Lord John van Lancaster,
Mijn broeder John,—dit aan Lord Westmoreland.—
Kom, Poins, te paard! te paard! Wij hebben saam
Vóór ’t middagmaal een dertig mijl te rijden.—
Gij Hans, kom morgen in de Tempelzaal
Tot mij te twee uur na den middag.
Daar neemt ge uw dienstbrief in ontvangst en geld,
Met last, hoe gij uw volk hebt uit te rusten.
Gansch England brandt, en hoog draagt Percy ’t hoofd;
Het zijne valle, of ’t onze zij gekloofd!
(De Prins, Poins en Bardolf af.)
Falstaff.
Vuurwoorden! dapp’re wereld!—Wijn hier, kom!—
Ha, ’k wenschte mij dit wijnhuis voor mijn trom!
(Falstaff af.)
Instant Access to Windows Kernel Programming Second Edition Pavel Yosifovich ebook Full Chapters

More Related Content

PPS
Over Naar (embedded) Linux
ODP
Oplijsting mogelijkheden open source
ODP
oplijsting_mogelijkheden_open_source
PPT
embedded Linux, van Black Tot QA
PDF
Starting out with Visual C 2010 2nd Edition Edition Tony Gaddis
PDF
Utrecht JUG - Pipeline as code
DOCX
Linux
PPT
Android
Over Naar (embedded) Linux
Oplijsting mogelijkheden open source
oplijsting_mogelijkheden_open_source
embedded Linux, van Black Tot QA
Starting out with Visual C 2010 2nd Edition Edition Tony Gaddis
Utrecht JUG - Pipeline as code
Linux
Android

Similar to Instant Access to Windows Kernel Programming Second Edition Pavel Yosifovich ebook Full Chapters (20)

PDF
Objectgeoriënteerd programmeren Cursusdeel 1 2nd Edition Arjan J F Kok
PDF
De 10 geboden van WordPress Development
PDF
XPages Introductie
ODP
Open Computer and Software Inventory
PDF
Operating System Design The Xinu Approach 2nd Edition Comer
PPTX
JavaVMs en GraalVM
PPT
Moderne Software Engineering
PPTX
PDF
Starting Out with C++: Early Objects 9th Edition by Tony Gaddis (eBook PDF)
ODP
Nagios Open Source Monitoring
PPTX
QNH pizza sessie
PDF
Architecting ASP.NET Core Applications Carl-Hugo Marcotte
PDF
IDMEF Specifics
ODP
General Drupal presentation in Dutch
PDF
JavaLand 2017 - Pipeline as code
PPTX
HTML 5, ASP.NET MVC & Windows Azure sessie voor Ivo Brugge
PPT
Lucius Drupal Development Cursus
PDF
PFZ Workshop - Automatiseren van functionele tests
PPTX
Alle voordelen van FlexPod en EMC VSPEX converged infrastructuren op een rij
PPS
Dev Days Windows Installer Technology Final
Objectgeoriënteerd programmeren Cursusdeel 1 2nd Edition Arjan J F Kok
De 10 geboden van WordPress Development
XPages Introductie
Open Computer and Software Inventory
Operating System Design The Xinu Approach 2nd Edition Comer
JavaVMs en GraalVM
Moderne Software Engineering
Starting Out with C++: Early Objects 9th Edition by Tony Gaddis (eBook PDF)
Nagios Open Source Monitoring
QNH pizza sessie
Architecting ASP.NET Core Applications Carl-Hugo Marcotte
IDMEF Specifics
General Drupal presentation in Dutch
JavaLand 2017 - Pipeline as code
HTML 5, ASP.NET MVC & Windows Azure sessie voor Ivo Brugge
Lucius Drupal Development Cursus
PFZ Workshop - Automatiseren van functionele tests
Alle voordelen van FlexPod en EMC VSPEX converged infrastructuren op een rij
Dev Days Windows Installer Technology Final
Ad

Instant Access to Windows Kernel Programming Second Edition Pavel Yosifovich ebook Full Chapters

  • 1. Full download ebooks at ebookmeta.com Windows Kernel Programming Second Edition Pavel Yosifovich https://ebookmeta.com/product/windows-kernel-programming- second-edition-pavel-yosifovich/ OR CLICK BUTTON DOWLOAD NOW Download more ebook from https://ebookmeta.com
  • 2. More products digital (pdf, epub, mobi) instant download maybe you interests ... Windows Kernel Programming 2nd Edition Pavel Yosifovich https://ebookmeta.com/product/windows-kernel-programming-2nd- edition-pavel-yosifovich/ Windows 10 System Programming Part 2 Pavel Yosifovich https://ebookmeta.com/product/windows-10-system-programming- part-2-pavel-yosifovich/ Windows registry forensics advanced digital forensic analysis of the Windows registry Second Edition Carvey https://ebookmeta.com/product/windows-registry-forensics- advanced-digital-forensic-analysis-of-the-windows-registry- second-edition-carvey/ Mastering Linux Kernel Development A kernel developer s reference manual 1st Edition Raghu Bharadwaj https://ebookmeta.com/product/mastering-linux-kernel-development- a-kernel-developer-s-reference-manual-1st-edition-raghu- bharadwaj/
  • 3. Expert Python Programming - Second Edition Micha■ Jaworski https://ebookmeta.com/product/expert-python-programming-second- edition-michal-jaworski/ Beginning Windows Mixed Reality Programming: For HoloLens and Mixed Reality Headsets, 2nd Edition Sean Ong https://ebookmeta.com/product/beginning-windows-mixed-reality- programming-for-hololens-and-mixed-reality-headsets-2nd-edition- sean-ong/ Functional Programming in C Second Edition Enrico Buonanno https://ebookmeta.com/product/functional-programming-in-c-second- edition-enrico-buonanno/ The Rust Programming Language, Second Edition Steve Klabnik https://ebookmeta.com/product/the-rust-programming-language- second-edition-steve-klabnik/ Communication And Libertarianism 1st Edition Pavel Slutskiy https://ebookmeta.com/product/communication-and- libertarianism-1st-edition-pavel-slutskiy/
  • 5. Windows Kernel Programming, Second Edition Pavel Yosifovich This book is for sale at http://leanpub.com/windowskernelprogrammingsecondedition This version was published on 2022-01-22 * * * * * This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools and many iterations to get reader feedback, pivot until you have the right book and build traction once you do. * * * * * © 2020 - 2022 Pavel Yosifovich
  • 6. Table of Contents Introduction Who Should Read This Book What You Should Know to Use This Book Book Contents Sample Code Chapter 1: Windows Internals Overview Processes Virtual Memory Page States System Memory Threads Thread Stacks System Services (a.k.a. System Calls) General System Architecture Handles and Objects Object Names Accessing Existing Objects Chapter 2: Getting Started with Kernel Development Installing the Tools Creating a Driver Project The DriverEntry and Unload Routines Deploying the Driver Simple Tracing Summary Chapter 3: Kernel Programming Basics General Kernel Programming Guidelines Unhandled Exceptions Termination
  • 7. Function Return Values IRQL C++ Usage Testing and Debugging Debug vs. Release Builds The Kernel API Functions and Error Codes Strings Dynamic Memory Allocation Linked Lists The Driver Object Object Attributes Device Objects Opening Devices Directly Summary Chapter 4: Driver from Start to Finish Introduction Driver Initialization Passing Information to the Driver Client / Driver Communication Protocol Creating the Device Object Client Code The Create and Close Dispatch Routines The Write Dispatch Routine Installing and Testing Summary Chapter 5: Debugging and Tracing Debugging Tools for Windows Introduction to WinDbg Tutorial: User mode debugging basics Kernel Debugging Local Kernel Debugging Local kernel Debugging Tutorial Full Kernel Debugging Using a Virtual Serial Port Using the Network
  • 8. Kernel Driver Debugging Tutorial Asserts and Tracing Asserts Extended DbgPrint Other Debugging Functions Trace Logging Viewing ETW Traces Summary Chapter 6: Kernel Mechanisms Interrupt Request Level (IRQL) Raising and Lowering IRQL Thread Priorities vs. IRQLs Deferred Procedure Calls Using DPC with a Timer Asynchronous Procedure Calls Critical Regions and Guarded Regions Structured Exception Handling Using __try/__except Using __try/__finally Using C++ RAII Instead of __try / __finally System Crash Crash Dump Information Analyzing a Dump File System Hang Thread Synchronization Interlocked Operations Dispatcher Objects Mutex Fast Mutex Semaphore Event Named Events Executive Resource High IRQL Synchronization The Spin Lock Queued Spin Locks Work Items Summary
  • 9. Chapter 7: The I/O Request Packet Introduction to IRPs Device Nodes IRP Flow IRP and I/O Stack Location Viewing IRP Information Dispatch Routines Completing a Request Accessing User Buffers Buffered I/O Direct I/O User Buffers for IRP_MJ_DEVICE_CONTROL Putting it All Together: The Zero Driver Using a Precompiled Header The DriverEntry Routine The Create and Close Dispatch Routines The Read Dispatch Routine The Write Dispatch Routine Test Application Read/Write Statistics Summary Chapter 8: Advanced Programming Techniques (Part 1) Driver Created Threads Memory Management Pool Allocations Secure Pools Overloading the new and delete Operators Lookaside Lists The “Classic” Lookaside API The Newer Lookaside API Calling Other Drivers Putting it All Together: The Melody Driver Client Code Invoking System Services Example: Enumerating Processes Summary
  • 10. Chapter 9: Process and Thread Notifications Process Notifications Implementing Process Notifications The DriverEntry Routine Handling Process Exit Notifications Handling Process Create Notifications Providing Data to User Mode The User Mode Client Thread Notifications Image Load Notifications Final Client Code Remote Thread Detection The Detector Client Summary
  • 11. Introduction Windows kernel programming is considered by many a dark art, available to select few that manage to somehow unlock the mysteries of the Windows kernel. Kernel development, however, is no different than user-mode development, at least in general terms. In both cases, a good understanding of the platform is essential for producing high quality code. The book is a guide to programming within the Windows kernel, using the well-known Visual Studio integrated development environment (IDE). This environment is familiar to many developers in the Microsoft space, so that the learning curve is restricted to kernel understanding, coding and debugging, with less friction from the development tools. The book targets software device drivers, a term I use to refer to drivers that do not deal with hardware. Software kernel drivers have full access to the kernel, allowing these to perform any operation allowed by the kernel. Some software drivers are more specific, such as file system mini filters, also described in the book. Who Should Read This Book The book is intended for software developers that target the Windows kernel, and need to write kernel drivers to achieve their goals. Common scenarios where kernel drivers are employed are in the Cyber Security space, where kernel drivers are the chief mechanism to get notified of important events, with the power to intercept certain operations. The book uses C and C++ for code examples, as the kernel API is all C. C++ is used where it makes sense, where its advantages are obvious in terms of maintenance, clarity, resource management, or any combination of these. The
  • 12. book does not use complex C++ constructs, such as template metaprogramming. The book is not about C++, it’s about Windows kernel drivers. What You Should Know to Use This Book Readers should be very comfortable with the C programming language, especially with pointers, structures, and its standard library, as these occur very frequently when working with kernel APIs. Basic C++ knowledge is highly recommended, although it is possible to traverse the book with C proficiency only.
  • 13. Book Contents Here is a quick rundown of the chapters in the book: Chapter 1 (“Windows Internals Overview) provides the fundamentals of the internal workings of the Windows OS at a high level, enough to get the fundamentals without being bogged down by too many details. Chapter 2 (“Getting Started with Kernel Development”) describes the tools and procedures needed to set up a development environment for developing kernel drivers. A very simple driver is created to make sure all the tools and procedures are working correctly. Chapter 3 (“Kernel Programming Basics) looks at the fundamentals of writing drivers, including bssic kernel APIs, handling of common programming tasks involving strings, linked lists, dynamic memory allocations, and more. Chapter 4 (“Driver from Start to Finish”) shows how to build a complete driver that performs some useful functionality, along with a client application to drive it. If you are new to Windows kernel development, you should read chapters 1 to 7 in order. Chapter 8 contains some advanced material you may want to go back to after you have built a few simple drivers. Chapters 9 onward describe specialized techniques, and in theory at least, can be read in any order. Sample Code All the sample code from the book is freely available on the book’s Github repository at https://github.com/zodiacon/windowskernelprogrammingbook2e. Updates to the code samples will be pushed to this repository. It’s
  • 14. recommended the reader clone the repository to the local machine, so it’s easy to experiment with the code directly. All code samples have been compiled with Visual Studio 2019. It’s possible to compile most code samples with earlier versions of Visual Studio if desired. There might be few features of the latest C++ standards that may not be supported in earlier versions, but these should be easy to fix. Happy reading! Pavel Yosifovich June 2022
  • 15. Chapter 1: Windows Internals Overview This chapter describes the most important concepts in the internal workings of Windows. Some of the topics will be described in greater detail later in the book, where it’s closely related to the topic at hand. Make sure you understand the concepts in this chapter, as these make the foundations upon any driver and even user mode low-level code, is built. In this chapter: Processes Virtual Memory Threads System Services System Architecture Handles and Objects Processes A process is a containment and management object that represents a running instance of a program. The term “process runs” which is used fairly often, is inaccurate. Processes don’t run – processes manage. Threads are the ones that execute code and technically run. From a high-level perspective, a process owns the following: An executable program, which contains the initial code and data used to execute code within the process. This is true for most processes, but some special ones don’t have an executable image (created directly by the kernel).
  • 16. A private virtual address space, used for allocating memory for whatever purposes the code within the process needs it. An access token (called primary token), which is an object that stores the security context of the process, used by threads executing in the process (unless a thread assumes a different token by using impersonation). A private handle table to executive objects, such as events, semaphores, and files. One or more threads of execution. A normal user-mode process is created with one thread (executing the classic main/WinMain function). A user mode process without threads is mostly useless, and under normal circumstances will be destroyed by the kernel. These elements of a process are depicted in figure 1-1. Figure 1-1: Important ingredients of a process A process is uniquely identified by its Process ID, which remains unique as long as the kernel process object exists. Once it’s destroyed, the same ID may be reused for new processes. It’s important to realize that the executable file itself is not a unique identifier of a process. For example, there may be five instances of notepad.exe running at the same time. Each of these Notepad instances has its own address space, threads, handle table, process ID, etc. All those five processes are using the same image file (notepad.exe) as their initial code and data. Figure 1-2 shows a screenshot of Task Manager’s Details tab showing five instances of Notepad.exe, each with its own attributes.
  • 17. Figure 1-2: Five instances of notepad Virtual Memory Every process has its own virtual, private, linear address space. This address space starts out empty (or close to empty, since the executable image and NtDll.Dll are the first to be mapped, followed by more subsystem DLLs). Once execution of the main (first) thread begins, memory is likely to be allocated, more DLLs loaded, etc. This address space is private, which means other processes cannot access it directly. The address space range starts at zero (technically the first and last 64KB of the address space cannot be committed), and goes all the way to a maximum which depends on the process “bitness” (32 or 64 bit) and the operating system “bitness” as follows: For 32-bit processes on 32-bit Windows systems, the process address space size is 2 GB by default. For 32-bit processes on 32-bit Windows systems that use the increase user virtual address space setting, can be configured to have up to 3GB of address space per process. To get the extended address space, the executable from which the process was created must have been marked with the LARGEADDRESSAWARE linker flag in its PE header. If it was not, it would still be limited to 2 GB. For 64-bit processes (on a 64-bit Windows system, naturally), the address space size is 8 TB (Windows 8 and earlier) or 128 TB (Windows 8.1 and later).
  • 18. For 32-bit processes on a 64-bit Windows system, the address space size is 4 GB if the executable image has the LARGEADDRESSAWARE flag in its PE header. Otherwise, the size remains at 2 GB. The requirement of the LARGEADDRESSAWARE flag stems from the fact that a 2 GB address range requires 31 bits only, leaving the most significant bit (MSB) free for application use. Specifying this flag indicates that the program is not using bit 31 for anything and so having that bit set (which would happen for addresses larger than 2 GB) is not an issue. Each process has its own address space, which makes any process address relative, rather than absolute. For example, when trying to determine what lies in address 0x20000, the address itself is not enough; the process to which this address relates to must be specified. The memory itself is called virtual, which means there is an indirect relationship between an address and the exact location where it’s found in physical memory (RAM). A buffer within a process may be mapped to physical memory, or it may temporarily reside in a file (such as a page file). The term virtual refers to the fact that from an execution perspective, there is no need to know if the memory about to be accessed is in RAM or not; if the memory is indeed mapped to RAM, the CPU will perform the virtual-to-physical translation before accessing the data. if the memory is not resident (specified by a flag in the translation table entry), the CPU will raise a page fault exception that causes the memory manager’s page fault handler to fetch the data from the appropriate file (if indeed it’s a valid page fault), copy it to RAM, make the required changes in the page table entries that map the buffer, and instruct the CPU to try again. Figure 1-3 shows this conceptual mapping from virtual to physical memory for two processes.
  • 19. Figure 1-3: virtual memory mapping The unit of memory management is called a page. Every attribute related to memory is always at a page’s granularity, such as its protection or state. The size of a page is determined by CPU type (and on some processors, may be configurable), and in any case, the memory manager must follow suit. Normal (sometimes called small) page size is 4 KB on all Windows-supported architectures. Apart from the normal (small) page size, Windows also supports large pages. The size of a large page is 2 MB (x86/x64/ARM64) or 4 MB (ARM). This is based on using the Page Directory Entry (PDE) to map the large page without using a page table. This results in quicker translation, but most importantly better use of the Translation Lookaside Buffer (TLB) – a cache of recently translated pages maintained by the CPU. In the case of a large page, a single TLB entry maps significantly more memory than a small page.
  • 20. The downside of large pages is the need to have the memory contiguous in RAM, which can fail if memory is tight or very fragmented. Also, large pages are always non-pageable and can only use read/write protection. Huge pages of 1 GB in size are supported on Windows 10 and Server 2016 and later. These are used automatically with large pages if an allocation is at least 1 GB in size, and that size can be located as contiguous in RAM. Page States Each page in virtual memory can be in one of three states: Free – the page is not allocated in any way; there is nothing there. Any attempt to access that page would cause an access violation exception. Most pages in a newly created process are free. Committed – the reverse of free; an allocated page that can be accessed successfully (assuming non-conflicting protection attributes; for example, writing to a read-only page causes an access violation). Committed pages are mapped to RAM or to a file (such as a page file). Reserved – the page is not committed, but the address range is reserved for possible future commitment. From the CPU’s perspective, it’s the same as Free – any access attempt raises an access violation exception. However, new allocation attempts using the VirtualAlloc function (or NtAllocateVirtualMemory, the related native API) that does not specify a specific address would not allocate in the reserved region. A classic example of using reserved memory to maintain contiguous virtual address space while conserving committed memory usage is described later in this chapter in the section “Thread Stacks”.
  • 21. System Memory The lower part of the address space is for user-mode processes use. While a particular thread is executing, its associated process address space is visible from address zero to the upper limit as described in the previous section. The operating system, however, must also reside somewhere – and that somewhere is the upper address range that’s supported on the system, as follows: On 32-bit systems running without the increase user virtual address space setting, the operating system resides in the upper 2 GB of virtual address space, from address 0x80000000 to 0xFFFFFFFF. On 32-bit systems configured with the increase user virtual address space setting, the operating system resides in the address space left. For example, if the system is configured with 3 GB user address space per process (the maximum), the OS takes the upper 1 GB (from address 0xC0000000 to 0xFFFFFFFF). The component that suffers mostly from this address space reduction is the file system cache. On 64-bit systems running Windows 8, Server 2012 and earlier, the OS takes the upper 8 TB of virtual address space. On 64-bit systems running Windows 8.1, Server 2012 R2 and later, the OS takes the upper 128 TB of virtual address space. Figure 1-4 shows the virtual memory layout for the two “extreme” cases: 32-bit process on a 32-bit system (left) and a 64-bit process on a 64-bit system (right). Figure 1-4: virtual memory layout
  • 22. System space is not process-relative – after all, it’s the same system, the same kernel, the same drivers that service every process on the system (the exception is some system memory that is on a per-session basis but is not important for this discussion). It follows that any address in system space is absolute rather than relative, since it “looks” the same from every process context. Of course, actual access from user mode into system space results in an access violation exception. System space is where the kernel itself, the Hardware Abstraction Layer (HAL), and kernel drivers reside once loaded. Thus, kernel drivers are automatically protected from direct user mode access. It also means they have a potentially system-wide impact. For example, if a kernel driver leaks memory, that memory will not be freed even after the driver unloads. User-mode processes, on the other hand, can never leak anything beyond their lifetime. The kernel is responsible for closing and freeing everything private to a dead process (all handles are closed and all private memory is freed). Threads The actual entities that execute code are threads. A Thread is contained within a process, using the resources exposed by the process to do work (such as virtual memory and handles to kernel objects). The most important information a thread owns is the following: Current access mode, either user or kernel. Execution context, including processor registers and execution state. One or two stacks, used for local variable allocations and call management. Thread Local Storage (TLS) array, which provides a way to store thread-private data with uniform access semantics. Base priority and a current (dynamic) priority. Processor affinity, indicating on which processors the thread is allowed to run on. The most common states a thread can be in are:
  • 23. Running – currently executing code on a (logical) processor. Ready – waiting to be scheduled for execution because all relevant processors are busy or unavailable. Waiting – waiting for some event to occur before proceeding. Once the event occurs, the thread goes to the Ready state. Figure 1-5 shows the state diagram for these states. The numbers in parenthesis indicate the state numbers, as can be viewed by tools such as Performance Monitor. Note that the Ready state has a sibling state called Deferred Ready, which is similar, and exists to minimize internal locking. Figure 1-5: Common thread states Thread Stacks Each thread has a stack it uses while executing, used to store local variables, parameters passed to functions (in some cases), and where return addresses are stored prior to making function calls. A thread has at least one stack residing in system (kernel) space, and it’s pretty small (default is 12 KB on 32-bit systems and 24 KB on 64-bit systems). A user-mode thread has a second stack in its process user-space address range and is considerably larger (by default can grow to 1 MB). An example with three user-mode threads and their stacks is shown in figure 1-6. In the figure, threads 1 and 2 are in process A and thread 3 is in process B.
  • 24. The kernel stack always resides in RAM while the thread is in the Running or Ready states. The reason for this is subtle and will be discussed later in this chapter. The user-mode stack, on the other hand, may be paged out, just like any other user-mode memory. The user-mode stack is handled differently than the kernel-mode stack in terms of its size. It starts out with a certain amount of committed memory (could be as small as a single page), where the next page is committed with a PAGE_GUARD attribute. The rest of the stack address space memory is reserved, thus not wasting memory. The idea is to grow the stack in case the thread’s code needs to use more stack space. If the thread needs more stack space it would access the guard page which would throw a page-guard exception. The memory manager then removes the guard protection, and commits an additional page, marking it with a PAGE_GUARD attribute. This way, the stack grows as needed, avoiding the entire stack memory being committed upfront. Figure 1-7 shows this layout. Figure 1-6: User mode threads and their stacks Technically, Windows uses 3 guard pages rather than one in most cases.
  • 25. Figure 1-7: Thread’s stack in user space The sizes of a thread’s user-mode stack are determined as follows: The executable image has a stack commit and reserved values in its Portable Executable (PE) header. These are taken as defaults if a thread does not specify alternative values. These are always used for the first thread in the process. When a thread is created with CreateThread (or similar functions), the caller can specify its required stack size, either the upfront committed size or the reserved size (but not both), depending on a flag provided to the function; specifying zero uses the defaults set in the PE header. Curiously enough, the functions CreateThread and CreateRemoteThread(Ex) only allow specifying a single value for the stack size and can be the committed or the reserved size, but not both. The native (undocumented) function, NtCreateThreadEx allows specifying both values. System Services (a.k.a. System Calls) Applications need to perform various operations that are not purely computational, such as allocating memory, opening files, creating threads, etc. These operations can only be ultimately performed by code running in kernel mode. So how would user-mode code be able to perform such operations?
  • 26. Let’s take a common (simple) example: a user running a Notepad process uses the File / Open menu to request opening a file. Notepad’s code responds by calling the CreateFile documented Windows API function. CreateFile is documented as implemented in kernel32.Dll, one of the Windows subsystem DLLs. This function still runs in user mode, so there is no way it can directly open a file. After some error checking, it calls NtCreateFile, a function implemented in NTDLL.dll, a foundational DLL that implements the API known as the Native API, and is the lowest layer of code which is still in user mode. This function (documented in the Windows Driver Kit for device driver developers) is the one that makes the transition to kernel mode. Before the actual transition, it puts a number, called system service number, into a CPU register (EAX on Intel/AMD architectures). Then it issues a special CPU instruction (syscall on x64 or sysenter on x86) that makes the actual transition to kernel mode while jumping to a predefined routine called the system service dispatcher. The system service dispatcher, in turn, uses the value in that EAX register as an index into a System Service Dispatch Table (SSDT). Using this table, the code jumps to the system service (system call) itself. For our Notepad example, the SSDT entry would point to the NtCreateFile function, implemented by the kernel’s I/O manager. Notice the function has the same name as the one in NTDLL.dll, and has the same parameters as well. On the kernel side is the real implementation. Once the system service is complete, the thread returns to user mode to execute the instruction following sysenter/syscall. This sequence of calls is depicted in figure 1-8.
  • 27. Figure 1-8: System service function call flow General System Architecture Figure 1-9 shows the general architecture of Windows, comprising of user-mode and kernel-mode components.
  • 28. Figure 1-9: Windows system architecture Here’s a quick rundown of the named boxes appearing in figure 1-9: User processes These are normal processes based on image files, executing on the system, such as instances of Notepad.exe, cmd.exe, explorer.exe, and so on. Subsystem DLLs Subsystem DLLs are dynamic link libraries (DLLs) that implement the API of a subsystem. A subsystem is a particular view of the capabilities exposed by the kernel. Technically, starting from Windows 8.1, there is only a single subsystem – the Windows Subsystem. The subsystem DLLs include well-known files, such as kernel32.dll, user32.dll, gdi32.dll, advapi32.dll, combase.dll, and many others. These include mostly the officially documented API of Windows. NTDLL.DLL A system-wide DLL, implementing the Windows native API. This is the lowest layer of code which is still in user mode. Its most important role is to make the transition to kernel mode for system call invocation. NTDLL also implements the Heap Manager, the Image Loader and some part of the user mode thread pool.
  • 29. Service Processes Service processes are normal Windows processes that communicate with the Service Control Manager (SCM, implemented in services.exe) and allow some control over their lifetime. The SCM can start, stop, pause, resume and send other messages to services. Services typically execute under one of the special Windows accounts – local system, network service or local service. Executive The Executive is the upper layer of NtOskrnl.exe (the “kernel”). It hosts most of the code that is in kernel mode. It includes mostly the various “managers”: Object Manager, Memory Manager, I/O Manager, Plug & Play Manager, Power Manager, Configuration Manager, etc. It’s by far larger than the lower Kernel layer. Kernel The Kernel layer implements the most fundamental and time- sensitive parts of kernel-mode OS code. This includes thread scheduling, interrupt and exception dispatching, and implementation of various kernel primitives such as mutexes and semaphores. Some of the kernel code is written in CPU-specific machine language for efficiency and for getting direct access to CPU-specific details. Device Drivers Device drivers are loadable kernel modules. Their code executes in kernel mode and so has the full power of the kernel. This book is dedicated to writing certain types of kernel drivers. Win32k.sys This is the kernel-mode component of the Windows subsystem. Essentially, it’s a kernel module (driver) that handles the user interface part of Windows and the classic Graphics Device Interface (GDI) APIs. This means that all windowing operations (CreateWindowEx, GetMessage, PostMessage, etc.) are handled by this component. The rest of the system has little-to-none knowledge of UI.
  • 30. Hardware Abstraction Layer (HAL) The HAL is a software abstraction layer over the hardware closest to the CPU. It allows device drivers to use APIs that do not require detailed and specific knowledge of things like Interrupt Controllers or DMA controller. Naturally, this layer is mostly useful for device drivers written to handle hardware devices. System Processes System processes is an umbrella term used to describe processes that are typically “just there”, doing their thing where normally these processes are not communicated with directly. They are important nonetheless, and some in fact, critical to the system’s well-being. Terminating some of them is fatal and causes a system crash. Some of the system processes are native processes, meaning they use the native API only (the API implemented by NTDLL). Example system processes include Smss.exe, Lsass.exe, Winlogon.exe, and Services.exe. Subsystem Process The Windows subsystem process, running the image Csrss.exe, can be viewed as a helper to the kernel for managing processes running under the Windows subsystem. It is a critical process, meaning if killed, the system would crash. There is one Csrss.exe instance per session, so on a standard system two instances would exist – one for session 0 and one for the logged-on user session (typically 1). Although Csrss.exe is the “manager” of the Windows subsystem (the only one left these days), its importance goes beyond just this role. Hyper-V Hypervisor The Hyper-V hypervisor exists on Windows 10 and server 2016 (and later) systems if they support Virtualization Based Security (VBS). VBS provides an extra layer of security, where the normal OS is a virtual machine controlled by Hyper-V. Two distinct Virtual Trust Levels (VTLs) are defined, where VTL 0 consists of the normal user- mode/kernel-mode we know of, and VTL 1 contains the secure
  • 31. kernel and Isolated User Mode (IUM). VBS is beyond the scope of this book. For more information, check out the Windows Internals book and/or the Microsoft documentation. Windows 10 version 1607 introduced the Windows Subsystem for Linux (WSL). Although this may look like yet another subsystem, like the old POSIX and OS/2 subsystems supported by Windows, it is not like that at all. The old subsystems were able to execute POSIX and OS/2 apps if these were compiled using a Windows compiler to use the PE format and Windows system calls. WSL, on the other hand, has no such requirement. Existing executables from Linux (stored in ELF format) can be run as-is on Windows, without any recompilation. To make something like this work, a new process type was created – the Pico process together with a Pico provider. Briefly, a Pico process is an empty address space (minimal process) that is used for WSL processes, where every system call (Linux system call) must be intercepted and translated to the Windows system call(s) equivalent using that Pico provider (a device driver). There is a true Linux (the user-mode part) installed on the Windows machine. The above description is for WSL version 1. Starting with Windows 10 version 2004, Windows supports a new version of WSL known as WSL 2. WSL 2 is not based on pico processes anymore. Instead, it’s based on a hybrid virtual machine technology that allows installing a full Linux system (including the Linux kernel), but still see and share the Windows machine’s resources, such as the file system. WSL 2 is faster than WSL 1 and solves some edge cases that didn’t work well in WSL 1, thanks to the real Linux kernel handling Linux system calls. Handles and Objects The Windows kernel exposes various types of objects for use by user- mode processes, the kernel itself and kernel-mode drivers. Instances of these types are data structures in system space, created by the Object Manager (part of the executive) when requested to do so by user-mode or kernel-mode code. Objects are reference counted – only when the
  • 32. last reference to the object is released will the object be destroyed and freed from memory. Since these object instances reside in system space, they cannot be accessed directly by user mode. User mode must use an indirect access mechanism, known as handles. A handle is an index to an entry in a table maintained on a process by process basis, stored in kernel space, that points to a kernel object residing in system space. There are various Create* and Open* functions to create/open objects and retrieve back handles to these objects. For example, the CreateMutex user-mode function allows creating or opening a mutex (depending on whether the object is named and exists). If successful, the function returns a handle to the object. A return value of zero means an invalid handle (and a function call failure). The OpenMutex function, on the other hand, tries to open a handle to a named mutex. If the mutex with that name does not exist, the function fails and returns null (0). Kernel (and driver) code can use either a handle or a direct pointer to an object. The choice is usually based on the API the code wants to call. In some cases, a handle given by user mode to the driver must be turned into a pointer with the ObReferenceObjectByHandle function. We’ll discuss these details in a later chapter. Most functions return null (zero) on failure, but some do not. Most notably, the CreateFile function returns INVALID_HANDLE_VALUE (-1) if it fails. Handle values are multiples of 4, where the first valid handle is 4; Zero is never a valid handle value. Kernel-mode code can use handles when creating/opening objects, but they can also use direct pointers to kernel objects. This is typically done when a certain API demands it. Kernel code can get a pointer to an object given a valid handle using the ObReferenceObjectByHandle
  • 33. function. If successful, the reference count on the object is incremented, so there is no danger that if the user-mode client holding the handle decided to close it while kernel code holds a pointer to the object would now hold a dangling pointer. The object is safe to access regardless of the handle-holder until the kernel code calls ObDerefenceObject, which decrements the reference count; if the kernel code missed this call, that’s a resource leak which will only be resolved in the next system boot. All objects are reference counted. The object manager maintains a handle count and total reference count for objects. Once an object is no longer needed, its client should close the handle (if a handle was used to access the object) or dereference the object (if kernel client using a pointer). From that point on, the code should consider its handle/pointer to be invalid. The Object Manager will destroy the object if its reference count reaches zero. Each object points to an object type, which holds information on the type itself, meaning there is a single type object for each type of object. These are also exposed as exported global kernel variables, some of which are defined in the kernel headers and are needed in certain cases, as we’ll see in later chapters. Object Names Some types of objects can have names. These names can be used to open objects by name with a suitable Open function. Note that not all objects have names; for example, processes and threads don’t have names – they have IDs. That’s why the OpenProcess and OpenThread functions require a process/thread identifier (a number) rather than a string-base name. Another somewhat weird case of an object that does not have a name is a file. The file name is not the object’s name – these are different concepts.
  • 34. Threads appear to have a name (starting from Windows 10), that can be set with the user-mode API SetThreadDescription. This is not, however, a true name, but rather a friendly name/description most useful in debugging, as Visual Studio shows a thread’s description, if there is any. From user-mode code, calling a Create function with a name creates the object with that name if an object with that name does not exist, but if it exists it just opens the existing object. In the latter case, calling GetLastError returns ERROR_ALREADY_EXISTS, indicating this is not a new object, and the returned handle is yet another handle to an existing object. The name provided to a Create function is not actually the final name of the object. It’s prepended with SessionsxBaseNamedObjects where x is the session ID of the caller. If the session is zero, the name is prepended with BaseNamedObjects. If the caller happens to be running in an AppContainer (typically a Universal Windows Platform process), then the prepended string is more complex and consists of the unique AppContainer SID: SessionsxAppContainerNamedObjects {AppContainerSID}. All the above means is that object names are session-relative (and in the case of AppContainer – package relative). If an object must be shared across sessions it can be created in session 0 by prepending the object name with Global; for example, creating a mutex with the CreateMutex function named GlobalMyMutex will create it under BaseNamedObjects. Note that AppContainers do not have the power to use session 0 object namespace. This hierarchy can be viewed with the Sysinternals WinObj tool (run elevated) as shown in figure 1-10.
  • 35. Figure 1-10: Sysinternals WinObj tool The view shown in figure 1-9 is the object manager namespace, comprising of a hierarchy of named objects. This entire structure is held in memory and manipulated by the Object Manager (part of the Executive) as required. Note that unnamed objects are not part of this structure, meaning the objects seen in WinObj do not comprise all the existing objects, but rather all the objects that were created with a name. Every process has a private handle table to kernel objects (whether named or not), which can be viewed with the Process Explorer and/or Handles Sysinternals tools. A screenshot of Process Explorer showing handles in some process is shown in figure 1-11. The default columns shown in the handles view are the object type and name only. However, there are other columns available, as shown in figure 1-11.
  • 36. Figure 1-11: Viewing handles in processes with Process Explorer By default, Process Explorer shows only handles for objects, which have names (according to Process Explorer’s definition of a name, discussed shortly). To view all handles in a process, select Show Unnamed Handles and Mappings from Process Explorer’s View menu. The various columns in the handle view provide more information for each handle. The handle value and the object type are self explanatory. The name column is tricky. It shows true object names for Mutexes (Mutants), Semaphores, Events, Sections, ALPC Ports, Jobs, Timers, Directory (object manager Directories, not file system directories), and other, less used object types. Yet others are shown with a name that has a different meaning than a true named object: Process and Thread objects, the name is shown as their unique ID. For File objects, it shows the file name (or device name) pointed to by the file object. It’s not the same as an object’s name, as there is no way to get a handle to a file object given the file name - only a new file object may be created that accesses the same underlying file or device (assuming sharing settings for the original file object allow it). (Registry) Key objects names are shown with the path to the registry key. This is not a name, for the same reasoning as for file objects. Token object names are shown with the user name stored in the token.
  • 37. Accessing Existing Objects The Access column in Process Explorer’s handles view shows the access mask which was used to open or create the handle. This access mask is key to what operations are allowed to be performed with a specific handle. For example, if client code wants to terminate a process, it must call the OpenProcess function first, to obtain a handle to the required process with an access mask of (at least) PROCESS_TERMINATE, otherwise there is no way to terminate the process with that handle. If the call succeeds, then the call to TerminateProcess is bound to succeed. Here’s a user-mode example for terminating a process given a process ID: bool KillProcess(DWORD pid) { // // open a powerful-enough handle to the process // HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); if (!hProcess) return false; // // now kill it with some arbitrary exit code // BOOL success = TerminateProcess(hProcess, 1); // // close the handle // CloseHandle(hProcess); return success != FALSE; } The Decoded Access column provides a textual description of the access mask (for some object types), making it easier to identify the exact access allowed for a particular handle. Double-clicking a handle entry (or right-clicking and selecting Properties) shows some of the object’s properties. Figure 1-12 shows a screenshot of an example event object properties.
  • 38. Figure 1-12: Object properties in Process Explorer Notice that the dialog shown in figure 1-12 is for the object’s properties, rather than the handle’s. In other words, looking at an object’s properties from any handle that points to the same object shows the same information. The properties in figure 1-12 include the object’s name (if any), its type, a short description, its address in kernel memory, the number of open handles, and some specific object information, such as the state and type of the event object shown. Note that the References shown do not indicate the actual number of outstanding references to the object (it does prior to Windows 8.1). A proper way to see the actual reference count for the object is to use the kernel debugger’s !trueref command, as shown here: lkd> !object 0xFFFFA08F948AC0B0 Object: ffffa08f948ac0b0 Type: (ffffa08f684df140) Event ObjectHeader: ffffa08f948ac080 (new version)
  • 39. HandleCount: 2 PointerCount: 65535 Directory Object: ffff90839b63a700 Name: ShellDesktopSwitchEvent lkd> !trueref ffffa08f948ac0b0 ffffa08f948ac0b0: HandleCount: 2 PointerCount: 65535 RealPointerCount: 3 We’ll take a closer look at the attributes of objects and the kernel debugger in later chapters. In the next chapter, we’ll start writing a very simple driver to show and use many of the tools we’ll need later in this book.
  • 40. Chapter 2: Getting Started with Kernel Development This chapter deals with the fundamentals needed to get up and running with kernel driver development. During the course of this chapter, you’ll install the necessary tools and write a very basic driver that can be loaded and unloaded. In this chapter: Installing the Tools Creating a Driver Project The DriverEntry and Unload routines Deploying the Driver Simple Tracing Installing the Tools In the old days (pre-2012), the process of developing and building drivers included using a dedicated build tool from the Device Driver Kit (DDK), without having an integrated development experience developers were used to when developing user-mode applications. There were some workarounds, but none of them was perfect nor officially supported by Microsoft. Fortunately, starting with Visual Studio 2012 and Windows Driver Kit 8, Microsoft officially supports building drivers with Visual Studio (with msbuild), without the need to use a separate compiler and build tools. To get started with driver development, the following tools must be installed (in this order) on your development machine:
  • 41. Visual Studio 2019 with the latest updates. Make sure the C++ workload is selected during installation. Note that any SKU will do, including the free Community edition. Windows 11 SDK (generally, the latest is recommended). Make sure at least the Debugging Tools for Windows item is selected during installation. Windows 11 Driver Kit (WDK) - it supports building drivers for Windows 7 and later versions of Windows. Make sure the wizard installs the project templates for Visual Studio at the end of the installation. The Sysinternals tools, which are invaluable in any “internals” work, can be downloaded for free from http://www.sysinternals.com. Click on Sysinternals Suite on the left of that web page and download the Sysinternals Suite zip file. Unzip to any folder, and the tools are ready to go. The SDK and WDK versions must match. Follow the guidelines in the WDK download page to load the corresponding SDK with the WDK. A quick way to make sure the WDK templates are installed correctly is to open Visual Studio and select New Project and look for driver projects, such as “Empty WDM Driver”. Creating a Driver Project With the above installations in place, a new driver project can be created. The template you’ll use in this section is “WDM Empty Driver”. Figure 2-1 shows what the New Project dialog looks like for this type of driver in Visual Studio 2019. Figure 2-2 shows the same initial wizard with Visual Studio 2019 if the Classic Project Dialog extension is installed and enabled. The project in both figures is named “Sample”.
  • 42. Figure 2-1: New WDM Driver Project in Visual Studio 2019 Figure 2-2: New WDM Driver Project in Visual Studio 2019 with the Classic Project Dialog extension Once the project is created, the Solution Explorer shows a single file within the Driver Files filter - Sample.inf. You won’t need this file in this example, so simply delete it (right-click and select Remove or press the Del key). Now it’s time to add a source file. Right-click the Source Files node in Solution Explorer and select Add / New Item… from the File menu.
  • 43. Select a C++ source file and name it Sample.cpp. Click OK to create it. The DriverEntry and Unload Routines Every driver has an entry point called DriverEntry by default. This can be considered the “main” function of the driver, comparable to the classic main of a user-mode application. This function is called by a system thread at IRQL PASSIVE_LEVEL (0). (IRQLs are discussed in detail in chapter 8.) DriverEntry has a predefined prototype, shown here: NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ); The _In_ annotations are part of the Source (Code) Annotation Language (SAL). These annotations are transparent to the compiler, but provide metadata useful for human readers and static analysis tools. I may remove these annotations in code samples to make it easier to read, but you should use SAL annotations whenever possible. A minimal DriverEntry routine could just return a successful status, like so: NTSTATUS DriverEntry( _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) { return STATUS_SUCCESS; } This code would not yet compile. First, you’ll need to include a header that has the required definitions for the types present in DriverEntry. Here’s one possibility: #include <ntddk.h>
  • 44. Now the code has a better chance of compiling, but would still fail. One reason is that by default, the compiler is set to treat warnings as errors, and the function does not make use of its given arguments. Removing treat warnings as errors from the compiler’s options is not recommended, as some warnings may be errors in disguise. These warnings can be resolved by removing the argument names entirely (or commenting them out), which is fine for C++ files. There is another, more “classic” way to solve this, which is to use the UNREFERENCED_PARAMETER macro: NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { UNREFERENCED_PARAMETER(DriverObject); UNREFERENCED_PARAMETER(RegistryPath); return STATUS_SUCCESS; } As it turns out, this macro actually references the argument given just by writing its value as is, and this shuts the compiler up, making the argument technically “referenced”. Building the project now compiles fine, but causes a linker error. The DriverEntry function must have C-linkage, which is not the default in C++ compilation. Here’s the final version of a successful build of the driver consisting of a DriverEntry function only: extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { UNREFERENCED_PARAMETER(DriverObject); UNREFERENCED_PARAMETER(RegistryPath); return STATUS_SUCCESS; } At some point, the driver may be unloaded. At that time, anything done in the DriverEntry function must be undone. Failure to do so creates a leak, which the kernel will not clean up until the next reboot. Drivers can have an Unload routine that is automatically called before the driver is
  • 45. unloaded from memory. Its pointer must be set using the DriverUnload member of the driver object: DriverObject->DriverUnload = SampleUnload; The unload routine accepts the driver object (the same one passed to DriverEntry) and returns void. As our sample driver has done nothing in terms of resource allocation in DriverEntry, there is nothing to do in the Unload routine, so we can leave it empty for now: void SampleUnload(_In_ PDRIVER_OBJECT DriverObject) { UNREFERENCED_PARAMETER(DriverObject); } Here is the complete driver source at this point: #include <ntddk.h> void SampleUnload(_In_ PDRIVER_OBJECT DriverObject) { UNREFERENCED_PARAMETER(DriverObject); } extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { UNREFERENCED_PARAMETER(RegistryPath); DriverObject->DriverUnload = SampleUnload; return STATUS_SUCCESS; } Deploying the Driver Now that we have a successfully compiled Sample.sys driver file, let’s install it on a system and then load it. Normally, you would install and load a driver on a virtual machine, to remove the risk of crashing your primary machine. Feel free to do so, or take the slight risk with this minimalist driver. Installing a software driver, just like installing a user-mode service, requires calling the CreateService API with proper arguments, or using a
  • 46. comparable tool. One of the well-known tools for this purpose is Sc.exe (short for Service Control), a built-in Windows tool for managing services. We’ll use this tool to install and then load the driver. Note that installation and loading of drivers is a privileged operation, normally available for administrators. Open an elevated command window and type the following (the last part should be the path on your system where the SYS file resides): sc create sample type= kernel binPath= c:devsamplex64debugsample.sys Note there is no space between type and the equal sign, and there is a space between the equal sign and kernel; same goes for the second part. If all goes well, the output should indicate success. To test the installation, you can open the registry editor (regedit.exe) and look for the driver details at HKLMSystemCurrentControlSetServicesSample. Figure 2-3 shows a screenshot of the registry editor after the previous command. Figure 2-3: Registry for an installed driver To load the driver, we can use the Sc.exe tool again, this time with the start option, which uses the StartService API to load the driver (the
  • 47. same API used to load services). However, on 64 bit systems drivers must be signed, and so normally the following command would fail: sc start sample Since it’s inconvenient to sign a driver during development (maybe even not possible if you don’t have a proper certificate), a better option is to put the system into test signing mode. In this mode, unsigned drivers can be loaded without a hitch. With an elevated command window, test signing can be turned on like so: bcdedit /set testsigning on Unfortunately, this command requires a reboot to take effect. Once rebooted, the previous start command should succeed. If you are testing on a Windows 10 (or later) system with Secure Boot enabled, changing the test signing mode will fail. This is one of the settings protected by Secure Boot (local kernel debugging is also protected by Secure Boot). If you can’t disable Secure Boot through BIOS setting, because of IT policy or some other reason, your best option is to test on a virtual machine. There is yet another setting that you may need to specify if you intend to test the driver on pre-Windows 10 machine. In this case, you have to set the target OS version in the project properties dialog, as shown in figure 2-4. Notice that I have selected all configurations and all platforms, so that when switching configurations (Debug/Release) or platforms (x86/x64/ARM/ARM64), the setting is maintained.
  • 48. Figure 2-4: Setting Target OS Platform in the project properties Once test signing mode is on, and the driver is loaded, this is the output you should see: c:/>sc start sample SERVICE_NAME: sample TYPE : 1 KERNEL_DRIVER STATE : 4 RUNNING (STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN) WIN32_EXIT_CODE : 0 (0x0) SERVICE_EXIT_CODE : 0 (0x0) CHECKPOINT : 0x0 WAIT_HINT : 0x0 PID : 0 FLAGS : This means everything is well, and the driver is loaded. To confirm, we can open Process Explorer and find the Sample.Sys driver image file. Figure 2-5 shows the details of the sample driver image loaded into system space.
  • 49. Other documents randomly have different content
  • 50. Nu, ’k leer u, neef, den duivel te bezweren. Heetspoor. En ik u, neef, den duivel weg te bannen Door waarheid; roep hem waarheid toe, hij vlucht.— Vermoogt gij hem te roepen, breng hem hier, Ik zweer, ik overmag hem, spot hem weg. ’t Gaat door; zeg hem de waarheid, en hij vlucht! Mortimer. Kom, kom; Staakt dit gepraat, dat ons niet verder brengt. Glendower. Driemaal heeft Hendrik Bolingbroke den strijd Met mijne macht gewaagd, en driemaal zond ik Hem van de Wye en ’t zandig bed des Severns, Bij storm, de kousen op den kop, naar huis. Heetspoor. Wat! ongeschoeid! en dat bij storm en onweer! Hoe blijft hij vrij van koorts, in ’s duivels naam? Glendower. Komt, neemt de kaart nu. Willen we ons gebied Alsnu naar ons verdrag in drieën deelen? Mortimer. De aartsdeken heeft voor ons het land alreeds Gedeeld in drie geheel gelijke stukken. England, van Trent en Severn tot hiertoe, Naar ’t zuiden en naar ’t oosten, is voor mij; Het westen, Wales, aan gene zij der Severns, En al het vruchtbre land, aldus begrensd, Aan Owen Glendower;—aan u, mijn waarde neef,
  • 51. Al ’t oov’rige, ten noorden van de Trent. Drievoudig zijn de stukken opgemaakt; En hebben wij die wederzijds bezegeld,— Wat heden avond nog gebeuren kan,— Dan trekken wij, neef Percy, gij en ik Alsook mylord van Worcester, morgen op, Om uwen vader en het Schotsche leger Te Shrewsbury, naar afspraak, aan te treffen. Mijn vader hier is nog wel niet gereed, Doch veertien dagen is zijn hulp te missen.— En in dien tijd hebt gij toch uw vazallen, Uw vrienden en uw magen wel bijeen? Glendower. Een korter tijd brengt mij, mylords, tot u; En onder mijn geleide ook uwe vrouwen. Nu sluipt gij weg en zegt haar geen vaarwel; Want anders zou een vloed van tranen stroomen, Bij ’t afscheid, dat gij van uw vrouwen neemt. Heetspoor. Mij dunkt, dat mijn deel, noord’lijk hier van Burton, Niet een der uwe in omvang evenaart. 97 Ziet, hoe de stroom, hier in mijn land zich kronk’lend, Een groote halve maan, een reuzenbrok, En dat van de’ allerbesten grond, er uit snijdt. Ik wil, dat hier de stroom worde afgedamd; En in een nieuwe bedding vloeie hier Dan vrij en recht de heldre, zilv’ren Trent; Met zulk een bocht zal die zich hier niet krommen, Dat zij mij zulk een rijken grond ontkaapt. Glendower. Niet krommen? ’t Moet en zal; gij ziet, zij doet het.
  • 52. Mortimer. Ja, maar ziet, Hoe hier de stroom zijn richting neemt, bij mij In ’t land dringt en geheel ten uwen bate Van ’t overland zoo veel aan mij ontfutselt, Als hij aan de’ andren kant aan u ontneemt. Worcester. Men graaft hem hier met weinig kosten door En wint in ’t noorden lichtlijk deze landtong; Dan zijn de scherpe bochten weg. Heetspoor. Ik wil ’t; met weinig kosten is ’t gedaan. Glendower. ’k Wil niets veranderd hebben. Heetspoor. Wilt gij ’t niet? Glendower. Neen, en gij doet het niet. Heetspoor. Wie zal ’t verbieden? Glendower. Nu, dat zal ik. Heetspoor. Laat mij u niet verstaan, En zeg het in het Welsch.
  • 53. Glendower. Ik spreek, heer, Engelsch, even goed als gij, En werd zelfs opgevoed aan ’t Engelsch hof, Waar ik, nog jong, voor menig Engelsch lied Een lieflijk tokk’len van de harp ontwierp, En aan de tong een hulprijk siersel schonk; Nooit heeft men zulk een gave in u herkend. Heetspoor. Daarover, neef, verheug ik mij van harte, ’k Waar’ liever nog een katje en riep miaauw, Dan een van die kling-klang-balladekramers; ’k Wil liever koop’ren luchters hooren draaien, Of ongesmeerde wagenraadren knarsen; Daar klemde ik zoo mijn tanden niet van saâm, Als van die lisp’lend zoete poëzie; Die is me, als ’t draven van een stijven knol. Glendower. Nu goed, verleg de Trent dan maar. Heetspoor. ’t Is me onverschillig; driemaal zooveel land Geef ik den eersten, besten, trouwen vriend; Maar geldt het een verdrag of koop, let wel, Dan twist ik om het tiende van een haar. Zijn onze stukken klaar? en gaan we op weg? Glendower. ’t Is held’re maan, gij kunt van nacht nog gaan; Ik zal den schrijver haasten en ga tevens De vrouwen op uw afreis voorbereiden. Want, o, ik ducht, mijn dochter wordt waanzinnig Zoozeer is ze aan haar Mortimer gehecht. 146
  • 54. (Glendower af.) Mortimer. Neef Percy, foei, wat dwarsboomt gij mijn vader! Heetspoor. Ik kan ’t niet laten; soms maakt hij mij toornig Door wat hij mij vertelt, van mier en mol, Van droomer Merlin en zijn profetieën, Van draken, van een vinnenloozen visch, Een raaf, die ruit, een grijp, geknot van wieken, Een leeuw, die rust, een kat, die sluipt en springt, En zooveel wirrelwarrig tuig, dat ik Geheel verheidend word. Denk,—gistren avond Hield hij mij vast, ten minste negen uren, Met al de duivels op te noemen, die Hem dienstbaar zijn; ’k riep: “Hum!” en “goed, ga voort”, Doch lette op niet één woord. Men wordt hem moede, Meer dan een struik’lig paard, een kijvend wijf, Een rook’rig huis. O veel, veel liever zou ik Op kaas en knoflook zitten, in een molen, Dan lekker smullen en zijn praatjes hooren In eenig lustslot van de christenheid. Mortimer. Hij is, geloof me, een waardig edelman, Van veel belezenheid en door-ervaren In diepe kunsten, dapper als een leeuw, Gezellig en in mildheid onuitputt’lijk Als Indiës mijnen. Moet ik ’t zeggen, neef? Hij koestert eerbied voor uw fieren geest, En doet zijn eigen aard, als gij zijn wenschen Zoo dwarsboomt, veel geweld aan, ja, dat doet hij. ’k Verzeker u, op aarde leeft geen mensch, Die zoo hem tarten mocht, als gij het deedt,
  • 55. En niet gevaarlijk wierd te recht gewezen; Doch waag het niet te vaak, dit smeek ik u. Worcester. Voorwaar, mylord, uw hoofdigheid is laakbaar; Gij hebt sinds uwe komst genoeg gedaan, Om zijn geduld volkomen uit te putten. Die fout, heer, moet gij leeren overmeest’ren; Zij geev’ soms blijk van fierheid, adel, moed,— In zoo ver kan zij u tot sieraad zijn,— Doch al te vaak verraadt zij felle woede, Ruwheid van doen, gebrek aan zelfbeheersching, Trots, nederzien op and’ren, eigenwijsheid; En zij zelfs met het kleinst gebrek uit deze Een edelman behept, dit rooft hem steeds Der menschen hart, en werpt ook op den glans Van al zijn verd’re deugd een booze vlek, Die haar van welverdienden lof versteekt. 189 Heetspoor. Nu, ’k heb mijn les; geluk met hofmanieren! Ziet, onze vrouwen; laat ons afscheid nemen. (Glendower komt terug, met de Vrouwen.) Mortimer. Dit is voor mij een dood’lijk grievend leed: Mijn vrouw verstaat geen Engelsch, ik geen Welsch. Glendower. Mijn dochter weent; zij wil van u niet scheiden; Zij wil soldaat zijn, wil met u in ’t veld. Mortimer. Mijn vader, zeg haar, dat zij met nicht Percy
  • 56. Ons onder uw geleide weldra volgt. (Glendower spreekt met zijn dochter in het Welsch, en zij antwoordt in dezelfde taal.) Glendower. Zij is als dol, een lastig, koppig schepsel, Dat voor geen overreding vatbaar is. (Zij spreekt tot Mortimer in het Welsch.) Mortimer. O, ik versta uw blik, dat lieflijk Welsch, Dat uit uw zwaar bewolkte heem’len stroomt, Ken ik te goed; en als ik mij niet schaamde, Gaf ik u antwoord in dezelfde taal. (Zij spreekt weder.) ’k Versta ook uwen kus, als gij den mijnen, En dat is een gevoelvol onderhoud; Doch nimmer wil ik ledigloopen, lieve, Eer ik uw taal geleerd heb; want uw tong Maakt Welsch zoo zoet als hooggestemde lied’ren, Die bij haar luit een schoone koningin Verrukk’lijk zingt in ’t zomer-lustprieel.
  • 57. K o n i n g H e n d r i k I V , Eerste Gedeelte, Derde Bedrijf, Tweede Tooneel. Glendower. Als gij ook wegsmelt, wordt zij gansch waanzinnig.
  • 58. (Zij spreekt weder.) Mortimer. Die taal! ’k ben één en al onwetendheid! Glendower. Zij wenscht, gij vlijt u op het weeld’rig bies; En legt uw dierbaar hoofd in haren schoot, Dan wil zij u uw liev’lingsliedjes zingen, Den god des slaaps bekronen op uw oogleên, Uw bloed betoov’rend met een zoete loomheid, Zóó lieflijk slaap en waken bij u scheiden, Als tusschen dag en nacht de scheiding is, Het uur, voordat des hemels zonnespan In ’t oosten zijnen gouden tocht begint. Mortimer. Van harte gaarne zit ik neer en luister; In dien tijd, hoop ik, komt ons stuk gereed. Glendower. Doe dat; de muzikanten, Die voor u spelen zullen, zweven thans Op duizend mijlen afstands in de lucht, Doch zullen daad’lijk hier zijn. Zit en luister. Heetspoor. Kom, Kaatje, gij verstaat de kunst om u neer te vlijen ook; kom, vlug, vlug! ik wil mijn hoofd in uw schoot leggen. 231 Lady Percy. Loop, gij malle gans! (Muziek laat zich hooren.)
  • 59. Heetspoor. Nu merk ik, dat de duivel Welsch verstaat; En ’t is geen wonder, dat hij luimen heeft; Hij is, bij God, een goede muzikant. Lady Percy. Dan moet gij door en door muzikaal wezen, want gij wordt geheel door uw luimen geregeerd. Lig stil, gij schelm, en hoor hoe de Lady Welsch zingt. Heetspoor. Ik hoorde liever Lady, mijn brak, Iersch huilen. Lady Percy. Wilt gij een gat in uw hoofd hebben? Heetspoor. Neen. Lady Percy. Wees dan stil. Heetspoor. Ook niet; dit is een vrouwengebrek. Lady Percy. Nu, God help’ u! Heetspoor. In het bed der Welsche Lady?
  • 60. Lady Percy. Wat zegt gij? Heetspoor. Stil! zij zingt. (Lady Mortimer zingt een Welsch lied.) Kom, Kaatje, nu moet gij eens voor mij zingen. Lady Percy. Ik niet, in vollen ernst niet. Heetspoor. “Ik niet, in vollen ernst niet!” Mijn hartje, gij zweert als een banketbakkersvrouw: “Gij niet, in vollen ernst niet!” en “Zoo waar ik leef!” en “Zoo waar mij God helpe!” en “Zoo waar de lieve zon schijnt!” En geeft zoo taffen eedwaarborg, als waart gij Nooit verder weg geweest dan Finsbury. Zweer als een edelvrouw, zooals gij zijt, Een vollen eed, die klinkt,—en laat “In ernst” En zulke peperkoekbetuigingen Aan fulpgalons en zondagsburgers over. Kom, zing! Lady Percy. Ik wil niet zingen. Heetspoor.
  • 61. ’t Is de naaste weg naar het snijderworden of roodborstjes africhten. —Als de stukken klaar zijn, wil ik binnen twee uren weg; kom dus binnen, als ge wilt. (Heetspoor af.) Glendower. Kom, kom, lord Mortimer, gij gaat zoo traag, Als deze heethoofd Percy vurig ijlt. De stukken zijn nu wis gereed; wij zeeg’len En dan terstond te paard! Mortimer. Van ganscher harte. (Allen af.) TWEEDE TOONEEL. L o n d e n . Een vertrek in het paleis. Koning Hendrik, Prins Hendrik en Lords komen op. Koning Hendrik. Verlaat ons, Lords; de prins van Wales en ik Wij hebben een vertrouw’lijk onderhoud; Doch blijft nabij, straks zullen we u behoeven. (De Lords af.) Ik weet niet, of het God zoo heeft beschikt Voor ongevall’ge diensten, die ik deed,
  • 62. Dat hij, naar zijn verborgen raad, een geesel En straf mij uit mijn eigen bloed verwekt; Doch gij doet mij, door heel uw levenswandel, Gelooven, dat gij uitgelezen zijt Tot heete wraak, als strenge roê, des hemels, Om mijne schuld te straffen. Zeg mij anders, Hoe zulke bandelooze, lage driften, Een zoo armzalig, voos, onwaardig streven, Een zoo onvruchtb’re lust en woest verkeer, Als waar gij aan verknocht zijt, mee vergroeid, De hoogheid van uw bloed verzellen konden, Ooit konden reiken tot uw vorstenhart? Prins Hendrik. Veroorloof, uwe hoogheid! ’k Wenschte, dat ik Van iedre smet mij zoo bevrijden kon, Als ik mij buiten twijfel rein kan wasschen Van meen’ge zonde, mij te last gelegd; Doch laat mij toch om die verschooning smeeken, Dat ik, eerst tal van sprookjes logenstraffend,— Zooals het oor van grootheid vaak moet hooren Van plasdankzoekers en van nieuwtjesventers,— Voor enkle ware zaken, die mijn jeugd Loszinnig, buiten ’t spoor geraakt, beging, Vergiff’nis vind om mijn oprechte erkenning. Koning Hendrik. Vergeve u God!—doch ik verbaas mij, Hendrik, Dat uw begeerten zoo de wieken uitslaan, Ver van de vlucht van heel uw voorgeslacht. Door ruwheid hebt ge uw zetel in den staatsraad Verbeurd; uw jong’re broeder nam dien in; Een vreemdling zijt gij schier voor alle harten Van ’t hof en van de prinsen van mijn bloed. De hoop en de verwachting van uw tijd,
  • 63. Vervlogen zijn ze, en iedre menschenziel Voorspelt zichzelf profetisch uwen val. Was ik met mijn aanwezigheid zoo gul, Zoo uitgestald voor ieders oog, zoo glansloos En voor gemeen verkeer te koop geweest,— Die meening, die de kroon mij heeft verschaft, Ware aan het troonbezit getrouw gebleven, Had mij een roemloos balling laten blijven, Als een, die niets was, niets verwachten liet. Ik kwam zeer zelden voor den dag, maar dan Werd ik ook aangegaapt als een komeet; Dan riep de vader tot zijn kroost: “Dat is hij!” Een ander vroeg: “Waar, wie is Bolingbroke?” Dan was de hoflijkheid des hemels mijn, 50 En kleedde ik mij in zulk een need’righeid, Dat ik verknochtheid afdwong van hun hart, En groet en jubelkreten aan hun mond, Zelfs aan de zijde des gekroonden konings. Zoo hield ik mijn persoon steeds frisch en nieuw; Zij werd, gelijk een hoogepriesterskleed, Bewond’rend slechts aanschouwd; en heel mijn praal, Zeldzaam, doch kostbaar, was gelijk een feest, En zoo, door ongewoonte, een plechtigheid. De koning was een spring-in-’t-veld, verzelschapt Van dwaze fratsenmakers, strooien geesten, Snel vlammend, snel verbrand; zijn waardigheid Versneed hij, mengde ’t hooge koningschap Met luchtsprongnarren, liet zijn grooten naam Ontheil’gen door hun spot, en gaf zijn aanzien, Zijn naam ten trots, den lach van knapen prijs, Den moedwil van elk ijdel, baardloos gekje; Hij werd een klant der openbare straat, En maakte zich tot leenman van de volksgunst, Totdat, wijl de oogen daag’lijks hem verslonden, Het volk van honing was verzaad, de smaak
  • 64. Hun tegenstond van ’t zoet, waarvan een weinig Meer dan een weinig veel te veel reeds is. Kwam nu een dag, dat hij zich moest vertoonen, Dan werd hij, als de koekoek is in Juni, Gehoord, niet opgemerkt; gezien, met oogen, Die, door gewoonte stomp en moe, niet meer Voor ’t staren vatbaar zijn, dat met bewondring Den zonneschijn der majesteit begroet, Haar zelden zichtbren glans eerbiedig huldigt; Zij knikkebolden met geloken oogleên, Recht voor zijn oog, en gunden hem een blik, Als wreev’le mannen aan hun vijand doen, Van overdaad, die walgde van zijn bijzijn. En, Hendrik, op diezelfde lijn staat gij, Want gij ook hebt uw vorstlijkheid versmeten, Door laakbaar, laag verkeer. Geen enkel oog, Dat niet, te vaak u ziend, u moede werd; Alleen het mijne wenschte u meer te zien, En doet nu iets, wat ik mijzelf verwijt, Het maakt zich blind door dwaze teederheid. Prins Hendrik. Ik wil voortaan, genadig heer en vader, Mijzelf meer zijn. Koning Hendrik. In ieder opzicht zijt gij, Voorwaar, te dezer stond, wat Richard was, Toen ik te Ravenspurg uit Frankrijk landde; En juist wat ik toen was, is Percy nu. Ja, bij mijn scepter en mijn zieleheil, Hij heeft veel hooger aanspraak op den troon, Dan gij hebt door de schaduw van uw erfrecht; Want zonder recht, ja zonder zweem van recht, Vult hij ’s rijks velden met zijn wapenmacht,
  • 65. Houdt stand voor de’ open muil des leeuws, en brengt, 102 Niet meer dan gij zijn jaren dankend, achtb’re Bisschoppen en vergrijsde lords in ’t veld, Tot schilden-splijten en tot bloedig strijden. En wat onsterfelijken roem verwierf hij Zich tegen Douglas, dien geprezen held, Wiens stoute tochten, grootsche wapenfeiten Bij elken krijger hem den eersten rang, Den hoogsten oorlogsroem verworven hadden, In alle rijken, waar men Christus eert! Driemaal heeft deze Heetspoor, Mars in winds’len, Die zuig’lingheld, in ’t veld den grooten Douglas Verslagen, ééns gevangen hem gemaakt, Hem weer geslaakt en toen als vriend gewonnen, Om diepe vijandschap den mond te stoppen, En onzen troon te schokken, dat hij vall’. En hoor nu toe: “Percy, Northumberland, Yorks hooge kerkvoogd, Douglas, Mortimer, Zijn tegen ons verbonden, staan in ’t veld.” Doch wat heb ik die tijding u te melden, U, Hendrik, u mijn vijanden te noemen, U, die mijn naaste en ergste vijand zijt? U, die wellicht uit onderdaan’ge vrees, Uit lagen lust, of als een luim u drijft, Mij zult bevechten in soldij van Percy, Den voet hem likken, voor zijn fronsblik kruipen, Om recht te toonen, hoe ontaard gij zijt. Prins Hendrik. Neen, denk dit niet, gij zult het zoo niet vinden; Vergeev’ God hun, die bij uw majesteit Mij zoo van uwen goeden dunk beroofden! Ik maak dit alles goed op Percy’s hoofd, En zal aan ’t einde van een dag vol roems Met fierheid tot u zeggen: “’k ben uw zoon”;
  • 66. Als ik in een gewaad van bloed u nader, Mijn trekken met een masker kleur van bloed, Dat, weggewasschen, ook mijn schande wegspoelt. Dat zal de dag zijn,—koom’ hij als hij wil!— Waarop eenmaal dat kind van eer en roem, De dapp’re Heetspoor, de geprezen ridder, En uw vergeten Hendrik samentreffen. O waar’ elke eer, die op zijn helmet troont, Een menigt’, en op mijn hoofd elke schimp Verdubbeld! want de dag genaakt, hij komt, Dat ik dien noordschen jong’ling dwing, zijn schat Van roem te ruilen voor mijn oogst van schande. Percy, mijn vorst, is slechts mijn zaakwaarnemer; Zijn heldendaden stapelt hij voor mij; En dra roep ik hem op tot rekenschap; Uitleev’ren zal hij mij zijn ganschen roem, Ja, ook het nietigst eerbetoon der wereld, Of ik rijt hem de reek’ning uit zijn hart. Dit zweer ik plechtig, bij den naam van God; En als het Hem behaagt, dat ik ’t volbreng, Dan heele dit, zoo smeek ik uwe hoogheid, Elke oude wond van mijn losbandigheid; Zoo niet, dan delgt de dood toch alle schuld; En ik wil honderdduizend dooden sterven, Eer ik een adem van deze’ eed verbreek. 159 Koning Hendrik. Dit doodt een honderdduizendtal verraders; Nu zij bevel en alles u vertrouwd. (Blunt komt op.) Spreek, wakkre Blunt! uw blikken zijn vol haast. Blunt.
  • 67. Dien heeft de zaak, die ik u melden kom. Lord Mortimer van Schotland zond bericht, Dat Douglas zich met de Engelsche oproerlingen Den elfden heeft vereend te Shrewsbury. Het wordt een zoo verschrikk’lijk machtig heer, Indien elk hunner zijn beloften houdt, Als ooit een staat met onheil heeft gedreigd. Koning Hendrik. De graaf van Westmoreland trok heden op, Met hem mijn zoon, lord John van Lancaster; “Want dit bericht, vijf dagen is het oud.— Aanstaanden Woensdag, Hendrik, breekt gij op; Wijzelf op Donderdag; verzamelplaats Zal Bridg’north zijn; gij, Hendrik, neemt uw weg Door Glostershire; naar deze reek’ning zal, Is alles goed geordend, in twaalf dagen Te Bridg’north onze macht vereenigd zijn. Van hier! veel is te doen en haast is goed; ’t Geluk wordt loom, als zich de mensch niet spoedt. (Allen af.) DERDE TOONEEL. E a s t c h e a p . Een vertrek in de herberg “Het Zwijnshoofd.” Falstaff en Bardolf komen op. Falstaff. Bardolf, ben ik niet schandelijk afgevallen na die laatste geschiedenis? vermager ik niet? slink ik niet weg? Verduiveld, mijn
  • 68. vel hangt om mij heen als het huiskleed van een oude madam; ik ben zoo verschrompeld als een goudpippeling. Nu, ik wil tot mijzelf inkeeren, maar dan terstond, terwijl ik nog wat goed in ’t vleesch ben; binnenkort zal ik zoo min wezen, dat ik de kracht niet heb, om tot mijzelf in te keeren. Als ik niet vergeten ben, hoe een kerk er van binnen uitziet, ben ik een peperkorrel, een brouwerspaard! Een kerk van binnen! Mijn omgang, mijn nietswaardige omgang heeft mij bedorven. Bardolf. Sir John, gij zijt zoo neerslachtig, gij hebt niet lang meer te leven. Falstaff. Ja, zoo is het.—Kom, zing mij eens een schuinsch liedje, vroolijk mij wat op. Ik was zoo deugdzaam gezind, als een man van stand behoeft te zijn, deugdzaam genoeg; vloekte weinig, dobbelde niet boven de zeven keer in de week, ging in slechte huizen niet meer dan eens in een vierendeel—uurs; betaalde het geld, dat ik borgde, drie- of viervoudig; leefde ordelijk en hield behoorlijk maat,—en nu leef ik recht ordeloos en buiten alle maat. 23 Bardolf. Nu, ge zijt zoo dik, Sir John, dat ge wel buiten alle maat moet zijn, buiten alle redelijke maat, Sir John. Falstaff. Verbeter jij je gezicht, en ik wil mijn leven beteren. Je bent onze admiraal, je draagt de lantaren aan den achtersteven,—neen, ze zit bij je in den neus; je bent de Ridder van de brandende Lamp. Bardolf. Kom, Sir John, mijn gezicht doet u geen kwaad.
  • 69. Falstaff. Neen, dat wil ik je wel bezweren, ik maak er een even goed gebruik van, als menigeen van een doodshoofd of een memento mori. Ik zie nooit je gelaat, of ik denk aan het helsche vuur en aan den rijken man, die in purper leefde; want daar zit hij al in zijn praal en brandt en brandt. Was je eenigermate aan de deugd verkleefd, dan zou ik zweren bij je gezicht; mijn eed zou wezen: “Bij die vuurvlam, die de engel Gods is.” Maar je bent gansch en al aan de zonde verslaafd, en zoudt inderdaad, zonder dien gloed op je gezicht, de zoon wezen van de buitenste duisternis. Toen je bij Gadshill den heuvel opliept om mijn paard te vangen,—als ik toen niet dacht, dat je een dwaallicht of een bliksemvuurbol waart, dan is er voor geld niets meer te koop. O, je bent een eeuwigdurende fakkeloptocht, een onuitblusschelijk vreugdevuur. Je hebt mij een duizend marken aan toortsen en kaarsen uitgehaald, als ik ’s nachts met je wandelde, de eene herberg uit, de andere in; maar voor de sek, die je mij hebt opgedronken, had ik bij den duursten kaarsenmaker in Europa even zoo goedkoop kaarsen kunnen hebben. Ik heb dien salamander van je nu al twee en dertig jaren van vuur voorzien, God loone ’t mij! Bardolf. Verduiveld, ik wenschte, dat mijn gezicht in uw buik zat! Falstaff. God beware me! dan had ik den brand in mijn ingewanden. (De Waardin komt op.) Hoe is het, mevrouw Koekeloer? Ben je er achter, wie mijn zakken geleegd heeft? Waardin.
  • 70. Wel, Sir John, wat denkt ge, Sir John? Denkt ge, dat ik dieven in mijn huis heb? Ik heb gezocht, ik heb gevraagd, en mijn man ook, man voor man, jongen voor jongen, meid voor meid; geen tiende van een haar is er ooit in mijn huis zoek geraakt. 67 Falstaff. Gelogen, waardin; Bardolf is er geschoren geworden en heeft er menig haar verloren; en ik durf zweren, dat mijn zakken geleêgd zijn. Loop heen, je bent een vrouwmensch; ga! Waardin. Wie, ik? Neen, zeg dat nog eens! God in den hemel! zoo heeft mij nog niemand in mijn eigen huis genoemd. Falstaff. Loop heen, ik ken je door en door. Waardin. Neen, Sir John; ge kent mij niet, Sir John; ik ken u, Sir John; ge zijt me geld schuldig, Sir John; en nu zoekt ge twist om van mij af te komen. Ik heb u een dozijn hemden op het lijf gekocht. Falstaff. Paklinnen, voddig paklinnen; ik heb ze aan bakkersvrouwen weggegeven en die hebben er builen van gemaakt. Waardin. Wat! zoowaar ik een eerlijke vrouw ben, Hollandsch linnen van acht schellingen de el! Bovendien zijt gij hier ook nog geld schuldig, Sir John, voor uw eten, en het tusschen in drinken, en geleend geld, vier en twintig pond.
  • 71. Falstaff (op Bardolf wijzend). Hij heeft ook zijn deel er van gehad, laat hem betalen! Waardin. Hij? lieve, God, hij is arm, hij heeft niets. Falstaff. Wat! hij arm? Zie zijn gezicht eens aan; wat noem je dan rijk? laat hem munt slaan uit zijn neus, munt slaan uit zijn wangen. Ik betaal geen duit. Wat, wil je een grasgroenen jonker van mij maken? Zou ik mijn gemak niet kunnen nemen in mijn eigen herberg, zonder dat men mij de zakken leêgt? Ik ben er een zegelring van mijn grootvader mee kwijt geraakt, die zijn veertig marken waard is. Waardin. O Jezus! ik heb den prins ik weet niet hoe dikwijls tegen hem hooren zeggen, dat die ring van koper was. Falstaff. Wat! de prins is een weerhaan, een uitknijper; verduiveld! als hij hier was, zou ik hem afrossen als een hond, zoo hij dat zeide. (Prins Hendrik en Poins komen op, marcheerend; Falstaff gaat den Prins, die op zijn commandostaf als op een fluit speelt, te gemoet.) Falstaff. Hoe is het, mijn jongen? Waait de wind uit dien hoek? Waarachtig? moeten wij allen marcheeren? Bardolf.
  • 72. Ja, twee aan twee, als gevangenen naar Newgate. 104 Waardin. Mylord, ik bid u, hoor mij. Prins Hendrik. Wat is er, vrouw Haastig? Hoe maakt uw man het? Ik mag hem wel; hij is een eerlijke kerel. Waardin. Beste mylord, hoor mij aan! Falstaff. Ik bid u, laat haar loopen en luister naar mij. Prins Hendrik. Wat wil je dan, Hans? Falstaff. Kort geleden ben ik ’s avonds hier in slaap gevallen, daar achter het tapijt, en toen zijn mij de zakken geleêgd; dit huis is een spelonk geworden; zij leêgen er iemand de zakken. Prins Hendrik. Wat ben je er meê kwijt geraakt, Hans? Falstaff. Wil je wel gelooven, Hein, drie of vier schuldbekentenissen van veertig pond elk, en een zegelring van mijn grootvader.
  • 73. Prins Hendrik. Een bagatel, een ding van acht stuivers. Waardin. Dat heb ik hem ook gezegd, mylord; en ik zeide, dat ik het uwe genade had hooren zeggen; en, mylord, hij spreekt allerschandelijkst van u, zoo’n vuilbek als hij is, en zeide, dat hij u zou afrossen. Prins Hendrik. Wat! dat zeide hij toch niet? Waardin. Als het niet waar is, is er geen waarachtigheid of eerlijkheid of vrouwelijkheid in mij. Falstaff. Je bent niet waarachtiger dan gestoofde pruimen, niet eerlijker dan een opgejaagde vos, en wat de vrouwelijkheid betreft, kan bij vergelijking juffer Marianne van den moorendans voor een buurtmeestersvrouw doorgaan. Loop, schepsel, loop rondom! Waardin. Zeg, wat voor een schepsel? wat voor een schepsel? Falstaff. Wat voor een schepsel? wel een schepsel, om God voor te danken. Waardin. Ik ben geen schepsel, om God voor te danken, onthoud dat maar; ik ben een eerlijken mans vrouw; en, je ridderschap er buiten gelaten,
  • 74. je bent een schelm, dat je mij zoo noemt. Falstaff. En, je vrouwelijkheid er buiten gelaten, je bent een beest, dat je het beter wilt weten. Waardin. Zeg eens, wat voor een beest, jij schelm? 141 Falstaff. Wat voor een beest? wel, een otter. Prins Hendrik. Een otter, Sir John! waarom een otter? Falstaff. Waarom? Wel, zij is nòch vleesch nòch visch; een mensch weet niet, waar haar toe te brengen. Waardin. Je bent een lasteraar, als je dat zegt; gij en iedereen weet, dat ik nergens toe te brengen ben, jij schelm, jij! Prins Hendrik. Je hebt gelijk, waardin; en hij belastert je op afschuwelijke manier. Waardin. Dat doet hij u ook, mylord; en hij zeide nog kort geleden, dat gij hem duizend pond schuldig waart.
  • 75. Prins Hendrik. Wat, man! ik je duizend pond schuldig? Falstaff. Duizend pond, Hein! een millioen; je vriendschap is een millioen waard; en je vriendschap ben je mij schuldig. Waardin. Neen, maar mylord, hij noemde u een weêrhaan, en zeide, dat hij u zou afrossen. Falstaff. Heb ik dat gezegd, Bardolf? Bardolf. Zeker, Sir John, dat hebt ge gezegd. Falstaff. Ja, als hij zeide, dat mijn ring van koper was. Prins Hendrik. Ik zeg, hij is van koper; durft ge zoo goed als je woord nu wezen? Falstaff. Wel, Hein, je weet, voor zoover je slechts een man bent, durf ik; maar voor zoover je een prins bent, vrees ik je, als het gebrul van een leeuwenwelp. Prins Hendrik.
  • 76. En waarom niet als de leeuw? Falstaff. De koning zelf is te vreezen als de leeuw. Denk je, dat ik je zal vreezen, zooals ik je vader vrees? Neen, als ik dat doe, straff’ mij God en moge mijn gordel bersten! Prins Hendrik. O, als dat gebeurde, hoe zou je pens om je knieën flodderen! Maar, kerel! voor waarheid, eerlijkheid en oprechtheid is er in je lijf geen plaats; het is volgepropt met darmen en vet. Een eerlijke vrouw van zakkenrollerij te beschuldigen! Wel, jij liederlijke, onbeschaamde, opgezwollen schelm, als er iets in je zak zat dan herbergiersrekeningen, nota’s uit knippen, en voor een armzaligen stuiver kandijsuiker om de keel glad te houden,—als je zakken gevuld waren met andere ongerechtigheden dan deze, dan ben ik een schurk. En toch durf je volhouden, dat je geen onrecht zoudt opsteken! Schaam je je niet? 184 Falstaff. Laat ik je zeggen, Hein: je weet, in den staat van onschuld is Adam gevallen; wat zou dan de arme Hans Falstaff doen in de dagen der verdorvenheid? Je ziet, ik heb meer vleesch dan andere menschen en daarom ook meer zwakheid. Je erkent dus, dat je mij de zakken geleêgd hebt? Prins Hendrik. Dit schijnt wel te blijken. Falstaff. Waardin, ik vergeef je. Ga, maak het ontbijt gereed; bemin je man, ga je bedienden na, zorg goed voor je gasten; je zult mij voor alle
  • 77. gezonde redenen toegankelijk vinden; je ziet, ik ben bevredigd.— Nog iets?—Neen, ik bid u, ga heen. (De Waardin af.) Nu, Hein, nu van het nieuws aan het hof; die straatrooverij, jongen,—hoe is dat in het effen gebracht? Prins Hendrik. O, mijn lieve rollènde, ik moet altijd je goede engel zijn.—Het geld is terugbetaald. Falstaff. Hm! ik houd niet van dat terugbetalen; ’t is dubbel werk. Prins Hendrik. Ik ben met mijn vader op goeden voet en kan alles doen. Falstaff. Plunder dan vóór alles de schatkist, en wel zonder omslag te maken. Bardolf. Ja, doe dat, mylord. Prins Hendrik. Ik heb je een commando te voet verschaft, Hans. Falstaff. Te paard zou mij liever geweest zijn. Waar kan ik er een vinden, die behoorlijk kan stelen? O, zoo’n knappen dief van twee-en-twintig of daaromtrent! Ik ben schandelijk aan lager wal. Nu, God zij gedankt voor die opstandelingen; zij doen niemand kwaad dan de braven; ik prijs, ik loof hen.
  • 78. Prins Hendrik. Bardolf! Bardolf. Mylord? Prins Hendrik. Breng dit stuk aan Lord John van Lancaster, Mijn broeder John,—dit aan Lord Westmoreland.— Kom, Poins, te paard! te paard! Wij hebben saam Vóór ’t middagmaal een dertig mijl te rijden.— Gij Hans, kom morgen in de Tempelzaal Tot mij te twee uur na den middag. Daar neemt ge uw dienstbrief in ontvangst en geld, Met last, hoe gij uw volk hebt uit te rusten. Gansch England brandt, en hoog draagt Percy ’t hoofd; Het zijne valle, of ’t onze zij gekloofd! (De Prins, Poins en Bardolf af.) Falstaff. Vuurwoorden! dapp’re wereld!—Wijn hier, kom!— Ha, ’k wenschte mij dit wijnhuis voor mijn trom! (Falstaff af.)