Играем с огнем: запускаем произвольный код на девелоперском iPhone 7
Под Новый год к нам в руки попал программатор JC PCIE-7. В процессе использования выяснилось, что его функционал ограничен, однако вещица оказалась с двойным дном. Внутри этого программатора мы обнаружили плату iPhone 7 специальной отладочной версии. За новогодними приключениями в мире исследования и отладки «яблочной» продукции — добро пожаловать под кат!
Наверное, только совсем ленивые исследователи безопасности не пощупали своими руками возможности, предоставляемые checkm8 и основанном на нем checkra1n (классный обзор checkm8 был недавно на Хабре). Конечно, мы тоже протестировали наши смартфоны и в процессе решили посмотреть, что есть полезного для исследователей на китайском рынке «железных» поделок. Интересный факт: если хочешь протестировать на безопасность какое-либо устройство, то на AliExpress уже есть для этого свои игрушки.
Наша игрушка пришла под самый Новый год — программатор JC PCIE-7, который легко найти на AliExpress:
Мы предполагали, что с помощью этого программатора сможем сделать бэкап флеш-памяти iPhone. Но при эксплуатации обнаружилось, что такой функции в программе просто нет! Да, программатор умеет читать и записывать конфигурацию во флеш-память и привязывать ее к телефону, но чтение произвольных блоков не поддерживается. Затем мы заметили необычные строки в консольном окне управляющей программы, похожие на журнал загрузки операционной системы:
Кадр момента загрузки из обучающего видео
Наконец, мы обратили внимание на функцию подключения программатора к компьютеру по протоколу DFU. В этом режиме программатор корректно определялся в iTunes как iPhone. Мы решили разобрать устройство и посмотреть, что же находится внутри и как происходит эмуляция режима DFU.
Внутри программатора установлены три платы:
- управляющая плата на базе STM32F103;
- плата-мультиплексор с напаянным чипом NVMe и колодкой;
- и, неожиданно, плата iPhone 7.
Оказалось, что программатор переключает мультиплексор таким образом, что сначала плата iPhone загружается с напаянной флеш-памяти, а затем к ней подключается чип NVMe, который нужно прошить. Управление выполняется по виртуальному COM-порту, причем сначала передаются команды переключения чипов NVMe, а затем плата пробрасывает отладочную консоль iPhone, имитируя DCSD-кабель. Внимательно просмотрев отправляемые в COM-порт команды, мы увидели строчки:
setenv diags-path /AppleInternal/Diags/bin/diag.img4
diags
Уже на этом моменте мы поняли, что плата iPhone 7 не совсем обычная (в ней, как минимум, есть папка AppleInternal). Чтобы посмотреть, как она себя ведет в более привычном «окружении», мы переставили плату и NVMe чип в донорский телефон:
Помимо шестеренки при загрузке, в отладочной консоли мы увидели строчку BUILD_STYLE: DEVELOPMENT:
После окончательной загрузки (с помощью упомянутых ранее команд diags) мы получили фиолетовый экран, а уже после нажатия клавиш громкости на экране отобразилось следующее меню:
То есть собранное нами устройство оказалось специальной версией iPhone для тестирования и разработки! К слову, подобные телефоны скупаются исследователями и даже коллекционерами — вот это настоящий подарок в нашу техническую коллекцию! В полноценном девелоперском iPhone установлена специальная сборка iOS с рутовой консолью, значительно облегчающая исследование телефона и поиск уязвимостей:
В нашем случае на телефоне установлена только диагностическая утилита, основное взаимодействие с которой осуществляется через отладочную консоль:
=======================================
::
:: iBoot for d10, Copyright 2007-2016, Apple Inc.
::
:: Local boot, Board 0x8 (d10ap)/Rev 0xd
::
:: BUILD_TAG: iBoot-3406.1.53.1.4
::
:: BUILD_STYLE: DEVELOPMENT
::
:: USB_SERIAL_NUMBER: CPID:8010 CPRV:11 CPFM:03 SCEP:01 BDID:08 ECID:000114422885E526 IBFL:3D
::
=======================================
Boot Failure Count: 0 Panic Fail Count: 0
Entering recovery mode, starting command prompt
] setenv diags-path /AppleInternal/Diags/bin/diag.img4
] diags
Unable to load image type 64696167 from flashnx_mount:432: reloading after unclean unmount, checkpoint xid 112, superblock xid 11
jumping into image at 0x810000000
pinot_quiesce()
mipi_dsim_quiesce()
Console router buffer allocated @ 0x87CB84018, size = 262144 bytes
WHO_AM_I doesn't match MPU6700's Chip ID! Expected 0x90 got 0x0
Carbon: MPU6900 is found.
Carbon: MPU6900 (south) detected
Carbon: MPU6900 (south) selected
MPU6900 not found. Expected 0x10, found 0x0
Carbon: MPU6900 (north) not detected
Phosphorous: BMP284 is found.
mcc-supported : 1
Phosphorous: BMP282 is not found on SPI 4. Expected 0x58, found 0x0
time-train: 26719 uS
Link 0 speed negotiate to 3
Link 0 width negotiate to 1
APCIE power on completed
Device 00:00:0 config space@0x610000000
Vendor:106B Device:1007 Revision:01 ClassCode:060400 Type:01
PriBus:00 SecBus:01 SubBus:01
Capability 0x01 Offset:0x40 Address:0x610000040
Capability 0x05 Offset:0x50 Address:0x610000050
Capability 0x10 Offset:0x70 Address:0x610000070
Extended Capability 0x0001 Ver:0x02 Offset:0x0100 Address:0x610000100
Extended Capability 0x0019 Ver:0x01 Offset:0x0148 Address:0x610000148
Extended Capability 0x001E Ver:0x01 Offset:0x0160 Address:0x610000160
Found device id 0x2002
Device 01:00:0 config space@0x610100000
Vendor:106B Device:2002 Revision:11 ClassCode:018002 Type:00
BAR0 MEM C0000000/00004000
BAR1 IO 00000000/00000004
Capability 0x01 Offset:0x40 Address:0x610100040
Capability 0x05 Offset:0x50 Address:0x610100050
Capability 0x10 Offset:0x70 Address:0x610100070
Extended Capability 0x0001 Ver:0x02 Offset:0x0100 Address:0x610100100
Extended Capability 0x0002 Ver:0x01 Offset:0x0148 Address:0x610100148
Extended Capability 0x0019 Ver:0x01 Offset:0x0168 Address:0x610100168
Extended Capability 0x0018 Ver:0x01 Offset:0x0178 Address:0x610100178
Extended Capability 0x001E Ver:0x01 Offset:0x0180 Address:0x610100180
APCIE Enumerate on completed
ICE BB not supported on this platform
D10 Diag (factory_d10_pvt)
BuildEng build D10Casaval24C302an (24C302an). Revision 6040f18.
Built at 2016/08/20 15:57:53
script: device -k ThermalSensor -e sochot 0 on 120
script: device -k ThermalSensor -e sochot 1 on 125
script: cbcolor
Setting Screen Color based on iPX Control Bits:
script: alias vbat=pmuadc --sel tigris --read vbat
script --cont startup.txt
script: alias bbon="meta 'baseband --on --load_firmware; baseband --wait_for_ready --ping'"
script: alias bbonbypass="meta 'baseband --on --load_firmware; baseband --wait_for_ready --ping --bypass en'"
script: alias bboff=baseband --off
script: alias getcd=bblib -e BB_GetCD()
script: alias erase_rfcal=smokey Tools/RFCalErase --run
script: alias erase_efs=smokey Tools/EFSErase --run
script: alias erase_pac=smokey Tools/RFPacErase --run
script: alias hdq_en=i2c --devwrite 1 0x75 0x1D 1
script: alias hdq_dis=i2c --devwrite 1 0x75 0x1D 0
script: alias bblib="smokeyshell -p -e 'if BBLib_cfg then print [[no init]] else require [[BBLib.14A]];BB_Init() end'"
script: alias wcs=smokey --run WCS --clean LogBehavior=ConsoleOnly
script: alias bblibcfg=bblib -e printLibCfg()
script: alias bbdebug="meta 'base --debug on;ramlog --on 10;consolerouter --add -s *.{warn,error,print},system.debug.debug -d ramlog --quiet;consoleformat --en --sink serial -o ts'"
script: alias gpsdebug="meta 'ramlog --on 10;consolerouter --add -s gps.debug.* -d ramlog'"
script: alias updateroot="meta 'usbfs --mount;cp -r usbfs:\AppleInternal nandfs:\;usbfs --unmount;smokeyshell -r'"
[00011442:2885E526] :-) help
DiagShell builtin commands:
"time" time
"echo" echo
"waitfor" waitfor
"repeat" repeat
"alias" alias [[=]]
"unalias" unalias
"true" true
"false" false
"args" args
"shopt" shopt
EDK Boot Loader commands (help for more info):
"accessory" Command to change power settings as well as identifying accessories connected to the unit
"aes" Command for AES encryption/decryption
"amux" Analog Mux selection command
"audio" General command to hande resetting/blanking/scripting of the audio subsystem
"audioparam" Audio parameter retrieval/setting utility
"audioreg" Manages register operations on audio blocks in the system
"barcode" Show S/N and ECID barcode
"baseband" Command to control/test baseband functionality
"battery" Command to display basic information about the battery
"baud" : Set UART Baud rate
"bl" BackLight Test
"blockdevice" Show information about boot devices. Bare quantities are in bytes.
"bluetooth" Command to control/test bluetooth functionality
"boardid" Get the board ID
"boardrev" Get the board revision
"bonfire" Run Bonfire
"bootcfg" Get the boot configuration
"buckcheck" Buck voltage check
"button" Test individual buttons on the unit
"buttoncnt" [--dqe] Count button presses on the unit
"camisp" camera command that can run in seperat steps.
"cat" Print the contents of a file.
"cbcolor" iPX Control Bit - Set screen color based on number of passed stations
"cbdump" iPX Control Bit - Dump the CB area from the NAND
"cberase" iPX Control Bit - Erase a control bit
"cbinit" iPX Control Bit - Initialize control bit area
"cbread" iPX Control Bit Read
"cbreadall" iPX Control Bit - read all
"cbwrite" iPX Control Bit Write
"charge" Charge controls for system
"chipid" Show ChipID
"clkmon" [signal/off]; Set Clock Test out pin to specified signal or switch it off
"consoleformat" Command to control the formatting of text display on serial output mediums like the console
"consolerouter" Main command that deals with all things console in the system
"consolesinkctrl" Manage the console sink controls
"cp" cp [-r]
Как можно видеть, функционал отладочной программы немаленький. Предназначена она в первую очередь для тестирования оборудования — большинство команд отвечают за тестирование различных аппаратных подсистем устройства. Наиболее полезными для нас оказались команды directory, memrw, memory и cat.
Выполнив команду directory, можно ознакомиться с содержимым файловой системы:
[00011442:2885E526] :-) dir fs0:
--------- 2016-08-29 07:01 AppleInternal
--------- 2016-09-22 11:27 System
--------- 2016-09-22 11:29 private
--------- 2016-09-22 11:28 usr
Выполнив команду cat -h, можно прочитать любой файл:
[00011442:2885E526] :-) cat -h
fs0:\AppleInternal\Diags\Logs\Smokey\Shared\ComponentLib\HallSensor\11A\HallSensor.lua
00000000: 2D 2D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D |--==============|
00000010: 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D |================|
00000020: 3D 3D 3D 3D 3D 3D 3D 3D 3D 0A 2D 2D 20 46 69 6C |=========.-- Fil|
00000030: 65 6E 61 6D 65 3A 20 20 48 61 6C 6C 53 65 6E 73 |ename: HallSens|
00000040: 6F 72 2E 6C 75 61 0A 2D 2D 20 44 65 73 63 72 69 |or.lua.-- Descri|
00000050: 70 74 69 6F 6E 3A 20 48 61 6C 6C 53 65 6E 73 6F |ption: HallSenso|
00000060: 72 20 74 65 73 74 20 66 69 6C 65 0A 2D 2D 3D 3D |r test file.--==|
00000070: 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D |================|
00000080: 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D |================|
00000090: 3D 3D 3D 3D 3D 0A 0A 72 65 71 75 69 72 65 20 22 |=====..require "|
000000A0: 43 6F 6D 70 6F 6E 65 6E 74 4C 69 62 2E 43 6F 6D |ComponentLib.Com|
000000B0: 6D 6F 6E 2E 31 31 41 22 0A 0A 6C 6F 63 61 6C 20 |mon.11A"..local |
000000C0: 43 4F 4D 50 4F 4E 45 4E 54 5F 4E 41 4D 45 20 3D |COMPONENT_NAME =|
000000D0: 20 22 48 61 6C 6C 53 65 6E 73 6F 72 22 0A 0A 2D | "HallSensor"..-|
000000E0: 2D 20 48 61 6C 6C 73 65 6E 73 6F 72 20 74 65 73 |- Hallsensor tes|
000000F0: 74 0A 66 75 6E 63 74 69 6F 6E 20 48 61 6C 6C 53 |t.function HallS|
00000100: 65 6E 73 6F 72 54 65 73 74 73 28 29 0A 09 53 51 |ensorTests()..SQ|
00000110: 41 5F 53 68 65 6C 6C 28 22 68 61 6C 6C 73 65 6E |A_Shell("hallsen|
00000120: 73 6F 72 20 2D 2D 6D 65 61 73 20 22 2E 2E 48 41 |sor --meas "..HA|
00000130: 4C 4C 5F 53 45 4E 53 4F 52 5F 4D 45 41 53 2E 2E |LL_SENSOR_MEAS..|
00000140: 22 20 2D 2D 64 65 6C 61 79 20 22 2E 2E 48 41 4C |" --delay "..HAL|
00000150: 4C 5F 53 45 4E 53 4F 52 5F 44 4C 59 29 0A 09 53 |L_SENSOR_DLY)..S|
00000160: 51 41 5F 53 68 65 6C 6C 28 22 68 61 6C 6C 73 65 |QA_Shell("hallse|
00000170: 6E 73 6F 72 20 2D 2D 69 72 71 69 6E 64 65 78 20 |nsor --irqindex |
00000180: 22 2E 2E 48 41 4C 4C 5F 53 45 4E 53 4F 52 5F 49 |"..HALL_SENSOR_I|
00000190: 52 51 5F 49 4E 44 45 58 29 0A 09 53 51 41 5F 53 |RQ_INDEX)..SQA_S|
000001A0: 68 65 6C 6C 28 22 68 61 6C 6C 73 65 6E 73 6F 72 |hell("hallsensor|
000001B0: 20 2D 2D 6F 66 66 20 20 22 29 0A 65 6E 64 0A 0A | --off ").end..|
Комбинируя эти две команды, мы считали все файлы с устройства (почти 150 МБ):
Среди файлов нашлась «пасхалка», рекомендующая не шутить с Iphone7 огнем:
Выполнив команду memory -dump, можно читать диапазоны ОЗУ:
[00011442:2885E526] :-) memory --dump 0x800000000 0x100
0: 30 83 43 5B 39 16 04 49 4D 47 34 30 83 43 40 14 0.C[9..IMG40.C@
10: 16 04 49 4D 34 50 16 04 64 69 61 67 16 01 31 04 .C@..".X..@.?..
20: 83 43 40 00 80 22 00 58 01 04 40 F9 3F 00 00 F1 ..T?...@..T...
30: 20 05 00 54 3F 04 00 F1 40 00 00 54 FA 01 00 14 ....B...B...B.t
40: 02 00 80 D2 42 00 00 91 42 08 00 91 42 CC 74 D3 B...B.l.B.B.Bp.
50: 42 08 04 91 42 AC 6C D3 42 C0 42 91 42 70 00 91 _...!..R....c..
60: 5F 00 00 B9 21 00 80 52 03 00 80 D2 63 00 00 91 c...c.t.c...c.l
70: 63 08 00 91 63 CC 74 D3 63 08 04 91 63 AC 6C D3 c.B.cP..a......
80: 63 C0 42 91 63 50 00 91 61 00 00 B9 03 00 80 D2 c...c...c.t.c..
90: 63 00 00 91 63 08 00 91 63 CC 74 D3 63 08 04 91 c.l.c.B.c@.....
A0: 63 AC 6C D3 63 C0 42 91 63 40 00 91 7F 00 00 B9 ...RA..........
B0: 81 00 80 52 41 00 00 B9 7F 00 00 B9 00 00 00 14 @..............
C0: 40 03 00 00 00 00 00 00 B0 03 00 00 00 00 00 00 . ...O...?.....
D0: 1F 20 03 D5 DF 4F 03 D5 DF 3F 03 D5 1F 87 08 D5 .?.. .;.!.....!
E0: 9F 3F 03 D5 20 E2 3B D5 21 00 80 D2 00 00 21 8A .......a...<.@
F0: 20 E2 1B D5 9B F9 FF 10 61 06 00 10 3C 00 40 F9 z...Y.@........
Наконец, с помощью команды memrw можно перезаписывать ОЗУ:
[00011442:2885E526] :-) memrw 0x800000000 0x12345678abcdef
0x800000000: 0x12345678ABCDEF
OK
[00011442:2885E526] :-) memory --dump 0x800000000 0x10
0: EF CD AB 78 56 34 12 00 4D 47 34 30 83 43 40 14 ...xV4..MG40.C@
Несмотря на то, что чтение памяти это уже в меру полезный функционал, мы решили проверить: можно ли перезаписать области исполняемого кода и запустить что-то свое? Ведь iPhone девелоперский, а функционал пока что пользовательский — так не пойдет!
Стандартными способами сделать это не удалось, возникала ошибка с достаточно подробным трейс-логом:
[00011442:2885E526] :-) memrw 0x87BF68AA0 0
panic: unhandled exception: 0
x0: 0x00000000 x1: 0x0000000A x2: 0x00000000 x3: 0x87BF68AA0
x4: 0x00000002 x5: 0x00000003 x6: 0x879D52218 x7: 0x00000003
x8: 0x87BF68E30 x9: 0x87BF6908C x10: 0x00000000 x11: 0x000000E0
x12: 0x000000E0 x13: 0x00000001 x14: 0x00000001 x15: 0x00000000
x16: 0x000000FF x17: 0x00000001 x18: 0x810000308 x19: 0x879D52228
x20: 0x00000008 x21: 0x00000000 x22: 0x87BF68AA0 x23: 0x00000007
x24: 0x00000001 x25: 0x87BF68AA0 x26: 0x00000000 x27: 0x00000002
x28: 0x87CA42332 fp: 0x87FBEFC20 lr: 0x87BF68D3C sp: 0x00000000
PC: 0x87BF68E30
SPSR: 0x80000005
ESR: 0x9600004F
FAR: 0x87BF68AA0
EC:0x25 - "Data Abort caused by current EL"
ISS:0x4F - "Permission Fault Level 3"
Memory Access Fault - write to read-only or unmapped address.
FAR contains target address.
0x87BF68AA0: /Users/build/archive/casaval_d10_202/src/shasta/BuildResults/D10diag/release/diag/TestDirectMemoryRW.macho + <0x4AA0> : text section
stack buffer at 0x87FBEEED0
printing callstack: 15 frames unrolled.
#0 0x87BF68E30
TestDirectMemoryRW.macho @ offset 0x4E30
#1 0x87BF68D38
TestDirectMemoryRW.macho @ offset 0x4D38
#2 0x87BF69620
TestDirectMemoryRW.macho @ offset 0x5620
#3 0x879B2C1D0
DiagShell.macho @ offset 0x41D0
#4 0x879B2C7F0
DiagShell.macho @ offset 0x47F0
#5 0x879B2D11C
DiagShell.macho @ offset 0x511C
#6 0x87FB75494
DxeMain.macho @ offset 0xD494
#7 0x87CAD8214
DiagBds.macho @ offset 0x4214
#8 0x87CAD8260
DiagBds.macho @ offset 0x4260
#9 0x87CAD82CC
DiagBds.macho @ offset 0x42CC
#10 0x87FB6C604
DxeMain.macho @ offset 0x4604
#11 0x87FB6C0F0
DxeMain.macho @ offset 0x40F0
#12 0x81034AA04
#13 0x81039C7E4
#14 0x81039C39C
Please report panic using panic.apple.com
hanging here...
В данном случае в трейс-логе сообщается, что при исполнении по адресу 0×87BF68E30 в модуле TestDirectMemoryRW.macho возникло исключение из-за записи в read-only адрес памяти. Но нет преград для технических исследователей под Новый год! Обратим внимание на самый последний вызов в стеке: DxeMain.macho. Присутствие аббревиатуры DXE и строки EDK Boot Loader commands позволяет сделать вывод, что на устройстве запущена EFI-совместимая система. И действительно, образ системы diags.img4 корректно открывается с помощью UEFITool:
Дизассемблирование программных модулей показало, что все исполняемые модули используют соглашения о вызовах EFI и стандартные структуры EDK:
Каждой команде терминала соответствует отдельный EFI-модуль, например, команде memory соответствует модуль TestUtilities.macho, который загружается в ОЗУ по адресу 0×87BE10000 (определено из трейс-лога).
Попробуем модифицировать программный код этого модуля, чтобы исполнить наш код.
По адресу 0×87BE1600D располагается текстовая строка, выводимая по команде memory –info, модифицируем ее:
[00011442:2885E526] :-) memory --info
Total Memory: 0x80000000, free: 0x79B48000, fragmented: 0x10028000, frags: 5, in use: 0x64B8000
[00011442:2885E526] :-) memory --dump 0x87BE1600D 0x30
7BE1600D: 54 6F 74 61 6C 20 4D 65 6D 6F 72 79 3A 20 30 78 Total Memory: 0
7BE1601D: 25 78 2C 20 66 72 65 65 3A 20 30 78 25 6C 78 2C fragmented: 0x
7BE1602D: 20 66 72 61 67 6D 65 6E 74 65 64 3A 20 30 78 25 x, frags: %d, i
Чтобы модифицировать нужную нам область памяти, требуется изменить права доступа на страницу по адресу 0×87BE14000 с read-only/execute на read/write/execute. Согласно документации AArch64, за права доступа отвечает специальная таблица трансляции. Таблица должна располагаться в ОЗУ и состоять из записей по 8 байт следующего формата:
Таблица трансляции второго уровня была обнаружена по адресу 0×87FBF4000, в диапазоне памяти, доступном для перезаписи. На этом уровне каждая запись соответствует 32 МБ (0×2000000) адресного пространства, поэтому нужная нам запись для диапазона 0×87A000000–0×87BFFFFFF находится по адресу 0×87FBF4000 + (0×87A000000 / 0×2000000) * 8 = 0×87FBF61E8:
[00011442:2885E526] :-) memory --dump 0x87FBF61E8 0x8
7FBF61E8: 03 C0 CE 7F 08 00 00 00
Запись имеет тип table, то есть указывает на таблицу трансляции третьего уровня по адресу 0×87FCEC000. В этой таблице каждая запись соответствует одной 16 Кб (0×4000) странице адресного пространства и имеет тип block. Нужная нам запись для страницы 0×87BE14000 находится по адресу 0×87FCEC000 + (0×87BE14000 — 0×87A000000) / 0×4000 * 8 = 0×87FCEFC28:
[00011442:2885E526] :-) memory --dump 0x87FCEFC28 8
7FCEFC28: AB 47 E1 7B 08 00 00 00 .G.{....+..{..`
Поскольку эта запись имеет тип block, она указывает на физическую страницу памяти и содержит атрибуты доступа. Нас интересует Lower block attributes, а именно поле Data Access Permissions bits:
Чтобы разрешить запись в страницу, устанавливаем значение этого поля в 0:
[00011442:2885E526] :-) memrw 0x87FCEFC28 --64 0x000000087BE1472B
0x87FCEFC28: 0x87BE1472B
OK
После этого у нас должен появиться доступ на запись для нужной области. После внесения требуемых изменений получаем желаемый результат:
[00011442:2885E526] :-) memrw 0x87BE16008 0x6C6548000A535341
0x87BE16008: 0x6C6548000A535341
OK
[00011442:2885E526] :-) memrw 0x87BE16010 0x0072626148206F6C
0x87BE16010: 0x72626148206F6C
OK
[00011442:2885E526] :-) memory --info
Hello Habr
The moral: с помощью описанного метода мы можем модифицировать любые системные приложения и исполнять произвольный код в среде UEFI на девелоперском iPhone.
Практической ценности для старых версий iPhone данное исследование не несет, но было весело разобраться в чем-то неизведанном и редком, особенно когда оно неожиданно появилось как подарок на Новый год.
P.S. А вот для исследования последних версий iPhone и получения SecureROM может пригодиться описанный метод: уязвимость checkm8 в них исправлена, а подобные «программаторы» на AliExpress на базе iPhone XR и iPhone 11 уже продаются.
Raccoon Security — специальная команда экспертов НТЦ «Вулкан» в области практической информационной безопасности, криптографии, схемотехники, обратной разработки и создания низкоуровневого программного обеспечения.