macOS IOKit
Reading time: 8 minutes
tip
Ucz się i ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Wsparcie HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegram lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów github.
Podstawowe informacje
I/O Kit to otwartoźródłowy, obiektowy framework sterowników urządzeń w jądrze XNU, obsługujący dynamicznie ładowane sterowniki urządzeń. Umożliwia dodawanie modułowego kodu do jądra w locie, wspierając różnorodny sprzęt.
Sterowniki IOKit zasadniczo eksportują funkcje z jądra. Typy parametrów tych funkcji są zdefiniowane z góry i są weryfikowane. Ponadto, podobnie jak XPC, IOKit jest po prostu kolejną warstwą na Mach messages.
Kod jądra IOKit XNU jest otwartoźródłowy i udostępniony przez Apple w https://github.com/apple-oss-distributions/xnu/tree/main/iokit. Ponadto, komponenty IOKit w przestrzeni użytkownika są również otwartoźródłowe https://github.com/opensource-apple/IOKitUser.
Jednakże, żadne sterowniki IOKit nie są otwartoźródłowe. Tak czy inaczej, od czasu do czasu wydanie sterownika może zawierać symbole, które ułatwiają jego debugowanie. Sprawdź, jak uzyskać rozszerzenia sterownika z oprogramowania układowego tutaj.
Jest napisany w C++. Możesz uzyskać zdemanglowane symbole C++ za pomocą:
# Get demangled symbols
nm -C com.apple.driver.AppleJPEGDriver
# Demangled symbols from stdin
c++filt
__ZN16IOUserClient202222dispatchExternalMethodEjP31IOExternalMethodArgumentsOpaquePK28IOExternalMethodDispatch2022mP8OSObjectPv
IOUserClient2022::dispatchExternalMethod(unsigned int, IOExternalMethodArgumentsOpaque*, IOExternalMethodDispatch2022 const*, unsigned long, OSObject*, void*)
caution
Funkcje exponowane przez IOKit mogą wykonywać dodatkowe kontrole bezpieczeństwa, gdy klient próbuje wywołać funkcję, ale należy zauważyć, że aplikacje są zazwyczaj ograniczone przez piaskownicę, z którymi funkcje IOKit mogą wchodzić w interakcje.
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
#Use kextstat to print the loaded drivers
kextstat
Executing: /usr/bin/kmutil showloaded
No variant specified, falling back to release
Index Refs Address Size Wired Name (Version) UUID <Linked Against>
1 142 0 0 0 com.apple.kpi.bsd (20.5.0) 52A1E876-863E-38E3-AC80-09BBAB13B752 <>
2 11 0 0 0 com.apple.kpi.dsep (20.5.0) 52A1E876-863E-38E3-AC80-09BBAB13B752 <>
3 170 0 0 0 com.apple.kpi.iokit (20.5.0) 52A1E876-863E-38E3-AC80-09BBAB13B752 <>
4 0 0 0 0 com.apple.kpi.kasan (20.5.0) 52A1E876-863E-38E3-AC80-09BBAB13B752 <>
5 175 0 0 0 com.apple.kpi.libkern (20.5.0) 52A1E876-863E-38E3-AC80-09BBAB13B752 <>
6 154 0 0 0 com.apple.kpi.mach (20.5.0) 52A1E876-863E-38E3-AC80-09BBAB13B752 <>
7 88 0 0 0 com.apple.kpi.private (20.5.0) 52A1E876-863E-38E3-AC80-09BBAB13B752 <>
8 106 0 0 0 com.apple.kpi.unsupported (20.5.0) 52A1E876-863E-38E3-AC80-09BBAB13B752 <>
9 2 0xffffff8003317000 0xe000 0xe000 com.apple.kec.Libm (1) 6C1342CC-1D74-3D0F-BC43-97D5AD38200A <5>
10 12 0xffffff8003544000 0x92000 0x92000 com.apple.kec.corecrypto (11.1) F5F1255F-6552-3CF4-A9DB-D60EFDEB4A9A <8 7 6 5 3 1>
Do numeru 9 wymienione sterowniki są załadowane pod adresem 0. Oznacza to, że nie są to prawdziwe sterowniki, ale część jądra i nie mogą być odładowane.
Aby znaleźć konkretne rozszerzenia, możesz użyć:
kextfind -bundle-id com.apple.iokit.IOReportFamily #Search by full bundle-id
kextfind -bundle-id -substring IOR #Search by substring in bundle-id
Aby załadować i odładować rozszerzenia jądra, wykonaj:
kextload com.apple.iokit.IOReportFamily
kextunload com.apple.iokit.IOReportFamily
IORegistry
IORegistry jest kluczową częścią frameworka IOKit w macOS i iOS, który służy jako baza danych do reprezentowania konfiguracji i stanu sprzętu systemu. To hierarchiczna kolekcja obiektów, które reprezentują cały sprzęt i sterowniki załadowane w systemie oraz ich wzajemne relacje.
Możesz uzyskać dostęp do IORegistry za pomocą cli ioreg
, aby go zbadać z konsoli (szczególnie przydatne dla iOS).
ioreg -l #List all
ioreg -w 0 #Not cut lines
ioreg -p <plane> #Check other plane
Możesz pobrać IORegistryExplorer
z Xcode Additional Tools z https://developer.apple.com/download/all/ i zbadać macOS IORegistry za pomocą graficznego interfejsu.
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 typ relacji lub szczególny widok konfiguracji sprzętowej i sterowników systemu. Oto niektóre z powszechnych płaszczyzn, które możesz napotkać w IORegistryExplorer:
- IOService Plane: To najbardziej ogólna płaszczyzna, wyświetlająca obiekty usług, które reprezentują sterowniki i nuby (kanały komunikacyjne między sterownikami). Pokazuje relacje dostawca-klient między tymi obiektami.
- IODeviceTree Plane: Ta płaszczyzna reprezentuje fizyczne połączenia między urządzeniami, gdy są podłączone do systemu. Często jest używana do wizualizacji hierarchii urządzeń podłączonych przez magistrale, takie jak USB lub PCI.
- IOPower Plane: Wyświetla obiekty i ich relacje w kontekście zarządzania energią. Może pokazywać, które obiekty wpływają na stan zasilania innych, co jest przydatne do debugowania problemów związanych z zasilaniem.
- IOUSB Plane: Skoncentrowana na urządzeniach USB i ich relacjach, pokazując hierarchię hubów USB i podłączonych urządzeń.
- IOAudio Plane: Ta płaszczyzna jest przeznaczona do reprezentowania urządzeń audio i ich relacji w systemie.
- ...
Przykład kodu komunikacji sterownika
Poniższy kod łączy się z usługą IOKit "YourServiceNameHere"
i wywołuje funkcję wewnątrz selektora 0. W tym celu:
- najpierw wywołuje
IOServiceMatching
iIOServiceGetMatchingServices
, aby uzyskać usługę. - Następnie nawiązuje połączenie, wywołując
IOServiceOpen
. - A na końcu wywołuje funkcję za pomocą
IOConnectCallScalarMethod
, wskazując selektor 0 (selektor to numer przypisany funkcji, którą chcesz wywołać).
#import <Foundation/Foundation.h>
#import <IOKit/IOKitLib.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
// Get a reference to the service using its name
CFMutableDictionaryRef matchingDict = IOServiceMatching("YourServiceNameHere");
if (matchingDict == NULL) {
NSLog(@"Failed to create matching dictionary");
return -1;
}
// Obtain an iterator over all matching services
io_iterator_t iter;
kern_return_t kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter);
if (kr != KERN_SUCCESS) {
NSLog(@"Failed to get matching services");
return -1;
}
// Get a reference to the first service (assuming it exists)
io_service_t service = IOIteratorNext(iter);
if (!service) {
NSLog(@"No matching service found");
IOObjectRelease(iter);
return -1;
}
// Open a connection to the service
io_connect_t connect;
kr = IOServiceOpen(service, mach_task_self(), 0, &connect);
if (kr != KERN_SUCCESS) {
NSLog(@"Failed to open service");
IOObjectRelease(service);
IOObjectRelease(iter);
return -1;
}
// Call a method on the service
// Assume the method has a selector of 0, and takes no arguments
kr = IOConnectCallScalarMethod(connect, 0, NULL, 0, NULL, NULL);
if (kr != KERN_SUCCESS) {
NSLog(@"Failed to call method");
}
// Cleanup
IOServiceClose(connect);
IOObjectRelease(service);
IOObjectRelease(iter);
}
return 0;
}
Są inne funkcje, które można wykorzystać do wywoływania funkcji IOKit oprócz IOConnectCallScalarMethod
, takie jak IOConnectCallMethod
, IOConnectCallStructMethod
...
Odwracanie punktu wejścia sterownika
Możesz je uzyskać na przykład z obrazu oprogramowania układowego (ipsw). Następnie załaduj go do swojego 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ę:
To okropne wywołanie demangled oznacza:
IOUserClient2022::dispatchExternalMethod(unsigned int, IOExternalMethodArgumentsOpaque*, IOExternalMethodDispatch2022 const*, unsigned long, OSObject*, void*)
Zauważ, że w poprzedniej definicji brakuje parametru self
, dobra definicja to:
IOUserClient2022::dispatchExternalMethod(self, unsigned int, IOExternalMethodArgumentsOpaque*, IOExternalMethodDispatch2022 const*, unsigned long, OSObject*, void*)
W rzeczywistości możesz znaleźć prawdziwą definicję w https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/iokit/Kernel/IOUserClient.cpp#L6388:
IOUserClient2022::dispatchExternalMethod(uint32_t selector, IOExternalMethodArgumentsOpaque *arguments,
const IOExternalMethodDispatch2022 dispatchArray[], size_t dispatchArrayCount,
OSObject * target, void * reference)
Z tą informacją możesz przepisać Ctrl+Right -> Edit function signature
i ustawić znane typy:
Nowy dekompilowany kod będzie wyglądać następująco:
Na następnym etapie musimy zdefiniować strukturę IOExternalMethodDispatch2022
. Jest ona open source w https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/iokit/IOKit/IOUserClient.h#L168-L176, możesz ją zdefiniować:
Teraz, podążając za (IOExternalMethodDispatch2022 *)&sIOExternalMethodArray
, możesz zobaczyć wiele danych:
Zmień typ danych na IOExternalMethodDispatch2022:
po zmianie:
Jak widzimy, mamy tam tablicę 7 elementów (sprawdź końcowy dekompilowany kod), kliknij, aby utworzyć tablicę 7 elementów:
Po utworzeniu tablicy możesz zobaczyć wszystkie eksportowane funkcje:
tip
Jeśli pamiętasz, aby wywołać eksportowaną funkcję z przestrzeni użytkownika, nie musimy wywoływać nazwy funkcji, ale numer selektora. Tutaj możesz zobaczyć, że selektor 0 to funkcja initializeDecoder
, selektor 1 to startDecoder
, selektor 2 initializeEncoder
...
tip
Ucz się i ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Wsparcie HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegram lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów github.