macOS Universal binaries & Mach-O Format
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Τα δυαδικά αρχεία Mac OS συνήθως είναι συμπιεσμένα ως universal binaries. Ένα universal binary μπορεί να υποστηρίζει πολλαπλές αρχιτεκτονικές στο ίδιο αρχείο.
Αυτά τα δυαδικά αρχεία ακολουθούν τη δομή Mach-O που βασικά αποτελείται από:
Header
Load Commands
Data
Αναζητήστε το αρχείο με: mdfind fat.h | grep -i mach-o | grep -E "fat.h$"
Η κεφαλίδα έχει τα μαγικά bytes ακολουθούμενα από τον αριθμό των archs που περιέχει το αρχείο (nfat_arch
) και κάθε αρχιτεκτονική θα έχει μια δομή fat_arch
.
Ελέγξτε το με:
ή χρησιμοποιώντας το εργαλείο Mach-O View:
Όπως μπορεί να σκέφτεστε, συνήθως ένα universal binary που έχει συμπιεστεί για 2 αρχιτεκτονικές διπλασιάζει το μέγεθος ενός που έχει συμπιεστεί μόνο για 1 αρχιτεκτονική.
Η κεφαλίδα περιέχει βασικές πληροφορίες σχετικά με το αρχείο, όπως μαγικά bytes για να το αναγνωρίσει ως αρχείο Mach-O και πληροφορίες σχετικά με την αρχιτεκτονική στόχο. Μπορείτε να το βρείτε σε: mdfind loader.h | grep -i mach-o | grep -E "loader.h$"
There are different file types, you can find them defined in the source code for example here. The most important ones are:
MH_OBJECT
: Μεταθέσιμο αρχείο αντικειμένου (ενδιάμεσα προϊόντα της μεταγλώττισης, όχι εκτελέσιμα ακόμα).
MH_EXECUTE
: Εκτελέσιμα αρχεία.
MH_FVMLIB
: Στατικό αρχείο βιβλιοθήκης VM.
MH_CORE
: Εκφορτώσεις κώδικα
MH_PRELOAD
: Προφορτωμένο εκτελέσιμο αρχείο (δεν υποστηρίζεται πλέον στο XNU)
MH_DYLIB
: Δυναμικές βιβλιοθήκες
MH_DYLINKER
: Δυναμικός συνδέτης
MH_BUNDLE
: "Αρχεία πρόσθετου". Δημιουργούνται χρησιμοποιώντας -bundle στο gcc και φορτώνονται ρητά από το NSBundle
ή το dlopen
.
MH_DYSM
: Συνοδευτικό αρχείο .dSym
(αρχείο με σύμβολα για αποσφαλμάτωση).
MH_KEXT_BUNDLE
: Επεκτάσεις πυρήνα.
Or using Mach-O View:
Ο πηγαίος κώδικας ορίζει επίσης αρκετές σημαίες χρήσιμες για τη φόρτωση βιβλιοθηκών:
MH_NOUNDEFS
: Χωρίς μη καθορισμένες αναφορές (πλήρως συνδεδεμένο)
MH_DYLDLINK
: Σύνδεση Dyld
MH_PREBOUND
: Δυναμικές αναφορές προδεσμευμένες.
MH_SPLIT_SEGS
: Το αρχείο χωρίζει τα r/o και r/w τμήματα.
MH_WEAK_DEFINES
: Το δυαδικό έχει αδύνατα καθορισμένα σύμβολα
MH_BINDS_TO_WEAK
: Το δυαδικό χρησιμοποιεί αδύνατα σύμβολα
MH_ALLOW_STACK_EXECUTION
: Κάνει τη στοίβα εκτελέσιμη
MH_NO_REEXPORTED_DYLIBS
: Η βιβλιοθήκη δεν έχει εντολές LC_REEXPORT
MH_PIE
: Θέση Ανεξάρτητου Εκτελέσιμου
MH_HAS_TLV_DESCRIPTORS
: Υπάρχει τμήμα με τοπικές μεταβλητές νήματος
MH_NO_HEAP_EXECUTION
: Καμία εκτέλεση για σελίδες σωρού/δεδομένων
MH_HAS_OBJC
: Το δυαδικό έχει τμήματα oBject-C
MH_SIM_SUPPORT
: Υποστήριξη προσομοιωτή
MH_DYLIB_IN_CACHE
: Χρησιμοποιείται σε dylibs/frameworks στην κοινή βιβλιοθήκη cache.
Η διάταξη του αρχείου στη μνήμη καθορίζεται εδώ, περιγράφοντας την τοποθεσία του πίνακα συμβόλων, το πλαίσιο του κύριου νήματος κατά την εκκίνηση εκτέλεσης και τις απαιτούμενες κοινές βιβλιοθήκες. Δίνονται οδηγίες στον δυναμικό φορτωτή (dyld) για τη διαδικασία φόρτωσης του δυαδικού στη μνήμη.
Χρησιμοποιεί τη δομή load_command, που ορίζεται στο αναφερόμενο loader.h
:
There are about 50 διαφορετικούς τύπους εντολών φόρτωσης που το σύστημα χειρίζεται διαφορετικά. Οι πιο κοινές είναι: LC_SEGMENT_64
, LC_LOAD_DYLINKER
, LC_MAIN
, LC_LOAD_DYLIB
, και LC_CODE_SIGNATURE
.
Βασικά, αυτός ο τύπος Load Command καθορίζει πώς να φορτώσει το __TEXT (εκτελέσιμο κώδικα) και το __DATA (δεδομένα για τη διαδικασία) τμήματα σύμφωνα με τους offsets που υποδεικνύονται στην ενότητα Δεδομένων όταν εκτελείται το δυαδικό.
Αυτές οι εντολές καθορίζουν τμήματα που είναι χαρτογραφημένα στο εικονικό χώρο μνήμης μιας διαδικασίας όταν εκτελείται.
Υπάρχουν διαφορετικοί τύποι τμημάτων, όπως το __TEXT τμήμα, το οποίο περιέχει τον εκτελέσιμο κώδικα ενός προγράμματος, και το __DATA τμήμα, το οποίο περιέχει δεδομένα που χρησιμοποιούνται από τη διαδικασία. Αυτά τα τμήματα βρίσκονται στην ενότητα δεδομένων του αρχείου Mach-O.
Κάθε τμήμα μπορεί να διαιρεθεί περαιτέρω σε πολλαπλές ενότητες. Η δομή εντολής φόρτωσης περιέχει πληροφορίες σχετικά με αυτές τις ενότητες εντός του αντίστοιχου τμήματος.
Στην κεφαλίδα πρώτα βρίσκετε την κεφαλίδα τμήματος:
Παράδειγμα κεφαλίδας τμήματος:
Αυτή η κεφαλίδα καθορίζει τον αριθμό των ενοτήτων των οποίων οι κεφαλίδες εμφανίζονται μετά από αυτήν:
Example of section header:
Αν προσθέσετε την εκτροπή τμήματος (0x37DC) + την εκτροπή όπου ξεκινά η αρχιτεκτονική, σε αυτή την περίπτωση 0x18000
--> 0x37DC + 0x18000 = 0x1B7DC
Είναι επίσης δυνατό να αποκτήσετε πληροφορίες κεφαλίδας από τη γραμμή εντολών με:
Common segments loaded by this cmd:
__PAGEZERO
: Δίνει εντολή στον πυρήνα να χαρτογραφήσει τη διεύθυνση μηδέν έτσι ώστε να μην μπορεί να διαβαστεί, να γραφτεί ή να εκτελεστεί. Οι μεταβλητές maxprot και minprot στη δομή είναι ρυθμισμένες σε μηδέν για να υποδείξουν ότι δεν υπάρχουν δικαιώματα ανάγνωσης-γραφής-εκτέλεσης σε αυτή τη σελίδα.
Αυτή η κατανομή είναι σημαντική για να μειώσει τις ευπάθειες αποσύνθεσης δείκτη NULL. Αυτό συμβαίνει επειδή το XNU επιβάλλει μια σκληρή σελίδα μηδέν που διασφαλίζει ότι η πρώτη σελίδα (μόνο η πρώτη) της μνήμης είναι μη προσβάσιμη (εκτός από το i386). Ένα δυαδικό αρχείο θα μπορούσε να εκπληρώσει αυτές τις απαιτήσεις δημιουργώντας μια μικρή __PAGEZERO (χρησιμοποιώντας το -pagezero_size
) για να καλύψει τα πρώτα 4k και να έχει την υπόλοιπη μνήμη 32bit προσβάσιμη τόσο σε λειτουργία χρήστη όσο και σε λειτουργία πυρήνα.
__TEXT
: Περιέχει εκτελέσιμο κώδικα με δικαιώματα ανάγνωσης και εκτέλεσης (όχι γραφής). Κοινές ενότητες αυτού του τμήματος:
__text
: Συμπιεσμένος δυαδικός κώδικας
__const
: Σταθερά δεδομένα (μόνο ανάγνωση)
__[c/u/os_log]string
: Σταθερές συμβολοσειρές C, Unicode ή os logs
__stubs
και __stubs_helper
: Συμμετέχουν κατά τη διαδικασία φόρτωσης δυναμικής βιβλιοθήκης
__unwind_info
: Δεδομένα αποσυμπίεσης στοίβας.
Σημειώστε ότι όλο αυτό το περιεχόμενο είναι υπογεγραμμένο αλλά και επισημασμένο ως εκτελέσιμο (δημιουργώντας περισσότερες επιλογές για εκμετάλλευση τμημάτων που δεν χρειάζονται απαραίτητα αυτό το προνόμιο, όπως οι αφιερωμένες ενότητες συμβολοσειρών).
__DATA
: Περιέχει δεδομένα που είναι αναγνώσιμα και γραφόμενα (όχι εκτελέσιμα).
__got:
Παγκόσμιος Πίνακας Μεταθέσεων
__nl_symbol_ptr
: Μη τεμπέλης (δεσμευμένος κατά τη φόρτωση) δείκτης συμβόλου
__la_symbol_ptr
: Τεμπέλης (δεσμευμένος κατά τη χρήση) δείκτης συμβόλου
__const
: Θα έπρεπε να είναι δεδομένα μόνο ανάγνωσης (όχι πραγματικά)
__cfstring
: Συμβολοσειρές CoreFoundation
__data
: Παγκόσμιες μεταβλητές (που έχουν αρχικοποιηθεί)
__bss
: Στατικές μεταβλητές (που δεν έχουν αρχικοποιηθεί)
__objc_*
(__objc_classlist, __objc_protolist, κ.λπ.): Πληροφορίες που χρησιμοποιούνται από το Objective-C runtime
__DATA_CONST
: __DATA.__const δεν είναι εγγυημένο ότι είναι σταθερό (δικαιώματα γραφής), ούτε είναι άλλοι δείκτες και ο GOT. Αυτή η ενότητα καθιστά το __const
, κάποιους αρχικοποιητές και τον πίνακα GOT (μόλις επιλυθεί) μόνο ανάγνωσης χρησιμοποιώντας το mprotect
.
__LINKEDIT
: Περιέχει πληροφορίες για τον συνδέτη (dyld) όπως, συμβόλων, συμβολοσειρών και καταχωρήσεων πίνακα μεταθέσεων. Είναι ένας γενικός κάδος για περιεχόμενα που δεν βρίσκονται ούτε στο __TEXT
ούτε στο __DATA
και το περιεχόμενό του περιγράφεται σε άλλες εντολές φόρτωσης.
πληροφορίες dyld: Επαναφορά, Μη τεμπέλης/τεμπέλης/ασθενής κωδικοί δέσμευσης και πληροφορίες εξαγωγής
Λειτουργίες εκκίνησης: Πίνακας διευθύνσεων εκκίνησης λειτουργιών
Δεδομένα στον Κώδικα: Νησίδες δεδομένων στο __text
Πίνακας Συμβόλων: Σύμβολα στο δυαδικό
Πίνακας Έμμεσων Συμβόλων: Δείκτες/συμβολα στήριξης
Πίνακας Συμβολοσειρών
Υπογραφή Κώδικα
__OBJC
: Περιέχει πληροφορίες που χρησιμοποιούνται από το Objective-C runtime. Αν και αυτές οι πληροφορίες μπορεί επίσης να βρεθούν στο τμήμα __DATA, εντός διαφόρων τμημάτων __objc_*.
__RESTRICT
: Ένα τμήμα χωρίς περιεχόμενο με μια μόνο ενότητα που ονομάζεται __restrict
(επίσης κενή) που διασφαλίζει ότι κατά την εκτέλεση του δυαδικού, θα αγνοήσει τις μεταβλητές περιβάλλοντος DYLD.
Όπως ήταν δυνατόν να δούμε στον κώδικα, τα τμήματα υποστηρίζουν επίσης σημαίες (αν και δεν χρησιμοποιούνται πολύ):
SG_HIGHVM
: Μόνο πυρήνας (δεν χρησιμοποιείται)
SG_FVMLIB
: Δεν χρησιμοποιείται
SG_NORELOC
: Το τμήμα δεν έχει μεταθέσεις
SG_PROTECTED_VERSION_1
: Κρυπτογράφηση. Χρησιμοποιείται για παράδειγμα από τον Finder για να κρυπτογραφήσει το τμήμα κειμένου __TEXT
.
LC_UNIXTHREAD/LC_MAIN
LC_MAIN
περιέχει το σημείο εισόδου στην ιδιότητα entryoff. Κατά τη διάρκεια της φόρτωσης, dyld απλά προσθέτει αυτή την τιμή στη (στη μνήμη) βάση του δυαδικού, στη συνέχεια πηδά σε αυτή την εντολή για να ξεκινήσει την εκτέλεση του κώδικα του δυαδικού.
LC_UNIXTHREAD
περιέχει τις τιμές που πρέπει να έχει ο καταχωρητής κατά την εκκίνηση του κύριου νήματος. Αυτό έχει ήδη αποσυρθεί αλλά dyld
εξακολουθεί να το χρησιμοποιεί. Είναι δυνατόν να δούμε τις τιμές των καταχωρητών που ορίζονται από αυτό με:
LC_CODE_SIGNATURE
Περιέχει πληροφορίες σχετικά με την υπογραφή κώδικα του αρχείου Macho-O. Περιέχει μόνο μια μετατόπιση που δείχνει στο blob υπογραφής. Αυτό είναι συνήθως στο τέλος του αρχείου. Ωστόσο, μπορείτε να βρείτε κάποιες πληροφορίες σχετικά με αυτή την ενότητα σε αυτή την ανάρτηση στο blog και σε αυτό το gist.
LC_ENCRYPTION_INFO[_64]
Υποστήριξη για κρυπτογράφηση δυαδικών αρχείων. Ωστόσο, φυσικά, αν ένας επιτιθέμενος καταφέρει να παραβιάσει τη διαδικασία, θα είναι σε θέση να εκφορτώσει τη μνήμη χωρίς κρυπτογράφηση.
LC_LOAD_DYLINKER
Περιέχει την διαδρομή προς το εκτελέσιμο του δυναμικού συνδέτη που χαρτογραφεί τις κοινές βιβλιοθήκες στον χώρο διευθύνσεων της διαδικασίας. Η τιμή είναι πάντα ρυθμισμένη σε /usr/lib/dyld
. Είναι σημαντικό να σημειωθεί ότι στο macOS, η χαρτογράφηση dylib συμβαίνει σε λειτουργία χρήστη, όχι σε λειτουργία πυρήνα.
LC_IDENT
Απαρχαιωμένο αλλά όταν ρυθμίζεται για να δημιουργεί εκφορτώσεις σε πανικό, δημιουργείται μια πυρήνα Mach-O και η έκδοση του πυρήνα ρυθμίζεται στην εντολή LC_IDENT
.
LC_UUID
Τυχαίο UUID. Είναι χρήσιμο για οτιδήποτε άμεσα αλλά το XNU το αποθηκεύει με τις υπόλοιπες πληροφορίες της διαδικασίας. Μπορεί να χρησιμοποιηθεί σε αναφορές σφαλμάτων.
LC_DYLD_ENVIRONMENT
Επιτρέπει την ένδειξη μεταβλητών περιβάλλοντος στο dyld πριν εκτελεστεί η διαδικασία. Αυτό μπορεί να είναι πολύ επικίνδυνο καθώς μπορεί να επιτρέψει την εκτέλεση αυθαίρετου κώδικα μέσα στη διαδικασία, οπότε αυτή η εντολή φόρτωσης χρησιμοποιείται μόνο σε dyld που έχει κατασκευαστεί με #define SUPPORT_LC_DYLD_ENVIRONMENT
και περιορίζει περαιτέρω την επεξεργασία μόνο σε μεταβλητές της μορφής DYLD_..._PATH
που καθορίζουν διαδρομές φόρτωσης.
LC_LOAD_DYLIB
Αυτή η εντολή φόρτωσης περιγράφει μια δυναμική εξάρτηση βιβλιοθήκης που δίνει οδηγίες στον φορτωτή (dyld) να φορτώσει και να συνδέσει την εν λόγω βιβλιοθήκη. Υπάρχει μια εντολή φόρτωσης LC_LOAD_DYLIB
για κάθε βιβλιοθήκη που απαιτεί το δυαδικό Mach-O.
Αυτή η εντολή φόρτωσης είναι μια δομή τύπου dylib_command
(η οποία περιέχει μια δομή dylib, περιγράφοντας την πραγματική εξαρτώμενη δυναμική βιβλιοθήκη):
Μπορείτε επίσης να αποκτήσετε αυτές τις πληροφορίες από το cli με:
Ορισμένες πιθανές βιβλιοθήκες που σχετίζονται με κακόβουλο λογισμικό είναι:
DiskArbitration: Παρακολούθηση USB drives
AVFoundation: Καταγραφή ήχου και βίντεο
CoreWLAN: Σαρώσεις Wifi.
Ένα Mach-O δυαδικό μπορεί να περιέχει έναν ή περισσότερους κατασκευαστές, οι οποίοι θα εκτελούνται πριν από τη διεύθυνση που καθορίζεται στο LC_MAIN. Οι μετατοπίσεις οποιωνδήποτε κατασκευαστών κρατούνται στην ενότητα __mod_init_func του τμήματος __DATA_CONST.
Στον πυρήνα του αρχείου βρίσκεται η περιοχή δεδομένων, η οποία αποτελείται από αρκετά τμήματα όπως ορίζονται στην περιοχή εντολών φόρτωσης. Μια ποικιλία τμημάτων δεδομένων μπορεί να φιλοξενηθεί μέσα σε κάθε τμήμα, με κάθε τμήμα να περιέχει κώδικα ή δεδομένα συγκεκριμένα για έναν τύπο.
Τα δεδομένα είναι βασικά το μέρος που περιέχει όλες τις πληροφορίες που φορτώνονται από τις εντολές φόρτωσης LC_SEGMENTS_64
Αυτό περιλαμβάνει:
Πίνακας συναρτήσεων: Ο οποίος περιέχει πληροφορίες σχετικά με τις συναρτήσεις του προγράμματος.
Πίνακας συμβόλων: Ο οποίος περιέχει πληροφορίες σχετικά με τη εξωτερική συνάρτηση που χρησιμοποιείται από το δυαδικό
Μπορεί επίσης να περιέχει εσωτερικές συναρτήσεις, ονόματα μεταβλητών καθώς και περισσότερα.
Για να το ελέγξετε, μπορείτε να χρησιμοποιήσετε το εργαλείο Mach-O View:
Ή από τη γραμμή εντολών:
Στο τμήμα __TEXT
(r-x):
__objc_classname
: Ονόματα κλάσεων (αλφαριθμητικά)
__objc_methname
: Ονόματα μεθόδων (αλφαριθμητικά)
__objc_methtype
: Τύποι μεθόδων (αλφαριθμητικά)
Στο τμήμα __DATA
(rw-):
__objc_classlist
: Δείκτες σε όλες τις κλάσεις Objetive-C
__objc_nlclslist
: Δείκτες σε μη-τεμπέλικες κλάσεις Objective-C
__objc_catlist
: Δείκτης σε Κατηγορίες
__objc_nlcatlist
: Δείκτης σε Μη-τεμπέλικες Κατηγορίες
__objc_protolist
: Λίστα πρωτοκόλλων
__objc_const
: Σταθερά δεδομένα
__objc_imageinfo
, __objc_selrefs
, objc__protorefs
...
_swift_typeref
, _swift3_capture
, _swift3_assocty
, _swift3_types, _swift3_proto
, _swift3_fieldmd
, _swift3_builtin
, _swift3_reflstr
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)