可能有一些非常简单的事情,我没有做或被忽视,但由于我是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:
<?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
我不知道为什么会这样。希望有人可以指出我在这里错过的东西,因为我完全没有想法。