Anatomia de uma ROM Android da Rockchip
Desempacotando e analisando uma imagem de firmware para dispositivos Rockchip RK322x, da imagem de fábrica até a extração das partições do Android.
1. Análise do contêiner de firmware (formato RKFW)
O ponto de partida é um arquivo de imagem de firmware, normalmente com extensão .img. O primeiro passo é identificar o formato dele. Com o hexdump, dá para inspecionar os primeiros bytes do arquivo.
$ hexdump -C rom_rk322x.img | head -n2
00000000 52 4b 46 57 66 00 00 00 00 08 00 00 06 01 e2 07 |RKFWf...........|
00000010 0c 11 16 21 32 41 32 32 33 66 00 00 00 4e a9 02 |...!2A223f...N..|A análise do header revela a assinatura RKFW. É um formato de contêiner usado pela Rockchip, principalmente em ferramentas de atualização de fábrica como o Rockchip Factory Tool.
2. Extraindo a imagem principal (RKFW → RKAF)
Para extrair o conteúdo do contêiner RKFW, vamos usar a ferramenta img_unpack, do conjunto rk2918_tools.
- Repositório da ferramenta: https://github.com/dayongxie/rk2918_tools
Depois de compilar as ferramentas, o img_unpack se usa assim:
usage: ./img_unpack <source> <destination>Executando a extração:
$ ./rk2918_tools/img_unpack rom_rk322x.img rom.img
rom version: 8.0.0
build time: 2018-12-17 22:33:50
chip: 33323241
checking md5sum....OKO contêiner RKFW guarda uma imagem principal no formato RKAF (Rockchip Android Firmware). Vamos conferir o header do arquivo extraído:
$ hexdump -C rom.img | head -n 2
00000000 52 4b 41 46 00 f0 c8 4c 52 4b 33 32 32 78 00 00 |RKAF...LRK322x..|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|Como esperado, a assinatura RKAF confirma que a extração deu certo.
3. Desempacotando o RKAF em partições individuais
O arquivo RKAF é um pacote que agrupa todas as partições do firmware (boot.img, system.img etc.). Para desempacotá-lo usamos o afptool, também parte do rk2918_tools.
USAGE:
afptool <-pack|-unpack> <Src> <Dest>
Example:
afptool -pack xxx update.img Pack files
afptool -unpack update.img xxx Unpack filesExecutando o desempacotamento:
$ ./rk2918_tools/afptool -unpack rom.img partitions
Check file...OK
------- UNPACK -------
package-file 0x00000800 0x000002D4
Image/MiniLoaderAll.bin 0x00001000 0x0002A94E
Image/parameter.txt 0x0002C000 0x00000400
Image/trust.img 0x0002C800 0x00400000
Image/uboot.img 0x0042C800 0x00400000
Image/misc.img 0x0082C800 0x0000C000
Image/baseparameter.img 0x00838800 0x00100000
Image/resource.img 0x00938800 0x00BE7A00
Image/kernel.img 0x01520800 0x007AED94
Image/boot.img 0x01CCF800 0x00189138
Image/recovery.img 0x01E59000 0x006E8F1C
Image/system.img 0x02542000 0x44214B84
Image/vendor.img 0x46757000 0x0650E51C
Image/oem.img 0x4CC65800 0x0002907C
RESERVED 0x00000000 0x00000000
UnPack OK!O comando criou o diretório partitions com a seguinte estrutura:
partitions/
├── Image
│ ├── baseparameter.img
│ ├── boot.img
│ ├── kernel.img
│ ├── MiniLoaderAll.bin
│ ├── misc.img
│ ├── oem.img
│ ├── parameter.txt
│ ├── recovery.img
│ ├── resource.img
│ ├── system.img
│ ├── trust.img
│ ├── uboot.img
│ └── vendor.img
├── package-file
└── RESERVED4. Análise dos arquivos de metadados
Antes de analisar as partições, vamos examinar os arquivos de metadados gerados.
package-file
Este arquivo funciona como um manifesto, mapeando nomes de partição para os respectivos arquivos de imagem.
# NAME Relative path
#
#HWDEF HWDEF
package-file package-file
bootloader Image/MiniLoaderAll.bin
parameter Image/parameter.txt
trust Image/trust.img
uboot Image/uboot.img
misc Image/misc.img
baseparameter Image/baseparameter.img
resource Image/resource.img
kernel Image/kernel.img
boot Image/boot.img
recovery Image/recovery.img
system Image/system.img
vendor Image/vendor.img
oem Image/oem.img
# Ҫд��backup�������ļ�����������update.img��
# SELF �ǹؼ��֣���ʾ�����ļ���update.img������
# �����������ļ�ʱ��������SELF�ļ������ݣ�����ͷ����Ϣ���м�¼
# �ڽ�������ļ�ʱ�������SELF�ļ������ݡ�
backup RESERVED
#update-script update-script
#recover-script recover-scriptAs linhas comentadas com caracteres corrompidos são resquícios de texto em outros idiomas e podem ser ignoradas.
parameter.txt
Este arquivo de texto é fundamental, porque define os parâmetros de boot e o layout das partições na memória flash.
FIRMWARE_VER:8.0
MACHINE_MODEL:RK322x
MACHINE_ID:007
MANUFACTURER:Rockchip
MAGIC: 0x5041524B
ATAG: 0x00200800
MACHINE: 322x
CHECK_MASK: 0x80
PWR_HLD: 0,0,A,0,1
CMDLINE: console=ttyFIQ0 androidboot.baseband=N/A androidboot.selinux=permissive androidboot.wificountrycode=US androidboot.veritymode=/dev/block/platform/30020000.dwmmc/by-name/metadata androidboot.hardware=rk30board androidboot.console=ttyFIQ0 firmware_class.path=/vendor/etc/firmware init=/init initrd=0x62000000,0x00800000 mtdparts=rk29xxnand:0x00002000@0x00002000(uboot),0x00002000@0x00004000(trust),0x00002000@0x00006000(misc),0x00000800@0x00008000(baseparameter),0x00008000@0x00008800(resource),0x00010000@0x00010800(kernel),0x00010000@0x00020800(boot),0x00020000@0x00030800(recovery),0x00008000@0x00050800(backup),0x00080000@0x00058800(cache),0x00300000@0x000d8800(system),0x00008000@0x003d8800(metadata),0x00080000@0x003e0800(vendor),0x00042000@0x00460800(oem),0x00000400@0x004a2800(frp),0x00001000@0x004a2c00(security),-@0x004a3c00(userdata)Componentes principais:
- Metadados: versão do firmware, modelo do dispositivo e fabricante.
CMDLINE: a linha de comando passada ao kernel do Linux durante o boot. Contém argumentos essenciais de inicialização.mtdparts: define o layout da memória flash (NAND/eMMC), especificando tamanho, offset e nome de cada partição.
5. Análise das partições individuais
Agora vamos analisar cada arquivo de imagem extraído.
MiniLoaderAll.bin (bootloader)
Este é o bootloader de primeiro estágio. A assinatura BOOTf confirma a identidade dele.
$ hexdump -C Image/MiniLoaderAll.bin | head -n 1
00000000 42 4f 4f 54 66 00 38 02 00 00 00 00 03 01 e2 07 |BOOTf.8.........|Sua função é inicializar o hardware básico e carregar o estágio seguinte do boot, o uboot.img.
uboot.img (U-Boot)
O bootloader de segundo estágio, baseado no popular Das U-Boot, com customizações da Rockchip. Sua assinatura é LOADER .
$ hexdump -C Image/uboot.img | head -n 1
00000000 4c 4f 41 44 45 52 20 20 00 00 00 00 00 00 00 00 |LOADER ........|Ele contém binários ELF não comprimidos (o formato executável do Linux/Unix) e assinaturas RSA para verificação de integridade.
trust.img (TrustZone)
Este arquivo contém o firmware do TEE (Trusted Execution Environment), conhecido como TrustZone. A assinatura TOS (Trusted Operating System) o identifica.
$ hexdump -C Image/trust.img | head -n 1
00000000 54 4f 53 20 20 20 20 20 00 00 00 00 00 00 00 00 |TOS ........|Ele é responsável pelas operações sensíveis à segurança, como gerenciamento de chaves criptográficas e secure boot.
kernel.img (kernel do Linux)
Contém o kernel do sistema operacional. Sua estrutura é:
- Offset
0x0–0xF: headerKRNL(16 bytes). - A partir de um offset específico: o kernel comprimido em LZO.
Para extrair e descomprimir o kernel:
# 1. Extract the LZO stream (adjust 'skip' and 'count' based on the image)
$ dd if=Image/kernel.img of=kernel.lzo bs=1 skip=$((0x3C1C)) count=8040763
# 2. Decompress with lzop
$ lzop -d kernel.lzoO resultado é um arquivo binário com o kernel do Linux puro para a arquitetura ARM.
boot.img e recovery.img (ramdisk)
No ecossistema da Rockchip, o boot.img e o recovery.img normalmente não contêm o kernel, e sim o ramdisk (initramfs) dos modos normal e de recuperação, respectivamente. Os dois têm estrutura parecida:
- Offset
0x0–0x7: headerKRNL(8 bytes). - A partir de
0x8: um arquivogzipcom o ramdisk em formato CPIO. - Fim do arquivo: alguns bytes de padding.
A assinatura 1f 8b 08 no offset 0x8 confirma o formato gzip.
$ hexdump -C Image/boot.img | head -n 1
00000000 4b 52 4e 4c 2c 91 18 00 1f 8b 08 00 00 00 00 00 |KRNL,...........|Processo de extração (exemplo com o boot.img):
# 1. Extract the gzip file (adjust 'count' according to its size)
$ dd if=Image/boot.img of=ramdisk.gz bs=1 skip=8 count=1610027
# 2. Decompress the ramdisk
$ gunzip ramdisk.gz
# 3. Extract the contents of the CPIO archive
$ mkdir ramdisk_contents
$ cd ramdisk_contents
$ cpio -idmv < ../ramdiskO resultado é a estrutura inicial de arquivos raiz do Android.
system.img, vendor.img, oem.img (partições do sistema)
Estas imagens contêm as principais partições do Android. Estão no formato Android sparse image, uma otimização que economiza espaço ao não armazenar os blocos vazios.
O número mágico 0xED26FF3A (lido como 3A FF 26 ED em little-endian) identifica esse formato.
$ hexdump -C Image/system.img | head -n 1
00000000 3a ff 26 ed 01 00 00 00 1c 00 0c 00 00 10 00 00 |:.&.............|Para acessá-las, primeiro converta para imagem raw e depois monte:
# 1. Convert the sparse image to a raw image
$ simg2img Image/system.img system_raw.img
# 2. Create a mount point and mount the image
$ mkdir sys_mount
$ sudo mount -o loop system_raw.img sys_mount
# 3. List the contents
$ ls sys_mount/
app etc lib media usr
bin fake-libs lib64 preinstall vendor
build.prop fonts lost+found priv-app xbin
...O mesmo processo vale para o vendor.img e o oem.img.
misc.img
Esta é uma partição pequena, usada para passar comandos entre o sistema e o modo de recuperação. Ela não tem sistema de arquivos formatado; os dados são escritos e lidos em offsets específicos.
$ hexdump -C Image/misc.img | tail
00004000 62 6f 6f 74 2d 72 65 63 6f 76 65 72 79 00 00 00 |boot-recovery...|
00004010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00004040 72 65 63 6f 76 65 72 79 0a 2d 2d 77 69 70 65 5f |recovery.--wipe_|
00004050 61 6c 6c 00 00 00 00 00 00 00 00 00 00 00 00 00 |all.............|No exemplo, vemos flags como boot-recovery e recovery --wipe_all.
Outros arquivos
baseparameter.img: um arquivo binário com parâmetros de hardware, como configurações de saída de vídeo (HDMI).resource.img: um pacote de recursos (RSCE) que pode conter o Device Tree Blob (DTB) e outros dados de configuração de hardware.
6. Juntando tudo: a tabela de sistemas de arquivos (fstab)
Para entender como o sistema monta essas partições durante o boot, analisamos o arquivo fstab (filesystem table), que fica dentro do ramdisk extraído do boot.img.
Arquivo: ramdisk_contents/fstab.rk30board
# Android fstab file
#<src> <mnt_point> <type> <mnt_flags and options> <fs_mgr_flags>
# The filesystem that contains the filesystem checker binary (typically /system) cannot
# specify MF_CHECK, and must come before any filesystems that do specify MF_CHECK
/dev/block/by-name/oem /oem ext4 ro,noatime,nodiratime,noauto_da_alloc wait,check
/dev/block/by-name/cache /cache ext4 noatime,nodiratime,nosuid,nodev,noauto_da_alloc,discard wait,check
/dev/block/by-name/metadata /metadata ext4 noatime,nodiratime,nosuid,nodev,noauto_da_alloc,discard wait
/dev/block/by-name/misc /misc emmc defaults defaults
/devices/platform/*usb* auto vfat defaults voldmanaged=usb:auto
/dev/block/zram0 none swap defaults wait,zramsize=50%,notrim
# For sdmmc
/devices/platform/30000000.dwmmc/mmc_host* auto auto defaults voldmanaged=sdcard1:auto,encryptable=userdata
# Full disk encryption has less effect on rk322x, so default to enable this.
#/dev/block/by-name/userdata /data f2fs noatime,nodiratime,nosuid,nodev,discard,inline_xattr wait,check,notrim,encryptable=/metadata/key_file,quota
/dev/block/by-name/userdata /data f2fs noatime,nodiratime,nosuid,nodev,discard,inline_xattr wait,check,notrimA tabela a seguir resume a ordem de montagem e os tipos:
Partição de origem (by-name) |
Ponto de montagem | Sistema de arquivos (FS) |
|---|---|---|
oem |
/oem |
ext4 |
cache |
/cache |
ext4 |
metadata |
/metadata |
ext4 |
misc |
/misc |
emmc (acesso direto) |
userdata |
/data |
f2fs |
