Меню

Распаковка android прошивки: делаем свою прошивку из стоковой, не копаясь в исходниках — «Хакер» – Как открыть прошивку Андроид для последующего её изменения

Leave a comment

Как распаковать прошивку img для ее редактирования

Все прошивки для планшетов на процессоре Allwinner имеют один и тот же формат  img (IMAGEWTY).

После долгих поисков я все-таки нашел программу, которая позволяет разобрать и собрать прошивку для планшетов на базе Allwinner. Называется она unPacker

Перейдем непосредственно к разборке файла прошивки.

Разборка IMG файла

Для разборки потребуется:

  • Файл самой прошивки
  • Программа unPacker, которую можно скачать здесь ( Для Allwinner a31s можно использовать imgRePacker ) 

 

Скачиваем архив и распаковываем. Запускаем программу unPacker.exe

распаковать прошивку img

Перетаскиваем в это окно наш файл и ждем распаковки.

После окончания распаковки появится новая папка название "прошивки.img.dump"

чем открыть прошивку img

В папке out  есть файл system.fex -это файл с системными файлами(папка system) . Он то нам и нужен.

Редактирование файла system.fex

Для редактирования этого файла нужна nix система и утилита для конвертации, которую можно скачать здесь

Создаем в домашней директории папку в которой будем редактировать нашу прошивку. Назовем ее например NEW. Теперь распаковываем файлы из архива ext4_utils.zip в папку NEW. Запускаем терминал и набираем

cd NEW make

Программа скомпилируется и мы получим инструмент для редактирования Sim2img. Теперь кладем в папку NEW наш файл system.fex и переименовываем его в sytsem.img

Вводим в терминале

./simg2img system.img output.img

Теперь у нас есть файл output.img . Теперь создаем папку например с названием sys

mkdir sys

И монтируем туда наш файл output

sudo mount output.img sys

Теперь в папке sys находятся файлы, которые можно редактировать. Например можно внести изменения в файл build.prop, которые улучшат работу системы.

Подробнее об изменениях в файле build.prop читайте здесь

После редактирования начинаем сборку

./mkuserimg.sh -s sys/ ./factoryfs_custom.img ext4 ./temp 512M

Полученный файл factoryfs_custom переименовываем в system.fex.iso

Примечание: можно аналогично редактировать и другие файлы образов (boot и bootloader)

Сборка img файла

 

Теперь что бы собрать отредактированные файлы в необходимый для прошивки формат, нужно файл system.fex.iso поместить с заменой в папку (на Windows) _iso и перетащить папку

название прошивки.img.dump снова в окошко программы unPacker и немного подождать. По окончанию запаковки получится файл название прошивки.img который можно использовать для перепрошивки устройства на Allwinner

Реверс-инжиниринг прошивки китайского Android-планшета / Журнал Хакер corporate blog / Habr

У китайцев особенное представление о копирайте — у них он просто не действует. В то же время свои наработки они защищают различными техническими средствами, почему-то «забывая» делиться ими со своими клиентами. Казалось бы, ситуация безвыходная: поступила партия китайских планшетов, и встала задача прошить их таким образом, чтобы контент заказчика не стирался при сбросе настроек, при этом имеется стоковая прошивка в неизвестном bin-формате, но отсутствует SDK. Что же делать, как собрать кастомную прошивку? Выход один — применить реверс-инжиниринг.

Разведка


Устройство, с которым предстояло поработать, было построено на базе GeneralPlus GP330xx SoC, а его системное ПО разработано с помощью OpenPlatform SDK, и, хотя китайцы заявляют о готовности предоставить исходные коды, они этого не делают. Несмотря на сложность поставленной задачи, оптимизма прибавлял включенный в устройстве по умолчанию рутовый доступ. Поэтому процесс изучения начался с запуска ADB Shell.

Все дисковое пространство планшета представляло собой одно большое блочное устройство NAND-флеш (/dev/block/nanda), побитое на разделы:

Disk /dev/block/nanda: 7457 MB, 7457472512 bytes
4 heads, 16 sectors/track, 227584 cylinders
Units = cylinders of 64 * 512 = 32768 bytes

Device Boot                Start         End      Blocks  Id System
/dev/block/nanda1             257      174335     5570528   b Win95 FAT32
/dev/block/nanda2          174336      207103     1048576  83 Linux
/dev/block/nanda3          207104      223487      524288  83 Linux
/dev/block/nanda4          223488      227583      131072  83 Linux

Часть памяти была выделена под так называемую Internal SD card. Нужно остановиться на этом термине подробнее. В Android каждая прикладная программа запускается в своей песочнице и использует для доступа к файлам системный API. Этот API позволяет обращаться к внутренней памяти (Internal Storage) и внешней памяти (External Storage). При этом внешняя память делится на removable storage media (SD-карта, которая вставляется в слот на торце устройства) и internal (non-removable) storage (раздел внутренней памяти, «мимикрирующий» под SD-карту). В данном планшете именно под внутреннюю SD-карту был отведен самый большой раздел — /dev/block/nanda1. Поэтому его решено было разбить на два раздела, выделив один из них под контент заказчика, а второй — под внутреннюю SD-карту.

Устройство/dev/block/nanda размечено с помощью MBR, а не GPT, поэтому максимальное количество primary разделов равно четырем. С помощью fdisk был удален раздел /dev/block/nanda1, и на его месте создан extended-раздел с двумя подразделами /dev/block/nanda5 и /dev/block/nanda6.

Колдуем над разделами


Просматривая список смонтированных устройств, видим, что раздел /dev/block/vold/253:97 смонтирован на /mnt/sdcard.
[email protected]:/etc # mount ... /dev/block/vold/253:97 /mnt/sdcard vfat rw,dirsync,nosuid,nodev,noexec,relatime,uid=1000,gid=1015,fmask=0602,dmask=0602,allow_utime=0020,codepage=cp437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro 0 0 /dev/block/vold/253:97 /mnt/secure/asec vfat rw,dirsync,nosuid,nodev,noexec,relatime,uid=1000,gid=1015,fmask=0602,dmask=0602,allow_utime=0020,codepage=cp437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro 0 0 ...

Какая связь между /dev/block/vold/253:97 и /dev/block/nanda1? Vold — это Volume Management daemon, демон монтирования внешних носителей. У него имеется конфигурационный файл, по синтаксису похожий на стандартный никсовый fstab, под названием vold.fstab:
## Vold 2.0 Generic fstab
...
dev_mount sdcard /mnt/sdcard auto /devices/virtual/block/nanda /devices/virtual/block/nanda/nanda1 /devices/virtual/block/nanda/nanda2 /devices/virtual/block/nanda/nanda3 /devices/virtual/block/nanda/nanda4
...

На первый взгляд все понятно: /mnt/sdcard — это путь монтирования, auto — автоматический выбор первого подходящего для монтирования раздела из списка разделов, указанных далее (/devices/virtual/…). Однако файл vold.fstab в данном устройстве был, по сути, «заглушкой». При внесении модификаций в строчку dev_mount sdcard… (например, подмонтировать свежесозданный раздел, отличный от /devices/virtual/block/nanda/nanda1), демон отказывался работать. Трудно сказать наверняка, связано ли это с кастомизированным ядром или же с кастомизированным демоном, но, как бы то ни было, мотивы разработчиков такого решения не ясны.

Таким образом, оказалось, что ни /dev/block/nanda5, ни /dev/block/nanda6 невозможно подмонтировать с помощью vold. Дальше можно было пойти двумя путями:

  1. Запускать монтирование SD-карты из init-скриптов вручную. Правда, этот путь не мог гарантировать 100%-й совместимости со всеми Android internals, иными словами, нельзя было бы поручиться за стабильность работы системы, убрав из нее ключевой компонент «общения» с внешними накопителями — vold.
  2. Взять открытые исходники vold и попробовать собрать его для данного устройства. Гарантий также никаких, кроме того, это могло бы потребовать изрядного количества времени, которого, как всегда, не хватало.

Для такого метода решения задачи пришлось бы писать shell-скрипты, вызываемые через ADB, и получить результирующий бинарник прошивки никак бы не вышло, а это, в свою очередь, удорожило бы работу технических специалистов заказчика, так что этот путь был оставлен про запас и исследование продолжилось в новом направлении.

Решение пришло внезапно


Столкнувшись с такой проблемой, я решил еще раз внимательно изучить то, что было у нас в руках. Особый интерес вызывал прошивальщик, который, помимо самого файла прошивки firmware.bin, содержал еще ряд вспомогательных ресурсов: bootheader.bin, bootpack.bin, bootresource.bin, scanram.bin, updater.bin. Они также необходимы, но нерелевантны для нашей задачи. Больший интерес представляют файлы, которые используются прошивальщиком для загрузки своего собственного кода на устройство: small_isp.bin, cmdline, initrd и kernel.

Данное устройство использовало для прошивки так называемый ISP mode (это обозначение одного из режимов программирования флеш-памяти). Алгоритм работы прошивальщика можно условно разделить на четыре этапа:

  1. Технический специалист перезагружает устройство в режиме прошивки, зажав при его включении кнопки <Home + Power>.
  2. Прошивальщик опознает устройство по USB и перезагружает его в ISP mode.
  3. Прошивальщик загружает на устройство Linux, передавая файлы cmdline, initrd и kernel.
    Файл kernel — это ядро ОС, initrd — раздел с ПО прошивальщика на стороне устройства, cmdline — параметры ядра, содержащие в себе размер файла initrd.
  4. Загруженная на устройстве Linux начинает принимать от прошивальщика основные файлы прошивки, распаковывать их и записывать в соответствии с внутренними алгоритмами.

Что же представляли собой эти внутренние алгоритмы? Решение пришло внезапно. Оказалось, что initrd содержал в себе исходные коды прошивальщика на языке Lua, а также бинарники дополнительных Lua-модулей. Для распаковки initrd необходимо выполнить следующие команды:
# mkdir initrd-unpacked
# cd initrd-unpacked
# gunzip < ../initrd | cpio -i --make-directories

Для обратной упаковки (при необходимости; например, для тестирования модифицированных версий скриптов):
# find ./ | cpio -H newc -o > initrd.cpio
# gzip initrd.cpio
# mv initrd.cpio.gz initrd

Это может показаться странным, но действительно разработчики зачем-то придумали свой собственный формат прошивки, при этом оставив скрипты, оперирующие с этим форматом, в initrd в открытом виде.

Pluto


Хидеры прошивки планшета были запакованы с помощью модуля Pluto, который упаковывает Lua-таблицы в бинарный формат. Язык программирования Lua вообще активно использует подключаемые модули, представляющие собой so-библиотеки, которые добавляют те или иные API. В добавок ко всему, как следовало из документации, Pluto был платформо- и архитектурнозависим. Intel и ARM (на которой был построен планшет) существенно отличаются: Intel использует little-endian порядок байт в представлении чисел, а ARM — big-endian.

И здесь возникла серьезная проблема: стандартный модуль Pluto не распаковывал полученные данные. Были испробованы разные версии Lua и даже разные архитектуры CPU (x86, x86_64, ARM). Оказалось, что просто разработчики прошивки использовали свою, ни с чем ни совместимую версию Pluto.

Для того чтобы распаковать данные, пришлось воспользоваться эмулятором QEMU для архитектуры ARM и установить на него Debian Linux. А затем установить Lua и положить модуль pluto.so, извлеченный из initrd, в каталог модулей Lua.

Подключение Lua-модулей

Язык программирования Lua расширяется за счет внешних подключаемых модулей, которые могут быть написаны как на Lua, так и на C. В последнем случае это обычные so-библиотеки, экспортирующие ряд API-функций.
Их подключение производится с помощью функции require, а за путь поиска бинарных модулей отвечает переменная package.cpath. У проприетарного LZO-модуля есть своя особенность подключения, которая заключается в его наименовании — lua_lzo.so. При этом сам модуль называется lzo, из-за чего его подключение вместо привычного:
package.cpath = package.cpath .. "/home/mikhail/lua_so/?.so
require ;lzo;

следует производить так:
package.cpath = package.cpath .. /home/mikhail/lua_so/lua_?.so
require lzo

Также стоит обратить внимание на пакетный менеджер LuaRocks, который позволяет устанавливать модули из единого репозитория и удобно их подключать. Например, в рамках данного исследования модули nixio и MD5 были подключены именно через LuaRocks.

LZO


Отдельную сложность преподнес также алгоритм сжатия LZO. Дело в том, что формат данных для этого алгоритма архивации не стандартизирован, поэтому сложно написать распаковщик, не зная, каким образом файл был запакован. Однако среди Lua-модулей initrd был модуль lua_lzo.so. На помощь пришел метод, описанный в предыдущем абзаце, правда, усложненный тем, что lua_lzo.so требовал в зависимости системную библиотеку liblzo.so (которая была взята из того же initrd) и нестандартное подключение модуля через package.cpath.

Алгоритм сжатия LZO


LZO — семейство блочных алгоритмов сжатия, обладающих важными для портативных компьютеров характеристиками:
  • очень высокой скоростью распаковки;
  • малым потреблением памяти;
  • поблочной распаковкой данных, порциями небольшого размера.

С точки зрения реверс-инжиниринга он имеет два недостатка:
  1. LZO включает в себя девять алгоритмов сжатия, и к каждому из них идет свой распаковщик.
  2. Структура файлов LZO-архивов не стандартизирована, разные библиотеки генерируют разную структуру.

В нашем случае архивные данные имели следующий формат:
  1. Magic-последовательность («PMOC»).
  2. Размер блока данных, используемый при упаковке (131072). Напомню, что в ARM используется система little-endian, а значит, что это число соответствует hex-значению 0x00000200 (см. рис. 3).
  3. Блоки данных, содержащие:
    1. Размер блока (например, 1816).
    2. Запакованные данные обозначенного выше размера.


Это означает, что блок запакованных данных размером 1816 байт распакуется в 128 килобайт информации.

Распаковка выполняется в цикле, блоками данных. Для распаковки используются функции:

  1. handle = >lzo.decompressInit(header), где header — magic number + размер блока архивации, handle — хендл, использующийся в двух других функциях
  2. ... = lzo.decompressPorcess(handle)
  3. lzo.decompressFinish(handle)

Примечательно то, что необходимо точно знать размер архива, чтобы распаковка выполнилась успешно. В противном случае распаковка зависает на статусе DECOMPRESS_NEED_MORE_DATA. Размер архива указан в заголовке 2 (см. рис. 1).
Компрессия данных выполняется сложнее, так как функции компрессии не документированы и их работоспособность выявлялась пробным путем. Функции аналогичны:
  1. handle, header= lzo.compressInit(blockSize)
  2. ...= lzo.compressProcess(handle, data)
  3. lzo.compressFinish(handle)

Отличительный момент компрессии от декомпрессии в том, что перед записью блока данных, полученных в результате выполнения функции lzo.compressProcess, необходимо записать размер упакованного блока данных. Это следует из общей документации на алгоритм сжатия LZO и из анализа архива, полученного при разборе оригинальной прошивки.
В итоге, исследуя исходный код скриптов, пытаясь понять их логику работы, форматы данных, а также проведя множество экспериментов, прошивку удалось распаковать.

Ресайз системного раздела


Распакованный файл системного раздела (system.bin) представлял собой образ файловой системы ext4. Для того чтобы записать данные заказчика, его необходимо было расширить на 1 Гб. Для этого нужно сделать следующее:
  1. Расширить саму файловую систему.
  2. В заголовке 2, в таблице разделов, уменьшить на 1 Гб раздел nanda1 и увеличить на столько же раздел nanda2.
  3. Снова заархивировать system.bin, пересчитать контрольные суммы и записать их в заголовки.

Сам же ресайз системного раздела выполняется следующими командами:
# mkdir system_new
# losetup /dev/loop0 system.bin
# e2fsck -f /dev/loop0
# resize2fs /dev/loop0 2G
# mount /dev/loop0 system_new
...
# umount system_new
# losetup -d /dev/loop0
В рамках решения данной задачи часть изменений в системе производилась не только в /system, но и в /data. Для этого необходимо было распаковать dataImage.tar.gz, сделать необходимые изменения и запаковать обратно. Подобным образом следует поступить и с userImage.tar.gz, если требуется внести изменения в контент SD-карты.
Для упаковки с сохранением прав доступа используем следующие команды:
# tar cvf - . | gzip -9 - > ../user.tar.gz
# tar cvfp - . | gzip -9 - > ../data.tar.gz
Заказчику было нужно не только записать свой контент в постоянную память устройства, но и заменить стандартный launcher своим собственным приложением, обеспечив требуемый User Experience.
Замена launcher’а (и других приложений по умолчанию) производилась путем редактирования файлов /data/system/packages.list и /data/system/packages.xml. Сначала дефолтные настройки выполнялись на устройстве, затем содержание файлов частично переносилось в прошивку.
Файл packages.list представляет собой список установленных в системе пакетов. Нужный пакет launcher’а называется com.soaw.launcher и добавляется строчкой:
com.soaw.launcher 10068 1 /data/data/com.soaw.launcher

А
package name="com.soaw.launcher" codePath="/system/app/SOAWLauncher.apk" nativeLibraryPath="/data/data/com.soaw.launcher/lib" flags="1" ft="141c2c2bbe0" it="141c2c2bbe0" ut="141c2c2bbe0" version="1" userId="10068"
sigs count=1;
cert index=20; key=... /sigs/package

Следующая запись — это настройки программ по умолчанию. Здесь задается выбор launcher’а и программы-медиаплеера.
<preferred-activities>
  <item name="com.soaw.launcher/.activity.HomeActivity" match="100000" set="2">
    <set name="com.android.launcher/com.android.launcher2.Launcher"/>
    <set name="com.soaw.launcher/.activity.HomeActivity"/>
    <filter>
      <action name="android.intent.action.MAIN"/>
      <cat name="android.intent.category.HOME"/>
      <cat name="android.intent.category.DEFAULT"/>
    </filter>
  </item>
  <item name="com.android.gallery3d/.app.MovieActivity" match="600000" set="2">
    <set name="com.generalplus.GaGaPlayer/.MoviePlayerActivity"/>
    <set name="com.android.gallery3d/.app.MovieActivity"/>
    <filter>
      <action name="android.intent.action.VIEW"/>
      <cat name="android.intent.category.DEFAULT"/>
      <type name="video/mp4"/>
    </filter>
  </item>
</preferred-activities>

Системные настройки


Как известно, Android имеет SQLite базу данных системных настроек, которую возможно модифицировать на этапе подготовки образа прошивки. Файл базы данных находится в /data/data/com.android.providers.settings/databases/settings.db.
Сокрытие нижней панели выполняется в таблице system следующими записями:
navigation_bar_mode = 4
navigation_bar_buttons_show = 0
navigation_bar_buttons_need_show = 0

Отключение экрана блокировки выполняется в таблице secure:
coockscreen.disabled = 1

Init-скрипты


Init-скрипты Android записываются на / в момент загрузки устройства и поэтому, хотя они и могут быть отредактированы непосредственно на устройстве, при следующей перезагрузке будут перезаписаны оригинальными файлами. Вероятнее всего, они располагаются в initrd, но исследования на эту тему не проводились.

Заключение


Наша жизнь — процесс. Закрытые программные системы — потемки. Процесс познания потемок и есть реверс-инжиниринг. Этот подход помог не только решить основную бизнес-задачу — выпустить кастомную прошивку, но и узнать больше о внутреннем устройстве Android в целом, что, несомненно, весьма интересно для настоящего хакера. Важно помнить, что реверс-инжиниринг — инструмент легальный и универсальный. Не будь его, мир никогда бы не узнал об опаснейших бэкдорах в прошивках ведущих производителей сетевого оборудования, об аппаратных «закладках» в микропроцессорах, об утечках данных в популярных интернет-приложениях. Если кто-то изобрел «черный ящик», то всегда найдется тот, кто сможет понять, как он работает.

Автор: Михаил Емельченков


Впервые опубликовано в журнале «Хакер» от 02/2014.

Подпишись на «Хакер»


Патчим прошивку Android за 5 минут / Habr

Задача


Все началось с того, что я захотел установить на планшет Digma Optima 7.61 игру GTA San Andreas. К сожалению, виртуальная SD-карта планшета имеет объем менее 1 Гб, а кэш игры весит порядка 2-3 Гб. На планшете установлен Android 4.4.2 и возможность просто взять и сменить память по умолчанию в нем отсутствует. Так же в нем отсутствует файл /etc/vold.fstab (он есть на более старых версиях андроида, и изменив данный файл с root-правами, можно поменять местами виртуальную и реальную карты памяти).

Необходимые инструменты


1. Компьютер или ноутбук с ОС Linux.
2. Утилиты adb и fastboot (входят в состав Android SDK, так же, как заметил tmnhy, входят в репозитории как отдельные пакеты).
3. Набор утилит bootimg_tools (нашел здесь).

Решение


1. Извлекаем с устройства загрузочный образ

— Подключаем устройство к компьютеру через usb-кабель и заходим в shell устройства:
adb shell

— Где-то в папке /dev/block на устройстве нужно найти файл с именем boot. У меня он находился по пути /dev/block/by-name/boot, но данный путь может различаться на разных устройствах.

— Извлекаем загрузочный образ:

dd if=/dev/block/path/to/boot of=/mnt/sdcard/boot-from-device.img

— Выходим из shell'а (exit) и извлекаем образ:
adb pull /mnt/sdcard/boot-from-device.img
2. Затем загрузочный образ нужно разобрать

— Скачиваем и распаковываем bootimg_tools.

— Добавляем bootimg_tools в PATH:

export PATH=$PATH:/path/to/bootimg_tools

— Распаковываем образ:
unpack boot-from-device.img

— Если все предыдущие шаги сделаны верно, то должна появиться папка boot-from-device. Внутри нее должны лежать файлы zImage и ramdisk.cpio.gz, а так же папка ramdisk. Как раз внутри последней лежит содержимое загрузочного образа, которое мы будем патчить.
3. Патчим

Для решения своей задачи я нашел строчку, которую нужно заменить, в файле init.sun8i.rc. Я просто заменил export EXTERNAL_STORAGE /mnt/sdcard на export EXTERNAL_STORAGE /mnt/extsd. Как я понимаю, это как раз и есть то значение, которое возвращает метод Environment.getExternalStorageDirectory() в Android API. В пользу этого предположения говорит тот факт, что после применения патча приложения начали использовать аппаратную карту памяти вместо виртуальной для хранения своих данных.
4. Заменяем загрузочный образ на устройстве

Я написал для этих целей небольшой скрипт:
repack_ramdisk boot-from-device/ramdisk
mkbootimg --kernel boot-from-device/zImage --ramdisk boot-from-device/new-ramdisk.cpio.gz --base 0x40000000 --cmdline 'console=ttyS0,115200 rw init=/init loglevel=4' -o new_boot.img
sudo adb reboot-bootloader
sudo fastboot flash boot new_boot.img
sudo fastboot reboot

Итоги


После проделанных манипуляций игра на планшете успешно заработала.

P.S.


Все вышеописанное вы проделываете со своим устройством только на свой страх и риск. За превращение вашего девайса в кирпич автор ответственности не несет.

Как извлечь APK файлы с IMG

1. Распаковываем *.zip архив с прошивкой в любую папку.

Firmware files

2. Запускаем утилиту ext4_unpacker.exe и выбираем файл system.img.

ext4_unpacker

Если у вас возникла ошибка «Unknown file format» можете смело переходить по этой ссылке, там описано решение проблеммы. Если же у вас все нормально открылось, тогда продолжаем.

ext4_unpacker

3. После открытия файла, нажимаем на кнопку сохранить как.

ext4_unpacker

4. Указываем имя файла с расширением .ext4 (например system.ext4).

5. После нажатия кнопки «Сохранить», появится прогресс бар.

ext4_unpacker

6. После завершения распаковки запустите утилиту ext2explore.exe от имени администратора.

7. В вкладке File выберите пункт Open Image. Перейдите в директорию с файлом созданным на предыдущих шагах (system.ext4) и нажмите Открыть.

8. Нажмите правой кнопкой на иконке в правой части окна, и в выпадающем меню выберите опцию Save.

Ext2explore

9. Выберите директорию, в нее будут извлечены все файлы прошивки.

Exr2explore

10. Подождите пока программа распаковывает файлы…

11. После окончания перейдите в папку которую вы выбрали, там будут все извлеченные файлы.

Output directory with APK files

Распаковка, редактирование и упаковка прошивок видеорегистраторов и IP камер от Xiong Mai

Предыстория

Не так давно приобрёл на Aliexpress IP камеру (чип Hi3516 платформа 53h30L) и 16-канальный гибридный видеорегистратор (чип Hi3521 платформа MBD6508E). Оба выполнены на чипсете от HiSilicon, так что проблем с совместимостью между собой не испытывают.
Разумеется, не обошлось и без глюков. Первый, и самый главный — у камеры криво работал WiFi — нельзя было подключиться к сети, если ключ был задан в HEX виде, а также периодически возникала проблема со шлюзом по умолчанию.

Прошивка оказалась старая, ещё июньская. Раздобыл несколько свежих прошивок и попробовал. Некоторые оказались глючными, но одна заработала нормально.
Возникла другая проблема — изменился пароль по умолчанию для telnet подключения. Этого я не стерпел и стал искать способы вернуть его обратно.
Сразу предупрежу, что данный способ опробован на видеорегистраторах и камерах на чипах HiSilicon, но должен сработать и с другой платформой, так как китайцы широко используют загрузчик U-boot.

Распаковка

Инструкция по распаковке довольно подробно расписана в этой статье, но вот процесс упаковки нигде не описан, что и побудило меня написать этот пост.
Расписываю по шагам, чтобы ничего не упустить:
Ставим Linux, я выбрал ubuntu.
Проверяем тип файла прошивки:
[email protected]:~/firmware# file General_HZXM_IPC_HI3516C_53h30L_V4.02.R11.20131108_ALL.bin 
General_HZXM_IPC_HI3516C_53h30L_V4.02.R11.20131108_ALL.bin: Zip archive data, at least v2.0 to extract

Распаковываем:
[email protected]:~/firmware# unzip General_HZXM_IPC_HI3516C_53h30L_V4.02.R11.20131108_ALL.bin 
Archive:  General_HZXM_IPC_HI3516C_53h30L_V4.02.R11.20131108_ALL.bin
  inflating: Install                 
  inflating: u-boot-all.bin.img      
  inflating: web-x.cramfs.img        
  inflating: custom-x.cramfs.img     
  inflating: user-x.cramfs.img       
  inflating: romfs-x.cramfs.img      
  inflating: logo-x.cramfs.img       
  inflating: InstallDesc

Смотрим содержимое Install:
{
   "Commands" : [
      "burn custom-x.cramfs.img custom",
      "burn romfs-x.cramfs.img romfs",
      "burn user-x.cramfs.img user",
      "burn logo-x.cramfs.img logo",
      "burn web-x.cramfs.img web"
   ],
   "Devices" : [
      [ "53h30L", "1.00" ]
   ]
}

InstallDesc:
   "UpgradeCommand" : [
      {
         "Command" : "Burn",
         "FileName" : "u-boot-all.bin.img"
      },
      {
         "Command" : "Burn",
         "FileName" : "custom-x.cramfs.img"
      },
      {
         "Command" : "Burn",
         "FileName" : "romfs-x.cramfs.img"
      },
      {
         "Command" : "Burn",
         "FileName" : "user-x.cramfs.img"
      },
      {
         "Command" : "Burn",
         "FileName" : "web-x.cramfs.img"
      },
      {
         "Command" : "Burn",
         "FileName" : "logo-x.cramfs.img"
      }
   ],
   "Hardware" : "53h30L",
   "Vendor" : "General"
}

Слово u-boot-all наводит на мысль, что файлы img являются образами загрузчика U-boot, поэтому ставим соответствующий пакет:
[email protected]:~/firmware# apt-get install u-boot-tools

Смотрим, что за файлы у нас были в архиве:
[email protected]:~/firmware# file u-boot-all.bin.img 
u-boot-all.bin.img: u-boot legacy uImage, linux, Linux/ARM, Firmware Image (gzip), 524288 bytes, Fri Nov  8 05:15:49 2013, Load Address: 0x00000000, Entry Point: 0x00080000, Header CRC: 0x8A551AA8, Data CRC: 0x8290AD90

[email protected]:~/firmware# file romfs-x.cramfs.img 
romfs-x.cramfs.img: u-boot legacy uImage, linux, Linux/ARM, OS Kernel Image (gzip), 4100096 bytes, Fri Nov  8 05:16:04 2013, Load Address: 0x00080000, Entry Point: 0x00580000, Header CRC: 0xD16AC90F, Data CRC: 0x54CDD868

[email protected]:~/firmware# file user-x.cramfs.img 
user-x.cramfs.img: u-boot legacy uImage, linux, Linux/ARM, OS Kernel Image (gzip), 7602112 bytes, Fri Nov  8 05:16:02 2013, Load Address: 0x00580000, Entry Point: 0x00CC0000, Header CRC: 0x106C19AD, Data CRC: 0x6D54ADA7

[email protected]:~/firmware# file web-x.cramfs.img 
web-x.cramfs.img: u-boot legacy uImage, linux, Linux/ARM, Standalone Program (gzip), 1572800 bytes, Fri Nov  8 05:15:51 2013, Load Address: 0x00CC0000, Entry Point: 0x00E40000, Header CRC: 0x87611FE5, Data CRC: 0x6BD90EBD

[email protected]:~/firmware# file custom-x.cramfs.img 
custom-x.cramfs.img: u-boot legacy uImage, linux, Linux/ARM, Standalone Program (gzip), 262080 bytes, Fri Nov  8 05:15:49 2013, Load Address: 0x00E40000, Entry Point: 0x00E80000, Header CRC: 0xF7C82692, Data CRC: 0x5A27F74C

[email protected]:~/firmware# file logo-x.cramfs.img 
logo-x.cramfs.img: u-boot legacy uImage, linux, Linux/ARM, Standalone Program (gzip), 262080 bytes, Fri Nov  8 05:15:47 2013, Load Address: 0x00E80000, Entry Point: 0x00EC0000, Header CRC: 0x4FE4A821, Data CRC: 0xF6671BD1

Прошу обратить внимание на два параметра Load Address и Entry Point. Я при первой сборке забыл их указать, они по умолчанию стали нулями, а это адрес загрузчика, который оказался затёрт после прошивки! Из-за этого я потратил лишний час на восстановление — пришлось снимать с улицы камеру, разбирать, и восстанавливать прошивку на программаторе. (Хотя камеру разбирал всё же не зря — добавил в кожух пакетик силикагеля, чтобы убрать возможную влагу из воздуха.)

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

[email protected]:~/firmware# dd bs=1 skip=64 if=logo-x.cramfs.img of=logo-x.cramfs
262080+0 записей получено
262080+0 записей отправлено
скопировано 262080 байт (262 kB), 0,891322 c, 294 kB/c

Для остальных файлов команды аналогичные.
Смотрим, что получилось:
[email protected]:~/firmware# file logo-x.cramfs 
logo-x.cramfs: Linux Compressed ROM File System data, little endian size 28672 version #2 sorted_dirs CRC 0xe29e6340, edition 0, 199 blocks, 2 files

Уже похоже на cramfs. Для работы с образами cramfs установим или обновим соответствующий пакет:
[email protected]:~/firmware# apt-get install cramfsprogs

Распаковываем образы:
[email protected]:~/firmware# cramfsck -x logo logo-x.cramfs
[email protected]:~/firmware# cramfsck -x user user.cramfs
[email protected]:~/firmware# cramfsck -x romfs romfs-x.cramfs
[email protected]:~/firmware# cramfsck -x web web-x.cramfs
[email protected]:~/firmware# cramfsck -x custom custom-x.cramfs

Каталоги я не создаю, они создадутся автоматически.
Загрузчик так не распаковать, это не образ cramfs, но его и не надо трогать.
Что внутри

Быстренько пробегусь по содержимому каждого файла внутри архива прошивки:
  • InstallDesc — описывает действия, которые нужно произвести с этими файлами при обновлении прошивки, install-скрипт.
  • logo-x.cramfs.img — картинка в формате 800x600 с логотипом изготовителя, которая появляется при загрузке аппарата.
  • romfs-x.cramfs.img — собственно сама операционная система linux под архитектуру ARM
  • u-boot-all.bin.img — загрузчик U-boot
  • custom-x.cramfs.img — содержит наименование платформы и дополнительные настройки
  • user-x.cramfs.img — прикладной софт, в том числе Sofia — сама программа видеорегистратора
  • web-x.cramfs.img — картинки веб-интерфейса, web.cab — плагин для Internet Explorer с локализацией, логотипы производителя.

Нас интересует romfs-x.cramfs.img, так как именно там присутствует файл passwd, в котором хранится пароль. Вот его содержимое, желающие могут попробовать сбрутить:
root:$1$RYIwEiRA$d5iRRVQ5ZeRTrJwGjRy.B0:0:0:root:/:/bin/sh

Я же просто сгенерил новый хеш на сайте и поменял его в файле.
Собираем обратно

После сделанных изменений нужно всё запаковать обратно:
[email protected]:~/firmware# mkcramfs romfs romfs-x.cramfs
Directory data: 3624 bytes
Everything: 4004 kilobytes
Super block: 76 bytes
CRC: 28c62b9b

Помните, я заострял внимание на значениях Load Address и Entry Point? Самое время о них вспомнить и добавить в команду.
Создаём образ U-boot:
[email protected]:~/firmware# mkimage -A arm -O linux -T ramdisk -n "linux" -e 0x00580000 -a 0x00080000 -d romfs-x.cramfs romfs-x.cramfs.img
Image Name:   linux
Created:      Fri Feb 21 14:27:38 2014
Image Type:   ARM Linux RAMDisk Image (gzip compressed)
Data Size:    4100096 Bytes = 4004.00 kB = 3.91 MB
Load Address: 00080000
Entry Point:  00580000

Кстати, чтобы обновить один модуль не обязательно прошивать всю прошивку, достаточно положить только нужный, и отредактировать файлы Install и InstallDesc, оставив только нужные строчки.
Складываем полученные файлы в отдельный каталог, пусть это будет new. Даём команду:
[email protected]:~/new# zip -D -X firmware.bin *
  adding: Install (deflated 22%)
  adding: InstallDesc (deflated 30%)
  adding: romfs-x.cramfs.img (deflated 0%)

Всё, прошивка готова. Осталось только прошить её через web-интерфейс через пункт update
Предостережение

Выполняя рекомендации из этой статьи, вы делаете на ваш страх и риск. Автор не несет ответственности за ваши действия. Допустив ошибку при модификации прошивки вы легко можете получить кирпич, который можно будет восстановить только на программаторе. Поэтому, если не уверены в своих действиях, не делайте этого.
Ссылки

Burn-in рутовый шелл в IP-камерах Vesta и не только
GNU/Linux и устройство на Rockchip 2918
Hacking RAM disks

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *