2 puntos por GN⁺ 2024-10-08 | 1 comentarios | Compartir por WhatsApp
  • Experimento que logró arrancar una build de iOS 15.0.2 para iPhone XR hasta PreBoard.app usando Virtualization.framework de una Mac con Apple silicon y un entorno vma2
  • La clave del enfoque es reutilizar la cadena de arranque de macOS 12.0.1 y reemplazar solo la imagen del sistema iOS, mtree, root_hash y trustcache, reduciendo la carga de modificar la cadena de arranque inicial
  • Al bajar la VM al estado CPFM 01 con la llamada privada _setProductionModeEnabled(false), TSS firma firmware arbitrario para dispositivos vma2 públicos, lo que reduce la necesidad del método vma2pwn anterior
  • El arranque real requiere parches de kernel y del sistema que tocan la verificación de plataforma de XNU, system keybag, verificación de tamaño de IOMFB, ramdisk, launchd, mount, DYLD shared cache, lockdownd y mobileactivationd
  • El mayor problema aún sin resolver es la compatibilidad de system keybag, y todavía no se confirma si la entrada táctil será posible mediante APIs privadas de Virtualization.framework

Objetivo del experimento y punto de partida

  • Con la transición a Apple silicon y después de Mac Catalyst, iOS y macOS se acercaron más, y al volverse posible virtualizar macOS, la pregunta central pasó a ser si iOS también podría virtualizarse modificando una cadena de arranque de la misma familia
  • El trabajo previo vma2pwn era un proyecto para crear una cadena de arranque macOS vma2 modificable para VM invitadas de macOS, y sirvió como base para este experimento
  • Un caso públicamente conocido de virtualización/emulación de iOS ya terminada es el producto virtual iPhone cloud de Corellium
  • También se tomaron como referencia qemu-t8030, trabajos basados en QEMU y textos de Zhuowei Zhang; en especial, la relación entre IOSurfaceRoot de macOS y IOCoreSurfaceRoot de iOS ayudó después a explorar parches del kernel
  • Zhuowei Zhang planteó que las apps macOS con GUI no pueden ejecutarse en iOS, pero las apps gráficas de iOS sí pueden ejecutarse en macOS, y esta propiedad también aplica en gran parte al sistema gráfico de iOS

Funciones privadas de Virtualization.framework

  • Virtualization.framework de Apple incluye una función privada no documentada: _setProductionModeEnabled(false)
  • Esta llamada y la función correspondiente en la configuración de la VM bajan la VM al Chip Fuse Mode CPFM 01, configurando el dispositivo virtual como “secure” pero “non-production”
  • En dispositivos físicos, TSS rechaza firmar blobs SHSH requeridos por dispositivos non-production/non-secure como CPFM 00 o 01
  • En los dispositivos vma2 públicos, TSS sí firma el firmware arbitrario proporcionado, así que la necesidad del enfoque vma2pwn para crear una cadena de firmware modificada se reduce mucho

Método de configuración de la VM de iOS

  • El enfoque más exitoso fue usar intacta la cadena de arranque de macOS 12.0.1 y reemplazar la imagen del sistema operativo por la imagen y archivos relacionados de una build de iOS 15.0.2 para iPhone XR
    • Los elementos reemplazados son la imagen del sistema, mtree, root_hash y trustcache
    • Este método evita en gran medida la necesidad de modificar la cadena de arranque previa a la inicialización de iOS y el ramdisk de recuperación
  • La build de iPhone XR fue elegida por su soporte arm64e y la posibilidad de una resolución más baja
  • Otras configuraciones de dispositivos arm64e también podrían funcionar, pero el kernel vma2 tiene codificado de forma fija que algunas claves sysctl devuelvan "iPad8,6"
  • Las builds arm64 presentaron problemas adicionales e incompatibilidades binarias, por lo que se consideró que valía menos la pena intentarlo
  • Para ejecutar la VM se usó super-tart, un fork de la app de terceros tart para gestionar VM en Apple silicon
    • super-tart permite usar las funciones privadas necesarias de Virtualization.framework
    • Algunos cambios, como el ajuste de _setProductionModeEnabled(false), todavía no se han publicado por completo
    • Las herramientas de Virtualization.framework que usan APIs privadas requieren desactivar SIP, y posiblemente también AMFI
  • Como herramienta de restauración se usó un fork de idevicerestore

Parches de kernel

  • Puede que hagan falta los parches de verificación de firma usados en vma2pwn, aunque no está claro si son estrictamente necesarios con el método CPFM 01
  • Los parches relacionados con firma hacen que las siguientes funciones del kernel vma2 devuelvan 0
    • _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 debe parchearse para que devuelva 1
  • Como los binarios de iOS no son binarios de plataforma simulador, al inicio terminan con EXEC, [0xe] Binary with wrong platform
    • Esto se resuelve parcheando XNU para saltarse la línea de verificación de PLATFORM_IOS
    • En el kernel vma2 se aplica cambiando B.NE por B
  • Por la incompatibilidad de system keybag, PreBoard.app muestra “Swipe up to upgrade.” en lugar de Setup.app
    • Aplicando dos parches a ipc_make_system_keybag para forzar que la función no devuelva error, es posible llegar hasta PreBoard.app
    • Esta limitación todavía no está resuelta por completo
  • La diferencia de tamaño de estructuras IOMFB entre los frameworks del sistema iOS y el kernel de macOS provoca un kernel panic con la cadena CLCDTransaction size mismatch. Returning error 0x%X.
    • Quitar la verificación de tamaño en IOMobileFramebufferUserClient::swap_submit detiene el panic

Preparación para parchar archivos del sistema

  • Como el ramdisk de recuperación y los archivos del sistema iOS están firmados, si no se vuelven a firmar tras el parcheo terminan al ejecutarse
  • En este entorno modificado se propone usar ldid de Procursus
    • Ejemplo de instalación: brew install ldid-procursus
    • Ejemplo de re-firma: ldid_macosx_arm64 -S -M <binary>
    • -S pseudo-firma el binario y -M preserva los entitlements existentes
  • Muchos binarios verifican su identity, así que antes de re-firmarlos hay que cambiar el nombre al identity y luego restaurarlo
    • keybagd confirma Identifier=com.apple.keybagd con codesign -d -v keybagd
    • mv keybagd com.apple.keybagd
    • ldid_macosx_arm64 -S -M com.apple.keybagd
    • mv com.apple.keybagd keybagd
  • Las funciones sin símbolos automáticos pueden localizarse buscando XRef de cadenas y rastreando la función llamadora mediante referencias a llamadas de logging
  • Para obtener un shell interactivo en la terminal serial se pueden portar Bash y un LaunchDaemon
    • El método usado consiste en copiar archivos relacionados desde payloads de jailbreak de iOS compatibles en versión, como Procursus

Modificación de DMG y ramdisk

  • Para parchar el sistema o el ramdisk de recuperación hay que modificar directamente el volumen DMG
  • En el ejemplo con iOS 15.0.2, el volumen iOS System incluido en el IPSW se convierte a un formato escribible
    • hdiutil convert -format UDRW -o 018-66258-074-rw.dmg 018-66258-074.dmg
    • Tras montarlo: sudo mount -uw /Volumes/Sky19A404.N104N841OS
    • Después de modificarlo: hdiutil convert -format ULFO -o 018-66258-074.dmg 018-66258-074-rw.dmg
    • Luego: asr imagescan --source 018-66258-074.dmg
  • Antes de arrancar iOS hay que modificar /usr/local/bin/restored_external del ramdisk de recuperación
    • La versión iOS de restored_external intenta crear el system keybag con MKBKeyBagCreateSystem, pero no es compatible con el kernel de macOS
    • Se evita eliminando la verificación de error
    • También se parchea la condición de la llamada ramrod_set_NVRAM_variable para establecer allow-root-hash-mismatch en true, es decir 1, y saltarse la autenticación del root hash
  • También hay que modificar /usr/sbin/asr del ramdisk de recuperación
    • Se puede usar asr64_patcher de iSuns9
    • Se busca la función que imprime la cadena "Image failed signature verification." y, en la función que la referencia, se cambia la llamada BL de ARMv8-A por un salto B que lleva a la ruta "Image passed signature verification"
    • En el binario asr de iOS 15.0.2, se aplica b #0x7c en el offset de archivo 0x27A18

Modificación del volumen del sistema iOS

  • Para ajustar el propio sistema iOS al kernel de macOS, la mayoría de los archivos que se instalarían en la raíz del sistema de archivos del volumen del sistema deben moverse a /System/Library/Templates/Data
  • Cuando el sistema arranca, esos archivos pasan a existir en /
  • Las carpetas vacías de la raíz normal podrían tener que permanecer en el volumen del sistema aunque realmente estén vacías
    • Un ejemplo es /Applications
    • Esta parte no se ha probado lo suficiente

Parches a launchd y keybagd

  • En el arranque temprano de iOS se ejecuta /sbin/launchd, y hacen falta parches para iniciar el proceso de boot inicial sin fallos
  • El primer parche se aplica al plist de configuración incrustado en el binario
    • Buscando la cadena <key>SIGTERMTimeout</key> se puede localizar la configuración correspondiente unos 172 bytes antes
    • Se agrega <key>PerformAfterUserspaceReboot</key><true/> a las secciones mount-phase-2, fips, tzinit, finish-demo-restore, fud, xpcroleaccountd, prng_seedctl y MSUEarlyBootTask
    • En la sección data-protection, RequireSuccess se cambia a <false/>
  • El cambio en data-protection es necesario porque /usr/libexec/init_data_protection falla al ejecutarse en la VM
    • Ese archivo es un enlace simbólico a /usr/libexec/seputil
  • Como modificar el plist incrustado puede exceder el espacio de cadenas disponible, se puede pegar XML comprimido con un minimizador XML y rellenar el área restante con espacios compatibles con XML
  • launchd también inicializa /usr/libexec/keybagd, pero este binario falla por las diferencias de kernel ya mencionadas
    • Una forma de evitarlo es compilar un ejecutable que simplemente termine con código 0 y usarlo para reemplazar keybagd
    • También se revisó el proyecto fixkeybag, pero su código para crear el system keybag también llama a MKBKeyBagCreateSystem, por lo que falla incluso con iOS ya arrancado
  • launchd necesita además un parche extra para convertir en NOP la rama condicional TBZ que provoca el panic con la cadena Userspace reboot changed system version: previous %s != current %s

Modificación de mount, DYLD shared cache y la capa gráfica

  • Como el proceso de restauración se maneja con la cadena de arranque y el ramdisk de macOS, el /sbin/mount de iOS no puede manejar correctamente los volúmenes APFS generados
  • La solución es tomar el binario mount del volumen de sistema macOS, ajustar sus metadatos Mach-O para que pueda ejecutarse en iOS y reemplazarlo
    • Esto puede hacerse manualmente o usando vtool, incluido en macOS
  • La modificación más difícil es el parche al DYLD shared cache
    • IOSurfaceRoot de macOS y IOCoreSurfaceRoot de iOS son básicamente el mismo driver, pero la diferencia de nombre rompe la compatibilidad
    • En el DYLD shared cache de iOS existe la cadena más larga "IOCoreSurfaceRoot", así que se reemplaza por "IOSurfaceRoot" y los bytes restantes se rellenan con 0x00
  • Para analizar y extraer el DYLD shared cache se usó la herramienta ipsw de blacktop
    • ipsw dyld split <dsc file> separa las dylib incrustadas
    • En el binario /System/Library/Frameworks/IOSurface.framework/IOSurface se busca la referencia a "IOCoreSurfaceRoot" dentro de __iosConnectInitalize
    • ipsw dyld a2o convierte la dirección virtual en offset de archivo
    • En el ejemplo se parchea el offset 0x28fde373 de dyld_shared_cache_arm64e
  • Tras modificar el DYLD shared cache aparece una excepción porque el cdhash en otra ubicación deja de coincidir
    • Con el GDB stub que ofrece el frontend de Virtualization.framework se pone un breakpoint en la función del kernel cs_validate_hash para inspeccionar el cdhash completo
    • En el ejemplo de iOS 15.0.2, se parchean los bytes originales en el offset de archivo 0x5a9cffc0 con el nuevo cdhash

Daemons del sistema y parche de activación

  • watchdogd verifica si se está ejecutando en una VM y entra en un crash-loop porque no tiene una ruta de salida limpia de código macOS, pero este crash se considera inocuo
  • En backboardd se probaron parches sobre llamadas relacionadas con migración de datos que podrían provocar PreBoard.app, pero no se observó diferencia aparte de quedarse detenido en el logo de Apple
  • En la función get_device_type_internal_block_invoke de lockdownd, se parchea la llamada getMGInt sobre "ShouldHactivate" por mov x0, #1 para forzar hactivation y saltarse las restricciones normales de activación de iOS en un entorno de desarrollo
  • mobileactivationd también puede parchearse para permitir hactivation
    • La función shouldHactivate se cambia por las instrucciones ARMv8-A mov x0, #0 y ret
  • Las modificaciones adicionales necesarias en el device tree vma2 quedan como tarea para quien lo intente
  • Para que algunas cosas funcionen puede hacer falta una medida anómala como chmod -R 777 /

Limitaciones restantes y entrada táctil

  • Para superar el problema de system keybag hace falta entender mejor la estructura correspondiente tanto en el sistema iOS como en el kernel y crear más parches
  • El proyecto ya lleva al menos varios cientos de horas, y el estado público actual llega solo a arrancar hasta PreBoard.app
  • Todavía no se ha confirmado si la función táctil funciona con el kernel y firmware públicos de vma2 Mac
  • Virtualization.framework incluye APIs privadas relacionadas con touch
    • _VZAppleTouchScreenConfiguration
    • _VZUSBTouchScreenConfiguration
    • _VZTouch
    • _VZMultiTouchEvent
  • Con estas APIs se pueden enviar eventos táctiles, pero todavía no se entiende por completo cómo usar correctamente sus parámetros
    • El enum TouchPhase es un enum simple que implementa valores con los mismos nombres que NSTouch.Phase
    • El código de ejemplo a veces puede generar excepciones
    • Tampoco está claro si los valores de coordenadas se mapean de la forma que espera la VM, ni si la VM puede procesarlos
  • La demo muestra la secuencia de arranque, aunque se recortó un tramo intermedio de unos 30 segundos

1 comentarios

 
GN⁺ 2024-10-08
Opiniones en Hacker News
  • Corellium ganó la disputa legal, así que ahora puede alquilar VMs de iOS en la nube para investigación de seguridad https://hn.algolia.com/?query=corellium
    Si se puede virtualizar iOS en una MacBook con Apple Silicon, podría bajar la demanda de servicios comerciales de virtualización de iOS
    Para individuos cuesta alrededor de USD 400 al mes, y para empresas USD 60,000 al año https://support.corellium.com/subscriptions/pricing

    • Dios mío, cuesta USD 4~USD 8 por hora; me pregunto quién paga por estas VMs
  • Bien. Ojalá después encuentren también cómo instalar macOS en un iPad, para que por fin podamos usar esa computadora que muchos esperábamos que Apple hiciera

    • Se puede empezar con Windows XP
      https://www.theverge.com/2024/7/22/24200536/windows-xp-ipad-...
    • Según la sección de trabajos previos, [Zhuowei Zhang] concluyó que las apps macOS con GUI no pueden ejecutarse en iOS, pero las apps iOS gráficas sí pueden ejecutarse en macOS
      Mac Catalyst también parece funcionar en una sola dirección, como era de esperarse
    • Totalmente de acuerdo, mil veces. En las últimas semanas estuve buscando exactamente esto: una tablet con un sistema operativo para desarrollo
      Por tamaño, el iPad Mini sería ideal, pero iPadOS no sirve para eso, y ahora estoy mirando la Surface Go. Aunque es algo grande
      Sé que no hay ningún producto con macOS, pero si alguien tiene recomendaciones de tablets pequeñas que corran Win11, se lo agradecería. Si hace falta, estoy dispuesto a pedir una desde China
    • El iPad Pro es el dispositivo más rápido con M4
    • ¿Basta con llamarla una MacBook Air con una protuberancia invertida y teclado desmontable?
  • Viendo el perfil de GitHub del autor, parece que acaba de graduarse de ciencias de la computación; es un trabajo realmente impresionante

    • Me imagino que pronto le llegará una oferta de Apple
  • Me da la sensación de que Apple no convirtió el Simulator en un Emulator porque no quiere que la gente escarbe en las capas internas de iOS

    • Otra razón por la que originalmente fue un Simulator y no un Emulator quizá sea que, en ese entonces, muchos componentes de iOS o iPhone OS eran forks de bibliotecas existentes de Mac OS X
    • Los desarrolladores todavía usan Macs Intel, y ahí no se puede virtualizar iOS ARM
    • Ahora que iPhone, Mac y iPad son todos arm64, y además basados en Apple Silicon, realmente me da curiosidad qué tan distintos son los bootloaders de iOS y macOS
      Una vez pasado el bootloader, sobre todo considerando que Apple también controla el hardware, me pregunto si tiene sentido seguir manteniendo tantas diferencias entre los dos sistemas operativos
  • La persona que creó qemu-t8030 logró ejecutar SpringBoard https://mastodon.social/@ntrung03/109712247237110967, pero no publicó el código
    Sería excelente si ese avance pudiera combinarse con este trabajo

  • Comentario anterior: https://news.ycombinator.com/item?id=40219423

  • Artículo relacionado: https://worthdoingbadly.com/hv/
    Trata sobre máquinas virtuales con aceleración por hardware en un iPhone 12 con jailbreak / iOS 14.1

  • Un poco tangencial, pero me pregunto si alguien ha virtualizado macOS ARM en x86-64

    • Es imposible. En general, “virtualización” significa ejecutar un sistema operativo mediante virtualización por hardware: la CPU anfitriona ejecuta el código de forma nativa y pasa toda la E/S al hipervisor
      Por eso solo se pueden virtualizar sistemas operativos compilados para la misma arquitectura de CPU que el sistema anfitrión
      Para los demás casos, como ejecutar software ARM en x86 o al revés, hay que usar emulación, que interpreta o recompila dinámicamente el código
      Por definición, cualquier cosa puede emularse sobre cualquier otra. Hace poco incluso hubo un caso en el que arrancaron Linux para MIPS en el Intel 4004, el primer microprocesador, pero el rendimiento puede ser un problema
    • Si pruebas virtualizar ARM genérico en QEMU, verás que ni siquiera llega al rendimiento de una Raspberry Pi. En versiones recientes debería venir incluido por defecto
      Virtualizar una CPU de la serie Mn probablemente sería todavía menos útil
    • Conviene echar un vistazo a los proyectos Hackintosh
  • Apple ya ofrece iOS Simulator en Xcode; me pregunto qué tiene este proyecto que sea mejor que las herramientas de Apple

    • Simulator no ejecuta iOS real ni builds iOS reales de las apps. Cuando ejecutas una app en Simulator, la app se compila para el conjunto de instrucciones nativo de la Mac actual, y se vincula y ejecuta contra frameworks y bibliotecas de Mac que imitan el comportamiento esperado de iOS o, en algunos casos, solo ofrecen una carcasa
      Por ejemplo, no puedes tomar un binario iOS de la App Store y ejecutarlo tal cual en iOS Simulator; en una Mac Intel, menos todavía
      Como Simulator no ejecuta un iOS completo, tampoco puedes investigar ni aprender cómo funcionan realmente las partes internas de iOS. Si escarbas lo suficiente en los frameworks de Simulator, al final vuelves a macOS
      En cambio, un emulador ejecuta el build completo de iOS, igual que en un dispositivo real. En teoría, podría ejecutar cualquier binario de iOS sin modificaciones e investigar cómo funciona el sistema operativo real
      Es parecido a la diferencia entre ejecutar una app con Wine y ejecutarla en una VM de Windows. Aunque en el caso de Simulator, se parece más a tener que recompilar y vincular la app específicamente para el entorno de Wine antes de ejecutar una app de Windows
      Si quieres estudiar las partes internas de Windows, no aprenderás mucho solo ejecutando cosas con Wine; en cambio, examinando una VM de Windows puedes aprender mucho más
  • Para las granjas de clics, esto va a ser un regalo de Navidad adelantado