From a4ce9f6f054fe4c8d88eac3c057a2a0c913c25cb Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sun, 5 Mar 2017 01:50:36 +0800 Subject: [PATCH] Add compress, decompress, cleanup command --- jni/magiskboot/compress.c | 73 +++++++++++++++++++++++++++++++++++++ jni/magiskboot/magiskboot.h | 14 +++++++ jni/magiskboot/main.c | 62 ++++++++++++++++++++----------- jni/magiskboot/parseimg.c | 50 ++----------------------- jni/magiskboot/repack.c | 22 +++++++---- jni/magiskboot/unpack.c | 14 ++----- jni/magiskboot/utils.c | 63 ++++++++++++++++++++++++++++++++ 7 files changed, 212 insertions(+), 86 deletions(-) diff --git a/jni/magiskboot/compress.c b/jni/magiskboot/compress.c index 7e19b4179..b71dfe1de 100644 --- a/jni/magiskboot/compress.c +++ b/jni/magiskboot/compress.c @@ -359,6 +359,7 @@ int decomp(file_t type, const char *to, const unsigned char *from, size_t size) return 0; } +// Output will be to.ext int comp(file_t type, const char *to, const unsigned char *from, size_t size) { char name[PATH_MAX]; switch (type) { @@ -388,3 +389,75 @@ int comp(file_t type, const char *to, const unsigned char *from, size_t size) { } return 0; } + +void decomp_file(char *from) { + int ok = 1; + unsigned char *file; + size_t size; + mmap_ro(from, &file, &size); + file_t type = check_type(file); + char *ext; + ext = strrchr(from, '.'); + if (ext == NULL) + error(1, "Bad filename extention"); + + // File type and extension should match + switch (type) { + case GZIP: + if (strcmp(ext, ".gz") != 0) + ok = 0; + break; + case XZ: + if (strcmp(ext, ".xz") != 0) + ok = 0; + break; + case LZMA: + if (strcmp(ext, ".lzma") != 0) + ok = 0; + break; + case BZIP2: + if (strcmp(ext, ".bz2") != 0) + ok = 0; + break; + case LZ4: + if (strcmp(ext, ".lz4") != 0) + ok = 0; + break; + default: + error(1, "Provided file \'%s\' is not a supported archive format", from); + } + if (ok) { + // If all match, strip out the suffix + *ext = '\0'; + decomp(type, from, file, size); + *ext = '.'; + unlink(from); + } else { + error(1, "Bad filename extention \'%s\'", ext); + } + munmap(file, size); +} + +void comp_file(const char *method, const char *from) { + file_t type; + if (strcmp(method, "gzip") == 0) { + type = GZIP; + } else if (strcmp(method, "xz") == 0) { + type = XZ; + } else if (strcmp(method, "lzma") == 0) { + type = LZMA; + } else if (strcmp(method, "lz4") == 0) { + type = LZ4; + } else if (strcmp(method, "bzip2") == 0) { + type = BZIP2; + } else { + error(1, "Only support following methods: " SUP_LIST); + } + unsigned char *file; + size_t size; + mmap_ro(from, &file, &size); + comp(type, from, file, size); + munmap(file, size); + unlink(from); +} + diff --git a/jni/magiskboot/magiskboot.h b/jni/magiskboot/magiskboot.h index 70b36710c..591cd3bdd 100644 --- a/jni/magiskboot/magiskboot.h +++ b/jni/magiskboot/magiskboot.h @@ -28,6 +28,10 @@ #define RAMDISK_FILE "ramdisk.cpio" #define SECOND_FILE "second" #define DTB_FILE "dtb" +#define NEW_BOOT "new-boot.img" + +#define SUP_LIST "gzip, xz, lzma, lz4, bzip2" +#define SUP_NUM 5 typedef enum { UNKNOWN, @@ -44,6 +48,12 @@ typedef enum { QCDT, } file_t; +extern char *SUP_EXT_LIST[SUP_NUM]; +extern file_t SUP_TYPE_LIST[SUP_NUM]; +// Cannot declare in header, but place a copy here for convenience +// char *SUP_EXT_LIST[SUP_NUM] = { "gz", "xz", "lzma", "bz2", "lz4" }; +// file_t SUP_TYPE_LIST[SUP_NUM] = { GZIP, XZ, LZMA, BZIP2, LZ4 }; + // Global variables extern unsigned char *kernel, *ramdisk, *second, *dtb; extern boot_img_hdr hdr; @@ -57,6 +67,7 @@ void hexpatch(const char *image, const char *from, const char *to); void cpio(const char *filename); void error(int rc, const char *msg, ...); void parse_img(unsigned char *orig, size_t size); +void cleanup(); // Compressions void gzip(int mode, const char* filename, const unsigned char* buf, size_t size); @@ -64,7 +75,9 @@ void lzma(int mode, const char* filename, const unsigned char* buf, size_t size) void lz4(int mode, const char* filename, const unsigned char* buf, size_t size); void bzip2(int mode, const char* filename, const unsigned char* buf, size_t size); int comp(file_t type, const char *to, const unsigned char *from, size_t size); +void comp_file(const char *method, const char *from); int decomp(file_t type, const char *to, const unsigned char *from, size_t size); +void decomp_file(char *from); // Utils void mmap_ro(const char *filename, unsigned char **buf, size_t *size); @@ -73,5 +86,6 @@ file_t check_type(const unsigned char *buf); void mem_align(size_t *pos, size_t align); void file_align(int fd, size_t align); int open_new(const char *filename); +void print_info(); #endif diff --git a/jni/magiskboot/main.c b/jni/magiskboot/main.c index ba24a3cf1..1c3e289bb 100644 --- a/jni/magiskboot/main.c +++ b/jni/magiskboot/main.c @@ -1,8 +1,3 @@ -#include -#include -#include -#include - #include "magiskboot.h" /******************** @@ -10,13 +5,23 @@ *********************/ static void usage(char *arg0) { - fprintf(stderr, "Boot Image Unpack/Repack Tool\n"); + fprintf(stderr, "\n"); fprintf(stderr, "%s --unpack \n", arg0); - fprintf(stderr, " Unpack into current directory\n\n"); + fprintf(stderr, " Unpack to kernel, ramdisk.cpio, (second), (dtb) into the\n current directory\n\n"); fprintf(stderr, "%s --repack \n", arg0); - fprintf(stderr, " Repack kernel, dtb, ramdisk... from current directory to new-image.img\n is the image you've just unpacked\n\n"); - fprintf(stderr, "%s --hexpatch \n", arg0); - fprintf(stderr, " Search in , and replace with \n\n"); + fprintf(stderr, " Repack kernel, ramdisk.cpio[.ext], second, dtb... from current directory\n"); + fprintf(stderr, " to new-image.img. is the original boot image you've just unpacked.\n"); + fprintf(stderr, " If file ramdisk.cpio exists, it will auto re-compress with the same method\n"); + fprintf(stderr, " used in , or it will attempt to find ramdisk.cpio.[ext], and repack\n"); + fprintf(stderr, " directly with the compressed file\n\n"); + fprintf(stderr, "%s --hexpatch \n", arg0); + fprintf(stderr, " Search in , and replace with \n\n"); + fprintf(stderr, "%s --compress[=method] \n", arg0); + fprintf(stderr, " Compress with [method], or gzip if not specified.\n Supported methods: " SUP_LIST "\n\n"); + fprintf(stderr, "%s --decompress \n", arg0); + fprintf(stderr, " Auto check file type, and decompress accordingly\n Supported methods: " SUP_LIST "\n\n"); + fprintf(stderr, "%s --cleanup\n", arg0); + fprintf(stderr, " Cleanup the current working directory\n\n"); exit(1); } @@ -30,21 +35,34 @@ void error(int rc, const char *msg, ...) { } int main(int argc, char *argv[]) { - if (argc < 3) - usage(argv[0]); - - if (strcmp(argv[1], "--unpack") == 0) { - unpack(argv[2]); - } else if (strcmp(argv[1], "--repack") == 0) { - repack(argv[2]); - } else if (strcmp(argv[1], "--hexpatch") == 0) { - if (argc < 5) + printf("MagiskBoot (by topjohnwu) - Boot Image Modification Tool\n"); + if (argc < 3) { + if (strcmp(argv[1], "--cleanup") == 0) { + cleanup(); + } else { usage(argv[0]); - hexpatch(argv[2], argv[3], argv[4]); + } } else { - usage(argv[0]); + if (strcmp(argv[1], "--unpack") == 0) { + unpack(argv[2]); + } else if (strcmp(argv[1], "--repack") == 0) { + repack(argv[2]); + } else if (strcmp(argv[1], "--hexpatch") == 0) { + if (argc < 5) + usage(argv[0]); + hexpatch(argv[2], argv[3], argv[4]); + } else if (strcmp(argv[1], "--decompress") == 0) { + decomp_file(argv[2]); + } else if (strstr(argv[1], "--compress") != NULL) { + char *method; + method = strchr(argv[1], '='); + if (method == NULL) method = "gzip"; + else method++; + comp_file(method, argv[2]); + } else { + usage(argv[0]); + } } - return 0; } diff --git a/jni/magiskboot/parseimg.c b/jni/magiskboot/parseimg.c index ffce19b67..b5c921340 100644 --- a/jni/magiskboot/parseimg.c +++ b/jni/magiskboot/parseimg.c @@ -8,54 +8,9 @@ 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); - printf("DTB [%d] @ 0x%08x\n", hdr.dt_size, hdr.tags_addr); - printf("PAGESIZE [%d]\n", hdr.page_size); - if (hdr.os_version != 0) { - int a,b,c,y,m = 0; - int os_version, os_patch_level; - os_version = hdr.os_version >> 11; - os_patch_level = hdr.os_version & 0x7ff; - - a = (os_version >> 14) & 0x7f; - b = (os_version >> 7) & 0x7f; - c = os_version & 0x7f; - printf("OS_VERSION [%d.%d.%d]\n", a, b, c); - - y = (os_patch_level >> 4) + 2000; - m = os_patch_level & 0xf; - printf("PATCH_LEVEL [%d-%02d]\n", y, m); - } - printf("NAME [%s]\n", hdr.name); - printf("CMDLINE [%s]\n", hdr.cmdline); - + // Check ramdisk compression type ramdisk_type = check_type(ramdisk); - switch (ramdisk_type) { - case GZIP: - printf("COMPRESSION [%s]\n", "gzip"); - break; - case LZOP: - printf("COMPRESSION [%s]\n", "lzop"); - break; - case XZ: - printf("COMPRESSION [%s]\n", "xz"); - break; - case LZMA: - printf("COMPRESSION [%s]\n", "lzma"); - break; - case BZIP2: - printf("COMPRESSION [%s]\n", "bzip2"); - break; - case LZ4: - printf("COMPRESSION [%s]\n", "lz4"); - break; - default: - error(1, "Unknown ramdisk format!"); - } - // Check MTK if (check_type(kernel) == MTK) { printf("MTK header found in kernel\n"); @@ -70,6 +25,9 @@ static void check_headers() { if (boot_type == ELF && hdr.dt_size) { dtb_type = check_type(dtb); } + + // Print info + print_info(); } static void elf_header_check(void *elf, int is64) { diff --git a/jni/magiskboot/repack.c b/jni/magiskboot/repack.c index dd8d6e362..5d834255f 100644 --- a/jni/magiskboot/repack.c +++ b/jni/magiskboot/repack.c @@ -24,17 +24,16 @@ void repack(const char* image) { size_t size; unsigned char *orig; char name[PATH_MAX]; - #define EXT_NUM 6 - char *ext_list[EXT_NUM] = { "gz", "lzo", "xz", "lzma", "bz2", "lz4" }; // Load original image mmap_ro(image, &orig, &size); // Parse original image + printf("\nParsing boot image: [%s]\n\n", image); parse_img(orig, size); // Create new image - int fd = open_new("new-boot.img"); + int fd = open_new(NEW_BOOT); // Set all sizes to 0 hdr.kernel_size = 0; @@ -62,27 +61,34 @@ void repack(const char* image) { if (access(RAMDISK_FILE, R_OK) == 0) { // If we found raw cpio, compress to original format + + // Before we start, clean up previous compressed files + for (int i = 0; i < SUP_NUM; ++i) { + sprintf(name, "%s.%s", RAMDISK_FILE, SUP_EXT_LIST[i]); + unlink(name); + } + size_t cpio_size; unsigned char *cpio; mmap_ro(RAMDISK_FILE, &cpio, &cpio_size); if (comp(ramdisk_type, RAMDISK_FILE, cpio, cpio_size)) - error(1, "Unsupported format! Please compress manually!"); + error(1, "Unsupported ramdisk format!"); munmap(cpio, cpio_size); } int found = 0; - for (int i = 0; i < EXT_NUM; ++i) { - sprintf(name, "%s.%s", RAMDISK_FILE, ext_list[i]); + for (int i = 0; i < SUP_NUM; ++i) { + sprintf(name, "%s.%s", RAMDISK_FILE, SUP_EXT_LIST[i]); if (access(name, R_OK) == 0) { + ramdisk_type = SUP_TYPE_LIST[i]; found = 1; break; } } if (!found) error(1, "No ramdisk exists!"); - hdr.ramdisk_size += restore(name, fd); file_align(fd, hdr.page_size); @@ -99,6 +105,8 @@ void repack(const char* image) { } // Write header back + printf("\nRepack to boot image: [%s]\n\n", NEW_BOOT); + print_info(); lseek(fd, 0, SEEK_SET); write(fd, &hdr, sizeof(hdr)); diff --git a/jni/magiskboot/unpack.c b/jni/magiskboot/unpack.c index b87a1973f..28be1fc62 100644 --- a/jni/magiskboot/unpack.c +++ b/jni/magiskboot/unpack.c @@ -13,6 +13,7 @@ void unpack(const char* image) { mmap_ro(image, &orig, &size); // Parse image + printf("\nParsing boot image: [%s]\n\n", image); parse_img(orig, size); if (boot_type == CHROMEOS) { @@ -34,19 +35,10 @@ void unpack(const char* image) { ramdisk += 512; hdr.ramdisk_size -= 512; } - if (decomp(ramdisk_type, RAMDISK_FILE, ramdisk, hdr.ramdisk_size)) { - printf("Unsupported format! Please decompress manually!\n"); - switch (ramdisk_type) { - case LZOP: - sprintf(name, "%s.%s", RAMDISK_FILE, "lzo"); - break; - default: - // Never happens - break; - } // Dump the compressed ramdisk - dump(ramdisk, hdr.ramdisk_size, name); + dump(ramdisk, hdr.ramdisk_size, RAMDISK_FILE ".unsupport"); + error(1, "Unsupported ramdisk format! Dumped to %s", RAMDISK_FILE ".unsupport"); } if (hdr.second_size) { diff --git a/jni/magiskboot/utils.c b/jni/magiskboot/utils.c index ca154be13..1c20ff1f1 100644 --- a/jni/magiskboot/utils.c +++ b/jni/magiskboot/utils.c @@ -1,6 +1,9 @@ #include "magiskboot.h" #include "elf.h" +char *SUP_EXT_LIST[SUP_NUM] = { "gz", "xz", "lzma", "bz2", "lz4" }; +file_t SUP_TYPE_LIST[SUP_NUM] = { GZIP, XZ, LZMA, BZIP2, LZ4 }; + void mmap_ro(const char *filename, unsigned char **buf, size_t *size) { int fd = open(filename, O_RDONLY); if (fd < 0) @@ -75,3 +78,63 @@ int open_new(const char *filename) { error(1, "Unable to create %s", filename); return fd; } + +void print_info() { + 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); + printf("DTB [%d] @ 0x%08x\n", hdr.dt_size, hdr.tags_addr); + printf("PAGESIZE [%d]\n", hdr.page_size); + if (hdr.os_version != 0) { + int a,b,c,y,m = 0; + int os_version, os_patch_level; + os_version = hdr.os_version >> 11; + os_patch_level = hdr.os_version & 0x7ff; + + a = (os_version >> 14) & 0x7f; + b = (os_version >> 7) & 0x7f; + c = os_version & 0x7f; + printf("OS_VERSION [%d.%d.%d]\n", a, b, c); + + y = (os_patch_level >> 4) + 2000; + m = os_patch_level & 0xf; + printf("PATCH_LEVEL [%d-%02d]\n", y, m); + } + printf("NAME [%s]\n", hdr.name); + printf("CMDLINE [%s]\n", hdr.cmdline); + + switch (ramdisk_type) { + case GZIP: + printf("COMPRESSION [%s]\n", "gzip"); + break; + case XZ: + printf("COMPRESSION [%s]\n", "xz"); + break; + case LZMA: + printf("COMPRESSION [%s]\n", "lzma"); + break; + case BZIP2: + printf("COMPRESSION [%s]\n", "bzip2"); + break; + case LZ4: + printf("COMPRESSION [%s]\n", "lz4"); + break; + default: + fprintf(stderr, "Unknown ramdisk format!\n"); + } +} + +void cleanup() { + printf("Cleaning up...\n"); + char name[PATH_MAX]; + unlink(KERNEL_FILE); + unlink(RAMDISK_FILE); + unlink(RAMDISK_FILE ".unsupport"); + unlink(SECOND_FILE); + unlink(DTB_FILE); + unlink(NEW_BOOT); + for (int i = 0; i < SUP_NUM; ++i) { + sprintf(name, "%s.%s", RAMDISK_FILE, SUP_EXT_LIST[i]); + unlink(name); + } +}