酷派CPB升级文件中的recovery.img

用上篇的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为例:

酷派CPB升级文件中的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节:

酷派CPB升级文件中的recovery.img

qcdt节下包含了两个dtb:

酷派CPB升级文件中的recovery.img

酷派CPB升级文件中的recovery.img

从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;
}



酷派CPB升级文件中的recovery.img

完整的代码》这里下载


你可能感兴趣的:(酷派CPB升级文件中的recovery.img)