Android boot.img 格式分析

首先需要搞到boot.img,网络上流传的方法是通过/proc/mtd 在获取需要的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
> ./adb shell
> su
> cat /proc/mtd

dev: size erasesize name
mtd0: 00700000 00020000 "boot"
mtd1: 07c20000 00020000 "cache"
mtd2: 00700000 00020000 "recovery"
mtd3: 00140000 00020000 "splash"
mtd4: 00700000 00020000 "FOTA_STO"
mtd5: 09e80000 00020000 "system"
mtd6: 0a4e0000 00020000 "userdata"
mtd7: 00080000 00020000 "misc"
mtd8: 00180000 00020000 "persist"

但是在Nexus4, Android 4.4.4 已经找不到这个文件了

1
2
3
> cat /proc/mtd

cat: /proc/mtd: No such file or directory

但是还是有方法可以获取到需要的信息。

1
2
3
4
5
6
> mount

.....
/dev/block/platform/msm_sdcc.1/by-name/system /system ext4 ro,seclabel,relatime,data=ordered 0 0
/dev/block/platform/msm_sdcc.1/by-name/cache /cache ext4 rw,seclabel,nosuid,nodev,noatime,data=ordered 0 0
.....

可以看到大致上面的输出(上面的输出省略了部分内容),从输出中可以看出 /dev/block/platform/msm_sdcc.1/by-name
是一个比较有意思的路径,有by-name 的信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
> ls /dev/block/platform/msm_sdcc.1/by-name/

lrwxrwxrwx root root 2014-06-30 20:50 DDR -> /dev/block/mmcblk0p24
lrwxrwxrwx root root 2014-06-30 20:50 aboot -> /dev/block/mmcblk0p12
lrwxrwxrwx root root 2014-06-30 20:50 abootb -> /dev/block/mmcblk0p15
lrwxrwxrwx root root 2014-06-30 20:50 boot -> /dev/block/mmcblk0p6
lrwxrwxrwx root root 2014-06-30 20:50 cache -> /dev/block/mmcblk0p22
lrwxrwxrwx root root 2014-06-30 20:50 grow -> /dev/block/mmcblk0p25
lrwxrwxrwx root root 2014-06-30 20:50 m9kefs1 -> /dev/block/mmcblk0p8
lrwxrwxrwx root root 2014-06-30 20:50 m9kefs2 -> /dev/block/mmcblk0p9
lrwxrwxrwx root root 2014-06-30 20:50 m9kefs3 -> /dev/block/mmcblk0p10
lrwxrwxrwx root root 2014-06-30 20:50 metadata -> /dev/block/mmcblk0p18
lrwxrwxrwx root root 2014-06-30 20:50 misc -> /dev/block/mmcblk0p19
lrwxrwxrwx root root 2014-06-30 20:50 modem -> /dev/block/mmcblk0p1
lrwxrwxrwx root root 2014-06-30 20:50 persist -> /dev/block/mmcblk0p20
lrwxrwxrwx root root 2014-06-30 20:50 recovery -> /dev/block/mmcblk0p7
lrwxrwxrwx root root 2014-06-30 20:50 rpm -> /dev/block/mmcblk0p11
lrwxrwxrwx root root 2014-06-30 20:50 rpmb -> /dev/block/mmcblk0p16
lrwxrwxrwx root root 2014-06-30 20:50 sbl1 -> /dev/block/mmcblk0p2
lrwxrwxrwx root root 2014-06-30 20:50 sbl2 -> /dev/block/mmcblk0p3
lrwxrwxrwx root root 2014-06-30 20:50 sbl2b -> /dev/block/mmcblk0p13
lrwxrwxrwx root root 2014-06-30 20:50 sbl3 -> /dev/block/mmcblk0p4
lrwxrwxrwx root root 2014-06-30 20:50 sbl3b -> /dev/block/mmcblk0p14
lrwxrwxrwx root root 2014-06-30 20:50 system -> /dev/block/mmcblk0p21
lrwxrwxrwx root root 2014-06-30 20:50 tz -> /dev/block/mmcblk0p5
lrwxrwxrwx root root 2014-06-30 20:50 tzb -> /dev/block/mmcblk0p17
lrwxrwxrwx root root 2014-06-30 20:50 userdata -> /dev/block/mmcblk0p23

哈哈,一清二楚。

1
2
3
4
5
6
7
> dd if=/dev/block/mmcblk0p6 of=/sdcard/boot.img bs=4096
5632+0 records in
5632+0 records out
23068672 bytes transferred in 2.398 secs (9619963 bytes/sec)

>./adb pull /sdcard/boot.img /tmp/boot.img
4270 KB/s (23068672 bytes in 5.275s)

boot.img 主要由两部分组成,kernel 和 ramdisk,下面使用010editor来写一个模版,解析boot.img。从Android的源码可以知道boot.img的结构 app/aboot/bootimg.h

1
2
3
4
5
6
7
8
9
10
11
+-----------------+ 
| boot header | 1 page
+-----------------+
| kernel | n pages
+-----------------+
| ramdisk | m pages
+-----------------+
| second stage | o pages
+-----------------+
| device tree | p pages
+-----------------+
  boot header 的结构定义如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct boot_img_hdr
{
unsigned char magic[BOOT_MAGIC_SIZE];
unsigned kernel_size; /* size in bytes */
unsigned kernel_addr; /* physical load addr */
unsigned ramdisk_size; /* size in bytes */
unsigned ramdisk_addr; /* physical load addr */
unsigned second_size; /* size in bytes */
unsigned second_addr; /* physical load addr */
unsigned tags_addr; /* physical addr for kernel tags */
unsigned page_size; /* flash page size we assume */
unsigned dt_size; /* device_tree in bytes */
unsigned unused; /* future expansion: should be 0 */
unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */

unsigned char cmdline[BOOT_ARGS_SIZE];
unsigned id[8]; /* timestamp / checksum / sha1 / etc */
};

010editor 模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#define BOOT_MAGIC_SIZE 8
#define BOOT_NAME_SIZE 16
#define BOOT_ARGS_SIZE 512

typedef struct boot_img_hdr
{
char magic[BOOT_MAGIC_SIZE];
uint kernel_size; /* size in bytes */
uint kernel_addr; /* physical load addr */
uint ramdisk_size; /* size in bytes */
uint ramdisk_addr; /* physical load addr */
uint second_size; /* size in bytes */
uint second_addr; /* physical load addr */
uint tags_addr; /* physical addr for kernel tags */
uint page_size; /* flash page size we assume */
uint dt_size; /* device_tree in bytes */
uint unused; /* future expansion: should be 0 */
ubyte name[BOOT_NAME_SIZE]; /* asciiz product name */

ubyte cmdline[BOOT_ARGS_SIZE];
uint id[8]; /* timestamp / checksum / sha1 / etc */
}BOOT_IMG_HDR;

typedef struct boot_hdr {
BOOT_IMG_HDR header;
ubyte unused[header.page_size - sizeof(header)];
}HEADER;

LittleEndian();
HEADER header_section;

local uint page_size = header_section.header.page_size;
local uint kernel_size = header_section.header.kernel_size;
local uint ramdisk_size = header_section.header.ramdisk_size;
local uint second_size = header_section.header.second_size;

Printf("page_size: %x\nkernel_size: %x\nramdisk_size: %x\nsecond_size: %x\n", page_size, kernel_size, ramdisk_size, second_size);

local uint n = (kernel_size + page_size - 1) / page_size;
local uint m = (ramdisk_size + page_size - 1) / page_size;
local uint o = (second_size + page_size - 1) / page_size;

typedef struct kernel {
ubyte kernel_data[kernel_size];
ubyte unused[n * page_size - kernel_size];
}KERNEL;

KERNEL kernel_section;

typedef struct ramdisk {
ubyte ramdisk_data[ramdisk_size];
ubyte unused[m * page_size - ramdisk_size];
}RAMDISK;

RAMDISK ramdisk_section;

typedef struct second {
ubyte second_data[second_size];
ubyte unused[o * page_size - second_size];

}SECOND;

SECOND second_section;