PoC demonstrando o dyld como um oráculo de assinatura PAC por meio de fixups encadeados Mach-O criados manualmente em arm64e, alcançando gravações controladas de ponteiros válidos para PAC e execução de callbacks de despacho no iOS.
Uma exploração controlada da maquinaria de page-in linking e chained fixup do dyld como um oráculo de assinatura PAC, no contexto do CVE-2026-20700.
No arm64e, todo ponteiro de função é autenticado por hardware. O objetivo aqui é mostrar que o próprio dyld pode ser direcionado — por meio de um Mach-O artesanal — para produzir ponteiros válidos de PAC em slots escolhidos pelo atacante, usando nada além do seu próprio mecanismo normal de fixup.
Testado em: iPhone 14 (iOS 18.5, arm64e).
__DATA.fixupPage64 — valores malformados de page_start / next conduzem o dyld para fora do limite da página, provando a alcançabilidade do branch.dispatch_source_t e chamado naturalmente pelo loop de eventos, sem invocação direta do código PoC.dyld-signing-oracle-poc/
├── Makefile ← orchestrates the full pipeline
├── src/
│ └── launcher.c ← iOS launcher (2 threads + dispatch chain-close)
├── generators/
│ ├── gen_exports.py ← generates exports.c (N dummy symbols)
│ ├── gen_client.py ← generates client.c (N imports, dyld gate stress)
│ └── gen_malformed_dylib.py ← generates libmalformed.dylib (hand-crafted Mach-O)
├── tools/
│ ├── scan_pointers.py ← classifies Mach-O pointer sections as W/R
│ └── inspect_fixups.py ← parses LC_DYLD_CHAINED_FIXUPS header
└── blog/
├── it/
│ └── dyld-signing-oracle.md ← write-up completo in italiano
└── en/
└── dyld-signing-oracle.md ← full write-up in English
| Arquivo | Gerado por |
|---|---|
exports.c | generators/gen_exports.py + símbolos sentinela do Makefile |
client.c | generators/gen_client.py |
libmalformed.dylib | generators/gen_malformed_dylib.py |
libexports.dylib | clang de exports.c |
libclient.dylib | clang de client.c |
PoCApp | clang de src/launcher.c |
PoCApp.ipa | etapa package do Makefile |
xcrun --sdk iphoneos --show-sdk-path)# Default full build (arm64, 99k symbols)
make
# Fast build for iteration
make SYMBOLS=10000
# Deterministic crash in fixupPage64 (branch reachability proof)
make stress
# Stable intra-image write-what-where
make exploit
# dyld writes PAC-valid pointer → dispatch calls it naturally
make chain_close
# Verify generated chained-fixup blob layout
make verify
# Parse LC_DYLD_CHAINED_FIXUPS header of libmalformed.dylib
make inspect
# Scan pointer sections (GOT/non-lazy) across compiled binaries
make scan
| Variável | Padrão | Descrição |
|---|---|---|
SYMBOLS | 99000 | Número de alvos de bind no libclient (< 100k para gate pré-26.3, < 64k para 26.3+) |
STACK_KB | 128 | Tamanho da pilha da thread de trabalho em KB |
BURN_KB | 0 | KB de pilha a consumir antes de dlopen (0 = automático) |
MARGIN_KB | 24 | Margem de auto-burn |
ARM64E | 0 | Usar o formato DYLD_CHAINED_PTR_ARM64E_USERLAND24 |
MALFORM_PAGEIN | 0 | Ativar a cadeia de page-in malformada |
MALFORM_TARGET_OFFSET | — | Offset alvo dentro de __DATA (ex.: 0x10) |
CHAIN_CLOSE | 0 | Segundo slot → _attacker_hook, habilitar a demo do dispatch |
# Ad-hoc signed (Sideloadly)
make chain_close
# drag PoCApp.ipa into Sideloadly
# Real certificate
make resign IDENTITY="iPhone Developer: ..." PROFILE=embedded.mobileprovision
# Monitor logs
idevicesyslog | grep "POC"
Ordem de carregamento em tempo de execução dentro de PoCApp:
libexports.dylib — carregado primeiro (RTLD_GLOBAL), fornece write_target_value e attacker_hook a qualquer dlopen subsequente.libclient.dylib — carregado pela Thread B (pilha de 128KB); ~99k alvos de bind estressam o gate de page-in linking do dyld.libmalformed.dylib — carregado pela Thread A; a cadeia de chained-fixup artesanal faz o dyld resolver e escrever _write_target_value (e opcionalmente _attacker_hook) em __DATA+0x10 / +0x20.chain_close, a main registra __DATA+0x20 como um handler de timer dispatch_source_t — o loop de eventos o chama 1 segundo depois, sem invocação direta do código PoC.Artigo técnico completo em italiano e inglês. Abrange: mecânica de hardware do PAC, dyld como produtor de ponteiros, codificação de chained-fixup do zero, mecânica do gate de page-in linking, armadilhas de engenharia de Mach-O (sizeofcmds, contagem de seções, stride), layout de dados validado por canários, o gate de 99k símbolos, prova de alcançabilidade por crash, primitiva intra-imagem estável, conceito de oráculo de assinatura arm64e, chain-close via timer do dispatch.