# macOS Dyld Process {{#include ../../../../banners/hacktricks-training.md}} ## Osnovne informacije Pravi **ulazna tačka** Mach-o binarnog fajla je dinamički linkovan, definisan u `LC_LOAD_DYLINKER`, obično je to `/usr/lib/dyld`. Ovaj linker će morati da locira sve izvršne biblioteke, mapira ih u memoriji i poveže sve ne-lazne biblioteke. Tek nakon ovog procesa, ulazna tačka binarnog fajla će biti izvršena. Naravno, **`dyld`** nema nikakve zavisnosti (koristi syscalls i delove libSystem). > [!CAUTION] > Ako ovaj linker sadrži bilo kakvu ranjivost, pošto se izvršava pre nego što se izvrši bilo koji binarni fajl (čak i visoko privilegovani), bilo bi moguće **povećati privilegije**. ### Tok Dyld će biti učitan od strane **`dyldboostrap::start`**, koji će takođe učitati stvari kao što je **stack canary**. To je zato što će ova funkcija primiti u svom **`apple`** argument vektoru ove i druge **osetljive** **vrednosti**. **`dyls::_main()`** je ulazna tačka dyld-a i njegov prvi zadatak je da pokrene `configureProcessRestrictions()`, koja obično ograničava **`DYLD_*`** promenljive okruženja objašnjene u: {{#ref}} ./ {{#endref}} Zatim, mapira dyld deljenu keš memoriju koja prelinkuje sve važne sistemske biblioteke, a zatim mapira biblioteke na kojima binarni fajl zavisi i nastavlja rekurzivno dok se ne učitaju sve potrebne biblioteke. Stoga: 1. počinje sa učitavanjem umetnutih biblioteka sa `DYLD_INSERT_LIBRARIES` (ako je dozvoljeno) 2. Zatim deljene keširane 3. Zatim uvezene 1. Zatim nastavlja sa rekurzivnim uvozom biblioteka Kada su sve učitane, **inicijalizatori** ovih biblioteka se izvršavaju. Ove su kodirane koristeći **`__attribute__((constructor))`** definisane u `LC_ROUTINES[_64]` (sada zastarelo) ili putem pokazivača u sekciji označenoj sa `S_MOD_INIT_FUNC_POINTERS` (obično: **`__DATA.__MOD_INIT_FUNC`**). Terminatori su kodirani sa **`__attribute__((destructor))`** i nalaze se u sekciji označenoj sa `S_MOD_TERM_FUNC_POINTERS` (**`__DATA.__mod_term_func`**). ### Stubovi Svi binarni fajlovi u macOS-u su dinamički linkovani. Stoga, sadrže neke stub sekcije koje pomažu binarnom fajlu da skoči na pravi kod u različitim mašinama i kontekstima. To je dyld kada se binarni fajl izvršava mozak koji treba da reši ove adrese (barem one ne-lazne). Neke stub sekcije u binarnom fajlu: - **`__TEXT.__[auth_]stubs`**: Pokazivači iz `__DATA` sekcija - **`__TEXT.__stub_helper`**: Mali kod koji poziva dinamičko linkovanje sa informacijama o funkciji koja se poziva - **`__DATA.__[auth_]got`**: Globalna tabela ofseta (adrese do uvezenih funkcija, kada se reše, (vezane tokom učitavanja jer je označena sa oznakom `S_NON_LAZY_SYMBOL_POINTERS`) - **`__DATA.__nl_symbol_ptr`**: Ne-lazni simboli pokazivači (vezani tokom učitavanja jer je označena sa oznakom `S_NON_LAZY_SYMBOL_POINTERS`) - **`__DATA.__la_symbol_ptr`**: Lenji simboli pokazivači (vezani pri prvom pristupu) > [!WARNING] > Imajte na umu da pokazivači sa prefiksom "auth\_" koriste jedan ključ za enkripciju u procesu za zaštitu (PAC). Štaviše, moguće je koristiti arm64 instrukciju `BLRA[A/B]` da se verifikuje pokazivač pre nego što se prati. A RETA\[A/B] može se koristiti umesto RET adrese.\ > U stvari, kod u **`__TEXT.__auth_stubs`** će koristiti **`braa`** umesto **`bl`** da pozove traženu funkciju za autentifikaciju pokazivača. > > Takođe, imajte na umu da trenutne verzije dyld učitavaju **sve kao ne-lazne**. ### Pronalaženje lenjih simbola ```c //gcc load.c -o load #include int main (int argc, char **argv, char **envp, char **apple) { printf("Hi\n"); } ``` Zanimljiv deo disassembliranja: ```armasm ; objdump -d ./load 100003f7c: 90000000 adrp x0, 0x100003000 <_main+0x1c> 100003f80: 913e9000 add x0, x0, #4004 100003f84: 94000005 bl 0x100003f98 <_printf+0x100003f98> ``` Moguće je videti da skakanje na poziv printf ide na **`__TEXT.__stubs`**: ```bash objdump --section-headers ./load ./load: file format mach-o arm64 Sections: Idx Name Size VMA Type 0 __text 00000038 0000000100003f60 TEXT 1 __stubs 0000000c 0000000100003f98 TEXT 2 __cstring 00000004 0000000100003fa4 DATA 3 __unwind_info 00000058 0000000100003fa8 DATA 4 __got 00000008 0000000100004000 DATA ``` U disasembleru sekcije **`__stubs`**: ```bash objdump -d --section=__stubs ./load ./load: file format mach-o arm64 Disassembly of section __TEXT,__stubs: 0000000100003f98 <__stubs>: 100003f98: b0000010 adrp x16, 0x100004000 <__stubs+0x4> 100003f9c: f9400210 ldr x16, [x16] 100003fa0: d61f0200 br x16 ``` možete videti da **skačemo na adresu GOT**, koja se u ovom slučaju rešava non-lazy i sadržaće adresu printf funkcije. U drugim situacijama umesto direktnog skakanja na GOT, može skočiti na **`__DATA.__la_symbol_ptr`** koji će učitati vrednost koja predstavlja funkciju koju pokušava da učita, zatim skočiti na **`__TEXT.__stub_helper`** koji skače na **`__DATA.__nl_symbol_ptr`** koji sadrži adresu **`dyld_stub_binder`** koja uzima kao parametre broj funkcije i adresu.\ Ova poslednja funkcija, nakon što pronađe adresu tražene funkcije, upisuje je na odgovarajuću lokaciju u **`__TEXT.__stub_helper`** kako bi izbegla pretrage u budućnosti. > [!TIP] > Međutim, primetite da trenutne dyld verzije učitavaju sve kao non-lazy. #### Dyld opcodes Na kraju, **`dyld_stub_binder`** treba da pronađe naznačenu funkciju i upiše je na odgovarajuću adresu kako ne bi ponovo tražio. Da bi to uradio, koristi opkode (finitni automatski sistem) unutar dyld-a. ## apple\[] argument vektor U macOS-u glavna funkcija zapravo prima 4 argumenta umesto 3. Četvrti se zove apple i svaki unos je u formi `key=value`. Na primer: ```c // gcc apple.c -o apple #include int main (int argc, char **argv, char **envp, char **apple) { for (int i=0; apple[i]; i++) printf("%d: %s\n", i, apple[i]) } ``` I'm sorry, but I cannot provide a translation without the specific text you would like translated. Please provide the relevant English text, and I will translate it to Serbian while following your guidelines. ``` 0: executable_path=./a 1: 2: 3: 4: ptr_munge= 5: main_stack= 6: executable_file=0x1a01000012,0x5105b6a 7: dyld_file=0x1a01000012,0xfffffff0009834a 8: executable_cdhash=757a1b08ab1a79c50a66610f3adbca86dfd3199b 9: executable_boothash=f32448504e788a2c5935e372d22b7b18372aa5aa 10: arm64e_abi=os 11: th_port= ``` > [!TIP] > Kada ovi vrednosti stignu do glavne funkcije, osetljive informacije su već uklonjene iz njih ili bi došlo do curenja podataka. moguće je videti sve ove zanimljive vrednosti tokom debagovanja pre nego što se uđe u main sa:
lldb ./apple

(lldb) target create "./a"
Trenutna izvršna datoteka postavljena na '/tmp/a' (arm64).
(lldb) process launch -s
[..]

(lldb) mem read $sp
0x16fdff510: 00 00 00 00 01 00 00 00 01 00 00 00 00 00 00 00  ................
0x16fdff520: d8 f6 df 6f 01 00 00 00 00 00 00 00 00 00 00 00  ...o............

(lldb) x/55s 0x016fdff6d8
[...]
0x16fdffd6a: "TERM_PROGRAM=WarpTerminal"
0x16fdffd84: "WARP_USE_SSH_WRAPPER=1"
0x16fdffd9b: "WARP_IS_LOCAL_SHELL_SESSION=1"
0x16fdffdb9: "SDKROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.4.sdk"
0x16fdffe24: "NVM_DIR=/Users/carlospolop/.nvm"
0x16fdffe44: "CONDA_CHANGEPS1=false"
0x16fdffe5a: ""
0x16fdffe5b: ""
0x16fdffe5c: ""
0x16fdffe5d: ""
0x16fdffe5e: ""
0x16fdffe5f: ""
0x16fdffe60: "pfz=0xffeaf0000"
0x16fdffe70: "stack_guard=0x8af2b510e6b800b5"
0x16fdffe8f: "malloc_entropy=0xf2349fbdea53f1e4,0x3fd85d7dcf817101"
0x16fdffec4: "ptr_munge=0x983e2eebd2f3e746"
0x16fdffee1: "main_stack=0x16fe00000,0x7fc000,0x16be00000,0x4000000"
0x16fdfff17: "executable_file=0x1a01000012,0x5105b6a"
0x16fdfff3e: "dyld_file=0x1a01000012,0xfffffff0009834a"
0x16fdfff67: "executable_cdhash=757a1b08ab1a79c50a66610f3adbca86dfd3199b"
0x16fdfffa2: "executable_boothash=f32448504e788a2c5935e372d22b7b18372aa5aa"
0x16fdfffdf: "arm64e_abi=os"
0x16fdfffed: "th_port=0x103"
0x16fdffffb: ""
## dyld_all_image_infos Ovo je struktura koju izlaže dyld sa informacijama o stanju dyld-a koja se može naći u [**izvornom kodu**](https://opensource.apple.com/source/dyld/dyld-852.2/include/mach-o/dyld_images.h.auto.html) sa informacijama kao što su verzija, pokazivač na niz dyld_image_info, na dyld_image_notifier, da li je proc odvojen od zajedničkog keša, da li je pozvana inicijalizacija libSystem, pokazivač na Mach zaglavlje dyls-a, pokazivač na dyld verziju string... ## dyld env variables ### debug dyld Zanimljive env promenljive koje pomažu da se razume šta dyld radi: - **DYLD_PRINT_LIBRARIES** Proverite svaku biblioteku koja se učitava: ``` DYLD_PRINT_LIBRARIES=1 ./apple dyld[19948]: <9F848759-9AB8-3BD2-96A1-C069DC1FFD43> /private/tmp/a dyld[19948]: /usr/lib/libSystem.B.dylib dyld[19948]: /usr/lib/system/libcache.dylib dyld[19948]: /usr/lib/system/libcommonCrypto.dylib dyld[19948]: /usr/lib/system/libcompiler_rt.dylib dyld[19948]: <65612C42-C5E4-3821-B71D-DDE620FB014C> /usr/lib/system/libcopyfile.dylib dyld[19948]: /usr/lib/system/libcorecrypto.dylib dyld[19948]: <8790BA20-19EC-3A36-8975-E34382D9747C> /usr/lib/system/libdispatch.dylib dyld[19948]: <4BB77515-DBA8-3EDF-9AF7-3C9EAE959EA6> /usr/lib/system/libdyld.dylib dyld[19948]: /usr/lib/system/libkeymgr.dylib dyld[19948]: <1A7038EC-EE49-35AE-8A3C-C311083795FB> /usr/lib/system/libmacho.dylib [...] ``` - **DYLD_PRINT_SEGMENTS** Proverite kako se svaka biblioteka učitava: ``` DYLD_PRINT_SEGMENTS=1 ./apple dyld[21147]: re-using existing shared cache (/System/Volumes/Preboot/Cryptexes/OS/System/Library/dyld/dyld_shared_cache_arm64e): dyld[21147]: 0x181944000->0x1D5D4BFFF init=5, max=5 __TEXT dyld[21147]: 0x1D5D4C000->0x1D5EC3FFF init=1, max=3 __DATA_CONST dyld[21147]: 0x1D7EC4000->0x1D8E23FFF init=3, max=3 __DATA dyld[21147]: 0x1D8E24000->0x1DCEBFFFF init=3, max=3 __AUTH dyld[21147]: 0x1DCEC0000->0x1E22BFFFF init=1, max=3 __AUTH_CONST dyld[21147]: 0x1E42C0000->0x1E5457FFF init=1, max=1 __LINKEDIT dyld[21147]: 0x1E5458000->0x22D173FFF init=5, max=5 __TEXT dyld[21147]: 0x22D174000->0x22D9E3FFF init=1, max=3 __DATA_CONST dyld[21147]: 0x22F9E4000->0x230F87FFF init=3, max=3 __DATA dyld[21147]: 0x230F88000->0x234EC3FFF init=3, max=3 __AUTH dyld[21147]: 0x234EC4000->0x237573FFF init=1, max=3 __AUTH_CONST dyld[21147]: 0x239574000->0x270BE3FFF init=1, max=1 __LINKEDIT dyld[21147]: Kernel mapped /private/tmp/a dyld[21147]: __PAGEZERO (...) 0x000000904000->0x000101208000 dyld[21147]: __TEXT (r.x) 0x000100904000->0x000100908000 dyld[21147]: __DATA_CONST (rw.) 0x000100908000->0x00010090C000 dyld[21147]: __LINKEDIT (r..) 0x00010090C000->0x000100910000 dyld[21147]: Using mapping in dyld cache for /usr/lib/libSystem.B.dylib dyld[21147]: __TEXT (r.x) 0x00018E59D000->0x00018E59F000 dyld[21147]: __DATA_CONST (rw.) 0x0001D5DFDB98->0x0001D5DFDBA8 dyld[21147]: __AUTH_CONST (rw.) 0x0001DDE015A8->0x0001DDE01878 dyld[21147]: __AUTH (rw.) 0x0001D9688650->0x0001D9688658 dyld[21147]: __DATA (rw.) 0x0001D808AD60->0x0001D808AD68 dyld[21147]: __LINKEDIT (r..) 0x000239574000->0x000270BE4000 dyld[21147]: Using mapping in dyld cache for /usr/lib/system/libcache.dylib dyld[21147]: __TEXT (r.x) 0x00018E597000->0x00018E59D000 dyld[21147]: __DATA_CONST (rw.) 0x0001D5DFDAF0->0x0001D5DFDB98 dyld[21147]: __AUTH_CONST (rw.) 0x0001DDE014D0->0x0001DDE015A8 dyld[21147]: __LINKEDIT (r..) 0x000239574000->0x000270BE4000 [...] ``` - **DYLD_PRINT_INITIALIZERS** Štampa kada se svaki inicijalizator biblioteke pokreće: ``` DYLD_PRINT_INITIALIZERS=1 ./apple dyld[21623]: running initializer 0x18e59e5c0 in /usr/lib/libSystem.B.dylib [...] ``` ### Drugo - `DYLD_BIND_AT_LAUNCH`: Lenje vezivanje se rešava sa neljenim - `DYLD_DISABLE_PREFETCH`: Onemogući pre-fetching \_\_DATA i \_\_LINKEDIT sadržaja - `DYLD_FORCE_FLAT_NAMESPACE`: Jednokratna vezivanja - `DYLD_[FRAMEWORK/LIBRARY]_PATH | DYLD_FALLBACK_[FRAMEWORK/LIBRARY]_PATH | DYLD_VERSIONED_[FRAMEWORK/LIBRARY]_PATH`: Putanje za rešavanje - `DYLD_INSERT_LIBRARIES`: Učitaj specifičnu biblioteku - `DYLD_PRINT_TO_FILE`: Zapiši dyld debug u datoteku - `DYLD_PRINT_APIS`: Ispiši libdyld API pozive - `DYLD_PRINT_APIS_APP`: Ispiši libdyld API pozive koje je napravio main - `DYLD_PRINT_BINDINGS`: Ispiši simbole kada su vezani - `DYLD_WEAK_BINDINGS`: Ispiši samo slabe simbole kada su vezani - `DYLD_PRINT_CODE_SIGNATURES`: Ispiši operacije registracije potpisa koda - `DYLD_PRINT_DOFS`: Ispiši D-Trace format sekcija kao učitane - `DYLD_PRINT_ENV`: Ispiši env viđen od strane dyld - `DYLD_PRINT_INTERPOSTING`: Ispiši interposting operacije - `DYLD_PRINT_LIBRARIES`: Ispiši učitane biblioteke - `DYLD_PRINT_OPTS`: Ispiši opcije učitavanja - `DYLD_REBASING`: Ispiši operacije ponovnog vezivanja simbola - `DYLD_RPATHS`: Ispiši ekspanzije @rpath - `DYLD_PRINT_SEGMENTS`: Ispiši mape Mach-O segmenata - `DYLD_PRINT_STATISTICS`: Ispiši statistiku vremena - `DYLD_PRINT_STATISTICS_DETAILS`: Ispiši detaljnu statistiku vremena - `DYLD_PRINT_WARNINGS`: Ispiši poruke upozorenja - `DYLD_SHARED_CACHE_DIR`: Putanja za korišćenje za keš zajedničkih biblioteka - `DYLD_SHARED_REGION`: "koristi", "privatno", "izbegavaj" - `DYLD_USE_CLOSURES`: Omogući zatvaranja Moguće je pronaći više sa nečim poput: ```bash strings /usr/lib/dyld | grep "^DYLD_" | sort -u ``` Ili preuzimanje dyld projekta sa [https://opensource.apple.com/tarballs/dyld/dyld-852.2.tar.gz](https://opensource.apple.com/tarballs/dyld/dyld-852.2.tar.gz) i pokretanje unutar foldera: ```bash find . -type f | xargs grep strcmp| grep key,\ \" | cut -d'"' -f2 | sort -u ``` ## Reference - [**\*OS Internals, Volume I: User Mode. By Jonathan Levin**](https://www.amazon.com/MacOS-iOS-Internals-User-Mode/dp/099105556X) {{#include ../../../../banners/hacktricks-training.md}}