macOS IOKit
Podstawowe informacje
IO Kit to otwarty, obiektowy framework sterowników urządzeń w jądrze XNU, obsługujący dynamicznie ładowane sterowniki urządzeń. Pozwala na dodawanie modułowego kodu do jądra w locie, obsługując różnorodny sprzęt.
Sterowniki IOKit w zasadzie eksportują funkcje z jądra. Typy parametrów tych funkcji są predefiniowane i weryfikowane. Ponadto, podobnie jak XPC, IOKit to kolejna warstwa na topie komunikatów Mach.
Kod IOKit XNU kernel jest udostępniony przez Apple pod adresem https://github.com/apple-oss-distributions/xnu/tree/main/iokit. Ponadto, komponenty IOKit w przestrzeni użytkownika są również dostępne jako otwarte oprogramowanie https://github.com/opensource-apple/IOKitUser.
Jednak żadne sterowniki IOKit nie są otwarte. Niemniej jednak, od czasu do czasu wydanie sterownika może zawierać symbole ułatwiające jego debugowanie. Sprawdź, jak pobrać rozszerzenia sterownika z firmware tutaj.
Jest napisany w C++. Możesz uzyskać zdemanglowane symbole C++ za pomocą:
Funkcje udostępnione przez IOKit mogą wykonywać dodatkowe kontrole bezpieczeństwa, gdy klient próbuje wywołać funkcję, ale zauważ, że aplikacje zazwyczaj są ograniczone przez piaskownicę, z którą funkcjami IOKit mogą współdziałać.
Sterowniki
W macOS znajdują się w:
/System/Library/Extensions
Pliki KEXT wbudowane w system operacyjny OS X.
/Library/Extensions
Pliki KEXT zainstalowane przez oprogramowanie firm trzecich
W iOS znajdują się w:
/System/Library/Extensions
Do numeru 9 wymienione sterowniki są załadowane pod adresem 0. Oznacza to, że nie są to rzeczywiste sterowniki, ale część jądra i nie mogą zostać odładowane.
Aby znaleźć konkretne rozszerzenia, można użyć:
Aby załadować i wyładować rozszerzenia jądra, wykonaj:
IORegistry
IORegistry to istotna część frameworka IOKit w systemach macOS i iOS, która służy jako baza danych do reprezentowania konfiguracji sprzętu i stanu systemu. Jest to hierarchiczna kolekcja obiektów reprezentujących cały sprzęt i sterowniki załadowane w systemie oraz ich wzajemne relacje.
Możesz uzyskać dostęp do IORegistry za pomocą wiersza poleceń ioreg
, aby go inspekcjonować z konsoli (szczególnie przydatne w przypadku iOS).
Możesz pobrać IORegistryExplorer
z Dodatkowych narzędzi Xcode ze strony https://developer.apple.com/download/all/ i przeglądać macOS IORegistry za pomocą interfejsu graficznego.
W IORegistryExplorer „płaszczyzny” są używane do organizowania i wyświetlania relacji między różnymi obiektami w IORegistry. Każda płaszczyzna reprezentuje określony rodzaj relacji lub określony widok sprzętu i konfiguracji sterownika systemu. Oto kilka powszechnych płaszczyzn, które możesz napotkać w IORegistryExplorer:
Płaszczyzna IOService: Jest to najbardziej ogólna płaszczyzna, wyświetlająca obiekty usług reprezentujące sterowniki i nuby (kanały komunikacyjne między sterownikami). Pokazuje relacje dostawca-klient między tymi obiektami.
Płaszczyzna IODeviceTree: Ta płaszczyzna reprezentuje fizyczne połączenia między urządzeniami, gdy są one podłączone do systemu. Często jest używana do wizualizacji hierarchii urządzeń podłączonych za pośrednictwem magistral takich jak USB lub PCI.
Płaszczyzna IOPower: Wyświetla obiekty i ich relacje w kontekście zarządzania zasilaniem. Może pokazać, które obiekty wpływają na stan zasilania innych, co jest przydatne do debugowania problemów związanych z zasilaniem.
Płaszczyzna IOUSB: Skupia się specjalnie na urządzeniach USB i ich relacjach, pokazując hierarchię hubów USB i podłączonych urządzeń.
Płaszczyzna IOAudio: Ta płaszczyzna służy do reprezentowania urządzeń audio i ich relacji w systemie.
...
Przykład kodu komunikacji ze sterownikiem
Poniższy kod łączy się z usługą IOKit o nazwie "YourServiceNameHere"
i wywołuje funkcję wewnątrz selektora 0. Aby to zrobić:
najpierw wywołuje
IOServiceMatching
iIOServiceGetMatchingServices
, aby uzyskać usługę.Następnie nawiązuje połączenie, wywołując
IOServiceOpen
.I w końcu wywołuje funkcję za pomocą
IOConnectCallScalarMethod
, wskazując selektor 0 (selektor to numer przypisany do funkcji, którą chcesz wywołać).
Istnieją inne funkcje, które można użyć do wywoływania funkcji IOKit oprócz IOConnectCallScalarMethod
takie jak IOConnectCallMethod
, IOConnectCallStructMethod
...
Odwracanie punktu wejścia sterownika
Możesz je na przykład uzyskać z obrazu oprogramowania (ipsw). Następnie załaduj go do ulubionego dekompilatora.
Możesz zacząć dekompilować funkcję externalMethod
, ponieważ jest to funkcja sterownika, która będzie odbierać wywołanie i wywoływać odpowiednią funkcję:
Ten okropny wywołanie zdemanglowane oznacza:
Zauważ, że w poprzedniej definicji brakuje parametru self
, dobra definicja wyglądałaby tak:
W rzeczywistości prawdziwą definicję można znaleźć pod adresem https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/iokit/Kernel/IOUserClient.cpp#L6388:
Z tą informacją możesz przepisać Ctrl+Right -> Edytuj sygnaturę funkcji
i ustawić znane typy:
Nowy zdekompilowany kod będzie wyglądać tak:
W następnym kroku musimy zdefiniować strukturę IOExternalMethodDispatch2022
. Jest dostępna jako open source pod adresem https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/iokit/IOKit/IOUserClient.h#L168-L176, możesz ją zdefiniować:
Teraz, idąc za (IOExternalMethodDispatch2022 *)&sIOExternalMethodArray
możesz zobaczyć wiele danych:
Zmień typ danych na IOExternalMethodDispatch2022:
po zmianie:
A ponieważ teraz mamy tam tablicę 7 elementów (sprawdź ostatecznie zdekompilowany kod), kliknij, aby utworzyć tablicę 7 elementów:
Po utworzeniu tablicy możesz zobaczyć wszystkie wyeksportowane funkcje:
Jeśli pamiętasz, aby wywołać funkcję wyeksportowaną z przestrzeni użytkownika, nie musisz wywoływać nazwy funkcji, ale numer selektora. Tutaj możesz zobaczyć, że selektor 0 to funkcja initializeDecoder
, selektor 1 to startDecoder
, selektor 2 to initializeEncoder
...
Last updated