EDR Neutralization
Published on 10 min read
Updated on
In this series27 min read in total
- Windows Internals
- EDR Internals
- EDR Neutralization
From driver-signing trust to evidence of an unauthorized termination primitive.
Bring Your Own Vulnerable Driver (BYOVD) uses a legitimate but vulnerable driver to request a privileged kernel operation. Here, that operation is process termination. The analysis therefore does not start with a function name and jump directly to exploitation; it follows the entire device protocol, from opening the device to the final effect.
Three observations must remain separate:
- a signature establishes loading trust under the active policy;
- an IOCTL selects a command in the driver’s own protocol;
- an import of
ZwTerminateProcessshows that the binary can call the routine.
None of these observations proves on its own that a process can terminate any PID it chooses.
From loading trust to exposed capability
A code-integrity policy can trust a driver’s signature without knowing the quality of every authorization check it implements. BYOVD exploits precisely this gap: code is admitted into the kernel, then its device interface may offer an overly broad capability to a caller that can reach it.
That capability may remain narrow, such as terminating a process, or become broader, such as reading or writing kernel memory. A termination primitive is neither a kernel-write primitive nor arbitrary kernel code execution. This distinction determines what the flaw can actually neutralize.
In this scenario, the final effect may pass through ZwTerminateProcess. The routine executes from ntoskrnl.exe, is declared in ntddk.h, and is resolved by a driver through NtosKrnl.lib. It receives a process handle and an exit status, not a Process Identifier (PID). If the protocol accepts a PID, the driver must therefore convert it into an object or handle, often through ZwOpenProcess, before requesting termination.
The existence of that path raises a more precise question: who can open the device and have the command accepted?
Finding a candidate without confusing triage and proof
LOLDB centralizes metadata about known Windows drivers, including hashes, certificates, imports, and usage categories. It narrows the search space; it does not replace analysis of the exact binary or an authorization test.
The Process Killers filter groups entries associated with an observed termination capability. It does not mean that every listed driver exposes the same IOCTL, accepts the same buffer format, or is usable from the same privilege level.
Triage therefore identifies which binaries deserve analysis. It still does not show how an application reaches the sensitive branch. Answering that question requires reconstructing the driver’s dispatch routine.
Reconstructing the IOCTL contract
An IOCTL is a 32-bit value structured by CTL_CODE(DeviceType, Function, Method, Access). Method describes buffer transfer; Access describes the device-handle rights the I/O manager requires before creating the request. Even FILE_ANY_ACCESS does not automatically make the device public: its Access Control List (ACL) first determines which security principals can obtain a handle.
In a Windows Driver Model (WDM) driver, DriverEntry is the entry point compiled into the vendor’s .sys file. It initializes the DRIVER_OBJECT structure. The MajorFunction[IRP_MJ_DEVICE_CONTROL] entry can contain the address of a dispatch routine supplied by that same driver. IRP_MJ_DEVICE_CONTROL is a major request code, not a function exported by Windows.
Identify the binary and device
Preserve the hash, version, and signature of the analyzed file. Locate device creation, its symbolic link, and the security descriptors governing who can open it.
Recover the dispatch routine
Follow initialization of
DRIVER_OBJECT.MajorFunction[]to theIRP_MJ_DEVICE_CONTROLentry. The resulting address belongs to a function compiled into the.sys, even though the major code is defined by the Windows Driver Kit (WDK).Decode each command
For every compared value, decode
DeviceType,Function,Method, andAccess, then record buffer sizes, offsets, and directions. A constant without its input format does not reconstruct the contract.Follow the privileged effect
Trace caller-controlled data to
ZwOpenProcess,ZwTerminateProcess, or another sensitive routine. Record every branch that validates caller identity, target, and execution context.Measure capability gain
Compare the effect obtained through the device with the same caller’s ordinary rights. A vulnerability exists when the driver grants a privileged operation the caller could not perform directly.
Reading the reverse-engineering captures
The preceding method supplies the narrative thread. The following captures show how its individual proofs appear during static analysis. They document one sample and lab session; they do not describe every driver with a similar import.
The import table first establishes which kernel routines the binary can resolve. It does not yet show which user-controlled entry reaches them.
Finding ZwTerminateProcess narrows the search to its references. The routine appears here as a symbol imported from the Windows kernel.
Cross-references then connect the import to functions in the driver that call it. This establishes internal reachability, but not yet reachability from an IOCTL.
The control-flow graph exposes the call and surrounding branches. Visible loops and tests must be interpreted with their buffers and bounds.
Pseudocode makes the relation between the handle and the call easier to read. The value’s origin must still be recovered before concluding that the caller controls the target.
References to that function finally lead to the routine preparing its arguments. This backward chain links the privileged effect to its command.
The visible dispatch branch selects an IOCTL constant. That value identifies a command for this binary version, not a generic Windows code.
These screens reconstruct a code path. Classifying it as a vulnerability still requires dynamic and comparative evidence.
When a termination IOCTL is actually a vulnerability
The documented path separates I/O-manager gates, vendor-driver logic, and the kernel-supplied effect:
DeviceIoControl is the user-mode API that sends the control code and buffers. Its entry point is exported by Kernel32.dll, its prototype is declared in ioapiset.h, and the application links it through Kernel32.lib. The I/O manager turns the call into an I/O Request Packet (IRP) carrying the IRP_MJ_DEVICE_CONTROL major code, then invokes the dispatch routine registered by the driver.
ZwOpenProcess and ZwTerminateProcess execute from ntoskrnl.exe, are declared in ntddk.h, and are linked by the driver through NtosKrnl.lib. The former can request a handle with PROCESS_TERMINATE; the latter attempts to terminate the process represented by that handle. Either can fail if the identifier is stale, access is not granted, the handle is invalid, applicable target protections intervene, or the process is already terminating.
Classifying the path as vulnerable requires evidence for the complete chain:
| Property | Required evidence |
|---|---|
| Accessibility | A caller within the threat model can open the device object |
| Reachability | The IOCTL reaches the termination branch through IRP_MJ_DEVICE_CONTROL |
| Target control | The caller provides or influences the PID or handle being used |
| Insufficient authorization | The driver does not correctly validate identity, rights, or target |
| Capability gain | The driver terminates a process the caller cannot open directly with PROCESS_TERMINATE |
| Impact | The target can be a system process, security service, or another user’s process |
| Reproducibility | The effect is confirmed on the exact driver, product, and Windows versions |
The factual demonstration is comparative: a caller can open the device, send the command with a controlled target, and cause a termination it could not obtain directly under its own rights. If the device is restricted to SYSTEM or a designated service, the handler authenticates the caller, and targets are tightly constrained, the same ZwTerminateProcess call may be an intentional administration function.
This boundary connects directly to the EDR internals technical review, which separates sensor registration, event delivery, correlation, and response. Terminating a service or removing one signal does not erase observations already collected through other sources.
Reducing BYOVD risk
Analysis of one case shows where to repair its protocol. Fleet-wide defense must also act before driver loading and after the driver appears:
- apply vendor updates and remove vulnerable versions;
- enable and verify the Microsoft Vulnerable Driver Blocklist, then complement it with Windows Defender Application Control or App Control for Business policy as appropriate;
- use Hypervisor-protected Code Integrity (HVCI) to strengthen kernel code integrity without treating it as a guarantee against every signed vulnerable driver;
- restrict the device ACL, choose an appropriate IOCTL
Accessfield, and validate sizes, caller identity, and every target in the handler; - monitor driver-service installation, kernel-image loading, access to sensitive devices, and security-product health;
- confirm the expected policies are actually active on endpoints because coverage depends on Windows version, configuration, and list state.
Conclusion
EDR neutralization through BYOVD is not the automatic consequence of a signature, a readable IOCTL, or a ZwTerminateProcess import. It results from a complete chain: the driver is admitted, its device is accessible, a command reaches a privileged routine, the target is controllable, and authorization fails to contain the effect.
This narrative turns a search for function names into a security analysis: establish the contract, trace the data, compare rights, and bound the exact primitive obtained.
References
- Microsoft,
DeviceIoControl,IRP_MJ_DEVICE_CONTROL, and Defining I/O control codes. - Microsoft,
ZwOpenProcessandZwTerminateProcess. - Microsoft, Driver security checklist, SDDL for Device Objects, and Microsoft recommended driver block rules.
- LOLDB, database consulted on July 23, 2026, using data from the LOLDrivers project.
- Cisco Talos, Exploring malicious Windows drivers, part 2.
- Altered Security, Evasion Lab.








