CPB解包:http://my.oschina.net/u/570986/blog/352839
用的cpbtool工具解包4.3.066.P3.140417.8730L.CPB文件,得到下列文件:
8626_msimage.mbn
boot.img
cache.img
dt.img
dummy.bin
efs1.bin
efs2.bin
efs3.bin
efs_image_meta.bin
emmc_appsboot.mbn
mba.mbn
mcfg_hw.mbn
mcfg_sw.mbn
MISC.img
MPRG8626.mbn
NON-HLOS.bin
nv.tar.mbn
panic.img
persist.img
PhoneInfo.yl
qdsp6sw.mbn
recovery.img
rpm.mbn
sbl1.mbn
sdi.mbn
system.img
tz.mbn
userdata.img
上面的解压出来的img文件与平常的img不同。boot.img和recovery.img不能用bootimg.exe解包(这是个别人用python写的,下载》这里)。以recovery.img为例:
前头填充了12字节,目前不知道什么用途。去掉这12字节后,用bootimg.exe还是不能解开,会提示“invalid bootimg”的错误。原因在于bootimg.exe工具还校验了ramdisk_addr、second_addr、tags_addr。
boot.img和recovery.img文件头格式如下:
#define BOOT_MAGIC "ANDROID!" #define BOOT_MAGIC_SIZE 8 #define BOOT_NAME_SIZE 16 #define BOOT_ARGS_SIZE 512 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 unused[2]; /* 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 */ };
bootimg.exe的python源码文件校验地址部分代码:
base = kernel_addr - 0x00008000 assert magic.decode('latin') == 'ANDROID!', 'invald bootimg' assert base == ramdisk_addr - 0x01000000, 'invalid bootimg' assert base == second_addr - 0x00f00000, 'invalid bootimg' assert base == tags_addr - 0x00000100, 'invalid bootimg'
修正这些地址域后就可以用bootimg.exe解开。但是bootimg.exe解开的并不完整, 4.3.066.P3.140417.8730L.CPB解开来的recovery.img还有一个qcdt节。猜测应该是qualcomm device tree节简称,高通cpu设备树。
qcdt节:
qcdt节下包含了两个dtb:
从qcdt节开始到文件结束都属于qcdt节的部分。因此封包程序不能用bootimg.exe封包成recovery.img,况且bootimg.exe封包并不会填充boot_img_hdr头的unsigned id[8];域,此域保存的是SHA1值。自己改的封包工具主要代码如下:
/* tools/mkbootimg/mkbootimg.c ** ** Copyright 2007, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #include <stdio.h> #include <stdlib.h> #include <string.h> //#include <unistd.h> #include <fcntl.h> #include <errno.h> #include <io.h> #include "sha.c" #include "bootimg.h" static void *load_file(const char *fn, unsigned *_sz) { char *data; int sz, ret; int fd; data = 0; fd = open(fn, O_RDONLY | _O_BINARY); if (fd < 0) return 0; sz = lseek(fd, 0, SEEK_END); if (sz < 0) goto oops; if (lseek(fd, 0, SEEK_SET) != 0) goto oops; data = (char*) malloc(sz); if (data == 0) { printf("malloc fail! File '%s' size: 0x%.8X(%u).\n", fn, sz, sz) ; goto oops; } ret = read(fd, data, sz) ; if (ret != sz) { printf("read error: %d! File '%s'.\n", ret, fn) ; goto oops; } close(fd); if (_sz) *_sz = sz; return data; oops: close(fd); if (data != 0) free(data); return 0; } int usage(void) { fprintf(stderr,"usage: mkbootimg\n" " --kernel <filename>\n" " --ramdisk <filename>\n" " [ --second <2ndbootloader-filename> ]\n" " [ --qcdt <qualcomm-bin-device-tree-filename> ]\n" " [ --cmdline <kernel-commandline> ]\n" " [ --board <boardname> ]\n" " [ --base <address> ]\n" " [ --pagesize <pagesize> ]\n" " -o|--output <filename>\n" ); return 1; } static unsigned char padding[4096] = { 0, }; int write_padding(int fd, unsigned pagesize, unsigned itemsize) { unsigned pagemask = pagesize - 1; unsigned count; if ((itemsize & pagemask) == 0) { return 0; } count = pagesize - (itemsize & pagemask); if (write(fd, padding, count) != count) { return -1; } else { return 0; } } int main(int argc, char **argv) { boot_img_hdr hdr; char *kernel_fn = 0; void *kernel_data = 0; char *ramdisk_fn = 0; void *ramdisk_data = 0; char *second_fn = 0; void *second_data = 0; char *qcdt_fn = NULL ; void *qcdt_data = NULL ; char *cmdline = ""; char *bootimg = 0; char *board = ""; unsigned pagesize = 2048; int fd; SHA_CTX ctx; uint8_t* sha; unsigned uiQcdtSize = 0 ; argc--; argv++; if (argc == 0) return usage() ; memset(&hdr, 0, sizeof(hdr)); /* default load addresses */ hdr.kernel_addr = 0x10008000; hdr.ramdisk_addr = 0x11000000; hdr.second_addr = 0x10F00000; hdr.tags_addr = 0x10000100; while (argc > 0) { char *arg = argv[0]; char *val = argv[1]; if (argc < 2) { return usage(); } argc -= 2; argv += 2; if (!strcmp(arg, "--output") || !strcmp(arg, "-o")) { bootimg = val; } else if (!strcmp(arg, "--kernel")) { kernel_fn = val; } else if (!strcmp(arg, "--ramdisk")) { ramdisk_fn = val; } else if (!strcmp(arg, "--second")) { second_fn = val; } else if (!strcmp(arg, "--qcdt")) { qcdt_fn = val ; } else if (!strcmp(arg, "--cmdline")) { cmdline = val; } else if (!strcmp(arg, "--base")) { unsigned base = strtoul(val, 0, 16); hdr.kernel_addr = base + 0x00008000; hdr.ramdisk_addr = base + 0x01000000; hdr.second_addr = base + 0x00F00000; hdr.tags_addr = base + 0x00000100; } else if (!strcmp(arg, "--board")) { board = val; } else if (!strcmp(arg,"--pagesize")) { pagesize = strtoul(val, 0, 10); if ((pagesize != 2048) && (pagesize != 4096)) { fprintf(stderr,"error: unsupported page size %d\n", pagesize); return -1; } } else { return usage(); } } hdr.page_size = pagesize; if (bootimg == 0) { fprintf(stderr,"error: no output filename specified\n"); return usage(); } if (kernel_fn == 0) { fprintf(stderr,"error: no kernel image specified\n"); return usage(); } if (ramdisk_fn == 0) { fprintf(stderr,"error: no ramdisk image specified\n"); return usage(); } if (strlen(board) >= BOOT_NAME_SIZE) { fprintf(stderr,"error: board name too large\n"); return usage(); } strcpy(hdr.name, board); memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE); if (strlen(cmdline) > (BOOT_ARGS_SIZE - 1)) { fprintf(stderr,"error: kernel commandline too large\n"); return 1; } strcpy((char*)hdr.cmdline, cmdline); kernel_data = load_file(kernel_fn, &hdr.kernel_size); if (kernel_data == 0) { fprintf(stderr,"error: could not load kernel '%s'\n", kernel_fn); return 1; } if (!strcmp(ramdisk_fn,"NONE")) { ramdisk_data = 0; hdr.ramdisk_size = 0; } else { ramdisk_data = load_file(ramdisk_fn, &hdr.ramdisk_size); if (ramdisk_data == 0) { fprintf(stderr,"error: could not load ramdisk '%s'\n", ramdisk_fn); return 1; } } if (second_fn) { second_data = load_file(second_fn, &hdr.second_size); if (second_data == 0) { fprintf(stderr,"error: could not load secondstage '%s'\n", second_fn); return 1; } } if (qcdt_fn) { qcdt_data = load_file(qcdt_fn, &uiQcdtSize); if (qcdt_data == 0) { fprintf(stderr,"error: could not load qualcomm binary device tree '%s'\n", qcdt_fn); return 1; } } /* put a hash of the contents in the header so boot images can be * differentiated based on their first 2k. */ SHA_init(&ctx); SHA_update(&ctx, kernel_data, hdr.kernel_size); SHA_update(&ctx, &hdr.kernel_size, sizeof(hdr.kernel_size)); SHA_update(&ctx, ramdisk_data, hdr.ramdisk_size); SHA_update(&ctx, &hdr.ramdisk_size, sizeof(hdr.ramdisk_size)); SHA_update(&ctx, second_data, hdr.second_size); SHA_update(&ctx, &hdr.second_size, sizeof(hdr.second_size)); if (qcdt_fn) { SHA_update(&ctx, qcdt_data, uiQcdtSize); SHA_update(&ctx, &uiQcdtSize, sizeof(uiQcdtSize)); // hdr.unused[0] = uiQcdtSize ; } sha = SHA_final(&ctx); memcpy(hdr.id, sha, SHA_DIGEST_SIZE > sizeof(hdr.id) ? sizeof(hdr.id) : SHA_DIGEST_SIZE); fd = open(bootimg, O_CREAT | O_TRUNC | O_WRONLY | _O_BINARY, 0644); if (fd < 0) { fprintf(stderr,"error: could not create '%s'\n", bootimg); return 1; } if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) goto fail; if (write_padding(fd, pagesize, sizeof(hdr))) goto fail; if (write(fd, kernel_data, hdr.kernel_size) != hdr.kernel_size) goto fail; if (write_padding(fd, pagesize, hdr.kernel_size)) goto fail; if (write(fd, ramdisk_data, hdr.ramdisk_size) != hdr.ramdisk_size) goto fail; if (write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail; if (second_data) { if (write(fd, second_data, hdr.second_size) != hdr.second_size) goto fail; if (write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail; } if (qcdt_data) { if (write(fd, qcdt_data, uiQcdtSize) != uiQcdtSize) goto fail; if (write_padding(fd, pagesize, uiQcdtSize)) goto fail; } free(kernel_data) ; free(ramdisk_data) ; free(second_data) ; free(qcdt_data) ; return 0; fail: free(kernel_data) ; free(ramdisk_data) ; free(second_data) ; free(qcdt_data) ; unlink(bootimg); close(fd); fprintf(stderr,"error: failed writing '%s': %s\n", bootimg, strerror(errno)); return 1; }
完整的代码》这里下载