强制特定驱动程序的无代码 kext (CDC-ACM)

Codeless kext to force a specific driver (CDC-ACM)

我想知道是否有办法以通用方式在 OS X 上使用 USB 调制解调器(华为 E1550 种类),就像通用 USB 调制解调器一样。问题是 OS 不会将其识别为合法的 CDC ACM 设备(它是合法的,但它没有宣传是这样的)。

在 Linux 上,加密狗被自动识别为 USB 串行设备。

有一些原因我不想在我的任何机器上使用 ZTE 或 Huawei 供应商驱动程序:这些人写的东西几乎无法工作(我最后一次使用 ZTE 驱动程序的经历包括向我的日志发送垃圾邮件,占用 RAM,而我无法禁用它),他们的驱动程序不向前兼容,他们忽略了将它们与较新的 OS 版本同步,并且他们通常打算将这些驱动程序与运营商过时软件一起分发。

Apple 的开发人员文档以一种模糊的方式写道,可以编写无代码的 kext 以在匹配的设备上强制使用特定的驱动程序,或者阻止为匹配的设备加载通用驱动程序。事实上,大多数对无代码 kexts 的搜索都会产生类似 "how do I prevent my serial dongle to be recognised as a modem?" 的问题,而我想要的是完全相反的!

到目前为止,我尝试编写这样一个无代码的 kext 以失败告终 — kextutil 告诉 kext 已成功加载,但它不存在,AppleCDCACM.kext 也是如此(它具有我想使用的 IOClass ).

仅供参考,从 Linux:

收集的 lsusb 信息
Bus 004 Device 005: ID 12d1:1001 Huawei Technologies Co., Ltd. E169/E620/E800 HSDPA Modem
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  idVendor           0x12d1 Huawei Technologies Co., Ltd.
  idProduct          0x1001 E169/E620/E800 HSDPA Modem
  bcdDevice            0.00
  iManufacturer           2 HUAWEI Technology
  iProduct                1 HUAWEI Mobile
  iSerial                 0 
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           85
    bNumInterfaces          3
    bConfigurationValue     1
    iConfiguration          3 Qualcomm Configuration
    bmAttributes         0xe0
      Self Powered
      Remote Wakeup
    MaxPower              500mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           3
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass    255 Vendor Specific Subclass
      bInterfaceProtocol    255 Vendor Specific Protocol
      iInterface              0 
      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               5
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x82  EP 2 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval              32
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval              32
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass    255 Vendor Specific Subclass
      bInterfaceProtocol    255 Vendor Specific Protocol
      iInterface              0 
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x83  EP 3 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval              32
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x02  EP 2 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval              32
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        2
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass    255 Vendor Specific Subclass
      bInterfaceProtocol    255 Vendor Specific Protocol
      iInterface              0 
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x84  EP 4 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval              32
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x03  EP 3 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval              32
Device Qualifier (for other device speed):
  bLength                10
  bDescriptorType         6
  bcdUSB               2.00
  bDeviceClass            0 
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  bNumConfigurations      1
can't get debug descriptor: Resource temporarily unavailable
Device Status:     0x0001
  Self Powered

我要连接的接口是接口 0(调制解调器)。

ioreg 是这样看的:

   | |   |       | | +-o HUAWEI Mobile@1d110000  
    | |   |       | |   +-o AppleUSBHostLegacyClient  
    | |   |       | |   +-o AppleUSBHostCompositeDevice  
    | |   |       | |   +-o IOUSBHostInterface@0  
    | |   |       | |   |   {
    | |   |       | |   |     "USBPortType" = 0
    | |   |       | |   |     "IOCFPlugInTypes" = {"2d9786c6-9ef3-11d4-ad51-000a27052861"="IOUSBFamily.kext/Contents/PlugIns/IOUSBLib.bundle"}
    | |   |       | |   |     "bcdDevice" = 0
    | |   |       | |   |     "USBSpeed" = 3
    | |   |       | |   |     "idProduct" = 4097
    | |   |       | |   |     "bConfigurationValue" = 1
    | |   |       | |   |     "bInterfaceSubClass" = 255
    | |   |       | |   |     "locationID" = 487653376
    | |   |       | |   |     "IOGeneralInterest" = "IOCommand is not serializable"
    | |   |       | |   |     "IOClassNameOverride" = "IOUSBInterface"
    | |   |       | |   |     "AppleUSBAlternateServiceRegistryID" = 4294969542
    | |   |       | |   |     "idVendor" = 4817
    | |   |       | |   |     "bInterfaceProtocol" = 255
    | |   |       | |   |     "bAlternateSetting" = 0
    | |   |       | |   |     "bInterfaceNumber" = 0
    | |   |       | |   |     "bInterfaceClass" = 255
    | |   |       | |   |   }
    | |   |       | |   |   
    | |   |       | |   +-o IOUSBHostInterface@1  
    | |   |       | |   |   {
    | |   |       | |   |     "USBPortType" = 0
    | |   |       | |   |     "IOCFPlugInTypes" = {"2d9786c6-9ef3-11d4-ad51-000a27052861"="IOUSBFamily.kext/Contents/PlugIns/IOUSBLib.bundle"}
    | |   |       | |   |     "bcdDevice" = 0
    | |   |       | |   |     "USBSpeed" = 3
    | |   |       | |   |     "idProduct" = 4097
    | |   |       | |   |     "bConfigurationValue" = 1
    | |   |       | |   |     "bInterfaceSubClass" = 255
    | |   |       | |   |     "locationID" = 487653376
    | |   |       | |   |     "IOGeneralInterest" = "IOCommand is not serializable"
    | |   |       | |   |     "IOClassNameOverride" = "IOUSBInterface"
    | |   |       | |   |     "AppleUSBAlternateServiceRegistryID" = 4294969544
    | |   |       | |   |     "idVendor" = 4817
    | |   |       | |   |     "bInterfaceProtocol" = 255
    | |   |       | |   |     "bAlternateSetting" = 0
    | |   |       | |   |     "bInterfaceNumber" = 1
    | |   |       | |   |     "bInterfaceClass" = 255
    | |   |       | |   |   }
    | |   |       | |   |   
    | |   |       | |   +-o IOUSBHostInterface@2  
    | |   |       | |       {
    | |   |       | |         "USBPortType" = 0
    | |   |       | |         "IOCFPlugInTypes" = {"2d9786c6-9ef3-11d4-ad51-000a27052861"="IOUSBFamily.kext/Contents/PlugIns/IOUSBLib.bundle"}
    | |   |       | |         "bcdDevice" = 0
    | |   |       | |         "USBSpeed" = 3
    | |   |       | |         "idProduct" = 4097
    | |   |       | |         "bConfigurationValue" = 1
    | |   |       | |         "bInterfaceSubClass" = 255
    | |   |       | |         "locationID" = 487653376
    | |   |       | |         "IOGeneralInterest" = "IOCommand is not serializable"
    | |   |       | |         "IOClassNameOverride" = "IOUSBInterface"
    | |   |       | |         "AppleUSBAlternateServiceRegistryID" = 4294969546
    | |   |       | |         "idVendor" = 4817
    | |   |       | |         "bInterfaceProtocol" = 255
    | |   |       | |         "bAlternateSetting" = 0
    | |   |       | |         "bInterfaceNumber" = 2
    | |   |       | |         "bInterfaceClass" = 255
    | |   |       | |       }
    | |   |       | |       

到目前为止,Info.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>BuildMachineOSBuild</key>
    <string>15C27b</string>
    <key>CFBundleDevelopmentRegion</key>
    <string>English</string>
    <key>CFBundleIdentifier</key>
    <string>name.fedevych.GenericWWAN</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>GenericWWAN</string>
    <key>CFBundlePackageType</key>
    <string>KEXT</string>
    <key>CFBundleShortVersionString</key>
    <string>99.0.0</string>
    <key>CFBundleSignature</key>
    <string>????</string>
    <key>CFBundleSupportedPlatforms</key>
    <array>
        <string>MacOSX</string>
    </array>
    <key>CFBundleVersion</key>
    <string>99.0.0</string>
    <key>IOKitPersonalities</key>
    <dict>
        <key>HUAWEI_0x12d11001_Control</key>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.apple.driver.usb.cdc.acm</string>
            <key>IOClass</key>
            <string>AppleUSBACMControl</string>
            <key>IOProviderClass</key>
            <string>IOUSBHostInterface</string>

            <key>idVendor</key>
            <integer>4817</integer>
            <key>idProduct</key>
            <integer>4097</integer>
            <key>bcdDevice</key>
            <integer>0</integer>

            <key>bInterfaceNumber</key>
            <integer>0</integer>
            <key>bConfigurationValue</key>
            <integer>1</integer>

            <key>IOMatchCategory</key>
            <string>com.apple.driver.AppleUSBACMControl</string>
        </dict>
        <key>HUAWEI_0x12d11001_Data</key>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>com.apple.driver.usb.cdc.acm</string>
            <key>IOClass</key>
            <string>AppleUSBACMData</string>
            <key>IOProviderClass</key>
            <string>IOUSBHostInterface</string>

            <key>idVendor</key>
            <integer>4817</integer>
            <key>idProduct</key>
            <integer>4097</integer>
            <key>bcdDevice</key>
            <integer>0</integer>

            <key>bInterfaceNumber</key>
            <integer>0</integer>
            <key>bConfigurationValue</key>
            <integer>1</integer>

        </dict>
    </dict>
    <key>OSBundleLibraries</key>
    <dict/>
</dict>
</plist>

有什么指点吗?

因此,我不能保证您的项目会成功 - 我不知道您的调制解调器是否可以使用标准 CDC 驱动程序。但我希望能帮助你找出答案。这真的有 5 个部分:

  1. 正确的匹配字典匹配有问题的 device/interface。
  2. 为实际驱动程序设置正确的 class 和包 ID。
  3. 无代码 kextinfo.plist 中需要注意的一些额外要点
  4. Kext 签名。
  5. Loading/Debugging.

I/O 配套USB配套

Apple 的 Q&A QA1076 是关于该主题的最佳资源。我建议尽可能具体。所以在你的情况下,例如:

IOProviderClass: IOUSBInterface
idVendor: 0x12d1
idProduct: 0x1001
bInterfaceNumber: 0
bConfigurationValue: 1

希望我没听错。当设备插入时,您应该能够在终端中通过 运行 ioreg -c IOUSBInterface 进行确认。这将以 OSX 的格式向您显示系统中所有 USB 接口的属性,并且您应该能够为您的调制解调器挑选一个,并确保这些属性与我提供的相匹配。

驱动程序 class 和包 ID

除了匹配条件之外,info.plist 中的 I/O 套件个性字典还需要指定 (C++) class 应为其创建实例以驱动匹配的设备,以及包含它的 kext 的包 ID。

现在的问题是,用什么驱动。我不太了解 CDC-ACM 设备,但据我所知,它们由一个控件和一个数据接口组成。这个的驱动程序似乎是

/System/Library/Extensions/IOUSBFamily.kext/Contents/PlugIns/AppleUSBCDCACMControl.kext
/System/Library/Extensions/IOUSBFamily.kext/Contents/PlugIns/AppleUSBCDCACMData.kext

分别在 OSX。其中每一个似乎都假设它们可以完全控制 USB 接口——似乎大多数设备将控制和数据端点拆分为 2 个独立的接口。在你的情况下,你只有一个。从技术上讲,多个驱动程序可以通过使用不同的匹配类别来匹配一项服务。但我不能保证 CDC-ACM 数据和控制驱动程序会对此感到满意。你可以试试…

为此,您实际上需要两个 I/O 套件个性词典,具有相同的匹配标准,但其中一个应该有一个非默认的 IOMatchCategory,例如相关的驱动程序包 ID。

所以尝试这样的事情:

<key>IOKitPersonalities</key>
<dict>
    <key>AppleUSBCDCACMControl</key>
    <dict>
        <key>CFBundleIdentifier</key>
        <string>com.apple.driver.AppleUSBCDCACMControl</string>
        <key>IOClass</key>
        <string>AppleUSBCDCACMControl</string>
        <key>IOProviderClass</key>
        <string>IOUSBInterface</string>
        <key>idVendor</key>
        <integer>4817</integer>
        <key>idProduct</key>
        <integer>4097</integer>
        <key>bInterfaceNumber</key>
        <integer>0</integer>
        <key>bConfigurationValue</key>
        <integer>1</integer>
        <key>IOMatchCategory</key>
        <string>com.apple.driver.AppleUSBCDCACMControl</string>
    </dict>
    <key>AppleUSBCDCACMData</key>
    <dict>
        <key>CFBundleIdentifier</key>
        <string>com.apple.driver.AppleUSBCDCACMData</string>
        <key>IOClass</key>
        <string>AppleUSBCDCACMData</string>
        <key>IOProviderClass</key>
        <string>IOUSBInterface</string>
        <key>IOUserClientClass</key>
        <string>AppleUSBCDCACMDataUserClient</string>
        <key>InputBuffers</key>
        <integer>8</integer>
        <key>OutputBuffers</key>
        <integer>16</integer>
        <key>idVendor</key>
        <integer>4817</integer>
        <key>idProduct</key>
        <integer>4097</integer>
        <key>bInterfaceNumber</key>
        <integer>0</integer>
        <key>bConfigurationValue</key>
        <integer>1</integer>
    </dict>
</dict>

无代码kext info.plist

因为您已经拥有 kextutil 似乎喜欢的 kext,您可能已经做对了:无代码 kexts 必须:

  • 有空 OSBundleLibraries 属性.
  • 没有 CFBundleExecutable 属性。

Kext 签名

在 OSX 10.10 和 10.11 上,所有 kexts,包括无代码的,都必须签名。在 10.9 上,如果它们驻留在 /System/Library/Extensions 中,则它们可以是无符号的;在 10.10 上,如果设置了内核选项 kext-dev-mode=1,则它们可以是无符号的。您需要一个特殊的 kext 签名附加到 Apple 的 Developer Id 证书才能签署 kexts。

加载和调试

/System/Library/Extensions(10.10 之前可写)或/Library/Extensions(10.9+)中的 Kexts 将在启动或设备热插拔时自动匹配。也可以使用 kextutil.

从这些位置之外手动加载它们

加载的 kext 二进制文件列在 kextstat 的输出中。无代码 kexts 没有二进制文件,因此不会出现。但是,如果 I/O Kit Personality 的 CFBundleIdentifier 处于活动状态,则包含驱动程序代码的包将显示。

要查看您的特定设备发生了什么,请使用 ioreg 命令行工具或 GUI 工具 IORegistryExplorer(来自 Apple 的硬件 I/O 工具包)或 IOJones(开源)。

最后的想法

考虑到 CDC-ACM Control/Data 拆分,您可能无法仅使用无代码 kext 来完成工作。您可能需要更深入地了解 Apple 的驱动程序是如何工作的,并可能在您自己的 kext 中覆盖他们的某些行为,以便他们找到正确的端点。祝你好运!