iOS auf Apple Silicon virtualisieren
(nickb.website)- Ein Experiment, bei dem ein iOS-15.0.2-Build für das iPhone XR mithilfe von Virtualization.framework und der vma2-Umgebung auf einem Apple-silicon-Mac bis zu
PreBoard.appgebootet wurde - Kern des Ansatzes ist die Wiederverwendung der Boot Chain von macOS 12.0.1; nur das iOS-System-Image,
mtree,root_hashundtrustcachewerden ersetzt, um den Aufwand für Änderungen an der frühen Boot Chain zu reduzieren - Wird die VM über den nicht öffentlichen Aufruf
_setProductionModeEnabled(false)in den CPFM-Status01versetzt, signiert TSS für öffentlich bekannte vma2-Geräte beliebige Firmware, wodurch die bisherige vma2pwn-Methode weniger nötig wird - Für den tatsächlichen Boot sind Kernel- und System-Patches nötig, die XNU-Plattformprüfungen, system keybag, IOMFB-Größenprüfungen, ramdisk,
launchd,mount, DYLD shared cache,lockdowndundmobileactivationdbetreffen - Die größte ungelöste Aufgabe ist die Kompatibilität des system keybag; außerdem ist noch unklar, ob Touch-Eingaben über private APIs von Virtualization.framework möglich sind
Ziel und Ausgangspunkt des Experiments
- Seit dem Wechsel zu Apple silicon und Mac Catalyst sind iOS und macOS näher zusammengerückt; mit der Möglichkeit zur Virtualisierung von macOS wurde die zentrale Frage, ob sich auch iOS durch Anpassungen an einer verwandten Boot Chain virtualisieren lässt
- Die frühere Arbeit vma2pwn war ein Projekt zum Erstellen einer veränderbaren vma2-macOS-Boot-Chain für macOS-Gast-VMs und bildet die Grundlage dieses Experiments
- Ein öffentlich bekanntes, fertiggestelltes Beispiel für iOS-Virtualisierung/-Emulation ist Corelliums virtual iPhone cloud
- Herangezogen wurden außerdem qemu-t8030, QEMU-basierte Arbeiten und ein Beitrag von Zhuowei Zhang; insbesondere die Beziehung zwischen
IOSurfaceRootin macOS undIOCoreSurfaceRootin iOS half später bei der Suche nach Kernel-Patches - Zhuowei Zhangs Beitrag ging davon aus, dass GUI-macOS-Apps nicht unter iOS laufen können, grafische iOS-Apps aber unter macOS; diese Eigenschaft gilt offenbar auch für große Teile des iOS-Grafiksystems
Private Funktionen von Virtualization.framework
- Apples Virtualization.framework enthält die nicht dokumentierte private Funktion
_setProductionModeEnabled(false) - Dieser Aufruf und die entsprechende Funktion in der VM-Konfiguration setzen die VM auf den Chip Fuse Mode CPFM
01herab und konfigurieren das virtuelle Gerät damit als „secure“, aber „non-production“ - Bei physischen Geräten verweigert TSS die Signatur der für non-production/non-secure-Geräte wie CPFM
00oder01nötigen SHSH-Blobs - Für öffentliche vma2-Geräte signiert TSS jedoch beliebige bereitgestellte Firmware, wodurch der Bedarf an der vma2pwn-Methode zum Erstellen modifizierter Firmware-Chains stark sinkt
Aufbau der iOS-VM
- Der erfolgreichste Ansatz bestand darin, die Boot Chain von macOS 12.0.1 unverändert zu verwenden und das System-OS-Image durch das Image und zugehörige Dateien eines iOS-15.0.2-Builds für das iPhone XR zu ersetzen
- Ersetzt wurden System-Image,
mtree,root_hashundtrustcache - Dieser Ansatz umgeht weitgehend die Notwendigkeit, die Boot Chain und die Recovery-ramdisk vor der iOS-Initialisierung zu verändern
- Ersetzt wurden System-Image,
- Der iPhone-XR-Build wurde wegen arm64e-Unterstützung und der möglicherweise niedrigeren Auflösung gewählt
- Auch mit anderen arm64e-Gerätekonfigurationen könnte es funktionieren, allerdings ist der vma2-Kernel so hartcodiert, dass er für einige sysctl-Keys
"iPad8,6"zurückgibt - arm64-Builds verursachten zusätzliche Probleme und binäre Inkompatibilitäten und wurden daher als kaum lohnend eingeschätzt
- Zum Ausführen der VM wurde super-tart verwendet, ein Fork von tart, einer Drittanbieter-App zur Verwaltung von Apple-silicon-VMs
- super-tart ermöglicht die Nutzung der benötigten privaten Funktionen von Virtualization.framework
- Einige Änderungen, etwa die Einstellung
_setProductionModeEnabled(false), sind noch nicht vollständig gepusht - Werkzeuge für Virtualization.framework, die private APIs verwenden, erfordern deaktiviertes SIP; möglicherweise muss auch AMFI deaktiviert werden
- Als Restore-Werkzeug wurde ein Fork von idevicerestore genutzt
Kernel-Patches
- Die in vma2pwn verwendeten Patches für Signaturprüfungen könnten nötig sein; beim CPFM-
01-Ansatz ist aber nicht sicher, ob sie zwingend erforderlich sind - Die Signatur-Patches sorgen im vma2-Kernel dafür, dass die folgenden Funktionen 0 zurückgeben
_apfs_extract_root_hash_arm_authenticate_root_hash__img4_firmware_property_callback_is_root_hash_authentication_required_img4_firmware_evaluate
lookup_in_static_trust_cachemuss so gepatcht werden, dass es 1 zurückgibt- Da iOS-Binaries keine Simulator-Plattform-Binaries sind, werden sie anfangs mit
EXEC, [0xe] Binary with wrong platformbeendet- Das lässt sich beheben, indem die Zeile mit der Prüfung auf
PLATFORM_IOSin XNU übersprungen wird - Im vma2-Kernel wurde dies umgesetzt, indem
B.NEdurchBersetzt wurde
- Das lässt sich beheben, indem die Zeile mit der Prüfung auf
- Wegen Inkompatibilität des system keybag zeigt
PreBoard.appstattSetup.appden Hinweis „Swipe up to upgrade.“ an- Mit zwei Patches an
ipc_make_system_keybag, die erzwingen, dass die Funktion keinen Fehler zurückgibt, lässt sichPreBoard.apperreichen - Diese Grenze ist noch nicht vollständig überwunden
- Mit zwei Patches an
- Eine abweichende Größe der IOMFB-Strukturen zwischen iOS-Systemframeworks und macOS-Kernel führt zusammen mit der Zeichenkette
CLCDTransaction size mismatch. Returning error 0x%X.zu einer Kernel Panic- Entfernt man die Größenprüfung in
IOMobileFramebufferUserClient::swap_submit, stoppt die Panic
- Entfernt man die Größenprüfung in
Vorbereitung von Systemdatei-Patches
- Recovery-ramdisk und iOS-Systemdateien sind signiert; ohne erneute Signatur nach dem Patchen werden sie beim Ausführen beendet
- Für die modifizierte Umgebung wird die Nutzung von Procursus’
ldidvorgeschlagen- Installationsbeispiel:
brew install ldid-procursus - Beispiel zum erneuten Signieren:
ldid_macosx_arm64 -S -M <binary> -Spseudo-signiert das Binary,-Mbewahrt vorhandene Entitlements
- Installationsbeispiel:
- Viele Binaries prüfen ihre Identity; daher muss vor dem erneuten Signieren der Name vorübergehend in die Identity geändert und danach wieder zurückgesetzt werden
keybagdzeigt mitcodesign -d -v keybagdden IdentifierIdentifier=com.apple.keybagdmv keybagd com.apple.keybagdldid_macosx_arm64 -S -M com.apple.keybagdmv com.apple.keybagd keybagd
- Funktionen ohne automatisch angehängte Symbole lassen sich finden, indem man String-XRefs sucht und über Referenzen auf Logging-Aufrufe die aufrufende Funktion zurückverfolgt
- Um über das serielle Terminal eine interaktive Shell zu erhalten, können Bash und ein LaunchDaemon portiert werden
- Dafür wurden die entsprechenden Dateien aus versionskompatiblen iOS-Jailbreak-Payloads wie Procursus kopiert
DMG und ramdisk ändern
- Um das System oder die Recovery-ramdisk zu patchen, muss das DMG-Volume direkt geändert werden
- Im Beispiel mit iOS 15.0.2 wird das im IPSW enthaltene iOS-System-Volume in eine schreibbare Form konvertiert
hdiutil convert -format UDRW -o 018-66258-074-rw.dmg 018-66258-074.dmg- Nach dem Mounten:
sudo mount -uw /Volumes/Sky19A404.N104N841OS - Nach den Änderungen:
hdiutil convert -format ULFO -o 018-66258-074.dmg 018-66258-074-rw.dmg - Anschließend:
asr imagescan --source 018-66258-074.dmg
- Vor dem Boot von iOS muss
/usr/local/bin/restored_externalin der Recovery-ramdisk geändert werden- Die iOS-Version von
restored_externalversucht, mitMKBKeyBagCreateSystemden system keybag zu erstellen, ist aber nicht mit dem macOS-Kernel kompatibel - Umgangen wird dies durch Entfernen der Fehlerprüfung
- Durch Patchen der Aufrufbedingung von
ramrod_set_NVRAM_variablewirdallow-root-hash-mismatchauf true, also1, gesetzt und die Root-Hash-Authentifizierung übersprungen
- Die iOS-Version von
- Auch
/usr/sbin/asrin der Recovery-ramdisk muss geändert werden- Dafür kann asr64_patcher von iSuns9 verwendet werden
- Man sucht die Funktion, die die Zeichenkette
"Image failed signature verification."ausgibt, und ersetzt in der referenzierenden Funktion den ARMv8-A-BL-Aufruf durch einenB-Sprung auf den Pfad"Image passed signature verification" - Im
asr-Binary von iOS 15.0.2 wird bei Datei-Offset0x27A18b #0x7cangewendet
iOS-System-Volume ändern
- Um iOS selbst an den macOS-Kernel anzupassen, müssen die meisten Dateien, die im Dateisystem-Root installiert würden, im System-Volume nach
/System/Library/Templates/Dataverschoben werden - Sobald das System bootet, sind diese Dateien unter
/vorhanden - Leere Ordner im normalen Root müssen möglicherweise im System-Volume erhalten bleiben, auch wenn sie tatsächlich leer sind
- Beispiel:
/Applications - Dieser Teil wurde nicht ausreichend getestet
- Beispiel:
Patches für launchd und keybagd
- Früh im iOS-Boot wird
/sbin/launchdausgeführt; damit der initiale Boot-Prozess ohne Fehler startet, sind Patches nötig - Der erste Patch betrifft die im Binary eingebettete Konfigurations-plist
- Sucht man die Zeichenkette
<key>SIGTERMTimeout</key>, findet man etwa 172 Byte davor die entsprechende Konfiguration - In den Abschnitten
mount-phase-2,fips,tzinit,finish-demo-restore,fud,xpcroleaccountd,prng_seedctl,MSUEarlyBootTaskwird<key>PerformAfterUserspaceReboot</key><true/>hinzugefügt - Im Abschnitt
data-protectionwirdRequireSuccessauf<false/>geändert
- Sucht man die Zeichenkette
- Die Änderung an
data-protectionist nötig, weil/usr/libexec/init_data_protectionin der VM fehlschlägt- Diese Datei ist ein symbolischer Link auf
/usr/libexec/seputil
- Diese Datei ist ein symbolischer Link auf
- Da Änderungen an der eingebetteten plist den vorhandenen String-Bereich überschreiten können, kann man das XML mit einem XML-Minimizer komprimieren und den restlichen Bereich mit XML-freundlichen Leerzeichen überschreiben
launchdinitialisiert auch/usr/libexec/keybagd, dieses Binary scheitert jedoch wegen der zuvor genannten Kernel-Unterschiede- Eine Umgehung besteht darin, ein ausführbares Programm zu kompilieren, das einfach mit Exit-Code 0 endet, und damit
keybagdzu ersetzen - Das Projekt fixkeybag wurde ebenfalls geprüft, aber auch der Code dieser App zur Erstellung des system keybag ruft
MKBKeyBagCreateSystemauf und scheitert daher selbst in gebootetem iOS-Zustand
- Eine Umgehung besteht darin, ein ausführbares Programm zu kompilieren, das einfach mit Exit-Code 0 endet, und damit
- Für
launchdist ein weiterer Patch nötig, der die bedingte VerzweigungTBZ, die die Panic-ZeichenketteUserspace reboot changed system version: previous %s != current %sauslöst, durchNOPersetzt
mount, DYLD shared cache und Anpassungen der Grafikschicht
- Da der Restore-Prozess über die macOS-Boot-Chain und die macOS-ramdisk abgewickelt wird, kann iOS’
/sbin/mountdie erstellten APFS-Volumes nicht korrekt behandeln - Die Lösung besteht darin, das
mount-Binary aus dem macOS-System-Volume zu übernehmen, die Mach-O-Metadaten so zu ändern, dass es unter iOS ausführbar ist, und es dann zu ersetzen- Das ist manuell möglich; auch das in macOS enthaltene
vtoolkann verwendet werden
- Das ist manuell möglich; auch das in macOS enthaltene
- Schwieriger ist der Patch des DYLD shared cache
IOSurfaceRootin macOS undIOCoreSurfaceRootin iOS sind im Grunde derselbe Treiber, aber wegen des Namensunterschieds nicht kompatibel- Da der iOS-DYLD-shared-cache die längere Zeichenkette
"IOCoreSurfaceRoot"enthält, wird sie durch"IOSurfaceRoot"ersetzt und die verbleibenden Bytes mit0x00aufgefüllt
- Für Analyse und Extraktion des DYLD shared cache wurde blacktops ipsw verwendet
- Mit
ipsw dyld split <dsc file>werden eingebettete dylibs getrennt - Im Binary
/System/Library/Frameworks/IOSurface.framework/IOSurfacesucht man in der Funktion__iosConnectInitalizedie Referenz auf"IOCoreSurfaceRoot" - Mit
ipsw dyld a2owird die virtuelle Adresse in einen Datei-Offset umgerechnet - Im Beispiel wurde Offset
0x28fde373indyld_shared_cache_arm64egepatcht
- Mit
- Nach der Änderung des DYLD shared cache kommt es wegen eines nicht passenden cdhash an anderer Stelle zu einer Exception
- Über den vom Virtualization.framework-Frontend bereitgestellten GDB-Stub wird ein Breakpoint auf die Kernel-Funktion
cs_validate_hashgesetzt, um den vollständigen cdhash zu ermitteln - Im Beispiel mit iOS 15.0.2 wurden die vorhandenen Bytes bei Datei-Offset
0x5a9cffc0durch den neuen cdhash ersetzt
- Über den vom Virtualization.framework-Frontend bereitgestellten GDB-Stub wird ein Breakpoint auf die Kernel-Funktion
System-Daemons und Aktivierungs-Patches
watchdogdprüft, ob es in einer VM läuft, und verursacht einen Crash-Loop, weil es keinen macOS-Codepfad zum sauberen Beenden gibt; dieser Crash wird jedoch als harmlos behandelt- In
backboarddwurden Patches an Aufrufen im Zusammenhang mit Datenmigration ausprobiert, diePreBoard.appauslösen könnten; außer einem Hängenbleiben beim Apple-Logo zeigte sich jedoch kein Unterschied - In der Funktion
get_device_type_internal_block_invokevonlockdowndwird dergetMGInt-Aufruf für"ShouldHactivate"zumov x0, #1gepatcht, um in der Entwicklungsumgebung hactivation zu erzwingen und normale iOS-Aktivierungsbeschränkungen zu umgehen - Auch
mobileactivationdkann so gepatcht werden, dass hactivation erlaubt wird- Die Funktion
shouldHactivatewird durch die ARMv8-A-Instruktionenmov x0, #0undretersetzt
- Die Funktion
- Weitere nötige Änderungen am vma2 device tree bleiben den Lesern als Aufgabe überlassen
- Für einige Verhaltensweisen können ungewöhnliche Maßnahmen wie
chmod -R 777 /nötig sein
Verbleibende Grenzen und Touch-Eingabe
- Um das Problem mit dem system keybag zu überwinden, müssen die entsprechenden Strukturen im iOS-System und im Kernel besser verstanden und weitere Patches erstellt werden
- In das Projekt sind bereits mindestens mehrere Hundert Stunden geflossen; der aktuell öffentlich gezeigte Stand bootet bis zu
PreBoard.app - Ob Touch-Funktionalität mit öffentlichem vma2-Mac-Kernel und Firmware funktioniert, ist noch nicht geklärt
- In Virtualization.framework gibt es private APIs rund um Touch
_VZAppleTouchScreenConfiguration_VZUSBTouchScreenConfiguration_VZTouch_VZMultiTouchEvent
- Mit diesen APIs lassen sich Touch-Events senden, die genaue Verwendung der Parameter ist aber noch nicht vollständig verstanden
- Das
TouchPhase-Enum ist ein einfaches Enum, das die gleichnamigen Werte vonNSTouch.Phaseimplementiert - Beispielcode kann gelegentlich Exceptions erzeugen
- Ob die Koordinatenwerte so gemappt werden, wie die VM es erwartet, und ob die VM sie verarbeiten kann, ist ebenfalls nicht bestätigt
- Das
- Die Demo zeigt die Boot-Sequenz; eine etwa 30 Sekunden lange Wartephase in der Mitte wurde herausgeschnitten
1 Kommentare
Hacker-News-Kommentare
Corellium hat den Rechtsstreit gewonnen und kann nun iOS-Cloud-VMs für Sicherheitsforschung vermieten https://hn.algolia.com/?query=corellium
Wenn sich iOS auf Apple-Silicon-MacBooks virtualisieren lässt, könnte das die Nachfrage nach kommerziellen iOS-Virtualisierungsdiensten senken
Für Privatpersonen liegt der Preis bei etwa 400 $ pro Monat, für Unternehmen bei 60.000 $ pro Jahr https://support.corellium.com/subscriptions/pricing
Gut. Als Nächstes wäre es schön, wenn jemand auch noch herausfindet, wie man macOS auf einem iPad installiert, damit wir endlich den Computer benutzen können, den Apple uns eigentlich hätte bauen sollen
https://www.theverge.com/2024/7/22/24200536/windows-xp-ipad-...
Auch Mac Catalyst scheint wie erwartet nur in eine Richtung zu funktionieren
Von der Größe her wäre ein iPad Mini ideal, aber iPadOS ist nutzlos, und gerade schaue ich mir das Surface Go an. Es ist nur etwas groß
Ich weiß zwar, dass es nichts mit macOS gibt, aber falls jemand ein kleines Tablet empfehlen kann, auf dem Win11 läuft, wäre ich dankbar. Wenn nötig, würde ich sogar aus China bestellen
Wenn man sich das GitHub-Profil des Autors ansieht, scheint er gerade erst sein Informatikstudium abgeschlossen zu haben, und das ist wirklich beeindruckende Arbeit
Ich habe das Gefühl, Apple hat den Simulator absichtlich nicht zu einem Emulator gemacht, weil sie nicht wollten, dass Leute in den internen Unterbau von iOS hineinstochern
Wenn man über den Bootloader hinaus ist, frage ich mich besonders angesichts von Apples vollständiger Hardwarekontrolle, warum man überhaupt noch so viele Unterschiede zwischen den beiden Betriebssystemen beibehalten sollte
Die Person hinter qemu-t8030 hat es geschafft, SpringBoard zu starten https://mastodon.social/@ntrung03/109712247237110967, den Code aber nicht veröffentlicht
Es wäre großartig, wenn sich dieser Fortschritt mit der vorliegenden Arbeit kombinieren ließe
https://www.xia0.sh/2024/03/09/Boot-Newer-iOS-with-QEMU-Step...
Frühere Kommentare: https://news.ycombinator.com/item?id=40219423
Verwandter Artikel: https://worthdoingbadly.com/hv/
Behandelt hardwarebeschleunigte virtuelle Maschinen auf einem jailbroken iPhone 12 / iOS 14.1
Etwas abseits vom Thema, aber ich frage mich, ob jemals jemand ARM-macOS auf x86-64 virtualisiert hat
Deshalb kann man nur Betriebssysteme virtualisieren, die für dieselbe CPU-Architektur wie das Hostsystem gebaut wurden
In allen anderen Fällen – etwa ARM-Software auf x86 oder umgekehrt – muss man Emulation verwenden, also Code interpretieren oder dynamisch neu kompilieren
Per Definition lässt sich zwar grundsätzlich alles auf allem emulieren. Kürzlich gab es sogar einen Fall, in dem Linux für MIPS auf dem ersten Mikroprozessor überhaupt, dem Intel 4004, gebootet wurde, aber die Leistung kann dabei natürlich zum Problem werden
Einen Mn-CPU zu virtualisieren, dürfte noch weniger sinnvoll sein
Apple stellt bereits den iOS Simulator in Xcode bereit, daher frage ich mich, was dieses Projekt besser macht als Apples eigenes Tool
Man kann zum Beispiel kein iOS-Binary aus dem App Store nehmen und unverändert im iOS Simulator ausführen, erst recht nicht auf einem Intel-Mac
Da der Simulator kein vollständiges iOS ausführt, kann man auch nicht untersuchen und lernen, wie das echte iOS intern funktioniert. Wenn man tief genug in die Frameworks des Simulators gräbt, landet man am Ende wieder bei macOS
Ein Emulator hingegen führt denselben vollständigen iOS-Build aus wie ein echtes Gerät. Theoretisch könnte man damit beliebige iOS-Binaries ohne Änderungen ausführen und untersuchen, wie das echte Betriebssystem arbeitet
Das ist ähnlich wie der Unterschied zwischen dem Ausführen einer App mit Wine und dem Ausführen derselben App in einer Windows-VM. Beim Simulator ist es aber eher so, als müsste man die Windows-App vor dem Start erst eigens für die Wine-Umgebung neu kompilieren und linken
Wenn man die Interna von Windows erforschen will, lernt man durch das bloße Ausführen unter Wine nicht besonders viel, während sich mit einer Windows-VM deutlich mehr untersuchen lässt
Für Clickfarmen wäre das ein frühes Weihnachtsgeschenk