iOS Exploiting
Tip
Leer en oefen AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
iOS Exploit Mitigations
1. Code Signing / Runtime Signature Verification
Ingevoer vroeg (iPhone OS → iOS) Dit is een van die fundamentele beskermings: alle uitvoerbare kode (apps, dynamic libraries, JIT-ed code, extensions, frameworks, caches) moet kriptografies geteken wees deur ’n sertifikaatketting wat in Apple se trustwortel gewortel is. Tydens runtime, voordat ’n binêr in geheue gelaai word (of voor spronge oor sekere grense), kontroleer die stelsel die handtekening. As die kode gemodifiseer is (bit-flipped, gepatch) of ongeteken, misluk die laai.
- Voorkom: die “classic payload drop + execute” fase in exploit-kettings; arbitrary code injection; die wysiging van ’n bestaande binêr om kwaadwillige logika in te voeg.
- Meganisme detail:
- Die Mach-O loader (en dynamic linker) kontroleer code pages, segments, entitlements, team IDs, en dat die handtekening die lêer se inhoud dek.
- Vir geheuegebiede soos JIT caches of dinamies gegenereerde kode, dwing Apple dat bladsye geteken of geverifieer moet wees via spesiale APIs (bv.
mprotectmet code-sign kontroles). - Die handtekening sluit entitlements en identiteite in; die OS dwing af dat sekere APIs of geprivilegieerde vermogens spesifieke entitlements vereis wat nie vervals kan word nie.
Voorbeeld
Stel ’n exploit verkry code execution in ’n proses en probeer shellcode na ’n heap skryf en daarna daarheen spring. Op iOS moet daardie bladsy as executable gemerk wees **en** voldoen aan code-signature-beperkings. Aangesien die shellcode nie deur Apple se sertifikaat onderteken is nie, misluk die sprong of weier die stelsel om daardie geheuegebied executable te maak.2. CoreTrust
Ingevoer rondom iOS 14+ era (of geleidelik op nuwer toestelle / later iOS) CoreTrust is die subsisteem wat runtime signature validation van binaries uitvoer (insluitend stelsel- en gebruikersbinaries) teen Apple’s root certificate eerder as om op gecachte userland trust stores staat te maak.
- Voorkom: post-install tampering van binaries, jailbreaking-tegnieke wat probeer om stelselbiblioteke of gebruikersapps te verwissel of te patch; om die stelsel te mislei deur vertroude binaries met kwaadwillige eweknieë te vervang.
- Meganisme detail:
- In plaas daarvan om ’n plaaslike trust-databasis of sertifikaat-cache te vertrou, haal CoreTrust of verwys na Apple se root direk of verifieer intermediate certificates in ’n veilige ketting.
- Dit verseker dat wysigings (bv. in die filesystem) aan bestaande binaries opgespoor en verwerp word.
- Dit bind entitlements, team IDs, code signing flags, en ander metadata aan die binêr by laai-tyd.
Voorbeeld
’n Jailbreak mag probeer om `SpringBoard` of `libsystem` te vervang met ’n gepatche weergawe om persistentie te kry. Maar wanneer die OS se loader of CoreTrust kontroleer, sien dit die handtekening-ontrerigheid (of gemodifiseerde entitlements) en weier om dit uit te voer.3. Data Execution Prevention (DEP / NX / W^X)
Ingevoer in baie OS’e vroeër; iOS het NX-bit / w^x al lank DEP dwing af dat bladsye wat as writable gemerk is (vir data) nie-executable is, en dat bladsye wat executable is nie-writable is. Jy kan nie bloot shellcode in ’n heap of stack skryf en dit uitvoer nie.
- Voorkom: direkte shellcode-uitvoering; klassieke buffer-overflow → sprong na ingevoegde shellcode.
- Meganisme detail:
- Die MMU / memory protection flags (via page tables) handhaaf die skeiding.
- Enige poging om ’n writable bladsy executable te maak, aktiveer ’n stelselkontrole (en is of verbode of vereis code-sign goedkeuring).
- In baie gevalle vereis dit om bladsye executable te maak dat OS APIs gebruik word wat addisionele beperkings of kontroles afdwing.
Voorbeeld
’n Overflow skryf shellcode op die heap. Die aanvaller probeer `mprotect(heap_addr, size, PROT_EXEC)` om dit executable te maak. Maar die stelsel weier of valideer dat die nuwe bladsy code-sign beperkings moet slaag (wat die shellcode nie kan).4. Address Space Layout Randomization (ASLR)
Ingevoer in iOS ~4–5 era (ongeveer iOS 4–5 tydperk) ASLR randomiseer die basisadresse van sleutel geheuegebiede: libraries, heap, stack, ens., by elke proses-opstart. Gadgets se adresse beweeg tussen draaie.
- Voorkom: hardcoding van gadget-adresse vir ROP/JOP; statiese exploit-kettings; blind spronge na bekende offsets.
- Meganisme detail:
- Elke gelaaide library / dynamic module word by ’n random offset herbasis.
- Stack en heap basispunte word gerandomiseer (binne sekere entropy-grense).
- Soms word ander streke (bv. mmap-alloceerings) ook gerandomiseer.
- Gecombineer met information-leak mitigations, dwing dit die aanvaller om eers ’n adres of pointer te leak om basisadresse tydens runtime te ontdek.
Voorbeeld
’n ROP-ketting verwag gadget by `0x….lib + offset`. Maar omdat `lib` by elke run verskillend herlokaliseer word, misluk die hardgekodeerde ketting. ’n Exploit moet eers die basisadres van die module leak voordat dit gadget-adresse bereken.5. Kernel Address Space Layout Randomization (KASLR)
Ingevoer in iOS ~ (iOS 5 / iOS 6 tydperk) Analoog aan user ASLR, KASLR randomiseer die basis van die kernel text en ander kernel-strukture by opstart.
- Voorkom: kernel-vlak exploits wat afhanklik is van ’n vaste ligging van kernel-kode of -data; statiese kernel-exploits.
- Meganisme detail:
- By elke opstart word die kernel se basisadres gerandomiseer (binne ’n reeks).
- Kernel-data strukture (soos
task_structs,vm_map, ens.) kan ook herlokaliseer of geoffset wees. - Aanvallers moet eers kernel-pointers lek of ’n information disclosure kwetsbaarheid gebruik om offsets te bereken voordat hulle kernel-strukture of kode kaap.
Voorbeeld
’n Lokale kwetsbaarheid mik om ’n kernel-funksie-pointer (bv. in ’n `vtable`) by `KERN_BASE + offset` te korrupteer. Maar aangesien `KERN_BASE` onbekend is, moet die aanvaller dit eers leak (bv. via ’n read primitive) voordat hy die korrekte adres vir korrupsie kan bereken.6. Kernel Patch Protection (KPP / AMCC)
Ingevoer in nuwer iOS / A-series hardware (post ongeveer iOS 15–16 era of nuwer chips) KPP (aka AMCC) monitor kontinu die integriteit van kernel text pages (via hash of checksum). As dit tampering (patches, inline hooks, kodewysigings) buite toegelate vensters opspoor, tree dit op met ’n kernel panic of herbegin.
- Voorkom: persistent kernel patching (die wysiging van kernel-instruksies), inline hooks, statiese funksie-overskrywings.
- Meganisme detail:
- ’n Hardware- of firmware-module monitor die kernel text area.
- Dit herhash periodiek of op aanvraag die bladsye en vergelyk teen verwagte waardes.
- As mismatch optree buite betroubare update-vensters, panikeer dit die toestel (om persistent kwaadwilligheid te voorkom).
- Aanvallers moet of die detectievensters ontwrig of legitimiteits-patch-paaie gebruik.
Voorbeeld
’n Exploit probeer die proloog van ’n kernel-funksie (bv. `memcmp`) patch om oproepe af te vang. Maar KPP merk dat die kodebladsy se hash nie meer by die verwagte waarde pas nie en aktiveer ’n kernel panic, wat die toestel laat crash voordat die patch kan stabiliseer.7. Kernel Text Read‐Only Region (KTRR)
Ingevoer in moderne SoCs (post ~A12 / nuwer hardware) KTRR is ’n hardware-afgedwonge meganisme: sodra die kernel text vroeg tydens boot vergrendel word, word dit read-only vanaf EL1 (die kernel), wat verdere skryf na code pages voorkom.
- Voorkom: enige wysigings aan kernel-kode ná boot (bv. patching, in-place code injection) op EL1 privilege-vlak.
- Meganisme detail:
- Tydens boot (in die secure/bootloader fase) merk die memory controller (of ’n veilige hardware-eenheid) die fisiese bladsye wat kernel text bevat as read-only.
- Selfs as ’n exploit volle kernel-privileges verkry, kan dit nie daardie bladsye skryf om instruksies te patch nie.
- Om dit te wysig, moet die aanvaller eers die boot-ketting kompromitteer, of KTRR self subverteer.
Voorbeeld
’n Privilege-escalation exploit spring in EL1 en probeer ’n trampoline in ’n kernel-funksie skryf (bv. in die `syscall` handler). Maar omdat die bladsye deur KTRR read-only gemerk is, misluk die skryf (of veroorsaak dit ’n fout), sodat die patch nie toegepas word nie.8. Pointer Authentication Codes (PAC)
Ingevoer met ARMv8.3 (hardware), Apple begin met A12 / iOS ~12+
- PAC is ’n hardware-funksie geïntroduseer in ARMv8.3-A om die tampering van pointer-waardes (return addresses, function pointers, sekere data pointers) op te spoor deur ’n klein kriptografiese handtekening (’n “MAC”) in ongebruikte hoër bits van die pointer in te sluit.
- Die handtekening (“PAC”) word bereken oor die pointer-waarde plus ’n modifier (’n kontekswaarde, bv. stack pointer of ander onderskeidende data). Sodoende kry dieselfde pointer-waarde in verskillende kontekste ’n ander PAC.
- By gebruikstyd, voordat die pointer gederefereer of daarheen gesprong word, kontroleer ’n authenticate instruksie die PAC. As dit geldig is, word die PAC verwyder en die suiwer pointer verkry; as dit ongeldig is, word die pointer “poisoned” (of ’n fout opgegooi).
- Die sleutels wat gebruik word vir die generering/validasie van PACs woon in geprivilegieerde registers (EL1, kernel) en is nie direk leesbaar vanuit user mode nie.
- Omdat nie alle 64 bits van ’n pointer in baie stelsels gebruik word nie (bv. 48-bit adresruimte), is die boonste bits “spaar” en kan die PAC sonder die verandering van die effektiewe adres huisves.
Architectural Basis & Key Types
-
ARMv8.3 bring vyf 128-bit sleutels in (elk geïmplementeer via twee 64-bit stelselregisters) vir pointer authentication.
-
APIAKey — vir instruction pointers (domein “I”, sleutel A)
-
APIBKey — tweede instruction pointer sleutel (domein “I”, sleutel B)
-
APDAKey — vir data pointers (domein “D”, sleutel A)
-
APDBKey — vir data pointers (domein “D”, sleutel B)
-
APGAKey — “generic” sleutel, vir signing van nie-pointer data of ander generiese gebruike
-
Hierdie sleutels is gestoor in geprivilegieerde stelselregisters (toeganklik slegs by EL1/EL2 ens.), nie toeganklik vanaf user mode nie.
-
Die PAC word bereken via ’n kriptografiese funksie (ARM stel QARMA as die algoritme voor) gebruikmakend van:
- Die pointer-waarde (kanoniese deel)
- ’n modifier (’n kontekswaarde, soos ’n salt)
- Die geheime sleutel
- Sommige interne tweak-logika As die resulterende PAC met wat in die boonste bits van die pointer gestoor is ooreenstem, slaag authenticatie.
Instruction Families
Die naamkonvensie is: PAC / AUT / XPAC, dan domeinletters.
PACxxinstruksies sign ’n pointer en voeg ’n PAC inAUTxxinstruksies authenticate + strip (valideer en verwyder die PAC)XPACxxinstruksies strip sonder validasie
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 |
Daar is gespesialiseerde / alias-vorme:
PACIASPis kort virPACIA X30, SP(sign the link register using SP as modifier)AUTIASPisAUTIA X30, SP(authenticate link register with SP)- Gekombineerde vorms soos
RETAA,RETAB(authenticate-and-return) ofBLRAA(authenticate & branch) bestaan in ARM-uitbreidings / compiler-ondersteuning. - Ook zero-modifier variante:
PACIZA/PACIZBwaar die modifier implisiet nul is, ens.
Modifiers
Die hoofdoel van die modifier is om die PAC te bind aan ’n spesifieke konteks sodat dieselfde adres in verskillende kontekste verskillende PACs lewer. Dit voorkom eenvoudige hergebruik van pointers oor rame of objekte. Dit is soos om ’n salt by ’n hash te voeg.
Dus:
- Die modifier is ’n kontekswaarde (’n ander register) wat in die PAC-berekening gemeng word. Tipiese keuses: die stack pointer (
SP), ’n frame pointer, of ’n object ID. - Om SP as modifier te gebruik is algemeen vir return address signing: die PAC word aan die spesifieke stack frame gekoppel. As jy probeer om die LR in ’n ander frame te hergebruik, verander die modifier en misluk PAC-validasie.
- Dieselfde pointer-waarde wat onder verskillende modifiers geteken is, lewer verskillende PACs.
- Die modifier hoef nie geheim te wees nie, maar idealiter is dit nie deur die aanvaller beheerbaar nie.
- Vir instruksies wat pointers teken of verifieer waar geen sinvolle modifier bestaan nie, gebruik sommige vorms nul of ’n implisiete konstante.
Apple / iOS / XNU Customizations & Observations
- Apple se PAC-implemantasie sluit per-boot diversifiers in sodat sleutels of tweaks by elke opstart verander, wat hergebruik oor boots belemmer.
- Hulle sluit ook cross-domain mitigations in sodat PACs wat in user mode geteken is nie maklik in kernel mode hergebruik kan word nie.
- Op Apple M1 / Apple Silicon het reverse engineering getoon dat daar nege modifier tipes en Apple-spesifieke stelselregisters vir sleutelbeheer is.
- Apple gebruik PAC oor baie kernel-substelsels: return address signing, pointer integriteit in kernel-data, signed thread contexts, ens.
- Google Project Zero het getoon hoe onder ’n kragtige memory read/write primitive in die kernel, mens kernel PACs kon forgeer (vir A sleutels) op A12-era toestelle, maar Apple het baie van daardie paaie gepatch.
- In Apple se stelsel is sommige sleutels global oor die kernel, terwyl user prosesse moontlik per-proses sleutel-willekeurigheid kry.
PAC Bypasses
- Kernel-mode PAC: theoretical vs real bypasses
- Omdat kernel PAC-sleutels en logika strak beheer word (geprivilegieerde registers, diversifiers, domein isolasie), is dit baie moeilik om arbitrair gesigneerde kernel-pointers te forgeer.
- Azad se 2020 “iOS Kernel PAC, One Year Later” rapporteer dat in iOS 12-13 hy ’n paar gedeeltelike bypasses gevind het (signing gadgets, hergebruik van signed states, onbeveiligde indirekte takke) maar geen volledige generiese bypass nie. bazad.github.io
- Apple se “Dark Magic” aanpassings beperk die eksploiteerbare oppervlak verder (domeinwissel, per-sleutel inskakel-bits). i.blackhat.com
- Daar is ’n bekende kernel PAC bypass CVE-2023-32424 op Apple silicon (M1/M2) gerapporteer deur Zecao Cai et al. i.blackhat.com
- Maar hierdie bypasses berus dikwels op baie spesifieke gadgets of implementasiefoute; hulle is nie generiese bypasses nie.
Dus word kernel PAC as uiters robuust beskou, al is dit nie perfek nie.
- User-mode / runtime PAC bypass techniques
Hierdie is meer algemeen en benut onvolmaakthede in hoe PAC toegepas of gebruik word in dynamic linking / runtime frameworks. Hieronder is klas-agtige voorbeelde met verduidelikings.
2.1 Shared Cache / A key issues
-
Die dyld shared cache is ’n groot pre-linked blob van stelsel-frameworks en biblioteke. Omdat dit so wyd gedeel word, is funksie-pointers binne die shared cache “pre-signed” en word deur baie prosesse gebruik. Aanvallers mik na hierdie reeds-gesigneerde pointers as “PAC oracles”.
-
Sommige bypass-tegnieke probeer om A-key gesigneerde pointers wat in die shared cache voorkom te onttrek of te hergebruik en dit in gadgets te kombineer.
-
Die “No Clicks Required” praatjie beskryf hoe om ’n oracle oor die shared cache te bou om relatiewe adresse af te lei en dit te kombineer met signed pointers om PAC te omseil. saelo.github.io
-
Ook is imports van funksie-pointers uit shared libraries in userspace gevind om onvoldoende beskerm deur PAC te wees, wat ’n aanvaller toelaat om funksie-pointers te kry sonder om hul handtekening te verander. (Project Zero bug entry) bugs.chromium.org
2.2 dlsym(3) / dynamic symbol resolution
-
Een bekende bypass is om
dlsym()aan te roep om ’n reeds gesigneerde funksie-pointer te kry (gesigneer met A-key, diversifier nul) en dit dan te gebruik. Omdatdlsym’n wettig gesigneerde pointer teruggee, omseil dit die noodsaaklikheid om PAC te forgeer. -
Epsilon se blog verduidelik hoe sekere bypasses dit uitbuit: die aanroep
dlsym("someSym")lewer ’n gesigneerde pointer en kan vir indirekte oproepe gebruik word. blog.epsilon-sec.com -
Synacktiv se “iOS 18.4 — dlsym considered harmful” beskryf ’n fout: sommige symboles wat via
dlsymop iOS 18.4 opgelos word, lewer pointers wat verkeerdelik gesigneer is (of met buggy diversifiers), wat ’n onbedoelde PAC-bypass moontlik maak. Synacktiv -
Die logika in dyld vir dlsym sluit in: wanneer
result->isCode, teken hulle die teruggegewe pointer met__builtin_ptrauth_sign_unauthenticated(..., key_asia, 0), d.i. konteks nul. blog.epsilon-sec.com
Dus is dlsym ’n gereelde pad in user-mode PAC bypasses.
2.3 Other DYLD / runtime relocations
-
Die DYLD loader en dinamiese relocasie-logika is kompleks en ka soms tydelik bladsye as read/write mappen om relocations uit te voer, en dan terugskakel na read-only. Aanvallers benut hierdie vensters. Synacktiv se praatjie beskryf “Operation Triangulation”, ’n timing-gebaseerde PAC-bypass via dinamiese relocations. Synacktiv
-
DYLD bladsye is nou beskerm met SPRR / VM_FLAGS_TPRO (sekere beskermingsvlae vir dyld). Maar vroeër weergawes het swakker wagte gehad. Synacktiv
-
In WebKit exploit-kettings is die DYLD loader dikwels ’n teiken vir PAC-bypass. Die slides noem dat baie PAC-bypasses die DYLD loader geteiken het (via relocatie, interposer hooks). Synacktiv
2.4 NSPredicate / NSExpression / ObjC / SLOP
-
In userland exploit-kettings word Objective-C runtime-metodes soos
NSPredicate,NSExpressionofNSInvocationgebruik om beheer-oproepe te smuggle sonder duidelike pointer-forgering. -
Op ouer iOS (voor PAC) het ’n exploit gebruik gemaak van fake NSInvocation objekte om willekeurige selectors op beheerde geheue aan te roep. Met PAC is aanpassings nodig. Maar die tegniek SLOP (SeLector Oriented Programming) is ook onder PAC uitgebrei. Project Zero
-
Die oorspronklike SLOP-tegniek het die ketting van ObjC-oproepe toegelaat deur fake invocations te skep; die bypass berus daarop dat ISA of selector pointers soms nie volledig deur PAC beskerm word nie. Project Zero
-
In omgewings waar pointer authentication gedeeltelik toegepas word, mag metodes / selectors / target pointers nie altyd PAC-beskerming hê nie, wat ruimte vir bypass gee.
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>
A buffer overflow overwrites a return address on the stack. The attacker writes the target gadget address but cannot compute the correct PAC. When the function returns, the CPU’s `AUTIA` instruction faults because the PAC mismatch. The chain fails.
Project Zero’s analysis on A12 (iPhone XS) showed how Apple’s PAC is used and methods of forging PACs if an attacker has a memory read/write primitive.
</details>
### 9. **Branch Target Identification (BTI)**
**Introduced with ARMv8.5 (later hardware)**
BTI is ’n hardware-funksie wat **indirect branch targets** kontroleer: wanneer `blr` of indirecte calls/jumps uitgevoer word, moet die teiken begin met ’n **BTI landing pad** (`BTI j` of `BTI c`). Om na gadget-adresse te spring wat nie die landing pad het nie, veroorsaak ’n uitsondering.
LLVM’s implementering noem drie variante van BTI-instruksies en hoe hulle op branch-tipes map.
| BTI Variant | Wat dit toelaat (watter branch types) | Tipiese plasing / gebruiksgeval |
|-------------|----------------------------------------|-------------------------------|
| **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 |
- In code compiled with branch target enforcement, compilers insert a BTI instruction (C, J, or JC) at each valid indirect-branch target (function beginnings or blocks reachable by jumps) so that indirect branches only succeed to those places.
- **Direct branches / calls** (i.e. fixed-address `B`, `BL`) are **not restricted** by BTI. Die aanname is dat code-pagine vertroulik is en ’n aanvaller dit nie kan verander nie (dus is direkte branches veilig).
- Verder is **RET / return** instruksies gewoonlik nie deur BTI beperk nie omdat return-adresse beskerm word via PAC of return signing-meganismes.
#### Mechanism and enforcement
- Wanneer die CPU ’n **indirect branch (BLR / BR)** dekodeer in ’n bladsy gemerk as “guarded / BTI-enabled,” kyk dit of die teikenadres se eerste instruksie ’n geldige BTI is (C, J, of JC soos toegelaat). Indien nie, gebeur ’n **Branch Target Exception**.
- Die BTI-instruksie-enkodering is ontwerp om opcodes te hergebruik wat vroeër vir NOPs gereserveer was (in vroeëre ARM-weergawes). Dus bly BTI-enabled binaries backward-compatible: op hardeware sonder BTI-ondersteuning tree daardie instruksies op as NOPs.
- Die compiler-passe wat BTIs byvoeg, plaas dit slegs waar nodig: funksies wat indirek opgeroep mag word, of basiese blokke geteiken deur jumps.
- Sommige patches en LLVM-kode toon dat BTI nie ingevaar word vir *alle* basiese blokke nie — slegs dié wat potensiële branch-reekse is (bv. van switch / jump tables).
#### BTI + PAC synergy
PAC beskerm die pointer-waarde (die bron) — dit verseker dat die ketting van indirecte calls / returns nie gemanipuleer is nie.
BTI verseker dat selfs ’n geldige pointer slegs na behoorlik gemerkte entry-punte mag wys.
Gekombineerd benodig ’n aanvaller beide ’n geldige pointer met die korrekte PAC én dat die teiken ’n BTI daarby het. Dit maak dit moeiliker om exploit gadgets saam te stel.
#### Example
<details>
<summary>Example</summary>
An exploit tries to pivot into gadget at `0xABCDEF` that doesn’t start with `BTI c`. The CPU, upon executing `blr x0`, checks the target and faults because the instruction alignment doesn’t include a valid landing pad. Thus many gadgets become unusable unless they include BTI prefix.
</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** is ’n funksie ingevoer in **ARMv8.1-A** wat voorkom dat **privileged code** (EL1 of EL2) **lees of skryf** na geheue wat as **user-accessible (EL0)** gemerk is, tensy PAN uitdruklik gedeaktiveer is.
- Die idee: selfs as die kernel mislei of gekompromitteer word, kan dit nie lukraak user-space pointers dereference sonder eers PAN te *clear* nie, en verminder dus die risiko van **`ret2usr`**-styl exploits of misbruik van user-beheerde buffers.
- Wanneer PAN geaktiveer is (PSTATE.PAN = 1), veroorsaak enige privileged load/store instruksie wat toegang probeer doen tot ’n virtuele adres wat “accessible at EL0” is ’n **permission fault**.
- Die kernel, wanneer dit regmatig user-space memory moet benader (bv. kopieer data na/van user buffers), moet **tans PAN deaktiveer** (of oorskakel na “unprivileged load/store” instruksies) om daardie toegang toe te laat.
- In Linux on ARM64 is PAN-ondersteuning rondom 2015 bekendgestel: kernel patches het feature-detektering bygevoeg, en `get_user` / `put_user` ens. vervang met variante wat PAN rondom user memory accesses clear.
**Belangrike nuanses / beperking / bug**
- Soos opgemerk deur Siguza en ander, beteken ’n spesifikasie-bug (of dubbelsinnige gedrag) in ARM se ontwerp dat **execute-only user mappings** (`--x`) moontlik **nie PAN trigger** nie. Met ander woorde, as ’n user bladsy uitvoerbaar maar sonder lees-permissie gemerk is, kan die kernel se leespoging PAN omseil omdat die argitektuur “accessible at EL0” as vereis lees-permissie beskou, nie net execute nie. Dit lei tot ’n PAN-bypass in sekere konfigurasies.
- As gevolg hiervan, indien iOS / XNU execute-only user pages toelaat (soos sommige JIT of code-cache opstellings mag hê), kan die kernel per ongeluk daaruit lees selfs met PAN geaktiveer. Dit is ’n bekende subtiele, potensieel uitbuitbare area in sekere ARMv8+ stelsels.
#### PXN (Privileged eXecute Never)
- **PXN** is ’n bladsy-tabel vlag (in die page table entries, leaf of block entries) wat aandui dat die bladsy **nie uitvoerbaar is wanneer in privileged mode** (bv. wanneer EL1 dit uitvoer) nie.
- PXN verhinder dat die kernel (of enige privileged code) na user-space bladsye spring en instruksies van daar uitvoer, selfs as beheer oorgeskuif word. Effektief stop dit kernel-vlak control-flow redirection na user geheue.
- Gecombineer met PAN verseker dit dat:
1. Kernel kan nie (by verstek) user-space data lees of skryf nie (PAN)
2. Kernel kan nie user-space code uitvoer nie (PXN)
- In die ARMv8 page table-formaat het leaf entries ’n `PXN` bit (en ook `UXN` vir unprivileged execute-never) in hul attribuut-bits.
Dus selfs as die kernel ’n korrupte function pointer het wat na user geheue wys, en dit probeer daarnatoe branch, sal die PXN-bit ’n fout veroorsaak.
#### Memory-permission model & how PAN and PXN map to page table bits
Om te verstaan hoe PAN / PXN werk, moet jy sien hoe ARM se translation en permission model werk (vereenvoudig):
- Elke bladsy of block entry het attribuut-velde insluitend **AP[2:1]** vir toegangspremisse (lees/skryf, privileged vs unprivileged) en **UXN / PXN** bits vir execute-never beperkings.
- Wanneer PSTATE.PAN 1 is (geaktiveer), dwing die hardeware gemodifiseerde semantiek af: privileged accesses na bladsye gemerk as “accessible by EL0” (dws user-accessible) word verwerp (fault).
- As gevolg van die genoemde bug, mag bladsye wat slegs uitvoerbaar is (geen lees-permissie) nie tel as “accessible by EL0” onder sekere implementasies nie, en so PAN omseil.
- Wanneer ’n bladsy se PXN-bit gestel is, is uitvoering verbode selfs al kom die instruksie-fetch vanaf ’n hoër privilege-vlak.
#### Kernel usage of PAN / PXN in a hardened OS (e.g. iOS / XNU)
In ’n geharde kernel-ontwerp (soos wat Apple moontlik gebruik):
- Die kernel aktiveer PAN by verstek (sodat privileged code beperk word).
- In paden wat regmatig user buffers moet lees of skryf (bv. syscall buffer copy, I/O, read/write user pointer), deaktiveer die kernel tydelik **PAN** of gebruik spesiale instruksies om dit te oorstuur.
- Nadat die user-data toegang voltooi is, moet dit PAN weer aktiveer.
- PXN word afgedwing via page tables: user pages het PXN = 1 (sodat kernel dit nie kan uitvoer nie), kernel pages het nie PXN nie (sodat kernel code kan uitvoer).
- Die kernel moet verseker dat geen code-paaie uitvoering in user geheue veroorsaak nie (wat PXN sou omseil) — dus word exploit-kettinge wat op “jump into user-controlled shellcode” staatmaak, geblokkeer.
Weens die genoemde PAN-bypass via execute-only bladsye, kan Apple in ’n werklike stelsel execute-only user pages deaktiveer of ’n omsingeling van die spesifikasie-kwessie aanbring.
#### Attack surfaces, bypasses, and mitigations
- **PAN bypass via execute-only pages**: soos bespreek, die spec laat ’n gaping toe: user pages met execute-only (geen lees-permissie) mag nie as “accessible at EL0” beskou word nie, dus sal PAN kernel reads na sodanige bladsye in sekere implementasies nie blokkeer nie. Dit gee die aanvaller ’n ongewoon pad om data te lewer via “execute-only” afdelings.
- **Temporal window exploit**: as die kernel PAN vir ’n langer tydperk as nodig deaktiveer, kan ’n race of kwaadwillige pad daardie venster uitbuit om onbedoelde user memory access te doen.
- **Forgotten re-enable**: indien kode-paaie versuim om PAN weer te aktiveer, mag opvolg-kernel-operasies verkeerdelik user memory benader.
- **Misconfiguration of PXN**: as page tables nie PXN op user bladsye stel nie of user code bladsye verkeerdelik map, mag die kernel mislei word om user-space code uit te voer.
- **Speculation / side-channels**: analoog aan speculative bypasses, kan daar mikroargitektoniese newe-effekte wees wat transiente schending van PAN / PXN-kontroles veroorsaak (al is sulke aanvalle sterk afhanklik van CPU-ontwerp).
- **Complex interactions**: In meer geavanceerde funksies (bv. JIT, shared memory, just-in-time code regions), mag die kernel fynkorrelmatige beheer nodig hê om sekere geheue-toegange of uitvoering in user-gemapte streke toe te laat; dit veilig onder PAN/PXN-beperkings ontwerp is nie triviaal nie.
#### Example
<details>
<summary>Code Example</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
If die kernel **nie** PXN op daardie user page gestel het nie, kan die branch slaag — wat onveilig sou wees.
As die kernel vergeet om PAN weer aan te sit nadat dit toegang tot user memory gehad het, skep dit 'n venster waarin verdere kernel-logika per ongeluk arbitrary user memory kan lees of skryf.
As die user pointer na 'n execute-only page wys (user page met slegs execute-permissie, geen read/write), kan, onder die PAN-spec bug, `ldr W2, [X1]` **nie** fout gee nie, selfs met PAN aangeskakel, wat afhangende van die implementering 'n bypass exploit moontlik maak.
</details>
<details>
<summary>Example</summary>
A kernel vulnerability probeer 'n user-provided function pointer neem en dit in kernel context aanroep (d.w.s. `call user_buffer`). Onder PAN/PXN is daardie operasie toegelaat nie of veroorsaak dit 'n fault.
</details>
---
### 11. **Top Byte Ignore (TBI) / Pointer Tagging**
**Introduced in ARMv8.5 / newer (or optional extension)**
TBI beteken dat die top byte (mees-belangrike byte) van 'n 64-bit pointer by address translation geïgnoreer word. Dit laat die OS of hardware toe om **tag bits** in die pointer se top byte in te sluit sonder om die werklike adres te verander.
- TBI staan vir **Top Byte Ignore** (soms *Address Tagging* genoem). Dit is 'n hardware-funksie (besikbaar in baie ARMv8+ implementasies) wat die **top 8 bits** (bits 63:56) van 'n 64-bit pointer ignoreer wanneer dit address translation / load/store / instruction fetch uitvoer.
- In praktyk behandel die CPU 'n pointer soos `0xTTxxxx_xxxx_xxxx` (waar `TT` = top byte) as `0x00xxxx_xxxx_xxxx` vir doeleindes van address translation, en ignoreer (masker af) die top byte. Die top byte kan deur software gebruik word om **metadata / tag bits** te stoor.
- Dit gee software “gratis” in-band ruimte om 'n byte tag in elke pointer in te sluit sonder om te verander watter geheue-ligging die pointer verwys.
- Die argitektuur verseker dat loads, stores, en instruction fetch die pointer met die top byte gemaskeer (d.w.s. tag verwyder) hanteer voordat die werklike memory access plaasvind.
Dus skei TBI die **logiese pointer** (pointer + tag) van die **fisiese adres** wat vir memory operasies gebruik word.
#### Why TBI: Use cases and motivation
- **Pointer tagging / metadata**: Jy kan ekstra metadata stoor (bv. object type, version, bounds, integrity tags) in daardie top byte. Wanneer jy later die pointer gebruik, word die tag op hardwarevlak geïgnoreer, so jy hoef dit nie handmatig te verwyder vir die memory access nie.
- **Memory tagging / MTE (Memory Tagging Extension)**: TBI is die basishardware-meganisme waarop MTE bou. In ARMv8.5 gebruik die **Memory Tagging Extension** bits 59:56 van die pointer as 'n **logiese tag** en vergelyk dit met 'n **allocation tag** wat in memory gestoor is.
- **Enhanced security & integrity**: Deur TBI te kombineer met pointer authentication (PAC) of runtime checks, kan jy vereis dat nie net die pointerwaarde maar ook die tag korrek is. 'n Aanvaller wat 'n pointer oorskryf sonder die korrekte tag sal 'n gemismate tag gee.
- **Compatibility**: Omdat TBI opsioneel is en tag bits deur hardware geïgnoreer word, bly bestaande ongetagde kode normaal werk. Die tag bits word effektief “don’t care” bits vir legacy kode.
#### Example
<details>
<summary>Example</summary>
'n Funksie-pointer het 'n tag in sy top byte gehad (bv. `0xAA`). 'n Exploit oorskryf die laer bits van die pointer maar vergeet die tag, so wanneer die kernel verifieer of sanitize, misluk of verwerp die pointer.
</details>
---
### 12. **Page Protection Layer (PPL)**
**Introduced in late iOS / modern hardware (iOS ~17 / Apple silicon / high-end models)** (sommige verslae wys PPL in macOS / Apple silicon, maar Apple bring analoog-beskermings na iOS)
- PPL is ontwerp as 'n **intra-kernel protection boundary**: selfs as die kernel (EL1) gekompromitteer is en lees/skryf-vaardighede het, behoort dit nie vrylik sekere **sensitiewe pages** te kan wysig nie (veral page tables, code-signing metadata, kernel code pages, entitlements, trust caches, ens.).
- Dit skep effektief 'n **“kernel binne die kernel”** — 'n kleiner vertroude komponent (PPL) met **verhoogde bevoegdhede** wat alleen protected pages kan wysig. Ander kernel-kode moet in PPL routines oproep om veranderinge te maak.
- Dit verminder die attack surface vir kernel exploits: selfs met volledige arbitrary R/W/execute in kernel mode, moet exploit-kode ook op een of ander manier in die PPL-domein inkom (of PPL omseil) om kritieke strukture te wysig.
- Op nuwer Apple silicon (A15+ / M2+) skuif Apple na **SPTM (Secure Page Table Monitor)**, wat in baie gevalle PPL vervang vir page-table beskerming op daardie platforms.
Hier is hoe PPL vermoedelik werk, gebaseer op publieke ontleding:
#### Use of APRR / permission routing (APRR = Access Permission ReRouting)
- Apple hardware gebruik 'n meganisme genaamd **APRR (Access Permission ReRouting)**, wat toelaat dat page table entries (PTEs) klein indeksies bevat in plaas van volle permission bits. Daardie indeksies word via APRR registers na werklike permissies gemappe. Dit maak dinamiese herleiding van permissies per domein moontlik.
- PPL benut APRR om privilegiese segregasie binne kernel context te bewerkstellig: slegs die PPL-domein mag die mapping tussen indeksies en effektiewe permissies opdateer. Dit wil sê, wanneer nie-PPL kernel-kode 'n PTE skryf of probeer permission-bits omskakel, ontzeg die APRR-logika dit (of handhaaf lees-alleen mapping).
- PPL-kode self hardloop in 'n beperkte streek (bv. `__PPLTEXT`) wat normaalweg nie-uitvoerbaar of nie-skyfbaar is totdat entry gates tydelik toegang verleen. Die kernel roep PPL entry points (“PPL routines”) om sensitiewe operasies uit te voer.
#### Gate / Entry & Exit
- Wanneer die kernel 'n beskermde page moet wysig (bv. verander permissies van 'n kernel code page, of page tables wysig), roep dit 'n **PPL wrapper** routine aan, wat validering doen en dan in die PPL-domein oorskakel. Buite daardie domein is die beskermde pages effektief lees-alleen of nie-wysigbaar deur die hoofkernel.
- Tydens PPL entry word die APRR-mappings aangepas sodat memory pages in die PPL-streek binne PPL as **executable & writable** gestel word. By exit word hulle teruggesit na lees-alleen / nie-skyfbaar. Dit verseker dat slegs goed-auditeerde PPL-routines beskrywing kan skryf aan beskermde pages.
- Buite PPL sal pogings deur kernel-kode om daardie beskermde pages te skryf 'n fault gee (permission denied) omdat die APRR-mapping vir daardie kode-domein nie skryf toelaat nie.
#### Protected page categories
Die pages wat PPL tipies beskerm sluit in:
- Page table strukture (translation table entries, mapping metadata)
- Kernel code pages, veral diegene wat kritieke logika bevat
- Code-sign metadata (trust caches, signature blobs)
- Entitlement tables, signature enforcement tables
- Ander hoë-waarde kernel strukture waar 'n patch diekening of credentials-manipulasie sou toelaat
Die idee is dat selfs as kernel memory ten volle beheer is, die aanvaller nie eenvoudig hierdie pages kan patch of herskryf nie, tensy hulle ook PPL-routines kompromitteer of PPL omseil.
#### Known Bypasses & Vulnerabilities
1. **Project Zero’s PPL bypass (stale TLB trick)**
- 'n Publieke uiteensetting deur Project Zero beskryf 'n bypass wat **stale TLB entries** benut.
- Die idee:
1. Alokeer twee fisiese pages A en B, merk hulle as PPL pages (dus beskerm).
2. Map twee virtuele adresse P en Q wie se L3 translation table pages van A en B kom.
3. Spin 'n thread wat voortdurend Q toegang om sy TLB entry lewendig te hou.
4. Roep `pmap_remove_options()` om mappings te verwyder wat by P begin; as gevolg van 'n fout verwyder die kode per ongeluk die TTEs vir beide P en Q, maar invalideer slegs die TLB entry vir P, wat Q se stale entry lewendig laat.
5. Hergebruik B (page Q se table) om arbitrary memory te map (bv. PPL-beskermde pages). Omdat die stale TLB entry steeds Q se ou mapping map, bly daardie mapping geldig vir daardie konteks.
6. Deur dit kan die aanvaller 'n writabele mapping van PPL-beskermde pages in plaas sit sonder om deur die PPL-interface te gaan.
- Hierdie exploit het fyn beheer van fisiese mapping en TLB-gedrag vereis. Dit demonstreer dat 'n sekuriteitsgrens wat op TLB / mapping-korrektheid staatmaak uiterste versigtigheid met TLB invalidasies en mapping konsistensie benodig.
- Project Zero het opgemerk dat omseilings soos hierdie subtiel en skaars is, maar moontlik in komplekse stelsels. Hulle beskou nogtans PPL as 'n stewige mitigasie.
2. **Other potential hazards & constraints**
- As 'n kernel exploit direk PPL routines kan binnetree (deur die PPL wrappers aan te roep), kan dit beperkings omseil. Daarom is argumentvalidering kritiek.
- Foute in die PPL-kode self (bv. arithmetic overflow, boundary checks) kan toelaat dat daar out-of-bounds wysigings binne PPL gemaak word. Project Zero het waargeneem dat so 'n fout in `pmap_remove_options_internal()` in hulle bypass uitgebuit is.
- Die PPL-grens is onherroeplik gebind aan hardware-handhawing (APRR, memory controller), so dit is slegs so sterk as die hardware-implementering.
#### Example
<details>
<summary>Code Example</summary>
Hier is 'n vereenvoudigde pseudocode / logika wat wys hoe 'n kernel in PPL kan oproep om beskermde pages te wysig:
```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
Die kernel kan baie normale operasies uitvoer, maar slegs deur ppl_call_* routines kan dit beskermde mappings verander of patch code.
Example
'n kernel exploit probeer om die entitlement table oor te skryf, of om code-sign enforcement te deaktiveer deur 'n kernel signature blob te verander. Omdat daardie bladsy PPL-protected is, word die skryf geblokkeer tensy dit deur die PPL interface gaan. Selfs met kernel code execution kan jy dus nie code-sign beperkings omseil of credential data arbitrêr wysig nie. Op iOS 17+ gebruik sekere devices SPTM om PPL-managed pages verder te isoleer.PPL → SPTM / Replacements / Future
- Op Apple se moderne SoCs (A15 of later, M2 of later) ondersteun Apple SPTM (Secure Page Table Monitor), wat PPL vervang vir page table protections.
- Apple noem in dokumentasie: “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.”
- Die SPTM-argitektuur skuif waarskynlik meer policy enforcement na ’n hoër-privilegieerde monitor buite kernel beheer, wat die trust boundary verder verklein.
MTE | EMTE | MIE
Hier is ’n hoërvlak-beskrywing van hoe EMTE werk onder Apple se MIE-opstelling:
- Tag assignment
- Wanneer memory gealloceer word (bv. in kernel of user space via secure allocators), word ’n secret tag aan daardie blok toegewys.
- Die pointer wat aan die user of kernel teruggestuur word, sluit daardie tag in sy hoë bits in (gebruik TBI / top byte ignore mechanisms).
- Tag checking on access
- Wanneer ’n load of store uitgevoer word met ’n pointer, kontroleer die hardware dat die pointer se tag ooreenstem met die memory block se tag (allocation tag). Indien dit nie ooreenstem nie, gooi dit onmiddellik ’n fault (aangesien dit synchronous is).
- Omdat dit synchronous is, bestaan daar geen “delayed detection” venster nie.
- Retagging on free / reuse
- Wanneer memory vrygeset word, verander die allocator die blok se tag (sodat ouer pointers met ou tags nie meer ooreenstem nie).
- ’n use-after-free pointer sou dus ’n verouderde tag hê en ’n mismatch veroorsaak wanneer dit aangespreek word.
- Neighbor-tag differentiation to catch overflows
- Angrensende allocations kry afsonderlike tags. As ’n buffer overflow in ’n buur se memory oorspoel, veroorsaak ’n tag mismatch ’n fault.
- Dit is veral effektief om klein overflows wat grens oorskry op te spoor.
- Tag confidentiality enforcement
- Apple moet voorkom dat tag values being leaked (omdat as ’n attacker die tag uitvind, hulle pointers met die korrekte tags kan maaks).
- Hulle sluit protections in (microarchitectural / speculative controls) om side-channel leakage van tag bits te vermy.
- Kernel and user-space integration
- Apple gebruik EMTE nie net in user-space nie, maar ook in kernel / OS-critical komponente (om die kernel teen memory corruption te beskerm).
- Die hardware/OS verseker dat tag-reëls van toepassing bly, selfs wanneer die kernel namens user space uitgevoer word.
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>
#### Beperkings & uitdagings
- **Intrablock overflows**: As overflow binne dieselfde allocation bly (nie ’n grens oorsteek nie) en die tag dieselfde bly, sal tag mismatch dit nie vang nie.
- **Tag width limitation**: Slegs ’n paar bits (bv. 4 bits, of ’n klein domein) is beskikbaar vir die tag—beperkte namespace.
- **Side-channel leaks**: As tag bits via cache / speculative execution geleak of andersins uitlek kan word, kan ’n aanvaller geldige tags leer en omseil. Apple se tag confidentiality enforcement is bedoel om dit te probeer beperk.
- **Performance overhead**: Tag checks by elke load/store voeg koste by; Apple moet hardware optimaliseer om die oorhoof laag te hou.
- **Compatibility & fallback**: Op ouer hardware of dele wat nie EMTE ondersteun nie, moet daar ’n fallback bestaan. Apple sê MIE word slegs geaktiveer op devices met ondersteuning.
- **Complex allocator logic**: Die allocator moet tags bestuur, retagging doen, grense belyn en mis-tag kollisies vermy. Bugs in allocator-logika kan kwesbaarhede invoer.
- **Mixed memory / hybrid areas**: Sommige geheue mag ongetagd bly (legacy), wat interoperabiliteit moeiliker maak.
- **Speculative / transient attacks**: Soos met baie mikroargitektuur beskermings, kan speculative execution of micro-op fusiess transientelik kontroles omseil of tag bits uitlek.
- **Limited to supported regions**: Apple mag EMTE slegs afdwing in selektiewe, hoë-risiko areas (kernel, security-critical subsystems), nie universeel nie.
---
## Sleutelverbeterings / verskille vergeleke met standaard MTE
Hier is die verbeterings en veranderinge wat Apple beklemtoon:
| 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.|
Omdat Apple beide die hardware en software stack beheer, kan dit EMTE stewig afdwing, prestasieprobleme vermy en side-channel gaps toemaak.
---
## Hoe EMTE in die praktyk werk (Apple / MIE)
Hier is ’n hoërvlak-beskrywing van hoe EMTE werk onder Apple se MIE opstelling:
1. **Tag assignment**
- Wanneer geheue gealloceer word (bv. in die kernel of user space via secure allocators), word ’n **secret tag** aan daardie blok toegeken.
- Die pointer wat aan die gebruiker of kernel teruggegee word, bevat daardie tag in sy hoë bits (gebruik makend van TBI / top byte ignore meganismes).
2. **Tag checking on access**
- Wanneer ’n load of store uitgevoer word met ’n pointer, kontroleer die hardware dat die pointer se tag ooreenstem met die memory block se tag (allocation tag). As dit nie ooreenstem nie, gooi dit onmiddellik ’n fault (omdat dit synchronous is).
- Omdat dit synchronous is, bestaan daar geen “delayed detection” venster nie.
3. **Retagging on free / reuse**
- Wanneer geheue vrygestel word, verander die allocator die blok se tag (sodat ou pointers met ou tags nie meer pas nie).
- ’n Use-after-free pointer sal dus ’n stalletjie tag hê en ’n mismatch veroorsaak wanneer dit geakses word.
4. **Neighbor-tag differentiation to catch overflows**
- Aangrensende allocations kry onderskeibare tags. As ’n buffer overflow na ’n buur se geheue uitloop, sal die tag mismatch ’n fault veroorsaak.
- Dit is veral kragtig om klein overflows wat oor grense gaan, te vang.
5. **Tag confidentiality enforcement**
- Apple moet voorkom dat tag waardes geleak word (want as ’n aanvaller die tag leer, kan hulle pointers met korrekte tags saamstel).
- Hulle sluit beskerming in (microarchitectural / speculative controls) om te probeer verhoed dat tag bits uitlek.
6. **Kernel and user-space integration**
- Apple gebruik EMTE nie net in user-space nie maar ook in kernel / OS-kritieke komponente (om die kernel teen memory corruption te beskerm).
- Die hardware/OS sorg dat tag reëls toegepas word selfs wanneer die kernel namens user space uitvoer.
Omdat EMTE in MIE ingebou is, gebruik Apple EMTE in synchronous mode oor sleutel aanvalsvlakke, nie net as opt-in of debug-modus nie.
---
## Exception handling in XNU
Wanneer ’n **exception** voorkom (bv. `EXC_BAD_ACCESS`, `EXC_BAD_INSTRUCTION`, `EXC_CRASH`, `EXC_ARM_PAC`, ens.), is die **Mach layer** van die XNU kernel verantwoordelik om dit te onderskep voordat dit ’n UNIX-styl **signal** (soos `SIGSEGV`, `SIGBUS`, `SIGILL`, ...) word.
Hierdie proses behels verskeie lae van exception propagasie en hantering voordat dit user space bereik of in ’n BSD signal omgeskakel word.
### Exception Flow (Hoëvlak)
1. **CPU triggers a synchronous exception** (bv. invalid pointer dereference, PAC failure, illegal instruction, ens.).
2. **Low-level trap handler** runs (`trap.c`, `exception.c` in XNU source).
3. Die trap handler roep **`exception_triage()`** aan, die kern van die Mach exception handling.
4. `exception_triage()` besluit hoe om die exception te route:
- Eerstens na die **thread's exception port**.
- Dan na die **task's exception port**.
- Dan na die **host's exception port** (dikwels `launchd` of `ReportCrash`).
As geen van hierdie ports die exception hanteer nie, kan die kernel:
- **Dit omskakel na ’n BSD signal** (vir user-space prosesse).
- **Panic** (vir kernel-space exceptions).
### Kernfunksie: `exception_triage()`
Die funksie `exception_triage()` roteer Mach exceptions op die ketting van moontlike handlers totdat een dit hanteer of totdat dit uiteindelik fataal is. Dit is gedefinieer in `osfmk/kern/exception.c`.
```c
void exception_triage(exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t codeCnt);
Tipiese oproepvloei:
exception_triage() └── exception_deliver() ├── exception_deliver_thread() ├── exception_deliver_task() └── exception_deliver_host()
As alles misluk → hanteer deur bsd_exception() → vertaal na ’n sein soos SIGSEGV.
Exception Ports
Elke Mach object (thread, task, host) kan exception ports registreer, waar exception messages naartoe gestuur word.
Hulle word deur die API gedefinieer:
task_set_exception_ports()
thread_set_exception_ports()
host_set_exception_ports()
Elke exception port het:
- A mask (watter exceptions dit wil ontvang)
- A port name (Mach port om boodskappe te ontvang)
- A behavior (hoe die kernel die boodskap stuur)
- A flavor (watter thread state ingesluit word)
Debuggers en Uitsonderingshantering
A debugger (bv., LLDB) stel ’n exception port op die teiken task of thread, gewoonlik met task_set_exception_ports().
Wanneer ’n uitsondering voorkom:
- Die Mach boodskap word na die debugger-proses gestuur.
- Die debugger kan besluit om die uitsondering te hanteer (herbegin, verander registers, slaan instruksie oor) of nie te hanteer nie.
- As die debugger dit nie hanteer nie, propageteer die uitsondering na die volgende vlak (task → host).
Flow of EXC_BAD_ACCESS
-
Thread dereferensieer ’n ongeldige pointer → CPU aktiveer Data Abort.
-
Kernel trap handler roep
exception_triage(EXC_BAD_ACCESS, ...)aan. -
Boodskap gestuur na:
-
Thread port → (debugger kan onderbreking onderskep).
-
As debugger ignoreer → Task port → (prosesvlak handler).
-
As ignoreer → Host port (gewoonlik ReportCrash).
- As niemand hanteer nie →
bsd_exception()vertaal naSIGSEGV.
PAC Exceptions
Wanneer Pointer Authentication (PAC) misluk (handtekening stem nie oor nie), word ’n spesiale Mach exception geopper:
EXC_ARM_PAC(type)- Codes kan besonderhede insluit (bv., sleuteltipe, pointer-tipe).
As die binêre die vlag TFRO_PAC_EXC_FATAL het, behandel die kernel PAC-mislukkings as fataal, en omseil debugger-onderskeping. Dit is om te verhoed dat aanvalleerders debuggers gebruik om PAC-ontledings te omseil, en dit is geaktiveer vir platform binaries.
Software Breakpoints
A software breakpoint (int3 on x86, brk on ARM64) word geïmplementeer deur ’n doelbewuste fout te veroorsaak.
Die debugger vang dit via die exception port:
- Wijzig instruksie pointer of geheue.
- Herstel die oorspronklike instruksie.
- Hervat uitvoering.
Dieselfde meganisme laat jou toe om ’n PAC-uitsondering te “vang” — tensy TFRO_PAC_EXC_FATAL gestel is, in welk geval dit nooit by die debugger uitkom nie.
Conversion to BSD Signals
As geen handler die uitsondering aanvaar nie:
-
Kernel roep
task_exception_notify() → bsd_exception(). -
Dit karteer Mach exceptions na seine:
| 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→ Kern vanexception_triage(),exception_deliver_*(). -
bsd/kern/kern_sig.c→ Logika vir sein-aflewering. -
osfmk/arm64/trap.c→ Lae-vlak trap handlers. -
osfmk/mach/exc.h→ Exception codes en strukture. -
osfmk/kern/task.c→ Task exception port opstelling.
Ou Kernel Heap (Pre-iOS 15 / Pre-A12 era)
Die kernel het ’n zone allocator (kalloc) gebruik, verdeeld in vaste-grootte “zones.”
Elke zone stoor slegs toewysings van ’n enkele grootteklas.
Vanaf die skermskoot:
| Zone Name | Element Size | Example Use |
|---|---|---|
default.kalloc.16 | 16 bytes | Baie klein kernel structs, pointers. |
default.kalloc.32 | 32 bytes | Klein structs, object headers. |
default.kalloc.64 | 64 bytes | IPC messages, klein kernel buffers. |
default.kalloc.128 | 128 bytes | Medium objects soos dele van OSObject. |
| … | … | … |
default.kalloc.1280 | 1280 bytes | Groot strukture, IOSurface/graphics metadata. |
Hoe dit gewerk het:
- Elke toewysingsversoek is afgerond na bo na die naaste zone-grootte.
(Byv., ’n 50-byte versoek beland in die
kalloc.64zone). - Geheue in elke zone is in ’n freelist gehou — stukke wat deur die kernel vrygestel is, het teruggegaan na daardie zone.
- As jy ’n 64-byte buffer oorloop het, sou jy die volgende objekt in dieselfde zone oor skryf.
Dit is waarom heap spraying / feng shui so effektief was: jy kon objekt-bures voorspel deur toewysings van dieselfde grootteklas te spuit.
The freelist
Binne elke kalloc-zone is vrygestelde objekte nie direk aan die stelsel teruggegee nie — hulle het in ’n freelist gegaan, ’n gekoppelde lys van beskikbare stukke.
-
Wanneer ’n stuk vrygestel is, het die kernel ’n pointer aan die begin van daardie stuk geskryf → die adres van die volgende vrye stukkie in dieselfde zone.
-
Die zone het ’n HEAD pointer na die eerste vrye stuk gehou.
-
Toewysing het altyd die huidige HEAD gebruik:
-
Pop HEAD (gee daardie geheue terug aan die aanroeper).
-
Werk HEAD by = HEAD->next (gestoor in die vrygestelde stukkie se header).
-
Vrygave het stukkies teruggedruk:
-
freed_chunk->next = HEAD -
HEAD = freed_chunk
Dus was die freelist net ’n gekoppelde lys opgebou binne die vrygestelde geheue self.
Normale toestand:
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)
Uitbuiting van die freelist
Omdat die eerste 8 bytes van ’n free chunk = freelist pointer, kan ’n aanvaller dit korrupteer:
-
Heap overflow in ’n aangrensende freed chunk → oorskryf sy “next” pointer.
-
Use-after-free skryf in ’n freed object → oorskryf sy “next” pointer.
Dan, by die volgende toewysing van daardie grootte:
- Die allocator haal die gekorrupte chunk uit die freelist.
- Volg die deur die aanvaller verskafte “next” pointer.
- Gee ’n pointer na arbitrêre geheue terug, wat fake object primitives of targeted overwrite moontlik maak.
Visuele voorbeeld van 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: voorspelbare bure van heap sprays, raw pointer freelist links, en geen tipe-skeiding het aanvallers toegelaat om UAF/overflow-foute in arbitrêre kernel memory control te eskaleer.
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.
Stappe:
- Spray allocations (fill the holes)
- Oor tyd raak die kernel heap gefragmenteer: sommige zones het gapings waar ou objekti vrygestel is.
- Die aanvaller maak eers baie dummy-allocations om hierdie gapings te vul, sodat die heap “gepak” en voorspelbaar raak.
- Force new pages
- Sodra die gapings gevul is, moet die volgende allocasies van nuwe bladsye kom wat by die zone gevoeg word.
- Vars bladsye beteken dat objekti saamgegroepeer sal wees, nie oor gefragmenteerde geheue versprei nie.
- Dit gee die aanvaller veel beter beheer oor bure.
- Place attacker objects
- Die aanvaller spray nou weer en skep baie deur-aanvaller-beheerde objekti in daardie nuwe bladsye.
- Hierdie objekti is voorspelbaar in grootte en plasing (aangesien hulle almal by dieselfde zone behoort).
- Free a controlled object (make a gap)
- Die aanvaller vrygestel doelbewus een van hul eie objekti.
- Dit skep ’n “gat” in die heap wat die allocator later sal hergebruik vir die volgende allocasie van daardie grootte.
- Victim object lands in the hole
- Die aanvaller laat die kernel ’n victim-objek (die een wat hulle wil korrupteer) allokeer.
- Aangesien die gat die eerste beskikbare slot in die freelist is, word die victim presies geplaas waar die aanvaller hul objek vrygestel het.
- Overflow / UAF into victim
- Nou het die aanvaller deur-aanvaller-beheerde objekti rondom die victim.
- Deur te overflow vanaf een van hul eie objekti (of ’n vrygestel een weer te gebruik), kan hulle betroubaar die victim se geheuevelde met gekose waardes oorskryf.
Waarom dit werk:
- Zone allocator voorspelbaarheid: allocations van dieselfde grootte kom altyd van dieselfde zone.
- Freelist gedrag: nuwe allocasies hergebruik die mees onlangse vrygestelde stuk eerste.
- Heap sprays: die aanvaller vul geheue met voorspelbare inhoud en beheer die uitleg.
- Eindresultaat: die aanvaller beheer waar die victim-objek land en watter data langs dit sit.
Modern Kernel Heap (iOS 15+/A12+ SoCs)
Apple het die allocator verhard en gemaak dat heap grooming baie moeiliker is:
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.
’n Aanvaller kan nie meer waarborg dat beheerde data (OSData) langs sensitiewe kernel-objekti (task_t) van dieselfde grootte eindig nie.
2. Slabs and Per-CPU Caches
- Die heap is verdeel in slabs (bladsye van geheue uitgesny in vaste-grootte stukke vir daardie zone).
- Elke zone het ’n per-CPU cache om kontensie te verminder.
- 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).
- Voordeel: Hierdie desentralisasie maak heap sprays minder deterministies, aangesien allocasies vanaf verskillende CPU’s se caches vervul kan word.
3. Randomization inside zones
- Binnen ’n zone word vrygestelde elemente nie in eenvoudige FIFO/LIFO-volgorde teruggegee nie.
- Moderne XNU gebruik encoded freelist pointers (safe-linking styl soos Linux, ingestel ~iOS 14).
- Elke freelist pointer is XOR-encoded met ’n per-zone geheime koekie.
- Dit verhoed dat aanvallers ’n vals freelist pointer kan vervals as hulle ’n write primitive kry.
- Sommige allocasies word gerandomiseer in hul plasing binne ’n slab, so spraying waarborg nie nabyheid nie.
4. Guarded Allocations
- Sekere kritieke kernel-objekti (bv. credentials, task strukture) word in guarded zones geallokeer.
- Hierdie zones voeg guard pages (unmapped geheue) tussen slabs in of gebruik redzones rondom objekti.
- Enige overflow in die guard page veroorsaak ’n fout → onmiddellike panic in plaas van stille korrupsie.
5. Page Protection Layer (PPL) and SPTM
- Selfs as jy ’n vrygestel objek beheer, kan jy nie alle kernel-geheue wysig nie:
- PPL (Page Protection Layer) dwing af dat sekere streek (bv. code signing data, entitlements) read-only is selfs vir die kernel self.
- Op A15/M2+ devices, word hierdie rol vervang/versterk deur SPTM (Secure Page Table Monitor) + TXM (Trusted Execution Monitor).
- Hierdie hardware-afgedwonge lae beteken aanvallers kan nie van ’n enkele heap korrupsie na arbitrêre patching van kritieke sekuriteitsstrukture eskaleer nie.
- (Added / Enhanced): ook, PAC (Pointer Authentication Codes) word in die kernel gebruik om pointers (veral function pointers, vtables) te beskerm sodat die vervalsing of korrupsie daarvan moeiliker word.
- (Added / Enhanced): zones kan zone_require / zone enforcement afdwing, d.w.s. dat ’n objek wat vrygestel word slegs teruggegee kan word deur sy korrekte typed zone; ongeldige cross-zone frees kan panic veroorsaak of geweier word. (Apple verwys daarna in hul memory safety posts)
6. Large Allocations
- Nie alle allocasies gaan deur
kalloc_typenie. - Baie groot versoeke (bo ~16 KB) omseil typed zones en word direk vanaf kernel VM (kmem) via page allocasies bedien.
- Hierdie is minder voorspelbaar, maar ook minder uitbuitbaar, aangesien hulle nie slabs met ander objekti deel nie.
7. Allocation Patterns Attackers Target
Selfs met hierdie beskerming soek aanvallers steeds na:
- Reference count objects: as jy retain/release-tellers kan manipuleer, kan jy use-after-free veroorsaak.
- Objects with function pointers (vtables): die korruptering van een gee steeds control flow.
- Shared memory objects (IOSurface, Mach ports): hierdie is steeds teiken omdat hulle user ↔ kernel oorbrug.
Maar — anders as voorheen — kan jy nie net OSData spray en verwag dat dit langs ’n task_t sal wees nie. Jy het type-specific bugs of info leaks nodig om sukses te behaal.
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.
Vergelykingstabel
| 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: groepeer allocasies per type of gebruik (pointer vs data) om tipe-konfusi e en cross-type reuse te verhoed.
- Metadata isolation: skei heap-metadata (bv. free lists, size/state bits) van objek-payloads sodat out-of-bounds skrywes minder waarskynlik metadata korrupteer.
- Guard pages / redzones: voeg unmapped bladsye of padding rondom allocasies in om overflows raak te vang.
- Memory tagging (EMTE / MIE): werk saam met hardware-tagging om use-after-free, out-of-bounds en ongeldige toegang te detecteer.
- Scalable performance: handhaaf lae overhead, vermy oormatige fragmentasie, en ondersteun baie allocasies per sekonde met lae latensie.
Architecture & Components
Hier is die hoofelemente van die xzone allocator:
Segment Groups & Zones
- Segment groups verdeel die adresruimte per gebruikskategorie: bv.
data,pointer_xzones,data_large,pointer_large. - Elke segment group bevat segments (VM ranges) wat allocasies vir daardie kategorie huisves.
- Geassosieer met elke segment is ’n metadata slab (afgesonderde VM area) wat metadata stoor (bv. free/used bits, size classes) vir daardie segment. Hierdie out-of-line (OOL) metadata verseker dat metadata nie deurmekaar raak met objek-payloads nie, wat korrupsie deur overflows beperk.
- Segmente word uitgesny in chunks (skywe) wat op hul beurt in blocks (allocasie-eenhede) verdeel word. ’n Chunk is gekoppel aan ’n spesifieke size class en segment group (d.w.s. alle blocks in ’n chunk deel dieselfde grootte & kategorie).
- Vir klein / medium allocasies gebruik dit vaste-grootte chunks; vir groot/baie groot kan dit aparte mapping gebruik.
Chunks & Blocks
- ’n Chunk is ’n streek (gewoonlik verskeie bladsye) toegeken aan allocasies van een grootteklas binne ’n groep.
- Binne ’n chunk is blocks slots beskikbaar vir allocasies. Vrygestelde blocks word via die metadata slab gevolg — bv. via bitmaps of free lists wat out-of-line gestoor word.
- Tussen chunks (of binne) kan guard slices / guard pages ingevoeg word (bv. unmapped slices) om out-of-bounds skrywes te vang.
Type / Type ID
- Elke allocasiepunt (of oproep na malloc, calloc, ens.) is geassosieer met ’n type identifier (’n
malloc_type_id_t) wat enkodeer watter soort objek gealloceer word. Daardie type ID word aan die allocator gegee, wat dit gebruik om te kies watter zone / segment die allocasie sal bedien. - As gevolg hiervan kan twee allocasies dieselfde grootte hê maar in heeltemal verskillende zones gaan as hul types verskil.
- In vroeë iOS 17 weergawes was nie alle APIs (bv. CFAllocator) volledig type-aware nie; Apple het sommige van daardie swakpunte in iOS 18 aangespreek.
Allocation & Freeing Workflow
Hoëvlak vloei van hoe allocasie en deallocasie in xzone werk:
- malloc / calloc / realloc / typed alloc word aangeroep met ’n grootte en type ID.
- Die allocator gebruik die type ID om die korrekte segment group / zone te kies.
- Binne daardie zone/segment soek dit ’n chunk met vrye blocks van die versoekte grootte.
- Dit kan na local caches / per-thread pools of free block lists van metadata kyk.
- As geen vrye block beskikbaar is nie, kan dit ’n nuwe chunk in daardie zone allokeer.
- Die metadata slab word opgedateer (free bit verwyder, boekhouding).
- As memory tagging (EMTE) in werking is, kry die teruggegewe block ’n tag en metadata word opgedateer om sy “live” toestand te weerspieël.
- Wanneer
free()geroep word:
- Die block word as vry gemerk in metadata (via OOL slab).
- Die block kan in ’n free list geplaas of in ’n pool vir hergebruik gehou word.
- Opsioneel kan block-inhoud gewist of gepoison word om data leaks of use-after-free uitbuiting te verminder.
- Die hardware tag wat met die block geassosieer is, kan ongeldig gemaak of her-getag word.
- As ’n hele chunk vry raak (alle blocks vry), kan die allocator daardie chunk reclaim (unmap of teruggee aan OS) onder geheue- druk.
Security Features & Hardening
Hierdie afdelings is die verdediging wat in moderne userland xzone ingebou is:
| 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 wat Enhanced Memory Tagging Extension (EMTE) in altyd-aan, sinchrone modus oor groot aanvalsvlakke bring.
- xzone allocator is ’n fundamentele grondslag van MIE in user space: allocasies via xzone kry tags, en toegangsbewaking word deur hardware uitgevoer.
- In MIE is die allocator, tag-toekenning, metadata-bestuur, en tag-konfidensialiteitsafdwinging geïntegreer om te verseker dat geheuefoute (bv. stale reads, OOB, UAF) onmiddellik opgevang word in plaas daarvan om later uitgebuit te word.
- As jy wil, kan ek ook ’n cheat-sheet of diagram van xzone-internals vir jou boek genereer. Wil jy dat ek dit volgende doen?
- :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 modules
-
Watcher anti-analysis: ’n Toegewese watcher-binary profileer voortdurend die toestel en breek die kill-chain af wanneer ’n navorsingsomgewing opgespoor word. Dit inspekteer
security.mac.amfi.developer_mode_status, die teenwoordigheid van ’ndiagnosticdconsole, lokaliteiteUSofIL, jailbreak-spore soos Cydia, prosesse soosbash,tcpdump,frida,sshd, ofcheckrain, mobiele AV-apps (McAfee, AvastMobileSecurity, NortonMobileSecurity), pasgemaakte HTTP-proxy-instellings, en pasgemaakte root CAs. As enige toets faal, blokkeer dit verdere payload-aflewering. -
Helper surveillance hooks: Die helper-komponent kommunikeer met ander fases deur
/tmp/helper.sock, en laai dan hook-stelle met name DMHooker en UMHooker. Hierdie hooks tap VOIP-audio-paaie (opnames beland onder/private/var/tmp/l/voip_%lu_%u_PART.m4a), implementeer ’n stelselwye keylogger, neem foto’s sonder UI, en hook SpringBoard om kennisgewings wat daardie aksies normaalweg sou veroorsaak, te onderdruk. Die helper tree dus op as ’n stilswyende validasie- + ligte toeslagslaag voordat swaarder implants soos Predator gelaai word. -
HiddenDot indicator suppression in SpringBoard: Met kernvlak-kode-inspuiting hook Predator
SBSensorActivityDataProvider._handleNewDomainData:(die agregasiepunt vir sensor-aktiwiteit). Die hook stel die Objective-Cself-pointer (x0) na nul sodat die oproep[nil _handleNewDomainData:newData]word, wat kamera/mikrofoon-opdaterings laat val en beide die groen/oranje kolletjies onderdruk. -
Mach exception-based hooking flow (DMHooker): Hooks word geïmplementeer via
EXC_BREAKPOINT+ exception ports, dan veranderthread_set_stateregisters en word uitvoering hervat. Terugkode2beteken “v pokrač met gewysigde thread state.” -
PAC-aware redirection for camera access checks: In
mediaserverdvind ’n pattern-scan (bv.memmem) ’n private routine nabyFigVideoCaptureSourceCreateWithSourceInfobinneCMCapture.framework. Die hook gee3terug om te herlei met ’n vooraf-ondertekende PAC-gecachete terugkeeradres, wat PAC tevrede stel terwyl die kontrole omseil word. -
VoIP capture pipeline in
mediaserverd: HooksAudioConverterNewenAudioConverterConvertComplexBuffer+52om buffers te tap, infer die monstersnelheid uit buffergroottes, omskep float32 PCM → int16 met NEON, downmix 4-kanaal na stereo, en berg viaExtAudioFileWrite(). Die VoIP-module self onderdruk nie indiakteurs nie, dus moet operateurs HiddenDot afsonderlik aktiveer.
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
Verwysings
- https://www.jamf.com/blog/predator-spyware-ios-recording-indicator-bypass-analysis/
- Google Threat Intelligence – Intellexa zero-day exploits continue
Tip
Leer en oefen AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.


