macOS IOKit
Basic Information
IO 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
Файли KEXT, вбудовані в операційну систему OS X.
/Library/Extensions
Файли KEXT, встановлені стороннім програмним забезпеченням
У iOS вони розташовані в:
/System/Library/Extensions
До номера 9 вказані драйвери завантажуються за адресою 0. Це означає, що це не справжні драйвери, а частина ядра, і їх не можна вивантажити.
Щоб знайти конкретні розширення, ви можете використовувати:
Щоб завантажити та вивантажити розширення ядра, виконайте:
IORegistry
IORegistry є важливою частиною фреймворку IOKit в macOS та iOS, яка слугує базою даних для представлення апаратної конфігурації та стану системи. Це ієрархічна колекція об'єктів, які представляють все апаратне забезпечення та драйвери, завантажені в системі, та їх взаємозв'язки.
Ви можете отримати IORegistry, використовуючи cli ioreg
, щоб перевірити його з консолі (особливо корисно для iOS).
Ви можете завантажити IORegistryExplorer
з Xcode Additional Tools з https://developer.apple.com/download/all/ і перевірити macOS IORegistry через графічний інтерфейс.
У IORegistryExplorer "площини" використовуються для організації та відображення відносин між різними об'єктами в IORegistry. Кожна площина представляє собою певний тип відносин або конкретний вигляд апаратного забезпечення та конфігурації драйверів системи. Ось деякі з поширених площин, з якими ви можете зіткнутися в IORegistryExplorer:
IOService Plane: Це найзагальніша площина, що відображає об'єкти сервісів, які представляють драйвери та нуби (канали зв'язку між драйверами). Вона показує відносини постачальника та клієнта між цими об'єктами.
IODeviceTree Plane: Ця площина представляє фізичні з'єднання між пристроями, коли вони підключені до системи. Вона часто використовується для візуалізації ієрархії пристроїв, підключених через шини, такі як USB або PCI.
IOPower Plane: Відображає об'єкти та їх відносини в термінах управління енергією. Вона може показувати, які об'єкти впливають на стан живлення інших, що корисно для налагодження проблем, пов'язаних з енергією.
IOUSB Plane: Спеціально зосереджена на USB-пристроях та їх відносинах, показуючи ієрархію USB-хабів та підключених пристроїв.
IOAudio Plane: Ця площина призначена для представлення аудіопристроїв та їх відносин у системі.
...
Приклад коду драйвера
Наступний код підключається до сервісу IOKit "YourServiceNameHere"
і викликає функцію всередині селектора 0. Для цього:
спочатку викликає
IOServiceMatching
таIOServiceGetMatchingServices
, щоб отримати сервіс.Потім встановлює з'єднання, викликавши
IOServiceOpen
.І нарешті викликає функцію з
IOConnectCallScalarMethod
, вказуючи селектор 0 (селектор - це номер, який функція, яку ви хочете викликати, має призначений).
Є інші функції, які можна використовувати для виклику функцій IOKit, окрім IOConnectCallScalarMethod
, такі як IOConnectCallMethod
, `IOConnectCallStructMethod...
Реверс інтерфейсу драйвера
Ви можете отримати їх, наприклад, з образу прошивки (ipsw). Потім завантажте його у ваш улюблений декомпілятор.
Ви можете почати декомпілювати функцію externalMethod
, оскільки це функція драйвера, яка буде отримувати виклик і викликати правильну функцію:
Цей жахливий виклик, розмальований, означає:
Зверніть увагу, що в попередньому визначенні пропущено параметр self
, хороше визначення буде таким:
Насправді, ви можете знайти справжнє визначення за адресою https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/iokit/Kernel/IOUserClient.cpp#L6388:
З цією інформацією ви можете переписати Ctrl+Right -> Edit function signature
і встановити відомі типи:
Новий декомпільований код виглядатиме так:
Для наступного кроку нам потрібно визначити структуру IOExternalMethodDispatch2022
. Вона є відкритим кодом у https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/iokit/IOKit/IOUserClient.h#L168-L176, ви можете визначити її:
Тепер, слідуючи за (IOExternalMethodDispatch2022 *)&sIOExternalMethodArray
, ви можете побачити багато даних:
Змініть тип даних на IOExternalMethodDispatch2022:
після зміни:
І як ми тепер знаємо, що в нас є масив з 7 елементів (перевірте фінальний декомпільований код), натисніть, щоб створити масив з 7 елементів:
Після створення масиву ви можете побачити всі експортовані функції:
Якщо ви пам'ятаєте, щоб викликати експортовану функцію з простору користувача, нам не потрібно викликати ім'я функції, а лише номер селектора. Тут ви можете побачити, що селектор 0 - це функція initializeDecoder
, селектор 1 - startDecoder
, селектор 2 - initializeEncoder
...
Last updated