我需要确定是否有使用USB键盘插入PC的硬件键盘 Logger . 它需要通过软件方法,从用户土地完成 . 但是wiki表示使用软件检测HKL是不可能的,有几种方法存在 . 最好的,我认为只有一个关于网络的主题是“检测硬件键盘记录,由Fabian Mihailowitsch - youtube” .

使用此概述我正在开发一种检测USB硬件键盘 Logger 的工具 . 用于检测PS / 2键盘 Logger 的源已经由作者共享并且可用here . 所以我的任务是让它只适用于USB .

正如所建议的那样,我使用libusb库来干扰系统中的USB设备 .

所以,我选择了一些方法来检测HKL:

  • 找到被HKL窃听的USB键盘 . 请注意,HKL通常在系统中的设备列表中不可见或由libusb返回 .

  • 通过以下方式检测Keyghost HKL:从USB HID设备中断读取,发送usb reset(libusb_reset_device),再次读取中断 . 如果上次读取时返回的数据不为空,则检测到键盘记录 . Mihailowitsch's presentation第45页对此进行了描述

  • 时间测量 . 这个想法是使用原始键盘的控制传输测量发送/接收数据包的时间数千次 . 如果已插入HKL,程序将再次测量时间,然后将时间与原始值进行比较 . 对于HKL来说,它必须更多(或不那么多) . 算法是:

  • 将输出报告发送到键盘(作为控制传输)(HID_REPORT_TYPE_OUTPUT 0x02)

  • 等待确认数据包

  • 重复循环(10.000次)

  • 测量时间

下面是根据检测步骤的代码 .

1. Find USB keyboard

libusb_device * UsbKeyboard::GetSpecifiedDevice(PredicateType pred)
{
    if (_usbDevices == nullptr) return nullptr;
    int i = 0;
    libusb_device *dev = nullptr;
    while ((dev = _usbDevices[i++]) != NULL)
    {
        struct libusb_device_descriptor desc;
        int r = libusb_get_device_descriptor(dev, &desc);
        if (r >= 0)
        {
            if (pred(desc))
                return dev;
        }
    }

    return nullptr;
}

libusb_device * UsbKeyboard::FindKeyboard()
{
    return GetSpecifiedDevice([&](libusb_device_descriptor &desc) {
        bool isKeyboard = false;
        auto dev_handle = libusb_open_device_with_vid_pid(_context, desc.idVendor, desc.idProduct);     
        if (dev_handle != nullptr)
        {
            unsigned char buf[255] = "";

            // product description contains 'Keyboard', usually string is 'USB Keyboard'            
            if (libusb_get_string_descriptor_ascii(dev_handle, desc.iProduct, buf, sizeof(buf)) >= 0)
                isKeyboard = strstr((char*)buf, "Keyboard") != nullptr;
            libusb_close(dev_handle);           
        }

        return isKeyboard;
    });
}

这里我们're iterating through all USB devices in system and checks their Product string. In my system this string for keyboard is ' USB键盘'(显然) . 通过Product string检测键盘是否稳定?还有其他方法吗?

2. Detect Keyghost HKL using Interrupt read

int UsbKeyboard::DetectKeyghost(libusb_device *kbdev)
{
    int r, i;

    int transferred;
    unsigned char answer[PACKET_INT_LEN];
    unsigned char question[PACKET_INT_LEN];
    for (i = 0; i < PACKET_INT_LEN; i++) question[i] = 0x40 + i;
    libusb_device_handle *devh = nullptr;
    if ((r = libusb_open(kbdev, &devh)) < 0)
    {
        ShowError("Error open device", r);
        return r;
    }

    r = libusb_set_configuration(devh, 1);
    if (r < 0)
    {
        ShowError("libusb_set_configuration error ", r);
        goto out;
    }
    printf("Successfully set usb configuration 1\n");

    r = libusb_claim_interface(devh, 0);
    if (r < 0)
    {
        ShowError("libusb_claim_interface error ", r);
        goto out;
    }

    r = libusb_interrupt_transfer(devh, 0x81 , answer, PACKET_INT_LEN,  
                &transferred, TIMEOUT);
    if (r < 0) 
    {
        ShowError("Interrupt read error ", r);
        goto out;
    }
    if (transferred < PACKET_INT_LEN) 
    {
        ShowError("Interrupt transfer short read %", r);
        goto out;
    }

    for (i = 0; i < PACKET_INT_LEN; i++) {
        if (i % 8 == 0)
            printf("\n");
        printf("%02x, %02x; ", question[i], answer[i]);
    }
    printf("\n");

out:
    libusb_close(devh);
    return 0;
}

我在libusb_interrupt_transfer上遇到了这样的错误:

libusb: error [hid_submit_bulk_transfer] HID transfer failed: [5] Access denied
Interrupt read error  - Input/Output Error (LIBUSB_ERROR_IO) (GetLastError() - 1168)

不知道为什么'access denied',然后IO错误,GetLastError()返回1168,这意味着 - 找不到元素(什么元素?) . 在这里寻求帮助 .

  • 时间测量 . 发送输出报告并等待ACK数据包 .

int UsbKeyboard :: SendOutputReport(libusb_device * kbdev){const int PACKET_INT_LEN = 1; int r,i; unsigned char answer [PACKET_INT_LEN]; unsigned char question [PACKET_INT_LEN]; for(i = 0; i <PACKET_INT_LEN; i)question [i] = 0x30 i; for(i = 1; i <PACKET_INT_LEN; i)answer [i] = 0;

libusb_device_handle *devh = nullptr;
if ((r = libusb_open(kbdev, &devh)) < 0)
{
    ShowError("Error open device", r);
    return r;
}

r = libusb_set_configuration(devh, 1);
if (r < 0) 
{
    ShowError("libusb_set_configuration error ", r);
    goto out;
}
printf("Successfully set usb configuration 1\n");

r = libusb_claim_interface(devh, 0);
if (r < 0) 
{
    ShowError("libusb_claim_interface error ", r);      
    goto out;
}
printf("Successfully claim interface\n");   

r = libusb_control_transfer(devh, CTRL_OUT, HID_SET_REPORT, (HID_REPORT_TYPE_OUTPUT << 8) | 0x00, 0, question, PACKET_INT_LEN, TIMEOUT);
if (r < 0) {
    ShowError("Control Out error ", r);
    goto out;
}

r = libusb_control_transfer(devh, CTRL_IN, HID_GET_REPORT, (HID_REPORT_TYPE_INPUT << 8) | 0x00, 0, answer, PACKET_INT_LEN, TIMEOUT);
if (r < 0) {
    ShowError("Control In error ", r);
    goto out;
}

out:libusb_close(devh);返回0; }

与读取中断相同的错误:控制输出错误 - 输入/输出错误(LIBUSB_ERROR_IO)(GetLastError() - 1168)

如何解决?还有如何等待ACK数据包?

谢谢 .

UPDATE:
我花了一天时间进行搜索和重新调整 . 所以目前我的问题只是通过libusb_control_transfer发送输出报告 . 由于Windows拒绝使用ReadFile从USB设备读取访问权限,因此无需实现具有中断读取的第二种方法 . 它只剩下libusb的东西,这是我想要工作的代码(来自第3个例子):

// sending Output report (LED)
// ...
    unsigned char buf[65]; 
        buf[0] = 1; // First byte is report number
        buf[1] = 0x80;

        r = libusb_control_transfer(devh, CTRL_OUT,
            HID_SET_REPORT/*0x9*/, (HID_REPORT_TYPE_OUTPUT/*0x2*/ << 8) | 0x00,
            0, buf, (uint16_t)2, 1000);
    ...

我得到的错误:

[ 0.309018] [00001c0c] libusb: debug [_hid_set_report] Failed to Write HID Output Report: [1] Incorrect function
Control Out error  - Input/Output Error (LIBUSB_ERROR_IO) (GetLastError() - 1168)

在libusb内部调用 DeviceIoControl 之后发生此错误 . 什么意思"Incorrect function"那里?