我需要确定是否有使用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"那里?