Структура и работа SD-карт, записанных утилитой PhoenixCard


  Структура     Прошивка       Эксперименты       RAW-образ  

Анализ и сравнение записанных карт

Здесь мы расскажем, какие "следственные" эксперименты были проведены для выяснения структуры записанных SD-карт в двух режимах (StartUp и Product) и понимания принципов действия утилиты Phoenix Card, а также процессов программирования устройства с картой Product.

Метод поиска истины прост: для каждого из режимов фиксируем его результаты (логи, содержимое карты, файлы и т.п.), а затем сравниваем, находим различия и анализируем их причины.

Все описанные ниже действия и манипуляции при желании можно повторить самостоятельно, чтобы подтвердить, уточнить или опровергнуть сделанные на их основе выводы и представления.


Для этих экспериментов используем файл imagewty-образа прошивки для ТВ-бокса на основе SoС Allwinner H616 (конкретная модель не имеет значения), пусть это будет файл с условным именем imagewty.img. Запись будет производиться на две помеченных карты SanDisk емкостью 8Gb.

  • 1. На первую карту записывем файл в режиме StartUp
  • 2. На вторую карту записывем файл в режиме Product

    Для сохранения содержимого карт в файлы будем подключать их через кард-ридер к USB-порту устройства с загруженным Android. В нашем случае используется одноплатник OPiZero2, имеющий порт UART с готовым разъемом для подключения его к ПК через переходник, чтобы можно было воспользоваться консольными командами терминала MobaXTerm. Теоретически, можно было бы работать с терминалом (например, Termux) самого Android, но практически это гораздо менее удобно, чем в предыдущем варианте.

    На этом устройстве любым способом (файловым менеджером или консольными командами) создадим две папки с говорящими (чтобы не запутаться) именами Product и Startup, в которые и будут сохранены бекапы частей соответствующих карт.


    1. Сравнение временных файлов Phoenix Card

    В процессе работы утилиты Phoenix Card в момент выбора в интерфейсе конкретного файла с образом прошивки в текущей папке создаются несколько временных файлов (чуть подробнее о них - Временные файлы PhoenixCard), которые как-то используются в работе утилиты, а по её закрытию - удаляются.

    Вот список и происхождение этих временных файлов.

  • 1. config.cfg - это конфигурация прошивальщика, файл создается при старте программы

  • 2. thisdata.fexF - это пустой файл размером 4096 байт, т.е. 8 блоков

  • 3. card.scj - это точная копия файла cardtool.fex из образа прошивки

  • 4. dlinfo.fex - это точная копия файла dlinfo.fex из образа прошивки

  • 5. gpt.fex - это слегка измененный файл sunxi_gpt.fex из образа прошивки

  • 6. mbr.fex - это слегка измененный файл sunxi_mbr.fex из образа прошивки

  • 7. script.cfg - это файл cardscript.fex из образа прошивки (с убранными пробелами)

  • 8. script.cfgF - это файл script.cfg из образа прошивки (модифицируетя)

    Проверим, нет ли в них отличий, проливающих свет на особенности записи в разных режимах.


    StartUp

    73728 card.scj
    913 config.cfg
    16384 dlinfo.fex
    8192 gpt.fex
    65536 mbr.fex
    2143 script.cfg
    2143 script.cfgF
    4096 thisdata.fexF
    Product

    3728 card.scj
    913 config.cfg
    6384 dlinfo.fex
    8192 gpt.fex
    5536 mbr.fex
    2143 script.cfg
    2158 script.cfgF
    11831296 thisdata.fex
    11831296 thisdata.fexF

    Результаты анализа и сравнения:

  • 1) thisdata.fex и thisdata.fexF - одинаковые файлы (в обоих режимах)

  • 2) Файл script.cfgF в режиме Product - это script.cfg, в котором добавлена единственная строка: data=0

  • 3) Файл script.cfgF в режиме StartUp - это script.cfg, в котором отсутствует data=0, и сделана замена mode=product на mode=bromrun

  • 4) Главное заметное отличие - в файле thisdata.fexF :
    в StartUp - это пустой файл из нулей размером 4 Кб
    в Product - файл 11 831 296 = 12 Mb !

    При этом файл thisdata.fex - это образ пустого диска FAT32

    Выводы. Кроме очевидной замены значения режима записи других существенных отличий в этих временных файлах не обнаружено.


    2. Сравнение логов сеанса Phoenix Card
    Ниже показаны сканы финального состояния окна сообщений в интерфейса Phoenix Card.


    Product


    StartUp

    В обоих режимах есть строки о записи boot0, boot1 и mbr (на самом деле, записывается таблица GPT, а не MBR), но дальше в логи отличаются:

  • startup - идут сообщения о записи остальных семи разделов

  • product - нет сообщений о записи этих разделов, зато есть две новых строки:
    1) запись чего-то с неизвестным именем []
    2) запись с именем [IMG File] ) !!!

    Поэтому можно предположить, что в режиме Product вместо содержимого разделов, начиная с ENV, на карту записывается какая-то часть исходного imagewty-образа прошивки или даже весь файл образа.

    Кроме того, есть отличия (непринципиальные) в финальном прогресс-баре:

  • В startup - отображается нулевой размер диска F
  • В product - отображается реальный размер диска F (8 Gb)


    3. Бекап содержимого карты, записанной в режиме Product
  • 1. Проверяем таблицу разделов GPT на карте (адреса и размеры - в блоках 512):


    console:/ $ su
    2|console:/ # sgdisk --print /dev/block/sda

    Number Start End Size Code Name
    1 73728 139263 32.0 MiB 0700 bootloader
    2 139264 172031 16.0 MiB 0700 env
    3 172032 237567 32.0 MiB 0700 boot
    4 237568 5349375 2.4 GiB 0700 super
    5 5349376 5382143 16.0 MiB 0700 misc
    6 5382144 5447679 32.0 MiB 0700 recovery
    7 5447680 8069119 1.3 GiB 0700 cache
    8 8069120 8101887 16.0 MiB 0700 vbmeta
    9 8101888 8134655 16.0 MiB 0700 vbmeta_system
    10 8134656 8167423 16.0 MiB 0700 vbmeta_vendor
    11 8167424 8200191 16.0 MiB 0700 metadata
    12 8200192 8232959 16.0 MiB 0700 private
    13 8232960 8233983 512.0 KiB 0700 frp
    14 8233984 8265727 15.5 MiB 0700 empty
    15 8265728 8298495 16.0 MiB 0700 media_data
    16 8298496 8331263 16.0 MiB 0700 Reserve0
    17 8331264 15677405 3.5 GiB 0700 UDISK

  • 2. Создаем папку product и делаем её текущей

    cd /storage/emulated/0/product

  • 3. Сохраняем в файл start.img содержимое начала карты (до раздела bootloader)

    dd if=/dev/block/sda of=start.img bs=512 count=73728 conv=fsync

    В файле start.img должны быть сохранены (с соответствующими смещениями): GPT, boot0 и boot_package

    4. Сохраняем в файл bootloader.img содержимое раздела bootloader

    dd if=/dev/block/sda1 of=bootloader.img conv=fsync

    В файле должены быть сохранен boot-resource - диск FAT16 с картинками (bootlogo.bmp и шрифты)

  • 5. Сохраняем в файл imagewty.img остальное содержимое карты (после раздела bootloader):

    dd if=/dev/block/sda bs=1M count=1900 skip=68 | gzip > imagewty.img.gz sync
    Примечания.
    1. Начальный адрес раздела env = 139264 блоков или 68 MB, поэтому пропускаем эти блоки (skip=68)
    2. Размер исходного файла img = 1857141 KB, поэтому в файл сохраняем 1900 Mb (округленно и с запасом)

  • 6. Делаем бекап полного RAW-образа карты


    cd /storage/emulated/0/firmwaresd
    dd if=/dev/block/sda bs=1M count=2048 | gzip > firmware.img.gz
    sync

    Файл firmware.img.gz позже можно будет разархивировать и записать на SD-карту с помощью утилит BalenaEtcher или Win32DiskImager или любой аналогичной утилиты на ПК с Windows, т.е. мы получим альтернативный вариант файла для записи "прошивочной" карты Android на ПК с Windows (или Linux) без использования достаточно капризной утилиты Phoenix Card.


    4. Бекап содержимого карты, записанной в режиме StartUp
  • 1. Проверяем таблицу разделов GPT на карте (адреса и размеры - в блоках 512):


    console:/ $ su
    2|console:/ # sgdisk --print /dev/block/sda

    Number Start End Size Code Name
    1 73728 139263 32.0 MiB 0700 bootloader
    2 139264 172031 16.0 MiB 0700 env
    3 172032 237567 32.0 MiB 0700 boot
    4 237568 5349375 2.4 GiB 0700 super
    5 5349376 5382143 16.0 MiB 0700 misc
    6 5382144 5447679 32.0 MiB 0700 recovery
    7 5447680 8069119 1.3 GiB 0700 cache
    8 8069120 8101887 16.0 MiB 0700 vbmeta
    9 8101888 8134655 16.0 MiB 0700 vbmeta_system
    10 8134656 8167423 16.0 MiB 0700 vbmeta_vendor
    11 8167424 8200191 16.0 MiB 0700 metadata
    12 8200192 8232959 16.0 MiB 0700 private
    13 8232960 8233983 512.0 KiB 0700 frp
    14 8233984 8265727 15.5 MiB 0700 empty
    15 8265728 8298495 16.0 MiB 0700 media_data
    16 8298496 8331263 16.0 MiB 0700 Reserve0
    17 8331264 15677405 3.5 GiB 0700 UDISK

  • 2. Создаем папку startup и делаем её текущей

    cd /storage/emulated/0/startup

  • 3. Сохраняем в файл start.img содержимое начала карты (до раздела bootloader)

    dd if=/dev/block/sda of=start.img bs=512 count=73728 conv=fsync

    В файле start.img должны быть сохранены (с соответствующими смещениями): GPT, boot0 и boot_package

  • 4. Сохраняем в файл bootloader.img содержимое раздела bootloader

    dd if=/dev/block/sda1 of=bootloader.img conv=fsync

    В файле должены быть сохранен boot-resource - диск FAT16 с картинками (bootlogo.bmp и шрифты)

  • 5. Сохраняем в файл env.img содержимое раздела ENV:

    dd if=/dev/block/sda2 of=env.img conv=fsync

    Делать бекап всех остальных разделов карты StartUp нет смысла, поскольку они отсутствуют на карте Product и сравнивать будет не с чем.


    5. Анализ файлов, извлеченных из карты Product

    Из файла start.img (начало карты) размером 34 MB после распаковки можно извлечь (по их смещениям) следующие следующие блобы, сохранив их в файлы:

  • gpt.img
  • boot0.img
  • package.img

    Сравнение этих файлов из бекапа с аналогичными из файла imagewty-образа дает такие результаты:

  • 1) cодержимое файла таблицы разделов gpt.img отличается от исходного файла sunxi_gpt.fex из imagewty-образа.

  • 2) cодержимое файла boot0.img полностью совпадает с файлом boo0_sdcard.fex из исходного imagewty-образа

    fc /b boot0.img boot0_sdcard.fex Различия не найдены

  • 3) Файл package.img отличается от исходного файла boot-package.img

    После распаковки gzip-архива imagewty.img.gz получаем файл imagewty.img, содержимое которого полностью совпадает с исходным файлом imagewty-образа, который был использован для записи прошивочной карты карты в режиме product.


    ВЫВОДЫ. Таким образом установлено, что в процессе своей работы утилита Phoenix Card в режиме product просто копирует исходный файл образа на карту, начиная с блока 139264, который в таблице разделов GPT соответствует началу второго раздела ENV.


    То есть таблица GPT фактически используется только для записи в самый первый раздел bootloader графических файлов для U-Boot, а также для определения адреса начального блока раздела ENV, с которого начинается оласть на карте для копирование файла образа.

    Остальные разделы таблицы игнорируются, а файл записывается поблочным копированием. При этом утилита Phoenix Card, вероятно, выполняет действия, аналогичные команде dd Linux:


    dd if=imagewtyname.img of=dev/block/sda bs=1M seek=68
    или

    dd if=imagewtyname.img of=dev/block/sda bs=512 seek=139264

    Механизм этого копирования, наверно, интересен, но сейчас для нас не так уж важен. Скорее всего, он реализован в одном из многочисленных библиотечных файлов, входящих в состав Phoenix Card.


    6. Сравнение содержимого двух записанных карт

    1. Файлы bootloader.img для product и statrtup слегка отличаются друг от друга ! При этом оба отличаются от исходного файла boot-resource.fex из образа Это говорит о том, что Phoenix Card делает в них при записи какие-то изменения.

    2. Файлы gpt.img для product и statrtup слегка отличаются друг от друга, а также от исходной таблицы sunxi_gpt.fex из образа.

  • 1) Содержимое файла таблицы разделов StartUp отличается от Product

    Отличия такие:


      Параметр |StartUp | Product
  • 1. Header CRC32 | 1ADFDB56 | F11FCAD4
  • 2. Last Usable LBA | 15523838 | 15677438
  • 3. Partitions CRC32 | DD87AED8 | 3CC56A06
  • 4. Usable Size LBA | 15450111 | 15603711
  • 5. Usable Size Mbyte | 7544 | 7619

    То есть используемый размер для Product несколько больше, чем StartUp, это происходит из-за увеличения раздела UDISK на 75 Mb (143600 блоков)

  • StartUp UDISK - 7192542 (3511.98 Mb ) 8331264 - 15523805
  • Product UDISK - 7346142 (3586.98 Mb ) 8331264 - 15677405 + 33 = 15677438(Last Usable LBA)

    При этом в режиме StartUp Phoenix Card записывает после таблицы GPT (со смещением 0x01c00 от начала карты) усеченный заголовок Phoenix Table, который содержит сигнатуру PHOENIX_CARD_IMG (16 байт), и за ней 32-разрядное слово 0x00200100, а также два 16-разрядных слова 0x0c и 0x02.

    Такой заголовок полностью описывается структурой (см. phoenix_info.c):



    struct phoenix_ptable
    { char signature[16]; /* "PHOENIX_CARD_IMG" */
    unsigned int unknown1; /* 0x00200100 */
    unsigned short parts; /* Number of partitions */
    unsigned short unknown2; /* 0x0001 */
    unsigned char pad[8];
    struct phoenix_entry
       {
       unsigned int start; /* 512 bytes blocks */
       unsigned int size; /* bytes */
       unsigned int unknown;
       unsigned int sig; /* "add" */
       } part[62];
    }

    Однако здесь он имеет какой-то очень урезанный вид. Хотя, не исключено, что эта запись как-то используется загрузчиком при загрузке системы с карты, поскольку такой заголовок в режиме Product вообще не записывается.

  • 3. Файлы package.img для product и statrtup отличаются друг от друга всего в трех байтах, при этом входящие в них блобы dtb, dtbo, monitor не отличаются, за исключением u-boot.

    Отличия в 2-х байтах U-Boot (product -> startup):

  • 0x0c D4 -> C3
  • 0xe0 11 -> 00

    Не исключено, что эти значения определяют режим работы U-Boot (product - startup)


    ВНИМАНИЕ. Файл u-boot для StartUp идентичен файлу uboot.img, извлеченному из package исходного образа, а также файлу u_boot.fex из образа. Таким образом, эти два байта в блобе u-boot модифицируются утилитой Phoenix Card в режиме Product.

    Третий отличающийся байт в package.img с адресом 0x14 - это часть контрольной суммы .