1. Firmware Container Analysis (RKFW Format)
The starting point is a firmware image file, usually with an .img
extension. The first step is to identify its format. Using hexdump
, we can inspect the first few bytes of the file.
$ 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..|
The header analysis reveals the RKFW
signature. This is a container format used by Rockchip, primarily in factory update tools like the Rockchip Factory Tool.
2. Extracting the Main Image (RKFW → RKAF)
To extract the contents of the RKFW
container, we will use the img_unpack
tool from the rk2918_tools suite.
- Tool Repository: https://github.com/dayongxie/rk2918_tools
After compiling the tools, img_unpack
can be used as follows:
usage: ./img_unpack <source> <destination>
Executing the extraction:
$ ./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
The RKFW
container stores a main image in the RKAF
(Rockchip Android Firmware) format. Let’s verify the header of the extracted file:
$ 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 |................|
As expected, the RKAF
signature confirms a successful extraction.
3. Unpacking the RKAF Archive into Individual Partitions
The RKAF
file is a package that groups all the firmware partitions (boot.img
, system.img
, etc.). To unpack it, we use the afptool
, also part of rk2918_tools
.
USAGE:
afptool <-pack|-unpack> <Src> <Dest>
Example:
afptool -pack xxx update.img Pack files
afptool -unpack update.img xxx Unpack files
Executing the unpack process:
$ ./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!
The command created the partitions
directory with the following structure:
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. Analysis of Metadata Files
Before analyzing the partitions, let’s examine the generated metadata files.
package-file
This file acts as a manifest, mapping partition names to their respective image files.
# 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
Commented lines with garbled characters are remnants of text in other languages and can be ignored.
parameter.txt
This text file is crucial, as it defines boot parameters and the partition layout on the flash memory.
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)
Key Components:
- Metadata: Firmware version, device model, and manufacturer.
CMDLINE
: The command line passed to the Linux kernel during boot. It contains essential boot arguments.mtdparts
: Defines the flash memory (NAND/eMMC) layout, specifying the size, offset, and name of each partition.
5. Individual Partition Analysis
Now, let’s analyze each extracted image file.
MiniLoaderAll.bin
(Bootloader)
This is the first-stage bootloader. Its BOOTf
signature confirms its identity.
$ 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.........|
Its function is to initialize basic hardware and load the next boot stage, uboot.img
.
uboot.img
(U-Boot)
The second-stage bootloader, based on the popular Das U-Boot, with Rockchip customizations. Its signature is 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 ........|
It contains uncompressed ELF binaries (the executable format for Linux/Unix) and RSA signatures for integrity verification.
trust.img
(TrustZone)
This file contains the firmware for the TEE (Trusted Execution Environment), known as TrustZone. The TOS
(Trusted Operating System) signature identifies it.
$ 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 ........|
It is responsible for security-sensitive operations, such as cryptographic key management and secure boot.
kernel.img
(Linux Kernel)
This contains the operating system’s kernel. Its structure is:
- Offset
0x0
–0xF
:KRNL
header (16 bytes). - Starting from a specific offset: The LZO-compressed kernel.
To extract and decompress the 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.lzo
The result is a binary file containing the raw Linux kernel for the ARM architecture.
boot.img
and recovery.img
(Ramdisk)
In the Rockchip ecosystem, boot.img
and recovery.img
usually do not contain the kernel but rather the ramdisk (initramfs) for normal and recovery modes, respectively. Both have a similar structure:
- Offset
0x0
–0x7
:KRNL
header (8 bytes). - Starting from
0x8
: Agzip
file containing the ramdisk in CPIO format. - End of file: A few bytes of padding.
The 1f 8b 08
signature at offset 0x8
confirms the gzip
format.
$ 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,...........|
Extraction process (example with 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 < ../ramdisk
The result is the initial root file structure for Android.
system.img
, vendor.img
, oem.img
(System Partitions)
These images contain the main Android partitions. They are in the Android sparse image format, an optimization to save space by not storing empty blocks.
The magic number 0xED26FF3A
(read as 3A FF 26 ED
in little-endian) identifies this format.
$ 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 |:.&.............|
To access them, first convert them to a raw image and then mount them:
# 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
...
The same process applies to vendor.img
and oem.img
.
misc.img
This is a small partition used to pass commands between the system and recovery mode. It does not have a formatted filesystem; data is written to and read from specific offsets.
$ 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.............|
In the example, we see flags like boot-recovery
and recovery --wipe_all
.
Other Files
baseparameter.img
: A binary file with hardware parameters, such as video output settings (HDMI).resource.img
: A resource package (RSCE
) that can contain the Device Tree Blob (DTB) and other hardware configuration data.
6. Putting It All Together: The Filesystem Table (fstab
)
To understand how the system mounts these partitions during boot, we analyze the fstab
(filesystem table) file located inside the ramdisk extracted from boot.img
.
File: 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,notrim
The following table summarizes the mount order and types:
Source Partition (by-name ) | Mount Point | Filesystem (FS) |
---|---|---|
oem | /oem | ext4 |
cache | /cache | ext4 |
metadata | /metadata | ext4 |
misc | /misc | emmc (direct access) |
userdata | /data | f2fs |