Add gzip native support

This commit is contained in:
topjohnwu 2017-02-28 05:37:47 +08:00
parent 2ccd8b8838
commit f621fb2060
10 changed files with 339 additions and 172 deletions

View File

@ -3,6 +3,7 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := bootimgtools
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := main.c unpack.c repack.c hexpatch.c parseimg.c
LOCAL_SRC_FILES := main.c unpack.c repack.c hexpatch.c parseimg.c compress.c
LOCAL_CFLAGS += -std=gnu11
LOCAL_LDLIBS += -lz
include $(BUILD_EXECUTABLE)

View File

@ -28,9 +28,6 @@ typedef struct boot_img_hdr boot_img_hdr;
#define BOOT_ARGS_SIZE 512
#define BOOT_EXTRA_ARGS_SIZE 1024
#define CHROMEOS_MAGIC "CHROMEOS"
#define CHROMEOS_MAGIC_SIZE 8
struct boot_img_hdr
{
uint8_t magic[BOOT_MAGIC_SIZE];
@ -76,10 +73,13 @@ struct boot_img_hdr
** +-----------------+
** | second stage | o pages
** +-----------------+
** | device tree | p pages
** +-----------------+
**
** n = (kernel_size + page_size - 1) / page_size
** m = (ramdisk_size + page_size - 1) / page_size
** o = (second_size + page_size - 1) / page_size
** p = (dt_size + page_size - 1) / page_size
**
** 0. all entities are page_size aligned in flash
** 1. kernel and ramdisk are required (size != 0)
@ -93,20 +93,4 @@ struct boot_img_hdr
** else: jump to kernel_addr
*/
/* Self defined stuffs */
// Global pointers to mmap
unsigned char *base, *kernel, *ramdisk, *second, *dtb;
// Parsed header
boot_img_hdr hdr;
int unpack(const char *image);
int repack(const char *image);
int hexpatch(char *image, char *from, char *to);
void error(int rc, const char *msg, ...);
void print_header();
void parse_elf();
void parse_aosp();
#endif

View File

@ -0,0 +1,59 @@
#include "magiskboot.h"
void gzip(int dec, const char* filename, unsigned char* buf, size_t size) {
int ret, flush, have, pos = 0;
z_stream strm;
unsigned char out[CHUNK];
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd < 0)
error(1, "Unable to create %s", filename);
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
if (dec) {
ret = inflateInit2(&strm, windowBits | ZLIB_GZIP);
} else {
ret = deflateInit2(&strm, 9, Z_DEFLATED, windowBits | ZLIB_GZIP, memLevel, Z_DEFAULT_STRATEGY);
}
if (ret != Z_OK)
error(1, "Unable to init zlib");
do {
strm.next_in = buf + pos;
if (pos + CHUNK > size) {
strm.avail_in = size - pos;
pos = size;
flush = Z_FINISH;
} else {
strm.avail_in = CHUNK;
pos += CHUNK;
flush = Z_NO_FLUSH;
}
do {
strm.avail_out = CHUNK;
strm.next_out = out;
if (dec) {
inflate(&strm, flush);
} else {
deflate(&strm, flush);
}
have = CHUNK - strm.avail_out;
if (write(fd, out, have) != have)
error(1, "Error in writing %s", filename);
} while (strm.avail_out == 0);
} while(pos < size);
if (dec) {
inflateEnd(&strm);
} else {
deflateEnd(&strm);
}
close(fd);
}

View File

@ -22,6 +22,8 @@
** +-----------------+
** | program header | dtb info
** +-----------------+
** | program header | (possible) cmdline info
** +-----------------+
** ~
** +-----------------+
** | section header | cmdline info

View File

@ -1,14 +1,4 @@
#include <getopt.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include "bootimg.h"
#include "magiskboot.h"
static int hex2int(char c) {
int first = c / 16 - 3;
@ -35,7 +25,7 @@ static void hexstr2str(char *hex, unsigned char *str) {
}
}
int hexpatch(char * image, char *from, char *to) {
void hexpatch(char * image, char *from, char *to) {
int fd = open(image, O_RDWR), patternsize = strlen(from) / 2, patchsize = strlen(to) / 2;
size_t filesize = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
@ -57,5 +47,4 @@ int hexpatch(char * image, char *from, char *to) {
free(pattern);
free(patch);
close(fd);
return 0;
}
}

View File

@ -0,0 +1,62 @@
#ifndef _ARCHIVE_H_
#define _ARCHIVE_H_
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include <zlib.h>
#include "bootimg.h"
#define windowBits 15
#define ZLIB_GZIP 16
#define memLevel 8
#define CHUNK 0x40000
#define CHROMEOS_MAGIC "CHROMEOS"
#define CHROMEOS_MAGIC_SIZE 8
#define KERNEL_FILE "kernel"
#define RAMDISK_FILE "ramdisk.cpio"
#define SECOND_FILE "second"
#define DTB_FILE "dtb"
typedef enum {
DONTCARE,
CHROMEOS,
AOSP,
ELF,
GZIP,
LZOP,
XZ,
LZMA,
BZIP2,
LZ4,
QCDT,
} file_t;
// Global variables
extern unsigned char *base, *kernel, *ramdisk, *second, *dtb;
extern boot_img_hdr hdr;
extern file_t boot_type, ramdisk_type, dtb_type;
extern int mtk_kernel, mtk_ramdisk;
// Main entries
void unpack(const char *image);
void repack(const char *image);
void hexpatch(char *image, char *from, char *to);
void error(int rc, const char *msg, ...);
// Parse image
void parse_img(unsigned char *orig, size_t size);
// Compressions
void gzip(int dec, const char* filename, unsigned char* buf, size_t size);
#endif

View File

@ -3,7 +3,7 @@
#include <stdlib.h>
#include <string.h>
#include "bootimg.h"
#include "magiskboot.h"
/********************
Patch Boot Image

View File

@ -6,8 +6,14 @@
#include "bootimg.h"
#include "elf.h"
#include "magiskboot.h"
void print_header() {
unsigned char *base, *kernel, *ramdisk, *second, *dtb;
boot_img_hdr hdr;
int mtk_kernel = 0, mtk_ramdisk = 0;
file_t boot_type, ramdisk_type, dtb_type;
static void check_headers() {
printf("KERNEL [%d] @ 0x%08x\n", hdr.kernel_size, hdr.kernel_addr);
printf("RAMDISK [%d] @ 0x%08x\n", hdr.ramdisk_size, hdr.ramdisk_addr);
printf("SECOND [%d] @ 0x%08x\n", hdr.second_size, hdr.second_addr);
@ -30,6 +36,58 @@ void print_header() {
}
printf("NAME [%s]\n", hdr.name);
printf("CMDLINE [%s]\n", hdr.cmdline);
// Check compression
if (memcmp(ramdisk, "\x1f\x8b\x08\x00", 4) == 0) {
// gzip header
printf("COMPRESSION [gzip]\n");
ramdisk_type = GZIP;
} else if (memcmp(ramdisk, "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a", 9) == 0) {
// lzop header
printf("COMPRESSION [lzop]\n");
ramdisk_type = LZOP;
} else if (memcmp(ramdisk, "\xfd""7zXZ\x00", 6) == 0) {
// xz header
printf("COMPRESSION [xz]\n");
ramdisk_type = XZ;
} else if (memcmp(ramdisk, "\x5d\x00\x00", 3) == 0
&& (ramdisk[12] == (unsigned char) '\xff' || ramdisk[12] == (unsigned char) '\x00')) {
// lzma header
printf("COMPRESSION [lzma]\n");
ramdisk_type = LZMA;
} else if (memcmp(ramdisk, "BZh", 3) == 0) {
// bzip2 header
printf("COMPRESSION [bzip2]\n");
ramdisk_type = BZIP2;
} else if ( ( memcmp(ramdisk, "\x04\x22\x4d\x18", 4) == 0
|| memcmp(ramdisk, "\x03\x21\x4c\x18", 4) == 0)
|| memcmp(ramdisk, "\x02\x21\x4c\x18", 4) == 0) {
// lz4 header
printf("COMPRESSION [lz4]\n");
ramdisk_type = LZ4;
} else {
error(1, "Unknown ramdisk format!");
}
// Check MTK
if (memcmp(kernel, "\x88\x16\x88\x58", 4) == 0) {
printf("MTK header found in kernel\n");
mtk_kernel = 1;
}
if (memcmp(ramdisk, "\x88\x16\x88\x58", 4) == 0) {
printf("MTK header found in ramdisk\n");
mtk_kernel = 1;
}
// Check dtb
if (boot_type == ELF && hdr.dt_size) {
if (memcmp(dtb, "QCDT", 4) == 0) {
dtb_type = QCDT;
} else if (memcmp(dtb, ELF_MAGIC, ELF_MAGIC_SIZE) == 0) {
dtb_type = ELF;
}
}
}
static void page_align(unsigned char **pos) {
@ -120,7 +178,7 @@ static void elf_set(int i, size_t size, size_t offset, size_t addr) {
}
}
void parse_elf() {
static void parse_elf() {
// Reset boot image header
memset(&hdr, 0, sizeof(hdr));
@ -191,10 +249,10 @@ void parse_elf() {
error(1, "ELF format error!");
}
print_header();
check_headers();
}
void parse_aosp() {
static void parse_aosp() {
printf("IMG [AOSP]\n");
@ -228,5 +286,21 @@ void parse_aosp() {
page_align(&pos);
}
print_header();
}
check_headers();
}
void parse_img(unsigned char *orig, size_t size) {
for(base = orig; base < (orig + size); base += 256) {
if (memcmp(base, CHROMEOS_MAGIC, CHROMEOS_MAGIC_SIZE) == 0) {
boot_type = CHROMEOS;
} else if (memcmp(base, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0) {
if (boot_type != CHROMEOS) boot_type = AOSP;
parse_aosp();
break;
} else if (memcmp(base, ELF_MAGIC, ELF_MAGIC_SIZE) == 0) {
boot_type = ELF;
parse_elf();
break;
}
}
}

View File

@ -1,18 +1,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <assert.h>
#include <string.h>
#include "magiskboot.h"
#include "bootimg.h"
#include "elf.h"
// Global pointer of current positions
// Global pointer of output
static int ofd, opos;
static size_t restore(const char *filename) {
@ -49,34 +37,24 @@ static void page_align() {
lseek(ofd, 0, SEEK_END);
}
int repack(const char* image) {
// Load original boot
int ifd = open(image, O_RDONLY), ret = -1;
void repack(const char* image) {
// Load original image
int ifd = open(image, O_RDONLY);
if (ifd < 0)
error(1, "Cannot open %s", image);
size_t isize = lseek(ifd, 0, SEEK_END);
lseek(ifd, 0, SEEK_SET);
unsigned char *orig = mmap(NULL, isize, PROT_READ, MAP_SHARED, ifd, 0);
// Parse original image
parse_img(orig, isize);
// Create new boot image
unlink("new-boot.img");
ofd = open("new-boot.img", O_RDWR | O_CREAT, 0644);
ofd = open("new-boot.img", O_RDWR | O_CREAT | O_TRUNC, 0644);
// Parse images
for(base = orig; base < (orig + isize); base += 256) {
if (memcmp(base, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0) {
parse_aosp();
break;
} else if (memcmp(base, ELF_MAGIC, ELF_MAGIC_SIZE) == 0) {
parse_elf();
break;
}
}
printf("\n");
char *name;
char name[PATH_MAX];
#define EXT_NUM 6
char *ext_list[EXT_NUM] = { "gz", "lzo", "xz", "lzma", "bz2", "lz4" };
// Set all sizes to 0
hdr.kernel_size = 0;
@ -90,52 +68,87 @@ int repack(const char* image) {
opos += hdr.page_size;
// Restore kernel
if (memcmp(kernel, "\x88\x16\x88\x58", 4) == 0) {
printf("Dumping MTK header back to kernel\n");
if (mtk_kernel) {
restore_buf(512, kernel);
hdr.kernel_size += 512;
}
hdr.kernel_size += restore("kernel");
hdr.kernel_size += restore(KERNEL_FILE);
page_align();
// Dump ramdisk
if (memcmp(ramdisk, "\x88\x16\x88\x58", 4) == 0) {
printf("Dumping MTK header back to ramdisk\n");
// Restore ramdisk
if (mtk_ramdisk) {
restore_buf(512, ramdisk);
hdr.ramdisk_size += 512;
}
if (access("ramdisk.gz", R_OK) == 0) {
name = "ramdisk.gz";
} else if (access("ramdisk.lzo", R_OK) == 0) {
name = "ramdisk.lzo";
} else if (access("ramdisk.xz", R_OK) == 0) {
name = "ramdisk.xz";
} else if (access("ramdisk.lzma", R_OK) == 0) {
name = "ramdisk.lzma";
} else if (access("ramdisk.bz2", R_OK) == 0) {
name = "ramdisk.bz2";
} else if (access("ramdisk.lz4", R_OK) == 0) {
name = "ramdisk.lz4";
if (access(RAMDISK_FILE, R_OK) == 0) {
// If we found raw cpio, recompress to original format
int rfd = open(RAMDISK_FILE, O_RDONLY);
if (rfd < 0)
error(1, "Cannot open " RAMDISK_FILE);
size_t cpio_size = lseek(rfd, 0, SEEK_END);
lseek(rfd, 0, SEEK_SET);
unsigned char *cpio = mmap(NULL, cpio_size, PROT_READ, MAP_SHARED, rfd, 0);
switch (ramdisk_type) {
case GZIP:
sprintf(name, "%s.%s", RAMDISK_FILE, "gz");
gzip(0, name, cpio, cpio_size);
break;
case LZOP:
sprintf(name, "%s.%s", RAMDISK_FILE, "lzo");
break;
case XZ:
sprintf(name, "%s.%s", RAMDISK_FILE, "xz");
break;
case LZMA:
sprintf(name, "%s.%s", RAMDISK_FILE, "lzma");
break;
case BZIP2:
sprintf(name, "%s.%s", RAMDISK_FILE, "bz2");
break;
case LZ4:
sprintf(name, "%s.%s", RAMDISK_FILE, "lz4");
break;
default:
// Never happens
break;
}
printf("Re-compressed %s to %s\n", RAMDISK_FILE, name);
munmap(cpio, cpio_size);
close(rfd);
} else {
error(1, "Ramdisk file doesn't exist!");
// If no raw cpio found, find compressed ones
int found = 0;
for (int i = 0; i < EXT_NUM; ++i) {
sprintf(name, "%s.%s", RAMDISK_FILE, ext_list[i]);
if (access(name, R_OK) == 0) {
found = 1;
break;
}
}
if (!found) {
error(1, "No ramdisk exists!");
}
}
hdr.ramdisk_size += restore(name);
page_align();
// Dump second
if (access("second", R_OK) == 0) {
hdr.second_size += restore("second");
// Restore second
if (access(SECOND_FILE, R_OK) == 0) {
hdr.second_size += restore(SECOND_FILE);
page_align();
}
// Dump dtb
if (access("dtb", R_OK) == 0) {
hdr.dt_size += restore("dtb");
// Restore dtb
if (access(DTB_FILE, R_OK) == 0) {
hdr.dt_size += restore(DTB_FILE);
page_align();
}
print_header();
// Write header back
lseek(ofd, 0, SEEK_SET);
write(ofd, &hdr, sizeof(hdr));
@ -143,5 +156,7 @@ int repack(const char* image) {
munmap(orig, isize);
close(ifd);
close(ofd);
return ret;
if (opos > isize) {
error(2, "Boot partition too small!");
}
}

View File

@ -1,20 +1,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <assert.h>
#include <string.h>
#include "bootimg.h"
#include "elf.h"
#include "magiskboot.h"
static void dump(unsigned char *buf, size_t size, const char *filename) {
unlink(filename);
int ofd = open(filename, O_WRONLY | O_CREAT, 0644);
int ofd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (ofd < 0)
error(1, "Cannot open %s", filename);
if (write(ofd, buf, size) != size)
@ -22,8 +9,8 @@ static void dump(unsigned char *buf, size_t size, const char *filename) {
close(ofd);
}
int unpack(const char* image) {
int fd = open(image, O_RDONLY), ret = 0;
void unpack(const char* image) {
int fd = open(image, O_RDONLY);
if (fd < 0)
error(1, "Cannot open %s", image);
@ -31,81 +18,75 @@ int unpack(const char* image) {
lseek(fd, 0, SEEK_SET);
unsigned char *orig = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
// Parse images
for(base = orig; base < (orig + size); base += 256) {
if (memcmp(base, CHROMEOS_MAGIC, CHROMEOS_MAGIC_SIZE) == 0) {
dump(base, 0, "chromeos");
} else if (memcmp(base, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0) {
parse_aosp();
break;
} else if (memcmp(base, ELF_MAGIC, ELF_MAGIC_SIZE) == 0) {
parse_elf();
break;
}
// Parse image
parse_img(orig, size);
if (boot_type == CHROMEOS) {
// The caller should know it's chromeos, as it needs additional signing
dump(base, 0, "chromeos");
}
char name[PATH_MAX], *ext;
char name[PATH_MAX];
// Dump kernel
if (memcmp(kernel, "\x88\x16\x88\x58", 4) == 0) {
printf("MTK header found in kernel\n");
if (mtk_kernel) {
kernel += 512;
hdr.kernel_size -= 512;
}
dump(kernel, hdr.kernel_size, "kernel");
dump(kernel, hdr.kernel_size, KERNEL_FILE);
// Dump ramdisk
if (memcmp(ramdisk, "\x88\x16\x88\x58", 4) == 0) {
printf("MTK header found in ramdisk\n");
if (mtk_ramdisk) {
ramdisk += 512;
hdr.ramdisk_size -= 512;
}
// Compression detection
if (memcmp(ramdisk, "\x1f\x8b\x08\x00", 4) == 0) {
// gzip header
printf("COMPRESSION [gzip]\n");
ext = "gz";
} else if (memcmp(ramdisk, "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a", 9) == 0) {
// lzop header
printf("COMPRESSION [lzop]\n");
ext = "lzo";
} else if (memcmp(ramdisk, "\xfd""7zXZ\x00", 6) == 0) {
// xz header
printf("COMPRESSION [xz]\n");
ext = "xz";
} else if (memcmp(ramdisk, "\x5d\x00\x00", 3) == 0
&& (ramdisk[12] == (unsigned char) '\xff' || ramdisk[12] == (unsigned char) '\x00')) {
// lzma header
printf("COMPRESSION [lzma]\n");
ext = "lzma";
} else if (memcmp(ramdisk, "BZh", 3) == 0) {
// bzip2 header
printf("COMPRESSION [bzip2]\n");
ext = "bz2";
} else if ( ( memcmp(ramdisk, "\x04\x22\x4d\x18", 4) == 0
|| memcmp(ramdisk, "\x03\x21\x4c\x18", 4) == 0)
|| memcmp(ramdisk, "\x02\x21\x4c\x18", 4) == 0) {
// lz4 header
printf("COMPRESSION [lz4]\n");
ext = "lz4";
} else {
error(1, "Unknown ramdisk format!");
switch (ramdisk_type) {
case GZIP:
sprintf(name, "%s.%s", RAMDISK_FILE, "gz");
gzip(1, RAMDISK_FILE, ramdisk, hdr.ramdisk_size);
break;
case LZOP:
sprintf(name, "%s.%s", RAMDISK_FILE, "lzo");
break;
case XZ:
sprintf(name, "%s.%s", RAMDISK_FILE, "xz");
break;
case LZMA:
sprintf(name, "%s.%s", RAMDISK_FILE, "lzma");
break;
case BZIP2:
sprintf(name, "%s.%s", RAMDISK_FILE, "bz2");
break;
case LZ4:
sprintf(name, "%s.%s", RAMDISK_FILE, "lz4");
break;
default:
// Never happens
break;
}
sprintf(name, "%s.%s", "ramdisk", ext);
// Dump the compressed ramdisk, just in case
dump(ramdisk, hdr.ramdisk_size, name);
if (hdr.second_size) {
// Dump second
dump(second, hdr.second_size, "second");
dump(second, hdr.second_size, SECOND_FILE);
}
if (hdr.dt_size) {
// Dump dtb
dump(dtb, hdr.dt_size, "dtb");
if (boot_type == ELF && (dtb_type != QCDT && dtb_type != ELF )) {
printf("Non QC dtb found in ELF kernel, recreate kernel\n");
gzip(0, KERNEL_FILE, kernel, hdr.kernel_size);
int kfp = open(KERNEL_FILE, O_WRONLY | O_APPEND);
write(kfp, dtb, hdr.dt_size);
close(kfp);
} else {
// Dump dtb
dump(dtb, hdr.dt_size, DTB_FILE);
}
}
munmap(orig, size);
close(fd);
return ret;
}