macOS Dyld Process
Informazioni di Base
Il vero punto di ingresso di un binario Mach-o è il collegamento dinamico, definito in LC_LOAD_DYLINKER
di solito è /usr/lib/dyld
.
Questo linker dovrà individuare tutte le librerie eseguibili, mapparle in memoria e collegare tutte le librerie non pigre. Solo dopo questo processo, il punto di ingresso del binario verrà eseguito.
Naturalmente, dyld
non ha dipendenze (utilizza chiamate di sistema ed estratti di libSystem).
Se questo linker contiene una qualsiasi vulnerabilità, poiché viene eseguito prima di eseguire qualsiasi binario (anche quelli altamente privilegiati), sarebbe possibile escalare i privilegi.
Flusso
Dyld verrà caricato da dyldboostrap::start
, che caricherà anche cose come il canary dello stack. Questo perché questa funzione riceverà nel suo argomento 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 di ambiente DYLD_*
spiegate in:
Quindi, mappa la cache condivisa di dyld che prelinka tutte le importanti librerie di sistema e quindi 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 della cache condivisa
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 deprecati) 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
).
Stub
Tutti i binari su macOS sono collegati dinamicamente. Pertanto, contengono alcune sezioni stub che aiutano il binario a saltare al codice corretto in diverse macchine e contesti. È dyld quando il binario viene eseguito il cervello che deve risolvere questi indirizzi (almeno quelli non pigri).
Alcune sezioni stub nel binario:
__TEXT.__[auth_]stubs
: Puntatori dalle sezioni__DATA
__TEXT.__stub_helper
: Piccolo codice che invoca il collegamento dinamico con informazioni sulla funzione da chiamare__DATA.__[auth_]got
: Tabella degli offset globali (indirizzi delle funzioni importate, risolti durante il tempo di caricamento poiché è contrassegnata con il flagS_NON_LAZY_SYMBOL_POINTERS
)__DATA.__nl_symbol_ptr
: Puntatori ai simboli non pigri (risolti durante il tempo di caricamento poiché è contrassegnata con il flagS_NON_LAZY_SYMBOL_POINTERS
)__DATA.__la_symbol_ptr
: Puntatori ai simboli pigri (risolti 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 al posto 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.
Trovare simboli pigri
Parte interessante dello smontaggio:
È possibile vedere che il salto per chiamare printf va a __TEXT.__stubs
:
Nell'analisi della sezione __stubs
:
Puoi vedere che stiamo saltando all'indirizzo del GOT, che in questo caso viene risolto in modo non lazy 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 si 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 ricerche future.
Tuttavia notare che le versioni attuali di dyld caricano tutto come non lazy.
Opcodes di Dyld
Infine, dyld_stub_binder
deve trovare la funzione indicata e scriverla nell'indirizzo corretto per non cercarla nuovamente. Per farlo utilizza opcode (una macchina a stati finiti) all'interno di dyld.
Vettore degli argomenti apple[]
In macOS la funzione principale riceve effettivamente 4 argomenti invece di 3. Il quarto è chiamato apple e ogni voce è nella forma chiave=valore
. Ad esempio:
Il Dynamic Linker (dyld) è il componente principale responsabile del caricamento dei file condivisi in macOS. È possibile sfruttare il processo dyld per iniettare librerie malevole in processi legittimi. Una volta iniettata con successo, la libreria malevola può essere utilizzata per eseguire codice dannoso all'interno del contesto del processo legittimo, consentendo così a un attaccante di ottenere privilegi elevati o compromettere il sistema.
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 visualizzare tutti questi valori interessanti durante il debug prima di entrare nella funzione principale con:
dyld_all_image_infos
Si tratta di una struttura esportata da dyld con informazioni sullo stato di dyld che possono essere trovate nel codice sorgente con informazioni come la versione, il puntatore all'array dyld_image_info, al dyld_image_notifier, se il processo è staccato dalla cache condivisa, se l'inizializzatore di libSystem è stato chiamato, il puntatore all'intestazione Mach di dyld, il puntatore alla stringa della versione di dyld...
Variabili d'ambiente dyld
debug dyld
Variabili d'ambiente 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 viene eseguito ciascun inizializzatore della libreria:
Altri
DYLD_BIND_AT_LAUNCH
: I collegamenti ritardati vengono risolti con quelli non ritardatiDYLD_DISABLE_PREFETCH
: Disabilita il prefetching dei contenuti __DATA e __LINKEDITDYLD_FORCE_FLAT_NAMESPACE
: Collegamenti a livello singoloDYLD_[FRAMEWORK/LIBRARY]_PATH | DYLD_FALLBACK_[FRAMEWORK/LIBRARY]_PATH | DYLD_VERSIONED_[FRAMEWORK/LIBRARY]_PATH
: Percorsi di risoluzioneDYLD_INSERT_LIBRARIES
: Carica una libreria specificaDYLD_PRINT_TO_FILE
: Scrive il debug di dyld in un fileDYLD_PRINT_APIS
: Stampa le chiamate API di libdyldDYLD_PRINT_APIS_APP
: Stampa le chiamate API di libdyld effettuate da mainDYLD_PRINT_BINDINGS
: Stampa i simboli quando vengono collegatiDYLD_WEAK_BINDINGS
: Stampa solo i simboli deboli quando vengono collegatiDYLD_PRINT_CODE_SIGNATURES
: Stampa le operazioni di registrazione della firma del codiceDYLD_PRINT_DOFS
: Stampa le sezioni del formato oggetto D-Trace caricateDYLD_PRINT_ENV
: Stampa l'ambiente visto da dyldDYLD_PRINT_INTERPOSTING
: Stampa le operazioni di interposizioneDYLD_PRINT_LIBRARIES
: Stampa le librerie caricateDYLD_PRINT_OPTS
: Stampa le opzioni di caricamentoDYLD_REBASING
: Stampa le operazioni di ricollocazione dei simboliDYLD_RPATHS
: Stampa le espansioni di @rpathDYLD_PRINT_SEGMENTS
: Stampa il mapping dei segmenti Mach-ODYLD_PRINT_STATISTICS
: Stampa le statistiche sui tempiDYLD_PRINT_STATISTICS_DETAILS
: Stampa statistiche dettagliate sui tempiDYLD_PRINT_WARNINGS
: Stampa messaggi di avvisoDYLD_SHARED_CACHE_DIR
: Percorso da utilizzare per la cache delle librerie condiviseDYLD_SHARED_REGION
: "use", "private", "avoid"DYLD_USE_CLOSURES
: Abilita le chiusure
È possibile trovarne di più con qualcosa del genere:
Oppure scaricare il progetto dyld da https://opensource.apple.com/tarballs/dyld/dyld-852.2.tar.gz e eseguire all'interno della cartella:
Riferimenti
Last updated