IOKit写入USB接口挂起/超时

时间:2018-03-19 04:21:35

标签: c macos usb hid iokit

可能有一些非常简单的事情,我没有做或被忽视,但由于我是IOKit的新手,所以我没有想法。

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

史努比日志:

enter image description here enter image description here

我还将设备连接到我的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:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleDevelopmentRegion</key>
    <string>$(DEVELOPMENT_LANGUAGE)</string>
    <key>CFBundleExecutable</key>
    <string>$(EXECUTABLE_NAME)</string>
    <key>CFBundleIdentifier</key>
    <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>$(PRODUCT_NAME)</string>
    <key>CFBundlePackageType</key>
    <string>KEXT</string>
    <key>CFBundleShortVersionString</key>
    <string>1.0</string>
    <key>CFBundleVersion</key>
    <string>1</string>
    <key>IOKitPersonalities</key>
    <dict>
        <key>HID Device</key>
        <dict>
            <key>bInterfaceNumber</key>
            <integer>0</integer>
            <key>bConfigurationValue</key>
            <integer>1</integer>
            <key>idProduct</key>
            <integer>1234</integer>
            <key>idVendor</key>
            <integer>1234</integer>
            <key>IOProbeScore</key>
            <integer>9000</integer>
            <key>CFBundleIdentifier</key>
            <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
            <key>IOClass</key>
            <string>IOService</string>
            <key>IOProviderClass</key>
            <string>IOUSBInterface</string>
        </dict>
    </dict>
    <key>OSBundleLibraries</key>
    <dict>
        <key>com.apple.kpi.iokit</key>
        <string>8.0</string>
        <key>com.apple.kpi.libkern</key>
        <string>8.0</string>
    </dict>
</dict>
</plist>

现在我使用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)); //<-- Here
                    if (ret != kIOReturnSuccess) {
                        puts("Could not write to pipe");
                    }

                    (*usbInterface)->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]

活动监视器确认已附加到/dev/ttys005

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

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

0 个答案:

没有答案