MTK Logo 逆向解析之 bin 转 rawx

31 阅读11分钟

既然是逆向,当然是倒着来了,先来看 mkimage 源码

vendor\mediatek\proprietary\scripts\sign-image_v2\mkimage20\

文件夹中一共包含3个文件,img_hdr.cfg mkimage mkimage20.c 分别为 cfg 配置文件,可执行二进制文件,可执行文件源码

一、分析源码

代码中定义了结构体 IMG_HDR_T 用来存储一些 image 基本信息,我们主要关注 main

可以看到要想执行 mkimage 必须包含三个参数 Usage: ./mkimage <img_path> <cfg_path> > out_image

实际上最终执行命令为 ./mkimage merge.raw img_hdr_logo.cfg > logo.bin

merge.raw 是压缩以后 raw 文件

img_hdr_logo.cfg 配置文件内容 NAME = logo

初始化 IMG_HDR_T img_hdr 基本数据

img_hdr.info.dsize = (unsigned int)(filesize(argv[IMG_PATH_IDX]) & 0xffffffff); 存储 merge.raw 文件数据大小

get_img_hdr_setting_from_cfg(argv[IMG_CFG_IDX], &img_hdr); 解析 img_hdr_logo.cfg 中数据到结构体 img_hdr 中

img = readfile(argv[1], img_hdr.info.dsize); 读取 merge.raw 文件数据

write(STDOUT_FILENO, &img_hdr, sizeof(IMG_HDR_T)); write(STDOUT_FILENO, img, img_hdr.info.dsize); write(STDOUT_FILENO, img_padding, img_padding_size);

最终将头部信息数据、文件数据、偏移数据依次写入 logo.bin 中

整体代码比较简单,就是典型 c 代码读取文件写入文件,只是按照特定数据格式


#include <stdint.h>
#include <unistd.h>
#include <errno.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

#define IMG_MAGIC         0x58881688
#define EXT_MAGIC         0x58891689

#define IMG_NAME_SIZE       32
#define IMG_HDR_SIZE        512

/* image types */
#define IMG_TYPE_ID_OFFSET           (0)
#define IMG_TYPE_RESERVED0_OFFSET    (8)
#define IMG_TYPE_RESERVED1_OFFSET    (16)
#define IMG_TYPE_GROUP_OFFSET        (24)

#define IMG_TYPE_ID_MASK             (0xffU << IMG_TYPE_ID_OFFSET)
#define IMG_TYPE_RESERVED0_MASK      (0xffU << IMG_TYPE_RESERVED0_OFFSET)
#define IMG_TYPE_RESERVED1_MASK      (0xffU << IMG_TYPE_RESERVED1_OFFSET)
#define IMG_TYPE_GROUP_MASK          (0xffU << IMG_TYPE_GROUP_OFFSET)

#define IMG_TYPE_GROUP_AP            (0x00U << IMG_TYPE_GROUP_OFFSET)
#define IMG_TYPE_GROUP_MD            (0x01U << IMG_TYPE_GROUP_OFFSET)
#define IMG_TYPE_GROUP_CERT          (0x02U << IMG_TYPE_GROUP_OFFSET)

/* AP group */
#define IMG_TYPE_IMG_AP_BIN (0x00 | IMG_TYPE_GROUP_AP)

/* MD group */
#define IMG_TYPE_IMG_MD_LTE (0x00 | IMG_TYPE_GROUP_MD)
#define IMG_TYPE_IMG_MD_C2K (0x01 | IMG_TYPE_GROUP_MD)

/* CERT group */
#define IMG_TYPE_CERT1      (0x00 | IMG_TYPE_GROUP_CERT)
#define IMG_TYPE_CERT1_MD   (0x01 | IMG_TYPE_GROUP_CERT)
#define IMG_TYPE_CERT2      (0x02 | IMG_TYPE_GROUP_CERT)

#define HDR_VERSION         1

#define IMG_PATH_IDX        1
#define IMG_CFG_IDX         2

//#define DEBUG_MODE

typedef union {
	struct {
		unsigned int magic;     /* always IMG_MAGIC */
		unsigned int
		dsize;     /* image size, image header and padding are not included */
		char name[IMG_NAME_SIZE];
		unsigned int maddr;     /* image load address in RAM */
		unsigned int mode;      /* maddr is counted from the beginning or end of RAM */
		/* extension */
		unsigned int ext_magic;    /* always EXT_MAGIC */
		unsigned int
		hdr_size;     /* header size is 512 bytes currently, but may extend in the future */
		unsigned int hdr_version;  /* see HDR_VERSION */
		unsigned int
		img_type;     /* please refer to #define beginning with IMG_TYPE_ */
		unsigned int
		img_list_end; /* end of image list? 0: this image is followed by another image 1: end */
		unsigned int
		align_size;   /* image size alignment setting in bytes, 16 by default for AES encryption */
		unsigned int
		dsize_extend; /* high word of image size for 64 bit address support */
		unsigned int
		maddr_extend; /* high word of image load address in RAM for 64 bit address support */
	} info;
	unsigned char data[IMG_HDR_SIZE];
} IMG_HDR_T;

unsigned int filesize(char *name)
{
	struct stat statbuf;

	if (stat(name, &statbuf) != 0) {
		fprintf(stderr, "Cannot open file %s\n", name);
		exit(0);
	}
	return statbuf.st_size;
}

char *readfile(char *name, unsigned int size)
{
	FILE *f;
	char *buf = NULL;

	f = fopen(name, "rb");
	if (f == NULL) {
		fprintf(stderr, "Cannot open file %s\n", name);
		goto _end;
	}

	buf = (char *)malloc(size);
	if (!buf) {
		fprintf(stderr, "error while malloc(%d)\n", size);
		goto _error;
	}

	if (fread(buf, 1, size, f) != size) {
		fprintf(stderr, "Error while reading file %s\n", name);
		free(buf);
		buf = NULL;
		goto _error;
	}

_error:
	fclose(f);
_end:
	return buf;
}

char xtod(char c)
{
	if (c >= '0' && c <= '9') return c - '0';
	if (c >= 'A' && c <= 'F') return c - 'A' + 10;
	if (c >= 'a' && c <= 'f') return c - 'a' + 10;
	return 0;
}

unsigned long long hex2dec(char *hex, int l)
{
	if (*hex == 0)
		return l;
	return hex2dec(hex + 1, l * 16 + xtod(*hex));
}

unsigned long long xstr2int(char *hex)
{
	return hex2dec(hex, 0);
}

int remove_chr_from_string(char *string, char c)
{
	int final_str_len = 0;
	final_str_len = strlen(string);
	int i = 0;

	while (i < final_str_len) {
		if (string[i] == c) {
			memmove(&string[i], &string[i + 1], final_str_len - i - 1);
			final_str_len--;
			string[final_str_len] = 0;
		}
		i++;
	}

	return 0;
}

int get_img_hdr_setting_from_cfg(const char *cfg_path, IMG_HDR_T *img_hdr)
{
#define MAX_LINE_LENGTH  (80)
	int ret = 0;
	FILE *fp = NULL;
	char line[MAX_LINE_LENGTH] = {0};

	fp = fopen(cfg_path, "r");
	if (NULL == fp) {
		fprintf(stderr, "Cannot open file %s\n", cfg_path);
		exit(0);
	}

	while (fgets(line, MAX_LINE_LENGTH, fp) != NULL) {
		int i = 0;
		char *obj_name = NULL;
		char *obj_value_str = NULL;
		unsigned int obj_value = 0;
		ret = remove_chr_from_string(line, ' ');
		ret = remove_chr_from_string(line, '\n');
		obj_name  = strtok(line, "=");
		if (NULL == obj_name)
			continue;
		obj_value_str = strtok(NULL, "=");
		if (NULL == obj_value_str || !strcmp(obj_name, "NAME"))
			obj_value = 0;
		else if (obj_value_str[0] == '0' && obj_value_str[1] == 'x')
			obj_value = xstr2int(obj_value_str);
		else
			obj_value = atoi(obj_value_str);

#ifdef DEBUG_MODE
		fprintf(stderr, "name = %s, value_str = %s, value = %d\n", obj_name,
			obj_value_str, obj_value);
#endif

		if (!strcmp(obj_name, "LOAD_ADDR"))
			img_hdr->info.maddr = obj_value;
		else if (!strcmp(obj_name, "LOAD_ADDR_H"))
			img_hdr->info.maddr_extend = obj_value;
		else if (!strcmp(obj_name, "LOAD_MODE"))
			img_hdr->info.mode = obj_value;
		else if (!strcmp(obj_name, "NAME"))
			strncpy(img_hdr->info.name, obj_value_str, IMG_NAME_SIZE);
		else if (!strcmp(obj_name, "IMG_TYPE"))
			img_hdr->info.img_type = obj_value;
		else if (!strcmp(obj_name, "IMG_LIST_END"))
			img_hdr->info.img_list_end = obj_value;
		else if (!strcmp(obj_name, "ALIGN_SIZE"))
			img_hdr->info.align_size = obj_value;
		else {
#ifdef DEBUG_MODE
			fprintf(stderr, "==> unknown object\n");
#endif
		}
	}

	fclose(fp);
_end:
	return ret;
}

int main(int argc, char *argv[])
{
	IMG_HDR_T img_hdr;
	char *img = NULL;
	char *img_padding = NULL;
	uint32_t img_padding_size = 0;
	int ret = 0;

	if (argc != 3) {
		fprintf(stderr, "Usage: ./mkimage <img_path> <cfg_path> > out_image\n");
		return 0;
	}

	memset(&img_hdr, 0xff, sizeof(IMG_HDR_T));

	/* legacy fields */
	img_hdr.info.magic = IMG_MAGIC;
	img_hdr.info.dsize = (unsigned int)(filesize(argv[IMG_PATH_IDX]) & 0xffffffff);
	memset(img_hdr.info.name, 0x0, sizeof(img_hdr.info.name));
	img_hdr.info.maddr = 0xffffffff;
	img_hdr.info.mode = 0xffffffff;

	/* extension fields */
	img_hdr.info.ext_magic = EXT_MAGIC;
	img_hdr.info.hdr_size = IMG_HDR_SIZE;
	img_hdr.info.hdr_version = HDR_VERSION;
	img_hdr.info.img_type = IMG_TYPE_IMG_AP_BIN;
	img_hdr.info.img_list_end = 0;
	img_hdr.info.align_size = 16;
	img_hdr.info.dsize_extend = 0;
	img_hdr.info.maddr_extend = 0;

	/* if external config exists, use it to override */
	/* add code here */
	if (argc > IMG_CFG_IDX)
		ret = get_img_hdr_setting_from_cfg(argv[IMG_CFG_IDX], &img_hdr);
	if (ret)
		goto _error;

#ifdef DEBUG_MODE
	{
		int i = 0;
		for (i = 0; i < 512; i++) {
			fprintf(stderr, "%02x ", img_hdr.data[i]);
			if ((i + 1) % 16 == 0)
				fprintf(stderr, "\n");
		}
	}
#endif

	/* current implementation will encounter malloc fail issue if image size is extremely large */
	img = readfile(argv[1], img_hdr.info.dsize);
	img_padding_size = ((img_hdr.info.dsize + (img_hdr.info.align_size - 1)) /
			    img_hdr.info.align_size) * img_hdr.info.align_size - img_hdr.info.dsize;
#ifdef DEBUG_MODE
	fprintf(stderr, "img_padding_size = 0x%x\n", img_padding_size);
#endif
	img_padding = malloc(img_padding_size);
	if (img_padding)
		memset(img_padding, 0x0, img_padding_size);

	/* for linux version mkimage, we only support this method */
	write(STDOUT_FILENO, &img_hdr, sizeof(IMG_HDR_T));
	write(STDOUT_FILENO, img, img_hdr.info.dsize);
	write(STDOUT_FILENO, img_padding, img_padding_size);

	return 0;
_error:
	free(img);
	free(img_padding);
	exit(1);
}

二、改造源码

可以看到上面的源码中并不包含解包的逻辑,这就需要我们自己来添加了。

既然知道了打包的数据格式,结构体 img_hdr + img 数据 + 偏移数据

那么反过来也不是什么难事,我们需要的仅仅只是第二部分 img 数据

那就需要一个读取起始位置和结束位置,上面有个关键信息 img_hdr.info.dsize 就是要读取的数据长度

结构体 img_hdr 数据长度末尾就是要 img 数据起始位置

下面代码进行了优化,仅仅只为了打包和解包 logo.bin 所以将原来 cfg 文件读取删掉了,直接默认赋值 logo

增加参数判断,-l 打包 -d 解包

#include <stdint.h>
#include <unistd.h>
#include <errno.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

#define IMG_MAGIC         0x58881688
#define EXT_MAGIC         0x58891689

#define IMG_NAME_SIZE       32
#define IMG_HDR_SIZE        512

/* image types */
#define IMG_TYPE_ID_OFFSET           (0)
#define IMG_TYPE_RESERVED0_OFFSET    (8)
#define IMG_TYPE_RESERVED1_OFFSET    (16)
#define IMG_TYPE_GROUP_OFFSET        (24)

#define IMG_TYPE_ID_MASK             (0xffU << IMG_TYPE_ID_OFFSET)
#define IMG_TYPE_RESERVED0_MASK      (0xffU << IMG_TYPE_RESERVED0_OFFSET)
#define IMG_TYPE_RESERVED1_MASK      (0xffU << IMG_TYPE_RESERVED1_OFFSET)
#define IMG_TYPE_GROUP_MASK          (0xffU << IMG_TYPE_GROUP_OFFSET)

#define IMG_TYPE_GROUP_AP            (0x00U << IMG_TYPE_GROUP_OFFSET)
#define IMG_TYPE_GROUP_MD            (0x01U << IMG_TYPE_GROUP_OFFSET)
#define IMG_TYPE_GROUP_CERT          (0x02U << IMG_TYPE_GROUP_OFFSET)

/* AP group */
#define IMG_TYPE_IMG_AP_BIN (0x00 | IMG_TYPE_GROUP_AP)

/* MD group */
#define IMG_TYPE_IMG_MD_LTE (0x00 | IMG_TYPE_GROUP_MD)
#define IMG_TYPE_IMG_MD_C2K (0x01 | IMG_TYPE_GROUP_MD)

/* CERT group */
#define IMG_TYPE_CERT1      (0x00 | IMG_TYPE_GROUP_CERT)
#define IMG_TYPE_CERT1_MD   (0x01 | IMG_TYPE_GROUP_CERT)
#define IMG_TYPE_CERT2      (0x02 | IMG_TYPE_GROUP_CERT)

#define HDR_VERSION         1

#define IMG_PATH_IDX        2
#define IMG_CFG_IDX         2

#define DEBUG_MODE

typedef union {
	struct {
		unsigned int magic;     /* always IMG_MAGIC */
		unsigned int
		dsize;     /* image size, image header and padding are not included */
		char name[IMG_NAME_SIZE];
		unsigned int maddr;     /* image load address in RAM */
		unsigned int mode;      /* maddr is counted from the beginning or end of RAM */
		/* extension */
		unsigned int ext_magic;    /* always EXT_MAGIC */
		unsigned int
		hdr_size;     /* header size is 512 bytes currently, but may extend in the future */
		unsigned int hdr_version;  /* see HDR_VERSION */
		unsigned int
		img_type;     /* please refer to #define beginning with IMG_TYPE_ */
		unsigned int
		img_list_end; /* end of image list? 0: this image is followed by another image 1: end */
		unsigned int
		align_size;   /* image size alignment setting in bytes, 16 by default for AES encryption */
		unsigned int
		dsize_extend; /* high word of image size for 64 bit address support */
		unsigned int
		maddr_extend; /* high word of image load address in RAM for 64 bit address support */
	} info;
	unsigned char data[IMG_HDR_SIZE];
} IMG_HDR_T;

unsigned int filesize(char *name)
{
	struct stat statbuf;

	if (stat(name, &statbuf) != 0) {
		fprintf(stderr, "Cannot open file %s\n", name);
		exit(0);
	}
	return statbuf.st_size;
}

char *readfile(char *name, unsigned int size)
{
	FILE *f;
	char *buf = NULL;

	f = fopen(name, "rb");
	if (f == NULL) {
		fprintf(stderr, "Cannot open file %s\n", name);
		goto _end;
	}

	buf = (char *)malloc(size);
	if (!buf) {
		fprintf(stderr, "error while malloc(%d)\n", size);
		goto _error;
	}

	//从文件 f 中读取占用 size*1 个字节的数据,存储到 buf
	if (fread(buf, 1, size, f) != size) {
		fprintf(stderr, "Error while reading file %s\n", name);
		free(buf);
		buf = NULL;
		goto _error;
	}

_error:
	fclose(f);
_end:
	return buf;
}

char xtod(char c)
{
	if (c >= '0' && c <= '9') return c - '0';
	if (c >= 'A' && c <= 'F') return c - 'A' + 10;
	if (c >= 'a' && c <= 'f') return c - 'a' + 10;
	return 0;
}

unsigned long long hex2dec(char *hex, int l)
{
	if (*hex == 0)
		return l;
	return hex2dec(hex + 1, l * 16 + xtod(*hex));
}

unsigned long long xstr2int(char *hex)
{
	return hex2dec(hex, 0);
}

int remove_chr_from_string(char *string, char c)
{
	int final_str_len = 0;
	final_str_len = strlen(string);
	int i = 0;

	while (i < final_str_len) {
		if (string[i] == c) {
			memmove(&string[i], &string[i + 1], final_str_len - i - 1);
			final_str_len--;
			string[final_str_len] = 0;
		}
		i++;
	}

	return 0;
}

int get_img_hdr_setting_from_cfg(const char *cfg_path, IMG_HDR_T *img_hdr)
{
#define MAX_LINE_LENGTH  (80)
	int ret = 0;
	FILE *fp = NULL;
	char line[MAX_LINE_LENGTH] = {0};

	fp = fopen(cfg_path, "r");
	if (NULL == fp) {
		fprintf(stderr, "Cannot open file %s\n", cfg_path);
		exit(0);
	}

	while (fgets(line, MAX_LINE_LENGTH, fp) != NULL) {
		int i = 0;
		char *obj_name = NULL;
		char *obj_value_str = NULL;
		unsigned int obj_value = 0;
		ret = remove_chr_from_string(line, ' ');
		ret = remove_chr_from_string(line, '\n');
		obj_name  = strtok(line, "=");
		if (NULL == obj_name)
			continue;
		obj_value_str = strtok(NULL, "=");
		if (NULL == obj_value_str || !strcmp(obj_name, "NAME"))
			obj_value = 0;
		else if (obj_value_str[0] == '0' && obj_value_str[1] == 'x')
			obj_value = xstr2int(obj_value_str);
		else
			obj_value = atoi(obj_value_str);

#ifdef DEBUG_MODE
		fprintf(stderr, "name = %s, value_str = %s, value = %d\n", obj_name,
			obj_value_str, obj_value);
#endif

		if (!strcmp(obj_name, "LOAD_ADDR"))
			img_hdr->info.maddr = obj_value;
		else if (!strcmp(obj_name, "LOAD_ADDR_H"))
			img_hdr->info.maddr_extend = obj_value;
		else if (!strcmp(obj_name, "LOAD_MODE"))
			img_hdr->info.mode = obj_value;
		else if (!strcmp(obj_name, "NAME"))
			strncpy(img_hdr->info.name, obj_value_str, IMG_NAME_SIZE);
		else if (!strcmp(obj_name, "IMG_TYPE"))
			img_hdr->info.img_type = obj_value;
		else if (!strcmp(obj_name, "IMG_LIST_END"))
			img_hdr->info.img_list_end = obj_value;
		else if (!strcmp(obj_name, "ALIGN_SIZE"))
			img_hdr->info.align_size = obj_value;
		else {
#ifdef DEBUG_MODE
			fprintf(stderr, "==> unknown object\n");
#endif
		}
	}

	fclose(fp);
_end:
	return ret;
}

int main(int argc, char *argv[])
{
	IMG_HDR_T img_hdr;
	char *img = NULL;
	char *img_padding = NULL;
	uint32_t img_padding_size = 0;
	int ret = 0;

	if (argc < 2) {
		fprintf(stderr, "pack:   ./mkimage20 -l logo.raw > logo.bin\n");
		fprintf(stderr, "unpack: ./mkimage20 -d logo.bin logo.raw \n");
		return 0;
	}

	// pack image
	if(!strcmp(argv[1], "-l"))
	{
		//用长度为sizeof(IMG_HDR_T)的初始值0xff 填充 img_hdr 内存
		memset(&img_hdr, 0xff, sizeof(IMG_HDR_T));

		/* legacy fields */
		img_hdr.info.magic = IMG_MAGIC;//0x58881688
		//计算 logo.raw 文件大小
		img_hdr.info.dsize = (unsigned int)(filesize(argv[IMG_PATH_IDX]) & 0xffffffff);
		//用长度为sizeof(name)的初始值 0x0 填充 name 内存
		memset(img_hdr.info.name, 0x0, sizeof(img_hdr.info.name));
		img_hdr.info.maddr = 0xffffffff;
		img_hdr.info.mode = 0xffffffff;

		/* extension fields */
		img_hdr.info.ext_magic = EXT_MAGIC;//0x58891689
		img_hdr.info.hdr_size = IMG_HDR_SIZE;//512
		img_hdr.info.hdr_version = HDR_VERSION;//1
		img_hdr.info.img_type = IMG_TYPE_IMG_AP_BIN;//(0x00 | (0x00U << 24))
		img_hdr.info.img_list_end = 0;
		img_hdr.info.align_size = 16;
		img_hdr.info.dsize_extend = 0;
		img_hdr.info.maddr_extend = 0;

		/* if external config exists, use it to override */
		/* add code here */
		//重新从 cfg 文件中读取 name 值, NAME = logo   img_hdr.info.name=logo
		strncpy(img_hdr.info.name, "logo", IMG_NAME_SIZE);
		/*if (argc > IMG_CFG_IDX)
			ret = get_img_hdr_setting_from_cfg(argv[IMG_CFG_IDX], &img_hdr);
		if (ret)
			goto _error;*/

		#ifdef DEBUG_MODE
			{
				int i = 0;
				for (i = 0; i < 512; i++) {
					fprintf(stderr, "%02x ", img_hdr.data[i]);
					if ((i + 1) % 16 == 0)
						fprintf(stderr, "\n");
				}
			}
		#endif

		/* current implementation will encounter malloc fail issue if image size is extremely large */
		//读取 logo.raw 文件数据
		img = readfile(argv[IMG_PATH_IDX], img_hdr.info.dsize);
		//计算偏移数据
		img_padding_size = ((img_hdr.info.dsize + (img_hdr.info.align_size - 1)) /
				    img_hdr.info.align_size) * img_hdr.info.align_size - img_hdr.info.dsize;
	#ifdef DEBUG_MODE
		fprintf(stderr, "img_padding_size = 0x%x\n", img_padding_size);
		fprintf(stderr, "info.dsize = 0x%x\n", img_hdr.info.dsize);
	#endif
		img_padding = malloc(img_padding_size);
		if (img_padding)
			memset(img_padding, 0x0, img_padding_size);

		/* for linux version mkimage, we only support this method */
		write(STDOUT_FILENO, &img_hdr, sizeof(IMG_HDR_T));
		write(STDOUT_FILENO, img, img_hdr.info.dsize);
		write(STDOUT_FILENO, img_padding, img_padding_size);

		return 0;
	_error:
		free(img);
		free(img_padding);
		exit(1);
	}
	else//unpack logo.bin
	{
	    FILE *input = fopen(argv[2], "rb");
	    if (!input) {
	        perror("Error opening input file");
	        return 1;
	    }

	    FILE *output = fopen(argv[3], "wb");
	    if (!output) {
	        perror("Error opening output file");
	        fclose(input);
	        return 1;
	    }

	    //读取结构体数据,获取真正raw部分数据长度
	    // IMG_HDR_T img_hdr;
	    memset(&img_hdr, 0xff, sizeof(IMG_HDR_T));
	    int count = fread(&img_hdr, 1, sizeof(IMG_HDR_T), input);
	#ifdef DEBUG_MODE
	    fprintf(stderr, "count: %d \n", count);
	    fprintf(stderr, "align_size: %d \n", img_hdr.info.align_size);
	    fprintf(stderr, "info.dsize: 0x%x\n", img_hdr.info.dsize);
	    fprintf(stderr, "info.dsize: %d \n", img_hdr.info.dsize);
	#endif
	    // fclose(input);

	    // 跳过头部
	    if (fseek(input, IMG_HDR_SIZE, SEEK_SET) != 0) {
	        perror("Error seeking in input file");
	        fclose(input);
	        fclose(output);
	        return 1;
	    }

	    // 从input复制数据到output
	    uint8_t buffer[img_hdr.info.dsize];//4096
	    size_t bytesRead;
	    while ((bytesRead = fread(buffer, 1, sizeof(buffer), input)) > 0) {
	    	#ifdef DEBUG_MODE
	        	fprintf(stderr, "bytesRead: %d \n", bytesRead);
	        #endif
	        if (bytesRead == img_hdr.info.dsize)
	        {
	            fwrite(buffer, 1, bytesRead, output);
	        }else{//跳过尾部偏移数据
	            break;
	        }
	    }

	    fclose(input);
	    fclose(output);
	    return 0;
	}
}

三、编译指令

gcc -o mkimage20 mkimage20.c -lz

mkimage20下载

四、解包 bin 文件

使用方法

pack:
./mkimage20 -l logo.raw > logo.bin

unpack: ./mkimage20 -d logo.bin logo.raw