Eksploatisanje iOS-a

Tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks

Mitigacije za iOS exploite

1. Code Signing / Provera potpisa u runtime-u

Uvedeno rano (iPhone OS → iOS) Ovo je jedna od osnovnih zaštita: sav izvršni kod (apps, dynamic libraries, JIT-ed code, extensions, frameworks, caches) mora biti kriptografski potpisan sertifikacionim lancem čiji je koren u Apple-ovom trust-u. U runtime-u, pre nego što se binarni fajl učita u memoriju (ili pre izvođenja skokova preko određenih granica), sistem proverava njegov potpis. Ako je kod izmenjen (bit-flipped, patched) ili nije potpisan, učitavanje ne uspeva.

  • Sprečava: fazu “classic payload drop + execute” u exploit lancima; arbitrary code injection; modifikovanje postojećeg binarnog fajla da se ubaci zlonamerni kod.
  • Detalji mehanizma:
  • Mach-O loader (and dynamic linker) proverava code pages, segments, entitlements, team IDs, i da li potpis pokriva sadržaj fajla.
  • Za memorijske regione kao što su JIT caches ili dinamički generisan kod, Apple zahteva da stranice budu potpisane ili validirane preko specijalnih API-ja (npr. mprotect sa code-sign proverenjem).
  • Potpis uključuje entitlements i identifikatore; OS zahteva da određeni API-ji ili privilegovane sposobnosti zahtevaju specifične entitlements koje nije moguće falsifikovati.
Primer Pretpostavimo da exploit dobije code execution u procesu i pokuša da upiše shellcode u heap i skoči na njega. Na iOS-u, ta stranica bi morala da bude označena kao executable **i** da zadovolji code-signature ograničenja. Pošto shellcode nije potpisan Apple-ovim sertifikatom, skok ne uspeva ili sistem odbija da tu memorijsku oblast učini executable.

2. CoreTrust

Uvedeno oko iOS 14+ (ili postepeno na novijim uređajima / kasnijim iOS verzijama) CoreTrust je subsistem koji vrši runtime validaciju potpisa binarnih fajlova (uključujući sistemske i korisničke binare) u odnosu na Apple-ov root certificate umesto da se oslanja na keširane userland trust store-ove.

  • Sprečava: post-install tampering binarnih fajlova, jailbreak tehnike koje pokušavaju da zamene ili patch-uju sistemske biblioteke ili user apps; obmanjivanje sistema zamenom trusted binarnih fajlova malicioznim verzijama.
  • Detalji mehanizma:
  • Umesto da veruje lokalnoj trust bazi ili kešu sertifikata, CoreTrust referiše direktno Apple-ov root ili verifikuje intermediainte u bezbednom lancu.
  • Osigurava da se izmene (npr. u filesystem-u) postojećih binarnih fajlova detektuju i odbacuju.
  • Veže entitlements, team IDs, code signing flagove i drugu meta-informaciju za binarni fajl pri učitavanju.
Primer Jailbreak bi mogao pokušati da zameni `SpringBoard` ili `libsystem` patch-ovanom verzijom da bi stekao perzistenciju. Ali kada loader sistema ili CoreTrust proveri, primeti mismatch potpisa (ili izmenjene entitlements) i odbije izvršavanje.

3. Data Execution Prevention (DEP / NX / W^X)

Uvedeno ranije u mnogim OS-ovima; iOS ima NX-bit / w^x već dugo DEP nameće da stranice označene kao writable (za podatke) budu non-executable, i stranice označene kao executable budu non-writable. Ne možete jednostavno upisati shellcode u heap ili stack region i izvršiti ga.

  • Sprečava: direktno izvršavanje shellcode-a; klasični buffer-overflow → skok na ubaceni shellcode.
  • Detalji mehanizma:
  • MMU / memory protection flagovi (putem page table-a) sprovode razdvajanje.
  • Bilo koji pokušaj da se writable stranica označi kao executable pokreće sistemsku proveru (i ili je zabranjen ili zahteva odobrenje code-sign).
  • U mnogim slučajevima, označavanje stranica kao executable zahteva korišćenje OS API-ja koji nameću dodatna ograničenja ili provere.
Primer Overflow upisuje shellcode na heap. Napadač pokuša `mprotect(heap_addr, size, PROT_EXEC)` da ga učini executable. Ali sistem odbija ili zahteva validaciju da nova stranica prođe code-sign ograničenja (što shellcode ne može).

4. Address Space Layout Randomization (ASLR)

Uvedeno oko iOS ~4–5 ere (okvirno iOS 4–5) ASLR nasumično određuje baze ključnih memorijskih regiona: libraries, heap, stack, itd., pri svakom pokretanju procesa. Adrese gadgeta se pomeraju između pokretanja.

  • Sprečava: hardkodiranje adresa gadgeta za ROP/JOP; statične exploit lance; blind skakanje na poznate offset-e.
  • Detalji mehanizma:
  • Svaka učitana biblioteka / dinamički modul se rebase-uje na nasumični offset.
  • Stack i heap base su randomizovani (u okviru određenih entropijskih ograničenja).
  • Ponekad su i drugi regioni (npr. mmap alokacije) takođe randomizovani.
  • U kombinaciji sa information-leak mitigacijama, prisiljava napadača da prvo leak-uje adresu ili pointer da otkrije bazne adrese u runtime-u.
Primer ROP lanac očekuje gadget na `0x….lib + offset`. Ali pošto je `lib` relociran drugačije pri svakom pokretanju, hardkodirani lanac ne funkcioniše. Exploit mora prvo da leak-uje baznu adresu modula pre izračunavanja adresa gadgeta.

5. Kernel Address Space Layout Randomization (KASLR)

Uvedeno oko iOS ~ (iOS 5 / iOS 6 vremenski okvir) Analogno user ASLR-u, KASLR nasumično određuje bazu kernel text i drugih kernel struktura pri boot-u.

  • Sprečava: kernel-level exploite koji se oslanjaju na fiksne lokacije kernel koda ili podataka; statične kernel exploite.
  • Detalji mehanizma:
  • Pri svakom boot-u, kernel base adresa je randomizovana (u opsegu).
  • Kernel strukture podataka (kao task_structs, vm_map, itd.) takođe mogu biti relocirane ili ofsetovane.
  • Napadači moraju prvo da leak-uju kernel pointere ili koriste information disclosure ranjivosti da izračunaju offset-e pre napada na kernel strukture ili kod.
Primer Lokalna ranjivost ima cilj da korumpira kernel function pointer (npr. u `vtable`) na `KERN_BASE + offset`. Ali pošto je `KERN_BASE` nepoznat, napadač mora najpre da ga leak-uje (npr. preko read primitive) pre nego što izračuna ispravnu adresu za korupciju.

6. Kernel Patch Protection (KPP / AMCC)

Uvedeno na novijim iOS / A-series hardveru (otprilike posle iOS 15–16 ere ili novijih čipova) KPP (takođe poznat kao AMCC) kontinuirano prati integritet kernel text stranica (putem hash-a ili checksum-a). Ako detektuje tampering (patch-eve, inline hook-ove, modifikacije koda) izvan dozvoljenih perioda, pokreće kernel panic ili reboot.

  • Sprečava: perzistentno patch-ovanje kernela (modifikovanje kernel instrukcija), inline hook-ove, statičke prepiske funkcija.
  • Detalji mehanizma:
  • Hardverski ili firmware modul nadgleda kernel text region.
  • Periodično ili na zahtev re-hash-uje stranice i upoređuje sa očekivanim vrednostima.
  • Ako se desi mismatch izvan benignih update perioda, izaziva panic uređaja (da bi se izbegla perzistencija malicioznog patch-a).
  • Napadači moraju ili izbeći detekcijske prozore ili koristiti legitimne puteve za patch.
Primer Exploit pokušava da patch-uje prolog kernel funkcije (npr. `memcmp`) da bi presretao pozive. Ali KPP primećuje da hash code stranice više ne odgovara očekivanoj vrednosti i izaziva kernel panic, rušeći uređaj pre nego što patch postane stabilan.

7. Kernel Text Read‐Only Region (KTRR)

Uvedeno u modernim SoC-ovima (posle ~A12 / noviji hardver) KTRR je hardverski sproveden mehanizam: jednom kada se kernel text zaključa rano tokom boot-a, postaje read-only iz EL1 (kernel), sprečavajući dalji upis u code stranice.

  • Sprečava: bilo kakve modifikacije kernel koda posle boota (npr. patch-ovanje, in-place code injection) na EL1 privilegijanom nivou.
  • Detalji mehanizma:
  • Tokom boota (u secure/bootloader fazi), memory controller (ili sigurna hardverska jedinica) označava fizičke stranice koje sadrže kernel text kao read-only.
  • Čak i ako exploit dobije potpune kernel privilegije, ne može da upisuje u te stranice da bi patch-ovao instrukcije.
  • Da bi ih menjao, napadač prvo mora kompromitovati boot chain ili podmititi/oboriti KTRR sam.
Primer Privilege-escalation exploit skoči u EL1 i pokuša da upiše trampoline u kernel funkciju (npr. u `syscall` handler). Ali pošto su stranice zaključane kao read-only od strane KTRR, upis ne uspeva (ili pokreće fault), pa patch ne bude primenjen.

8. Pointer Authentication Codes (PAC)

Uvedeno sa ARMv8.3 (hardver), Apple počevši od A12 / iOS ~12+

  • PAC je hardverska funkcija uvedena u ARMv8.3-A za detekciju modifikacije vrednosti pokazivača (return addresses, function pointers, određeni data pointers) ubacivanjem malog kriptografskog potpisa (“MAC”) u neiskorišćene visoke bitove pokazivača.
  • Potpis (“PAC”) se računa preko vrednosti pointera plus modifier (kontekst vrednost, npr. stack pointer ili neki identifikator). Tako ista vrednost pointera u različitim kontekstima dobija različit PAC.
  • Pri upotrebi, instrukcija za autentikaciju proverava PAC. Ako je validan, PAC se uklanja i dobija se „čisti“ pointer; ako nije, pointer postaje “poisoned” (ili se podiže fault).
  • Ključevi korišćeni za proizvodnju/validaciju PAC-a žive u privilegovanim registrima (EL1, kernel) i nisu direktno čitljivi iz user moda.
  • Pošto se ne koriste svi 64 bita pointera u mnogim sistemima (npr. 48-bit address space), gornji bitovi su “slobodni” i mogu držati PAC bez menjanja efektivne adrese.

Arhitektonska osnova i tipovi ključeva

  • ARMv8.3 uvodi pet 128-bitnih ključeva (svaki implementiran kroz dva 64-bit sistema registra) za pointer authentication.

  • APIAKey — za instruction pointers (domen “I”, ključ A)

  • APIBKey — drugi ključ za instruction pointers (domen “I”, ključ B)

  • APDAKey — za data pointers (domen “D”, ključ A)

  • APDBKey — za data pointers (domen “D”, ključ B)

  • APGAKey — “generic” ključ, za potpisivanje ne-pointer podataka ili druge generičke upotrebe

  • Ovi ključevi se čuvaju u privilegovanim sistemskim registrima (dostupnim samo na EL1/EL2 itd.), nisu dostupni iz user moda.

  • PAC se računa kriptografskom funkcijom (ARM predlaže QARMA kao algoritam) koristeći:

  1. Vrednost pointera (kanonični deo)
  2. modifier (kontekst vrednost, poput soli)
  3. Tajni ključ
  4. Internu tweak logiku Ako rezultatni PAC odgovara onome što je smešteno u gornjim bitovima pointera, autentikacija uspeva.

Porodice instrukcija

Konvencija imenovanja: PAC / AUT / XPAC, pa zatim sufiksi domena.

  • PACxx instrukcije potpisuju pointer i ubacuju PAC
  • AUTxx instrukcije autentikuju + uklanjaju (validiraju i uklone PAC)
  • XPACxx instrukcije uklanjaju bez validacije

Domeni / sufiksi:

MnemonicMeaning / DomainKey / DomainExample Usage in Assembly
PACIASign instruction pointer with APIAKey“I, A”PACIA X0, X1 — sign pointer in X0 using APIAKey with modifier X1
PACIBSign instruction pointer with APIBKey“I, B”PACIB X2, X3
PACDASign data pointer with APDAKey“D, A”PACDA X4, X5
PACDBSign data pointer with APDBKey“D, B”PACDB X6, X7
PACG / PACGAGeneric (non-pointer) signing with APGAKey“G”PACGA X8, X9, X10 (sign X9 with modifier X10 into X8)
AUTIAAuthenticate APIA-signed instruction pointer & strip PAC“I, A”AUTIA X0, X1 — check PAC on X0 using modifier X1, then strip
AUTIBAuthenticate APIB domain“I, B”AUTIB X2, X3
AUTDAAuthenticate APDA-signed data pointer“D, A”AUTDA X4, X5
AUTDBAuthenticate APDB-signed data pointer“D, B”AUTDB X6, X7
AUTGAAuthenticate generic / blob (APGA)“G”AUTGA X8, X9, X10 (validate generic)
XPACIStrip PAC (instruction pointer, no validation)“I”XPACI X0 — remove PAC from X0 (instruction domain)
XPACDStrip PAC (data pointer, no validation)“D”XPACD X4 — remove PAC from data pointer in X4

Postoje specijalizovane / alias forme:

  • PACIASP je skraćeno za PACIA X30, SP (potpiši link register koristeći SP kao modifier)
  • AUTIASP je AUTIA X30, SP (autentikuj link register sa SP)
  • Kombinovane forme kao RETAA, RETAB (authenticate-and-return) ili BLRAA (authenticate & branch) postoje u ARM ekstenzijama / podršci kompajlera.
  • Takođe varijante sa nultim modifier-om: PACIZA / PACIZB gde je modifier implicitno nula, itd.

Modifiers

Glavni cilj modifier-a je da veže PAC za specifičan kontekst tako da ista adresa potpisana u različitim kontekstima daje različit PAC. Ovo sprečava jednostavnu ponovnu upotrebu pointer-a između frame-ova ili objekata. Radi se o dodavanju soli u hash.

Dakle:

  • modifier je kontekstualna vrednost (drugi registar) koja se meša u PAC računanje. Tipični izbori: stack pointer (SP), frame pointer, ili neki object ID.
  • Korišćenje SP kao modifier-a je uobičajeno za potpisivanje return adresa: PAC je vezan za konkretan stack frame. Ako pokušate da ponovo upotrebite LR u drugom frame-u, modifier se menja i PAC validacija ne uspe.
  • Ista vrednost pointera potpisana sa različitim modifier-ima daje različite PAC-ove.
  • Modifier ne mora biti tajan, ali idealno nije kontrolisan od strane napadača.
  • Za instrukcije koje potpisuju ili verifikuju pointere gde nema smislenog modifier-a, neke forme koriste nulu ili implicitnu konstantu.

Apple / iOS / XNU prilagođavanja & zapažanja

  • Apple-ova PAC implementacija uključuje per-boot diversifiers tako da se ključevi ili tweak-ovi menjaju pri svakom boot-u, sprečavajući ponovnu upotrebu između boot-ova.
  • Takođe uključuju cross-domain mitigacije tako da PAC-ovi potpisani u user mode ne mogu lako da se ponovo iskoriste u kernel modu, itd.
  • Na Apple M1 / Apple Silicon, reverzni inženjering je pokazao da postoji devet tipova modifier-a i Apple-specifični sistemski registri za kontrolu ključeva.
  • Apple koristi PAC u mnogim kernel subsistemima: potpisivanje return adresa, integritet pointera u kernel podacima, potpisani thread konteksti, itd.
  • Google Project Zero je pokazao kako uz moćan memory read/write primitive u kernel-u, moguće je foržovati kernel PAC-ove (za A ključeve) na A12-era uređajima, ali je Apple zakrpio mnoge od tih puteva.
  • U Apple-ovom sistemu, neki ključevi su globalni unutar kernela, dok procesi u user modu mogu dobiti per-process key randomness.

PAC bypass tehnike

  1. Kernel-mode PAC: teorijski vs realni bypass-ovi
  • Pošto su kernel PAC ključevi i logika strogo kontrolisani (privilegovani registri, diversifier-i, izolacija domena), foržovanje arbitrarno potpisanih kernel pointera je vrlo teško.
  • Azad-ov 2020 rad “iOS Kernel PAC, One Year Later” izveštava da je u iOS 12-13 pronađeno nekoliko delimičnih bypass-a (signing gadgets, reuse of signed states, unprotected indirect branches) ali nije bilo potpunog generičkog bypass-a. bazad.github.io
  • Apple-ove “Dark Magic” prilagodbe dodatno su suzile surface za exploit (domain switching, per-key enabling bits). i.blackhat.com
  • Postoji poznati kernel PAC bypass CVE-2023-32424 na Apple silicon-u (M1/M2) prijavljen od Zecao Cai i saradnika. i.blackhat.com
  • Ali ti bypass-ovi često zavise od vrlo specifičnih gadget-a ili implementacionih bug-ova; nisu generalno primenjivi.

Dakle, kernel PAC se smatra veoma robusnim, iako nije savršen.

  1. User-mode / runtime PAC bypass tehnike

Ove su češće i iskorišćavaju nedostatke u primeni PAC-a ili runtime framework-ovima. Ispod su klase sa primerima.

2.1 Shared Cache / A key problemi

  • dyld shared cache je veliki pred-linkovani blob sistemskih framework-a i biblioteka. Pošto se toliko široko deli, function pointer-i unutar shared cache-a su “pre-potpisi” i koriste ih mnogi procesi. Napadači ciljaju te već potpisane pointere kao “PAC oracles”.

  • Neki bypass pristupi pokušavaju da izvuku ili ponovo upotrebe A-key potpisane pointere prisutne u shared cache-u i ponovo ih kombinuju u gadget-e.

  • Predavanje “No Clicks Required” opisuje izgradnju oracle-a nad shared cache-om da bi se inferirale relativne adrese i kombinovalo to sa potpisanim pointerima za bypass PAC-a. saelo.github.io

  • Takođe, import-ovi function pointer-a iz shared libraries u userspace su ponekad bili nedovoljno zaštićeni od strane PAC-a, dopuštajući napadaču da dobije function pointer-e bez menjanja njihovog potpisa. (Project Zero bug entry) bugs.chromium.org

2.2 dlsym(3) / dinamičko rezolviranje simbola

  • Jedan poznat bypass je pozvati dlsym() da dobijete već potpisan function pointer (potpisan A-key, diversifier zero) i zatim ga koristiti. Pošto dlsym vraća legitimno potpisan pointer, upotreba istog zaobilazi potrebu za foržovanjem PAC-a.

  • Epsilon-ov blog detaljno opisuje kako neki bypassi iskorišćavaju ovo: poziv dlsym("someSym") vraća potpisani pointer koji se može koristiti za indirektne pozive. blog.epsilon-sec.com

  • Synacktiv-ov tekst “iOS 18.4 — dlsym considered harmful” opisuje bag: neki simboli rešeni preko dlsym na iOS 18.4 vraćaju pointere koji su netačno potpisani (ili sa buggy diversifier-ima), omogućavajući nenamerni PAC bypass. Synacktiv

  • Logika u dyld za dlsym uključuje: kada je result->isCode, oni potpisuju vraćeni pointer sa __builtin_ptrauth_sign_unauthenticated(..., key_asia, 0), tj. kontekst nula. blog.epsilon-sec.com

Dakle, dlsym je čest vektor u user-mode PAC bypass-ima.

2.3 Ostale DYLD / runtime relocations

  • DYLD loader i logika dinamičkih relocacija su kompleksni i ponekad privremeno mapiraju stranice kao read/write da bi izvršili relocacije, pa ih onda vraćaju na read-only. Napadači iskorišćavaju te prozore. Synacktiv-ovo predavanje opisuje “Operation Triangulation”, timing-baziran PAC bypass kroz dinamičke relocacije. Synacktiv

  • DYLD stranice su sada zaštićene sa SPRR / VM_FLAGS_TPRO (neki protection flag-ovi za dyld). Ali ranije verzije imale su slabije zaštite. Synacktiv

  • U WebKit exploit lancima, DYLD loader je često meta za PAC bypass. Slajdovi napominju da su mnogi PAC bypass-i ciljali DYLD loader (preko relocacija, interposer hook-ova). Synacktiv

2.4 NSPredicate / NSExpression / ObjC / SLOP

  • U userland exploit lancima, Objective-C runtime metode kao NSPredicate, NSExpression ili NSInvocation koriste se za prenos kontrolnih poziva bez očiglednog foržovanja pointer-a.

  • Na starijim iOS verzijama (pre PAC), exploit je koristio fake NSInvocation objekte da pozove proizvoljne selektore na kontrolisanoj memoriji. Sa PAC-om su potrebne modifikacije. Ali tehnika SLOP (SeLector Oriented Programming) je proširena i pod PAC-om. Project Zero

  • Originalna SLOP tehnika je omogućila chaining ObjC poziva kreiranjem lažnih invokacija; bypass zavisi od toga da ISA ili selector pointer-i ponekad nisu u potpunosti PAC-zaštićeni. Project Zero

  • U okruženjima gde je pointer authentication delimično primenjena, metode / selektori / target pointer-i možda nisu uvek PAC-zaštićeni, što daje prostor za bypass.

Primer toka

Primer potpisivanja i autentikacije ``` ; 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>Primer</summary>
A buffer overflow prepisuje return adresu na stacku. Napadač upisuje ciljnu adresu gadgeta ali ne može da izračuna ispravan PAC. Kada funkcija vrati, CPU-ova `AUTIA` instrukcija izazove fault zbog neusaglašenog PAC-a. Lanac ne uspeva.
Project Zero-ova analiza na A12 (iPhone XS) je pokazala kako Apple-ov PAC funkcioniše i metode falsifikovanja PAC-ova ako napadač ima memory read/write primitiv.
</details>


### 9. **Branch Target Identification (BTI)**
**Introduced with ARMv8.5 (later hardware)**
BTI je hardverska funkcija koja proverava **indirect branch targets**: pri izvršavanju `blr` ili indirektnih poziva/skokova, cilj mora da počne sa **BTI landing pad** (`BTI j` ili `BTI c`). Skakanje u adrese gadgeta koje nemaju landing pad pokreće izuzetak.

LLVM-ova implementacija beleži tri varijante BTI instrukcija i kako one mapiraju na tipove grana.

| BTI Variant | Šta dozvoljava (koji tipovi grana) | Tipično postavljanje / upotreba |
|-------------|----------------------------------------|-------------------------------|
| **BTI C** | Targets of *call*-style indirect branches (e.g. `BLR`, or `BR` using X16/X17) | Staviti na ulaz funkcija koje se mogu pozivati indirektno |
| **BTI J** | Targets of *jump*-style branches (e.g. `BR` used for tail calls) | Postaviti na početak blokova dostupnih preko jump tabela ili tail-call-ova |
| **BTI JC** | Acts as both C and J | Može biti meta i call i jump grana |

- U kodu kompajliranom sa branch target enforcement, kompajleri ubacuju BTI instrukciju (C, J, ili JC) na svaki validan indirect-branch target (početci funkcija ili blokovi dostupni skokovima) tako da indirektne grane uspevaju samo ka tim mestima.
- **Direktne grane / pozivi** (tj. fiks-adresni `B`, `BL`) **nisu ograničeni** od strane BTI. Pretpostavka je da su code page-ovi poverljivi i da ih napadač ne može promeniti (tako da su direktne grane bezbedne).
- Takođe, **RET / return** instrukcije generalno nisu ograničene BTI jer su return adrese zaštićene preko PAC ili mehanizama potpisivanja return-a.

#### Mehanizam i sprovođenje

- Kada CPU dekodira **indirect branch (BLR / BR)** u strani označenoj kao “guarded / BTI-enabled,” proverava da li prva instrukcija na ciljnoj adresi predstavlja validan BTI (C, J, ili JC kako je dozvoljeno). Ako nije, događa se **Branch Target Exception**.
- Kodiranje BTI instrukcije je dizajnirano da ponovo koristi opkode ranije rezervisane za NOP-ove (u ranijim ARM verzijama). Dakle, BTI-enabled binarni fajlovi ostaju back-compatible: na hardveru bez BTI podrške te instrukcije deluju kao NOP.
- Compiler pass-ovi koji dodaju BTI ubacuju ih samo gde je potrebno: funkcije koje se mogu pozivati indirektno, ili basic blokove ciljne skokovima.
- Neki patch-evi i LLVM kod pokazuju da BTI nije ubačen za *sve* basic blokove — samo za one koji su potencijalni branch targeti (npr. iz switch / jump tabela).

#### BTI + PAC sinergija

PAC štiti vrednost pointera (izvor) — osigurava da lanac indirektnih poziva / return-ova nije izmenjen.

BTI obezbeđuje da čak i validan pointer mora ciljati samo pravilno označene ulazne tačke.

Kombinovano, napadaču je potrebno i validan pointer sa ispravnim PAC i da ciljna lokacija ima postavljen BTI. To dodatno otežava konstrukciju exploit gadget-a.

#### Primer


<details>
<summary>Primer</summary>
Exploit pokušava da pivotuje u gadget na `0xABCDEF` koji ne počinje sa `BTI c`. CPU, pri izvršenju `blr x0`, proverava cilj i pravi fault jer instrukcija na toj adresi nema validan landing pad. Mnogi gadgeti postaju neupotrebljivi osim ako ne sadrže BTI prefiks.
</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** je funkcija uvedena u **ARMv8.1-A** koja sprečava **privileged code** (EL1 ili EL2) da **čita ili piše** memoriju koja je označena kao **user-accessible (EL0)**, osim ako PAN nije eksplicitno onemogućen.
- Ideja: čak i ako je kernel prevaren ili kompromitovan, on ne može proizvoljno dereferencirati user-space pointer-e bez prethodnog *isključivanja* PAN, čime se smanjuju rizici od exploit-a tipa **`ret2usr`** ili zloupotrebe user-kontrolisanih buffera.
- Kada je PAN omogućen (PSTATE.PAN = 1), svaka privilegovana load/store instrukcija koja pristupa virtuelnoj adresi koja je “accessible at EL0” izaziva **permission fault**.
- Kernel, kada mora legitimno da pristupi user-space memoriji (npr. kopiranje podataka iz/ka user buffer-a), mora **privremeno da onemogući PAN** (ili da koristi „unprivileged load/store“ instrukcije) da bi omogućio taj pristup.
- U Linux-u na ARM64, podrška za PAN uvedena je oko 2015: kernel patch-evi dodali su detekciju funkcije i zamenili `get_user` / `put_user` itd. varijantama koje brišu PAN oko pristupa user memoriji.

**Ključna nijansa / ograničenje / bag**
- Kao što su Siguza i drugi primetili, specifikacioni bag (ili dvosmisleno ponašanje) u ARM dizajnu znači da **execute-only user mappings** (`--x`) možda **ne pokreću PAN**. Drugim rečima, ako je user page označen kao izvršan ali bez prava čitanja, pokušaj kernela da ga čita može zaobići PAN jer arhitektura smatra da “accessible at EL0” zahteva pravo čitanja, ne samo izvršavanje. To vodi do PAN bypass-a u određenim konfiguracijama.
- Zbog toga, ako iOS / XNU dozvoljava execute-only user stranice (kao što neke JIT ili code-cache postavke mogu), kernel bi mogao nenamerno da čita iz njih čak i sa PAN enabled. Ovo je poznato suptilno eksploatisano područje u nekim ARMv8+ sistemima.

#### PXN (Privileged eXecute Never)

- **PXN** je bit u page table-u (u page table entry-ima, leaf ili block entry-ima) koji označava da je stranica **neizvršna kada se izvršava u privilegovanom modu** (tj. kada EL1 izvršava).
- PXN sprečava kernel (ili bilo koji privilegovani kod) da skoci ili izvrši instrukcije iz user-space stranica čak i ako je kontrola preusmerena. U suštini, to zaustavlja kernel-level preusmeravanje kontrolnog toka u user memoriju.
- Kombinovano sa PAN, ovo obezbeđuje da:
1. Kernel ne može (po defaultu) da čita ili piše user-space podatke (PAN)
2. Kernel ne može da izvršava user-space kod (PXN)
- U ARMv8 page table formatu, leaf entry-ji imaju `PXN` bit (i takođe `UXN` za unprivileged execute-never) u svojim atributnim bitovima.

Tako čak i ako kernel ima korumpiran funkcioni pointer koji pokazuje ka user memoriji i pokuša tamo da se granje, PXN bit će prouzrokovati fault.

#### Model permisija memorije & kako se PAN i PXN mapiraju na page table bitove

Da biste razumeli kako PAN / PXN rade, potrebno je videti kako ARM-ov translation i permission model funkcioniše (pojednostavljeno):

- Svaka page ili block entry ima atribut polja uključujući **AP[2:1]** za pristupna prava (čitanje/pisanje, privileged vs unprivileged) i **UXN / PXN** bitove za execute-never restrikcije.
- Kada je PSTATE.PAN 1 (omogućen), hardver sprovodi modifikovana semantika: privilegovani pristupi strenghtuju pravila — privilegovani pristupi stranicama označenim kao “accessible by EL0” (tj. user-accessible) su zabranjeni (fault).
- Zbog pomenutog buga, stranice koje su označene samo kao izvršne (bez prava čitanja) možda se ne smatraju “accessible by EL0” u nekim implementacijama, čime se može zaobići PAN.
- Kada je PXN bit stranice postavljen, čak i ako fetch instrukcije dolaze sa višeg privilegijskog nivoa, izvršenje je zabranjeno.

#### Korišćenje PAN / PXN u kernelu izdatom za hardened OS (npr. iOS / XNU)

U dizajnu ojačanog kernela (kao što Apple može koristiti):

- Kernel omogućava PAN po defaultu (tako da je privileged code ograničen).
- U putanjama koje legitimno trebaju da čitaju ili pišu user buffere (npr. kopiranje podataka iz sistema poziva, I/O, read/write user pointer), kernel privremeno **isključuje PAN** ili koristi specijalne instrukcije za nadjačavanje.
- Nakon završetka pristupa user podacima, mora ponovo da uključi PAN.
- PXN se sprovodi putem page table-a: user stranice imaju PXN = 1 (tako kernel ne može da ih izvrši), kernel stranice nemaju PXN (tako kernel kod može da se izvršava).
- Kernel mora osigurati da nijedan kod put ne dovodi do izvršavanja u user memorijskim regionima (što bi zaobišlo PXN) — tako su exploit lanci koji zavise od “jump into user-controlled shellcode” blokirani.

Zbog pomenutog PAN bypass-a preko execute-only stranica, u realnom sistemu Apple bi mogao onemogućiti ili zabraniti execute-only user stranice, ili zakrpiti specifikacionu slabost.

#### Površine napada, bypass-ovi i mitigacije

- **PAN bypass preko execute-only stranica**: kao što je diskutuovano, spec dozvoljava prazninu: user stranice sa execute-only (bez read permisije) možda neće biti blokirane PAN-om, pa kernelovi čitaoci iz takvih stranica mogu proći tokom nekih implementacija. Ovo daje napadaču neuobičajen put da unese podatke kroz “execute-only” sekcije.
- **Temporal window exploit**: ako kernel isključi PAN na prozor duži nego što je neophodno, race ili maliciozni put može iskoristiti taj prozor za neželjeni pristup user memoriji.
- **Zaboravljeno ponovno uključivanje**: ako kod putanje zaboravi da ponovo uključi PAN, naredne kernel operacije bi mogle pogrešno pristupati user memoriji.
- **Pogrešna konfiguracija PXN**: ako page table ne postavlja PXN na user stranice ili pogrešno mapira user code stranice, kernel može biti prevaren da izvrši user-space kod.
- **Spekulativno / side-channels**: analogno spekulativnim zaobilaženjima, mogu postojati mikroarhitekturni side-effekti koji uzrokuju tranzijentna kršenja PAN / PXN provera (iako su takvi napadi visoko zavisni od dizajna CPU-a).
- **Kompleksne interakcije**: U naprednijim funkcijama (npr. JIT, shared memory, just-in-time code regions), kernel može zahtevaniti finu kontrolu da dozvoli određene memorijske pristupe ili izvršenje u user-mapped regionima; dizajniranje tih mehanizama bezbedno pod PAN/PXN ograničenjima nije trivijalno.


#### Primer

<details>
<summary>Primer koda</summary>
Here are illustrative pseudo-assembly sequences showing enabling/disabling PAN around user memory access, and how a fault might occur.

// 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

Ako kernel **nije** postavio PXN na tu user stranicu, onda grana možda uspe — što bi bilo nesigurno.

Ako kernel zaboravi da ponovo omogući PAN nakon pristupa korisničkoj memoriji, otvara se prozor u kojem dalja kernel logika može slučajno da pročita/upiše proizvoljnu korisničku memoriju.

Ako je user pointer u execute-only strani (user stranica sa samo execute dozvolom, bez read/write), pod PAN spec bugu, `ldr W2, [X1]` možda **ne** bi izazvao fault čak i sa PAN omogućenim, omogućavajući bypass exploit, u zavisnosti od implementacije.

</details>

<details>
<summary>Primer</summary>
Kernel ranjivost pokušava da uzme user-provided function pointer i pozove ga u kernel kontekstu (tj. `call user_buffer`). Pod PAN/PXN, ta operacija je zabranjena ili prouzrokuje fault.
</details>

---

### 11. **Top Byte Ignore (TBI) / Pointer Tagging**
**Introduced in ARMv8.5 / newer (or optional extension)**
TBI znači da se top byte (najviše-signifikantni bajt) 64-bitnog pointera ignoriše pri address translation. Ovo omogućava OS-u ili hardveru da ugradi **tag bits** u top byte pointera bez uticaja na stvarnu adresu.

- TBI znači **Top Byte Ignore** (ponekad nazivan *Address Tagging*). To je hardverska funkcija (dostupna u mnogim ARMv8+ implementacijama) koja **ignoriše top 8 bitova** (bitovi 63:56) 64-bitnog pointera pri izvođenju **address translation / load/store / instruction fetch**.
- U praksi, CPU tretira pointer `0xTTxxxx_xxxx_xxxx` (gde je `TT` = top byte) kao `0x00xxxx_xxxx_xxxx` za potrebe address translation, ignorišući (maskirajući) top byte. Top byte može biti korišćen od strane softvera za skladištenje **metadata / tag bits**.
- Ovo daje softveru “besplatan” in-band prostor da ugradi bajt taga u svaki pointer bez menjanja koje memorijsko mesto taj pointer referencira.
- Arhitektura obezbeđuje da load-ovi, store-ovi i instruction fetch tretiraju pointer sa maskiranim top bytom (tj. tag uklonjen) pre nego što izvrše stvarni pristup memoriji.

Dakle, TBI razdvaja **logički pointer** (pointer + tag) od **fizičke adrese** koja se koristi za memorijske operacije.

#### Zašto TBI: slučajevi upotrebe i motivacija

- **Pointer tagging / metadata**: Možete čuvati dodatne metapodatke (npr. tip objekta, verziju, granice, integrity tagove) u tom top bytu. Kada kasnije koristite pointer, tag se na hardverskom nivou ignoriše, pa ga ne morate ručno skidati za memorijski pristup.
- **Memory tagging / MTE (Memory Tagging Extension)**: TBI je osnovni hardverski mehanizam na kojem MTE gradi. U ARMv8.5, **Memory Tagging Extension** koristi bitove 59:56 pointera kao **logički tag** i proverava ga u odnosu na **allocation tag** koji je sačuvan u memoriji.
- **Poboljšana sigurnost i integritet**: Kombinacijom TBI i pointer authentication (PAC) ili runtime provera, možete zahtevati ne samo ispravnu vrednost pointera nego i ispravan tag. Napadač koji overwrituje pointer bez ispravnog taga će proizvesti neusaglašen tag.
- **Kompatibilnost**: Pošto je TBI opcion, a tag bitovi su od strane hardvera ignorisani, postojeći neotagovani kod nastavlja da radi normalno. Tag bitovi efektivno postaju “nebitni” za legacy kod.

#### Primer
<details>
<summary>Primer</summary>
Function pointer je sadržao tag u svom top bytu (recimo `0xAA`). Exploit prepisuje niže bitove pointera ali zanemaruje tag, pa kada kernel verifikuje ili sanitizuje, pointer ne prođe proveru ili bude odbijen.
</details>

---

### 12. **Page Protection Layer (PPL)**
**Introduced in late iOS / modern hardware (iOS ~17 / Apple silicon / high-end models)** (neki izveštaji pokazuju PPL otprilike na macOS / Apple silicon, ali Apple uvodi slične zaštite i na iOS)

- PPL je dizajniran kao **intra-kernel protection boundary**: čak i ako je kernel (EL1) kompromitovan i ima read/write mogućnosti, **ne bi trebalo da može slobodno da menja** određene **osetljive stranice** (posebno page tables, code-signing metadata, kernel code pages, entitlements, trust caches, itd.).
- Efektivno stvara **“kernel unutar kernela”** — manji trusted komponent (PPL) sa **povišenim privilegijama** koji jedino može da menja zaštićene stranice. Ostali kernel kod mora da pozove PPL rutine da bi izvršio promene.
- Ovo smanjuje attack surface za kernel exploite: čak i sa potpunim arbitrary R/W/execute u kernel modu, exploit kod mora dodatno da uđe u PPL domen (ili zaobiđe PPL) da bi modifikovao kritične strukture.
- Na novijem Apple silicon-u (A15+ / M2+), Apple prelazi na **SPTM (Secure Page Table Monitor)**, koji u mnogim slučajevima zamenjuje PPL za zaštitu page-table-a na tim platformama.

Evo kako se veruje da PPL funkcioniše, na osnovu javnih analiza:

#### Upotreba APRR / permission routing (APRR = Access Permission ReRouting)

- Apple hardware koristi mehanizam nazvan **APRR (Access Permission ReRouting)**, koji dozvoljava page table entry-ima (PTEs) da sadrže male indekse, umesto punih permission bitova. Ti indeksi se mapiraju preko APRR registara na stvarne dozvole. Ovo omogućava dinamičko remapiranje dozvola po domenu.
- PPL koristi APRR da bi segregirao privilegije unutar kernel konteksta: samo PPL domen ima dozvolu da ažurira mapiranje između indeksa i efektivnih dozvola. To znači da, kada non-PPL kernel kod upiše PTE ili pokuša da promeni permission bitove, APRR logika to onemogućava (ili primenjuje read-only mapiranje).
- PPL kod sam radi u ograničenom regionu (npr. `__PPLTEXT`) koji je obično neizvršiv ili neupisiv dok entry gate-ovi privremeno ne dozvole pristup. Kernel poziva PPL entry point-e (“PPL routines”) da bi izvršio osetljive operacije.

#### Gate / Entry & Exit

- Kada kernel treba da modifikuje zaštićenu stranicu (npr. promeni dozvole kernel code stranice, ili modifikuje page tables), poziva se u **PPL wrapper** rutinu, koja radi validaciju i zatim prelazi u PPL domen. Izvan tog domena, zaštićene stranice su efektivno read-only ili nemodifikovane od strane glavnog kernela.
- Tokom PPL entry, APRR mapiranja se prilagođavaju tako da memorijske stranice u PPL regionu budu postavljene kao **executable & writable** unutar PPL. Po izlazu, vraćaju se na read-only / non-writable. Ovo osigurava da samo dobro pregledane PPL rutine mogu pisati u zaštićene stranice.
- Izvan PPL, pokušaji kernel koda da upiše u te zaštićene stranice će dovesti do fault-a (permission denied) jer APRR mapiranje za taj kod domen ne dozvoljava pisanje.

#### Kategorije zaštićenih stranica

Stranice koje PPL tipično štiti uključuju:

- Strukture page table-a (translation table entries, mapping metadata)
- Kernel code stranice, posebno one koje sadrže kritičnu logiku
- Code-sign metadata (trust caches, signature blobs)
- Entitlement tabele, tabele za enforcement potpisivanja
- Druge visokovredne kernel strukture gde patchovanje omogućava zaobilaženje provera potpisa ili manipulaciju credential-ima

Ideja je da čak i ako je kernel memorija potpuno kontrolisana, napadač ne može jednostavno da patch-uje ili prepiše ove stranice, osim ako takođe ne kompromituje PPL rutine ili ne zaobiđe PPL.


#### Poznati bypass-i i ranjivosti

1. **Project Zero’s PPL bypass (stale TLB trick)**

- Javna analiza od Project Zero opisuje bypass koji uključuje **stale TLB entries**.
- Ideja:

1. Alocirajte dve fizičke stranice A i B, označite ih kao PPL stranice (tako da budu zaštićene).
2. Mapirajte dve virtuelne adrese P i Q čije L3 translation table stranice dolaze iz A i B.
3. Pokrenite thread koji kontinuirano pristupa Q, održavajući njegov TLB entry živim.
4. Pozovite `pmap_remove_options()` da uklonite mapiranja počevši od P; zbog buga, kod greškom uklanja TTEs za oba P i Q, ali samo invalidira TLB entry za P, ostavljajući Q-ev stale entry živim.
5. Ponovo iskoristite B (stranicu Q-ove tabele) da mapirate proizvoljnu memoriju (npr. PPL-zaštićene stranice). Pošto stale TLB entry i dalje mapira Q-ovu staru mapu, to mapiranje ostaje validno u tom kontekstu.
6. Kroz ovo, napadač može postaviti writable mapu PPL-zaštićenih stranica bez prolaska kroz PPL interfejs.

- Ovaj exploit je zahtevao fino upravljanje fizičkim mapiranjem i ponašanjem TLB-a. Pokazuje da bezbednosna granica zasnovana na TLB / tačnosti mapiranja mora biti izuzetno pažljiva u vezi TLB invalidacija i konzistentnosti mapiranja.

- Project Zero je primetio da su bypass-i ovakve vrste suptilni i retki, ali mogući u kompleksnim sistemima. Ipak, oni smatraju PPL solidnom mitigacijom.

2. **Ostale potencijalne opasnosti i ograničenja**

- Ako kernel exploit može direktno da uđe u PPL rutine (pozivajući PPL wrapper-e), može zaobići restrikcije. Zbog toga je validacija argumenata kritična.
- Bugovi u samom PPL kodu (npr. arithmetic overflow, provere granica) mogu omogućiti out-of-bounds modifikacije unutar PPL. Project Zero je uočio da je takav bug u `pmap_remove_options_internal()` iskorišćen u njihovom bypass-u.
- PPL granica je neraskidivo vezana za hardware enforcement (APRR, memory controller), tako da je snažna koliko i implementacija hardvera.



#### Primer
<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.

Example 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:

  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).
  1. 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.
  1. 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.
  1. 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.
  1. 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.
  1. 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.
Example ``` 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>

#### Ograničenja i izazovi

- **Intrablock overflows**: Ako overflow ostane unutar iste alokacije (ne pređe granicu) i tag ostane isti, tag mismatch ga ne otkriva.
- **Tag width limitation**: Dostupno je samo nekoliko bitova (npr. 4 bita, ili mali domen) za tag — ograničen namespace.
- **Side-channel leaks**: Ako se tag bitovi mogu leak-ovati (putem cache / speculative execution), napadač može saznati važeće tagove i zaobići zaštitu. Apple-ova primena tag confidentiality enforcement pokušava da to ublaži.
- **Performance overhead**: Provere tagova pri svakom load/store dodaju trošak; Apple mora optimizovati hardver da bi smanjio overhead.
- **Compatibility & fallback**: Na starijem hardveru ili delovima koji ne podržavaju EMTE mora postojati fallback. Apple tvrdi da je MIE omogućen samo na uređajima sa podrškom.
- **Complex allocator logic**: Alokator mora da upravlja tagovima, retagovanjem, poravnavanjem granica i da izbegne sudare tagova. Bagovi u logici alokatora mogu uvesti ranjivosti.
- **Mixed memory / hybrid areas**: Neki delovi memorije mogu ostati untagged (legacy), što otežava interoperabilnost.
- **Speculative / transient attacks**: Kao i kod mnogih mikroarhitektonskih zaštita, speculative execution ili micro-op fuzije mogu privremeno zaobići provere ili leak-ovati tag bitove.
- **Limited to supported regions**: Apple može primeniti EMTE selektivno, u visokorizičnim oblastima (kernel, security-critical subsistemi), a ne univerzalno.



---

## Ključna unapređenja / razlike u odnosu na standardni MTE

Evo poboljšanja i izmena na koje Apple naglašava:

| 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 zahteva da i pristupi iz tagged regiona ka non-tagged memory takođe validiraju poznavanje taga, što otežava zaobilaženje mešanim alokacijama. |
| **Tag confidentiality / secrecy** | Tags might be observable or leaked via side channels | Apple dodaje **Tag Confidentiality Enforcement**, koji pokušava da spreči leakage vrednosti tagova (putem speculative side-channels itd.). |
| **Allocator integration & retagging** | MTE leaves much of allocator logic to software | Apple-ovi secure typed allocators (kalloc_type, xzone malloc, etc.) integrišu se sa EMTE: kada se memory alocira ili oslobodi, tagovi se upravljaju na finom granularitetu. |
| **Always-on by default** | In many platforms, MTE is optional or off by default | Apple omogućava EMTE / MIE po defaultu na podržanom hardveru (npr. iPhone 17 / A19) za kernel i mnoge user processes. |

Pošto Apple kontroliše i hardver i softverski stack, može strogo da primeni EMTE, izbegne performansne zamke i zatvori side-channel rupe.

---

## Kako EMTE radi u praksi (Apple / MIE)

Evo opisa visokog nivoa kako EMTE funkcioniše u Apple-ovom MIE okruženju:

1. **Tag assignment**
- Kada se memorija alocira (npr. u kernelu ili user space preko secure allocators), toj memorijskoj jedinici se dodeli **secret tag**.
- Pokazivač koji se vraća korisniku ili kernelu sadrži taj tag u visokim bitovima (koristeći TBI / top byte ignore mehanizme).

2. **Tag checking on access**
- Kad se izvrši load ili store koristeći pokazivač, hardver proverava da li tag pokazivača odgovara tagu memorijske jedinice (allocation tag). Ako se ne poklapa, odmah se javlja fault (pošto je synchronous).
- Pošto je synchronous, nema prozora za "odloženo otkrivanje".

3. **Retagging on free / reuse**
- Kada se memorija oslobodi, alokator menja tag bloka (tako da stari pokazivači sa starim tagom više ne odgovaraju).
- Use-after-free pokazivač će zato imati zastareli tag i prilikom pristupa će doći do mismatch-a.

4. **Neighbor-tag differentiation to catch overflows**
- Susednim alokacijama dodeljuju se različiti tagovi. Ako buffer overflow prelije u memoriju suseda, tag mismatch će izazvati fault.
- Ovo je posebno efikasno za detekciju malih overflow-ova koji prelaze granicu.

5. **Tag confidentiality enforcement**
- Apple mora sprečiti da se vrednosti tagova leak-uju (jer ako napadač sazna tag, može konstruisati pokazivače sa ispravnim tagom).
- Uključene su zaštite (mikroarhitektonske / speculative kontrole) da bi se izbeglo leakage tag bitova.

6. **Kernel and user-space integration**
- Apple koristi EMTE ne samo u user-space već i u kernelu / OS-critical komponentama (da zaštiti kernel od korupcije memorije).
- Hardver/OS osiguravaju da pravila tagova važe čak i kada kernel izvršava radnje u ime user space-a.

Pošto je EMTE ugrađen u MIE, Apple koristi EMTE u synchronous modu preko ključnih površina napada, ne kao opcioni ili debug režim.



---

## Exception handling in XNU

Kada se dogodi **exception** (npr. `EXC_BAD_ACCESS`, `EXC_BAD_INSTRUCTION`, `EXC_CRASH`, `EXC_ARM_PAC`, itd.), **Mach layer** XNU kernela presreće taj događaj pre nego što se konvertuje u UNIX-style **signal** (kao `SIGSEGV`, `SIGBUS`, `SIGILL`, ...).

Ovaj proces uključuje više slojeva propagacije i obrade exception-a pre nego što stigne do user space-a ili bude pretvoren u BSD signal.


### Exception Flow (High-Level)

1.  **CPU triggers a synchronous exception** (npr. dereferenciranje nevažećeg pokazivača, PAC failure, ilegalna instrukcija, itd.).

2.  **Low-level trap handler** se izvršava (`trap.c`, `exception.c` u XNU source).

3.  Trap handler poziva **`exception_triage()`**, jezgro Mach exception handling-a.

4.  `exception_triage()` odlučuje kako da usmeri exception:

-   Prvo na **thread's exception port**.

-   Zatim na **task's exception port**.

-   Zatim na **host's exception port** (često `launchd` ili `ReportCrash`).

Ako nijedan od ovih portova ne obradi exception, kernel može:

-   **Konvertovati ga u BSD signal** (za user-space procese).

-   **Panic** (za exception-e u kernel prostoru).


### Core Function: `exception_triage()`

Funkcija `exception_triage()` rutira Mach exception-e kroz lanac mogućih handler-a dok je neko ne obradi ili dok ne postane fatalan. Definisana je u `osfmk/kern/exception.c`.
```c
void exception_triage(exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t codeCnt);

Tipičan tok poziva:

exception_triage() └── exception_deliver() ├── exception_deliver_thread() ├── exception_deliver_task() └── exception_deliver_host()

Ako svi zakažu → obrađuje se pomoću bsd_exception() → prevodi se u signal kao što je SIGSEGV.

Portovi izuzetaka

Svaki Mach objekat (thread, task, host) može registrovati portove izuzetaka, na koje se šalju poruke o izuzecima.

Definisani su API-jem:

task_set_exception_ports()
thread_set_exception_ports()
host_set_exception_ports()

Each exception port has:

  • A mask (koje izuzetke želi da prima)
  • A port name (Mach port to receive messages)
  • A behavior (kako kernel šalje poruku)
  • A flavor (koje thread state da uključi)

Debuggers and Exception Handling

A debugger (e.g., LLDB) sets an exception port on the target task or thread, usually using task_set_exception_ports().

When an exception occurs:

  • The Mach message is sent to the debugger process.
  • The debugger can decide to handle (resume, modify registers, skip instruction) or not handle the exception.
  • If the debugger doesn’t handle it, the exception propagates to the next level (task → host).

Flow of EXC_BAD_ACCESS

  1. Thread dereferences invalid pointer → CPU raises Data Abort.

  2. Kernel trap handler calls exception_triage(EXC_BAD_ACCESS, ...).

  3. Message sent to:

  • Thread port → (debugger can intercept breakpoint).

  • If debugger ignores → Task port → (process-level handler).

  • If ignored → Host port (usually ReportCrash).

  1. If no one handles → bsd_exception() translates to SIGSEGV.

PAC Exceptions

When Pointer Authentication (PAC) fails (signature mismatch), a special Mach exception is raised:

  • EXC_ARM_PAC (type)
  • Codes may include details (e.g., key type, pointer type).

If the binary has the flag TFRO_PAC_EXC_FATAL, the kernel treats PAC failures as fatal, bypassing debugger interception. This is to prevent attackers from using debuggers to bypass PAC checks and it’s enabled for platform binaries.

Software Breakpoints

A software breakpoint (int3 on x86, brk on ARM64) is implemented by causing a deliberate fault.
The debugger catches this via the exception port:

  • Modifies instruction pointer or memory.
  • Restores original instruction.
  • Resumes execution.

This same mechanism is what allows you to “catch” a PAC exception — unless TFRO_PAC_EXC_FATAL is set, in which case it never reaches the debugger.

Conversion to BSD Signals

If no handler accepts the exception:

  • Kernel calls task_exception_notify() → bsd_exception().

  • This maps Mach exceptions to signals:

Mach ExceptionSignal
EXC_BAD_ACCESSSIGSEGV or SIGBUS
EXC_BAD_INSTRUCTIONSIGILL
EXC_ARITHMETICSIGFPE
EXC_SOFTWARESIGTRAP
EXC_BREAKPOINTSIGTRAP
EXC_CRASHSIGKILL
EXC_ARM_PACSIGILL (on non-fatal)

### Key Files in XNU Source

  • osfmk/kern/exception.c → Core of exception_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)

The kernel used a zone allocator (kalloc) divided into fixed-size “zones.” Each zone only stores allocations of a single size class.

From the screenshot:

Zone NameElement SizeExample Use
default.kalloc.1616 bytesVeoma male kernel strukture, pokazivači.
default.kalloc.3232 bytesMale strukture, zaglavlja objekata.
default.kalloc.6464 bytesIPC poruke, sitni kernel baferi.
default.kalloc.128128 bytesSrednji objekti kao delovi OSObject.
default.kalloc.12801280 bytesVelike strukture, IOSurface/graphics metadata.

How it worked:

  • Each allocation request gets rounded up to the nearest zone size. (E.g., a 50-byte request lands in the kalloc.64 zone).
  • Memory in each zone was kept in a free list — chunks freed by the kernel went back into that zone.
  • If you overflowed a 64-byte buffer, you’d overwrite the next object in the same zone.

This is why heap spraying / feng shui was so effective: you could predict object neighbors by spraying allocations of the same size class.

The freelist

Inside each kalloc zone, freed objects weren’t returned directly to the system — they went into a freelist, a linked list of available chunks.

  • When a chunk was freed, the kernel wrote a pointer at the start of that chunk → the address of the next free chunk in the same zone.

  • The zone kept a HEAD pointer to the first free chunk.

  • Allocation always used the current HEAD:

  1. Pop HEAD (return that memory to the caller).

  2. Update HEAD = HEAD->next (stored in the freed chunk’s header).

  • Freeing pushed chunks back:

  • freed_chunk->next = HEAD

  • HEAD = freed_chunk

So the freelist was just a linked list built inside the freed memory itself.

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)

Eksploatacija freelist-a

Pošto prvih 8 bajtova jednog free chunk-a predstavlja freelist pointer, napadač može da ga pokvari:

  1. Heap overflow u susedni freed chunk → prepiše njegov “next” pointer.

  2. Use-after-free upis u freed object → prepiše njegov “next” pointer.

Zatim, pri sledećoj alokaciji te veličine:

  • Allocator izvlači korumpirani chunk.

  • Sledi napadačem-dostavljen “next” pointer.

  • Vraća pointer na proizvoljnu memoriju, omogućavajući fake object primitives ili targeted overwrite.

Vizuelni primer 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:

  1. 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.
  1. 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.
  1. 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).
  1. 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.
  1. 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.
  1. 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:
  1. Try per-CPU cache.
  2. If empty, pull from the global freelist.
  3. 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:

  1. Type lookupOSData maps to kalloc_type_osdata zone (size 64 bytes).
  2. 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).
  1. 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

FeatureOld Heap (Pre-iOS 15)Modern Heap (iOS 15+ / A12+)
Allocation granularityFixed size buckets (kalloc.16, kalloc.32, etc.)Size + type-based buckets (kalloc_type)
Placement predictabilityHigh (same-size objects side by side)Low (same-type grouping + randomness)
Freelist managementRaw pointers in freed chunks (easy to corrupt)Encoded pointers (safe-linking style)
Adjacent object controlEasy via sprays/frees (feng shui predictable)Hard — typed zones separate attacker objects
Kernel data/code protectionsFew hardware protectionsPPL / SPTM protect page tables & code pages, and PAC protects pointers
Allocation reuse validationNone (freelist pointers raw)zone_require / zone enforcement
Exploit reliabilityHigh with heap spraysMuch lower, requires logic bugs or info leaks
Large allocations handlingAll small allocations managed equallyLarge 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:

  1. malloc / calloc / realloc / typed alloc is invoked with a size and type ID.
  2. The allocator uses the type ID to pick the correct segment group / zone.
  3. 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.
  1. The metadata slab is updated (free bit cleared, bookkeeping).
  2. If memory tagging (EMTE) is in play, the returned block gets a tag assigned, and metadata is updated to reflect its “live” state.
  3. 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:

FeaturePurposeNotes
Metadata decouplingPrevent overflow from corrupting metadataMetadata lives in separate VM region (metadata slab)
Guard pages / unmapped slicesCatch out-of-bounds writesHelps detect buffer overflows rather than silently corrupting adjacent blocks
Type-based segregationPrevent cross-type reuse & type confusionEven same-size allocations from different types go to different zones
Memory Tagging (EMTE / MIE)Detect invalid access, stale references, OOB, UAFxzone works in concert with hardware EMTE in synchronous mode (“Memory Integrity Enforcement”)
Delayed reuse / poisoning / zapReduce chance of use-after-free exploitationFreed blocks may be poisoned, zeroed, or quarantined before reuse
Chunk reclamation / dynamic unmappingReduce memory waste and fragmentationEntire chunks may be unmapped when unused
Randomization / placement variationPrevent deterministic adjacencyBlocks in a chunk and chunk selection may have randomized aspects
Segregation of “data-only” allocationsSeparate allocations that don’t store pointersReduces 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

ios Physical UAF - 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

  1. Go to the page https://ipsw.me/ and download the iOS versions you want to diff. These will be .ipsw files.
  2. Decompress until you get the bin format of the kernelcache of both .ipsw files. You have information on how to do this on:

macOS Kernel Extensions & Kernelcache

  1. Open Ghidra with ghidraRun, create a new project and load the kernelcaches.
  2. Open each kernelcache so they are automatically analyzed by Ghidra.
  3. Then, on the project Window of Ghidra, right click each kernelcache, select Export, select format Binary BinExport (v2) for BinDiff and export them.
  4. 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 moduli

  • Watcher anti-analysis: Posvećeni watcher binarni fajl neprekidno profilira uređaj i prekida kill-chain kada se otkrije istraživačko okruženje. Pregledava security.mac.amfi.developer_mode_status, prisustvo diagnosticd konzole, locale US ili IL, tragove jailbreak-a kao što su Cydia, procese kao što su bash, tcpdump, frida, sshd ili checkrain, mobilne AV aplikacije (McAfee, AvastMobileSecurity, NortonMobileSecurity), prilagođena HTTP proxy podešavanja i prilagođene root CA-e. Neuspeh bilo koje provere blokira dalju isporuku payload-a.
  • Helper surveillance hooks: Helper komponenta komunicira sa drugim fazama preko /tmp/helper.sock, zatim učitava skupove hook-ova nazvane DMHooker i UMHooker. Ovi hook-ovi presreću VOIP audio puteve (snimci se čuvaju pod /private/var/tmp/l/voip_%lu_%u_PART.m4a), implementiraju sistemski keylogger, prave fotografije bez UI, i hook-uju SpringBoard da suzbiju notifikacije koje bi te radnje inače izazvale. Dakle, helper deluje kao prikriveni sloj za validaciju i lagano nadgledanje pre nego što se ubace teži implantati kao što je 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

Reference

Tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks