iOS Exploiting

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

iOS Exploit Mitigations

1. Code Signing / Runtime Signature Verification

Introduced early (iPhone OS → iOS) Bu temel korumalardan biridir: tüm yürütülebilir kod (apps, dynamic libraries, JIT-ed code, extensions, frameworks, caches) Apple’ın güvenine dayanan sertifika zinciri ile kriptografik olarak imzalanmış olmalıdır. Runtime’da, bir binary belleğe yüklenmeden önce (veya belirli sınırlar arasında atlama yapılmadan önce) sistemi imzayı kontrol eder. Kod değiştirilmişse (bit-flip, patch) veya imzasızsa yükleme başarısız olur.

  • Engeller: exploit zincirlerindeki “klasik payload drop + execute” aşamasını; arbitrary code injection; mevcut bir binary’yi kötü amaçlı mantık eklemek için modifiye etmeyi.
  • Mekanizma detayları:
  • Mach-O loader (ve dynamic linker) kod sayfalarını, segmentleri, entitlements, team ID’leri ve imzanın dosya içeriğini kapsadığını kontrol eder.
  • JIT cache’ler veya dinamik üretilen kod gibi bellek bölgeleri için Apple, sayfaların imzalanmış olmasını veya özel API’lerle doğrulanmasını zorunlu kılar (ör. mprotect ile code-sign kontrolleri).
  • İmza, entitlements ve identifier’ları içerir; OS belirli API’lerin veya ayrıcalıklı yeteneklerin belirli entitlements gerektirdiğini ve bunların taklit edilemeyeceğini zorlar.
Example Bir exploit bir process içinde kod çalıştırma elde eder ve shellcode’u heap’e yazıp oraya atlamaya çalışır. iOS’ta o sayfa executable olarak işaretlenmeli **ve** code-signature kısıtlamalarını karşılamalıdır. Shellcode Apple’ın sertifikasıyla imzalanmadığından, atlama başarısız olur veya sistem o bellek bölgesinin executable yapılmasını reddeder.

2. CoreTrust

Introduced around iOS 14+ era (or gradually in newer devices / later iOS) CoreTrust, binary’lerin (sistem ve kullanıcı binary’leri dahil) runtime signature validation işlemini Apple’ın root certificate’ına karşı yapan alt sistemdir; userland trust cache’lerine güvenmez.

  • Engeller: kurulum sonrası binary’lere müdahaleyi, system library veya user app’leri değiştirip patchlemeye çalışan jailbreak tekniklerini; trusted binary’leri kötü amaçlı karşılıklarıyla değiştirme saldırılarını.
  • Mekanizma detayları:
  • Lokal bir trust veritabanına veya sertifika cache’ine güvenmek yerine CoreTrust doğrudan Apple’ın root’una başvurur veya güven zincirindeki intermediate sertifikaları güvenli bir zincir içinde doğrular.
  • Dosya sistemi üzerindeki mevcut binary’lerdeki modifikasyonları (ör. filesystem değişiklikleri) tespit eder ve reddeder.
  • Entitlements, team ID’leri, code signing flag’leri ve diğer metadata’yı load zamanında binary’ye bağlar.
Example Bir jailbreak, persistence elde etmek için `SpringBoard` veya `libsystem`’i patch’lenmiş bir sürümle değiştirmeye çalışabilir. Ancak OS loader veya CoreTrust doğrulaması yaparken imza uyuşmazlığını (veya modifiye edilmiş entitlements’i) fark eder ve çalıştırmayı reddeder.

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

Introduced in many OSes earlier; iOS had NX-bit / w^x for a long time DEP, writable (data) olarak işaretlenmiş sayfaların non-executable, executable olarak işaretlenmiş sayfaların ise non-writable olmasını zorunlu kılar. Heap veya stack bölgesine shellcode yazıp çalıştırmak mümkün değildir.

  • Engeller: doğrudan shellcode çalıştırma; klasik buffer-overflow → injected shellcode’a atlama.
  • Mekanizma detayları:
  • MMU / memory protection flag’leri (page table üzerinden) bu ayrımı uygular.
  • Writable bir sayfayı executable hale getirme girişimi sistem kontrolünü tetikler (ve ya yasaklanır ya da code-sign onayı gerektirir).
  • Birçok durumda sayfaları executable yapmak OS API’leri üzerinden yapılmalı ve ek kısıtlamalar/kontroller uygulanır.
Example Bir overflow shellcode’u heap’e yazar. Saldırgan `mprotect(heap_addr, size, PROT_EXEC)` ile executable yapmaya çalışır. Ancak sistem bunu reddeder veya yeni sayfanın code-sign kısıtlamalarını geçmesi gerektiğini doğrular (ki shellcode bunu sağlayamaz).

4. Address Space Layout Randomization (ASLR)

Introduced in iOS ~4–5 era (roughly iOS 4–5 timeframe) ASLR, kütüphanelerin, heap’in, stack’in vb. ana bellek bölgelerinin base adreslerini her process başlatılışında rastgeleleştirir. Gadget adresleri her çalışma arasında değişir.

  • Engeller: ROP/JOP için gadget adreslerini hardcode etmeyi; statik exploit zincirlerini; bilinen offset’lere kör atlama yapmayı.
  • Mekanizma detayları:
  • Her yüklenen library / dynamic module rastgele bir offset’te rebase edilir.
  • Stack ve heap base pointer’ları (belli entropy limitleri içinde) rastgelelenir.
  • Bazen diğer bölgeler (ör. mmap tahsisi) de rastgelelenir.
  • Information-leak mitigations ile birlikte, saldırgana önce bir adres veya pointer leak etme zorunluluğu getirir.
Example Bir ROP zinciri `0x….lib + offset`’teki gadget’ı bekler. Ancak `lib` her çalıştırmada farklı yerde rebase edildiği için hardcoded zincir başarısız olur. Bir exploit öncelikle modülün base adresini leak etmek zorundadır, sonra gadget adreslerini hesaplayabilir.

5. Kernel Address Space Layout Randomization (KASLR)

Introduced in iOS ~ (iOS 5 / iOS 6 timeframe) Kullanıcı ASLR’sine benzer şekilde, KASLR her boot’ta kernel text ve diğer kernel yapılarının base’ini rastgeleler.

  • Engeller: kernel seviyesinde kod veya veri için sabit lokasyonlara güvenen exploitleri; statik kernel exploitlerini.
  • Mekanizma detayları:
  • Her boot’ta kernel’in base adresi bir aralık içinde rastgelelenir.
  • Kernel veri yapıları (ör. task_structs, vm_map, vb.) da relocate edilebilir veya offsetlenebilir.
  • Saldırganlar önce kernel pointer’larını leak etmeli veya bilgi açıklama (information disclosure) açıkları kullanmalıdır ki offset hesaplanabilsin.
Example Bir local vulnerability, bir kernel function pointer’ını (`vtable` içindeki gibi) `KERN_BASE + offset` adresinde bozmayı hedefler. Ancak `KERN_BASE` bilinmediği için saldırgan önce onu leak etmek zorundadır (ör. bir read primitive ile) ve sonra doğru adresi hesaplayıp bozar.

6. Kernel Patch Protection (KPP / AMCC)

Introduced in newer iOS / A-series hardware (post around iOS 15–16 era or newer chips) KPP (aka AMCC) kernel text sayfalarının bütünlüğünü (hash veya checksum yoluyla) sürekli izler. Eğer izin verilen pencereler dışında bir tamper (patch, inline hook, code modification) algılanırsa kernel panic veya reboot tetiklenir.

  • Engeller: persistent kernel patching (kernel talimatlarını değiştirme), inline hook’lar, static function overwrite’lar.
  • Mekanizma detayları:
  • Bir donanım veya firmware modülü kernel text bölgesini izler.
  • Periyodik veya talep üzerine sayfaları yeniden hash’ler ve beklenen değerlerle karşılaştırır.
  • Uyumsuzluklar benign update pencereleri dışında ise cihazı panikletir (cihazı çökertir) — persistent kötü amaçlı patch’i engellemek için.
  • Saldırganlar ya tespit pencerelerini atlamalı ya da meşru patch yollarını kullanmalıdır.
Example Bir exploit bir kernel fonksiyonunun prologunu (ör. `memcmp`) patchlemeye çalışır. Ancak KPP, kod sayfasının hash’inin beklenenle uyuşmadığını fark eder ve kernel panic tetiklenir; cihaz patch stabil hale gelmeden çökür.

7. Kernel Text Read‐Only Region (KTRR)

Introduced in modern SoCs (post ~A12 / newer hardware) KTRR, donanım tarafından zorlanan bir mekanizmadır: kernel text boot sırasında kilitlenip EL1’den (kernel) yazılamaz hale getirilir, böylece kod sayfalarına daha sonra yazılamaz.

  • Engeller: boot sonrası kernel kodunu değiştirmeyi (ör. patch, in-place code injection) EL1 ayrıcalık seviyesinde.
  • Mekanizma detayları:
  • Boot sırasında (secure/bootloader aşamasında) memory controller veya güvenli bir donanım birimi kernel text içeren fiziksel sayfaları read-only olarak işaretler.
  • Bir exploit tam kernel ayrıcalıkları elde etse bile bu sayfalara yazamaz.
  • Değiştirmek için saldırgan önce boot zincirini bozmalı veya KTRR’yi alt etmelidir.
Example Bir privilege-escalation exploit EL1’e atlar ve kernel fonksiyonuna bir trampoline yazmak ister (ör. `syscall` handler içinde). Ancak sayfalar KTRR tarafından read-only olarak kilitlendiğinden yazma başarısız olur veya fault oluşur; böylece patch uygulanamaz.

8. Pointer Authentication Codes (PAC)

Introduced with ARMv8.3 (hardware), Apple beginning with A12 / iOS ~12+

  • PAC, pointer değerlerinin (return adresleri, function pointer’lar, bazı data pointer’lar) değiştirilmesini tespit etmek için ARMv8.3-A ile sunulan bir donanım özelliğidir; pointer’ın kullanılmayan yüksek bitlerine küçük bir kriptografik imza (“MAC”) gömülür.
  • İmza (“PAC”), pointer değeri ile bir modifier (bağlam değeri, ör. stack pointer veya ayırt edici bir veri) üzerinden hesaplanır. Böylece aynı pointer değeri farklı context’lerde farklı PAC üretir.
  • Kullanım zamanında, pointer dereference veya branching yapılmadan önce bir authenticate talimatı PAC’i kontrol eder. Eğer geçerliyse PAC temizlenir ve saf pointer elde edilir; geçersizse pointer “poisoned” olur veya fault tetiklenir.
  • PAC üretip doğrulamak için kullanılan anahtarlar ayrıcalıklı register’larda (EL1, kernel) tutulur ve user moddan doğrudan okunamaz.
  • Birçok sistemde pointer’ın tüm 64 biti kullanılmadığı için (ör. 48-bit adres alanı) üst bitler “boş”tır ve PAC’i adresi değiştirmeden oraya koymak mümkün olur.

Architectural Basis & Key Types

  • ARMv8.3, beş 128-bit anahtar tanıtır (her biri iki 64-bit system register ile uygulanır).

  • APIAKey — instruction pointers için (domain “I”, key A)

  • APIBKey — ikinci instruction pointer key (domain “I”, key B)

  • APDAKey — data pointer’lar için (domain “D”, key A)

  • APDBKey — data pointer’lar için (domain “D”, key B)

  • APGAKey — “generic” key, pointer olmayan verileri veya genel kullanım için

  • Bu anahtarlar ayrıcalıklı system register’larda saklanır (sadece EL1/EL2 gibi erişilebilir), user moddan erişilemez.

  • PAC, kriptografik bir fonksiyon (ARM QARMA önerir) ile şu girdiler kullanılarak hesaplanır:

  1. Pointer değeri (canonical portion)
  2. Bir modifier (bağlam değeri, ör. bir salt)
  3. Gizli anahtar
  4. İçsel tweak mantığı Elde edilen PAC pointer’ın üst bitlerinde tutulanla eşleşirse authentication başarılı olur.

Instruction Families

Adlandırma kuralı: PAC / AUT / XPAC, ardından domain harfleri.

  • PACxx talimatları bir pointer’ı sign eder ve PAC ekler
  • AUTxx talimatları authenticate + strip yapar (doğrular ve PAC’i kaldırır)
  • XPACxx talimatları doğrulamadan strip eder

Domains / suffix’ler:

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

Özel / alias formlar da vardır:

  • PACIASP PACIA X30, SP için kısaltmadır (link register’ı SP ile modifier kullanarak sign et)
  • AUTIASP AUTIA X30, SP (link register’ı SP ile authenticate et)
  • RETAA, RETAB (authenticate-and-return) veya BLRAA (authenticate & branch) gibi combined formlar ARM extension’larında / compiler desteğinde bulunur.
  • Ayrıca modifier sıfır olan varyantlar: PACIZA / PACIZB gibi, modifier implicit olarak zero’dır.

Modifiers

Modifier’ın ana hedefi PAC’i belirli bir bağlama bağlamaktır; böylece aynı adres farklı bağlamlarda imzalandığında farklı PAC’ler oluşur. Bu bir hash’e salt eklemek gibidir.

Bundan dolayı:

  • modifier, PAC hesaplamasına karıştırılan bir bağlam değeri (başka bir register)dır. Tipik seçimler: stack pointer (SP), frame pointer veya bir object ID.
  • SP’i modifier olarak kullanmak return address signing için yaygındır: PAC belirli stack frame’e bağlanır. LR’ı farklı bir frame’de yeniden kullanmaya çalışırsanız modifier değişir ve PAC doğrulaması başarısız olur.
  • Aynı pointer değeri farklı modifier’larla imzalandığında farklı PAC’ler elde edilir.
  • Modifier gizli olmak zorunda değildir, ama ideal olarak saldırgan tarafından kontrol edilmez.
  • Anlamlı bir modifier olmayan durumlarda bazı formlar zero veya implicit constant kullanır.

Apple / iOS / XNU Customizations & Observations

  • Apple’ın PAC uygulaması per-boot diversifier içerir; böylece anahtarlar veya tweak’ler her boot’ta değişir ve boot’lar arası tekrar kullanım engellenir.
  • Ayrıca cross-domain mitigations vardır; user modda imzalanmış PAC’ler kernel modda kolayca yeniden kullanılamaz.
  • Apple Silicon (M1) üzerinde tersine mühendislik, dokuz modifier tipi ve anahtar kontrolü için Apple-özel system register’ları olduğunu göstermiştir.
  • Apple PAC’i birçok kernel alt sisteminde kullanır: return address signing, kernel veri pointer bütünlüğü, imzalı thread context’leri vb.
  • Google Project Zero, kernel’de güçlü bir memory read/write primitive altında, A anahtarları için kernel PAC’leri sahteleyebileceğini gösterdi (A12-era cihazlarda), ancak Apple bu yolların birçoğunu yamaladı.
  • Apple sisteminde bazı anahtarlar kernel genelinde iken user process’ler per-process anahtar randomness alabilir.

PAC Bypasses

  1. Kernel-mode PAC: theoretical vs real bypasses
  • Kernel PAC anahtarları ve mantığı sıkı kontrol edildiği (ayrıcalıklı register’lar, diversifier’lar, domain izolasyonu) için arbitrary signed kernel pointer’ları forge etmek çok zordur.
  • Azad’ın 2020 “iOS Kernel PAC, One Year Later” raporu iOS 12-13’te bazı kısmi bypass’lar bulduğunu (signing gadgets, reuse of signed states, unprotected indirect branches) bildirir, ancak genel bir bypass yoktu. bazad.github.io
  • Apple’ın “Dark Magic” özelleştirmeleri exploitable yüzeyleri daha da daralttı (domain switching, per-key enabling bit’leri). i.blackhat.com
  • Apple silicon (M1/M2) üzerinde Zecao Cai ve diğ. tarafından raporlanan bilinen bir kernel PAC bypass CVE-2023-32424 vardır. i.blackhat.com
  • Ancak bu bypass’lar genellikle çok özel gadget’lara veya implementasyon hatalarına dayanır; genel amaçlı değildir.

Dolayısıyla kernel PAC yüksek derecede sağlam kabul edilir, ama kusursuz değildir.

  1. User-mode / runtime PAC bypass techniques

Bunlar daha yaygındır ve PAC’in dinamik linking / runtime framework’lerde uygulanmasındaki kusurları suistimal eder. Aşağıda sınıflar ve örnekler vardır.

2.1 Shared Cache / A key issues

  • dyld shared cache geniş, önceden linklenmiş bir sistem framework ve kütüphane blob’udur. Bu kadar geniş paylaşılabilir olduğu için shared cache içindeki function pointer’lar “önceden imzalanmış”tır ve birçok process tarafından kullanılır. Saldırganlar bu önceden imzalı pointer’ları “PAC oracles” olarak hedef alır.
  • Bazı bypass teknikleri shared cache’teki A-key ile imzalanmış pointer’ları çıkarmaya veya yeniden kullanmaya çalışır.
  • “No Clicks Required” konuşması shared cache üzerinde relative adresleri çıkarmak için bir oracle kurmayı ve imzalı pointer’larla bunu birleştirerek PAC’i atlatmayı anlatır. saelo.github.io
  • Ayrıca userspace’taki shared library import’ları aracılığıyla alınan function pointer’ların PAC ile yetersiz korunmuş olduğu, saldırgana signature değiştirmeden pointer elde etme imkanı verdiği bulunmuştur. (Project Zero bug entry) bugs.chromium.org

2.2 dlsym(3) / dynamic symbol resolution

  • Bilinen bypass’lardan biri dlsym() çağırıp zaten imzalanmış bir function pointer almak ve bunu kullanmaktır. dlsym meşru olarak imzalanmış bir pointer döndürdüğü için, bunu kullanmak PAC sahteleştirme ihtiyacını ortadan kaldırır.
  • Epsilon’un blog’u bazı bypass’ların bunu nasıl suistimal ettiğini detaylandırır: dlsym("someSym") çağrısı imzalı bir pointer döndürür ve indirect çağrılar için kullanılabilir. blog.epsilon-sec.com
  • Synacktiv’in “iOS 18.4 — dlsym considered harmful” yazısı bir hatayı anlatır: iOS 18.4’te bazı semboller dlsym aracılığıyla çözümlendiğinde yanlış imzalanmış pointer’lar (veya hatalı diversifier’lar) dönüyordu; bu da istemeden PAC bypass’a yol açıyordu. Synacktiv
  • dyld içindeki logic şu şekildedir: result->isCode olduğunda döndürülen pointer’ı __builtin_ptrauth_sign_unauthenticated(..., key_asia, 0) ile sign eder; yani context zero ile. blog.epsilon-sec.com

Dolayısıyla dlsym user-mode PAC bypass’larında sık bir vektördür.

2.3 Other DYLD / runtime relocations

  • DYLD loader ve dynamic relocation mantığı karmaşıktır ve bazen relocasyon yapmak için sayfaları geçici olarak read/write mapler, sonra tekrar read-only yapar. Saldırganlar bu pencereleri suistimal eder. Synacktiv’in “Operation Triangulation” zamanlama tabanlı PAC bypass’ını anlattığı konuşma buna örnektir. Synacktiv
  • DYLD sayfaları artık SPRR / VM_FLAGS_TPRO gibi korumalarla korunuyor. Ancak önceki sürümlerde korumalar zayıftı. Synacktiv
  • WebKit exploit zincirlerinde DYLD loader sıkça PAC bypass hedefi olmuştur. Slaytlar birçok PAC bypass’ın DYLD loader’ı (relocation, interposer hook’lar yoluyla) hedef aldığını belirtir. Synacktiv

2.4 NSPredicate / NSExpression / ObjC / SLOP

  • Userland exploit zincirlerinde Objective-C runtime metodları (NSPredicate, NSExpression, NSInvocation) kontrol çağrılarını belli belirsiz şekilde taşımak için kullanılır.
  • PAC öncesi eski iOS sürümlerinde bir exploit fake NSInvocation objeleri kullanarak controlled memory üzerinde arbitrary selector çağrıları yapabiliyordu. PAC ile bunun için değişiklikler gerekli oldu. Ancak SLOP (SeLector Oriented Programming) tekniği PAC altında da genişletildi. Project Zero
  • Orijinal SLOP tekniği, sahte invocation’lar oluşturarak ObjC çağrılarını zincirlemeyi sağlıyordu; bypass, ISA veya selector pointer’larının bazen tam olarak PAC ile korunmamasına dayanıyordu. Project Zero
  • Pointer authentication kısmen uygulandığı ortamlarda, methodlar / selector’lar / target pointer’lar her zaman PAC korumalı olmayabilir; bu da bypass için fırsat verir.

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>
Bir buffer overflow, stack üzerinde bir return adresini ezerek yazar. Saldırgan hedef gadget adresini yazar ancak doğru PAC'ı hesaplayamaz. Fonksiyon döndüğünde, CPU’nun `AUTIA` instruksyonu PAC uyuşmazlığı nedeniyle hata verir. Zincir başarısız olur.
Project Zero’nun A12 (iPhone XS) üzerindeki analizi, Apple’ın PAC’ını nasıl kullandığını ve eğer bir saldırganın bellek okuma/yazma primitive’i varsa PAC’ları sahtelemeye yönelik yöntemleri gösterdi.
</details>


### 9. **Branch Target Identification (BTI)**
**ARMv8.5 ile tanıtıldı (daha yeni donanım)**
BTI, **dolaylı branch hedeflerini** kontrol eden bir donanım özelliğidir: `blr` veya dolaylı call/jump'lar yürütülürken hedef, bir **BTI landing pad** ile başlamalıdır (`BTI j` veya `BTI c`). Landing pad içermeyen gadget adreslerine atlamak bir istisna (exception) tetikler.

LLVM’nin uygulama notları BTI instruksyonlarının üç varyantını ve bunların branch türlerine nasıl eşlendiğini not eder.

| BTI Variant | Neye izin verir (hangi branch türleri) | Tipik yerleşim / kullanım durumu |
|-------------|----------------------------------------|-------------------------------|
| **BTI C** | *call*-stil dolaylı branch hedefleri (ör. `BLR`, veya X16/X17 kullanılarak `BR`) | Dolaylı çağrılabilecek fonksiyonların girişine konur |
| **BTI J** | *jump*-stil branch hedefleri (ör. tail call için kullanılan `BR`) | jump tabloları veya tail-call ile erişilebilen blokların başına konur |
| **BTI JC** | Hem C hem J olarak davranır | Hem call hem jump branch’leri tarafından hedef alınabilir |

- Branch target enforcement ile derlenen kodda, derleyiciler her geçerli dolaylı-branch hedefinde (fonksiyon başlangıçları veya jump’larla erişilebilen bloklar) bir BTI instruksyonu (C, J veya JC) ekler, böylece dolaylı branch’ler sadece bu yerlere başarılı olabilir.
- **Direkt branch / call** (yani sabit-adresli `B`, `BL`) BTI tarafından **kısıtlanmaz**. Varsayım, kod sayfalarının güvenilir olduğu ve saldırganın bunları değiştiremeyeceği yönündedir (dolayısıyla direkt branch’ler güvenlidir).
- Ayrıca, **RET / return** instruksyonları genellikle BTI ile kısıtlanmaz çünkü return adresleri PAC veya return signing mekanizmalarıyla korunur.

#### Mekanizma ve uygulanma

- CPU, “guarded / BTI-enabled” olarak işaretlenmiş bir sayfada bir **dolaylı branch (BLR / BR)** decode ettiğinde, hedef adresin ilk instruksyonunun geçerli bir BTI (izin verilen C, J veya JC) olup olmadığını kontrol eder. Eğer değilse, bir **Branch Target Exception** oluşur.
- BTI instruksyonunun encoding’i, önceki ARM sürümlerinde NOP olarak ayrılmış opcode’ları yeniden kullanacak şekilde tasarlanmıştır. Bu yüzden BTI etkin iken oluşturulmuş ikili dosyalar geriye dönük uyumludur: BTI desteklemeyen donanımda bu instruksyonlar NOP gibi davranır.
- BTI ekleyen derleyici pass’ları yalnızca gerekli yerlere BTI ekler: dolaylı olarak çağrılabilecek fonksiyonlar veya jump’larla hedeflenebilen temel bloklar.
- Bazı yamalar ve LLVM kodu, BTI’nin *tüm* temel bloklara eklenmediğini — yalnızca potansiyel branch hedeflerine (ör. switch / jump tablolarından gelenler) eklendiğini gösterir.

#### BTI + PAC sinerjisi

PAC, pointer değerini (kaynağı) korur — dolaylı çağrıların / return’lerin zincirinin kurcalanmadığını garanti eder.

BTI ise geçerli bir pointer olsa bile sadece doğru şekilde işaretlenmiş giriş noktalarına yönlendirilmesini sağlar.

Birlikte, bir saldırganın hem doğru PAC’a sahip geçerli bir pointer’a hem de hedefin orada bir BTI taşımasına ihtiyacı olur. Bu, exploit gadget’ları oluşturma zorluğunu artırır.

#### Örnek


<details>
<summary>Example</summary>
Bir exploit, `0xABCDEF` adresindeki ve `BTI c` ile başlamayan bir gadget’a pivot yapmaya çalışır. CPU, `blr x0` yürütürken hedefi kontrol eder ve instruksyon hizalaması geçerli bir landing pad içermediği için hata verir. Böylece birçok gadget, BTI öneki içermediği sürece kullanılamaz hale gelir.
</details>


### 10. **Privileged Access Never (PAN) & Privileged Execute Never (PXN)**
**Daha yeni ARMv8 uzantılarında / iOS desteğinde tanıtıldı (sertleştirilmiş kernel için)**

#### PAN (Privileged Access Never)

- **PAN**, **ARMv8.1-A** ile tanıtılan ve **ayrıcalıklı kodun** (EL1 veya EL2) **user-accessible (EL0)** olarak işaretlenmiş belleği **okumasını veya yazmasını** engelleyen bir özelliktir; ta ki PAN açıkça devre dışı bırakılana kadar.
- Fikir: kernel kandırılsa veya ele geçirilse bile, user-space pointer’larını keyfi olarak dereference edemez; PAN önce temizlenmeden bu erişimlere izin verilmez. Böylece **`ret2usr`** tarzı exploit’lerin veya kullanıcı kontrollü buffer’ların kötüye kullanılmasının riski azaltılır.
- PAN etkin olduğunda (PSTATE.PAN = 1), “EL0 tarafından erişilebilir” olarak görülen sanal adreslere erişen herhangi bir ayrıcalıklı load/store instruksyonu bir **permission fault** tetikler.
- Kernel, meşru olarak user-space belleğe erişmesi gerektiğinde (ör. kullanıcı buffer’larına veri kopyalama), PAN’ı **geçici olarak devre dışı bırakmak** zorundadır (veya “unprivileged load/store” instruksyonlarını kullanmak).
- Linux’ta ARM64 için PAN desteği yaklaşık 2015 civarında eklendi: kernel yamaları özellik tespiti ekledi ve `get_user` / `put_user` vb. fonksiyonları PAN’ı çevreleyen varyantlarla değiştirdi.

**Önemli nüans / sınırlama / bug**
- Siguza ve diğerlerinin belirttiği gibi, ARM spesifikasyonundaki bir hata (veya belirsiz davranış) PAN’ın, **sadece execute-permission’a sahip user mapping’lerin** (`--x`) **PAN’ı tetiklemeyebileceği** anlamına gelir. Başka bir deyişle, bir user sayfası executable olarak işaretlenmiş ama read izni yoksa, kernel’in okuma denemesi PAN tarafından engellenmeyebilir çünkü mimari “EL0 tarafından erişilebilir” olmayı readable izin gerektiren bir durum olarak değerlendirebilir. Bu, belirli konfigürasyonlarda PAN için bir bypass’a yol açar.
- Bu yüzden, eğer iOS / XNU execute-only user sayfalarına izin veriyorsa (bazı JIT veya code-cache düzenlemelerinde olduğu gibi), kernel PAN etkin olsa bile bu sayfalardan kazara okuyabilir. Bu bazı ARMv8+ sistemlerinde bilinen ince bir istismar alanıdır.

#### PXN (Privileged eXecute Never)

- **PXN**, sayfa tablo girdilerinde (leaf veya block entry’lerde) bulunan ve sayfanın **ayrıcalıklı modda yürütülemeyeceğini** belirten bir flag’tir (yani EL1’in oradan yürütme yapmasını engeller).
- PXN, kernel’in (veya herhangi bir ayrıcalıklı kodun) kontrol saptırıldığında user-space sayfalarından talimatları atlamasını veya yürütmesini engeller. Etkisiyle, kernel seviyesinde kontrol akışının user belleğe yönlendirilmesini durdurur.
- PAN ile birleştiğinde:
1. Kernel varsayılan olarak kullanıcı verisini okuyamaz/yazamaz (PAN)
2. Kernel kullanıcı kodunu çalıştıramaz (PXN)
- ARMv8 sayfa tablo formatında, leaf entry’lerin attribute bitleri içinde `PXN` biti (ve ayrıca `UXN` unprivileged execute-never için) bulunur.

Dolayısıyla kernel’in bozulmuş bir function pointer’ı user belleğe işaret etse ve oraya branch etmeye çalışsa, PXN biti bir hata oluşturur.

#### Bellek-izin modeli & PAN ve PXN’in sayfa tablosu bitlerine nasıl eşlendiği

PAN / PXN’in nasıl çalıştığını anlamak için ARM’ın çeviri ve izin modeline bakmak gerekir (basitleştirilmiş):

- Her sayfa veya block girdisinin, erişim izinleri için **AP[2:1]** ve execute-never kısıtlamaları için **UXN / PXN** bitleri gibi attribute alanları vardır.
- PSTATE.PAN 1 olduğunda, donanım değiştirilmiş semantiği uygular: EL0 tarafından erişilebilir olarak işaretlenmiş sayfalara ayrıcalıklı erişimler engellenir (fault).
- Bahsedilen hata nedeniyle, sadece executable (okunabilir olmayan) olarak işaretlenmiş sayfalar bazı uygulamalarda “EL0 tarafından erişilebilir” sayılmayabilir ve böylece PAN’ı atlatabilir.
- Bir sayfanın PXN biti set edilmişse, instruction fetch daha yüksek bir ayrıcalık seviyesinden gelse bile yürütme yasaktır.

#### Sertleştirilmiş bir kernel’de PAN / PXN’in kullanımı (ör. iOS / XNU)

Sertleştirilmiş bir kernel tasarımında (Apple’ın kullanabileceği gibi):

- Kernel varsayılan olarak PAN’ı etkinleştirir (böylece ayrıcalıklı kod kısıtlanır).
- Kullanıcı buffer’larını meşru olarak okumayı/yazmayı gerektiren yollar (ör. syscall buffer kopyası, I/O, read/write user pointer) PAN’ı geçici olarak **devre dışı bırakır** veya bu erişimi sağlamak için özel instruksyonlar kullanır.
- Kullanıcı verisine erişim tamamlandıktan sonra PAN yeniden etkinleştirilmelidir.
- PXN sayfa tabloları aracılığıyla uygulanır: kullanıcı sayfalarının PXN = 1 olarak ayarlanması (böylece kernel bunları çalıştıramaz), kernel sayfalarının PXN içermemesi (böylece kernel kodu çalıştırılabilir).
- Kernel, kontrol akışının user bellek bölgelerine yönlenmesine neden olabilecek hiçbir kod yolunun olmadığından emin olmalıdır — aksi halde “user kontrollü shellcode’a atlama”ya dayanan exploit zincirleri engellenir.

Execute-only sayfalar yoluyla PAN bypass’ı nedeniyle, gerçek bir sistemde Apple bu tür execute-only user sayfalarını devre dışı bırakabilir veya spesifikasyon zayıflığını yamayla giderebilir.


#### Saldırı yüzeyleri, bypass’lar ve mitigasyonlar

- **Execute-only sayfalar aracılığıyla PAN bypass**: belirtildiği gibi, spesifikasyon bir boşluk bırakır: sadece execute (okuma izni olmayan) olarak işaretlenmiş user sayfalar bazı implementasyonlarda “EL0 tarafından erişilebilir” sayılmayabilir; böylece PAN kernel okumalarını engellemez. Bu, saldırgan için “execute-only” bölümler aracılığıyla veri besleme gibi sıra dışı yollar sağlar.
- **Zamansal pencere (temporal window) istismarı**: eğer kernel PAN’ı gerekli olandan daha uzun süre devre dışı bırakırsa, bir yarış durumu veya kötü amaçlı yol bu pencereyi kullanarak istenmeyen user bellek erişimleri gerçekleştirebilir.
- **Yeniden etkinleştirmeyi unutma**: eğer kod yolları PAN’ı yeniden etkinleştirmeyi unutursa, sonraki kernel işlemleri yanlışlıkla user belleğine erişebilir.
- **PXN yanlış yapılandırması**: eğer sayfa tabloları user sayfalarında PXN set etmezse veya user kod sayfalarını yanlış map’lerse, kernel user-space kodunu çalıştırmaya zorlanabilir.
- **Spekülasyon / yan kanallar**: spekülatif atlamalara benzer şekilde, PAN / PXN kontrollerinin geçici olarak ihlaline yol açan mikro-mimari yan-etkiler olabilir (ancak bu tür saldırılar CPU tasarımına güçlü şekilde bağımlıdır).
- **Karmaşık etkileşimler**: JIT, shared memory, just-in-time code bölgeleri gibi gelişmiş özelliklerde, kernel bazı user-mapped bölgelerde belirli erişim veya yürütme izinlerine ince kontrollere ihtiyaç duyar; PAN/PXN kısıtları altında bunları güvenli tasarlamak zordur.


#### Örnek

<details>
<summary>Code Example</summary>
Kullanıcı bellek erişimi etrafında PAN’ın etkinleştirilmesi/devre dışı bırakılmasını ve bir hatanın nasıl oluşabileceğini gösteren açıklayıcı pseudo-assembly dizileri burada gösterilmiştir.
</details>

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

Eğer kernel o kullanıcı sayfasında PXN'i **ayarlamamış olsaydı**, o branch başarılı olabilir — bu güvensiz olur.

Kernel kullanıcı bellek erişiminden sonra PAN'ı yeniden etkinleştirmeyi unutursa, sonraki kernel mantığının yanlışlıkla rastgele kullanıcı belleğini okuyup/yazabileceği bir pencere açılır.

Eğer kullanıcı işaretçisi yalnızca execute iznine (okuma/yazma yok) sahip bir execute-only sayfaya işaret ediyorsa, PAN spesifikasyonu hatası altında, `ldr W2, [X1]` PAN etkin olsa bile **hata vermeyebilir**, uygulamaya bağlı olarak bir bypass exploit'e izin verebilir.

</details>

<details>
<summary>Örnek</summary>
Bir kernel açığı, kullanıcı tarafından sağlanan bir function pointer'ı alıp kernel bağlamında çağırmaya çalışır (örn. `call user_buffer`). PAN/PXN altında bu işlem yasaklanır veya hata verir.
</details>

---

### 11. **Top Byte Ignore (TBI) / Pointer Tagging**
**Introduced in ARMv8.5 / newer (or optional extension)**
TBI, 64-bit bir işaretçinin en üst baytının adres çevriminde göz ardı edilmesi anlamına gelir. Bu, OS veya donanımın işaretçinin en üst baytına **tag bitleri** gömmesine izin verir, gerçek adresi etkilemeden.

- TBI, **Top Byte Ignore** anlamına gelir (bazen *Address Tagging* olarak da adlandırılır). Bu, donanım özelliğidir (birçok ARMv8+ uygulamasında mevcut) ve **64-bit bir işaretçinin en yüksek 8 bitini** (bitler 63:56) adres çevirme sırasında yok sayar (maskeler). Bu, load/store/instruction fetch sırasında gerçekleşir.
- Etki olarak, CPU bir işaretçi `0xTTxxxx_xxxx_xxxx` (burada `TT` = en üst bayt) adres çevirme açısından `0x00xxxx_xxxx_xxxx` olarak ele alır; en üst baytı yok sayar (maskeler). En üst bayt, yazılım tarafından **metadata / tag bitleri** saklamak için kullanılabilir.
- Bu, yazılıma her işaretçiye bir bayt tag eklemek için “ücretsiz” in-band alan sağlar; işaretçinin hangi bellek konumuna referans ettiği değişmez.
- Mimari, load/store ve instruction fetch işlemlerinde işaretçinin en üst baytının maskelendiğini (yani tag'in çıkarıldığını) garanti eder, böylece gerçek bellek erişimi yapılmadan önce tag yok sayılır.

Böylece TBI, **mantıksal işaretçi**yi (işaretçi + tag) bellek operasyonlarında kullanılan **fiziksel adresten** ayırır.

#### Neden TBI: Kullanım durumları ve motivasyon

- **Pointer tagging / metadata**: En üst baytta ekstra metadata (ör. nesne türü, versiyon, bounds, bütünlük tagleri) saklayabilirsiniz. İşaretçi daha sonra kullanıldığında, tag donanım seviyesinde yok sayıldığından, bellek erişimi için elle strip etmenize gerek kalmaz.
- **Memory tagging / MTE (Memory Tagging Extension)**: TBI, MTE'nin üzerine inşa ettiği temel donanım mekanizmasıdır. ARMv8.5'te, **Memory Tagging Extension** işaretçinin bitleri 59:56'yı mantıksal tag olarak kullanır ve bunu bellekte saklanan bir **allocation tag** ile karşılaştırır.
- **Geliştirilmiş güvenlik & bütünlük**: TBI'yi pointer authentication (PAC) veya runtime kontrollerle birleştirerek, sadece işaretçi değerinin değil aynı zamanda tag'in de doğru olmasını zorlayabilirsiniz. Bir saldırgan işaretçiyi doğru tag olmadan overwrite ederse tag mismatch oluşur.
- **Uyumluluk**: TBI isteğe bağlıdır ve tag bitleri donanım tarafından yok sayıldığından, mevcut taglenmemiş kod normal şekilde çalışmaya devam eder. Tag bitleri eski kod için efektif olarak “önemsiz” bitler haline gelir.

#### Örnek
<details>
<summary>Örnek</summary>
Bir function pointer en üst baytında bir tag içeriyordu (ör. `0xAA`). Bir exploit işaretçinin düşük bitlerini overwrite etti ama tag'i dikkate almadı; kernel doğruladığında veya sanitize ettiğinde işaretçi başarısız olur veya reddedilir.
</details>

---

### 12. **Page Protection Layer (PPL)**
**Introduced in late iOS / modern hardware (iOS ~17 / Apple silicon / high-end models)** (some reports show PPL circa macOS / Apple silicon, but Apple is bringing analogous protections to iOS)

- PPL, **kernel içinde intra-kernel koruma sınırı** olarak tasarlanmıştır: kernel (EL1) ele geçirilmiş ve okuma/yazma yetkisine sahip olsa bile, **belirli hassas sayfaları serbestçe değiştirememelidir** (özellikle page table'lar, code-signing metadata, kernel kod sayfaları, entitlements, trust cache'ler vb.).
- Bu, etkili olarak bir **“kernel içinde kernel”** yaratır — korunmuş sayfaları yalnızca değiştirebilen, daha küçük, güvenilir bir bileşen (PPL) vardır. Diğer kernel kodu değişiklik yapmak için PPL rutinlerini çağırmak zorundadır.
- Bu, kernel exploitleri için saldırı yüzeyini azaltır: kernel modunda tam arbitrary R/W/execute elde edilmiş olsa bile, exploit kodunun kritik yapıları değiştirebilmek için PPL alanına girmesi (veya PPL'i atlatması) gerekir.
- Yeni Apple silicon (A15+ / M2+) üzerinde Apple, birçok durumda page-table koruması için PPL'in yerini alan **SPTM (Secure Page Table Monitor)**'a geçiş yapıyor.

Aşağıda PPL'in nasıl çalıştığına dair kamuya açık analizlere dayalı inançlar yer almaktadır:

#### APRR / permission routing kullanımı (APRR = Access Permission ReRouting)

- Apple donanımı, sayfa tablo girdilerinin (PTE'lerin) tam izin bitleri yerine küçük indeksler içermesine izin veren ve bu indeksleri APRR kayıtları aracılığıyla gerçek izinlere eşleyen bir mekanizma olan **APRR (Access Permission ReRouting)** kullanır. Bu, domain başına izinlerin dinamik yeniden eşlenmesine izin verir.
- PPL, APRR'den yararlanarak kernel bağlamı içinde ayrıcalıkları ayırır: sadece PPL domain'inin indeks ile etkili izinler arasındaki eşlemeyi güncellemesine izin verilir. Yani non-PPL kernel kodu bir PTE yazdığında veya izin bitlerini çevirmeye çalıştığında, APRR mantığı bunu engeller (veya salt okunur eşlem uygular).
- PPL kodu kendisi kısıtlı bir bölgede (örn. `__PPLTEXT`) çalışır; bu bölge normalde giriş kapıları (entry gates) geçici olarak izin verene kadar executable veya writable değildir. Kernel, PPL rutinlerini çağırarak hassas işlemleri gerçekleştirir.

#### Giriş / Çıkış Kapısı

- Kernel korunmuş bir sayfayı değiştirmesi gerektiğinde (örn. bir kernel kod sayfasının izinlerini değiştirmek ya da page table'ları değiştirmek), bir **PPL wrapper** rutinini çağırır; bu rutin doğrulama yapar ve sonra PPL domain'ine geçiş yapar. Bu domain dışında korunmuş sayfalar esasen ana kernel tarafından yazılamaz veya değiştirilemez.
- PPL girişinde, APRR eşlemeleri ayarlanır, böylece PPL bölgesindeki bellek sayfaları PPL içinde **çalıştırılabilir & yazılabilir** olur. Çıkışta bunlar tekrar salt okunur / yazılamaz hale döndürülür. Bu, yalnızca iyi denetlenmiş PPL rutinlerinin korunmuş sayfalara yazabilmesini sağlar.
- PPL dışında, kernel kodunun bu korunmuş sayfalara yazma girişimleri hataya (permission denied) yol açar çünkü o kod domain'i için APRR eşlemesi yazmaya izin vermez.

#### Korunan sayfa kategorileri

PPL'in tipik olarak koruduğu sayfalar şunları içerir:

- Page table yapıları (çeviri tablo girdileri, mapping metadata)
- Kernel kod sayfaları, özellikle kritik mantığı içerenler
- Code-sign metadata (trust cache'ler, imza blob'ları)
- Entitlement tabloları, imza uygulama tabloları
- Bir yama ile imza kontrollerini veya kimlik bilgisi manipülasyonunu atlamaya izin verecek diğer yüksek değerli kernel yapıları

Fikir, kernel belleği tam kontrol edilse bile, saldırganın bu sayfaları basitçe yamalayıp tekrar yazamaması; aksi takdirde PPL rutinlerini de bozması veya PPL'i atlatması gerektiğidir.


#### Bilinen Bypasses & Vulnerabilities

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

- Project Zero tarafından yayımlanan bir writeup, **stale TLB entries** içeren bir bypass'ı anlatır.
- Fikir:

1. İki fiziksel sayfa A ve B ayırın, bunları PPL sayfaları olarak işaretleyin (yani korunmuş).
2. L3 çeviri tablo sayfaları A ve B'den gelen iki sanal adres P ve Q eşleyin.
3. Bir thread'i Q'ya sürekli erişecek şekilde döndürün, TLB girdisini canlı tutarak.
4. `pmap_remove_options()`'u çağırarak P'den başlayan map'leri kaldırın; bir bug yüzünden kod yanlışlıkla hem P hem de Q için TTE'leri kaldırır, fakat sadece P için TLB girdisini invalid eder, Q'nun stale girdisini canlı bırakır.
5. B'yi (Q'nun tablosu) yeniden kullanarak rasgele belleği (örn. PPL korunmuş sayfalar) map edin. Çünkü stale TLB girdisi hâlâ Q'nun eski mapping'ini map ettiğinden, o mapping o context için geçerli kalır.
6. Bununla, saldırgan PPL korumalı sayfaların writable mapping'ini PPL arayüzünü kullanmadan yerleştirebilir.

- Bu exploit fiziksel mapping ve TLB davranışı üzerinde hassas kontrol gerektirdi. Bu, TLB invalidasyonları ve mapping tutarlılığı konusunda güvenlik sınırının son derece dikkatli olması gerektiğini gösterir.

- Project Zero, bunun gibi bypass'ların ince ve nadir olduğunu, ancak karmaşık sistemlerde mümkün olduğunu belirtti. Yine de PPL'i sağlam bir mitigasyon olarak görüyorlar.

2. **Diğer potansiyel tehlikeler & kısıtlar**

- Eğer bir kernel exploit doğrudan PPL rutinlerine giriş yapabilirse (PPL wrapper'larını çağırarak), kısıtlamaları atlayabilir. Bu yüzden argüman doğrulaması kritik önem taşır.
- PPL kodunun kendisindeki hatalar (örn. aritmetik taşma, boundary kontrolleri) PPL içinde out-of-bounds değişikliklere izin verebilir. Project Zero, `pmap_remove_options_internal()`'deki böyle bir hatanın bypass'ta kullanıldığını gözlemledi.
- PPL sınırı donanım uygulaması (APRR, memory controller) ile sıkı şekilde bağlıdır, bu yüzden uygulanışının gücü donanımın sağlamlığı kadar iyidir.



#### Örnek
<details>
<summary>Kod Örneği</summary>
İşte bir kernelin korunmuş sayfaları değiştirmek için PPL'e nasıl çağrı yapabileceğini gösteren basitleştirilmiş pseudocode / mantık:
</details>
```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

Çekirdek birçok normal işlemi yapabilir, ancak yalnızca ppl_call_* rutinleri aracılığıyla korumalı eşlemeleri değiştirebilir veya kodu yama yapabilir.

Örnek Bir kernel exploit, entitlement tablosunu üzerine yazmaya çalışır veya bir kernel signature blob'unu değiştirerek code-sign zorlamasını devre dışı bırakır. Çünkü o sayfa PPL-korumalıdır, yazma PPL arayüzü üzerinden gitmedikçe engellenir. Yani kernel kod yürütmesi olsa bile code-sign kısıtlamalarını atlayamaz veya credential verilerini rastgele değiştiremezsiniz. iOS 17+ üzerinde bazı cihazlar PPL tarafından yönetilen sayfaları daha da izole etmek için SPTM kullanır.

PPL → SPTM / İkame / Gelecek

  • Apple’ın modern SoC’larında (A15 veya sonrası, M2 veya sonrası), Apple SPTM (Secure Page Table Monitor) destekler; bu, sayfa tablosu korumaları için PPL’in yerini alır.
  • Apple belgelerinde şöyle diyor: “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.”
  • SPTM mimarisi muhtemelen daha fazla politika uygulamasını kernel kontrolü dışındaki daha yüksek ayrıcalıklı bir monitöre kaydırır ve güven sınırını daha da küçültür.

MTE | EMTE | MIE

EMTE’nin Apple’ın MIE düzeninde nasıl çalıştığına dair üst düzey açıklama:

  1. Tag assignment
  • Bellek ayrıldığında (ör. kernel veya user space içinde secure allocator’lar aracılığıyla), o bloğa bir secret tag atanır.
  • Kullanıcıya veya kernela dönen pointer, yüksek biti içinde o tag’i içerir (TBI / top byte ignore mekanizmalarını kullanarak).
  1. Tag checking on access
  • Bir pointer kullanılarak load veya store yürütüldüğünde, donanım pointer’ın tag’inin bellek bloğunun tag’i (allocation tag) ile eşleşip eşleşmediğini kontrol eder. Uyuşmazlık varsa hemen fault verir (çünkü synchronous).
  • Synchronous olduğu için “gecikmeli tespit” penceresi yoktur.
  1. Retagging on free / reuse
  • Bellek serbest bırakıldığında, allocator bloğun tag’ini değiştirir (böylece eski tag’lere sahip pointer’lar artık eşleşmez).
  • Bir use-after-free pointer’ı bu yüzden eski bir tag’e sahip olur ve erişildiğinde uyuşmazlık oluşur.
  1. Neighbor-tag differentiation to catch overflows
  • Komşu ayrımlara farklı tag’ler verilir. Eğer bir buffer overflow komşu belleğe taşarsa, tag uyuşmazlığı fault’a neden olur.
  • Bu, sınırı geçen küçük overflow’ları yakalamada özellikle etkilidir.
  1. Tag confidentiality enforcement
  • Apple, tag değerlerinin leak olmasını engellemelidir (çünkü saldırgan tag’i öğrenirse doğru tag’lere sahip pointer’lar üretebilir).
  • Tag bitlerinin yan kanal sızıntılarını önlemek için microarchitectural / speculative kontroller gibi korumalar içerirler.
  1. Kernel and user-space integration
  • Apple EMTE’yi sadece user-space’te değil aynı zamanda kernel / OS-critical bileşenlerde de kullanır (kernenli bellek bozulmalarına karşı korumak için).
  • Donanım/OS, kernel user space adına çalışırken bile tag kurallarının uygulanmasını sağlar.
Örnek ``` 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>

#### Sınırlamalar ve zorluklar

- **Intrablock overflows**: Eğer overflow aynı allocation içinde kalıyorsa (boundary’i aşmıyor) ve tag aynıysa, tag mismatch bunu yakalamıyor.
- **Tag width limitation**: Tag için sadece birkaç bit (örn. 4 bit veya küçük bir domain) kullanılabiliyor—sınırlı isim alanı.
- **Side-channel leaks**: Eğer tag bitleri cache / speculative execution gibi yollarla leaked olabiliyorsa, saldırgan geçerli tagleri öğrenip bypass yapabilir. Apple’ın tag confidentiality enforcement bu durumu hafifletmeyi amaçlıyor.
- **Performance overhead**: Her load/store için yapılan tag check’leri maliyet ekler; Apple donanımı optimize ederek overhead’i düşürmeli.
- **Compatibility & fallback**: Eski donanımda veya EMTE’yi desteklemeyen parçalarda fallback olmalı. Apple, MIE’nin yalnızca destekleyen cihazlarda etkin olduğunu iddia ediyor.
- **Complex allocator logic**: Allocator tag’leri, retagging, hizalama boundary’leri yönetmeli ve tag çakışmalarından kaçınmalı. Allocator mantığındaki hatalar yeni güvenlik açıkları oluşturabilir.
- **Mixed memory / hybrid areas**: Bazı bellek alanları untagged (legacy) kalabilir, bu da birlikte çalışmayı zorlaştırır.
- **Speculative / transient attacks**: Birçok mikro-mimari korumada olduğu gibi, speculative execution veya micro-op füzyonları check’leri geçici olarak bypass edebilir veya tag bitlerini leak edebilir.
- **Limited to supported regions**: Apple EMTE’yi yalnızca seçilmiş, yüksek riskli alanlarda (kernel, security-critical subsystems) uygulayabilir, evrensel olmayabilir.



---

## Standart MTE’ye göre temel iyileştirmeler / farklar

Apple’ın vurguladığı geliştirmeler ve değişiklikler şunlar:

| Feature | Original MTE | EMTE (Apple’s enhanced) / MIE |
|---|---|---|
| **Check mode** | Supports synchronous and asynchronous modes. In async, tag mismatches are reported later (delayed)| Apple insists on **synchronous mode** by default—tag mismatches are caught immediately, no delay/race windows allowed.|
| **Coverage of non-tagged memory** | Accesses to non-tagged memory (e.g. globals) may bypass checks in some implementations | EMTE requires that accesses from a tagged region to non-tagged memory also validate tag knowledge, making it harder to bypass by mixing allocations.|
| **Tag confidentiality / secrecy** | Tags might be observable or leaked via side channels | Apple adds **Tag Confidentiality Enforcement**, which attempts to prevent leakage of tag values (via speculative side-channels etc.).|
| **Allocator integration & retagging** | MTE leaves much of allocator logic to software | Apple’s secure typed allocators (kalloc_type, xzone malloc, etc.) integrate with EMTE: when memory is allocated or freed, tags are managed at fine granularity.|
| **Always-on by default** | In many platforms, MTE is optional or off by default | Apple enables EMTE / MIE by default on supported hardware (e.g. iPhone 17 / A19) for kernel and many user processes.|

Apple donanım ve yazılım yığını üzerinde tam kontrol sahibi olduğu için, EMTE’yi sıkı şekilde uygulayabilir, performans tuzaklarından kaçınabilir ve side-channel açıklarını kapatabilir.

---

## EMTE pratikte nasıl çalışır (Apple / MIE)

Aşağıda Apple’ın MIE düzeninde EMTE’nin nasıl çalıştığına dair daha yüksek seviyeli bir açıklama var:

1. **Tag assignment**
- Bellek allocate edildiğinde (örn. kernel veya user space’de secure allocators aracılığıyla), o blok için bir **secret tag** atanır.
- Kullanıcıya veya kernel’e döndürülen pointer, yüksek bitlerinde o tag’i içerir (TBI / top byte ignore mekanizmalarını kullanarak).

2. **Tag checking on access**
- Bir pointer ile load veya store çalıştırıldığında, donanım pointer’ın tag’inin belleğin blok tag’i (allocation tag) ile eşleşip eşleşmediğini kontrol eder. Eğer mismatch varsa, hemen fault oluşur (çünkü synchronous).
- Senkron olduğu için “gecikmeli tespit” penceresi yoktur.

3. **Retagging on free / reuse**
- Bellek free edildiğinde, allocator bloğun tag’ini değiştirir (böylece eski pointer’lar artık eşleşmez).
- Use-after-free durumunda pointer’ın tag’i eski kalacağından erişimde mismatch oluşur.

4. **Neighbor-tag differentiation to catch overflows**
- Komşu allocation’lara farklı tag’ler verilir. Eğer bir buffer overflow komşu belleğe sızarsa, tag mismatch fault tetikler.
- Bu, boundary’yi aşan küçük overflow’ları yakalamada özellikle etkilidir.

5. **Tag confidentiality enforcement**
- Apple tag değerlerinin leak olmasını engellemek zorunda (çünkü saldırgan tag’i öğrenirse doğru tag’e sahip pointer’lar oluşturabilir).
- Spekülatif side-channel’lar vb. yoluyla tag bitlerinin leak edilmesini önlemeye yönelik korumalar eklerler.

6. **Kernel and user-space integration**
- Apple EMTE’yi yalnızca user-space’de değil, kernel / OS-criticall komponentlerde de kullanır (kernel’i bellek bozulmalarına karşı korumak için).
- Donanım/OS, tag kurallarının kullanıcı adına kernel çalışırken bile uygulanmasını garanti eder.

EMTE, MIE’ye entegre olduğu için Apple ana saldırı yüzeylerinde synchronous modda EMTE kullanır; bunu isteğe bağlı veya sadece debug modu olarak bırakmaz.



---

## XNU’da exception handling

Bir **exception** oluştuğunda (örn. `EXC_BAD_ACCESS`, `EXC_BAD_INSTRUCTION`, `EXC_CRASH`, `EXC_ARM_PAC`, vb.), XNU kernel’in **Mach layer**’ı bunu UNIX tarzı bir **signal**’a (ör. `SIGSEGV`, `SIGBUS`, `SIGILL`, ...) dönüşmeden önce yakalamaktan sorumludur.

Bu süreç, user space’e ulaşmadan veya BSD signal’e çevrilmeden önce birden çok katmanda exception propagasyonu ve handling içerir.


### Exception Flow (Yüksek Seviye)

1.  **CPU synchronous exception tetikler** (örn. geçersiz pointer dereference, PAC failure, illegal instruction, vb.).

2.  **Low-level trap handler** çalışır (`trap.c`, `exception.c` in XNU source).

3.  Trap handler **`exception_triage()`**’yi çağırır; bu Mach exception handling’in çekirdeğidir.

4.  `exception_triage()` exception’ın nasıl yönlendirileceğine karar verir:

-   Önce **thread'in exception port**'una.
-   Sonra **task'ın exception port**'una.
-   Ardından **host'ın exception port**'una (genelde `launchd` veya `ReportCrash`).

Eğer bu portların hiçbiri exception’ı handle etmezse, kernel şunları yapabilir:

-   **Bunu bir BSD signal’e çevirir** (user-space process’ler için).
-   **Panic** oluşturur (kernel-space exception’ları için).


### Temel Fonksiyon: `exception_triage()`

`exception_triage()` Mach exception’larını, bunları handle eden bir tane bulunana kadar veya nihai olarak fatal olana kadar yukarıya doğru yönlendirir. Bu fonksiyon `osfmk/kern/exception.c` içinde tanımlıdır.
```c
void exception_triage(exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t codeCnt);

Tipik Çağrı Akışı:

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

Eğer bunların hepsi başarısız olursa → bsd_exception() tarafından işlenir → SIGSEGV gibi bir sinyale dönüştürülür.

İstisna Portları

Her Mach nesnesi (thread, task, host) istisna mesajlarının gönderildiği istisna portları kaydedebilir.

Bunlar API tarafından tanımlanır:

task_set_exception_ports()
thread_set_exception_ports()
host_set_exception_ports()

Her istisna portunun şunları vardır:

  • Bir mask (almak istediği istisnalar)
  • Bir port name (mesajları almak için Mach portu)
  • Bir behavior (kernelin mesajı nasıl gönderdiği)
  • Bir flavor (hangi thread state’in dahil edileceği)

Debugger’lar ve İstisna İşleme

Bir debugger (ör. LLDB) hedef task veya thread’e genellikle task_set_exception_ports() kullanarak bir istisna portu ayarlar.

Bir istisna oluştuğunda:

  • Mach mesajı debugger sürecine gönderilir.
  • Debugger, istisnayı işlemeye (resume, registerları değiştirme, instruktion atlama) veya işlememeye karar verebilir.
  • Eğer debugger işlemiyorsa, istisna bir sonraki seviyeye yayılır (task → host).

EXC_BAD_ACCESS Akışı

  1. Thread geçersiz bir pointer’ı dereference eder → CPU Data Abort tetikler.

  2. Kernel trap handler exception_triage(EXC_BAD_ACCESS, ...) çağırır.

  3. Mesaj şuraya gönderilir:

  • Thread port → (debugger breakpoint’i yakalayabilir).

  • Eğer debugger görmezden gelirse → Task port → (process-seviyesi handler).

  • Eğer yine görmezden gelinirse → Host port (genellikle ReportCrash).

  1. Eğer kimse işlemiyorsa → bsd_exception() bunu SIGSEGV’e çevirir.

PAC İstisnaları

Pointer Authentication (PAC) başarısız olduğunda (imza uyuşmazlığı), özel bir Mach istisnası yükseltilir:

  • EXC_ARM_PAC (tip)
  • Kodlar detaylar içerebilir (ör. anahtar tipi, pointer tipi).

Eğer binary’de TFRO_PAC_EXC_FATAL flag’i varsa, kernel PAC hatalarını fatal olarak ele alır ve debugger yakalamalarını atlar. Bu, saldırganların debugger kullanarak PAC kontrollerini atlamasını önlemek için yapılmıştır ve genellikle platform ikili dosyaları için etkinleştirilir.

Yazılım Breakpoint’leri

Yazılım breakpoint’i (int3 on x86, brk on ARM64) kasıtlı bir hata oluşturarak uygulanır.
Debugger bunu istisna portu üzerinden yakalar:

  • Instruction pointer veya belleği değiştirir.
  • Orijinal instruktion’ı geri yükler.
  • Çalışmaya devam ettirir.

Aynı mekanizma bir PAC istisnasını “yakalamanıza” da olanak verir — ta ki TFRO_PAC_EXC_FATAL ayarlı olmadığı sürece; o ayar varsa istisna debugger’a hiç ulaşmaz.

BSD Sinyallerine Dönüşüm

Hiçbir handler istisnayı kabul etmezse:

  • Kernel task_exception_notify() → bsd_exception() çağırır.

  • Bu, Mach istisnalarını sinyallere eşler:

Mach ExceptionSignal
EXC_BAD_ACCESSSIGSEGV or SIGBUS
EXC_BAD_INSTRUCTIONSIGILL
EXC_ARITHMETICSIGFPE
EXC_SOFTWARESIGTRAP
EXC_BREAKPOINTSIGTRAP
EXC_CRASHSIGKILL
EXC_ARM_PACSIGILL (ölümcül olmayan durumda)

XNU Kaynak Kodunda Önemli Dosyalar

  • osfmk/kern/exception.cexception_triage(), exception_deliver_*()’in ana kısmı.

  • bsd/kern/kern_sig.c → Sinyal teslim mantığı.

  • osfmk/arm64/trap.c → Düşük seviyeli trap handler’ları.

  • osfmk/mach/exc.h → İstisna kodları ve yapıları.

  • osfmk/kern/task.c → Task istisna portu kurulumu.


Eski Kernel Heap (Pre-iOS 15 / Pre-A12 dönemi)

Kernel, sabit boyutlu “zone“lara ayrılmış bir zone allocator (kalloc) kullanıyordu.
Her zone sadece tek bir boyut sınıfındaki tahsisleri depolardı.

Ekran görüntüsünden:

Zone NameElement SizeExample Use
default.kalloc.1616 bytesÇok küçük kernel yapıları, pointer’lar.
default.kalloc.3232 bytesKüçük yapılar, obje başlıkları.
default.kalloc.6464 bytesIPC mesajları, çok küçük kernel buffer’ları.
default.kalloc.128128 bytesOSObject gibi orta boyutlu objelerin parçaları.
default.kalloc.12801280 bytesBüyük yapılar, IOSurface/grafik metadata’sı.

Nasıl çalışıyordu:

  • Her tahsis isteği en yakın zone boyutuna yukarı yuvarlanır.
    (Örn. 50 baytlık istek kalloc.64 zonuna düşer).
  • Her zon içindeki bellek bir freelist içinde tutuluyordu — kernel tarafından free edilen parçalar o zone’a geri giderdi.
  • Eğer 64 baytlık bir buffer’ı taşırırsanız, aynı zon içindeki bir sonraki objeyi ezerdiniz.

Bu yüzden heap spraying / feng shui çok etkiliydi: aynı boyut sınıfında tahsisler spreylerseniz obje komşularını tahmin edebilirdiniz.

Freelist

Her kalloc zonu içinde, freed edilen objeler doğrudan sisteme dönmez — bir freelist’e, yani kullanılabilir chunk’ların bağlı listesine giderdi.

  • Bir chunk free edildiğinde, kernel o chunk’ın başına bir pointer yazar → aynı zon içindeki bir sonraki boş chunk’ın adresi.

  • Zone, ilk boş chunk’a işaret eden bir HEAD tutardı.

  • Tahsis her zaman mevcut HEAD’i kullanırdı:

  1. HEAD çıkarılır (o bellek çağırana verilir).

  2. HEAD = HEAD->next olarak güncellenir (freed chunk’ın header’ında saklanan değer).

  • Free etmek chunk’ları geri iter:

  • freed_chunk->next = HEAD

  • HEAD = freed_chunk

Yani freelist, freed edilmiş belleğin içine inşa edilmiş bir bağlı listedir.

Normal durum:

Zone page (64-byte chunks for example):
[ A ] [ F ] [ F ] [ A ] [ F ] [ A ] [ F ]

Freelist view:
HEAD ──► [ F ] ──► [ F ] ──► [ F ] ──► [ F ] ──► NULL
(next ptrs stored at start of freed chunks)

Freelist’ten faydalanma

Çünkü bir free chunk’ın ilk 8 baytı = freelist pointer, bir saldırgan bunu bozabilir:

  1. Heap overflow bitişik freed chunk’a → “next” pointer’ını overwrite etmek.

  2. Use-after-free freed objeye yazma → “next” pointer’ını overwrite etmek.

Sonra, o boyuttaki bir sonraki allocation sırasında:

  • Allocator bozuk chunk’ı pop eder.

  • Saldırgan tarafından sağlanan “next” pointer’ı takip eder.

  • Rastgele belleğe işaret eden bir pointer döndürür; fake object primitives veya hedefe yönelik overwrite’a olanak tanır.

Freelist poisoning’in görsel örneği:

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 modules

  • Watcher anti-analysis: Özel bir watcher ikili dosyası cihazı sürekli profiller ve bir araştırma ortamı tespit edildiğinde kill-chain’i sonlandırır. security.mac.amfi.developer_mode_status, bir diagnosticd console’un varlığını, locales US veya IL, Cydia gibi jailbreak izlerini, bash, tcpdump, frida, sshd veya checkrain gibi süreçleri, mobil AV uygulamalarını (McAfee, AvastMobileSecurity, NortonMobileSecurity), özelleştirilmiş HTTP proxy ayarlarını ve özelleştirilmiş root CAs’ları inceler. Herhangi bir kontrol başarısız olursa daha fazla payload teslimatı engellenir.
  • Helper surveillance hooks: Helper bileşeni diğer aşamalarla /tmp/helper.sock üzerinden iletişim kurar, ardından DMHooker ve UMHooker adlı hook setlerini yükler. Bu hook’lar VOIP ses yollarına müdahale eder (kayıtlar /private/var/tmp/l/voip_%lu_%u_PART.m4a altında saklanır), sistem genelinde bir keylogger uygular, UI olmadan fotoğraf çeker ve bu eylemlerin normalde tetikleyeceği bildirimleri bastırmak için SpringBoard’u hook’lar. Bu nedenle helper, Predator gibi daha ağır implantlar bırakılmadan önce gizli bir doğrulama ve hafif gözetim katmanı olarak görev yapar.

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

Referanslar

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin