macOS IOKit
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
基本信息
I/O Kit 是一个开源的面向对象的 设备驱动框架,位于 XNU 内核中,处理 动态加载的设备驱动程序。它允许在内核中动态添加模块化代码,支持多种硬件。
IOKit 驱动程序基本上会 从内核导出函数。这些函数参数的 类型 是 预定义的 并经过验证。此外,类似于 XPC,IOKit 只是 Mach 消息 之上的另一层。
IOKit XNU 内核代码 由 Apple 在 https://github.com/apple-oss-distributions/xnu/tree/main/iokit 开源。此外,用户空间的 IOKit 组件也开源 https://github.com/opensource-apple/IOKitUser。
然而,没有 IOKit 驱动程序 是开源的。无论如何,偶尔会发布带有符号的驱动程序,这使得调试更容易。查看如何 从固件获取驱动程序扩展。
它是用 C++ 编写的。您可以使用以下命令获取去除修饰的 C++ 符号:
IOKit 暴露的函数 在客户端尝试调用函数时可以执行 额外的安全检查,但请注意,应用程序通常受到 沙箱 的 限制,只能与特定的 IOKit 函数进行交互。
驱动程序
在 macOS 中,它们位于:
/System/Library/Extensions
内置于 OS X 操作系统的 KEXT 文件。
/Library/Extensions
由第三方软件安装的 KEXT 文件
在 iOS 中,它们位于:
/System/Library/Extensions
直到第9个,列出的驱动程序是加载在地址0。这意味着这些不是实际的驱动程序,而是内核的一部分,无法卸载。
为了找到特定的扩展,您可以使用:
要加载和卸载内核扩展,请执行:
IORegistry
IORegistry 是 macOS 和 iOS 中 IOKit 框架的一个关键部分,作为表示系统硬件配置和状态的数据库。它是一个 层次化的对象集合,代表系统上加载的所有硬件和驱动程序 及其相互关系。
您可以使用 cli ioreg
从控制台检查 IORegistry(对 iOS 特别有用)。
您可以从 Xcode 附加工具 下载 IORegistryExplorer
,网址为 https://developer.apple.com/download/all/,并通过 图形 界面检查 macOS IORegistry。
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F902778555-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVXPBd5ePyq2S6WpIV6Cj%252Fuploads%252Fgit-blob-04b2754165cfa28e3b0ae64c6be53a64ad306e01%252Fimage%2520%281167%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=5aeea3d9&sv=1)
在 IORegistryExplorer 中,“平面”用于组织和显示 IORegistry 中不同对象之间的关系。每个平面代表特定类型的关系或系统硬件和驱动程序配置的特定视图。以下是您可能在 IORegistryExplorer 中遇到的一些常见平面:
IOService 平面:这是最通用的平面,显示代表驱动程序和 nubs(驱动程序之间的通信通道)的服务对象。它显示这些对象之间的提供者-客户端关系。
IODeviceTree 平面:该平面表示设备与系统之间的物理连接。它通常用于可视化通过 USB 或 PCI 等总线连接的设备层次结构。
IOPower 平面:以电源管理的方式显示对象及其关系。它可以显示哪些对象影响其他对象的电源状态,便于调试与电源相关的问题。
IOUSB 平面:专注于 USB 设备及其关系,显示 USB 集线器和连接设备的层次结构。
IOAudio 平面:该平面用于表示音频设备及其在系统中的关系。
...
驱动程序通信代码示例
以下代码连接到 IOKit 服务 "YourServiceNameHere"
并调用选择器 0 内的函数。为此:
首先调用
IOServiceMatching
和IOServiceGetMatchingServices
来获取服务。然后通过调用
IOServiceOpen
建立连接。最后调用
IOConnectCallScalarMethod
函数,指示选择器 0(选择器是您要调用的函数分配的数字)。
There are 其他 functions that can be used to call IOKit functions apart of IOConnectCallScalarMethod
like IOConnectCallMethod
, IOConnectCallStructMethod
...
反向工程驱动入口点
You could obtain these for example from a 固件镜像 (ipsw). Then, load it into your favourite decompiler.
You could start decompiling the externalMethod
function as this is the driver function that will be receiving the call and calling the correct function:
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F902778555-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVXPBd5ePyq2S6WpIV6Cj%252Fuploads%252Fgit-blob-dde297c56e1244809d507515176081db65acab3d%252Fimage%2520%281168%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=e2e2c4e2&sv=1)
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F902778555-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVXPBd5ePyq2S6WpIV6Cj%252Fuploads%252Fgit-blob-64d3e5b2bad38f5d7850b7dfed52fbdb542f8dbb%252Fimage%2520%281169%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=b464abcc&sv=1)
That awful call demagled means:
注意在之前的定义中缺少了 self
参数,正确的定义应该是:
实际上,您可以在 https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/iokit/Kernel/IOUserClient.cpp#L6388 找到真实的定义:
使用此信息,您可以重写 Ctrl+Right -> Edit function signature
并设置已知类型:
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F902778555-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVXPBd5ePyq2S6WpIV6Cj%252Fuploads%252Fgit-blob-cd027ceda82c2b408c8aa48cb59c3e9c46d6ee87%252Fimage%2520%281174%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=8736ccc6&sv=1)
新的反编译代码将如下所示:
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F902778555-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVXPBd5ePyq2S6WpIV6Cj%252Fuploads%252Fgit-blob-67050294c0a23090cf6a9ba72b8b2312ceb8e0ca%252Fimage%2520%281175%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=2bf68bfa&sv=1)
在下一步中,我们需要定义 IOExternalMethodDispatch2022
结构体。它是开源的,您可以在 https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/iokit/IOKit/IOUserClient.h#L168-L176 中找到,您可以定义它:
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F902778555-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVXPBd5ePyq2S6WpIV6Cj%252Fuploads%252Fgit-blob-3ab03424cb577f03918cd2e23b0b71c14aff4a90%252Fimage%2520%281170%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=b27254e8&sv=1)
现在,跟随 (IOExternalMethodDispatch2022 *)&sIOExternalMethodArray
,您可以看到很多数据:
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F902778555-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVXPBd5ePyq2S6WpIV6Cj%252Fuploads%252Fgit-blob-fc9d9f99db40b57534c138c03f6241711c3ad1c8%252Fimage%2520%281176%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=bdebb7a9&sv=1)
将数据类型更改为 IOExternalMethodDispatch2022:
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F902778555-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVXPBd5ePyq2S6WpIV6Cj%252Fuploads%252Fgit-blob-ad2301b735832707d0363ab1d1d1483081c58a10%252Fimage%2520%281177%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=a2150f4c&sv=1)
更改后:
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F902778555-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVXPBd5ePyq2S6WpIV6Cj%252Fuploads%252Fgit-blob-295913e3a928f47355078b0c9590ff604a6469d8%252Fimage%2520%281179%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=41a7f5c3&sv=1)
正如我们现在所看到的,这里有一个 7 个元素的数组(检查最终的反编译代码),点击以创建一个 7 个元素的数组:
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F902778555-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVXPBd5ePyq2S6WpIV6Cj%252Fuploads%252Fgit-blob-07443434251acc2f39c534ca546150c360fa704b%252Fimage%2520%281180%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=6bef5053&sv=1)
数组创建后,您可以看到所有导出的函数:
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F902778555-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVXPBd5ePyq2S6WpIV6Cj%252Fuploads%252Fgit-blob-7981733f5ae41e7332bad797cc9981f4fd63dcf6%252Fimage%2520%281181%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=9ac6f78d&sv=1)
如果您记得,要从用户空间 调用 一个 导出 函数,我们不需要调用函数的名称,而是 选择器编号。在这里,您可以看到选择器 0 是函数 initializeDecoder
,选择器 1 是 startDecoder
,选择器 2 是 initializeEncoder
...
学习与实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习与实践 GCP 黑客技术:
HackTricks Training GCP Red Team Expert (GRTE)
Last updated