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

GTA*_*E86 5 macos iokit kernel-extension driverkit

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

在我的无代码 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 世界中的 IOUSBHostInterface 是否等同于 KEXT 世界中的 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>
Run Code Online (Sandbox Code Playgroud)

我不确定 IOResourceMatch - 值是 IOKit,这是我想要走的方向。

更新第二个:

进步!

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

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

更新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>
Run Code Online (Sandbox Code Playgroud)

我错过了最后两个。清理我的项目,构建,再次签名。当我尝试从 Xcode 运行时,仍然出现错误。当我从 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]
Run Code Online (Sandbox Code Playgroud)

重新启动后我得到这个:

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]
Run Code Online (Sandbox Code Playgroud)

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

更新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>
Run Code Online (Sandbox Code Playgroud)

Jon*_*den 3

我非常努力地反对让同样的事情发挥作用。最后,我设法获得了一个有效的 DEXT,它可以禁用特定供应商 ID/产品 ID 组合的 Apple HID 驱动程序。我们已获得供应商 ID 的 DriverKit 权利。

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

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

  1. DEXT 世界中的 IOUSBHostInterface 是否等同于 KEXT 世界中的 IOUSBInterface?

我相信是这样。我用过IOUSBHostInterface,我们IOUSBInterface在 KEXT 中也有。

  1. IOUSBHostDevice 是否等同于 IOUSBDevice?

我不知道,但我相信是这样。

  1. 对于无代码 DEXT,我需要对 .cpp 或 .iig 执行任何操作吗?我的大部分工作不是要在 plist 和 entitlements 文件中完成吗?

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

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

我的 DEXT 链接到DriverKit.framework. 我不知道是否需要。

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

也许这些可以帮助:

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

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

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

  • 通过运行启用系统扩展开发模式systemextensionsctl developer on

  • 确保您没有安装旧的无代码 KEXT。(从/Library/Extensions和/或 中删除它/System/Library/Extensions。确保之后重新启动)

提示和注意事项

  • 您可能需要包含 DriverKit 权利的手动配置配置文件。我认为我的问题是我在企业开发团队而不是公共开发团队中获得了 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

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

  • 您可能希望每次更改 DEXT 时都导入版本,Info.plist以确保您实际上使用的是正确的版本。(systemextensionsctl将显示已加载的版本)。