diff --git a/native/src/Android.mk b/native/src/Android.mk index a8b31cf3c..0b691ba84 100644 --- a/native/src/Android.mk +++ b/native/src/Android.mk @@ -111,7 +111,6 @@ LOCAL_STATIC_LIBRARIES := \ LOCAL_SRC_FILES := \ boot/main.cpp \ boot/bootimg.cpp \ - boot/hexpatch.cpp \ boot/compress.cpp \ boot/format.cpp \ boot/dtb.cpp \ diff --git a/native/src/base/files.hpp b/native/src/base/files.hpp index 043d46847..4610ffc29 100644 --- a/native/src/base/files.hpp +++ b/native/src/base/files.hpp @@ -58,7 +58,6 @@ bool frm_rf(int dirfd); } // extern "C" -using rust::fd_path; int fd_pathat(int dirfd, const char *name, char *path, size_t size); void mv_path(const char *src, const char *dest); void mv_dir(int src, int dest); diff --git a/native/src/base/include/base.hpp b/native/src/base/include/base.hpp index 2b57e5dcf..7ca70dc5f 100644 --- a/native/src/base/include/base.hpp +++ b/native/src/base/include/base.hpp @@ -6,3 +6,6 @@ #include "../logging.hpp" #include "../missing.hpp" #include "../base-rs.hpp" + +using rust::xpipe2; +using rust::fd_path; \ No newline at end of file diff --git a/native/src/base/lib.rs b/native/src/base/lib.rs index 6104b601e..5d2dbc9ce 100644 --- a/native/src/base/lib.rs +++ b/native/src/base/lib.rs @@ -26,6 +26,11 @@ pub mod ffi { Debug, } + unsafe extern "C++" { + include!("misc.hpp"); + fn mut_u8_patch(buf: &mut [u8], from: &[u8], to: &[u8]) -> Vec; + } + extern "Rust" { fn log_with_rs(level: LogLevel, msg: &[u8]); fn exit_on_error(b: bool); diff --git a/native/src/base/misc.cpp b/native/src/base/misc.cpp index 1aec02d05..313d136b6 100644 --- a/native/src/base/misc.cpp +++ b/native/src/base/misc.cpp @@ -32,8 +32,8 @@ void byte_data::swap(byte_data &o) { std::swap(_sz, o._sz); } -vector byte_data::patch(byte_view from, byte_view to) { - vector v; +rust::Vec byte_data::patch(byte_view from, byte_view to) { + rust::Vec v; if (_buf == nullptr) return v; auto p = _buf; @@ -50,6 +50,14 @@ vector byte_data::patch(byte_view from, byte_view to) { return v; } +rust::Vec mut_u8_patch( + rust::Slice buf, + rust::Slice from, + rust::Slice to) { + byte_data data(buf); + return data.patch(from, to); +} + int fork_dont_care() { if (int pid = xfork()) { waitpid(pid, nullptr, 0); diff --git a/native/src/base/misc.hpp b/native/src/base/misc.hpp index f82b54499..8374cedad 100644 --- a/native/src/base/misc.hpp +++ b/native/src/base/misc.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "xwrap.hpp" @@ -195,7 +196,7 @@ struct byte_data : public byte_view { uint8_t *buf() { return _buf; } void swap(byte_data &o); - std::vector patch(byte_view from, byte_view to); + rust::Vec patch(byte_view from, byte_view to); }; template @@ -217,6 +218,11 @@ struct heap_data : public byte_data { friend byte_channel; }; +rust::Vec mut_u8_patch( + rust::Slice buf, + rust::Slice from, + rust::Slice to); + uint64_t parse_uint64_hex(std::string_view s); int parse_int(std::string_view s); diff --git a/native/src/base/misc.rs b/native/src/base/misc.rs index e9cceb536..869c41d85 100644 --- a/native/src/base/misc.rs +++ b/native/src/base/misc.rs @@ -9,6 +9,8 @@ use std::{fmt, io, slice, str}; use libc::c_char; use thiserror::Error; +use crate::ffi; + pub fn copy_str>(dest: &mut [u8], src: T) -> usize { let src = src.as_ref(); let len = min(src.len(), dest.len() - 1); @@ -346,3 +348,13 @@ impl LibcReturn for *mut T { self.is_null() } } + +pub trait MutBytesExt { + fn patch(&mut self, from: &[u8], to: &[u8]) -> Vec; +} + +impl> MutBytesExt for T { + fn patch(&mut self, from: &[u8], to: &[u8]) -> Vec { + ffi::mut_u8_patch(self.as_mut(), from, to) + } +} diff --git a/native/src/base/xwrap.hpp b/native/src/base/xwrap.hpp index 490ce517d..ce7a6dda8 100644 --- a/native/src/base/xwrap.hpp +++ b/native/src/base/xwrap.hpp @@ -5,10 +5,6 @@ #include #include -#include "base-rs.hpp" - -using rust::xpipe2; - extern "C" { FILE *xfopen(const char *pathname, const char *mode); diff --git a/native/src/boot/hexpatch.cpp b/native/src/boot/hexpatch.cpp deleted file mode 100644 index d61cff961..000000000 --- a/native/src/boot/hexpatch.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "magiskboot.hpp" - -using namespace std; - -static void hex2byte(string_view hex, uint8_t *buf) { - char high, low; - for (int i = 0, length = hex.length(); i < length; i += 2) { - high = toupper(hex[i]) - '0'; - low = toupper(hex[i + 1]) - '0'; - buf[i / 2] = ((high > 9 ? high - 7 : high) << 4) + (low > 9 ? low - 7 : low); - } -} - -int hexpatch(const char *file, string_view from, string_view to) { - mmap_data m(file, true); - - vector pattern(from.length() / 2); - vector patch(to.length() / 2); - - hex2byte(from, pattern.data()); - hex2byte(to, patch.data()); - - auto v = m.patch(pattern, patch); - for (size_t off : v) { - fprintf(stderr, "Patch @ %08zX [%s] -> [%s]\n", off, from.data(), to.data()); - } - return v.empty() ? 1 : 0; -} diff --git a/native/src/boot/lib.rs b/native/src/boot/lib.rs index 553f18951..6f14d0318 100644 --- a/native/src/boot/lib.rs +++ b/native/src/boot/lib.rs @@ -3,9 +3,11 @@ pub use base; use cpio::*; +use patch::*; use payload::*; mod cpio; +mod patch; mod payload; // Suppress warnings in generated code #[allow(warnings)] @@ -31,5 +33,6 @@ pub mod ffi { ) -> bool; unsafe fn cpio_commands(argc: i32, argv: *const *const c_char) -> bool; + fn hexpatch(file: &[u8], from: &[u8], to: &[u8]) -> bool; } } diff --git a/native/src/boot/magiskboot.hpp b/native/src/boot/magiskboot.hpp index 699b4fdbf..bccdd0f1c 100644 --- a/native/src/boot/magiskboot.hpp +++ b/native/src/boot/magiskboot.hpp @@ -17,7 +17,6 @@ int unpack(const char *image, bool skip_decomp = false, bool hdr = false); void repack(const char *src_img, const char *out_img, bool skip_comp = false); int split_image_dtb(const char *filename); -int hexpatch(const char *file, std::string_view from, std::string_view to); int dtb_commands(int argc, char *argv[]); size_t patch_verity(rust::Slice data); diff --git a/native/src/boot/main.cpp b/native/src/boot/main.cpp index 6465b74f3..9a43d06a1 100644 --- a/native/src/boot/main.cpp +++ b/native/src/boot/main.cpp @@ -200,7 +200,7 @@ int main(int argc, char *argv[]) { } 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(argv[2], argv[3], argv[4]); + return rust::hexpatch(byte_view(argv[2]), byte_view(argv[3]), byte_view(argv[4])) ? 0 : 1; } else if (argc > 2 && action == "cpio"sv) { if (!rust::cpio_commands(argc - 2, argv + 2)) usage(argv[0]); diff --git a/native/src/boot/patch.rs b/native/src/boot/patch.rs new file mode 100644 index 000000000..817e07543 --- /dev/null +++ b/native/src/boot/patch.rs @@ -0,0 +1,37 @@ +use base::{MappedFile, MutBytesExt, ResultExt, Utf8CStr}; + +fn hex2byte(hex: &[u8]) -> Vec { + let mut v = Vec::new(); + v.reserve(hex.len() / 2); + for bytes in hex.chunks(2) { + if bytes.len() != 2 { + break; + } + let high = bytes[0].to_ascii_uppercase() - b'0'; + let low = bytes[1].to_ascii_uppercase() - b'0'; + let h = if high > 9 { high - 7 } else { high }; + let l = if low > 9 { low - 7 } else { low }; + v.push(h << 4 | l); + } + v +} + +pub fn hexpatch(file: &[u8], from: &[u8], to: &[u8]) -> bool { + fn inner(file: &[u8], from: &[u8], to: &[u8]) -> anyhow::Result { + 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 pattern = hex2byte(from.as_bytes()); + let patch = hex2byte(to.as_bytes()); + + let v = map.patch(pattern.as_slice(), patch.as_slice()); + for off in &v { + eprintln!("Patch @ {:#010X} [{}] -> [{}]", off, from, to); + } + + Ok(!v.is_empty()) + } + inner(file, from, to).log().unwrap_or(false) +}