2 Punkte von GN⁺ 2024-10-08 | 1 Kommentare | Auf WhatsApp teilen
  • 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.app gebootet wurde
  • Kern des Ansatzes ist die Wiederverwendung der Boot Chain von macOS 12.0.1; nur das iOS-System-Image, mtree, root_hash und trustcache werden 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-Status 01 versetzt, 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, lockdownd und mobileactivationd betreffen
  • 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 IOSurfaceRoot in macOS und IOCoreSurfaceRoot in 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 01 herab 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 00 oder 01 nö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_hash und trustcache
    • Dieser Ansatz umgeht weitgehend die Notwendigkeit, die Boot Chain und die Recovery-ramdisk vor der iOS-Initialisierung zu verändern
  • 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_cache muss 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 platform beendet
    • Das lässt sich beheben, indem die Zeile mit der Prüfung auf PLATFORM_IOS in XNU übersprungen wird
    • Im vma2-Kernel wurde dies umgesetzt, indem B.NE durch B ersetzt wurde
  • Wegen Inkompatibilität des system keybag zeigt PreBoard.app statt Setup.app den 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 sich PreBoard.app erreichen
    • Diese Grenze ist noch nicht vollständig überwunden
  • 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

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’ ldid vorgeschlagen
    • Installationsbeispiel: brew install ldid-procursus
    • Beispiel zum erneuten Signieren: ldid_macosx_arm64 -S -M <binary>
    • -S pseudo-signiert das Binary, -M bewahrt vorhandene Entitlements
  • 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
    • keybagd zeigt mit codesign -d -v keybagd den Identifier Identifier=com.apple.keybagd
    • mv keybagd com.apple.keybagd
    • ldid_macosx_arm64 -S -M com.apple.keybagd
    • mv 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_external in der Recovery-ramdisk geändert werden
    • Die iOS-Version von restored_external versucht, mit MKBKeyBagCreateSystem den 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_variable wird allow-root-hash-mismatch auf true, also 1, gesetzt und die Root-Hash-Authentifizierung übersprungen
  • Auch /usr/sbin/asr in 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 einen B-Sprung auf den Pfad "Image passed signature verification"
    • Im asr-Binary von iOS 15.0.2 wird bei Datei-Offset 0x27A18 b #0x7c angewendet

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

Patches für launchd und keybagd

  • Früh im iOS-Boot wird /sbin/launchd ausgefü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, MSUEarlyBootTask wird <key>PerformAfterUserspaceReboot</key><true/> hinzugefügt
    • Im Abschnitt data-protection wird RequireSuccess auf <false/> geändert
  • Die Änderung an data-protection ist nötig, weil /usr/libexec/init_data_protection in der VM fehlschlägt
    • Diese Datei ist ein symbolischer Link auf /usr/libexec/seputil
  • 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
  • launchd initialisiert 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 keybagd zu ersetzen
    • Das Projekt fixkeybag wurde ebenfalls geprüft, aber auch der Code dieser App zur Erstellung des system keybag ruft MKBKeyBagCreateSystem auf und scheitert daher selbst in gebootetem iOS-Zustand
  • Für launchd ist ein weiterer Patch nötig, der die bedingte Verzweigung TBZ, die die Panic-Zeichenkette Userspace reboot changed system version: previous %s != current %s auslöst, durch NOP ersetzt

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/mount die 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 vtool kann verwendet werden
  • Schwieriger ist der Patch des DYLD shared cache
    • IOSurfaceRoot in macOS und IOCoreSurfaceRoot in 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 mit 0x00 aufgefü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/IOSurface sucht man in der Funktion __iosConnectInitalize die Referenz auf "IOCoreSurfaceRoot"
    • Mit ipsw dyld a2o wird die virtuelle Adresse in einen Datei-Offset umgerechnet
    • Im Beispiel wurde Offset 0x28fde373 in dyld_shared_cache_arm64e gepatcht
  • 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_hash gesetzt, um den vollständigen cdhash zu ermitteln
    • Im Beispiel mit iOS 15.0.2 wurden die vorhandenen Bytes bei Datei-Offset 0x5a9cffc0 durch den neuen cdhash ersetzt

System-Daemons und Aktivierungs-Patches

  • watchdogd prü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 backboardd wurden Patches an Aufrufen im Zusammenhang mit Datenmigration ausprobiert, die PreBoard.app auslösen könnten; außer einem Hängenbleiben beim Apple-Logo zeigte sich jedoch kein Unterschied
  • In der Funktion get_device_type_internal_block_invoke von lockdownd wird der getMGInt-Aufruf für "ShouldHactivate" zu mov x0, #1 gepatcht, um in der Entwicklungsumgebung hactivation zu erzwingen und normale iOS-Aktivierungsbeschränkungen zu umgehen
  • Auch mobileactivationd kann so gepatcht werden, dass hactivation erlaubt wird
    • Die Funktion shouldHactivate wird durch die ARMv8-A-Instruktionen mov x0, #0 und ret ersetzt
  • 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 von NSTouch.Phase implementiert
    • 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
  • Die Demo zeigt die Boot-Sequenz; eine etwa 30 Sekunden lange Wartephase in der Mitte wurde herausgeschnitten

1 Kommentare

 
GN⁺ 2024-10-08
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

    • Meine Güte, 4 bis 8 $ pro Stunde – ich frage mich, wer für solche VMs bezahlt
  • 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

    • Man könnte mit Windows XP anfangen
      https://www.theverge.com/2024/7/22/24200536/windows-xp-ipad-...
    • Laut dem Abschnitt zur Vorarbeit kam [Zhuowei Zhang] zu dem Schluss, dass GUI-macOS-Apps auf iOS nicht laufen können, grafische iOS-Apps aber auf macOS schon
      Auch Mac Catalyst scheint wie erwartet nur in eine Richtung zu funktionieren
    • Dem stimme ich wirklich zu 1000 % zu. Ich suche seit einigen Wochen genau nach so etwas, also einem Tablet mit einem Betriebssystem für Entwicklung
      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
    • Das iPad Pro ist mit dem M4 das schnellste Gerät
    • Reicht es, es einfach ein MacBook Air mit umgedrehtem Kamerabuckel und abnehmbarer Tastatur zu nennen?
  • 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 würde vermuten, ein Jobangebot von Apple kommt bald
  • 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

    • Ein weiterer Grund, warum es ursprünglich ein Simulator und kein Emulator war, könnte sein, dass damals viele Bestandteile von iOS bzw. iPhone OS Forks bestehender Mac-OS-X-Bibliotheken waren
    • Entwickler nutzen immer noch Intel-Macs, und dort lässt sich ARM-iOS nicht virtualisieren
    • Jetzt, da iPhone, Mac und iPad alle arm64 und dazu auch noch Apple-Silicon-basiert sind, frage ich mich wirklich, wie unterschiedlich die Bootloader von iOS und macOS eigentlich sind
      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

  • 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

    • Nein, das ist nicht möglich. Im Allgemeinen bedeutet „Virtualisierung“, ein Betriebssystem mittels Hardware-Virtualisierung auszuführen, wobei die Host-CPU den Code nativ ausführt und alle Ein-/Ausgaben an den Hypervisor übergibt
      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
    • Wenn man in QEMU generisches ARM virtualisiert, merkt man, dass man nicht einmal an die Leistung eines Raspberry Pi herankommt. In neueren Versionen sollte das standardmäßig enthalten sein
      Einen Mn-CPU zu virtualisieren, dürfte noch weniger sinnvoll sein
    • Schau dir das Hackintosh-Projekt an
  • Apple stellt bereits den iOS Simulator in Xcode bereit, daher frage ich mich, was dieses Projekt besser macht als Apples eigenes Tool

    • Der Simulator führt weder echtes iOS noch den iOS-Build einer App aus. Wenn man eine App im Simulator ausführt, wird sie für den nativen Befehlssatz des aktuellen Macs kompiliert und gegen Mac-Frameworks und -Bibliotheken gelinkt, die das erwartete iOS-Verhalten nachahmen oder teils nur pro forma bereitstellen
      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