Краткий обзор
На первый взгляд ПО приставки является клоном Android. Доступ по ssh закрыт. Работает только с действующим абонементом от дистрибьютора. Стоковая прошивка полностью шифрована. Всё глухо, как в танке.
Подготовка
Первым делом я подробно ознакомился с техническим описанием процессора. Порадовали меня две вещи: у процессора был интерфейс UART и он поддерживал загрузку системы с разных источников (USB, SD и т.д.), которая могла настраиваться с наружи при помощи конфигурационного регистра. На борту приставки также имелось место для mSD карты, но разьём был не припаян. Для того, чтобы найти пятачки конфигурационного регистра и пины UART мне пришлось спаять процессор и прозвонить дорожки. Когда все контакты были найдены я подключил адаптер UART и запустил приставку. На экрана высветился U-Boot. Загрузка системы прерывалась нажатием клавиш и U-Boot выходил в режим ввода, но ни на какие клавиши, кроме enter никак не реагировал. И эта лазейка тоже была закрыта.
QA5:A;SVN:B72;POC:17F;STS:0;BOOT:0;INIT:0;READ:0;CHECK:0;PASS:0; no sdio debug board detected TE : 1583722 BT : 19:30:15 Apr 13 2015 PMU:NONE ##### VDDEE voltage = 0x044c CPU clock is 792MHz DDR mode: 32 bit mode DDR size: 1GB DDR check: Pass! DDR clock: 792MHz with 2T mode DDR pll bypass: Disabled DDR init use : 13644 us HHH Boot From SDIO C SD_boot_type: 00000002 card_type: 00000003 0x0000009f Aml log : M8-R2048 TPL pass! ucl decompress...pass 0x12345678 Boot from internal device 1st tSD/fSD on SDIO C TE : 1867612 System Started ==================COMIGO BOOTLOADER================== ==========12fc92:S:Enc (Apr 13 2015 - 19:29:55)========== clr h-ram DRAM: 1 GiB relocation Offset is: 2febc000 show partition table: part: 0, name : logo, size : 800000 part: 1, name : recovery_bak, size : 1000000 part: 2, name : recovery, size : 1000000 part: 3, name : boot, size : 1000000 part: 4, name : system, size : 32000000 part: 5, name : data, size : 8c000000 part: 6, name : cache, size : 20800000 part: 7, name : sec_gpt, size : end aml_card_type=0x100 MMC: out reg=c1108058,value=fffcf800 out reg=c1108058,value=fffcfa00 [mmc_register] add mmc dev_num=0, port=1, if_type=6 [mmc_register] add mmc dev_num=1, port=2, if_type=6 SDIO Port B: 0, SDIO Port C: 1 power init out reg=c110804c,value=dfffffff IR init done! register usb cfg[0][1] = 3ff6fcf4 register usb cfg[2][0] = 3ff72a6c NAND: EMMC BOOT: not init nand do not init nand : cause boot_device_flag without nand get_boot_device_flag: init_ret -1 get_boot_device_flag EMMC BOOT: init_part Emmckey: Access range is illegal! Emmckey: Access range is illegal! Unknown partition type on device 'SDIO Port C' Device 'SDIO Port C' wp size=8388608 port=2 [mmc_init] SDIO Port C:1, if_type=6, initialized OK! mmc_device_init mmc_get_partition_table Start mmc_get_partition_table Partition table get from SPL is : name offset size flag =================================================================================== 0: pri_gpt 0 800000 0 1: env 800000 800000 0 2: reserved 1000000 4000000 0 3: logo 5000000 800000 1 4: recovery_bak 5800000 1000000 1 5: recovery 6800000 1000000 1 6: boot 7800000 1000000 1 7: system 8800000 32000000 1 8: data 3a800000 8c000000 4 9: cache c6800000 20800000 2 10: sec_gpt eb800000 800000 0 mmc read lba=0x8000, blocks=0x1 mmc read lba=0x8001, blocks=0x1 mmc_read_partition_tbl: mmc read partition OK! eMMC/TSD partition table have been checked OK! i=0,register --- emmc_key MMC BOOT, emmc_env_relocate_spec : env_relocate_spec 59 set_storage_device_flag: store 2 [imgread]Secure kernel sz 0x5b36a0 Aml log : M8-R2048 IMG pass! vpu clk_level in dts: 3 set vpu clk: 182150000Hz, readback: 182150000Hz(0x701) Net: Meson_Ethernet init suspend firmware done. (ret:0) cvbs trimming.1.v5: 0xa0, 0x0 upgrade_comigo_environment: expect 6 active 6 init_comigo_environment type:flash,start to read mac... device init start aml_keys: version 0 can not be init 3ff72c68 current storer:emmc_key flash init key ok!! init flash success all key names list are(ret=18): uuid serialno mac 4:3:3:0:3:a:4:2:3:3:3:a:3:3:3:9:3:a:3:0:3:2:3:a:3:1:4:6:3:a:3:4:3:9: mac is: 43:30:3a:42:33:3a:33:39:3a:30:32:3a:31:46:3a:34:39: read ok!! read mac success,mac=C0:B3:39:02:1F:49 androidboot.mac is exist in bootargs, mac=C0:B3:39:02:1F:49 androidboot.serialno=A0652602C5706198 androidboot.uuid=4a3842462f47694d364b6f544d3236596b34374e3977 BOARD VERSION=2 reboot_mode=charging hdcp get form storage medium: auto don't found keyname,uboot_key_read:1634 prefetch hdcp keys from auto failed AKSV invalid hdmi tx power init mode = 6 vic = 4 set HDMI vic: 4 mode is: 6 viu chan = 1 config HPLL config HPLL done reconfig packet setting done key save in emmc key size=44 the key name is : the key data is :4a3842462f47694d364b6f544d3236596b34374e3977 key size=32 the key name is :serialno the key data is :41303635323630324335373036313938 A0652602C5706198 efuse version is not selected. Hit ENTER key to stop autoboot: 1 tstc enter exit abortboot: 1 COMIGO#
С оригинальным U-Boot’ом на этом этапе сделать ничего было нельзя и я решил проверить загрузку с mSD карты. Для этого я припаял разьём и соединил пару контактов конфигурационного регистра с массой, чтобы процессор грузил систему с карты. Новый U-Boot был от экспериментального борта ODROID-C, который базировался на таком же процессоре.


Собрав всё это, я вставил SD карту, включил приставку и… увидел такое:
SERIAL:4;STS:0;BOOT:1;INIT:0;READ:0;CHECK:FFFFBF00;USB:3;
И этот текст повторялся каждую секунду вновь и вновь. Процессор вовсе и не собирался грузить мой U-Boot и это меня огорчило.
Поиск причины
Мне стало ясно, что в процессоре был активирован secured boot и он проверял код на подлинность прежде чем его запускать. Параметр CHECK:FFFFBF00 указывал на то, что код, загруженый с mSD карты более чем полностью по каким-то причинам не устраивал процессора. Для сравнения, загрузка оригинала начиналась в свою очередь так:
QA5:A;SVN:B72;POC:17F;STS:0;BOOT:0;INIT:0;READ:0;CHECK:0;PASS:0;
Что же проверял процессор? Этот ответ я надеялся найти в сурсах U-Boot’а для AMLogic. После недолгих поисков, я увидел, что SPL часть от U-Boot’a заканчивается вот такой структурой
typedef struct { unsigned int nSizeH; ///4@0 struct st_secure{ unsigned int nORGFileLen; ///4@4 unsigned int nSkippedLen; ///4@8 unsigned int nHASHLength; ///4@12 unsigned int nAESLength; ///4@16 unsigned char szHashKey[32];//32@20 unsigned char szTmCreate[24]; //24@52 unsigned char szReserved[60]; //60@76 }secure; //136@136 unsigned char szAES_Key_IMG[60];//60@136 unsigned char szTmCreate[48]; //48@196 unsigned int nSizeT; ///4@244 unsigned int nVer; ///4@248 unsigned int unAMLID; ///4@252 }st_aml_chk_blk; //256
Небольшое отступление. Двухступенчатая загрузка системы очень часто применяется на встроенном оборудовании. Т.е. ROM процессора грузит сначала небольшую часть кода (так называемый SPL) и передаёт ему управление. Тот в свою очередь после основных настроек грузит вторую, большую часть (TPL) и передаёт ей управление. Ну а TPL после окончательных настроек грузит ядро и запускает его.
Забегая немного вперёд, скажу, что сам SPL состоит из 32 КБ, в конце которого находится структура st_aml_chk_blk, которая в расшифрованом виде выглядит вот так:

Стало быть этот блок данных процессор использует для проверки SPL.
В поисках решения
Чтобы заставить процессор загрузить мой U-Boot, я испробовал множество вариантов. Но все они не приносили желаемого результата — процессор упорно выдавал CHECK:FFFFBF00. Я постепенно приходил к выводу, что защита сделана на 100% и дыр нет.
После очередной неудачной попытки я оставил приставку и пошёл на кухню (за чаем, конечно), раздумывая подключать JTAG, а когда вернулся, меня ждал вот такой результат:
SERIAL:4;STS:0;BOOT:1;INIT:0;READ:0;CHECK:FFFFBF00;USB:3;SERIAL:4;STS:0;BOOT:1;INIT:0;READ:0;CHECK:FFFFBF00;USB:3;SERIAL:4;STS:0;BOOT:1;INIT:0;READ:0;CHECK:FFFFBF00;USB:3;SERIAL:4;STS:0;BOOT:1;INIT:0;READ:0;CHECK:FFFFBF00;USB:3;SERIAL:4;STS:0;BOOT:1;INIT:0;READ:0;CHECK:FFFFBF00;USB:3;SERIAL:4;STS:0;BOOT:1;INIT:0;READ:0;CHECK:FFFFBF00;USB:3;SERIAL:4;STS:0;BOOT:1;INIT:0;READ:0;CHECK:0;PASS:1; ----------------------------------------------------------------------- * Welcome to Hardkernel's ODROID-C... (Built at 19:33:00 Dec 8 2014) * ----------------------------------------------------------------------- CPU : AMLogic S805 MEM : 1024MB (DDR3@792MHz) BID : <Unknown> S/N : ***** Warning!! ***************************************************** * This board have not been autorized or product keys are not valid. * * Please contact with Hardkernel or your distributor * *********************************************************************
О как! После некоторого времени (это было примерно секунд 40) процессор выдавал CHECK:0;PASS:1; и грузил мой U-Boot. Он конечно зависал потом, но это не имело значения, доступ к системе был получен.
Анализ
Первым делом я написал программу, которая сделала дамп ROM’а процессора и фьюза (это такой участок памяти в процессоре, который может быть прошит только один раз. Здесь как раз и хранятся ключи AES, public RSA и некоторые конфигурации процессора). Заполучив таким образом ключ AES я расшифровал оригинальный U-Boot и проанализировал ROM. Принцип загрузки SPL был таков: ROM первым делом считывал конфигурацию из фьюза и сохранял её как переменную. Далее он грузил 32 КБ с флэшки в память и смотрел, что показывала конфигурация на предмет проверки сигнатуры и шифрования. В нашем случае ROM затем вычитывал экспоненту e и модуль N из фьюза, собирал PublicKey(e,N) с которым он расшифровывал st_aml_chk_blk, затем вырешивал sha2 от SPL без st_aml_chk_blk и сравнивал то что получилось с ключом из st_aml_chk_blk. И в случае несовпадения дальнейших действий не предпринимал. Так что же заставило процессор выполнить мой SPL? Сигнатура ведь по-любому не совпадала…
Для поддержки RSA в ROM была включена (с большой вероятностью) библиотека PolarSSL (разобрав ROM я нашёл параллели к сурсам этой библиотеке). ROM управлял свободной памятью используя собственный механизм (примерно как malloc и memfree). Перед использованием функций из библиотеки PolarSSL ROM выделял ей определенный кусок памяти, но в некоторых случаях не всегда освобождал его. Например тогда, когда функция RSA отваливалась из-за невозможности расшифровать инвалидный блок, который я использовал в своём SPL в этой попытке. Что же получалось? ROM выделял память, пробовал расшифровать мою поддельную сигнатуру, забывал освободить память, выдавал ошибку CHECK:FFFFBF00 и цикл повторялся. В один прекрасный момент очередной кусок новой памяти затирал переменную из фьюза, которую ROM сохранял в самом начале. В следующем цикле в этой переменной уже было значение 0, что значило: просто грузи всё что есть и запускай.
Дальше в принципе не было ничего интересного. Я переделал оригинальный U-Boot, убрал проверку TPL, ядра и вернул ему обратно дар речи, чтобы он реагировал на команды. Расшифровав ядро и собрав минималку на BusyBox я запустил линукс из переделанного U-Boot’а, который начинал грузиться через 40 секунд.
ссылка на оригинал статьи https://habr.com/ru/post/487086/
Добавить комментарий