diff --git a/native/src/base/files.cpp b/native/src/base/files.cpp index 0bf8b801f..9c53e7603 100644 --- a/native/src/base/files.cpp +++ b/native/src/base/files.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -433,55 +434,25 @@ sFILE make_file(FILE *fp) { return sFILE(fp, [](FILE *fp){ return fp ? fclose(fp) : 1; }); } -int byte_data::patch(str_pairs list) { - if (_buf == nullptr) - return 0; - int count = 0; - for (uint8_t *p = _buf, *eof = _buf + _sz; p < eof; ++p) { - for (auto &[from, to] : list) { - if (memcmp(p, from.data(), from.length() + 1) == 0) { - LOGD("Patch @ %08X [%s] -> [%s]\n", (unsigned)(p - _buf), from.data(), to.data()); - memset(p, 0, from.length()); - memcpy(p, to.data(), to.length()); - ++count; - p += from.length(); - } - } +byte_view::byte_view(string_view s, bool with_nul) +: byte_view(static_cast(s.data()), s.length()) { + if (with_nul && s[s.length()] == '\0') { + ++_sz; } - return count; } -int byte_data::patch(byte_pairs list) { - if (_buf == nullptr) - return 0; - int count = 0; - for (uint8_t *p = _buf, *eof = _buf + _sz; p < eof; ++p) { - for (auto &[from, to] : list) { - if (memcmp(p, from.buf(), from.sz()) == 0) { - LOGD("Patch @ %08X\n", (unsigned)(p - _buf)); - memset(p, 0, from.sz()); - memcpy(p, to.buf(), to.sz()); - ++count; - p += from.sz(); - } - } - } - return count; -} - -bool byte_view::contains(string_view pattern) const { +bool byte_view::contains(byte_view pattern) const { if (_buf == nullptr) return false; for (uint8_t *p = _buf, *eof = _buf + _sz; p < eof; ++p) { - if (memcmp(p, pattern.data(), pattern.length() + 1) == 0) { - LOGD("Found pattern [%s]\n", pattern.data()); + if (memcmp(p, pattern.buf(), pattern.sz()) == 0) { return true; } } return false; } -bool byte_view::equals(const byte_view &o) const { +bool byte_view::equals(byte_view o) const { return _sz == o._sz && memcmp(_buf, o._buf, _sz) == 0; } @@ -496,6 +467,24 @@ heap_data byte_view::clone() const { return copy; } +vector byte_data::patch(byte_view from, byte_view to) { + vector v; + if (_buf == nullptr) + return v; + auto p = _buf; + auto eof = _buf + _sz; + while (p < eof) { + p = static_cast(memmem(p, eof - p, from.buf(), from.sz())); + if (p == nullptr) + return v; + memset(p, 0, from.sz()); + memcpy(p, to.buf(), to.sz()); + v.push_back(p - _buf); + p += from.sz(); + } + return v; +} + void heap_data::realloc(size_t sz) { _buf = static_cast(::realloc(_buf, sz)); } @@ -504,23 +493,33 @@ mmap_data::mmap_data(const char *name, bool rw) { int fd = xopen(name, (rw ? O_RDWR : O_RDONLY) | O_CLOEXEC); if (fd < 0) return; - struct stat st; + + run_finally g([=] { close(fd); }); + struct stat st{}; if (fstat(fd, &st)) return; if (S_ISBLK(st.st_mode)) { uint64_t size; ioctl(fd, BLKGETSIZE64, &size); - _sz = size; + init(fd, size, rw); } else { - _sz = st.st_size; + init(fd, st.st_size, rw); } - void *b = _sz > 0 - ? xmmap(nullptr, _sz, PROT_READ | PROT_WRITE, rw ? MAP_SHARED : MAP_PRIVATE, fd, 0) +} + +void mmap_data::init(int fd, size_t sz, bool rw) { + _sz = sz; + void *b = sz > 0 + ? xmmap(nullptr, sz, PROT_READ | PROT_WRITE, rw ? MAP_SHARED : MAP_PRIVATE, fd, 0) : nullptr; - close(fd); _buf = static_cast(b); } +mmap_data::~mmap_data() { + if (_buf) + munmap(_buf, _sz); +} + string find_apk_path(const char *pkg) { char buf[PATH_MAX]; size_t len = strlen(pkg); diff --git a/native/src/base/files.hpp b/native/src/base/files.hpp index 89993e837..bb3713ae3 100644 --- a/native/src/base/files.hpp +++ b/native/src/base/files.hpp @@ -1,8 +1,6 @@ #pragma once -#include #include -#include #include #include #include @@ -48,38 +46,44 @@ struct heap_data; struct byte_view { byte_view() : _buf(nullptr), _sz(0) {} byte_view(const void *buf, size_t sz) : _buf((uint8_t *) buf), _sz(sz) {} - byte_view(std::string_view str) : byte_view(str.data(), str.length()) {} + + // byte_view, or any of its sub-type, can be copied as byte_view + byte_view(const byte_view &o) : _buf(o._buf), _sz(o._sz) {} + + // String as bytes + byte_view(std::string_view s, bool with_nul = true); + byte_view(const char *s, bool with_nul = true) + : byte_view(std::string_view(s), with_nul) {} + byte_view(const std::string &s, bool with_nul = true) + : byte_view(std::string_view(s), with_nul) {} + + // Vector as bytes byte_view(const std::vector &v) : byte_view(v.data(), v.size()) {} const uint8_t *buf() const { return _buf; } - const size_t &sz() const { return _sz; } + size_t sz() const { return _sz; } - bool contains(std::string_view pattern) const; - bool equals(const byte_view &o) const; + bool contains(byte_view pattern) const; + bool equals(byte_view o) const; heap_data clone() const; protected: uint8_t *_buf; size_t _sz; - byte_view(uint8_t *buf, size_t sz) : _buf(buf), _sz(sz) {} void swap(byte_view &o); }; struct byte_data : public byte_view { - using str_pairs = std::initializer_list>; - using byte_pairs = std::initializer_list>; - byte_data() = default; - byte_data(void *buf, size_t sz) : byte_view(static_cast(buf), sz) {} + byte_data(void *buf, size_t sz) : byte_view(buf, sz) {} using byte_view::buf; using byte_view::sz; uint8_t *buf() { return _buf; } size_t &sz() { return _sz; } - int patch(str_pairs list); - int patch(byte_pairs list); + std::vector patch(byte_view from, byte_view to); }; #define MOVE_ONLY(clazz) \ @@ -92,7 +96,6 @@ struct heap_data : public byte_data { MOVE_ONLY(heap_data) explicit heap_data(size_t sz) : byte_data(malloc(sz), sz) {} - heap_data(const void *buf, size_t sz) : heap_data(sz) { memcpy(_buf, buf, sz); } ~heap_data() { free(_buf); } void realloc(size_t sz); @@ -101,8 +104,11 @@ struct heap_data : public byte_data { struct mmap_data : public byte_data { MOVE_ONLY(mmap_data) - mmap_data(const char *name, bool rw = false); - ~mmap_data() { if (_buf) munmap(_buf, _sz); } + explicit mmap_data(const char *name, bool rw = false); + mmap_data(int fd, size_t sz, bool rw = false) { init(fd, sz, rw); } + ~mmap_data(); +private: + void init(int fd, size_t sz, bool rw); }; extern "C" { diff --git a/native/src/boot/cpio.cpp b/native/src/boot/cpio.cpp index 33448dfff..b933f68a1 100644 --- a/native/src/boot/cpio.cpp +++ b/native/src/boot/cpio.cpp @@ -45,7 +45,7 @@ static uint32_t x8u(const char *hex) { cpio_entry::cpio_entry(uint32_t mode) : mode(mode), uid(0), gid(0), data(0) {} -cpio_entry::cpio_entry(uint32_t mode, const byte_view &data) : +cpio_entry::cpio_entry(uint32_t mode, byte_view data) : mode(mode), uid(0), gid(0), data(data.clone()) {} cpio_entry::cpio_entry(const cpio_newc_header *h) : @@ -187,8 +187,7 @@ void cpio::mkdir(mode_t mode, const char *name) { } void cpio::ln(const char *target, const char *name) { - byte_view link(target); - auto e = new cpio_entry(S_IFLNK, link); + auto e = new cpio_entry(S_IFLNK, {target, false}); insert(name, e); fprintf(stderr, "Create symlink [%s] -> [%s]\n", name, target); } diff --git a/native/src/boot/cpio.hpp b/native/src/boot/cpio.hpp index 10e8ce5cd..4a03dfe8d 100644 --- a/native/src/boot/cpio.hpp +++ b/native/src/boot/cpio.hpp @@ -17,7 +17,7 @@ struct cpio_entry { heap_data data; explicit cpio_entry(uint32_t mode); - explicit cpio_entry(uint32_t mode, const byte_view &data); + explicit cpio_entry(uint32_t mode, byte_view data); explicit cpio_entry(const cpio_newc_header *h); }; diff --git a/native/src/boot/dtb.cpp b/native/src/boot/dtb.cpp index 5eb0ee551..bb95f4aac 100644 --- a/native/src/boot/dtb.cpp +++ b/native/src/boot/dtb.cpp @@ -223,7 +223,7 @@ static bool fdt_patch(void *fdt) { // Force remove AVB for 2SI since it may bootloop some devices int len; const void *value = fdt_getprop(fdt, node, "fsmgr_flags", &len); - heap_data copy(value, len); + heap_data copy = byte_view(value, len).clone(); if (patch_verity(copy)) { modified = true; fdt_setprop(fdt, node, "fsmgr_flags", copy.buf(), copy.sz()); @@ -291,8 +291,7 @@ static bool dt_table_patch(const Header *hdr, const char *out) { total_size += xwrite(fd, buf, dtb_map.begin()->first); // mmap rw to patch table values retroactively - auto mmap_sz = lseek(fd, 0, SEEK_CUR); - auto addr = (uint8_t *) xmmap(nullptr, mmap_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + mmap_data m(fd, lseek(fd, 0, SEEK_CUR), true); // Guess alignment using gcd uint32_t align = 1; @@ -319,17 +318,16 @@ static bool dt_table_patch(const Header *hdr, const char *out) { // Patch headers if constexpr (is_aosp) { - auto hdr_rw = reinterpret_cast
(addr); + auto hdr_rw = reinterpret_cast
(m.buf()); hdr_rw->total_size = le_to_be(total_size); } - auto tables_rw = reinterpret_cast(addr + sizeof(Header)); + auto tables_rw = reinterpret_cast
(m.buf() + sizeof(Header)); for (int i = 0; i < num_dtb; ++i) { auto &blob = dtb_map[be_to_le(tables_rw[i].offset)]; tables_rw[i].offset = le_to_be(blob.offset); tables_rw[i].len = le_to_be(blob.len); } - munmap(addr, mmap_sz); close(fd); return true; diff --git a/native/src/boot/hexpatch.cpp b/native/src/boot/hexpatch.cpp index 504c90138..d61cff961 100644 --- a/native/src/boot/hexpatch.cpp +++ b/native/src/boot/hexpatch.cpp @@ -20,5 +20,9 @@ int hexpatch(const char *file, string_view from, string_view to) { hex2byte(from, pattern.data()); hex2byte(to, patch.data()); - return m.patch({ make_pair(pattern, patch) }) > 0 ? 0 : 1; + 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/ramdisk.cpp b/native/src/boot/ramdisk.cpp index dfaecdcf5..5d3102721 100644 --- a/native/src/boot/ramdisk.cpp +++ b/native/src/boot/ramdisk.cpp @@ -186,8 +186,7 @@ void magisk_cpio::backup(const char *orig) { } if (!rm_list.empty()) { - byte_view rm(rm_list); - auto rm_list_file = new cpio_entry(S_IFREG, rm); + auto rm_list_file = new cpio_entry(S_IFREG, {rm_list, false}); backups.emplace(".backup/.rmlist", rm_list_file); } diff --git a/native/src/core/module.cpp b/native/src/core/module.cpp index 2e2e91b59..b06d2c1a8 100644 --- a/native/src/core/module.cpp +++ b/native/src/core/module.cpp @@ -1,3 +1,4 @@ +#include #include #include #include diff --git a/native/src/init/rootdir.cpp b/native/src/init/rootdir.cpp index 5a018e60e..99dabb1fd 100644 --- a/native/src/init/rootdir.cpp +++ b/native/src/init/rootdir.cpp @@ -244,7 +244,9 @@ void MagiskInit::patch_ro_root() { int src = xopen("/init", O_RDONLY | O_CLOEXEC); mmap_data init("/init"); // Force disable early mount on original init - init.patch({ make_pair("android,fstab", "xxx") }); + for (size_t off : init.patch("android,fstab", "xxx")) { + LOGD("Patch @ %08zX [android,fstab] -> [xxx]\n", off); + } int dest = xopen(ROOTOVL "/init", O_CREAT | O_WRONLY | O_CLOEXEC, 0); xwrite(dest, init.buf(), init.sz()); fclone_attr(src, dest); diff --git a/native/src/init/twostage.cpp b/native/src/init/twostage.cpp index 53e84d1ec..0e1079709 100644 --- a/native/src/init/twostage.cpp +++ b/native/src/init/twostage.cpp @@ -13,7 +13,9 @@ void FirstStageInit::prepare() { restore_ramdisk_init(); auto init = mmap_data("/init", true); // Redirect original init to magiskinit - init.patch({ make_pair(INIT_PATH, REDIR_PATH) }); + for (size_t off : init.patch(INIT_PATH, REDIR_PATH)) { + LOGD("Patch @ %08zX [" INIT_PATH "] -> [" REDIR_PATH "]\n", off); + } } void LegacySARInit::first_stage_prep() { @@ -22,7 +24,9 @@ void LegacySARInit::first_stage_prep() { int dest = xopen("/data/init", O_CREAT | O_WRONLY, 0); { mmap_data init("/init"); - init.patch({ make_pair(INIT_PATH, REDIR_PATH) }); + for (size_t off : init.patch(INIT_PATH, REDIR_PATH)) { + LOGD("Patch @ %08zX [" INIT_PATH "] -> [" REDIR_PATH "]\n", off); + } write(dest, init.buf(), init.sz()); fclone_attr(src, dest); close(dest); diff --git a/native/src/zygisk/memory.cpp b/native/src/zygisk/memory.cpp index ed928d302..0b4158fcf 100644 --- a/native/src/zygisk/memory.cpp +++ b/native/src/zygisk/memory.cpp @@ -1,3 +1,4 @@ +#include #include "memory.hpp" namespace jni_hook { diff --git a/native/src/zygisk/zygisk.hpp b/native/src/zygisk/zygisk.hpp index 78f8de3d0..58ebffb12 100644 --- a/native/src/zygisk/zygisk.hpp +++ b/native/src/zygisk/zygisk.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include