HID.DLL导出函数HidD_GetInputReport探究

13 篇文章 0 订阅
5 篇文章 0 订阅

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:
。。。。

后续部分,请查看:http://www.usbzh.com/article/detail-933.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单的 `hid.dll` 导出函数的示例代码,供参考: ```c #include <Windows.h> #include <hidsdi.h> BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { switch (fdwReason) { case DLL_PROCESS_ATTACH: // DLL 初始化 break; case DLL_PROCESS_DETACH: // DLL 卸载 break; case DLL_THREAD_ATTACH: // 新线程创建 break; case DLL_THREAD_DETACH: // 线程结束 break; } return TRUE; } // 导出函数:获取 HID 设备信息 extern "C" __declspec(dllexport) BOOL GetHidDeviceInfo( DWORD dwVendorId, // 设备厂商 ID DWORD dwProductId, // 设备产品 ID PHIDD_ATTRIBUTES pHidAttributes // 输出设备属性结构体 ) { BOOL bResult = FALSE; HDEVINFO hDeviceInfo = NULL; // 枚举所有 HID 设备 hDeviceInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_HID, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (hDeviceInfo == INVALID_HANDLE_VALUE) { return FALSE; } // 遍历所有 HID 设备 DWORD dwIndex = 0; SP_DEVICE_INTERFACE_DATA deviceInterfaceData = { 0 }; deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); while (SetupDiEnumDeviceInterfaces(hDeviceInfo, NULL, &GUID_DEVINTERFACE_HID, dwIndex, &deviceInterfaceData)) { // 获取设备接口数据 DWORD dwRequiredSize = 0; SetupDiGetDeviceInterfaceDetail(hDeviceInfo, &deviceInterfaceData, NULL, 0, &dwRequiredSize, NULL); if (dwRequiredSize == 0) { break; } PSP_DEVICE_INTERFACE_DETAIL_DATA pDeviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, dwRequiredSize); if (pDeviceInterfaceDetailData == NULL) { break; } pDeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); if (SetupDiGetDeviceInterfaceDetail(hDeviceInfo, &deviceInterfaceData, pDeviceInterfaceDetailData, dwRequiredSize, NULL, NULL)) { // 打开设备 HANDLE hDevice = CreateFile(pDeviceInterfaceDetailData->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (hDevice != INVALID_HANDLE_VALUE) { // 获取设备属性 HIDD_ATTRIBUTES hidAttributes = { 0 }; hidAttributes.Size = sizeof(HIDD_ATTRIBUTES); if (HidD_GetAttributes(hDevice, &hidAttributes)) { // 比较设备厂商 ID 和产品 ID if (hidAttributes.VendorID == dwVendorId && hidAttributes.ProductID == dwProductId) { // 输出设备属性 CopyMemory(pHidAttributes, &hidAttributes, sizeof(HIDD_ATTRIBUTES)); bResult = TRUE; CloseHandle(hDevice); break; } } CloseHandle(hDevice); } } LocalFree(pDeviceInterfaceDetailData); ++dwIndex; } SetupDiDestroyDeviceInfoList(hDeviceInfo); return bResult; } ``` 此示例代码中,我们定义了一个名为 `GetHidDeviceInfo` 的函数,该函数可以用来获取指定厂商 ID 和产品 ID 的 HID 设备的属性信息。我们将该函数作为 `hid.dll` 的导出函数,供其他程序调用。 需要注意的是,在 `DllMain` 函数中,我们可以进行 DLL 的初始化和卸载工作,例如打开和关闭一些资源,但是我们需要避免在此函数中进行太多的操作,以免影响系统的性能和稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值