BYOVD: The Windows Kernel Internals That Let Attackers Kill Your EDR

In February 2026, Huntress responded to an intrusion where an attacker loaded a 15-year-old EnCase forensic driver — its certificate expired and revoked since 2010 — into the Windows kernel and used it to kill every security process on the system. Windows accepted the driver without complaint. This is a deep dive into the kernel architecture that makes Bring Your Own Vulnerable Driver attacks possible: how drivers interact with the kernel, why Protected Process Light doesn't stop them, how kernel callbacks work and how they're dismantled, and why Microsoft's defenses keep falling short.

BYOVD is not a new technique. Lazarus Group was using it to blind security tools in 2021. What has changed is the scale: it has migrated from APT tradecraft to standard ransomware playbook. BlackByte, RansomHub, Kasseika, Qilin, Reynolds, Interlock — every major ransomware family now includes a BYOVD component. Tools like Terminator and EDRKillShifter are sold on underground forums for as little as $300. A $100,000 EDR-killer tool marketed by an actor called Baphomet claims to defeat every major endpoint security product on the market.

To understand why this technique is so effective, you need to understand how the Windows kernel works.

Why the Kernel Matters

Windows divides execution into two privilege domains: user mode (Ring 3) and kernel mode (Ring 0). Every application — including your EDR — runs in user mode with restricted access to hardware and system memory. The kernel, along with its loaded drivers, runs with unrestricted access to everything.

Ring -1
Hypervisor (Secure Kernel) — VBS/HVCI. Enforces code integrity checks on kernel memory. Can prevent unsigned code execution even at Ring 0. Only present when VBS is enabled.
Ring 0
Kernel Mode — ntoskrnl.exe, HAL, loaded drivers (including vulnerable ones). Full access to all memory, hardware, and system structures. No process isolation. A loaded driver can read and write any kernel data structure.
Ring 3
User Mode — Applications, services, EDR agent processes. Subject to access controls, process isolation, PPL restrictions. Cannot directly access kernel memory without going through syscall interface.

This architecture creates the fundamental asymmetry that BYOVD exploits. EDR agents run their user-mode processes at Ring 3, but register kernel-mode components (drivers, callbacks, minifilters) at Ring 0 for visibility. If an attacker can load their own driver into Ring 0, they operate at the same privilege level as the EDR's kernel components — with no process isolation to stop them from modifying anything.

Inside the kernel, there are no access controls between loaded modules. A driver loaded via sc.exe has the same memory access as ntoskrnl.exe itself. Every data structure, every callback registration, every process token is directly accessible to any code running at Ring 0.

The Windows Driver Model: Signed Trust, Unsigned Intent

Windows requires all kernel-mode drivers to be digitally signed by a trusted Certificate Authority. This policy, called Driver Signature Enforcement (DSE), was designed to prevent arbitrary code from loading into the kernel. In theory, only code vetted by Microsoft's signing process should run at Ring 0.

In practice, DSE has a critical gap. Windows does not check certificate revocation lists (CRLs) at driver load time. It validates that a driver has a cryptographically valid signature chain, but it does not verify whether the signing certificate has been revoked. This means a driver signed with a certificate that expired in 2010 and was subsequently revoked — like the EnCase driver used in the February 2026 Huntress incident — will still load successfully.

"The EnCase driver's certificate expired in 2010 and was subsequently revoked, yet Windows still loads it, a gap in Driver Signature Enforcement that attackers continue to exploit." — Anna Pham and Dray Agha, Huntress

There is also a backward compatibility exception: drivers signed with certificates issued before July 29, 2015, that chain to a supported cross-signed CA, are accepted by default. This was intended to avoid breaking legacy hardware drivers. It has become a permanent vulnerability.

The BYOVD technique exploits this trust gap. The attacker does not need to create or sign their own driver. They bring a legitimate, vendor-signed driver that contains a known vulnerability. Windows trusts the signature. The driver loads into Ring 0. The attacker then communicates with the driver through its IOCTL interface to execute privileged operations.

Inside EPROCESS: Where Protection Lives

Every process running on Windows is represented in the kernel by an _EPROCESS structure. This is the kernel's internal record of everything about a process: its PID, memory space, security token, and — critically — its protection level.

The _EPROCESS structure contains a field called Protection (of type _PS_PROTECTION) that defines the process's Protected Process Light status. This field sits at a specific offset from the base of the structure (the exact offset varies by Windows build; on recent Windows 11 builds it's around 0x87A).

// _PS_PROTECTION structure (simplified)
typedef struct _PS_PROTECTION {
    union {
        UCHAR Level;
        struct {
            UCHAR Type  : 3;    // _PS_PROTECTED_TYPE (0=None, 1=Light, 2=Full)
            UCHAR Audit : 1;    // Audit flag
            UCHAR Signer: 4;    // _PS_PROTECTED_SIGNER (who signed/authorized it)
        };
    };
} PS_PROTECTION;

The Type field determines the protection category (None, PPL, or Full Protected). The Signer field determines the trust level. Together, they produce a combined protection level that determines what other processes can interact with this one.

The process's access token — the structure that determines what privileges the process holds — is also stored at an offset within _EPROCESS (around 0x4B8 on recent builds). This token contains the SEP_TOKEN_PRIVILEGES structure at its own internal offset (typically 0x40), which lists every privilege the process holds.

The reference for these undocumented offsets is the Vergilius Project, which documents internal Windows structures across every build.

Why does all this matter? Because a driver with arbitrary kernel memory read/write can locate any process's _EPROCESS structure, read the protection field, zero it out, and instantly strip PPL protection. It can also replace the access token with the token from a SYSTEM process, escalating any unprivileged process to full system privileges.

// Conceptual: Token stealing via EPROCESS manipulation
// 1. Walk ActiveProcessLinks to find target EPROCESS
// 2. Read Token field from System (PID 4) EPROCESS
// 3. Overwrite Token field in attacker's EPROCESS

// EPROCESS offsets (Windows 11 24H2 example):
#define EPROCESS_UNIQUEPROCESSID_OFFSET  0x440
#define EPROCESS_FLINK_OFFSET            0x448
#define EPROCESS_TOKEN_OFFSET            0x4B8

// Walk the process list from PsInitialSystemProcess
// Copy the SYSTEM token to the attacker's process
// Result: unprivileged process now runs as SYSTEM

Protected Process Light: The Lock That Doesn't Hold

Protected Process Light was introduced in Windows 8.1 to prevent user-mode code from accessing critical system processes. When a process is flagged as PPL, the kernel restricts which operations other processes can perform on it, even from an elevated or SYSTEM context. You cannot open a PPL process with PROCESS_VM_READ or PROCESS_TERMINATE access, regardless of your privilege level.

EDR agents register their core processes as PPL (typically at the PsProtectedSignerAntimalware-Light level, value 0x31). This is designed to prevent malware from simply calling TerminateProcess() on the EDR's agent.

The protection hierarchy has multiple levels. A process can only interact with processes at the same or lower protection level:

Level Signer Value Examples
Full Protected WinSystem 0x72 Secure System process
Full Protected WinTcb 0x62 System, csrss.exe, smss.exe
PPL WinTcb-Light 0x61 services.exe, wininit.exe
PPL Antimalware-Light 0x31 MsMpEng.exe, EDR agents
PPL Lsa-Light 0x41 lsass.exe (when RunAsPPL enabled)
None N/A 0x00 Normal user processes

PPL enforcement happens entirely in user mode — the kernel enforces it when processing handle requests through ObOpenObjectByPointer and similar functions. But kernel-mode code bypasses this entirely. A loaded driver does not go through the handle-based access control path. It can directly access any kernel data structure, including the _EPROCESS blocks of PPL processes.

This is the fundamental reason BYOVD defeats PPL. PPL was designed to stop user-mode tampering. It was never designed to resist kernel-mode code. Once an attacker loads a vulnerable driver, they can:

  1. Locate the EDR's _EPROCESS structure in kernel memory
  2. Overwrite the Protection field from 0x31 to 0x00
  3. The EDR process is now unprotected and can be terminated from user mode
  4. Alternatively, call ZwTerminateProcess directly from kernel mode, bypassing all user-mode checks
Note

Tools like EDRSandblast, PPLKiller, and Backstab all exploit this pattern. EDRSandblast targets kernel callbacks as well. PPLKiller directly modifies the Protection field. Backstab abuses the Microsoft-signed Process Explorer driver (PROCEXP152.sys) to obtain kernel handles to PPL processes — using a Microsoft-signed tool to bypass Microsoft's own protection.

Kernel Callbacks: How EDRs See and How Attackers Blind Them

PPL protection is only part of the story. EDR agents also rely on kernel callbacks — registration mechanisms that notify the EDR driver when specific system events occur. These are the EDR's eyes and ears at Ring 0.

Notify Routine Callbacks

EDR drivers register themselves with the kernel to receive notifications about process creation, thread creation, and image (DLL/EXE) loading. The kernel maintains internal arrays for each category:

// Kernel callback registration APIs
PsSetCreateProcessNotifyRoutine()     // Process creation/exit
PsSetCreateThreadNotifyRoutine()      // Thread creation/exit
PsSetLoadImageNotifyRoutine()         // Image (DLL/EXE) loading

These arrays are stored at fixed locations relative to kernel symbols. A driver with arbitrary kernel memory access can enumerate these arrays, identify which callbacks belong to an EDR driver (by checking if the callback function address falls within the EDR driver's memory range), and overwrite or null out the callback entries.

Object Callbacks (ObRegisterCallbacks)

EDR drivers use ObRegisterCallbacks() to intercept handle operations on Process and Thread object types. This lets the EDR inspect every attempt to open a handle to a process and strip dangerous access rights (like PROCESS_VM_WRITE or PROCESS_TERMINATE).

These callbacks are stored in a CallbackList within the _OBJECT_TYPE structures pointed to by PsProcessType and PsThreadType. Each entry in the list is an OB_CALLBACK_ENTRY structure that includes an Enabled flag. EDRSandblast disables EDR object callbacks by simply toggling this flag to false.

ETW Threat Intelligence Provider

The ETW-Ti (Event Tracing for Windows — Threat Intelligence) provider gives EDR products real-time telemetry on sensitive operations: memory allocations in remote processes, APC injection, direct syscalls, and more. EDR killers can disable ETW-Ti by patching the EtwThreatIntProvRegHandle structure in kernel memory, effectively blinding the EDR to suspicious runtime behavior.

The pattern across all three categories is identical: the EDR relies on kernel data structures that are accessible to any code running at Ring 0. A BYOVD driver provides Ring 0 access. From there, it's a matter of finding the right offsets and writing the right values.

Three Vulnerability Classes That Power BYOVD

Cisco Talos's research identified three primary vulnerability classes in drivers exploited for BYOVD campaigns:

1. Arbitrary MSR Write

Model-Specific Registers (MSRs) control low-level CPU configuration. Some vulnerable drivers expose IOCTL handlers that let user-mode code write arbitrary values to MSRs. By overwriting the LSTAR MSR (which holds the syscall handler address), an attacker can redirect all syscalls through their own code, effectively hijacking the entire system call path. On HVCI-enabled systems, the hypervisor prevents this by enforcing W^X (Write XOR Execute) on kernel memory and validating MSR writes.

2. Arbitrary Kernel Memory Read/Write

The most common class. Drivers intended for hardware monitoring, overclocking, or diagnostics (like MSI Afterburner's RTCore64.sys) expose IOCTLs that allow reading from and writing to arbitrary physical or virtual memory addresses. This provides a universal primitive: the attacker can read any kernel structure, modify any value, and chain operations to achieve any desired outcome — token theft, PPL stripping, callback removal, or direct code execution.

3. Insufficient Access Controls

Some drivers expose sensitive kernel operations (like ZwTerminateProcess) through their IOCTL interface without properly restricting which user-mode processes can invoke them. TG Soft's viragt64.sys driver, for example, exposes a process termination IOCTL that Kasseika ransomware used to kill EDR processes. The Zemana anti-keylogger driver (zamguard64.sys) has a similar vulnerability (CVE-2024-1853) exploited by the Terminator and Killer Ultra tools.

Critical

The LOLDrivers project (loldrivers.io) catalogs known vulnerable drivers with hashes, CVEs, and exploitation details. As of early 2026, it lists hundreds of vulnerable drivers. Microsoft's blocklist covers only a subset. New vulnerable drivers are discovered regularly — the Lenovo LnvMSRIO.sys driver (CVE-2025-8061) was disclosed as recently as September 2025.

Real-World: The EnCase EDR Killer (February 2026)

The Huntress incident from early February 2026 demonstrates the complete BYOVD attack chain against a live enterprise environment. The attacker gained initial access through compromised SonicWall SSL VPN credentials (no MFA enabled), then deployed a custom EDR killer.

Payload Obfuscation

The EDR killer binary contained the EnCase forensic driver (EnPortv.sys) encoded using a wordlist-based substitution cipher. Each byte of the driver was converted into an English word using a 256-word dictionary embedded in the binary. The word's index in the array equals the byte it represents. The encoded payload appears to be ordinary English text, evading static analysis tools that scan for known driver signatures.

// Wordlist substitution cipher (conceptual)
// Dictionary: ["about", "above", "across", ... "zone"]
//              0x00     0x01     0x02          0xFF
//
// Byte 0x4D ("M") maps to word at index 77: "block"
// Byte 0x5A ("Z") maps to word at index 90: "both"
//
// Driver bytes are encoded as space-separated English words
// Decoder reverses lookup: word → index → byte

Driver Loading

The decoded driver was written to C:\Windows\System32\drivers\OemHwUpd.sys (disguised as a firmware update utility) and registered as a kernel-mode service. Despite the expired and revoked certificate, Windows loaded the driver because DSE validated only the cryptographic chain, not the revocation status.

The Kill Loop

Once loaded, the driver exposed an IOCTL interface for arbitrary process termination. The EDR killer maintained an internal list of 59 security tool process names, hashed for comparison. It ran a continuous loop with a 1-second sleep interval, checking for the presence of these processes and terminating them immediately. If a security process restarted, it was killed again within seconds.

"The kill loop runs continuously with a 1-second sleep interval, ensuring any security process that restarts is immediately terminated again." — Huntress

The attack was disrupted before ransomware deployment, but the EDR killer had successfully neutralized endpoint security across the compromised system.

Microsoft's Defenses and Why They Keep Falling Short

The Vulnerable Driver Blocklist

Microsoft maintains a hash-based blocklist of known vulnerable drivers, enforced through Windows Defender Application Control (WDAC). Since Windows 11 22H2, this blocklist is enabled by default when HVCI or Memory Integrity is active. It blocks specific driver hashes from loading into the kernel.

The limitation is inherent to the approach: the blocklist is reactive. A driver must first be identified as vulnerable, reported to Microsoft, analyzed, and added to the list. The blocklist is updated once or twice per year with major Windows releases, though Microsoft now offers optional updates through Windows Update. In the gap between discovery and blocklisting, every system is exposed. And newly discovered vulnerable drivers — like the wsftprm.sys driver found by Northwave that loads successfully on fully patched Windows 11 with Secure Boot and HVCI enabled — are immediately usable for BYOVD attacks.

Hypervisor-Protected Code Integrity (HVCI)

HVCI is the strongest available mitigation. It uses the Windows hypervisor (Secure Kernel at Ring -1) to enforce code integrity for all kernel-mode code. HVCI prevents kernel memory pages from being simultaneously writable and executable (W^X enforcement), blocks unsigned code execution even at Ring 0, validates that all code loaded into the kernel is properly signed, and prevents MSR-based exploitation techniques.

HVCI is enabled by default on new Windows 11 devices. However, many organizations disable it for compatibility with legacy drivers, performance concerns, or because their hardware doesn't support virtualization-based security (VBS). Enterprise environments running Windows Server or older hardware frequently lack HVCI protection entirely.

Even with HVCI, a legitimately signed vulnerable driver will still load. HVCI prevents unsigned code injection and MSR manipulation, but it does not prevent a signed driver from exposing arbitrary memory read/write IOCTLs. The driver is signed, so it passes code integrity checks. The vulnerability is in the driver's logic, not its signature.

Attack Surface Reduction (ASR) Rules

Microsoft Defender's ASR includes a rule to "Block abuse of exploited vulnerable signed drivers" that prevents applications from writing known vulnerable drivers to disk. This is useful but doesn't cover drivers loaded through other mechanisms (like being dropped by a service or decoded from an obfuscated payload as in the EnCase incident).

Windows Defender Application Control (WDAC)

WDAC provides the most granular control. Organizations can define custom driver policies that extend the Microsoft blocklist, create allowlists of approved drivers, or block entire certificate chains. This is the enterprise-grade solution, but it requires significant policy management overhead and can break legitimate software if misconfigured.

CVE-2025-59033

In 2025, a vulnerability was disclosed in the blocklist enforcement itself: on systems without HVCI enabled, blocklist entries that use a FileAttribRef qualifier (matching by file name or version in addition to certificate hash) are not properly enforced. This means the blocklist is less effective on the exact systems that need it most — those without HVCI.

Key Takeaways

  1. Enable HVCI/Memory Integrity on every endpoint. This is the single most impactful defense. HVCI ensures the vulnerable driver blocklist is enforced, prevents MSR-based attacks, and blocks unsigned kernel code execution. If your organization has disabled HVCI for compatibility reasons, the risk calculation has changed. BYOVD is now a standard ransomware technique, not an advanced threat.
  2. Deploy WDAC driver policies beyond the default blocklist. The Microsoft blocklist is a starting point, not a solution. Create custom policies that restrict which drivers can load in your environment. Allowlisting is more robust than blocklisting for high-value systems.
  3. Monitor for driver installation activity. Alert on new kernel-mode service creation, especially services with names mimicking OEM or hardware components (the EnCase killer used "OemHwUpd"). Watch for sc create commands with type= kernel, unexpected driver files in System32\drivers, and service installations outside normal software deployment windows.
  4. Audit your driver inventory. Use tools like Sigcheck (Sysinternals) to enumerate all loaded kernel drivers and cross-reference against the LOLDrivers catalog. Remove or restrict any driver that appears on the vulnerable list. Pay particular attention to hardware monitoring, overclocking, and legacy diagnostic drivers.
  5. Don't rely on PPL alone. PPL was designed to resist user-mode tampering. It provides zero protection against kernel-mode attacks. If your EDR vendor's entire anti-tamper strategy is PPL registration, you have a single point of failure that any BYOVD tool can bypass.
  6. Credential hygiene stops the chain early. Every BYOVD attack requires administrative access to load a driver. The Huntress incident started with compromised VPN credentials without MFA. Token theft escalates privileges. Enforcing MFA on all remote access, restricting local admin rights, and monitoring for privilege escalation prevents the attacker from reaching the point where BYOVD becomes possible.

BYOVD exposes a structural tension in Windows security. Microsoft's backward compatibility guarantees — accepting drivers with expired certificates, maintaining legacy signing exceptions, updating the blocklist only periodically — exist because breaking hardware drivers causes real operational damage. But those same guarantees create a permanent exploitation surface that every ransomware group on the planet now understands how to use.

The defenders' toolkit is improving: HVCI, WDAC, the blocklist, ASR rules. But until Microsoft fundamentally changes how driver trust works — enforcing CRL checks at load time, shortening the blocklist update cycle, or moving to a mandatory allowlisting model — the gap between signed trust and actual safety will remain wide enough for an attacker to drive a vulnerable driver through.

Sources

← all articles