Mengemulasikan iPhone dengan QEMU
(eshard.com)- eShard, berdasarkan pekerjaan emulasi iOS open-source yang sudah ada, menargetkan emulator yang dapat mem-boot iOS 14 di QEMU serta menjalankan UI dan sebagian aplikasi
- Alih-alih memasukkan patch kernel langsung ke dalam QEMU, mereka memanfaatkan PongoOS dan checkra1n KPF untuk memisahkan patch XNU, lalu membuat isi patch dapat ditinjau dengan tool berbasis diff Mach-O
- Karena emulasi GPU Apple Silicon terlalu luas cakupannya, mereka lebih dulu memilih software rendering, dan memastikan lewat patch
QuartzCorepada iPhone yang di-jailbreak bahwa UI UIKit dapat digambar meski lambat - Untuk mengatasi masalah layar yang tetap hitam, mereka melanjutkan dengan menonaktifkan randomisasi alamat, debugging GDB, bypass pairing
lockdownd, menonaktifkan PAC, porting ke QEMU 8.2.1, dan otomatisasi patch dyld cache - Pada akhirnya, mereka menampilkan UI input passcode UIKit di layar QEMU dan memanipulasi textbox lewat input keyboard VNC, serta menyiapkan fondasi yang diperlukan hingga
SpringBoarddapat ditampilkan
Titik awal emulasi iOS
- Dalam peninjauan solusi open-source yang sudah ada, alephsecurity/xnu-qemu-arm64 pernah dicoba dijalankan, tetapi proyeknya berstatus read-only
- Setelah itu, TrungNguyen1909/qemu-t8030 digunakan sebagai titik awal
- Memungkinkan restore iOS melalui koneksi USB menggunakan QEMU “companion” kedua
- Mendukung menjalankan iOS 14
- Berbasis versi QEMU yang lebih baru
- Menyediakan wiki yang membahas cara menjalankan emulator
- Dengan memodifikasi
System/Library/xpc/launchd.plist, akses shell dan SSH dapat diperoleh dengan cepat - Target jangka panjangnya adalah emulasi iOS yang fungsional dengan UI dan setidaknya mampu menjalankan sebagian aplikasi
Memisahkan patch kernel dengan PongoOS
- Proyek
t8030memasukkan kode patch kernel XNU ke QEMU itu sendiri, tetapi karena kemungkinan jumlah patch akan bertambah, diperlukan struktur yang lebih rapi - Berdasarkan pengalaman dengan iPhone yang benar-benar di-jailbreak, mereka meninjau cara menerapkan patch checkra1n menggunakan PongoOS
- Dalam alur jailbreak umum, setelah perangkat di-pwn dengan checkmate, PongoOS disuntikkan ke SRAM dan modul
checkra1n-kpfdikirim melalui USB- Dalam pekerjaan ini, untuk menghindari penanganan USB awal, mereka memperbesar SRAM iPhone yang diemulasikan dan menggunakan PongoOS serta modul checkra1n KPF
- Pada tahap awal menjalankan PongoOS, masalah muncul karena tidak ada kode inisialisasi yang biasanya dijalankan bootrom atau iBoot
- Pengaturan FPU diperlukan sebelum instruksi double/float
- Masalah ini diselesaikan dengan merujuk dokumentasi ARM dan kode terkait QEMU yang sudah ada
- Fitur perangkat setelah A13 tidak didukung Pongo, sehingga merusak pattern matching pada sebagian patch
- Instruksi Pointer Authentication (PAC) seperti
autdadanxpacdditambahkan - Apple menggunakan slide yang berbeda
- Pada patch
task_for_pid(tfp0), ditemukan perbedaan alamat dan pola biner antara iPhone X dan iPhone 11
- Instruksi Pointer Authentication (PAC) seperti
File patch kernel deklaratif
- Pongo memungkinkan penggunaan patch checkra1n yang sudah ada untuk berbagai versi iOS, tetapi metode penerapan dinamis sulit dibaca, dimodifikasi, dan dibagikan
- Untuk memperlakukannya seperti patch kode sungguhan, mereka membuat file patch deklaratif dengan tool internal
- Membuat file patch teks berbasis perbedaan assembly dengan melakukan diff pada dua
Mach-O - Menulis program terpisah untuk menerapkan file patch yang dihasilkan ke biner
- Membuat file patch teks berbasis perbedaan assembly dengan melakukan diff pada dua
- Setelah boot dengan Pongo, mereka memakai QEMU monitor untuk men-dump bagian memori yang dipatch Pongo
- Setelah itu, kernel yang sudah dipatch disusun ulang dan sebuah file patch besar yang memuat semua modifikasi dibuat
- Dengan memecah patch besar tersebut dan memberi komentar, menjadi mungkin untuk meninjau dan mengendalikan bagian kernel mana yang dipatch
Strategi menggambar layar tanpa GPU
- Rendering grafis pada iPhone modern pada akhirnya melewati API Metal milik Apple dan membutuhkan GPU sungguhan
- Karena emulasi GPU Apple Silicon dianggap terlalu kompleks, mereka meninjau dua opsi
- Software rendering menggunakan bootarg
gpu=0seperti yang dulu dimungkinkan pada iOS lama - Meneruskan panggilan Metal ke iPhone sungguhan atau Mac dengan macOS untuk melakukan rendering
- Software rendering menggunakan bootarg
- Di iOS 14, opsi bootarg
gpu=0pada kernel XNU sudah hilang - Dari analisis framework
QuartzCoredengan Ghidra, software rendering ternyata dipanggil sebagai fallback ketika rendererMetaltidak ada - Pada iPhone sungguhan yang di-jailbreak, mereka mempatch
QuartzCoredan memastikan software rendering digunakan- UI menjadi jauh lebih lambat
- Artefak muncul di beberapa area, dan bagian tersebut kemungkinan secara langsung meminta rendering
Metal
- Dari eksperimen ini, mereka menilai software rendering juga memungkinkan di QEMU untuk cakupan yang tidak memakai
MetalatauOpenGLsecara langsung, yaitu sebagian besar aplikasi UIKit
Eksperimen proxy panggilan Metal
- Alternatif mem-proxy panggilan Metal juga diuji dengan dua iPhone fisik
- Mem-parsing semua header iOS dengan LLVM
- Pointer objek Objective-C di server direpresentasikan sebagai pointer stub di klien
- Menghasilkan kode pertukaran struct dan pointer secara otomatis
- Melakukan hook pada semua fungsi dan metode
- Meneruskan semua panggilan ke server dan mengembalikan hasil eksekusinya
- Round trip panggilan dasar untuk inisialisasi Metal sebagian berhasil
- Namun, bahasa Objective-C dan API
Metalsangat kompleks dan kaya fitur, sehingga beban kerja untuk membuatnya benar-benar berjalan sangat besar - Pendekatan ini ditunda, dan mereka memutuskan menyelesaikan masalah lain terlebih dahulu dengan software rendering meski ada batasan
- Framework iOS juga mengekspos private API yang tidak ada di header publik, dan meski ada cara untuk mem-parsingnya menjadi header, sebagian besar sulit digunakan langsung dan menambah kompleksitas
Debugging IOSurface dan framebuffer
- Setelah mencoba software rendering, perangkat framebuffer minimal tetap diperlukan, tetapi QEMU
t8030asli belum mengimplementasikannya - Mereka menemukan fork QEMUAppleSilicon yang memiliki pekerjaan dukungan IOMFB dan menggunakannya untuk debugging display
- Saat melakukan restore iOS dengan versi ini, logo Apple dan progress bar terlihat, tetapi pada boot normal layar tetap sepenuhnya hitam
- Setelah melihat kext IOMFB dengan Ghidra dan meninjau implementasi framebuffer QEMU, tampaknya ada dua mode
- Raw framebuffer pada alamat hardware tetap
- API yang lebih kompleks yang mengatur beberapa plane melalui register dan menulis data surface lewat DMA
- Mereka dapat menampilkan surface ARGB sembarang melalui raw framebuffer, tetapi saat boot sistem tidak menulis ke framebuffer tersebut
- Pada mode display kedua, terlihat trace bahwa kernel mengatur graphical plane melalui register, tetapi setelah itu tidak ada output layar
Menonaktifkan randomisasi alamat dan debugging GDB
- Akses SSH saja membatasi observasi sistem saat berjalan, sehingga perlu men-debug kernel dan user space dengan GDB
- Randomisasi alamat kernel diatur saat inisialisasi board
t8030, sehingga bisa dimatikan sepenuhnya - Di userland terdapat randomisasi executable dan randomisasi dynamic library di dalam dyld cache
- Executable dinonaktifkan dengan mempatch fungsi
_load_machfiledi kernel - Library dyld cache sekali dirandomisasi alamatnya saat boot, lalu dimuat pada alamat yang sama oleh semua executable
- Executable dinonaktifkan dengan mempatch fungsi
- Dyld cache di
/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64eberisi semua library framework dalam bentuk blob biner besar - Mereka membuat tool C yang melakukan
dlopenpada semua library framework dan mencantumkan image yang dimuat serta offset-nya dengan fungsi_dyld* - Dengan menggabungkan cara ini dan proses mengembalikan alamat GDB, library di dyld cache dapat di-debug
- Yang terutama menjadi perhatian adalah kext
IOMFB,backboardd,SpringBoard, danQuartzCore - Kemudian mereka juga menemukan cara menonaktifkan dyld cache dengan patch kernel, dan menggunakan library Rust object dari proyek Gimli untuk menemukan langsung alamat virtual dyld cache di host
- Untuk debugging user space diperlukan GDB server di guest, misalnya mereka menggunakan paket
debugserverdari Procursus
Log sistem dan bypass lockdownd
- Dengan GDB,
backboarddtampak mulai berjalan normal, tetapi untuk memahami situasi sebenarnya diperlukan log sistem - Pada iPhone sungguhan, log sistem dapat dilihat dengan
idevicesyslogsetelah pairing USB dengan komputer - Proses pairing mencakup pembuatan key pair, private key disimpan di iPhone, dan
lockdowndmemverifikasi identitas komputer - Di lingkungan emulasi, interaksi USB dimungkinkan, tetapi
lockdowndtidak berjalan dengan benar - Hasil analisis Ghidra menunjukkan
lockdowndmencoba memakaikeybaguntuk menyimpan private key, dan ini membutuhkan SEP yang tidak ada - Mereka menyuntikkan shellcode yang menggantikan sebagian fungsi yang ada agar key pair publik/privat yang sudah dibuat sebelumnya dibaca dari filesystem, lalu dimuat setiap kali
lockdowndmencoba mengambilnya darikeybag - Dengan debugging dan patch tambahan, mereka menyimulasikan bahwa pengguna telah memercayai komputer dan iPhone sudah dibuka kuncinya
- Pada akhirnya, QEMU companion dapat melakukan pairing dengan iPhone yang diemulasikan
- Dari log terlihat bahwa
QuartzCoreberhasil diinisialisasi, mendeteksi ukuran display, dan menggunakan fallback software rendering - Semuanya tampak normal, tetapi layar tetap tidak tampil
- Satu kesalahan terkait pixel format diakali dengan memaksa RGBA, tetapi kemudian dihapus
Masalah PAC dan porting QEMU 8
- Saat memperbaiki kesalahan pixel format pada
backboardd, muncul masalah tambahan akibat fitur keamanan iOS - Pemeriksaan tanda tangan saat load dan runtime sudah diselesaikan dengan patch kernel, tetapi saat menjalankan
backboarddyang dimodifikasi, terjadi kegagalan Pointer Authentication - Pointer Authentication adalah fitur yang ditambahkan di ARMv8.3, dan ini adalah masalah baru yang dihadapi pada board
t8030yang sedang diemulasikan, bukant8015yang sebelumnya digunakan - Awalnya mereka mempertimbangkan mengubah semua instruksi PAC menjadi NOP atau instruksi ekuivalen tanpa PAC
- Kemudian diketahui bahwa biner ARM64 PAC dapat dibangun dengan dua cara
- Menggunakan set instruksi PAC khusus yang hanya berjalan pada CPU ARMv8.3+
- Menggunakan set instruksi “unused” yang ditafsirkan sebagai PAC pada ARMv8.3+ dan sebagai instruksi ekuivalen tanpa PAC pada ARM lama
- Mereka memverifikasi perilaku ini dengan pengujian pada buildroot dan sistem ARM64 Linux, lalu memastikan biner untuk
t8030menggunakan set instruksi backward compatible arm64e - Mereka menduga jika PAC enforcing saja dimatikan di QEMU, kode akan berjalan seperti kode tanpa PAC, tetapi di QEMU 7 ini tidak berfungsi, sementara QEMU 8 memiliki perilaku berbeda
- Codebase saat ini di-porting ke QEMU 8.2.1
- Instruksi khusus Apple
genter,gexit - Kode penanganan GL exception levels
- Banyak modifikasi pada generic code QEMU membuat porting sulit
- Instruksi khusus Apple
- Setelah berbagai panic XNU, debugging kernel GDB, debugging QEMU sendiri, dan git bisect, iOS kembali bisa boot di QEMU 8
- Dengan demikian, PAC dapat dinonaktifkan dan kode executable apa pun bisa dimodifikasi di lokasi yang diinginkan
Melacak penyebab layar hitam
- Karena menurut log sistem
backboarddtampak berjalan normal, mereka menelusuri lebih dalam alasan tampilan tidak muncul - Jika raw ARGB frame ditulis langsung ke alamat, display sungguhan berubah, dan mereka dapat menggambar pada beberapa graphical plane
- Jadi implementasi display sendiri tampak normal, dan tersisa tiga kemungkinan
backboarddtidak menulis apa pun- Menulis ke alamat yang salah
- Data yang ditulis tidak valid
- Dengan QEMU monitor, mereka memperoleh alamat fisik yang tidak kontigu, lalu men-dump memori DMA fisik menggunakan skrip dan menggabungkannya menjadi satu file
- Mereka menafsirkannya sebagai frame ARGB dengan
ffplay, tetapi tidak memperoleh hasil yang bermakna - Berikutnya, mereka memasang breakpoint pada
iosurface_lockuntuk mendapatkan alamat surface yang dipetakan ke memoribackboardd, lalu menyelidikinya - Sesekali ditemukan bentuk aneh yang tampak seperti logo Apple, tetapi tampaknya ada masalah pada cara frame ditulis
- Ketika pekerjaan yang sama dilakukan pada iPhone 10 sungguhan, raw ARGB frame lengkap dari layar saat ini dapat di-dump dengan mudah
- Pada iPhone 11, yaitu setelah
t8030, surface tampaknya dikirim dalam bentuk terkompresi yang dapat diproses GPU - Karena hal ini tidak terjadi pada
t8015milik iPhone X, mereka memodifikasi DTB QEMU agar mengirimchip-idsebagai 8015, bukan 8030 - Hasilnya, setelah boot, logo Apple muncul di layar
Progress bar dan patch aktivasi
- Meski logo Apple sudah muncul, UI tidak bergerak lebih jauh, dan log sistem menampilkan banyak pesan dari berbagai daemon dan library
- Mereka melanjutkan dengan menebak kesalahan mana yang benar-benar terkait masalah UI, lalu memperbaikinya satu per satu
- Masalah terkait aktivasi pengguna ditemukan, dan sumber kesalahannya adalah daemon
mobileactivationdserta frameworkSpringBoardFoundation - Setelah keduanya dipatch, progress bar putih yang mirip dengan yang terlihat pada tahap restore muncul
- Progress bar tampak bergerak, tetapi setelah beberapa jam terlihat berhenti di 90%
Peningkatan iterasi patch dyld cache dan user space
- Berkat penonaktifan randomisasi alamat, patch user space dan framework dyld cache menjadi mungkin
- Seperti pada kernel, mereka membuat file patch teks untuk tiap biner/library dan menerapkannya dengan tool internal
- Karena dyld cache berukuran sekitar 2 GB, mempatch langsung atau menyalinnya berulang lewat SSH tidak praktis
- Karena bekerja di lingkungan Linux, NVMe juga tidak bisa dimodifikasi langsung
- Tool diff/patch internal diperluas agar sesuai untuk dyld cache dengan menemukan offset framework di dalam blob dyld cache
- Mereka menambahkan opsi untuk menghasilkan perintah
ddsederhana yang bisa langsung diterapkan di iPhone, beserta perintah revert - Setelah filesystem di-remount dalam mode baca/tulis, modifikasi dyld cache dapat diiterasi dengan cepat dengan menerapkan perintah
dd - Agar perubahan diterapkan, hanya perlu reboot iOS
- Agar cara ini bekerja, sebagian patch tambahan pada pemeriksaan tanda tangan kernel diperlukan
Menjalankan PreBoard dan menampilkan layar UIKit
- Sebelum menyelesaikan progress bar yang macet, mereka bereksperimen dengan proses sistem
PreBoard PreBoardtampaknya hanya ditampilkan kepada pengguna saat terjadi masalah seperti pembaruan yang terhenti- Seperti
SpringBoard, ini adalah aplikasi sistem yang menggambar langsung melaluibackboardd, sehingga dapat dijalankan langsung dari command line - Hasil eksekusinya menampilkan layar putih yang meminta “swipe to upgrade”
- Berdasarkan pengalaman sebelumnya menggunakan server VNC pada iPhone fisik, mereka menambahkan VNC, dan setelah berbagai kegagalan, layar dibuka bukan dengan swipe melainkan tombol keyboard
- Segera setelah dibuka, QEMU berhenti berjalan karena iOS menggunakan illegal instruction
- Analisis
backboarddmenunjukkan frameworkvImagemenggunakan instruksi AMX (Apple Matrix Coprocessor) untuk operasi grafis terakselerasi hardware seperti_vHorizontal_Scale_ARGB_8888_Accelerate - AMX adalah set instruksi proprietary Apple yang tidak diimplementasikan di CPU ARM emulasi QEMU
- Framework
vImagememiliki versi software alternatif yang hanya memakai instruksi ARM generik, sehingga mereka kembali mempatch agar versi itu digunakan - Hasil akhirnya, jendela
UIKitsungguhan ditampilkan, dengan layar input passcode dan textbox yang berfungsi - Event keyboard yang disuntikkan melalui VNC dapat digunakan untuk mengetik ke textbox
- Pada titik ini, komponen yang dibutuhkan agar
SpringBoardtampil dengan benar sudah siap, dan memulainya tampak hanya soal waktu - Tulisan berikutnya berlanjut ke Part 2
1 komentar
Komentar Hacker News
Akan menyenangkan kalau https://github.com/devos50/qemu-ios berkembang hingga mendukung iPhone OS 3.x, sehingga aplikasi iPhone awal bisa dicoba kembali sebagai bentuk pelestarian digital
https://github.com/touchHLE/touchHLE juga bagus, tetapi selain aplikasi yang sangat dasar, biasanya perlu patch per aplikasi
Untuk menjalankan aplikasi 32-bit di iOS 10, QEMU juga perlu mendukung iPhone 7
Dulu saya pernah mengemulasikan NumWorks N0100[1] dan HP Prime G1[2] dengan QEMU, sampai firmware resminya benar-benar bisa berjalan
[1] https://github.com/boricj/qemu/tree/numworks_calculators
[2] https://github.com/boricj/qemu/tree/s3c2416-boricj
Kalau proyek ini diterapkan dengan cara yang menarik, sepertinya kita bisa memasang image pmOS minimal dan versi QEMU ini di ponsel yang dukungan hardware postmarketOS-nya cukup baik, lalu mem-boot iOS di ponsel Android
Mungkin juga QEMU bisa dikustomisasi lebih jauh untuk meneruskan hardware ponsel seperti modem dan Bluetooth ke mesin virtual iOS
Rasanya itu saja sudah cukup memuaskan, bahkan tanpa emulasi iOS/Android
Versi arsip: https://archive.ph/l1CwO
Apakah ini berarti sekarang kita bisa melakukan hal-hal seperti pengujian Safari atau kompilasi untuk iOS di sistem Linux tanpa hardware Apple?
https://github.com/ChefKissInc/QEMUAppleSilicon
Ini adalah perangkat Apple Silicon yang diemulasikan di QEMU, dan saat ini hanya mendukung iPhone 11
Video demo: https://nitter.poast.org/eshard/status/1908162866609311962
Saya mencoba mengikuti panduan menjalankannya: https://github.com/TrungNguyen1909/qemu-t8030/wiki/Bringing-...
Terjadi crash berkali-kali, lebih banyak daripada yang ingin saya akui, tetapi hasilnya memang cukup keren
Tidak ada penyebutan tentang koneksi jaringan. Sepertinya chipset Wi-Fi atau modem seluler tidak diemulasikan
Saya penasaran bagaimana perangkat yang diemulasikan ini akan dihubungkan ke internet. Mungkin lewat semacam Ethernet melalui USB
Apa yang dibutuhkan agar Apple mau menerima pengembangan iOS multiplatform?
Dari sudut pandang Apple, mereka tidak mendapat apa-apa dengan mengizinkan model pengembangan seperti itu
Agar hal seperti ini terjadi, cara Apple memandang dunia harus berubah, dan itu tampaknya akan menjadi perubahan besar seperti ketika Microsoft sampai batas tertentu menerima Linux lewat WSL dan .NET untuk Linux
Apakah ada repositori yang bisa dipakai untuk mereproduksi ini?