Search code examples
windowsdriverhidkmdf

HID submit HID_XFER_PACKET to simulate keystrokes


I'm trying to write a KMDF driver to simulate keystrokes.

When the driver receives IOCTL_HID_READ_REPORT it redirects the request to a queue:

switch (IoControlCode)
{
case IOCTL_HID_GET_DEVICE_DESCRIPTOR:
    KdPrint(("GET DEVICE DESCRIPTOR\n"));
    _Analysis_assume_(deviceContext->HidDescriptor.bLength != 0);
    status = RequestCopyFromBuffer(Request, &deviceContext->HidDescriptor, deviceContext->HidDescriptor.bLength);
    break;

case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
    KdPrint(("GET DEVICE ATTRIBUTES\n"));
    status = RequestCopyFromBuffer(Request, &queueContext->DeviceContext->HidDeviceAttributes, sizeof(HID_DEVICE_ATTRIBUTES));
    break;

case IOCTL_HID_GET_REPORT_DESCRIPTOR:
    KdPrint(("GET REPORT DESCRIPTOR\n"));
    status = RequestCopyFromBuffer(Request, deviceContext->ReportDescriptor, deviceContext->HidDescriptor.DescriptorList[0].wReportLength);
    break;

case IOCTL_HID_READ_REPORT:
   WdfRequestForwardToIoQueue(Request, QueueContext->DeviceContext->ManualQueue); // <= HERE
    break;}

With a timer, items are regularly dequeued and the keyboard input report is copied in the request

void EvtTimerFunc(_In_  WDFTIMER Timer)
{
    NTSTATUS                status;
    WDFQUEUE                queue;
    PMANUAL_QUEUE_CONTEXT   queueContext;
    WDFREQUEST              request;


    KdPrint(("EvtTimerFunc\n"));

    queue = (WDFQUEUE)WdfTimerGetParentObject(Timer);
    queueContext = GetManualQueueContext(queue);

    //
    // see if we have a request in manual queue
    //
    status = WdfIoQueueRetrieveNextRequest(queueContext->Queue, &request);

    if (NT_SUCCESS(status))
    {
        KdPrint(("Handling"));

        HID_XFER_PACKET hidXferPacket;

        BYTE keycodes[6] = {0};
        keycodes[0] = 0x04;

        HID_KEYBOARD_INPUT_REPORT report;
        report.ReportId = REPORT_ID_KEYBOARD_INPUT;
        report.Modifiers = 0;
        report._reserved = 0;
        memcpy(&report.KeyCodes, &keycodes, 6);

        hidXferPacket.reportBuffer = (UCHAR*)&report;
        hidXferPacket.reportBufferLen = sizeof(HID_KEYBOARD_INPUT_REPORT);
        hidXferPacket.reportId = REPORT_ID_KEYBOARD_INPUT;

        RequestCopyFromBuffer(request, hidXferPacket.reportBuffer, sizeof(HID_KEYBOARD_INPUT_REPORT));
        
        WdfRequestComplete(request, status);
    }
}
   

Although everything works without error, no keystroke are emitted. What am I missing ?!

Descriptor:

HID_REPORT_DESCRIPTOR g_reportDescriptor[] = {
    0x05, 0x01,        // USAGE_PAGE (Generic Desktop)
    0x09, 0x02,        // USAGE (Mouse)
    0xA1, 0x01,        // COLLECTION (Application)
    0x85,                  REPORT_ID_MOUSE_INPUT,
    0x09, 0x01,            // USAGE_PAGE (Pointer)
    0xA1, 0x00,            // COLLECTION (Physical)
    0x05, 0x09,                // USAGE_PAGE (Buttons)
    0x19, 0x01,                // USAGE_MINIMUM (1)
    0x29, 0x03,                // USAGE_MAXIMUM (3)
    0x15, 0x00,                // LOGICAL_MINIMUM (0)
    0x25, 0x01,                // LOGICAL_MAXIMUM (1)
    0x95, 0x03,                // REPORT_COUNT (3)
    0x75, 0x01,                // REPORT_SIZE (1)
    0x81, 0x02,                // INPUT (Data, Variable, Absolute)
    0x95, 0x01,                // REPORT_COUNT (1)
    0x75, 0x05,                // REPORT_SIZE (5)
    0x81, 0x01,                // INPUT (Constant)
    0x05, 0x01,                // USAGE_PAGE (Generic Desktop)
    0x09, 0x30,                // USAGE (X)
    0x09, 0x31,                // USAGE (Y)
    0x15, 0x81,                // LOGICAL_MINIMUM (-127)
    0x25, 0x7F,                // LOGICAL_MAXIMUM (127)
    0x75, 0x08,                // REPORT_SIZE (8)
    0x95, 0x02,                // REPORT_COUNT (2)
    0x81, 0x06,                // Input (Data, Variable, Relative)
    0xC0,                  // END_COLLECTION
    0xC0,              // END_COLLECTION

    0x05, 0x01,        // USAGE_PAGE (Generic Desktop)
    0x09, 0x00,        // USAGE (Undefined)
    0xa1, 0x01,        // COLLECTION (Application)
    0x85,                  REPORT_ID_MOUSE_OUTPUT,
    0x09, 0x00,            // USAGE (Undefined)
    0x15, 0x00,            // LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,      // LOGICAL_MAXIMUM (255)
    0x95, 0x03,            // REPORT_COUNT (3)
    0x75, 0x08,            // REPORT_SIZE (8)
    0x91, 0x02,            // OUTPUT (Data, Variable, Absolute)
    0xc0,              // END_COLLECTION

    0x05, 0x01,        // USAGE_PAGE (Generic Desktop)
    0x09, 0x06,        // USAGE (Keyboard)
    0xA1, 0x01,        // COLLECTION (Application)
    0x85,                  REPORT_ID_KEYBOARD_INPUT,
    0x05, 0x07,            // USAGE_PAGE (Keyboard Key Codes)
    0x19, 0xE0,            // USAGE_MINIMUM (224)
    0x29, 0xE7,            // USAGE_MAXIMUM (231)
    0x15, 0x00,            // LOGICAL_MINIMUM (0)
    0x25, 0x01,            // LOGICAL_MAXIMUM (1)
    0x75, 0x01,            // REPORT_SIZE (1)
    0x95, 0x08,            // REPORT_COUNT (8)
    0x81, 0x02,            // INPUT (Data, Variable, Absolute)
    0x95, 0x01,            // REPORT_COUNT (1)
    0x75, 0x08,            // REPORT_SIZE (8)
    0x81, 0x01,            // INPUT (Constant)
    0x19, 0x00,            // USAGE_MINIMUM (0)
    0x29, 0x65,            // USAGE_MAXIMUM (101)
    0x15, 0x00,            // LOGICAL_MINIMUM (0)
    0x25, 0x65,            // LOGICAL_MAXIMUM (101)
    0x95, 0x06,            // REPORT_COUNT (6)
    0x75, 0x08,            // REPORT_SIZE (8)
    0x81, 0x00,            // INPUT (Data, Array, Absolute)
    0x05, 0x08,            // USAGE_PAGE (LEDs)
    0x19, 0x01,            // USAGE_MINIMUM (Num Lock)
    0x29, 0x05,            // USAGE_MAXIMUM (Kana)
    0x95, 0x05,            // REPORT_COUNT (5)
    0x75, 0x01,            // REPORT_SIZE (1)
    0x91, 0x02,            // OUTPUT (Data, Variable, Absolute)
    0x95, 0x01,            // REPORT_COUNT (1)
    0x75, 0x03,            // REPORT_SIZE (3)
    0x91, 0x01,            // OUTPUT (Constant)
    0xC0,              // END_COLLECTION

    0x05, 0x01,        // USAGE_PAGE (Generic Desktop)
    0x09, 0x00,        // USAGE (Undefined)
    0xa1, 0x01,        // COLLECTION (Application)
    0x85,                  REPORT_ID_KEYBOARD_OUTPUT,
    0x09, 0x00,            // USAGE (Undefined)
    0x15, 0x00,            // LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,      // LOGICAL_MAXIMUM (255)
    0x95, 0x08,            // REPORT_COUNT (8)
    0x75, 0x08,            // REPORT_SIZE (8)
    0x91, 0x02,            // OUTPUT (Data, Variable, Absolute)
    0xc0               // END_COLLECTION
};

HID_DESCRIPTOR g_hidDescriptor = {
    0x09,        // length of HID descriptor
    0x21,        // descriptor type == HID 0x21
    0x0100,      // hid spec release
    0x00,        // country code == Not Specified
    0x01,        // number of HID class descriptors
    {            // DescriptorList[0]
        0x22,                             // report descriptor type 0x22
        sizeof(g_reportDescriptor)        // total length of report descriptor
    }
};

Solution

  • I was using a Hyper V virtual machine as a debug machine, and this is why it didn't work. As soon as I used another computer, the keystrokes were sent.

    If you're trying to emulate keystroke or mouse move, this is what I recommend: