iOS Exploiting

Tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks का समर्थन करें

iOS Exploit Mitigations

1. Code Signing / Runtime Signature Verification

Introduced early (iPhone OS → iOS) यह एक मूलभूत सुरक्षा है: सभी executable code (apps, dynamic libraries, JIT-ed code, extensions, frameworks, caches) को क्रिप्टोग्राफिक रूप से Apple की ट्रस्टेड certificate chain से साइन किया जाना चाहिए। runtime पर, किसी बाइनरी को मेमोरी में लोड करने से पहले (या कुछ boundaries पार करने से पहले) सिस्टम उसकी signature की जाँच करता है। अगर कोड मॉडिफाई हुआ है (bit-flipped, patched) या unsigned है, तो लोड फेल हो जाता है।

  • Thwarts: exploit chains में “classic payload drop + execute” स्टेज; arbitrary code injection; किसी मौजूदा binary को malicious logic डालने के लिए modify करना।
  • Mechanism detail:
  • Mach-O loader (और dynamic linker) code pages, segments, entitlements, team IDs और यह कि signature फाइल की contents को कवर करती है या नहीं — इन चीज़ों की जाँच करता है।
  • JIT caches या dynamically generated code जैसे मेमोरी रीज़न्स के लिए, Apple यह enforce करता है कि pages को signed किया गया हो या special APIs (उदा. mprotect with code-sign checks) के माध्यम से validate किया जाए।
  • signature में entitlements और identifiers शामिल होते हैं; OS यह enforce करता है कि कुछ APIs या privileged capabilities के लिए specific entitlements चाहिए जो forge नहीं किए जा सकते।
Example मान लीजिए exploit किसी process में code execution हासिल कर लेता है और heap में shellcode लिखकर वहाँ jump करने की कोशिश करता है। iOS पर, उस page को executable flag के साथ-साथ code-signature constraints भी पूरा करना होगा। चूंकि shellcode Apple के सर्टिफिकेट से साइन नहीं है, इसलिए jump फेल होगा या सिस्टम उस मेमोरी रीज़न को executable बनाने से मना कर देगा।

2. CoreTrust

Introduced around iOS 14+ era (or gradually in newer devices / later iOS) CoreTrust वह सबसिस्टम है जो binaries (system और user दोनों) की runtime signature validation करता है और यह भरोसा स्थानीय userland trust stores के बजाय Apple’s root certificate पर करता है।

  • Thwarts: बाइनरीज़ के post-install tampering, jailbreaking techniques जो system libraries या user apps को swap/patch करने की कोशिश करते हैं; ट्रिक करने की कोशिश जिसमें trusted binaries को malicious counterparts से replace किया जाए।
  • Mechanism detail:
  • स्थानीय trust database या certificate cache पर भरोसा करने के बजाय, CoreTrust सीधे Apple के root की तरफ़ रेफ़र करता है या intermediate certificates को secure chain में verify करता है।
  • यह सुनिश्चित करता है कि filesystem में मौजूदा binaries में किये गए modifications (उदा. patch) detect और reject हो जाएँ।
  • यह entitlements, team IDs, code signing flags और अन्य metadata को load time पर binary से लिंक करता है।
Example एक jailbreak कोशिश कर सकता है कि `SpringBoard` या `libsystem` को patched version से replace कर दे ताकि persistence मिले। लेकिन जब OS का loader या CoreTrust जाँच करता है, तो signature mismatch (या modified entitlements) दिखते हैं और वो execute करने से मना कर देता है।

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) pages को non-executable और executable pages को non-writable के रूप में चिह्नित किया जाए। आप बस heap या stack में shellcode लिखकर उसे execute नहीं कर सकते।

  • Thwarts: direct shellcode execution; classic buffer-overflow → injected shellcode पर jump।
  • Mechanism detail:
  • MMU / memory protection flags (page tables के माध्यम से) यह separation enforce करते हैं।
  • किसी writable page को executable बनाना system check ट्रिगर करता है (और या तो forbid किया जाता है या code-sign approval की आवश्यकता होती है)।
  • कई मामलों में, pages को executable बनाने के लिए ऐसे OS APIs से गुजरना पड़ता है जो अतिरिक्त constraints या checks लगाते हैं।
Example एक overflow shellcode को heap पर लिखता है। attacker `mprotect(heap_addr, size, PROT_EXEC)` चलाने की कोशिश करता है ताकि उसे executable बनाया जा सके। पर सिस्टम इनकार कर देता है या validate करता है कि नया page code-sign constraints पास करे (जो shellcode नहीं कर सकता)।

4. Address Space Layout Randomization (ASLR)

Introduced in iOS ~4–5 era (roughly iOS 4–5 timeframe) ASLR key memory regions के base addresses (libraries, heap, stack आदि) को हर process launch पर randomize करता है। gadgets के addresses run-to-run बदलते रहते हैं।

  • Thwarts: ROP/JOP के लिए gadget addresses को hardcode करने; static exploit chains; ज्ञात offsets पर blind jump करना।
  • Mechanism detail:
  • हर loaded library / dynamic module को एक randomized offset पर rebase किया जाता है।
  • Stack और heap base pointers randomized होते हैं (कुछ entropy limits के अंदर)।
  • कभी-कभी अन्य regions (उदा. mmap allocations) भी randomized होते हैं।
  • information-leak mitigations के साथ मिलकर यह attacker को पहले किसी address या pointer को leak करके base addresses runtime पर खोजने के लिए मजबूर करता है।
Example एक ROP chain `0x….lib + offset` में gadget की उम्मीद करता है। पर चूंकि `lib` हर run पर अलग जगह relocate होती है, hardcoded chain fail हो जाती है। एक exploit को module का base address पता करने के लिए पहले leak करना होगा।

5. Kernel Address Space Layout Randomization (KASLR)

Introduced in iOS ~ (iOS 5 / iOS 6 timeframe) यूज़र ASLR के समान, KASLR kernel text और अन्य kernel structures के base को boot समय पर randomize करता है।

  • Thwarts: kernel-level exploits जो kernel code या data के fixed location पर निर्भर करते हैं; static kernel exploits।
  • Mechanism detail:
  • हर boot पर kernel का base address एक range के भीतर randomize होता है।
  • kernel data structures (जैसे task_structs, vm_map, आदि) भी relocate या offset किए जा सकते हैं।
  • attackers को पहले kernel pointers leak करने या information disclosure vulnerabilities का प्रयोग करके offsets compute करने होंगे, फिर ही kernel structures या code hijack कर सकते हैं।
Example एक local vulnerability kernel function pointer (उदा. `vtable` में) को `KERN_BASE + offset` पर corrupt करने का लक्ष्य रखती है। पर चूंकि `KERN_BASE` unknown है, attacker को पहले कुछ leak करना होगा (उदा. read primitive) ताकि सही address calculate कर सके।

6. Kernel Patch Protection (KPP / AMCC)

Introduced in newer iOS / A-series hardware (post around iOS 15–16 era or newer chips) KPP (aka AMCC) kernel text pages की integrity को लगातार monitor करता है (hash या checksum के माध्यम से)। अगर यह tampering (patches, inline hooks, code modifications) detect करता है जो allowed windows के बाहर हैं, तो यह kernel panic या reboot trigger कर देता है।

  • Thwarts: persistent kernel patching (kernel instructions modify करना), inline hooks, static function overwrites।
  • Mechanism detail:
  • एक hardware या firmware module kernel text region को monitor करता है।
  • यह periodical या on-demand pages को re-hash करता है और expected values से compare करता है।
  • अगर mismatches occur होती हैं और वे benign update windows के बाहर हैं, तो यह device को panic कर देता है (persistent malicious patch से बचने के लिए)।
  • attackers को या तो detection windows से बचना होगा या legitimate patch paths का उपयोग करना होगा।
Example एक exploit kernel function prologue (उदा. `memcmp`) को patch करके calls intercept करने की कोशिश करता है। पर KPP नोटिस कर लेता है कि code page का hash अब expected value से मेल नहीं खाता और kernel panic ट्रिगर कर देता है, जिससे डिवाइस crash हो जाता है और patch stabilize होने से पहले हट जाता है।

7. Kernel Text Read‐Only Region (KTRR)

Introduced in modern SoCs (post ~A12 / newer hardware) KTRR एक hardware-enforced mechanism है: boot के दौरान kernel text को lock कर दिया जाता है और EL1 (kernel) से उन code pages को write से रोक दिया जाता है।

  • Thwarts: boot के बाद kernel code में किसी भी तरह का modification (उदा. patching, in-place code injection) EL1 privilege level से।
  • Mechanism detail:
  • boot (secure/bootloader stage) के दौरान memory controller (या कोई secure hardware unit) physical pages जो kernel text रखती हैं उन्हें read-only mark कर देता है।
  • भले ही exploit को full kernel privileges मिल जाएँ, वह उन pages पर लिख नहीं सकता।
  • उन्हें modify करने के लिए attacker को पहले boot chain compromise करना होगा, या KTRR को ही subvert करना होगा।
Example एक privilege-escalation exploit EL1 में jump करता है और किसी kernel function में trampoline लिखने की कोशिश करता है (उदा. `syscall` handler)। पर चूंकि KTRR ने pages को read-only लॉक कर रखा है, write fail हो जाता है (या fault ट्रिगर होता है), इसलिए patches apply नहीं होते।

8. Pointer Authentication Codes (PAC)

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

  • PAC एक hardware feature है जो pointer values (return addresses, function pointers, certain data pointers) के tampering का पता लगाने के लिए ऊपरी unused bits में एक छोटा cryptographic signature (एक “MAC”) embed करता है।
  • signature (“PAC”) pointer value और एक modifier (context value, उदा. stack pointer या कोई distinguishing data) दोनों पर compute की जाती है। इस तरह एक ही pointer value अलग contexts में अलग PAC देता है।
  • उपयोग के समय, pointer को dereference या branch करने से पहले एक authenticate instruction PAC की जाँच करता है। अगर valid है तो PAC strip हो जाता है और शुद्ध pointer मिलता है; अगर invalid है तो pointer “poisoned” हो जाता है (या fault उठता है)।
  • PAC बनाने/मान्य करने के लिए जिन keys का उपयोग होता है वे privileged registers (EL1, kernel) में रहते हैं और user mode से सीधे पढ़े नहीं जा सकते।
  • चूँकि कई सिस्टम में सभी 64 bits का उपयोग नहीं होता (उदा. 48-bit address space), ऊपरी bits “spare” रहते हैं और PAC वहां रखी जा सकती है बिना effective address बदलें।

Architectural Basis & Key Types

  • ARMv8.3 पाँच 128-bit keys introduce करता है (प्रत्येक दो 64-bit system registers के माध्यम से implement) pointer authentication के लिए।

  • APIAKey — instruction pointers के लिए (domain “I”, key A)

  • APIBKey — दूसरा instruction pointer key (domain “I”, key B)

  • APDAKey — data pointers के लिए (domain “D”, key A)

  • APDBKey — data pointers के लिए (domain “D”, key B)

  • APGAKey — “generic” key, non-pointer data या अन्य generic उपयोग के लिए

  • ये keys privileged system registers में store होते हैं (केवल EL1/EL2 आदि पर accessible), user mode से accessible नहीं।

  • PAC एक cryptographic function (ARM QARMA algorithm सुझाता है) से compute होती है जो निम्नों पर निर्भर करती है:

  1. Pointer value (canonical हिस्सा)
  2. एक modifier (context value, जैसे salt)
  3. Secret key
  4. कुछ internal tweak logic यदि परिणामस्वरूप PAC pointer के ऊपरी bits में रखी गई value से मेल खाती है तो authentication सफल हो जाती है।

Instruction Families

नामकरण के लिए convention है: PAC / AUT / XPAC, फिर domain letters।

  • PACxx instructions एक pointer को sign करते हैं और PAC insert करते हैं
  • AUTxx instructions authenticate + strip करते हैं (validate और PAC हटाना)
  • XPACxx instructions strip करते हैं बिना validate किए

Domains / suffixes:

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

(तालिका में mnemonics और assembly examples को अपरिवर्तित रखा गया है।)

There are specialized / alias forms:

  • PACIASP is shorthand for PACIA X30, SP (sign the link register using SP as modifier)
  • AUTIASP is AUTIA X30, SP (authenticate link register with SP)
  • Combined forms like RETAA, RETAB (authenticate-and-return) or BLRAA (authenticate & branch) exist in ARM extensions / compiler support.
  • Also zero-modifier variants: PACIZA / PACIZB where the modifier is implicitly zero, etc.

Modifiers

modifier का मुख्य उद्देश्य PAC को एक specific context से bind करना है ताकि एक ही address जो अलग contexts में sign हो उसे अलग PAC मिले। यह pointer reuse across frames या objects रोकता है। यह salt की तरह है।

इसलिए:

  • modifier एक context value (एक और register) होता है जो PAC computation में mix होता है। आम तौर पर उपयोग: stack pointer (SP), frame pointer, या कोई object ID।
  • SP को modifier के रूप में इस्तेमाल करना return address signing के लिए सामान्य है: PAC specific stack frame से जुड़ जाता है। अगर कोई LR को दूसरे frame में reuse करता है तो modifier बदल जाता है, इसलिए PAC validation fail होती है।
  • एक ही pointer value अलग modifiers के साथ sign होने पर अलग PAC उत्पन्न होगा।
  • modifier secret होना ज़रूरी नहीं है, पर ideally attacker-controlled नहीं होना चाहिए।
  • जिन instructions में sign/verify करते समय कोई meaningful modifier नहीं मिलता, वहाँ कुछ forms zero या implicit constant का उपयोग करती हैं।

Apple / iOS / XNU Customizations & Observations

  • Apple की PAC implementation में per-boot diversifiers शामिल हैं ताकि keys या tweaks हर boot पर बदलें और boots के बीच reuse रोकें।
  • वे cross-domain mitigations भी शामिल करते हैं ताकि user mode में sign किए गए PACs को kernel mode में आसानी से reuse न किया जा सके।
  • Apple M1 / Apple Silicon पर reverse engineering से पता चला कि वहाँ nine modifier types और key control के लिए Apple-specific system registers हैं।
  • Apple PAC को कई kernel subsystems में उपयोग करता है: return address signing, kernel data में pointer integrity, signed thread contexts, आदि।
  • Google Project Zero ने दिखाया कि powerful memory read/write primitive होने पर kernel PACs (A keys) को forge किया जा सकता है A12-era devices पर, पर Apple ने उन रास्तों को patch किया।
  • Apple के सिस्टम में कुछ keys global across kernel हो सकते हैं, जबकि user processes को per-process key randomness दिया जाता है।

PAC Bypasses

  1. Kernel-mode PAC: theoretical vs real bypasses
  • चूँकि kernel PAC keys और logic tightly controlled हैं (privileged registers, diversifiers, domain isolation), arbitrary signed kernel pointers को forge करना बहुत कठिन है।
  • Azad के 2020 “iOS Kernel PAC, One Year Later” रिपोर्ट में बताया गया कि iOS 12-13 में कुछ partial bypasses (signing gadgets, reuse of signed states, unprotected indirect branches) मिले थे पर कोई full generic bypass नहीं मिला। bazad.github.io
  • Apple की “Dark Magic” customizations exploitable surfaces को और भी कम करती हैं (domain switching, per-key enabling bits)। i.blackhat.com
  • Apple silicon (M1/M2) पर Zecao Cai et al. द्वारा रिपोर्ट किया गया एक ज्ञात kernel PAC bypass CVE-2023-32424 है। i.blackhat.com
  • पर ये bypasses अक्सर बहुत specific gadgets या implementation bugs पर निर्भर करते हैं; वे सामान्य प्रयोजन के bypass नहीं होते।

इसलिए kernel PAC को बहुत मजबूत माना जाता है, हालांकि परिपूर्ण नहीं।

  1. User-mode / runtime PAC bypass techniques

ये अधिक आम हैं और PAC के अनुप्रयोग या runtime frameworks में imperfections का फायदा उठाती हैं। नीचे कुछ वर्ग और उदाहरण दिए गए हैं।

2.1 Shared Cache / A key issues

  • dyld shared cache एक बड़ा pre-linked blob है system frameworks और libraries का। क्योंकि यह बहुत साझा किया जाता है, shared cache के अंदर function pointers पहले से “pre-signed” होते हैं और कई processes द्वारा उपयोग किए जाते हैं। attackers इन pre-signed pointers को “PAC oracles” के रूप में target करते हैं।

  • कुछ bypass techniques shared cache में मौजूद A-key signed pointers को extract या reuse करने की कोशिश करती हैं और उन्हें gadgets के साथ मिलाकर उपयोग करती हैं।

  • “No Clicks Required” टॉक एक oracle बनाने का वर्णन करता है जो shared cache पर आधारित है ताकि relative addresses infer करके signed pointers के साथ PAC bypass किया जा सके। saelo.github.io

  • कुछ userland shared library imports में function pointers को पर्याप्त रूप से PAC से सुरक्षित नहीं पाया गया, जिससे attacker को signed pointers बदले बिना function pointers मिल गए। (Project Zero bug entry) bugs.chromium.org

2.2 dlsym(3) / dynamic symbol resolution

  • एक ज्ञात bypass है dlsym() को कॉल करना ताकि एक पहले से signed function pointer मिल जाए (A-key से signed, diversifier zero के साथ) और फिर उसका उपयोग करना। क्योंकि dlsym वैध रूप से signed pointer लौटाता है, इसका उपयोग करके PAC forge करने की जरूरत नहीं पड़ती।

  • Epsilon का ब्लॉग दर्शाता है कि कुछ bypasses इसे exploit करते हैं: dlsym("someSym") एक signed pointer देता है जिसे indirect calls के लिए इस्तेमाल किया जा सकता है। blog.epsilon-sec.com

  • Synacktiv का “iOS 18.4 — dlsym considered harmful” बताता है कि iOS 18.4 में कुछ symbols जो dlsym से resolve होते थे वे pointers return करते थे जो गलत तरीके से signed थे (या buggy diversifiers के साथ), जिससे अनायास PAC bypass संभव हुआ। Synacktiv

  • dyld में dlsym के लॉजिक में: जब result->isCode होता है, वे returned pointer को __builtin_ptrauth_sign_unauthenticated(..., key_asia, 0) के साथ sign करते हैं, यानी context zero। blog.epsilon-sec.com

इस प्रकार, dlsym user-mode PAC bypasses के लिए एक सामान्य vector है।

2.3 Other DYLD / runtime relocations

  • DYLD loader और dynamic relocation logic complex है और कभी-कभी relocations करने के लिए pages को अस्थायी रूप से read/write के रूप में map करता है, फिर उन्हें वापस read-only कर देता है। attackers इन windows का फायदा उठाते हैं। Synacktiv की talk “Operation Triangulation” dynamic relocations के माध्यम से timing-based PAC bypass बताती है। Synacktiv

  • DYLD pages अब SPRR / VM_FLAGS_TPRO जैसी protection flags से सुरक्षित हैं। पर पुराने versions में guards कमज़ोर थे। Synacktiv

  • WebKit exploit chains में, DYLD loader को अक्सर PAC bypass के लिए target किया गया है। slides में बताया गया है कि कई PAC bypasses ने DYLD loader को निशाना बनाया है (relocation, interposer hooks के माध्यम से)। Synacktiv

2.4 NSPredicate / NSExpression / ObjC / SLOP

  • userland exploit chains में Objective-C runtime methods जैसे NSPredicate, NSExpression या NSInvocation का उपयोग control calls smuggle करने के लिए किया जाता है बिना सीधे pointer forging के।

  • पुराने iOS (PAC से पहले) में एक exploit ने fake NSInvocation objects का उपयोग arbitrary selectors कॉल करने के लिए किया था। PAC आने के बाद तकनीक में बदलाव करने पड़े। पर SLOP (SeLector Oriented Programming) को PAC के तहत भी विस्तार दिया गया है। Project Zero

  • मूल SLOP technique fake invocations बनाकर ObjC calls chain करने देती थी; bypass इस बात पर निर्भर करती थी कि ISA या selector pointers कभी-कभी पूरी तरह PAC-protected नहीं होते थे। Project Zero

  • उन वातावरणों में जहाँ pointer authentication आंशिक रूप से लागू है, methods / selectors / target pointers हमेशा PAC protection में नहीं होते, जिससे bypass की गुंजाइश रहती है।

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>उदाहरण</summary>
A buffer overflow स्टैक पर मौजूद return address को overwrite कर देता है। attacker लक्ष्य gadget पता लिखता है पर सही PAC को compute नहीं कर पाता। जब फ़ंक्शन return करता है, CPU का `AUTIA` instruction fault करता है क्योंकि PAC मेल नहीं खाता। exploit chain विफल हो जाती है।
Project Zero का A12 (iPhone XS) पर analysis दिखाता है कि Apple का PAC कैसे इस्तेमाल होता है और PACs को forge करने के तरीके किस तरह संभव हैं जब attacker के पास memory read/write primitive हो।
</details>


### 9. **Branch Target Identification (BTI)**
**Introduced with ARMv8.5 (later hardware)**
BTI एक हार्डवेयर फीचर है जो **indirect branch targets** की जांच करता है: जब `blr` या indirect calls/jumps execute होते हैं, तो target का first instruction एक **BTI landing pad** (`BTI j` या `BTI c`) से शुरू होना चाहिए। landing pad के बिना gadget addresses में jump करने पर exception ट्रिगर होता है।

LLVM की implementation में BTI instructions के तीन variants और वे branch types से कैसे map होते हैं, नोट किए गए हैं।

| BTI Variant | What it permits (which branch types) | Typical placement / use case |
|-------------|----------------------------------------|-------------------------------|
| **BTI C** | call-style indirect branches के targets (उदा. `BLR`, या `BR` जब X16/X17 उपयोग हो रहे हों) | उन functions के entry पर रखा जाता है जिन्हें indirectly call किया जा सकता है |
| **BTI J** | jump-style branches के targets (उदा. `BR` जिसे tail calls के लिए उपयोग किया जाता है) | उन basic blocks की शुरुआत में रखा जाता है जो jump tables या tail-calls से पहुंचने योग्य हों |
| **BTI JC** | C और J दोनों के रूप में काम करता है | इसे या तो call या jump branches लक्षित कर सकते हैं |

- branch target enforcement के साथ compile किए गए code में compilers हर मान्य indirect-branch target (function शुरुआतें या jumps से reachable blocks) पर BTI instruction (C, J, या JC) डालते हैं ताकि indirect branches केवल उन्हीं जगहों पर सफल हों।
- **Direct branches / calls** (यानी fixed-address `B`, `BL`) BTI द्वारा **नहीं रोके जाते**। धारणा यह है कि code pages trusted हैं और attacker उन्हें बदल नहीं सकता (इसलिए direct branches को सुरक्षित माना गया है)।
- इसके अलावा, **RET / return** instructions सामान्यतः BTI द्वारा प्रतिबंधित नहीं होते क्योंकि return addresses को PAC या return signing mechanisms के द्वारा सुरक्षित किया जाता है।

#### Mechanism and enforcement

- जब CPU किसी पेज को “guarded / BTI-enabled” के रूप में decode करता है और वहाँ किसी **indirect branch (BLR / BR)** को पढ़ता है, तो यह जांचता है कि target address का पहला instruction वैध BTI (C, J, या JC जैसा अनुमति है) है या नहीं। अगर नहीं, तो **Branch Target Exception** होता है।
- BTI instruction का encoding पहले से NOPs के लिए reserve किए गए opcodes को reuse करने के लिए डिज़ाइन किया गया है (पहले के ARM संस्करणों में)। इसलिए BTI-enabled binaries backward-compatible बने रहते हैं: जिन hardware में BTI support नहीं है, वहां ये instructions NOP की तरह व्यवहार करेंगे।
- जो compiler passes BTIs जोड़ते हैं वे इन्हें केवल जहां आवश्यक हो वहां डालते हैं: वे functions जो indirectly call हो सकते हैं, या वे basic blocks जिन्हें jumps target करते हैं।
- कुछ patches और LLVM कोड दिखाते हैं कि BTI हर basic block के लिए insert नहीं किया जाता — केवल उन blocks के लिए जो संभावित branch targets हैं (उदा. switch / jump tables से आने वाले)।

#### BTI + PAC synergy

PAC pointer value (source) को सुरक्षित करता है — यह सुनिश्चित करता है कि indirect calls / returns की chain में छेड़छाड़ नहीं हुई है।

BTI यह सुनिश्चित करता है कि भले ही pointer वैध हो, वह केवल ठीक से mark किए गए entry points को ही target कर सके।

मिलाकर, attacker को एक वैध pointer जिस पर सही PAC हो और साथ ही target पर BTI मौजूद होना दोनों चाहिए। इससे exploit gadgets बनाना और कठिन हो जाता है।

#### Example


<details>
<summary>उदाहरण</summary>
एक exploit `0xABCDEF` पर स्थित gadget में pivot करने की कोशिश करता है जो `BTI c` से शुरू नहीं होता। CPU जब `blr x0` execute करता है, तो यह target की जांच करता है और fault कर देता है क्योंकि instruction alignment में वैध landing pad नहीं है। इसलिए कई gadgets तब तक अनउपयोगी हो जाते हैं जब तक उनमें 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** एक फीचर है जो **ARMv8.1-A** में पेश किया गया था और यह **privileged code** (EL1 या EL2) को उन memory accesses (read/write) से रोकता है जो कि **user-accessible (EL0)** के रूप में मार्क की गई हों, जब तक कि PAN को स्पष्ट रूप से disable न किया गया हो।
- विचार यह है: यदि kernel को trick या compromise भी कर दिया जाता है, तो वह बिना पहले PAN clear किए arbitrary user-space pointers को dereference नहीं कर सकेगा, इस तरह **ret2usr** जैसी exploits या user-controlled buffers के दुरुपयोग का खतरा घटता है।
- जब PAN enabled होता है (PSTATE.PAN = 1), तो कोई भी privileged load/store instruction जो ऐसे virtual address को access करता है जो “accessible at EL0” माना जाता है, permission fault ट्रिगर करता है।
- जब kernel को वैध रूप से user-space memory तक पहुंचनी होती है (उदा. user buffers से data copy करना), तो kernel को अस्थायी रूप से PAN disable करना पड़ता है (या “unprivileged load/store” instructions का उपयोग करना पड़ता है) ताकि वह access संभव हो सके।
- Linux on ARM64 में PAN support लगभग 2015 के आस-पास introduce हुआ: kernel patches ने इस फीचर का detection जोड़ा और get_user / put_user आदि को उन variants से replace किया जो user memory accesses के आसपास PAN को clear करते थे।

**मुख्य नुанс / limitation / bug**
- जैसा कि Siguza और अन्य ने नोट किया है, ARM के design में एक specification bug (या ambiguous व्यवहार) का मतलब है कि execute-only user mappings (`--x`) PAN को trigger नहीं कर सकतीं। दूसरे शब्दों में, यदि कोई user page executable के रूप में मार्क है पर read permission नहीं है, तो kernel का read प्रयास PAN को बायपास कर सकता है क्योंकि architecture “accessible at EL0” के लिए readable permission की अपेक्षा करता है, सिर्फ executable होने की नहीं। यह कुछ configurations में PAN bypass की ओर ले जाता है।
- इसलिए, यदि iOS / XNU execute-only user pages की अनुमति देते हैं (जैसा कि कुछ JIT या code-cache सेटअप कर सकते हैं), तो kernel गलती से उन pages को PAN enabled होने के बावजूद पढ़ सकता है। यह कुछ ARMv8+ सिस्टम्स में ज्ञात एक सूक्ष्म exploitable क्षेत्र है।

#### PXN (Privileged eXecute Never)

- **PXN** एक page table flag है (page table entries में, leaf या block entries) जो इंगित करता है कि वह page privileged mode में execute नहीं की जा सकती (यानी जब EL1 उसे execute करे)।
- PXN kernel (या कोई भी privileged code) को user-space pages से jump करने या वहां से instructions execute करने से रोकता है भले ही control divert हो जाए। प्रभावी रूप से, यह kernel-level control-flow redirection into user memory को रोकता है।
- PAN के साथ मिलाकर यह सुनिश्चित करता है कि:
1. Kernel (डिफ़ॉल्ट रूप से) user-space data को read या write नहीं कर सकता (PAN)
2. Kernel user-space code को execute नहीं कर सकता (PXN)
- ARMv8 page table format में, leaf entries में PXN bit होती है (और unprivileged execute-never के लिए UXN भी) उनके attribute bits में।

इसलिए भले ही kernel के पास corrupted function pointer हो जो user memory की ओर इशारा करता हो और वह वहां branch करने की कोशिश करे, PXN bit fault उत्पन्न कर देगा।

#### Memory-permission model & how PAN and PXN map to page table bits

समझने के लिए कि PAN / PXN कैसे काम करते हैं, आपको ARM के translation और permission model को देखना होगा (सरलीकृत):

- प्रत्येक page या block entry में attribute fields होते हैं जिनमें AP[2:1] शामिल हैं access permissions के लिए (read/write, privileged बनाम unprivileged) और UXN / PXN bits execute-never प्रतिबंधों के लिए।
- जब PSTATE.PAN 1 (enabled) होता है, तो hardware modified semantics लागू करता है: privileged accesses उन pages पर जो “accessible by EL0” के रूप में मार्क हैं (यानी user-accessible) अस्वीकार कर देता है (fault)।
- उपरोक्त उल्लेखित bug के कारण, केवल executable (no read permission) के रूप में मार्क किए गए pages कुछ implementations में “accessible by EL0” के रूप में गिने नहीं जा सकते, जिससे PAN bypass हो सकता है।
- जब किसी page का PXN bit सेट होता है, तो भले ही instruction fetch higher privilege level से आये, execution निषिद्ध होगा।

#### Kernel usage of PAN / PXN in a hardened OS (e.g. iOS / XNU)

कठोर kernel डिज़ाइन में (जैसा कि Apple उपयोग कर सकता है):

- Kernel डिफ़ॉल्ट रूप से PAN enable करता है (ताकि privileged code constrained रहे)।
- उन pathways में जिनको वैध रूप से user buffers पढ़ने/लिखने की आवश्यकता होती है (उदा. syscall buffer copy, I/O, read/write user pointer), kernel अस्थायी रूप से PAN disable करता है या override करने के लिए विशेष instructions का उपयोग करता है।
- user data access समाप्त होने के बाद, उसे PAN को फिर से enable करना चाहिए।
- PXN page tables के माध्यम से लागू होता है: user pages के लिए PXN = 1 होता है (ताकि kernel उन्हें execute न कर सके), kernel pages में PXN नहीं होता (ताकि kernel code execute कर सके)।
- Kernel को सुनिश्चित करना चाहिए कि कोई code path execution flow को user memory regions में नहीं भेजे (जो PXN को बायपास कर दे) — इसलिए exploit chains जो “jump into user-controlled shellcode” पर निर्भर हैं, अवरोधित हो जाते हैं।

PAN bypass via execute-only pages के कारण, वास्तविक सिस्टम में Apple execute-only user pages को अक्षम या इनकार कर सकता है, या उस specification weakness के आसपास patch कर सकता है।

#### Attack surfaces, bypasses, and mitigations

- **PAN bypass via execute-only pages**: जैसा ऊपर बताया गया, spec एक गैप अनुमति देता है: execute-only (no read perm) वाले user pages कुछ implementations में “accessible at EL0” नहीं माने जा सकते, इसलिए PAN ऐसे pages से kernel reads को ब्लॉक नहीं करेगा। इससे attacker को execute-only sections के माध्यम से डेटा फीड करने का एक असामान्य मार्ग मिल सकता है।
- **Temporal window exploit**: अगर kernel आवश्यक से अधिक लंबी अवधि के लिए PAN disable कर देता है, तो एक race या malicious path उस window का उपयोग करके अनचाही user memory access कर सकता है।
- **Forgotten re-enable**: अगर कुछ code paths PAN को फिर से enable करने में विफल रहते हैं, तो बाद के kernel operations गलती से user memory को access कर सकते हैं।
- **Misconfiguration of PXN**: अगर page tables user pages पर PXN सेट नहीं करते या user code pages को गलत तरीके से map करते हैं, तो kernel को user-space code execute करने के लिए trick किया जा सकता है।
- **Speculation / side-channels**: speculative bypasses के समान, microarchitectural side-effects हो सकते हैं जो PAN / PXN checks के अस्थायी उल्लंघन का कारण बनें (हालाँकि ऐसे हमले CPU design पर बहुत निर्भर करते हैं)।
- **Complex interactions**: advanced features में (उदा. JIT, shared memory, just-in-time code regions), kernel को user-mapped regions में कुछ memory accesses या execution की अनुमति देने के लिए सूक्ष्म नियंत्रण की आवश्यकता हो सकती है; PAN/PXN constraints के तहत इन्हें सुरक्षित रूप से डिजाइन करना जटिल है।

#### Example

<details>
<summary>Code Example</summary>
यहाँ कुछ illustrative pseudo-assembly sequences हैं जो user memory access के आसपास PAN को enable/disable दिखाते हैं, और यह कैसे fault उत्पन्न हो सकता है।
</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

If the kernel had **not** set PXN on that user page, then the branch might succeed — which would be insecure.

If the kernel forgets to re-enable PAN after user memory access, it opens a window where further kernel logic might accidentally read/write arbitrary user memory.

If the user pointer is into an execute-only page (user page with only execute permission, no read/write), under the PAN spec bug, `ldr W2, [X1]` might **not** fault even with PAN enabled, enabling a bypass exploit, depending on implementation.

</details>

<details>
<summary>Example</summary>
A kernel vulnerability tries to take a user-provided function pointer and call it in kernel context (i.e. `call user_buffer`). Under PAN/PXN, that operation is disallowed or faults.
</details>

---

### 11. **Top Byte Ignore (TBI) / Pointer Tagging**
**Introduced in ARMv8.5 / newer (or optional extension)**
TBI means the top byte (most-significant byte) of a 64-bit pointer is ignored by address translation. This lets OS or hardware embed **tag bits** in the pointer’s top byte without affecting the actual address.

- TBI stands for **Top Byte Ignore** (sometimes called *Address Tagging*). It is a hardware feature (available in many ARMv8+ implementations) that **ignores the top 8 bits** (bits 63:56) of a 64-bit pointer when performing **address translation / load/store / instruction fetch**.
- In effect, the CPU treats a pointer `0xTTxxxx_xxxx_xxxx` (where `TT` = top byte) as `0x00xxxx_xxxx_xxxx` for the purposes of address translation, ignoring (masking off) the top byte. The top byte can be used by software to store **metadata / tag bits**.
- This gives software “free” in-band space to embed a byte of tag in each pointer without altering which memory location it refers to.
- The architecture ensures that loads, stores, and instruction fetch treat the pointer with its top byte masked (i.e. tag stripped off) before performing the actual memory access.

Thus TBI decouples the **logical pointer** (pointer + tag) from the **physical address** used for memory operations.

#### Why TBI: Use cases and motivation

- **Pointer tagging / metadata**: You can store extra metadata (e.g. object type, version, bounds, integrity tags) in that top byte. When you later use the pointer, the tag is ignored at hardware level, so you don’t need to strip manually for the memory access.
- **Memory tagging / MTE (Memory Tagging Extension)**: TBI is the base hardware mechanism that MTE builds on. In ARMv8.5, the **Memory Tagging Extension** uses bits 59:56 of the pointer as a **logical tag** and checks it against an **allocation tag** stored in memory.
- **Enhanced security & integrity**: By combining TBI with pointer authentication (PAC) or runtime checks, you can force not just the pointer value but also the tag to be correct. An attacker overwriting a pointer without the correct tag will produce a mismatched tag.
- **Compatibility**: Because TBI is optional and tag bits are ignored by hardware, existing untagged code continues to operate normally. The tag bits effectively become “don’t care” bits for legacy code.

#### Example
<details>
<summary>Example</summary>
A function pointer included a tag in its top byte (say `0xAA`). An exploit overwrites the pointer low bits but neglects the tag, so when the kernel verifies or sanitizes, the pointer fails or is rejected.
</details>

---

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

- PPL is designed as an **intra-kernel protection boundary**: even if the kernel (EL1) is compromised and has read/write capabilities, **it should not be able to freely modify** certain **sensitive pages** (especially page tables, code-signing metadata, kernel code pages, entitlements, trust caches, etc.).
- It effectively creates a **“kernel within the kernel”** — a smaller trusted component (PPL) with **elevated privileges** that alone can modify protected pages. Other kernel code must call into PPL routines to effect changes.
- This reduces the attack surface for kernel exploits: even with full arbitrary R/W/execute in kernel mode, exploit code must also somehow get into the PPL domain (or bypass PPL) to modify critical structures.
- On newer Apple silicon (A15+ / M2+), Apple is transitioning to **SPTM (Secure Page Table Monitor)**, which in many cases replaces PPL for page-table protection on those platforms.

Here’s how PPL is believed to operate, based on public analysis:

#### Use of APRR / permission routing (APRR = Access Permission ReRouting)

- Apple hardware uses a mechanism called **APRR (Access Permission ReRouting)**, which allows page table entries (PTEs) to contain small indices, rather than full permission bits. Those indices are mapped via APRR registers to actual permissions. This allows dynamic remapping of permissions per domain.
- PPL leverages APRR to segregate privilege within kernel context: only the PPL domain is permitted to update the mapping between indices and effective permissions. That is, when non-PPL kernel code writes a PTE or tries to flip permission bits, the APRR logic disallows it (or enforces read-only mapping).
- PPL code itself runs in a restricted region (e.g. `__PPLTEXT`) which is normally non-executable or non-writable until entry gates temporarily allow it. The kernel calls PPL entry points (“PPL routines”) to perform sensitive operations.

#### Gate / Entry & Exit

- When the kernel needs to modify a protected page (e.g. change permissions of a kernel code page, or modify page tables), it calls into a **PPL wrapper** routine, which does validation and then transitions into the PPL domain. Outside that domain, the protected pages are effectively read-only or non-modifiable by the main kernel.
- During PPL entry, the APRR mappings are adjusted so that memory pages in the PPL region are set to **executable & writable** within PPL. Upon exit, they are returned to read-only / non-writable. This ensures that only well-audited PPL routines can write to protected pages.
- Outside PPL, attempts by kernel code to write to those protected pages will fault (permission denied) because the APRR mapping for that code domain doesn’t permit writing.

#### Protected page categories

The pages that PPL typically protects include:

- Page table structures (translation table entries, mapping metadata)
- Kernel code pages, especially those containing critical logic
- Code-sign metadata (trust caches, signature blobs)
- Entitlement tables, signature enforcement tables
- Other high-value kernel structures where a patch would allow bypassing signature checks or credentials manipulation

The idea is that even if the kernel memory is fully controlled, the attacker cannot simply patch or rewrite these pages, unless they also compromise PPL routines or bypass PPL.


#### Known Bypasses & Vulnerabilities

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

- A public writeup by Project Zero describes a bypass involving **stale TLB entries**.
- The idea:

1. Allocate two physical pages A and B, mark them as PPL pages (so they are protected).
2. Map two virtual addresses P and Q whose L3 translation table pages come from A and B.
3. Spin a thread to continuously access Q, keeping its TLB entry alive.
4. Call `pmap_remove_options()` to remove mappings starting at P; due to a bug, the code mistakenly removes the TTEs for both P and Q, but only invalidates the TLB entry for P, leaving Q’s stale entry live.
5. Reuse B (page Q’s table) to map arbitrary memory (e.g. PPL-protected pages). Because the stale TLB entry still maps Q’s old mapping, that mapping remains valid for that context.
6. Through this, the attacker can put writable mapping of PPL-protected pages in place without going through PPL interface.

- This exploit required fine control of physical mapping and TLB behavior. It demonstrates that a security boundary relying on TLB / mapping correctness must be extremely careful about TLB invalidations and mapping consistency.

- Project Zero commented that bypasses like this are subtle and rare, but possible in complex systems. Still, they regard PPL as a solid mitigation.

2. **Other potential hazards & constraints**

- If a kernel exploit can directly enter PPL routines (via calling the PPL wrappers), it might bypass restrictions. Thus argument validation is critical.
- Bugs in the PPL code itself (e.g. arithmetic overflow, boundary checks) can allow out-of-bounds modifications inside PPL. Project Zero observed that such a bug in `pmap_remove_options_internal()` was exploited in their bypass.
- The PPL boundary is irrevocably tied to hardware enforcement (APRR, memory controller), so it's only as strong as the hardware implementation.



#### Example
<details>
<summary>Code Example</summary>
Here’s a simplified pseudocode / logic showing how a kernel might call into PPL to modify protected pages:
```c
// In kernel (outside PPL domain)
function kernel_modify_pptable(pt_addr, new_entry) {
// validate arguments, etc.
return ppl_call_modify(pt_addr, new_entry)  // call PPL wrapper
}

// In PPL (trusted domain)
function ppl_call_modify(pt_addr, new_entry) {
// temporarily enable write access to protected pages (via APRR adjustments)
aprr_set_index_for_write(PPL_INDEX)
// perform the modification
*pt_addr = new_entry
// restore permissions (make pages read-only again)
aprr_restore_default()
return success
}

// If kernel code outside PPL does:
*pt_addr = new_entry  // a direct write
// It will fault because APRR mapping for non-PPL domain disallows write to that page
उदाहरण The kernel can do many normal operations, but only through `ppl_call_*` routines can it change protected mappings or patch code.
उदाहरण A kernel exploit tries to overwrite the entitlement table, or disable code-sign enforcement by modifying a kernel signature blob. Because that page is PPL-protected, the write is blocked unless going through the PPL interface. So even with kernel code execution, you cannot bypass code-sign constraints or modify credential data arbitrarily. On iOS 17+ certain devices use SPTM to further isolate PPL-managed pages.

PPL → SPTM / प्रतिस्थापन / भविष्य

  • On Apple’s modern SoCs (A15 or later, M2 or later), Apple supports SPTM (Secure Page Table Monitor), which replaces PPL for page table protections.
  • Apple calls out in documentation: “Page Protection Layer (PPL) and Secure Page Table Monitor (SPTM) enforce execution of signed and trusted code … PPL manages the page table permission overrides … Secure Page Table Monitor replaces PPL on supported platforms.”
  • The SPTM architecture likely shifts more policy enforcement into a higher-privileged monitor outside kernel control, further reducing the trust boundary.

MTE | EMTE | MIE

Here’s a higher-level description of how EMTE operates under Apple’s MIE setup:

  1. Tag assignment
  • When memory is allocated (e.g. in kernel or user space via secure allocators), a secret tag is assigned to that block.
  • The pointer returned to the user or kernel includes that tag in its high bits (using TBI / top byte ignore mechanisms).
  1. Tag checking on access
  • Whenever a load or store is executed using a pointer, the hardware checks that the pointer’s tag matches the memory block’s tag (allocation tag). If mismatch, it faults immediately (since synchronous).
  • Because it’s synchronous, there is no “delayed detection” window.
  1. Retagging on free / reuse
  • When memory is freed, the allocator changes the block’s tag (so older pointers with old tags no longer match).
  • A use-after-free pointer would therefore have a stale tag and mismatch when accessed.
  1. Neighbor-tag differentiation to catch overflows
  • Adjacent allocations are given distinct tags. If a buffer overflow spills into neighbor’s memory, tag mismatch causes a fault.
  • This is especially powerful in catching small overflows that cross boundary.
  1. Tag confidentiality enforcement
  • Apple must prevent tag values being leaked (because if attacker learns the tag, they could craft pointers with correct tags).
  • They include protections (microarchitectural / speculative controls) to avoid side-channel leakage of tag bits.
  1. Kernel and user-space integration
  • Apple uses EMTE not just in user-space but also in kernel / OS-critical components (to guard kernel against memory corruption).
  • The hardware/OS ensures tag rules apply even when kernel is executing on behalf of user space.
उदाहरण ``` Allocate A = 0x1000, assign tag T1 Allocate B = 0x2000, assign tag T2

// pointer P points into A with tag T1 P = (T1 << 56) | 0x1000

// Valid store *(P + offset) = value // tag T1 matches allocation → allowed

// Overflow attempt: P’ = P + size_of_A (into B region) *(P’ + delta) = value → pointer includes tag T1 but memory block has tag T2 → mismatch → fault

// Free A, allocator retags it to T3 free(A)

// Use-after-free: *(P) = value → pointer still has old tag T1, memory region is now T3 → mismatch → fault

</details>

#### सीमाएँ और चुनौतियाँ

- **Intrablock overflows**: यदि overflow उसी allocation के अंदर रहता है (boundary को पार नहीं करता) और tag वही रहता है, तो tag mismatch इसे पकड़ नहीं पाता।
- **Tag width limitation**: tag के लिए केवल कुछ बिट्स (उदा. 4 bits, या छोटा domain) उपलब्ध होते हैं—namespace सीमित है।
- **Side-channel leaks**: यदि tag बिट्स leaked हो सकते हैं (via cache / speculative execution), तो attacker वेलिड tags सीखकर बायपास कर सकता है। Apple की tag confidentiality enforcement इसे कम करने की कोशिश करती है।
- **Performance overhead**: हर load/store पर tag checks जोड़ने से लागत बढ़ती है; Apple को hardware को optimize करना होगा ताकि overhead कम रहे।
- **Compatibility & fallback**: पुराने hardware या उन हिस्सों पर जो EMTE सपोर्ट नहीं करते, fallback मौजूद होना चाहिए। Apple का दावा है कि MIE केवल उन devices पर enabled है जिनमें hardware support है।
- **Complex allocator logic**: allocator को tags manage करने, retagging, boundary align करने और mis-tag collisions से बचने का काम करना होता है। allocator लॉजिक में बग vulnerabilities पैदा कर सकते हैं।
- **Mixed memory / hybrid areas**: कुछ memory legacy के कारण untagged रह सकती है, जिससे interoperability जटिल हो जाती है।
- **Speculative / transient attacks**: कई microarchitectural protections की तरह, speculative execution या micro-op fusions checks को transient रूप से बायपास कर सकते हैं या tag bits को leak कर सकते हैं।
- **Limited to supported regions**: Apple केवल selective, high-risk क्षेत्रों (kernel, security-critical subsystems) में EMTE लागू कर सकता है, सार्वभौमिक रूप से नहीं।


---

## Key enhancements / differences compared to standard MTE

यहां Apple द्वारा बताई गई सुधारित चीज़ें और परिवर्तन दिए गए हैं:

| 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 hardware और software दोनों को नियंत्रित करता है, वह EMTE को कड़ाई से लागू कर सकता है, performance समस्याओं से बच सकता है, और side-channel holes को बंद कर सकता है।

---

## How EMTE works in practice (Apple / MIE)

यहाँ एक high-level विवरण है कि Apple के MIE सेटअप में EMTE कैसे काम करता है:

1. **Tag assignment**
- जब memory allocate होती है (उदा. kernel या user space में secure allocators के माध्यम से), तो उस block को एक **secret tag** दिया जाता है।
- उपयोगकर्ता या kernel को जो pointer लौटता है, उसमे tag शामिल होता है (high bits में) — TBI / top byte ignore mechanisms का उपयोग करके।

2. **Tag checking on access**
- जब भी किसी pointer से load या store execute होता है, hardware चेक करता है कि pointer का tag उस memory block के allocation tag से मेल खाता है या नहीं। यदि mismatch, तो तुरंत fault होता है (क्योंकि synchronous mode)।
- क्योंकि यह synchronous है, इसलिए कोई “delayed detection” विंडो नहीं रहती।

3. **Retagging on free / reuse**
- जब memory free होती है, allocator उस block का tag बदल देता है (ताकि पुराने pointers जिनमें पुराना tag है, अब मैच न करें)।
- एक use-after-free pointer इसलिए stale tag रखेगा और access पर mismatch दिखेगा।

4. **Neighbor-tag differentiation to catch overflows**
- adjacent allocations को अलग tags दिए जाते हैं। यदि buffer overflow पड़ोसी के memory में spill करता है, तो tag mismatch fault पैदा करता है।
- यह छोटे overflows जो boundary पार करते हैं उन्हें पकड़ने में विशेष रूप से प्रभावी है।

5. **Tag confidentiality enforcement**
- Apple को tag values के leakage को रोकना होगा (क्योंकि यदि attacker tag सीख लेता है, तो वह सही tag वाले pointers तैयार कर सकता है)।
- वे microarchitectural / speculative controls शामिल करते हैं ताकि tag बिट्स के side-channel leakage को रोका जा सके।

6. **Kernel and user-space integration**
- Apple EMTE का उपयोग केवल user-space में नहीं बल्कि kernel / OS-critical components में भी करता है (kernel को memory corruption से बचाने के लिए)।
- hardware/OS यह सुनिश्चित करते हैं कि tag नियम तब भी लागू हों जब kernel user space की ओर से executing हो।


क्योंकि EMTE MIE में बिल्ट है, Apple महत्वपूर्ण attack surfaces पर synchronous mode में EMTE लागू करता है, न कि इसे opt-in या debugging mode के रूप में रखता है।


---

## Exception handling in XNU

जब कोई **exception** होता है (उदा., `EXC_BAD_ACCESS`, `EXC_BAD_INSTRUCTION`, `EXC_CRASH`, `EXC_ARM_PAC`, आदि), तो XNU kernel की **Mach layer** इसे UNIX-style **signal** (जैसे `SIGSEGV`, `SIGBUS`, `SIGILL`, ...) बनने से पहले intercept करने के लिए जिम्मेदार होती है।

यह प्रक्रिया user space तक पहुँचने या BSD signal में बदलने से पहले कई स्तरों के exception propagation और handling को शामिल करती है।


### Exception Flow (High-Level)

1.  **CPU triggers a synchronous exception** (उदा., invalid pointer dereference, PAC failure, illegal instruction, आदि)।

2.  **Low-level trap handler** चलता है (`trap.c`, `exception.c` in XNU source)।

3.  trap handler **`exception_triage()`** को कॉल करता है, जो Mach exception handling का core है।

4.  `exception_triage()` तय करता है कि exception को कैसे route किया जाए:

-   पहले **thread's exception port** को भेजा जाता है।

-   फिर **task's exception port** को।

-   फिर **host's exception port** (अक्सर `launchd` या `ReportCrash`) को।

यदि इन में से कोई भी port exception को handle नहीं करता, तो kernel कर सकता है:

-   **इसे BSD signal में convert कर देना** (user-space processes के लिए)।

-   **panic** कर देना (kernel-space exceptions के लिए)।


### Core Function: `exception_triage()`

फंक्शन `exception_triage()` Mach exceptions को संभव handlers की श्रृंखला में route करता है जब तक कि कोई handler इसे handle न कर ले या अंततः fatal न हो जाए। यह `osfmk/kern/exception.c` में परिभाषित है।
```c
void exception_triage(exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t codeCnt);

सामान्य कॉल फ्लो:

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

यदि सभी असफल होते हैं → bsd_exception() द्वारा संभाला जाता है → किसी सिग्नल जैसे SIGSEGV में अनुवादित किया जाता है।

एक्सेप्शन पोर्ट्स

प्रत्येक Mach ऑब्जेक्ट (thread, task, host) एक्सेप्शन पोर्ट्स रजिस्टर कर सकता है, जहाँ एक्सेप्शन संदेश भेजे जाते हैं।

वे API द्वारा परिभाषित होते हैं:

task_set_exception_ports()
thread_set_exception_ports()
host_set_exception_ports()

प्रत्येक exception port में होते हैं:

  • एक mask (कौन से exceptions यह प्राप्त करना चाहता है)
  • एक port name (मैसेज प्राप्त करने के लिए Mach port)
  • एक behavior (कर्नेल मैसेज कैसे भेजता है)
  • एक flavor (कौन सा thread state शामिल होगा)

Debuggers and Exception Handling

एक debugger (उदा., LLDB) लक्ष्य task या thread पर एक exception port सेट करता है, आमतौर पर task_set_exception_ports() का उपयोग करके।

जब एक exception होता है:

  • Mach message debugger process को भेजा जाता है।
  • debugger तय कर सकता है कि exception को handle करे (resume, registers बदलना, instruction स्किप करना) या नहीं handle करे।
  • अगर debugger इसे handle नहीं करता, तो exception अगले स्तर पर propagate होता है (task → host)。

Flow of EXC_BAD_ACCESS

  1. Thread invalid pointer को dereference करता है → CPU Data Abort उठाता है।

  2. Kernel trap handler exception_triage(EXC_BAD_ACCESS, ...) कॉल करता है।

  3. Message भेजा जाता है:

  • Thread port → (debugger breakpoint को intercept कर सकता है)।

  • अगर debugger ignore करे → Task port → (process-level handler)।

  • अगर ignore किया गया → Host port (आमतौर पर ReportCrash)।

  1. अगर कोई भी handle नहीं करता → bsd_exception() इसे SIGSEGV में translate कर देता है।

PAC Exceptions

जब Pointer Authentication (PAC) फेल होता है (signature mismatch), एक special Mach exception उठता है:

  • EXC_ARM_PAC (type)
  • Codes में विवरण हो सकते हैं (उदा., key type, pointer type)।

यदि बायनेरी में flag TFRO_PAC_EXC_FATAL सेट है, तो कर्नेल PAC failures को fatal के रूप में मानता है, debugger interception को bypass करता हुआ। यह attackers को debuggers का उपयोग करके PAC checks bypass करने से रोकने के लिए है और यह platform binaries के लिए सक्षम होता है।

Software Breakpoints

एक software breakpoint (int3 on x86, brk on ARM64) को जानबूझकर fault करके लागू किया जाता है।
debugger इसे exception port के माध्यम से पकड़ता है:

  • instruction pointer या memory को modify करता है।
  • original instruction restore करता है।
  • execution resume करता है।

यही mechanism आपको एक PAC exception “catch” करने की अनुमति देता है — जब तक TFRO_PAC_EXC_FATAL सेट नहीं है, उस स्थिति में यह कभी debugger तक नहीं पहुँचता।

Conversion to BSD Signals

अगर कोई handler exception स्वीकार नहीं करता:

  • Kernel task_exception_notify() → bsd_exception() कॉल करता है।

  • यह Mach exceptions को signals में map करता है:

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

### Key Files in XNU Source

  • osfmk/kern/exception.cexception_triage(), exception_deliver_*() का core।

  • bsd/kern/kern_sig.c → Signal delivery logic।

  • osfmk/arm64/trap.c → Low-level trap handlers।

  • osfmk/mach/exc.h → Exception codes और structures।

  • osfmk/kern/task.c → Task exception port setup।


Old Kernel Heap (Pre-iOS 15 / Pre-A12 era)

Kernel एक zone allocator (kalloc) उपयोग करता था जो fixed-size “zones” में विभाजित था।
हर zone केवल एक ही size class की allocations रखता था।

स्क्रीनशॉट से:

Zone NameElement SizeExample Use
default.kalloc.1616 bytesबहुत छोटे kernel structs, pointers.
default.kalloc.3232 bytesछोटे structs, object headers.
default.kalloc.6464 bytesIPC messages, छोटे kernel buffers.
default.kalloc.128128 bytesमध्यम ऑब्जेक्ट जैसे हिस्से of OSObject.
default.kalloc.12801280 bytesबड़े structures, IOSurface/graphics metadata.

यह कैसे काम करता था:

  • हर allocation request को निकटतम zone size पर round up किया जाता था।
    (उदा., 50-byte request kalloc.64 zone में जाता था)।
  • हर zone की मेमोरी एक freelist में रखी जाती थी — kernel द्वारा free किए गए chunks वापस उसी zone में जाते थे।
  • अगर आप एक 64-byte buffer overflow करते थे, तो आप उसी zone के अगले object को overwrite कर देते थे।

यही कारण था कि heap spraying / feng shui इतने प्रभावी थे: आप उसी size class की allocations स्प्रे करके object neighbors का अनुमान लगा सकते थे।

The freelist

हर kalloc zone के अंदर, freed objects सिस्टम को सीधे वापस नहीं किए जाते थे — वे freelist में चले जाते थे, जो उपलब्ध chunks की linked list थी।

  • जब एक chunk free होता था, कर्नेल उस chunk के start पर एक pointer लिखता था → उसी zone के अगले free chunk का address।

  • Zone एक HEAD pointer रखता था जो पहले free chunk का पता देता था।

  • Allocation हमेशा current HEAD का उपयोग करता था:

  1. HEAD को pop करें (उस memory को caller को return किया जाता है)।

  2. HEAD = HEAD->next अपडेट करें (जो freed chunk के header में स्टोर होता था)।

  • Free करना chunks को वापस push करता था:

  • freed_chunk->next = HEAD

  • HEAD = freed_chunk

तो freelist बस उसी freed memory के अंदर बनाई गई linked list थी।

Normal state:

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

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

freelist का शोषण

क्योंकि किसी free chunk के पहले 8 bytes = freelist pointer होते हैं, एक हमलावर इसे बिगाड़ (corrupt) सकता है:

  1. Heap overflow एक adjacent freed chunk में → इसके “next” pointer को overwrite कर देना।

  2. Use-after-free एक freed object में write करके → इसके “next” pointer को overwrite करना।

फिर, उस size के अगले allocation पर:

  • allocator corrupted chunk को pop करता है।
  • attacker-supplied “next” pointer को follow करता है।
  • arbitrary memory के लिए एक pointer return करता है, जिससे fake object primitives या targeted overwrite संभव हो पाते हैं।

freelist poisoning का visual उदाहरण:

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 डिज़ाइन ने हार्डेनिंग से पहले exploitation को बहुत प्रभावी बना दिया था: heap sprays से predictable neighbors, raw pointer freelist links, और कोई type separation न होने के कारण attackers UAF/overflow बग्स को arbitrary kernel memory control में escalate कर पाते थे।

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.
इस तरह, जब memory corruption होगा, attacker reliably victim object को controlled डेटा से overwrite कर सकेगा।

Steps:

  1. Spray allocations (fill the holes)
  • समय के साथ kernel heap fragmented हो जाता है: कुछ zones में पुराने freed objects के कारण holes बन जाते हैं।
  • attacker सबसे पहले बहुत सारी dummy allocations करके इन gaps को भरता है, ताकि heap “packed” और predictable बन जाए।
  1. Force new pages
  • एक बार holes भर जाने पर, अगली allocations zone में add की गई नई pages से आनी पड़ती हैं।
  • नई pages का मतलब है कि objects एक साथ clustered होंगे, पुराने fragmented memory में scattered नहीं होंगे।
  • इससे attacker को neighbors पर बेहतर control मिलता है।
  1. Place attacker objects
  • attacker अब फिर से spray करता है, उन नई pages में बहुत सारे attacker-controlled objects बनाता है।
  • ये objects size और placement में predictable होते हैं (क्योंकि वे उसी zone के हैं)।
  1. Free a controlled object (make a gap)
  • attacker जानबूझकर अपने एक object को free करता है।
  • यह heap में एक “hole” बनाता है, जिसे allocator बाद में उसी size की अगली allocation के लिए reuse करेगा।
  1. Victim object lands in the hole
  • attacker kernel को trigger करता है ताकि victim object (जिसे वह corrupt करना चाहता है) allocate हो।
  • चूँकि hole freelist में पहला available slot होता है, victim ठीक वहीं placed होगा जहाँ attacker ने अपना object free किया था।
  1. Overflow / UAF into victim
  • अब attacker के आसपास attacker-controlled objects हैं।
  • अपने किसी object से overflow करके (या freed object को reuse करके) attacker reliably victim की memory fields को चुने हुए मानों से overwrite कर सकता है।

Why it works:

  • Zone allocator predictability: एक ही size की allocations हमेशा उसी zone से आती हैं।
  • Freelist behavior: नई allocations सबसे हाल में freed chunk को सबसे पहले reuse करती हैं।
  • Heap sprays: attacker predictable content से memory भरता है और layout को control करता है।
  • End result: attacker control करता है कि victim object कहाँ आयेगा और उसके पास क्या data रहेगा।

आधुनिक Kernel Heap (iOS 15+/A12+ SoCs)

Apple ने allocator को harden किया और heap grooming को काफी कठिन बना दिया:

1. From Classic kalloc to kalloc_type

  • Before: हर size class (16, 32, 64, … 1280, आदि) के लिए एक single kalloc.<size> zone मौजूद था। उसी size के कोई भी object वहाँ रखा जाता था → attacker objects privileged kernel objects के बगल में आ सकते थे।
  • Now:
  • Kernel objects अब typed zones (kalloc_type) से allocate होते हैं।
  • हर object type (उदा., ipc_port_t, task_t, OSString, OSData) का अपना dedicated zone होता है, भले ही उनका size समान हो।
  • object type ↔ zone का mapping compile time पर kalloc_type system से generated होता है।

एक attacker अब यह guarantee नहीं कर सकता कि controlled data (OSData) उसी size के sensitive kernel objects (task_t) के adjacent पहुंचेगा।

2. Slabs and Per-CPU Caches

  • heap को slabs में बाँटा गया है (उस zone के लिए fixed-size chunks में काटी गई pages)।
  • हर zone का एक per-CPU cache होता है ताकि contention कम हो।
  • Allocation path:
  1. पहले per-CPU cache देखें।
  2. अगर खाली है, तो global freelist से खींचें।
  3. अगर freelist खाली है, तो नया slab (एक या अधिक pages) allocate करें।
  • Benefit: यह decentralization heap sprays को कम deterministic बनाती है, क्योंकि allocations अलग-अलग CPUs’ caches से satisfy हो सकती हैं।

3. Randomization inside zones

  • एक zone के भीतर, freed elements simple FIFO/LIFO order में वापस नहीं दिए जाते।
  • Modern XNU encoded freelist pointers का उपयोग करता है (Linux जैसा safe-linking, ~iOS 14 के आसपास आया)।
  • हर freelist pointer को per-zone secret cookie के साथ XOR-encode किया जाता है।
  • इससे attacker के लिए fake freelist pointer forge करना मुश्किल हो जाता है यदि वे write primitive हासिल भी कर लें।
  • कुछ allocations को slab के भीतर randomized placement मिलता है, इसलिए spraying adjacency की गारंटी नहीं देता।

4. Guarded Allocations

  • कुछ critical kernel objects (उदा., credentials, task structures) guarded zones में allocate किए जाते हैं।
  • ये zones slabs के बीच guard pages (unmapped memory) या objects के चारों ओर redzones डालते हैं।
  • guard page में overflow होने पर fault trigger होता है → immediate panic होता है बजाय silent corruption के।

5. Page Protection Layer (PPL) and SPTM

  • भले ही आप किसी freed object को control कर लें, आप kernel memory का सब कुछ modify नहीं कर सकते:
  • PPL (Page Protection Layer) सुनिश्चित करता है कि कुछ regions (उदा., code signing data, entitlements) kernel के लिए भी read-only रहें।
  • A15/M2+ devices पर यह भूमिका/सुरक्षा SPTM (Secure Page Table Monitor) + TXM (Trusted Execution Monitor) द्वारा बदली/मजबूत की गई है।
  • ये hardware-enforced layers attackers को single heap corruption से critical security structures को arbitrary patch करने से रोकते हैं।
  • (Added / Enhanced): kernel में pointers (विशेषकर function pointers, vtables) को सुरक्षित करने के लिए PAC (Pointer Authentication Codes) भी उपयोग किया जाता है ताकि उन्हें forge/ corrupt करना कठिन हो।
  • (Added / Enhanced): zones अब zone_require / zone enforcement लागू कर सकते हैं, यानी किसी object को free करने पर केवल उसके correct typed zone से ही लौटाया जा सके; invalid cross-zone frees panic या reject हो सकते हैं। (Apple ने इसे अपनी memory safety posts में संकेत दिया है)

6. Large Allocations

  • सभी allocations kalloc_type से नहीं जातीं।
  • बहुत बड़े requests (~16 KB से ऊपर) typed zones को bypass करते हैं और सीधे kernel VM (kmem) से page allocations के जरिए serve किए जाते हैं।
  • ये कम predictable होते हैं, पर कम exploitable भी होते हैं क्योंकि वे slabs किसी अन्य objects के साथ share नहीं करते।

7. Allocation Patterns Attackers Target

इन protections के बावजूद, attackers अभी भी इन चीज़ों को टार्गेट करते हैं:

  • Reference count objects: यदि आप retain/release counters को tamper कर सकें, तो use-after-free को जनरेट किया जा सकता है।
  • Objects with function pointers (vtables): किसी को corrupt करना अभी भी control flow दे सकता है।
  • Shared memory objects (IOSurface, Mach ports): ये अभी भी attack targets हैं क्योंकि वे user ↔ kernel को bridge करते हैं।

पर — पहले की तरह — आप सिर्फ OSData spray करके उम्मीद नहीं कर सकते कि वह task_t के बगल में आ जाएगा। सफल होने के लिए आपको type-specific bugs या info leaks की ज़रूरत होगी।

Example: Allocation Flow in Modern Heap

मान लीजिए userspace IOKit को call करके एक OSData object allocate कराता है:

  1. Type lookupOSData map होता है kalloc_type_osdata zone (size 64 bytes) में।
  2. per-CPU cache में free elements देखें।
  • यदि मिलता है → उसे return करें।
  • यदि खाली → global freelist पर जाएँ।
  • यदि freelist खाली → नया slab allocate करें (4KB page → 64 chunks of 64 bytes)।
  1. chunk caller को return करें।

Freelist pointer protection:

  • हर freed chunk में next free chunk का address store होता है, पर secret key के साथ encoded होता है।
  • attacker data से उस field को overwrite करना तब काम नहीं करेगा जब तक कि आप 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

आधुनिक Userland Heap (iOS, macOS — type-aware / xzone malloc)

हाल के Apple OS versions (विशेषकर iOS 17+) में, Apple ने userland allocator के रूप में अधिक सुरक्षित सिस्टम, xzone malloc (XZM) पेश किया। यह kernel के kalloc_type का user-space analogue है, जो type awareness, metadata isolation, और memory tagging safeguards लागू करता है।

Goals & Design Principles

  • Type segregation / type awareness: allocations को type या usage (pointer vs data) के हिसाब से group करना ताकि type confusion और cross-type reuse रोका जा सके।
  • Metadata isolation: heap metadata (उदा. free lists, size/state bits) को object payloads से अलग रखना ताकि out-of-bounds writes से metadata corrupt होने की संभावना कम हो।
  • Guard pages / redzones: allocations के चारों ओर unmapped pages या padding डालना ताकि overflows पकड़े जा सकें।
  • Memory tagging (EMTE / MIE): hardware tagging के साथ मिलकर use-after-free, out-of-bounds, और invalid accesses का पता लगाने में मदद करना।
  • Scalable performance: कम overhead बनाए रखना, excessive fragmentation से बचना, और high allocation rates के साथ low latency देना।

Architecture & Components

नीचे xzone allocator के मुख्य elements दिए गए हैं:

Segment Groups & Zones

  • Segment groups address space को usage categories से partition करते हैं: उदा. data, pointer_xzones, data_large, pointer_large
  • हर segment group में segments (VM ranges) होते हैं जो उस category की allocations host करते हैं।
  • हर segment के साथ एक metadata slab (separate VM area) जुड़ा होता है जो metadata (उदा. free/used bits, size classes) स्टोर करता है। यह out-of-line (OOL) metadata सुनिश्चित करता है कि metadata object payloads के साथ mix न हो और overflow से corrupt न हो।
  • Segments को chunks में काटा जाता है जो फिर blocks में subdivide होते हैं (allocation units)। एक chunk एक specific size class और segment group के लिए tied होता है (यानी chunk के अंदर के सभी blocks एक ही size & category साझा करते हैं)।
  • small/medium allocations के लिए fixed-size chunks उपयोग होंगे; large/huge allocations के लिए अलग mapping हो सकती है।

Chunks & Blocks

  • एक chunk एक region है (अक्सर कई pages) जो एक size class के allocations को समर्पित होता है।
  • chunk के अंदर, blocks उपलब्ध allocation slots होते हैं। Freed blocks को metadata slab के माध्यम से track किया जाता है — उदा. bitmaps या out-of-line free lists के जरिए।
  • chunks के बीच (या भीतर) guard slices / guard pages डाले जा सकते हैं (उदा. unmapped slices) ताकि out-of-bounds writes पकड़े जा सकें।

Type / Type ID

  • हर allocation site (या malloc, calloc, आदि को call) एक type identifier (malloc_type_id_t) से जुड़ा होता है जो बताता है कि किस तरह का object allocate हो रहा है। वह type ID allocator को दी जाती है, जो सही zone/segment चुनने के लिए इसका उपयोग करती है।
  • इसलिए, भले ही दो allocations का size समान हो, वे अलग types होने पर पूरी तरह अलग zones में जा सकती हैं।
  • early iOS 17 versions में सभी APIs (उदा., CFAllocator) पूरी तरह type-aware नहीं थे; Apple ने iOS 18 में कुछ कमजोरियों को address किया।

Allocation & Freeing Workflow

यहाँ xzone में allocation और deallocation का high-level flow है:

  1. malloc / calloc / realloc / typed alloc size और type ID के साथ invoke होता है।
  2. allocator type ID का उपयोग करके सही segment group / zone चुनता है।
  3. उस zone/segment में वह उस size के free blocks वाले chunk की तलाश करता है।
  • यह local caches / per-thread pools या metadata से free block lists देख सकता है।
  • अगर free block नहीं मिलता, तो zone में नया chunk allocate कर सकता है।
  1. metadata slab update होता है (free bit cleared, bookkeeping)।
  2. यदि memory tagging (EMTE) सक्रिय है, तो returned block को एक tag दिया जाता है, और metadata इसे “live” state में अपडेट करता है।
  3. जब free() कॉल होता है:
  • block metadata में freed के रूप में mark होता है (OOL slab के जरिए)।
  • block free list में रखा जा सकता है या reuse के लिए pooled किया जा सकता है।
  • वैकल्पिक रूप से, block contents को cleared या poisoned किया जा सकता है ताकि data leaks या use-after-free exploitation कम हो।
  • block के साथ जुड़ा hardware tag invalidated या re-tagged हो सकता है।
  • अगर पूरा chunk free हो जाता है (सभी blocks free), तो allocator memory pressure में उस chunk को reclaim कर सकता है (unmap या OS को return)।

Security Features & Hardening

ये modern userland xzone में built-in defenses हैं:

FeaturePurposeNotes
Metadata decouplingPrevent overflow from corrupting metadataMetadata अलग VM region (metadata slab) में रहता है
Guard pages / unmapped slicesCatch out-of-bounds writesBuffer overflows को detect करता है बजाय silent adjacent block corrupt के
Type-based segregationPrevent cross-type reuse & type confusionSame-size allocations अलग types पर different zones में जाती हैं
Memory Tagging (EMTE / MIE)Detect invalid access, stale references, OOB, UAFxzone hardware EMTE के साथ synchronous mode में काम करता है (“Memory Integrity Enforcement”)
Delayed reuse / poisoning / zapReduce chance of use-after-free exploitationFreed blocks को poisoned, zeroed, या quarantined किया जा सकता है
Chunk reclamation / dynamic unmappingReduce memory waste and fragmentationUnused chunks unmap किए जा सकते हैं
Randomization / placement variationPrevent deterministic adjacencyBlocks और chunk selection में randomized पहलू हो सकते हैं
Segregation of “data-only” allocationsSeparate allocations that don’t store pointersउन allocations को अलग रखा जाता है जो pointers नहीं रखते, जिससे attacker का metadata/control पर control कम होता है

Interaction with Memory Integrity Enforcement (MIE / EMTE)

  • Apple की MIE (Memory Integrity Enforcement) hardware + OS framework है जो Enhanced Memory Tagging Extension (EMTE) को always-on, synchronous mode में लाती है प्रमुख attack surfaces पर।
  • xzone allocator user space में MIE की बुनियाद है: xzone से होने वाली allocations को tags मिलते हैं, और accesses hardware द्वारा चेक होते हैं।
  • MIE में allocator, tag assignment, metadata management, और tag confidentiality enforcement को integrate किया गया है ताकि memory errors (उदा. stale reads, OOB, UAF) तुरंत पकड़े जाएँ और बाद में exploit न हों।

यदि आप चाहें, मैं आपकी book के लिए xzone internals का एक cheat-sheet या diagram भी बना सकता हूँ। क्या आप चाहेंगे कि मैं वह अगला बनाऊं?

: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: हाल के in-the-wild chains ने WebKit JIT bug (patched as CVE-2023-41993) का दुरुपयोग सिर्फ JavaScript-level arbitrary read/write पाने के लिए किया। exploit तुरंत एक purchased framework JSKit में pivot करता है, ताकि किसी भी भविष्य के Safari bug को बस वही primitive deliver करना पड़े।
  • Version abstraction & PAC bypasses: JSKit कई iOS releases के लिए support और कई selectable Pointer Authentication Code bypass modules बंडल करता है। यह framework target build का fingerprint बनाकर appropriate PAC bypass logic चुनता है, और हर step (primitive validation, shellcode launch) को verify करता है।
  • Manual Mach-O mapping: JSKit memory से सीधे Mach-O headers parse करता है, dyld-cached images के अंदर जरूरी symbols resolve करता है, और additional Mach-O payloads manual map कर सकता है बिना उन्हें disk पर लिखे। इससे renderer process in-memory ही रहता है और filesystem artifacts से जुड़े code-signature checks से बचता है।
  • Portfolio model: Debug strings जैसे “exploit number 7” दिखाते हैं कि suppliers कई interchangeable WebKit exploits रखते हैं। एक बार JS primitive JSKit के interface से मेल खा जाए, बाकी chain campaigns के across unchanged रहता है।

Kernel bridge: IPC UAF -> code-sign bypass pattern

  • Kernel IPC UAF (CVE-2023-41992): दूसरा stage, जो अभी भी Safari context में चलता है, IPC code में kernel use-after-free trigger करता है, freed object को userspace से re-allocate कराता है, और dangling pointers को abuse करके arbitrary kernel read/write में pivot करता है। यह stage पहले से JSKit द्वारा compute किए गए PAC bypass material को reuse भी करता है बजाय कि उसे फिर से derive करने के।
  • Code-signing bypass (CVE-2023-41991): kernel R/W मिलने के साथ, exploit trust cache / code-signing structures को patch करता है ताकि unsigned payloads system के रूप में execute हों। फिर यह stage बाद के payloads को एक lightweight kernel R/W service expose करता है।
  • Composed pattern: यह chain एक reusable recipe दिखाती है जिसे defenders आगे भी expect कर सकते हैं:
WebKit renderer RCE -> kernel IPC UAF -> kernel arbitrary R/W -> code-sign bypass -> unsigned system stager

PREYHUNTER helper & watcher modules

  • Watcher anti-analysis: एक समर्पित watcher बाइनरी लगातार डिवाइस की प्रोफाइलिंग करती है और जब कोई research environment पता चलता है तो kill-chain को abort कर देती है। यह security.mac.amfi.developer_mode_status, एक diagnosticd console की मौजूदगी, locales US या IL, jailbreak के निशान जैसे Cydia, bash, tcpdump, frida, sshd, या checkrain जैसे processes, मोबाइल AV apps (McAfee, AvastMobileSecurity, NortonMobileSecurity), कस्टम HTTP proxy सेटिंग्स, और कस्टम root CAs की जाँच करती है। किसी भी चेक में असफल होने पर आगे की payload delivery ब्लॉक कर दी जाती है।
  • Helper surveillance hooks: helper component अन्य stages से /tmp/helper.sock के माध्यम से संवाद करता है, फिर DMHooker और UMHooker नाम के hook सेट लोड करता है। ये hooks VOIP audio paths को टैप करते हैं (रिकॉर्डिंग्स /private/var/tmp/l/voip_%lu_%u_PART.m4a में सेव होती हैं), एक system-wide keylogger लागू करते हैं, बिना UI के photos कैप्चर करते हैं, और उन क्रियाओं से उत्पन्न होने वाली notifications को दबाने के लिए SpringBoard को hook करते हैं। इसलिए helper, भारी implants जैसे Predator को ड्रोप करने से पहले एक stealthy validation + light-surveillance लेयर के रूप में कार्य करता है।

WebKit DFG Store-Barrier UAF + ANGLE PBO OOB (iOS 26.1)

Webkit Dfg Store Barrier Uaf Angle Oob

iMessage/Media Parser Zero-Click Chains

Imessage Media Parser Zero Click Coreaudio Pac Bypass

संदर्भ

Tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks का समर्थन करें