iOS Exploiting
Tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
iOS Exploit Mitigations
1. Code Signing / Runtime Signature Verification
Introduced early (iPhone OS → iOS) Це один із фундаментальних захистів: весь виконуваний код (apps, dynamic libraries, JIT-ed code, extensions, frameworks, caches) має бути криптографічно підписаний ланцюжком сертифікатів, що корениться в довірі Apple. Під час виконання, перед завантаженням бінарника в пам’ять (або перед виконанням переходів через певні межі), система перевіряє його підпис. Якщо код змінено (bit-flipped, patched) або він не підписаний, завантаження не вдається.
- Thwarts: стадію «classic payload drop + execute» в ланцюгах експлойтів; arbitrary code injection; модифікацію існуючого бінарника для вставки шкідливої логіки.
- Mechanism detail:
- The Mach-O loader (and dynamic linker) перевіряє code pages, segments, entitlements, team IDs, і те, що підпис покриває вміст файлу.
- Для регіонів пам’яті, як-от JIT caches або динамічно згенерований код, Apple вимагає, щоб сторінки були підписані або підтверджені через спеціальні API (наприклад
mprotectwith code-sign checks). - Підпис включає entitlements і identifiers; OS примушує до того, що певні API або привілейовані можливості вимагають конкретних entitlements, які не можуть бути підроблені.
Example
Припустимо, експлойт отримує code execution в процесі і намагається записати shellcode в heap та перейти до нього. На iOS ця сторінка повинна бути позначена як executable **і** відповідати code-signature constraints. Оскільки shellcode не підписаний сертифікатом Apple, перехід не вдається або система відхиляє зробити ту область пам'яті executable.2. CoreTrust
Introduced around iOS 14+ era (or gradually in newer devices / later iOS) CoreTrust — підсистема, що виконує runtime signature validation бінарників (включно із системними та користувацькими) проти Apple’s root certificate, замість покладання на кешовані userland trust stores.
- Thwarts: post-install tampering бінарників, jailbreak-методи, які намагаються замінити або запатчити системні бібліотеки чи user apps; обман системи шляхом підміни довірених бінарників на шкідливі аналоги.
- Mechanism detail:
- Замість довіри до локальної trust database або кешу сертифікатів, CoreTrust звертається безпосередньо до Apple’s root або перевіряє проміжні сертифікати у захищеному ланцюжку.
- Він гарантує, що модифікації (наприклад у filesystem) існуючих бінарників виявляються й відхиляються.
- Він зв’язує entitlements, team IDs, code signing flags та іншу метадані з бінарником під час завантаження.
Example
Jailbreak може спробувати замінити `SpringBoard` або `libsystem` на запатчену версію для отримання persistency. Але коли OS loader або CoreTrust перевіряє, він помічає mismatch підпису (або змінені entitlements) і відмовляється виконувати.3. Data Execution Prevention (DEP / NX / W^X)
Introduced in many OSes earlier; iOS had NX-bit / w^x for a long time DEP примушує сторінки, позначені як writable (для даних), бути non-executable, а сторінки, позначені як executable — non-writable. Ви не можете просто записати shellcode в heap або stack і виконати його.
- Thwarts: пряме виконання shellcode; класичний buffer-overflow → перехід до інжектованого shellcode.
- Mechanism detail:
- MMU / memory protection flags (через page tables) забезпечують цю роздільність.
- Будь-яка спроба позначити writable page як executable запускає системну перевірку (і або забороняється, або вимагає code-sign approval).
- У багатьох випадках зробити сторінки executable можна лише через OS APIs, які накладають додаткові обмеження або перевірки.
Example
Переповнення записує shellcode в heap. Атакувальник намагається викликати `mprotect(heap_addr, size, PROT_EXEC)`, щоб зробити її executable. Але система відмовляє або перевіряє, що нова сторінка повинна пройти code-sign constraints (чого shellcode не може).4. Address Space Layout Randomization (ASLR)
Introduced in iOS ~4–5 era (roughly iOS 4–5 timeframe) ASLR рандомізує базові адреси ключових регіонів пам’яті: libraries, heap, stack тощо при кожному запуску процесу. Адреси gadget-ів змінюються між запусками.
- Thwarts: хардкодування адрес gadget-ів для ROP/JOP; статичні exploit-ланцюги; сліпе стрибання на відомі офсети.
- Mechanism detail:
- Кожна завантажена бібліотека / динамічний модуль переміщується на рандомізований offset.
- Stack і heap base pointers рандомізовані (в межах певного ентропійного ліміту).
- Іноді й інші регіони (наприклад mmap allocations) також рандомізуються.
- У поєднанні з information-leak mitigations це змушує атакувальника спочатку виконати leak адреси або вказівника, щоб визначити базові адреси під час виконання.
Example
ROP-ланцюг очікує gadget в `0x….lib + offset`. Але оскільки `lib` релокований інакше при кожному запуску, хардкод-ланцюг не проходить. Експлойт мусить спочатку отримати leak базової адреси модуля перед обчисленням адрес gadget-ів.5. Kernel Address Space Layout Randomization (KASLR)
Introduced in iOS ~ (iOS 5 / iOS 6 timeframe) Аналогічно user ASLR, KASLR рандомізує базу kernel text та інших kernel-структур під час завантаження системи.
- Thwarts: kernel-level exploits, які покладаються на фіксовані розташування kernel-коду або даних; статичні kernel-експлойти.
- Mechanism detail:
- При кожному boot базова адреса ядра рандомізується (в межах діапазону).
- Kernel data structures (напр.,
task_structs,vm_mapтощо) також можуть переміщатися або мати офсет. - Атакувальники повинні спочатку отримати leak kernel pointers або використати information disclosure уразливість, щоб обчислити офсети перед hijack-ом kernel-структур чи коду.
Example
Локальна уразливість прагне пошкодити kernel function pointer (наприклад у `vtable`) на `KERN_BASE + offset`. Але оскільки `KERN_BASE` невідомий, атакувальник повинен спочатку отримати leak (наприклад через read primitive), перш ніж обчислити правильну адресу для корупції.6. Kernel Patch Protection (KPP / AMCC)
Introduced in newer iOS / A-series hardware (post around iOS 15–16 era or newer chips) KPP (aka AMCC) постійно моніторить цілісність kernel text pages (через hash або checksum). Якщо він виявляє tampering (patches, inline hooks, code modifications) поза дозволеними вікнами, він викликає kernel panic або reboot.
- Thwarts: persistent kernel patching (модифікацію інструкцій ядра), inline hooks, статичні перезаписи функцій.
- Mechanism detail:
- Апаратний або firmware модуль моніторить область kernel text.
- Він періодично або за запитом повторно хешує сторінки й порівнює з очікуваними значеннями.
- Якщо є невідповідності поза benign update windows, він викликає panic пристрою (щоб уникнути persistent malicious patch).
- Атакувальникам потрібно або уникати вікон виявлення, або використовувати легітимні шляхи патчу.
Example
Експлойт намагається запатчити пролог функції ядра (наприклад `memcmp`), щоб перехоплювати виклики. Але KPP помічає, що hash code page більше не відповідає очікуваному значенню і викликає kernel panic, крашучи пристрій до того, як патч стабілізується.7. Kernel Text Read‐Only Region (KTRR)
Introduced in modern SoCs (post ~A12 / newer hardware) KTRR — апаратно-примусова механіка: після того як kernel text заблоковано рано під час boot, вона стає read-only з EL1 (kernel), перешкоджаючи подальшим записам у code pages.
- Thwarts: будь-які модифікації kernel-коду після boot (наприклад patching, in-place code injection) на рівні привілеїв EL1.
- Mechanism detail:
- Під час boot (у secure/bootloader стадії) memory controller (або secure hardware unit) помічає фізичні сторінки, що містять kernel text, як read-only.
- Навіть якщо експлойт отримає повні kernel privileges, він не зможе писати в ці сторінки, щоб патчити інструкції.
- Щоб їх змінити, атакувальник має спочатку скомпрометувати boot chain або підривати сам KTRR.
Example
Privilege-escalation експлойт переходить в EL1 і записує trampoline у kernel function (наприклад в syscall handler). Але через те, що сторінки заблоковані як read-only KTRR, запис не вдається (або викликає fault), тож патчі не застосовуються.8. Pointer Authentication Codes (PAC)
Introduced with ARMv8.3 (hardware), Apple beginning with A12 / iOS ~12+
- PAC — це апаратна функція, введена в ARMv8.3-A, щоб виявляти підміни pointer values (return addresses, function pointers, certain data pointers) шляхом вбудовування невеликого криптографічного підпису («MAC») у невикористані високі біти вказівника.
- Підпис («PAC») обчислюється над значенням вказівника плюс modifier (контекстне значення, наприклад stack pointer або деякі відмінні дані). Таким чином те саме значення вказівника в різних контекстах дає різний PAC.
- При використанні, перед дереференсом або переходом через цей вказівник виконуються інструкції аутентифікації. Якщо верифікація успішна, PAC знімається і отримується чистий вказівник; якщо ні — вказівник «поїться» (poisoned) або піднімається fault.
- Ключі, що використовуються для обчислення/перевірки PAC, зберігаються в привілейованих регістрах (EL1, kernel) і недоступні з user mode.
- Оскільки не всі 64 біт адреси використовуються в багатьох системах (наприклад 48-bit address space), верхні біти є «вільними» і можуть містити PAC без зміни ефективної адреси.
Architectural Basis & Key Types
-
ARMv8.3 вводить п’ять 128-bit ключів (кожен реалізований через два 64-bit системні регістри) для pointer authentication.
-
APIAKey — для instruction pointers (domain “I”, key A)
-
APIBKey — другий ключ для instruction pointers (domain “I”, key B)
-
APDAKey — для data pointers (domain “D”, key A)
-
APDBKey — для data pointers (domain “D”, key B)
-
APGAKey — «generic» ключ, для підпису не-pointer даних або інших загальних цілей
-
Ці ключі зберігаються в привілейованих системних регістрах (доступних лише на EL1/EL2 тощо), недоступних з user mode.
-
PAC обчислюється через криптографічну функцію (ARM пропонує QARMA як алгоритм) із використанням:
- Значення вказівника (canonical portion)
- modifier (контекстне значення, як salt)
- Секретного ключа
- Деякої внутрішньої tweak-логіки Якщо отриманий PAC співпадає з тим, що збережено в верхніх бітах вказівника, аутентифікація вдається.
Instruction Families
Номенклатура: PAC / AUT / XPAC, потім літери домену.
PACxxінструкції підписують вказівник і вставляють PACAUTxxінструкції аутентифікують + знімають (validates and removes PAC)XPACxxінструкції знімають без перевірки
Domains / suffixes:
| Mnemonic | Meaning / Domain | Key / Domain | Example Usage in Assembly |
|---|---|---|---|
| PACIA | Sign instruction pointer with APIAKey | “I, A” | PACIA X0, X1 — sign pointer in X0 using APIAKey with modifier X1 |
| PACIB | Sign instruction pointer with APIBKey | “I, B” | PACIB X2, X3 |
| PACDA | Sign data pointer with APDAKey | “D, A” | PACDA X4, X5 |
| PACDB | Sign data pointer with APDBKey | “D, B” | PACDB X6, X7 |
| PACG / PACGA | Generic (non-pointer) signing with APGAKey | “G” | PACGA X8, X9, X10 (sign X9 with modifier X10 into X8) |
| AUTIA | Authenticate APIA-signed instruction pointer & strip PAC | “I, A” | AUTIA X0, X1 — check PAC on X0 using modifier X1, then strip |
| AUTIB | Authenticate APIB domain | “I, B” | AUTIB X2, X3 |
| AUTDA | Authenticate APDA-signed data pointer | “D, A” | AUTDA X4, X5 |
| AUTDB | Authenticate APDB-signed data pointer | “D, B” | AUTDB X6, X7 |
| AUTGA | Authenticate generic / blob (APGA) | “G” | AUTGA X8, X9, X10 (validate generic) |
| XPACI | Strip PAC (instruction pointer, no validation) | “I” | XPACI X0 — remove PAC from X0 (instruction domain) |
| XPACD | Strip PAC (data pointer, no validation) | “D” | XPACD X4 — remove PAC from data pointer in X4 |
There are specialized / alias forms:
PACIASPis shorthand forPACIA X30, SP(sign the link register using SP as modifier)AUTIASPisAUTIA X30, SP(authenticate link register with SP)- Combined forms like
RETAA,RETAB(authenticate-and-return) orBLRAA(authenticate & branch) exist in ARM extensions / compiler support. - Also zero-modifier variants:
PACIZA/PACIZBwhere the modifier is implicitly zero, etc.
Modifiers
Головна мета modifier — зв’язати PAC з конкретним контекстом, щоб одне й те саме підписане значення адреси в різних контекстах давало різні PAC. Це запобігає простому повторному використанню вказівника між фреймами або об’єктами. Це як додавання salту до хешу.
Отже:
- modifier — контекстне значення (інший регістр), яке змішується в обчисленні PAC. Типові варіанти: stack pointer (
SP), frame pointer або якийсь object ID. - Використання SP як modifier звичне для підпису return address: PAC прив’язується до конкретного stack frame. Якщо ви намагаєтесь повторно використати LR у іншому фреймі, modifier зміниться і верифікація PAC провалиться.
- Те саме значення вказівника, підписане з різними modifiers, дає різні PAC.
- modifier не повинен бути секретним, але бажано, щоб він не контролювався атакувальником.
- Для інструкцій, що підписують або перевіряють вказівники, де немає значущого modifier, деякі форми використовують нуль або імпліцитну константу.
Apple / iOS / XNU Customizations & Observations
- Apple-реалізація PAC включає per-boot diversifiers, тож ключі або tweaks змінюються при кожному завантаженні, що ускладнює повторне використання across boots.
- Вони також включають cross-domain mitigations, так що PAC, підписані в user mode, не можуть легко бути використані в kernel mode тощо.
- На Apple M1 / Apple Silicon реверс-інженіринг показав, що існують nine modifier types і Apple-специфічні системні регістри для контролю ключів.
- Apple використовує PAC у багатьох kernel-підсистемах: підписування return addresses, pointer integrity у kernel-даних, підписані thread contexts тощо.
- Google Project Zero показав, як при сильному memory read/write примітиві в kernel можна було підробити kernel PACs (для A keys) на A12-era пристроях, але Apple закрила багато з тих шляхів.
- В системі Apple деякі ключі є глобальними для ядра, тоді як user processes можуть отримувати per-process key randomness.
PAC Bypasses
- Kernel-mode PAC: theoretical vs real bypasses
- Оскільки kernel PAC keys і логіка жорстко контрольовані (привілейовані регістри, diversifiers, domain isolation), підробка довільних підписаних kernel-вказівників дуже складна.
- Azad’s 2020 “iOS Kernel PAC, One Year Later” повідомив, що в iOS 12–13 він знайшов кілька часткових обхідних шляхів (signing gadgets, reuse of signed states, unprotected indirect branches), але не повний generic bypass. bazad.github.io
- Apple’s “Dark Magic” кастомізації ще більше звужують поверхні для експлуатації (domain switching, per-key enabling bits). i.blackhat.com
- Існує відомий kernel PAC bypass CVE-2023-32424 на Apple silicon (M1/M2), повідомлений Zecao Cai et al. i.blackhat.com
- Але ці bypass-и часто залежать від дуже специфічних gadget-ів або імплементаційних багів; вони не є загальними.
Отже kernel PAC вважається високостійким, хоч і не ідеальним.
- User-mode / runtime PAC bypass techniques
Це більш поширене, і вони експлуатують недосконалості у застосуванні PAC або в runtime/framework-логіці. Нижче класи з прикладами.
2.1 Shared Cache / A key issues
-
dyld shared cache — великий попередньо пов’язаний blob system frameworks і бібліотек. Оскільки він широко спільний, function pointers всередині shared cache «pre-signed» і потім використовуються багатьма процесами. Атакувальники націлюються на ці вже-підписані pointers як «PAC oracles».
-
Деякі техніки обходу намагаються витягти або повторно використати A-key підписані pointers, що знаходяться в shared cache, і повторно їх використовувати у gadget-ланцюгах.
-
Доповідь “No Clicks Required” описує побудову oracle над shared cache для визначення відносних адрес і комбінування цього з підписаними pointers для обходу PAC. saelo.github.io
-
Також імпорти function pointers з shared libraries в userspace інколи виявлялися недостатньо захищеними PAC, дозволяючи атакувальнику отримати function pointers без зміни їх підпису. (Project Zero bug entry) bugs.chromium.org
2.2 dlsym(3) / dynamic symbol resolution
-
Один відомий bypass — викликати
dlsym()для отримання вже підписаного function pointer (signed with A-key, diversifier zero) і потім його використати. Оскількиdlsymповертає легітимно підписаний pointer, його використання обходить необхідність підробляти PAC. -
Epsilon’s блог детально описує, як деякі bypass-и експлуатують це: виклик
dlsym("someSym")повертає підписаний pointer, який можна використовувати для indirect calls. blog.epsilon-sec.com -
Synacktiv’s “iOS 18.4 — dlsym considered harmful” описує баг: деякі символи, resolved через
dlsymна iOS 18.4, повертають pointers, які неправильно підписані (або з багованими diversifiers), що дозволяє ненавмисний PAC bypass. Synacktiv -
Логіка в dyld для dlsym містить: коли
result->isCode, вони підписують повернений pointer через__builtin_ptrauth_sign_unauthenticated(..., key_asia, 0), тобто контекст нуль. blog.epsilon-sec.com
Отже, dlsym є частим вектором у user-mode PAC bypass-ах.
2.3 Other DYLD / runtime relocations
-
DYLD loader і логіка динамічних релокацій складні й іноді тимчасово маплять сторінки як read/write, щоб виконати релокації, потім повертають їх до read-only. Атакувальники експлуатують ці вікна. Synacktiv описує “Operation Triangulation”, таймінговий bypass PAC через динамічні релокації. Synacktiv
-
DYLD-сторінки зараз захищаються SPRR / VM_FLAGS_TPRO (деякі protection flags для dyld). Але в попередніх версіях захисти були слабші. Synacktiv
-
У WebKit exploit-ланцюгах DYLD loader часто є мішенню для PAC bypass. Слайди згадують, що багато PAC bypass-ів націлювалися на DYLD loader (через релокацію, interposer hooks). Synacktiv
2.4 NSPredicate / NSExpression / ObjC / SLOP
-
В userland exploit-ланцюгах Objective-C runtime методи як
NSPredicate,NSExpressionабоNSInvocationвикористовуються, щоб пронести виклики контролю без очевидного підроблення pointer-ів. -
На старіших iOS (до PAC) експлойт використовував fake NSInvocation об’єкти, щоб викликати довільні селектори на контрольованій пам’яті. З PAC техніку треба змінювати. Але техніка SLOP (SeLector Oriented Programming) також була адаптована під PAC. Project Zero
-
Початкова SLOP-методика дозволяла ланцюжити ObjC виклики створенням підроблених invocations; обхід базувався на тому, що ISA або selector pointers іноді не були повністю захищені PAC. Project Zero
-
У середовищах, де pointer authentication застосовується частково, методи / селектори / target pointers не завжди мають PAC-захист, що дає можливість для обходу.
Example Flow
Example Signing & Authenticating
``` ; Example: function prologue / return address protection my_func: stp x29, x30, [sp, #-0x20]! ; push frame pointer + LR mov x29, sp PACIASP ; sign LR (x30) using SP as modifier ; … body … mov sp, x29 ldp x29, x30, [sp], #0x20 ; restore AUTIASP ; authenticate & strip PAC ret; Example: indirect function pointer stored in a struct ; suppose X1 contains a function pointer PACDA X1, X2 ; sign data pointer X1 with context X2 STR X1, [X0] ; store signed pointer
; later retrieval: LDR X1, [X0] AUTDA X1, X2 ; authenticate & strip BLR X1 ; branch to valid target
; Example: stripping for comparison (unsafe) LDR X1, [X0] XPACI X1 ; strip PAC (instruction domain) CMP X1, #some_label_address BEQ matched_label
</details>
<details>
<summary>Example</summary>
Переповнення буфера перезаписує адресу повернення на стеку. Атакуючий записує адресу цільового gadget, але не може обчислити правильний PAC. Коли функція повертається, інструкція CPU `AUTIA` аварійно завершується через невідповідність PAC. Ланцюжок не вдається.
Project Zero’s analysis on A12 (iPhone XS) показав, як Apple використовує PAC і методи підробки PAC, якщо атакуючий має примітив читання/запису пам’яті.
</details>
### 9. **Branch Target Identification (BTI)**
**Introduced with ARMv8.5 (later hardware)**
BTI — апаратна можливість, що перевіряє **indirect branch targets**: при виконанні `blr` або непрямих викликів/переходів, ціль повинна починатися з **BTI landing pad** (`BTI j` або `BTI c`). Перехід в адреси gadget, які не мають landing pad, викликає виключення.
LLVM’s implementation зазначає три варіанти інструкцій BTI і те, як вони відображаються на типи переходів.
| BTI Variant | What it permits (which branch types) | Typical placement / use case |
|-------------|----------------------------------------|-------------------------------|
| **BTI C** | Targets of *call*-style indirect branches (e.g. `BLR`, or `BR` using X16/X17) | Put at entry of functions that may be called indirectly |
| **BTI J** | Targets of *jump*-style branches (e.g. `BR` used for tail calls) | Placed at the beginning of blocks reachable by jump tables or tail-calls |
| **BTI JC** | Acts as both C and J | Can be targeted by either call or jump branches |
- У коді, скомпільованому з enforced branch target, компілятори вставляють BTI-інструкцію (C, J або JC) у кожну дійсну ціль непрямого переходу (початки функцій або блоки, досяжні через переходи), так що непрямі переходи вдаються лише в ці місця.
- **Direct branches / calls** (тобто фіксовані `B`, `BL`) **не обмежуються** BTI. Припускається, що сторінки коду довірені і атакуючий не може їх змінити (тому direct branches вважаються безпечними).
- Також **RET / return** instructions зазвичай не обмежуються BTI, тому що адреси повернення захищені через PAC або механізми підписування повернень.
#### Mechanism and enforcement
- Коли CPU декодує **indirect branch (BLR / BR)** на сторінці, позначеній як “guarded / BTI-enabled,” воно перевіряє, чи перша інструкція за цільовою адресою є дійсним BTI (C, J або JC, як дозволено). Якщо ні — відбувається **Branch Target Exception**.
- Формат кодування інструкції BTI спроєктовано так, щоб повторно використовувати опкоди, раніше зарезервовані для NOPs (в ранніших версіях ARM). Тому двійкові файли з BTI залишаються сумісними з попереднім апаратним забезпеченням: на апаратурі без підтримки BTI ці інструкції працюють як NOP.
- Pass’и компілятора, що додають BTI, вставляють їх лише там, де потрібно: у функціях, які можуть викликатися непрямо, або в базових блоках, на які спрямовані переходи.
- Деякі патчі та код LLVM показують, що BTI не вставляється для *усіх* базових блоків — лише для тих, які є потенційними цілями переходів (наприклад, з switch / jump tables).
#### BTI + PAC synergy
PAC захищає значення покажчика (джерело) — гарантує, що ланцюжок непрямих викликів/повернень не був підроблений.
BTI гарантує, що навіть дійсний покажчик може націлюватися лише на правильно позначені точки входу.
У сукупності, атакуючому потрібні як дійсний покажчик з коректним PAC, так і те, щоб ціль мала вставлений BTI. Це ускладнює побудову експлойт-ґаджетів.
#### Example
<details>
<summary>Example</summary>
Експлойт намагається переключитися в gadget за адресою `0xABCDEF`, який не починається з `BTI c`. CPU при виконанні `blr x0` перевіряє ціль і викликає помилку, бо вирівнювання інструкцій не містить дійсної landing pad. Таким чином багато gadget-ів стають непридатними, якщо вони не мають префіксу BTI.
</details>
### 10. **Privileged Access Never (PAN) & Privileged Execute Never (PXN)**
**Introduced in more recent ARMv8 extensions / iOS support (for hardened kernel)**
#### PAN (Privileged Access Never)
- **PAN** — можливість, введена в **ARMv8.1-A**, яка забороняє **privileged code** (EL1 або EL2) **читати або записувати** пам’ять, позначену як **user-accessible (EL0)**, якщо PAN явно не відключено.
- Ідея: навіть якщо kernel підставлено або скомпрометовано, він не може довільно роздерференсити user-space pointers без попереднього *очищення* PAN, зменшуючи ризики експлойтів типу **`ret2usr`** або зловживань контролем користувацьких буферів.
- Коли PAN увімкнено (PSTATE.PAN = 1), будь-яка привілейована інструкція load/store, що звертається до віртуальної адреси, яка “доступна на EL0”, викликає **permission fault**.
- Kernel, коли має легітимну потребу доступу до user-space memory (наприклад, копіювання даних в/з user buffers), повинен **тимчасово відключити PAN** (або використати “unprivileged load/store” інструкції), щоб дозволити цей доступ.
- В Linux на ARM64 підтримка PAN з’явилася близько 2015 року: патчі ядра додали виявлення цієї можливості та замінили `get_user` / `put_user` тощо на варіанти, які чистять PAN під час доступу до користувацької пам’яті.
**Key nuance / limitation / bug**
- Як зауважували Siguza та інші, помилка специфікації (або неоднозначність) в ARM означає, що **execute-only user mappings** (`--x`) можуть **не провокувати PAN**. Іншими словами, якщо user page позначено як виконувальна, але без прав на читання, спроба kernel прочитати її може обійти PAN, бо архітектура вважає «доступною на EL0» сторінку, яка потребує права на читання, а не лише на виконання. Це веде до PAN-bypass у певних конфігураціях.
- Через це, якщо iOS / XNU дозволяє execute-only user pages (як це буває для деяких JIT або code-cache налаштувань), kernel може випадково читати з них навіть при увімкненому PAN. Це відома тонка вразливість в деяких ARMv8+ системах.
#### PXN (Privileged eXecute Never)
- **PXN** — біт в таблиці сторінок (в записах page table, leaf або block entries), що вказує, що сторінка **не виконується при запусці в привілейованому режимі** (тобто коли EL1 виконує інструкції).
- PXN забороняє kernel (або будь-якому привілейованому коду) переходити в або виконувати інструкції з user-space сторінок навіть якщо контроль було відхилено. По суті, це унеможливлює перенаправлення control-flow ядра у користувацьку пам’ять.
- У поєднанні з PAN це забезпечує:
1. Kernel не може (за замовчуванням) читати або записувати user-space дані (PAN)
2. Kernel не може виконувати user-space код (PXN)
- У форматі ARMv8 page table, leaf entries мають біт `PXN` (а також `UXN` для execute-never з неприваджованого рівня) у своїх бітових атрибутах.
Таким чином, навіть якщо kernel має пошкоджений function pointer, що вказує в user memory, і намагається перейти туди, біт PXN викличе помилку.
#### Memory-permission model & how PAN and PXN map to page table bits
Щоб зрозуміти, як працюють PAN / PXN, треба уявити модель трансляції та прав ARM (спрощено):
- Кожен page або block entry має поля атрибутів, включаючи **AP[2:1]** для прав доступу (читання/запис, привілейований vs неприваджований) та **UXN / PXN** біти для заборони виконання.
- Коли PSTATE.PAN = 1 (увімкнено), апарат примушує змінену семантику: привілейовані доступи до сторінок, позначених як “accessible by EL0” (тобто доступні користувачу), забороняються (fault).
- Через згадану помилку, сторінки, які позначені лише як виконувальні (без прав читання), можуть не вважатися “accessible by EL0” на певних реалізаціях, що дозволяє обійти PAN.
- Коли на сторінці встановлено біт PXN, навіть якщо інструкційний вибір походить від вищого рівня привілеїв, виконання забороняється.
#### Kernel usage of PAN / PXN in a hardened OS (e.g. iOS / XNU)
У загартованому дизайні ядра (такому як у Apple):
- Kernel зазвичай вмикає PAN за замовчуванням (щоб обмежити привілейований код).
- У шляхах, де потрібно легітимно читати або писати user buffers (наприклад, syscall buffer copy, I/O, read/write user pointer), kernel тимчасово **вимикає PAN** або використовує спеціальні інструкції для обходу.
- Після завершення доступу до user data, він має знову увімкнути PAN.
- PXN забезпечується через page tables: user pages мають PXN = 1 (щоб kernel не міг їх виконувати), kernel pages — не мають PXN (щоб kernel-код міг виконуватися).
- Kernel повинен упевнитися, що жоден шлях виконання не призведе до переходу в user memory regions (що обійшло б PXN) — отже ланцюжки експлойтів, які використовують “jump into user-controlled shellcode”, блокуються.
Через згаданий PAN bypass через execute-only pages, у реальній системі Apple може заборонити execute-only user pages або обійти цю проблему патчами.
#### Attack surfaces, bypasses, and mitigations
- **PAN bypass via execute-only pages**: як обговорювалося, специфікація залишає прогалину: user pages з execute-only (без прав читання) можуть не вважатися “accessible at EL0”, тож PAN не блокує kernel reads з таких сторінок на певних реалізаціях. Це дає атакуючому нетиповий шлях передати дані через “execute-only” секції.
- **Temporal window exploit**: якщо kernel вимикає PAN на довший за необхідне проміжок, гонка або зловмисний шлях може використати це вікно для небажаного доступу до user memory.
- **Forgotten re-enable**: якщо код забуває знову ввімкнути PAN, подальші операції ядра можуть неправильно доступатися до user пам’яті.
- **Misconfiguration of PXN**: якщо page tables не встановлюють PXN на user pages або неправильно відображають user code pages, kernel може бути обдурений і виконати user-space код.
- **Speculation / side-channels**: аналогічно до speculative bypasses, можуть існувати мікроархітектурні сайд-ефекти, що спричиняють транзитні порушення PAN / PXN перевірок (хоча такі атаки сильно залежать від дизайну CPU).
- **Complex interactions**: у просунутих можливостях (наприклад JIT, shared memory, just-in-time code regions) kernel може потребувати тонкого контролю для дозволу певних доступів або виконання у user-mapped областях; проєктування цього безпечно з PAN/PXN вимогами є нетривіальним.
#### Example
<details>
<summary>Code Example</summary>
Тут наведено ілюстративні pseudo-assembly послідовності, що показують увімкнення/вимкнення PAN навколо доступу до user memory, і як може виникнути помилка.
// Suppose kernel entry point, PAN is enabled (privileged code cannot access user memory by default)
; Kernel receives a syscall with user pointer in X0 ; wants to read an integer from user space mov X1, X0 ; X1 = user pointer
; disable PAN to allow privileged access to user memory MSR PSTATE.PAN, #0 ; clear PAN bit, disabling the restriction
ldr W2, [X1] ; now allowed load from user address
; re-enable PAN before doing other kernel logic MSR PSTATE.PAN, #1 ; set PAN
; … further kernel work …
; Later, suppose an exploit corrupts a pointer to a user-space code page and jumps there BR X3 ; branch to X3 (which points into user memory)
; Because the target page is marked PXN = 1 for privileged execution, ; the CPU throws an exception (fault) and rejects execution
Якщо kernel мав **not** встановлений PXN на цю user-сторінку, то розгалуження може виконатися — що було б незахищено.
Якщо kernel забуває знову ввімкнути PAN після доступу до user-пам’яті, це відкриває вікно, в якому подальша kernel-логіка може випадково читати/записувати довільну user-пам’ять.
Якщо user-указівник вказує на execute-only сторінку (user-сторінка з лише execute-пермісією, без read/write), то згідно з багом у специфікації PAN, `ldr W2, [X1]` може **не** викликати fault навіть при увімкненому PAN, що дозволяє обхідний експлойт, залежно від реалізації.
</details>
<details>
<summary>Приклад</summary>
A kernel vulnerability tries to take a user-provided function pointer and call it in kernel context (i.e. `call user_buffer`). Under PAN/PXN, that operation is disallowed or faults.
</details>
---
### 11. **Top Byte Ignore (TBI) / Pointer Tagging**
**Introduced in ARMv8.5 / newer (or optional extension)**
TBI означає, що верхній байт (найстарший байт) 64-бітного указівника ігнорується при трансляції адрес. Це дає OS або апаратурі можливість вбудовувати в указівник у верхній байт біт(и) тегу без впливу на фактичну адресу.
- TBI stands for **Top Byte Ignore** (sometimes called *Address Tagging*). It is a hardware feature (available in many ARMv8+ implementations) that **ignores the top 8 bits** (bits 63:56) of a 64-bit pointer when performing **address translation / load/store / instruction fetch**.
- По суті, CPU трактує вказівник `0xTTxxxx_xxxx_xxxx` (де `TT` = top byte) як `0x00xxxx_xxxx_xxxx` для цілей адресної трансляції, ігноруючи (маскуючи) верхній байт. Верхній байт може використовуватись програмним забезпеченням для збереження метаданих / бітів тегу.
- Це дає програмному забезпеченню “безкоштовний” in-band простір для вбудовування байта тегу в кожний указівник без зміни того, на яку ділянку пам’яті він посилається.
- Архітектура забезпечує, що операції load, store та instruction fetch трактують указівник з маскованим верхнім байтом (тобто тег відкидається) перед фактичним доступом до пам’яті.
Таким чином TBI розділяє **логічний указівник** (pointer + tag) від **фізичної адреси**, що використовується для операцій з пам’яттю.
#### Why TBI: Use cases and motivation
- **Pointer tagging / metadata**: У верхньому байті можна зберігати додаткові метадані (наприклад тип об’єкта, версію, межі, теги цілісності). Коли пізніше ви використовуєте указівник, тег ігнорується на апаратному рівні, тож не потрібно явно прибирати його перед доступом до пам’яті.
- **Memory tagging / MTE (Memory Tagging Extension)**: TBI — базовий апаратний механізм, на якому будується MTE. В ARMv8.5, **Memory Tagging Extension** використовує біти 59:56 указівника як **логічний тег** і порівнює його з **allocation tag**, що зберігається в пам’яті.
- **Enhanced security & integrity**: Комбінуючи TBI з pointer authentication (PAC) або перевірками під час виконання, можна вимагати, щоб не лише значення указівника, а й тег були коректними. Атакуючий, який перезаписує указівник без правильного тегу, отримає невідповідність тегів.
- **Compatibility**: Оскільки TBI є опціональним і біти тегу ігноруються апаратурою, існуючий нетегований код продовжує працювати нормально. Біти тегу фактично стають “dont-care” бітами для спадкового коду.
#### Example
<details>
<summary>Приклад</summary>
A function pointer included a tag in its top byte (say `0xAA`). An exploit overwrites the pointer low bits but neglects the tag, so when the kernel verifies or sanitizes, the pointer fails or is rejected.
</details>
---
### 12. **Page Protection Layer (PPL)**
**Introduced in late iOS / modern hardware (iOS ~17 / Apple silicon / high-end models)** (some reports show PPL circa macOS / Apple silicon, but Apple is bringing analogous protections to iOS)
- PPL спроектовано як внутрішній kernel-бар’єр захисту: навіть якщо kernel (EL1) скомпрометовано і має можливості читати/писати, **його не повинно бути можливим довільно змінювати** певні **чутливі сторінки** (особливо page tables, code-signing metadata, kernel code pages, entitlements, trust caches тощо).
- Це фактично створює **“kernel всередині kernel”** — меншу довірену компоненту (PPL) з **підвищеними привілеями**, яка виключно може модифікувати захищені сторінки. Інший kernel-код має викликати PPL-рутину, щоб внести зміни.
- Це зменшує поверхню атаки для kernel-експлойтів: навіть маючи повний довільний R/W/execute у kernel-режимі, експлойт має ще якось потрапити в домен PPL (або обійти PPL), щоб змінити критичні структури.
- На новіших Apple silicon (A15+ / M2+) Apple переходить до **SPTM (Secure Page Table Monitor)**, який у багатьох випадках замінює PPL для захисту page-table на тих платформах.
Ось як, на основі публічного аналізу, вважають, що працює PPL:
#### Use of APRR / permission routing (APRR = Access Permission ReRouting)
- Apple hardware uses a mechanism called **APRR (Access Permission ReRouting)**, which allows page table entries (PTEs) to contain small indices, rather than full permission bits. Those indices are mapped via APRR registers to actual permissions. This allows dynamic remapping of permissions per domain.
- PPL використовує APRR, щоб сегрегувати привілеї всередині kernel-контексту: лише домен PPL має право оновлювати відображення між індексами та ефективними пермісіями. Тобто коли non-PPL kernel-код записує PTE або намагається змінити біт(и) пермісій, логіка APRR забороняє це (або накладає режим read-only).
- PPL-код сам запускається в обмеженій області (наприклад `__PPLTEXT`), яка зазвичай non-executable або non-writable до моменту входу, коли шлюзи тимчасово дозволяють доступ. Kernel викликає PPL entry points (“PPL routines”), щоб виконати чутливі операції.
#### Gate / Entry & Exit
- Коли kernel потребує змінити захищену сторінку (наприклад змінити пермісії kernel code page або модифікувати page tables), він викликає PPL wrapper-рутину, яка виконує валідацію і потім переходить у домен PPL. Поза цим доменом захищені сторінки фактично є read-only або незмінними для основного kernel.
- Під час входу в PPL, APRR-мапи коригуються так, щоб пам’яті в PPL-області мали встановлені permissions **executable & writable** всередині PPL. Після виходу вони повертаються до read-only / non-writable. Це гарантує, що лише перевірені PPL-рутину можуть писати в захищені сторінки.
- Поза PPL, спроби kernel-коду записати в ці захищені сторінки викличуть fault (permission denied), бо APRR-мапінг для цього домену не дозволяє запис.
#### Protected page categories
Сторінки, які PPL зазвичай захищає, включають:
- Структури page table (translation table entries, mapping metadata)
- Kernel code pages, особливо ті, що містять критичну логіку
- Code-sign metadata (trust caches, signature blobs)
- Entitlement tables, signature enforcement tables
- Інші високовартісні kernel-структури, модифікація яких дозволила б обійти перевірки підписів або маніпулювати привілеями
Ідея в тому, що навіть якщо пам’ять kernel повністю контрольована, атакуючий не може просто пропатчити чи перезаписати ці сторінки, якщо тільки він не скомпрометував також PPL-рутину або не обійшов PPL.
#### Known Bypasses & Vulnerabilities
1. **Project Zero’s PPL bypass (stale TLB trick)**
- Публічний розбір від Project Zero описує обхід, що включає **stale TLB entries**.
- Ідея:
1. Виділити дві фізичні сторінки A і B, позначити їх як PPL-сторінки (щоб вони були захищені).
2. Замапити дві віртуальні адреси P і Q, чий L3 translation table pages походять з A і B.
3. Запустити потік, який постійно звертається до Q, утримуючи його TLB entry активним.
4. Викликати `pmap_remove_options()` щоб видалити відображення починаючи з P; через баг код помилково видаляє TTEs для обох P і Q, але інвалідовує лише TLB entry для P, залишаючи Q зі stale entry.
5. Пере використовувати B (page Q’s table) для мапінгу довільної пам’яті (наприклад PPL-захищених сторінок). Оскільки stale TLB entry все ще мапить старе відображення Q, це відображення лишається дійсним для того контексту.
6. Через це атакуючий може встановити writable mapping PPL-захищених сторінок без проходження через інтерфейс PPL.
- Цей експлойт вимагав тонкого контролю фізичних відображень та поведінки TLB. Він демонструє, що межа безпеки, яка спирається на коректність TLB/мапінгів, має бути надзвичайно уважною щодо інвалідизації TLB і консистентності відображень.
- Project Zero зауважили, що обходи такого роду є тонкими і рідкісними, але можливі у складних системах. Тим не менш, вони вважають PPL серйозною мірою пом’якшення.
2. **Other potential hazards & constraints**
- Якщо kernel-експлойт може безпосередньо потрапити в PPL-рутину (через виклики PPL wrappers), він може обійти обмеження. Тому критично важлива валідація аргументів.
- Баги в самому PPL-коді (наприклад переповнення арифметики, помилки перевірки меж) можуть дозволити OOB-модифікації всередині PPL. Project Zero помітили, що такий баг в `pmap_remove_options_internal()` використовували в їхньому обході.
- Межа PPL незворотно пов’язана з апаратним забезпеченням (APRR, memory controller), тож її сила залежить від реалізації апаратури.
#### Example
<details>
<summary>Code Example</summary>
Here’s a simplified pseudocode / logic showing how a kernel might call into PPL to modify protected pages:
```c
// In kernel (outside PPL domain)
function kernel_modify_pptable(pt_addr, new_entry) {
// validate arguments, etc.
return ppl_call_modify(pt_addr, new_entry) // call PPL wrapper
}
// In PPL (trusted domain)
function ppl_call_modify(pt_addr, new_entry) {
// temporarily enable write access to protected pages (via APRR adjustments)
aprr_set_index_for_write(PPL_INDEX)
// perform the modification
*pt_addr = new_entry
// restore permissions (make pages read-only again)
aprr_restore_default()
return success
}
// If kernel code outside PPL does:
*pt_addr = new_entry // a direct write
// It will fault because APRR mapping for non-PPL domain disallows write to that page
The kernel can do many normal operations, but only through ppl_call_* routines can it change protected mappings or patch code.
Приклад
A kernel exploit tries to overwrite the entitlement table, or disable code-sign enforcement by modifying a kernel signature blob. Because that page is PPL-protected, the write is blocked unless going through the PPL interface. So even with kernel code execution, you cannot bypass code-sign constraints or modify credential data arbitrarily. On iOS 17+ certain devices use SPTM to further isolate PPL-managed pages.PPL → SPTM / Replacements / Future
- On Apple’s modern SoCs (A15 or later, M2 or later), Apple supports SPTM (Secure Page Table Monitor), which replaces PPL for page table protections.
- Apple calls out in documentation: “Page Protection Layer (PPL) and Secure Page Table Monitor (SPTM) enforce execution of signed and trusted code … PPL manages the page table permission overrides … Secure Page Table Monitor replaces PPL on supported platforms.”
- The SPTM architecture likely shifts more policy enforcement into a higher-privileged monitor outside kernel control, further reducing the trust boundary.
MTE | EMTE | MIE
Here’s a higher-level description of how EMTE operates under Apple’s MIE setup:
- Призначення тега
- When memory is allocated (e.g. in kernel or user space via secure allocators), a secret tag is assigned to that block.
- The pointer returned to the user or kernel includes that tag in its high bits (using TBI / top byte ignore mechanisms).
- Перевірка тега при доступі
- Whenever a load or store is executed using a pointer, the hardware checks that the pointer’s tag matches the memory block’s tag (allocation tag). If mismatch, it faults immediately (since synchronous).
- Because it’s synchronous, there is no “delayed detection” window.
- Ретегування при free / повторному використанні
- When memory is freed, the allocator changes the block’s tag (so older pointers with old tags no longer match).
- A use-after-free pointer would therefore have a stale tag and mismatch when accessed.
- Розрізнення сусідніх тегів для виявлення переповнень
- Adjacent allocations are given distinct tags. If a buffer overflow spills into neighbor’s memory, tag mismatch causes a fault.
- This is especially powerful in catching small overflows that cross boundary.
- Захист конфіденційності тегів
- Apple must prevent tag values being leaked (because if attacker learns the tag, they could craft pointers with correct tags).
- They include protections (microarchitectural / speculative controls) to avoid side-channel leakage of tag bits.
- Інтеграція з kernel та user-space
- Apple uses EMTE not just in user-space but also in kernel / OS-critical components (to guard kernel against memory corruption).
- The hardware/OS ensures tag rules apply even when kernel is executing on behalf of user space.
Приклад
``` Allocate A = 0x1000, assign tag T1 Allocate B = 0x2000, assign tag T2// pointer P points into A with tag T1 P = (T1 << 56) | 0x1000
// Valid store *(P + offset) = value // tag T1 matches allocation → allowed
// Overflow attempt: P’ = P + size_of_A (into B region) *(P’ + delta) = value → pointer includes tag T1 but memory block has tag T2 → mismatch → fault
// Free A, allocator retags it to T3 free(A)
// Use-after-free: *(P) = value → pointer still has old tag T1, memory region is now T3 → mismatch → fault
</details>
#### Обмеження та виклики
- **Intrablock overflows**: Якщо переповнення залишається в межах однієї алокації (не переходить межу) і тег залишається тим самим, tag mismatch цього не вловить.
- **Tag width limitation**: Для тегу доступні лише кілька бітів (наприклад, 4 біти, або невеликий домен) — обмежений простір імен.
- **Side-channel leaks**: Якщо бітів тегу можна бути leaked (через cache / speculative execution), атакуючий може дізнатися валідні теги і обійти захист. Apple додає заходи для зменшення цієї проблеми.
- **Performance overhead**: Перевірки тегів при кожному load/store додають витрати; Apple має оптимізувати апаратну частину, щоб зменшити накладні витрати.
- **Compatibility & fallback**: На старішому обладнанні або в частинах, що не підтримують EMTE, має існувати fallback. Apple стверджує, що MIE включається лише на пристроях із підтримкою.
- **Complex allocator logic**: Алокатор має керувати тегами, retagging, вирівнюванням меж і уникати колізій mis-tag. Помилки в логіці алокатора можуть вводити вразливості.
- **Mixed memory / hybrid areas**: Частина пам’яті може залишатися без тегів (legacy), що ускладнює взаємодію.
- **Speculative / transient attacks**: Як і для багатьох мікроархітектурних захистів, speculative execution або micro-op fusions можуть тимчасово обійти перевірки або leak бітів тегу.
- **Limited to supported regions**: Apple може застосовувати EMTE лише в вибраних, високоризикових зонах (kernel, security-critical subsystems), а не повсюдно.
---
## Ключові поліпшення / відмінності у порівнянні зі стандартним MTE
Here are the improvements and changes Apple emphasizes:
| Feature | Original MTE | EMTE (Apple’s enhanced) / MIE |
|---|---|---|
| **Check mode** | Supports synchronous and asynchronous modes. In async, tag mismatches are reported later (delayed)| Apple insists on **synchronous mode** by default—tag mismatches are caught immediately, no delay/race windows allowed.|
| **Coverage of non-tagged memory** | Accesses to non-tagged memory (e.g. globals) may bypass checks in some implementations | EMTE requires that accesses from a tagged region to non-tagged memory also validate tag knowledge, making it harder to bypass by mixing allocations.|
| **Tag confidentiality / secrecy** | Tags might be observable or leaked via side channels | Apple adds **Tag Confidentiality Enforcement**, which attempts to prevent leakage of tag values (via speculative side-channels etc.).|
| **Allocator integration & retagging** | MTE leaves much of allocator logic to software | Apple’s secure typed allocators (kalloc_type, xzone malloc, etc.) integrate with EMTE: when memory is allocated or freed, tags are managed at fine granularity.|
| **Always-on by default** | In many platforms, MTE is optional or off by default | Apple enables EMTE / MIE by default on supported hardware (e.g. iPhone 17 / A19) for kernel and many user processes.|
Оскільки Apple контролює й апаратну, і програмну частини стеку, вона може суворо застосовувати EMTE, уникнути проблем з продуктивністю та закрити канали витоку.
---
## Як EMTE працює на практиці (Apple / MIE)
Here’s a higher-level description of how EMTE operates under Apple’s MIE setup:
1. **Tag assignment**
- When memory is allocated (e.g. in kernel or user space via secure allocators), a **secret tag** is assigned to that block.
- The pointer returned to the user or kernel includes that tag in its high bits (using TBI / top byte ignore mechanisms).
2. **Tag checking on access**
- Whenever a load or store is executed using a pointer, the hardware checks that the pointer’s tag matches the memory block’s tag (allocation tag). If mismatch, it faults immediately (since synchronous).
- Because it's synchronous, there is no “delayed detection” window.
3. **Retagging on free / reuse**
- When memory is freed, the allocator changes the block’s tag (so older pointers with old tags no longer match).
- A use-after-free pointer would therefore have a stale tag and mismatch when accessed.
4. **Neighbor-tag differentiation to catch overflows**
- Adjacent allocations are given distinct tags. If a buffer overflow spills into neighbor’s memory, tag mismatch causes a fault.
- This is especially powerful in catching small overflows that cross boundary.
5. **Tag confidentiality enforcement**
- Apple must prevent tag values being leaked (because if attacker learns the tag, they could craft pointers with correct tags).
- They include protections (microarchitectural / speculative controls) to avoid side-channel leakage of tag bits.
6. **Kernel and user-space integration**
- Apple uses EMTE not just in user-space but also in kernel / OS-critical components (to guard kernel against memory corruption).
- The hardware/OS ensures tag rules apply even when kernel is executing on behalf of user space.
Because EMTE is built into MIE, Apple uses EMTE in synchronous mode across key attack surfaces, not as opt-in or debugging mode.
---
## Обробка винятків у XNU
When an **exception** occurs (e.g., `EXC_BAD_ACCESS`, `EXC_BAD_INSTRUCTION`, `EXC_CRASH`, `EXC_ARM_PAC`, etc.), the **Mach layer** of the XNU kernel is responsible for intercepting it before it becomes a UNIX-style **signal** (like `SIGSEGV`, `SIGBUS`, `SIGILL`, ...).
This process involves multiple layers of exception propagation and handling before reaching user space or being converted to a BSD signal.
### Потік винятків (високорівневий)
1. **CPU triggers a synchronous exception** (e.g., invalid pointer dereference, PAC failure, illegal instruction, etc.).
2. **Low-level trap handler** runs (`trap.c`, `exception.c` in XNU source).
3. The trap handler calls **`exception_triage()`**, the core of the Mach exception handling.
4. `exception_triage()` decides how to route the exception:
- First to the **thread's exception port**.
- Then to the **task's exception port**.
- Then to the **host's exception port** (often `launchd` or `ReportCrash`).
If none of these ports handle the exception, the kernel may:
- **Convert it into a BSD signal** (for user-space processes).
- **Panic** (for kernel-space exceptions).
### Core Function: `exception_triage()`
The function `exception_triage()` routes Mach exceptions up the chain of possible handlers until one handles it or until it's finally fatal. It's defined in `osfmk/kern/exception.c`.
```c
void exception_triage(exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t codeCnt);
Типовий потік викликів:
exception_triage() └── exception_deliver() ├── exception_deliver_thread() ├── exception_deliver_task() └── exception_deliver_host()
Якщо всі зазнають невдачі → обробляється bsd_exception() → перетворюється на сигнал, наприклад SIGSEGV.
Порти виключень
Кожен об’єкт Mach (thread, task, host) може зареєструвати exception ports, куди надсилаються повідомлення про винятки.
Вони визначені API:
task_set_exception_ports()
thread_set_exception_ports()
host_set_exception_ports()
Each exception port has:
- A mask (які винятки він хоче отримувати)
- A port name (Mach port для отримання повідомлень)
- A behavior (як kernel надсилає повідомлення)
- A flavor (який thread state включити)
Debuggers and Exception Handling
A debugger (наприклад, LLDB) встановлює an exception port на цільовий task або thread, зазвичай використовуючи task_set_exception_ports().
Коли відбувається виняток:
- Mach message надсилається в процес debugger.
- Debugger може вирішити handle (resume, змінити регістри, пропустити інструкцію) або не handle виняток.
- Якщо debugger не обробляє його, виняток поширюється на наступний рівень (task → host).
Flow of EXC_BAD_ACCESS
-
Thread дереференсує недійсний вказівник → CPU піднімає Data Abort.
-
Kernel trap handler викликає
exception_triage(EXC_BAD_ACCESS, ...). -
Повідомлення надсилається до:
-
Thread port → (debugger може перехопити breakpoint).
-
Якщо debugger ігнорує → Task port → (process-level handler).
-
Якщо ігнорують → Host port (зазвичай ReportCrash).
- Якщо ніхто не обробляє →
bsd_exception()перетворює вSIGSEGV.
PAC Exceptions
Коли Pointer Authentication (PAC) не проходить перевірку (невідповідність підпису), піднімається спеціальний Mach exception:
EXC_ARM_PAC(type)- Коди можуть містити деталі (наприклад, тип ключа, тип вказівника).
Якщо у бінарі встановлено прапор TFRO_PAC_EXC_FATAL, kernel трактує PAC failures як фатальні, обходячи перехоплення debugger. Це зроблено, щоб запобігти використанню debugger для обходу PAC перевірок і увімкнено для platform binaries.
Software Breakpoints
Software breakpoint (int3 на x86, brk на ARM64) реалізовується шляхом умисного спричинення fault.
Debugger ловить це через exception port:
- Змінює instruction pointer або пам’ять.
- Відновлює оригінальну інструкцію.
- Відновлює виконання.
Цей же механізм дозволяє “catch” PAC exception — якщо не встановлено TFRO_PAC_EXC_FATAL, в іншому випадку це ніколи не досягає debugger’а.
Conversion to BSD Signals
Якщо жоден handler не приймає exception:
-
Kernel викликає
task_exception_notify() → bsd_exception(). -
Це відображає Mach exceptions у сигнали:
| Mach Exception | Signal |
|---|---|
| EXC_BAD_ACCESS | SIGSEGV or SIGBUS |
| EXC_BAD_INSTRUCTION | SIGILL |
| EXC_ARITHMETIC | SIGFPE |
| EXC_SOFTWARE | SIGTRAP |
| EXC_BREAKPOINT | SIGTRAP |
| EXC_CRASH | SIGKILL |
| EXC_ARM_PAC | SIGILL (on non-fatal) |
### Key Files in XNU Source
-
osfmk/kern/exception.c→ Core ofexception_triage(),exception_deliver_*(). -
bsd/kern/kern_sig.c→ Signal delivery logic. -
osfmk/arm64/trap.c→ Low-level trap handlers. -
osfmk/mach/exc.h→ Exception codes and structures. -
osfmk/kern/task.c→ Task exception port setup.
Old Kernel Heap (Pre-iOS 15 / Pre-A12 era)
Kernel використовував zone allocator (kalloc), поділений на фіксовані “zones”.
Кожна zone зберігала алокації лише одного розміру (size class).
Зі знімка екрана:
| Zone Name | Element Size | Example Use |
|---|---|---|
default.kalloc.16 | 16 bytes | Дуже малі kernel structs, pointers. |
default.kalloc.32 | 32 bytes | Малі структури, заголовки об’єктів. |
default.kalloc.64 | 64 bytes | IPC messages, крихітні kernel buffers. |
default.kalloc.128 | 128 bytes | Середні об’єкти, наприклад частини OSObject. |
| … | … | … |
default.kalloc.1280 | 1280 bytes | Великі структури, IOSurface/graphics metadata. |
Як це працювало:
- Кожен запит на алокацію округлювався вгору до найближчого розміру zone.
(Напр., запит на 50 байт потрапляв у
kalloc.64zone). - Пам’ять у кожній zone зберігалася у freelist — chunks, які звільнялися kernel-ом, поверталися в ту ж zone.
- Якщо ви переповнювали буфер розміром 64 байти, ви б перезаписали наступний об’єкт у тій же zone.
Ось чому heap spraying / feng shui був таким ефективним: можна було передбачити сусідні об’єкти, «розпилюючи» алокації одного й того ж size class.
The freelist
Всередині кожної kalloc zone звільнені об’єкти не поверталися одразу в систему — вони йшли у freelist, зв’язаний список доступних chunk-ів.
-
Коли chunk звільняли, kernel записував вказівник на початку цього chunk → адресу наступного вільного chunk-а в тій же zone.
-
Zone зберігала HEAD вказівник на перший вільний chunk.
-
Алокація завжди використовувала поточний HEAD:
-
Pop HEAD (повернути цю пам’ять виклику).
-
Оновити HEAD = HEAD->next (записано в заголовку звільненого chunk-а).
-
Freeing штовхав chunks назад:
-
freed_chunk->next = HEAD -
HEAD = freed_chunk
Отже, freelist — це просто зв’язаний список, побудований всередині самої звільненої пам’яті.
Normal state:
Zone page (64-byte chunks for example):
[ A ] [ F ] [ F ] [ A ] [ F ] [ A ] [ F ]
Freelist view:
HEAD ──► [ F ] ──► [ F ] ──► [ F ] ──► [ F ] ──► NULL
(next ptrs stored at start of freed chunks)
Експлуатація freelist
Оскільки перші 8 байт вільного chunk = freelist pointer, атакуючий може його пошкодити:
-
Heap overflow у сусідній freed chunk → перезаписати його “next” pointer.
-
Use-after-free запис у freed object → перезаписати його “next” pointer.
Потім, при наступному виділенні пам’яті цього розміру:
-
Аллокатор витягає (pops) пошкоджений chunk.
-
Слідує наданому атакуючим “next” pointer.
-
Повертає pointer на довільну ділянку пам’яті, що дозволяє fake object primitives або цілеспрямований перезапис.
Візуальний приклад freelist poisoning:
Before corruption:
HEAD ──► [ F1 ] ──► [ F2 ] ──► [ F3 ] ──► NULL
After attacker overwrite of F1->next:
HEAD ──► [ F1 ]
(next) ──► 0xDEAD_BEEF_CAFE_BABE (attacker-chosen)
Next alloc of this zone → kernel hands out memory at attacker-controlled address.
This freelist design made exploitation highly effective pre-hardening: predictable neighbors from heap sprays, raw pointer freelist links, and no type separation allowed attackers to escalate UAF/overflow bugs into arbitrary kernel memory control.
Heap Grooming / Feng Shui
The goal of heap grooming is to shape the heap layout so that when an attacker triggers an overflow or use-after-free, the target (victim) object sits right next to an attacker-controlled object.
That way, when memory corruption happens, the attacker can reliably overwrite the victim object with controlled data.
Steps:
- Spray allocations (fill the holes)
- Over time, the kernel heap gets fragmented: some zones have holes where old objects were freed.
- The attacker first makes lots of dummy allocations to fill these gaps, so the heap becomes “packed” and predictable.
- Force new pages
- Once the holes are filled, the next allocations must come from new pages added to the zone.
- Fresh pages mean objects will be clustered together, not scattered across old fragmented memory.
- This gives the attacker much better control of neighbors.
- Place attacker objects
- The attacker now sprays again, creating lots of attacker-controlled objects in those new pages.
- These objects are predictable in size and placement (since they all belong to the same zone).
- Free a controlled object (make a gap)
- The attacker deliberately frees one of their own objects.
- This creates a “hole” in the heap, which the allocator will later reuse for the next allocation of that size.
- Victim object lands in the hole
- The attacker triggers the kernel to allocate the victim object (the one they want to corrupt).
- Since the hole is the first available slot in the freelist, the victim is placed exactly where the attacker freed their object.
- Overflow / UAF into victim
- Now the attacker has attacker-controlled objects around the victim.
- By overflowing from one of their own objects (or reusing a freed one), they can reliably overwrite the victim’s memory fields with chosen values.
Why it works:
- Zone allocator predictability: allocations of the same size always come from the same zone.
- Freelist behavior: new allocations reuse the most recently freed chunk first.
- Heap sprays: attacker fills memory with predictable content and controls layout.
- End result: attacker controls where the victim object lands and what data sits next to it.
Modern Kernel Heap (iOS 15+/A12+ SoCs)
Apple hardened the allocator and made heap grooming much harder:
1. From Classic kalloc to kalloc_type
- Before: a single
kalloc.<size>zone existed for each size class (16, 32, 64, … 1280, etc.). Any object of that size was placed there → attacker objects could sit next to privileged kernel objects. - Now:
- Kernel objects are allocated from typed zones (
kalloc_type). - Each type of object (e.g.,
ipc_port_t,task_t,OSString,OSData) has its own dedicated zone, even if they’re the same size. - The mapping between object type ↔ zone is generated from the kalloc_type system at compile time.
An attacker can no longer guarantee that controlled data (OSData) ends up adjacent to sensitive kernel objects (task_t) of the same size.
2. Slabs and Per-CPU Caches
- The heap is divided into slabs (pages of memory carved into fixed-size chunks for that zone).
- Each zone has a per-CPU cache to reduce contention.
- Allocation path:
- Try per-CPU cache.
- If empty, pull from the global freelist.
- If freelist is empty, allocate a new slab (one or more pages).
- Benefit: This decentralization makes heap sprays less deterministic, since allocations may be satisfied from different CPUs’ caches.
3. Randomization inside zones
- Within a zone, freed elements are not handed back in simple FIFO/LIFO order.
- Modern XNU uses encoded freelist pointers (safe-linking like Linux, introduced ~iOS 14).
- Each freelist pointer is XOR-encoded with a per-zone secret cookie.
- This prevents attackers from forging a fake freelist pointer if they gain a write primitive.
- Some allocations are randomized in their placement within a slab, so spraying doesn’t guarantee adjacency.
4. Guarded Allocations
- Certain critical kernel objects (e.g., credentials, task structures) are allocated in guarded zones.
- These zones insert guard pages (unmapped memory) between slabs or use redzones around objects.
- Any overflow into the guard page triggers a fault → immediate panic instead of silent corruption.
5. Page Protection Layer (PPL) and SPTM
- Even if you control a freed object, you can’t modify all of kernel memory:
- PPL (Page Protection Layer) enforces that certain regions (e.g., code signing data, entitlements) are read-only even to the kernel itself.
- On A15/M2+ devices, this role is replaced/enhanced by SPTM (Secure Page Table Monitor) + TXM (Trusted Execution Monitor).
- These hardware-enforced layers mean attackers can’t escalate from a single heap corruption to arbitrary patching of critical security structures.
- (Added / Enhanced): also, PAC (Pointer Authentication Codes) is used in the kernel to protect pointers (especially function pointers, vtables) so that forging or corrupting them becomes harder.
- (Added / Enhanced): zones may enforce zone_require / zone enforcement, i.e. that an object freed can only be returned through its correct typed zone; invalid cross-zone frees may panic or be rejected. (Apple alludes to this in their memory safety posts)
6. Large Allocations
- Not all allocations go through
kalloc_type. - Very large requests (above ~16 KB) bypass typed zones and are served directly from kernel VM (kmem) via page allocations.
- These are less predictable, but also less exploitable, since they don’t share slabs with other objects.
7. Allocation Patterns Attackers Target
Even with these protections, attackers still look for:
- Reference count objects: if you can tamper with retain/release counters, you may cause use-after-free.
- Objects with function pointers (vtables): corrupting one still yields control flow.
- Shared memory objects (IOSurface, Mach ports): these are still attack targets because they bridge user ↔ kernel.
But — unlike before — you can’t just spray OSData and expect it to neighbor a task_t. You need type-specific bugs or info leaks to succeed.
Example: Allocation Flow in Modern Heap
Suppose userspace calls into IOKit to allocate an OSData object:
- Type lookup →
OSDatamaps tokalloc_type_osdatazone (size 64 bytes). - Check per-CPU cache for free elements.
- If found → return one.
- If empty → go to global freelist.
- If freelist empty → allocate a new slab (page of 4KB → 64 chunks of 64 bytes).
- Return chunk to caller.
Freelist pointer protection:
- Each freed chunk stores the address of the next free chunk, but encoded with a secret key.
- Overwriting that field with attacker data won’t work unless you know the key.
Comparison Table
| Feature | Old Heap (Pre-iOS 15) | Modern Heap (iOS 15+ / A12+) |
|---|---|---|
| Allocation granularity | Fixed size buckets (kalloc.16, kalloc.32, etc.) | Size + type-based buckets (kalloc_type) |
| Placement predictability | High (same-size objects side by side) | Low (same-type grouping + randomness) |
| Freelist management | Raw pointers in freed chunks (easy to corrupt) | Encoded pointers (safe-linking style) |
| Adjacent object control | Easy via sprays/frees (feng shui predictable) | Hard — typed zones separate attacker objects |
| Kernel data/code protections | Few hardware protections | PPL / SPTM protect page tables & code pages, and PAC protects pointers |
| Allocation reuse validation | None (freelist pointers raw) | zone_require / zone enforcement |
| Exploit reliability | High with heap sprays | Much lower, requires logic bugs or info leaks |
| Large allocations handling | All small allocations managed equally | Large ones bypass zones → handled via VM |
Modern Userland Heap (iOS, macOS — type-aware / xzone malloc)
In recent Apple OS versions (especially iOS 17+), Apple introduced a more secure userland allocator, xzone malloc (XZM). This is the user-space analog to the kernel’s kalloc_type, applying type awareness, metadata isolation, and memory tagging safeguards.
Goals & Design Principles
- Type segregation / type awareness: group allocations by type or usage (pointer vs data) to prevent type confusion and cross-type reuse.
- Metadata isolation: separate heap metadata (e.g. free lists, size/state bits) from object payloads so that out-of-bounds writes are less likely to corrupt metadata.
- Guard pages / redzones: insert unmapped pages or padding around allocations to catch overflows.
- Memory tagging (EMTE / MIE): work in conjunction with hardware tagging to detect use-after-free, out-of-bounds, and invalid accesses.
- Scalable performance: maintain low overhead, avoid excessive fragmentation, and support many allocations per second with low latency.
Architecture & Components
Below are the main elements in the xzone allocator:
Segment Groups & Zones
- Segment groups partition the address space by usage categories: e.g.
data,pointer_xzones,data_large,pointer_large. - Each segment group contains segments (VM ranges) that host allocations for that category.
- Associated with each segment is a metadata slab (separate VM area) that stores metadata (e.g. free/used bits, size classes) for that segment. This out-of-line (OOL) metadata ensures that metadata is not intermingled with object payloads, mitigating corruption from overflows.
- Segments are carved into chunks (slices) which in turn are subdivided into blocks (allocation units). A chunk is tied to a specific size class and segment group (i.e. all blocks in a chunk share the same size & category).
- For small / medium allocations, it will use fixed-size chunks; for large/huges, it may map separately.
Chunks & Blocks
- A chunk is a region (often several pages) dedicated to allocations of one size class within a group.
- Inside a chunk, blocks are slots available for allocations. Freed blocks are tracked via the metadata slab — e.g. via bitmaps or free lists stored out-of-line.
- Between chunks (or within), guard slices / guard pages may be inserted (e.g. unmapped slices) to catch out-of-bounds writes.
Type / Type ID
- Every allocation site (or call to malloc, calloc, etc.) is associated with a type identifier (a
malloc_type_id_t) which encodes what kind of object is being allocated. That type ID is passed to the allocator, which uses it to select which zone / segment to serve the allocation. - Because of this, even if two allocations have the same size, they may go into entirely different zones if their types differ.
- In early iOS 17 versions, not all APIs (e.g. CFAllocator) were fully type-aware; Apple addressed some of those weaknesses in iOS 18.
Allocation & Freeing Workflow
Here is a high-level flow of how allocation and deallocation operate in xzone:
- malloc / calloc / realloc / typed alloc is invoked with a size and type ID.
- The allocator uses the type ID to pick the correct segment group / zone.
- Within that zone/segment, it seeks a chunk that has free blocks of the requested size.
- It may consult local caches / per-thread pools or free block lists from metadata.
- If no free block is available, it may allocate a new chunk in that zone.
- The metadata slab is updated (free bit cleared, bookkeeping).
- If memory tagging (EMTE) is in play, the returned block gets a tag assigned, and metadata is updated to reflect its “live” state.
- When
free()is called:
- The block is marked as freed in metadata (via OOL slab).
- The block may be placed into a free list or pooled for reuse.
- Optionally, block contents may be cleared or poisoned to reduce data leaks or use-after-free exploitation.
- The hardware tag associated with the block may be invalidated or re-tagged.
- If an entire chunk becomes free (all blocks freed), the allocator may reclaim that chunk (unmap it or return to OS) under memory pressure.
Security Features & Hardening
These are the defenses built into modern userland xzone:
| Feature | Purpose | Notes |
|---|---|---|
| Metadata decoupling | Prevent overflow from corrupting metadata | Metadata lives in separate VM region (metadata slab) |
| Guard pages / unmapped slices | Catch out-of-bounds writes | Helps detect buffer overflows rather than silently corrupting adjacent blocks |
| Type-based segregation | Prevent cross-type reuse & type confusion | Even same-size allocations from different types go to different zones |
| Memory Tagging (EMTE / MIE) | Detect invalid access, stale references, OOB, UAF | xzone works in concert with hardware EMTE in synchronous mode (“Memory Integrity Enforcement”) |
| Delayed reuse / poisoning / zap | Reduce chance of use-after-free exploitation | Freed blocks may be poisoned, zeroed, or quarantined before reuse |
| Chunk reclamation / dynamic unmapping | Reduce memory waste and fragmentation | Entire chunks may be unmapped when unused |
| Randomization / placement variation | Prevent deterministic adjacency | Blocks in a chunk and chunk selection may have randomized aspects |
| Segregation of “data-only” allocations | Separate allocations that don’t store pointers | Reduces attacker control over metadata or control fields |
Interaction with Memory Integrity Enforcement (MIE / EMTE)
- Apple’s MIE (Memory Integrity Enforcement) is the hardware + OS framework that brings Enhanced Memory Tagging Extension (EMTE) into always-on, synchronous mode across major attack surfaces.
- xzone allocator is a fundamental foundation of MIE in user space: allocations done via xzone get tags, and accesses are checked by hardware.
- In MIE, the allocator, tag assignment, metadata management, and tag confidentiality enforcement are integrated to ensure that memory errors (e.g. stale reads, OOB, UAF) are caught immediately, not exploited later.
- If you like, I can also generate a cheat-sheet or diagram of xzone internals for your book. Do you want me to do that next?
- :contentReference[oai:20]{index=20}
(Old) Physical Use-After-Free via IOSurface
Ghidra Install BinDiff
Download BinDiff DMG from https://www.zynamics.com/bindiff/manual and install it.
Open Ghidra with ghidraRun and go to File –> Install Extensions, press the add button and select the path /Applications/BinDiff/Extra/Ghidra/BinExport and click OK and isntall it even if there is a version mismatch.
Using BinDiff with Kernel versions
- Go to the page https://ipsw.me/ and download the iOS versions you want to diff. These will be
.ipswfiles. - Decompress until you get the bin format of the kernelcache of both
.ipswfiles. You have information on how to do this on:
macOS Kernel Extensions & Kernelcache
- Open Ghidra with
ghidraRun, create a new project and load the kernelcaches. - Open each kernelcache so they are automatically analyzed by Ghidra.
- Then, on the project Window of Ghidra, right click each kernelcache, select
Export, select formatBinary BinExport (v2) for BinDiffand export them. - Open BinDiff, create a new workspace and add a new diff indicating as primary file the kernelcache that contains the vulnerability and as secondary file the patched kernelcache.
Finding the right XNU version
If you want to check for vulnerabilities in a specific version of iOS, you can check which XNU release version the iOS version uses at [https://www.theiphonewiki.com/wiki/kernel]https://www.theiphonewiki.com/wiki/kernel).
For example, the versions 15.1 RC, 15.1 and 15.1.1 use the version Darwin Kernel Version 21.1.0: Wed Oct 13 19:14:48 PDT 2021; root:xnu-8019.43.1~1/RELEASE_ARM64_T8006.
JSKit-Based Safari Chains and PREYHUNTER Stagers
Renderer RCE abstraction with JSKit
- Reusable entry: Recent in-the-wild chains abused a WebKit JIT bug (patched as CVE-2023-41993) purely to gain JavaScript-level arbitrary read/write. The exploit immediately pivots into a purchased framework called JSKit, so any future Safari bug only needs to deliver the same primitive.
- Version abstraction & PAC bypasses: JSKit bundles support for a wide range of iOS releases together with multiple, selectable Pointer Authentication Code bypass modules. The framework fingerprints the target build, selects the appropriate PAC bypass logic, and verifies every step (primitive validation, shellcode launch) before progressing.
- Manual Mach-O mapping: JSKit parses Mach-O headers directly from memory, resolves the symbols it needs inside dyld-cached images, and can manually map additional Mach-O payloads without writing them to disk. This keeps the renderer process in-memory only and evades code-signature checks tied to filesystem artifacts.
- Portfolio model: Debug strings such as “exploit number 7” show that the suppliers maintain multiple interchangeable WebKit exploits. Once the JS primitive matches JSKit’s interface, the rest of the chain is unchanged across campaigns.
Kernel bridge: IPC UAF -> code-sign bypass pattern
- Kernel IPC UAF (CVE-2023-41992): The second stage, still running inside the Safari context, triggers a kernel use-after-free in IPC code, re-allocates the freed object from userland, and abuses the dangling pointers to pivot into arbitrary kernel read/write. The stage also reuses PAC bypass material previously computed by JSKit instead of re-deriving it.
- Code-signing bypass (CVE-2023-41991): With kernel R/W available, the exploit patches the trust cache / code-signing structures so unsigned payloads execute as
system. The stage then exposes a lightweight kernel R/W service to later payloads. - Composed pattern: This chain demonstrates a reusable recipe that defenders should expect going forward:
WebKit renderer RCE -> kernel IPC UAF -> kernel arbitrary R/W -> code-sign bypass -> unsigned system stager
PREYHUNTER модулі helper & watcher
- Watcher anti-analysis: Спеціальний бінарний watcher постійно профілює пристрій і перериває kill-chain, коли виявлено дослідницьке середовище. Він перевіряє
security.mac.amfi.developer_mode_status, наявність консоліdiagnosticd, локаліUSабоIL, сліди jailbreak, такі як Cydia, процеси на кшталтbash,tcpdump,frida,sshdабоcheckrain, мобільні AV-додатки (McAfee, AvastMobileSecurity, NortonMobileSecurity), кастомні налаштування HTTP proxy та кастомні root CA. Невдача в будь-якій з перевірок блокує подальшу доставку payload. - Helper surveillance hooks: Компонент helper спілкується з іншими стадіями через
/tmp/helper.sock, після чого завантажує набори хукiв під назвами DMHooker і UMHooker. Ці хуки підключаються до VOIP аудіо-потоків (записи зберігаються під/private/var/tmp/l/voip_%lu_%u_PART.m4a), реалізують system-wide keylogger, роблять знімки без UI та хукaють SpringBoard, щоб приглушити сповіщення, які ці дії зазвичай викликають. Таким чином helper виступає як прихований шар валідації і легкого спостереження перед тим, як будуть закинуті важчі implants, такі як Predator.
WebKit DFG Store-Barrier UAF + ANGLE PBO OOB (iOS 26.1)
Webkit Dfg Store Barrier Uaf Angle Oob
iMessage/Media Parser Zero-Click Chains
Imessage Media Parser Zero Click Coreaudio Pac Bypass
Джерела
Tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.


