iOS 보안 기능들과 탈옥 미리보기

ref

용어 정리

0. 보안 기능

SSV

시스템 볼륨에 대한 무결성을 보장하는 보안 기능이며, iOS15에서 도입됐다.
애플은 전체 시스템 볼륨에 대한 무결성을 빠르게 검증하기 위한 MerkleTree 를 가지고 있다.

MerkleTree는 트리형태로 하위노드들의 해시값을 다시 해싱해서 상위노드를 만드는 구조라서 파일이 변경된 경우 상위해쉬로 전파되어 루트까지 해시값이 변경되게 된다.
이때 루트 해시값이 변경됐다면 확인하면 파일시스템이 변경됨을 알 수 있다.

hash(B) 가 변경된 경우

                  root'    (변경)
                 /     \
    (변경)   hAB'       hCD    (변경 없음)
             /  \       / \
           hA   hB'   hC  hD
                 |
                 B'  파일또는 메타데이터 변경

공격자가 권한을 갖게되면 연결된 모든 해시값들을 재 계산 후 노드의 값들을 변경할 수 있을것이다.
SSV 기능으로 정상 root 해시값을 애플의 개인키로 서명하고 저장하기 때문에 공격자가 root 까지 재계산 하더라도 서명을 추가할 수 없게된다.

언제든 MerkleTree의 애플의 공개키 기반 해시 검사 루틴을 수행하면 무결성이 깨진것을 확인할 수 있게된다.
(서명된 값이 변조되지 않았으면서 검증 함수가 우회되지 않았다는 가정하에)

서명된 해시값(expectedSeal)은 애플이 펌웨어를 만들때 정상 시스템을 기준으로 만들어지고, 펌웨어를 기기에 설치할때, 부팅할때, 부팅 후 파일을 읽을때 검사한다.

  1. 애플의 공개키로 expectedSeal의 서명이 올바른지 확인. 공격자는 애플 개인키를 얻을 수 없기 때문에 expectedSeal을 변경할 수 없다.
  2. expectedSeal 값이 변경되지 않음을 확인하고, 부팅할 파일시스템에서 계산된 actualSeal 값과 다르지 않다면 애플의 공개키만 사용해서 검증이 가능하다.

애플의 공개키는 BootROM에 저장되어 있고, 물리적으로 readonly이기 때문에 expectedSeal은 절대 변경될 수 없음을 전제로 한다.

그래서 결국엔 함수를 우회해야하는데, 파일을 변경해도 해시값을 원본값을 리턴하도록 해시함수를 수정하거나 expectedSeal을 공개키로 검증하는 함수를 항상 참이 나오도록 우회하는 방법이 논리적으로 가능성있는 방향이다.


1. 파일시스템 구성에 따른 분류

rootful

탈옥용 파일 패키지, 트윅들이 직접 루트파일시스템에 설치되는 방식이다. 읽기 전용이였던 시스템 파티션을 읽기, 쓰기로 재마운트하고 탈옥파일과 트윅들을 설치하게 된다

이 방식은 기존 도구들과 호환성이 좋지만, 기존 시스템 파일들과 탈옥파일들이 섞여서 깔끔하게 제거하는 것이 어렵고 잘못된 파일이 패치되는 경우 부팅시 문제가 생길수도 있게된다.

iOS 15부터는 SSV(Signed System Volume) 때문에 시스템 볼륨을 변경하기 어려워서 원본 시스템 볼륨을 복사한 파일시스템으로 부팅하는 방식인 FakeFS를 사용하기도 했다.
이 방법은 원본 볼륨과 복사본을 동시에 유지해야하기 때문에 저장공간이 두배로 필요하고, 부팅체인에 개입이 가능한 취약점이 필요 (checkm8)하게 된다. (다른 방법이 있을수도있긴함)

rootless

탈옥용 파일들을 시스템 볼륨이 아닌 /var/jb 같은 경로에 설치하는 방식이기 때문에 SSV의 우회가 필요 없어졌다. 요즘 rootless들은 실제 데이터들을 /private/preboot 파티션에 저장하고, /var/jb 를 심볼릭 링크로 연결해둔다.

iPhone:/var root# ls -la /var/jb
lrwxr-xr-x 1 root wheel 140 Jun 10  2024 /var/jb -> /private/preboot/C896A982DC76C68E87BFF110585F94461F7F72CCE92F9D497C5695F10EA96257204ADFE8836F6389343D4350ADC339F2/dopamine-UP1ZyJ/procursus//

rootful은 시스템에 바로 설치하기 떄문에 프로그램들에서 경로 관련 코드가 실행될 때 시스템의 경로를 그대로 사용할 수 있지만, rootless는 /var/jb 를 붙여서 사용해야하기 때문에 트윅이나 바이너리가 호환되지 않는다.

정상 시스템 볼륨으로 부팅 후 유저랜드 취약점부터 커널 프리미티브 환경을 만들어서 사용하기 떄문에 SSV 우회도 필요 없으며, 탈옥 제거가 쉽다.

정리

  • rootful : 시스템 볼륨을 직접 수정해서 탈옥 파일을 설치하는 방식
  • fakefs : 시스템 볼륨을 복사해서 만든 FakeFS 에 탈옥파일 설치 후 부팅하는 방식
  • rootless : 시스템 볼륨 수정 없이 파일시스템의 다른 영역에 파일들을 설치하는 방식

2. 익스플로잇 트리거 방식에 따른 분류

Tethered

Tethered는 묶여있다는 의미로 기기를 부팅할 때마다 컴퓨터 등 외부 장치가 필요한 방식이다.
기기에는 정상 부팅 경로의 파일(커널, boot argument, ramdisk 등)을 수정하여 탈옥 환경이 유지되어 있지만, 외부에서 취약점을 트리거해야하기 때문에 부팅을 위해서는 컴퓨터가 필요하게 되고, 컴퓨터 없이는 정상 부팅조차 실행되지 않게된다.

기기에 탈옥용 파일이나 변경된 root filesystem이 남아 있을 수 있지만, 이를 실행할 수 있게 만드는 부팅 패치는 RAM에만 존재하거나 컴퓨터에서 전달된다. 따라서 전원이 꺼지면 패치가 사라지고, 컴퓨터 없이 정상 홈 화면까지 부팅하지 못하거나 Recovery 상태에 머무를 수 있다.

Semi-Tethered (palera1n)

여전히 탈옥 유지를 위해서는 컴퓨터가 필요하지만, 정상 부팅 경로를 남겨뒀기 때문에 컴퓨터에서 취약점을 트리거하지 않으면 순정 상태로 부팅되는 방식이다.

정상 시스템과 탈옥 환경을 분리하고, exploit이 적용되지 않은 경우에는 Apple의 원본 커널과 시스템 snapshot을 사용한다. 컴퓨터에서 exploit을 적용한 경우에만 부팅·커널 패치와 탈옥 bootstrap이 활성화된다.

Tethered와 semi-tethered의 차이는 추가 취약점이 필요하기보다, 구조적인 차이인 경우가 많아서 아래 사항들을 구현하면 Semi-Tethered 가 된다.

  • 원본 시스템은 보존하고, 탈옥 환경을 분리 (RootFS/FakeFS)
  • 취약점 트리거 실패 시 안전하게 stock boot로 폴백
  • 탈옥 daemon이 정상 부팅을 방해하지 않는 구조

Untethered

기기 의존이 없고, 순정 부팅을 유지할 필요가 없기 때문에 추가적인 컴퓨터 없이 취약점 트리거가 기기 내부에서 발생하기 때문에 핸드폰을 재부팅해도 자동으로 탈옥 상태가 유지되도록 구현한 방식이다.

탈옥 패치가 반드시 영구적으로 남아야 하는것은 아니고 매번 다시 트리거돼서 필요한 권한을 획득하게 만들면 된다.

다른 탈옥들과는 달리 기기를 탈옥상태로 유지하는 것이 목표이기 때문에 저장장치에 탈옥을 위한 데이터를 남겨두고, 익스플로잇 코드를 자동실행할 수 있도록 시스템서비스로 등록해야 한다.

Semi-Untethered (dopamine)

위에서 설명하지 않았지만 기기 의존이 없다는 말은 컴퓨터 없이 기기안에서 트리거가 가능하다는 의미이고, 일반적으로 순정 상태로 부팅 이후에 사용자가 트리거해서 탈옥상태로 만드는 방식을 사용한다.


3. 탈옥의 목표

일반적으로 iOS가 탈옥 상태가 되려면 단순히 root 계정을 얻는 것만으로는 부족하고, 여러 보안 계층을 넘어 임의 코드 실행, 권한 상승, 코드 서명 정책 처리, 탈옥 환경 구성이 가능한 환경이 만들어져야 한다.

  초기 코드 실행
  커널 권한 또는 강력한 primitive 확보 (Sandbox 탈출 등)
  Bootstrap 및 탈옥 daemon 실행
  Tweak injection

1. 초기 코드 실행

앱이나 운영체제 등의 프로그램은 개발자가 의도한대로 빌드되어 동작하게 된다.
취약점을 이용해서 공격자가 원하는 임의 코드를 실행하도록 만드는것이 첫번째 목표이다.

초기 코드 실행 단계이기 때문에 이때는 앱 프로세스의 권한으로 임의 코드를 실행시킬 수 있도록 만들면 된다.
coruna의 경우를 생각해보면 Webkit 취약점을 사용해서 원하는 wasm 코드를 실행할 수 있도록 만드는 것부터 시작한다.

sideloading나 trollstore를 사용해서 앱을 설치하면 원하는 코드를 실행하는 것이 가능하기 때문에 앱 취약점이 따로 필요하지 않을 수 있다.

2. 권한 상승

제일 핵심이되는 작업이며 다양한 보호기법들이 있기 때문에 권한 상승의 의미는 다양하다. 초기 코드 실행이 어떤 부분에서 발생했냐에 따라 추가되는 작업이다.

앱 취약점에서 시작됐다면, 임의코드 실행이 가능해져도 권한은 앱 권한을 벗어날 수 없다. 만약 root 권한을 획득했다고 하더라도 iOS는 다양한 보안 기능을 통해서 모든 권한을 갖고있지 않도록 구현되어 있기 때문에 원하는 권한을 얻을 때 까지 샌드박스를 걷어내는 작업이 필수적이다.

앱 기반 탈옥에서는 일반적으로 sandbox 안에서도 접근할 수 있는 syscall, socket, Mach API 또는 IOKit interface를 통해 kernel 취약점을 트리거한다.
이후 kernel memory를 읽고 쓸 수 있는 kernel read/write 등의 primitive를 확보하고, 이를 이용해 현재 프로세스와 시스템의 보안 상태를 변경한다.

  • Kernel RW
    일반적으로 앱 프로세스에서는 Kernel 메모리의 RW가 불가능하기 때문에 이 경계를 넘어갈 수 있어야한다.
  • KASLR과 빌드별 구조
    커널 취약점은 커널메모리에 대한 구조를 파악할 수 있어야한다. 부팅마다 변경되는 주소인 KASLR slide, 빌드 버전마다 달라질 수 있는 구조체 오프셋을 미리 찾아두고, 그에맞게 주소를 계산해서 트리거 한다.
  • PAC bypass
    arm64e 부터 데이터영역을 사용하는 간접분기 임의함수 호출에 대해 포인터 서명값을 검증하는 PAC라는 기법이 도입돼서 임의코드 실행에 우회가 필요할 수 있다.
  • PPL, SPTM 등의 보호 메모리
    kernel write 권한이 있어도 모든 메모리를 수정할 수 있는것이 아니다. page table 등은 PPL, SPTM 이라는 기법에 의해 승인된 write 경로 이외에는 쓰기가 불가능하다. 물리메모리를 직접 RW 하는 방법 등으로 우회해야한다.
  • Root 획득
    기본적으로 유닉스 시스템에서는 UID/GID 를 통해 권한 관리를 하고있기 때문에 credential을 변경하여 Unix 권한을 얻어야한다.
  • Sandbox 탈출
    일반 앱은 sandbox profile에 의해 일부 파일, Mach service, IOKit 등에 접근이 제한되기 때문에 sandbox 상태를 변경하여 우회해야한다.
  • Platformize/entitlement 처리
    다른 프로세스의 task port 를 획득하거나 권한이 필요한 서비스를 사용하기 위해서는 entitlement를 마음대로 사용할 수 있어야한다. 이미 entitlement가 있는 프로세스에 코드를 주입해서 원하는 작업을 실행하거나 커널패치로 entitlement를 주입하게된다.
  • Code-signing (AMFI) 우회
    애플 서명이 없는 Mach-O 와 dylib 은 root 권한으로도 실행되지 않는다. 원하는 파일의 cdhash를 TrustCache에 등록하거나 AMFI 로직을 패치해서 우회하기도 한다.

3. Bootstrap 및 탈옥 daemon 실행

이제 필요한 모든 권한을 얻었으니 탈옥 사용자를 위한 환경을 만들고, 시스템 전체에 탈옥정책을 전파해서 안정적인 탈옥환경 실행이 가능하도록 한다.

탈옥을 위한 JBROOT 를 설정하고, 탈옥용 툴들을 설치한다. 일반적으로 shell, dpkg, apt, cli 관리도구, tweak loader 등이 포함된다.

탈옥 환경을 좀 더 안정적으로 관리하기 위한 jailbreakd 같은 데몬을 실행하고, launchd에 launchdhook.dylib 를 주입해서 시스템 전체에서 프로세스와 프로세스간 통신에 개입하게된다.

준비가 다 되면 사용자공간만 재시작(!= 리스프링)해서 탈옥 툴이 원하는 구성을 완벽하게 적용한다. 커널공간은 유지되기 때문에 exploit 상태는 잃지 않는다.

4. Tweak Injection

Tweak은 대상 process 안에서 실행되는 Mach-O 동적 라이브러리다. Tweak Injection은 설치된 모든 tweak을 모든 process에 넣는 것이 아니라, TweakLoader가 각 tweak의 filter를 확인하여 SpringBoard, 특정 앱 또는 daemon 등 적용 대상 process에 선택적으로 dylib를 로드하는 과정이다.

  SpringBoard가 실행될 때:

  launchd
    -> SpringBoard 생성
    -> systemhook 삽입
    -> TweakLoader 실행
    -> 설치된 tweak들의 filter 검사
    -> LockScreenTweak만 SpringBoard에 로드

Palera1n (checkm8)

checkm8 BootROM 취약점을 사용하는 semi-tethered 탈옥 도구이다.
PC 에서 기기를 DFU 모드로 연결 후 Palera1n 도구를 실행시켜 PongoOS로 진입시키고 KPF가 부팅할 XNU를 패치한 뒤 ramdisk와 overlay를 전달하여 jbinit, launchd hook, loader가 rootless 또는 rootful 환경을 구성하는 구조이다.

1. Palera1n 툴 실행

palera1n은 checkm8 익스플로잇부터 탈옥 환경 구성까지 필요한 프로그램과 payload를 올바른 순서로 실행하고 전달하는 오케스트레이터 역할을 한다.
rootful, rootless, FakeFS 설정, safe mode 등 다양한 옵션으로 리소스를 실행시켜 기기에 환경을 구성하게 된다.

  • 탈옥 방식과 부팅 옵션은 인자로 전달되어 palerain_flags 형태로 파싱해둔다.
  • 연결된 기기의 ECID, CPID(SoC), 보드ID, 모델정보 등을 usb 프로토콜로 획득한다. (recovery protocol 등)
  • PongoOS, KPF, ramdisk 및 binpack payload 는 palera1n이 빌드될때 다른 저장소에서 다운로드 후 임베드된다.

2. checkm8 트리거 및 PongoOS 진입

DFU 모드가 감지되면 exec_checkra1n 함수를 실행하게 되는데, palera1n 바이너리 내부에 포함된 checkra1n, Pongo_bin 을 tmp 폴더에 풀고 checkra1n -Ep -k /tmp/Pongo.bin.XXXXXX 형태로 프로세스를 실행해서 취약점을 트리거한 뒤 PongoOS를 실행하는 작업까지 진행된다.

DFU 상태에서는 기본적으로 BootROM이 정의한 USB/DFU 요청과 데이터를 보내며 통신할 수 있다. checkm8는 DFU USB 처리코드의 UAF 취약점을 사용해서 실행흐름을 공격자가 주입한 코드로 이동시켜 결국엔 PongoOS를 실행하게된다.

모든 USB장치는 제어요청을 처리하기 위해 EP0을 가지고있는데, DFU 프로토콜도 주로 EP0 위에서 구현되어 있다.
정상 DFU 프로토콜은 PC에서 펌웨어 데이터를 보낼때(EP0 SETUP → DATA → STATUS) 기기에서는 SRAM 에 usb_device_io_request 구조체수신버퍼인 io_buffer를 준비하는데 데이터가 정상적으로 버퍼에 복사되면 callback을 호출하고 관련 전역상태를 초기화하여 정상완료처리한다. 이 취약점은 io_buffer 포인터가 댕글링되는 상황을 이용한다.

struct usb_device_io_request {
   int endpoint;
   void *io_buffer;
   int length;
   void (*callback)(struct usb_device_io_request *);
   struct usb_device_io_request *next;
};
  1. SecureROM에서 DFU 모드에 진입하게되면, 특정 크기의 io_buffer가 만들어진다.

    [objects][BBBBBBBB][objects][L][........][L]
               ↑ P                      H1=8
    
  2. PC는 표준 USB control request인 SET_FEATURE(ENDPOINT_HALT)를 보내 기기의 EP0 IN endpoint를 HALT 상태로 설정한다.
    이후 PC가 GET_DESCRIPTOR 요청을 반복하면 SecureROM은 응답을 보내기 위한 usb_device_io_request 객체와 buffer를 SRAM heap에 할당한다.
    그러나 EP0 IN이 HALT 상태이므로 응답이 완료되지 않고 request 객체들이 pending queue에 남는다.
    이후에 공격자가 USB reset을 진행하는데 일부 request는 callback에서도 새 request를 생성하지만 이 request는 reset에서 제외되는 문제가 있어서 memory leak 상태로 남게된다.
    새로운 request는 free된 힙영역이 병합되지 못하게 만들면서 공격자가 예측할 수 있는 레이아웃을 만들게된다. 최소한 크기가 큰 io_buffer를 멀리 날릴 수 있다.

    L: 정리과정에서 생성된 Leaked request
    해제 전: [R1][buffer1][R2][buffer2][L1][R3][buffer3]
    해제 후: [--------- free ---------][L1][----- free -----]
    재할당 : [새 request][L1][새 request][L2][new io_buffer]
    
  3. PC는 DFU_DNLOAD control transfer를 시작한다 (EP0 IN이 STALL이라 PC → 기기는 가능함). SETUP packet의 wLength로 일정 크기의 DATA가 뒤따를 것이라고 알리고, SecureROM은 다음과 같은 DATA phase 상태를 설정한다.

    ep0_data_phase_buffer = DFU모드 진입시 생성한 io_buffer
    ep0_data_phase_remaining = 전송 예정 크기
    

    이후 PC는 비동기 전송이 정상 완료되기 전에 host-side transfer를 취소해서 기기를 대기하게한다. 데이터 크기가 반드시 작거나 헤더 크기인 것은 아니다. 중요한 것은 DATA phase가 시작됐지만 완료되지 않았다는 점이다

  4. PC가 DFU 상태 변경 요청이나 USB reset을 발생시키면 기존 세션의 old_io_buffer는 해제된다. 그러나 정상 DATA completion 경로가 실행되지 않았기 때문에 다음 내부 상태가 초기화되지 않고 남는다.

    ep0_data_phase_buffer → 해제된 old_io_buffer 주소
    ep0_data_phase_remaining → 남은 길이
    

    이전 USB control transfer 자체는 종료되지만, 그 전송이 남긴 목적지 포인터와 길이 같은 내부 상태는 남는다.

  5. USB reset 이후에 공격자는 다시 HALT 상태로 만들고 GET_DESCRIPTOR 를 발생시킨다. SoC 별로 계산된 수 만큼만 발생시킨다. allocator 입장에서는 L1이 아직 관리되는 메모리이기 때문에 새로 할당되는 io_buffer

Heap grooming의 영향으로 새 io_buffer는 다른 주소에 배치되고, 이전 old_io_buffer 영역에는 pending USB I/O request 객체들이 배치되도록 유도된다.

 old address H: usb_device_io_request
 new address J: new_io_buffer
 stale ep0_data_phase_buffer → H

 이것은 새 DFU DATA가 크기 때문에 request가 그 자리에 놓이는 것이
 아니라, 이전에 조정해 둔 allocator 배치와 재초기화 중의 할당 순서
 때문에 발생한다.
  1. PC가 새로운 Host-to-Device control transfer로 overwrite 데이터를
    보낸다. SecureROM의 EP0 DATA 처리 코드는 초기화되지 않은
    새 PC 데이터
    → USB RX buffer
    → stale ep0_data_phase_buffer
    → 이전 io_buffer 주소에 배치된 request 객체

    따라서 해당 주소에 있는 pending request 객체의 callbacknext
    필드가 공격자가 구성한 값으로 덮인다.

  2. USB reset 또는 pending queue 정리 과정이 실행되면 SecureROM은
    request의 completion callback을 호출한다. 변조된 callback으로 인해
    SecureROM gadget/callback chain이 실행되고, 최종적으로 SRAM payload로
    제어 흐름이 이동한다.


이 작업은 checkra1n 의 exploit 개발자가 SoC별 SecureROM을 역공학해 미리 계산한 뒤 checkra1n에 설정값으로 넣어 둡니다.

1. SecureROM allocator 분석

먼저 SecureROM dump를 역공학하여 다음 동작을 찾습니다.

malloc(size)
free(address)
free block 선택 방식
allocation alignment
heap block header 크기
인접 free block 병합 방식

분석 결과를 단순화하면 allocator는 다음과 같이 동작한다고 모델링할 수 있습니다.

void *malloc(size_t requested)
{
size = align(requested + HEAP_HEADER_SIZE);

  block = find_smallest_free_block_that_fits(size);
  split(block, size);

  return block->data;

}

따라서 실제 계산에서는 데이터 크기뿐 아니라 header와 alignment까지 포함해야 합니다.

실제 block 크기 =
align(requested size + allocator metadata)

2. DFU 초기화의 할당 순서 분석

SecureROM의 DFU/USB 함수를 역공학하여 allocation trace를 만듭니다.

DFU iteration 시작

alloc(string descriptor 크기)
alloc(device descriptor 관련 크기)
alloc(configuration 관련 크기)
alloc(io_buffer 크기 B)
alloc(endpoint request 크기 R)

종료 시점도 추적합니다.

USB reset

free(io_buffer)
free(descriptor 객체)
request completion callback
callback에서 ZLP request 새로 할당
기존 request free
endpoint head/tail 초기화

중요한 것은 단순한 객체 목록이 아니라 정확한 순서입니다.

alloc A
alloc B
free A
alloc L
free B

순서가 달라지면 최종 heap 모양도 달라집니다.

3. Heap 상태를 직접 시뮬레이션

분석한 allocator를 PC에서 작은 시뮬레이터로 재현할 수 있습니다.

초기:
[free 100]

alloc descriptor(10):
[D 10][free 90]

alloc io_buffer(20):
[D 10][B 20][free 70]

alloc request(5):
[D 10][B 20][R 5][free 65]

reset cleanup과 leak도 동일하게 적용합니다.

free(D)
free(B)
leak(L)
free(R)
coalesce()

그다음 leak 요청 개수를 바꾸면서 결과를 계산합니다.

leak 0개 → new B 주소 = old B 주소 실패
leak 1개 → new B 주소 = 다른 주소 후보
leak 2개 → target R 위치 불일치 실패
leak N개 → B와 R 모두 원하는 위치 성공

4. 만족해야 하는 조건

exploit 설정은 최소한 다음 조건을 만족해야 합니다.

new_io_buffer_address != stale_buffer_address

그리고 새 pending request가 stale write 범위와 겹쳐야 합니다.

target_request_start
<= stale_write_start + write_length

target_callback_address
= target_request_start + callback_offset

개념적으로 overwrite padding은 다음처럼 계산합니다.

padding =
target_callback_address - stale_write_start

불완전한 DATA phase에서 이미 일부 바이트가 수신되어 포인터가 전진했다면 그것도 반영합니다.

stale_write_start =
old_io_buffer_start + already_received

최종적으로:

padding =
(target_request_start + callback_field_offset)

  • (old_io_buffer_start + already_received)

5. 후보 요청 횟수 탐색

개발자는 GET_DESCRIPTOR 요청 중 다음 두 종류의 횟수를 조합합니다.

leak이 발생하는 요청
leak이 발생하지 않는 요청

이를 통해 leak 객체 앞뒤에 원하는 크기의 free 영역을 만듭니다.

for hole_count in candidates:
for leak_count in candidates:
simulate_heap(hole_count, leak_count)

      if new_buffer_moved &&
         target_request_overlaps_stale_write:
          save_configuration()

공개 ipwndfu에는 이 결과가 DeviceConfig 형태로 저장돼 있습니다.

DeviceConfig(
securerom_version,
cpid,
large_leak,
overwrite,
hole,
leak
)

cpid/version → 어떤 SecureROM 배치를 사용할지 선택
hole → grooming 중 hole을 만드는 요청 횟수
leak → reclaim 단계의 request 생성 횟수
overwrite → padding, callback, next 등이 포함된 바이트 배열

SoC마다 값이 다른 것을 공개 구현에서 확인할 수 있습니다. axi0mX checkm8.py
(https://github.com/axi0mX/ipwndfu/blob/master/checkm8.py)

6. 실제 기기에서 검증

정적 계산만으로 끝나지 않습니다. 다음 방법으로 실제 배치를 확인하고 조정합니다.

  • SecureROM dump와 역어셈블 결과 분석
  • USB 요청별 allocation/free trace 재구성
  • 디버그 가능한 개발 장치나 하드웨어 디버깅 사용
  • 예상 callback 위치에 식별 가능한 값을 써서 결과 확인
  • USB controller와 timing을 바꿔 반복성 측정
  • exploit 성공 후 USB serial의 PWND:[checkm8] 표식 확인

palera1n 실행 시점

일반 사용자가 palera1n을 실행할 때는 이 계산을 다시 수행하지 않습니다.

기기 USB serial에서 CPID/SRTG 확인

미리 만들어진 SoC별 exploit configuration 선택

정해진 leak/hole 요청 순서 실행

미리 만들어진 overwrite와 payload 전송

따라서 H0, H1, request offset은 우연히 기대하는 값이 아니라 SecureROM allocator, allocation 순서, 객체 크기를 역공학하고 heap 동
작을 시뮬레이션하여 SoC별로 미리 구해 둔 값입니다. 다만 USB 취소 타이밍에는 변동이 있어 계산이 맞더라도 실전에서는 실패 후 재시
도가 필요할 수 있습니다.


dopamine

이녀석은 지금쓰는것중 제일좋은녀석이라 정리 rootless

트윅

Ellekit tweakLoader? ? 훅?
frida
그누구야 트롤스토어

가능한것과 불가능한것

모든 권한을 가진 프로그램 직접실행

Comments

ESC
Type to search...