iOS 14 QEMU 에뮬레이션 여정의 시작
- 기존 오픈소스 프로젝트인
alephsecurity/xnu-qemu-arm64
를 사용했지만 읽기 전용(read-only)이라 확장성 부족 문제 있었음
- 이후
TrungNguyen1909/qemu-t8030
프로젝트를 사용하며 다음 기능들 활용 가능했음:
- iOS 복원 기능 (USB 연결용 QEMU 동반)
- iOS 14 실행
- 최신 QEMU 버전 기반
- 상세 위키 문서 제공
-
launchd.plist
수정으로 쉘 및 SSH 접근 성공하며 좋은 출발점으로 삼음
- 목표는 UI와 앱 실행 가능한 완전한 iOS 에뮬레이션 환경 구축임
커널 패치 및 PongoOS 도입
-
t8030
프로젝트는 QEMU 내부에서 커널 패치하는 구조였음 → 유지보수 및 확장성 문제 발생
- 탈옥 경험 바탕으로
PongoOS
를 통해 checkra1n
패치를 적용하는 구조로 전환
- QEMU에서 SRAM 크기 증가시켜 PongoOS 실행하고, checkra1n-KPF 모듈 주입
- 부트 시 부트롬/iboot 기능 누락으로 FPU 미설정 이슈 발생 → ARM 문서 참고해 해결
- A13 이후 PAC(Pointer Authentication) 도입으로 일부 패치 무효화됨
-
task_for_pid0 (tfp0)
예시로 PAC 도입 전후의 바이너리 비교
커널 패치 자동화 도구 개발
- 기존 checkra1n 동적 패치 방식은 읽기 어렵고 수정 불편 → 선언적 텍스트 기반 패치 방식 도입
- 두 개의
Mach-O
바이너리 비교하여 어셈블리 차이점 추출 후 텍스트 패치 생성
- Pongo로 부팅 후 메모리 덤프하여 커널 재조립 → 전체 패치를 텍스트 파일로 정리 및 주석화
그래픽 렌더링: Metal vs 소프트웨어 렌더링
- iOS는 모든 UI 렌더링을
Metal
API를 통해 수행 → GPU 필요
- GPU 에뮬레이션 복잡함으로 대안 고려:
- 소프트웨어 렌더링
- Metal 호출을 실기기로 프록시 전달
- iOS 14에서는
gpu=0
bootarg 제거됨 → QuartzCore 분석해 fallback 동작 확인
- 탈옥폰에서
QuartzCore
패치하여 소프트웨어 렌더링 작동 확인 (느리지만 가능)
- Metal 프록시 방안도 실험하였으나 Objective-C 및 API 복잡성으로 중단
프레임버퍼 및 IOSurface 디버깅
-
t8030
QEMU에는 프레임버퍼 구현 없음 → ChefKissInc/QEMUAppleSilicon
포크 사용
- 초기 부팅 시 Apple 로고와 진행 표시 보였지만 이후 검은 화면 → 디버깅 시작
- IOMFB kext 분석 결과, 두 가지 모드 존재:
- 고정 주소 프레임버퍼 (초기 표시용)
- DMA 기반 다중 평면 구성
- 시스템 부팅 중 DMA 기반 모드 사용 → QEMU의 트레이스로 커널 레지스터 설정 확인
- 하지만 여전히 화면에 출력 없음
주소 랜덤화 비활성화
- 커널 주소 랜덤화는 보드 초기화 코드에서 해제 가능
- 사용자 영역의 랜덤화는
_load_machfile
패치하여 비활성화
- dyld 캐시는 모든 동적 라이브러리 포함한 큰 바이너리 → 부팅 시 고정 주소에 로드됨
- C 도구를 만들어 dlopen 후
_dyld_*
함수로 주소 확인
- GDB로
dyld
라이브러리 디버깅 가능하게 함 → 특히 IOMFB
, SpringBoard
, QuartzCore
관심 가짐
USB 로그 접근 및 lockdownd 우회
- 실기기에서는
idevicesyslog
로 시스템 로그 수집 가능 → USB 인증 필요
- lockdownd는 키 저장에 SEP가 필요한 keybag 사용 → 에뮬레이터에 없음
- 기존 함수 자리에 쉘코드 삽입하여 키 파일에서 직접 로딩하게 함
- USB 연결된 QEMU 간 키 인증 우회 성공 → 로그 수집 가능
- QuartzCore 정상 초기화 및 소프트웨어 렌더링 사용 확인됨
PAC(Pointer Authentication) 우회
-
backboardd
수정 중 PAC 오류 발생 → ARMv8.3에서 도입된 보안 기능
- PAC 명령어를 NOP 대체하는 방식은 지나치게 침습적
- PAC 명령어는 호환 방식으로 컴파일 가능 → QEMU에서 PAC 무시하면 실행 가능
- QEMU 7은 PAC 우회 불가 → QEMU 8.2.1로 마이그레이션
- Apple 전용 명령어 및 GL 예외 레벨 등 수많은 QEMU 커스텀 코드 이식 필요
- 결과적으로 QEMU 8에서 iOS 부팅 성공 및 PAC 무력화 가능해짐
backboardd
와 그래픽 출력 확인
-
backboardd
동작하나 화면 표시 없음 → 여러 원인 가능성 존재
- DMA 메모리 덤프해도 유의미한 출력 없음
-
iosurface_lock
에서 주소 확인하고 프레임 덤프했으나 압축된 형태로 GPU에 전달되는 듯
- iPhone X (t8015)에서는 비압축 출력 확인됨 → QEMU의 DTB를 수정하여
chip-id
를 t8030 → t8015로 변경
- 결과적으로 부팅 후 Apple 로고 표시됨
진행 표시줄과 시스템 오류 추적
- 로고 이후 하얀색 진행 표시줄 출력 → 90%에서 정지
- 로그 분석 통해
mobileactivationd
와 SpringBoardFoundation
문제 발견 → 패치 후 UI 변경됨
- 진행 막힘 문제 해결을 위해 다수의 시스템 로그 분석 필요
dyld 캐시 및 사용자 공간 패치 자동화
- 커널과 동일한 방식으로 사용자 공간도 텍스트 기반 패치 방식 사용
- dyld 캐시는 2GB 크기로 수정에 비효율적 → 내부 도구 개선하여:
- dyld 내 오프셋 추적
-
dd
명령어로 특정 위치 직접 패치
- 커널 서명 검사 우회 패치 병행 필요
PreBoard
실행 및 UI 확인
-
PreBoard
앱은 오류 시 표시되는 시스템 앱 → 직접 실행 가능
- VNC 서버 추가하여 키보드로 화면 잠금 해제 시도
- unlock 이후
vImage
프레임워크에서 AMX(Apple Matrix Coprocessor) 명령어 사용 → QEMU 미지원
-
vImage
의 소프트웨어 fallback 경로로 패치하여 문제 해결
- 패치 후 텍스트 입력 가능한 화면까지 표시 성공
결론
- SpringBoard 실행 직전까지 도달 → 이제 완전한 UI 실행은 시간 문제
- 커널, 사용자 공간, 그래픽, 보안 기능(PAC 등) 다각적 분석 및 패치 수행
- QEMU 기반의 실질적인 iOS 앱 디버깅 및 테스트 환경 가능성 확인