macOS Universal binaries & Mach-O Format
Вивчайте та практикуйте хакінг AWS: Школа хакінгу HackTricks AWS Red Team Expert (ARTE)
Вивчайте та практикуйте хакінг GCP:
Школа хакінгу HackTricks GCP Red Team Expert (GRTE)
Основна інформація
Бінарні файли Mac OS зазвичай компілюються як універсальні бінарні файли. Універсальний бінарний файл може підтримувати кілька архітектур у одному файлі.
Ці бінарні файли відповідають структурі Mach-O, яка в основному складається з:
Заголовка
Команд завантаження
Даних
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F2585115637-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FhAv2kYoPrT3n8552GaQU%252Fuploads%252Fgit-blob-82966ab5b38151fe2dc0fe3dabf4912d1df2a87a%252Fimage%2520%28470%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=1597be4e&sv=1)
Fat Header
Шукайте файл за допомогою: mdfind fat.h | grep -i mach-o | grep -E "fat.h$"
Заголовок містить магічні байти, за якими слідує кількість архітектур, які містить файл (nfat_arch
), і кожна архітектура матиме структуру fat_arch
.
Перевірте це за допомогою:
або використовуючи інструмент Mach-O View:
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F2585115637-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FhAv2kYoPrT3n8552GaQU%252Fuploads%252Fgit-blob-4642e6584e039d6779efab2800251a06510781e8%252Fimage%2520%281094%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=7735d9e5&sv=1)
Як ви, можливо, мислите, зазвичай універсальний бінарний файл, скомпільований для 2 архітектур, подвоює розмір того, що скомпільовано лише для 1 архітектури.
Заголовок Mach-O
Заголовок містить базову інформацію про файл, таку як магічні байти для ідентифікації його як файлу Mach-O та інформацію про цільову архітектуру. Ви можете знайти його за допомогою: mdfind loader.h | grep -i mach-o | grep -E "loader.h$"
Типи файлів Mach-O
Існують різні типи файлів, ви можете знайти їх визначені в вихідному коді, наприклад, тут. Найважливіші з них:
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
: Розширення ядра.
Або використовуючи Mach-O View:
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F2585115637-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FhAv2kYoPrT3n8552GaQU%252Fuploads%252Fgit-blob-955989eef1c9adb340f4afea304accd082857c33%252Fimage%2520%281133%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=7f24992f&sv=1)
Прапорці Mach-O
Вихідний код також визначає кілька корисних прапорців для завантаження бібліотек:
MH_NOUNDEFS
: Немає невизначених посилань (повністю зв'язаний)MH_DYLDLINK
: Посилання DyldMH_PREBOUND
: Динамічні посилання попередньо зв'язані.MH_SPLIT_SEGS
: Файл розділяє сегменти r/o та r/w.MH_WEAK_DEFINES
: У бінарному файлі є слабкі визначені символиMH_BINDS_TO_WEAK
: Бінарний файл використовує слабкі символиMH_ALLOW_STACK_EXECUTION
: Зробити стек виконавчимMH_NO_REEXPORTED_DYLIBS
: Бібліотека не містить команд LC_REEXPORTMH_PIE
: Виконавчий файл з незалежними від положення адресиMH_HAS_TLV_DESCRIPTORS
: Є розділ зі змінними локального потокуMH_NO_HEAP_EXECUTION
: Відсутнє виконання для сторінок купи/данихMH_HAS_OBJC
: У бінарному файлі є розділи oBject-CMH_SIM_SUPPORT
: Підтримка симулятораMH_DYLIB_IN_CACHE
: Використовується на dylibs/frameworks у спільному кеші бібліотек.
Команди завантаження Mach-O
Тут вказано розташування файлу в пам'яті, деталізуючи розташування таблиці символів, контекст основного потоку при початку виконання та необхідні спільні бібліотеки. Надаються інструкції для динамічного завантажувача (dyld) щодо процесу завантаження бінарного файлу в пам'ять.
Використовує структуру load_command, визначену в зазначеному loader.h
:
Існує близько 50 різних типів команд завантаження, які система обробляє по-різному. Найпоширеніші з них: LC_SEGMENT_64
, LC_LOAD_DYLINKER
, LC_MAIN
, LC_LOAD_DYLIB
та LC_CODE_SIGNATURE
.
LC_SEGMENT/LC_SEGMENT_64
Фактично, цей тип команди завантаження визначає, як завантажувати сегменти __TEXT (виконавчий код) та __DATA (дані для процесу) згідно з вказаними зміщеннями в розділі Дані при виконанні бінарного файлу.
Ці команди визначають сегменти, які відображаються в віртуальному просторі пам'яті процесу під час його виконання.
Існують різні типи сегментів, такі як сегмент __TEXT, який містить виконавчий код програми, та сегмент __DATA, який містить дані, використовувані процесом. Ці сегменти розташовані в розділі даних файлу Mach-O.
Кожен сегмент може бути поділений на кілька секцій. Структура команди завантаження містить інформацію про ці секції у відповідному сегменті.
У заголовку спочатку ви знаходите заголовок сегмента:
Приклад заголовка сегмента:
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F2585115637-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FhAv2kYoPrT3n8552GaQU%252Fuploads%252Fgit-blob-31be65974335f158eff11db40d6e8919e8c6284f%252Fimage%2520%281126%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=a671894b&sv=1)
Цей заголовок визначає кількість секцій, заголовки яких з'являються після нього:
Приклад заголовка розділу:
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F2585115637-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FhAv2kYoPrT3n8552GaQU%252Fuploads%252Fgit-blob-345e6bee98a3a612946950d81de618f091594ea3%252Fimage%2520%281108%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=be25a2ea&sv=1)
Якщо ви додаєте зміщення розділу (0x37DC) + зміщення, де починається архітектура, у цьому випадку 0x18000
--> 0x37DC + 0x18000 = 0x1B7DC
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F2585115637-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FhAv2kYoPrT3n8552GaQU%252Fuploads%252Fgit-blob-6874f9c8693e06b38da477e9a84ffe0d920b4b09%252Fimage%2520%28701%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=18715a33&sv=1)
Також можна отримати інформацію про заголовки з командного рядка за допомогою:
Спільні сегменти, завантажені цією командою:
__PAGEZERO
: Це вказує ядру відобразити адресу нуль, щоб її не можна було читати, записувати або виконувати. Змінні maxprot та minprot у структурі встановлені на нуль, щоб показати, що на цій сторінці немає прав на читання-запис-виконання.Це виділення важливе для пом'якшення вразливостей нульового вказівника. Це тому, що XNU застосовує жорстку сторінку нуль, яка забезпечує, що перша сторінка (тільки перша) пам'яті недоступна (крім в i386). Бінарний файл може відповісти цим вимогам, створивши невеликий __PAGEZERO (використовуючи
-pagezero_size
) для охоплення перших 4 кб та зробивши решту пам'яті 32-біт доступною як у режимі користувача, так і в режимі ядра.__TEXT
: Містить виконуваний код з дозволами на читання та виконання (без можливості запису). Загальні розділи цього сегмента:__text
: Скомпільований бінарний код__const
: Константні дані (тільки для читання)__[c/u/os_log]string
: Константи рядків C, Unicode або os logs__stubs
та__stubs_helper
: Використовуються під час процесу завантаження динамічних бібліотек__unwind_info
: Дані розгортання стеку.Зверніть увагу, що весь цей вміст підписаний, але також позначений як виконуваний (створюючи більше варіантів для експлуатації розділів, які не обов'язково потребують цієї привілеї, наприклад, розділів, присвячених рядкам).
__DATA
: Містить дані, які можна читати та писати (без можливості виконання).__got:
Глобальна таблиця зміщень__nl_symbol_ptr
: Вказівник на символи Non lazy (bind at load)__la_symbol_ptr
: Вказівник на символи Lazy (bind on use)__const
: Повинні бути дані тільки для читання (насправді ні)__cfstring
: Строки CoreFoundation__data
: Глобальні змінні (які були ініціалізовані)__bss
: Статичні змінні (які не були ініціалізовані)__objc_*
(__objc_classlist, __objc_protolist, тощо): Інформація, використовувана середовищем виконання Objective-C__DATA_CONST
: __DATA.__const не гарантується, що воно є постійним (права на запис), так само як і інші вказівники та таблиця GOT. Цей розділ робить__const
, деякі ініціалізатори та таблицю GOT (після вирішення) тільки для читання за допомогоюmprotect
.__LINKEDIT
: Містить інформацію для лінкера (dyld), таку як, символи, рядки та записи таблиці перенесення. Це загальний контейнер для вмісту, який не знаходиться ані в__TEXT
, ані в__DATA
, а його вміст описаний в інших командах завантаження.Інформація dyld: Rebase, опкоди для не-лінивого/лінивого/слабкого зв'язування та інформація про експорт
Початок функцій: Таблиця початкових адрес функцій
Дані у коді: Дані на островах в __text
Таблиця символів: Символи в бінарному файлі
Таблиця непрямих символів: Вказівники/заглушки символів
Таблиця рядків
Підпис коду
__OBJC
: Містить інформацію, використовувану середовищем виконання Objective-C. Хоча цю інформацію також можна знайти в сегменті __DATA, в різних розділах __objc_*.__RESTRICT
: Сегмент без вмісту з одним розділом під назвою__restrict
(також порожній), який забезпечує, що під час виконання бінарного файлу будуть ігноруватися змінні середовища DYLD.
Як можна було побачити в коді, сегменти також підтримують прапорці (хоча вони не використовуються дуже часто):
SG_HIGHVM
: Тільки для ядра (не використовується)SG_FVMLIB
: Не використовуєтьсяSG_NORELOC
: Сегмент не має перерозташуванняSG_PROTECTED_VERSION_1
: Шифрування. Використовується, наприклад, Finder для шифрування тексту в сегменті__TEXT
.
LC_UNIXTHREAD/LC_MAIN
LC_UNIXTHREAD/LC_MAIN
LC_MAIN
містить точку входу в атрибуті entryoff. Під час завантаження dyld просто додає це значення до (в пам'яті) бази бінарного файлу, а потім переходить до цієї інструкції для початку виконання коду бінарного файлу.
LC_UNIXTHREAD
містить значення, які повинні мати регістри при запуску головного потоку. Це вже застаріло, але dyld
все ще використовує його. Можна побачити значення регістрів, встановлені цим, за допомогою:
LC_CODE_SIGNATURE
LC_CODE_SIGNATURE
Містить інформацію про підпис коду файлу Mach-O. Він містить лише зсув, який вказує на блоб підпису. Зазвичай це знаходиться в самому кінці файлу. Однак ви можете знайти деяку інформацію про цей розділ у цьому дописі у блозі та у цьому фрагменті.
LC_ENCRYPTION_INFO[_64]
LC_ENCRYPTION_INFO[_64]
Підтримка шифрування бінарного коду. Однак, звісно, якщо зловмисник здатний скомпрометувати процес, він зможе витягнути пам'ять в розшифрованому вигляді.
LC_LOAD_DYLINKER
LC_LOAD_DYLINKER
Містить шлях до виконуваного файлу динамічного зв'язувача, який відображає спільні бібліотеки в адресний простір процесу. Значення завжди встановлено на /usr/lib/dyld
. Важливо зауважити, що в macOS відображення dylib відбувається в режимі користувача, а не в режимі ядра.
LC_IDENT
LC_IDENT
Застарілий, але якщо налаштовано на генерацію дампів при паніці, створюється дамп ядра Mach-O, і версія ядра встановлюється в команді LC_IDENT
.
LC_UUID
LC_UUID
Випадковий UUID. Він корисний для чого завгодно, але XNU кешує його разом з іншою інформацією про процес. Він може бути використаний у звітах про аварії.
LC_DYLD_ENVIRONMENT
LC_DYLD_ENVIRONMENT
Дозволяє вказати змінні середовища для dyld перед виконанням процесу. Це може бути дуже небезпечно, оскільки це може дозволити виконати довільний код всередині процесу, тому ця команда завантаження використовується лише в dyld, побудованому з #define SUPPORT_LC_DYLD_ENVIRONMENT
та додатково обмежує обробку лише змінних у формі DYLD_..._PATH
, що вказують шляхи завантаження.
LC_LOAD_DYLIB
LC_LOAD_DYLIB
Ця команда завантаження описує залежність динамічної бібліотеки, яка вказує завантажувачу (dyld) завантажити та зв'язати цю бібліотеку. Існує команда завантаження LC_LOAD_DYLIB
для кожної бібліотеки, яку потребує бінарний файл Mach-O.
Ця команда завантаження є структурою типу
dylib_command
(яка містить структуру dylib, що описує фактичну залежну динамічну бібліотеку):
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F2585115637-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FhAv2kYoPrT3n8552GaQU%252Fuploads%252Fgit-blob-50dda35adcced1775eb1fc53d0e8dfcb74c378cc%252Fimage%2520%28486%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=6df1c424&sv=1)
Ви також можете отримати цю інформацію з командного рядка за допомогою:
Деякі потенційно пов'язані з шкідливим ПЗ бібліотеки:
DiskArbitration: Моніторинг USB-накопичувачів
AVFoundation: Захоплення аудіо та відео
CoreWLAN: Сканування Wifi.
Mach-O бінарний файл може містити один або більше конструкторів, які будуть виконані перед адресою, вказаною в LC_MAIN. Зміщення будь-яких конструкторів зберігаються в розділі __mod_init_func сегмента __DATA_CONST.
Дані Mach-O
У основі файлу знаходиться область даних, яка складається з кількох сегментів, які визначені в області команд завантаження. В кожному сегменті можуть міститися різні секції даних, причому кожна секція містить код або дані, що специфічні для типу.
Дані - це в основному частина, що містить всю інформацію, яка завантажується командами завантаження LC_SEGMENTS_64
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F2585115637-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FhAv2kYoPrT3n8552GaQU%252Fuploads%252Fgit-blob-d417c71bdb7ae7c103ed1040488950039aa93799%252Fimage%2520%28507%29%2520%283%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=3f9bf465&sv=1)
Це включає:
Таблиця функцій: Яка містить інформацію про функції програми.
Таблиця символів: Яка містить інформацію про зовнішню функцію, використану бінарним файлом
Також може містити внутрішні функції, назви змінних та інше.
Для перевірки цього можна використовувати інструмент Mach-O View:
![](https://book.hacktricks.xyz/~gitbook/image?url=https%3A%2F%2F2585115637-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FhAv2kYoPrT3n8552GaQU%252Fuploads%252Fgit-blob-e3b3dbe9f2830202b64f16caa9c24f7ee5062df9%252Fimage%2520%281120%29.png%3Falt%3Dmedia&width=768&dpr=4&quality=100&sign=30712e20&sv=1)
Або з командного рядка:
Загальні розділи Objective-C
У сегменті __TEXT
(r-x):
__objc_classname
: Імена класів (рядки)__objc_methname
: Назви методів (рядки)__objc_methtype
: Типи методів (рядки)
У сегменті __DATA
(rw-):
__objc_classlist
: Вказівники на всі класи Objective-C__objc_nlclslist
: Вказівники на неліниві класи Objective-C__objc_catlist
: Вказівник на категорії__objc_nlcatlist
: Вказівник на неліниві категорії__objc_protolist
: Список протоколів__objc_const
: Константні дані__objc_imageinfo
,__objc_selrefs
,objc__protorefs
...
Swift
_swift_typeref
,_swift3_capture
,_swift3_assocty
,_swift3_types, _swift3_proto
,_swift3_fieldmd
,_swift3_builtin
,_swift3_reflstr
Last updated