
KslDump — Why bring your own knife when Defender already left one in the kitchen?
I reported the issue to Microsoft on 7 March 2026. However, almost 20 days earlier, the game-hacking community had already reversed and publicly discussed it. From my side, I do not follow their projects and I was not aware of any of this. It is also clear that these are two completely separate and unrelated projects.
Why bring your own knife when Defender already left one in the kitchen?
KslDump extracts credentials from PPL-protected LSASS using only Microsoft-signed components. No exploit is deployed. No driver is loaded. The entire attack chain ships pre-installed with Windows Defender. Microsoft patched the running version (wd\KslD.sys) by nulling out MmCopyMemory, but left the old vulnerable version (drivers\KslD.sys) sitting on disk. The attacker doesn't bring anything — they just point the service back to what Microsoft forgot to clean up.
https://github.com/user-attachments/assets/78dfce25-56b3-4eb8-9de2-7c183601e597
KslD.sys is a kernel driver shipped with Microsoft Defender. It is Microsoft-signed, loaded as a trusted kernel module, and exposes a device object \\.\KslD accessible from usermode.
The driver accepts IOCTL 0x222044 with multiple sub-commands that provide unrestricted kernel and physical memory access to any process that can open the device handle.
| SubCmd | Capability | Impact |
|---|---|---|
| 2 | Returns CR3, IDTR, and other CPU control registers to usermode | Instant KASLR defeat |
| 12 | Calls MmCopyMemory() with attacker-controlled address and size | Arbitrary kernel/physical memory read |
The only gate to the device handle is a process name string stored in a registry key (AllowedProcessName) under the driver's service key. This value is:
The difference is one line in CCommand::Initialize:
// 82 KB version (patched) — deliberately clears the pointer:
v3 = MmGetSystemRoutineAddress(L"MmCopyMemory");
if (v3 >= 0) {
*(a1 + 24) = 0; // ← NULLs it — SubCmd 12 is dead
}
// 333 KB version (vulnerable) — stores the pointer:
ptr = MmGetSystemRoutineAddress(L"MmCopyMemory");
if (ptr) {
*(this + 0x18) = ptr; // ← Keeps it — SubCmd 12 works
}
Defender platform updates appear to drop the patched 82 KB version into drivers\wd\ and point ImagePath at it, while the older 333 KB version remains in drivers\. On tested systems, the old binary was never removed. The exploit simply switches ImagePath back to the vulnerable version and restarts the service. Both binaries are Microsoft-signed and trusted by the OS.
Microsoft’s public documentation shows that KB4052623 delivers Defender platform updates, including a historical move of Defender drivers to System32\drivers\wd, while Windows servicing keeps WinSxS-backed component-store files via NTFS hard links and only removes superseded component versions during cleanup. On the tested system, this explains why the newer 82 KB KslD.sys could arrive through the Defender platform-update path while the older 333 KB System32\drivers\KslD.sys remained present as the current CBS-backed component-store copy until superseded by a newer CBS version.
Microsoft maintains a Vulnerable Driver Blocklist (DriverSiPolicy.p7b) specifically to prevent BYOVD attacks. This blocklist is enforced via HVCI and blocks known-vulnerable signed drivers from loading.
From Microsoft's own documentation:
"The vulnerable driver blocklist is designed to help harden systems against non-Microsoft-developed drivers across the Windows ecosystem"
Microsoft's own drivers are excluded from the blocklist by design.
The root cause is simple: MmCopyMemory does not respect PPL.
PPL (Protected Process Light) was designed to prevent credential theft by blocking OpenProcess and ReadProcessMemory calls against LSASS. But PPL only protects the usermode API path. It has no authority over kernel-mode physical memory reads.
KslD.sys gives usermode code a direct path to MmCopyMemory() — Microsoft's own kernel API for copying memory by physical or virtual address. The driver performs:
The result: a Microsoft-signed driver provides a complete PPL bypass out of the box.
The core of the vulnerability is SubCmd 12 — an unrestricted MmCopyMemory() wrapper:
IOCTL: 0x222044
Input: struct {
DWORD SubCmd; // 12
DWORD Reserved; // 0
QWORD Address; // Target VA or PA
QWORD Size; // Bytes to read
DWORD Flags; // 1 = Physical, 2 = Virtual
DWORD Padding;
}
Output: Raw memory contents (up to Size bytes)
Physical read (Flags = 1) is the critical primitive. Physical memory access is not subject to process protection levels, EPROCESS flags, or any usermode API restrictions, this is what bypasses PPL.
Virtual read (Flags = 2) reads kernel virtual addresses directly, useful for walking kernel structures (EPROCESS, ntoskrnl exports) without manual page table translation.