QEMU से iPhone emulation करना
(eshard.com)- eShard का लक्ष्य मौजूदा open source iOS emulation कार्य के आधार पर iOS 14 को QEMU में boot करना और UI व कुछ apps चलाने में सक्षम emulator बनाना था
- QEMU के अंदर सीधे kernel patches डालने के बजाय PongoOS और checkra1n KPF का उपयोग करके XNU patches को अलग किया गया, और Mach-O diff आधारित tool से patches की समीक्षा संभव बनाई गई
- Apple Silicon GPU emulation का दायरा बहुत बड़ा था, इसलिए पहले software rendering चुना गया, और jailbroken iPhone के
QuartzCorepatch से पुष्टि हुई कि UIKit UI धीमा सही, पर draw हो सकता है - screen के काली बनी रहने की समस्या हल करने के लिए address randomization disable करना, GDB debugging,
lockdowndpairing bypass, PAC disable करना, QEMU 8.2.1 porting, और dyld cache patch automation जारी रखे गए - अंततः QEMU screen पर UIKit passcode input UI दिखाया गया और VNC keyboard input से textbox को manipulate किया गया;
SpringBoarddisplay तक के लिए जरूरी आधार तैयार हो गया
iOS emulation की शुरुआत
- मौजूदा open source solutions की समीक्षा में alephsecurity/xnu-qemu-arm64 को चलाने का अनुभव था, लेकिन project read-only स्थिति में था
- इसके बाद TrungNguyen1909/qemu-t8030 को शुरुआती आधार के रूप में इस्तेमाल किया गया
- दूसरे “companion” QEMU के जरिए USB connection से iOS restore संभव
- iOS 14 चलाने का support
- अधिक नए QEMU version पर आधारित
- emulator चलाने का तरीका बताने वाला wiki उपलब्ध
System/Library/xpc/launchd.plistको modify करके जल्दी से shell और SSH access हासिल किया गया- long-term goal UI के साथ और कम से कम कुछ apps चला सकने वाला functional iOS emulation है
PongoOS से kernel patches अलग करना
t8030project ने XNU kernel patch code को QEMU में ही रखा था, लेकिन आगे patches बढ़ने की संभावना थी, इसलिए ज्यादा साफ structure की जरूरत थी- असली jailbroken iPhone के अनुभव के आधार पर PongoOS का इस्तेमाल करके checkra1n patches लागू करने का तरीका जांचा गया
- सामान्य jailbreak flow में checkmate से pwn होने के बाद PongoOS को SRAM में inject किया जाता है और
checkra1n-kpfmodule USB से भेजा जाता है- इस काम में शुरुआती USB handling से बचने के लिए emulated iPhone की SRAM बढ़ाई गई और PongoOS व checkra1n KPF module का उपयोग किया गया
- PongoOS execution की शुरुआत में bootrom या iBoot द्वारा की जाने वाली initialization code न होने से समस्याएं आईं
- double/float instructions से पहले FPU setup जरूरी था
- ARM documentation और मौजूदा QEMU संबंधित code देखकर इसे हल किया गया
- A13 के बाद वाले device features Pongo द्वारा supported नहीं थे, जिससे कुछ patches की pattern matching टूट गई
- Pointer Authentication(PAC) instructions
autda,xpacdजोड़े गए - Apple अलग slide का उपयोग करता है
task_for_pid(tfp0)patch में iPhone X और iPhone 11 के addresses और binary patterns का अंतर दिखा
- Pointer Authentication(PAC) instructions
Declarative kernel patch files
- Pongo ने कई iOS versions के लिए मौजूदा checkra1n patches का उपयोग संभव बनाया, लेकिन dynamic application तरीका पढ़ने, modify करने और share करने में कठिन था
- इन्हें असली code patches की तरह handle करने के लिए internal tool से declarative patches files बनाई गईं
- दो
Mach-Oका diff करके assembly differences आधारित text patch file बनाई गई - generated patch file को binary पर apply करने के लिए अलग program लिखा गया
- दो
- Pongo से boot करने के बाद QEMU monitor का उपयोग करके Pongo द्वारा patched memory sections dump किए गए
- इसके बाद patched kernel को फिर से assemble किया गया और सभी modifications वाला बड़ा patch file बनाया गया
- बड़े patch को भागों में बांटकर और comments जोड़कर kernel के किन हिस्सों को patch किया जा रहा है, इसकी review और control संभव हुआ
GPU के बिना screen draw करने की strategy
- नए iPhone की graphics rendering आखिरकार Apple के Metal API से गुजरती है और real GPU की जरूरत होती है
- Apple Silicon GPU को emulate करना बहुत complex माना गया, इसलिए दो विकल्पों पर विचार किया गया
- पुराने iOS में जैसे संभव था,
gpu=0bootarg के जरिए software rendering - Metal calls को real iPhone या macOS वाले Mac तक forward करके rendering कराना
- पुराने iOS में जैसे संभव था,
- iOS 14 में XNU kernel का
gpu=0bootarg option हट चुका था QuartzCoreframework को Ghidra से analyze करने पर पता चला कि software rendering,Metalrenderer न होने पर fallback के रूप में call होने वाली structure थी- real jailbroken iPhone पर
QuartzCorepatch करके software rendering के use की पुष्टि हुई- UI काफी धीमा था
- कुछ areas में artifacts आए, और संभव है कि उन हिस्सों ने direct
Metalrendering मांगी हो
- इस experiment से माना गया कि
MetalयाOpenGLको direct use न करने वाली सीमा में, यानी अधिकांश UIKit apps में QEMU पर भी software rendering संभव है
Metal call proxy experiment
- Metal calls को proxy करने का alternative भी दो physical iPhones पर test किया गया
- LLVM से सभी iOS headers parse करना
- server के Objective-C object pointers को client में stub pointers के रूप में represent करना
- structures और pointer exchange code auto-generate करना
- सभी functions और methods hook करना
- सभी calls server को forward करना और execution result लौटाना
- Metal initialization के basic call round trips कुछ हद तक सफल रहे
- लेकिन Objective-C language और
MetalAPI complex व बहुत feature-rich हैं, इसलिए real operation तक पहुंचने का workload बहुत बड़ा था - इस approach को बाद के लिए टालकर, limitations के बावजूद software rendering से दूसरे issues पहले हल करने का फैसला हुआ
- iOS frameworks में public headers में न मौजूद private API भी exposed थे, और उन्हें parse करके headers बनाने का तरीका था, लेकिन अधिकतर direct use करना मुश्किल था और complexity बढ़ती थी
IOSurface और framebuffer debugging
- software rendering try करने के बाद भी कम से कम framebuffer device की जरूरत थी, लेकिन original
t8030QEMU में यह implemented नहीं था - IOMFB support work वाले QEMUAppleSilicon fork को ढूंढकर display debugging में इस्तेमाल किया गया
- इस version से iOS restore करते समय Apple logo और progress bar दिखे, लेकिन normal boot में screen पूरी तरह black रही
- Ghidra से IOMFB kext देखने और QEMU framebuffer implementation की जांच करने पर दो modes दिखे
- fixed hardware address वाला raw framebuffer
- registers से कई planes set करके DMA से surface data लिखने वाला ज्यादा complex API
- raw framebuffer से arbitrary ARGB surface display हो सकता था, लेकिन boot के दौरान system उस framebuffer में write नहीं कर रहा था
- दूसरे display mode में kernel द्वारा registers से graphical plane set करने का trace दिखा, लेकिन उसके बाद screen output नहीं था
Address randomization हटाना और GDB debugging
- सिर्फ SSH access से running system observe करने की सीमा थी, इसलिए kernel और user space को GDB से debug करना जरूरी हुआ
- kernel address randomization
t8030board initialization में set था, इसलिए इसे पूरी तरह बंद किया जा सकता था - userland में executable randomization और dyld cache के अंदर dynamic library randomization था
- executable को kernel के
_load_machfilefunction को patch करके disable किया गया - dyld cache libraries boot के समय एक बार address-randomized होती हैं और फिर सभी executables में उसी address पर load होती हैं
- executable को kernel के
/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64eके dyld cache में सभी framework libraries बड़े binary blob के रूप में मौजूद हैं- C tool बनाकर सभी framework libraries को
dlopenकिया गया और_dyld*functions से loaded images व offsets list किए गए - इस तरीके और GDB addresses को reverse करने की process को साथ इस्तेमाल करके dyld cache libraries को debug किया जा सका
- खास दिलचस्पी
IOMFBkext,backboardd,SpringBoard,QuartzCoreमें थी - बाद में kernel patch से dyld cache disable करने का तरीका भी मिला, और host पर dyld cache के virtual addresses सीधे खोजने के लिए Gimli project की Rust object library इस्तेमाल की गई
- user space debugging के लिए guest का GDB server जरूरी था, उदाहरण के लिए Procursus का
debugserverpackage इस्तेमाल किया गया
System logs और lockdownd bypass
- GDB से
backboarddnormal तरीके से start होता दिख रहा था, लेकिन असली स्थिति समझने के लिए system logs की जरूरत थी - real iPhone पर computer के साथ USB pairing के बाद
idevicesyslogसे system logs देखे जा सकते हैं - pairing process में key pair generation शामिल है, private key iPhone में save होती है और
lockdowndcomputer की identity verify करता है - emulation environment में USB interaction संभव था, लेकिन
lockdowndठीक से काम नहीं कर रहा था - Ghidra analysis से पता चला कि
lockdowndprivate key storage के लिएkeybagइस्तेमाल करना चाहता था, जिसके लिए अनुपस्थित SEP चाहिए था - मौजूदा functions के कुछ हिस्सों को replace करने वाला shellcode inject करके pre-generated public/private key pair को file system से पढ़ने और
lockdowndकेkeybagसे fetch करने की कोशिश करने पर हर बार load कराने की व्यवस्था की गई - अतिरिक्त debugging और patching से simulate किया गया कि user ने computer पर trust किया है और iPhone unlocked है
- आखिरकार companion QEMU से emulated iPhone के साथ pair किया जा सका
- logs में पुष्टि हुई कि
QuartzCorenormal initialize हो रहा है, display size detect कर रहा है और software rendering fallback इस्तेमाल कर रहा है - सब कुछ normal जैसा दिखा, लेकिन screen अब भी display नहीं हो रही थी
- pixel format से जुड़ी एक single error को RGBA force करके bypass किया गया, लेकिन बाद में उसे हटा दिया गया
PAC issue और QEMU 8 porting
backboarddकी pixel format error ठीक करते समय iOS security feature की वजह से additional problem सामने आई- load-time और runtime signature checks kernel patch से हल हुए, लेकिन modified
backboarddचलाते समय Pointer Authentication failure हुआ - Pointer Authentication ARMv8.3 में जोड़ा गया feature है, और पहले इस्तेमाल किए गए t8015 के बजाय emulated
t8030board पर यह नई समस्या थी - शुरुआत में सभी PAC instructions को NOP या PAC-less equivalent instructions में बदलने का तरीका सोचा गया
- बाद में पता चला कि ARM64 PAC binaries दो तरीकों से build हो सकती हैं
- सिर्फ ARMv8.3+ CPU पर चलने वाली dedicated PAC instruction set का उपयोग
- ऐसी “unused” instruction set का उपयोग जो ARMv8.3+ में PAC के रूप में और पुराने ARM में PAC-less equivalent instructions के रूप में interpret होती है
- buildroot और ARM64 Linux system पर test करके इस behavior को verify किया गया, और पुष्टि हुई कि
t8030binaries backward compatible instruction set arm64e इस्तेमाल करती हैं - लगा कि QEMU में सिर्फ PAC enforcing बंद करने से code PAC-less code की तरह चलेगा, लेकिन QEMU 7 में यह काम नहीं किया और QEMU 8 का behavior अलग था
- current codebase को QEMU 8.2.1 पर port किया गया
- Apple-specific instructions
genter,gexit - GL exception levels handling code
- QEMU generic code में बहुत modifications होने से porting कठिन थी
- Apple-specific instructions
- कई XNU panics, kernel GDB debugging, QEMU की खुद की debugging और git bisect के बाद iOS को QEMU 8 में फिर से boot कराया गया
- इससे PAC disable करके किसी भी executable code को इच्छित location पर modify करना संभव हुआ
Black screen के कारण की tracking
- system logs के अनुसार
backboarddnormal काम करता दिखा, इसलिए display न होने का कारण और गहराई से trace किया गया - raw ARGB frame को address पर directly write करने से actual display बदलता था, और कई graphical planes पर draw किया जा सकता था
- इसलिए display implementation खुद normal दिखी और तीन संभावनाएं बचीं
backboarddकुछ भी नहीं लिख रहा- गलत address पर लिख रहा है
- लिखा गया data valid नहीं है
- QEMU monitor से non-contiguous physical addresses लिए गए, और script से physical DMA memory dump करके एक file में जोड़ी गई
ffplayसे उसे ARGB frame की तरह interpret किया गया, लेकिन meaningful result नहीं मिला- अगला कदम
iosurface_lockपर breakpoint लगाकरbackboarddmemory में mapped surface address लेना और जांचना था - कभी-कभी Apple logo जैसी अजीब shape मिली, लेकिन frame writing method में issue लगता था
- यही काम real iPhone 10 पर करने पर current screen का पूरा raw ARGB frame आसानी से dump हो गया
- iPhone 11, यानी
t8030के बाद, surface GPU द्वारा process किए जा सकने वाले compressed format में deliver होती दिखी - iPhone X के
t8015में ऐसा नहीं होता था, इसलिए QEMU के DTB मेंchip-idको 8030 के बजाय 8015 pass करने के लिए modify किया गया - नतीजतन boot के बाद screen पर Apple logo display हुआ
Progress bar और authentication patches
- Apple logo display होने के बाद भी UI आगे नहीं बढ़ा, और system logs में कई daemons और libraries के बहुत सारे messages output हुए
- कौन-सी error actual UI issue से जुड़ी है, इसका अनुमान लगाकर एक-एक करके ठीक किया गया
- user authentication से जुड़ी problem मिली, और error के sources
mobileactivationddaemon औरSpringBoardFoundationframework थे - इन्हें patch करने के बाद restore stage में दिखने जैसी white progress bar display हुई
- progress bar चलती हुई लग रही थी, लेकिन कई घंटों बाद भी 90% पर रुकी हुई दिखी
dyld cache और user space patch iteration सुधारना
- address randomization disable होने से user space और dyld cache framework patches संभव हुए
- kernel की तरह हर binary/library के लिए text patch files बनाकर internal tool से apply की गईं
- dyld cache लगभग 2GB का था, इसलिए direct patch करना या SSH से बार-बार copy करना practical नहीं था
- Linux environment में काम करने के कारण NVMe को सीधे modify भी नहीं किया जा सकता था
- internal diff/patch tool को dyld cache के लिए extend किया गया ताकि framework offsets को dyld cache blob के अंदर खोज सके
- iPhone पर सीधे apply किए जा सकने वाले simple
ddcommands और revert commands generate करने का option जोड़ा गया - file system को read/write mode में remount करने के बाद
ddcommands apply करके dyld cache modifications को तेजी से iterate किया जा सका - changes apply होने के लिए सिर्फ iOS reboot जरूरी था
- इस तरीके के काम करने के लिए kernel signature check पर कुछ additional patches भी जरूरी थे
PreBoard execution और UIKit screen display
- अटकी हुई progress bar हल करने से पहले system process
PreBoardपर experiment किया गया PreBoardकेवल update interruption जैसी समस्याओं के समय user को display होता लगता थाSpringBoardकी तरह यहbackboarddके जरिए direct draw करने वाला system application था, इसलिए command line से सीधे start किया जा सकता था- run करने पर “swipe to upgrade” मांगने वाली white screen display हुई
- पहले physical iPhone पर VNC server use करने के अनुभव के आधार पर VNC जोड़ा गया, और कई failures के बाद swipe नहीं बल्कि keyboard keys से screen unlock की गई
- unlock के तुरंत बाद QEMU ने iOS के illegal instruction use करने पर execution रोक दिया
backboarddanalysis से पता चला किvImageframework_vHorizontal_Scale_ARGB_8888_Accelerateजैसे hardware-accelerated graphics operations के लिए AMX(Apple Matrix Coprocessor) instructions इस्तेमाल करता है- AMX, QEMU के emulated ARM CPU में implemented न होने वाली Apple की proprietary instruction set है
vImageframework में केवल generic ARM instructions इस्तेमाल करने वाला alternative software version था, इसलिए फिर patch करके उसे use कराया गया- final result के रूप में असली
UIKitwindow display हुई और passcode input screen व working textbox दिखाई दिया - VNC से injected keyboard events के जरिए textbox में input किया जा सका
- इस point पर
SpringBoardको सही तरह display करने के लिए required components तैयार हो गए, और start होना बस समय की बात लगता है - अगला लेख Part 2 में जारी है
1 टिप्पणियां
Hacker News की राय
अच्छा होगा अगर https://github.com/devos50/qemu-ios इतना विकसित हो जाए कि iPhone OS 3.x तक सपोर्ट करे, ताकि शुरुआती iPhone ऐप्स को डिजिटल संरक्षण के तौर पर अनुभव किया जा सके
https://github.com/touchHLE/touchHLE भी बेहतरीन है, लेकिन बहुत बेसिक ऐप्स को छोड़कर ऐप-विशेष पैच की जरूरत पड़ती है
iOS 10 पर 32-bit ऐप्स चलाने के लिए QEMU को iPhone 7 भी सपोर्ट करना होगा
पहले QEMU से NumWorks N0100[1] और HP Prime G1[2] को emulate करके आधिकारिक firmware को सच में चलने लायक स्तर तक बनाया था
[1] https://github.com/boricj/qemu/tree/numworks_calculators
[2] https://github.com/boricj/qemu/tree/s3c2416-boricj
इस प्रोजेक्ट का मजेदार उपयोग यह हो सकता है कि postmarketOS hardware support वाले किसी अच्छे फोन पर न्यूनतम pmOS image और QEMU का यह version install करके Android phone पर iOS boot किया जाए
QEMU को और customize करके modem, Bluetooth जैसे फोन hardware को iOS virtual machine तक pass through करना भी शायद संभव हो
iOS/Android emulation के बिना सिर्फ इतना हो जाए तो भी संतोष होगा
Archived version: https://archive.ph/l1CwO
क्या इसका मतलब है कि अब Apple hardware के बिना भी Linux system पर Safari testing या iOS के लिए compiling जैसी चीजें की जा सकती हैं?
https://github.com/ChefKissInc/QEMUAppleSilicon
यह QEMU में emulate होने वाला Apple Silicon device है, और फिलहाल सिर्फ iPhone 11 को सपोर्ट करता है
Demo video: https://nitter.poast.org/eshard/status/1908162866609311962
Run instructions follow करके देखा: https://github.com/TrungNguyen1909/qemu-t8030/wiki/Bringing-...
जितनी बार crash हुआ, मानने में शर्म आएगी, लेकिन यह काफी cool है
Network connectivity का कोई जिक्र नहीं है। लगता है Wi-Fi या cellular modem chipset को emulate नहीं किया गया है
उत्सुकता है कि इस emulated device को internet से कैसे जोड़ा जाएगा। शायद USB के जरिए Ethernet जैसा कोई तरीका हो सकता है
Apple को multiplatform iOS development स्वीकार करने के लिए क्या चाहिए होगा?
Apple के नजरिए से ऐसे development model को अनुमति देकर उसे कुछ हासिल नहीं होगा
ऐसा होने के लिए Apple का दुनिया को देखने का तरीका ही बदलना होगा, और यह बदलाव उतना ही बड़ा होगा जितना Microsoft ने WSL और Linux के लिए .NET के साथ Linux को कुछ हद तक अपनाया था
क्या इसे reproduce करने के लिए कोई repository है?