macOS IOKit

Μάθε το χάκινγκ στο AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

Βασικές Πληροφορίες

Το I/O 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 δεν είναι ανοιχτού κώδικα. Παρ' όλα αυτά, κατά καιρούς μια έκδοση ενός οδηγού μπορεί να περιέχει σύμβολα που διευκολύνουν την αποσφαλμάτωσή του. Ελέγξτε πώς να πάρετε τις επεκτάσεις οδηγού από το firmware εδώ.

Είναι γραμμένο σε C++. Μπορείτε να πάρετε αποδιαιρεμένα σύμβολα C++ με:

# 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*)

Οι εκθέσεις συναρτήσεων του IOKit μπορούν να πραγματοποιήσουν επιπλέον ελέγχους ασφαλείας όταν ένας πελάτης προσπαθεί να καλέσει μια συνάρτηση, αλλά να σημειωθεί ότι οι εφαρμογές είναι συνήθως περιορισμένες από το sandbox με το οποίο το IOKit μπορεί να αλληλεπιδράσει.

Οδηγοί

Στο macOS βρίσκονται στα:

  • /System/Library/Extensions

  • Αρχεία KEXT που έχουν ενσωματωθεί στο λειτουργικό σύστημα OS X.

  • /Library/Extensions

  • Αρχεία KEXT που έχουν εγκατασταθεί από λογισμικό τρίτων

Στο iOS βρίσκονται στα:

  • /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>

Μέχρι τον αριθμό 9, οι αναφερόμενοι οδηγοί φορτώνονται στη διεύθυνση 0. Αυτό σημαίνει ότι αυτοί δεν είναι πραγματικοί οδηγοί αλλά μέρος του πυρήνα και δεν μπορούν να απενεργοποιηθούν.

Για να βρείτε συγκεκριμένες επεκτάσεις, μπορείτε να χρησιμοποιήσετε:

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

Για να φορτώσετε και να απενεργοποιήσετε επεκτάσεις πυρήνα, κάντε τα εξής:

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

IORegistry

Το IORegistry είναι ένας κρίσιμος μέρος του πλαισίου IOKit στο macOS και το iOS, το οποίο λειτουργεί ως μια βάση δεδομένων για την αναπαράσταση της υπαρξιακής διάταξης και κατάστασης του υλικού του συστήματος. Είναι μια ιεραρχική συλλογή αντικειμένων που αναπαριστούν όλο το υλικό και τους προγραμματιστές που φορτώνονται στο σύστημα και τις σχέσεις τους μεταξύ τους.

Μπορείτε να αποκτήσετε το IORegistry χρησιμοποιώντας το εργαλείο γραμμής εντολών ioreg για να το επιθεωρήσετε από την κονσόλα (ιδιαίτερα χρήσιμο για το iOS).

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

Μπορείτε να κατεβάσετε το IORegistryExplorer από τα Επιπλέον Εργαλεία του Xcode από το https://developer.apple.com/download/all/ και να επιθεωρήσετε το macOS IORegistry μέσω μιας γραφικής διεπαφής.

Στο IORegistryExplorer, τα "planes" χρησιμοποιούνται για να οργανώσουν και να εμφανίσουν τις σχέσεις μεταξύ διάφορων αντικειμένων στο IORegistry του macOS. Κάθε plane αντιπροσωπεύει ένα συγκεκριμένο τύπο σχέσης ή μια συγκεκριμένη προβολή της υλικής σύνθεσης και της διαμόρφωσης των οδηγών του συστήματος. Παρακάτω παρουσιάζονται μερικά από τα κοινά planes που μπορείτε να συναντήσετε στο IORegistryExplorer:

  1. IOService Plane: Αυτό είναι το πιο γενικό plane, που εμφανίζει τα αντικείμενα υπηρεσίας που αντιπροσωπεύουν οδηγούς και nubs (κανάλια επικοινωνίας μεταξύ των οδηγών). Εμφανίζει τις σχέσεις παροχέα-πελάτη μεταξύ αυτών των αντικειμένων.

  2. IODeviceTree Plane: Αυτό το plane αναπαριστά τις φυσικές συνδέσεις μεταξύ συσκευών καθώς είναι συνδεδεμένες στο σύστημα. Χρησιμοποιείται συχνά για να οπτικοποιήσει την ιεραρχία των συσκευών που συνδέονται μέσω διαύλων όπως USB ή PCI.

  3. IOPower Plane: Εμφανίζει αντικείμενα και τις σχέσεις τους σε σχέση με τη διαχείριση ισχύος. Μπορεί να εμφανίσει ποια αντικείμενα επηρεάζουν την κατάσταση ισχύος άλλων, χρήσιμο για την αντιμετώπιση προβλημάτων που σχετίζονται με την ισχύ.

  4. IOUSB Plane: Εστιάζει ειδικά σε συσκευές USB και τις σχέσεις τους, εμφανίζοντας την ιεραρχία των USB hubs και των συνδεδεμένων συσκευών.

  5. IOAudio Plane: Αυτό το plane χρησιμοποιείται για την αναπαράσταση συσκευών ήχου και των σχέσεών τους εντός του συστήματος.

  6. ...

Παράδειγμα Κώδικα Επικοινωνίας Οδηγού

Ο παρακάτω κώδικας συνδέεται με την υπηρεσία IOKit "YourServiceNameHere" και καλεί τη συνάρτηση μέσα στον επιλογέα 0. Για να το κάνετε:

  • πρώτα καλεί την IOServiceMatching και την IOServiceGetMatchingServices για να λάβει την υπηρεσία.

  • Στη συνέχεια, εγκαθιστά μια σύνδεση καλώντας την IOServiceOpen.

  • Και τέλος καλεί μια συνάρτηση με την IOConnectCallScalarMethod δηλώνοντας τον επιλογέα 0 (ο επιλογέας είναι ο αριθμός που έχει ανατεθεί στη συνάρτηση που θέλετε να καλέσετε).

#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;
}

Υπάρχουν άλλες λειτουργίες που μπορούν να χρησιμοποιηθούν για να καλέσουν τις λειτουργίες του IOKit εκτός από τη IOConnectCallScalarMethod όπως η IOConnectCallMethod, IOConnectCallStructMethod...

Ανάκτηση του σημείου εισόδου του προγράμματος οδήγησης (driver entrypoint)

Μπορείτε να αποκτήσετε αυτές, για παράδειγμα, από μια εικόνα firmware (ipsw). Στη συνέχεια, φορτώστε την στον αγαπημένο σας αποκωδικοποιητή.

Μπορείτε να ξεκινήσετε την αποκωδικοποίηση της συνάρτησης externalMethod καθώς αυτή είναι η συνάρτηση του προγράμματος οδήγησης που θα λαμβάνει την κλήση και θα καλεί τη σωστή συνάρτηση:

Αυτή η αποκωδικοποίηση της κλήσης σημαίνει:

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

Παρατηρήστε ότι στον προηγούμενο ορισμό λείπει η παράμετρος self, ο σωστός ορισμός θα ήταν:

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

Πραγματικά, μπορείτε να βρείτε τον πραγματικό ορισμό στο 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)

Με αυτές τις πληροφορίες μπορείτε να ξαναγράψετε το Ctrl+Right -> Επεξεργασία υπογραφής συνάρτησης και να ορίσετε τους γνωστούς τύπους:

Ο νέος αποκωδικοποιημένος κώδικας θα φαίνεται όπως παρακάτω:

Για το επόμενο βήμα, πρέπει να έχουμε ορίσει τη δομή IOExternalMethodDispatch2022. Είναι ανοικτού κώδικα στο https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/iokit/IOKit/IOUserClient.h#L168-L176, μπορείτε να την ορίσετε:

Τώρα, ακολουθώντας το (IOExternalMethodDispatch2022 *)&sIOExternalMethodArray μπορείτε να δείτε πολλά δεδομένα:

Αλλάξτε τον τύπο δεδομένων σε IOExternalMethodDispatch2022:

μετά την αλλαγή:

Και τώρα μπορούμε να δημιουργήσουμε έναν πίνακα με 7 στοιχεία:

Αφού δημιουργηθεί ο πίνακας, μπορείτε να δείτε όλες τις εξαγόμενες συναρτήσεις:

Αν θυμάστε, για να καλέσετε μια εξαγόμενη συνάρτηση από τον χώρο χρήστη, δεν χρειάζεται να καλέσετε το όνομα της συνάρτησης, αλλά τον αριθμό επιλογής. Εδώ μπορείτε να δείτε ότι ο αριθμός επιλογής 0 είναι η συνάρτηση initializeDecoder, ο αριθμός επιλογής 1 είναι η startDecoder, ο αριθμός επιλογής 2 είναι η initializeEncoder...

Μάθετε το hacking του AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

Last updated