mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-04-19 06:01:28 +00:00
Move magiskboot cli to argh
This commit is contained in:
parent
1f162b819d
commit
8ae7641e8a
@ -92,7 +92,6 @@ LOCAL_STATIC_LIBRARIES := \
|
||||
libboot-rs
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
boot/main.cpp \
|
||||
boot/bootimg.cpp \
|
||||
boot/compress.cpp \
|
||||
boot/format.cpp \
|
||||
@ -102,7 +101,7 @@ LOCAL_LDFLAGS := -static
|
||||
|
||||
ifdef B_CRT0
|
||||
LOCAL_STATIC_LIBRARIES += crt0
|
||||
LOCAL_LDFLAGS += -lm
|
||||
LOCAL_LDFLAGS += -lm -Wl,--defsym=vfprintf=musl_vfprintf
|
||||
endif
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
397
native/src/boot/cli.rs
Normal file
397
native/src/boot/cli.rs
Normal file
@ -0,0 +1,397 @@
|
||||
use crate::payload::extract_boot_from_payload;
|
||||
use crate::sign::{sha1_hash, verify_boot_image};
|
||||
use argh::FromArgs;
|
||||
use base::{cmdline_logging, libc::umask, log_err, map_args, raw_cstr, EarlyExitExt, LoggedResult, MappedFile, ResultExt, Utf8CStr};
|
||||
use std::ffi::c_char;
|
||||
use crate::cpio::cpio_commands;
|
||||
use crate::dtb::dtb_commands;
|
||||
use crate::ffi::{cleanup, compress, decompress_raw, formats, repack, sign, split_image_dtb, unpack, verify};
|
||||
use crate::patch::hexpatch;
|
||||
|
||||
#[derive(FromArgs)]
|
||||
struct Cli {
|
||||
#[argh(subcommand)]
|
||||
action: Action,
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
#[argh(subcommand)]
|
||||
enum Action {
|
||||
Unpack(Unpack),
|
||||
Repack(Repack),
|
||||
Verify(Verify),
|
||||
Sign(Sign),
|
||||
Extract(Extract),
|
||||
HexPatch(HexPatch),
|
||||
Cpio(Cpio),
|
||||
Dtb(Dtb),
|
||||
Split(Split),
|
||||
Sha1(Sha1),
|
||||
Cleanup(Cleanup),
|
||||
Compress(Compress),
|
||||
Decompress(Decompress),
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
#[argh(subcommand, name = "unpack")]
|
||||
struct Unpack {
|
||||
#[argh(switch, short = 'n')]
|
||||
no_decompress: bool,
|
||||
#[argh(switch, short = 'h')]
|
||||
dump_header: bool,
|
||||
#[argh(positional)]
|
||||
img: String,
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
#[argh(subcommand, name = "repack")]
|
||||
struct Repack {
|
||||
#[argh(switch, short = 'n')]
|
||||
no_compress: bool,
|
||||
#[argh(positional)]
|
||||
img: String,
|
||||
#[argh(positional, default = r#""new-boot.img".to_string()"#)]
|
||||
out: String,
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
#[argh(subcommand, name = "verify")]
|
||||
struct Verify {
|
||||
#[argh(positional)]
|
||||
img: String,
|
||||
#[argh(positional)]
|
||||
cert: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
#[argh(subcommand, name = "sign")]
|
||||
struct Sign {
|
||||
#[argh(positional)]
|
||||
img: String,
|
||||
#[argh(positional)]
|
||||
args: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
#[argh(subcommand, name = "extract")]
|
||||
struct Extract {
|
||||
#[argh(positional)]
|
||||
payload: String,
|
||||
#[argh(positional)]
|
||||
args: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
#[argh(subcommand, name = "hexpatch")]
|
||||
struct HexPatch {
|
||||
#[argh(positional)]
|
||||
file: String,
|
||||
#[argh(positional)]
|
||||
src: String,
|
||||
#[argh(positional)]
|
||||
dest: String,
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
#[argh(subcommand, name = "cpio")]
|
||||
struct Cpio {
|
||||
#[argh(positional)]
|
||||
cmds: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
#[argh(subcommand, name = "dtb")]
|
||||
struct Dtb {
|
||||
#[argh(positional)]
|
||||
cmds: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
#[argh(subcommand, name = "split")]
|
||||
struct Split {
|
||||
#[argh(switch, short = 'n')]
|
||||
no_decompress: bool,
|
||||
#[argh(positional)]
|
||||
file: String,
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
#[argh(subcommand, name = "sha1")]
|
||||
struct Sha1 {
|
||||
#[argh(positional)]
|
||||
file: String,
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
#[argh(subcommand, name = "cleanup")]
|
||||
struct Cleanup {}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
#[argh(subcommand, name = "compress")]
|
||||
struct Compress {
|
||||
#[argh(option, short = 'f', default = r#""gzip".to_string()"#)]
|
||||
format: String,
|
||||
#[argh(positional)]
|
||||
file: String,
|
||||
#[argh(positional)]
|
||||
out: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
#[argh(subcommand, name = "decompress")]
|
||||
struct Decompress {
|
||||
#[argh(positional)]
|
||||
file: String,
|
||||
#[argh(positional)]
|
||||
out: Option<String>,
|
||||
}
|
||||
|
||||
fn print_usage(cmd: &str) {
|
||||
eprintln!(
|
||||
r#"MagiskBoot - Boot Image Modification Tool
|
||||
|
||||
Usage: {} <action> [args...]
|
||||
|
||||
Supported actions:
|
||||
unpack [-n] [-h] <bootimg>
|
||||
Unpack <bootimg> to its individual components, each component to
|
||||
a file with its corresponding file name in the current directory.
|
||||
Supported components: kernel, kernel_dtb, ramdisk.cpio, second,
|
||||
dtb, extra, and recovery_dtbo.
|
||||
By default, each component will be decompressed on-the-fly.
|
||||
If '-n' is provided, all decompression operations will be skipped;
|
||||
each component will remain untouched, dumped in its original format.
|
||||
If '-h' is provided, the boot image header information will be
|
||||
dumped to the file 'header', which can be used to modify header
|
||||
configurations during repacking.
|
||||
Return values:
|
||||
0:valid 1:error 2:chromeos
|
||||
|
||||
repack [-n] <origbootimg> [outbootimg]
|
||||
Repack boot image components using files from the current directory
|
||||
to [outbootimg], or 'new-boot.img' if not specified. Current directory
|
||||
should only contain required files for [outbootimg], or incorrect
|
||||
[outbootimg] may be produced.
|
||||
<origbootimg> is the original boot image used to unpack the components.
|
||||
By default, each component will be automatically compressed using its
|
||||
corresponding format detected in <origbootimg>. If a component file
|
||||
in the current directory is already compressed, then no addition
|
||||
compression will be performed for that specific component.
|
||||
If '-n' is provided, all compression operations will be skipped.
|
||||
If env variable PATCHVBMETAFLAG is set to true, all disable flags in
|
||||
the boot image's vbmeta header will be set.
|
||||
|
||||
verify <bootimg> [x509.pem]
|
||||
Check whether the boot image is signed with AVB 1.0 signature.
|
||||
Optionally provide a certificate to verify whether the image is
|
||||
signed by the public key certificate.
|
||||
Return value:
|
||||
0:valid 1:error
|
||||
|
||||
sign <bootimg> [name] [x509.pem pk8]
|
||||
Sign <bootimg> with AVB 1.0 signature.
|
||||
Optionally provide the name of the image (default: '/boot').
|
||||
Optionally provide the certificate/private key pair for signing.
|
||||
If the certificate/private key pair is not provided, the AOSP
|
||||
verity key bundled in the executable will be used.
|
||||
|
||||
extract <payload.bin> [partition] [outfile]
|
||||
Extract [partition] from <payload.bin> to [outfile].
|
||||
If [outfile] is not specified, then output to '[partition].img'.
|
||||
If [partition] is not specified, then attempt to extract either
|
||||
'init_boot' or 'boot'. Which partition was chosen can be determined
|
||||
by whichever 'init_boot.img' or 'boot.img' exists.
|
||||
<payload.bin> can be '-' to be STDIN.
|
||||
|
||||
hexpatch <file> <hexpattern1> <hexpattern2>
|
||||
Search <hexpattern1> in <file>, and replace it with <hexpattern2>
|
||||
|
||||
cpio <incpio> [commands...]
|
||||
Do cpio commands to <incpio> (modifications are done in-place).
|
||||
Each command is a single argument; add quotes for each command.
|
||||
See "cpio --help" for supported commands.
|
||||
|
||||
dtb <file> <action> [args...]
|
||||
Do dtb related actions to <file>.
|
||||
See "dtb --help" for supported actions.
|
||||
|
||||
split [-n] <file>
|
||||
Split image.*-dtb into kernel + kernel_dtb.
|
||||
If '-n' is provided, decompression operations will be skipped;
|
||||
the kernel will remain untouched, split in its original format.
|
||||
|
||||
sha1 <file>
|
||||
Print the SHA1 checksum for <file>
|
||||
|
||||
cleanup
|
||||
Cleanup the current working directory
|
||||
|
||||
compress[=format] <infile> [outfile]
|
||||
Compress <infile> with [format] to [outfile].
|
||||
<infile>/[outfile] can be '-' to be STDIN/STDOUT.
|
||||
If [format] is not specified, then gzip will be used.
|
||||
If [outfile] is not specified, then <infile> will be replaced
|
||||
with another file suffixed with a matching file extension.
|
||||
Supported formats:
|
||||
|
||||
{1}
|
||||
|
||||
decompress <infile> [outfile]
|
||||
Detect format and decompress <infile> to [outfile].
|
||||
<infile>/[outfile] can be '-' to be STDIN/STDOUT.
|
||||
If [outfile] is not specified, then <infile> will be replaced
|
||||
with another file removing its archive format file extension.
|
||||
Supported formats:
|
||||
|
||||
{1}
|
||||
"#,
|
||||
cmd, formats()
|
||||
);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn main(
|
||||
argc: i32,
|
||||
argv: *const *const c_char,
|
||||
_envp: *const *const c_char,
|
||||
) -> i32 {
|
||||
cmdline_logging();
|
||||
umask(0);
|
||||
let res: LoggedResult<()> = try {
|
||||
let mut cmds = map_args(argc, argv)?;
|
||||
if argc < 2 {
|
||||
print_usage(cmds.first().unwrap_or(&"magiskboot"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if cmds[1].starts_with("--") {
|
||||
cmds[1] = &cmds[1][2..];
|
||||
}
|
||||
|
||||
if let Some(fmt) = str::strip_prefix(cmds[1], "compress=") {
|
||||
cmds.insert(1, "compress");
|
||||
cmds.insert(2, "-f");
|
||||
cmds[3] = fmt;
|
||||
}
|
||||
|
||||
let mut cli = Cli::from_args(&[cmds[0]], &cmds[1..]).on_early_exit(|| print_usage(cmds[0]));
|
||||
match cli.action {
|
||||
Action::Unpack(Unpack {
|
||||
no_decompress,
|
||||
dump_header,
|
||||
ref mut img,
|
||||
}) => {
|
||||
return unpack(Utf8CStr::from_string(img).as_ptr(), no_decompress, dump_header);
|
||||
}
|
||||
Action::Repack(Repack {
|
||||
no_compress,
|
||||
ref mut img,
|
||||
ref mut out,
|
||||
}) => {
|
||||
repack(
|
||||
Utf8CStr::from_string(img).as_ptr(),
|
||||
Utf8CStr::from_string(out).as_ptr(),
|
||||
no_compress,
|
||||
);
|
||||
}
|
||||
Action::Verify(Verify {
|
||||
ref mut img,
|
||||
ref mut cert,
|
||||
}) => {
|
||||
return verify(Utf8CStr::from_string(img).as_ptr(), cert.as_mut().map(|x| Utf8CStr::from_string(x).as_ptr()).unwrap_or(std::ptr::null()));
|
||||
}
|
||||
Action::Sign(Sign {
|
||||
ref mut img,
|
||||
ref mut args,
|
||||
}) => {
|
||||
let (pem, pk8) = match args.get_mut(1..=2) {
|
||||
Some([pem,pk8]) => (Utf8CStr::from_string(pem).as_ptr(), Utf8CStr::from_string(pk8).as_ptr()),
|
||||
_ => (std::ptr::null(), std::ptr::null()),
|
||||
};
|
||||
return sign(
|
||||
Utf8CStr::from_string(img).as_ptr(),
|
||||
args.first_mut().map(|x| Utf8CStr::from_string(x).as_ptr()).unwrap_or(raw_cstr!("/boot")),
|
||||
pem, pk8
|
||||
)
|
||||
}
|
||||
Action::Extract(Extract {
|
||||
ref payload,
|
||||
ref args,
|
||||
}) => {
|
||||
if args.len() > 2 {
|
||||
Err(log_err!("Too many arguments"))?;
|
||||
}
|
||||
extract_boot_from_payload(
|
||||
payload,
|
||||
args.first().map(|x| x.as_str()),
|
||||
args.get(1).map(|x| x.as_str()),
|
||||
)
|
||||
.log_with_msg(|w| w.write_str("Failed to extract from payload"))?;
|
||||
}
|
||||
Action::HexPatch(HexPatch {
|
||||
ref mut file,
|
||||
ref mut src,
|
||||
ref mut dest,
|
||||
}) => {
|
||||
if !hexpatch(file, Utf8CStr::from_string(src), Utf8CStr::from_string(dest)) {
|
||||
Err(log_err!("Failed to patch"))?;
|
||||
}
|
||||
}
|
||||
Action::Cpio(Cpio {
|
||||
ref cmds,
|
||||
}) => {
|
||||
return if cpio_commands(&cmds.iter().map(|x| x.as_str()).collect::<Vec<_>>()) {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
Action::Dtb(Dtb {
|
||||
ref cmds,
|
||||
}) => {
|
||||
return if dtb_commands(&cmds.iter().map(|x| x.as_str()).collect::<Vec<_>>()) {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
Action::Split(Split {
|
||||
no_decompress,
|
||||
ref mut file,
|
||||
}) => {
|
||||
return split_image_dtb(Utf8CStr::from_string(file).as_ptr(), no_decompress);
|
||||
}
|
||||
Action::Sha1(Sha1 { ref mut file }) => {
|
||||
let file = MappedFile::open(Utf8CStr::from_string(file))?;
|
||||
let mut sha1 = [0u8; 20];
|
||||
sha1_hash(file.as_ref(), &mut sha1);
|
||||
for byte in &sha1 {
|
||||
print!("{:02x}", byte);
|
||||
}
|
||||
println!();
|
||||
}
|
||||
Action::Cleanup(_) => {
|
||||
eprintln!("Cleaning up...");
|
||||
cleanup();
|
||||
}
|
||||
Action::Decompress(Decompress {
|
||||
ref mut file,
|
||||
ref mut out,
|
||||
}) => {
|
||||
decompress_raw(Utf8CStr::from_string(file).as_mut_ptr(), out.as_mut().map(|x| Utf8CStr::from_string(x).as_ptr()).unwrap_or(std::ptr::null()));
|
||||
}
|
||||
Action::Compress(Compress {
|
||||
ref mut file,
|
||||
ref mut format,
|
||||
ref mut out,
|
||||
}) => {
|
||||
compress(Utf8CStr::from_string(format).as_ptr(), Utf8CStr::from_string(file).as_ptr(), out.as_mut().map(|x| Utf8CStr::from_string(x).as_ptr()).unwrap_or(std::ptr::null()));
|
||||
}
|
||||
}
|
||||
};
|
||||
if res.is_ok() {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
@ -12,3 +12,13 @@ void decompress(char *infile, const char *outfile);
|
||||
bool decompress(rust::Slice<const uint8_t> buf, int fd);
|
||||
bool xz(rust::Slice<const uint8_t> buf, rust::Vec<uint8_t> &out);
|
||||
bool unxz(rust::Slice<const uint8_t> buf, rust::Vec<uint8_t> &out);
|
||||
|
||||
inline ::rust::String formats() {
|
||||
std::string s;
|
||||
for (int fmt = GZIP; fmt < LZOP; ++fmt) {
|
||||
s += fmt2name[(format_t) fmt];
|
||||
s += ' ';
|
||||
}
|
||||
s.pop_back();
|
||||
return {s};
|
||||
}
|
||||
|
@ -15,12 +15,12 @@ use num_traits::cast::AsPrimitive;
|
||||
use size::{Base, Size, Style};
|
||||
|
||||
use base::libc::{
|
||||
c_char, dev_t, gid_t, major, makedev, minor, mknod, mode_t, uid_t, O_CLOEXEC, O_CREAT,
|
||||
dev_t, gid_t, major, makedev, minor, mknod, mode_t, uid_t, O_CLOEXEC, O_CREAT,
|
||||
O_RDONLY, O_TRUNC, O_WRONLY, S_IFBLK, S_IFCHR, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, S_IRGRP,
|
||||
S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR, S_IXGRP, S_IXOTH, S_IXUSR,
|
||||
};
|
||||
use base::{
|
||||
cstr_buf, log_err, map_args, BytesExt, EarlyExitExt, FsPath, LoggedResult, MappedFile,
|
||||
cstr_buf, log_err, BytesExt, EarlyExitExt, FsPath, LoggedResult, MappedFile,
|
||||
ResultExt, Utf8CStr, Utf8CStrBuf, WriteExt,
|
||||
};
|
||||
|
||||
@ -753,14 +753,8 @@ impl Display for CpioEntry {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cpio_commands(argc: i32, argv: *const *const c_char) -> bool {
|
||||
pub fn cpio_commands(cmds: &Vec<&str>) -> bool {
|
||||
let res: LoggedResult<()> = try {
|
||||
if argc < 1 {
|
||||
Err(log_err!("No arguments"))?;
|
||||
}
|
||||
|
||||
let cmds = map_args(argc, argv)?;
|
||||
|
||||
let mut cli =
|
||||
CpioCli::from_args(&["magiskboot", "cpio"], &cmds).on_early_exit(print_cpio_usage);
|
||||
|
||||
|
@ -7,7 +7,7 @@ use fdt::{
|
||||
};
|
||||
|
||||
use base::{
|
||||
libc::c_char, log_err, map_args, EarlyExitExt, LoggedResult, MappedFile, ResultExt, Utf8CStr,
|
||||
EarlyExitExt, LoggedResult, MappedFile, ResultExt, Utf8CStr,
|
||||
};
|
||||
|
||||
use crate::{check_env, patch::patch_verity};
|
||||
@ -274,13 +274,8 @@ fn dtb_patch(file: &Utf8CStr) -> LoggedResult<bool> {
|
||||
Ok(patched)
|
||||
}
|
||||
|
||||
pub fn dtb_commands(argc: i32, argv: *const *const c_char) -> bool {
|
||||
pub fn dtb_commands(cmds: &Vec<&str>) -> bool {
|
||||
let res: LoggedResult<()> = try {
|
||||
if argc < 1 {
|
||||
Err(log_err!("No arguments"))?;
|
||||
}
|
||||
let cmds = map_args(argc, argv)?;
|
||||
|
||||
let mut cli =
|
||||
DtbCli::from_args(&["magiskboot", "dtb"], &cmds).on_early_exit(print_dtb_usage);
|
||||
|
||||
|
@ -6,11 +6,7 @@
|
||||
pub use libz_rs_sys::*;
|
||||
pub use libbz2_rs_sys::*;
|
||||
pub use base;
|
||||
use cpio::cpio_commands;
|
||||
use dtb::dtb_commands;
|
||||
use patch::hexpatch;
|
||||
use payload::extract_boot_from_payload;
|
||||
use sign::{get_sha, sha1_hash, sha256_hash, sign_boot_image, verify_boot_image, SHA};
|
||||
use sign::{get_sha, sha256_hash, sign_boot_image, verify_boot_image, SHA};
|
||||
use std::env;
|
||||
|
||||
mod cpio;
|
||||
@ -21,6 +17,7 @@ mod payload;
|
||||
#[allow(warnings)]
|
||||
mod proto;
|
||||
mod sign;
|
||||
mod cli;
|
||||
|
||||
#[cxx::bridge]
|
||||
pub mod ffi {
|
||||
@ -35,16 +32,30 @@ pub mod ffi {
|
||||
unsafe extern "C++" {
|
||||
include!("compress.hpp");
|
||||
fn decompress(buf: &[u8], fd: i32) -> bool;
|
||||
#[cxx_name = "decompress"]
|
||||
unsafe fn decompress_raw(infile: *mut c_char, outfile: *const c_char);
|
||||
unsafe fn compress(format: *const c_char, infile: *const c_char, outfile: *const c_char);
|
||||
fn xz(buf: &[u8], out: &mut Vec<u8>) -> bool;
|
||||
fn unxz(buf: &[u8], out: &mut Vec<u8>) -> bool;
|
||||
|
||||
include!("bootimg.hpp");
|
||||
include!("magiskboot.hpp");
|
||||
#[cxx_name = "boot_img"]
|
||||
type BootImage;
|
||||
#[cxx_name = "get_payload"]
|
||||
fn payload(self: &BootImage) -> &[u8];
|
||||
#[cxx_name = "get_tail"]
|
||||
fn tail(self: &BootImage) -> &[u8];
|
||||
|
||||
fn cleanup();
|
||||
|
||||
unsafe fn unpack(image: *const c_char, skip_decomp: bool, hdr: bool) -> i32;
|
||||
unsafe fn repack(src_img: *const c_char, out_img: *const c_char, skip_comp: bool);
|
||||
unsafe fn verify(image: *const c_char, cert: *const c_char) -> i32;
|
||||
unsafe fn sign(image: *const c_char, name: *const c_char, cert: *const c_char, key: *const c_char) -> i32;
|
||||
unsafe fn split_image_dtb(filename: *const c_char, skip_decomp: bool) -> i32;
|
||||
|
||||
fn formats() -> String;
|
||||
}
|
||||
|
||||
extern "Rust" {
|
||||
@ -53,29 +64,19 @@ pub mod ffi {
|
||||
fn update(self: &mut SHA, data: &[u8]);
|
||||
fn finalize_into(self: &mut SHA, out: &mut [u8]);
|
||||
fn output_size(self: &SHA) -> usize;
|
||||
fn sha1_hash(data: &[u8], out: &mut [u8]);
|
||||
fn sha256_hash(data: &[u8], out: &mut [u8]);
|
||||
|
||||
fn hexpatch(file: &[u8], from: &[u8], to: &[u8]) -> bool;
|
||||
}
|
||||
|
||||
#[namespace = "rust"]
|
||||
#[allow(unused_unsafe)]
|
||||
extern "Rust" {
|
||||
fn extract_boot_from_payload(
|
||||
partition: Utf8CStrRef,
|
||||
in_path: Utf8CStrRef,
|
||||
out_path: Utf8CStrRef,
|
||||
) -> bool;
|
||||
unsafe fn cpio_commands(argc: i32, argv: *const *const c_char) -> bool;
|
||||
unsafe fn verify_boot_image(img: &BootImage, cert: *const c_char) -> bool;
|
||||
unsafe fn sign_boot_image(
|
||||
payload: &[u8],
|
||||
name: *const c_char,
|
||||
cert: *const c_char,
|
||||
key: *const c_char,
|
||||
) -> Vec<u8>;
|
||||
unsafe fn dtb_commands(argc: i32, argv: *const *const c_char) -> bool;
|
||||
unsafe fn verify_boot_image(img: &BootImage, cert: *const c_char) -> bool;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,3 +28,16 @@ static inline bool check_env(const char *name) {
|
||||
const char *val = getenv(name);
|
||||
return val != nullptr && val == "true"sv;
|
||||
}
|
||||
|
||||
static inline void cleanup() {
|
||||
unlink(HEADER_FILE);
|
||||
unlink(KERNEL_FILE);
|
||||
unlink(RAMDISK_FILE);
|
||||
unlink(SECOND_FILE);
|
||||
unlink(KER_DTB_FILE);
|
||||
unlink(EXTRA_FILE);
|
||||
unlink(RECV_DTBO_FILE);
|
||||
unlink(DTB_FILE);
|
||||
unlink(BOOTCONFIG_FILE);
|
||||
rm_rf(VND_RAMDISK_DIR);
|
||||
}
|
@ -1,228 +0,0 @@
|
||||
#include <base.hpp>
|
||||
|
||||
#include "boot-rs.hpp"
|
||||
#include "magiskboot.hpp"
|
||||
#include "compress.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#ifdef USE_CRT0
|
||||
__BEGIN_DECLS
|
||||
int musl_vfprintf(FILE *stream, const char *format, va_list arg);
|
||||
int vfprintf(FILE *stream, const char *format, va_list arg) {
|
||||
return musl_vfprintf(stream, format, arg);
|
||||
}
|
||||
__END_DECLS
|
||||
#endif
|
||||
|
||||
static void print_formats() {
|
||||
for (int fmt = GZIP; fmt < LZOP; ++fmt) {
|
||||
fprintf(stderr, "%s ", fmt2name[(format_t) fmt]);
|
||||
}
|
||||
}
|
||||
|
||||
static void usage(char *arg0) {
|
||||
fprintf(stderr,
|
||||
R"EOF(MagiskBoot - Boot Image Modification Tool
|
||||
|
||||
Usage: %s <action> [args...]
|
||||
|
||||
Supported actions:
|
||||
unpack [-n] [-h] <bootimg>
|
||||
Unpack <bootimg> to its individual components, each component to
|
||||
a file with its corresponding file name in the current directory.
|
||||
Supported components: kernel, kernel_dtb, ramdisk.cpio, second,
|
||||
dtb, extra, and recovery_dtbo.
|
||||
By default, each component will be decompressed on-the-fly.
|
||||
If '-n' is provided, all decompression operations will be skipped;
|
||||
each component will remain untouched, dumped in its original format.
|
||||
If '-h' is provided, the boot image header information will be
|
||||
dumped to the file 'header', which can be used to modify header
|
||||
configurations during repacking.
|
||||
Return values:
|
||||
0:valid 1:error 2:chromeos
|
||||
|
||||
repack [-n] <origbootimg> [outbootimg]
|
||||
Repack boot image components using files from the current directory
|
||||
to [outbootimg], or 'new-boot.img' if not specified. Current directory
|
||||
should only contain required files for [outbootimg], or incorrect
|
||||
[outbootimg] may be produced.
|
||||
<origbootimg> is the original boot image used to unpack the components.
|
||||
By default, each component will be automatically compressed using its
|
||||
corresponding format detected in <origbootimg>. If a component file
|
||||
in the current directory is already compressed, then no addition
|
||||
compression will be performed for that specific component.
|
||||
If '-n' is provided, all compression operations will be skipped.
|
||||
If env variable PATCHVBMETAFLAG is set to true, all disable flags in
|
||||
the boot image's vbmeta header will be set.
|
||||
|
||||
verify <bootimg> [x509.pem]
|
||||
Check whether the boot image is signed with AVB 1.0 signature.
|
||||
Optionally provide a certificate to verify whether the image is
|
||||
signed by the public key certificate.
|
||||
Return value:
|
||||
0:valid 1:error
|
||||
|
||||
sign <bootimg> [name] [x509.pem pk8]
|
||||
Sign <bootimg> with AVB 1.0 signature.
|
||||
Optionally provide the name of the image (default: '/boot').
|
||||
Optionally provide the certificate/private key pair for signing.
|
||||
If the certificate/private key pair is not provided, the AOSP
|
||||
verity key bundled in the executable will be used.
|
||||
|
||||
extract <payload.bin> [partition] [outfile]
|
||||
Extract [partition] from <payload.bin> to [outfile].
|
||||
If [outfile] is not specified, then output to '[partition].img'.
|
||||
If [partition] is not specified, then attempt to extract either
|
||||
'init_boot' or 'boot'. Which partition was chosen can be determined
|
||||
by whichever 'init_boot.img' or 'boot.img' exists.
|
||||
<payload.bin> can be '-' to be STDIN.
|
||||
|
||||
hexpatch <file> <hexpattern1> <hexpattern2>
|
||||
Search <hexpattern1> in <file>, and replace it with <hexpattern2>
|
||||
|
||||
cpio <incpio> [commands...]
|
||||
Do cpio commands to <incpio> (modifications are done in-place).
|
||||
Each command is a single argument; add quotes for each command.
|
||||
See "cpio --help" for supported commands.
|
||||
|
||||
dtb <file> <action> [args...]
|
||||
Do dtb related actions to <file>.
|
||||
See "dtb --help" for supported actions.
|
||||
|
||||
split [-n] <file>
|
||||
Split image.*-dtb into kernel + kernel_dtb.
|
||||
If '-n' is provided, decompression operations will be skipped;
|
||||
the kernel will remain untouched, split in its original format.
|
||||
|
||||
sha1 <file>
|
||||
Print the SHA1 checksum for <file>
|
||||
|
||||
cleanup
|
||||
Cleanup the current working directory
|
||||
|
||||
compress[=format] <infile> [outfile]
|
||||
Compress <infile> with [format] to [outfile].
|
||||
<infile>/[outfile] can be '-' to be STDIN/STDOUT.
|
||||
If [format] is not specified, then gzip will be used.
|
||||
If [outfile] is not specified, then <infile> will be replaced
|
||||
with another file suffixed with a matching file extension.
|
||||
Supported formats: )EOF", arg0);
|
||||
|
||||
print_formats();
|
||||
|
||||
fprintf(stderr, R"EOF(
|
||||
|
||||
decompress <infile> [outfile]
|
||||
Detect format and decompress <infile> to [outfile].
|
||||
<infile>/[outfile] can be '-' to be STDIN/STDOUT.
|
||||
If [outfile] is not specified, then <infile> will be replaced
|
||||
with another file removing its archive format file extension.
|
||||
Supported formats: )EOF");
|
||||
|
||||
print_formats();
|
||||
|
||||
fprintf(stderr, "\n\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
cmdline_logging();
|
||||
umask(0);
|
||||
|
||||
if (argc < 2)
|
||||
usage(argv[0]);
|
||||
|
||||
// Skip '--' for backwards compatibility
|
||||
string_view action(argv[1]);
|
||||
if (str_starts(action, "--"))
|
||||
action = argv[1] + 2;
|
||||
|
||||
if (action == "cleanup") {
|
||||
fprintf(stderr, "Cleaning up...\n");
|
||||
unlink(HEADER_FILE);
|
||||
unlink(KERNEL_FILE);
|
||||
unlink(RAMDISK_FILE);
|
||||
unlink(SECOND_FILE);
|
||||
unlink(KER_DTB_FILE);
|
||||
unlink(EXTRA_FILE);
|
||||
unlink(RECV_DTBO_FILE);
|
||||
unlink(DTB_FILE);
|
||||
unlink(BOOTCONFIG_FILE);
|
||||
rm_rf(VND_RAMDISK_DIR);
|
||||
} else if (argc > 2 && action == "sha1") {
|
||||
uint8_t sha1[20];
|
||||
{
|
||||
mmap_data m(argv[2]);
|
||||
sha1_hash(m, byte_data(sha1, sizeof(sha1)));
|
||||
}
|
||||
for (uint8_t i : sha1)
|
||||
printf("%02x", i);
|
||||
printf("\n");
|
||||
} else if (argc > 2 && action == "split") {
|
||||
if (argv[2] == "-n"sv) {
|
||||
if (argc == 3)
|
||||
usage(argv[0]);
|
||||
return split_image_dtb(argv[3], true);
|
||||
} else {
|
||||
return split_image_dtb(argv[2]);
|
||||
}
|
||||
} else if (argc > 2 && action == "unpack") {
|
||||
int idx = 2;
|
||||
bool nodecomp = false;
|
||||
bool hdr = false;
|
||||
for (;;) {
|
||||
if (idx >= argc)
|
||||
usage(argv[0]);
|
||||
if (argv[idx][0] != '-')
|
||||
break;
|
||||
for (char *flag = &argv[idx][1]; *flag; ++flag) {
|
||||
if (*flag == 'n')
|
||||
nodecomp = true;
|
||||
else if (*flag == 'h')
|
||||
hdr = true;
|
||||
else
|
||||
usage(argv[0]);
|
||||
}
|
||||
++idx;
|
||||
}
|
||||
return unpack(argv[idx], nodecomp, hdr);
|
||||
} else if (argc > 2 && action == "repack") {
|
||||
if (argv[2] == "-n"sv) {
|
||||
if (argc == 3)
|
||||
usage(argv[0]);
|
||||
repack(argv[3], argv[4] ? argv[4] : NEW_BOOT, true);
|
||||
} else {
|
||||
repack(argv[2], argv[3] ? argv[3] : NEW_BOOT);
|
||||
}
|
||||
} else if (argc > 2 && action == "verify") {
|
||||
return verify(argv[2], argv[3]);
|
||||
} else if (argc > 2 && action == "sign") {
|
||||
if (argc == 5) usage(argv[0]);
|
||||
return sign(
|
||||
argv[2],
|
||||
argc > 3 ? argv[3] : "/boot",
|
||||
argc > 5 ? argv[4] : nullptr,
|
||||
argc > 5 ? argv[5] : nullptr);
|
||||
} else if (argc > 2 && action == "decompress") {
|
||||
decompress(argv[2], argv[3]);
|
||||
} else if (argc > 2 && str_starts(action, "compress")) {
|
||||
compress(action[8] == '=' ? &action[9] : "gzip", argv[2], argv[3]);
|
||||
} else if (argc > 4 && action == "hexpatch") {
|
||||
return hexpatch(byte_view(argv[2]), byte_view(argv[3]), byte_view(argv[4])) ? 0 : 1;
|
||||
} else if (argc > 2 && action == "cpio") {
|
||||
return rust::cpio_commands(argc - 2, argv + 2) ? 0 : 1;
|
||||
} else if (argc > 2 && action == "dtb") {
|
||||
return rust::dtb_commands(argc - 2, argv + 2) ? 0 : 1;
|
||||
} else if (argc > 2 && action == "extract") {
|
||||
return rust::extract_boot_from_payload(
|
||||
argv[2],
|
||||
argc > 3 ? argv[3] : "",
|
||||
argc > 4 ? argv[4] : ""
|
||||
) ? 0 : 1;
|
||||
} else {
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -102,13 +102,9 @@ fn hex2byte(hex: &[u8]) -> Vec<u8> {
|
||||
v
|
||||
}
|
||||
|
||||
pub fn hexpatch(file: &[u8], from: &[u8], to: &[u8]) -> bool {
|
||||
pub fn hexpatch(file: &mut String, from: &Utf8CStr, to: &Utf8CStr) -> bool {
|
||||
let res: LoggedResult<bool> = try {
|
||||
let file = Utf8CStr::from_bytes(file)?;
|
||||
let from = Utf8CStr::from_bytes(from)?;
|
||||
let to = Utf8CStr::from_bytes(to)?;
|
||||
|
||||
let mut map = MappedFile::open_rw(file)?;
|
||||
let mut map = MappedFile::open_rw(Utf8CStr::from_string(file))?;
|
||||
let pattern = hex2byte(from.as_bytes());
|
||||
let patch = hex2byte(to.as_bytes());
|
||||
|
||||
|
@ -12,7 +12,7 @@ use crate::{
|
||||
proto::update_metadata::{mod_InstallOperation::Type, DeltaArchiveManifest},
|
||||
};
|
||||
use base::{
|
||||
error, ffi::Utf8CStrRef, LoggedError, LoggedResult, ReadSeekExt, ResultExt, Utf8CStr, WriteExt,
|
||||
error, LoggedError, LoggedResult, ReadSeekExt, ResultExt, WriteExt,
|
||||
};
|
||||
|
||||
macro_rules! bad_payload {
|
||||
@ -28,10 +28,10 @@ macro_rules! bad_payload {
|
||||
|
||||
const PAYLOAD_MAGIC: &str = "CrAU";
|
||||
|
||||
fn do_extract_boot_from_payload(
|
||||
in_path: &Utf8CStr,
|
||||
partition_name: Option<&Utf8CStr>,
|
||||
out_path: Option<&Utf8CStr>,
|
||||
pub fn extract_boot_from_payload(
|
||||
in_path: &str,
|
||||
partition_name: Option<&str>,
|
||||
out_path: Option<&str>,
|
||||
) -> LoggedResult<()> {
|
||||
let mut reader = BufReader::new(if in_path == "-" {
|
||||
unsafe { File::from_raw_fd(0) }
|
||||
@ -179,24 +179,3 @@ fn do_extract_boot_from_payload(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn extract_boot_from_payload(
|
||||
in_path: Utf8CStrRef,
|
||||
partition: Utf8CStrRef,
|
||||
out_path: Utf8CStrRef,
|
||||
) -> bool {
|
||||
let res: LoggedResult<()> = try {
|
||||
let partition = if partition.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(partition)
|
||||
};
|
||||
let out_path = if out_path.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(out_path)
|
||||
};
|
||||
do_extract_boot_from_payload(in_path, partition, out_path)?
|
||||
};
|
||||
res.log_with_msg(|w| w.write_str("Failed to extract from payload"))
|
||||
.is_ok()
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user