macOS IOKit
Базова інформація
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 за допомогою ioreg
в командному рядку для його перевірки з консолі (особливо корисно для iOS).
Ви можете завантажити IORegistryExplorer
з Додаткових інструментів Xcode з https://developer.apple.com/download/all/ та переглянути macOS IORegistry через графічний інтерфейс.
У IORegistryExplorer "площини" використовуються для організації та відображення взаємозв'язків між різними об'єктами в IORegistry. Кожна площина представляє певний тип відносин або певний вид апаратної частини та конфігурації драйвера системи. Ось деякі зі звичайних площин, з якими ви можете зіткнутися в IORegistryExplorer:
Площина IOService: Це найзагальніша площина, яка відображає об'єкти служб, що представляють драйвери та nubs (канали зв'язку між драйверами). Вона показує відносини між постачальниками та клієнтами цих об'єктів.
Площина IODeviceTree: Ця площина представляє фізичні зв'язки між пристроями, як вони підключені до системи. Часто використовується для візуалізації ієрархії пристроїв, підключених через шини, такі як USB або PCI.
Площина IOPower: Відображає об'єкти та їх відносини з точки зору керування живленням. Вона може показати, які об'єкти впливають на стан живлення інших, що корисно для відлагодження проблем, пов'язаних з живленням.
Площина IOUSB: Спеціально спрямована на USB-пристрої та їх відносини, показуючи ієрархію USB хабів та підключених пристроїв.
Площина IOAudio: Ця площина призначена для представлення аудіопристроїв та їх відносин всередині системи.
...
Приклад коду взаємодії з драйвером
Наведений нижче код підключається до служби 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 -> Редагувати підпис функції
та встановити відомі типи:
Новий декомпільований код буде виглядати так:
Для наступного кроку нам потрібно мати визначену структуру 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