Исследуем обфускацию прошивки Linksys WRT120N

от автора

Недавно мое внимание привлек факт, что в обновлениях прошивок для Linksys WRT120N используют какую-то обфускацию. Мне показалось, что будет интересно порыться в ней, и я решил взглянуть.

Последняя версия прошивки не выглядит как прошивка, с которой можно сразу работать
image

Как вы можете видеть, есть небольшой блок данных, сжатых LZMA — это просто HTML-файлы для веб-интерфейса роутера. Большая часть прошивки состоит из каких-то странных, случайных данных. Т.к. мне больше ничего с ней не сделать, а любопытство все сильнее пыталось одолеть меня, я купил эту модель роутера себе (как они стоимость Amazon Prime-то взвинтили!).

Анализ железа

При первом же взгляде на железо стало видно, что WRT120N работает на Atheros AR7240 SoC, имеет 2MB SPI флеша, 32MB RAM и что-то похожее на Serial и JTAG-разводку:
image

Для того, чтобы поглубже взглянуть на процесс загрузки, я решил начать с последовательного порта.
image

Я уже ранее рассказывал про последовательные порты, поэтому не буду заострять внимание на методы нахождения пинов и скорости в этой статье. Было легко найти выводы порта с использованием мультиметра и визуального осмотра платы:

    Pin 2 – RX     Pin 3 – TX     Pin 5 – Ground

Порт работает на скорости 115200 бод и выдает интересную загрузочную информацию:

$ sudo miniterm.py /dev/ttyUSB0 115200 --- Miniterm on /dev/ttyUSB0: 115200,8,N,1 --- --- Quit: Ctrl+]  |  Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---    ======================================================================= Wireless Router WG7005G11-LF-88 Loader v0.03 build Feb  5 2009 15:59:08                     Arcadyan Technology Corporation ======================================================================= flash MX25L1605D found.  Copying boot params.....DONE  Press Space Bar 3 times to enter command mode ... Flash Checking  Passed.  Unzipping firmware at 0x80002000 ... [ZIP 3] [ZIP 1]  done In c_entry() function ... install_exception  install exception handler ... install interrupt handler ... ulVal: 0x484fb Set GPIO #11 to OUTPUT Set GPIO #1 to OUTPUT Set GPIO #0 to OUTPUT Set GPIO #6 to INPUT Set GPIO #12 to INPUT Timer 0 is requested ##### _ftext      = 0x80002000 ##### _fdata      = 0x80447420 ##### __bss_start = 0x804D5B04 ##### end         = 0x81869518 ##### Backup Data from 0x80447420 to 0x81871518~0x818FFBFC len 583396 ##### Backup Data completed ##### Backup Data verified [INIT] HardwareStartup .. [INIT] System Log Pool startup ... [INIT] MTinitialize .. CPU Clock 350000000 Hz init_US_counter : time1 = 270713 , time2 = 40272580, diff 40001867 US_counter = 70  cnt1 41254774 cnt2 41256561, diff 1787 Runtime code version: v1.0.04 System startup... [INIT] Memory COLOR 0, 1600000 bytes .. [INIT] Memory COLOR 1, 1048576 bytes .. [INIT] Memory COLOR 2, 2089200 bytes .. [INIT] tcpip_startup .. Data size: 1248266 e89754967e337d9f35e8290e231c9f92 Set flash memory layout to Boot Parameters found !!! Bootcode version: v0.03 Serial number: JUT00L602233 Hardware version: 01A  ... 

Похоже, прошивка сделана компанией Arcadyan, особенно интересно было сообщение ‘Unzipping firmware…’, быстрый гуглёж привел меня к посту про деобфускацию прошивок от Arcadyan, но тут, похоже, применяется немного другой метод.

Через последовательный порт можно только использовать меню загрузчика. Во время загрузки можно в него залезть, если нажать три раза пробел, и выполнить некоторые действия, такие как очистка флеша и установка настроек платы:

Press Space Bar 3 times to enter command mode ...123 Yes, Enter command mode ...   [WG7005G11-LF-88 Boot]:?  ======================  [U] Upload to Flash    [E] Erase Flash        [G] Run Runtime Code   [A] Set MAC Address   [#] Set Serial Number   [V] Set Board Version   [H] Set Options   [P] Print Boot Params   [I] Load ART From TFTP   [1] Set SKU Number   [2] Set PIN Number   ======================

К сожалению, загрузчик не позволял сдампить содержимое RAM или флеша. Хоть на плате и есть JTAG-разводка, я решил сдампить флеш напрямую, т.к. процесс дампа через JTAG, как правило, не быстрый, а подключение SPI очень простое.

Наверное любое устройство, которое поддерживает протокол SPI, может читать флеш. Я использовал кабель FTDI C232HM и программку spiflash.py из состава libmpsse

$ sudo spiflash --read=flash.bin --size=$((0x200000)) --verify FT232H Future Technology Devices International, Ltd initialized at 15000000 hertz Reading 2097152 bytes starting at address 0x0...saved to flash.bin. Verifying...success.

Флеш состоит из трех LZMA-блоков и небольшого количества MIPS-кода, но сама прошивка все еще нехорошая:
image

Два первых LZMA-блока — часть recovery image, а MIPS-код это сам загрузчик. Все остальное место занимает обфусцированный файл прошивки, кроме нулей и каких-то данных в конце.

Анализ загрузчика

Загрузчик, помимо того, что он расшифровывает прошивку и загружает ее по адресу в память, содержит некоторые интересные штучки. Я пропущу скучные вещи, вроде того как я искал адрес загрузки загрузчика, вручную определял функции стандартной библиотеки C, находил таблицу смещения JUMP-ов и т.д., а сразу перейду к интересному.

Сначала, на раннем этапе загрузки, загрузчик проверяет, не нажата ли кнопка reset. Если она нажата, то он загружает образ “Tiny_ETCPIP_Kernel” — маленький recovery image, с веб-интерфейсом.
image

Это хорошая новость. Теперь мы знаем, что если что-то пойдет не так в процессе обновления прошивки, то можно будет нажать reset и оживить устройство.
А есть еще и скрытый режим администратора в меню загрузчика:
image

Нажатие "!" приведет к включению режима администратора, который разблокирует некоторые опции, включая чтение и запись в память.

[WG7005G11-LF-88 Boot]:!  Enter Administrator Mode !  ======================  [U] Upload to Flash    [E] Erase Flash        [G] Run Runtime Code   [M] Upload to Memory   [R] Read from Memory   [W] Write to Memory    [Y] Go to Memory       [A] Set MAC Address   [#] Set Serial Number   [V] Set Board Version   [H] Set Options   [P] Print Boot Params   [I] Load ART From TFTP   [1] Set SKU Number   [2] Set PIN Number   ======================  [WG7005G11-LF-88 Boot]:

Самая интересная часть загрузчика, конечно же, та, которая загружает обфусцированную прошивку в память.

Анализ обфускации

Деобфускация выполняется в функции load_os, которой передается указатель на обфусцированный образ и адрес, куда следует поместить распакованный образ:
image
Сама распаковка не особо сложная:
image

В общем, если прошивка начинается с 04 01 09 20 (а наша именно с этих байт и начинается), то выполняется алгоритм расшифровки, который:

  • Переставляет два 32-байтных блока данных по адресам 0×04 и 0×68
  • Переставляет 4 бита у первых 32 байт, начиная с адреса 0×04
  • Побайтно переставляет смежные 32 байта, начиная с 0×04

После этого всего, данные по адресу 0×04 содержат верный LZMA-заголовок, которые потом разжимаются.

Реализовать утилиту деобфускации было просто, и прошивка WRT120N теперь может быть распакована и разжата.

$ ./wrt120n ./firmware/FW_WRT120N_1.0.07.002_US.bin ./deobfuscated.bin Doing block swap... Doing nibble-swap... Doing byte-swap... Saving data to ./deobfuscated.bin... Done!

image
Анализ распакованной, но не разжатой прошивки

Если кому-то интересно, можете скачать утилиту для распаковки.

ссылка на оригинал статьи http://habrahabr.ru/post/213191/