콘텐츠로 건너뛰기

Tamarine으로 아이폰/아이패드 JTAG디버깅 / 시리얼 로그 출력해보기

준비물

  • 1.5mm 일자 드라이버
  • APPLE-LM-BO-V2A Apple Lightning Male connector breakout board (DataSheet, Drawing, 구매링크), 여기서 필자는 둘중에 두번째의 초록색 male connector 달린 제품 사용.
  • 마이크로5핀 to USB 케이블 (라즈베리파이 피코를 PC에 연결할 용도로 쓰임)
  • 아두이노 암/암 점퍼 케이블 8개

조립 완성 사진

Pico용 SDK / tamarin(구버전) 펌웨어 컴파일

seo@seos-macbook tamarin % cd ~/Desktop

seo@seos-macbook Desktop % mkdir

seo@seos-macbook Desktop % mkdir iphone_jtag

seo@seos-macbook Desktop % cd iphone_jtag

seo@seos-macbook iphone_jtag % mkdir -p tamarin

seo@seos-macbook iphone_jtag % cd $_

seo@seos-macbook tamarin % git clone <https://github.com/raspberrypi/pico-sdk.git>
Cloning into 'pico-sdk'...
...

cd pico-sdk; git submodule update --init

seo@seos-macbook pico-sdk % export PICO_SDK_PATH=$(pwd) 

seo@seos-macbook pico-sdk % cd ../

seo@seos-macbook tamarin % git clone <https://github.com/stacksmashing/tamarin-firmware.git>; cd $(basename $_ .git)
Cloning into 'tamarin-firmware'...
...

cd tamarin-firmware

seo@seos-macbook tamarin-firmware % mkdir build; cd $_

seo@seos-macbook build % cmake ..

seo@seos-macbook build % make -j$(nproc)
[  0%] Creating directories for 'pioasmBuild'
...
[100%] Built target tamarin_firmware
seo@seos-macbook build % 
  • tamarin_firmware.uf2 파일이 생성됐는지 확인
seo@seos-macbook build % ls -la
total 5208
drwxr-xr-x  22 seo  staff     704 Dec 29 19:54 .
drwxr-xr-x  23 seo  staff     736 Dec 29 19:53 ..
-rw-r--r--   1 seo  staff   30069 Dec 29 19:54 CMakeCache.txt
-rw-r--r--   1 seo  staff   15734 Dec 29 19:54 CMakeDoxyfile.in
-rw-r--r--   1 seo  staff   21594 Dec 29 19:54 CMakeDoxygenDefaults.cmake
drwxr-xr-x  18 seo  staff     576 Dec 29 19:54 CMakeFiles
-rw-r--r--   1 seo  staff  195244 Dec 29 19:54 Makefile
-rw-r--r--   1 seo  staff    2270 Dec 29 19:54 cmake_install.cmake
drwxr-xr-x   3 seo  staff      96 Dec 29 19:54 generated
-rw-r--r--   1 seo  staff    3051 Dec 29 19:54 lightning_rx.pio.h
-rw-r--r--   1 seo  staff    3079 Dec 29 19:54 lightning_tx.pio.h
drwxr-xr-x   8 seo  staff     256 Dec 29 19:54 pico-sdk
-rw-r--r--   1 seo  staff      60 Dec 29 19:54 pico_flash_region.ld
drwxr-xr-x  11 seo  staff     352 Dec 29 19:54 pioasm
drwxr-xr-x   3 seo  staff      96 Dec 29 19:54 pioasm-install
-rw-r--r--   1 seo  staff    1746 Dec 29 19:54 probe.pio.h
-rwxr-xr-x   1 seo  staff   42068 Dec 29 19:54 tamarin_firmware.bin
-rw-r--r--   1 seo  staff  738759 Dec 29 19:54 tamarin_firmware.dis
-rwxr-xr-x   1 seo  staff  832920 Dec 29 19:54 tamarin_firmware.elf
-rw-r--r--   1 seo  staff  545393 Dec 29 19:54 tamarin_firmware.elf.map
-rw-r--r--   1 seo  staff  118382 Dec 29 19:54 tamarin_firmware.hex
**-rw-r--r--   1 seo  staff   84480 Dec 29 19:54 tamarin_firmware.uf2**

Pico 보드에 tamarin 펌웨어 업로드

  • Pico 보드를 펌웨어 업로드 모드로 진입방법
    • BOOTSEL 버튼 누른 상태에서 USB 연결
  • picotool info 명령어로 USB 연결 확인 (picotool은 brew로 설치 가능함)
seo@seos-macbook tamarin-firmware % picotool info
Program Information
 name:          tamarin_firmware
 features:      UART stdin / stdout
 binary start:  0x10000000
 binary end:    0x1000946c
  • Tamarin 펌웨어 업로드
seo@seos-macbook build % pwd
/Users/seo/Desktop/iphone_jtag/tamarin/tamarin-firmware/build

seo@seos-macbook build % picotool load -v ./tamarin_firmware.uf2 -f
Loading into Flash:   [==============================]  100%
Verifying Flash:      [==============================]  100%
  OK
seo@seo
  • USB 재연결 후 Tamarine Cable 연결됐는지 확인 Screenshot 2025-12-29 at 8.11.35 PM.png

DCSD 모드로 시리얼 로그 확인하기

  • 환경: 아이패드 7세대 / iPadOS 15.0 (turdus_merula로 tethered-downgrade된 상태)
  • USB-A 8핀 일반 케이블에 기기 연결
  • tamarin 모드 설정
#!/bin/zsh
minicom -D /dev/tty.usbmodem313371 -b 115200
  • DCSD 모드 2번 설정
  • 새 터미널 탭 열기
  • bootx 문자열을 임의로 바이너리 패치해서 최종적으로 부팅이 되지 않도록 만들고, pongo 모드로 진입 (만약, untethered-downgrade한 상태라면 → 생략하고 바로 다음 단계로 넘어갈 수 있음)
seo@seos-macbook turdus_m3rula_1.1_b0ea3ee7_macos % cat 150-boot-pongo.sh
#!/bin/zsh
./bin/turdusra1n_patched -t /Users/seo/Desktop/turdus_m3rula_1.1_b0ea3ee7_macos/image4/[ECID_REDACTED]-iPad7\\,11-15.0-iBoot.img4  -i /Users/seo/Desktop/turdus_m3rula_1.1_b0ea3ee7_macos/image4/[ECID_REDACTED]-iPad7\\,11-signed-SEP.img4  -p /Users/seo/Desktop/turdus_m3rula_1.1_b0ea3ee7_macos/image4/[ECID_REDACTED]-iPad7\\,11-15.0-SEP.im4p

seo@seos-macbook turdus_m3rula_1.1_b0ea3ee7_macos % ./150-boot-pongo.sh
turdusra1n 0.2.0-6aafc6eb (usb backend: IOKit)
- <Log> Waiting for recovery or DFU mode device
- <Log> Found DFU mode device
- <Log> checkm8 reset stage
- <Log> Found DFU mode device
- <Log> checkm8 setup stage
- <Log> Entered initial checkm8 state after 9 steps
- <Log> Stalled input endpoint after 1 steps
- <Log> Found DFU mode device
- <Log> checkm8 trigger stage
- <Log> Checkmate?
- <Log> Detected pwned DFU mode device
- <Log> Sending boot image
- <Log> boot image sent
- <Log> Found download mode device
- <Log> Sending pongo image
- <Log> Found pongo mode device
- <Log> Sent sep_racer (1211608 bytes)
- <Log> Sent modload msg
- <Log> Sent sepfw (1439122 bytes)
- <Log> Sent sepfw msg
- <Log> Sent sep (1255758 bytes)
- <Log> Sent sep msg
- <Log> Sent sep_flag msg
- <Log> Sent pwn_seprom msg
- <Log> Sent kpf_tethered (92248 bytes)
- <Log> Sent modload msg
- <Log> Sent kpf msg
- <Log> Sent bootux
#!/bin/zsh
minicom -D /dev/tty.usbmodem313374 -b 115200
  • palera1n 탈옥 및 boot-args에 “serial=3 debug=0x14e” 추가
seo@seos-macbook turdus_m3rula_1.1_b0ea3ee7_macos % ./palera1n-macos-arm64 -l -v -e "serial=3 debug=0x14e"
  • USB-A 8핀 일반 케이블 연결을 해제하고, 재빨리 브레이크아웃 보드에 연결
  • 이제부터는 serial.sh 실행한 터미널 창에서 로그 확인 가능
  • iBoot
  • Booting…

JTAG 모드로 SecureRom 디버깅

  • 환경: 아이폰8 / iOS 14.4.2
  • 머신: 인텔 맥 카날리나 10.15.2

OpenOCD 빌드 및 환경 설치

  • UTM 가상머신에서 작업 / Ubuntu 24.04 Server arm64
  • 빌드 및 컴파일
seo@seo:~/iphone_jtag$  git clone <https://github.com/tihmstar/openocd>
Cloning into 'openocd'...
...

seo@seo:~/iphone_jtag/openocd$ cd openocd

seo@seo:~/iphone_jtag/openocd$ git submodule update --init

seo@seo:~/iphone_jtag/openocd$ ./bootstrap

seo@seo:~/iphone_jtag/openocd$ ./configure --enable-tamarin

seo@seo:~/iphone_jtag/openocd$ make -j$(nproc)
Makefile:5524: warning: overriding commands for target `check-recursive'
...

  • 컴파일된 바이너리 생성 확인
seo@seos-macbook openocd % file src/openocd
src/openocd: Mach-O 64-bit executable arm64
  • 자기 AP칩에 맞는 cfg 다운로드 / 설정 가져오기
seo@seos-macbook openocd % wget <https://github.com/lambdaconcept/bonobo-configs/raw/refs/heads/master/t8015.cfg>

seo@seos-macbook openocd % cp -r ./tcl/target .

SecureRom 디버깅 및 이미지 덤프

  • USB-A 8핀 일반 케이블에 기기 연결
  • minicom에서 tamarin 모드 설정
#!/bin/zsh
sudo minicom -D /dev/tty.usbmodem313371 -b 115200
  • JTAG mode 1번으로 설정
...
Good morning!

1: JTAG mode
2: DCSD mode
3: Reset device
4: Reset and enter DFU mode (iPhone X and up only)
5: Reenumerate

F: Force JTAG mode without sending command
J: Force SPAM-JTAG mode without sending command
R: Reset Tamarin cable
S: SPAM mode (Apple Watch UART)
U: Go into firmware update mode
> 1
Enabling JTAG mode.
Restarting enumeration!
Done restarting enumeration!
Tristar request received: 74 00 02 1F
DCSD mode active.
Connect to the second serial port of the
Tamarin Cable to access the monitor.
JTAG mode active, ID pin in Hi-Z.
You can now connect with an SWD debugger.
Good morning!
  • Demotion
seo@seos-macbook turdus_m3rula_1.1_b0ea3ee7_macos % ./palera1n-macos-arm64 -d -l
...
 - [12/30/25 01:15:20] <Verbose>: DFU mode device found
 - [12/30/25 01:15:20] <Info>: Checking if device is ready
 - [12/30/25 01:15:20] <Verbose>: Attempting to perform checkm8 on 8015 11
 - [12/30/25 01:15:20] <Info>: Setting up the exploit
 - [12/30/25 01:15:20] <Verbose>: == checkm8 setup stage ==
 - [12/30/25 01:15:20] <Verbose>: Entered initial checkm8 state after 1 steps
 - [12/30/25 01:15:20] <Verbose>: Stalled input endpoint after 1 steps
 - [12/30/25 01:15:20] <Verbose>: DFU mode device found
 - [12/30/25 01:15:20] <Verbose>: == checkm8 trigger stage ==
 - [12/30/25 01:15:20] <Info>: Checkmate!
 - [12/30/25 01:15:20] <Verbose>: Device should now be demoted
 - [12/30/25 01:15:20] <Verbose>: DFU mode device disconnected
 - [12/30/25 01:15:20] <Verbose>: DFU mode device found
 - [12/30/25 01:15:20] <Info>: Demoted device waiting for debugger
 - [12/30/25 01:15:20] <Verbose>: Skipping demoted 8015 11
  • 아이폰 케이블 분리 및 Tamarine 케이블로 재연결 / Tamarine cable 연결
  • OpenOCD로 연결
./src/openocd -f tcl/interface/tamarin.cfg -f t8015.cfg -c "bindto 0.0.0.0" 
  • telnet으로 제어 인터페이스에 접근 및 halt 수행
  • telnet 127.0.0.1 4444
  • targets iphone.ecore0
  • halt
seo@seos-macbook openocd % telnet 127.0.0.1 4444
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Open On-Chip Debugger
> targets
    TargetName         Type       Endian TapName            State       
--  ------------------ ---------- ------ ------------------ ------------
 0  iphone.dbg         mem_ap     little iphone.cpu         running
 1  iphone.mem         mem_ap     little iphone.cpu         running
 2  iphone.ecore0      aarch64    little iphone.cpu         running
 3  iphone.ecore1      aarch64    little iphone.cpu         poweroff
 4  iphone.ecore2      aarch64    little iphone.cpu         poweroff
 5  iphone.ecore3      aarch64    little iphone.cpu         poweroff
 6  iphone.pcore0      aarch64    little iphone.cpu         poweroff
 7  iphone.pcore1      aarch64    little iphone.cpu         poweroff
 8* iphone.sep         aarch64    little iphone.cpu         unknown

> targets iphone.ecore0
> halt
Timeout waiting for target iphone.ecore0 halt
  • halt 수행시 Timeout waiting for… 에러 출력시에 minicom 창에서 F: Force JTAG mode without sending command, 즉 F모드로 tamarin 모드 설정.
  • 이후엔 제대로 halt 됨 target halted in AArch64 state due to debug-request, current mode: EL1T cpsr: 0x800002c4 pc: 0x100000568 MMU: enabled, D-Cache: enabled, I-Cache: enabled
seo@seos-macbook openocd_tihmstar % sudo ./src/openocd -f tcl/interface/tamarin.cfg -f t8015.cfg
Open On-Chip Debugger 0.10.0+dev-gd91b411c (2025-12-29-23:11)
Licensed under GNU GPL v2
For bug reports, read
	<http://openocd.org/doc/doxygen/bugs.html>
Info : only one transport option; autoselect 'swd'
Warn : Transport "swd" was already selected
adapter speed: 1000 kHz

Warn : Interface already configured, ignoring
Warn : Transport "swd" was already selected
Info : clock speed 10000 kHz
Info : SWD DPIDR 0x03000067
Error: iphone.ecore0: missing UTT configuration, halt may not work
Info : iphone.ecore0: hardware has 2 breakpoints, 3 watchpoints
Error: iphone.ecore1: missing UTT configuration, halt may not work
Error: iphone.ecore1 powered down!
Error: iphone.ecore2: missing UTT configuration, halt may not work
Error: iphone.ecore2 powered down!
Error: iphone.ecore3: missing UTT configuration, halt may not work
Error: iphone.ecore3 powered down!
Error: iphone.pcore0: missing UTT configuration, halt may not work
Error: iphone.pcore0 powered down!
Error: iphone.pcore1: missing UTT configuration, halt may not work
Error: iphone.pcore1 powered down!
Error: iphone.sep: missing UTT configuration, halt may not work
Info : Listening on port 3333 for gdb connections
Info : Listening on port 3334 for gdb connections
Info : Listening on port 3335 for gdb connections
Info : Listening on port 3336 for gdb connections
Info : Listening on port 3337 for gdb connections
Info : Listening on port 3338 for gdb connections
Info : Listening on port 3339 for gdb connections
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : accepting 'telnet' connection on tcp/4444
Error: Timeout waiting for target iphone.ecore0 halt

Info : iphone.ecore0 cluster 0 core 0 multi core
target halted in AArch64 state due to debug-request, current mode: EL1T
cpsr: 0x800002c4 pc: 0x100000568
MMU: enabled, D-Cache: enabled, I-Cache: enabled
  • 디버거 연결
  • lldb
  • gdb-remote 3333
  • SecureRom 이미지 덤프
(lldb) memory read --binary --outfile ./dump.bin --force 0x100000000 0x100020000
131072 bytes written to 'dump.bin'

커널 디버깅 (실패)

아이디어…

(lldb) p/x 0x207 & 0xfffffffe
(unsigned int) 0x00000206
// Demote 설정 전 값에서 0xfffffffe AND 연산한게 바로 0x206임.

(lldb) x/wx 0x2352BC000
0x2352bc000: 0x00000206
(lldb) x/gx 0x2352BC000
0x2352bc000: 0x2200000000000206
// A11칩 기준 demotion_reg 주소는 0x2352BC000.
// <https://github.com/axi0mX/ipwndfu/blob/master/device_platform.py>

pongoOS> peek 0x2352BC000
0x2352bc000: 207 (7 2 0 0)
// 기존 값 (Demote 안됨)
pongoOS> peek 0x2352BC004
0x2352bc004: 22000000 (0 0 0 22)
  • gaster에서 demotion flag 건드린다음, 커스텀 부트로더와 커널 올리고 하면 될지도?
  • 단, ramdisk 쉘 부팅상태로 진입해야됨. SEP 패닉 발생 가능성 있음.

시행착오

  • demotion flag를 pongoOS shell에서 건드릴려고 했으나 안됐음.
pongoOS> poke 0x2352BC000 206
writing 206 @ 0x2352bc000
pongoOS> poke 0x2352BC000 0x206
writing 206 @ 0x2352bc000
pongoOS> peek 0x2352BC000
0x2352bc000: 207 (7 2 0 0)
  • Checkra1n 0.1337.x에서 시도: demote 성공
pongoOS> fuse demote
pongoOS> peek 0x2352BC000
0x2352bc000: 206 (6 2 0 0)

//부팅
bootx

... 이후 부팅은 실패

  • gaster에서 demotion 이후에 SSHRD_Script로 램디스크 부팅할려고 헀으나… 실패
static bool
gaster_demote(usb_handle_t *handle, const uint8_t *src, uint8_t *dst, size_t len) {
	struct {
		uint32_t magic_0, magic_1, func, pad, r[8];
	} exec_cmd_armv7;
	uint8_t data[DFU_MAX_TRANSFER_SZ], *response;
	struct {
		uint64_t magic, func, x[8];
	} exec_cmd;
	uint32_t r_armv7;
	size_t data_sz;
	uint64_t r;

	if(cpid == 0x8015) {
		exec_cmd.magic = EXEC_MAGIC;
		exec_cmd.func = 0x10000F804;	//STR X1, [X0]; RET;
		exec_cmd.x[0] = 0x2352BC000;	//write where?
		exec_cmd.x[1] = 0x2200000000000207;	//write what!
		exec_cmd.x[2] = 0;
		exec_cmd.x[3] = 0;
		exec_cmd.x[4] = 0;
		exec_cmd.x[5] = 0;
		exec_cmd.x[6] = 0;
		memcpy(data, &exec_cmd, sizeof(exec_cmd) - sizeof(r));
		data_sz = sizeof(exec_cmd) - sizeof(r);
		memcpy(data + data_sz, src, len);
		data_sz += len;
	}
	if(gaster_command(handle, data, data_sz, &response, len + 2 * sizeof(r))) {
		memcpy(&r, response, sizeof(r));
		if(r != DONE_MAGIC) {
			free(response);
			return false;
		}
		memcpy(&r, response + sizeof(r), sizeof(r));
		if((uint32_t)r != 0) {
			free(response);
			return false;
		}
		memcpy(dst, response + 2 * sizeof(r), len);
		free(response);
		return true;
	}
	return false;
}

...
} else if(argc == 2 && strcmp(argv[1], "pwn") == 0) {
		if(gaster_checkm8(&handle)) {
			uint8_t idk[AES_BLOCK_SZ + AES_KEY_SZ_BYTES_256];
			printf("gaster_demote ret = %d\\n", gaster_demote(&handle, idk, idk, sizeof(idk)));
			ret = 0;
		}
...
seo@seos-macbook SSHRD_Script % ./Darwin/irecovery -f sshramdisk/iBSS.img4
[==================================================] 100.0%
seo@seos-macbook Darwin % ./irecovery -s
> 
  • 원했던 예상 결과
seo@seos-macbook Darwin % ./irecovery -s
96ede82803e085b:365

=======================================
::
:: iBoot for d20, Copyright 2007-2020, Apple Inc.
::
::	Remote boot, Board 0xa (d201ap)/Rev 0xf
::
::	BUILD_TAG: iBoot-6723.80.19
::
::	BUILD_STYLE: RELEASE
...

생각 정리

  • 일반 케이블과 DCSD/JTAG 케이블을 매번 분리해서 사용하는데 있어서 커널 디버깅은 비효율적.
    • 유저환경에서 램디스크 모드에서 익스플로잇 프로그램을 실행시킬려면 일반 케이블로 연결해서 쉘 명령어를 입력해야할텐데, 커널 디버깅을 할려면 다시 DCSD/JTAG 케이블로 연결시켜야되니 불편함.
  • iOS 12.x~14.x는 KTRW로 아이폰8 커널 디버깅
  • QEMUAppleSilicon으로 가상 아이폰11 iOS 14.0b5 커널 디버깅도 가능
  • iOS 15.x+의 경우, macOS 12.0.1+로 대체하여 커널 디버깅 – super-tart로 라이브 커널 디버깅하는 방법이 좋을듯 (macOS 12.0.1+)