macOS IOKit

Reading time: 8 minutes

tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Podržite HackTricks

Osnovne informacije

I/O Kit je open-source, objektno orijentisan framework za drajvere uređaja u XNU kernelu, koji upravlja dinamički učitanim drajverima uređaja. Omogućava dodavanje modularnog koda u kernel u hodu, podržavajući raznovrsni hardver.

IOKit drajveri će u osnovi izvoziti funkcije iz kernela. Ovi parametri funkcija su preddefinisani i verifikovani. Štaviše, slično XPC-u, IOKit je samo još jedan sloj iznad Mach poruka.

IOKit XNU kernel kod je open-source od strane Apple-a na https://github.com/apple-oss-distributions/xnu/tree/main/iokit. Takođe, komponente IOKit korisničkog prostora su takođe open-source https://github.com/opensource-apple/IOKitUser.

Međutim, nema IOKit drajvera koji su open-source. U svakom slučaju, s vremena na vreme, objavljivanje drajvera može doći sa simbolima koji olakšavaju njegovo debagovanje. Proverite kako da dobijete ekstenzije drajvera iz firmvera ovde.

Napisano je u C++. Možete dobiti demanglovane C++ simbole sa:

bash
# 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

IOKit izložene funkcije mogu izvršiti dodatne bezbednosne provere kada klijent pokuša da pozove funkciju, ali imajte na umu da su aplikacije obično ograničene od sandbox-a sa kojim IOKit funkcije mogu da interaguju.

Drajveri

U macOS-u se nalaze u:

  • /System/Library/Extensions
  • KEXT datoteke ugrađene u OS X operativni sistem.
  • /Library/Extensions
  • KEXT datoteke instalirane od strane softvera trećih strana

U iOS-u se nalaze u:

  • /System/Library/Extensions
bash
#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 broja 9, navedeni drajveri su učitani na adresi 0. To znači da to nisu pravi drajveri već deo kernela i ne mogu se ukloniti.

Da biste pronašli specifične ekstenzije, možete koristiti:

bash
kextfind -bundle-id com.apple.iokit.IOReportFamily #Search by full bundle-id
kextfind -bundle-id -substring IOR #Search by substring in bundle-id

Da biste učitali i ispraznili kernel ekstenzije, uradite:

bash
kextload com.apple.iokit.IOReportFamily
kextunload com.apple.iokit.IOReportFamily

IORegistry

IORegistry je ključni deo IOKit okvira u macOS i iOS koji služi kao baza podataka za predstavljanje hardverske konfiguracije i stanja sistema. To je hijerarhijska kolekcija objekata koja predstavlja sav hardver i drajvere učitane na sistemu, i njihove međusobne odnose.

Možete dobiti IORegistry koristeći cli ioreg da biste ga pregledali iz konzole (posebno korisno za iOS).

bash
ioreg -l #List all
ioreg -w 0 #Not cut lines
ioreg -p <plane> #Check other plane

Možete preuzeti IORegistryExplorer iz Xcode Additional Tools sa https://developer.apple.com/download/all/ i pregledati macOS IORegistry kroz grafički interfejs.

U IORegistryExplorer, "planovi" se koriste za organizovanje i prikazivanje odnosa između različitih objekata u IORegistry. Svaki plan predstavlja specifičnu vrstu odnosa ili poseban pogled na hardversku i drajversku konfiguraciju sistema. Evo nekih od uobičajenih planova koje možete sresti u IORegistryExplorer:

  1. IOService Plane: Ovo je najopštiji plan, koji prikazuje servisne objekte koji predstavljaju drajvere i nubs (kanale komunikacije između drajvera). Prikazuje odnose između provajdera i klijenata ovih objekata.
  2. IODeviceTree Plane: Ovaj plan predstavlja fizičke veze između uređaja dok su priključeni na sistem. Često se koristi za vizualizaciju hijerarhije uređaja povezanih putem magistrala kao što su USB ili PCI.
  3. IOPower Plane: Prikazuje objekte i njihove odnose u smislu upravljanja energijom. Može pokazati koji objekti utiču na stanje napajanja drugih, što je korisno za otklanjanje grešaka povezanih sa energijom.
  4. IOUSB Plane: Specifično fokusiran na USB uređaje i njihove odnose, prikazuje hijerarhiju USB hubova i povezanih uređaja.
  5. IOAudio Plane: Ovaj plan je za predstavljanje audio uređaja i njihovih odnosa unutar sistema.
  6. ...

Primer koda za Driver Comm

Sledeći kod se povezuje na IOKit servis "YourServiceNameHere" i poziva funkciju unutar selektora 0. Za to:

  • prvo poziva IOServiceMatching i IOServiceGetMatchingServices da dobije servis.
  • Zatim uspostavlja vezu pozivajući IOServiceOpen.
  • I konačno poziva funkciju sa IOConnectCallScalarMethod označavajući selektor 0 (selektor je broj koji je funkciji koju želite da pozovete dodeljen).
objectivec
#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;
}

Postoje druge funkcije koje se mogu koristiti za pozivanje IOKit funkcija pored IOConnectCallScalarMethod kao što su IOConnectCallMethod, IOConnectCallStructMethod...

Reverzno inženjerstvo ulazne tačke drajvera

Možete ih dobiti, na primer, iz firmware slike (ipsw). Zatim, učitajte je u svoj omiljeni dekompajler.

Možete početi dekompilaciju funkcije externalMethod jer je to funkcija drajvera koja će primati poziv i pozivati odgovarajuću funkciju:

Ta strašna pozivna funkcija demanglovana znači:

cpp
IOUserClient2022::dispatchExternalMethod(unsigned int, IOExternalMethodArgumentsOpaque*, IOExternalMethodDispatch2022 const*, unsigned long, OSObject*, void*)

Napomena kako u prethodnoj definiciji nedostaje self parametar, dobra definicija bi bila:

cpp
IOUserClient2022::dispatchExternalMethod(self, unsigned int, IOExternalMethodArgumentsOpaque*, IOExternalMethodDispatch2022 const*, unsigned long, OSObject*, void*)

Zapravo, pravu definiciju možete pronaći na https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/iokit/Kernel/IOUserClient.cpp#L6388:

cpp
IOUserClient2022::dispatchExternalMethod(uint32_t selector, IOExternalMethodArgumentsOpaque *arguments,
const IOExternalMethodDispatch2022 dispatchArray[], size_t dispatchArrayCount,
OSObject * target, void * reference)

Sa ovom informacijom možete prepraviti Ctrl+Desno -> Edit function signature i postaviti poznate tipove:

Novi dekompilirani kod će izgledati ovako:

Za sledeći korak potrebno je definisati IOExternalMethodDispatch2022 strukturu. Ona je otvorenog koda na https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/iokit/IOKit/IOUserClient.h#L168-L176, možete je definisati:

Sada, prateći (IOExternalMethodDispatch2022 *)&sIOExternalMethodArray možete videti mnogo podataka:

Promenite Tip Podataka u IOExternalMethodDispatch2022:

posle promene:

I kao što sada znamo, imamo niz od 7 elemenata (proverite konačni dekompilirani kod), kliknite da kreirate niz od 7 elemenata:

Nakon što je niz kreiran, možete videti sve eksportovane funkcije:

tip

Ako se sećate, da pozovete eksportovanu funkciju iz korisničkog prostora, ne treba da pozivate ime funkcije, već broj selektora. Ovde možete videti da je selektor 0 funkcija initializeDecoder, selektor 1 je startDecoder, selektor 2 initializeEncoder...

tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Podržite HackTricks