Khởi đầu hành trình giả lập iOS 14 trên QEMU
- Ban đầu đã dùng dự án mã nguồn mở
alephsecurity/xnu-qemu-arm64, nhưng do ở trạng thái chỉ đọc (read-only) nên thiếu khả năng mở rộng
- Sau đó chuyển sang dự án
TrungNguyen1909/qemu-t8030 và có thể tận dụng các tính năng sau:
- Khôi phục iOS (kèm QEMU đồng hành cho kết nối USB)
- Chạy iOS 14
- Dựa trên phiên bản QEMU mới nhất
- Có tài liệu wiki chi tiết
- Đã sửa
launchd.plist để truy cập shell và SSH thành công, qua đó tạo được điểm khởi đầu tốt
- Mục tiêu là xây dựng một môi trường giả lập iOS hoàn chỉnh có thể chạy UI và ứng dụng
Vá kernel và đưa PongoOS vào
- Dự án
t8030 có cấu trúc vá kernel ngay bên trong QEMU → phát sinh vấn đề về bảo trì và mở rộng
- Dựa trên kinh nghiệm jailbreak, đã chuyển sang cấu trúc áp dụng bản vá
checkra1n thông qua PongoOS
- Tăng kích thước SRAM trong QEMU để chạy PongoOS, rồi chèn mô-đun checkra1n-KPF
- Khi khởi động, do thiếu một số chức năng của bootrom/iboot nên phát sinh lỗi FPU chưa được cấu hình → tham khảo tài liệu ARM để xử lý
- Từ A13 trở đi, PAC (Pointer Authentication) được đưa vào, khiến một số bản vá mất hiệu lực
- So sánh nhị phân trước và sau khi PAC được đưa vào bằng ví dụ
task_for_pid0 (tfp0)
Phát triển công cụ tự động hóa vá kernel
- Cách vá động hiện có của checkra1n khó đọc và bất tiện khi sửa đổi → đưa vào phương thức vá dạng khai báo dựa trên văn bản
- So sánh hai nhị phân
Mach-O để trích xuất khác biệt ở mức assembly, sau đó tạo bản vá văn bản
- Dump bộ nhớ sau khi khởi động bằng Pongo để tái lắp ráp kernel → sắp xếp toàn bộ bản vá vào tệp văn bản và thêm chú thích
Kết xuất đồ họa: Metal so với kết xuất phần mềm
- iOS thực hiện toàn bộ việc kết xuất UI thông qua API
Metal → cần GPU
- Do giả lập GPU quá phức tạp, đã cân nhắc các phương án thay thế:
- Kết xuất phần mềm
- Proxy các lời gọi Metal sang thiết bị thật
- Trên iOS 14, bootarg
gpu=0 đã bị loại bỏ → phân tích QuartzCore và xác nhận cơ chế fallback
- Vá
QuartzCore trên máy đã jailbreak để xác nhận kết xuất phần mềm hoạt động được (dù chậm nhưng khả thi)
- Cũng đã thử phương án proxy Metal, nhưng dừng lại vì Objective-C và API quá phức tạp
Gỡ lỗi framebuffer và IOSurface
t8030 QEMU không có triển khai framebuffer → dùng fork ChefKissInc/QEMUAppleSilicon
- Khi khởi động ban đầu có hiện logo Apple và thanh tiến trình, nhưng sau đó màn hình đen → bắt đầu gỡ lỗi
- Kết quả phân tích IOMFB kext cho thấy có hai chế độ:
- Framebuffer địa chỉ cố định (dùng cho hiển thị ban đầu)
- Cấu hình đa mặt phẳng dựa trên DMA
- Trong quá trình hệ thống khởi động, chế độ dựa trên DMA được dùng → kiểm tra việc thiết lập thanh ghi kernel bằng trace của QEMU
- Tuy vậy, vẫn không có gì được hiển thị trên màn hình
Vô hiệu hóa ngẫu nhiên hóa địa chỉ
- Có thể tắt ngẫu nhiên hóa địa chỉ kernel trong mã khởi tạo bo mạch
- Ngẫu nhiên hóa ở không gian người dùng được vô hiệu hóa bằng cách vá
_load_machfile
- Dyld cache là một nhị phân lớn chứa toàn bộ thư viện động → được nạp vào địa chỉ cố định khi khởi động
- Tạo công cụ C để
dlopen, sau đó kiểm tra địa chỉ bằng các hàm _dyld_*
- Cho phép gỡ lỗi thư viện
dyld bằng GDB → đặc biệt quan tâm tới IOMFB, SpringBoard, QuartzCore
Truy cập log USB và vượt qua lockdownd
- Trên thiết bị thật, có thể thu thập log hệ thống bằng
idevicesyslog → cần xác thực USB
- lockdownd dùng keybag cần SEP để lưu khóa → trình giả lập không có
- Chèn shellcode vào vị trí hàm hiện có để nạp trực tiếp từ tệp khóa
- Đã vượt qua xác thực khóa giữa các QEMU kết nối USB → có thể thu thập log
- Xác nhận QuartzCore khởi tạo bình thường và đang dùng kết xuất phần mềm
Vượt qua PAC (Pointer Authentication)
- Khi sửa
backboardd, phát sinh lỗi PAC → đây là tính năng bảo mật được đưa vào từ ARMv8.3
- Cách thay lệnh PAC bằng NOP là quá xâm lấn
- Có thể biên dịch lệnh PAC theo cách tương thích → nếu QEMU bỏ qua PAC thì vẫn chạy được
- QEMU 7 không thể vượt qua PAC → chuyển sang QEMU 8.2.1
- Cần chuyển rất nhiều mã tùy biến QEMU như lệnh riêng của Apple, exception level của GL, v.v.
- Kết quả là đã khởi động thành công iOS trên QEMU 8 và có thể vô hiệu hóa tác động của PAC
Xác nhận backboardd và đầu ra đồ họa
backboardd có hoạt động nhưng không hiển thị hình ảnh → có thể do nhiều nguyên nhân
- Dump bộ nhớ DMA cũng không cho ra nội dung có ý nghĩa
- Đã xác định địa chỉ trong
iosurface_lock và dump frame, nhưng có vẻ dữ liệu được gửi tới GPU ở dạng nén
- Trên iPhone X (t8015), xác nhận đầu ra không nén → sửa DTB của QEMU để đổi
chip-id từ t8030 sang t8015
- Kết quả là sau khi khởi động, logo Apple được hiển thị
Theo dõi thanh tiến trình và lỗi hệ thống
- Sau logo, thanh tiến trình màu trắng xuất hiện → dừng ở 90%
- Qua phân tích log, phát hiện vấn đề ở
mobileactivationd và SpringBoardFoundation → sau khi vá thì UI thay đổi
- Để giải quyết hiện tượng bị kẹt ở thanh tiến trình, cần phân tích thêm nhiều log hệ thống
Tự động hóa vá dyld cache và không gian người dùng
- Tương tự kernel, không gian người dùng cũng dùng phương thức vá dạng văn bản
- Dyld cache có kích thước 2GB nên rất kém hiệu quả khi sửa trực tiếp → đã cải tiến công cụ nội bộ để:
- Theo dõi offset trong dyld
- Vá trực tiếp vào vị trí cụ thể bằng lệnh
dd
- Đồng thời cũng cần bản vá để vượt qua kiểm tra chữ ký kernel
Chạy PreBoard và xác nhận UI
- Ứng dụng
PreBoard là app hệ thống hiển thị khi có lỗi → có thể chạy trực tiếp
- Thêm máy chủ VNC để thử mở khóa màn hình bằng bàn phím
- Sau khi mở khóa, framework
vImage dùng lệnh AMX (Apple Matrix Coprocessor) → QEMU không hỗ trợ
- Vá sang đường fallback phần mềm của
vImage để giải quyết vấn đề
- Sau bản vá, đã hiển thị thành công đến màn hình có thể nhập văn bản
Kết luận
- Đã tiến tới ngay trước khi chạy SpringBoard → việc chạy UI hoàn chỉnh giờ chỉ còn là vấn đề thời gian
- Đã thực hiện phân tích và vá theo nhiều hướng với kernel, không gian người dùng, đồ họa, và các tính năng bảo mật như PAC
- Xác nhận tiềm năng tạo ra môi trường thực tế để gỡ lỗi và kiểm thử ứng dụng iOS dựa trên QEMU
1 bình luận
Ý kiến trên Hacker News