Implement UART/PPP support, firmware AES/SHA1 compatibility, production VSVFL NAND page programming and block erases, and display clock status. Preserve the host tools, emuagent v10, firmware generation helpers, dependency patches and handoff in contrib/ipod-emu. NAND data survives restart; application installation can still leave SpringBoard reporting device locked.
11 KiB
Passation — simulateur iPod Touch 2G / iPhone OS 2.2.1
État au 2026-09-30. Environnement : conteneur Arch Linux, utilisateur dev avec sudo, sans CAP_NET_ADMIN, sans /dev/ppp ni TUN.
Objectif
On fournit un simulateur d'iPod Touch 2G sous iPhone OS 2.2.1 qui sert surtout à un agent IA pour tester les applications iOS 2.x d'AlloVoisins. Les apps sont compilées en armv6 avec /opt/cctools et /opt/theos/sdks/iPhoneOS2.2.1.sdk. L'agent doit pouvoir faire les choses suivantes, sans intervention humaine :
- installer une app ;
- la lancer ;
- lire ses logs ;
- toucher l'écran et prendre des captures ;
- utiliser le réseau.
On veut le comportement le plus fidèle possible à un vrai appareil. La consigne de l'utilisateur est de travailler en autonomie et de se créer ses propres outils, voire une skill.
Ce qui marche
- Boot 2.2.1 (5H11a), SpringBoard prêt en environ 25 s.
- 2.1.1 (5F138) marche aussi, avec l'ancienne image de devos50.
- Écran : capture 320×480 par QMP. Touch, boutons et VNC sur
127.0.0.1:5900. - Réseau / Internet : PPP sur l'UART1 émulée, relié à
ipod-netdcôté hôte (libslirp, en userland).- iPod en 10.0.2.15, passerelle 10.0.2.2, DNS 10.0.2.3.
- Le DNS et HTTP marchent depuis l'iPod, et Safari affiche example.com.
- Agent sur l'iPod (
emuagent, v10), joignable depuis l'hôte sur127.0.0.1:7788viaipod-agent. Commandes :launch(bundle id, avec--logpour stdout/stderr et--url),apps,front;exec,ps,kill,respring;put,get,ls,rm,mkdir;fetch,net,routes,sc(SCDynamicStore) ;settime,sync.
- Persistance NAND : programmation des pages et métadonnées, effacement des blocs de 128 pages et détection des
pages vierges fonctionnent avec le format VSVFL de production. La base 5H11a a été migrée ;
nand-write=onest inscrit dans ses options machine. Les nouveauxipod-build-fw/ipod-mkimageutilisentgen-v1/mknand. - Apps :
ipod-mkimage MonApp.app|.ipa|.deb|dossier/construit une image dérivée. Les apps signées avecldidpassent grâce au boot-argamfi_allow_any_signature. - Heure :
start -W/waitenvoiesettimedès que l'agent répond, avant la fin du démarrage de SpringBoard. Ce réglage précoce évite d'initialiser les timers de l'interface en 1970 avec des préférences datées dans le futur. - Veille : agent v10, propriété
SleepDisabled=truesurIOPMrootDomain(acceptée). Les assertions publiquesIOPMAssertionCreateWithNamesont non supportées sur ce firmware. Le SoC ne sait toujours pas reprendre une veille. - Réglages de l'image : langue fr, région fr_FR, fuseau Europe/Paris. Verrouillage auto désactivé, pas d'alerte « Edit Home Screen ».
- Reconstruction complète depuis l'IPSW Apple :
ipod-build-fw 5H11a.
Limites connues, et suite logique par priorité
- Installation / lancement dans une session conservée : les apps copiées dans
/Applicationssont maintenant persistées, mais la reconstruction du catalogue lors d'unrespringreste peu fiable.push-appsynchronise puis redémarre l'émulateur sans-fet sans reconstruire l'image. Le lancement après ce redémarrage répond encore parfoisdevice locked; un écran de code a été observé dans l'image de test. Ne pas annoncer ce workflow comme entièrement validé.ipod-mkimagereste disponible pour intégrer l'app avant le premier démarrage.- La persistance elle-même est validée : témoin texte et binaire de 256 Kio identiques après redémarrage ; fichier
aléatoire de 8 Mio conservé, SHA-1 calculé dans l'iPod identique à l'hôte :
4d322e06f3433b874bc77d8b0298d97346210eb5. - Le téléchargement de 8 Mio par
geta été tronqué. Le client vérifie désormais la longueur reçue et signale ce cas. Utiliser un calcul d'empreinte dans l'iPod pour distinguer le transport de l'intégrité NAND. - Ancienne base sauvegardée :
images/5H11a/nand-readonly-backup,rootfs-v8-backup.img,machine-opts-readonly-backup. Session d'origine :run/nand-before-persistenceetfw-before-persistence. Session de test avec app et fichier de 8 Mio :run/nand-persistence-verified(firmwarepersistence-test-v10).
- La persistance elle-même est validée : témoin texte et binaire de 256 Kio identiques après redémarrage ; fichier
aléatoire de 8 Mio conservé, SHA-1 calculé dans l'iPod identique à l'hôte :
- Horloge RTC du PMU non émulée : le D1759 passe par un accès indirect, index en
0x61et donnée en0x62. Le modèle PCF50633 existant est faux pour le 2G. Contournement en place :settime. - Réglages > Wi-Fi affiche « Pas de Wi-Fi », parce que la puce BCM4325 n'est pas émulée. Le réseau passe par une interface ppp0, que l'app peut voir comme un VPN ou une connexion transitoire. Émuler le WiFi pour de vrai (SDIO + firmware FullMAC) serait un gros chantier ; le pont slirp est réutilisable.
- Pas encore écrits :
- un script
ipod-test-app(construit l'image, boote, lance l'app avec--log, fait une capture, affiche les logs) ; - une skill Claude/Codex qui documente ce workflow ;
- la mise à jour de
~/ipod-emu/README.md(réseau, agent, heure, français).
- un script
- Mise à jour de l'agent à chaud (
putpuiskill emuagent) : elle coupe PPP pendant la renégociation. Préférer reconstruire l'image.
Démarrer
ipod-emu start -f -W # 2.2.1 (défaut), NAND vierge, attend SpringBoard puis règle l'heure
ipod-agent ping # l'agent répond quand PPP est monté (quelques secondes)
ipod-agent launch com.apple.mobilesafari --url http://example.com/
ipod-qmp screenshot /tmp/s.png # tap X Y | swipe | home | hmp "info registers"
ipod-emu stop
Ne jamais toucher l'écran avant la fin de ipod-emu wait ou start -W : le contrôleur tactile fait planter QEMU s'il est touché pendant son démarrage.
Logs :
~/ipod-emu/run/serial.log: console kernel et syslog, pppd, emuagent ;~/ipod-emu/run/qemu.log;~/ipod-emu/run/netd.log: avecIPOD_NETD_FWD=-v, trace de chaque paquet IP.
Debug : IPOD_QEMU_EXTRA="-d unimp,guest_errors -D ~/ipod-emu/run/int.log" ; IPOD_QEMU=~/ipod-emu/bin/qemu-gdb pour avoir une backtrace en cas de crash.
Carte des fichiers
| Où | Quoi |
|---|---|
~/qemu-ios |
Fork Mahtan/devos50 (branche ipod_touch_2g). Sources et outils sauvegardés dans le dépôt (outils sous contrib/ipod-emu). Build : cd build && make -j4 |
/opt/ios-legacy/bin/ |
Copies installées des outils (réinstaller avec sudo install -m 755 ~/ipod-emu/bin/X /opt/ios-legacy/bin/) |
~/ipod-emu/bin/ipod-emu |
Launcher : QEMU (serial0 = fichier, serial1 = run/uart1.sock), ipod-netd, wait, settime |
~/ipod-emu/bin/ipod-qmp |
Écran, touch, boutons, HMP |
~/ipod-emu/bin/ipod-agent |
Client de l'agent (protocole : ligne à champs séparés par TAB, réponse OK <n> [info]\n + n octets) |
~/ipod-emu/bin/ipod-mkimage |
Image dérivée avec apps / .deb / overlay (re-signe avec ldid en gardant les entitlements) |
~/ipod-emu/bin/ipod-build-fw |
IPSW → NOR + rootfs (mkbase-rootfs) + NAND (gen-v1/mknand, VSVFL de production, signature 2 et écritures activées) |
~/ipod-emu/bin/mkbase-rootfs |
LaunchDaemons réduits, fstab rw, Lockdown (assets/), prefs, fr/Paris, intègre agent/overlay |
~/ipod-emu/agent/ |
emuagent.c + Makefile (make → overlay/), entitlements.plist (com.apple.springboard.launchapplications etc., indispensables pour SBSLaunchApplication) |
~/ipod-emu/netd/ipod-netd.c |
Serveur PPP (HDLC, LCP, IPCP) ↔ libslirp. gcc -O2 -o ipod-netd ipod-netd.c $(pkg-config --cflags --libs slirp) -Wno-deprecated-declarations |
~/ipod-emu/bin/armdis.py, dtdump.py |
Désassembleur capstone (base, début, fin, arm) et dump du DeviceTree. Kexts du kernelcache : base de fichier 0xc0029000 |
~/ipod-emu/fw-5H11a/dec/ |
kernelcache, iBoot, LLB, DeviceTree déchiffrés (clés via api.ipsw.me) |
~/ipod-emu/xpwn/ |
Outil hfsplus (patché : grow alloue ensuite dans l'espace neuf) |
Découvertes clés (modifs QEMU)
- AES (
ipod_touch_aes.c) :- clé GID choisie d'après le contenu du KBAG (
ipod_touch_gid_keys.h) ; - le dernier bloc incomplet d'une IMG3 est laissé en clair ;
- la vérification de longueur LZSS d'iBoot est patchée, trouvée par signature ;
- dans le DeviceTree déchiffré, les propriétés DMA de
uart1sont renommées : le pilote reste en PIO.
- clé GID choisie d'après le contenu du KBAG (
- SHA1 (
ipod_touch_sha1.c) : c'est une fonction de compression brute.CONFIG 0x2= premier bloc,0x8puis0xa= suite ;- état H0–H4 lisible et écrivable, mots byte-swappés ;
- bit
0x4= mode asynchrone, avec IRQ 40 (activée par0x0c, acquittée par0x08, levée par un timer de 20 µs).
- UART (
ipod_touch_uart.c, nouveau modèle, remplace l'Exynos) :- IRQ activées dans UCON (
0x2000TX,0x1000/0x0880RX) ; - flags en attente dans UTRSTAT (
0x08/0x10/0x20), effacés en écrivant 1 ; UFSTAT: un FIFO plein vaut 0 + le bit0x100;- FIFO limité à 8 octets.
- IRQ activées dans UCON (
- NAND / FMSS (
ipod_touch_fmss.c) :- La programmation
CSGENRC=0xa02utilise une liste de paires enD10, terminée par un mot zéro.D08=8est la taille d'une paire, pas le numéro de page ;D18est une ancienne valeur de lecture. - Premier mot : masque CE dans les bits 0–3, commande 80h/81h dans les bits 16–23 et flags dans les autres bits.
Deuxième mot : page physique.
D20pointe deux adresses de données (2048 octets chacune) par page ;D1Ccontient les métadonnées de 12 octets. Toutes les paires doivent être enregistrées. - Effacement reconnu dans la liste du séquenceur
C04par les écritures immédiates NAND 60h/D0h ;D0Cpointe la page de début de bloc,D10un index CE,D18=1. Supprimer les 128 fichiers de pages du bloc. - Une page sans fichier est vierge (
FF).C30=0x20000000pour une lecture entièrement vierge fait retourner0xe00002e5par le pilote ; sans ce statut,_FTLRestoreignore les blocs de logs et perd les écritures. - Les autres micro-commandes restent émulées par les chemins de haut niveau existants ; pas d'interpréteur complet.
.ipod-nand-format=vsvfl-production-v1dans la NAND : le launcher refusenand-write=onsur une ancienne image.
- La programmation
- Écran MIPI DSI :
CLKCTRL[31]contrôleSTATUS.TxReadyHsClk; le bit doit aussi pouvoir retomber à zéro. Le modèle précédent le renvoyait toujours actif, bloquant le pilote lors de l'arrêt de l'écran. - Machine :
- stubs RAM MPVD (
0x39600000) et0x38100000; - la NAND 2.2.1 exige la signature
0x43313132; - options
legacy-noretnand-write.
- stubs RAM MPVD (
- Réseau iOS :
- pppd est lancé avec
serviceid emuppp; - l'agent publie
Setup:/Network/Service/emupppetSetup:/Network/Global/IPv4 ServiceOrder, sans quoi IPMonitor n'installe ni route ni DNS ; - mDNSResponder est réactivé (nécessaire au DNS) ;
- tous les descripteurs passés à pppd doivent être
FD_CLOEXEC; - SpringBoard refuse
SBSLaunchApplicationsans l'entitlementlaunchapplications.
- pppd est lancé avec
Pièges
pkill -f 'ipod-netd -s'tue aussi le shell qui lance la commande : utiliserpkill -x ipod-netd.ipod-build-fwréécritimages/5H11a/. Refairemakedansagent/avant, si l'agent a changé.-fefface la session persistée. Ne pas l'utiliser pour vérifier la conservation d'un fichier.- QEMU et netd sont lancés avec
setsidpour survivre à la fin du terminal appelant. Le launcher suit netd par PID. - Un
.deb2.x qui dépend d'un jailbreak (bash, etc.) ne marchera pas : aucun shell dans l'image.