Formato de firmware IMAGEWTY: estrutura e análise
Exploração técnica do formato de firmware IMAGEWTY, da sua estrutura e dos componentes que o formam.
O formato IMAGEWTY é usado pelas ferramentas LiveSuit, PhoenixSuit, PhoenixUSB e PhoenixCard, todas de código fechado, assim como seus protocolos e padrões.
Ferramentas de extração e repack
-
imgRePacker (Windows) Só funcionou no Windows, apesar de existir versão para Linux. Não conseguiu processar imagens com header
0x403. -
imagewty-tool (Linux) Funcional e ainda em desenvolvimento. Testado com sucesso em imagens com headers
0x300e0x403. -
AWUtils (Linux) Desatualizada, e a extração não funcionou como esperado (bugs).
Estrutura básica
O layout básico de uma imagem no formato IMAGEWTY pode ser representado assim:
Esta estrutura permite criar uma imagem válida mesmo sem os dados aleatórios (garbage) presentes nas imagens tradicionais. Numa visualização hexadecimal dá para observar dados adicionais de propósito desconhecido.
+------------------------------+
| Global Header (96 bytes) |
+------------------------------+
| Garbage / Unused (928 bytes) |
+------------------------------+
| File Header #1 (1024 bytes) |
+------------------------------+
| File Header #2 (1024 bytes) |
+------------------------------+
| File Header #3 (1024 bytes) |
+------------------------------+
| ... |
+------------------------------+
| File Header #48 (1024 bytes) |
+------------------------------+
| |
| File Data #1 |
| (size varies) |
| |
+------------------------------+
| |
| File Data #2 |
| (size varies) |
| |
+------------------------------+
| ... |
+------------------------------+
| |
| File Data #48 |
| (size varies) |
| |
+------------------------------+A imagem é composta por um header global, seguido dos headers individuais de cada arquivo e, por fim, dos arquivos em si.
No exemplo, a ilustração contém 48 arquivos, cada um com seu respectivo header.
Header global
Embora o header tenha 96 bytes, apenas 68 bytes são de fato usados. A estrutura é esta:
+---------+-----------+----------------------------------------+
| Offset | Size | Field / Description |
+---------+-----------+----------------------------------------+
| 0x00 | 8 bytes | Magic / Signature ("IMAGEWTY") |
| 0x08 | 4 bytes | Header Version |
| 0x0C | 4 bytes | Header Size |
| 0x10 | 4 bytes | Base RAM |
| 0x14 | 4 bytes | Format Version |
| 0x18 | 4 bytes | Total Image Size (compressed) |
| 0x1C | 4 bytes | Header Size Including Alignment |
| 0x20 | 4 bytes | File Header Length |
| 0x24 | 4 bytes | USB Product ID |
| 0x28 | 4 bytes | USB Vendor ID |
| 0x2C | 4 bytes | Hardware ID |
| 0x30 | 4 bytes | Firmware ID |
| 0x34 | 4 bytes | Unknown Field #1 |
| 0x38 | 4 bytes | Unknown Field #2 |
| 0x3C | 4 bytes | Number of Files in Archive |
| 0x40 | 4 bytes | Unknown Field #3 |
| 0x44… | padding | Zeros to align to Header Size (96 B) |
+---------+-----------+----------------------------------------+O header começa com a assinatura de 8 bytes “IMAGEWTY”. Os campos restantes são armazenados em blocos de 4 bytes, totalizando 68 bytes de dados reais. Os 28 bytes extras e a área de garbage de 928 bytes podem ser preenchidos com zeros.

Offset: de 0x000 a 0x3FF — inclui os 96 bytes de header e os 928 bytes de garbage, totalizando 1024 bytes.
Depois disso, os headers dos arquivos começam no offset 0x400.
Valores esperados
Valores presentes no header global da imagem de exemplo:
Magic / Signature = "IMAGEWTY"
Header Version = 0x300 (v3)
Header Size = 0x60 (96 Bytes)
Base RAM = 0x4D00000
Format Version = 0x100234
Total Size = 0xA34B3800 (2,612.70 MB)
Header + Alignment = 0x0 (0)
File Header Length = 0x400 (1024 Bytes)
USB Product ID = 0x1234
USB Vendor ID = 0x8743
Hardware ID = 0x100
Firmware ID = 0x100
Unknown Field #1 = 0x1 (1)
Unknown Field #2 = 0x400 (1024)
Number of Files = 0x30 (48)
Unknown Field #3 = 0x400 (1024)Como o arquivo é little-endian, os dados podem aparecer de outra forma quando vistos em hexadecimal.
- Header Size → tamanho do header global
- File Header Length → tamanho de cada header de arquivo
- Number of Files → total de arquivos na imagem
Headers dos arquivos
O primeiro header de arquivo começa no offset fixo 0x400, logo depois dos 1024 bytes do header global com o garbage.
Todos os arquivos seguem a mesma estrutura de header, com a maioria dos valores mudando muito pouco:
+------------+--------+----------------------+
| Offset | Size | Field |
+------------+--------+----------------------+
| 0x400 | 4 B | Filename Length |
| 0x404 | 4 B | Header Size |
| 0x408 | 8 B | Maintype |
| 0x410 | 16 B | Subtype |
| 0x420 | 4 B | Unknown0 |
| 0x424 | 256 B | Filename |
| 0x524 | 4 B | Stored Length |
| 0x528 | 4 B | Pad #1 |
| 0x52C | 4 B | Original Length |
| 0x530 | 4 B | Pad #2 |
| 0x534 | 4 B | File Offset |
| 0x538-0x7FF| 456 B | Garbage / Padding |
+------------+--------+----------------------+- Filename Length → tamanho do nome do arquivo
- Header Size → tamanho deste header de arquivo (normalmente 1024 bytes)
- Maintype → tipo principal (ex.:
"COMMON") - Subtype → subtipo (ex.:
"BOARD_CONFIG_BIN") - Filename → nome do arquivo, preenchido com nulos (ex.:
boot.fex) - Stored Length → tamanho armazenado do arquivo (com padding)
- Original Length → tamanho real do arquivo (sem padding)
- File Offset → posição inicial dos dados do arquivo
Valores esperados (exemplo: sys_config.fex)
Filename Length = 0x100 (256)
File Header Size = 0x400 (1024)
Maintype = "COMMON "
Subtype = "SYS_CONFIG100000"
Unknown = 0x0 (0)
Filename = "sys_config.fex"
Stored Length = 0x800 (2048)
Pad #1 = 0x0 (0)
File Length = 0x7BF (1983)
Pad #2 = 0x0 (0)
File Offset = 0xD800 (55296)- Stored Length → tamanho do arquivo incluindo o padding
- File Length → tamanho real do arquivo, sem padding
- File Offset → posição inicial do arquivo dentro da imagem
Header de arquivo preenchido com garbage
Visão geral
Nos testes que fiz, imagens geradas com o imagewty-tool e gravadas com o PhoenixSuit não apresentaram nenhum erro.
+------------------------------+
| Global Header (96 bytes) |
+------------------------------+
| Garbage / Unused (928 bytes) |
+------------------------------+
| File Header #1 (1024 bytes) | <- starts at offset 0x400
+------------------------------+
| File Header #2 (1024 bytes) |
+------------------------------+
| File Header #3 (1024 bytes) |
+------------------------------+
| ... |
+------------------------------+
| File Header #48 (1024 bytes) |
+------------------------------+
| |
| File Data #1 |
| (size varies) |
| |
+------------------------------+
| |
| File Data #2 |
| (size varies) |
| |
+------------------------------+
| ... |
+------------------------------+
| |
| File Data #48 |
| (size varies) |
| |
+------------------------------+Por enquanto, recomendo a leitura de:
- Estrutura da imagem de firmware do Android: http://nskhuman.ru/allwinner/firmware.php?np=1 O imagewty-tool e estes posts são baseados no “Structure of the Android firmware image”.
Também pode ser útil:
- Propósito dos arquivos na imagem de firmware: http://nskhuman.ru/allwinner/firmware.php?np=2
- Partições: como as seções são usadas: http://nskhuman.ru/allwinner/firmware.php?np=4
- Tabela de partições GPT: http://nskhuman.ru/allwinner/firmware.php?np=3
Próximo post
No próximo post vou tratar dos arquivos extraídos da imagem e de como modificá-los, como o boot.fex e o super.fex.
$ lsarisc.fex dlinfo.fex sys_config.fex Vboot-resource.fex
aultls32.fex dtbo.fex sys_partition.fex Vdtbo.fex
aultools.fex env.fex toc0.fex vendor_boot.fex
board.fex fes1.fex toc1.fex Venv.fex
boot0_nand.fex misc.fex u-boot-crash.fex Vmisc.fex
boot0_sdcard.fex Reserve0.fex u-boot.fex vmlinux.fex
boot.fex split_xxxx.fex usbtool_crash.fex VReserve0.fex
boot_package.fex sunxi.fex usbtool.fex Vsuper.fex
boot-resource.fex sunxi_gpt.fex vbmeta.fex Vvbmeta.fex
cardscript.fex sunxi_mbr.fex vbmeta_system.fex Vvbmeta_system.fex
cardtool.fex sunxi_version.fex vbmeta_vendor.fex Vvbmeta_vendor.fex
config.fex super.fex Vboot.fex Vvendor_boot.fex