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:
-
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. -
IOCTL extraction. It walks the
.textsection with capstone and collectscmp reg, immvalues that survive the IOCTL bit layout, then flags anyMETHOD_NEITHERcode that has noProbeForRead/ProbeForWriteanywhere in the binary. -
Scoring. Each dangerous primitive has a weight; a missing probe on a
NEITHERIOCTL 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)
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)
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)