4 คะแนน โดย GN⁺ 2025-04-07 | 1 ความคิดเห็น | แชร์ทาง WhatsApp

จุดเริ่มต้นของการเดินทางจำลอง iOS 14 บน QEMU

  • เดิมใช้โปรเจกต์โอเพนซอร์ส alephsecurity/xnu-qemu-arm64 แต่เป็นแบบอ่านอย่างเดียว (read-only) จึงมีข้อจำกัดด้านการขยายต่อ
  • ต่อมาเปลี่ยนมาใช้โปรเจกต์ TrungNguyen1909/qemu-t8030 ทำให้สามารถใช้ความสามารถต่อไปนี้ได้:
    • ฟังก์ชันกู้คืน iOS (พร้อม QEMU อีกตัวสำหรับการเชื่อมต่อ USB)
    • รัน iOS 14
    • อิงกับ QEMU เวอร์ชันใหม่
    • มีเอกสารวิกิแบบละเอียด
  • แก้ไข launchd.plist แล้วเข้าถึงเชลล์และ SSH ได้สำเร็จ จึงใช้เป็นจุดเริ่มต้นที่ดี
  • เป้าหมายคือสร้างสภาพแวดล้อมจำลอง iOS ที่สมบูรณ์ ซึ่งสามารถแสดง UI และรันแอปได้

การแพตช์เคอร์เนลและการนำ PongoOS มาใช้

  • โปรเจกต์ t8030 ใช้โครงสร้างที่แพตช์เคอร์เนลภายใน QEMU โดยตรง → ทำให้เกิดปัญหาด้านการบำรุงรักษาและการต่อยอด
  • จากประสบการณ์ด้านการเจลเบรก จึงเปลี่ยนไปใช้โครงสร้างที่นำแพตช์ checkra1n มาใช้ผ่าน PongoOS
  • เพิ่มขนาด SRAM ใน QEMU เพื่อรัน PongoOS และฉีดโมดูล checkra1n-KPF
  • ระหว่างบูตเกิดปัญหา FPU ไม่ถูกตั้งค่า เพราะขาดฟังก์ชันบางส่วนของ bootrom/iboot → แก้ไขโดยอ้างอิงเอกสาร ARM
  • หลัง A13 มีการนำ PAC (Pointer Authentication) มาใช้ ทำให้แพตช์บางส่วนใช้ไม่ได้อีก
  • ใช้ task_for_pid0 (tfp0) เป็นตัวอย่างในการเปรียบเทียบไบนารีก่อนและหลังมี PAC

การพัฒนาเครื่องมืออัตโนมัติสำหรับแพตช์เคอร์เนล

  • วิธีแพตช์แบบไดนามิกเดิมของ checkra1n อ่านยากและแก้ไขไม่สะดวก → จึงนำรูปแบบแพตช์เชิงประกาศที่อิงข้อความมาใช้
  • เปรียบเทียบไบนารี Mach-O สองไฟล์เพื่อดึงความต่างระดับแอสเซมบลี แล้วสร้างแพตช์ข้อความขึ้นมา
  • บูตผ่าน Pongo แล้วดัมพ์หน่วยความจำเพื่อประกอบเคอร์เนลใหม่ → จัดระเบียบแพตช์ทั้งหมดเป็นไฟล์ข้อความพร้อมคอมเมนต์

การเรนเดอร์กราฟิก: Metal เทียบกับซอฟต์แวร์เรนเดอร์

  • iOS ใช้ API Metal ในการเรนเดอร์ UI ทั้งหมด → จึงต้องมี GPU
  • เนื่องจากการจำลอง GPU ซับซ้อน จึงพิจารณาทางเลือกดังนี้:
    • ซอฟต์แวร์เรนเดอร์
    • ส่งต่อการเรียก Metal ไปยังอุปกรณ์จริงผ่านพร็อกซี
  • ใน iOS 14 มีการเอา bootarg gpu=0 ออกไป → วิเคราะห์ QuartzCore แล้วพบพฤติกรรม fallback
  • แพตช์ QuartzCore บนเครื่องที่เจลเบรกแล้ว และยืนยันได้ว่าซอฟต์แวร์เรนเดอร์ทำงานได้ (แม้จะช้าแต่ทำได้จริง)
  • มีการทดลองแนวทางพร็อกซี Metal ด้วย แต่หยุดไปเพราะความซับซ้อนของ Objective-C และ API

การดีบักเฟรมบัฟเฟอร์และ IOSurface

  • QEMU ของ t8030 ไม่มีการทำเฟรมบัฟเฟอร์ไว้ → จึงใช้ฟอร์ก ChefKissInc/QEMUAppleSilicon
  • ตอนบูตช่วงแรกมองเห็นโลโก้ Apple และแถบความคืบหน้า แต่หลังจากนั้นจอกลายเป็นสีดำ → จึงเริ่มดีบัก
  • จากการวิเคราะห์ IOMFB kext พบว่ามีอยู่สองโหมด:
    • เฟรมบัฟเฟอร์ที่ใช้แอดเดรสคงที่ (สำหรับการแสดงผลช่วงต้น)
    • โครงสร้างหลายเพลนแบบอิง DMA
  • ระหว่างบูตระบบมีการใช้โหมดแบบอิง DMA → ใช้ trace ของ QEMU เพื่อตรวจสอบการตั้งค่ารีจิสเตอร์ของเคอร์เนล
  • แต่ถึงอย่างนั้นก็ยังไม่มีภาพออกบนหน้าจอ

การปิดการสุ่มแอดเดรส

  • การสุ่มแอดเดรสของเคอร์เนลสามารถปิดได้ในโค้ดเริ่มต้นของบอร์ด
  • การสุ่มใน user space ถูกปิดโดยแพตช์ _load_machfile
  • dyld cache เป็นไบนารีขนาดใหญ่ที่รวมไลบรารีไดนามิกทั้งหมดไว้ → ถูกโหลดที่แอดเดรสคงที่ตอนบูต
  • สร้างเครื่องมือ C เพื่อ dlopen แล้วตรวจสอบแอดเดรสผ่านฟังก์ชัน _dyld_*
  • ทำให้สามารถดีบักไลบรารี dyld ด้วย GDB ได้ → โดยเฉพาะ IOMFB, SpringBoard, QuartzCore

การเข้าถึงล็อกผ่าน USB และการข้าม lockdownd

  • บนอุปกรณ์จริงสามารถเก็บล็อกระบบด้วย idevicesyslog ได้ → แต่ต้องผ่านการยืนยันตัวตนผ่าน USB
  • lockdownd ใช้ keybag ที่ต้องพึ่ง SEP สำหรับเก็บคีย์ → ซึ่งไม่มีในอีมูเลเตอร์
  • จึงแทรกเชลล์โค้ดไว้แทนฟังก์ชันเดิม เพื่อให้โหลดจากไฟล์คีย์โดยตรง
  • สามารถข้ามการยืนยันคีย์ระหว่าง QEMU ที่เชื่อมต่อผ่าน USB ได้สำเร็จ → จึงเก็บล็อกได้
  • ยืนยันได้ว่า QuartzCore เริ่มทำงานตามปกติและใช้ซอฟต์แวร์เรนเดอร์อยู่

การข้าม PAC (Pointer Authentication)

  • ระหว่างแก้ไข backboardd พบข้อผิดพลาดเกี่ยวกับ PAC → เป็นฟีเจอร์ความปลอดภัยที่ถูกนำมาใช้ใน ARMv8.3
  • วิธีแทนที่คำสั่ง PAC ด้วย NOP นั้นรุกล้ำระบบมากเกินไป
  • คำสั่ง PAC สามารถคอมไพล์ในรูปแบบที่ยังเข้ากันได้ → หากให้ QEMU เพิกเฉยต่อ PAC ก็ยังรันได้
  • QEMU 7 ไม่สามารถข้าม PAC ได้ → จึงย้ายไปใช้ QEMU 8.2.1
  • ต้องย้ายโค้ดปรับแต่ง QEMU จำนวนมาก ทั้งคำสั่งเฉพาะของ Apple และ exception level ของ GL เป็นต้น
  • ผลลัพธ์คือสามารถบูต iOS บน QEMU 8 ได้สำเร็จ และทำให้ PAC ใช้งานไม่ได้ในทางปฏิบัติ

การยืนยัน backboardd และเอาต์พุตกราฟิก

  • backboardd ทำงานอยู่แต่ยังไม่มีภาพแสดงบนหน้าจอ → อาจเกิดได้จากหลายสาเหตุ
  • แม้ดัมพ์หน่วยความจำ DMA แล้วก็ยังไม่พบเอาต์พุตที่มีความหมาย
  • ตรวจสอบแอดเดรสใน iosurface_lock และดัมพ์เฟรมออกมา แต่ดูเหมือนถูกบีบอัดก่อนส่งไปยัง GPU
  • บน iPhone X (t8015) พบเอาต์พุตที่ไม่ถูกบีบอัด → จึงแก้ DTB ของ QEMU เปลี่ยน chip-id จาก t8030 เป็น t8015
  • ผลคือหลังบูตสามารถแสดงโลโก้ Apple ได้

การติดตามแถบความคืบหน้าและข้อผิดพลาดของระบบ

  • หลังโลโก้มีแถบความคืบหน้าสีขาวปรากฏขึ้น → แต่ค้างอยู่ที่ 90%
  • จากการวิเคราะห์ล็อกพบปัญหาใน mobileactivationd และ SpringBoardFoundation → หลังแพตช์แล้ว UI เปลี่ยนไป
  • การแก้ปัญหาการค้างของแถบต้องอาศัยการวิเคราะห์ล็อกระบบจำนวนมาก

การทำแพตช์ dyld cache และ user space แบบอัตโนมัติ

  • ใน user space ก็ใช้แนวทางแพตช์แบบข้อความเช่นเดียวกับเคอร์เนล
  • dyld cache มีขนาด 2GB ทำให้แก้ไขตรง ๆ ไม่มีประสิทธิภาพ → จึงปรับปรุงเครื่องมือภายในให้สามารถ:
    • ติดตามออฟเซ็ตภายใน dyld
    • แพตช์ตำแหน่งเฉพาะได้โดยตรงด้วยคำสั่ง dd
  • จำเป็นต้องทำแพตช์เพื่อข้ามการตรวจสอบลายเซ็นเคอร์เนลควบคู่กันไปด้วย

การรัน PreBoard และการยืนยัน UI

  • แอป PreBoard เป็นแอประบบที่จะแสดงเมื่อเกิดข้อผิดพลาด → และสามารถสั่งรันได้โดยตรง
  • เพิ่มเซิร์ฟเวอร์ VNC เพื่อพยายามปลดล็อกหน้าจอด้วยคีย์บอร์ด
  • หลังปลดล็อก vImage framework ใช้คำสั่ง AMX (Apple Matrix Coprocessor) → ซึ่ง QEMU ยังไม่รองรับ
  • แพตช์ให้ vImage ใช้เส้นทาง fallback แบบซอฟต์แวร์ จึงแก้ปัญหาได้
  • หลังแพตช์แล้วสามารถแสดงหน้าจอที่พิมพ์ข้อความได้สำเร็จ

บทสรุป

  • ไปถึงจุดก่อนการรัน SpringBoard ได้แล้ว → จากนี้การรัน UI เต็มรูปแบบน่าจะเป็นเพียงเรื่องของเวลา
  • มีการวิเคราะห์และแพตช์ทั้งเคอร์เนล, user space, กราฟิก, และฟีเจอร์ความปลอดภัย (เช่น PAC) จากหลายมิติ
  • ยืนยันความเป็นไปได้ของสภาพแวดล้อมสำหรับดีบักและทดสอบแอป iOS บน QEMU ที่ใช้งานได้จริง

1 ความคิดเห็น

 
GN⁺ 2025-04-07
ความคิดเห็นบน Hacker News
  • อยากให้โปรเจกต์ https://github.com/devos50/qemu-ios พัฒนาไปจนรองรับ iPhone OS 3.x เพื่อให้สามารถสัมผัสแอป iPhone ยุคแรกได้ในแง่ของการอนุรักษ์ดิจิทัล
  • https://github.com/touchHLE/touchHLE ก็ยอดเยี่ยมเช่นกัน แต่ถ้าไม่ใช่แอปพื้นฐานก็ต้องมีการแพตช์
  • เคยลองรันตามคำแนะนำใน https://github.com/TrungNguyen1909/qemu-t8030/… แต่แครชหลายครั้ง ถึงอย่างนั้นก็ยังเจ๋งมาก
  • เคยอีมูเลต NumWorks N0100 และ HP Prime G1 ด้วย QEMU มาก่อน ซึ่งสำเร็จมากพอที่จะรันเฟิร์มแวร์ทางการได้
  • วิธีใช้งานโปรเจกต์นี้แบบสนุก ๆ คือ ติดตั้ง postmarketOS ลงบนโทรศัพท์ที่รองรับฮาร์ดแวร์ได้ดี แล้วใช้ QEMU บูต iOS บนโทรศัพท์ Android โดยอาจปรับแต่ง QEMU เพื่อส่งผ่านฮาร์ดแวร์ของโทรศัพท์เข้าไปยัง iOS VM
  • สงสัยว่านี่หมายความว่าสามารถทดสอบ Safari และคอมไพล์ iOS บนระบบ Linux ได้โดยไม่ต้องมีฮาร์ดแวร์ของ Apple หรือไม่
  • https://github.com/ChefKissInc/QEMUAppleSilicon
  • ไม่มีการพูดถึงการเชื่อมต่อเครือข่าย ดูเหมือนว่าจะไม่ได้อีมูเลตชิปเซ็ต WiFi หรือโมเด็มเซลลูลาร์ เลยสงสัยว่าจะทำให้อุปกรณ์ที่อีมูเลตเชื่อมต่ออินเทอร์เน็ตได้อย่างไร อาจเป็นวิธีอย่าง Ethernet ผ่าน USB
  • เวอร์ชันที่เก็บถาวร: https://archive.ph/l1CwO
  • สงสัยว่ามีรีโพซิทอรีที่สามารถใช้ทำซ้ำสิ่งนี้ได้หรือไม่
  • สงสัยว่า Apple จะต้องการอะไรบ้างจึงจะยอมรับการพัฒนา iOS แบบหลายแพลตฟอร์ม