mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-25 10:47:38 +00:00
Boot IMG tools complete re-write
Fix #27, Fix #35, Fix #68, Fix #70, Fix #71, Fix #72, Fix #75, Fix #87
This commit is contained in:
parent
e11fb2c09e
commit
ee2a30470a
@ -28,6 +28,9 @@ 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];
|
||||
@ -43,7 +46,14 @@ struct boot_img_hdr
|
||||
|
||||
uint32_t tags_addr; /* physical addr for kernel tags */
|
||||
uint32_t page_size; /* flash page size we assume */
|
||||
uint32_t unused[2]; /* future expansion: should be 0 */
|
||||
uint32_t dt_size; /* device tree in bytes */
|
||||
|
||||
/* operating system version and security patch level; for
|
||||
* version "A.B.C" and patch level "Y-M-D":
|
||||
* ver = A << 14 | B << 7 | C (7 bits for each of A, B, C)
|
||||
* lvl = ((Y - 2000) & 127) << 4 | M (7 bits for Y, 4 bits for M)
|
||||
* os_version = ver << 11 | lvl */
|
||||
uint32_t os_version;
|
||||
|
||||
uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */
|
||||
|
||||
@ -83,8 +93,8 @@ struct boot_img_hdr
|
||||
** else: jump to kernel_addr
|
||||
*/
|
||||
|
||||
int extract(char *image);
|
||||
int repack(char *image);
|
||||
int extract(const char *image);
|
||||
int repack(const char *image);
|
||||
int hexpatch(char *image, char *from, char *to);
|
||||
|
||||
#endif
|
||||
|
@ -11,139 +11,120 @@
|
||||
|
||||
#include "bootimg.h"
|
||||
|
||||
void dump(uint8_t *ptr, size_t size, char* filename) {
|
||||
// Global pointer of current positions
|
||||
unsigned char *base, *pos;
|
||||
|
||||
static void dump(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, 0644);
|
||||
assert(ofd >= 0);
|
||||
int ret = write(ofd, ptr, size);
|
||||
int ret = write(ofd, pos, size);
|
||||
assert(ret == size);
|
||||
close(ofd);
|
||||
pos += size;
|
||||
}
|
||||
|
||||
//TODO: Search for other header types
|
||||
void dump_ramdisk(uint8_t *ptr, size_t size) {
|
||||
//GZip header
|
||||
if(memcmp(ptr, "\x1f\x8b\x08\x00", 4) == 0) {
|
||||
dump(ptr, size, "ramdisk.gz");
|
||||
//MTK header
|
||||
} else if(memcmp(ptr, "\x88\x16\x88\x58", 4) == 0) {
|
||||
if(memcmp(ptr+8, "RECOVERY", 8)==0) {
|
||||
dump(ptr, 0, "ramdisk-mtk-recovery");
|
||||
} else if(memcmp(ptr+8, "ROOTFS\0\0", 8)==0) {
|
||||
dump(ptr, 0, "ramdisk-mtk-boot");
|
||||
} else {
|
||||
exit(1);
|
||||
}
|
||||
dump(ptr, 0, "ramdisk-mtk"); //Create an mtk flag
|
||||
dump_ramdisk(ptr+512, size-512);
|
||||
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
|
||||
struct 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 {
|
||||
//Since our first aim is to extract/repack ramdisk
|
||||
//Stop if we can't find it
|
||||
//Still dump it for debug purposes
|
||||
dump(ptr, size, "ramdisk");
|
||||
|
||||
fprintf(stderr, "Unknown ramdisk type\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void search_security_hdr(uint8_t *buf, size_t size) {
|
||||
if(memcmp(buf, "CHROMEOS", 8) == 0) {
|
||||
dump(buf, 0, "chromeos");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int search_security(uint8_t *buf, size_t size, int pos) {
|
||||
//Rockchip signature
|
||||
if(memcmp(buf+1024, "SIGN", 4) == 0) {
|
||||
//Rockchip signature AT LEAST means the bootloader will check the crc
|
||||
dump(buf, 0, "rkcrc"); //Create an flag to tell it
|
||||
|
||||
//And it's possible there is a security too
|
||||
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 we didn't parse the whole file, it is highly likely there is a boot signature
|
||||
if(pos < size) {
|
||||
return 1;
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* - At the moment we dump kernel + ramdisk + second + DT, it's likely we only want ramdisk
|
||||
* - Error-handling via assert() is perhaps not the best
|
||||
*/
|
||||
int extract(char *image) {
|
||||
|
||||
int fd = open(image, O_RDONLY);
|
||||
off_t size = lseek(fd, 0, SEEK_END);
|
||||
int extract(const char* image) {
|
||||
int fd = open(image, O_RDONLY), ret = 0;
|
||||
size_t size = lseek(fd, 0, SEEK_END);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
uint8_t *orig = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
uint8_t *base = orig;
|
||||
assert(base);
|
||||
unsigned char *orig = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
|
||||
search_security_hdr(base, size);
|
||||
|
||||
//We're searching for the header in the whole file, we could stop earlier.
|
||||
//At least HTC and nVidia have a signature header
|
||||
while(base<(orig+size)) {
|
||||
if(memcmp(base, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0)
|
||||
// Check headers
|
||||
for(base = orig; base < (orig + size); base += 256) {
|
||||
if (memcmp(base, CHROMEOS_MAGIC, CHROMEOS_MAGIC_SIZE) == 0) {
|
||||
dump(0, "chromeos");
|
||||
} else if (memcmp(base, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0) {
|
||||
ret = aosp();
|
||||
break;
|
||||
//We're searching every 256bytes, is it ok?
|
||||
base += 256;
|
||||
}
|
||||
assert(base < (orig+size));
|
||||
|
||||
struct boot_img_hdr *hdr = (struct boot_img_hdr*) base;
|
||||
assert(
|
||||
hdr->page_size == 2048 ||
|
||||
hdr->page_size == 4096 ||
|
||||
hdr->page_size == 16384
|
||||
);
|
||||
|
||||
long pos = hdr->page_size;
|
||||
dump(base+pos, hdr->kernel_size, "kernel");
|
||||
pos += hdr->kernel_size + hdr->page_size-1;
|
||||
pos &= ~(hdr->page_size-1L);
|
||||
|
||||
dump_ramdisk(base+pos, hdr->ramdisk_size);
|
||||
pos += hdr->ramdisk_size + hdr->page_size-1;
|
||||
pos &= ~(hdr->page_size-1L);
|
||||
|
||||
if(hdr->second_size) {
|
||||
assert( (pos+hdr->second_size) <= size);
|
||||
dump(base+pos, hdr->second_size, "second");
|
||||
pos += hdr->second_size + hdr->page_size-1;
|
||||
pos &= ~(hdr->page_size-1L);
|
||||
}
|
||||
|
||||
//This is non-standard, so we triple check
|
||||
if( hdr->unused[0] &&
|
||||
pos < size &&
|
||||
(pos+hdr->unused[0]) <= size) {
|
||||
|
||||
if(memcmp(base+pos, "QCDT", 4) == 0 ||
|
||||
memcmp(base+pos, "SPRD", 4) == 0 ||
|
||||
memcmp(base+pos, "DTBH", 4) == 0 ||
|
||||
memcmp(base+pos, "\xD0\x0D\xFE\xED", 4) == 0
|
||||
) {
|
||||
dump(base+pos, hdr->unused[0], "dt");
|
||||
pos += hdr->unused[0] + hdr->page_size-1;
|
||||
pos &= ~(hdr->page_size-1L);
|
||||
}
|
||||
}
|
||||
|
||||
//If we think we find some security-related infos in the boot.img
|
||||
//create a "secure" flag to warn the user it is dangerous
|
||||
if(search_security(base, size, pos)) {
|
||||
dump(base, 0, "secure");
|
||||
}
|
||||
|
||||
munmap(orig, size);
|
||||
close(fd);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -11,134 +11,147 @@
|
||||
|
||||
#include "bootimg.h"
|
||||
|
||||
off_t file_size(char *filename) {
|
||||
struct stat st;
|
||||
if(stat(filename, &st))
|
||||
exit(1);
|
||||
return st.st_size;
|
||||
}
|
||||
// Global pointer of current positions
|
||||
void *ibase, *ipos;
|
||||
int ofd, opos;
|
||||
|
||||
int append_file(int ofd, char *filename, off_t pos) {
|
||||
lseek(ofd, pos, SEEK_SET);
|
||||
static size_t dump(const char *filename) {
|
||||
int fd = open(filename, O_RDONLY);
|
||||
int size = lseek(fd, 0, SEEK_END);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Cannot open %s\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
size_t size = lseek(fd, 0, SEEK_END);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
sendfile(ofd, fd, NULL, size);
|
||||
if (sendfile(ofd, fd, NULL, size) < 0) {
|
||||
fprintf(stderr, "Cannot write %s\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
close(fd);
|
||||
opos += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
int append_ramdisk(int ofd, off_t pos) {
|
||||
if(access("ramdisk-mtk", R_OK) == 0) {
|
||||
char buf[512];
|
||||
off_t size = file_size("ramdisk.gz");
|
||||
memcpy(buf, "\x88\x16\x88\x58", 4);
|
||||
uint32_t v = size;
|
||||
memcpy(buf+4, &v, sizeof(v)); //Should convert to LE
|
||||
|
||||
//TODO: RECOVERY OR ROOTFS?
|
||||
char str[32];
|
||||
memset(str, 0, sizeof(str));
|
||||
if(access("ramdisk-mtk-boot", R_OK)==0) {
|
||||
strcpy(str, "ROOTFS");
|
||||
} else if(access("ramdisk-mtk-recovery", R_OK)==0) {
|
||||
strcpy(str, "RECOVERY");
|
||||
} else {
|
||||
exit(1);
|
||||
}
|
||||
memcpy(buf+8, str, sizeof(str));
|
||||
|
||||
memset(buf+8+sizeof(str), 0xff, 512-8-sizeof(str));
|
||||
|
||||
pwrite(ofd, buf, sizeof(buf), pos);
|
||||
|
||||
return append_file(ofd, "ramdisk.gz", pos + 512) + 512;
|
||||
} else if(access("ramdisk.gz", R_OK) == 0) {
|
||||
return append_file(ofd, "ramdisk.gz", pos);
|
||||
} else {
|
||||
return append_file(ofd, "ramdisk", pos);
|
||||
}
|
||||
}
|
||||
|
||||
void post_process(struct boot_img_hdr *hdr, int ofd, int pos) {
|
||||
if(access("rkcrc", R_OK) == 0) {
|
||||
fprintf(stderr, "Rockchip CRCs not supported yet\n");
|
||||
static void dump_buf(size_t size, const void *buf) {
|
||||
if (write(ofd, buf, size) < 0) {
|
||||
fprintf(stderr, "Cannot dump from input file\n");
|
||||
exit(1);
|
||||
}
|
||||
//Round up the file size
|
||||
ftruncate(ofd, pos);
|
||||
opos += size;
|
||||
}
|
||||
|
||||
int repack(char *image) {
|
||||
|
||||
//TODO: Merge with extract.c?
|
||||
//{
|
||||
int ifd = open(image, O_RDONLY);
|
||||
off_t isize = lseek(ifd, 0, SEEK_END);
|
||||
lseek(ifd, 0, SEEK_SET);
|
||||
uint8_t *iorig = mmap(NULL, isize, PROT_READ, MAP_SHARED, ifd, 0);
|
||||
uint8_t *ibase = iorig;
|
||||
assert(ibase);
|
||||
|
||||
while(ibase<(iorig+isize)) {
|
||||
if(memcmp(ibase, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0)
|
||||
break;
|
||||
ibase += 256;
|
||||
static void in_page_align(uint32_t pagesize) {
|
||||
uint32_t itemsize = ipos - ibase, pagemask = pagesize - 1L;
|
||||
if (itemsize & pagemask) {
|
||||
ipos += pagesize - (itemsize & pagemask);
|
||||
}
|
||||
assert(ibase < (iorig+isize));
|
||||
//}
|
||||
//
|
||||
struct boot_img_hdr *ihdr = (struct boot_img_hdr*) ibase;
|
||||
assert(
|
||||
ihdr->page_size == 2048 ||
|
||||
ihdr->page_size == 4096 ||
|
||||
ihdr->page_size == 16384
|
||||
);
|
||||
}
|
||||
|
||||
unlink("new-boot.img");
|
||||
int ofd = open("new-boot.img", O_RDWR|O_CREAT, 0644);
|
||||
ftruncate(ofd, ihdr->page_size);
|
||||
//Write back original header, we'll change it later
|
||||
write(ofd, ihdr, sizeof(*ihdr));
|
||||
static void out_page_align(uint32_t pagesize) {
|
||||
uint32_t pagemask = pagesize - 1L;
|
||||
if (opos & pagemask) {
|
||||
opos += pagesize - (opos & pagemask);
|
||||
}
|
||||
ftruncate(ofd, opos);
|
||||
lseek(ofd, 0, SEEK_END);
|
||||
}
|
||||
|
||||
struct boot_img_hdr *hdr = mmap(NULL, sizeof(*ihdr), PROT_READ|PROT_WRITE, MAP_SHARED, ofd, 0);
|
||||
//First set everything to zero, so we know where we are at.
|
||||
hdr->kernel_size = 0;
|
||||
hdr->ramdisk_size = 0;
|
||||
hdr->second_size = 0;
|
||||
hdr->unused[0] = 0;
|
||||
memset(hdr->id, 0, sizeof(hdr->id)); //Setting id to 0 might be wrong?
|
||||
static int aosp() {
|
||||
printf("AOSP Boot Image Detected\n");
|
||||
|
||||
int pos = hdr->page_size;
|
||||
int size = 0;
|
||||
char *name;
|
||||
struct boot_img_hdr hdr, ihdr;
|
||||
|
||||
size = append_file(ofd, "kernel", pos);
|
||||
pos += size + hdr->page_size - 1;
|
||||
pos &= ~(hdr->page_size-1);
|
||||
hdr->kernel_size = size;
|
||||
// Read the original header
|
||||
memcpy(&ihdr, ibase, sizeof(ihdr));
|
||||
hdr = ihdr;
|
||||
|
||||
size = append_ramdisk(ofd, pos);
|
||||
pos += size + hdr->page_size - 1;
|
||||
pos &= ~(hdr->page_size-1);
|
||||
hdr->ramdisk_size = size;
|
||||
// Set all sizes to 0
|
||||
hdr.kernel_size = 0;
|
||||
hdr.ramdisk_size = 0;
|
||||
hdr.second_size = 0;
|
||||
hdr.dt_size = 0;
|
||||
|
||||
if(access("second", R_OK) == 0) {
|
||||
size = append_file(ofd, "second", pos);
|
||||
pos += size + hdr->page_size - 1;
|
||||
pos &= ~(hdr->page_size-1);
|
||||
hdr->second_size = size;
|
||||
// Skip a page
|
||||
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);
|
||||
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);
|
||||
|
||||
// Dump ramdisk
|
||||
if (memcmp(ipos, "\x88\x16\x88\x58", 4) == 0) {
|
||||
printf("Dumping MTK header back to ramdisk\n");
|
||||
dump_buf(512, ipos);
|
||||
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";
|
||||
} else {
|
||||
fprintf(stderr, "Ramdisk file doesn't exist!\n");
|
||||
return 1;
|
||||
}
|
||||
hdr.ramdisk_size += dump(name);
|
||||
out_page_align(hdr.page_size);
|
||||
|
||||
// Dump second
|
||||
if (access("second", R_OK) == 0) {
|
||||
hdr.second_size += dump("second");
|
||||
out_page_align(hdr.page_size);
|
||||
}
|
||||
|
||||
if(access("dt", R_OK) == 0) {
|
||||
size = append_file(ofd, "dt", pos);
|
||||
pos += size + hdr->page_size - 1;
|
||||
pos &= ~(hdr->page_size-1);
|
||||
hdr->unused[0] = size;
|
||||
// Dump dtb
|
||||
if (access("dtb", R_OK) == 0) {
|
||||
hdr.dt_size += dump("dtb");
|
||||
out_page_align(hdr.page_size);
|
||||
}
|
||||
|
||||
post_process(hdr, ofd, pos);
|
||||
munmap(hdr, sizeof(*ihdr));
|
||||
close(ofd);
|
||||
// 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);
|
||||
return ret;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user