No description
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-10-23 11:36:07 -03:00
vhidev-hid-takeover First commit 2026-10-23 11:36:07 -03:00
.gitignore First commit 2026-10-23 11:36:07 -03:00
README.md First commit 2026-10-23 11:36:07 -03:00
vhidev-hid-takeover.sln First commit 2026-10-23 11:36:07 -03:00

vhidev-hid-takeover

Research PoC: reverse-engineering a third-party virtual HID driver (vhidflt.sys / hardware id root\vhidev) and driving it from a plain user-mode process to synthesize keyboard, mouse, consumer-control and system-control input, with no vendor runtime involved.

Research use only. Run inside a disposable VM. The driver package in resource/ is a third-party WHQL-signed binary — this project does not redistribute it as a product, it is kept here only as the reverse-engineering target the PoC was written against. Loading it on a machine you care about and then injecting input into whatever window happens to have focus is a great way to lose that machine.


Background

The vhidev package exposes a KMDF root-enumerated bus driver that children out multiple HID collections. One of those collections — the vendor-defined COL05 — accepts a single 64-byte Output report whose first byte is a fixed report id and whose second byte selects a virtual device:

[0] = 5        vendor report id (fixed)
[1] = selector:
      1  -> keyboard   (modifiers + 32-byte NKRO bitmap, bytes 2..34)
      2  -> mouse      (buttons, int8 X, int8 Y, int8 wheel, bytes 2..5)
      3  -> consumer   (16-bit LE usage code, bytes 2..3)
      4  -> system     (16-bit LE usage code, bytes 2..3)
[2..63] = payload (unused tail zeroed)

The driver's internal dispatcher routes the payload to the correct child HID collection, so the host OS sees four separate, perfectly ordinary HID devices delivering input. From the input-stack side it is indistinguishable from a real USB composite device.

This project answers two questions:

  1. Can the vendor package be installed and bound to the host without the vendor's own installer? Yes — install.c reproduces what devcon install vhidflt.inf root\vhidev does using SetupAPI / UpdateDriverForPlugAndPlayDevices directly, so no third-party installer or service is required.
  2. Is the COL05 interface reachable from user mode without any additional secret / handshake? Yes — once the devnode is bound, the HID child is enumerated and CreateFile + WriteFile of a 64-byte report is enough. Nothing authenticates the writer.

The second point is the actual research finding: a signed virtual-HID driver intended for a specific product can be repurposed into a generic system-wide input-injection primitive by any process that happens to have SeLoadDriverPrivilege once (install) and admin + raw HID write access afterwards.

Repository layout

vhidev-hid-takeover.sln          Visual Studio solution (x64)
vhidev-hid-takeover/
  app.manifest                   requestedExecutionLevel = requireAdministrator
  header/
    common.h                     logging + small platform helpers
    install.h                    SetupAPI install / state check
    hid.h                        COL05 report shape + high-level senders
    ui.h                         console menu
  source/
    main.c                       boot: elevate → install if needed → open → menu
    install.c                    devcon-style install via SetupAPI
    hid.c                        64-byte report builders + WriteFile loop
    ui.c                         demo menu (keyboard typing, mouse paths,
                                 vol/mute, play/pause, sleep, …)
  resource/
    vhidflt.inf                  vendor INF (install source)
    vhidflt.sys                  vendor KMDF driver (WHQL-signed)
    vhidflt.sys.i64              IDA Pro database from the RE pass
    WdfCoinstaller01009.dll      KMDF coinstaller
    wudf.cat                     catalog

How it works end to end

  1. main.c checks for elevation (manifest already asks for it) and, if the root\vhidev devnode is not present, calls vhidev_install().
  2. vhidev_install() reads the class from the INF (SetupDiGetINFClassA), creates an empty devnode in a temporary device info set, stamps root\vhidev as the SPDRP_HARDWAREID, registers it with DIF_REGISTERDEVICE, then kicks UpdateDriverForPlugAndPlayDevices to copy the INF into the DriverStore and bind the driver. From here on the devnode is persistent across reboots.
  3. hid_open() enumerates the HID interface class (GUID_DEVINTERFACE_HID), opens each device, pulls preparsed data via HIDP, and picks the one whose top-level vendor-defined usage matches COL05.
  4. The high-level helpers in hid.c (hid_send_mouse, hid_send_keyboard, hid_send_consumer, hid_send_system) build the 64-byte selector-prefixed report and WriteFile it.
  5. ui.c is a small menu that exercises each path (type a string, draw a square with the mouse, mute, volume up/down, play/pause, sleep, …) so the PoC visibly works without an attached app.

Build

  • Visual Studio 2022, Windows 10/11 SDK, platform x64.
  • Open vhidev-hid-takeover.sln, build Release.
  • Run vhidev-hid-takeover.exe elevated. The resource\ directory must sit next to the exe (the vcxproj copies it to the output automatically).

Research notes

  • The INF declares class HIDClass; after install, there is no service to start — PnP starts the driver on demand when the first child is opened.
  • vhidev_is_installed() uses CM_Locate_DevNodeA on the hardware id (root\vhidev) with CM_LOCATE_DEVNODE_NORMAL. Note that this expects a device instance id in general, but the specific call shape used here is the one that works reliably against the enumerator-created root node; earlier versions in the LeagueBot codebase got this wrong and re-installed on every launch, stacking duplicate devnodes.
  • The report-id / selector scheme means a single 64-byte write path serves four distinct HID classes. For fuzzing follow-ups this is a convenient single surface to target the driver's dispatcher.

What this project is not

  • Not a product, not a cheat, not a redistribution of the vendor driver.
  • Not a vulnerability disclosure. The behaviour exercised here is the driver's documented function — the point is that a signed, locally-installed virtual-HID driver is a generic input-injection primitive, which is intentional on the vendor's side and inherently high-privilege on the host.

License

No license granted. All rights reserved. Published for research reference.