BYOVD - Capcom.sys SMEP-disable code exec¶
Capcom's legitimately signed anti-cheat driver exposes an IOCTL that disables SMEP and directly invokes a user-supplied function pointer in ring 0, granting any authenticated user arbitrary kernel code execution.
Mechanism¶
Note
A signed kernel driver that passes an unchecked user-mode function pointer into a ring-0 CALL instruction collapses the user/kernel boundary entirely. Because the CPU is already executing in CPL 0 when the callback fires, no privilege transition is needed — the driver is the exploit. SMEP must be cleared first (CR4 bit 20) so the CPU does not fault when fetching instructions from a user-space page; Capcom.sys performs this clearance itself before branching to the caller's pointer, then restores CR4 afterward. Any unprivileged process that can open the device handle inherits ring-0 execution unconditionally.
Walkthrough¶
Affected driver: Capcom.sys — distributed with several Capcom PC game titles as an anti-cheat component. The driver is signed by CAPCOM Co., Ltd. (certificate valid 2016-05-02 to 2017-05-02).
Device name: \\.\Htsysm72FB
IOCTL code: 0xAA013044
Input buffer layout (conceptual):
The driver's dispatch routine receives the IOCTL, reads the function pointer from the input buffer, executes inline assembly to clear CR4 bit 20 (SMEP), calls the pointer, then restores CR4. The driver also provides a pointer to MmGetSystemRoutineAddress in the same buffer, acting as a kernel-mode GetProcAddress for callers that need to resolve ntoskrnl exports at runtime.
Conceptual exploitation path:
1. OpenFile("\\.\Htsysm72FB") // obtain device handle
2. VirtualAlloc(shellcode, RWX) // allocate ring-3 shellcode page
3. Write token-stealing payload // e.g. walk EPROCESS, replace token
4. DeviceIoControl(handle, 0xAA013044,
&buffer, ...) // driver disables SMEP, CALLs shellcode
5. shellcode executes at CPL 0 // token stolen → SYSTEM
Because SMEP is toggled off and back on by the driver itself, the payload runs from user-space memory with full kernel privileges. No kernel allocation or ROP chain is required.
SMEP toggle sequence (illustrative, not verbatim Capcom code)
Detection¶
- Driver hash blocklist: LOLDrivers catalogs multiple Capcom.sys variants. Representative SHA-256 values from the LOLDrivers database:
da6ca1fb539f825ca0f012ed6976baf57ef9c70143b7a1e88b4650bf7a925e242b188ae51ec3be082e4d08f7483777ec5e66d30e393a4e9b5b9dc9af93d1f09bac26150bc98ee0419a8b23e4cda3566e0eba94718ba8059346a9696401e9793d(Full list at loldrivers.io)- Device open: Monitor
CreateFilecalls to\\.\Htsysm72FB; any process opening this path is suspicious unless the legitimate Capcom game is installed. - ETW / Sysmon: Driver load events for
Capcom.sys; alert onImageLoadevents where the image name matches known Capcom driver filenames or hashes. - IOCTL tracing: ETW kernel provider
Microsoft-Windows-Kernel-IoTraceor a kernel filter driver can log0xAA013044directed at the Capcom device. - CR4 modification: Hypervisor-based monitoring (e.g., Windows Kernel Patch Protection shadow CR4 checks, or VT-x CR4 write exiting) can detect the SMEP toggle.
- Behavioral: A process with no Capcom game ancestry opening
\\.\Htsysm72FBand immediately spawning a privileged child is a high-fidelity indicator.
Mitigation¶
- Microsoft Vulnerable Driver Blocklist (WDAC): Capcom.sys is on Microsoft's recommended driver block list. Enabling the built-in blocklist (Windows 11 default, or via WDAC policy
DriverSiPolicy.p7b) prevents the driver from loading. - HVCI (Hypervisor-Protected Code Integrity): Enforces that all kernel code be signed and integrity-checked at the hypervisor level; a user-mode page called from ring 0 will generate a fault even if SMEP is cleared.
- WDAC custom policy: Author a deny policy for the Capcom certificate (
CAPCOM Co., Ltd.) or the specific file hashes. - Audit driver allow-lists: Inventory loaded drivers via
sc query type= driveror EDR telemetry; remove or block Capcom.sys if the corresponding game is not authorized. - Driver hardening (development): Validate all IOCTL callers with an ACL; never dereference user-supplied function pointers at CPL 0.