From 7ef0746c52274a1bfe44cd84500b11b680a622b6 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 25 Feb 2017 03:29:12 +0800 Subject: [PATCH] Add ELF support --- jni/bootimgtools/Android.mk | 2 +- jni/bootimgtools/bootimg.h | 12 ++ jni/bootimgtools/elf.h | 149 +++++++++++++++++++++++ jni/bootimgtools/main.c | 52 ++++---- jni/bootimgtools/parseimg.c | 232 ++++++++++++++++++++++++++++++++++++ jni/bootimgtools/repack.c | 116 ++++++++---------- jni/bootimgtools/unpack.c | 171 ++++++++++++-------------- 7 files changed, 552 insertions(+), 182 deletions(-) create mode 100644 jni/bootimgtools/elf.h create mode 100644 jni/bootimgtools/parseimg.c diff --git a/jni/bootimgtools/Android.mk b/jni/bootimgtools/Android.mk index 6d6fc8f6f..733220bc8 100644 --- a/jni/bootimgtools/Android.mk +++ b/jni/bootimgtools/Android.mk @@ -3,6 +3,6 @@ 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 +LOCAL_SRC_FILES := main.c unpack.c repack.c hexpatch.c parseimg.c LOCAL_CFLAGS += -std=gnu11 include $(BUILD_EXECUTABLE) diff --git a/jni/bootimgtools/bootimg.h b/jni/bootimgtools/bootimg.h index 3a7e46353..48b08fa14 100644 --- a/jni/bootimgtools/bootimg.h +++ b/jni/bootimgtools/bootimg.h @@ -93,8 +93,20 @@ 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 diff --git a/jni/bootimgtools/elf.h b/jni/bootimgtools/elf.h new file mode 100644 index 000000000..447209528 --- /dev/null +++ b/jni/bootimgtools/elf.h @@ -0,0 +1,149 @@ + +#ifndef _ELF_H_ +#define _ELF_H_ + +#include + +/* +** ELF structure +** +** +-----------------+ +** | ELF magic | | 4 bytes +** +------------ + +** | ELF class | | 1 byte +** +------------ + +** | ELF header | +** +-----------------+ +** ~ +** +-----------------+ +** | program header | kernel info +** +-----------------+ +** | program header | ramdisk info +** +-----------------+ +** | program header | dtb info +** +-----------------+ +** ~ +** +-----------------+ +** | section header | cmdline info +** +-----------------+ +** ~ +** +-----------------+ +** | | +** | Data | +** | | +** +-----------------+ + +*/ + +typedef uint32_t elf32_addr; +typedef uint16_t elf32_half; +typedef uint32_t elf32_off; +typedef uint32_t elf32_word; + +typedef uint64_t elf64_addr; +typedef uint16_t elf64_half; +typedef uint64_t elf64_off; +typedef uint32_t elf64_word; +typedef uint64_t elf64_xword; + +#define ELF_MAGIC "\x7f""ELF" +#define ELF_MAGIC_SIZE 4 + +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_OSABI 7 +#define EI_PAD 8 + +#define ELFCLASSNONE 0 +#define ELFCLASS32 1 +#define ELFCLASS64 2 +#define ELFCLASSNUM 3 + +#define ET_EXEC 2 +#define EM_ARM 40 +#define EI_NIDENT 16 + +typedef struct elf32_ehdr{ + unsigned char e_ident[EI_NIDENT]; + elf32_half e_type; + elf32_half e_machine; + elf32_word e_version; + elf32_addr e_entry; /* Entry point */ + elf32_off e_phoff; + elf32_off e_shoff; + elf32_word e_flags; + elf32_half e_ehsize; + elf32_half e_phentsize; + elf32_half e_phnum; + elf32_half e_shentsize; + elf32_half e_shnum; + elf32_half e_shstrndx; +} elf32_ehdr; + +typedef struct elf64_ehdr { + unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ + elf64_half e_type; + elf64_half e_machine; + elf64_word e_version; + elf64_addr e_entry; /* Entry point virtual address */ + elf64_off e_phoff; /* Program header table file offset */ + elf64_off e_shoff; /* Section header table file offset */ + elf64_word e_flags; + elf64_half e_ehsize; + elf64_half e_phentsize; + elf64_half e_phnum; + elf64_half e_shentsize; + elf64_half e_shnum; + elf64_half e_shstrndx; +} elf64_ehdr; + +typedef struct elf32_phdr{ + elf32_word p_type; + elf32_off p_offset; + elf32_addr p_vaddr; + elf32_addr p_paddr; + elf32_word p_filesz; + elf32_word p_memsz; + elf32_word p_flags; + elf32_word p_align; +} elf32_phdr; + +typedef struct elf64_phdr { + elf64_word p_type; + elf64_word p_flags; + elf64_off p_offset; /* Segment file offset */ + elf64_addr p_vaddr; /* Segment virtual address */ + elf64_addr p_paddr; /* Segment physical address */ + elf64_xword p_filesz; /* Segment size in file */ + elf64_xword p_memsz; /* Segment size in memory */ + elf64_xword p_align; /* Segment alignment, file & memory */ +} elf64_phdr; + +typedef struct elf32_shdr { + elf32_word s_name; + elf32_word s_type; + elf32_word s_flags; + elf32_addr s_addr; + elf32_off s_offset; + elf32_word s_size; + elf32_word s_link; + elf32_word s_info; + elf32_word s_addralign; + elf32_word s_entsize; +} elf32_shdr; + +typedef struct elf64_shdr { + elf64_word s_name; /* Section name, index in string tbl */ + elf64_word s_type; /* Type of section */ + elf64_xword s_flags; /* Miscellaneous section attributes */ + elf64_addr s_addr; /* Section virtual addr at execution */ + elf64_off s_offset; /* Section file offset */ + elf64_xword s_size; /* Size of section in bytes */ + elf64_word s_link; /* Index of another section */ + elf64_word s_info; /* Additional section information */ + elf64_xword s_addralign; /* Section alignment */ + elf64_xword s_entsize; /* Entry size if section holds table */ +} elf64_shdr; + +#endif diff --git a/jni/bootimgtools/main.c b/jni/bootimgtools/main.c index 7ff39e5f9..9eed10c86 100644 --- a/jni/bootimgtools/main.c +++ b/jni/bootimgtools/main.c @@ -1,5 +1,7 @@ -#include #include +#include +#include +#include #include "bootimg.h" @@ -7,7 +9,7 @@ Patch Boot Image *********************/ -static int usage(char *arg0) { +static void usage(char *arg0) { fprintf(stderr, "Boot Image Unpack/Repack Tool\n"); fprintf(stderr, "%s --unpack \n", arg0); fprintf(stderr, " Unpack into current directory\n\n"); @@ -15,30 +17,34 @@ static int usage(char *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"); - return 1; + exit(1); +} + +void error(int rc, const char *msg, ...) { + va_list ap; + va_start(ap, msg); + vfprintf(stderr, msg, ap); + fprintf(stderr,"\n\n"); + va_end(ap); + exit(rc); } int main(int argc, char *argv[]) { - char ch; - struct option long_options[] = { - {"unpack", required_argument, NULL, 'u'}, - {"repack", required_argument, NULL, 'r'}, - {"hexpatch", required_argument, NULL, 'p'}, - {NULL, 0, NULL, 0} - }; - while ((ch = getopt_long(argc, argv, "e:r:p:", long_options, NULL)) != -1) { - switch (ch) { - case 'e': - return unpack(optarg); - case 'r': - return repack(optarg); - case 'p': - if (argc < 5) return usage(argv[0]); - optind += 2; - return hexpatch(argv[optind - 3], argv[optind - 2], argv[optind - 1]); - default: - return usage(argv[0]); - } + 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) + usage(argv[0]); + hexpatch(argv[2], argv[3], argv[4]); + } else { + usage(argv[0]); } + return 0; + } diff --git a/jni/bootimgtools/parseimg.c b/jni/bootimgtools/parseimg.c new file mode 100644 index 000000000..4230c2fe9 --- /dev/null +++ b/jni/bootimgtools/parseimg.c @@ -0,0 +1,232 @@ +#include +#include +#include +#include +#include + +#include "bootimg.h" +#include "elf.h" + +void print_header() { + 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); +} + +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; + size_t r_e_size, r_p_size, r_s_size; + + if (is64) { + e_size = ((elf64_ehdr *) elf)->e_ehsize; + mach = ((elf64_ehdr *) elf)->e_machine; + ver = ((elf64_ehdr *) elf)->e_version; + p_size = ((elf64_ehdr *) elf)->e_phentsize; + p_num = ((elf64_ehdr *) elf)->e_phnum; + s_size = ((elf64_ehdr *) elf)->e_shentsize; + s_num = ((elf64_ehdr *) elf)->e_shnum; + r_e_size = sizeof(elf64_ehdr); + r_p_size = sizeof(elf64_phdr); + r_s_size = sizeof(elf64_shdr); + } else { + e_size = ((elf32_ehdr *) elf)->e_ehsize; + mach = ((elf32_ehdr *) elf)->e_machine; + ver = ((elf32_ehdr *) elf)->e_version; + p_size = ((elf32_ehdr *) elf)->e_phentsize; + p_num = ((elf32_ehdr *) elf)->e_phnum; + s_size = ((elf32_ehdr *) elf)->e_shentsize; + s_num = ((elf32_ehdr *) elf)->e_shnum; + r_e_size = sizeof(elf32_ehdr); + r_p_size = sizeof(elf32_phdr); + r_s_size = sizeof(elf32_shdr); + } + + if (e_size != r_e_size) + error(1, "Header size not %d", r_e_size); + + if (mach != EM_ARM) + error(1, "ELF machine is not ARM"); + + if (ver != 1) + error(1, "Unknown ELF version"); + + if (p_size != r_p_size) + error(1, "Program header size not %d", r_p_size); + + if (p_num < 2 || p_num > 4) + error(1, "Unexpected number of elements: %d", p_num); + + if (s_num && s_size != r_s_size) + error(1, "Section header size not %d", r_s_size); + + if (s_num > 1) + error(1, "More than one section header"); +} + +static void elf_set(int i, size_t size, size_t offset, size_t addr) { + if (size <= 4096) { + // Possible cmdline + memset(hdr.cmdline, 0, BOOT_ARGS_SIZE); + strncpy((char *) hdr.cmdline, (char *) (base + offset), BOOT_ARGS_SIZE); + hdr.cmdline[strcspn((char*) hdr.cmdline, "\n")] = '\0'; + return; + } + switch(i) { + case 0: + // kernel + kernel = base + offset; + hdr.kernel_size = size; + hdr.kernel_addr = addr; + break; + case 1: + // ramdisk + ramdisk = base + offset; + hdr.ramdisk_size = size; + hdr.ramdisk_addr = addr; + break; + case 2: + // dtb + dtb = base + offset; + hdr.dt_size = size; + hdr.tags_addr = addr; + break; + } +} + +void parse_elf() { + + // Reset boot image header + memset(&hdr, 0, sizeof(hdr)); + + // Hardcode pagesize + hdr.page_size = 4096; + + switch(base[EI_CLASS]) { + + case ELFCLASS32: { + + elf32_ehdr *elf32; + elf32_phdr *ph32; + elf32_shdr *sh32; + + printf("IMAGE [ELF32]\n"); + + elf32 = (elf32_ehdr *) base; + + elf_header_check(elf32, 0); + + ph32 = (elf32_phdr *) (base + elf32->e_phoff); + 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); + } + + if (elf32->e_shnum) { + // cmdline + memset(hdr.cmdline, 0, BOOT_ARGS_SIZE); + strncpy((char *) hdr.cmdline, (char *) (base + sh32->s_offset + 8), BOOT_ARGS_SIZE); + hdr.cmdline[strcspn((char*) hdr.cmdline, "\n")] = '\0'; + } + + break; + } + + case ELFCLASS64: { + + elf64_ehdr *elf64; + elf64_phdr *ph64; + elf64_shdr *sh64; + + printf("IMAGE [ELF64]\n"); + + elf64 = (elf64_ehdr *) base; + + elf_header_check(elf64, 1); + + ph64 = (elf64_phdr *) (base + elf64->e_phoff); + 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); + } + + if (elf64->e_shnum) { + // cmdline + memset(hdr.cmdline, 0, BOOT_ARGS_SIZE); + strncpy((char *) hdr.cmdline, (char *) (base + sh64->s_offset + 8), BOOT_ARGS_SIZE); + hdr.cmdline[strcspn((char*) hdr.cmdline, "\n")] = '\0'; + } + break; + } + + default: + error(1, "ELF format error!"); + } + + print_header(); +} + +void parse_aosp() { + + printf("IMG [AOSP]\n"); + + unsigned char *pos = base; + + // Read the header + memcpy(&hdr, pos, sizeof(hdr)); + pos += hdr.page_size; + + // Kernel position + kernel = pos; + pos += hdr.kernel_size; + page_align(&pos); + + // Ramdisk position + ramdisk = pos; + pos += hdr.ramdisk_size; + page_align(&pos); + + if (hdr.second_size) { + // Second position + second = pos; + pos += hdr.second_size; + page_align(&pos); + } + + if (hdr.dt_size) { + // dtb position + dtb = pos; + pos += hdr.dt_size; + page_align(&pos); + } + + print_header(); +} \ No newline at end of file diff --git a/jni/bootimgtools/repack.c b/jni/bootimgtools/repack.c index 23c443bf7..09cf5a737 100644 --- a/jni/bootimgtools/repack.c +++ b/jni/bootimgtools/repack.c @@ -10,12 +10,12 @@ #include #include "bootimg.h" +#include "elf.h" // Global pointer of current positions -static void *ibase, *ipos; static int ofd, opos; -static size_t dump(const char *filename) { +static size_t restore(const char *filename) { int fd = open(filename, O_RDONLY); if (fd < 0) { fprintf(stderr, "Cannot open %s\n", filename); @@ -32,67 +32,76 @@ static size_t dump(const char *filename) { return size; } -static void dump_buf(size_t size, const void *buf) { - if (write(ofd, buf, size) < 0) { +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); } opos += size; } -static void in_page_align(uint32_t pagesize) { - uint32_t itemsize = ipos - ibase, pagemask = pagesize - 1L; - if (itemsize & pagemask) { - ipos += pagesize - (itemsize & pagemask); - } -} - -static void out_page_align(uint32_t pagesize) { - uint32_t pagemask = pagesize - 1L; +static void page_align() { + uint32_t pagemask = hdr.page_size - 1L; if (opos & pagemask) { - opos += pagesize - (opos & pagemask); + opos += hdr.page_size - (opos & pagemask); } ftruncate(ofd, opos); lseek(ofd, 0, SEEK_END); } -static int aosp() { - printf("AOSP Boot Image Detected\n"); +int repack(const char* image) { + // Load original boot + int ifd = open(image, O_RDONLY), ret = -1; + 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); + + // Create new boot image + unlink("new-boot.img"); + ofd = open("new-boot.img", O_RDWR | O_CREAT, 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; - boot_img_hdr hdr, ihdr; - - // Read the original header - memcpy(&ihdr, ibase, sizeof(ihdr)); - hdr = ihdr; - + // Set all sizes to 0 hdr.kernel_size = 0; hdr.ramdisk_size = 0; hdr.second_size = 0; hdr.dt_size = 0; - // Skip a page + // Skip a page for header ftruncate(ofd, hdr.page_size); lseek(ofd, 0, SEEK_END); opos += hdr.page_size; - ipos = ibase + hdr.page_size; - // Dump zImage - if (memcmp(ipos, "\x88\x16\x88\x58", 4) == 0) { - printf("Dumping MTK header back to zImage\n"); - dump_buf(512, ipos); + // Restore kernel + if (memcmp(kernel, "\x88\x16\x88\x58", 4) == 0) { + printf("Dumping MTK header back to kernel\n"); + restore_buf(512, kernel); hdr.kernel_size += 512; } - hdr.kernel_size += dump("kernel"); - ipos += ihdr.kernel_size; - in_page_align(hdr.page_size); - out_page_align(hdr.page_size); + hdr.kernel_size += restore("kernel"); + page_align(); // Dump ramdisk - if (memcmp(ipos, "\x88\x16\x88\x58", 4) == 0) { + if (memcmp(ramdisk, "\x88\x16\x88\x58", 4) == 0) { printf("Dumping MTK header back to ramdisk\n"); - dump_buf(512, ipos); + restore_buf(512, ramdisk); hdr.ramdisk_size += 512; } if (access("ramdisk.gz", R_OK) == 0) { @@ -108,50 +117,31 @@ static int aosp() { } else if (access("ramdisk.lz4", R_OK) == 0) { name = "ramdisk.lz4"; } else { - fprintf(stderr, "Ramdisk file doesn't exist!\n"); - return 1; + error(1, "Ramdisk file doesn't exist!"); } - hdr.ramdisk_size += dump(name); - out_page_align(hdr.page_size); + hdr.ramdisk_size += restore(name); + page_align(); // Dump second if (access("second", R_OK) == 0) { - hdr.second_size += dump("second"); - out_page_align(hdr.page_size); + hdr.second_size += restore("second"); + page_align(); } // Dump dtb if (access("dtb", R_OK) == 0) { - hdr.dt_size += dump("dtb"); - out_page_align(hdr.page_size); + hdr.dt_size += restore("dtb"); + page_align(); } + print_header(); + // Write header back lseek(ofd, 0, SEEK_SET); write(ofd, &hdr, sizeof(hdr)); - return 0; -} - -int repack(const char* image) { - // Load original boot - int ifd = open(image, O_RDONLY), ret = -1; - size_t isize = lseek(ifd, 0, SEEK_END); - lseek(ifd, 0, SEEK_SET); - void *orig = mmap(NULL, isize, PROT_READ, MAP_SHARED, ifd, 0); - - // Create new boot image - unlink("new-boot.img"); - ofd = open("new-boot.img", O_RDWR | O_CREAT, 0644); - - // Check headers - for(ibase = orig; ibase < (orig + isize); ibase += 256) { - if (memcmp(ibase, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0) { - ret = aosp(); - break; - } - } munmap(orig, isize); close(ifd); + close(ofd); return ret; } diff --git a/jni/bootimgtools/unpack.c b/jni/bootimgtools/unpack.c index 5b0e48bb3..996ed8646 100644 --- a/jni/bootimgtools/unpack.c +++ b/jni/bootimgtools/unpack.c @@ -10,119 +10,100 @@ #include #include "bootimg.h" +#include "elf.h" -// Global pointer of current positions -static unsigned char *base, *pos; - -static void dump(size_t size, const char *filename) { +static void dump(unsigned char *buf, size_t size, const char *filename) { unlink(filename); int ofd = open(filename, O_WRONLY | O_CREAT, 0644); - assert(ofd >= 0); - int ret = write(ofd, pos, size); - assert(ret == size); + if (ofd < 0) + error(1, "Cannot open %s", filename); + if (write(ofd, buf, size) != size) + error(1, "Cannot dump %s", filename); close(ofd); - pos += size; -} - -static void page_align(uint32_t pagesize) { - uint32_t itemsize = pos - base, pagemask = pagesize - 1L; - if (itemsize & pagemask) { - pos += pagesize - (itemsize & pagemask); - } -} - -static int aosp() { - printf("AOSP Boot Image Detected\n"); - - char name[PATH_MAX], *ext; - - // Read the header - boot_img_hdr hdr; - memcpy(&hdr, base, sizeof(hdr)); - - pos = base + hdr.page_size; - - // Dump zImage - if (memcmp(pos, "\x88\x16\x88\x58", 4) == 0) { - printf("MTK header found in zImage\n"); - pos += 512; - hdr.kernel_size -= 512; - } - dump(hdr.kernel_size, "kernel"); - page_align(hdr.page_size); - - // Dump ramdisk - if (memcmp(pos, "\x88\x16\x88\x58", 4) == 0) { - printf("MTK header found in ramdisk\n"); - pos += 512; - hdr.ramdisk_size -= 512; - } - // Compression detection - if (memcmp(pos, "\x1f\x8b\x08\x00", 4) == 0) { - // gzip header - printf("gzip ramdisk format detected!\n"); - ext = "gz"; - } else if (memcmp(pos, "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a", 9) == 0) { - // lzop header - printf("lzop ramdisk format detected!\n"); - ext = "lzo"; - } else if (memcmp(pos, "\xfd""7zXZ\x00", 6) == 0) { - // xz header - printf("xz ramdisk format detected!\n"); - ext = "xz"; - } else if (memcmp(pos, "\x5d\x00\x00", 3) == 0 - && (pos[12] == (unsigned char) '\xff' || pos[12] == (unsigned char) '\x00')) { - // lzma header - printf("lzma ramdisk format detected!\n"); - ext = "lzma"; - } else if (memcmp(pos, "BZh", 3) == 0) { - // bzip2 header - printf("bzip2 ramdisk format detected!\n"); - ext = "bz2"; - } else if ( ( memcmp(pos, "\x04\x22\x4d\x18", 4) == 0 - || memcmp(pos, "\x03\x21\x4c\x18", 4) == 0) - || memcmp(pos, "\x02\x21\x4c\x18", 4) == 0) { - // lz4 header - printf("lz4 ramdisk format detected!\n"); - ext = "lz4"; - } else { - fprintf(stderr, "Unknown ramdisk format!\n"); - return 1; - } - sprintf(name, "%s.%s", "ramdisk", ext); - dump(hdr.ramdisk_size, name); - page_align(hdr.page_size); - - if (hdr.second_size) { - // Dump second - dump(hdr.second_size, "second"); - page_align(hdr.page_size); - } - - if (hdr.dt_size) { - // Dump dtb - dump(hdr.dt_size, "dtb"); - page_align(hdr.page_size); - } - - return 0; } int unpack(const char* image) { int fd = open(image, O_RDONLY), ret = 0; + 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); - // Check headers + // Parse images for(base = orig; base < (orig + size); base += 256) { if (memcmp(base, CHROMEOS_MAGIC, CHROMEOS_MAGIC_SIZE) == 0) { - dump(0, "chromeos"); + dump(base, 0, "chromeos"); } else if (memcmp(base, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0) { - ret = aosp(); + parse_aosp(); + break; + } else if (memcmp(base, ELF_MAGIC, ELF_MAGIC_SIZE) == 0) { + parse_elf(); break; } } + + char name[PATH_MAX], *ext; + + // Dump kernel + if (memcmp(kernel, "\x88\x16\x88\x58", 4) == 0) { + printf("MTK header found in kernel\n"); + kernel += 512; + hdr.kernel_size -= 512; + } + dump(kernel, hdr.kernel_size, "kernel"); + + // Dump ramdisk + if (memcmp(ramdisk, "\x88\x16\x88\x58", 4) == 0) { + printf("MTK header found in ramdisk\n"); + 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!"); + } + sprintf(name, "%s.%s", "ramdisk", ext); + dump(ramdisk, hdr.ramdisk_size, name); + + if (hdr.second_size) { + // Dump second + dump(second, hdr.second_size, "second"); + } + + if (hdr.dt_size) { + // Dump dtb + dump(dtb, hdr.dt_size, "dtb"); + } + munmap(orig, size); close(fd); return ret;