Move hexpatch to Rust

This commit is contained in:
topjohnwu 2023-06-20 18:17:26 -07:00
parent 5805573625
commit 399b9e5eba
13 changed files with 78 additions and 39 deletions

View File

@ -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 \

View File

@ -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);

View File

@ -6,3 +6,6 @@
#include "../logging.hpp"
#include "../missing.hpp"
#include "../base-rs.hpp"
using rust::xpipe2;
using rust::fd_path;

View File

@ -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<usize>;
}
extern "Rust" {
fn log_with_rs(level: LogLevel, msg: &[u8]);
fn exit_on_error(b: bool);

View File

@ -32,8 +32,8 @@ void byte_data::swap(byte_data &o) {
std::swap(_sz, o._sz);
}
vector<size_t> byte_data::patch(byte_view from, byte_view to) {
vector<size_t> v;
rust::Vec<size_t> byte_data::patch(byte_view from, byte_view to) {
rust::Vec<size_t> v;
if (_buf == nullptr)
return v;
auto p = _buf;
@ -50,6 +50,14 @@ vector<size_t> byte_data::patch(byte_view from, byte_view to) {
return v;
}
rust::Vec<size_t> mut_u8_patch(
rust::Slice<uint8_t> buf,
rust::Slice<const uint8_t> from,
rust::Slice<const uint8_t> to) {
byte_data data(buf);
return data.patch(from, to);
}
int fork_dont_care() {
if (int pid = xfork()) {
waitpid(pid, nullptr, 0);

View File

@ -6,6 +6,7 @@
#include <string_view>
#include <bitset>
#include <random>
#include <cxx.h>
#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<size_t> patch(byte_view from, byte_view to);
rust::Vec<size_t> patch(byte_view from, byte_view to);
};
template<size_t N>
@ -217,6 +218,11 @@ struct heap_data : public byte_data {
friend byte_channel;
};
rust::Vec<size_t> mut_u8_patch(
rust::Slice<uint8_t> buf,
rust::Slice<const uint8_t> from,
rust::Slice<const uint8_t> to);
uint64_t parse_uint64_hex(std::string_view s);
int parse_int(std::string_view s);

View File

@ -9,6 +9,8 @@ use std::{fmt, io, slice, str};
use libc::c_char;
use thiserror::Error;
use crate::ffi;
pub fn copy_str<T: AsRef<[u8]>>(dest: &mut [u8], src: T) -> usize {
let src = src.as_ref();
let len = min(src.len(), dest.len() - 1);
@ -346,3 +348,13 @@ impl<T> LibcReturn for *mut T {
self.is_null()
}
}
pub trait MutBytesExt {
fn patch(&mut self, from: &[u8], to: &[u8]) -> Vec<usize>;
}
impl<T: AsMut<[u8]>> MutBytesExt for T {
fn patch(&mut self, from: &[u8], to: &[u8]) -> Vec<usize> {
ffi::mut_u8_patch(self.as_mut(), from, to)
}
}

View File

@ -5,10 +5,6 @@
#include <poll.h>
#include <fcntl.h>
#include "base-rs.hpp"
using rust::xpipe2;
extern "C" {
FILE *xfopen(const char *pathname, const char *mode);

View File

@ -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<uint8_t> pattern(from.length() / 2);
vector<uint8_t> 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;
}

View File

@ -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;
}
}

View File

@ -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<uint8_t> data);

View File

@ -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]);

37
native/src/boot/patch.rs Normal file
View File

@ -0,0 +1,37 @@
use base::{MappedFile, MutBytesExt, ResultExt, Utf8CStr};
fn hex2byte(hex: &[u8]) -> Vec<u8> {
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<bool> {
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)
}