diff --git a/jni/magiskboot/Android.mk b/jni/magiskboot/Android.mk index 5568d391e..e2118f929 100644 --- a/jni/magiskboot/Android.mk +++ b/jni/magiskboot/Android.mk @@ -4,14 +4,16 @@ include $(CLEAR_VARS) LOCAL_MODULE := magiskboot LOCAL_STATIC_LIBRARIES := liblzma liblz4 libbz2 LOCAL_C_INCLUDES := \ + jni/ndk-compression/zlib/ \ jni/ndk-compression/xz/src/liblzma/api/ \ jni/ndk-compression/lz4/lib/ \ - jni/ndk-compression/bzip2 + jni/ndk-compression/bzip2/ -LOCAL_SRC_FILES := main.c unpack.c repack.c hexpatch.c parseimg.c compress.c +LOCAL_SRC_FILES := main.c unpack.c repack.c hexpatch.c parseimg.c compress.c utils.c cpio.c LOCAL_LDLIBS += -lz include $(BUILD_EXECUTABLE) +include jni/ndk-compression/zlib/Android.mk include jni/ndk-compression/xz/src/liblzma/Android.mk include jni/ndk-compression/lz4/lib/Android.mk include jni/ndk-compression/bzip2/Android.mk diff --git a/jni/magiskboot/compress.c b/jni/magiskboot/compress.c index b174f63a6..7e19b4179 100644 --- a/jni/magiskboot/compress.c +++ b/jni/magiskboot/compress.c @@ -5,13 +5,6 @@ #include "magiskboot.h" -static int open_new(const char *filename) { - int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (fd < 0) - error(1, "Unable to create %s", filename); - return fd; -} - static void write_file(const int fd, const void *buf, const size_t size, const char *filename) { if (write(fd, buf, size) != size) error(1, "Error in writing %s", filename); @@ -29,7 +22,7 @@ static void report(const int mode, const char* filename) { } // Mode: 0 = decode; 1 = encode -void gzip(int mode, const char* filename, unsigned char* buf, size_t size) { +void gzip(int mode, const char* filename, const unsigned char* buf, size_t size) { size_t ret = 0, flush, have, pos = 0; z_stream strm; unsigned char out[CHUNK]; @@ -100,7 +93,7 @@ void gzip(int mode, const char* filename, unsigned char* buf, size_t size) { // Mode: 0 = decode xz/lzma; 1 = encode xz; 2 = encode lzma -void lzma(int mode, const char* filename, unsigned char* buf, size_t size) { +void lzma(int mode, const char* filename, const unsigned char* buf, size_t size) { size_t have, pos = 0; lzma_ret ret = 0; lzma_stream strm = LZMA_STREAM_INIT; @@ -164,7 +157,7 @@ void lzma(int mode, const char* filename, unsigned char* buf, size_t size) { } // Mode: 0 = decode; 1 = encode -void lz4(int mode, const char* filename, unsigned char* buf, size_t size) { +void lz4(int mode, const char* filename, const unsigned char* buf, size_t size) { LZ4F_decompressionContext_t dctx; LZ4F_compressionContext_t cctx; LZ4F_frameInfo_t info; @@ -275,7 +268,7 @@ void lz4(int mode, const char* filename, unsigned char* buf, size_t size) { } // Mode: 0 = decode; 1 = encode -void bzip2(int mode, const char* filename, unsigned char* buf, size_t size) { +void bzip2(int mode, const char* filename, const unsigned char* buf, size_t size) { size_t ret = 0, action, have, pos = 0; bz_stream strm; char out[CHUNK]; @@ -342,7 +335,7 @@ void bzip2(int mode, const char* filename, unsigned char* buf, size_t size) { close(fd); } -int decomp(file_t type, const char *to, unsigned char *from, size_t size) { +int decomp(file_t type, const char *to, const unsigned char *from, size_t size) { switch (type) { case GZIP: gzip(0, to, from, size); @@ -366,7 +359,7 @@ int decomp(file_t type, const char *to, unsigned char *from, size_t size) { return 0; } -int comp(file_t type, const char *to, unsigned char *from, size_t size) { +int comp(file_t type, const char *to, const unsigned char *from, size_t size) { char name[PATH_MAX]; switch (type) { case GZIP: diff --git a/jni/magiskboot/hexpatch.c b/jni/magiskboot/hexpatch.c index dc768dc8c..5c89df2db 100644 --- a/jni/magiskboot/hexpatch.c +++ b/jni/magiskboot/hexpatch.c @@ -14,7 +14,7 @@ static unsigned hex2ascii(char c, char d) { return high + low; } -static void hexstr2str(char *hex, unsigned char *str) { +static void hexstr2str(const char *hex, unsigned char *str) { char buf = 0; for(int i = 0, length = strlen(hex); i < length; ++i){ if(i % 2){ @@ -25,12 +25,11 @@ static void hexstr2str(char *hex, unsigned char *str) { } } -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); +void hexpatch(const char *image, const char *from, const char *to) { + int patternsize = strlen(from) / 2, patchsize = strlen(to) / 2; + size_t filesize; unsigned char *file, *pattern, *patch; - file = mmap(NULL, filesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + mmap_rw(image, &file, &filesize); pattern = malloc(patternsize); patch = malloc(patchsize); hexstr2str(from, pattern); @@ -46,5 +45,4 @@ void hexpatch(char * image, char *from, char *to) { munmap(file, filesize); free(pattern); free(patch); - close(fd); } diff --git a/jni/magiskboot/magiskboot.h b/jni/magiskboot/magiskboot.h index 45972ad4b..70b36710c 100644 --- a/jni/magiskboot/magiskboot.h +++ b/jni/magiskboot/magiskboot.h @@ -45,7 +45,7 @@ typedef enum { } file_t; // Global variables -extern unsigned char *base, *kernel, *ramdisk, *second, *dtb; +extern unsigned char *kernel, *ramdisk, *second, *dtb; extern boot_img_hdr hdr; extern file_t boot_type, ramdisk_type, dtb_type; extern int mtk_kernel, mtk_ramdisk; @@ -53,17 +53,25 @@ 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 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); -file_t check_type(unsigned char *buf); // Compressions -void gzip(int mode, const char* filename, unsigned char* buf, size_t size); -void lzma(int mode, const char* filename, unsigned char* buf, size_t size); -void lz4(int mode, const char* filename, unsigned char* buf, size_t size); -void bzip2(int mode, const char* filename, unsigned char* buf, size_t size); -int comp(file_t type, const char *to, unsigned char *from, size_t size); -int decomp(file_t type, const char *to, unsigned char *from, size_t size); +void gzip(int mode, const char* filename, const unsigned char* buf, size_t size); +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); +int decomp(file_t type, const char *to, const unsigned char *from, size_t size); + +// Utils +void mmap_ro(const char *filename, unsigned char **buf, size_t *size); +void mmap_rw(const char *filename, unsigned char **buf, size_t *size); +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); #endif diff --git a/jni/magiskboot/parseimg.c b/jni/magiskboot/parseimg.c index 0ab95d3c6..ffce19b67 100644 --- a/jni/magiskboot/parseimg.c +++ b/jni/magiskboot/parseimg.c @@ -1,49 +1,12 @@ -#include -#include -#include -#include -#include - #include "bootimg.h" #include "elf.h" #include "magiskboot.h" -unsigned char *base, *kernel, *ramdisk, *second, *dtb; +unsigned char *kernel, *ramdisk, *second, *dtb; boot_img_hdr hdr; int mtk_kernel = 0, mtk_ramdisk = 0; file_t boot_type, ramdisk_type, dtb_type; -file_t check_type(unsigned char *buf) { - if (memcmp(buf, CHROMEOS_MAGIC, CHROMEOS_MAGIC_SIZE) == 0) { - return CHROMEOS; - } else if (memcmp(buf, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0) { - return AOSP; - } else if (memcmp(buf, ELF_MAGIC, ELF_MAGIC_SIZE) == 0) { - return ELF; - } else if (memcmp(buf, "\x1f\x8b\x08\x00", 4) == 0) { - return GZIP; - } else if (memcmp(buf, "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a", 9) == 0) { - return LZOP; - } else if (memcmp(buf, "\xfd""7zXZ\x00", 6) == 0) { - return XZ; - } else if (memcmp(buf, "\x5d\x00\x00", 3) == 0 - && (buf[12] == (unsigned char) '\xff' || buf[12] == (unsigned char) '\x00')) { - return LZMA; - } else if (memcmp(buf, "BZh", 3) == 0) { - return BZIP2; - } else if ( ( memcmp(buf, "\x04\x22\x4d\x18", 4) == 0 - || memcmp(buf, "\x03\x21\x4c\x18", 4) == 0) - || memcmp(buf, "\x02\x21\x4c\x18", 4) == 0) { - return LZ4; - } else if (memcmp(buf, "\x88\x16\x88\x58", 4) == 0) { - return MTK; - } else if (memcmp(buf, "QCDT", 4) == 0) { - return QCDT; - } else { - return UNKNOWN; - } -} - 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); @@ -109,13 +72,6 @@ static void check_headers() { } } -static void page_align(unsigned char **pos) { - uint32_t itemsize = *pos - base, pagemask = hdr.page_size - 1L; - if (itemsize & pagemask) { - *pos += hdr.page_size - (itemsize & pagemask); - } -} - static void elf_header_check(void *elf, int is64) { size_t e_size, mach, ver, p_size, p_num, s_size, s_num; @@ -167,7 +123,7 @@ static void elf_header_check(void *elf, int is64) { error(1, "More than one section header"); } -static void elf_set(int i, size_t size, size_t offset, size_t addr) { +static void elf_set(int i, unsigned char *base, size_t size, size_t offset, size_t addr) { if (size <= 4096) { // Possible cmdline memset(hdr.cmdline, 0, BOOT_ARGS_SIZE); @@ -197,7 +153,7 @@ static void elf_set(int i, size_t size, size_t offset, size_t addr) { } } -static void parse_elf() { +static void parse_elf(unsigned char *base) { // Reset boot image header memset(&hdr, 0, sizeof(hdr)); @@ -224,7 +180,7 @@ static void parse_elf() { sh32 = (elf32_shdr *) (base + elf32->e_shoff); for (int i = 0; i < elf32->e_phnum; ++i) { - elf_set(i, ph32[i].p_filesz, ph32[i].p_offset, ph32[i].p_paddr); + elf_set(i, base, ph32[i].p_filesz, ph32[i].p_offset, ph32[i].p_paddr); } if (elf32->e_shnum) { @@ -253,7 +209,7 @@ static void parse_elf() { sh64 = (elf64_shdr *) (base + elf64->e_shoff); for (int i = 0; i < elf64->e_phnum; ++i) { - elf_set(i, ph64[i].p_filesz, ph64[i].p_offset, ph64[i].p_paddr); + elf_set(i, base, ph64[i].p_filesz, ph64[i].p_offset, ph64[i].p_paddr); } if (elf64->e_shnum) { @@ -272,44 +228,45 @@ static void parse_elf() { check_headers(); } -static void parse_aosp() { +static void parse_aosp(unsigned char *base) { printf("IMG [AOSP]\n"); - unsigned char *pos = base; + size_t pos = 0; // Read the header - memcpy(&hdr, pos, sizeof(hdr)); + memcpy(&hdr, base, sizeof(hdr)); pos += hdr.page_size; // Kernel position - kernel = pos; + kernel = base + pos; pos += hdr.kernel_size; - page_align(&pos); + mem_align(&pos, hdr.page_size); // Ramdisk position - ramdisk = pos; + ramdisk = base + pos; pos += hdr.ramdisk_size; - page_align(&pos); + mem_align(&pos, hdr.page_size); if (hdr.second_size) { // Second position - second = pos; + second = base + pos; pos += hdr.second_size; - page_align(&pos); + mem_align(&pos, hdr.page_size); } if (hdr.dt_size) { // dtb position - dtb = pos; + dtb = base + pos; pos += hdr.dt_size; - page_align(&pos); + mem_align(&pos, hdr.page_size); } check_headers(); } void parse_img(unsigned char *orig, size_t size) { + unsigned char *base; for(base = orig; base < (orig + size); base += 256) { switch (check_type(base)) { case CHROMEOS: @@ -319,11 +276,11 @@ void parse_img(unsigned char *orig, size_t size) { // Don't override CHROMEOS if (boot_type != CHROMEOS) boot_type = AOSP; - parse_aosp(); + parse_aosp(base); return; case ELF: boot_type = ELF; - parse_elf(); + parse_elf(base); return; default: continue; diff --git a/jni/magiskboot/repack.c b/jni/magiskboot/repack.c index c19d56126..dd8d6e362 100644 --- a/jni/magiskboot/repack.c +++ b/jni/magiskboot/repack.c @@ -1,61 +1,41 @@ #include "magiskboot.h" -// Global pointer of output -static int ofd, opos; +static size_t restore(const char *filename, int fd) { + int ifd = open(filename, O_RDONLY); + if (ifd < 0) + error(1, "Cannot open %s\n", filename); -static size_t restore(const char *filename) { - int fd = open(filename, O_RDONLY); - if (fd < 0) { - fprintf(stderr, "Cannot open %s\n", filename); - exit(1); + size_t size = lseek(ifd, 0, SEEK_END); + lseek(ifd, 0, SEEK_SET); + if (sendfile(fd, ifd, NULL, size) != size) { + error(1, "Cannot write %s\n", filename); } - size_t size = lseek(fd, 0, SEEK_END); - lseek(fd, 0, SEEK_SET); - if (sendfile(ofd, fd, NULL, size) < 0) { - fprintf(stderr, "Cannot write %s\n", filename); - exit(1); - } - close(fd); - opos += size; + close(ifd); return size; } -static void restore_buf(size_t size, const void *buf) { - if (write(ofd, buf, size) != size) { - fprintf(stderr, "Cannot dump from input file\n"); - exit(1); +static void restore_buf(const void *buf, size_t size, int fd) { + if (write(fd, buf, size) != size) { + error(1, "Cannot dump from input file\n"); } - opos += size; -} - -static void page_align() { - uint32_t pagemask = hdr.page_size - 1L; - if (opos & pagemask) { - opos += hdr.page_size - (opos & pagemask); - } - ftruncate(ofd, opos); - lseek(ofd, 0, SEEK_END); } 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 - ofd = open("new-boot.img", O_RDWR | O_CREAT | O_TRUNC, 0644); - + 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 + parse_img(orig, size); + + // Create new image + int fd = open_new("new-boot.img"); + // Set all sizes to 0 hdr.kernel_size = 0; hdr.ramdisk_size = 0; @@ -63,39 +43,33 @@ void repack(const char* image) { hdr.dt_size = 0; // Skip a page for header - ftruncate(ofd, hdr.page_size); - lseek(ofd, 0, SEEK_END); - opos += hdr.page_size; + ftruncate(fd, hdr.page_size); + lseek(fd, 0, SEEK_END); // Restore kernel if (mtk_kernel) { - restore_buf(512, kernel); + restore_buf(kernel, 512, fd); hdr.kernel_size += 512; } - hdr.kernel_size += restore(KERNEL_FILE); - page_align(); + hdr.kernel_size += restore(KERNEL_FILE, fd); + file_align(fd, hdr.page_size); // Restore ramdisk if (mtk_ramdisk) { - restore_buf(512, ramdisk); + restore_buf(ramdisk, 512, fd); hdr.ramdisk_size += 512; } if (access(RAMDISK_FILE, R_OK) == 0) { // If we found raw cpio, compress 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); + 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!\n"); + error(1, "Unsupported format! Please compress manually!"); munmap(cpio, cpio_size); - close(rfd); } int found = 0; @@ -109,29 +83,28 @@ void repack(const char* image) { if (!found) error(1, "No ramdisk exists!"); - hdr.ramdisk_size += restore(name); - page_align(); + hdr.ramdisk_size += restore(name, fd); + file_align(fd, hdr.page_size); // Restore second if (access(SECOND_FILE, R_OK) == 0) { - hdr.second_size += restore(SECOND_FILE); - page_align(); + hdr.second_size += restore(SECOND_FILE, fd); + file_align(fd, hdr.page_size); } // Restore dtb if (access(DTB_FILE, R_OK) == 0) { - hdr.dt_size += restore(DTB_FILE); - page_align(); + hdr.dt_size += restore(DTB_FILE, fd); + file_align(fd, hdr.page_size); } // Write header back - lseek(ofd, 0, SEEK_SET); - write(ofd, &hdr, sizeof(hdr)); + lseek(fd, 0, SEEK_SET); + write(fd, &hdr, sizeof(hdr)); - munmap(orig, isize); - close(ifd); - close(ofd); - if (opos > isize) { + munmap(orig, size); + if (lseek(fd, 0, SEEK_CUR) > size) { error(2, "Boot partition too small!"); } + close(fd); } diff --git a/jni/magiskboot/unpack.c b/jni/magiskboot/unpack.c index 1a25008af..b87a1973f 100644 --- a/jni/magiskboot/unpack.c +++ b/jni/magiskboot/unpack.c @@ -1,29 +1,23 @@ #include "magiskboot.h" static void dump(unsigned char *buf, size_t size, const char *filename) { - 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) + int fd = open_new(filename); + if (write(fd, buf, size) != size) error(1, "Cannot dump %s", filename); - close(ofd); + close(fd); } void unpack(const char* image) { - int fd = open(image, O_RDONLY); - if (fd < 0) - error(1, "Cannot open %s", image); - - size_t size = lseek(fd, 0, SEEK_END); - lseek(fd, 0, SEEK_SET); - unsigned char *orig = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + size_t size; + unsigned char *orig; + mmap_ro(image, &orig, &size); // 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"); + dump(orig, 0, "chromeos"); } char name[PATH_MAX]; @@ -74,6 +68,5 @@ void unpack(const char* image) { } munmap(orig, size); - close(fd); } diff --git a/jni/magiskboot/utils.c b/jni/magiskboot/utils.c new file mode 100644 index 000000000..ca154be13 --- /dev/null +++ b/jni/magiskboot/utils.c @@ -0,0 +1,77 @@ +#include "magiskboot.h" +#include "elf.h" + +void mmap_ro(const char *filename, unsigned char **buf, size_t *size) { + int fd = open(filename, O_RDONLY); + if (fd < 0) + error(1, "Cannot open %s", filename); + *size = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); + *buf = mmap(NULL, *size, PROT_READ, MAP_SHARED, fd, 0); + close(fd); +} + +void mmap_rw(const char *filename, unsigned char **buf, size_t *size) { + int fd = open(filename, O_RDWR); + if (fd < 0) + error(1, "Cannot open %s", filename); + *size = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); + *buf = mmap(NULL, *size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + close(fd); +} + +file_t check_type(const unsigned char *buf) { + if (memcmp(buf, CHROMEOS_MAGIC, CHROMEOS_MAGIC_SIZE) == 0) { + return CHROMEOS; + } else if (memcmp(buf, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0) { + return AOSP; + } else if (memcmp(buf, ELF_MAGIC, ELF_MAGIC_SIZE) == 0) { + return ELF; + } else if (memcmp(buf, "\x1f\x8b\x08\x00", 4) == 0) { + return GZIP; + } else if (memcmp(buf, "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a", 9) == 0) { + return LZOP; + } else if (memcmp(buf, "\xfd""7zXZ\x00", 6) == 0) { + return XZ; + } else if (memcmp(buf, "\x5d\x00\x00", 3) == 0 + && (buf[12] == (unsigned char) '\xff' || buf[12] == (unsigned char) '\x00')) { + return LZMA; + } else if (memcmp(buf, "BZh", 3) == 0) { + return BZIP2; + } else if ( ( memcmp(buf, "\x04\x22\x4d\x18", 4) == 0 + || memcmp(buf, "\x03\x21\x4c\x18", 4) == 0) + || memcmp(buf, "\x02\x21\x4c\x18", 4) == 0) { + return LZ4; + } else if (memcmp(buf, "\x88\x16\x88\x58", 4) == 0) { + return MTK; + } else if (memcmp(buf, "QCDT", 4) == 0) { + return QCDT; + } else { + return UNKNOWN; + } +} + +void mem_align(size_t *pos, size_t align) { + size_t mask = align - 1; + if (*pos & mask) { + *pos += align - (*pos & mask); + } +} + +void file_align(int fd, size_t align) { + size_t pos = lseek(fd, 0, SEEK_CUR); + size_t mask = align - 1; + if (pos & mask) { + pos += align - (pos & mask); + ftruncate(fd, pos); + lseek(fd, 0, SEEK_END); + } +} + +int open_new(const char *filename) { + int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd < 0) + error(1, "Unable to create %s", filename); + return fd; +}