Kevlar driver emulation harness
Patterned after Kevlar (Kernel Export Virtualization Layer And Runtime): map x64 .sys into synthetic kernel space and run DriverEntry under Unicorn without live kernel load.
Use when
- Static RE of AC/game drivers stalls on environment probes
- Need execution traces of CPUID/MSR/IOCTL setup paths
- Want safe detonation of suspicious drivers
Architecture checklist
- PE map + relocs + imports → host stubs or real exports
- Synthetic
DRIVER_OBJECT, KPCR, EPROCESS/ETHREAD, PsLoadedModuleList
- Hooks: CPUID, RDTSC, MSR, syscall, interrupts
- Pool/user memory models; IRP dispatch stubs
- Per-driver vfs/registry isolation
- Instruction coverage / exception logs
Method
- Load target
.sys (e.g. EAC class drivers) in harness
- Fill missing stubs iteratively from crash/unmapped logs
- Capture probe sequences (timing, module lists, registry)
- Feed insights back to IDA/AiDA annotations
Local path
Documents/Kevlar / https://github.com/NetVar1337/Kevlar
Stub inventory (what to synthesize first)
| Kernel dependency |
Stub behavior |
Notes |
ExAllocatePool2/ExFreePoolWithTag |
malloc into emulated pool space; track tags |
log tag histogram = allocation fingerprint |
MmGetSystemRoutineAddress |
hash-table of exported names → stub or real |
first DriverEntry call usually |
IoCreateDevice |
fake DEVICE_OBJECT into synthetic namespace |
record device name + extents |
PsSetCreateProcessNotifyRoutine etc. |
record registration, invoke manually later |
callback list = behavior map |
RtlInitUnicodeString/RtlCompareMemory |
implement directly |
trivial, do first |
KeQueryInterruptTime/KeQueryTickCount |
controllable fake clock |
determinism for replay |
| CPUID/RDTSC/MSR |
Unicorn hooks returning scripted values |
environment-probe capture point |
IOCTL reconstruction workflow
- Emulate DriverEntry → capture device name + dispatch table fill (MajorFunction[IRP_MJ_DEVICE_CONTROL])
- Synthesize IRP: fixed fake IRP + IO_STACK_LOCATION with user-controlled IoCtlCode + InBuf/InBufLen/OutBuf/OutBufLen
- Sweep CTL codes: for each, run with canary buffers (0x41 fill, lengths 8..0x400 geometric) — crash (unmapped) = length/decode bug surfaced; log METHOD (buffered/direct/NEITHER) from code fields
- Re-run under coverage (Unicorn block hook) to extract handler CFG per IOCTL → feed IDA (
ida-reverse) to name functions
- Double-fetch hunting: place InBuf in emulated user memory, mutate between reads via hook — METHOD_NEITHER handlers frequently re-read
Determinism & state snapshot
- Seed all RNG hooks; snapshot full memory after DriverEntry; restore per IOCTL sweep run → reproducible traces (diffable with
binary-diff).
- Anti-emulation probes to expect:
KdDebuggerEnabled, SharedUserData->KdDebuggerEnabled, NMI/INT3 self-checks, DbgBreakPoint with SEH — stub all to clean-kernel values.
Limits (when to go live/hypervisor instead)
- No real DPC/timer/work-item execution — deferred work invisible; if driver arms a timer to complete setup, emulation sees half the story (
hypervisor-memory-introspection for live-but-isolated).
- SMP: single-vCPU Unicorn; drivers with per-core structures (GS/KPCR indexing) need KPCR per-core synth or patching.
- Interrupts/IRQL semantics fake — real race bugs won't reproduce; IOCTL logic bugs will.
Pair with
eac-kernel-driver-re, hypervisor-dev, ida-reverse, byovd.
1---2name: kevlar-driver-emulation3description: Kevlar-style Windows kernel driver emulation: Unicorn-based DriverEntry harness, synthetic KERNEL env, import stubs, tracing for .sys RE.4license: GPL-3.0-or-later5---67# Kevlar driver emulation harness89Patterned after **Kevlar** (Kernel Export Virtualization Layer And Runtime): map x64 `.sys` into synthetic kernel space and run `DriverEntry` under Unicorn without live kernel load.1011## Use when12- Static RE of AC/game drivers stalls on environment probes13- Need execution traces of CPUID/MSR/IOCTL setup paths14- Want safe detonation of suspicious drivers1516## Architecture checklist17- PE map + relocs + imports → host stubs or real exports18- Synthetic `DRIVER_OBJECT`, KPCR, EPROCESS/ETHREAD, PsLoadedModuleList19- Hooks: CPUID, RDTSC, MSR, syscall, interrupts20- Pool/user memory models; IRP dispatch stubs21- Per-driver vfs/registry isolation22- Instruction coverage / exception logs2324## Method251. Load target `.sys` (e.g. EAC class drivers) in harness262. Fill missing stubs iteratively from crash/unmapped logs273. Capture probe sequences (timing, module lists, registry)284. Feed insights back to IDA/AiDA annotations2930## Local path31`Documents/Kevlar` / https://github.com/NetVar1337/Kevlar3233## Stub inventory (what to synthesize first)34| Kernel dependency | Stub behavior | Notes |35|---|---|---|36| `ExAllocatePool2/ExFreePoolWithTag` | malloc into emulated pool space; track tags | log tag histogram = allocation fingerprint |37| `MmGetSystemRoutineAddress` | hash-table of exported names → stub or real | first DriverEntry call usually |38| `IoCreateDevice` | fake DEVICE_OBJECT into synthetic namespace | record device name + extents |39| `PsSetCreateProcessNotifyRoutine` etc. | record registration, invoke manually later | callback list = behavior map |40| `RtlInitUnicodeString/RtlCompareMemory` | implement directly | trivial, do first |41| `KeQueryInterruptTime/KeQueryTickCount` | controllable fake clock | determinism for replay |42| CPUID/RDTSC/MSR | Unicorn hooks returning scripted values | environment-probe capture point |4344## IOCTL reconstruction workflow451. Emulate DriverEntry → capture device name + dispatch table fill (MajorFunction[IRP_MJ_DEVICE_CONTROL])462. Synthesize IRP: fixed fake IRP + IO_STACK_LOCATION with user-controlled IoCtlCode + InBuf/InBufLen/OutBuf/OutBufLen473. Sweep CTL codes: for each, run with canary buffers (0x41 fill, lengths 8..0x400 geometric) — crash (unmapped) = length/decode bug surfaced; log METHOD (buffered/direct/NEITHER) from code fields484. Re-run under coverage (Unicorn block hook) to extract handler CFG per IOCTL → feed IDA (`ida-reverse`) to name functions495. Double-fetch hunting: place InBuf in emulated user memory, mutate between reads via hook — METHOD_NEITHER handlers frequently re-read5051## Determinism & state snapshot52- Seed all RNG hooks; snapshot full memory after DriverEntry; restore per IOCTL sweep run → reproducible traces (diffable with `binary-diff`).53- Anti-emulation probes to expect: `KdDebuggerEnabled`, `SharedUserData->KdDebuggerEnabled`, NMI/INT3 self-checks, `DbgBreakPoint` with SEH — stub all to clean-kernel values.5455## Limits (when to go live/hypervisor instead)56- No real DPC/timer/work-item execution — deferred work invisible; if driver arms a timer to complete setup, emulation sees half the story (`hypervisor-memory-introspection` for live-but-isolated).57- SMP: single-vCPU Unicorn; drivers with per-core structures (GS/KPCR indexing) need KPCR per-core synth or patching.58- Interrupts/IRQL semantics fake — real race bugs won't reproduce; IOCTL logic bugs will.5960## Pair with61`eac-kernel-driver-re`, `hypervisor-dev`, `ida-reverse`, `byovd`.