> For the complete documentation index, see [llms.txt](https://docs.redteamleaders.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.redteamleaders.com/offensive-security/windows-kernel-and-driver-exploitation/byovd-fundamentals.md).

# BYOVD Fundamentals

## Part 1 — BYOVD Fundamentals & the Windows Kernel Attack Surface

> **In this part:** the integrity controls BYOVD sidesteps, exactly *why* a signed-but-vulnerable driver defeats them, the mechanics of loading a driver from user mode, the device/DACL model, and the end-to-end operational lifecycle. Parts 2 and 3 get hands-on with reversing and exploitation.

***

### 1.1 Ring 0 and why it's the crown jewel

Windows runs code in two privilege rings that matter to us:

* **Ring 3 (user mode):** every normal process. Isolated address spaces, mediated access to hardware, subject to ACLs and integrity levels.
* **Ring 0 (kernel mode):** `ntoskrnl.exe`, the HAL, and every loaded driver. One flat, shared address space. Code here can read/write any physical page, any process's memory, disable security callbacks, and rewrite the structures that *define* who is SYSTEM.

There is essentially **no security boundary inside ring 0**. A driver is as privileged as the kernel itself. That is why Microsoft invests so heavily in controlling *what* gets to run there — and why an attacker who can execute even a tiny amount of logic in the kernel has effectively won the box.

The privilege ladder an attacker climbs looks like this:

```
Low-priv user ──► Admin/SeLoadDriver ──► Load signed driver ──► IOCTL abuse ──► Ring 0 R/W ──► SYSTEM / rootkit
                  (UAC bypass, etc.)      (BYOVD starts here)
```

**Important framing:** BYOVD is *not* usually a remote exploit. It's a **local privilege escalation and defense-evasion** primitive. The attacker already needs local admin (or at least `SeLoadDriverPrivilege`) to install the driver. What BYOVD buys is the jump from *admin* (still constrained by EDR, still ring 3) to *kernel* (game over). That gap — admin-to-kernel — is exactly where modern defenses (EDR, tamper protection, credential guard) live, and BYOVD tunnels underneath all of them.

### 1.2 The integrity controls in your way

<figure><img src="/files/b9EVhx6QYimKdrrnw1Po" alt=""><figcaption></figcaption></figure>

#### Driver Signature Enforcement (DSE)

On 64-bit Windows, the kernel's code-integrity component (`ci.dll`) verifies an Authenticode signature before mapping a driver image. No valid chain to a trusted root → `STATUS_INVALID_IMAGE_HASH`, load refused. DSE is the wall.

A single global variable inside `ci.dll` — historically referred to as `g_CiOptions` (and the older `nt!g_CiEnabled`) — governs the policy. If you have a kernel write primitive, flipping that value to `0` disables enforcement and lets you load *any* unsigned driver. (More on this attack in Part 3; note HVCI protects this variable, see below.)

#### WHQL, cross-signing, and the 2015 policy

Since Windows 10 1607, newly-signed kernel drivers must carry a **Microsoft attestation / WHQL signature** obtained through the Hardware Dev Center. This is why attackers prize **older, pre-2015 signed drivers** (grandfathered in) and **still-valid vendor drivers** (RTCore64, dbutil, gdrv, WinRing0…) — the signature requirement is already met for them.

#### PatchGuard (Kernel Patch Protection, KPP)

PatchGuard periodically checks that critical kernel structures (SSDT, IDT, key `ntoskrnl` code, MSRs like `LSTAR`, GDT) haven't been tampered with. If it detects patching, it bugchecks the box (`CRITICAL_STRUCTURE_CORRUPTION`, `0x109`). **Why this matters for BYOVD:** the classic "hook the syscall table" rootkit is dead on x64. Modern kernel attackers prefer **data-only attacks** — edit an EPROCESS token, toggle a callback array entry — which PatchGuard does *not* watch. BYOVD pairs naturally with data-only techniques.

#### HVCI / Memory Integrity (VBS)

Hypervisor-Enforced Code Integrity uses the CPU virtualization extensions to run code-integrity checks in a more-privileged context (VTL1) than even the kernel (VTL0). It enforces **W^X** on kernel pages: a page can be writable *or* executable, never both, and executable kernel pages must pass code integrity. Consequences for the attacker:

* **You cannot execute injected kernel shellcode** — no allocating RWX and jumping to it. This kills a whole class of "map my code and call it" exploits.
* **`g_CiOptions` and other CI structures are protected** — the naive DSE-flip is neutralized on HVCI systems.
* **You are pushed toward data-only exploitation** — token theft, callback removal, and abusing *existing* signed code still work, because they don't introduce new executable kernel code.

HVCI is *the* modern speed bump. It's on by default on many OEM Windows 11 installs and on Secured-core PCs, but is still absent on a large fraction of the fleet — which is why BYOVD remains devastatingly effective in practice.

#### The Vulnerable Driver Blocklist

Microsoft ships a driver **blocklist** (a WDAC policy identifying known-abused drivers by hash/signer). When enabled, HVCI-capable systems refuse to load listed drivers. It historically updated slowly (a gap attackers exploited for years), but since 2023 it's on by default for new Windows 11 installs and updated more regularly. **The blocklist is finite and reactive** — a freshly-discovered vulnerable driver isn't on it yet, which is the entire economy of "new BYOVD driver" research.

#### Why BYOVD beats all of it (summary table)

| Control           | Does BYOVD defeat it? | How                                                                     |
| ----------------- | --------------------- | ----------------------------------------------------------------------- |
| DSE               | ✅                     | The driver is genuinely signed.                                         |
| WHQL / cross-sign | ✅                     | Uses drivers that already have valid MS signatures.                     |
| PatchGuard        | ✅                     | Uses data-only edits KPP doesn't monitor.                               |
| HVCI              | ⚠️ Partially          | Data-only attacks (token theft) still work; code-exec & DSE-flip don't. |
| Blocklist         | ⚠️ If listed          | Beaten by using a *not-yet-listed* vulnerable driver.                   |
| EDR (ring 3)      | ✅                     | Kernel code executes beneath EDR's user-mode hooks; can then blind it.  |

### 1.3 How a driver actually gets loaded

To reach a driver's IOCTL handler you must first get it into the kernel. There are three common mechanisms; the **Service Control Manager (SCM)** route is by far the most common in BYOVD tooling.

#### Method A — Service Control Manager (needs admin)

A kernel driver is just a service of type `SERVICE_KERNEL_DRIVER (1)`. The SCM creates a registry key under `HKLM\SYSTEM\CurrentControlSet\Services\<name>` and, on start, calls `NtLoadDriver`, which triggers the CI signature check and maps the image.

```c
// Minimal driver loader via the Service Control Manager. Requires admin.
// Compile: cl loader.c /link advapi32.lib
#include <windows.h>
#include <stdio.h>

int load_driver(const wchar_t *svc, const wchar_t *path) {
    SC_HANDLE scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (!scm) { printf("[-] OpenSCManager: %lu\n", GetLastError()); return 1; }

    SC_HANDLE h = CreateServiceW(
        scm, svc, svc,
        SERVICE_ALL_ACCESS,
        SERVICE_KERNEL_DRIVER,          // type = 1
        SERVICE_DEMAND_START,           // start on request
        SERVICE_ERROR_NORMAL,
        path,                           // fully-qualified path to the .sys
        NULL, NULL, NULL, NULL, NULL);

    if (!h) {
        if (GetLastError() == ERROR_SERVICE_EXISTS)
            h = OpenServiceW(scm, svc, SERVICE_ALL_ACCESS);
        else { printf("[-] CreateService: %lu\n", GetLastError()); return 1; }
    }

    if (!StartServiceW(h, 0, NULL) &&
         GetLastError() != ERROR_SERVICE_ALREADY_RUNNING) {
        printf("[-] StartService: %lu\n", GetLastError());  // 577 = bad signature
        return 1;
    }
    printf("[+] Driver '%ls' loaded.\n", svc);
    CloseServiceHandle(h); CloseServiceHandle(scm);
    return 0;
}
```

From the command line the same thing is a two-liner — this is what most real-world BYOVD loaders do under the hood:

```bat
sc create rtcore64 type= kernel binPath= C:\byovd\RTCore64.sys
sc start  rtcore64
:: ... use it ...
sc stop   rtcore64
sc delete rtcore64
```

> **Detection note (previewing Part 3):** `CreateService` with a kernel type and a `binPath` outside `C:\Windows\System32\drivers` is a *loud* signal. Event ID **4697** (service installed) and Sysmon **13** (registry set on `...\Services\*\ImagePath`) both fire. Serious operators know this and try to minimize the on-disk/registry footprint.

#### Method B — `NtLoadDriver` directly (needs `SeLoadDriverPrivilege`)

You can skip the SCM and call `NtLoadDriver` yourself, pointing it at a registry key you create under `\Registry\Machine\System\CurrentControlSet\Services\...`. This requires `SeLoadDriverPrivilege`, which admins have (disabled by default, enable it with `AdjustTokenPrivileges`). Slightly quieter than SCM but still touches the registry.

#### Method C — abusing an *already-loaded* driver

The cleanest BYOVD variant loads **no new driver at all**: it targets a vulnerable driver that's already present (shipped by an OEM, a game anticheat, an installed utility). No `CreateService`, no new `.sys` on disk, far less telemetry. Enumerate loaded modules (`NtQuerySystemInformation(SystemModuleInformation)`) and check them against a known-vulnerable list.

### 1.4 The device object and its DACL — a subtle attack surface

When a driver initializes it typically calls `IoCreateDevice` and then `IoCreateSymbolicLink` to expose a name like `\??\RTCore64`, reachable from user mode as `\\.\RTCore64`. Two properties decide who can talk to it:

1. **The device's DACL.** If the driver uses `IoCreateDeviceSecure` with a tight SDDL string, only SYSTEM/Administrators can open it. Many vulnerable drivers instead use plain `IoCreateDevice`, which inherits a permissive default — so **even a low-integrity or non-admin process can `CreateFile` the device**. Combined with an `FILE_ANY_ACCESS` IOCTL, that turns a "need admin" bug into a "any user" LPE.
2. **The IOCTL's `Access` field** (bits 15–14 of the code). `FILE_ANY_ACCESS` means the I/O manager won't require read/write access on the handle to dispatch the IOCTL.

```c
// Open the device exposed by the loaded driver.
HANDLE dev = CreateFileW(L"\\\\.\\RTCore64",
                         GENERIC_READ | GENERIC_WRITE,
                         0, NULL, OPEN_EXISTING, 0, NULL);
if (dev == INVALID_HANDLE_VALUE)
    printf("[-] CreateFile failed: %lu\n", GetLastError());
```

If `CreateFile` succeeds from a medium-integrity, non-admin shell, you've discovered a device with a weak DACL — worth checking on every target driver.

### 1.5 The complete BYOVD operational lifecycle

Putting the pieces together, an end-to-end operation looks like this:

```mermaid
flowchart TD
    A[Recon: which vulnerable drivers are usable?] --> B{Driver already loaded?}
    B -- Yes --> D[Open device handle]
    B -- No --> C[Drop .sys + CreateService + StartService]
    C --> D
    D --> E[Enumerate / trigger vulnerable IOCTL]
    E --> F[Build arbitrary kernel READ primitive]
    F --> G[Leak ntoskrnl base + resolve offsets]
    G --> H[Build arbitrary kernel WRITE primitive]
    H --> I{HVCI enabled?}
    I -- No --> J[Flip g_CiOptions / exec kernel shellcode]
    I -- Yes --> K[Data-only: steal token / remove EDR callbacks]
    J --> L[Install rootkit / persist]
    K --> L
    L --> M[Cleanup: stop + delete service, remove .sys]
```

Each stage has both an offensive technique and a defensive tripwire — we map them fully in Part 3 (see the detection map). Keep the lifecycle in mind: **most BYOVD detections don't target the exploit itself (which is invisible, running in the kernel) — they target the noisy setup and teardown around it.**

### 1.6 The toolchain & the ecosystem

A few resources define the modern BYOVD landscape. Know them:

* **LOLDrivers** (`loldrivers.io`) — the canonical, community-maintained catalog of known-vulnerable and malicious drivers, with hashes, sample IOCTLs, and detection artifacts. Your first stop for both offense (candidates) and defense (blocklist source, hunting IOCs).
* **Microsoft's recommended driver block rules** — the official blocklist WDAC policy XML; diffable to see what's newly covered.
* **`sc.exe` / `OpenSCManager`** — loading.
* **IDA Pro / Ghidra** — reversing (Part 2).
* **WinDbg** (`windbg`, `kd`) — kernel debugging, resolving offsets, validating primitives against live memory.
* **`DeviceIoControl` fuzzers** (e.g. IOCTLbf-style, `ioctlfuzzer`, custom harnesses) — discovering reachable/buggy IOCTLs (Part 2).
* Public research frameworks & write-ups: `KDU` (Kernel Driver Utility) by hfiref0x, the `Physmem` primitives collection, and numerous EDR-killer write-ups (`AuKill`, `Terminator`, `Backstab`, `Spyboy`).

#### The canonical vulnerable drivers you'll see referenced

| Driver           | Vendor / origin               | Notable primitive                                             |
| ---------------- | ----------------------------- | ------------------------------------------------------------- |
| `RTCore64.sys`   | MSI Afterburner / Micro-Star  | Arbitrary R/W via `MmMapIoSpace` (MSR + phys). CVE‑2019‑16098 |
| `dbutil_2_3.sys` | Dell                          | Arbitrary R/W. CVE‑2021‑21551                                 |
| `gdrv.sys`       | GIGABYTE                      | Arbitrary phys R/W, MSR write. CVE‑2018‑19320 etc.            |
| `Capcom.sys`     | Capcom (game DRM)             | IOCTL that calls a user-supplied pointer *in ring 0*          |
| `WinRing0.sys`   | OpenLibSys (many OEM tools)   | MSR + phys read/write                                         |
| `AsrDrv10x.sys`  | ASRock                        | phys R/W, MSR                                                 |
| `iqvw64e.sys`    | Intel                         | Used by RobbinHood ransomware to disable AV                   |
| `procexp.sys`    | Sysinternals Process Explorer | Handle/kill primitives (EDR-kill abuse)                       |

Each of these is a *case study* in a different vulnerability class — which is exactly what Part 2 dissects.

***

**Key takeaways for Part 1**

* BYOVD wins because the driver's signature is *real*; the bug is in the driver, not the kernel, so DSE/WHQL/PatchGuard are all satisfied.
* HVCI is the one control that meaningfully constrains BYOVD, pushing attackers from code-exec to data-only techniques.
* Loading is loud (`CreateService`/registry/`ImageLoad`); the exploit itself is quiet. Defense concentrates on the setup.
* The whole game is finding the ring‑3‑to‑ring‑0 bridge inside a signed driver.

Continue to **Part 2 — Reversing Drivers to Find IOCTLs & Vulnerability Classes →**
