DEV Community

Mr.Cupcake
Mr.Cupcake

Posted on Edited on

I built a Windows driver vuln hunter in a day — and learned why heuristics lie

A few weeks ago I was fuzzing Windows kernel drivers and realized something
uncomfortable: the interesting bugs aren't the crashes you find by throwing
bytes at an IOCTL. They're the ones that were designed in — drivers that
expose arbitrary kernel memory read/write to anyone who can open a device. The
problem is spotting those by hand, across dozens of signed .sys files, is
slow.

So I gave myself a constraint: build a static driver vulnerability hunter in
one day, with no driver ever loaded (my analysis box is a cheap VPS that
Defender quietly quarantines every BYOVD binary it sees). Here's what came out.

What the tool does

DrvSniper takes a .sys (local path or URL) and, without executing
anything, does three things:

  1. Imports + strings. It parses the PE import table and scans every ascii string for dangerous APIs. The string scan matters because a lot of drivers resolve risky routines dynamically with MmGetSystemRoutineAddress — those never show up in the import table.
  2. IOCTL extraction. It walks the .text section with capstone and collects cmp reg, imm values that survive the IOCTL bit layout, then flags any METHOD_NEITHER code that has no ProbeForRead/ProbeForWrite anywhere in the binary.
  3. Scoring. Each dangerous primitive has a weight; a missing probe on a NEITHER IOCTL adds a bonus. The driver gets CRITICAL / HIGH / MEDIUM / LOW.

Crucially, the driver is fetched and analyzed in memory only, so Defender
never sees a dropped .sys on disk. That's what makes this safe to run on a
normal Windows host.

Demo 1: Blackbone → CRITICAL

Pointed at BlackBoneDrv10.sys, the tool immediately lit up:

[3] MmCopyVirtualMemory              arbitrary cross-process memory R/W
[3] MmMapLockedPagesSpecifyCache     maps arbitrary physical pages via MDL
[2] KeStackAttachProcess             attaches to an arbitrary process context
[2] PsLookupProcessByProcessId       resolves EPROCESS by PID
=> severity: CRITICAL (score 10)
Enter fullscreen mode Exit fullscreen mode

That maps exactly to what manual RE shows: the BBCopyMemory handler for
IOCTL 0x803 calls MmCopyVirtualMemory(..., KernelMode, ...) on a
user-supplied PID and address with no validation — arbitrary R/W over any
process, including System (PID 4) and lsass. Combined with a device object
created without FILE_DEVICE_SECURE_OPEN, any user process can open it.
Vulnerable by design, and the tool found it in under a second.

Demo 2: WinDivert → LOW (the lesson)

Then I ran it on WinDivert64.sys, a legit networking driver I'd previously
reversed and found clean. The first version of my scorer screamed HIGH —
because WinDivert imports MmMapLockedPagesSpecifyCache.

That's a false positive, and it's the interesting part. MmMapLockedPagesSpecifyCache
is used safely by thousands of clean drivers to map their own buffers. My
first instinct — "list every scary API and add up the points" — was wrong.
The fix was weighting: MmCopyVirtualMemory is almost always an
intentional, user-exposed primitive (weight 3), while
MmMapLockedPagesSpecifyCache is ambiguous and routinely safe (weight 1).

After the fix:

BlackBoneDrv10.sys  CRITICAL (10)
WinDivert64.sys     LOW      (2)
Enter fullscreen mode Exit fullscreen mode

A hunter that flags the clean driver is worse than useless — it trains you to
ignore it. Weighting signals instead of counting them is what made the tool
trustworthy.

What it is, and what it isn't

This is triage, not proof. A CRITICAL score means "look here first", not
"this is exploitable". It doesn't model data flow, so it can't tell you
whether a user-supplied address actually reaches a primitive — that's still
manual RE. And cmp-based IOCTL recovery misses dispatch via hash tables or
lookup switches.

But as a first-pass filter over a corpus of signed drivers, it does exactly
what I wanted: it points me at the drivers worth my time and stays quiet on the
ones that aren't.

Try it

The code is small and dependency-light (pefile, capstone). Point it at any
.sys and see what it says — then go prove or disprove the score the old
fashioned way.

Next post: turning the CRITICAL hits into a real, documented finding — the
gap between "this driver is dangerous" and "here is the exact IOCTL and
struct that proves it."

Top comments (0)