mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-10-16 16:51:23 +00:00
Rename module core to native
This commit is contained in:
308
native/jni/magiskboot/bootimg.c
Normal file
308
native/jni/magiskboot/bootimg.c
Normal file
@@ -0,0 +1,308 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "bootimg.h"
|
||||
#include "magiskboot.h"
|
||||
#include "utils.h"
|
||||
#include "logging.h"
|
||||
|
||||
#define INSUF_BLOCK_RET 2
|
||||
#define CHROMEOS_RET 3
|
||||
#define ELF32_RET 4
|
||||
#define ELF64_RET 5
|
||||
|
||||
static void dump(void *buf, size_t size, const char *filename) {
|
||||
int fd = creat(filename, 0644);
|
||||
xwrite(fd, buf, size);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static size_t restore(const char *filename, int fd) {
|
||||
int ifd = xopen(filename, O_RDONLY);
|
||||
size_t size = lseek(ifd, 0, SEEK_END);
|
||||
lseek(ifd, 0, SEEK_SET);
|
||||
xsendfile(fd, ifd, NULL, size);
|
||||
close(ifd);
|
||||
return size;
|
||||
}
|
||||
|
||||
static void restore_buf(int fd, const void *buf, size_t size) {
|
||||
xwrite(fd, buf, size);
|
||||
}
|
||||
|
||||
static void print_hdr(const boot_img_hdr *hdr) {
|
||||
fprintf(stderr, "KERNEL [%d] @ 0x%08x\n", hdr->kernel_size, hdr->kernel_addr);
|
||||
fprintf(stderr, "RAMDISK [%d] @ 0x%08x\n", hdr->ramdisk_size, hdr->ramdisk_addr);
|
||||
fprintf(stderr, "SECOND [%d] @ 0x%08x\n", hdr->second_size, hdr->second_addr);
|
||||
fprintf(stderr, "EXTRA [%d] @ 0x%08x\n", hdr->extra_size, hdr->tags_addr);
|
||||
fprintf(stderr, "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;
|
||||
fprintf(stderr, "OS_VERSION [%d.%d.%d]\n", a, b, c);
|
||||
|
||||
y = (os_patch_level >> 4) + 2000;
|
||||
m = os_patch_level & 0xf;
|
||||
fprintf(stderr, "PATCH_LEVEL [%d-%02d]\n", y, m);
|
||||
}
|
||||
fprintf(stderr, "NAME [%s]\n", hdr->name);
|
||||
fprintf(stderr, "CMDLINE [%s]\n", hdr->cmdline);
|
||||
}
|
||||
|
||||
int parse_img(const char *image, boot_img *boot) {
|
||||
memset(boot, 0, sizeof(*boot));
|
||||
int is_blk = mmap_ro(image, &boot->map_addr, &boot->map_size);
|
||||
|
||||
// Parse image
|
||||
fprintf(stderr, "Parsing boot image: [%s]\n", image);
|
||||
for (void *head = boot->map_addr; head < boot->map_addr + boot->map_size; head += 256) {
|
||||
size_t pos = 0;
|
||||
|
||||
switch (check_type(head)) {
|
||||
case CHROMEOS:
|
||||
// The caller should know it's chromeos, as it needs additional signing
|
||||
boot->flags |= CHROMEOS_FLAG;
|
||||
continue;
|
||||
case ELF32:
|
||||
exit(ELF32_RET);
|
||||
case ELF64:
|
||||
exit(ELF64_RET);
|
||||
case AOSP:
|
||||
// Read the header
|
||||
memcpy(&boot->hdr, head + pos, sizeof(boot->hdr));
|
||||
pos += boot->hdr.page_size;
|
||||
|
||||
print_hdr(&boot->hdr);
|
||||
|
||||
boot->kernel = head + pos;
|
||||
pos += boot->hdr.kernel_size;
|
||||
mem_align(&pos, boot->hdr.page_size);
|
||||
|
||||
boot->ramdisk = head + pos;
|
||||
pos += boot->hdr.ramdisk_size;
|
||||
mem_align(&pos, boot->hdr.page_size);
|
||||
|
||||
if (boot->hdr.second_size) {
|
||||
boot->second = head + pos;
|
||||
pos += boot->hdr.second_size;
|
||||
mem_align(&pos, boot->hdr.page_size);
|
||||
}
|
||||
|
||||
if (boot->hdr.extra_size) {
|
||||
boot->extra = head + pos;
|
||||
pos += boot->hdr.extra_size;
|
||||
mem_align(&pos, boot->hdr.page_size);
|
||||
}
|
||||
|
||||
if (pos < boot->map_size) {
|
||||
boot->tail = head + pos;
|
||||
boot->tail_size = boot->map_size - pos;
|
||||
}
|
||||
|
||||
// Search for dtb in kernel
|
||||
for (uint32_t i = 0; i < boot->hdr.kernel_size; ++i) {
|
||||
if (memcmp(boot->kernel + i, DTB_MAGIC, 4) == 0) {
|
||||
boot->dtb = boot->kernel + i;
|
||||
boot->dt_size = boot->hdr.kernel_size - i;
|
||||
boot->hdr.kernel_size = i;
|
||||
fprintf(stderr, "DTB [%u]\n", boot->dt_size);
|
||||
}
|
||||
}
|
||||
|
||||
boot->ramdisk_type = check_type(boot->ramdisk);
|
||||
boot->kernel_type = check_type(boot->kernel);
|
||||
|
||||
// Check MTK
|
||||
if (boot->kernel_type == MTK) {
|
||||
fprintf(stderr, "MTK_KERNEL_HDR [512]\n");
|
||||
boot->flags |= MTK_KERNEL;
|
||||
memcpy(&boot->mtk_kernel_hdr, boot->kernel, sizeof(mtk_hdr));
|
||||
boot->kernel += 512;
|
||||
boot->hdr.kernel_size -= 512;
|
||||
boot->kernel_type = check_type(boot->kernel);
|
||||
}
|
||||
if (boot->ramdisk_type == MTK) {
|
||||
fprintf(stderr, "MTK_RAMDISK_HDR [512]\n");
|
||||
boot->flags |= MTK_RAMDISK;
|
||||
memcpy(&boot->mtk_ramdisk_hdr, boot->ramdisk, sizeof(mtk_hdr));
|
||||
boot->ramdisk += 512;
|
||||
boot->hdr.ramdisk_size -= 512;
|
||||
boot->ramdisk_type = check_type(boot->ramdisk);
|
||||
}
|
||||
|
||||
char fmt[16];
|
||||
|
||||
get_type_name(boot->kernel_type, fmt);
|
||||
fprintf(stderr, "KERNEL_FMT [%s]\n", fmt);
|
||||
get_type_name(boot->ramdisk_type, fmt);
|
||||
fprintf(stderr, "RAMDISK_FMT [%s]\n", fmt);
|
||||
|
||||
return boot->flags & CHROMEOS_FLAG ? CHROMEOS_RET :
|
||||
((is_blk && boot->tail_size < 500 * 1024) ? INSUF_BLOCK_RET : 0);
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
LOGE("No boot image magic found!\n");
|
||||
}
|
||||
|
||||
void unpack(const char* image) {
|
||||
boot_img boot;
|
||||
int ret = parse_img(image, &boot);
|
||||
int fd;
|
||||
|
||||
// Dump kernel
|
||||
if (COMPRESSED(boot.kernel_type)) {
|
||||
fd = creat(KERNEL_FILE, 0644);
|
||||
decomp(boot.kernel_type, fd, boot.kernel, boot.hdr.kernel_size);
|
||||
close(fd);
|
||||
} else {
|
||||
dump(boot.kernel, boot.hdr.kernel_size, KERNEL_FILE);
|
||||
}
|
||||
|
||||
if (boot.dt_size) {
|
||||
// Dump dtb
|
||||
dump(boot.dtb, boot.dt_size, DTB_FILE);
|
||||
}
|
||||
|
||||
// Dump ramdisk
|
||||
if (COMPRESSED(boot.ramdisk_type)) {
|
||||
fd = creat(RAMDISK_FILE, 0644);
|
||||
decomp(boot.ramdisk_type, fd, boot.ramdisk, boot.hdr.ramdisk_size);
|
||||
close(fd);
|
||||
} else {
|
||||
dump(boot.ramdisk, boot.hdr.ramdisk_size, RAMDISK_FILE ".raw");
|
||||
LOGE("Unknown ramdisk format! Dumped to %s\n", RAMDISK_FILE ".raw");
|
||||
}
|
||||
|
||||
if (boot.hdr.second_size) {
|
||||
// Dump second
|
||||
dump(boot.second, boot.hdr.second_size, SECOND_FILE);
|
||||
}
|
||||
|
||||
if (boot.hdr.extra_size) {
|
||||
// Dump extra
|
||||
dump(boot.extra, boot.hdr.extra_size, EXTRA_FILE);
|
||||
}
|
||||
|
||||
munmap(boot.map_addr, boot.map_size);
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
void repack(const char* orig_image, const char* out_image) {
|
||||
boot_img boot;
|
||||
|
||||
// There are possible two MTK headers
|
||||
size_t mtk_kernel_off, mtk_ramdisk_off;
|
||||
|
||||
// Parse original image
|
||||
parse_img(orig_image, &boot);
|
||||
|
||||
fprintf(stderr, "Repack to boot image: [%s]\n", out_image);
|
||||
|
||||
// Create new image
|
||||
int fd = creat(out_image, 0644);
|
||||
|
||||
// Skip a page for header
|
||||
write_zero(fd, boot.hdr.page_size);
|
||||
|
||||
if (boot.flags & MTK_KERNEL) {
|
||||
// Record position and skip MTK header
|
||||
mtk_kernel_off = lseek(fd, 0, SEEK_CUR);
|
||||
write_zero(fd, 512);
|
||||
}
|
||||
if (COMPRESSED(boot.kernel_type)) {
|
||||
size_t raw_size;
|
||||
void *kernel_raw;
|
||||
mmap_ro(KERNEL_FILE, &kernel_raw, &raw_size);
|
||||
boot.hdr.kernel_size = comp(boot.kernel_type, fd, kernel_raw, raw_size);
|
||||
munmap(kernel_raw, raw_size);
|
||||
} else {
|
||||
boot.hdr.kernel_size = restore(KERNEL_FILE, fd);
|
||||
}
|
||||
// Restore dtb
|
||||
if (boot.dt_size && access(DTB_FILE, R_OK) == 0) {
|
||||
boot.hdr.kernel_size += restore(DTB_FILE, fd);
|
||||
}
|
||||
file_align(fd, boot.hdr.page_size, 1);
|
||||
|
||||
if (boot.flags & MTK_RAMDISK) {
|
||||
// Record position and skip MTK header
|
||||
mtk_ramdisk_off = lseek(fd, 0, SEEK_CUR);
|
||||
write_zero(fd, 512);
|
||||
}
|
||||
if (access(RAMDISK_FILE, R_OK) == 0) {
|
||||
// If we found raw cpio, compress to original format
|
||||
size_t cpio_size;
|
||||
void *cpio;
|
||||
mmap_ro(RAMDISK_FILE, &cpio, &cpio_size);
|
||||
boot.hdr.ramdisk_size = comp(boot.ramdisk_type, fd, cpio, cpio_size);
|
||||
munmap(cpio, cpio_size);
|
||||
} else {
|
||||
// Find compressed ramdisk
|
||||
char name[PATH_MAX];
|
||||
int found = 0;
|
||||
for (int i = 0; SUP_EXT_LIST[i]; ++i) {
|
||||
sprintf(name, "%s.%s", RAMDISK_FILE, SUP_EXT_LIST[i]);
|
||||
if (access(name, R_OK) == 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
LOGE("No ramdisk exists!\n");
|
||||
boot.hdr.ramdisk_size = restore(name, fd);
|
||||
}
|
||||
file_align(fd, boot.hdr.page_size, 1);
|
||||
|
||||
// Restore second
|
||||
if (boot.hdr.second_size && access(SECOND_FILE, R_OK) == 0) {
|
||||
boot.hdr.second_size = restore(SECOND_FILE, fd);
|
||||
file_align(fd, boot.hdr.page_size, 1);
|
||||
}
|
||||
|
||||
// Restore extra
|
||||
if (boot.hdr.extra_size && access(EXTRA_FILE, R_OK) == 0) {
|
||||
boot.hdr.extra_size = restore(EXTRA_FILE, fd);
|
||||
file_align(fd, boot.hdr.page_size, 1);
|
||||
}
|
||||
|
||||
// Check tail info, currently only for LG Bump and Samsung SEANDROIDENFORCE
|
||||
if (boot.tail_size >= 16) {
|
||||
if (memcmp(boot.tail, "SEANDROIDENFORCE", 16) == 0 ||
|
||||
memcmp(boot.tail, LG_BUMP_MAGIC, 16) == 0 ) {
|
||||
restore_buf(fd, boot.tail, 16);
|
||||
}
|
||||
}
|
||||
|
||||
// Write MTK headers back
|
||||
if (boot.flags & MTK_KERNEL) {
|
||||
lseek(fd, mtk_kernel_off, SEEK_SET);
|
||||
boot.mtk_kernel_hdr.size = boot.hdr.kernel_size;
|
||||
boot.hdr.kernel_size += 512;
|
||||
restore_buf(fd, &boot.mtk_kernel_hdr, sizeof(mtk_hdr));
|
||||
}
|
||||
if (boot.flags & MTK_RAMDISK) {
|
||||
lseek(fd, mtk_ramdisk_off, SEEK_SET);
|
||||
boot.mtk_ramdisk_hdr.size = boot.hdr.ramdisk_size;
|
||||
boot.hdr.ramdisk_size += 512;
|
||||
restore_buf(fd, &boot.mtk_ramdisk_hdr, sizeof(mtk_hdr));
|
||||
}
|
||||
// Main header
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
restore_buf(fd, &boot.hdr, sizeof(boot.hdr));
|
||||
|
||||
// Print new image info
|
||||
print_hdr(&boot.hdr);
|
||||
|
||||
munmap(boot.map_addr, boot.map_size);
|
||||
close(fd);
|
||||
}
|
127
native/jni/magiskboot/bootimg.h
Normal file
127
native/jni/magiskboot/bootimg.h
Normal file
@@ -0,0 +1,127 @@
|
||||
/* tools/mkbootimg/bootimg.h
|
||||
**
|
||||
** Copyright 2007, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "types.h"
|
||||
|
||||
#ifndef _BOOT_IMAGE_H_
|
||||
#define _BOOT_IMAGE_H_
|
||||
|
||||
typedef struct boot_img_hdr boot_img_hdr;
|
||||
|
||||
#define BOOT_MAGIC "ANDROID!"
|
||||
#define BOOT_MAGIC_SIZE 8
|
||||
#define BOOT_NAME_SIZE 16
|
||||
#define BOOT_ARGS_SIZE 512
|
||||
#define BOOT_EXTRA_ARGS_SIZE 1024
|
||||
|
||||
struct boot_img_hdr
|
||||
{
|
||||
uint8_t magic[BOOT_MAGIC_SIZE];
|
||||
|
||||
uint32_t kernel_size; /* size in bytes */
|
||||
uint32_t kernel_addr; /* physical load addr */
|
||||
|
||||
uint32_t ramdisk_size; /* size in bytes */
|
||||
uint32_t ramdisk_addr; /* physical load addr */
|
||||
|
||||
uint32_t second_size; /* size in bytes */
|
||||
uint32_t second_addr; /* physical load addr */
|
||||
|
||||
uint32_t tags_addr; /* physical addr for kernel tags */
|
||||
uint32_t page_size; /* flash page size we assume */
|
||||
uint32_t extra_size; /* extra blob size 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 */
|
||||
|
||||
uint8_t cmdline[BOOT_ARGS_SIZE];
|
||||
|
||||
uint32_t id[8]; /* timestamp / checksum / sha1 / etc */
|
||||
|
||||
/* Supplemental command line data; kept here to maintain
|
||||
* binary compatibility with older versions of mkbootimg */
|
||||
uint8_t extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
** +-----------------+
|
||||
** | boot header | 1 page
|
||||
** +-----------------+
|
||||
** | kernel | n pages
|
||||
** +-----------------+
|
||||
** | ramdisk | m pages
|
||||
** +-----------------+
|
||||
** | second stage | o pages
|
||||
** +-----------------+
|
||||
** | extra blobs | 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 = (extra_size + page_size - 1) / page_size
|
||||
**
|
||||
** 0. all entities are page_size aligned in flash
|
||||
** 1. kernel and ramdisk are required (size != 0)
|
||||
** 2. second is optional (second_size == 0 -> no second)
|
||||
** 3. load each element (kernel, ramdisk, second) at
|
||||
** the specified physical address (kernel_addr, etc)
|
||||
** 4. prepare tags at tag_addr. kernel_args[] is
|
||||
** appended to the kernel commandline in the tags.
|
||||
** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
|
||||
** 6. if second_size != 0: jump to second_addr
|
||||
** else: jump to kernel_addr
|
||||
*/
|
||||
|
||||
typedef struct mtk_hdr {
|
||||
uint8_t magic[4]; /* MTK magic */
|
||||
uint32_t size; /* Size of the content */
|
||||
uint8_t name[32]; /* The type of the header */
|
||||
} mtk_hdr;
|
||||
|
||||
// Flags
|
||||
#define MTK_KERNEL 0x1
|
||||
#define MTK_RAMDISK 0x2
|
||||
#define CHROMEOS_FLAG 0x4
|
||||
|
||||
typedef struct boot_img {
|
||||
size_t map_size;
|
||||
uint32_t dt_size;
|
||||
size_t tail_size;
|
||||
uint8_t flags;
|
||||
file_t kernel_type, ramdisk_type;
|
||||
|
||||
boot_img_hdr hdr;
|
||||
mtk_hdr mtk_kernel_hdr, mtk_ramdisk_hdr;
|
||||
|
||||
void *map_addr;
|
||||
void *kernel;
|
||||
void *dtb;
|
||||
void *ramdisk;
|
||||
void *second;
|
||||
void *extra;
|
||||
void *tail;
|
||||
} boot_img;
|
||||
|
||||
#endif
|
512
native/jni/magiskboot/compress.c
Normal file
512
native/jni/magiskboot/compress.c
Normal file
@@ -0,0 +1,512 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <zlib.h>
|
||||
#include <lzma.h>
|
||||
#include <lz4.h>
|
||||
#include <lz4frame.h>
|
||||
#include <lz4hc.h>
|
||||
#include <bzlib.h>
|
||||
|
||||
#include "magiskboot.h"
|
||||
#include "logging.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define CHUNK 0x40000
|
||||
|
||||
// Mode: 0 = decode; 1 = encode
|
||||
size_t gzip(int mode, int fd, const void *buf, size_t size) {
|
||||
size_t ret = 0, have, total = 0;
|
||||
z_stream strm;
|
||||
unsigned char out[CHUNK];
|
||||
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
|
||||
switch(mode) {
|
||||
case 0:
|
||||
ret = inflateInit2(&strm, 15 | 16);
|
||||
break;
|
||||
case 1:
|
||||
ret = deflateInit2(&strm, 9, Z_DEFLATED, 15 | 16, 8, Z_DEFAULT_STRATEGY);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret != Z_OK)
|
||||
LOGE("Unable to init zlib stream\n");
|
||||
|
||||
strm.next_in = (void *) buf;
|
||||
strm.avail_in = size;
|
||||
|
||||
do {
|
||||
strm.avail_out = CHUNK;
|
||||
strm.next_out = out;
|
||||
switch(mode) {
|
||||
case 0:
|
||||
ret = inflate(&strm, Z_FINISH);
|
||||
break;
|
||||
case 1:
|
||||
ret = deflate(&strm, Z_FINISH);
|
||||
break;
|
||||
}
|
||||
if (ret == Z_STREAM_ERROR)
|
||||
LOGE("Error when running gzip\n");
|
||||
have = CHUNK - strm.avail_out;
|
||||
total += xwrite(fd, out, have);
|
||||
} while (strm.avail_out == 0);
|
||||
|
||||
switch(mode) {
|
||||
case 0:
|
||||
inflateEnd(&strm);
|
||||
break;
|
||||
case 1:
|
||||
deflateEnd(&strm);
|
||||
break;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
// Mode: 0 = decode xz/lzma; 1 = encode xz; 2 = encode lzma
|
||||
size_t lzma(int mode, int fd, const void *buf, size_t size) {
|
||||
size_t have, total = 0;
|
||||
lzma_ret ret = 0;
|
||||
lzma_stream strm = LZMA_STREAM_INIT;
|
||||
lzma_options_lzma opt;
|
||||
unsigned char out[CHUNK];
|
||||
|
||||
// Initialize preset
|
||||
lzma_lzma_preset(&opt, 9);
|
||||
lzma_filter filters[] = {
|
||||
{ .id = LZMA_FILTER_LZMA2, .options = &opt },
|
||||
{ .id = LZMA_VLI_UNKNOWN, .options = NULL },
|
||||
};
|
||||
|
||||
switch(mode) {
|
||||
case 0:
|
||||
ret = lzma_auto_decoder(&strm, UINT64_MAX, 0);
|
||||
break;
|
||||
case 1:
|
||||
ret = lzma_stream_encoder(&strm, filters, LZMA_CHECK_CRC32);
|
||||
break;
|
||||
case 2:
|
||||
ret = lzma_alone_encoder(&strm, &opt);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (ret != LZMA_OK)
|
||||
LOGE("Unable to init lzma stream\n");
|
||||
|
||||
strm.next_in = buf;
|
||||
strm.avail_in = size;
|
||||
|
||||
do {
|
||||
strm.avail_out = CHUNK;
|
||||
strm.next_out = out;
|
||||
ret = lzma_code(&strm, LZMA_FINISH);
|
||||
if (ret != LZMA_OK && ret != LZMA_STREAM_END)
|
||||
LOGE("LZMA error %d!\n", ret);
|
||||
have = CHUNK - strm.avail_out;
|
||||
total += xwrite(fd, out, have);
|
||||
} while (strm.avail_out == 0);
|
||||
|
||||
lzma_end(&strm);
|
||||
return total;
|
||||
}
|
||||
|
||||
// Mode: 0 = decode; 1 = encode
|
||||
size_t lz4(int mode, int fd, const void *buf, size_t size) {
|
||||
LZ4F_decompressionContext_t dctx;
|
||||
LZ4F_compressionContext_t cctx;
|
||||
LZ4F_frameInfo_t info;
|
||||
|
||||
size_t blockSize, outCapacity, avail_in, ret = 0, pos = 0, total = 0;
|
||||
size_t have, read;
|
||||
void *out = NULL;
|
||||
|
||||
// Initialize context
|
||||
switch(mode) {
|
||||
case 0:
|
||||
ret = LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION);
|
||||
break;
|
||||
case 1:
|
||||
ret = LZ4F_createCompressionContext(&cctx, LZ4F_VERSION);
|
||||
break;
|
||||
}
|
||||
|
||||
if (LZ4F_isError(ret))
|
||||
LOGE("Context creation error: %s\n", LZ4F_getErrorName(ret));
|
||||
|
||||
// Allocate out buffer
|
||||
blockSize = 1 << 22;
|
||||
switch(mode) {
|
||||
case 0:
|
||||
// Read header
|
||||
read = blockSize;
|
||||
ret = LZ4F_getFrameInfo(dctx, &info, buf, &read);
|
||||
if (LZ4F_isError(ret))
|
||||
LOGE("LZ4F_getFrameInfo error: %s\n", LZ4F_getErrorName(ret));
|
||||
switch (info.blockSizeID) {
|
||||
case LZ4F_default:
|
||||
case LZ4F_max64KB: outCapacity = 1 << 16; break;
|
||||
case LZ4F_max256KB: outCapacity = 1 << 18; break;
|
||||
case LZ4F_max1MB: outCapacity = 1 << 20; break;
|
||||
case LZ4F_max4MB: outCapacity = 1 << 22; break;
|
||||
default:
|
||||
LOGE("Impossible unless more block sizes are allowed\n");
|
||||
}
|
||||
pos += read;
|
||||
break;
|
||||
case 1:
|
||||
outCapacity = LZ4F_compressFrameBound(blockSize, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
out = xmalloc(outCapacity);
|
||||
|
||||
// Write header
|
||||
if (mode == 1) {
|
||||
LZ4F_preferences_t prefs;
|
||||
memset(&prefs, 0, sizeof(prefs));
|
||||
prefs.autoFlush = 1;
|
||||
prefs.compressionLevel = 9;
|
||||
prefs.frameInfo.blockMode = 1;
|
||||
prefs.frameInfo.blockSizeID = 7;
|
||||
prefs.frameInfo.contentChecksumFlag = 1;
|
||||
have = ret = LZ4F_compressBegin(cctx, out, size, &prefs);
|
||||
if (LZ4F_isError(ret))
|
||||
LOGE("Failed to start compression: error %s\n", LZ4F_getErrorName(ret));
|
||||
total += xwrite(fd, out, have);
|
||||
}
|
||||
|
||||
do {
|
||||
if (pos + blockSize >= size) {
|
||||
avail_in = size - pos;
|
||||
} else {
|
||||
avail_in = blockSize;
|
||||
}
|
||||
|
||||
do {
|
||||
switch(mode) {
|
||||
case 0:
|
||||
have = outCapacity;
|
||||
read = avail_in;
|
||||
ret = LZ4F_decompress(dctx, out, &have, buf + pos, &read, NULL);
|
||||
break;
|
||||
case 1:
|
||||
read = avail_in;
|
||||
have = ret = LZ4F_compressUpdate(cctx, out, outCapacity, buf + pos, avail_in, NULL);
|
||||
break;
|
||||
}
|
||||
if (LZ4F_isError(ret))
|
||||
LOGE("LZ4 coding error: %s\n", LZ4F_getErrorName(ret));
|
||||
|
||||
total += xwrite(fd, out, have);
|
||||
// Update status
|
||||
pos += read;
|
||||
avail_in -= read;
|
||||
} while(avail_in != 0 && ret != 0);
|
||||
|
||||
} while(pos < size && ret != 0);
|
||||
|
||||
switch(mode) {
|
||||
case 0:
|
||||
LZ4F_freeDecompressionContext(dctx);
|
||||
break;
|
||||
case 1:
|
||||
have = ret = LZ4F_compressEnd(cctx, out, outCapacity, NULL);
|
||||
if (LZ4F_isError(ret))
|
||||
LOGE("Failed to end compression: error %s\n", LZ4F_getErrorName(ret));
|
||||
|
||||
total += xwrite(fd, out, have);
|
||||
|
||||
LZ4F_freeCompressionContext(cctx);
|
||||
break;
|
||||
}
|
||||
|
||||
free(out);
|
||||
return total;
|
||||
}
|
||||
|
||||
// Mode: 0 = decode; 1 = encode
|
||||
size_t bzip2(int mode, int fd, const void* buf, size_t size) {
|
||||
size_t ret = 0, have, total = 0;
|
||||
bz_stream strm;
|
||||
char out[CHUNK];
|
||||
|
||||
strm.bzalloc = NULL;
|
||||
strm.bzfree = NULL;
|
||||
strm.opaque = NULL;
|
||||
|
||||
switch(mode) {
|
||||
case 0:
|
||||
ret = BZ2_bzDecompressInit(&strm, 0, 0);
|
||||
break;
|
||||
case 1:
|
||||
ret = BZ2_bzCompressInit(&strm, 9, 0, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret != BZ_OK)
|
||||
LOGE("Unable to init bzlib stream\n");
|
||||
|
||||
strm.next_in = (void *) buf;
|
||||
strm.avail_in = size;
|
||||
|
||||
do {
|
||||
strm.avail_out = CHUNK;
|
||||
strm.next_out = out;
|
||||
switch(mode) {
|
||||
case 0:
|
||||
ret = BZ2_bzDecompress(&strm);
|
||||
break;
|
||||
case 1:
|
||||
ret = BZ2_bzCompress(&strm, BZ_FINISH);
|
||||
break;
|
||||
}
|
||||
have = CHUNK - strm.avail_out;
|
||||
total += xwrite(fd, out, have);
|
||||
} while (strm.avail_out == 0);
|
||||
|
||||
switch(mode) {
|
||||
case 0:
|
||||
BZ2_bzDecompressEnd(&strm);
|
||||
break;
|
||||
case 1:
|
||||
BZ2_bzCompressEnd(&strm);
|
||||
break;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
#define LZ4_LEGACY_BLOCKSIZE 0x800000
|
||||
|
||||
// Mode: 0 = decode; 1 = encode
|
||||
size_t lz4_legacy(int mode, int fd, const void* buf, size_t size) {
|
||||
size_t pos = 0;
|
||||
int have;
|
||||
char *out;
|
||||
unsigned block_size, insize, total = 0;
|
||||
|
||||
switch(mode) {
|
||||
case 0:
|
||||
out = xmalloc(LZ4_LEGACY_BLOCKSIZE);
|
||||
// Skip magic
|
||||
pos += 4;
|
||||
break;
|
||||
case 1:
|
||||
out = xmalloc(LZ4_COMPRESSBOUND(LZ4_LEGACY_BLOCKSIZE));
|
||||
// Write magic
|
||||
total += xwrite(fd, "\x02\x21\x4c\x18", 4);
|
||||
break;
|
||||
}
|
||||
|
||||
do {
|
||||
switch(mode) {
|
||||
case 0:
|
||||
// Read block size
|
||||
block_size = *(unsigned *)(buf + pos);
|
||||
pos += 4;
|
||||
if (block_size > LZ4_COMPRESSBOUND(LZ4_LEGACY_BLOCKSIZE))
|
||||
goto done;
|
||||
have = LZ4_decompress_safe(buf + pos, out, block_size, LZ4_LEGACY_BLOCKSIZE);
|
||||
if (have < 0)
|
||||
LOGE("Cannot decode lz4_legacy block\n");
|
||||
pos += block_size;
|
||||
break;
|
||||
case 1:
|
||||
if (pos + LZ4_LEGACY_BLOCKSIZE >= size)
|
||||
insize = size - pos;
|
||||
else
|
||||
insize = LZ4_LEGACY_BLOCKSIZE;
|
||||
have = LZ4_compress_HC(buf + pos, out, insize, LZ4_COMPRESSBOUND(LZ4_LEGACY_BLOCKSIZE), 9);
|
||||
if (have == 0)
|
||||
LOGE("lz4_legacy compression error\n");
|
||||
pos += insize;
|
||||
// Write block size
|
||||
total += xwrite(fd, &have, sizeof(have));
|
||||
break;
|
||||
}
|
||||
// Write main data
|
||||
total += xwrite(fd, out, have);
|
||||
} while(pos < size);
|
||||
|
||||
done:
|
||||
if (mode == 1) {
|
||||
// Append original size to output
|
||||
unsigned uncomp = size;
|
||||
xwrite(fd, &uncomp, sizeof(uncomp));
|
||||
}
|
||||
free(out);
|
||||
return total;
|
||||
}
|
||||
|
||||
long long decomp(file_t type, int to, const void *from, size_t size) {
|
||||
switch (type) {
|
||||
case GZIP:
|
||||
return gzip(0, to, from, size);
|
||||
case XZ:
|
||||
return lzma(0, to, from, size);
|
||||
case LZMA:
|
||||
return lzma(0, to, from, size);
|
||||
case BZIP2:
|
||||
return bzip2(0, to, from, size);
|
||||
case LZ4:
|
||||
return lz4(0, to, from, size);
|
||||
case LZ4_LEGACY:
|
||||
return lz4_legacy(0, to, from, size);
|
||||
default:
|
||||
// Unsupported
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
long long comp(file_t type, int to, const void *from, size_t size) {
|
||||
switch (type) {
|
||||
case GZIP:
|
||||
return gzip(1, to, from, size);
|
||||
case XZ:
|
||||
return lzma(1, to, from, size);
|
||||
case LZMA:
|
||||
return lzma(2, to, from, size);
|
||||
case BZIP2:
|
||||
return bzip2(1, to, from, size);
|
||||
case LZ4:
|
||||
return lz4(1, to, from, size);
|
||||
case LZ4_LEGACY:
|
||||
return lz4_legacy(1, to, from, size);
|
||||
default:
|
||||
// Unsupported
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Below are utility functions for commandline
|
||||
*/
|
||||
|
||||
void decomp_file(char *from, const char *to) {
|
||||
int strip = 1;
|
||||
void *file;
|
||||
size_t size = 0;
|
||||
if (strcmp(from, "-") == 0)
|
||||
stream_full_read(STDIN_FILENO, &file, &size);
|
||||
else
|
||||
mmap_ro(from, &file, &size);
|
||||
file_t type = check_type(file);
|
||||
char *ext;
|
||||
ext = strrchr(from, '.');
|
||||
if (to == NULL)
|
||||
to = from;
|
||||
if (ext != NULL) {
|
||||
// Strip out a matched file extension
|
||||
switch (type) {
|
||||
case GZIP:
|
||||
if (strcmp(ext, ".gz") != 0)
|
||||
strip = 0;
|
||||
break;
|
||||
case XZ:
|
||||
if (strcmp(ext, ".xz") != 0)
|
||||
strip = 0;
|
||||
break;
|
||||
case LZMA:
|
||||
if (strcmp(ext, ".lzma") != 0)
|
||||
strip = 0;
|
||||
break;
|
||||
case BZIP2:
|
||||
if (strcmp(ext, ".bz2") != 0)
|
||||
strip = 0;
|
||||
break;
|
||||
case LZ4_LEGACY:
|
||||
case LZ4:
|
||||
if (strcmp(ext, ".lz4") != 0)
|
||||
strip = 0;
|
||||
break;
|
||||
default:
|
||||
LOGE("Provided file \'%s\' is not a supported archive format\n", from);
|
||||
}
|
||||
if (strip)
|
||||
*ext = '\0';
|
||||
}
|
||||
|
||||
int fd;
|
||||
|
||||
if (strcmp(to, "-") == 0) {
|
||||
fd = STDOUT_FILENO;
|
||||
} else {
|
||||
fd = creat(to, 0644);
|
||||
fprintf(stderr, "Decompressing to [%s]\n", to);
|
||||
}
|
||||
|
||||
decomp(type, fd, file, size);
|
||||
close(fd);
|
||||
if (to == from && ext != NULL) {
|
||||
*ext = '.';
|
||||
unlink(from);
|
||||
}
|
||||
if (strcmp(from, "-") == 0)
|
||||
free(file);
|
||||
else
|
||||
munmap(file, size);
|
||||
}
|
||||
|
||||
void comp_file(const char *method, const char *from, const char *to) {
|
||||
file_t type;
|
||||
char *ext, dest[PATH_MAX];
|
||||
if (strcmp(method, "gzip") == 0) {
|
||||
type = GZIP;
|
||||
ext = "gz";
|
||||
} else if (strcmp(method, "xz") == 0) {
|
||||
type = XZ;
|
||||
ext = "xz";
|
||||
} else if (strcmp(method, "lzma") == 0) {
|
||||
type = LZMA;
|
||||
ext = "lzma";
|
||||
} else if (strcmp(method, "lz4") == 0) {
|
||||
type = LZ4;
|
||||
ext = "lz4";
|
||||
} else if (strcmp(method, "lz4_legacy") == 0) {
|
||||
type = LZ4_LEGACY;
|
||||
ext = "lz4";
|
||||
} else if (strcmp(method, "bzip2") == 0) {
|
||||
type = BZIP2;
|
||||
ext = "bz2";
|
||||
} else {
|
||||
fprintf(stderr, "Only support following methods: ");
|
||||
for (int i = 0; SUP_LIST[i]; ++i)
|
||||
fprintf(stderr, "%s ", SUP_LIST[i]);
|
||||
fprintf(stderr, "\n");
|
||||
exit(1);
|
||||
}
|
||||
void *file;
|
||||
size_t size;
|
||||
if (strcmp(from, "-") == 0)
|
||||
stream_full_read(STDIN_FILENO, &file, &size);
|
||||
else
|
||||
mmap_ro(from, &file, &size);
|
||||
if (to == NULL) {
|
||||
if (strcmp(from, "-") == 0)
|
||||
strcpy(dest, "-");
|
||||
else
|
||||
snprintf(dest, sizeof(dest), "%s.%s", from, ext);
|
||||
} else
|
||||
strcpy(dest, to);
|
||||
int fd;
|
||||
if (strcmp(dest, "-") == 0) {
|
||||
fd = STDOUT_FILENO;
|
||||
} else {
|
||||
fd = creat(dest, 0644);
|
||||
fprintf(stderr, "Compressing to [%s]\n", dest);
|
||||
}
|
||||
comp(type, fd, file, size);
|
||||
close(fd);
|
||||
if (strcmp(from, "-") == 0)
|
||||
free(file);
|
||||
else
|
||||
munmap(file, size);
|
||||
if (to == NULL)
|
||||
unlink(from);
|
||||
}
|
||||
|
111
native/jni/magiskboot/dtb.c
Normal file
111
native/jni/magiskboot/dtb.c
Normal file
@@ -0,0 +1,111 @@
|
||||
#include <libfdt.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "magiskboot.h"
|
||||
#include "utils.h"
|
||||
|
||||
static void print_props(const void *fdt, int node, int depth) {
|
||||
int prop;
|
||||
fdt_for_each_property_offset(prop, fdt, node) {
|
||||
for (int i = 0; i < depth; ++i) printf(" ");
|
||||
printf(" ");
|
||||
int size;
|
||||
const char *name;
|
||||
const char *value = fdt_getprop_by_offset(fdt, prop, &name, &size);
|
||||
printf("[%s]: [%s]\n", name, value);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_subnode(const void *fdt, int parent, int depth) {
|
||||
int node;
|
||||
fdt_for_each_subnode(node, fdt, parent) {
|
||||
for (int i = 0; i < depth; ++i) printf(" ");
|
||||
printf("#%d: %s\n", node, fdt_get_name(fdt, node, NULL));
|
||||
print_props(fdt, node, depth);
|
||||
print_subnode(fdt, node, depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int find_fstab(const void *fdt, int parent) {
|
||||
int node, fstab;
|
||||
fdt_for_each_subnode(node, fdt, parent) {
|
||||
if (strcmp(fdt_get_name(fdt, node, NULL), "fstab") == 0)
|
||||
return node;
|
||||
fstab = find_fstab(fdt, node);
|
||||
if (fstab != -1)
|
||||
return fstab;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void dtb_dump(const char *file) {
|
||||
size_t size ;
|
||||
void *dtb, *fdt;
|
||||
fprintf(stderr, "Loading dtbs from [%s]\n", file);
|
||||
mmap_ro(file, &dtb, &size);
|
||||
// Loop through all the dtbs
|
||||
int dtb_num = 0;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (memcmp(dtb + i, DTB_MAGIC, 4) == 0) {
|
||||
fdt = dtb + i;
|
||||
fprintf(stderr, "Dumping dtb.%04d\n", dtb_num++);
|
||||
print_subnode(fdt, 0, 0);
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
munmap(dtb, size);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void dtb_patch(const char *file, int patch) {
|
||||
size_t size ;
|
||||
void *dtb, *fdt;
|
||||
fprintf(stderr, "Loading dtbs from [%s]\n", file);
|
||||
if (patch)
|
||||
mmap_rw(file, &dtb, &size);
|
||||
else
|
||||
mmap_ro(file, &dtb, &size);
|
||||
// Loop through all the dtbs
|
||||
int dtb_num = 0, found = 0;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (memcmp(dtb + i, DTB_MAGIC, 4) == 0) {
|
||||
fdt = dtb + i;
|
||||
int fstab = find_fstab(fdt, 0);
|
||||
if (fstab > 0) {
|
||||
fprintf(stderr, "Found fstab in dtb.%04d\n", dtb_num++);
|
||||
int block;
|
||||
fdt_for_each_subnode(block, fdt, fstab) {
|
||||
fprintf(stderr, "Found block [%s] in fstab\n", fdt_get_name(fdt, block, NULL));
|
||||
uint32_t value_size;
|
||||
void *value = (void *) fdt_getprop(fdt, block, "fsmgr_flags", &value_size);
|
||||
if (patch) {
|
||||
void *dup = xmalloc(value_size);
|
||||
memcpy(dup, value, value_size);
|
||||
memset(value, 0, value_size);
|
||||
found |= patch_verity(&dup, &value_size, 1);
|
||||
memcpy(value, dup, value_size);
|
||||
free(dup);
|
||||
} else {
|
||||
found |= patch_verity(&value, &value_size, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
munmap(dtb, size);
|
||||
exit(!found);
|
||||
}
|
||||
|
||||
int dtb_commands(const char *cmd, int argc, char *argv[]) {
|
||||
if (argc == 0) return 1;
|
||||
if (strcmp(cmd, "dump") == 0)
|
||||
dtb_dump(argv[0]);
|
||||
else if (strcmp(cmd, "patch") == 0)
|
||||
dtb_patch(argv[0], 1);
|
||||
else if (strcmp(cmd, "test") == 0)
|
||||
dtb_patch(argv[0], 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
38
native/jni/magiskboot/hexpatch.c
Normal file
38
native/jni/magiskboot/hexpatch.c
Normal file
@@ -0,0 +1,38 @@
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "magiskboot.h"
|
||||
#include "utils.h"
|
||||
|
||||
static void hex2byte(const char *hex, unsigned char *str) {
|
||||
char high, low;
|
||||
for (int i = 0, length = strlen(hex); i < length; i += 2) {
|
||||
high = toupper(hex[i]) - '0';
|
||||
low = toupper(hex[i + 1]) - '0';
|
||||
str[i / 2] = ((high > 9 ? high - 7 : high) << 4) + (low > 9 ? low - 7 : low);
|
||||
}
|
||||
}
|
||||
|
||||
void hexpatch(const char *image, const char *from, const char *to) {
|
||||
int patternsize = strlen(from) / 2, patchsize = strlen(to) / 2;
|
||||
size_t filesize;
|
||||
void *file, *pattern, *patch;
|
||||
mmap_rw(image, &file, &filesize);
|
||||
pattern = xmalloc(patternsize);
|
||||
patch = xmalloc(patchsize);
|
||||
hex2byte(from, pattern);
|
||||
hex2byte(to, patch);
|
||||
for (size_t i = 0; filesize > 0 && i < filesize - patternsize; ++i) {
|
||||
if (memcmp(file + i, pattern, patternsize) == 0) {
|
||||
fprintf(stderr, "Patch @ %08X [%s]->[%s]\n", (unsigned) i, from, to);
|
||||
memset(file + i, 0, patternsize);
|
||||
memcpy(file + i, patch, patchsize);
|
||||
i += patternsize - 1;
|
||||
}
|
||||
}
|
||||
munmap(file, filesize);
|
||||
free(pattern);
|
||||
free(patch);
|
||||
}
|
35
native/jni/magiskboot/magiskboot.h
Normal file
35
native/jni/magiskboot/magiskboot.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef _MAGISKBOOT_H_
|
||||
#define _MAGISKBOOT_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "logging.h"
|
||||
#include "bootimg.h"
|
||||
|
||||
#define KERNEL_FILE "kernel"
|
||||
#define RAMDISK_FILE "ramdisk.cpio"
|
||||
#define SECOND_FILE "second"
|
||||
#define EXTRA_FILE "extra"
|
||||
#define DTB_FILE "dtb"
|
||||
#define NEW_BOOT "new-boot.img"
|
||||
|
||||
// Main entries
|
||||
void unpack(const char *image);
|
||||
void repack(const char* orig_image, const char* out_image);
|
||||
void hexpatch(const char *image, const char *from, const char *to);
|
||||
int parse_img(const char *image, boot_img *boot);
|
||||
int cpio_commands(int argc, char *argv[]);
|
||||
void comp_file(const char *method, const char *from, const char *to);
|
||||
void decomp_file(char *from, const char *to);
|
||||
int dtb_commands(const char *cmd, int argc, char *argv[]);
|
||||
|
||||
// Compressions
|
||||
size_t gzip(int mode, int fd, const void *buf, size_t size);
|
||||
size_t lzma(int mode, int fd, const void *buf, size_t size);
|
||||
size_t lz4(int mode, int fd, const void *buf, size_t size);
|
||||
size_t bzip2(int mode, int fd, const void *buf, size_t size);
|
||||
size_t lz4_legacy(int mode, int fd, const void *buf, size_t size);
|
||||
long long comp(file_t type, int to, const void *from, size_t size);
|
||||
long long decomp(file_t type, int to, const void *from, size_t size);
|
||||
|
||||
#endif
|
166
native/jni/magiskboot/main.c
Normal file
166
native/jni/magiskboot/main.c
Normal file
@@ -0,0 +1,166 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "magiskboot.h"
|
||||
#include "utils.h"
|
||||
#include "sha1.h"
|
||||
|
||||
/********************
|
||||
Patch Boot Image
|
||||
*********************/
|
||||
|
||||
static void usage(char *arg0) {
|
||||
fprintf(stderr,
|
||||
"Usage: %s <action> [args...]\n"
|
||||
"\n"
|
||||
"Supported actions:\n"
|
||||
" --parse <bootimg>\n"
|
||||
" Parse <bootimg> only, do not unpack. Return values: \n"
|
||||
" 0:OK 1:error 2:insufficient boot partition size\n"
|
||||
" 3:chromeos 4:ELF32 5:ELF64\n"
|
||||
"\n"
|
||||
" --unpack <bootimg>\n"
|
||||
" Unpack <bootimg> to kernel, ramdisk.cpio, (second), (dtb), (extra) into\n"
|
||||
" the current directory. Return value is the same as --parse\n"
|
||||
"\n"
|
||||
" --repack <origbootimg> [outbootimg]\n"
|
||||
" Repack kernel, ramdisk.cpio[.ext], second, dtb... from current directory\n"
|
||||
" to [outbootimg], or new-boot.img if not specified.\n"
|
||||
" It will compress ramdisk.cpio with the same method used in <origbootimg>,\n"
|
||||
" or attempt to find ramdisk.cpio.[ext], and repack directly with the\n"
|
||||
" compressed ramdisk file\n"
|
||||
"\n"
|
||||
" --hexpatch <file> <hexpattern1> <hexpattern2>\n"
|
||||
" Search <hexpattern1> in <file>, and replace with <hexpattern2>\n"
|
||||
"\n"
|
||||
" --cpio <incpio> [commands...]\n"
|
||||
" Do cpio commands to <incpio> (modifications are done directly)\n"
|
||||
" Each command is a single argument, use quotes if necessary\n"
|
||||
" Supported commands:\n"
|
||||
" rm [-r] ENTRY\n"
|
||||
" Remove ENTRY, specify [-r] to remove recursively\n"
|
||||
" mkdir MODE ENTRY\n"
|
||||
" Create directory ENTRY in permissions MODE\n"
|
||||
" ln TARGET ENTRY\n"
|
||||
" Create a symlink to TARGET with the name ENTRY\n"
|
||||
" mv SOURCE DEST\n"
|
||||
" Move SOURCE to DEST\n"
|
||||
" add MODE ENTRY INFILE\n"
|
||||
" Add INFILE as ENTRY in permissions MODE; replaces ENTRY if exists\n"
|
||||
" extract [ENTRY OUT]\n"
|
||||
" Extract ENTRY to OUT, or extract all entries to current directory\n"
|
||||
" test\n"
|
||||
" Test the current cpio's patch status\n"
|
||||
" Return value: 0/stock 1/Magisk 2/other (phh, SuperSU, Xposed)\n"
|
||||
" patch KEEPVERITY KEEPFORCEENCRYPT\n"
|
||||
" Ramdisk patches. KEEP**** are boolean values\n"
|
||||
" backup ORIG [SHA1]\n"
|
||||
" Create ramdisk backups from ORIG\n"
|
||||
" SHA1 of stock boot image is optional\n"
|
||||
" restore\n"
|
||||
" Restore ramdisk from ramdisk backup stored within incpio\n"
|
||||
" magisk ORIG HIGHCOMP KEEPVERITY KEEPFORCEENCRYPT [SHA1]\n"
|
||||
" Do Magisk patches and backups all in one step\n"
|
||||
" Create ramdisk backups from ORIG\n"
|
||||
" HIGHCOMP, KEEP**** are boolean values\n"
|
||||
" SHA1 of stock boot image is optional\n"
|
||||
" sha1\n"
|
||||
" Print stock boot SHA1 if previously stored\n"
|
||||
"\n"
|
||||
" --dtb-<cmd> <dtb>\n"
|
||||
" Do dtb related cmds to <dtb> (modifications are done directly)\n"
|
||||
" Supported commands:\n"
|
||||
" dump\n"
|
||||
" Dump all contents from dtb for debugging\n"
|
||||
" test\n"
|
||||
" Check if fstab has verity/avb flags\n"
|
||||
" Return value: 0/no flags 1/flag exists\n"
|
||||
" patch\n"
|
||||
" Search for fstab and remove verity/avb\n"
|
||||
"\n"
|
||||
" --compress[=method] <infile> [outfile]\n"
|
||||
" Compress <infile> with [method] (default: gzip), optionally to [outfile]\n"
|
||||
" <infile>/[outfile] can be '-' to be STDIN/STDOUT\n"
|
||||
" Supported methods: "
|
||||
, arg0);
|
||||
for (int i = 0; SUP_LIST[i]; ++i)
|
||||
fprintf(stderr, "%s ", SUP_LIST[i]);
|
||||
fprintf(stderr,
|
||||
"\n\n"
|
||||
" --decompress <infile> [outfile]\n"
|
||||
" Detect method and decompress <infile>, optionally to [outfile]\n"
|
||||
" <infile>/[outfile] can be '-' to be STDIN/STDOUT\n"
|
||||
" Supported methods: ");
|
||||
for (int i = 0; SUP_LIST[i]; ++i)
|
||||
fprintf(stderr, "%s ", SUP_LIST[i]);
|
||||
fprintf(stderr,
|
||||
"\n\n"
|
||||
" --sha1 <file>\n"
|
||||
" Print the SHA1 checksum for <file>\n"
|
||||
"\n"
|
||||
" --cleanup\n"
|
||||
" Cleanup the current working directory\n"
|
||||
"\n");
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
fprintf(stderr, "MagiskBoot v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") (by topjohnwu) - Boot Image Modification Tool\n");
|
||||
|
||||
umask(0);
|
||||
if (argc > 1 && strcmp(argv[1], "--cleanup") == 0) {
|
||||
fprintf(stderr, "Cleaning up...\n");
|
||||
char name[PATH_MAX];
|
||||
unlink(KERNEL_FILE);
|
||||
unlink(RAMDISK_FILE);
|
||||
unlink(RAMDISK_FILE ".raw");
|
||||
unlink(SECOND_FILE);
|
||||
unlink(DTB_FILE);
|
||||
unlink(EXTRA_FILE);
|
||||
for (int i = 0; SUP_EXT_LIST[i]; ++i) {
|
||||
sprintf(name, "%s.%s", RAMDISK_FILE, SUP_EXT_LIST[i]);
|
||||
unlink(name);
|
||||
}
|
||||
} else if (argc > 2 && strcmp(argv[1], "--sha1") == 0) {
|
||||
char sha1[21], *buf;
|
||||
size_t size;
|
||||
mmap_ro(argv[2], (void **) &buf, &size);
|
||||
SHA1(sha1, buf, size);
|
||||
for (int i = 0; i < 20; ++i)
|
||||
printf("%02x", sha1[i]);
|
||||
printf("\n");
|
||||
munmap(buf, size);
|
||||
} else if (argc > 2 && strcmp(argv[1], "--parse") == 0) {
|
||||
boot_img boot;
|
||||
exit(parse_img(argv[2], &boot));
|
||||
} else if (argc > 2 && strcmp(argv[1], "--unpack") == 0) {
|
||||
unpack(argv[2]);
|
||||
} else if (argc > 2 && strcmp(argv[1], "--repack") == 0) {
|
||||
repack(argv[2], argc > 3 ? argv[3] : NEW_BOOT);
|
||||
} else if (argc > 2 && strcmp(argv[1], "--decompress") == 0) {
|
||||
decomp_file(argv[2], argc > 3 ? argv[3] : NULL);
|
||||
} else if (argc > 2 && strncmp(argv[1], "--compress", 10) == 0) {
|
||||
char *method;
|
||||
method = strchr(argv[1], '=');
|
||||
if (method == NULL) method = "gzip";
|
||||
else method++;
|
||||
comp_file(method, argv[2], argc > 3 ? argv[3] : NULL);
|
||||
} else if (argc > 4 && strcmp(argv[1], "--hexpatch") == 0) {
|
||||
hexpatch(argv[2], argv[3], argv[4]);
|
||||
} else if (argc > 2 && strcmp(argv[1], "--cpio") == 0) {
|
||||
if (cpio_commands(argc - 2, argv + 2)) usage(argv[0]);
|
||||
} else if (argc > 2 && strncmp(argv[1], "--dtb", 5) == 0) {
|
||||
char *cmd = argv[1] + 5;
|
||||
if (*cmd == '\0') usage(argv[0]);
|
||||
else ++cmd;
|
||||
if (dtb_commands(cmd, argc - 2, argv + 2)) usage(argv[0]);
|
||||
} else {
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
335
native/jni/magiskboot/ramdisk.c
Normal file
335
native/jni/magiskboot/ramdisk.c
Normal file
@@ -0,0 +1,335 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <utils.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "magiskboot.h"
|
||||
#include "cpio.h"
|
||||
|
||||
static void cpio_patch(struct vector *v, int keepverity, int keepforceencrypt) {
|
||||
fprintf(stderr, "Patch with flag KEEPVERITY=[%s] KEEPFORCEENCRYPT=[%s]\n",
|
||||
keepverity ? "true" : "false", keepforceencrypt ? "true" : "false");
|
||||
cpio_entry *e;
|
||||
vec_for_each(v, e) {
|
||||
if (!e) continue;
|
||||
if (!keepverity) {
|
||||
if (strncmp(e->filename, ".backup", 7) && strstr(e->filename, "fstab") && S_ISREG(e->mode)) {
|
||||
patch_verity(&e->data, &e->filesize, 1);
|
||||
} else if (strcmp(e->filename, "verity_key") == 0) {
|
||||
fprintf(stderr, "Remove [verity_key]\n");
|
||||
cpio_free(e);
|
||||
vec_cur(v) = NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!keepforceencrypt) {
|
||||
if (strstr(e->filename, "fstab") != NULL && S_ISREG(e->mode)) {
|
||||
patch_encryption(&e->data, &e->filesize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define STOCK_BOOT 0x0
|
||||
#define MAGISK_PATCH 0x1
|
||||
#define OTHER_PATCH 0x2
|
||||
|
||||
static int cpio_test(struct vector *v) {
|
||||
const char *OTHER_LIST[] = { "sbin/launch_daemonsu.sh", "sbin/su", "init.xposed.rc", "boot/sbin/launch_daemonsu.sh", NULL };
|
||||
const char *MAGISK_LIST[] = { ".backup/.magisk", "init.magisk.rc", "overlay/init.magisk.rc", NULL };
|
||||
|
||||
for (int i = 0; OTHER_LIST[i]; ++i)
|
||||
if (cpio_find(v, OTHER_LIST[i]) > 0)
|
||||
return OTHER_PATCH;
|
||||
|
||||
for (int i = 0; MAGISK_LIST[i]; ++i)
|
||||
if (cpio_find(v, MAGISK_LIST[i]) > 0)
|
||||
return MAGISK_PATCH;
|
||||
|
||||
return STOCK_BOOT;
|
||||
}
|
||||
|
||||
static char *cpio_sha1(struct vector *v) {
|
||||
cpio_entry *e;
|
||||
char sha1[41];
|
||||
vec_for_each(v, e) {
|
||||
if (!e) continue;
|
||||
if (strcmp(e->filename, "init.magisk.rc") == 0
|
||||
|| strcmp(e->filename, "overlay/init.magisk.rc") == 0) {
|
||||
for (void *pos = e->data; pos < e->data + e->filesize; pos = strchr(pos + 1, '\n') + 1) {
|
||||
if (memcmp(pos, "# STOCKSHA1=", 12) == 0) {
|
||||
pos += 12;
|
||||
memcpy(sha1, pos, 40);
|
||||
sha1[40] = '\0';
|
||||
return strdup(sha1);
|
||||
}
|
||||
}
|
||||
} else if (strcmp(e->filename, ".backup/.sha1") == 0) {
|
||||
return e->data;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void cpio_backup(struct vector *v, struct vector *bak, const char *orig, const char *sha1) {
|
||||
struct vector o_body, *o = &o_body;
|
||||
cpio_entry *m, *n, *rem, *cksm;
|
||||
char buf[PATH_MAX];
|
||||
int res, backup;
|
||||
|
||||
m = xcalloc(sizeof(*m), 1);
|
||||
m->filename = strdup(".backup");
|
||||
m->mode = S_IFDIR;
|
||||
vec_push_back(bak, m);
|
||||
|
||||
rem = xcalloc(sizeof(*rem), 1);
|
||||
rem->filename = strdup(".backup/.rmlist");
|
||||
rem->mode = S_IFREG;
|
||||
|
||||
if (sha1) {
|
||||
fprintf(stderr, "Save SHA1: [%s] -> [.backup/.sha1]\n", sha1);
|
||||
cksm = xcalloc(sizeof(*cksm), 1);
|
||||
vec_push_back(bak, cksm);
|
||||
cksm->filename = strdup(".backup/.sha1");
|
||||
cksm->mode = S_IFREG;
|
||||
cksm->data = strdup(sha1);
|
||||
cksm->filesize = strlen(sha1) + 1;
|
||||
}
|
||||
|
||||
vec_init(o);
|
||||
parse_cpio(o, orig);
|
||||
// Remove possible backups in original ramdisk
|
||||
cpio_rm(o, 1, ".backup");
|
||||
cpio_rm(v, 1, ".backup");
|
||||
|
||||
// Sort both vectors before comparing
|
||||
vec_sort(o, cpio_cmp);
|
||||
vec_sort(v, cpio_cmp);
|
||||
|
||||
// Start comparing
|
||||
size_t i = 0, j = 0;
|
||||
while(i != vec_size(o) || j != vec_size(v)) {
|
||||
backup = 0;
|
||||
if (i != vec_size(o) && j != vec_size(v)) {
|
||||
m = vec_entry(o)[i];
|
||||
n = vec_entry(v)[j];
|
||||
res = strcmp(m->filename, n->filename);
|
||||
} else if (i == vec_size(o)) {
|
||||
n = vec_entry(v)[j];
|
||||
res = 1;
|
||||
} else if (j == vec_size(v)) {
|
||||
m = vec_entry(o)[i];
|
||||
res = -1;
|
||||
}
|
||||
|
||||
if (res < 0) {
|
||||
// Something is missing in new ramdisk, backup!
|
||||
++i;
|
||||
backup = 1;
|
||||
fprintf(stderr, "Backup missing entry: ");
|
||||
} else if (res == 0) {
|
||||
++i; ++j;
|
||||
if (m->filesize == n->filesize && memcmp(m->data, n->data, m->filesize) == 0)
|
||||
continue;
|
||||
// Not the same!
|
||||
backup = 1;
|
||||
fprintf(stderr, "Backup mismatch entry: ");
|
||||
} else {
|
||||
// Something new in ramdisk, record in rem
|
||||
++j;
|
||||
rem->data = xrealloc(rem->data, rem->filesize + strlen(n->filename) + 1);
|
||||
memcpy(rem->data + rem->filesize, n->filename, strlen(n->filename) + 1);
|
||||
rem->filesize += strlen(n->filename) + 1;
|
||||
fprintf(stderr, "Record new entry: [%s] -> [.backup/.rmlist]\n", n->filename);
|
||||
}
|
||||
if (backup) {
|
||||
sprintf(buf, ".backup/%s", m->filename);
|
||||
fprintf(stderr, "[%s] -> [%s]\n", m->filename, buf);
|
||||
free(m->filename);
|
||||
m->filename = strdup(buf);
|
||||
vec_push_back(bak, m);
|
||||
// NULL the original entry, so it won't be freed
|
||||
vec_entry(o)[i - 1] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (rem->filesize)
|
||||
vec_push_back(bak, rem);
|
||||
else
|
||||
cpio_free(rem);
|
||||
|
||||
// Cleanup
|
||||
cpio_vec_destroy(o);
|
||||
}
|
||||
|
||||
static void cpio_restore(struct vector *v) {
|
||||
cpio_entry *e;
|
||||
vec_for_each(v, e) {
|
||||
if (!e) continue;
|
||||
if (strncmp(e->filename, ".backup", 7) == 0) {
|
||||
if (e->filename[7] == '\0') continue;
|
||||
if (e->filename[8] == '.') {
|
||||
if (strcmp(e->filename, ".backup/.rmlist") == 0) {
|
||||
for (int pos = 0; pos < e->filesize; pos += strlen(e->data + pos) + 1)
|
||||
cpio_rm(v, 0, e->data + pos);
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
fprintf(stderr, "Restore [%s] -> [%s]\n", e->filename, e->filename + 8);
|
||||
vec_cur(v) = NULL;
|
||||
char *new_name = strdup(e->filename + 8);
|
||||
free(e->filename);
|
||||
e->filename = new_name;
|
||||
cpio_vec_insert(v, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Some known stuff we can remove
|
||||
cpio_rm(v, 1, ".backup");
|
||||
cpio_rm(v, 1, "overlay");
|
||||
cpio_rm(v, 0, "sbin/magic_mask.sh");
|
||||
cpio_rm(v, 0, "init.magisk.rc");
|
||||
cpio_rm(v, 0, "magisk");
|
||||
cpio_rm(v, 0, "ramdisk-recovery.xz");
|
||||
}
|
||||
|
||||
static void restore_high_compress(struct vector *v, const char *incpio) {
|
||||
// Check if the ramdisk is in high compression mode
|
||||
if (cpio_extract(v, "ramdisk.cpio.xz", incpio) == 0) {
|
||||
void *xz;
|
||||
size_t size;
|
||||
full_read(incpio, &xz, &size);
|
||||
int fd = creat(incpio, 0644);
|
||||
lzma(0, fd, xz, size);
|
||||
close(fd);
|
||||
free(xz);
|
||||
cpio_rm(v, 0, "ramdisk.cpio.xz");
|
||||
cpio_rm(v, 0, "init");
|
||||
struct vector vv;
|
||||
vec_init(&vv);
|
||||
parse_cpio(&vv, incpio);
|
||||
cpio_entry *e;
|
||||
vec_for_each(&vv, e)
|
||||
vec_push_back(v, e);
|
||||
vec_destroy(&vv);
|
||||
}
|
||||
}
|
||||
|
||||
static void enable_high_compress(struct vector *v, struct vector *b, const char *incpio) {
|
||||
cpio_entry *init, *magiskinit;
|
||||
|
||||
// Swap magiskinit with original init
|
||||
int i = cpio_find(b, ".backup/init"), j = cpio_find(v, "init");
|
||||
init = vec_entry(b)[i];
|
||||
magiskinit = vec_entry(v)[j];
|
||||
free(init->filename);
|
||||
init->filename = strdup("init");
|
||||
vec_entry(v)[j] = init;
|
||||
vec_entry(b)[i] = NULL;
|
||||
|
||||
dump_cpio(v, incpio);
|
||||
cpio_vec_destroy(v);
|
||||
void *cpio;
|
||||
size_t size;
|
||||
full_read(incpio, &cpio, &size);
|
||||
int fd = creat(incpio, 0644);
|
||||
lzma(1, fd, cpio, size);
|
||||
close(fd);
|
||||
free(cpio);
|
||||
vec_init(v);
|
||||
vec_push_back(v, magiskinit);
|
||||
cpio_add(v, 0, "ramdisk.cpio.xz", incpio);
|
||||
}
|
||||
|
||||
int cpio_commands(int argc, char *argv[]) {
|
||||
char *incpio = argv[0];
|
||||
++argv;
|
||||
--argc;
|
||||
|
||||
struct vector v;
|
||||
vec_init(&v);
|
||||
parse_cpio(&v, incpio);
|
||||
|
||||
int cmdc;
|
||||
char *cmdv[6];
|
||||
|
||||
while (argc) {
|
||||
cmdc = 0;
|
||||
for (char *tok = strtok(argv[0], " "); tok; tok = strtok(NULL, " "))
|
||||
cmdv[cmdc++] = tok;
|
||||
|
||||
if (strcmp(cmdv[0], "test") == 0) {
|
||||
exit(cpio_test(&v));
|
||||
} else if (strcmp(cmdv[0], "restore") == 0) {
|
||||
restore_high_compress(&v, incpio);
|
||||
cpio_restore(&v);
|
||||
} else if (strcmp(cmdv[0], "sha1") == 0) {
|
||||
char *sha1 = cpio_sha1(&v);
|
||||
if (sha1)
|
||||
printf("%s\n", sha1);
|
||||
return 0;
|
||||
} else if (cmdc >= 2 && strcmp(cmdv[0], "backup") == 0) {
|
||||
struct vector back;
|
||||
vec_init(&back);
|
||||
cpio_backup(&v, &back, cmdv[1], cmdc > 2 ? cmdv[2] : NULL);
|
||||
cpio_entry *e;
|
||||
vec_for_each(&back, e)
|
||||
if (e) vec_push_back(&v, e);
|
||||
vec_destroy(&back);
|
||||
} else if (cmdc >= 5 && strcmp(cmdv[0], "magisk") == 0) {
|
||||
cpio_patch(&v, strcmp(cmdv[3], "true") == 0, strcmp(cmdv[4], "true") == 0);
|
||||
|
||||
struct vector back;
|
||||
vec_init(&back);
|
||||
cpio_backup(&v, &back, cmdv[1], cmdc > 5 ? cmdv[5] : NULL);
|
||||
|
||||
cpio_entry *e;
|
||||
e = xcalloc(sizeof(*e), 1);
|
||||
e->filename = strdup(".backup/.magisk");
|
||||
e->mode = S_IFREG;
|
||||
e->data = xmalloc(50);
|
||||
snprintf(e->data, 50, "KEEPVERITY=%s\nKEEPFORCEENCRYPT=%s\n", cmdv[3], cmdv[4]);
|
||||
e->filesize = strlen(e->data) + 1;
|
||||
vec_push_back(&back, e);
|
||||
|
||||
// Enable high compression mode
|
||||
if (strcmp(cmdv[2], "true") == 0)
|
||||
enable_high_compress(&v, &back, incpio);
|
||||
|
||||
vec_for_each(&back, e)
|
||||
if (e) vec_push_back(&v, e);
|
||||
vec_destroy(&back);
|
||||
} else if (cmdc >= 2 && strcmp(cmdv[0], "rm") == 0) {
|
||||
int recur = cmdc > 2 && strcmp(cmdv[1], "-r") == 0;
|
||||
cpio_rm(&v, recur, cmdv[1 + recur]);
|
||||
} else if (cmdc == 3 && strcmp(cmdv[0], "mv") == 0) {
|
||||
cpio_mv(&v, cmdv[1], cmdv[2]);
|
||||
} else if (cmdc == 3 && strcmp(cmdv[0], "patch") == 0) {
|
||||
cpio_patch(&v, strcmp(cmdv[1], "true") == 0, strcmp(cmdv[2], "true") == 0);
|
||||
} else if (strcmp(cmdv[0], "extract") == 0) {
|
||||
if (cmdc == 3) {
|
||||
return cpio_extract(&v, cmdv[1], cmdv[2]);
|
||||
} else {
|
||||
cpio_extract_all(&v);
|
||||
return 0;
|
||||
}
|
||||
} else if (cmdc == 3 && strcmp(cmdv[0], "mkdir") == 0) {
|
||||
cpio_mkdir(&v, strtoul(cmdv[1], NULL, 8), cmdv[2]);
|
||||
} else if (cmdc == 3 && strcmp(cmdv[0], "ln") == 0) {
|
||||
cpio_ln(&v, cmdv[1], cmdv[2]);
|
||||
} else if (cmdc == 4 && strcmp(cmdv[0], "add") == 0) {
|
||||
cpio_add(&v, strtoul(cmdv[1], NULL, 8), cmdv[2], cmdv[3]);
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
--argc;
|
||||
++argv;
|
||||
}
|
||||
|
||||
dump_cpio(&v, incpio);
|
||||
cpio_vec_destroy(&v);
|
||||
return 0;
|
||||
}
|
79
native/jni/magiskboot/types.c
Normal file
79
native/jni/magiskboot/types.c
Normal file
@@ -0,0 +1,79 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "bootimg.h"
|
||||
#include "types.h"
|
||||
|
||||
file_t check_type(const void *buf) {
|
||||
if (memcmp(buf, CHROMEOS_MAGIC, 8) == 0) {
|
||||
return CHROMEOS;
|
||||
} else if (memcmp(buf, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0) {
|
||||
return AOSP;
|
||||
} else if (memcmp(buf, ELF32_MAGIC, 5) == 0) {
|
||||
return ELF32;
|
||||
} else if (memcmp(buf, ELF64_MAGIC, 5) == 0) {
|
||||
return ELF64;
|
||||
} else if (memcmp(buf, GZIP_MAGIC, 4) == 0) {
|
||||
return GZIP;
|
||||
} else if (memcmp(buf, LZOP_MAGIC, 9) == 0) {
|
||||
return LZOP;
|
||||
} else if (memcmp(buf, XZ_MAGIC, 6) == 0) {
|
||||
return XZ;
|
||||
} else if (memcmp(buf, "\x5d\x00\x00", 3) == 0
|
||||
&& (((char *)buf)[12] == '\xff' || ((char *)buf)[12] == '\x00')) {
|
||||
return LZMA;
|
||||
} else if (memcmp(buf, BZIP_MAGIC, 3) == 0) {
|
||||
return BZIP2;
|
||||
} else if (memcmp(buf, LZ4_MAGIC, 4) == 0) {
|
||||
return LZ4;
|
||||
} else if (memcmp(buf, LZ4_LEG_MAGIC, 4) == 0) {
|
||||
return LZ4_LEGACY;
|
||||
} else if (memcmp(buf, MTK_MAGIC, 4) == 0) {
|
||||
return MTK;
|
||||
} else if (memcmp(buf, DTB_MAGIC, 4) == 0) {
|
||||
return DTB;
|
||||
} else {
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
void get_type_name(file_t type, char *name) {
|
||||
char *s;
|
||||
switch (type) {
|
||||
case CHROMEOS:
|
||||
s = "chromeos";
|
||||
break;
|
||||
case AOSP:
|
||||
s = "aosp";
|
||||
break;
|
||||
case GZIP:
|
||||
s = "gzip";
|
||||
break;
|
||||
case LZOP:
|
||||
s = "lzop";
|
||||
break;
|
||||
case XZ:
|
||||
s = "xz";
|
||||
break;
|
||||
case LZMA:
|
||||
s = "lzma";
|
||||
break;
|
||||
case BZIP2:
|
||||
s = "bzip2";
|
||||
break;
|
||||
case LZ4:
|
||||
s = "lz4";
|
||||
break;
|
||||
case LZ4_LEGACY:
|
||||
s = "lz4_legacy";
|
||||
break;
|
||||
case MTK:
|
||||
s = "mtk";
|
||||
break;
|
||||
case DTB:
|
||||
s = "dtb";
|
||||
break;
|
||||
default:
|
||||
s = "raw";
|
||||
}
|
||||
strcpy(name, s);
|
||||
}
|
42
native/jni/magiskboot/types.h
Normal file
42
native/jni/magiskboot/types.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifndef _TYPES_H_
|
||||
#define _TYPES_H_
|
||||
|
||||
typedef enum {
|
||||
UNKNOWN,
|
||||
CHROMEOS,
|
||||
AOSP,
|
||||
ELF32,
|
||||
ELF64,
|
||||
GZIP,
|
||||
LZOP,
|
||||
XZ,
|
||||
LZMA,
|
||||
BZIP2,
|
||||
LZ4,
|
||||
LZ4_LEGACY,
|
||||
MTK,
|
||||
DTB
|
||||
} file_t;
|
||||
|
||||
#define COMPRESSED(type) (type >= GZIP && type <= LZ4_LEGACY)
|
||||
|
||||
#define CHROMEOS_MAGIC "CHROMEOS"
|
||||
#define ELF32_MAGIC "\x7f""ELF\x01"
|
||||
#define ELF64_MAGIC "\x7f""ELF\x02"
|
||||
#define GZIP_MAGIC "\x1f\x8b\x08\x00"
|
||||
#define LZOP_MAGIC "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a"
|
||||
#define XZ_MAGIC "\xfd""7zXZ\x00"
|
||||
#define BZIP_MAGIC "BZh"
|
||||
#define LZ4_MAGIC "\x04\x22\x4d\x18"
|
||||
#define LZ4_LEG_MAGIC "\x02\x21\x4c\x18"
|
||||
#define MTK_MAGIC "\x88\x16\x88\x58"
|
||||
#define DTB_MAGIC "\xd0\x0d\xfe\xed"
|
||||
#define LG_BUMP_MAGIC "\x41\xa9\xe4\x67\x74\x4d\x1d\x1b\xa4\x29\xf2\xec\xea\x65\x52\x79"
|
||||
|
||||
#define SUP_LIST ((char *[]) { "gzip", "xz", "lzma", "bzip2", "lz4", "lz4_legacy", NULL })
|
||||
#define SUP_EXT_LIST ((char *[]) { "gz", "xz", "lzma", "bz2", "lz4", "lz4", NULL })
|
||||
|
||||
file_t check_type(const void *buf);
|
||||
void get_type_name(file_t type, char *name);
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user