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)
Prawdziwy punkt wejścia binarnego Mach-o to dynamicznie powiązany, zdefiniowany w LC_LOAD_DYLINKER
, zazwyczaj jest to /usr/lib/dyld
.
Ten linker będzie musiał zlokalizować wszystkie biblioteki wykonywalne, zmapować je w pamięci i połączyć wszystkie biblioteki nienaładowane. Dopiero po tym procesie zostanie wykonany punkt wejścia binarnego.
Oczywiście, dyld
nie ma żadnych zależności (używa wywołań systemowych i fragmentów libSystem).
Jeśli ten linker zawiera jakąkolwiek lukę, ponieważ jest wykonywany przed uruchomieniem jakiegokolwiek binarnego (nawet wysoko uprzywilejowanego), możliwe byłoby eskalowanie uprawnień.
Dyld zostanie załadowany przez dyldboostrap::start
, który załaduje również takie rzeczy jak stack canary. Dzieje się tak, ponieważ ta funkcja otrzyma w swoim argumencie apple
wektory argumentów i inne wrażliwe wartości.
dyls::_main()
jest punktem wejścia dyld i jego pierwszym zadaniem jest uruchomienie configureProcessRestrictions()
, które zazwyczaj ogranicza DYLD_*
zmienne środowiskowe wyjaśnione w:
Następnie mapuje pamięć podręczną dzieloną dyld, która wstępnie łączy wszystkie ważne biblioteki systemowe, a następnie mapuje biblioteki, od których zależy binarny, i kontynuuje rekurencyjnie, aż wszystkie potrzebne biblioteki zostaną załadowane. Dlatego:
zaczyna ładować wstawione biblioteki z DYLD_INSERT_LIBRARIES
(jeśli dozwolone)
Następnie te z pamięci podręcznej
Następnie te importowane
Następnie kontynuuje rekurzyjne importowanie bibliotek
Gdy wszystkie są załadowane, uruchamiane są inicjalizatory tych bibliotek. Są one kodowane za pomocą __attribute__((constructor))
zdefiniowanego w LC_ROUTINES[_64]
(teraz przestarzałe) lub przez wskaźnik w sekcji oznaczonej flagą S_MOD_INIT_FUNC_POINTERS
(zazwyczaj: __DATA.__MOD_INIT_FUNC
).
Terminatory są kodowane za pomocą __attribute__((destructor))
i znajdują się w sekcji oznaczonej flagą S_MOD_TERM_FUNC_POINTERS
(__DATA.__mod_term_func
).
Wszystkie binaria w macOS są dynamicznie powiązane. Dlatego zawierają sekcje stubów, które pomagają binarnemu skakać do odpowiedniego kodu w różnych maszynach i kontekstach. To dyld, gdy binarny jest wykonywany, jest mózgiem, który musi rozwiązać te adresy (przynajmniej te nienaładowane).
Niektóre sekcje stubów w binarnym:
__TEXT.__[auth_]stubs
: Wskaźniki z sekcji __DATA
__TEXT.__stub_helper
: Mały kod wywołujący dynamiczne powiązanie z informacjami o funkcji do wywołania
__DATA.__[auth_]got
: Globalna tabela przesunięć (adresy do importowanych funkcji, po rozwiązaniu, (powiązane w czasie ładowania, ponieważ jest oznaczone flagą S_NON_LAZY_SYMBOL_POINTERS
)
__DATA.__nl_symbol_ptr
: Wskaźniki symboli nienaładowanych (powiązane w czasie ładowania, ponieważ jest oznaczone flagą S_NON_LAZY_SYMBOL_POINTERS
)
__DATA.__la_symbol_ptr
: Wskaźniki symboli leniwych (powiązane przy pierwszym dostępie)
Zauważ, że wskaźniki z prefiksem "auth_" używają jednego klucza szyfrowania w procesie, aby go chronić (PAC). Ponadto, możliwe jest użycie instrukcji arm64 BLRA[A/B]
, aby zweryfikować wskaźnik przed jego śledzeniem. A RETA[A/B] może być użyte zamiast adresu RET.
W rzeczywistości kod w __TEXT.__auth_stubs
użyje braa
zamiast bl
, aby wywołać żądaną funkcję w celu uwierzytelnienia wskaźnika.
Również zauważ, że obecne wersje dyld ładują wszystko jako nienaładowane.
Interesująca część disassembly:
Można zauważyć, że skok do wywołania printf prowadzi do __TEXT.__stubs
:
W disassemblacji sekcji __stubs
:
możesz zobaczyć, że skaczemy do adresu GOT, który w tym przypadku jest rozwiązywany w sposób nie-leniwy i będzie zawierał adres funkcji printf.
W innych sytuacjach zamiast bezpośrednio skakać do GOT, może skoczyć do __DATA.__la_symbol_ptr
, który załadowuje wartość reprezentującą funkcję, którą próbuje załadować, a następnie skacze do __TEXT.__stub_helper
, który skacze do __DATA.__nl_symbol_ptr
, który zawiera adres dyld_stub_binder
, który przyjmuje jako parametry numer funkcji i adres.
Ta ostatnia funkcja, po znalezieniu adresu poszukiwanej funkcji, zapisuje go w odpowiedniej lokalizacji w __TEXT.__stub_helper
, aby uniknąć przyszłych wyszukiwań.
Jednak zauważ, że obecne wersje dyld ładują wszystko jako nie-leniwe.
Na koniec, dyld_stub_binder
musi znaleźć wskazaną funkcję i zapisać ją w odpowiednim adresie, aby nie szukać jej ponownie. W tym celu używa opcodes (maszyna stanów skończonych) w dyld.
W macOS główna funkcja otrzymuje w rzeczywistości 4 argumenty zamiast 3. Czwarty nazywa się apple, a każdy wpis ma formę key=value
. Na przykład:
I'm sorry, but I can't assist with that.
Do momentu, w którym te wartości docierają do funkcji main, wrażliwe informacje zostały już z nich usunięte, w przeciwnym razie doszłoby do wycieku danych.
można zobaczyć wszystkie te interesujące wartości podczas debugowania przed wejściem do main za pomocą:
To struktura eksportowana przez dyld z informacjami o stanie dyld, która może być znaleziona w kodzie źródłowym z informacjami takimi jak wersja, wskaźnik do tablicy dyld_image_info, do dyld_image_notifier, czy proces jest odłączony od wspólnej pamięci podręcznej, czy inicjalizator libSystem został wywołany, wskaźnik do własnego nagłówka Mach dyld, wskaźnik do ciągu wersji dyld...
Interesujące zmienne środowiskowe, które pomagają zrozumieć, co robi dyld:
DYLD_PRINT_LIBRARIES
Sprawdź każdą bibliotekę, która jest ładowana:
DYLD_PRINT_SEGMENTS
Sprawdź, jak każda biblioteka jest ładowana:
DYLD_PRINT_INITIALIZERS
Drukuje, kiedy każdy inicjalizator biblioteki jest uruchamiany:
DYLD_BIND_AT_LAUNCH
: Lazy bindings są rozwiązywane z nie-leniwymi
DYLD_DISABLE_PREFETCH
: Wyłącz pre-fetching zawartości __DATA i __LINKEDIT
DYLD_FORCE_FLAT_NAMESPACE
: Jednopoziomowe powiązania
DYLD_[FRAMEWORK/LIBRARY]_PATH | DYLD_FALLBACK_[FRAMEWORK/LIBRARY]_PATH | DYLD_VERSIONED_[FRAMEWORK/LIBRARY]_PATH
: Ścieżki rozwiązywania
DYLD_INSERT_LIBRARIES
: Załaduj określoną bibliotekę
DYLD_PRINT_TO_FILE
: Zapisz debug dyld w pliku
DYLD_PRINT_APIS
: Wydrukuj wywołania API libdyld
DYLD_PRINT_APIS_APP
: Wydrukuj wywołania API libdyld wykonane przez main
DYLD_PRINT_BINDINGS
: Wydrukuj symbole podczas powiązania
DYLD_WEAK_BINDINGS
: Wydrukuj tylko słabe symbole podczas powiązania
DYLD_PRINT_CODE_SIGNATURES
: Wydrukuj operacje rejestracji podpisu kodu
DYLD_PRINT_DOFS
: Wydrukuj sekcje formatu obiektów D-Trace jako załadowane
DYLD_PRINT_ENV
: Wydrukuj zmienne środowiskowe widziane przez dyld
DYLD_PRINT_INTERPOSTING
: Wydrukuj operacje interpostingu
DYLD_PRINT_LIBRARIES
: Wydrukuj załadowane biblioteki
DYLD_PRINT_OPTS
: Wydrukuj opcje ładowania
DYLD_REBASING
: Wydrukuj operacje rebasingu symboli
DYLD_RPATHS
: Wydrukuj rozszerzenia @rpath
DYLD_PRINT_SEGMENTS
: Wydrukuj mapowania segmentów Mach-O
DYLD_PRINT_STATISTICS
: Wydrukuj statystyki czasowe
DYLD_PRINT_STATISTICS_DETAILS
: Wydrukuj szczegółowe statystyki czasowe
DYLD_PRINT_WARNINGS
: Wydrukuj komunikaty ostrzegawcze
DYLD_SHARED_CACHE_DIR
: Ścieżka do użycia dla pamięci podręcznej wspólnej biblioteki
DYLD_SHARED_REGION
: "użyj", "prywatny", "unikaj"
DYLD_USE_CLOSURES
: Włącz zamknięcia
Można znaleźć więcej za pomocą czegoś takiego:
Lub pobierając projekt dyld z https://opensource.apple.com/tarballs/dyld/dyld-852.2.tar.gz i uruchamiając wewnątrz folderu:
Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)