iOS Exploiting

Reading time: 59 minutes

tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks

iOS Exploit Mitigations

1. Code Signing / Runtime Signature Verification

Introduced early (iPhone OS → iOS) Esta é uma das proteções fundamentais: todo código executável (apps, dynamic libraries, JIT-ed code, extensions, frameworks, caches) deve ser assinado criptograficamente por uma cadeia de certificados enraizada na confiança da Apple. Em tempo de execução, antes de carregar um binário na memória (ou antes de realizar saltos através de certas fronteiras), o sistema verifica sua assinatura. Se o código for modificado (bit-flipped, patchado) ou não assinado, o carregamento falha.

  • Impede: a etapa “classic payload drop + execute” em cadeias de exploit; injeção arbitrária de código; modificar um binário existente para inserir lógica maliciosa.
  • Detalhe do mecanismo:
  • O Mach-O loader (e o dynamic linker) verifica páginas de código, segmentos, entitlements, team IDs, e que a assinatura cobre o conteúdo do arquivo.
  • Para regiões de memória como JIT caches ou código gerado dinamicamente, a Apple exige que as páginas sejam assinadas ou validadas via APIs especiais (por exemplo, mprotect com verificações de code-sign).
  • A assinatura inclui entitlements e identificadores; o OS impõe que certas APIs ou capacidades privilegiadas exijam entitlements específicos que não podem ser forjados.
Example Suponha que um exploit obtenha execução de código em um processo e tente escrever shellcode no heap e saltar para ele. No iOS, essa página precisaria ser marcada como executável **e** satisfazer as restrições de code-signature. Como o shellcode não é assinado com o certificado da Apple, o salto falha ou o sistema rejeita tornar aquela região de memória executável.

2. CoreTrust

Introduced around iOS 14+ era (or gradually in newer devices / later iOS) CoreTrust é o subsistema que realiza a validação de assinatura em tempo de execução de binários (incluindo binários do sistema e do usuário) contra o certificado raiz da Apple em vez de confiar em stores de confiança em userland.

  • Impede: adulteração pós-instalação de binários, técnicas de jailbreaking que tentam trocar ou patchar libraries do sistema ou apps de usuário; enganar o sistema substituindo binários confiáveis por equivalentes maliciosos.
  • Detalhe do mecanismo:
  • Em vez de confiar em um banco de confiança local ou cache de certificados, o CoreTrust busca ou referencia diretamente o root da Apple ou verifica certificados intermediários em uma cadeia segura.
  • Garante que modificações (por exemplo, no filesystem) em binários existentes sejam detectadas e rejeitadas.
  • Vincula entitlements, team IDs, flags de code signing e outros metadados ao binário no momento do load.
Example Um jailbreak poderia tentar substituir `SpringBoard` ou `libsystem` por uma versão patchada para ganhar persistência. Mas quando o loader do OS ou o CoreTrust verificam, detectam a incompatibilidade da assinatura (ou entitlements modificados) e se recusam a executar.

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

Introduced in many OSes earlier; iOS had NX-bit / w^x for a long time DEP impõe que páginas marcadas como escritas (para dados) sejam não-executáveis, e páginas marcadas como executáveis sejam não-graváveis. Você não pode simplesmente escrever shellcode em uma região de heap ou stack e executá-lo.

  • Impede: execução direta de shellcode; classic buffer-overflow → salto para shellcode injetado.
  • Detalhe do mecanismo:
  • A MMU / flags de proteção de memória (via page tables) aplicam a separação.
  • Qualquer tentativa de marcar uma página gravável como executável dispara uma verificação do sistema (e é ou proibida ou requer aprovação de code-sign).
  • Em muitos casos, tornar páginas executáveis requer passar por APIs do OS que impõem restrições ou verificações adicionais.
Example Um overflow escreve shellcode no heap. O atacante tenta `mprotect(heap_addr, size, PROT_EXEC)` para torná-lo executável. Mas o sistema recusa ou valida que a nova página deve passar por restrições de code-sign (o que o shellcode não consegue).

4. Address Space Layout Randomization (ASLR)

Introduced in iOS ~4–5 era (roughly iOS 4–5 timeframe) ASLR randomiza os endereços base de regiões de memória chave: libraries, heap, stack, etc., a cada execução do processo. Os endereços dos gadgets mudam entre execuções.

  • Impede: hardcoding de endereços de gadgets para ROP/JOP; cadeias de exploit estáticas; saltos cegos para offsets conhecidos.
  • Detalhe do mecanismo:
  • Cada library / módulo dinâmico carregado é rebased em um offset randomizado.
  • Ponteiros base da stack e do heap são randomizados (dentro de certos limites de entropia).
  • Às vezes outras regiões (por exemplo, mmap allocations) também são randomizadas.
  • Combinado com mitigações de information-leak, força o atacante a primeiro vazar um endereço ou ponteiro para descobrir endereços base em tempo de execução.
Example Uma cadeia ROP espera um gadget em `0x….lib + offset`. Mas como `lib` é deslocada de forma diferente a cada execução, a cadeia hardcoded falha. Um exploit deve primeiro vazar o endereço base do módulo antes de calcular os endereços dos gadgets.

5. Kernel Address Space Layout Randomization (KASLR)

Introduced in iOS ~ (iOS 5 / iOS 6 timeframe) Análogo ao ASLR de usuário, KASLR randomiza a base do kernel text e outras estruturas do kernel no momento do boot.

  • Impede: exploits ao nível de kernel que dependem de localização fixa de código ou dados do kernel; exploits de kernel estáticos.
  • Detalhe do mecanismo:
  • A cada boot, o endereço base do kernel é randomizado (dentro de um intervalo).
  • Estruturas de dados do kernel (como task_structs, vm_map, etc.) também podem ser realocadas ou ter offsets ajustados.
  • Atacantes devem primeiro vazar ponteiros do kernel ou usar vulnerabilidades de informação para calcular offsets antes de sequestrar estruturas ou código do kernel.
Example Uma vulnerabilidade local visa corromper um ponteiro de função do kernel (por exemplo em `vtable`) em `KERN_BASE + offset`. Mas como `KERN_BASE` é desconhecido, o atacante deve vazá-lo primeiro (por exemplo via uma primitive de leitura) antes de calcular o endereço correto para corromper.

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) monitora continuamente a integridade das páginas de texto do kernel (via hash ou checksum). Se detectar adulteração (patches, inline hooks, modificações de código) fora de janelas permitidas, aciona um kernel panic ou reboot.

  • Impede: patching persistente do kernel (modificar instruções do kernel), inline hooks, sobrescritas estáticas de funções.
  • Detalhe do mecanismo:
  • Um módulo de hardware ou firmware monitora a região de texto do kernel.
  • Periodicamente ou sob demanda, re-hasheia as páginas e compara com os valores esperados.
  • Se ocorrerem incompatibilidades fora de janelas de atualização benignas, provoca um panic no dispositivo (para evitar patches maliciosos persistentes).
  • Atacantes devem ou evitar janelas de detecção ou usar caminhos legítimos de patch.
Example Um exploit tenta patchar o prólogo de uma função do kernel (por exemplo `memcmp`) para interceptar chamadas. Mas KPP percebe que o hash da página de código não bate com o valor esperado e provoca um kernel panic, travando o dispositivo antes que o patch se estabilize.

7. Kernel Text Read‐Only Region (KTRR)

Introduced in modern SoCs (post ~A12 / newer hardware) KTRR é um mecanismo aplicado por hardware: uma vez que o kernel text é bloqueado cedo durante o boot, ele se torna somente-leitura a partir de EL1 (o kernel), impedindo escritas posteriores em páginas de código.

  • Impede: quaisquer modificações ao código do kernel após o boot (por exemplo patching, injeção de código in-place) no nível de privilégio EL1.
  • Detalhe do mecanismo:
  • Durante o boot (na fase secure/bootloader), o memory controller (ou uma unidade de hardware segura) marca as páginas físicas contendo o kernel text como somente-leitura.
  • Mesmo que um exploit ganhe privilégios completos de kernel, não pode escrever nessas páginas para patchar instruções.
  • Para modificá-las, o atacante precisa primeiro comprometer a cadeia de boot, ou subverter o próprio KTRR.
Example Um exploit de elevação de privilégio salta para EL1 e escreve um trampoline em uma função do kernel (por exemplo no handler de `syscall`). Mas porque as páginas estão bloqueadas como somente-leitura pelo KTRR, a escrita falha (ou dispara uma falha), então os patches não são aplicados.

8. Pointer Authentication Codes (PAC)

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

  • PAC é uma feature de hardware introduzida em ARMv8.3-A para detectar adulteração de valores de ponteiro (return addresses, function pointers, certos data pointers) ao embutir uma pequena assinatura criptográfica (um “MAC”) nos bits altos não usados do ponteiro.
  • A assinatura (“PAC”) é computada sobre o valor do ponteiro mais um modifier (um valor de contexto, por exemplo stack pointer ou algum dado distintivo). Dessa forma o mesmo valor de ponteiro em contextos diferentes recebe um PAC diferente.
  • No momento do uso, antes de dreferenciar ou fazer branch via esse ponteiro, uma instrução de authenticate checa o PAC. Se válido, o PAC é removido e o ponteiro puro é obtido; se inválido, o ponteiro fica “poisoned” (ou uma falha é gerada).
  • As chaves usadas para produzir/validar PACs residem em registradores privilegiados (EL1, kernel) e não são diretamente legíveis a partir do modo usuário.
  • Porque nem todos os 64 bits de um ponteiro são usados em muitos sistemas (por ex. espaço de endereçamento de 48 bits), os bits superiores são “espaciais” e podem conter o PAC sem alterar o endereço efetivo.

Architectural Basis & Key Types

  • ARMv8.3 introduz cinco chaves de 128-bit (cada uma implementada via dois registradores de 64-bit de sistema) para pointer authentication.

  • APIAKey — para instruction pointers (domínio “I”, chave A)

  • APIBKey — segunda chave de instruction pointer (domínio “I”, chave B)

  • APDAKey — para data pointers (domínio “D”, chave A)

  • APDBKey — para data pointers (domínio “D”, chave B)

  • APGAKey — chave “genérica”, para assinar dados não-ponteiro ou outros usos genéricos

  • Essas chaves são armazenadas em registradores de sistema privilegiados (acessíveis apenas em EL1/EL2 etc.), não acessíveis do modo usuário.

  • O PAC é calculado via uma função criptográfica (ARM sugere QARMA como algoritmo) usando:

  1. O valor do ponteiro (porção canônica)
  2. Um modifier (um valor de contexto, como um salt)
  3. A chave secreta
  4. Alguma lógica interna de tweak Se o PAC resultante corresponder ao que está armazenado nos bits altos do ponteiro, a autenticação tem sucesso.

Instruction Families

A convenção de nomes é: PAC / AUT / XPAC, depois as letras do domínio.

  • PACxx instruções assinam um ponteiro e inserem um PAC
  • AUTxx instruções autenticam + removem (validam e removem o PAC)
  • XPACxx instruções removem sem validar

Domains / sufixos:

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

Existem formas especializadas / aliases:

  • PACIASP é atalho para PACIA X30, SP (assinar o link register usando SP como modifier)
  • AUTIASP é AUTIA X30, SP (autenticar link register com SP)
  • Formas combinadas como RETAA, RETAB (authenticate-and-return) ou BLRAA (authenticate & branch) existem em extensões ARM / suporte de compilador.
  • Também variantes com modifier zero: PACIZA / PACIZB onde o modifier é implicitamente zero, etc.

Modifiers

O objetivo principal do modifier é vincular o PAC a um contexto específico para que o mesmo endereço assinado em frames ou objetos diferentes produza PACs diferentes. É como adicionar um salt a um hash.

Portanto:

  • O modifier é um valor de contexto (outro registrador) que é misturado no cálculo do PAC. Escolhas típicas: stack pointer (SP), frame pointer, ou algum ID de objeto.
  • Usar SP como modifier é comum para signing do return address: o PAC fica atrelado ao frame de stack específico. Se você tentar reutilizar o LR em um frame diferente, o modifier muda, então a validação do PAC falha.
  • O mesmo valor de ponteiro assinado sob modifiers diferentes produz PACs diferentes.
  • O modifier não precisa ser secreto, mas idealmente não é controlado pelo atacante.
  • Para instruções que assinam ou verificam ponteiros onde nenhum modifier significativo existe, algumas formas usam zero ou uma constante implícita.

Apple / iOS / XNU Customizations & Observations

  • A implementação de PAC da Apple inclui diversificadores por boot de modo que chaves ou tweaks mudam a cada boot, impedindo reuso entre boots.
  • Eles também incluem mitigações cross-domain de forma que PACs assinados em user mode não possam ser facilmente reutilizados em kernel mode, etc.
  • No Apple M1 / Apple Silicon, engenharia reversa mostrou que há nove tipos de modifier e registradores de sistema específicos da Apple para controle de chaves.
  • A Apple usa PAC em muitos subsistemas do kernel: signing de return address, integridade de ponteiros em dados do kernel, signed thread contexts, etc.
  • Google Project Zero mostrou como, sob uma primitive poderosa de leitura/escrita de memória no kernel, era possível forjar PACs do kernel (para chaves A) em dispositivos da era A12, mas a Apple corrigiu muitos desses caminhos.
  • No sistema da Apple, algumas chaves são globais ao kernel, enquanto processos de usuário podem receber randomness por-processo para chaves.

PAC Bypasses

  1. Kernel-mode PAC: theoretical vs real bypasses
  • Porque as chaves e a lógica de PAC do kernel são rigidamente controladas (registradores privilegiados, diversificadores, isolamento de domínio), forjar ponteiros assinados arbitrários do kernel é muito difícil.
  • Azad's 2020 "iOS Kernel PAC, One Year Later" relata que em iOS 12-13 ele encontrou alguns bypasses parciais (signing gadgets, reuse de signed states, indirect branches sem proteção) mas nenhum bypass genérico completo. bazad.github.io
  • As customizações da Apple detalhadas em "Dark Magic" estreitam ainda mais as superfícies exploráveis (domain switching, bits de habilitação por chave). i.blackhat.com
  • Há um conhecido kernel PAC bypass CVE-2023-32424 em Apple silicon (M1/M2) reportado por Zecao Cai et al. i.blackhat.com
  • Mas esses bypasses frequentemente dependem de gadgets muito específicos ou bugs de implementação; não são bypasses de uso geral.

Assim, PAC no kernel é considerado altamente robusto, embora não perfeito.

  1. User-mode / runtime PAC bypass techniques

Esses são mais comuns, e exploram imperfeições em como o PAC é aplicado ou usado no dynamic linking / runtime frameworks. Abaixo estão classes, com exemplos.

2.1 Shared Cache / A key issues

  • O dyld shared cache é um grande blob pre-linked de frameworks e libraries do sistema. Porque é tão amplamente compartilhado, ponteiros de função dentro do shared cache são “pre-signed” e então usados por muitos processos. Atacantes miram esses ponteiros já assinados como “PAC oracles”.

  • Algumas técnicas de bypass tentam extrair ou reutilizar ponteiros assinados com A-key presentes no shared cache e reutilizá-los em gadgets.

  • A talk "No Clicks Required" descreve construir um oracle sobre o shared cache para inferir endereços relativos e combinar isso com ponteiros assinados para burlar PAC. saelo.github.io

  • Além disso, imports de function pointers de shared libraries em userspace foram encontradas insuficientemente protegidas por PAC, permitindo que um atacante obtenha ponteiros de função sem alterar sua assinatura. (entrada de bug do Project Zero) bugs.chromium.org

2.2 dlsym(3) / dynamic symbol resolution

  • Um bypass conhecido é chamar dlsym() para obter um ponteiro de função já assinado (signed com A-key, diversifier zero) e então usá-lo. Como dlsym retorna um ponteiro legitimamente assinado, usá-lo contorna a necessidade de forjar PAC.

  • O blog da Epsilon detalha como alguns bypasses exploram isso: chamar dlsym("someSym") retorna um ponteiro assinado e pode ser usado para chamadas indiretas. blog.epsilon-sec.com

  • A publicação da Synacktiv "iOS 18.4 --- dlsym considered harmful" descreve um bug: alguns símbolos resolvidos via dlsym em iOS 18.4 retornam ponteiros que estão incorretamente assinados (ou com diversifiers bugados), permitindo bypass não intencional do PAC. Synacktiv

  • A lógica no dyld para dlsym inclui: quando result->isCode, eles assinam o ponteiro retornado com __builtin_ptrauth_sign_unauthenticated(..., key_asia, 0), i.e. contexto zero. blog.epsilon-sec.com

Assim, dlsym é um vetor frequente em bypasses de PAC em user-mode.

2.3 Other DYLD / runtime relocations

  • O loader DYLD e a lógica de relocação dinâmica são complexos e às vezes mapeiam temporariamente páginas como read/write para realizar relocations, depois as tornam read-only novamente. Atacantes exploram essas janelas. A palestra da Synacktiv descreve "Operation Triangulation", um bypass baseado em timing do PAC via relocations dinâmicas. Synacktiv

  • Páginas do DYLD agora são protegidas com SPRR / VM_FLAGS_TPRO (algumas flags de proteção para dyld). Mas versões anteriores tinham guardas mais fracos. Synacktiv

  • Em cadeias de exploit do WebKit, o loader DYLD é frequentemente alvo para bypass de PAC. Os slides mencionam que muitos bypasses de PAC miraram o DYLD loader (via relocation, interposer hooks). Synacktiv

2.4 NSPredicate / NSExpression / ObjC / SLOP

  • Em cadeias de exploit userland, métodos do runtime Objective-C como NSPredicate, NSExpression ou NSInvocation são usados para contrabandear chamadas de controle sem forjar ponteiros de forma óbvia.

  • Em iOS mais antigos (antes do PAC), um exploit usou fake NSInvocation objects para chamar selectors arbitrários em memória controlada. Com PAC, modificações são necessárias. Mas a técnica SLOP (SeLector Oriented Programming) foi estendida sob PAC também. Project Zero

  • A técnica original SLOP permitia encadear chamadas ObjC criando invocations falsos; o bypass se apoiava no fato de que ISA ou selector pointers às vezes não eram totalmente protegidos por PAC. Project Zero

  • Em ambientes onde pointer authentication é aplicada parcialmente, métodos / selectors / target pointers podem não ter proteção PAC completa, abrindo espaço para 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>Exemplo</summary>
A buffer overflow sobrescreve um endereço de retorno na stack. O atacante escreve o endereço do gadget alvo mas não consegue calcular o PAC correto. Quando a função retorna, a instrução `AUTIA` da CPU falha por causa da incompatibilidade do PAC. A cadeia falha.
A análise do Project Zero sobre A12 (iPhone XS) mostrou como o PAC da Apple é usado e métodos de forjar PACs se um atacante tem um primitive de leitura/escrita de memória.
</details>


### 9. **Branch Target Identification (BTI)**
**Introduzido com ARMv8.5 (hardware mais recente)**
BTI é uma feature de hardware que verifica **indirect branch targets**: ao executar `blr` ou chamadas/jumps indiretos, o alvo deve começar com um **BTI landing pad** (`BTI j` ou `BTI c`). Saltar para endereços de gadget que não têm o landing pad dispara uma exceção.

A implementação do LLVM nota três variantes de instruções BTI e como elas mapeiam para tipos de branch.

| BTI Variant | O que permite (quais tipos de branch) | Colocação típica / caso de uso |
|-------------|----------------------------------------|-------------------------------|
| **BTI C** | Targets de indirect branches estilo *call* (e.g. `BLR`, ou `BR` usando X16/X17) | Colocado na entrada de funções que podem ser chamadas indiretamente |
| **BTI J** | Targets de branches estilo *jump* (e.g. `BR` usado para tail calls) | Colocado no início de blocks alcançáveis por jump tables ou tail-calls |
| **BTI JC** | Atua como ambos C e J | Pode ser alvo tanto por call quanto por jump branches |

- Em código compilado com branch target enforcement, os compiladores inserem uma instrução BTI (C, J, ou JC) em cada indirect-branch target válido (inícios de funções ou blocos alcançáveis por jumps) para que indirect branches só tenham sucesso nesses lugares.
- **Direct branches / calls** (i.e. endereços fixos `B`, `BL`) **não são restringidos** por BTI. A suposição é que páginas de código são confiáveis e o atacante não pode alterá-las (então direct branches são seguros).
- Além disso, instruções `RET` / return geralmente não são restringidas por BTI porque os endereços de retorno são protegidos via PAC ou mecanismos de return signing.

#### Mecanismo e aplicação

- Quando a CPU decodifica um **indirect branch (BLR / BR)** numa página marcada como “guarded / BTI-enabled,” ela verifica se a primeira instrução do endereço alvo é um BTI válido (C, J, ou JC conforme permitido). Se não for, ocorre uma **Branch Target Exception**.
- A codificação da instrução BTI foi desenhada para reutilizar opcodes previamente reservados para NOPs (em versões ARM anteriores). Assim, binários com BTI continuam backward-compatible: em hardware sem suporte a BTI, essas instruções funcionam como NOPs.
- Os passes do compilador que adicionam BTIs inserem-nos apenas onde necessário: funções que podem ser chamadas indiretamente, ou basic blocks alvos de jumps.
- Alguns patches e código do LLVM mostram que BTI não é inserido para *todos* os basic blocks — apenas aqueles que são potenciais targets de branch (e.g. de switch / jump tables).

#### Sinergia BTI + PAC

PAC protege o valor do pointer (a origem) — assegura que a cadeia de chamadas/retornos indiretos não foi adulterada.

BTI garante que mesmo um pointer válido só pode apontar para entry points devidamente marcados.

Combinados, um atacante precisa de ambos: um pointer válido com PAC correto e que o alvo tenha um BTI colocado lá. Isso aumenta a dificuldade de construir gadgets de exploit.

#### Exemplo


<details>
<summary>Exemplo</summary>
Um exploit tenta pivotar para um gadget em `0xABCDEF` que não começa com `BTI c`. A CPU, ao executar `blr x0`, verifica o alvo e falha porque o alinhamento da instrução não inclui um landing pad válido. Assim muitos gadgets tornam-se inutilizáveis a menos que incluam o prefixo BTI.
</details>


### 10. **Privileged Access Never (PAN) & Privileged Execute Never (PXN)**
**Introduzido em extensões ARMv8 mais recentes / suporte iOS (para kernel hardened)**

#### PAN (Privileged Access Never)

- **PAN** é uma feature introduzida no **ARMv8.1-A** que previne que código **privilegiado** (EL1 ou EL2) **leia ou escreva** memória marcada como **user-accessible (EL0)**, a menos que PAN seja explicitamente desativado.
- A ideia: mesmo que o kernel seja enganado ou comprometido, ele não pode desreferenciar ponteiros do espaço do usuário arbitrariamente sem primeiro *limpar* PAN, reduzindo o risco de exploits estilo **`ret2usr`** ou uso indevido de buffers controlados pelo usuário.
- Quando PAN está habilitado (PSTATE.PAN = 1), qualquer instrução privilegiada de load/store que acesse um endereço virtual que seja “accessible at EL0” dispara uma **permission fault**.
- O kernel, quando precisa legitimamente acessar memória do usuário (e.g. copiar dados de/para buffers do usuário), deve **desabilitar temporariamente PAN** (ou usar instruções de “unprivileged load/store”) para permitir esse acesso.
- No Linux em ARM64, o suporte a PAN foi introduzido por volta de 2015: patches no kernel adicionaram detecção da feature, e substituíram `get_user` / `put_user` etc. por variantes que limpam PAN ao redor de acessos à memória do usuário.

**Nuance / limitação / bug**
- Como notado por Siguza e outros, um bug de especificação (ou comportamento ambíguo) no design ARM significa que **execute-only user mappings** (`--x`) podem **não acionar PAN**. Em outras palavras, se uma página de usuário estiver marcada como executável mas sem permissão de leitura, a tentativa do kernel de ler pode contornar PAN porque a arquitetura considera “accessible at EL0” como requerendo permissão de leitura, não apenas executável. Isso leva a um bypass de PAN em certas configurações.
- Por causa disso, se iOS / XNU permite páginas de usuário execute-only (como algumas configurações JIT ou code-cache podem fazer), o kernel pode ler acidentalmente delas mesmo com PAN habilitado. Esta é uma área sutil conhecida por ser potencialmente explorável em alguns sistemas ARMv8+.

#### PXN (Privileged eXecute Never)

- **PXN** é um flag de page table (nas entradas da page table, leaf ou block entries) que indica que a página é **não-executável quando executada em modo privilegiado** (i.e. quando EL1 executa).
- PXN previne que o kernel (ou qualquer código privilegiado) faça jump para ou execute instruções de páginas do espaço do usuário mesmo se o controle for desviado. Na prática, impede uma redireção de control-flow ao nível do kernel para memória do usuário.
- Combinado com PAN, isso garante que:
1. O kernel não pode (por padrão) ler ou escrever dados do usuário (PAN)
2. O kernel não pode executar código do usuário (PXN)
- No formato de page table ARMv8, as entradas leaf têm um bit `PXN` (e também `UXN` para unprivileged execute-never) nos seus bits de atributo.

Portanto, mesmo se o kernel tiver um function pointer corrompido apontando para memória do usuário, e tentar fazer branch para lá, o bit PXN causaria uma fault.

#### Modelo de permissões de memória & como PAN e PXN mapeiam para bits da page table

Para entender como PAN / PXN operam, é preciso ver como a tradução e o modelo de permissões do ARM funcionam (simplificado):

- Cada page ou block entry tem campos de atributo incluindo **AP[2:1]** para permissões de acesso (read/write, privileged vs unprivileged) e bits **UXN / PXN** para restrições de execute-never.
- Quando PSTATE.PAN está 1 (habilitado), o hardware aplica semântica modificada: acessos privilegiados a páginas marcadas como “accessible by EL0” (i.e. acessíveis pelo usuário) são negados (fault).
- Por causa do bug mencionado, páginas marcadas apenas como executáveis (sem permissão de leitura) podem não contar como “accessible by EL0” em certas implementações, portanto contornando PAN.
- Quando o bit PXN de uma página está setado, mesmo que o fetch de instrução venha de um nível de privilégio superior, a execução é proibida.

#### Uso do kernel de PAN / PXN em um OS hardened (e.g. iOS / XNU)

Em um design de kernel hardened (como o que a Apple pode usar):

- O kernel habilita PAN por padrão (portanto o código privilegiado é restringido).
- Em caminhos que legitimamente precisam ler ou escrever buffers do usuário (e.g. cópia de buffer de syscall, I/O, read/write de user pointer), o kernel desabilita PAN temporariamente ou usa instruções especiais para sobrepor.
- Depois de terminar o acesso a dados do usuário, deve reabilitar PAN.
- PXN é aplicado via page tables: páginas do usuário têm PXN = 1 (portanto o kernel não pode executá-las), páginas do kernel não têm PXN (portanto código do kernel pode ser executado).
- O kernel deve garantir que nenhum caminho de código cause fluxo de execução para regiões de memória do usuário (o que contornaria PXN) — então cadeias de exploit que dependem de “jump para shellcode controlado pelo usuário” são bloqueadas.

Devido ao bypass de PAN via páginas execute-only, em um sistema real, a Apple pode desabilitar ou não permitir páginas execute-only de usuário, ou aplicar patches que contornem a fraqueza da especificação.


#### Superfícies de ataque, bypasses e mitigations

- **PAN bypass via execute-only pages**: como discutido, a spec permite uma lacuna: páginas do usuário com execute-only (sem permissão de leitura) podem não ser contadas como “accessible at EL0,” então PAN não bloqueará leituras do kernel dessas páginas em algumas implementações. Isso dá ao atacante um caminho incomum para injetar dados via seções “execute-only”.
- **Exploit de janela temporal**: se o kernel desabilita PAN por uma janela maior do que o necessário, uma race ou caminho malicioso pode explorar essa janela para realizar acessos não-intencionados à memória do usuário.
- **Esquecer de reabilitar**: se caminhos de código falham em reabilitar PAN, operações subsequentes do kernel podem acessar incorretamente memória do usuário.
- **Misconfiguração de PXN**: se as page tables não setarem PXN nas páginas do usuário ou mapearem incorretamente páginas de código do usuário, o kernel pode ser enganado a executar código do espaço do usuário.
- **Speculation / side-channels**: análogo a bypasses especulativos, podem existir efeitos microarquiteturais transitórios que causem violação transitória das checagens PAN / PXN (embora tais ataques dependam muito do design da CPU).
- **Interações complexas**: em features mais avançadas (e.g. JIT, shared memory, just-in-time code regions), o kernel pode precisar de controle fino para permitir certos acessos à memória ou execução em regiões mapeadas ao usuário; projetar isso com segurança sob restrições PAN/PXN não é trivial.


#### Exemplo

<details>
<summary>Exemplo de Código</summary>
Here are illustrative pseudo-assembly sequences showing enabling/disabling PAN around user memory access, and how a fault might occur.
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">  </span></div>

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

Se o kernel **não** tivesse setado PXN nessa página de usuário, então o branch poderia ter sucesso — o que seria inseguro.

Se o kernel esquecer de reativar PAN após o acesso à memória do usuário, isso abre uma janela em que lógica adicional do kernel pode acidentalmente ler/escrever memória de usuário arbitrária.

Se o ponteiro do usuário apontar para uma página de execute-only (página do usuário com apenas permissão de execução, sem read/write), sob o bug da especificação PAN, `ldr W2, [X1]` pode **não** falhar mesmo com PAN habilitado, permitindo um exploit de bypass, dependendo da implementação.

</details>

<details>
<summary>Example</summary>
Uma vulnerabilidade no kernel tenta pegar um ponteiro de função fornecido pelo usuário e chamá-lo no contexto do kernel (i.e. `call user_buffer`). Sob PAN/PXN, essa operação é proibida ou causa fault.
</details>

---

### 11. **Top Byte Ignore (TBI) / Pointer Tagging**
**Introduzido em ARMv8.5 / versões mais recentes (ou extensão opcional)**
TBI significa que o top byte (most-significant byte) de um ponteiro de 64 bits é ignorado pela tradução de endereço. Isso permite que o OS ou hardware incorporem **tag bits** no top byte do ponteiro sem afetar o endereço real.

- TBI stands for **Top Byte Ignore** (às vezes chamado de *Address Tagging*). É um recurso de hardware (disponível em muitas implementações ARMv8+) que **ignora os 8 bits mais altos** (bits 63:56) de um ponteiro de 64 bits ao realizar **address translation / load/store / instruction fetch**.
- Na prática, a CPU trata um ponteiro `0xTTxxxx_xxxx_xxxx` (onde `TT` = top byte) como `0x00xxxx_xxxx_xxxx` para efeitos de tradução de endereço, ignorando (mascarando) o top byte. O top byte pode ser usado pelo software para armazenar **metadata / tag bits**.
- Isso dá ao software um espaço in-band “gratuito” para incorporar um byte de tag em cada ponteiro sem alterar a localização de memória à qual se refere.
- A arquitetura garante que loads, stores, and instruction fetch tratem o ponteiro com seu top byte mascarado (i.e. tag removido) antes de realizar o acesso real à memória.

Assim, TBI desacopla o **logical pointer** (pointer + tag) do **physical address** usado para operações de memória.

#### Why TBI: Use cases and motivation

- **Pointer tagging / metadata**: Você pode armazenar metadata extra (e.g. object type, version, bounds, integrity tags) nesse top byte. Quando você usar o ponteiro depois, a tag é ignorada a nível de hardware, então não é necessário removê-la manualmente antes do acesso à memória.
- **Memory tagging / MTE (Memory Tagging Extension)**: TBI é o mecanismo de hardware base no qual MTE se apoia. No ARMv8.5, a **Memory Tagging Extension** usa os bits 59:56 do ponteiro como uma **logical tag** e os verifica contra uma **allocation tag** armazenada na memória.
- **Enhanced security & integrity**: Ao combinar TBI com pointer authentication (PAC) ou verificações em runtime, você pode exigir não só o valor do ponteiro, mas também que a tag esteja correta. Um atacante que sobrescrever um ponteiro sem a tag correta produzirá uma tag não correspondente.
- **Compatibility**: Como TBI é opcional e os tag bits são ignorados pelo hardware, código legado sem tags continua a operar normalmente. Os tag bits efetivamente se tornam bits “don’t care” para código legado.

#### Example
<details>
<summary>Example</summary>
Um ponteiro de função incluía uma tag no seu top byte (por exemplo `0xAA`). Um exploit sobrescreve os bits baixos do ponteiro mas negligencia a tag, então quando o kernel verifica ou sanitiza, o ponteiro falha ou é rejeitado.
</details>

---

### 12. **Page Protection Layer (PPL)**
**Introduzido em iOS recente / hardware moderno (iOS ~17 / Apple silicon / modelos high-end)** (alguns relatos mostram PPL por volta do macOS / Apple silicon, mas a Apple está trazendo proteções análogas para iOS)

- PPL é projetado como uma **intra-kernel protection boundary**: mesmo se o kernel (EL1) estiver comprometido e tiver capacidades de read/write, **ele não deveria poder modificar livremente** certas **páginas sensíveis** (especialmente page tables, code-signing metadata, kernel code pages, entitlements, trust caches, etc.).
- Efetivamente cria um **“kernel dentro do kernel”** — um componente menor e confiável (PPL) com **privilégios elevados** que sozinho pode modificar páginas protegidas. Outro código do kernel deve chamar rotinas PPL para efetuar mudanças.
- Isso reduz a superfície de ataque para exploits de kernel: mesmo com R/W/execute arbitrário em modo kernel, o código de exploit também precisa de alguma forma entrar no domínio PPL (ou contornar o PPL) para modificar estruturas críticas.
- Em Apple silicon mais recentes (A15+ / M2+), a Apple está migrando para **SPTM (Secure Page Table Monitor)**, que em muitos casos substitui o PPL para proteção de page tables nessas plataformas.

Eis como se acredita que o PPL opere, com base em análises públicas:

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

- O hardware Apple usa um mecanismo chamado **APRR (Access Permission ReRouting)**, que permite que page table entries (PTEs) contenham pequenos índices, ao invés de bits de permissão completos. Esses índices são mapeados via registradores APRR para permissões reais. Isso permite remapping dinâmico de permissões por domínio.
- O PPL aproveita o APRR para segregar privilégios dentro do contexto do kernel: apenas o domínio PPL tem permissão para atualizar o mapeamento entre índices e permissões efetivas. Ou seja, quando código de kernel não-PPL escreve um PTE ou tenta alterar bits de permissão, a lógica APRR o impede (ou impõe um mapeamento read-only).
- O código PPL em si roda em uma região restringida (ex.: `__PPLTEXT`) que normalmente é não-executável ou não-escritível até que portões de entrada a permitam temporariamente. O kernel chama pontos de entrada PPL (“PPL routines”) para executar operações sensíveis.

#### Gate / Entry & Exit

- Quando o kernel precisa modificar uma página protegida (ex.: alterar permissões de uma página de código do kernel, ou modificar page tables), ele chama uma rotina **PPL wrapper**, que faz validação e então transita para o domínio PPL. Fora desse domínio, as páginas protegidas são efetivamente read-only ou não modificáveis pelo kernel principal.
- Durante a entrada no PPL, os mappings APRR são ajustados para que as páginas de memória na região PPL fiquem **executable & writable** dentro do PPL. Ao sair, elas retornam a read-only / non-writable. Isso garante que somente rotinas PPL bem auditadas possam escrever nas páginas protegidas.
- Fora do PPL, tentativas de código do kernel de escrever nessas páginas protegidas irão falhar (permission denied) porque o mapeamento APRR para aquele domínio de código não permite escrita.

#### Protected page categories

As páginas que o PPL normalmente protege incluem:

- Estruturas de page table (translation table entries, mapping metadata)
- Kernel code pages, especialmente aquelas contendo lógica crítica
- Code-sign metadata (trust caches, signature blobs)
- Entitlement tables, signature enforcement tables
- Outras estruturas de alto valor do kernel em que um patch permitiria contornar verificações de assinatura ou manipulação de credenciais

A ideia é que mesmo se a memória do kernel estiver totalmente controlada, o atacante não possa simplesmente patchar ou reescrever essas páginas, a menos que também comprometa rotinas PPL ou contorne o PPL.


#### Known Bypasses & Vulnerabilities

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

- Um writeup público do Project Zero descreve um bypass envolvendo **stale TLB entries**.
- A ideia:

1. Alocar duas páginas físicas A e B, marcá-las como PPL páginas (assim são protegidas).
2. Mapear dois endereços virtuais P e Q cujas páginas da L3 translation table vêm de A e B.
3. Rodar uma thread que acesse continuamente Q, mantendo sua entrada de TLB viva.
4. Chamar `pmap_remove_options()` para remover mapeamentos começando em P; devido a um bug, o código remove por engano os TTEs tanto de P quanto de Q, mas apenas invalida a entrada TLB de P, deixando a entrada stale de Q viva.
5. Reusar B (a tabela da página Q) para mapear memória arbitrária (ex.: PPL-protected pages). Porque a stale TLB entry ainda mapeia o velho mapeamento de Q, esse mapeamento permanece válido para aquele contexto.
6. Por meio disso, o atacante pode colocar um mapeamento writável de PPL-protected pages no lugar sem passar pela interface PPL.

- Esse exploit exigiu controle fino do mapeamento físico e do comportamento do TLB. Isso demonstra que uma fronteira de segurança que depende da corretude do TLB / mapping precisa ser extremamente cuidadosa com invalidações de TLB e consistência de mapeamento.

- O Project Zero comentou que bypasses como esse são sutis e raros, mas possíveis em sistemas complexos. Mesmo assim, eles consideram o PPL uma mitigação sólida.

2. **Other potential hazards & constraints**

- Se um exploit de kernel puder entrar diretamente nas rotinas PPL (via chamada aos PPL wrappers), ele pode contornar as restrições. Assim, a validação de argumentos é crítica.
- Bugs no próprio código PPL (ex.: arithmetic overflow, boundary checks) podem permitir modificações out-of-bounds dentro do PPL. O Project Zero observou que um bug desse tipo em `pmap_remove_options_internal()` foi explorado em seu bypass.
- A fronteira PPL está irrevogavelmente ligada à aplicação do enforcement do hardware (APRR, memory controller), então é tão forte quanto a implementação do hardware.



#### Example
<details>
<summary>Code Example</summary>
Aqui está um pseudocódigo / lógica simplificada mostrando como um kernel pode chamar o PPL para modificar páginas protegidas:
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">c</span></div>

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

O kernel pode realizar muitas operações normais, mas somente através das rotinas ppl_call_* ele pode alterar mappings protegidos ou patchar código.

Exemplo Um kernel exploit tenta sobrescrever a entitlement table, ou desabilitar a enforcement do code-sign ao modificar um kernel signature blob. Como essa página é protegida pelo PPL, a escrita é bloqueada a menos que passe pela interface PPL. Portanto, mesmo com execução de código no kernel, você não pode contornar as restrições de code-sign ou modificar dados de credenciais arbitrariamente. No iOS 17+ certos dispositivos usam SPTM para isolar ainda mais páginas gerenciadas pelo PPL.

PPL → SPTM / Substituições / Futuro

  • Nos SoCs modernos da Apple (A15 ou mais recente, M2 ou mais recente), a Apple suporta SPTM (Secure Page Table Monitor), que substitui PPL para proteções de page table.
  • A Apple afirma na documentação: “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.”
  • A arquitetura SPTM provavelmente desloca mais a aplicação de políticas para um monitor de maior privilégio fora do controle do kernel, reduzindo ainda mais a fronteira de confiança.

MTE | EMTE | MIE

Aqui está uma descrição em alto nível de como o EMTE opera sob a configuração MIE da Apple:

  1. Atribuição de tag
  • Quando memória é alocada (ex.: no kernel ou em user space via secure allocators), uma tag secreta é atribuída a esse bloco.
  • O ponteiro retornado para o usuário ou kernel inclui essa tag nos bits altos (usando TBI / top byte ignore mechanisms).
  1. Verificação de tag no acesso
  • Sempre que um load ou store é executado usando um ponteiro, o hardware verifica se a tag do ponteiro corresponde à tag do bloco de memória (allocation tag). Se houver incompatibilidade, ocorre uma falha imediatamente (por ser síncrono).
  • Por ser síncrono, não há janela de “detecção atrasada”.
  1. Retagging ao free / reuse
  • Quando a memória é liberada, o allocator muda a tag do bloco (para que ponteiros antigos com tags antigas não mais correspondam).
  • Um ponteiro use-after-free teria, portanto, uma tag obsoleta e incompatibilidade quando acessado.
  1. Diferenciação de tags entre vizinhos para detectar overflows
  • Alocações adjacentes recebem tags distintas. Se um buffer overflow vaza para a memória do vizinho, a incompatibilidade de tags causa uma falha.
  • Isso é especialmente poderoso para detectar pequenos overflows que cruzam a fronteira.
  1. Aplicação da confidencialidade de tags
  • A Apple deve evitar que os valores de tag sejam leaked (porque se um atacante souber a tag, ele poderia forjar ponteiros com as tags corretas).
  • Eles incluem proteções (microarquiteturais / controles especulativos) para evitar a exposição por canais laterais dos bits de tag.
  1. Integração kernel e user-space
  • A Apple usa EMTE não apenas em user-space, mas também em componentes críticos do kernel/OS (para proteger o kernel contra corrupção de memória).
  • O hardware/OS garante que as regras de tag se apliquem mesmo quando o kernel está executando em nome do user space.
Exemplo ``` 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>

#### Limitações & desafios

- **Intrablock overflows**: Se o overflow permanecer dentro da mesma alocação (não cruzar o boundary) e a tag permanecer a mesma, tag mismatch não o detecta.
- **Tag width limitation**: Apenas alguns bits (ex.: 4 bits, ou domínio pequeno) estão disponíveis para a tag—namespace limitado.
- **Side-channel leaks**: Se os bits de tag puderem ser leaked (via cache / speculative execution), o atacante pode aprender tags válidas e contornar. A tag confidentiality enforcement da Apple visa mitigar isso.
- **Performance overhead**: Checks de tag em cada load/store adicionam custo; a Apple precisa otimizar o hardware para reduzir esse overhead.
- **Compatibility & fallback**: Em hardware mais antigo ou em partes que não suportam EMTE, deve existir fallback. A Apple afirma que MIE só é habilitado em dispositivos com suporte.
- **Complex allocator logic**: O allocator precisa gerenciar tags, retagging, alinhar boundaries e evitar colisões de mis-tag. Bugs na lógica do allocator podem introduzir vulnerabilidades.
- **Mixed memory / hybrid areas**: Parte da memória pode permanecer untagged (legacy), tornando a interoperabilidade mais complicada.
- **Speculative / transient attacks**: Como em muitas proteções microarquiteturais, speculative execution ou micro-op fusions podem contornar checks de forma transitória ou leak bits de tag.
- **Limited to supported regions**: A Apple pode aplicar EMTE apenas em áreas seletivas e de alto risco (kernel, subsistemas críticos de segurança), não universalmente.



---

## Principais melhorias / diferenças comparadas ao MTE padrão

Aqui estão as melhorias e mudanças que a Apple enfatiza:

| Feature | Original MTE | EMTE (Apple’s enhanced) / MIE |
|---|---|---|
| **Check mode** | Supports synchronous and asynchronous modes. In async, tag mismatches are reported later (delayed)| Apple insiste em **synchronous mode** por padrão—tag mismatches são detectados imediatamente, sem janelas de delay/race.|
| **Coverage of non-tagged memory** | Accesses to non-tagged memory (e.g. globals) may bypass checks in some implementations | EMTE exige que acessos de uma região tagged para memória non-tagged também validem conhecimento da tag, dificultando bypass por mistura de alocações.|
| **Tag confidentiality / secrecy** | Tags might be observable or leaked via side channels | A Apple adiciona **Tag Confidentiality Enforcement**, que tenta prevenir leak de valores de tag (via speculative side-channels etc.).|
| **Allocator integration & retagging** | MTE leaves much of allocator logic to software | Secure typed allocators da Apple (kalloc_type, xzone malloc, etc.) se integram com EMTE: quando memória é alocada ou liberada, tags são gerenciadas em granularidade fina.|
| **Always-on by default** | In many platforms, MTE is optional or off by default | A Apple habilita EMTE / MIE por padrão em hardware suportado (ex.: iPhone 17 / A19) para kernel e muitos processos de user-space.|

Como a Apple controla tanto o hardware quanto a stack de software, ela pode impor EMTE de forma estrita, evitar problemas de performance e fechar vetores de side-channel.

---

## Como EMTE funciona na prática (Apple / MIE)

Aqui está uma descrição de alto nível de como EMTE opera sob o setup MIE da Apple:

1. **Tag assignment**
- Quando memória é alocada (ex.: no kernel ou user space via secure allocators), uma **secret tag** é atribuída ao bloco.
- O pointer retornado ao usuário ou kernel inclui essa tag nos bits altos (usando TBI / top byte ignore mechanisms).

2. **Tag checking on access**
- Sempre que um load ou store é executado usando um pointer, o hardware verifica se a tag do pointer bate com a tag do bloco de memória (allocation tag). Em caso de mismatch, ocorre fault imediatamente (já que é síncrono).
- Por ser síncrono, não existe uma janela de “detecção atrasada”.

3. **Retagging on free / reuse**
- Quando a memória é liberada, o allocator altera a tag do bloco (assim pointers antigos com tags velhas não batem mais).
- Um use-after-free terá, portanto, uma tag stale e causará mismatch quando acessado.

4. **Neighbor-tag differentiation to catch overflows**
- Alocações adjacentes recebem tags distintas. Se um buffer overflow derramar em memória do vizinho, tag mismatch provoca fault.
- Isso é especialmente eficaz para detectar small overflows que cruzam boundary.

5. **Tag confidentiality enforcement**
- A Apple precisa evitar que valores de tag sejam leakados (porque, se o atacante aprende a tag, pode forjar pointers com a tag correta).
- Eles incluem proteções (controles microarquiteturais / speculative) para prevenir side-channel leak de bits de tag.

6. **Kernel and user-space integration**
- A Apple usa EMTE não só em user-space mas também em componentes do kernel / críticos ao OS (para proteger o kernel contra corrupção de memória).
- Hardware/OS asseguram que as regras de tag se apliquem mesmo quando o kernel executa em nome do user space.

Como EMTE é construído sobre MIE, a Apple usa EMTE em modo síncrono nas principais superfícies de ataque, não como opt-in ou modo de debugging.



---

## Exception handling in XNU

Quando ocorre uma **exception** (ex.: `EXC_BAD_ACCESS`, `EXC_BAD_INSTRUCTION`, `EXC_CRASH`, `EXC_ARM_PAC`, etc.), a camada **Mach** do kernel XNU é responsável por interceptá‑la antes que se torne um **signal** estilo UNIX (como `SIGSEGV`, `SIGBUS`, `SIGILL`, ...).

Esse processo envolve múltiplas camadas de propagação e handling da exception antes de chegar ao user space ou ser convertido para um BSD signal.


### Exception Flow (High-Level)

1.  **CPU triggers a synchronous exception** (ex.: invalid pointer dereference, PAC failure, illegal instruction, etc.).

2.  **Low-level trap handler** runs (`trap.c`, `exception.c` in XNU source).

3.  O trap handler chama **`exception_triage()`**, o núcleo do Mach exception handling.

4.  `exception_triage()` decide como rotear a exception:

-   Primeiro para a **thread's exception port**.

-   Depois para a **task's exception port**.

-   Depois para a **host's exception port** (frequentemente `launchd` ou `ReportCrash`).

Se nenhuma dessas ports tratar a exception, o kernel pode:

-   **Convertê‑la em um BSD signal** (para processos user-space).

-   **Panic** (para exceptions no kernel-space).


### Core Function: `exception_triage()`

A função `exception_triage()` roteia Mach exceptions pela cadeia de possíveis handlers até que uma a trate ou até que seja finalmente fatal. Está definida em `osfmk/kern/exception.c`.
<div class="codeblock_filename_container"><span class="codeblock_filename_inner hljs">c</span></div>

```c
void exception_triage(exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t codeCnt);

Fluxo de Chamada Típico:

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

Se todas falharem → tratado por bsd_exception() → traduzido em um sinal como SIGSEGV.

Portas de Exceção

Cada objeto Mach (thread, task, host) pode registrar portas de exceção, para onde as mensagens de exceção são enviadas.

Elas são definidas pela API:

task_set_exception_ports()
thread_set_exception_ports()
host_set_exception_ports()

Cada exception port tem:

  • mask (quais exceções ele deseja receber)
  • port name (Mach port para receber mensagens)
  • behavior (como o kernel envia a mensagem)
  • flavor (qual thread state incluir)

Debuggers e tratamento de exceções

Um debugger (e.g., LLDB) configura um exception port na task ou thread alvo, normalmente usando task_set_exception_ports().

Quando uma exception ocorre:

  • A mensagem Mach é enviada para o processo do debugger.
  • O debugger pode decidir handle (retomar, modificar registradores, pular instrução) ou not handle a exception.
  • Se o debugger não a handle, a exception propaga para o próximo nível (task → host).

Fluxo de EXC_BAD_ACCESS

  1. Thread desreferencia um ponteiro inválido → CPU gera Data Abort.

  2. O trap handler do kernel chama exception_triage(EXC_BAD_ACCESS, ...).

  3. Mensagem enviada para:

  • Thread port → (debugger pode interceptar breakpoint).

  • Se o debugger ignorar → Task port → (handler a nível de processo).

  • Se ignorado → Host port (geralmente ReportCrash).

  1. Se ninguém tratar → bsd_exception() converte para SIGSEGV.

Exceções PAC

Quando Pointer Authentication (PAC) falha (incompatibilidade de assinatura), uma special Mach exception é levantada:

  • EXC_ARM_PAC (type)
  • Os códigos podem incluir detalhes (ex.: key type, pointer type).

Se o binário tiver a flag TFRO_PAC_EXC_FATAL, o kernel trata falhas de PAC como fatais, contornando a interceptação pelo debugger. Isso evita que atacantes usem debuggers para burlar checagens PAC e está habilitado para platform binaries.

Software Breakpoints

Um software breakpoint (int3 on x86, brk on ARM64) é implementado causando uma falha deliberada.
O debugger captura isso via o exception port:

  • Modifica o instruction pointer ou a memória.
  • Restaura a instrução original.
  • Retoma a execução.

Esse mesmo mecanismo permite "capturar" uma PAC exception --- a menos que TFRO_PAC_EXC_FATAL esteja definida, caso em que nunca alcança o debugger.

Conversão para sinais BSD

Se nenhum handler aceitar a exception:

  • O kernel chama task_exception_notify() → bsd_exception().

  • Isso mapeia Mach exceptions para sinais:

Mach ExceptionSignal
EXC_BAD_ACCESSSIGSEGV or SIGBUS
EXC_BAD_INSTRUCTIONSIGILL
EXC_ARITHMETICSIGFPE
EXC_SOFTWARESIGTRAP
EXC_BREAKPOINTSIGTRAP
EXC_CRASHSIGKILL
EXC_ARM_PACSIGILL (quando não fatal)

Arquivos-chave no código-fonte do XNU

  • osfmk/kern/exception.c → Núcleo de exception_triage(), exception_deliver_*().
  • bsd/kern/kern_sig.c → Lógica de entrega de sinais.
  • osfmk/arm64/trap.c → Manipuladores de trap de baixo nível.
  • osfmk/mach/exc.h → Códigos de exception e estruturas.
  • osfmk/kern/task.c → Configuração do exception port da task.

Heap do Kernel Antigo (Pre-iOS 15 / Pre-A12 era)

O kernel usava um zone allocator (kalloc) dividido em "zones" de tamanho fixo. Cada zone armazenava apenas alocações de uma única classe de tamanho.

A partir do screenshot:

Nome da ZoneTamanho do ElementoExemplo de Uso
default.kalloc.1616 bytesStructs muito pequenos do kernel, ponteiros.
default.kalloc.3232 bytesStructs pequenos, cabeçalhos de objetos.
default.kalloc.6464 bytesIPC messages, pequenos buffers do kernel.
default.kalloc.128128 bytesObjetos médios como partes de OSObject.
default.kalloc.12801280 bytesEstruturas grandes, metadata de IOSurface/graphics.

Como funcionava:

  • Cada requisição de alocação era arredondada para cima ao tamanho da zone mais próxima. (P.ex., uma requisição de 50 bytes caía na zone kalloc.64).
  • A memória em cada zone era mantida em uma freelist — chunks liberados pelo kernel voltavam para aquela zone.
  • Se você overflowasse um buffer de 64 bytes, sobrescreveria o próximo objeto na mesma zone.

É por isso que heap spraying / feng shui era tão eficaz: você podia prever os vizinhos de objetos ao sprayar alocações da mesma classe de tamanho.

The freelist

Dentro de cada zone do kalloc, objetos liberados não voltavam diretamente para o sistema — iam para uma freelist, uma lista ligada de chunks disponíveis.

  • Quando um chunk era liberado, o kernel escrevia um pointer no início daquele chunk → o endereço do próximo chunk livre na mesma zone.

  • A zone mantinha um pointer HEAD para o primeiro chunk livre.

  • A alocação sempre usava o HEAD atual:

  1. Pop HEAD (retorna essa memória para o caller).

  2. Atualiza HEAD = HEAD->next (armazenado no header do chunk liberado).

  • Ao liberar, os chunks eram empurrados de volta:

  • freed_chunk->next = HEAD

  • HEAD = freed_chunk

Portanto, a freelist era apenas uma lista ligada construída dentro da própria memória liberada.

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)

Exploração do freelist

Como os primeiros 8 bytes de um free chunk = freelist pointer, um atacante poderia corrompê-lo:

  1. Heap overflow em um freed chunk adjacente → sobrescrever seu “next” pointer.

  2. Use-after-free: escrever em um freed object → sobrescrever seu “next” pointer.

Então, na próxima alocação desse tamanho:

  • O allocator retira o chunk corrompido.

  • Segue o “next” pointer fornecido pelo atacante.

  • Retorna um pointer para memória arbitrária, permitindo fake object primitives ou targeted overwrite.

Exemplo visual de freelist poisoning:

Before corruption:
HEAD ──► [ F1 ] ──► [ F2 ] ──► [ F3 ] ──► NULL

After attacker overwrite of F1->next:
HEAD ──► [ F1 ]
(next) ──► 0xDEAD_BEEF_CAFE_BABE  (attacker-chosen)

Next alloc of this zone → kernel hands out memory at attacker-controlled address.

This freelist design made exploitation highly effective pre-hardening: predictable neighbors from heap sprays, raw pointer freelist links, and no type separation allowed attackers to escalate UAF/overflow bugs into arbitrary kernel memory control.

Heap Grooming / Feng Shui

O objetivo do heap grooming é modelar o layout do heap para que, quando um atacante dispara um overflow ou use-after-free, o objeto alvo (victim) fique imediatamente ao lado de um objeto controlado pelo atacante.
Dessa forma, quando a corrupção de memória ocorrer, o atacante pode sobrescrever de forma confiável o objeto victim com dados controlados.

Passos:

  1. Spray allocations (fill the holes)
  • Com o tempo, o kernel heap fica fragmentado: algumas zonas têm buracos onde objetos antigos foram liberados.
  • O atacante primeiro faz muitas alocações dummy para preencher essas lacunas, fazendo com que o heap fique “compactado” e previsível.
  1. Force new pages
  • Uma vez que os buracos estão preenchidos, as próximas alocações devem vir de novas páginas adicionadas à zona.
  • Páginas novas significam que os objetos serão agrupados juntos, não espalhados por memória fragmentada antiga.
  • Isso dá ao atacante muito mais controle sobre os vizinhos.
  1. Place attacker objects
  • O atacante então faz spray novamente, criando muitos objetos controlados pelo atacante nessas novas páginas.
  • Esses objetos são previsíveis em tamanho e posicionamento (já que todos pertencem à mesma zona).
  1. Free a controlled object (make a gap)
  • O atacante deliberadamente libera um de seus próprios objetos.
  • Isso cria um “buraco” no heap, que o allocator irá reutilizar para a próxima alocação desse tamanho.
  1. Victim object lands in the hole
  • O atacante aciona o kernel para alocar o objeto victim (aquele que deseja corromper).
  • Como o buraco é o primeiro slot disponível na freelist, o victim é colocado exatamente onde o atacante liberou seu objeto.
  1. Overflow / UAF into victim
  • Agora o atacante tem objetos controlados por ele ao redor do victim.
  • Ao fazer overflow a partir de um de seus próprios objetos (ou reusar um objeto liberado), ele pode sobrescrever de forma confiável os campos de memória do victim com valores escolhidos.

Por que funciona:

  • Predictabilidade do zone allocator: alocações do mesmo tamanho sempre vêm da mesma zona.
  • Comportamento da freelist: novas alocações reutilizam primeiro o chunk mais recentemente liberado.
  • Heap sprays: o atacante preenche a memória com conteúdo previsível e controla o layout.
  • Resultado final: o atacante controla onde o objeto victim é alocado e quais dados ficam ao seu lado.

Modern Kernel Heap (iOS 15+/A12+ SoCs)

Apple endureceu o allocator e tornou o heap grooming muito mais difícil:

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.

Um atacante não pode mais garantir que dados controlados (OSData) acabem adjacentes a objetos kernel sensíveis (task_t) do mesmo tamanho.

2. Slabs and Per-CPU Caches

  • O heap é dividido em slabs (páginas de memória cortadas em chunks de tamanho fixo para aquela zona).
  • Cada zona tem um cache por CPU para reduzir contenção.
  • Caminho de alocação:
  1. Tenta o cache per-CPU.
  2. Se vazio, pega da freelist global.
  3. Se a freelist estiver vazia, aloca um novo slab (uma ou mais páginas).
  • Benefício: essa descentralização torna os heap sprays menos determinísticos, já que alocações podem ser satisfeitas a partir dos caches de CPUs diferentes.

3. Randomization inside zones

  • Dentro de uma zona, elementos liberados não são devolvidos em simples ordem FIFO/LIFO.
  • O XNU moderno usa encoded freelist pointers (estilo safe-linking como no Linux, introduzido ~iOS 14).
  • Cada ponteiro da freelist é XOR-encoded com um cookie secreto por zona.
  • Isso impede que atacantes forjem um ponteiro de freelist falso se obtiverem uma primitive de escrita.
  • Algumas alocações são randomizadas em sua posição dentro de um slab, então o spraying não garante adjacência.

4. Guarded Allocations

  • Certos objetos kernel críticos (por exemplo, credentials, task structures) são alocados em guarded zones.
  • Essas zonas inserem guard pages (memória não mapeada) entre slabs ou usam redzones ao redor de objetos.
  • Qualquer overflow na guard page aciona uma falha → panic imediato ao invés de corrupção silenciosa.

5. Page Protection Layer (PPL) and SPTM

  • Mesmo que você controle um objeto liberado, não pode modificar toda a memória do kernel:
  • PPL (Page Protection Layer) faz cumprir que certas regiões (por ex., code signing data, entitlements) são read-only mesmo para o próprio kernel.
  • Em dispositivos A15/M2+, esse papel é substituído/aperfeiçoado por SPTM (Secure Page Table Monitor) + TXM (Trusted Execution Monitor).
  • Essas camadas reforçadas por hardware significam que atacantes não conseguem escalar de uma única corrupção de heap para patchar arbitrariamente estruturas críticas de segurança.
  • (Added / Enhanced): também, PAC (Pointer Authentication Codes) é usado no kernel para proteger ponteiros (especialmente function pointers, vtables) de modo que forjá-los ou corrompê-los fique mais difícil.
  • (Added / Enhanced): zones podem impor zone_require / zone enforcement, i.e. que um objeto liberado só possa ser retornado pela sua zone tipada correta; frees cross-zone inválidos podem causar panic ou serem rejeitados. (A Apple alude a isso em seus posts sobre memory safety)

6. Large Allocations

  • Nem todas as alocações passam por kalloc_type.
  • Requisições muito grandes (acima de ~16 KB) bypassam typed zones e são servidas diretamente do kernel VM (kmem) via alocações de página.
  • Essas são menos previsíveis, mas também menos exploráveis, já que não compartilham slabs com outros objetos.

7. Allocation Patterns Attackers Target

Mesmo com essas proteções, atacantes ainda procuram por:

  • Reference count objects: se você consegue adulterar contadores retain/release, pode causar use-after-free.
  • Objects with function pointers (vtables): corromper um ainda pode dar controle de fluxo.
  • Shared memory objects (IOSurface, Mach ports): continuam sendo alvos pois fazem ponte user ↔ kernel.

Mas — ao contrário do passado — você não pode apenas sprayar OSData e esperar que ele fique ao lado de um task_t. Você precisa de bugs específicos de tipo ou info leaks para ter sucesso.

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: agrupar alocações por tipo ou uso (pointer vs data) para prevenir type confusion e reutilização entre tipos.
  • Metadata isolation: separar metadata do heap (ex.: free lists, bits de tamanho/estado) do payload dos objetos para que writes fora dos limites sejam menos prováveis de corromper metadata.
  • Guard pages / redzones: inserir páginas não mapeadas ou padding ao redor de alocações para detectar overflows.
  • Memory tagging (EMTE / MIE): trabalhar em conjunto com tagging de hardware para detectar use-after-free, out-of-bounds e acessos inválidos.
  • Scalable performance: manter overhead baixo, evitar fragmentação excessiva e suportar muitas alocações por segundo com baixa latência.

Architecture & Components

Below are the main elements in the xzone allocator:

Segment Groups & Zones

  • Segment groups particionam o espaço de endereço por categorias de uso: ex.: data, pointer_xzones, data_large, pointer_large.
  • Cada segment group contém segments (ranges de VM) que hospedam alocações para aquela categoria.
  • Associado a cada segment há um metadata slab (área VM separada) que armazena metadata (ex.: bits free/used, classes de tamanho) para esse segment. Essa metadata out-of-line (OOL) garante que a metadata não fique misturada com o payload dos objetos, mitigando corrupção por overflows.
  • Segments são divididos em chunks (slices) que por sua vez são subdivididos em blocks (unidades de alocação). Um chunk está ligado a uma classe de tamanho e segment group específica (i.e. todos os blocks em um chunk compartilham o mesmo tamanho & categoria).
  • Para alocações pequenas/médias, usa-se chunks de tamanho fixo; para grandes/huge, pode mapear separadamente.

Chunks & Blocks

  • Um chunk é uma região (frequentemente várias páginas) dedicada a alocações de uma classe de tamanho dentro de um group.
  • Dentro de um chunk, blocks são slots disponíveis para alocações. Blocks liberados são rastreados via metadata slab — ex.: via bitmaps ou free lists armazenadas out-of-line.
  • Entre chunks (ou dentro), podem ser inseridos guard slices / guard pages (ex.: slices não mapeados) para detectar writes fora dos limites.

Type / Type ID

  • Cada site de alocação (ou chamada para malloc, calloc, etc.) está associado a um type identifier (um malloc_type_id_t) que codifica que tipo de objeto está sendo alocado. Esse type ID é passado para o allocator, que o usa para selecionar qual zone / segment deve servir a alocação.
  • Por causa disso, mesmo que duas alocações tenham o mesmo tamanho, elas podem ir para zonas inteiramente diferentes se seus tipos diferirem.
  • Em versões iniciais do iOS 17, nem todas as APIs (ex.: CFAllocator) eram totalmente type-aware; a Apple corrigiu algumas dessas fraquezas no iOS 18.

Allocation & Freeing Workflow

Aqui está um fluxo em alto nível de como alocação e desalocação operam no xzone:

  1. malloc / calloc / realloc / typed alloc é invocado com um tamanho e type ID.
  2. O allocator usa o type ID para escolher o segment group / zone correto.
  3. Dentro dessa zone/segment, procura um chunk que tenha blocks livres do tamanho requisitado.
  • Pode consultar local caches / per-thread pools ou free block lists da metadata.
  • Se nenhum block livre estiver disponível, pode alocar um novo chunk nessa zone.
  1. A metadata slab é atualizada (bit de livre limpo, bookkeeping).
  2. Se memory tagging (EMTE) estiver em uso, o bloco retornado recebe uma tag, e a metadata é atualizada para refletir seu estado “live”.
  3. Quando free() é chamado:
  • O block é marcado como liberado na metadata (via slab OOL).
  • O block pode ser colocado em uma free list ou pooled para reuse.
  • Opcionalmente, o conteúdo do block pode ser limpo ou envenenado para reduzir vazamento de dados ou exploração de use-after-free.
  • A tag de hardware associada ao block pode ser invalidada ou re-tagged.
  • Se um chunk inteiro ficar livre (todos os blocks liberados), o allocator pode reclaim esse chunk (unmap ou retornar ao SO) sob pressão de memória.

Security Features & Hardening

Estas são as defesas embutidas no xzone moderno:

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)

  • O MIE (Memory Integrity Enforcement) da Apple é o framework hardware + OS que traz o Enhanced Memory Tagging Extension (EMTE) em modo sempre ativo e síncrono através das principais superfícies de ataque.
  • O allocator xzone é uma fundação fundamental do MIE no user space: alocações feitas via xzone recebem tags, e acessos são verificados pelo hardware.
  • No MIE, o allocator, atribuição de tags, gerenciamento de metadata e enforcement da confidencialidade das tags são integrados para garantir que erros de memória (ex.: leituras obsoletas, OOB, UAF) sejam detectados imediatamente, não explorados depois.

Se quiser, também posso gerar um cheat-sheet ou diagrama dos internos do xzone para seu livro. Quer que eu faça isso a seguir? ::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.

iMessage/Media Parser Zero-Click Chains

Imessage Media Parser Zero Click Coreaudio Pac Bypass

tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks