Pular para o conteúdo
Fux da Sec
← voltar

Anatomia de uma ROM Android da Rockchip

·9 min·por Fux

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.

BASH
$ 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.

Depois de compilar as ferramentas, o img_unpack se usa assim:

PLAINTEXT
usage: ./img_unpack <source> <destination>

Executando a extração:

BASH
$ ./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....OK

O contêiner RKFW guarda uma imagem principal no formato RKAF (Rockchip Android Firmware). Vamos conferir o header do arquivo extraído:

BASH
$ 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.

PLAINTEXT
USAGE:
    afptool <-pack|-unpack> <Src> <Dest>
Example:
    afptool -pack xxx update.img    Pack files
    afptool -unpack update.img xxx  Unpack files

Executando o desempacotamento:

BASH
$ ./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:

PLAINTEXT
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
└── RESERVED

4. 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.

PLAINTEXT
# 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-script

As 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.

PLAINTEXT
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.

BASH
$ 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 .

BASH
$ 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.

BASH
$ 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 0x00xF: header KRNL (16 bytes).
  • A partir de um offset específico: o kernel comprimido em LZO.

Para extrair e descomprimir o kernel:

BASH
# 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.lzo

O 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 0x00x7: header KRNL (8 bytes).
  • A partir de 0x8: um arquivo gzip com o ramdisk em formato CPIO.
  • Fim do arquivo: alguns bytes de padding.

A assinatura 1f 8b 08 no offset 0x8 confirma o formato gzip.

BASH
$ 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):

BASH
# 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 < ../ramdisk

O 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.

BASH
$ 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:

BASH
# 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.

BASH
$ 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

PLAINTEXT
# 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,notrim

A 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