Translated ['src/macos-hardening/macos-security-and-privilege-escalation

This commit is contained in:
Translator 2025-10-01 01:54:27 +00:00
parent 2c62c15400
commit 14a26af3bd
5 changed files with 427 additions and 198 deletions

View File

@ -61,6 +61,7 @@
- [Deofuscation vbs (cscript.exe)](generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/desofuscation-vbs-cscript.exe.md)
- [Discord Cache Forensics](generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/discord-cache-forensics.md)
- [Local Cloud Storage](generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/local-cloud-storage.md)
- [Mach O Entitlements And Ipsw Indexing](generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/mach-o-entitlements-and-ipsw-indexing.md)
- [Office file analysis](generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/office-file-analysis.md)
- [PDF File analysis](generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/pdf-file-analysis.md)
- [PNG tricks](generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/png-tricks.md)

View File

@ -1,4 +1,4 @@
# Специфічні трюки для програмного забезпечення та типів файлів
# Специфічні трюки для програмного забезпечення/типів файлів
{{#include ../../../banners/hacktricks-training.md}}
@ -54,4 +54,9 @@ video-and-audio-file-analysis.md
zips-tricks.md
{{#endref}}
{{#ref}}
mach-o-entitlements-and-ipsw-indexing.md
{{#endref}}
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -0,0 +1,213 @@
# Mach-O Entitlements Extraction & IPSW Indexing
{{#include ../../../banners/hacktricks-training.md}}
## Огляд
Ця сторінка описує, як програмно витягувати entitlements з Mach-O бінарів, обходячи LC_CODE_SIGNATURE та розбираючи підпис SuperBlob, а також як масштабувати це для Apple IPSW прошивок шляхом маунтування та індексації їх вмісту для судової пошукової/дифової аналізу.
Якщо потрібне оновлення знань про формат Mach-O та підписування коду, див. також: macOS code signing та внутрішні структури SuperBlob.
- Check macOS code signing details (SuperBlob, Code Directory, special slots): [macOS Code Signing](../../../macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-code-signing.md)
- Check general Mach-O structures/load commands: [Universal binaries & Mach-O Format](../../../macos-hardening/macos-security-and-privilege-escalation/macos-files-folders-and-binaries/universal-binaries-and-mach-o-format.md)
## Entitlements in Mach-O: where they live
Entitlements зберігаються всередині даних підпису коду, на які посилається load command LC_CODE_SIGNATURE, і розташовані в сегменті __LINKEDIT. Підпис — це CS_SuperBlob, що містить кілька blobів (code directory, requirements, entitlements, CMS тощо). Entitlements blob — це CS_GenericBlob, дані якого є Apple Binary Property List (bplist00), що відображає ключі entitlements у значення.
Ключові структури (з xnu):
```c
/* mach-o/loader.h */
struct mach_header_64 {
uint32_t magic;
cpu_type_t cputype;
cpu_subtype_t cpusubtype;
uint32_t filetype;
uint32_t ncmds;
uint32_t sizeofcmds;
uint32_t flags;
uint32_t reserved;
};
struct load_command {
uint32_t cmd;
uint32_t cmdsize;
};
/* Entitlements live behind LC_CODE_SIGNATURE (cmd=0x1d) */
struct linkedit_data_command {
uint32_t cmd; /* LC_CODE_SIGNATURE */
uint32_t cmdsize; /* sizeof(struct linkedit_data_command) */
uint32_t dataoff; /* file offset of data in __LINKEDIT */
uint32_t datasize; /* file size of data in __LINKEDIT */
};
/* osfmk/kern/cs_blobs.h */
typedef struct __SC_SuperBlob {
uint32_t magic; /* CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0 */
uint32_t length;
uint32_t count;
CS_BlobIndex index[];
} CS_SuperBlob;
typedef struct __BlobIndex {
uint32_t type; /* e.g., CSMAGIC_EMBEDDED_ENTITLEMENTS = 0xfade7171 */
uint32_t offset; /* offset of entry */
} CS_BlobIndex;
typedef struct __SC_GenericBlob {
uint32_t magic; /* same as type when standalone */
uint32_t length;
char data[]; /* Apple Binary Plist containing entitlements */
} CS_GenericBlob;
```
Важливі константи:
- LC_CODE_SIGNATURE cmd = 0x1d
- CS SuperBlob magic = 0xfade0cc0
- Entitlements blob type (CSMAGIC_EMBEDDED_ENTITLEMENTS) = 0xfade7171
- DER entitlements may be present via special slot (e.g., -7), see the macOS Code Signing page for special slots and DER entitlements notes
Note: Multi-arch (fat) binaries contain multiple Mach-O slices. You must pick the slice for the architecture you want to inspect and then walk its load commands.
## Extraction steps (generic, lossless-enough)
1) Parse Mach-O header; iterate ncmds worth of load_command records.
2) Locate LC_CODE_SIGNATURE; read linkedit_data_command.dataoff/datasize to map the Code Signing SuperBlob placed in __LINKEDIT.
3) Validate CS_SuperBlob.magic == 0xfade0cc0; iterate count entries of CS_BlobIndex.
4) Locate index.type == 0xfade7171 (embedded entitlements). Read the pointed CS_GenericBlob and parse its data as an Apple binary plist (bplist00) to key/value entitlements.
Implementation notes:
- Code signature structures use big-endian fields; swap byte order when parsing on little-endian hosts.
- The entitlements GenericBlob data itself is a binary plist (handled by standard plist libraries).
- Some iOS binaries may carry DER entitlements; also some stores/slots differ across platforms/versions. Cross-check both standard and DER entitlements as needed.
- For fat binaries, use the fat headers (FAT_MAGIC/FAT_MAGIC_64) to locate the correct slice and offset before walking Mach-O load commands.
## Minimal parsing outline (Python)
The following is a compact outline showing the control flow to find and decode entitlements. It intentionally omits robust bounds checks and full fat binary support for brevity.
```python
import plistlib, struct
LC_CODE_SIGNATURE = 0x1d
CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0
CSMAGIC_EMBEDDED_ENTITLEMENTS = 0xfade7171
# all code-signing integers are big-endian per cs_blobs.h
be32 = lambda b, off: struct.unpack_from(">I", b, off)[0]
def parse_entitlements(macho_bytes):
# assume already positioned at a single-arch Mach-O slice
magic, = struct.unpack_from("<I", macho_bytes, 0)
is64 = magic in (0xfeedfacf,)
if is64:
ncmds = struct.unpack_from("<I", macho_bytes, 0x10)[0]
sizeofcmds = struct.unpack_from("<I", macho_bytes, 0x14)[0]
off = 0x20
else:
# 32-bit not shown
return None
code_sig_off = code_sig_size = None
for _ in range(ncmds):
cmd, cmdsize = struct.unpack_from("<II", macho_bytes, off)
if cmd == LC_CODE_SIGNATURE:
# struct linkedit_data_command is little-endian in file
_, _, dataoff, datasize = struct.unpack_from("<IIII", macho_bytes, off)
code_sig_off, code_sig_size = dataoff, datasize
off += cmdsize
if code_sig_off is None:
return None
blob = macho_bytes[code_sig_off: code_sig_off + code_sig_size]
if be32(blob, 0x0) != CSMAGIC_EMBEDDED_SIGNATURE:
return None
count = be32(blob, 0x8)
# iterate BlobIndex entries (8 bytes each after 12-byte header)
for i in range(count):
idx_off = 12 + i*8
btype = be32(blob, idx_off)
boff = be32(blob, idx_off+4)
if btype == CSMAGIC_EMBEDDED_ENTITLEMENTS:
# GenericBlob is big-endian header followed by bplist
glen = be32(blob, boff+4)
data = blob[boff+8: boff+glen]
return plistlib.loads(data)
return None
```
Usage tips:
- Щоб працювати з fat binaries, спочатку прочитайте struct fat_header/fat_arch, виберіть потрібний архітектурний зріз, потім передайте піддіапазон у parse_entitlements.
- На macOS ви можете перевірити результати за допомогою: codesign -d --entitlements :- /path/to/binary
## Example findings
Привілейовані platform binaries часто запитують чутливі entitlements, такі як:
- com.apple.security.network.server = true
- com.apple.rootless.storage.early_boot_mount = true
- com.apple.private.kernel.system-override = true
- com.apple.private.pmap.load-trust-cache = ["cryptex1.boot.os", "cryptex1.boot.app", "cryptex1.safari-downlevel"]
Пошук їх у великому масштабі по firmware images надзвичайно цінний для attack surface mapping і diffing між релізами/пристроями.
## Scaling across IPSWs (mounting and indexing)
Щоб перерахувати виконувані файли та витягнути entitlements у масштабі без зберігання повних образів:
- Використовуйте ipsw tool від @blacktop для завантаження і монтування файлових систем прошивки. Монтування використовує apfs-fuse, тож ви можете обходити APFS томи без повного витягання.
```bash
# Download latest IPSW for iPhone11,2 (iPhone XS)
ipsw download ipsw -y --device iPhone11,2 --latest
# Mount IPSW filesystem (uses underlying apfs-fuse)
ipsw mount fs <IPSW_FILE>
```
- Переглядайте змонтовані томи, щоб знайти Mach-O файли (перевіряючи magic та/або використовуючи file/otool), а потім проаналізуйте entitlements та імпортовані frameworks.
- Зберігайте нормалізований вигляд у реляційній базі даних, щоб уникнути лінійного росту при тисячах IPSWs:
- executables, operating_system_versions, entitlements, frameworks
- many-to-many: executable↔OS version, executable↔entitlement, executable↔framework
Приклад запиту, щоб перерахувати всі версії ОС, які містять задане ім'я executable:
```sql
SELECT osv.version AS "Versions"
FROM device d
LEFT JOIN operating_system_version osv ON osv.device_id = d.id
LEFT JOIN executable_operating_system_version eosv ON eosv.operating_system_version_id = osv.id
LEFT JOIN executable e ON e.id = eosv.executable_id
WHERE e.name = "launchd";
```
Примітки щодо портативності БД (якщо ви реалізуєте власний індексер):
- Використовуйте ORM/абстракцію (наприклад, SeaORM), щоб зробити код незалежним від БД (SQLite/PostgreSQL).
- SQLite вимагає AUTOINCREMENT лише для INTEGER PRIMARY KEY; якщо ви хочете i64 PK у Rust, генеруйте сутності як i32 і конвертуйте типи — SQLite внутрішньо зберігає INTEGER як 8-байтове знакове значення.
## Open-source tooling and references for entitlement hunting
- Firmware mount/download: https://github.com/blacktop/ipsw
- Entitlement databases and references:
- Jonathan Levins entitlement DB: https://newosxbook.com/ent.php
- entdb: https://github.com/ChiChou/entdb
- Large-scale indexer (Rust, self-hosted Web UI + OpenAPI): https://github.com/synacktiv/appledb_rs
- Apple headers for structures and constants:
- loader.h (Mach-O headers, load commands)
- cs_blobs.h (SuperBlob, GenericBlob, CodeDirectory)
For more on code signing internals (Code Directory, special slots, DER entitlements), see: [macOS Code Signing](../../../macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-code-signing.md)
## References
- [appledb_rs: a research support tool for Apple platforms](https://www.synacktiv.com/publications/appledbrs-un-outil-daide-a-la-recherche-sur-plateformes-apple.html)
- [synacktiv/appledb_rs](https://github.com/synacktiv/appledb_rs)
- [blacktop/ipsw](https://github.com/blacktop/ipsw)
- [Jonathan Levins entitlement DB](https://newosxbook.com/ent.php)
- [ChiChou/entdb](https://github.com/ChiChou/entdb)
- [XNU cs_blobs.h](https://github.com/apple-oss-distributions/xnu/blob/main/osfmk/kern/cs_blobs.h)
- [XNU mach-o/loader.h](https://github.com/apple-oss-distributions/xnu/blob/main/EXTERNAL_HEADERS/mach-o/loader.h)
- [SQLite Datatypes](https://sqlite.org/datatype3.html)
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -1,61 +1,61 @@
# macOS Universal binaries & Mach-O Format
# macOS Універсальні бінарні файли та формат Mach-O
{{#include ../../../banners/hacktricks-training.md}}
## Basic Information
## Основна інформація
Mac OS бінарники зазвичай компілюються як **універсальні бінарники**. **Універсальний бінарник** може **підтримувати кілька архітектур в одному файлі**.
Бінарні файли Mac OS зазвичай компілюються як **універсальні бінарні файли**. **Універсальний бінарний файл** може **підтримувати кілька архітектур в одному файлі**.
Ці бінарники слідують **Mach-O структурі**, яка в основному складається з:
Ці бінарні файли слідують структурі **Mach-O**, яка в основному складається з:
- Заголовка
- Команд завантаження
- Даних
- Заголовок
- Команди завантаження
- Дані
![https://alexdremov.me/content/images/2022/10/6XLCD.gif](<../../../images/image (470).png>)
## Fat Header
Шукайте файл за допомогою: `mdfind fat.h | grep -i mach-o | grep -E "fat.h$"`
Search for the file with: `mdfind fat.h | grep -i mach-o | grep -E "fat.h$"`
<pre class="language-c"><code class="lang-c"><strong>#define FAT_MAGIC 0xcafebabe
</strong><strong>#define FAT_CIGAM 0xbebafeca /* NXSwapLong(FAT_MAGIC) */
</strong>
struct fat_header {
<strong> uint32_t magic; /* FAT_MAGIC або FAT_MAGIC_64 */
</strong><strong> uint32_t nfat_arch; /* кількість структур, що слідують */
<strong> uint32_t magic; /* FAT_MAGIC or FAT_MAGIC_64 */
</strong><strong> uint32_t nfat_arch; /* number of structs that follow */
</strong>};
struct fat_arch {
cpu_type_t cputype; /* специфікатор процесора (int) */
cpu_subtype_t cpusubtype; /* специфікатор машини (int) */
uint32_t offset; /* зсув файлу до цього об'єктного файлу */
uint32_t size; /* розмір цього об'єктного файлу */
uint32_t align; /* вирівнювання як ступінь 2 */
cpu_type_t cputype; /* cpu specifier (int) */
cpu_subtype_t cpusubtype; /* machine specifier (int) */
uint32_t offset; /* file offset to this object file */
uint32_t size; /* size of this object file */
uint32_t align; /* alignment as a power of 2 */
};
</code></pre>
Заголовок має **магічні** байти, за якими слідує **число** **архітектур**, які файл **містить** (`nfat_arch`), і кожна архітектура матиме структуру `fat_arch`.
Заголовок містить **magic**-байти, за якими йде **кількість** **архітектур**, які **містить** файл (`nfat_arch`), і для кожної архітектури існує структура `fat_arch`.
Перевірте це за допомогою:
Перевірити це можна за допомогою:
<pre class="language-shell-session"><code class="lang-shell-session">% file /bin/ls
/bin/ls: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64e:Mach-O 64-bit executable arm64e]
/bin/ls (для архітектури x86_64): Mach-O 64-bit executable x86_64
/bin/ls (для архітектури arm64e): Mach-O 64-bit executable arm64e
/bin/ls (for architecture x86_64): Mach-O 64-bit executable x86_64
/bin/ls (for architecture arm64e): Mach-O 64-bit executable arm64e
% otool -f -v /bin/ls
Fat headers
fat_magic FAT_MAGIC
<strong>nfat_arch 2
</strong><strong>архітектура x86_64
</strong><strong>architecture x86_64
</strong> cputype CPU_TYPE_X86_64
cpusubtype CPU_SUBTYPE_X86_64_ALL
capabilities 0x0
<strong> offset 16384
</strong><strong> size 72896
</strong> align 2^14 (16384)
<strong>архітектура arm64e
<strong>architecture arm64e
</strong> cputype CPU_TYPE_ARM64
cpusubtype CPU_SUBTYPE_ARM64E
capabilities PTR_AUTH_VERSION USERSPACE 0
@ -64,15 +64,15 @@ capabilities PTR_AUTH_VERSION USERSPACE 0
</strong> align 2^14 (16384)
</code></pre>
або за допомогою інструменту [Mach-O View](https://sourceforge.net/projects/machoview/):
or using the [Mach-O View](https://sourceforge.net/projects/machoview/) tool:
<figure><img src="../../../images/image (1094).png" alt=""><figcaption></figcaption></figure>
Як ви, напевно, думаєте, зазвичай універсальний бінарник, скомпільований для 2 архітектур, **подвоює розмір** одного, скомпільованого лише для 1 архітектури.
Як ви, мабуть, здогадуєтеся, зазвичай універсальний бінарний файл, скомпільований для 2 архітектур, **подвоює розмір** порівняно з тим, що скомпільований лише для однієї архітектури.
## **Mach-O Header**
Заголовок містить основну інформацію про файл, таку як магічні байти для його ідентифікації як Mach-O файл та інформацію про цільову архітектуру. Ви можете знайти його за допомогою: `mdfind loader.h | grep -i mach-o | grep -E "loader.h$"`
Заголовок містить базову інформацію про файл, таку як magic-байти для ідентифікації його як Mach-O файлу та інформацію про цільову архітектуру. Ви можете знайти його в: `mdfind loader.h | grep -i mach-o | grep -E "loader.h$"`
```c
#define MH_MAGIC 0xfeedface /* the mach magic number */
#define MH_CIGAM 0xcefaedfe /* NXSwapInt(MH_MAGIC) */
@ -99,19 +99,19 @@ uint32_t flags; /* flags */
uint32_t reserved; /* reserved */
};
```
### Mach-O File Types
### Типи файлів Mach-O
Є різні типи файлів, ви можете знайти їх визначення в [**джерельному коді, наприклад, тут**](https://opensource.apple.com/source/xnu/xnu-2050.18.24/EXTERNAL_HEADERS/mach-o/loader.h). Найважливіші з них:
Існують різні типи файлів, їх можна знайти визначеними в [**source code for example here**](https://opensource.apple.com/source/xnu/xnu-2050.18.24/EXTERNAL_HEADERS/mach-o/loader.h). Найважливіші з них:
- `MH_OBJECT`: Переміщуваний об'єктний файл (проміжні продукти компіляції, ще не виконувані).
- `MH_OBJECT`: Relocatable object file (intermediate products of compilation, not executables yet).
- `MH_EXECUTE`: Виконувані файли.
- `MH_FVMLIB`: Фіксований файл бібліотеки VM.
- `MH_CORE`: Знімки коду
- `MH_FVMLIB`: Файл бібліотеки Fixed VM.
- `MH_CORE`: Дампи коду
- `MH_PRELOAD`: Попередньо завантажений виконуваний файл (більше не підтримується в XNU)
- `MH_DYLIB`: Динамічні бібліотеки
- `MH_DYLINKER`: Динамічний зв'язувач
- `MH_BUNDLE`: "Файли плагінів". Генеруються за допомогою -bundle в gcc і явно завантажуються за допомогою `NSBundle` або `dlopen`.
- `MH_DYSM`: Супутній файл `.dSym` (файл з символами для налагодження).
- `MH_DYLINKER`: Динамічний лінкер
- `MH_BUNDLE`: "Plugin files". Генеруються за допомогою -bundle в gcc і явно завантажуються через `NSBundle` або `dlopen`.
- `MH_DYSM`: Супутній `.dSym` файл (файл із символами для налагодження).
- `MH_KEXT_BUNDLE`: Розширення ядра.
```bash
# Checking the mac header of a binary
@ -124,71 +124,71 @@ MH_MAGIC_64 ARM64 E USR00 EXECUTE 19 1728 NOUNDEFS DY
<figure><img src="../../../images/image (1133).png" alt=""><figcaption></figcaption></figure>
## **Mach-O Прапори**
## **Mach-O прапори**
Джерельний код також визначає кілька прапорів, корисних для завантаження бібліотек:
Исходний код також визначає кілька прапорів, корисних для завантаження бібліотек:
- `MH_NOUNDEFS`: Немає невизначених посилань (повністю зв'язано)
- `MH_DYLDLINK`: Зв'язування Dyld
- `MH_NOUNDEFS`: Немає невизначених посилань (повністю зв'язаний)
- `MH_DYLDLINK`: Dyld лінкування
- `MH_PREBOUND`: Динамічні посилання попередньо зв'язані.
- `MH_SPLIT_SEGS`: Файл розділяє сегменти r/o та r/w.
- `MH_WEAK_DEFINES`: Бінарний файл має слабко визначені символи
- `MH_BINDS_TO_WEAK`: Бінарний файл використовує слабкі символи
- `MH_ALLOW_STACK_EXECUTION`: Зробити стек виконуваним
- `MH_NO_REEXPORTED_DYLIBS`: Бібліотека не має команд LC_REEXPORT
- `MH_PIE`: Виконуваний файл, незалежний від позиції
- `MH_HAS_TLV_DESCRIPTORS`: Є секція з локальними змінними потоку
- `MH_NO_HEAP_EXECUTION`: Немає виконання для сторінок купи/даних
- `MH_HAS_OBJC`: Бінарний файл має секції oBject-C
- `MH_SIM_SUPPORT`: Підтримка емулятора
- `MH_SPLIT_SEGS`: Файл розділяє r/o та r/w сегменти.
- `MH_WEAK_DEFINES`: Бінарний файл має слабо визначені символи
- `MH_BINDS_TO_WEAK`: Бінарний файл використовує weak символи
- `MH_ALLOW_STACK_EXECUTION`: Дозволяє виконання коду на стеку
- `MH_NO_REEXPORTED_DYLIBS`: Бібліотека без команд LC_REEXPORT
- `MH_PIE`: Position Independent Executable
- `MH_HAS_TLV_DESCRIPTORS`: Є секція з thread-local змінними
- `MH_NO_HEAP_EXECUTION`: Заборонено виконання на сторінках heap/даних
- `MH_HAS_OBJC`: Бінарний файл містить секції Objective-C
- `MH_SIM_SUPPORT`: Підтримка симулятора
- `MH_DYLIB_IN_CACHE`: Використовується для dylibs/frameworks у кеші спільних бібліотек.
## **Команди завантаження Mach-O**
**Розташування файлу в пам'яті** вказується тут, детально описуючи **місцезнаходження таблиці символів**, контекст основного потоку на початку виконання та необхідні **спільні бібліотеки**. Інструкції надаються динамічному завантажувачу **(dyld)** щодо процесу завантаження бінарного файлу в пам'ять.
Тут визначається розташування файлу в пам'яті, з детальним описом розташування таблиці символів, контексту головного потоку на початку виконання та необхідних спільних бібліотек. Надаються інструкції динамічному завантажувачу (dyld) щодо процесу завантаження бінарного файлу в пам'ять.
Використовується структура **load_command**, визначена в згаданому **`loader.h`**:
Використовується структура `load_command`, визначена у згаданому `loader.h`:
```objectivec
struct load_command {
uint32_t cmd; /* type of load command */
uint32_t cmdsize; /* total size of command in bytes */
};
```
Є близько **50 різних типів команд завантаження**, які система обробляє по-різному. Найпоширеніші з них: `LC_SEGMENT_64`, `LC_LOAD_DYLINKER`, `LC_MAIN`, `LC_LOAD_DYLIB` та `LC_CODE_SIGNATURE`.
There are about **50 different types of load commands** that the system handles differently. The most common ones are: `LC_SEGMENT_64`, `LC_LOAD_DYLINKER`, `LC_MAIN`, `LC_LOAD_DYLIB`, and `LC_CODE_SIGNATURE`.
### **LC_SEGMENT/LC_SEGMENT_64**
> [!TIP]
> В основному, цей тип команди завантаження визначає **як завантажити \_\_TEXT** (виконуваний код) **та \_\_DATA** (дані для процесу) **сегменти** відповідно до **зсувів, вказаних у секції даних** під час виконання бінарного файлу.
> По суті, цей тип Load Command визначає, **як завантажувати сегменти \_\_TEXT** (виконуваний код) **та \_\_DATA** (дані процесу) **відповідно до зсувів, вказаних у секції даних**, коли бінарник виконується.
Ці команди **визначають сегменти**, які **відображаються** у **віртуальному адресному просторі** процесу під час його виконання.
Ці команди **визначають сегменти**, які **відображаються** в **віртуальній пам'яті процесу** під час його виконання.
Існують **різні типи** сегментів, такі як сегмент **\_\_TEXT**, який містить виконуваний код програми, та сегмент **\_\_DATA**, який містить дані, що використовуються процесом. Ці **сегменти розташовані в секції даних** файлу Mach-O.
Існують **різні типи** сегментів, наприклад сегмент **\_\_TEXT**, який містить виконуваний код програми, та сегмент **\_\_DATA**, який містить дані, що використовуються процесом. Ці **сегменти знаходяться в секції даних** файлу Mach-O.
**Кожен сегмент** може бути додатково **поділений** на кілька **секцій**. **Структура команди завантаження** містить **інформацію** про **ці секції** в межах відповідного сегмента.
**Кожен сегмент** може бути додатково **поділений** на кілька **секцій**. **Структура load command** містить **інформацію** про **ці секції** в межах відповідного сегменту.
У заголовку спочатку ви знайдете **заголовок сегмента**:
У заголовку спочатку знаходиться **segment header**:
<pre class="language-c"><code class="lang-c">struct segment_command_64 { /* для 64-бітних архітектур */
<pre class="language-c"><code class="lang-c">struct segment_command_64 { /* for 64-bit architectures */
uint32_t cmd; /* LC_SEGMENT_64 */
uint32_t cmdsize; /* включає sizeof section_64 structs */
char segname[16]; /* ім'я сегмента */
uint64_t vmaddr; /* адреса пам'яті цього сегмента */
uint64_t vmsize; /* розмір пам'яті цього сегмента */
uint64_t fileoff; /* зсув файлу цього сегмента */
uint64_t filesize; /* кількість для відображення з файлу */
int32_t maxprot; /* максимальний захист VM */
int32_t initprot; /* початковий захист VM */
<strong> uint32_t nsects; /* кількість секцій у сегменті */
</strong> uint32_t flags; /* прапори */
uint32_t cmdsize; /* includes sizeof section_64 structs */
char segname[16]; /* segment name */
uint64_t vmaddr; /* memory address of this segment */
uint64_t vmsize; /* memory size of this segment */
uint64_t fileoff; /* file offset of this segment */
uint64_t filesize; /* amount to map from the file */
int32_t maxprot; /* maximum VM protection */
int32_t initprot; /* initial VM protection */
<strong> uint32_t nsects; /* number of sections in segment */
</strong> uint32_t flags; /* flags */
};
</code></pre>
Приклад заголовка сегмента:
Example of segment header:
<figure><img src="../../../images/image (1126).png" alt=""><figcaption></figcaption></figure>
Цей заголовок визначає **кількість секцій, заголовки яких з'являються після** нього:
Цей заголовок визначає **кількість секцій**, заголовки яких з'являються після нього:
```c
struct section_64 { /* for 64-bit architectures */
char sectname[16]; /* name of this section */
@ -205,62 +205,62 @@ uint32_t reserved2; /* reserved (for count or sizeof) */
uint32_t reserved3; /* reserved */
};
```
Приклад **заголовка секції**:
Приклад **section header**:
<figure><img src="../../../images/image (1108).png" alt=""><figcaption></figcaption></figure>
Якщо ви **додасте** **зсув секції** (0x37DC) + **зсув**, де **архітектура починається**, в цьому випадку `0x18000` --> `0x37DC + 0x18000 = 0x1B7DC`
Якщо ви **додасте** **section offset** (0x37DC) до **offset**, де **arch starts** (у цьому випадку `0x18000`) --> `0x37DC + 0x18000 = 0x1B7DC`
<figure><img src="../../../images/image (701).png" alt=""><figcaption></figcaption></figure>
Також можливо отримати **інформацію про заголовки** з **командного рядка** за допомогою:
Також можна отримати **headers information** з **command line** за допомогою:
```bash
otool -lv /bin/ls
```
Загальні сегменти, завантажені цим cmd:
Common segments loaded by this cmd:
- **`__PAGEZERO`:** Він інструктує ядро **відобразити** **адресу нуль** так, щоб вона **не могла бути прочитана, записана або виконана**. Змінні maxprot і minprot у структурі встановлені в нуль, щоб вказати, що **немає прав на читання-запис-виконання на цій сторінці**.
- Це виділення важливе для **зменшення вразливостей, пов'язаних з розіменуванням нульових вказівників**. Це пов'язано з тим, що XNU забезпечує жорстку нульову сторінку, яка гарантує, що перша сторінка (тільки перша) пам'яті недоступна (за винятком i386). Бінарний файл може виконати ці вимоги, створивши невелику \_\_PAGEZERO (використовуючи `-pagezero_size`), щоб покрити перші 4k, а решта 32-бітної пам'яті була доступна як в режимі користувача, так і в режимі ядра.
- **`__TEXT`**: Містить **виконуваний** **код** з **правами на читання** та **виконання** (без запису)**.** Загальні секції цього сегмента:
- **`__PAGEZERO`:** Він інструктує ядро **відобразити** адресу нуль так, щоб її **не можна було читати, записувати або виконувати**. Змінні maxprot і minprot у структурі встановлені в нуль, щоб вказати, що на цій сторінці **немає прав на читання-запис-виконання**.
- Це виділення важливе для **пом’якшення вразливостей через dereference NULL pointer**. Це тому, що XNU накладає жорстку сторінку нуля, яка забезпечує, що перша сторінка (тільки перша) пам’яті недоступна (за винятком i386). Бінарник може виконати цю вимогу, створивши невеликий \_\_PAGEZERO (використовуючи `-pagezero_size`) щоб покрити перші 4k і зробивши решту 32-бітної пам’яті доступною як у користувацькому, так і в ядровому режимі.
- **`__TEXT`**: Містить **виконуваний** **код** з правами **читання** та **виконання** (без запису)**.** Звичайні секції цього сегмента:
- `__text`: Скомпільований бінарний код
- `__const`: Константні дані (тільки для читання)
- `__[c/u/os_log]string`: Константи рядків C, Unicode або os logs
- `__stubs` та `__stubs_helper`: Бере участь у процесі завантаження динамічної бібліотеки
- `__unwind_info`: Дані про розгортання стеку.
- Зверніть увагу, що весь цей вміст підписаний, але також позначений як виконуваний (створюючи більше можливостей для експлуатації секцій, які не обов'язково потребують цього привілею, як секції, присвячені рядкам).
- **`__DATA`**: Містить дані, які є **читабельними** та **записуваними** (без виконуваних)**.**
- `__got:` Глобальна таблиця зсувів
- `__nl_symbol_ptr`: Неледачний (прив'язка при завантаженні) вказівник символу
- `__la_symbol_ptr`: Ледачий (прив'язка при використанні) вказівник символу
- `__const`: Має бути даними тільки для читання (насправді не так)
- `__cfstring`: Рядки CoreFoundation
- `__[c/u/os_log]string`: C, Unicode або os log рядкові константи
- `__stubs` і `__stubs_helper`: Залучені під час динамічного завантаження бібліотек
- `__unwind_info`: Дані для розгортання стеку (stack unwind)
- Зауважте, що весь цей вміст підписаний, але також позначений як виконуваний (що створює більше опцій для експлуатації секцій, які фактично не потребують цього привілею, наприклад секції, присвячені рядкам).
- **`__DATA`**: Містить дані, які **можна читати** і **записувати** (без виконання)**.**
- `__got:` Global Offset Table
- `__nl_symbol_ptr`: Non lazy (bind at load) symbol pointer
- `__la_symbol_ptr`: Lazy (bind on use) symbol pointer
- `__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: Переміщення, неледачні/ледачі/слабкі коди прив'язки та інформація про експорт
- Початок функцій: Таблиця початкових адрес функцій
- Дані в коді: Острівці даних у \_\_text
- Таблиця символів: Символи в бінарному файлі
- Таблиця непрямих символів: Вказівники/стаб символів
- Таблиця рядків
- Код підпису
- **`__OBJC`**: Містить інформацію, що використовується середовищем виконання Objective-C. Хоча ця інформація також може бути знайдена в сегменті \_\_DATA, в різних секціях \_\_objc\_\*.
- **`__RESTRICT`**: Сегмент без вмісту з єдиною секцією, що називається **`__restrict`** (також порожня), яка забезпечує, що при виконанні бінарного файлу він ігноруватиме змінні середовища DYLD.
- `__objc_*` (\_\_objc_classlist, \_\_objc_protolist, etc): Інформація, що використовується рантаймом Objective-C
- **`__DATA_CONST`**: \_\_DATA.\_\_const не гарантується як константа (має права на запис), так само як і інші покажчики та GOT. Цей сегмент робить `__const`, деякі ініціалізатори та таблицю GOT (після її розв’язання) **тільки для читання** за допомогою `mprotect`.
- **`__LINKEDIT`**: Містить інформацію для лінкера (dyld), таку як таблиці символів, рядків та записів релокацій. Це загальний контейнер для вмісту, який не входить до `__TEXT` або `__DATA`, і його вміст описується в інших load командах.
- dyld information: Rebase, опкоди non-lazy/lazy/weak binding та інформація про export
- Початки функцій: Таблиця адрес початку функцій
- Data In Code: Острови даних у \_\_text
- Таблиця символів: Символи у бінарному файлі
- Indirect Symbol Table: Показникові/заглушкові символи
- String Table
- Code Signature
- **`__OBJC`**: Містить інформацію, яку використовує рантайм Objective-C. Хоча ця інформація також може бути знайдена в сегменті \_\_DATA, у різних секціях \_\_objc\_\*.
- **`__RESTRICT`**: Сегмент без вмісту з єдиною секцією під назвою **`__restrict`** (також порожньою), який гарантує, що при виконанні бінарника він ігноруватиме DYLD змінні середовища.
Як було видно в коді, **сегменти також підтримують прапорці** (хоча вони не використовуються дуже часто):
As it was possible to see in the code, **segments also support flags** (although they aren't used very much):
- `SG_HIGHVM`: Тільки ядро (не використовується)
- `SG_FVMLIB`: Не використовується
- `SG_NORELOC`: Сегмент не має переміщення
- `SG_PROTECTED_VERSION_1`: Шифрування. Використовується, наприклад, Finder для шифрування тексту сегмента `__TEXT`.
- `SG_NORELOC`: Сегмент не має релокацій
- `SG_PROTECTED_VERSION_1`: Шифрування. Використовується, наприклад, Finder для шифрування текстового сегмента `__TEXT`.
### **`LC_UNIXTHREAD/LC_MAIN`**
**`LC_MAIN`** містить точку входу в **атрибуті entryoff.** Під час завантаження **dyld** просто **додає** це значення до (в пам'яті) **бази бінарного файлу**, а потім **переходить** до цієї інструкції, щоб почати виконання коду бінарного файлу.
**`LC_MAIN`** містить точку входу в атрибуті **entryoff.** Під час завантаження **`dyld`** просто **додає** це значення до (в пам’яті) **бази бінарника**, після чого **переходить** до цієї інструкції, щоб розпочати виконання коду бінарника.
**`LC_UNIXTHREAD`** містить значення, які повинні мати регістри при запуску основного потоку. Це вже застаріло, але **`dyld`** все ще використовує це. Можна побачити значення регістрів, встановлені цим:
**`LC_UNIXTHREAD`** містить значення, які повинні бути встановлені у регістрах при запуску головного потоку. Воно вже застаріле, але **`dyld`** все ще його використовує. Можна побачити значення регістрів, встановлені цим, за допомогою:
```bash
otool -l /usr/lib/dyld
[...]
@ -286,34 +286,39 @@ cpsr 0x00000000
```
### **`LC_CODE_SIGNATURE`**
Містить інформацію про **код підпису файлу Macho-O**. Він містить лише **зсув**, який **вказує** на **блоб підпису**. Це зазвичай знаходиться в самому кінці файлу.\
Однак ви можете знайти деяку інформацію про цей розділ у [**цьому блозі**](https://davedelong.com/blog/2018/01/10/reading-your-own-entitlements/) та у [**цих гістах**](https://gist.github.com/carlospolop/ef26f8eb9fafd4bc22e69e1a32b81da4).
{{#ref}}
../../../generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/mach-o-entitlements-and-ipsw-indexing.md
{{#endref}}
Містить інформацію про **code signature файлу Mach-O**. Воно містить лише **offset**, який **вказує** на **signature blob**. Зазвичай це розташовано в самому кінці файлу.\
However, you can find some information about this section in [**this blog post**](https://davedelong.com/blog/2018/01/10/reading-your-own-entitlements/) and this [**gists**](https://gist.github.com/carlospolop/ef26f8eb9fafd4bc22e69e1a32b81da4).
### **`LC_ENCRYPTION_INFO[_64]`**
Підтримка шифрування бінарних файлів. Однак, звичайно, якщо зловмисник зможе скомпрометувати процес, він зможе скинути пам'ять у незашифрованому вигляді.
Підтримка шифрування бінарників. Проте, якщо зловмисникові вдасться скомпрометувати процес, він зможе дампнути пам'ять у незашифрованому вигляді.
### **`LC_LOAD_DYLINKER`**
Містить **шлях до виконуваного файлу динамічного зв'язувача**, який відображає спільні бібліотеки в адресному просторі процесу. **Значення завжди встановлюється на `/usr/lib/dyld`**. Важливо зазначити, що в macOS, відображення dylib відбувається в **режимі користувача**, а не в режимі ядра.
Містить **шлях до виконуваного файлу dynamic linker**, який відображає shared libraries в адресний простір процесу. The **value is always set to `/usr/lib/dyld`**. Важливо зазначити, що в macOS відображення dylib відбувається в **user mode**, а не в kernel mode.
### **`LC_IDENT`**
Застарілий, але коли налаштований для генерації дампів при паніці, створюється дамп ядра Mach-O, і версія ядра встановлюється в команді `LC_IDENT`.
Застарілий, але коли налаштовано генерацію дампів при panic, створюється Mach-O core dump і версія ядра встановлюється в команді `LC_IDENT`.
### **`LC_UUID`**
Випадковий UUID. Він корисний для чого завгодно, але XNU кешує його разом з рештою інформації про процес. Його можна використовувати в звітах про збої.
Випадковий UUID. Прямого широкого застосування немає, але XNU кешує його разом з рештою інформації про процес. Може використовуватись у crash reports.
### **`LC_DYLD_ENVIRONMENT`**
Дозволяє вказати змінні середовища для dyld перед виконанням процесу. Це може бути дуже небезпечно, оскільки може дозволити виконувати довільний код всередині процесу, тому ця команда завантаження використовується лише в dyld, зібраному з `#define SUPPORT_LC_DYLD_ENVIRONMENT`, і додатково обмежує обробку лише змінними у формі `DYLD_..._PATH`, що вказують шляхи завантаження.
Дозволяє вказати змінні оточення для dyld перед запуском процесу. Це може бути досить небезпечно, оскільки дозволяє виконати довільний код всередині процесу, тому ця load command використовується лише в збірках dyld з `#define SUPPORT_LC_DYLD_ENVIRONMENT` і додатково обмежує обробку лише змінними у формі `DYLD_..._PATH`, які задають шляхи завантаження.
### **`LC_LOAD_DYLIB`**
Ця команда завантаження описує залежність **динамічної** **бібліотеки**, яка **інструктує** **завантажувач** (dyld) **завантажити та зв'язати цю бібліотеку**. Існує команда завантаження `LC_LOAD_DYLIB` **для кожної бібліотеки**, яка потрібна бінарному файлу Mach-O.
Ця load command описує залежність від **dynamic** **library**, яка **наказує** **loader** (dyld) **завантажити та зв'язати цю бібліотеку**. Існує команда `LC_LOAD_DYLIB` **для кожної бібліотеки**, яку вимагає Mach-O бінар.
- Ця команда завантаження є структурою типу **`dylib_command`** (яка містить структуру dylib, що описує фактичну залежну динамічну бібліотеку):
- Ця load command — структура типу **`dylib_command`** (яка містить struct dylib, що описує власне залежну dynamic library):
```objectivec
struct dylib_command {
uint32_t cmd; /* LC_LOAD_{,WEAK_}DYLIB */
@ -330,7 +335,7 @@ uint32_t compatibility_version; /* library's compatibility vers number*/
```
![](<../../../images/image (486).png>)
Ви також можете отримати цю інформацію з командного рядка за допомогою:
Ви також можете отримати цю інформацію з cli за допомогою:
```bash
otool -L /bin/ls
/bin/ls:
@ -338,32 +343,32 @@ otool -L /bin/ls
/usr/lib/libncurses.5.4.dylib (compatibility version 5.4.0, current version 5.4.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.0.0)
```
Деякі потенційні бібліотеки, пов'язані з шкідливим ПЗ:
Деякі потенційні бібліотеки, пов'язані з malware:
- **DiskArbitration**: Моніторинг USB-накопичувачів
- **AVFoundation:** Захоплення аудіо та відео
- **CoreWLAN**: Сканування Wifi.
> [!NOTE]
> Mach-O бінарний файл може містити один або **більше** **конструкторів**, які будуть **виконані** **перед** адресою, вказаною в **LC_MAIN**.\
> Зсуви будь-яких конструкторів зберігаються в секції **\_\_mod_init_func** сегмента **\_\_DATA_CONST**.
## **Дані Mach-O**
В основі файлу лежить регіон даних, який складається з кількох сегментів, як визначено в регіоні команд завантаження. **Різноманітні секції даних можуть бути розміщені в кожному сегменті**, при цьому кожна секція **містить код або дані**, специфічні для певного типу.
- **CoreWLAN**: Сканування WiFi
> [!TIP]
> Дані в основному є частиною, що містить всю **інформацію**, яка завантажується командами завантаження **LC_SEGMENTS_64**
> A Mach-O binary can contain one or **more** **constructors**, that will be **executed** **before** the address specified in **LC_MAIN**.\
> The offsets of any constructors are held in the **\_\_mod_init_func** section of the **\_\_DATA_CONST** segment.
## **Mach-O Дані**
У центрі файлу знаходиться область даних, яка складається з кількох сегментів, як визначено в області load-commands. **У кожному сегменті може міститися різноманіття секцій даних**, причому кожна секція **містить код або дані**, специфічні для певного типу.
> [!TIP]
> The data is basically the part containing all the **information** that is loaded by the load commands **LC_SEGMENTS_64**
![https://www.oreilly.com/api/v2/epubs/9781785883378/files/graphics/B05055_02_38.jpg](<../../../images/image (507) (3).png>)
Це включає:
- **Таблиця функцій:** Яка містить інформацію про функції програми.
- **Таблиця символів**: Яка містить інформацію про зовнішні функції, що використовуються бінарним файлом
- Вона також може містити внутрішні функції, імена змінних та інше.
- **Function table:** Яка містить інформацію про функції програми.
- **Symbol table**: Яка містить інформацію про зовнішні функції, що використовуються бінарним файлом
- Також може містити імена внутрішніх функцій, змінних та інше.
Щоб перевірити це, ви можете використовувати інструмент [**Mach-O View**](https://sourceforge.net/projects/machoview/):
Щоб перевірити це, ви можете використати інструмент [**Mach-O View**](https://sourceforge.net/projects/machoview/):
<figure><img src="../../../images/image (1120).png" alt=""><figcaption></figcaption></figure>
@ -371,20 +376,20 @@ otool -L /bin/ls
```bash
size -m /bin/ls
```
## Objetive-C Загальні Розділи
## Objetive-C Common Sections
В `__TEXT` сегменті (r-x):
У `__TEXT` сегменті (r-x):
- `__objc_classname`: Імена класів (рядки)
- `__objc_methname`: Імена методів (рядки)
- `__objc_methtype`: Типи методів (рядки)
В `__DATA` сегменті (rw-):
У `__DATA` сегменті (rw-):
- `__objc_classlist`: Вказівники на всі класи Objective-C
- `__objc_nlclslist`: Вказівники на не-ліниві класи Objective-C
- `__objc_catlist`: Вказівник на категорії
- `__objc_nlcatlist`: Вказівник на не-ліниві категорії
- `__objc_classlist`: Вказівники на всі Objetive-C класи
- `__objc_nlclslist`: Вказівники на Non-Lazy Objective-C класи
- `__objc_catlist`: Вказівник на Categories
- `__objc_nlcatlist`: Вказівник на Non-Lazy Categories
- `__objc_protolist`: Список протоколів
- `__objc_const`: Константні дані
- `__objc_imageinfo`, `__objc_selrefs`, `objc__protorefs`...

View File

@ -2,14 +2,19 @@
{{#include ../../../banners/hacktricks-training.md}}
## Basic Information
## Базова інформація
Mach-o бінарники містять команду завантаження під назвою **`LC_CODE_SIGNATURE`**, яка вказує на **зсув** та **розмір** підписів всередині бінарника. Насправді, використовуючи графічний інструмент MachOView, можна знайти в кінці бінарника розділ під назвою **Code Signature** з цією інформацією:
{{#ref}}
../../../generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/mach-o-entitlements-and-ipsw-indexing.md
{{#endref}}
Mach-o бінарні файли містять load command під назвою **`LC_CODE_SIGNATURE`**, який вказує **offset** і **size** підписів всередині бінарного файлу. Насправді, використовуючи GUI-інструмент MachOView, можна знайти в кінці бінарного файлу розділ під назвою **Code Signature** з цією інформацією:
<figure><img src="../../../images/image (1) (1) (1) (1).png" alt="" width="431"><figcaption></figcaption></figure>
Магічний заголовок підпису коду - **`0xFADE0CC0`**. Потім ви отримуєте інформацію, таку як довжина та кількість блобів суперBlob, які їх містять.\
Цю інформацію можна знайти в [джерельному коді тут](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/kern/cs_blobs.h#L276):
Магічний заголовок Code Signature — **`0xFADE0CC0`**. Далі міститься інформація, така як довжина та кількість blobs суперBlob, який їх містить.\
It's possible to find this information in the [source code here](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/kern/cs_blobs.h#L276):
```c
/*
* Structure of an embedded-signature SuperBlob
@ -38,14 +43,14 @@ char data[];
} CS_GenericBlob
__attribute__ ((aligned(1)));
```
Звичайні об'єкти, що містяться, це Директорія Коду, Вимоги та Права, а також Синтаксис Криптографічного Повідомлення (CMS).\
Крім того, зверніть увагу, як дані, закодовані в об'єктах, закодовані в **Big Endian.**
Типові blobs включають Code Directory, Requirements та Entitlements, а також Cryptographic Message Syntax (CMS).\
Зверніть увагу, що дані, закодовані в blobs, записані у **Big Endian.**
Крім того, підписи можуть бути відокремлені від бінарних файлів і зберігатися в `/var/db/DetachedSignatures` (використовується iOS).
Крім того, підписи можуть бути відокремлені від бінарних файлів і збережені в `/var/db/DetachedSignatures` (використовується iOS).
## Об'єкт Директорії Коду
## Code Directory Blob
Можна знайти декларацію [Об'єкта Директорії Коду в коді](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/kern/cs_blobs.h#L104):
It's possible to find the declaration of the [Code Directory Blob in the code](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/kern/cs_blobs.h#L104):
```c
typedef struct __CodeDirectory {
uint32_t magic; /* magic number (CSMAGIC_CODEDIRECTORY) */
@ -101,12 +106,12 @@ char end_withLinkage[0];
} CS_CodeDirectory
__attribute__ ((aligned(1)));
```
Зверніть увагу, що існують різні версії цієї структури, де старі можуть містити менше інформації.
Note that there are different versions of this struct where old ones might contain less information.
## Сторінки підпису коду
## Signing Code Pages
Хешування повного бінарного файлу було б неефективним і навіть марним, якщо він завантажений в пам'ять лише частково. Тому підпис коду насправді є хешем хешів, де кожна бінарна сторінка хешується окремо.\
Насправді, у попередньому коді **Code Directory** ви можете побачити, що **розмір сторінки вказано** в одному з його полів. Більше того, якщо розмір бінарного файлу не є кратним розміру сторінки, поле **CodeLimit** вказує, де закінчується підпис.
Хешування всього binary було б неефективним і навіть марним, якщо він завантажується в memory лише частково. Тому code signature фактично є hash of hashes, де кожна binary page хешується окремо.\
Насправді, у попередньому **Code Directory** коді видно, що **page size is specified** в одному з його полів. Більше того, якщо розмір binary не є кратним розміру сторінки, поле **CodeLimit** вказує, де знаходиться кінець signature.
```bash
# Get all hashes of /bin/ps
codesign -d -vvvvvv /bin/ps
@ -144,25 +149,25 @@ openssl sha256 /tmp/*.page.*
```
## Entitlements Blob
Зверніть увагу, що програми можуть також містити **entitlement blob**, де визначені всі права. Більше того, деякі бінарні файли iOS можуть мати свої права, специфічні для спеціального слота -7 (замість спеціального слота -5 для прав).
Note that applications might also contain an **entitlement blob** where all the entitlements are defined. Moreover, some iOS binaries might have their entitlements specific in the special slot -7 (instead of in the -5 entitlements special slot).
## Special Slots
## Спеціальні слоти
MacOS програми не мають всього необхідного для виконання всередині бінарного файлу, але також використовують **зовнішні ресурси** (зазвичай всередині **bundle** програми). Тому в бінарному файлі є кілька слотів, які міститимуть хеші деяких цікавих зовнішніх ресурсів, щоб перевірити, чи не були вони змінені.
MacOS applications doesn't have everything they need to execute inside the binary but they also use **external resources** (usually inside the applications **bundle**). Therefore, there are some slots inside the binary who will be containing the hashes of some interesting external resources to check they weren't modified.
Насправді, в структурах Code Directory можна побачити параметр **`nSpecialSlots`**, який вказує на кількість спеціальних слотів. Спеціального слота 0 немає, а найпоширеніші (від -1 до -6) це:
Actually, it's possible to see in the Code Directory structs a parameter called **`nSpecialSlots`** indicating the number of the special slots. The there isn't a special slot 0 and the most common ones (from -1 to -6 are):
- Хеш `info.plist` (або той, що всередині `__TEXT.__info__plist`).
- Хеш вимог
- Хеш каталогу ресурсів (хеш файлу `_CodeSignature/CodeResources` всередині bundle).
- Специфічний для програми (не використовується)
- Хеш прав
- Тільки DMG підписи коду
- Хеш `info.plist` (or the one inside `__TEXT.__info__plist`).
- Хеш Requirements
- Хеш Resource Directory (хеш файлу `_CodeSignature/CodeResources` inside the bundle).
- Application specific (unused)
- Хеш entitlements
- DMG code signatures only
- DER Entitlements
## Code Signing Flags
Кожен процес має пов'язану бітову маску, відому як `status`, яка ініціюється ядром, і деякі з них можуть бути переозначені **підписом коду**. Ці прапори, які можуть бути включені в підпис коду, [визначені в коді](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/kern/cs_blobs.h#L36):
Every process has related a bitmask known as the `status` which is started by the kernel and some of them can be overridden by the **code signature**. These flags that can be included in the code signing are [defined in the code](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/kern/cs_blobs.h#L36):
```c
/* code signing attributes of a process */
#define CS_VALID 0x00000001 /* dynamically valid */
@ -207,15 +212,15 @@ CS_RESTRICT | CS_ENFORCEMENT | CS_REQUIRE_LV | CS_RUNTIME | CS_LINKER_SIGNED)
#define CS_ENTITLEMENT_FLAGS (CS_GET_TASK_ALLOW | CS_INSTALLER | CS_DATAVAULT_CONTROLLER | CS_NVRAM_UNRESTRICTED)
```
Зверніть увагу, що функція [**exec_mach_imgact**](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/kern/kern_exec.c#L1420) також може динамічно додавати прапори `CS_EXEC_*` під час запуску виконання.
Зауважте, що функція [**exec_mach_imgact**](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/kern/kern_exec.c#L1420) також може динамічно додавати прапори `CS_EXEC_*` під час початку виконання.
## Вимоги до підпису коду
## Вимоги підпису коду
Кожен додаток зберігає деякі **вимоги**, які він повинен **виконати**, щоб мати можливість виконуватися. Якщо **вимоги додатка не виконуються**, він не буде виконаний (оскільки, ймовірно, був змінений).
Кожен додаток зберігає деякі **вимоги**, які він повинен **задовольнити**, щоб його можна було виконати. Якщо **вимоги**, що містяться в додатку, не виконуються додатком, він не буде виконаний (оскільки, ймовірно, був змінений).
Вимоги бінарного файлу використовують **спеціальну граматику**, яка є потоком **виразів** і кодуються як блоби, використовуючи `0xfade0c00` як магічне число, чий **хеш зберігається в спеціальному кодовому слоті**.
Вимоги бінарного файлу використовують **спеціальну граматику**, яка є потоком **виразів**, і кодуються як blobs з використанням `0xfade0c00` як магічного числа, хеш якого **зберігається в спеціальному слоті коду**.
Вимоги бінарного файлу можна побачити, запустивши:
Вимоги бінарного файлу можна переглянути, виконавши:
```bash
codesign -d -r- /bin/ls
Executable=/bin/ls
@ -225,10 +230,10 @@ codesign -d -r- /Applications/Signal.app/
Executable=/Applications/Signal.app/Contents/MacOS/Signal
designated => identifier "org.whispersystems.signal-desktop" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = U68MSDN6DR
```
> [!NOTE]
> Зверніть увагу, як ці підписи можуть перевіряти такі речі, як інформація про сертифікацію, TeamID, ID, права доступу та багато інших даних.
> [!TIP]
> Зверніть увагу, що ці підписи можуть перевіряти такі речі, як інформація про сертифікацію, TeamID, IDs, entitlements та багато інших даних.
Більше того, можливо згенерувати деякі скомпільовані вимоги, використовуючи інструмент `csreq`:
Крім того, можна згенерувати деякі скомпільовані вимоги за допомогою інструменту `csreq`:
```bash
# Generate compiled requirements
csreq -b /tmp/output.csreq -r='identifier "org.whispersystems.signal-desktop" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = U68MSDN6DR'
@ -240,57 +245,57 @@ od -A x -t x1 /tmp/output.csreq
0000020 00 00 00 21 6f 72 67 2e 77 68 69 73 70 65 72 73
[...]
```
Можливо отримати цю інформацію та створити або змінити вимоги за допомогою деяких API з `Security.framework`, таких як:
Можна отримати доступ до цієї інформації та створювати або змінювати вимоги за допомогою деяких API з `Security.framework`, наприклад:
#### **Перевірка дійсності**
#### **Checking Validity**
- **`Sec[Static]CodeCheckValidity`**: Перевіряє дійсність SecCodeRef відповідно до вимоги.
- **`SecRequirementEvaluate`**: Валідовує вимогу в контексті сертифіката.
- **`SecTaskValidateForRequirement`**: Валідовує запущений SecTask відповідно до вимоги `CFString`.
- **`Sec[Static]CodeCheckValidity`**: Перевіряє дійсність `SecCodeRef` відповідно до Requirement.
- **`SecRequirementEvaluate`**: Валідовує Requirement у контексті сертифікату.
- **`SecTaskValidateForRequirement`**: Валідовує запущений `SecTask` відповідно до вимоги у вигляді `CFString`.
#### **Створення та управління вимогами коду**
#### **Creating and Managing Code Requirements**
- **`SecRequirementCreateWithData`:** Створює `SecRequirementRef` з двійкових даних, що представляють вимогу.
- **`SecRequirementCreateWithString`:** Створює `SecRequirementRef` з рядкової виразу вимоги.
- **`SecRequirementCopy[Data/String]`**: Отримує двійкове представлення даних `SecRequirementRef`.
- **`SecRequirementCreateGroup`**: Створює вимогу для членства в групі додатків.
- **`SecRequirementCreateWithData`:** Створює `SecRequirementRef` з бінарних даних, що представляють вимогу.
- **`SecRequirementCreateWithString`:** Створює `SecRequirementRef` з рядкового виразу вимоги.
- **`SecRequirementCopy[Data/String]`**: Отримує бінарне подання `SecRequirementRef`.
- **`SecRequirementCreateGroup`**: Створює вимогу для членства в app-group
#### **Доступ до інформації про підпис коду**
#### **Accessing Code Signing Information**
- **`SecStaticCodeCreateWithPath`**: Ініціалізує об'єкт `SecStaticCodeRef` з шляху файлової системи для перевірки підписів коду.
- **`SecCodeCopySigningInformation`**: Отримує інформацію про підпис з `SecCodeRef` або `SecStaticCodeRef`.
- **`SecStaticCodeCreateWithPath`**: Ініціалізує об'єкт `SecStaticCodeRef` з файлового шляху для інспекції підписів коду.
- **`SecCodeCopySigningInformation`**: Отримує інформацію про підпис із `SecCodeRef` або `SecStaticCodeRef`.
#### **Модифікація вимог коду**
#### **Modifying Code Requirements**
- **`SecCodeSignerCreate`**: Створює об'єкт `SecCodeSignerRef` для виконання операцій підпису коду.
- **`SecCodeSignerSetRequirement`**: Встановлює нову вимогу для підписувача коду, яку потрібно застосувати під час підпису.
- **`SecCodeSignerAddSignature`**: Додає підпис до коду, що підписується, з вказаним підписувачем.
- **`SecCodeSignerCreate`**: Створює `SecCodeSignerRef` для виконання операцій підписування коду.
- **`SecCodeSignerSetRequirement`**: Встановлює нову вимогу для `code signer`, яка застосовується під час підписування.
- **`SecCodeSignerAddSignature`**: Додає підпис до коду, що підписується вказаним підписувачем.
#### **Валідування коду з вимогами**
#### **Validating Code with Requirements**
- **`SecStaticCodeCheckValidity`**: Валідовує статичний об'єкт коду відповідно до вказаних вимог.
- **`SecStaticCodeCheckValidity`**: Валідовує статичний об'єкт коду відповідно до зазначених вимог.
#### **Додаткові корисні API**
#### **Additional Useful APIs**
- **`SecCodeCopy[Internal/Designated]Requirement`: Отримати SecRequirementRef з SecCodeRef**
- **`SecCodeCopyGuestWithAttributes`**: Створює `SecCodeRef`, що представляє об'єкт коду на основі специфічних атрибутів, корисно для пісочниці.
- **`SecCodeCopyPath`**: Отримує шлях файлової системи, пов'язаний з `SecCodeRef`.
- **`SecCodeCopySigningIdentifier`**: Отримує ідентифікатор підпису (наприклад, Team ID) з `SecCodeRef`.
- **`SecCodeGetTypeID`**: Повертає ідентифікатор типу для об'єктів `SecCodeRef`.
- **`SecRequirementGetTypeID`**: Отримує CFTypeID `SecRequirementRef`.
- **`SecCodeCopy[Internal/Designated]Requirement`: Get SecRequirementRef from SecCodeRef**
- **`SecCodeCopyGuestWithAttributes`**: Створює `SecCodeRef`, що представляє об’єкт коду на основі певних атрибутів, корисно для sandboxing.
- **`SecCodeCopyPath`**: Отримує файловий шлях, пов’язаний із `SecCodeRef`.
- **`SecCodeCopySigningIdentifier`**: Отримує signing identifier (наприклад, Team ID) з `SecCodeRef`.
- **`SecCodeGetTypeID`**: Повертає ідентифікатор типу для обєктів `SecCodeRef`.
- **`SecRequirementGetTypeID`**: Отримує CFTypeID для `SecRequirementRef`
#### **Прапори та константи підпису коду**
#### **Code Signing Flags and Constants**
- **`kSecCSDefaultFlags`**: Значення за замовчуванням, що використовуються в багатьох функціях Security.framework для операцій підпису коду.
- **`kSecCSSigningInformation`**: Прапор, що використовується для вказівки на те, що інформацію про підпис слід отримати.
- **`kSecCSDefaultFlags`**: Прапори за замовчуванням, що використовуються у багатьох функціях `Security.framework` для операцій підписування коду.
- **`kSecCSSigningInformation`**: Прапор, що вказує на необхідність отримати інформацію про підпис.
## Примус підпису коду
## Code Signature Enforcement
**Ядро** є тим, хто **перевіряє підпис коду** перед тим, як дозволити виконання коду додатка. Більше того, один зі способів мати можливість записувати та виконувати новий код в пам'яті - це зловживання JIT, якщо `mprotect` викликано з прапором `MAP_JIT`. Зверніть увагу, що додаток потребує спеціального права для того, щоб мати можливість це робити.
Саме **ядро** перевіряє **підпис коду** перед тим, як дозволити виконання коду додатка. Крім того, одним із способів записати й виконати в пам'яті новий код є зловживання JIT, якщо `mprotect` викликається з прапором `MAP_JIT`. Зверніть увагу, що додаток потребує спеціального entitlement, щоб мати можливість це зробити.
## `cs_blobs` & `cs_blob`
[**cs_blob**](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/sys/ubc_internal.h#L106) структура містить інформацію про права, що має запущений процес. `csb_platform_binary` також інформує, чи є додаток платформним бінарним (що перевіряється в різні моменти операційною системою для застосування механізмів безпеки, таких як захист прав SEND до портів завдань цих процесів).
[**cs_blob**](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/sys/ubc_internal.h#L106) структура містить інформацію про дозволи (entitlements) запущеного процесу. `csb_platform_binary` також вказує, чи є додаток platform binary (що перевіряється ОС у різні моменти для застосування механізмів безпеки, наприклад щоб захищати SEND права до task портів цих процесів).
```c
struct cs_blob {
struct cs_blob *csb_next;