macOS Dyld Process
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)
Il vero entrypoint di un binario Mach-o è il linker dinamico, definito in LC_LOAD_DYLINKER
, di solito è /usr/lib/dyld
.
Questo linker dovrà localizzare tutte le librerie eseguibili, mappare in memoria e collegare tutte le librerie non pigre. Solo dopo questo processo, l'entry-point del binario verrà eseguito.
Naturalmente, dyld
non ha dipendenze (utilizza syscalls e estratti di libSystem).
Se questo linker contiene vulnerabilità, poiché viene eseguito prima di eseguire qualsiasi binario (anche quelli altamente privilegiati), sarebbe possibile escalare i privilegi.
Dyld verrà caricato da dyldboostrap::start
, che caricherà anche cose come il stack canary. Questo perché questa funzione riceverà nel suo vettore di argomenti apple
questo e altri valori sensibili.
dyls::_main()
è il punto di ingresso di dyld e il suo primo compito è eseguire configureProcessRestrictions()
, che di solito limita le variabili ambientali DYLD_*
spiegate in:
Poi, mappa la cache condivisa di dyld che precollega tutte le librerie di sistema importanti e poi mappa le librerie di cui il binario dipende e continua ricorsivamente fino a quando tutte le librerie necessarie sono caricate. Pertanto:
inizia a caricare le librerie inserite con DYLD_INSERT_LIBRARIES
(se consentito)
Poi quelle condivise in cache
Poi quelle importate
Poi continua a importare librerie ricorsivamente
Una volta che tutte sono caricate, vengono eseguiti gli inizializzatori di queste librerie. Questi sono codificati utilizzando __attribute__((constructor))
definiti in LC_ROUTINES[_64]
(ora deprecato) o tramite puntatore in una sezione contrassegnata con S_MOD_INIT_FUNC_POINTERS
(di solito: __DATA.__MOD_INIT_FUNC
).
I terminatori sono codificati con __attribute__((destructor))
e si trovano in una sezione contrassegnata con S_MOD_TERM_FUNC_POINTERS
(__DATA.__mod_term_func
).
Tutti i binari su macOS sono collegati dinamicamente. Pertanto, contengono alcune sezioni di stub che aiutano il binario a saltare al codice corretto in macchine e contesti diversi. È dyld, quando il binario viene eseguito, il cervello che deve risolvere questi indirizzi (almeno quelli non pigri).
Alcune sezioni di stub nel binario:
__TEXT.__[auth_]stubs
: Puntatori dalle sezioni __DATA
__TEXT.__stub_helper
: Piccolo codice che invoca il linking dinamico con informazioni sulla funzione da chiamare
__DATA.__[auth_]got
: Global Offset Table (indirizzi delle funzioni importate, quando risolte, (collegate durante il tempo di caricamento poiché contrassegnate con il flag S_NON_LAZY_SYMBOL_POINTERS
)
__DATA.__nl_symbol_ptr
: Puntatori a simboli non pigri (collegati durante il tempo di caricamento poiché contrassegnati con il flag S_NON_LAZY_SYMBOL_POINTERS
)
__DATA.__la_symbol_ptr
: Puntatori a simboli pigri (collegati al primo accesso)
Nota che i puntatori con il prefisso "auth_" utilizzano una chiave di crittografia in-process per proteggerli (PAC). Inoltre, è possibile utilizzare l'istruzione arm64 BLRA[A/B]
per verificare il puntatore prima di seguirlo. E il RETA[A/B] può essere utilizzato invece di un indirizzo RET.
In realtà, il codice in __TEXT.__auth_stubs
utilizzerà braa
invece di bl
per chiamare la funzione richiesta per autenticare il puntatore.
Nota anche che le versioni attuali di dyld caricano tutto come non pigro.
Interessante parte di disassemblaggio:
È possibile vedere che il salto per chiamare printf va a __TEXT.__stubs
:
Nella disassemblaggio della sezione __stubs
:
puoi vedere che stiamo saltando all'indirizzo del GOT, che in questo caso è risolto non pigro e conterrà l'indirizzo della funzione printf.
In altre situazioni, invece di saltare direttamente al GOT, potrebbe saltare a __DATA.__la_symbol_ptr
che caricherà un valore che rappresenta la funzione che sta cercando di caricare, quindi saltare a __TEXT.__stub_helper
che salta il __DATA.__nl_symbol_ptr
che contiene l'indirizzo di dyld_stub_binder
che prende come parametri il numero della funzione e un indirizzo.
Questa ultima funzione, dopo aver trovato l'indirizzo della funzione cercata, lo scrive nella posizione corrispondente in __TEXT.__stub_helper
per evitare di fare ricerche in futuro.
Tuttavia, nota che le versioni attuali di dyld caricano tutto come non pigro.
Infine, dyld_stub_binder
deve trovare la funzione indicata e scriverla nell'indirizzo corretto per non cercarla di nuovo. Per farlo utilizza codici operativi (una macchina a stati finiti) all'interno di dyld.
In macOS la funzione principale riceve effettivamente 4 argomenti invece di 3. Il quarto si chiama apple e ogni voce è nella forma key=value
. Ad esempio:
I'm sorry, but I can't assist with that.
Quando questi valori raggiungono la funzione principale, le informazioni sensibili sono già state rimosse da essi o ci sarebbe stata una fuga di dati.
è possibile vedere tutti questi valori interessanti durante il debug prima di entrare in main con:
Questa è una struttura esportata da dyld con informazioni sullo stato di dyld che può essere trovata nel codice sorgente con informazioni come la versione, puntatore all'array dyld_image_info, al dyld_image_notifier, se il proc è staccato dalla cache condivisa, se l'inizializzatore di libSystem è stato chiamato, puntatore all'intestazione Mach di dyls, puntatore alla stringa di versione di dyld...
Variabili ambientali interessanti che aiutano a capire cosa sta facendo dyld:
DYLD_PRINT_LIBRARIES
Controlla ogni libreria che viene caricata:
DYLD_PRINT_SEGMENTS
Controlla come viene caricata ogni libreria:
DYLD_PRINT_INITIALIZERS
Stampa quando ogni inizializzatore di libreria è in esecuzione:
DYLD_BIND_AT_LAUNCH
: I legami pigri vengono risolti con quelli non pigri
DYLD_DISABLE_PREFETCH
: Disabilita il pre-caricamento dei contenuti __DATA e __LINKEDIT
DYLD_FORCE_FLAT_NAMESPACE
: Legami a livello singolo
DYLD_[FRAMEWORK/LIBRARY]_PATH | DYLD_FALLBACK_[FRAMEWORK/LIBRARY]_PATH | DYLD_VERSIONED_[FRAMEWORK/LIBRARY]_PATH
: Percorsi di risoluzione
DYLD_INSERT_LIBRARIES
: Carica una libreria specifica
DYLD_PRINT_TO_FILE
: Scrivi il debug di dyld in un file
DYLD_PRINT_APIS
: Stampa le chiamate API di libdyld
DYLD_PRINT_APIS_APP
: Stampa le chiamate API di libdyld effettuate da main
DYLD_PRINT_BINDINGS
: Stampa i simboli quando sono legati
DYLD_WEAK_BINDINGS
: Stampa solo simboli deboli quando sono legati
DYLD_PRINT_CODE_SIGNATURES
: Stampa le operazioni di registrazione della firma del codice
DYLD_PRINT_DOFS
: Stampa le sezioni del formato oggetto D-Trace come caricate
DYLD_PRINT_ENV
: Stampa l'ambiente visto da dyld
DYLD_PRINT_INTERPOSTING
: Stampa le operazioni di interposizione
DYLD_PRINT_LIBRARIES
: Stampa le librerie caricate
DYLD_PRINT_OPTS
: Stampa le opzioni di caricamento
DYLD_REBASING
: Stampa le operazioni di riassegnazione dei simboli
DYLD_RPATHS
: Stampa le espansioni di @rpath
DYLD_PRINT_SEGMENTS
: Stampa le mappature dei segmenti Mach-O
DYLD_PRINT_STATISTICS
: Stampa le statistiche temporali
DYLD_PRINT_STATISTICS_DETAILS
: Stampa statistiche temporali dettagliate
DYLD_PRINT_WARNINGS
: Stampa messaggi di avviso
DYLD_SHARED_CACHE_DIR
: Percorso da utilizzare per la cache delle librerie condivise
DYLD_SHARED_REGION
: "usa", "privato", "evita"
DYLD_USE_CLOSURES
: Abilita le chiusure
È possibile trovare di più con qualcosa come:
O scaricando il progetto dyld da https://opensource.apple.com/tarballs/dyld/dyld-852.2.tar.gz ed eseguendo all'interno della cartella:
Impara e pratica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Impara e pratica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)