Début du parcours d’émulation d’iOS 14 avec QEMU
- Le projet open source existant
alephsecurity/xnu-qemu-arm64 a été utilisé au départ, mais comme il était en lecture seule (read-only), il posait des problèmes de manque d’extensibilité
- Le projet
TrungNguyen1909/qemu-t8030 a ensuite été utilisé, ce qui a permis de tirer parti des fonctions suivantes :
- Fonction de restauration iOS (avec un QEMU compagnon pour la connexion USB)
- Exécution d’iOS 14
- Basé sur une version récente de QEMU
- Documentation wiki détaillée
- En modifiant
launchd.plist, l’accès au shell et en SSH a été obtenu, ce qui en a fait un bon point de départ
- L’objectif est de construire un environnement d’émulation iOS complet capable d’exécuter l’interface UI et les applications
Patches noyau et adoption de PongoOS
- Le projet
t8030 appliquait les patches noyau directement dans QEMU → problèmes de maintenance et d’extensibilité
- Fort de l’expérience du jailbreak, l’approche a été remplacée par une application des patches
checkra1n via PongoOS
- Exécution de PongoOS en augmentant la taille de la SRAM dans QEMU, puis injection du module checkra1n-KPF
- Au démarrage, des fonctions absentes dans la bootrom et
iboot provoquaient un problème de FPU non configurée → résolu en s’appuyant sur la documentation ARM
- Depuis l’A13, l’introduction de PAC (Pointer Authentication) a rendu certains patches inopérants
- Comparaison de binaires avant/après l’introduction de PAC avec l’exemple de
task_for_pid0 (tfp0)
Développement d’un outil d’automatisation des patches noyau
- L’ancienne méthode de patch dynamique de checkra1n était difficile à lire et peu pratique à modifier → adoption d’un format déclaratif de patchs textuels
- Création de patchs texte après extraction des différences d’assembleur en comparant deux binaires
Mach-O
- Après démarrage via Pongo, dump mémoire puis réassemblage du noyau → tous les patches ont été organisés et commentés dans des fichiers texte
Rendu graphique : Metal vs rendu logiciel
- iOS effectue tout le rendu de l’interface via l’API
Metal → besoin d’un GPU
- L’émulation GPU étant complexe, d’autres pistes ont été envisagées :
- rendu logiciel
- proxy des appels Metal vers un appareil physique
- Dans iOS 14, le bootarg
gpu=0 a été supprimé → analyse de QuartzCore pour vérifier le comportement de repli
- En patchant
QuartzCore sur un iPhone jailbreaké, le rendu logiciel a été validé (lent, mais fonctionnel)
- Une approche de proxy Metal a aussi été testée, mais abandonnée à cause de la complexité d’Objective-C et de l’API
Débogage du framebuffer et d’IOSurface
- Le QEMU de
t8030 n’implémente pas de framebuffer → utilisation du fork ChefKissInc/QEMUAppleSilicon
- Au démarrage initial, le logo Apple et l’indicateur de progression apparaissaient, puis écran noir → début du débogage
- L’analyse du kext IOMFB a révélé deux modes :
- framebuffer à adresse fixe (pour l’affichage initial)
- configuration multi-plan basée sur DMA
- Pendant le boot du système, le mode basé sur DMA est utilisé → vérification via les traces QEMU de la configuration des registres noyau
- Malgré cela, toujours aucune sortie à l’écran
Désactivation de la randomisation des adresses
- La randomisation des adresses du noyau peut être désactivée dans le code d’initialisation de la carte
- La randomisation de l’espace utilisateur a été désactivée en patchant
_load_machfile
- Le cache dyld est un gros binaire contenant toutes les bibliothèques dynamiques → il est chargé à une adresse fixe au démarrage
- Un outil en C a été créé pour faire un
dlopen, puis vérifier les adresses avec les fonctions _dyld_*
- Le débogage de la bibliothèque
dyld a ainsi été rendu possible avec GDB → intérêt particulier pour IOMFB, SpringBoard et QuartzCore
Accès aux logs via USB et contournement de lockdownd
- Sur un appareil réel, il est possible de collecter les logs système avec
idevicesyslog → nécessite une authentification USB
- lockdownd utilise un keybag nécessitant le SEP pour stocker les clés → absent dans l’émulateur
- Du shellcode a été inséré à la place d’une fonction existante afin de charger directement depuis un fichier de clés
- Le contournement de l’authentification par clés entre QEMU connectés en USB a réussi → collecte des logs possible
- Confirmation que QuartzCore s’initialise correctement et utilise le rendu logiciel
Contournement de PAC (Pointer Authentication)
- Une erreur PAC est apparue lors de la modification de
backboardd → fonctionnalité de sécurité introduite avec ARMv8.3
- Remplacer les instructions PAC par des NOP était trop intrusif
- Les instructions PAC peuvent être compilées de manière compatible → l’exécution devient possible si QEMU ignore PAC
- QEMU 7 ne permettait pas de contourner PAC → migration vers QEMU 8.2.1
- Il a fallu porter de nombreux morceaux de code custom QEMU, notamment des instructions spécifiques à Apple et les niveaux d’exception GL
- Résultat : démarrage réussi d’iOS sur QEMU 8 et neutralisation possible de PAC
Vérification de backboardd et de la sortie graphique
backboardd fonctionne, mais rien ne s’affiche à l’écran → plusieurs causes possibles
- Même en dumpant la mémoire DMA, aucune sortie significative n’a été observée
- L’adresse a été retrouvée dans
iosurface_lock et des frames ont été dumpées, mais elles semblaient envoyées au GPU sous une forme compressée
- Sur l’iPhone X (
t8015), une sortie non compressée a été confirmée → modification du DTB de QEMU pour changer le chip-id de t8030 à t8015
- Résultat : le logo Apple s’est affiché après le démarrage
Barre de progression et suivi des erreurs système
- Après le logo, une barre de progression blanche s’affiche → blocage à 90 %
- L’analyse des logs a révélé des problèmes dans
mobileactivationd et SpringBoardFoundation → l’interface a changé après patch
- Pour résoudre ce blocage de progression, il a fallu analyser un grand nombre de logs système
Automatisation des patches du cache dyld et de l’espace utilisateur
- Comme pour le noyau, l’espace utilisateur a adopté une méthode de patchs textuels
- Le cache dyld fait 2 Go et est inefficace à modifier → amélioration des outils internes pour :
- suivre les offsets dans dyld
- patcher directement des positions spécifiques avec la commande
dd
- Il a aussi fallu appliquer en parallèle un patch de contournement de la vérification de signature du noyau
Exécution de PreBoard et vérification de l’interface
- L’application
PreBoard est une application système affichée en cas d’erreur → elle peut être exécutée directement
- Un serveur VNC a été ajouté afin de tenter un déverrouillage de l’écran au clavier
- Après le déverrouillage, le framework
vImage utilisait des instructions AMX (Apple Matrix Coprocessor) → non prises en charge par QEMU
- Le problème a été résolu en patchant vers le chemin de repli logiciel de
vImage
- Après patch, l’affichage a pu aller jusqu’à un écran permettant la saisie de texte
Conclusion
- Le système atteint désormais l’étape juste avant l’exécution de SpringBoard → le lancement d’une interface complète n’est plus qu’une question de temps
- Des analyses et patches ont été menés sur plusieurs fronts : noyau, espace utilisateur, graphismes et fonctions de sécurité (PAC, etc.)
- La possibilité d’un environnement concret de débogage et de test d’applications iOS basé sur QEMU a ainsi été démontrée
1 commentaires
Commentaires Hacker News