将无代码 KEXT 迁移到无代码 DEXT

Migrating a codeless KEXT to a codeless DEXT

我正在将无代码 KEXT 迁移到无代码 DEXT。我观看了 WWDC 视频并阅读了 Apple Developer 网站上的大部分信息。我遇到的困难不是要做什么,而是如何开始。带有示例项目的不错教程会有所帮助。

在我的无代码 KEXT 中,对于 4 个独立的设备,我为每个设备的 IOUSBDevice 和 IOUSBInterface 设置了 IOKitPersonalities。 KEXT 允许我将我的设备与我的“驱动程序”相匹配,这样 Apple HID 驱动程序就不会抓住它们。我希望在无代码 DEXT 中做相同或类似的事情。

到目前为止,我已经在一个应用程序中创建了一个名为 MyUsbDriver 的 DriverKit 目标(对于 DriverKit.framework)并添加了一个 USBDriverKit.framework。这向我的项目添加了一个文件夹 MyUsbDriver,其中包含文件 MyUsbDriver.cpp、MyUsbDriver.iig、Info.plist 和 MyUsbDriver.entitlements。这是我的问题:

  1. 看起来 IOService 的默认子类适用于 USB - 这与 KEXT 中的 IOClass 相同。是真的吗?

  2. DEXT-world中的IOUSBHostInterface是否等同于KEXT-world中的IOUSBInterface?

  3. IOUSBHostDevice是否等同于IOUSBDevice?

  4. 我需要对无代码 DEXT 的 .cpp 或 .iig 做任何事情吗?我的大部分工作不是在 plist 和 entitlements 文件中完成吗?

  5. 我的 MyUsbDriver 目标框架和库中是否需要 USBDriverKit.framework?

  6. 在哪里可以找到如何完成此迁移的合适示例?

如有任何帮助,我们将不胜感激。

更新:

使用示例和答案中的其他链接,我能够得到一些东西。我确实有一个“Doh”时刻:我最初的测试项目类型是命令行工具,我永远无法嵌入 DEXT。我几乎只是手动编辑了 pbxproj 文件。然而,在查看来自 Scott Knight 的原始示例 USBApp 时,我意识到他使用的项目类型是 App,事后看来,这是有道理的,但当时令人困惑。

这里是 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>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>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
    <key>CFBundleShortVersionString</key>
    <string>1.0</string>
    <key>CFBundleVersion</key>
    <string>1</string>
    <key>IOKitPersonalities</key>
    <dict>
        <key>MyUsbDrver</key>
        <dict>
            <key>CFBundleIdentifier</key>
            <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
            <key>CFBundleIdentifierKernel</key>
            <string>com.apple.kpi.iokit</string>
            <key>IOClass</key>
            <string>IOUserService</string>
            <key>IOMatchCategory</key>
            <string>com.apple.null.driver</string>
            <key>IOProviderClass</key>
            <string>IOUsbHostInterface</string>
            <key>IOResourceMatch</key>
            <string>IOKit</string>
            <key>IOUserClass</key>
            <string>MyUsbDrver</string>
            <key>IOUserServerName</key>
            <string>Home.MyUsbDrver</string>
            <key>bConfigurationValue</key>
            <integer>1</integer>
            <key>bInterfaceNumber</key>
            <integer>0</integer>
            <key>idProduct</key>
            <integer>2</integer>
            <key>idVendor</key>
            <integer>5843</integer>
        </dict>
    </dict>
    <key>OSBundleUsageDescription</key>
    <string>Codless DEXT to match on IOKit.</string>
</dict>
</plist>

我不确定 IOResourceMatch - 值是 IOKit,这是我尝试去的方向。

更新第二个:

进步!

我最终不得不手动更改我的 pbxproj 文件中的签名条款。禁用 SIP,在我的应用程序中设置系统扩展 activation/deactivation 并进行命令行签名。我发现此存储库对于激活代码的体面 Objective-C 示例很有帮助 - https://github.com/google/santa.git。一切构建和代码签名似乎都是成功的。得到有趣的错误

SystemExtension "Home.MyUsbDrver" request did fail: Error Domain=OSSystemExtensionErrorDomain Code=8 "(null)"

更新 3:

我检查了我的 DEXT 和应用授权,看起来应用授权需要更新。这就是我现在的应用程序:

<?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>com.apple.security.app-sandbox</key>
    <true/>
    <key>com.apple.security.files.user-selected.read-only</key>
    <true/>
    <key>com.apple.developer.system-extension.install</key>
    <true/>
    <key>com.apple.developer.system-extension.uninstall</key>
    <true/>
</dict>
</plist>

我错过了最后两个。清理我的项目,构建,再次签名。当我从 Xcode 尝试 运行ning 时,仍然出现错误。当我从 Finder 运行 我的应用程序时,我得到了系统首选项对话框。在那之后,Xcode 的结果仍然相同,现在只有 Finder 运行 时应用程序的闪光。我重新启动 - 仍然是相同的结果。但是,当我从终端 运行 systemextensionsctl -list 时,我得到:

3 extension(s)
--- com.apple.system_extension.driver_extension
enabled active  teamID  bundleID (version)  name    [state]
        <REDACTED>  Home.MyUsbDrver (1.0/1) Home.MyUsbDrver [terminated waiting to uninstall on reboot]
*   *   <REDACTED>  Home.MyUsbDrver (1.0/1) Home.MyUsbDrver [activated enabled]
        <REDACTED>  Home.MyUsbDrver (1.0/1) Home.MyUsbDrver [activated waiting to upgrade]

重启后我得到这个:

1 extension(s)
--- com.apple.system_extension.driver_extension
enabled active  teamID  bundleID (version)  name    [state]
*   *   <REDACTED>  Home.MyUsbDrver (1.0/1) Home.MyUsbDrver [activated enabled]

所以,看起来我的系统扩展已经到位,但实际上我不确定为什么,因为我刚刚重新启动并且没有 运行 我的应用程序。

更新 4:

我发现我的权利的问题只是文件的格式。我在 TextEdit 中更改了它,现在我可以与我的设备通信。这是我最终得到的结果:

<?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>com.apple.developer.driverkit</key>
    <true/>
    <key>com.apple.developer.driverkit.transport.usb</key>
    <array>
        <dict>
            <key>idVendor</key>
            <integer>VID0</integer>
            <key>idProductArray</key>
            <array>
                <integer>PID0</integer>
                <integer>PID1</integer>
                <integer>PID2</integer>
                <integer>PID3</integer>
                <integer>PID4</integer>
            </array>
        </dict>
    </array>
    <key>com.apple.security.app-sandbox</key>
    <true/>
</dict>
</plist>

我一直在努力反对让同样的事情发挥作用。最后,我设法获得了一个有效的 DEXT,它禁用了特定供应商 ID/product ID 组合的 Apple HID 驱动程序。我们已经为我们的供应商 ID 获得了 DriverKit 授权。

  1. It looks like the default subclass of IOService is OK for USB - that is the same as the IOClass from the KEXT. Is that true?

这对我有用。我尝试完全删除 .iig.cpp 文件,但与 KEXT 不同的是,似乎需要编译一些代码才能使签名正常工作。所以我最终得到了 IOService.

的一个空子类
  1. Is IOUSBHostInterface in DEXT-world equivalent to IOUSBInterface in KEXT-world?

我相信是的。我使用了 IOUSBHostInterface,我们的 KEXT 中有 IOUSBInterface

  1. Is IOUSBHostDevice equivalent to IOUSBDevice?

我不知道,但我相信。

  1. Do I need to do anything to the .cpp or .iig for codeless DEXT? Isn't most of my work to be done in the plist and entitlements files?

我不需要更改 .cpp.iig 文件中的任何内容。在释放 .cpp 文件之前,您可能希望删除 os_log(OS_LOG_DEFAULT, "Hello World"); 行。但是在调试时,判断 DEXT 是否实际加载对我很有用。您可以 运行 log stream --source | grep 'HELLO' 在终端中查找日志。

  1. Do I need the USBDriverKit.framework in my Frameworks and Libraries of MyUsbDriver target?

我的 DEXT 链接到 DriverKit.framework。不知道有没有必要

  1. Where can I find a decent example of how to complete this migration?

也许这些可以帮助:

我为自己和未来的开发者记下的一些笔记

在开发 DriverKit 扩展 (dext) 期间,执行以下操作:

  • 禁用系统完整性保护 (SIP):https://apple.stackexchange.com/a/208481/21491。 (在恢复模式下重启,运行 csrutil disable)。记得再次开启!

  • 通过运行ning systemextensionsctl developer on

    启用系统扩展开发模式
  • 确保您没有安装旧的无代码 KEXT。 (从 /Library/Extensions and/or /System/Library/Extensions 中删除它。确保之后重新启动)

提示和注意事项

  • 您可能需要包含 DriverKit 授权的手动配置文件。我认为我的问题是我在企业开发团队而不是 public 开发团队中获得了 DriverKit 权利。

  • 加载扩展的应用程序需要“系统扩展”授权,但不需要手动配置文件。

  • 注意系统偏好设置中的一个愚蠢错误。每次加载 dext 时,您都需要同意加载它。但是,如果“安全和隐私”窗格已经打开,则不会显示同意按钮。您需要重新启动系统偏好设置才能显示。我一直在慷慨地使用终端中的命令 pkill -9 "System Preferences"; open /System/Library/PreferencePanes/Security.prefPane 来解决这个问题。

  • 您可以使用systemextensionsctl卸载dext或重置系统状态。但是,这实际上并没有改变驱动程序匹配,因此您需要重新启动。慷慨地。我使用这个终端命令是因为我很懒:osascript -e 'tell app "System Events" to restart'.

  • 您可以使用ioreg检查设备是否匹配到扩展名:ioreg -lirc IOUSBHostInterface.

  • 让扩展正常工作的关键是将 IOProviderClass 设置为 IOUSBHostInterface 而不是 Info.plist 文件中的 IOResources。 (为了 参考,KEXT 使用 IOUSBInterface 这是 类 之一 Apple 已弃用)

  • 您可能希望在每次对 DEXT 进行更改时更改 Info.plist 中的版本,以确保您实际使用的是正确的版本。 (systemextensionsctl 将显示它加载的版本)。