Fuzzing Windows drivers
TL;DR: Hypervisor-assisted snapshot fuzzers (kAFL, WTF, Jackalope) drive
DeviceIoControland IRP entry points at native speed while restoring kernel state per iteration — the practical way to find IOCTL bugs in modern third-party drivers.
What it is
Driver fuzzing targets the kernel-mode entry points exposed to user-mode callers — primarily IRP_MJ_DEVICE_CONTROL, IRP_MJ_READ, IRP_MJ_WRITE, and FastIO callbacks (see kernel-objects-and-irps). Naïve in-VM fuzzing crashes the kernel each finding, so the modern approach is to snapshot a known-good VM, replay inputs from that snapshot, and rewind on crash or timeout. Coverage feedback is gathered via Intel PT, KVM, or instrumented hypervisor traps.
Preconditions / where it applies
- Target driver loaded on a controlled Windows VM (test-signing or attestation-bypass build for unsigned modules)
- Known set of accepted IOCTL codes — extract via static analysis of
IoCreateDevice/IoCreateSymbolicLink+ the dispatch table, or via runtime hooking with WinDbg - Hardware support for the chosen engine: Intel PT for kAFL/WTF; bochscpu for WTF’s emulated mode
Technique
Typical pipeline:
- Reverse the dispatch table.
MajorFunction[IRP_MJ_DEVICE_CONTROL]→ identify the IOCTL switch. IDA scripts (drvhunter) or Ghidra automate enumeration ofMETHOD_*codes and expected buffer sizes. - Build a harness. A user-mode stub that opens
\\.\DeviceName, callsDeviceIoControl(handle, ioctl, in, in_len, out, out_len, &ret), and surfaces the input buffer to the fuzzer. - Capture a snapshot. WTF uses
bdump.jsinside WinDbg to dump CPU + physical memory; kAFL relies on KVM-Nyx. The snapshot taken at the harness’s “just before DeviceIoControl” point. - Fuzz. Mutate input buffer (and IOCTL code, if dispatch supports many). Each iteration restores the snapshot, applies the input, and steps the kernel until the syscall returns or a bug check fires.
- Triage. Bug check 0xBE, 0x1E, 0x3B, etc. → tag, dedupe by faulting RIP, minimise input, replay under live WinDbg with kernel-debugging-with-windbg.
Specific tooling:
1
2
3
4
kAFL — KVM-Nyx + AFL frontend; Intel PT coverage; great for x86_64 Windows
WTF (Snapshot Fuzzer, Microsoft) — supports bochscpu / kvm / whv backends; replay-friendly
Jackalope — TinyInst-based black-box coverage; useful when source-level instrumentation is impossible
HEVD + IOCTLpus — practice ground for bug-class triggers
Wins: Driverquery + symbol-aware grammars (e.g. specifying buffer layouts) dramatically improve hit rate vs flat byte mutation. Hooking ETW kernel-mode allocator events further accelerates UAF/double-fetch triage.
Detection and defence
- Driver hardening:
IoValidateDeviceIoControlAccess, ProbeForRead/Write on all user buffers, capture once into local stack copy to avoid double-fetch - Use METHOD_BUFFERED where possible — least foot-gun. Document METHOD_NEITHER paths and pen-test them aggressively
- HVCI (hvci-vbs) and kernel CFG (cfg-cet-kernel) cut exploitability of discovered bugs
- WHQL + Microsoft Driver Verifier (
verifier /standard /driver foo.sys) catches many fuzzable bug classes pre-shipping
References
- What the Fuzz (Microsoft) — snapshot fuzzer
- kAFL paper — original design
- HEVD project — training driver with seeded bugs
Related: kernel-objects-and-irps, kernel-debugging-with-windbg, double-fetch, symbolic-execution-for-windows-bugs