In this section, we shall take a brief look at some of the Windows kernel mitigations that might hinder or completely block our exploits. Additional details and how to bypass/overcome each of these obstacles(if possible) will be discussed later as per the exploitation scenario.
Also known as
Patch Guard(PG), this is one of the more prominent and effective anti-tampering kernel mitigations aimed at stopping rootkits(and shady software including PSPs) from ravaging around the kernel to accomplish their objectives such as AVs hooking
System Service Descriptor Table(SSDT) to gain visibility into system calls etc. It was first introduced in
Windows XP x64.
KPP is designed to detect any changes to critical Windows kernel structures/registers and
bugcheck(Code: 0x109/CRITICAL_STRUCTURE_CORRUPTION) or crash the system with a much dreaded
Blue/Green Screen Of Death(BSOD/GSOD).
However, it is polled and the beauty of
KPP lies in its randomness(apart from its obfuscation) of these checks which means it is quite possible that the changes are not caught instantly but after some time has passed by. This way it takes away the reliability from hooking random stuff in the kernel even if it cannot stop it right away.
Bypasses do exist against
KPP but since it is a moving target, vulnerabilities may be fixed as happened with
InfinityHook. Also, note that
KPP may be disabled by using a bootkit or hooks can simply be hidden using
EPT/NPT ghost hooks by loading a rogue hypervisor.
Astute readers may observe that there's nothing stopping us from tampering whatever we want in the kernel for an extremely short duration of time to accomplish our goals and then reverting the changes immediately before
KPP even gets a chance to trigger on it and none will be the wiser.
Well, this sounds nice in theory, however, since we have no way of knowing when the value was last checked, doing this has a very real(albeit small) chance of
BSODing a target system. In our job, no matter how small the chances are, this is not recommended at all and should only be considered as a last resort option.
Also known as
Kernel Mode Code Signing(KMCS), it is another prominent and quite effective mitigations to ensure that all kernel drivers are properly signed with a valid digital signature. It was first introduced in
Windows Vista x64.
Windows 10 RS1/1607,
DSE allows third-party drivers to be loaded iff:
1. Driver is
Attestation Signed(signed using
Extended Validation(EV) code signing certificate + countersigned by
Microsoft Windows Hardware Compatibility Publisher)
2. Driver is
Windows Hardware Quality Labs/WHQL-testing Signed
However, there are three notable exceptions to this rule under which it will still allow a driver to load:
SecureBoot(SB) is turned off from
UEFI settings OR
2. The system was upgraded from an earlier version or a build earlier than
Windows 10 RS1/1607 OR
3. Driver was
Cross Signed using a valid certificate issued prior to 29th October, 2015
Some bypasses include temporary patching of a global variable that controls
KPP-protected) by exploiting a vulnerable signed driver, using kernel shellcode/
PIC as the payload instead of a driver or acquiring valid certificates from third-parties.
KASLR is designed to prevent predicting addresses of some desired kernel memory by randomizing the base address of the kernel image, kernel modules and device drivers on a per-boot/load basis. It was first introduced in
Over the years, it has undergone some significant changes like
High Entropy ASLR(22 bits of entropy) and
Force ASLR(randomize even for
non-ASLR compiled modules) along with the information disclosure leaks that have been fixed by Microsoft make this a truly effective mitigation.
Some of the interesting changes made to
KASLR over the years are:
1. The offset of
Self-Reference PML4E has been randomized from the static value of
0x1ed. This consequently leads to
VA randomization of the base of paging structures(
PxE) and its entries
2. Kernel address leak from
GDI objects have been fixed
3. Kernel address leak from
GdiSharedHandleTable(PEB) has been fixed
4. Kernel address leak from
SGDT/SIDT instruction is fixed when
VBS is enabled
Low-IL processes cannot use
EnumDeviceDrivers() to leak kernel addresses
HAL Heap VA is now randomized
There exists bypasses against
KASLR but they usually rely on additional vulnerabilities in the form of information leaks.
DEP is designed to prevent code execution in non-executable portions of memory/data segment of memory. In other words,
DEP ensures that no memory page is both writable and executable(
W^X) simultaneously. It was first introduced(fully) in
Windows 8, drivers now have a pool type known as
NonPagedPoolNx which essentially marks it as non-executable non-paged memory pool.
DEP is enforced on a per-page basis via a
Page Table Entry(PTE) control bit known as
Some bypasses include using
Return Oriented Programming(ROP) payload in the kernel/re-using existing kernel code to execute our code, flipping the
NX bit in the
PTE or redirecting execution flow to a
User-Mode(UM) allocated page.
SMEP prevents execution of
Kernel-Mode code residing in
User-Mode page. In other words, if code residing in
CPL-3 is executed in context of
bugcheck(Code: 0xfc/ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY or crash the system with a
BSOD/GSOD. It was first introduced(fully) in
This is a particularly effective mitigation for
LOCAL kernel exploits where we somehow gain control over the
RIP register in
Ring 0, allocate memory in
User-Mode and jump to get kernel shellcode execution in
Ring 3 which is not possible anymore with
SMEP is controlled by the
20th bit of the
CR4 register and enforced at page level by the
Owner control bit/
User/Supervisor(U/S) bit in the
Page Table Entry(PTE).
Some bypasses include using
Return Oriented Programming(ROP) chain in the kernel to flip the
KPP-protected) or using an arbitrary read/write primitive to flip the
U/S bit in
Supervisor Mode Execution Protection by Stephen Fischer
Also known as
Software SMEP, this software mitigation is designed to protect against leaking kernel memory via
Speculative Execution Variant 3 or
Meltdown(CVE-2017-5754). It was first introduced in
Windows 10 RS4/1803.
This mitigation is the Windows equivalent of Linux's
Kernel Page Table Isolation(KPTI) based off of
KAISER and involves the separation of
Kernel-Mode page tables from
User-Mode page tables for each process. This means that most of the
System Space is not mapped in the
User-Mode page tables while the
Kernel-Mode page tables both of the mappings. The
Kernel-Mode page table base is stored in
nt!_KPRCB.KernelDirectoryTableBase while the
User-Mode page table base is stored in
KVAS is enforced on a per-process basis.
We may call
SystemKernelVaShadowInformation class to check whether
KVAS is enabled.
Some bypasses for
KVAS include leaking the base
VA of the
PML4 table and then using
ROP gadgets to turn off the
NX bit in the
PML4E of the shellcode
Also known as
Device Guard(DG), it is an incredibly powerful and flexible second-generation application control/whitelisting solution for both
Kernel-Mode code. It was first introduced in
Windows 10 RS1/1607.
WDAC allows creation and enforcement of configurable
Code Integrity(CI) policies that can either be for
Ring 3 or
Ring 0 code. However, we are concerned with the
Ring 0 portion only i.e. auditing/blocking conflicting device drivers via
Kernel Mode Code Integrity(KMCI) or Hypervisor-enforced Code Integrity(HVCI). It supports both
Audit mode(only log event with Event ID =
3076, do not actually block loading) and
Enforce/Block mode(log and block it for real with Event ID =
3077). Note that there's also an additional event with Event ID =
3089 that gives extended signer information of the device driver at fault.
WDAC allows granular control over what
Kernel-Mode code should be allowed to load and as a result may effectively mitigate the threat from signed and vulnerable drivers.
CI policies start out as
XML files and they are converted to a binary format before being deployed. It allows enforcement of multiple policies and they can even be signed to protect against possible tampering from a
Here is a
Powershell one-liner to deploy an example
Audit policy from
Microsoft that only allows
WHQL-test Signed and
Attestation Signed third-party device drivers to load:
ConvertFrom-CIPolicy -XmlFilePath C:\Windows\schemas\CodeIntegrity\ExamplePolicies\DefaultWindows_Audit.xml -BinaryFilePath C:\Windows\System32\CodeIntegrity\SIPolicy.p7bRestart-ComputerImport-Module .\WDACTools.psd1$Events = Get-WDACCodeIntegrityEvent -Kernel -SignerAndWhqlChecks$Events
Do not forget to remove
UMCI from the
CI policy before deploying it since we do not want to be flooded by events from
Bypasses would heavily depend on the specific scenario at hand.
Also known as
Virtual Secure Mode(VSM), this is not a mitigation per se but rather a set of powerful features leveraging Microsoft's hypervisor called
Hyper-V using hardware virtualization capabilities of modern processors to enforce additional security boundaries. It was first introduced in
Windows 10 TS1/1507.
The minimum requirements of
Second Level Address Translation(SLAT) support -
Intel EPT or
Virtualization Extensions support -
Intel VT-x or
AMD-V preferably with
Mode Based Execution Control(MBEC) or
Guest Mode Execute Trap(GMET) respectively
However, to fully secure the hypervisor from all kinds of attacks including physical and enforce
VBS security, the following additional requirements should be satisfied:
Input Output Memory Management Unit(IOMMU) support -
Intel VT-d or
Trusted Platform Module(TPM)
On capable hardware
Hyper-V and subsequently
VBS(only base features like
HyperGuard) may be enabled by executing the following command from an admin prompt and rebooting:
bcdedit /set hypervisorlaunchtype auto
VBS splits the trust into two separate partitions/VMs(also called
Virtual Trust Level(VTL)):
VTL-0 Ring 0(ntoskrnl.exe) - The assume-compromised VM which runs the normal kernel
VTL-1 Ring 0(securekernel.exe) - The protected VM also called
Secure Kernel Mode(SKM) which runs a minimalized and secure kernel,
VTL-1 has full control over
VTL-0 and is responsible for maintaining its security. Furthermore, access to
VTL-1 pages by a lower
VTL-0 can be controlled via
SLAT and is thus protected from compromise even if the normal kernel is compromised.
There also's an
Isolated User Mode(IUM) or
VTL-1 Ring 3 where only special Microsoft-signed processes called
LsaIso.exe) can run and the normal
Ring 3 where all other
User-Mode code is run i.e. in
VTL-0 Ring 3.
Also known as
Secure Kernel Patch Guard(SKPG),
HG is designed to detect any changes to critical kernel structures/
CPU registers and
bugcheck(Code: 0x18C/HYPERGUARD_VIOLATION) if any inconsistency is detected much like its predecessor
However, it does not share the same weaknesses of
PG in the sense that
HG can detect the changes in real-time and crash the system as soon as any tampering occurs unlike the former which is polled and adversaries may get away with a burst tampering tactic.
HG operates in
VTL-1 Ring 0 unlike
PG and sets up
Secure Intercepts that trigger when certain events occur in the kernel. As a result of this design, it is also better resilient to attacks.
Among the major things(in our context) that
HG protects are:
1. Control registers,
Model Specific Register(MSR)s,
IDTR etc. This implies that we can no longer disable
SMEP via flipping 20th bit of
CR4 register nor can we use exposed
__writemsr in vulnerable drivers to achieve function pointer overwrite primitive via
MSR_LSTAR and get code execution.
Global Descriptor Table(GDT)
Interrupt Descriptor Table(IDT)
Some workarounds may include direct
PTE manipulation to bypass
SMEP instead of tampering with
Also known as
Memory Integrity, this is one of the core components of
VBS that is designed to enhance
CI via hypervisor and enforce
W ^ X in the kernel to keep in check what a malicious device driver can do even after it is allowed to load. It is also utilized by
Custom Code Integrity(CCI) when hardware support is available for strong code guarantees.
HVCI may be turned on by executing the following command from an admin prompt and rebooting:
reg add "HKLM\SYSTEM\CurrentControlSet\Control\DeviceGuard\Scenarios\HypervisorEnforcedCodeIntegrity" /v "Enabled" /t REG_DWORD /d 1 /f
HVCI provides the following security guarantees:
1. Only properly signed kernel pages can become executable.
CI is actually enforced by the hypervisor(
skci.dll in Secure Kernel/VTL-1 Ring 0). This implies that it wouldn't be possible to load unsigned drivers even if we have already compromised the kernel(
VTL-0 Ring 0) i.e. patching
CI.dll in kernel.
2. Kernel pages can never be
+X at the same time. This implies that
Ring 0 code once loaded cannot be modified and dynamically loaded code(
Ring 0 shellcode) is not allowed either since kernel cannot allocate
+RWX code permissions
3. Additionally, it mitigates the ability to directly modify
PTE control bits in the kernel to bypass
This is achieved with the help of kernel's
EPT along with
MBEC/GMET(or it's software emulation called
Restricted User Mode(RUM) if hardware support is not available) which are additional "secured" control bits maintained by
VTL-1 Ring 0.
Some workarounds for
HVCI include using code-reuse techniques such as
ROP/COP/JOP payloads in the kernel, resorting to data corruption attacks, finding leftover
+RWX pages from the early boot phase or compromising either
Ring -1/Hypervisor directly or via
This is Microsoft's
Forward-Edge Control Flow Integrity(CFI) implementation in the kernel that protects against indirect function calls by validating against a
call targets which are additionally protected from modification by the hypervisor/
KCFG is another particularly effective mitigation along with
HVCI that mitigates against overwriting function pointer and executing it to obtain code execution.
nt!MiInitializeKernelCfg is used to initialize the
CFG bitmap for the kernel and
nt!_guard_dispatch_icall is used to validate
call targets via the bitmap.
Bypasses may include modifying an
Import Address Table(IAT) entry with the address of shellcode(
KCFG does not take
call targets into consideration.
This is one of the newer
VBS mitigations that is designed to enforce immutability of
+R0 pages of kernel memory via
SLAT and protect it from data corruption attacks.
There are two variants of this mitigation:
Static KDP is aimed to prevent data corruption attacks commonly used to elevate privileges, kill defences, disable
PPL by tampering with the
Protection byte in
nt!_EPROCESS structure etc. with a
Ring 0 R/W primitive. With
PSP drivers can protect a section of their image using
MmProtectDriverSection which would make it
Read Only(RO) using
EPT entries thus enforcing immutability from
VTL-0 Ring 0.
Dynamic KDP is aimed at letting device drivers allocate a secure
+RO memory pool using
Analysis of the Attack Surface of Windows 10 Virtualization-Based Security by Rafal Wojtczuk
BlueHat v18 || Hardening hyper-v through offensive security research by Jordan Rabet
This is a hardware-based mitigation created by
Intel for enforcing both
Forward-Edge CFI and
Backward-Edge CFI. Support for
CET has been added in
Windows 10 20H1/2004.
Indirect Branch Tracking(IBT) to protect against
Forward-Edge cases i.e.
indirect CALL/JMP and
Hardware-enforced Shadow Stack to protect against
Backward-Edge cases i.e.
CFG already protects against
Forward-Edge cases, Microsoft has decided to rely on that(plus
Extended Flow Guard(XFG)) and discard
CFG does not provide any protection against
Backward-Edge cases which is where
CET comes in and mitigates corruption of return addresses on the stack.
When a mismatch is detected between a target return address on the stack and its preserved return address on the
Hardware Shadow Stack, a
Control Flow Protection Fault is generated.
CET essentially takes away our ability to use
ROP to get code execution.