IOKit写入USB接口挂起/超时

可能有一些非常简单的东西,我没有做或被忽略但是我没有想法,因为我是IOKit的新手。

我想重新创建一些只有Windows的软件,我带有USB设备。 我在VM上安装了Snoopy,然后点击程序上的一个按钮,关闭LED,然后查看日志,希望了解发生了什么。 看起来每个按钮点击软件,就会发送2个数据包。 一个到接口,一个到端点,前6个字节是相同的。 我不知道为什么会这样。

史努比日志:

在此处输入图像描述 在此处输入图像描述

我还将设备连接到我的Ubuntu VM并运行sudo lsusb -v以在设备上收集更多信息:

  Bus 001 Device 009: ID 1234:1234 Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 1.10 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x1234 idProduct 0x1234 bcdDevice 1.00 iManufacturer 1 (error) iProduct 2 (error) iSerial 3 (error) bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 34 bNumInterfaces 1 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 100mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 3 Human Interface Device bInterfaceSubClass 1 Boot Interface Subclass bInterfaceProtocol 1 Keyboard iInterface 0 HID Device Descriptor: bLength 9 bDescriptorType 33 bcdHID 1.01 bCountryCode 0 Not supported bNumDescriptors 1 bDescriptorType 34 Report wDescriptorLength 40 Report Descriptors: ** UNAVAILABLE ** Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Device Status: 0x0000 (Bus Powered) 

我采取的下一步是编写一个无代码kext,以防止macOS在我的用户登陆软件之前抓住它。 Kexstat确认它正在运行。 plist:

     CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType KEXT CFBundleShortVersionString 1.0 CFBundleVersion 1 IOKitPersonalities  HID Device  bInterfaceNumber 0 bConfigurationValue 1 idProduct 1234 idVendor 1234 IOProbeScore 9000 CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) IOClass IOService IOProviderClass IOUSBInterface   OSBundleLibraries  com.apple.kpi.iokit 8.0 com.apple.kpi.libkern 8.0    

现在我使用IOKit在C中编写了一个应用程序,试图写入设备上唯一的管道(我可以看到)。 应用程序一直到WritePipe函数,然后挂起。 什么都没发生。 这是代码:

 CFMutableDictionaryRef matchingDictionary = NULL; CFNumberRef numberRef; SInt32 idVendor = 0x1234; SInt32 idProduct = 0x1234; // Create a matching dictionary for IOUSBDevice matchingDictionary = IOServiceMatching(kIOUSBDeviceClassName); // Add the USB Vendor ID to the matching dictionary numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &idVendor); CFDictionaryAddValue(matchingDictionary, CFSTR(kUSBVendorID), numberRef); CFRelease(numberRef); // Add the USB Product ID to the matching dictionary numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &idProduct); CFDictionaryAddValue(matchingDictionary, CFSTR(kUSBProductID), numberRef); CFRelease(numberRef); io_iterator_t iterator = 0; io_service_t usbDeviceRef; kern_return_t err; // Find all kernel objects that match the dictionary err = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDictionary, &iterator); if (err == 0) { // Iterate over all matching kernel objects while ((usbDeviceRef = IOIteratorNext(iterator)) != 0) { // Create a driver for this device instance SInt32 score; IOUSBDeviceInterface300** usbDevice = NULL; io_iterator_t iterator; IOCFPlugInInterface** plugin; IOUSBConfigurationDescriptorPtr config; IOUSBFindInterfaceRequest interfaceRequest; IOUSBInterfaceInterface300** usbInterface; IOReturn ret; /* * All the different packs I tried sending */ char out[] = { 0x02, 0x00, 0x02, 0x4a, 0x30, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /*char out[] = { 0x02, 0x00, 0x02, 0x4a, 0x30, 0x78, 0x7a, 0xf5, 0x25, 0xa8, 0x1e, 0x7c, 0x46, 0x3c, 0x5d, 0x7f, 0xf8, 0xd4, 0x9b, 0x8a, 0xa2, 0xf1, 0xc8, 0xa8, 0x88, 0x4d, 0xba, 0x7b, 0xf4, 0x2f, 0x42, 0x28, 0xef, 0xa3, 0xee, 0x8e, 0x0f, 0x1a, 0x57, 0x1f, 0x7d, 0xed, 0x3b, 0x49, 0x8d, 0xed, 0x64, 0x93, 0x40, 0x75, 0x5a, 0x29, 0x98, 0x59, 0x6f, 0x7b, 0x39, 0xe8, 0xe8, 0x2e, 0xe9, 0x69, 0xe7, 0x7f }; // set data to send*/ //char out[] = { 0x02, 0x00, 0x02, 0x4a, 0x30, 0x78, 0x00, 0x00}; //char out[] = { 0x21, 0x09, 0x00, 0x03, 0x00, 0x00, 0x40, 0x00}; IOCreatePlugInInterfaceForService(usbDeviceRef, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &score); IOObjectRelease(usbDeviceRef); (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID300), (LPVOID)&usbDevice); (*plugin)->Release(plugin); if ((*usbDevice)->USBDeviceOpen(usbDevice) == kIOReturnSuccess) { ret = (*usbDevice)->GetConfigurationDescriptorPtr(usbDevice, 0, &config); if (ret == kIOReturnSuccess) { (*usbDevice)->SetConfiguration(usbDevice, config->bConfigurationValue); interfaceRequest.bInterfaceClass = kIOUSBFindInterfaceDontCare; interfaceRequest.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; interfaceRequest.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; interfaceRequest.bAlternateSetting = kIOUSBFindInterfaceDontCare; (*usbDevice)->CreateInterfaceIterator(usbDevice, &interfaceRequest, &iterator); usbDeviceRef = IOIteratorNext(iterator); IOObjectRelease(iterator); IOCreatePlugInInterfaceForService(usbDeviceRef, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &score); IOObjectRelease(usbDeviceRef); (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID300), (LPVOID)&usbInterface); (*plugin)->Release(plugin); ret = (*usbInterface)->USBInterfaceOpen(usbInterface); if (ret == kIOReturnSuccess) { UInt8 pipe_ref = 1; ret = (*usbInterface)->GetPipeStatus(usbInterface, pipe_ref); switch (ret) { case kIOReturnNoDevice: puts("No Device"); break; case kIOReturnNotOpen: puts("Not Open"); break; case kIOReturnSuccess: puts("Open"); break; case kIOReturnBusy: puts("Busy"); break; default: printf("%08x\n", ret); } ret = (*usbInterface)->WritePipe(usbInterface, pipe_ref, out, sizeof(out)); //USBInterfaceClose(usbInterface); (*usbDevice)->USBDeviceClose(usbDevice); return 0; } else { puts("Could not open interface"); } } } else { printf("Could not open device\n"); return -1; } IOObjectRelease(usbDeviceRef); } IOObjectRelease(iterator); } return 0; 

当它挂起时,我打开了Activity Monitor并查看了示例,看起来它正在击中一个mach_msg_trap (无论我是否使用sudo运行)。 调用图:

 Call graph: 2713 Thread_48027 DispatchQueue_1: com.apple.main-thread (serial) + 2713 start (in libdyld.dylib) + 1 [0x7fffc7122235] + 2713 main (in HID Driver) + 1322 [0x100000db6] main.c:111 + 2713 IOUSBInterfaceClass::WritePipe(unsigned char, void*, unsigned int, unsigned int, unsigned int) (in IOUSBLib) + 161 [0x1020aa217] + 2713 IOConnectCallMethod (in IOKit) + 256 [0x7fffb38fa1a2] + 2713 io_connect_method (in IOKit) + 375 [0x7fffb3974c91] + 2713 mach_msg (in libsystem_kernel.dylib) + 55 [0x7fffc7248797] + 2713 mach_msg_trap (in libsystem_kernel.dylib) + 10 [0x7fffc724934a] 

Activity Monitor确认它已附加到/dev/ttys005

 /private/var/db/dyld/dyld_shared_cache_x86_64h 0 /dev/ttys005 1 /dev/ttys005 2 /dev/ttys005 

我不知道为什么会这样。 希望有人可以指出我错过的东西,因为我完全没有想法。