既然是逆向,当然是倒着来了,先来看 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
实际上最终执行命令为 ./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 > 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
使用方法
pack:
./mkimage20 -l logo.raw > logo.bin
unpack:
./mkimage20 -d logo.bin logo.raw