HidD_GetInputReport的功能
HidD_GetInputReport用于获取输入报告(input report)。
说明:
不过微软关于此函数有一个特别的说明,就是只能获取当前的输入报告,不能连续的获取,因为可能会丢数据。所以如果要连续的获取输入报告,需要使用ReadFile函数。
同时,有些设备可能不支持HidD_GetInputReport,所以使用此函数时可能没有响应。
更多详见:
- https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/hidsdi/nf-hidsdi-hidd_getinputreport
- https://docs.microsoft.com/en-us/windows-hardware/drivers/hid/obtaining-hid-reports#obtaining-hid-reports-by-user-mode-applications
HidD_GetInputReport应用层
HidD_GetInputReport函数在ReactOS中实现如下:
HIDAPI
BOOLEAN WINAPI
HidD_GetInputReport(IN HANDLE HidDeviceObject,
IN OUT PVOID ReportBuffer,
IN ULONG ReportBufferLength)
{
DWORD RetLen;
return DeviceIoControl(HidDeviceObject, IOCTL_HID_GET_INPUT_REPORT,
NULL, 0,
ReportBuffer, ReportBufferLength,
&RetLen, NULL) != 0;
}
源代码路径为:
E:\reactos\ReactOS-0.4.13-src-2020-0731\ReactOS-0.4.13\dll\win32\hid\hid.c
可以看到,该函数是通过IOCTL_HID_GET_INPUT_REPORT实现的。故我们需要在内核驱动hidclass驱动中查看内核实现。
HidD_GetInputReport内核层
在最新的ReactOS中,其实这个IOCTL并未实现。
case IOCTL_HID_GET_INPUT_REPORT:
{
DPRINT1("[HIDUSB] IOCTL_HID_GET_INPUT_REPORT not implemented \n");
ASSERT(FALSE);
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_NOT_IMPLEMENTED;
}
不过,REACTOS未实现,并不代表windows未实现,只是因为reactos是不一个半成品工程。
所以既然已经知道,该函数是实现在hidclass.sys中,故需要一些特别的方法。
这里结合IDA来进行分析。
我们看过HidRegisterMinidriver的源代码,知道其对原hidusb驱动的的回调函数进行了HOOK,这样当应用层下发IOCTL_HID_GET_INPUT_REPORT后,会进入HIDCLASS设置的回调函数,其函数名为:HidpMajorHandler。
#define IRP_MJ_DEVICE_CONTROL 0x0e
...
v20->MajorFunction[14] = (int (__fastcall *)(_DEVICE_OBJECT *, _IRP *))HidpMajorHandler;
...
在其函数HidpMajorHandler内部继续跟踪
case 14:
v15 = HidpIrpMajorDeviceControl(v8, v4, -1073741824, a4);
所以HidpIrpMajorDeviceControl才是真实的IOCTL_HID_GET_INPUT_REPORT实现。
通过http://www.pnpon.com/import/ioctl.html 查询IOCTL_HID_GET_INPUT_REPORT的值为0xb01a2,故需要在HidpIrpMajorDeviceControl内部查找关于它的代码。
可以看到,代码为:
case 0xB0191u: //IOCTL_HID_SET_FEATURE
case 0xB0192u: //IOCTL_HID_GET_FEATURE
case 0xB0195u: //IOCTL_HID_SET_OUTPUT_REPORT
case 0xB01A2u: //IOCTL_HID_GET_INPUT_REPORT
case 0xB01A6u: //
v12 = HidpGetSetReport(a1, v4, (unsigned int)v109[6], v108);
v105 = v12;
在这个函数中,会进行一些必要的判断,然后调用hidusb中.
v35 = HidpCallDriverSynchronous(*(_QWORD *)v8, v45);
所以看到,这还是进入了miniport设备中。
在hidusb中,其实就是下发IRP到总线驱动,然后获取输入报告内容。当然这里输入报告指针中的第一个字节是ReportID.
进入HIDUSB.SYS驱动后,其执行的是被HIDCLASS.SYS hook掉的ioctl对应的函数HumInternalIoctl。
在HumInternalIoctl中查找对应的IOCTL 0xB01A2u:
。。。。