Virtualizar iOS en Apple silicon
(nickb.website)- Experimento que logró arrancar una build de iOS 15.0.2 para iPhone XR hasta
PreBoard.appusando 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_hashytrustcache, reduciendo la carga de modificar la cadena de arranque inicial - Al bajar la VM al estado CPFM
01con 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,lockdowndymobileactivationd - 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
IOSurfaceRootde macOS yIOCoreSurfaceRootde 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
00o01 - 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_hashytrustcache - 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
- Los elementos reemplazados son la imagen del sistema,
- 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_cachedebe 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.NEporB
- Esto se resuelve parcheando XNU para saltarse la línea de verificación de
- Por la incompatibilidad de system keybag,
PreBoard.appmuestra “Swipe up to upgrade.” en lugar deSetup.app- Aplicando dos parches a
ipc_make_system_keybagpara forzar que la función no devuelva error, es posible llegar hastaPreBoard.app - Esta limitación todavía no está resuelta por completo
- Aplicando dos parches a
- 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_submitdetiene el panic
- Quitar la verificación de tamaño en
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
ldidde Procursus- Ejemplo de instalación:
brew install ldid-procursus - Ejemplo de re-firma:
ldid_macosx_arm64 -S -M <binary> -Spseudo-firma el binario y-Mpreserva los entitlements existentes
- Ejemplo de instalación:
- Muchos binarios verifican su identity, así que antes de re-firmarlos hay que cambiar el nombre al identity y luego restaurarlo
keybagdconfirmaIdentifier=com.apple.keybagdconcodesign -d -v keybagdmv keybagd com.apple.keybagdldid_macosx_arm64 -S -M com.apple.keybagdmv 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_externaldel ramdisk de recuperación- La versión iOS de
restored_externalintenta crear el system keybag conMKBKeyBagCreateSystem, 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_variablepara establecerallow-root-hash-mismatchen true, es decir1, y saltarse la autenticación del root hash
- La versión iOS de
- También hay que modificar
/usr/sbin/asrdel 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 llamadaBLde ARMv8-A por un saltoBque lleva a la ruta"Image passed signature verification" - En el binario
asrde iOS 15.0.2, se aplicab #0x7cen el offset de archivo0x27A18
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
- Un ejemplo es
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 seccionesmount-phase-2,fips,tzinit,finish-demo-restore,fud,xpcroleaccountd,prng_seedctlyMSUEarlyBootTask - En la sección
data-protection,RequireSuccessse cambia a<false/>
- Buscando la cadena
- El cambio en
data-protectiones necesario porque/usr/libexec/init_data_protectionfalla al ejecutarse en la VM- Ese archivo es un enlace simbólico a
/usr/libexec/seputil
- Ese archivo es un enlace simbólico a
- 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
launchdtambié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
- Una forma de evitarlo es compilar un ejecutable que simplemente termine con código 0 y usarlo para reemplazar
launchdnecesita además un parche extra para convertir enNOPla rama condicionalTBZque provoca el panic con la cadenaUserspace 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/mountde iOS no puede manejar correctamente los volúmenes APFS generados - La solución es tomar el binario
mountdel 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
- Esto puede hacerse manualmente o usando
- La modificación más difícil es el parche al DYLD shared cache
IOSurfaceRootde macOS yIOCoreSurfaceRootde 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 con0x00
- 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/IOSurfacese busca la referencia a"IOCoreSurfaceRoot"dentro de__iosConnectInitalize ipsw dyld a2oconvierte la dirección virtual en offset de archivo- En el ejemplo se parchea el offset
0x28fde373dedyld_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_hashpara inspeccionar el cdhash completo - En el ejemplo de iOS 15.0.2, se parchean los bytes originales en el offset de archivo
0x5a9cffc0con el nuevo cdhash
- Con el GDB stub que ofrece el frontend de Virtualization.framework se pone un breakpoint en la función del kernel
Daemons del sistema y parche de activación
watchdogdverifica 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
backboarddse probaron parches sobre llamadas relacionadas con migración de datos que podrían provocarPreBoard.app, pero no se observó diferencia aparte de quedarse detenido en el logo de Apple - En la función
get_device_type_internal_block_invokedelockdownd, se parchea la llamadagetMGIntsobre"ShouldHactivate"pormov x0, #1para forzar hactivation y saltarse las restricciones normales de activación de iOS en un entorno de desarrollo mobileactivationdtambién puede parchearse para permitir hactivation- La función
shouldHactivatese cambia por las instrucciones ARMv8-Amov x0, #0yret
- La función
- 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
TouchPhasees un enum simple que implementa valores con los mismos nombres queNSTouch.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
- El enum
- La demo muestra la secuencia de arranque, aunque se recortó un tramo intermedio de unos 30 segundos
1 comentarios
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
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
https://www.theverge.com/2024/7/22/24200536/windows-xp-ipad-...
Mac Catalyst también parece funcionar en una sola dirección, como era de esperarse
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
Viendo el perfil de GitHub del autor, parece que acaba de graduarse de ciencias de la computación; es un trabajo realmente impresionante
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
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
https://www.xia0.sh/2024/03/09/Boot-Newer-iOS-with-QEMU-Step...
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
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
Virtualizar una CPU de la serie Mn probablemente sería todavía menos útil
Apple ya ofrece iOS Simulator en Xcode; me pregunto qué tiene este proyecto que sea mejor que las herramientas de Apple
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