← Back to Blog
March 2026 Vulnerability Research BYOVD Kernel

Abusing a Signed Kernel Driver to Kill PPL-Protected Processes

We reverse-engineered a signed anti-cheat kernel driver and found an IOCTL vulnerability that enables arbitrary process termination — including PPL-protected processes like Windows Defender and EDR agents.

Introduction

During vulnerability research into kernel-mode drivers, we identified a signed anti-cheat driver shipped with a commercial game that exposes dangerous functionality to user-mode processes without adequate privilege checks. Kernel drivers operate at the highest privilege level on Windows, and anti-cheat systems leverage this power to protect games from tampering. However, when the driver's IOCTL interface is poorly secured, attackers can weaponize that same kernel-level access against the operating system itself.

This research demonstrates a Bring Your Own Vulnerable Driver (BYOVD) attack — a technique where attackers load a legitimately signed but vulnerable driver to gain kernel-level capabilities, bypassing security controls that are enforced only at the user-mode boundary.

Background

The driver exposes a device interface that allows a user-mode component to control its behavior through IOCTL (I/O Control) requests. It operates as part of an anti-cheat system where the privileged kernel component assists a companion user-mode client in enforcing process control. One supported command allows the user-mode component to specify a process identifier (PID), which the driver then uses to perform a process termination operation from kernel mode.

Anti-cheat drivers require kernel-level process termination capabilities to immediately stop unauthorized software from interacting with or modifying game memory. However, if this capability is exposed through an IOCTL handler without proper access validation, it becomes exploitable outside the intended anti-cheat context.

What Is PPL?

Protected Process Light (PPL) is a Windows security feature introduced in Windows 8.1. Processes marked as PPL — such as antivirus engines, LSASS, and certain system services — cannot be opened with full access rights from user-mode code, even by administrators. Any attempt to call OpenProcess or TerminateProcess against a PPL-protected process from user mode returns ACCESS_DENIED.

The critical detail: PPL is enforced at the user-mode boundary. Kernel-mode code operating with OBJ_KERNEL_HANDLE bypasses this check entirely.

IOCTL Enumeration

All IOCTLs use FILE_ANY_ACCESS (access bits 14–15 = 0b00), meaning the device handle requires no special privilege to obtain. The driver exposes 10 IOCTL codes:

IOCTL In Out Action
0x22200000Re-register Ps* kernel callbacks
0x22200400Unregister all kernel callbacks
0x22200801036Dequeue process entry (info leak)
0x22201810360Enqueue fake entry, add name to protected list
0x22201C10360Kill process by PID via ZwTerminateProcess
0x22202010360Enqueue fake entry, flag=0
0x22202480Set timeout + re-register callbacks
0x22204004Returns version DWORD (3)
0x22204480Register user event object
0x22204800Dereference registered event

The Vulnerability: Arbitrary Process Termination

IOCTL 0x22201C allows termination of any process on the system, including PPL-protected processes.

Call Chain

DeviceIoControl
  → IRP_MJ_DEVICE_CONTROL Handler (0x140001540)   [no privilege check]
       → IOCTL_0x22201C_TerminateFromList (0x14000264C)
            └ reads target PID from first 4 bytes of 1036-byte input buffer
            └ CRC32(name) → RemovePIDFromProtectedList
            └ KillProcessByPID (0x140002848)
                 └ ZwOpenProcess(pid, PROCESS_ALL_ACCESS, OBJ_KERNEL_HANDLE)
                 └ ZwTerminateProcess(handle, 0)

The IOCTL dispatch routine accepts requests through IRP_MJ_DEVICE_CONTROL without performing any privilege validation. When the handler receives IOCTL 0x22201C, it forwards the supplied 1036-byte input buffer to an internal termination routine. The target PID is extracted from the first 4 bytes of the user-controlled buffer. The routine also performs a CRC32-based lookup and removal against the driver's internal protected process list before invoking KillProcessByPID.

KillProcessByPID opens the target process with ZwOpenProcess using PROCESS_ALL_ACCESS and OBJ_KERNEL_HANDLE, then immediately calls ZwTerminateProcess. Because these are kernel-mode calls with OBJ_KERNEL_HANDLE, PPL protection is bypassed entirely.

The result: antivirus engines, EDR agents, system services, and any PPL-protected process can be terminated by any user with access to the device handle.

Decompiled KillProcessByPID

__int64 __fastcall KillProcessByPID(unsigned int pid)
{
    HANDLE ProcessHandle = 0;
    OBJECT_ATTRIBUTES oa;
    CLIENT_ID cid;

    oa.Length = 48;
    oa.Attributes = 514;     // OBJ_KERNEL_HANDLE | OBJ_INHERIT
    oa.RootDirectory = 0;
    oa.ObjectName = 0;
    cid.UniqueProcess = (HANDLE)pid;
    cid.UniqueThread = 0;

    NTSTATUS status = ZwOpenProcess(&ProcessHandle, 0x1FFFFF,  // PROCESS_ALL_ACCESS
                                    &oa, &cid);
    if (NT_SUCCESS(status) && ProcessHandle) {
        status = ZwTerminateProcess(ProcessHandle, 0);
        ZwClose(ProcessHandle);
    }
    return status;
}

Input Buffer Layout

The IOCTL expects exactly 1036 bytes with the PID in the first 4 bytes:

#pragma pack(push, 1)
typedef struct {
    DWORD pid;        // offset 0  - target PID
    WORD  _pad;       // offset 4
    CHAR  name[1030]; // offset 6  - CRC32'd for protected list removal
} KILL_INPUT;
#pragma pack(pop)

Proof of Concept: Disabling Windows Defender

To demonstrate real-world impact, we built a proof of concept targeting MsMpEng.exe (the Windows Defender antimalware service process). Because the Windows Service Control Manager (SCM) automatically restarts the WinDefend service on failure (default delay ~5 seconds), each restart spawns a new MsMpEng.exe with a different PID. The PoC addresses this by entering a loop that refreshes the target PID and re-terminates the process every 700ms, effectively keeping Defender disabled indefinitely.

This same technique applies to any AV/EDR agent running as a PPL-protected process.

Impact

  • EDR/AV bypass: Terminate any endpoint security product, including PPL-protected processes that Windows is designed to shield from tampering
  • Defense evasion: Clear the way for malware deployment by killing security monitoring before execution
  • BYOVD weaponization: The driver is legitimately signed, meaning it loads without driver signature enforcement issues
  • Persistence disruption: Continuously kill security processes faster than the SCM can restart them
  • Low barrier: No special privileges required beyond the ability to load the driver and obtain a device handle

Defensive Recommendations

  • Implement IOCTL access validation — verify the calling process identity and privilege level before processing sensitive commands
  • Use driver block lists (Microsoft's Vulnerable Driver Blocklist) to prevent known-vulnerable signed drivers from loading
  • Enable Hypervisor-Protected Code Integrity (HVCI) to restrict which drivers can load
  • Monitor for suspicious driver loading events (Sysmon Event ID 6) in your SIEM
  • Implement kernel callback protections that detect when security-critical callbacks are being unregistered

References

Concerned about BYOVD or endpoint security bypass in your environment?

Redmount Cyber performs adversary simulation and red team assessments that test your defenses against real-world attack techniques.

Request an Assessment