mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-22 07:57:39 +00:00
Better bytes support in C++
This commit is contained in:
parent
f8c38eab74
commit
5e2ef1b7f4
@ -1,3 +1,4 @@
|
|||||||
|
#include <sys/mman.h>
|
||||||
#include <sys/sendfile.h>
|
#include <sys/sendfile.h>
|
||||||
#include <sys/sysmacros.h>
|
#include <sys/sysmacros.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
@ -433,55 +434,25 @@ sFILE make_file(FILE *fp) {
|
|||||||
return sFILE(fp, [](FILE *fp){ return fp ? fclose(fp) : 1; });
|
return sFILE(fp, [](FILE *fp){ return fp ? fclose(fp) : 1; });
|
||||||
}
|
}
|
||||||
|
|
||||||
int byte_data::patch(str_pairs list) {
|
byte_view::byte_view(string_view s, bool with_nul)
|
||||||
if (_buf == nullptr)
|
: byte_view(static_cast<const void *>(s.data()), s.length()) {
|
||||||
return 0;
|
if (with_nul && s[s.length()] == '\0') {
|
||||||
int count = 0;
|
++_sz;
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int byte_data::patch(byte_pairs list) {
|
bool byte_view::contains(byte_view pattern) const {
|
||||||
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 {
|
|
||||||
if (_buf == nullptr)
|
if (_buf == nullptr)
|
||||||
return false;
|
return false;
|
||||||
for (uint8_t *p = _buf, *eof = _buf + _sz; p < eof; ++p) {
|
for (uint8_t *p = _buf, *eof = _buf + _sz; p < eof; ++p) {
|
||||||
if (memcmp(p, pattern.data(), pattern.length() + 1) == 0) {
|
if (memcmp(p, pattern.buf(), pattern.sz()) == 0) {
|
||||||
LOGD("Found pattern [%s]\n", pattern.data());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
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;
|
return _sz == o._sz && memcmp(_buf, o._buf, _sz) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -496,6 +467,24 @@ heap_data byte_view::clone() const {
|
|||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vector<size_t> byte_data::patch(byte_view from, byte_view to) {
|
||||||
|
vector<size_t> v;
|
||||||
|
if (_buf == nullptr)
|
||||||
|
return v;
|
||||||
|
auto p = _buf;
|
||||||
|
auto eof = _buf + _sz;
|
||||||
|
while (p < eof) {
|
||||||
|
p = static_cast<uint8_t *>(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) {
|
void heap_data::realloc(size_t sz) {
|
||||||
_buf = static_cast<uint8_t *>(::realloc(_buf, sz));
|
_buf = static_cast<uint8_t *>(::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);
|
int fd = xopen(name, (rw ? O_RDWR : O_RDONLY) | O_CLOEXEC);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return;
|
return;
|
||||||
struct stat st;
|
|
||||||
|
run_finally g([=] { close(fd); });
|
||||||
|
struct stat st{};
|
||||||
if (fstat(fd, &st))
|
if (fstat(fd, &st))
|
||||||
return;
|
return;
|
||||||
if (S_ISBLK(st.st_mode)) {
|
if (S_ISBLK(st.st_mode)) {
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
ioctl(fd, BLKGETSIZE64, &size);
|
ioctl(fd, BLKGETSIZE64, &size);
|
||||||
_sz = size;
|
init(fd, size, rw);
|
||||||
} else {
|
} 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;
|
: nullptr;
|
||||||
close(fd);
|
|
||||||
_buf = static_cast<uint8_t *>(b);
|
_buf = static_cast<uint8_t *>(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mmap_data::~mmap_data() {
|
||||||
|
if (_buf)
|
||||||
|
munmap(_buf, _sz);
|
||||||
|
}
|
||||||
|
|
||||||
string find_apk_path(const char *pkg) {
|
string find_apk_path(const char *pkg) {
|
||||||
char buf[PATH_MAX];
|
char buf[PATH_MAX];
|
||||||
size_t len = strlen(pkg);
|
size_t len = strlen(pkg);
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <mntent.h>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -48,38 +46,44 @@ struct heap_data;
|
|||||||
struct byte_view {
|
struct byte_view {
|
||||||
byte_view() : _buf(nullptr), _sz(0) {}
|
byte_view() : _buf(nullptr), _sz(0) {}
|
||||||
byte_view(const void *buf, size_t sz) : _buf((uint8_t *) buf), _sz(sz) {}
|
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<uint8_t> &v) : byte_view(v.data(), v.size()) {}
|
byte_view(const std::vector<uint8_t> &v) : byte_view(v.data(), v.size()) {}
|
||||||
|
|
||||||
const uint8_t *buf() const { return _buf; }
|
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 contains(byte_view pattern) const;
|
||||||
bool equals(const byte_view &o) const;
|
bool equals(byte_view o) const;
|
||||||
heap_data clone() const;
|
heap_data clone() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint8_t *_buf;
|
uint8_t *_buf;
|
||||||
size_t _sz;
|
size_t _sz;
|
||||||
|
|
||||||
byte_view(uint8_t *buf, size_t sz) : _buf(buf), _sz(sz) {}
|
|
||||||
void swap(byte_view &o);
|
void swap(byte_view &o);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct byte_data : public byte_view {
|
struct byte_data : public byte_view {
|
||||||
using str_pairs = std::initializer_list<std::pair<std::string_view, std::string_view>>;
|
|
||||||
using byte_pairs = std::initializer_list<std::pair<byte_view, byte_view>>;
|
|
||||||
|
|
||||||
byte_data() = default;
|
byte_data() = default;
|
||||||
byte_data(void *buf, size_t sz) : byte_view(static_cast<uint8_t *>(buf), sz) {}
|
byte_data(void *buf, size_t sz) : byte_view(buf, sz) {}
|
||||||
|
|
||||||
using byte_view::buf;
|
using byte_view::buf;
|
||||||
using byte_view::sz;
|
using byte_view::sz;
|
||||||
uint8_t *buf() { return _buf; }
|
uint8_t *buf() { return _buf; }
|
||||||
size_t &sz() { return _sz; }
|
size_t &sz() { return _sz; }
|
||||||
|
|
||||||
int patch(str_pairs list);
|
std::vector<size_t> patch(byte_view from, byte_view to);
|
||||||
int patch(byte_pairs list);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MOVE_ONLY(clazz) \
|
#define MOVE_ONLY(clazz) \
|
||||||
@ -92,7 +96,6 @@ struct heap_data : public byte_data {
|
|||||||
MOVE_ONLY(heap_data)
|
MOVE_ONLY(heap_data)
|
||||||
|
|
||||||
explicit heap_data(size_t sz) : byte_data(malloc(sz), sz) {}
|
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); }
|
~heap_data() { free(_buf); }
|
||||||
|
|
||||||
void realloc(size_t sz);
|
void realloc(size_t sz);
|
||||||
@ -101,8 +104,11 @@ struct heap_data : public byte_data {
|
|||||||
struct mmap_data : public byte_data {
|
struct mmap_data : public byte_data {
|
||||||
MOVE_ONLY(mmap_data)
|
MOVE_ONLY(mmap_data)
|
||||||
|
|
||||||
mmap_data(const char *name, bool rw = false);
|
explicit mmap_data(const char *name, bool rw = false);
|
||||||
~mmap_data() { if (_buf) munmap(_buf, _sz); }
|
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" {
|
extern "C" {
|
||||||
|
@ -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) : 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()) {}
|
mode(mode), uid(0), gid(0), data(data.clone()) {}
|
||||||
|
|
||||||
cpio_entry::cpio_entry(const cpio_newc_header *h) :
|
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) {
|
void cpio::ln(const char *target, const char *name) {
|
||||||
byte_view link(target);
|
auto e = new cpio_entry(S_IFLNK, {target, false});
|
||||||
auto e = new cpio_entry(S_IFLNK, link);
|
|
||||||
insert(name, e);
|
insert(name, e);
|
||||||
fprintf(stderr, "Create symlink [%s] -> [%s]\n", name, target);
|
fprintf(stderr, "Create symlink [%s] -> [%s]\n", name, target);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ struct cpio_entry {
|
|||||||
heap_data data;
|
heap_data data;
|
||||||
|
|
||||||
explicit cpio_entry(uint32_t mode);
|
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);
|
explicit cpio_entry(const cpio_newc_header *h);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -223,7 +223,7 @@ static bool fdt_patch(void *fdt) {
|
|||||||
// Force remove AVB for 2SI since it may bootloop some devices
|
// Force remove AVB for 2SI since it may bootloop some devices
|
||||||
int len;
|
int len;
|
||||||
const void *value = fdt_getprop(fdt, node, "fsmgr_flags", &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)) {
|
if (patch_verity(copy)) {
|
||||||
modified = true;
|
modified = true;
|
||||||
fdt_setprop(fdt, node, "fsmgr_flags", copy.buf(), copy.sz());
|
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);
|
total_size += xwrite(fd, buf, dtb_map.begin()->first);
|
||||||
|
|
||||||
// mmap rw to patch table values retroactively
|
// mmap rw to patch table values retroactively
|
||||||
auto mmap_sz = lseek(fd, 0, SEEK_CUR);
|
mmap_data m(fd, lseek(fd, 0, SEEK_CUR), true);
|
||||||
auto addr = (uint8_t *) xmmap(nullptr, mmap_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
|
||||||
|
|
||||||
// Guess alignment using gcd
|
// Guess alignment using gcd
|
||||||
uint32_t align = 1;
|
uint32_t align = 1;
|
||||||
@ -319,17 +318,16 @@ static bool dt_table_patch(const Header *hdr, const char *out) {
|
|||||||
|
|
||||||
// Patch headers
|
// Patch headers
|
||||||
if constexpr (is_aosp) {
|
if constexpr (is_aosp) {
|
||||||
auto hdr_rw = reinterpret_cast<Header *>(addr);
|
auto hdr_rw = reinterpret_cast<Header *>(m.buf());
|
||||||
hdr_rw->total_size = le_to_be(total_size);
|
hdr_rw->total_size = le_to_be(total_size);
|
||||||
}
|
}
|
||||||
auto tables_rw = reinterpret_cast<Table *>(addr + sizeof(Header));
|
auto tables_rw = reinterpret_cast<Table *>(m.buf() + sizeof(Header));
|
||||||
for (int i = 0; i < num_dtb; ++i) {
|
for (int i = 0; i < num_dtb; ++i) {
|
||||||
auto &blob = dtb_map[be_to_le(tables_rw[i].offset)];
|
auto &blob = dtb_map[be_to_le(tables_rw[i].offset)];
|
||||||
tables_rw[i].offset = le_to_be(blob.offset);
|
tables_rw[i].offset = le_to_be(blob.offset);
|
||||||
tables_rw[i].len = le_to_be(blob.len);
|
tables_rw[i].len = le_to_be(blob.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
munmap(addr, mmap_sz);
|
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -20,5 +20,9 @@ int hexpatch(const char *file, string_view from, string_view to) {
|
|||||||
hex2byte(from, pattern.data());
|
hex2byte(from, pattern.data());
|
||||||
hex2byte(to, patch.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;
|
||||||
}
|
}
|
||||||
|
@ -186,8 +186,7 @@ void magisk_cpio::backup(const char *orig) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!rm_list.empty()) {
|
if (!rm_list.empty()) {
|
||||||
byte_view rm(rm_list);
|
auto rm_list_file = new cpio_entry(S_IFREG, {rm_list, false});
|
||||||
auto rm_list_file = new cpio_entry(S_IFREG, rm);
|
|
||||||
backups.emplace(".backup/.rmlist", rm_list_file);
|
backups.emplace(".backup/.rmlist", rm_list_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include <sys/mman.h>
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
@ -244,7 +244,9 @@ void MagiskInit::patch_ro_root() {
|
|||||||
int src = xopen("/init", O_RDONLY | O_CLOEXEC);
|
int src = xopen("/init", O_RDONLY | O_CLOEXEC);
|
||||||
mmap_data init("/init");
|
mmap_data init("/init");
|
||||||
// Force disable early mount on original 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);
|
int dest = xopen(ROOTOVL "/init", O_CREAT | O_WRONLY | O_CLOEXEC, 0);
|
||||||
xwrite(dest, init.buf(), init.sz());
|
xwrite(dest, init.buf(), init.sz());
|
||||||
fclone_attr(src, dest);
|
fclone_attr(src, dest);
|
||||||
|
@ -13,7 +13,9 @@ void FirstStageInit::prepare() {
|
|||||||
restore_ramdisk_init();
|
restore_ramdisk_init();
|
||||||
auto init = mmap_data("/init", true);
|
auto init = mmap_data("/init", true);
|
||||||
// Redirect original init to magiskinit
|
// 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() {
|
void LegacySARInit::first_stage_prep() {
|
||||||
@ -22,7 +24,9 @@ void LegacySARInit::first_stage_prep() {
|
|||||||
int dest = xopen("/data/init", O_CREAT | O_WRONLY, 0);
|
int dest = xopen("/data/init", O_CREAT | O_WRONLY, 0);
|
||||||
{
|
{
|
||||||
mmap_data init("/init");
|
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());
|
write(dest, init.buf(), init.sz());
|
||||||
fclone_attr(src, dest);
|
fclone_attr(src, dest);
|
||||||
close(dest);
|
close(dest);
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include <sys/mman.h>
|
||||||
#include "memory.hpp"
|
#include "memory.hpp"
|
||||||
|
|
||||||
namespace jni_hook {
|
namespace jni_hook {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <sys/mman.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user