Virtualizando o iOS no Apple silicon
(nickb.website)- Este é um experimento que usou o Virtualization.framework do Apple silicon Mac e um ambiente vma2 para inicializar uma build do iPhone XR com iOS 15.0.2 até o
PreBoard.app - O ponto central da abordagem é reutilizar a cadeia de boot do macOS 12.0.1 e trocar apenas a imagem do sistema iOS,
mtree,root_hashetrustcache, reduzindo a necessidade de modificar a cadeia de boot inicial - Ao chamar a função privada
_setProductionModeEnabled(false)para reduzir a VM ao estado CPFM01, o TSS assina firmware arbitrário para dispositivos vma2 públicos, diminuindo a necessidade do método vma2pwn anterior - O boot real exige patches de kernel e sistema que mexem em verificação de plataforma do XNU, system keybag, verificação de tamanho do IOMFB, ramdisk,
launchd,mount, DYLD shared cache,lockdowndemobileactivationd - O maior desafio ainda não resolvido é a compatibilidade do system keybag, e ainda não foi confirmado se entrada por toque seria possível via APIs privadas do Virtualization.framework
Objetivo do experimento e ponto de partida
- Com a transição para Apple silicon e o Mac Catalyst, iOS e macOS ficaram mais próximos, e a possibilidade de virtualizar o macOS levantou a questão central: seria possível virtualizar o iOS modificando uma cadeia de boot da mesma família?
- O trabalho anterior vma2pwn era um projeto para criar uma cadeia de boot macOS vma2 modificável para VMs guest de macOS, e serviu de base para este experimento
- Como caso público de virtualização/emulação de iOS concluída, existe o produto virtual iPhone cloud da Corellium
- Também foram consultados qemu-t8030, trabalhos baseados em QEMU e textos de Zhuowei Zhang; em especial, a relação entre
IOSurfaceRootno macOS eIOCoreSurfaceRootno iOS ajudou depois na busca por patches de kernel - Zhuowei Zhang considerou que apps gráficos de macOS não podem rodar no iOS, mas apps gráficos de iOS podem rodar no macOS, e essa propriedade também se aplica a boa parte do sistema gráfico do iOS
Recursos privados do Virtualization.framework
- O Virtualization.framework da Apple tem uma função privada não documentada
_setProductionModeEnabled(false) - Essa chamada e o recurso correspondente nas configurações da VM reduzem a VM para o Chip Fuse Mode CPFM
01, configurando o dispositivo virtual como “secure” e ao mesmo tempo “non-production” - Em dispositivos físicos, o TSS se recusa a assinar blobs SHSH exigidos por dispositivos non-production/non-secure como CPFM
00ou01 - Para dispositivos vma2 públicos, o TSS assina o firmware arbitrário fornecido, o que reduz bastante a necessidade do método vma2pwn de construir uma cadeia de firmware modificada
Como a VM de iOS foi montada
- A abordagem com mais sucesso foi usar a cadeia de boot do macOS 12.0.1 como está e substituir a imagem do sistema OS por imagens e arquivos relacionados da build do iPhone XR com iOS 15.0.2
- Os itens substituídos são a imagem do sistema,
mtree,root_hashetrustcache - Isso evita em grande parte a necessidade de modificar a cadeia de boot anterior à inicialização do iOS e o ramdisk de recuperação
- Os itens substituídos são a imagem do sistema,
- A build do iPhone XR foi escolhida por causa do suporte a arm64e e da possibilidade de resolução mais baixa
- Outras configurações de dispositivos arm64e também podem funcionar, mas o kernel vma2 está hardcoded para retornar
"iPad8,6"em algumas chaves sysctl - Builds arm64 sofreram com problemas adicionais e incompatibilidade binária, então foram consideradas pouco interessantes para teste
- Para executar a VM, foi usado o super-tart, um fork do app de terceiros tart para gerenciamento de VMs Apple silicon
- O super-tart permite usar os recursos privados necessários do Virtualization.framework
- Algumas mudanças, incluindo a alteração de
_setProductionModeEnabled(false), ainda não foram totalmente publicadas - Ferramentas do Virtualization.framework que usam API privada exigem desativar o SIP, e talvez também o AMFI
- Como ferramenta de restauração, foi usado um fork do idevicerestore
Patches de kernel
- O patch de verificação de assinatura usado no vma2pwn pode ser necessário, mas no método com CPFM
01não está claro se ele é obrigatório - Os patches ligados à assinatura no kernel vma2 fazem as funções abaixo retornarem 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_cachedeve ser patchado para retornar 1- Como binários de iOS não são binários de plataforma simulador, no início eles encerravam com
EXEC, [0xe] Binary with wrong platform- Isso é resolvido com um patch para pular a linha de verificação
PLATFORM_IOSno XNU - No kernel vma2, isso é feito trocando
B.NEporB
- Isso é resolvido com um patch para pular a linha de verificação
- Por causa da incompatibilidade do system keybag, o
PreBoard.appmostra “Swipe up to upgrade.” no lugar doSetup.app- Aplicando dois patches em
ipc_make_system_keybagpara forçar a função a não retornar erro, dá para chegar até oPreBoard.app - Essa limitação ainda não foi totalmente resolvida
- Aplicando dois patches em
- A diferença no tamanho da struct IOMFB entre frameworks de sistema do iOS e o kernel do macOS provoca kernel panic com a string
CLCDTransaction size mismatch. Returning error 0x%X.- Remover a verificação de tamanho em
IOMobileFramebufferUserClient::swap_submitfaz o panic parar
- Remover a verificação de tamanho em
Preparação para patch de arquivos do sistema
- O ramdisk de recuperação e os arquivos do sistema iOS são assinados, então eles encerram na execução se forem patchados sem reassinatura
- No ambiente modificado, é sugerido usar o
ldiddo Procursus- Exemplo de instalação:
brew install ldid-procursus - Exemplo de reassinatura:
ldid_macosx_arm64 -S -M <binary> -Saplica pseudo-sign ao binário, e-Mpreserva os entitlements existentes
- Exemplo de instalação:
- Muitos binários fazem verificação de identity, então antes de reassiná-los é preciso renomeá-los para a identity e depois restaurar o nome original
- Em
keybagd, a verificação deIdentifier=com.apple.keybagdé feita comcodesign -d -v keybagd mv keybagd com.apple.keybagdldid_macosx_arm64 -S -M com.apple.keybagdmv com.apple.keybagd keybagd
- Em
- Funções sem símbolos anexados automaticamente podem ser encontradas buscando XRefs de strings e rastreando a função chamadora por referências de logging
- Para obter um shell interativo no terminal serial, é possível portar Bash e um LaunchDaemon
- Foi usado o método de copiar os arquivos relevantes de payloads de jailbreak iOS compatíveis com a versão, como o Procursus
Modificação de DMG e ramdisk
- Para patchar o sistema ou o ramdisk de recuperação, é preciso modificar diretamente o volume DMG
- No exemplo do iOS 15.0.2, o volume iOS System incluído no IPSW é convertido para um formato com leitura e escrita
hdiutil convert -format UDRW -o 018-66258-074-rw.dmg 018-66258-074.dmg- Após montar:
sudo mount -uw /Volumes/Sky19A404.N104N841OS - Depois das alterações:
hdiutil convert -format ULFO -o 018-66258-074.dmg 018-66258-074-rw.dmg - Em seguida:
asr imagescan --source 018-66258-074.dmg
- Antes do boot do iOS, é necessário modificar
/usr/local/bin/restored_externalno ramdisk de recuperação- A versão de iOS de
restored_externaltenta criar um system keybag comMKBKeyBagCreateSystem, mas isso não é compatível com o kernel do macOS - O desvio é feito removendo a checagem de erro
- A condição da chamada
ramrod_set_NVRAM_variableé patchada para definirallow-root-hash-mismatchcomo true, isto é,1, pulando a autenticação do root hash
- A versão de iOS de
- Também é preciso modificar
/usr/sbin/asrno ramdisk de recuperação- É possível usar o asr64_patcher do iSuns9
- Encontra-se a função que imprime a string
"Image failed signature verification."e, na função que a referencia, troca-se a chamada ARMv8-ABLpor um saltoBque segue para o caminho"Image passed signature verification" - No binário
asrdo iOS 15.0.2, isso aplicab #0x7cno offset de arquivo0x27A18
Modificação do volume de sistema do iOS
- Para alinhar o próprio sistema iOS ao kernel do macOS, a maior parte dos arquivos que seriam instalados na raiz do sistema de arquivos deve ser movida para
/System/Library/Templates/Datano volume do sistema - Quando o sistema inicializa, esses arquivos passam a existir em
/ - Pastas vazias da raiz normal podem precisar permanecer no volume do sistema mesmo estando de fato vazias
- Um exemplo é
/Applications - Essa parte ainda não foi suficientemente testada
- Um exemplo é
Patches em launchd e keybagd
- No boot inicial do iOS,
/sbin/launchdé executado, e ele precisa de patches para iniciar o processo de boot inicial sem falhas - O primeiro patch é aplicado ao plist de configuração embutido no binário
- Procure a string
<key>SIGTERMTimeout</key>; cerca de 172 bytes antes dela está a configuração correspondente - Adicione
<key>PerformAfterUserspaceReboot</key><true/>às seçõesmount-phase-2,fips,tzinit,finish-demo-restore,fud,xpcroleaccountd,prng_seedctleMSUEarlyBootTask - Troque
RequireSuccessda seçãodata-protectionpara<false/>
- Procure a string
- A mudança em
data-protectioné necessária porque/usr/libexec/init_data_protectionfalha ao rodar na VM- Esse arquivo é um link simbólico para
/usr/libexec/seputil
- Esse arquivo é um link simbólico para
- Como a alteração do plist embutido pode ultrapassar o espaço original de string, dá para colar um XML comprimido com um XML minimizer e sobrescrever a área restante com caracteres de espaço compatíveis com XML
- O
launchdtambém inicializa/usr/libexec/keybagd, mas esse binário falha por causa das diferenças de kernel citadas antes- Uma forma de contornar isso é compilar um executável que simplesmente encerre com código 0 para substituir o
keybagd - O projeto fixkeybag também foi analisado, mas o código de criação de system keybag desse app também chama
MKBKeyBagCreateSystem, então ele falha mesmo em um iOS já inicializado
- Uma forma de contornar isso é compilar um executável que simplesmente encerre com código 0 para substituir o
- O
launchdtambém precisa de um patch adicional que transforma emNOPa ramificação condicionalTBZque provoca a string de panicUserspace reboot changed system version: previous %s != current %s
Modificações em mount, DYLD shared cache e camada gráfica
- Como o processo de restauração usa a cadeia de boot e o ramdisk do macOS, o
/sbin/mountdo iOS não consegue lidar corretamente com o volume APFS criado - A solução é pegar o binário
mountdo volume de sistema do macOS, ajustar os metadados Mach-O para que ele possa rodar no iOS e então substituí-lo- Isso pode ser feito manualmente, e também com o
vtoolincluído no macOS
- Isso pode ser feito manualmente, e também com o
- A modificação mais difícil é o patch no DYLD shared cache
IOSurfaceRootdo macOS eIOCoreSurfaceRootdo iOS são basicamente o mesmo driver, mas a diferença de nome impede a compatibilidade- Como o DYLD shared cache do iOS contém a string mais longa
"IOCoreSurfaceRoot", ela pode ser trocada por"IOSurfaceRoot"e os bytes restantes preenchidos com0x00
- Para analisar e extrair o DYLD shared cache, foi usada a ferramenta ipsw, de blacktop
ipsw dyld split <dsc file>separa as dylibs embutidas- No binário
/System/Library/Frameworks/IOSurface.framework/IOSurface, encontra-se a referência a"IOCoreSurfaceRoot"na função__iosConnectInitalize ipsw dyld a2oconverte endereço virtual em offset de arquivo- No exemplo, foi patchado o offset
0x28fde373dedyld_shared_cache_arm64e
- Depois de modificar o DYLD shared cache, há exceções porque o cdhash em outra posição não bate mais
- Com o GDB stub fornecido pelo frontend do Virtualization.framework, coloca-se um breakpoint em
cs_validate_hashno kernel para verificar o cdhash completo - No exemplo do iOS 15.0.2, os bytes antigos no offset de arquivo
0x5a9cffc0foram substituídos pelo novo cdhash
- Com o GDB stub fornecido pelo frontend do Virtualization.framework, coloca-se um breakpoint em
Daemons do sistema e patches de ativação
- O
watchdogdentra em crash-loop porque verifica se está rodando em uma VM e não tem um caminho de encerramento limpo no macOS, mas esse crash é tratado como inofensivo - No
backboardd, foram testados patches em chamadas ligadas à migração de dados que poderiam levar aoPreBoard.app, mas além de travar no logo da Apple não houve diferença observável - Na função
get_device_type_internal_block_invokedolockdownd, a chamadagetMGIntreferente a"ShouldHactivate"é patchada paramov x0, #1, forçando hactivation para contornar as restrições normais de ativação do iOS em ambiente de desenvolvimento - O
mobileactivationdtambém pode ser patchado para permitir hactivation- A função
shouldHactivateé substituída pelas instruções ARMv8-Amov x0, #0eret
- A função
- Ajustes adicionais necessários na device tree vma2 ficam como tarefa para o leitor
- Algumas ações podem exigir medidas anormais como
chmod -R 777 /
Limitações restantes e entrada por toque
- Para superar o problema do system keybag, será preciso entender melhor a estrutura correspondente existente no sistema iOS e no kernel, e criar patches adicionais
- O projeto já consumiu pelo menos várias centenas de horas, e o estado atual publicado chega ao boot até o
PreBoard.app - Ainda não foi confirmado se a função de toque funciona com o kernel e firmware públicos do vma2 Mac
- O Virtualization.framework tem APIs privadas relacionadas a toque
_VZAppleTouchScreenConfiguration_VZUSBTouchScreenConfiguration_VZTouch_VZMultiTouchEvent
- Essas APIs podem enviar eventos de toque, mas o uso exato dos parâmetros ainda não foi totalmente entendido
- O enum
TouchPhaseé um enum simples que implementa valores com os mesmos nomes deNSTouch.Phase - O código de exemplo às vezes pode gerar exceções
- Ainda não foi verificado se os valores de coordenadas são mapeados da forma esperada pela VM, nem se a VM consegue processá-los
- O enum
- A demo mostra a sequência de boot, e o trecho de espera de cerca de 30 segundos no meio foi cortado
1 comentários
Comentários do Hacker News
A Corellium venceu a disputa judicial e agora pode alugar VMs de iOS na nuvem para pesquisa de segurança https://hn.algolia.com/?query=corellium
Se for possível virtualizar iOS em um MacBook Apple Silicon, a demanda por serviços comerciais de virtualização de iOS pode cair
Para pessoas físicas custa cerca de US$ 400 por mês, e para empresas algo em torno de US$ 60.000 por ano https://support.corellium.com/subscriptions/pricing
Ótimo. Na próxima, seria bom descobrirem também como instalar macOS em um iPad, para que enfim possamos usar aquele computador que queríamos que a Apple tivesse criado
https://www.theverge.com/2024/7/22/24200536/windows-xp-ipad-...
O Mac Catalyst também parece funcionar só em uma direção, como era de se esperar
Pelo tamanho, o iPad Mini seria ótimo, mas o iPadOS não serve para nada, e agora estou olhando o Surface Go. Só que ele é um pouco grande
Sei que não existe nada com macOS, mas se alguém tiver recomendação de tablet pequeno que rode Win11, seria ótimo saber. Se precisar, penso até em encomendar da China
Pelo perfil do autor no GitHub, parece que ele acabou de se formar em ciência da computação; é um trabalho realmente impressionante
Tenho a sensação de que a Apple nunca transformou o Simulator em Emulator porque não quer que as pessoas fuçem nas camadas internas do iOS
Depois de passar do bootloader, especialmente com a Apple controlando até o hardware, fica a dúvida de por que ainda seria necessário manter tantas diferenças entre os dois sistemas operacionais
A pessoa que criou o qemu-t8030 conseguiu executar o SpringBoard https://mastodon.social/@ntrung03/109712247237110967, mas não publicou o código
Seria excelente se esse avanço pudesse ser combinado com este trabalho
https://www.xia0.sh/2024/03/09/Boot-Newer-iOS-with-QEMU-Step...
Comentários anteriores: https://news.ycombinator.com/item?id=40219423
Artigo relacionado: https://worthdoingbadly.com/hv/
Trata de máquinas virtuais com aceleração por hardware em um iPhone 12 com jailbreak / iOS 14.1
Fugindo um pouco do assunto, fico curioso se alguém já virtualizou macOS ARM em x86-64
Por isso, só é possível virtualizar sistemas operacionais compilados para a mesma arquitetura de CPU do sistema host
Em todos os demais casos, como rodar software ARM em x86 ou o contrário, é preciso usar emulação, que interpreta o código ou o recompila dinamicamente
Pela definição, dá para emular qualquer coisa em cima de qualquer outra. Recentemente, houve até o caso de inicializar Linux para MIPS em um Intel 4004, o primeiro microprocessador, mas desempenho pode ser um problema
Virtualizar a CPU Mn parece ainda menos útil
A Apple já fornece o iOS Simulator no Xcode; então fico me perguntando em que este projeto é melhor do que a ferramenta da Apple
Por exemplo, você não pode pegar um binário iOS da App Store e simplesmente executá-lo no iOS Simulator, especialmente em Macs Intel
Como o Simulator não executa um iOS completo, também não dá para investigar e aprender como as partes internas do iOS realmente funcionam. Se você cavar fundo o suficiente nos frameworks do Simulator, no fim acaba voltando ao macOS
Já um emulador executa o build completo do iOS, igual ao de um dispositivo real. Em teoria, você pode executar qualquer binário iOS sem modificações e investigar como o sistema operacional de fato funciona
É parecido com a diferença entre rodar um app no Wine e rodá-lo em uma VM do Windows. Só que, no caso do Simulator, é ainda mais próximo de uma situação em que você precisaria recompilar e relincar o app especificamente para o ambiente do Wine antes de executá-lo
Se você quer estudar as partes internas do Windows, não aprende tanto apenas rodando coisas no Wine, mas investigando uma VM do Windows aprende muito mais
Vai ser um presente de Natal antecipado para as click farms