You've already forked ReZygisk
mirror of
https://github.com/PerformanC/ReZygisk.git
synced 2025-09-06 06:37:01 +00:00
Replace native bridge with fuse + ptrace
This commit is contained in:
@@ -13,16 +13,7 @@ LOCAL_LDLIBS := -llog
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := zygisk_loader
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
|
||||
FILE_LIST := $(filter %.cpp, $(call walk, $(LOCAL_PATH)/loader))
|
||||
LOCAL_SRC_FILES := $(FILE_LIST:COMMON_FILE_LIST:$(LOCAL_PATH)/%=%)
|
||||
LOCAL_STATIC_LIBRARIES := cxx common
|
||||
LOCAL_LDLIBS := -llog
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := zygisk_injector
|
||||
LOCAL_MODULE := zygisk
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
|
||||
FILE_LIST := $(filter %.cpp, $(call walk, $(LOCAL_PATH)/injector))
|
||||
LOCAL_SRC_FILES := $(FILE_LIST:COMMON_FILE_LIST:$(LOCAL_PATH)/%=%)
|
||||
|
||||
@@ -8,32 +8,14 @@
|
||||
|
||||
namespace zygiskd {
|
||||
|
||||
bool sMagicRead = false;
|
||||
static std::string sSocketName;
|
||||
|
||||
void ReadMagic() {
|
||||
sMagicRead = true;
|
||||
char magic[PATH_MAX]{0};
|
||||
auto fp = fopen(kZygiskMagic, "r");
|
||||
if (fp == nullptr) {
|
||||
PLOGE("Open magic file");
|
||||
return;
|
||||
}
|
||||
fgets(magic, PATH_MAX, fp);
|
||||
fclose(fp);
|
||||
sSocketName.append(LP_SELECT("zygiskd32", "zygiskd64")).append(magic);
|
||||
LOGD("Socket name: %s", sSocketName.data());
|
||||
}
|
||||
|
||||
int Connect(uint8_t retry) {
|
||||
if (!sMagicRead) ReadMagic();
|
||||
int fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
struct sockaddr_un addr{
|
||||
.sun_family = AF_UNIX,
|
||||
.sun_path={0},
|
||||
};
|
||||
strcpy(addr.sun_path + 1, sSocketName.data());
|
||||
socklen_t socklen = sizeof(sa_family_t) + strlen(addr.sun_path + 1) + 1;
|
||||
strcpy(addr.sun_path, kCPSocketPath);
|
||||
socklen_t socklen = sizeof(addr);
|
||||
|
||||
while (retry--) {
|
||||
int r = connect(fd, reinterpret_cast<struct sockaddr*>(&addr), socklen);
|
||||
@@ -66,16 +48,6 @@ namespace zygiskd {
|
||||
return fd;
|
||||
}
|
||||
|
||||
std::string ReadNativeBridge() {
|
||||
UniqueFd fd = Connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("ReadNativeBridge");
|
||||
return "";
|
||||
}
|
||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::ReadNativeBridge);
|
||||
return socket_utils::read_string(fd);
|
||||
}
|
||||
|
||||
uint32_t GetProcessFlags(uid_t uid) {
|
||||
UniqueFd fd = Connect(1);
|
||||
if (fd == -1) {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
# define LP_SELECT(lp32, lp64) lp32
|
||||
#endif
|
||||
|
||||
constexpr auto kZygiskMagic = "/system/zygisk_magic";
|
||||
constexpr auto kCPSocketPath = "/dev/zygisk/" LP_SELECT("cp32", "cp64") ".sock";
|
||||
|
||||
class UniqueFd {
|
||||
using Fd = int;
|
||||
@@ -54,7 +54,6 @@ namespace zygiskd {
|
||||
enum class SocketAction {
|
||||
PingHeartBeat,
|
||||
RequestLogcatFd,
|
||||
ReadNativeBridge,
|
||||
GetProcessFlags,
|
||||
ReadModules,
|
||||
RequestCompanionSocket,
|
||||
@@ -65,8 +64,6 @@ namespace zygiskd {
|
||||
|
||||
int RequestLogcatFd();
|
||||
|
||||
std::string ReadNativeBridge();
|
||||
|
||||
std::vector<Module> ReadModules();
|
||||
|
||||
uint32_t GetProcessFlags(uid_t uid);
|
||||
|
||||
@@ -8,12 +8,19 @@ using namespace std;
|
||||
void *self_handle = nullptr;
|
||||
|
||||
extern "C" [[gnu::visibility("default")]]
|
||||
void entry(void *handle) {
|
||||
void entry(void* handle) {
|
||||
LOGI("Zygisk library injected");
|
||||
self_handle = handle;
|
||||
|
||||
if (!zygiskd::PingHeartbeat()) {
|
||||
LOGE("Zygisk daemon is not running");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef NDEBUG
|
||||
logging::setfd(zygiskd::RequestLogcatFd());
|
||||
#endif
|
||||
self_handle = handle;
|
||||
|
||||
LOGD("Load injector successfully");
|
||||
LOGD("Start hooking");
|
||||
hook_functions();
|
||||
}
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
#include <string_view>
|
||||
#include <sys/system_properties.h>
|
||||
#include <unistd.h>
|
||||
#include <array>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "dl.h"
|
||||
#include "logging.h"
|
||||
#include "native_bridge_callbacks.h"
|
||||
|
||||
extern "C" [[gnu::visibility("default")]]
|
||||
uint8_t NativeBridgeItf[sizeof(NativeBridgeCallbacks<__ANDROID_API_R__>) * 2]{0};
|
||||
|
||||
namespace {
|
||||
constexpr auto kZygoteProcesses = {"zygote", "zygote32", "zygote64", "usap32", "usap64"};
|
||||
constexpr auto kInjector = "/system/" LP_SELECT("lib", "lib64") "/libzygisk_injector.so";
|
||||
|
||||
void* sOriginalBridge = nullptr;
|
||||
}
|
||||
|
||||
__used __attribute__((destructor))
|
||||
void Destructor() {
|
||||
if (sOriginalBridge) {
|
||||
dlclose(sOriginalBridge);
|
||||
}
|
||||
}
|
||||
|
||||
__used __attribute__((constructor))
|
||||
void Constructor() {
|
||||
if (getuid() != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string_view cmdline = getprogname();
|
||||
if (std::none_of(
|
||||
kZygoteProcesses.begin(), kZygoteProcesses.end(),
|
||||
[&](const char* p) { return cmdline == p; }
|
||||
)) {
|
||||
LOGW("Not started as zygote (cmdline=%s)", cmdline.data());
|
||||
return;
|
||||
}
|
||||
|
||||
std::string native_bridge;
|
||||
do {
|
||||
if (!zygiskd::PingHeartbeat()) break;
|
||||
#ifdef NDEBUG
|
||||
logging::setfd(zygiskd::RequestLogcatFd());
|
||||
#endif
|
||||
LOGI("Read native bridge");
|
||||
native_bridge = zygiskd::ReadNativeBridge();
|
||||
|
||||
LOGI("Load injector");
|
||||
auto handle = DlopenExt(kInjector, RTLD_NOW);
|
||||
if (handle == nullptr) {
|
||||
LOGE("Failed to dlopen injector: %s", dlerror());
|
||||
break;
|
||||
}
|
||||
auto entry = dlsym(handle, "entry");
|
||||
if (entry == nullptr) {
|
||||
LOGE("Failed to dlsym injector entry: %s", dlerror());
|
||||
dlclose(handle);
|
||||
break;
|
||||
}
|
||||
reinterpret_cast<void (*)(void*)>(entry)(handle);
|
||||
} while (false);
|
||||
|
||||
do {
|
||||
if (native_bridge.empty() || native_bridge == "0") break;
|
||||
|
||||
LOGI("Load original native bridge: %s", native_bridge.data());
|
||||
sOriginalBridge = dlopen(native_bridge.data(), RTLD_NOW);
|
||||
if (sOriginalBridge == nullptr) {
|
||||
LOGE("%s", dlerror());
|
||||
break;
|
||||
}
|
||||
|
||||
auto* original_native_bridge_itf = dlsym(sOriginalBridge, "NativeBridgeItf");
|
||||
if (original_native_bridge_itf == nullptr) {
|
||||
LOGE("%s", dlerror());
|
||||
break;
|
||||
}
|
||||
|
||||
long sdk = 0;
|
||||
char value[PROP_VALUE_MAX + 1];
|
||||
if (__system_property_get("ro.build.version.sdk", value) > 0) {
|
||||
sdk = strtol(value, nullptr, 10);
|
||||
}
|
||||
|
||||
auto callbacks_size = 0;
|
||||
if (sdk >= __ANDROID_API_R__) {
|
||||
callbacks_size = sizeof(NativeBridgeCallbacks<__ANDROID_API_R__>);
|
||||
} else if (sdk == __ANDROID_API_Q__) {
|
||||
callbacks_size = sizeof(NativeBridgeCallbacks<__ANDROID_API_Q__>);
|
||||
}
|
||||
|
||||
memcpy(NativeBridgeItf, original_native_bridge_itf, callbacks_size);
|
||||
} while (false);
|
||||
|
||||
logging::setfd(-1);
|
||||
}
|
||||
@@ -102,58 +102,44 @@ extract "$ZIPFILE" 'service.sh' "$MODPATH"
|
||||
mv "$TMPDIR/sepolicy.rule" "$MODPATH"
|
||||
|
||||
HAS32BIT=false && [ -d "/system/lib" ] && HAS32BIT=true
|
||||
HAS64BIT=false && [ -d "/system/lib64" ] && HAS64BIT=true
|
||||
|
||||
mkdir "$MODPATH/bin"
|
||||
mkdir "$MODPATH/system"
|
||||
mkdir "$MODPATH/system/lib64"
|
||||
[ "$HAS32BIT" = true ] && mkdir "$MODPATH/system/lib"
|
||||
[ "$HAS64BIT" = true ] && mkdir "$MODPATH/system/lib64"
|
||||
|
||||
if [ "$ARCH" = "x86" ] || [ "$ARCH" = "x64" ]; then
|
||||
if [ "$HAS32BIT" = true ]; then
|
||||
ui_print "- Extracting x86 libraries"
|
||||
extract "$ZIPFILE" 'bin/x86/zygiskd' "$MODPATH/bin" true
|
||||
mv "$MODPATH/bin/zygiskd" "$MODPATH/bin/zygiskd32"
|
||||
extract "$ZIPFILE" 'lib/x86/libzygisk_injector.so' "$MODPATH/system/lib" true
|
||||
extract "$ZIPFILE" 'lib/x86/libzygisk_loader.so' "$MODPATH/system/lib" true
|
||||
ln -sf "zygiskd32" "$MODPATH/bin/zygiskwd"
|
||||
mv "$MODPATH/bin/zygiskd" "$MODPATH/bin/zygisk-cp32"
|
||||
extract "$ZIPFILE" 'lib/x86/libzygisk.so' "$MODPATH/system/lib" true
|
||||
fi
|
||||
|
||||
if [ "$HAS64BIT" = true ]; then
|
||||
ui_print "- Extracting x64 libraries"
|
||||
extract "$ZIPFILE" 'bin/x86_64/zygiskd' "$MODPATH/bin" true
|
||||
mv "$MODPATH/bin/zygiskd" "$MODPATH/bin/zygiskd64"
|
||||
extract "$ZIPFILE" 'lib/x86_64/libzygisk_injector.so' "$MODPATH/system/lib64" true
|
||||
extract "$ZIPFILE" 'lib/x86_64/libzygisk_loader.so' "$MODPATH/system/lib64" true
|
||||
ln -sf "zygiskd64" "$MODPATH/bin/zygiskwd"
|
||||
fi
|
||||
ui_print "- Extracting x64 libraries"
|
||||
extract "$ZIPFILE" 'bin/x86_64/zygiskd' "$MODPATH/bin" true
|
||||
extract "$ZIPFILE" 'lib/x86_64/libzygisk.so' "$MODPATH/system/lib64" true
|
||||
ln -sf "zygiskd" "$MODPATH/bin/zygisk-wd"
|
||||
ln -sf "zygiskd" "$MODPATH/bin/zygisk-fuse"
|
||||
ln -sf "zygiskd" "$MODPATH/bin/zygisk-cp64"
|
||||
else
|
||||
if [ "$HAS32BIT" = true ]; then
|
||||
ui_print "- Extracting arm libraries"
|
||||
extract "$ZIPFILE" 'bin/armeabi-v7a/zygiskd' "$MODPATH/bin" true
|
||||
mv "$MODPATH/bin/zygiskd" "$MODPATH/bin/zygiskd32"
|
||||
extract "$ZIPFILE" 'lib/armeabi-v7a/libzygisk_injector.so' "$MODPATH/system/lib" true
|
||||
extract "$ZIPFILE" 'lib/armeabi-v7a/libzygisk_loader.so' "$MODPATH/system/lib" true
|
||||
ln -sf "zygiskd32" "$MODPATH/bin/zygiskwd"
|
||||
mv "$MODPATH/bin/zygiskd" "$MODPATH/bin/zygisk-cp32"
|
||||
extract "$ZIPFILE" 'lib/armeabi-v7a/libzygisk.so' "$MODPATH/system/lib" true
|
||||
fi
|
||||
|
||||
if [ "$HAS64BIT" = true ]; then
|
||||
ui_print "- Extracting arm64 libraries"
|
||||
extract "$ZIPFILE" 'bin/arm64-v8a/zygiskd' "$MODPATH/bin" true
|
||||
mv "$MODPATH/bin/zygiskd" "$MODPATH/bin/zygiskd64"
|
||||
extract "$ZIPFILE" 'lib/arm64-v8a/libzygisk_injector.so' "$MODPATH/system/lib64" true
|
||||
extract "$ZIPFILE" 'lib/arm64-v8a/libzygisk_loader.so' "$MODPATH/system/lib64" true
|
||||
ln -sf "zygiskd64" "$MODPATH/bin/zygiskwd"
|
||||
fi
|
||||
ui_print "- Extracting arm64 libraries"
|
||||
extract "$ZIPFILE" 'bin/arm64-v8a/zygiskd' "$MODPATH/bin" true
|
||||
extract "$ZIPFILE" 'lib/arm64-v8a/libzygisk.so' "$MODPATH/system/lib64" true
|
||||
ln -sf "zygiskd" "$MODPATH/bin/zygisk-wd"
|
||||
ln -sf "zygiskd" "$MODPATH/bin/zygisk-fuse"
|
||||
ln -sf "zygiskd" "$MODPATH/bin/zygisk-cp64"
|
||||
fi
|
||||
|
||||
ui_print "- Generating magic"
|
||||
MAGIC=$(tr -dc 'a-f0-9' </dev/urandom | head -c 18)
|
||||
echo -n "$MAGIC" > "$MODPATH/system/zygisk_magic"
|
||||
|
||||
ui_print "- Setting permissions"
|
||||
chmod 0744 "$MODPATH/daemon.sh"
|
||||
set_perm_recursive "$MODPATH/bin" 0 2000 0755 0755
|
||||
set_perm_recursive "$MODPATH/bin" 0 0 0755 0755
|
||||
set_perm_recursive "$MODPATH/system/lib" 0 0 0755 0644 u:object_r:system_lib_file:s0
|
||||
set_perm_recursive "$MODPATH/system/lib64" 0 0 0755 0644 u:object_r:system_lib_file:s0
|
||||
|
||||
|
||||
@@ -6,8 +6,6 @@ if [ "$ZYGISK_ENABLED" ]; then
|
||||
fi
|
||||
|
||||
cd "$MODDIR"
|
||||
getprop ro.dalvik.vm.native.bridge > /dev/.native_bridge
|
||||
resetprop ro.dalvik.vm.native.bridge libzygisk_loader.so
|
||||
|
||||
if [ "$(which magisk)" ]; then
|
||||
for file in ../*; do
|
||||
@@ -21,3 +19,5 @@ if [ "$(which magisk)" ]; then
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
sh -c "bin/zygisk-fuse &"
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
deny vold fusectlfs file write
|
||||
|
||||
allow * tmpfs * *
|
||||
allow zygote appdomain_tmpfs dir *
|
||||
allow zygote appdomain_tmpfs file *
|
||||
|
||||
@@ -8,8 +8,6 @@ if [ "$ZYGISK_ENABLED" ]; then
|
||||
fi
|
||||
|
||||
cd "$MODDIR"
|
||||
export NATIVE_BRIDGE=$(cat /dev/.native_bridge)
|
||||
rm /dev/.native_bridge
|
||||
|
||||
if [ "$(which magisk)" ]; then
|
||||
for file in ../*; do
|
||||
@@ -26,4 +24,4 @@ fi
|
||||
|
||||
log -p i -t "zygisksu" "Start watchdog"
|
||||
[ "$DEBUG" = true ] && export RUST_BACKTRACE=1
|
||||
exec "bin/zygiskwd" "watchdog" >/dev/null 2>&1
|
||||
exec "bin/zygisk-wd" >/dev/null 2>&1
|
||||
|
||||
@@ -9,7 +9,6 @@ rust-version = "1.69"
|
||||
android_logger = "0.13"
|
||||
anyhow = { version = "1.0", features = ["backtrace"] }
|
||||
bitflags = { version = "2.3" }
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
const_format = "0.2"
|
||||
futures = "0.3"
|
||||
konst = "0.3"
|
||||
@@ -19,11 +18,13 @@ log = "0.4"
|
||||
memfd = "0.6"
|
||||
num_enum = "0.5"
|
||||
passfd = "0.1"
|
||||
rand = "0.8"
|
||||
proc-maps = "0.3"
|
||||
ptrace-do = "0.1"
|
||||
rustix = { version = "0.38", features = [ "fs", "process", "mount", "net", "thread"] }
|
||||
tokio = { version = "1.28", features = ["full"] }
|
||||
|
||||
binder = { git = "https://github.com/Kernel-SU/binder_rs", rev = "c9f2b62d6a744fd2264056c638c1b061a6a2932d" }
|
||||
fuser = { git = "https://github.com/Dr-TSNG/fuser", default-features = false }
|
||||
|
||||
[profile.release]
|
||||
strip = true
|
||||
|
||||
@@ -17,15 +17,25 @@ pub const MAX_LOG_LEVEL: LevelFilter = LevelFilter::Trace;
|
||||
#[cfg(not(debug_assertions))]
|
||||
pub const MAX_LOG_LEVEL: LevelFilter = LevelFilter::Info;
|
||||
|
||||
pub const PROP_NATIVE_BRIDGE: &str = "ro.dalvik.vm.native.bridge";
|
||||
pub const PROP_CTL_RESTART: &str = "ctl.restart";
|
||||
pub const ZYGISK_LOADER: &str = "libzygisk_loader.so";
|
||||
pub const ZYGISK_MAGIC: &str = "/system/zygisk_magic";
|
||||
pub const ZYGISK_LIBRARY: &str = "libzygisk.so";
|
||||
|
||||
pub const PATH_PCL: &str = "/system/etc/preloaded-classes";
|
||||
pub const PATH_SYSTEM_LIB32: &str = "/system/lib";
|
||||
pub const PATH_SYSTEM_LIB64: &str = "/system/lib64";
|
||||
pub const PATH_WORK_DIR: &str = "/dev/zygisk"; // TODO: Replace with /debug_ramdisk/zygisk
|
||||
pub const PATH_PROP_OVERLAY: &str = concatcp!(PATH_WORK_DIR, "/module.prop");
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
pub const PATH_CP_SOCKET: &str = concatcp!(PATH_WORK_DIR, "/cp64.sock");
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
pub const PATH_CP_SOCKET: &str = concatcp!(PATH_WORK_DIR, "/cp32.sock");
|
||||
pub const PATH_FUSE_DIR: &str = concatcp!(PATH_WORK_DIR, "/fuse");
|
||||
pub const PATH_FUSE_PCL: &str = concatcp!(PATH_FUSE_DIR, "/preloaded-classes");
|
||||
|
||||
pub const PATH_MODULES_DIR: &str = "..";
|
||||
pub const PATH_MODULE_PROP: &str = "module.prop";
|
||||
pub const PATH_ZYGISKD32: &str = "bin/zygiskd32";
|
||||
pub const PATH_ZYGISKD64: &str = "bin/zygiskd64";
|
||||
pub const PATH_CP32_BIN: &str = "bin/zygisk-cp32";
|
||||
pub const PATH_CP64_BIN: &str = "bin/zygisk-cp64";
|
||||
|
||||
pub const STATUS_LOADED: &str = "😋 Zygisksu is loaded";
|
||||
pub const STATUS_CRASHED: &str = "❌ Zygiskd has crashed";
|
||||
@@ -39,7 +49,6 @@ pub const STATUS_ROOT_IMPL_MULTIPLE: &str = "❌ Multiple root implementations i
|
||||
pub enum DaemonSocketAction {
|
||||
PingHeartbeat,
|
||||
RequestLogcatFd,
|
||||
ReadNativeBridge,
|
||||
GetProcessFlags,
|
||||
ReadModules,
|
||||
RequestCompanionSocket,
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
use anyhow::{bail, Result};
|
||||
use std::ffi::{c_char, c_void};
|
||||
|
||||
const ANDROID_NAMESPACE_TYPE_SHARED: u64 = 0x2;
|
||||
const ANDROID_DLEXT_USE_NAMESPACE: u64 = 0x200;
|
||||
pub const ANDROID_NAMESPACE_TYPE_SHARED: u64 = 0x2;
|
||||
pub const ANDROID_DLEXT_USE_NAMESPACE: u64 = 0x200;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct AndroidNamespace {
|
||||
pub struct AndroidNamespace {
|
||||
_unused: [u8; 0],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct AndroidDlextinfo {
|
||||
pub struct AndroidDlextinfo {
|
||||
pub flags: u64,
|
||||
pub reserved_addr: *mut c_void,
|
||||
pub reserved_size: libc::size_t,
|
||||
@@ -22,7 +22,7 @@ struct AndroidDlextinfo {
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn android_dlopen_ext(
|
||||
pub fn android_dlopen_ext(
|
||||
filename: *const c_char,
|
||||
flags: libc::c_int,
|
||||
extinfo: *const AndroidDlextinfo,
|
||||
|
||||
335
zygiskd/src/fuse.rs
Normal file
335
zygiskd/src/fuse.rs
Normal file
@@ -0,0 +1,335 @@
|
||||
use std::cmp::min;
|
||||
use anyhow::{bail, Result};
|
||||
use std::ffi::{CString, OsStr};
|
||||
use std::{fs, thread};
|
||||
use std::sync::{mpsc, Mutex};
|
||||
use std::time::{Duration, SystemTime};
|
||||
use fuser::{FileAttr, Filesystem, FileType, ReplyAttr, ReplyData, ReplyDirectory, ReplyEntry, ReplyOpen, Request};
|
||||
use libc::ENOENT;
|
||||
use log::{debug, error, info};
|
||||
use proc_maps::{get_process_maps, MapRange, Pid};
|
||||
use ptrace_do::{RawProcess, TracedProcess};
|
||||
use rustix::mount::mount_bind;
|
||||
use rustix::path::Arg;
|
||||
use rustix::process::getpid;
|
||||
use crate::{constants, dl};
|
||||
use crate::utils::LateInit;
|
||||
|
||||
pub struct DelegateFilesystem;
|
||||
|
||||
const fn attr(inode: u64, size: u64, kind: FileType) -> FileAttr {
|
||||
FileAttr {
|
||||
ino: inode,
|
||||
size,
|
||||
blocks: 0,
|
||||
atime: SystemTime::UNIX_EPOCH,
|
||||
mtime: SystemTime::UNIX_EPOCH,
|
||||
ctime: SystemTime::UNIX_EPOCH,
|
||||
crtime: SystemTime::UNIX_EPOCH,
|
||||
kind,
|
||||
perm: 0o644,
|
||||
nlink: 0,
|
||||
uid: 0,
|
||||
gid: 0,
|
||||
rdev: 0,
|
||||
blksize: 0,
|
||||
flags: 0,
|
||||
}
|
||||
}
|
||||
|
||||
const ANDROID_LIBC: &str = "bionic/libc.so";
|
||||
const ANDROID_LIBDL: &str = "bionic/libdl.so";
|
||||
|
||||
const INO_DIR: u64 = 1;
|
||||
const INO_PCL: u64 = 2;
|
||||
|
||||
static ATTR_DIR: FileAttr = attr(INO_DIR, 0, FileType::Directory);
|
||||
static ATTR_PCL: LateInit<FileAttr> = LateInit::new();
|
||||
|
||||
static PCL_CONTENT: LateInit<Vec<u8>> = LateInit::new();
|
||||
|
||||
const ENTRIES: &[(u64, FileType, &str)] = &[
|
||||
(INO_DIR, FileType::Directory, "."),
|
||||
(INO_DIR, FileType::Directory, ".."),
|
||||
(INO_PCL, FileType::RegularFile, "preloaded-classes"),
|
||||
];
|
||||
|
||||
const TTL: Duration = Duration::from_secs(1);
|
||||
|
||||
impl Filesystem for DelegateFilesystem {
|
||||
fn lookup(&mut self, _req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEntry) {
|
||||
if parent != INO_DIR {
|
||||
reply.error(ENOENT);
|
||||
return;
|
||||
}
|
||||
match name.as_str().unwrap() {
|
||||
"preloaded-classes" => reply.entry(&TTL, &ATTR_PCL, 0),
|
||||
_ => reply.error(ENOENT),
|
||||
}
|
||||
}
|
||||
|
||||
fn getattr(&mut self, _req: &Request<'_>, ino: u64, reply: ReplyAttr) {
|
||||
match ino {
|
||||
INO_DIR => reply.attr(&TTL, &ATTR_DIR),
|
||||
INO_PCL => reply.attr(&TTL, &ATTR_PCL),
|
||||
_ => reply.error(ENOENT),
|
||||
}
|
||||
}
|
||||
|
||||
fn open(&mut self, req: &Request<'_>, ino: u64, _flags: i32, reply: ReplyOpen) {
|
||||
if ino == INO_PCL {
|
||||
let pid = req.pid();
|
||||
let process = format!("/proc/{}/cmdline", pid);
|
||||
let process = fs::read_to_string(process).unwrap();
|
||||
let process = &process[..process.find('\0').unwrap()];
|
||||
info!("Process {} is reading preloaded-classes", process);
|
||||
match process {
|
||||
// "zygote" => ptrace_zygote(pid, false).unwrap(),
|
||||
"zygote64" => ptrace_zygote(pid, true).unwrap(),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
reply.opened(0, 0);
|
||||
}
|
||||
|
||||
fn read(&mut self, _req: &Request<'_>, ino: u64, _fh: u64, offset: i64, size: u32, _flags: i32, _lock_owner: Option<u64>, reply: ReplyData) {
|
||||
let offset = offset as usize;
|
||||
let size = size as usize;
|
||||
if ino == INO_PCL {
|
||||
let len = PCL_CONTENT.len();
|
||||
if offset >= len {
|
||||
reply.data(&[]);
|
||||
} else {
|
||||
let end = min(offset + size, len);
|
||||
reply.data(&PCL_CONTENT[offset..end]);
|
||||
}
|
||||
} else {
|
||||
reply.error(ENOENT);
|
||||
}
|
||||
}
|
||||
|
||||
fn readdir(&mut self, _req: &Request<'_>, ino: u64, _fh: u64, offset: i64, mut reply: ReplyDirectory) {
|
||||
if ino != INO_DIR {
|
||||
reply.error(ENOENT);
|
||||
return;
|
||||
}
|
||||
for (i, entry) in ENTRIES.iter().enumerate().skip(offset as usize) {
|
||||
if reply.add(entry.0, (i + 1) as i64, entry.1, entry.2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
reply.ok();
|
||||
}
|
||||
}
|
||||
|
||||
fn find_module_for_pid(pid: Pid, library: &str) -> Result<MapRange> {
|
||||
let maps = get_process_maps(pid)?;
|
||||
for map in maps.into_iter() {
|
||||
if let Some(p) = map.filename() {
|
||||
if p.as_str()?.contains(library) {
|
||||
return Ok(map);
|
||||
}
|
||||
}
|
||||
}
|
||||
bail!("Cannot find module {library} for pid {pid}");
|
||||
}
|
||||
|
||||
fn find_remote_procedure(
|
||||
pid: Pid,
|
||||
library: &str,
|
||||
local_addr: usize,
|
||||
) -> Result<usize> {
|
||||
let local_module = find_module_for_pid(getpid().as_raw_nonzero().get(), library)?;
|
||||
debug!(
|
||||
"Identifed local range {library} ({:?}) at {:x}",
|
||||
local_module.filename(),
|
||||
local_module.start()
|
||||
);
|
||||
|
||||
let remote_module = find_module_for_pid(pid, library)?;
|
||||
debug!(
|
||||
"Identifed remote range {library} ({:?}) at {:x}",
|
||||
remote_module.filename(),
|
||||
remote_module.start()
|
||||
);
|
||||
|
||||
Ok(local_addr - local_module.start() + remote_module.start())
|
||||
}
|
||||
|
||||
fn ptrace_zygote(pid: u32, is64: bool) -> Result<()> {
|
||||
static LAST_32: Mutex<u32> = Mutex::new(0);
|
||||
static LAST_64: Mutex<u32> = Mutex::new(0);
|
||||
|
||||
let mut last = match is64 {
|
||||
true => LAST_64.lock().unwrap(),
|
||||
false => LAST_32.lock().unwrap(),
|
||||
};
|
||||
if *last == pid {
|
||||
return Ok(());
|
||||
}
|
||||
*last = pid;
|
||||
let (sender, receiver) = mpsc::channel::<()>();
|
||||
|
||||
let worker = move || -> Result<()> {
|
||||
info!("Injecting into pid {}, is64 = {}", pid, is64);
|
||||
let lib_dir = match is64 {
|
||||
true => constants::PATH_SYSTEM_LIB64,
|
||||
false => constants::PATH_SYSTEM_LIB32,
|
||||
};
|
||||
let zygisk_lib = format!("{}/{}", lib_dir, constants::ZYGISK_LIBRARY);
|
||||
let lib_dir = CString::new(lib_dir)?;
|
||||
let zygisk_lib = CString::new(zygisk_lib)?;
|
||||
let libc_base = find_module_for_pid(pid as i32, ANDROID_LIBC)?.start();
|
||||
let mmap_remote = find_remote_procedure(
|
||||
pid as i32,
|
||||
ANDROID_LIBC,
|
||||
libc::mmap as usize,
|
||||
)?;
|
||||
let munmap_remote = find_remote_procedure(
|
||||
pid as i32,
|
||||
ANDROID_LIBC,
|
||||
libc::munmap as usize,
|
||||
)?;
|
||||
let dlopen_remote = find_remote_procedure(
|
||||
pid as i32,
|
||||
ANDROID_LIBDL,
|
||||
dl::android_dlopen_ext as usize,
|
||||
)?;
|
||||
let dlsym_remote = find_remote_procedure(
|
||||
pid as i32,
|
||||
ANDROID_LIBDL,
|
||||
libc::dlsym as usize,
|
||||
)?;
|
||||
|
||||
let tracer = TracedProcess::attach(RawProcess::new(pid as i32))?;
|
||||
sender.send(())?;
|
||||
let frame = tracer.next_frame()?;
|
||||
debug!("Waited for a frame");
|
||||
|
||||
// Map a buffer in the remote process
|
||||
let mmap_params: [usize; 6] = [
|
||||
0,
|
||||
0x1000,
|
||||
(libc::PROT_READ | libc::PROT_WRITE) as usize,
|
||||
(libc::MAP_ANONYMOUS | libc::MAP_PRIVATE) as usize,
|
||||
0,
|
||||
0,
|
||||
];
|
||||
let (regs, mut frame) = frame.invoke_remote(
|
||||
mmap_remote,
|
||||
libc_base,
|
||||
&mmap_params,
|
||||
)?;
|
||||
let buf_addr = regs.return_value();
|
||||
debug!("Buffer addr: {:x}", buf_addr);
|
||||
|
||||
// Find the address of __loader_android_create_namespace
|
||||
let sym = CString::new("__loader_android_create_namespace")?;
|
||||
frame.write_memory(buf_addr, sym.as_bytes_with_nul())?;
|
||||
let (regs, mut frame) = frame.invoke_remote(
|
||||
dlsym_remote,
|
||||
libc_base,
|
||||
&[libc::RTLD_DEFAULT as usize, buf_addr],
|
||||
)?;
|
||||
let android_create_namespace_remote = regs.return_value();
|
||||
debug!("__loader_android_create_namespace addr: {:x}", android_create_namespace_remote);
|
||||
|
||||
// Create a linker namespace for remote process
|
||||
frame.write_memory(buf_addr, zygisk_lib.as_bytes_with_nul())?;
|
||||
frame.write_memory(buf_addr + 0x100, lib_dir.as_bytes_with_nul())?;
|
||||
let ns_params: [usize; 7] = [
|
||||
buf_addr, // name
|
||||
buf_addr + 0x100, // ld_library_path
|
||||
0, // default_library_path
|
||||
dl::ANDROID_NAMESPACE_TYPE_SHARED as usize, // type
|
||||
0, // permitted_when_isolated_path
|
||||
0, // parent
|
||||
dlopen_remote, // caller_addr
|
||||
];
|
||||
let (regs, mut frame) = frame.invoke_remote(
|
||||
android_create_namespace_remote,
|
||||
libc_base,
|
||||
&ns_params,
|
||||
)?;
|
||||
let ns_addr = regs.return_value();
|
||||
debug!("Linker namespace addr: {:x}", ns_addr);
|
||||
|
||||
// Load zygisk into remote process
|
||||
let info = dl::AndroidDlextinfo {
|
||||
flags: dl::ANDROID_DLEXT_USE_NAMESPACE,
|
||||
reserved_addr: std::ptr::null_mut(),
|
||||
reserved_size: 0,
|
||||
relro_fd: 0,
|
||||
library_fd: 0,
|
||||
library_fd_offset: 0,
|
||||
library_namespace: ns_addr as *mut _,
|
||||
};
|
||||
let info = unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
&info as *const _ as *const u8,
|
||||
std::mem::size_of::<dl::AndroidDlextinfo>(),
|
||||
)
|
||||
};
|
||||
frame.write_memory(buf_addr + 0x200, info)?;
|
||||
let (regs, mut frame) = frame.invoke_remote(
|
||||
dlopen_remote,
|
||||
libc_base,
|
||||
&[buf_addr, libc::RTLD_NOW as usize, buf_addr + 0x200],
|
||||
)?;
|
||||
let handle = regs.return_value();
|
||||
debug!("Load zygisk into remote process: {:x}", handle);
|
||||
|
||||
let entry = CString::new("entry")?;
|
||||
frame.write_memory(buf_addr, entry.as_bytes_with_nul())?;
|
||||
let (regs, frame) = frame.invoke_remote(
|
||||
dlsym_remote,
|
||||
libc_base,
|
||||
&[handle, buf_addr],
|
||||
)?;
|
||||
let entry = regs.return_value();
|
||||
debug!("Call zygisk entry: {:x}", entry);
|
||||
let (_, frame) = frame.invoke_remote(
|
||||
entry,
|
||||
libc_base,
|
||||
&[handle],
|
||||
)?;
|
||||
|
||||
// Cleanup
|
||||
let _ = frame.invoke_remote(
|
||||
munmap_remote,
|
||||
libc_base,
|
||||
&[buf_addr],
|
||||
)?;
|
||||
debug!("Cleaned up");
|
||||
Ok(())
|
||||
};
|
||||
|
||||
thread::spawn(move || {
|
||||
if let Err(e) = worker() {
|
||||
error!("Crashed: {:?}", e);
|
||||
}
|
||||
});
|
||||
|
||||
receiver.recv()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn main() -> Result<()> {
|
||||
fs::create_dir(constants::PATH_WORK_DIR)?;
|
||||
fs::create_dir(constants::PATH_FUSE_DIR)?;
|
||||
PCL_CONTENT.init(fs::read(constants::PATH_PCL)?);
|
||||
ATTR_PCL.init(attr(INO_PCL, PCL_CONTENT.len() as u64, FileType::RegularFile));
|
||||
let options = [
|
||||
fuser::MountOption::FSName(String::from("zygisk")),
|
||||
fuser::MountOption::AllowOther,
|
||||
fuser::MountOption::RO,
|
||||
];
|
||||
let session = fuser::spawn_mount2(
|
||||
DelegateFilesystem,
|
||||
constants::PATH_FUSE_DIR,
|
||||
&options,
|
||||
)?;
|
||||
mount_bind(constants::PATH_FUSE_PCL, constants::PATH_PCL)?;
|
||||
session.join();
|
||||
bail!("Fuse mount exited unexpectedly");
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
use std::fs;
|
||||
use anyhow::Result;
|
||||
use crate::constants;
|
||||
use crate::utils::LateInit;
|
||||
|
||||
pub static MAGIC: LateInit<String> = LateInit::new();
|
||||
pub static PATH_TMP_DIR: LateInit<String> = LateInit::new();
|
||||
pub static PATH_TMP_PROP: LateInit<String> = LateInit::new();
|
||||
|
||||
pub fn setup() -> Result<()> {
|
||||
let name = fs::read_to_string(constants::ZYGISK_MAGIC)?;
|
||||
let path_tmp_dir = format!("/dev/{}", name);
|
||||
let path_tmp_prop = format!("{}/module.prop", path_tmp_dir);
|
||||
|
||||
MAGIC.init(name);
|
||||
PATH_TMP_DIR.init(path_tmp_dir);
|
||||
PATH_TMP_PROP.init(path_tmp_prop);
|
||||
Ok(())
|
||||
}
|
||||
@@ -3,29 +3,13 @@
|
||||
|
||||
mod constants;
|
||||
mod dl;
|
||||
mod magic;
|
||||
mod fuse;
|
||||
mod root_impl;
|
||||
mod utils;
|
||||
mod watchdog;
|
||||
mod zygiskd;
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::{Subcommand, Parser};
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version = constants::VERSION_FULL, about, long_about = None)]
|
||||
struct Args {
|
||||
#[command(subcommand)]
|
||||
command: Commands,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum Commands {
|
||||
/// Start zygisk watchdog
|
||||
Watchdog,
|
||||
/// Start zygisk daemon
|
||||
Daemon,
|
||||
}
|
||||
|
||||
|
||||
fn init_android_logger(tag: &str) {
|
||||
@@ -36,14 +20,15 @@ fn init_android_logger(tag: &str) {
|
||||
);
|
||||
}
|
||||
|
||||
async fn start() -> Result<()> {
|
||||
async fn start(name: &str) -> Result<()> {
|
||||
root_impl::setup();
|
||||
magic::setup()?;
|
||||
let cli = Args::parse();
|
||||
match cli.command {
|
||||
Commands::Watchdog => watchdog::entry().await?,
|
||||
Commands::Daemon => zygiskd::entry()?,
|
||||
};
|
||||
match name.trim_start_matches("zygisk-") {
|
||||
"wd" => watchdog::main().await?,
|
||||
"fuse" => fuse::main()?,
|
||||
"cp32" => zygiskd::main()?,
|
||||
"cp64" => zygiskd::main()?,
|
||||
_ => println!("Available commands: wd, fuse, cp"),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -53,7 +38,7 @@ async fn main() {
|
||||
let nice_name = process.split('/').last().unwrap();
|
||||
init_android_logger(nice_name);
|
||||
|
||||
if let Err(e) = start().await {
|
||||
if let Err(e) = start(nice_name).await {
|
||||
log::error!("Crashed: {}\n{}", e, e.backtrace());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use anyhow::Result;
|
||||
use std::{fs, io::{Read, Write}, os::unix::net::UnixStream, process::Command};
|
||||
use std::{fs, io::{Read, Write}, os::unix::net::UnixStream};
|
||||
use std::ffi::c_char;
|
||||
use std::os::unix::net::UnixListener;
|
||||
use std::process::Command;
|
||||
use std::sync::OnceLock;
|
||||
use rand::distributions::{Alphanumeric, DistString};
|
||||
use rustix::net::{AddressFamily, bind_unix, listen, socket, SocketAddrUnix, SocketType};
|
||||
use rustix::thread::gettid;
|
||||
|
||||
@@ -50,10 +50,6 @@ impl<T> std::ops::Deref for LateInit<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn random_string() -> String {
|
||||
Alphanumeric.sample_string(&mut rand::thread_rng(), 8)
|
||||
}
|
||||
|
||||
pub fn set_socket_create_context(context: &str) -> Result<()> {
|
||||
let path = "/proc/thread-self/attr/sockcreate";
|
||||
match fs::write(path, context) {
|
||||
@@ -66,15 +62,16 @@ pub fn set_socket_create_context(context: &str) -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_native_bridge() -> String {
|
||||
std::env::var("NATIVE_BRIDGE").unwrap_or_default()
|
||||
pub fn chcon(path: &str, context: &str) -> Result<()> {
|
||||
Command::new("chcon").arg(context).arg(path).status()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn log_raw(level: i32, tag: &str, message: &str) -> Result<()> {
|
||||
let tag = std::ffi::CString::new(tag)?;
|
||||
let message = std::ffi::CString::new(message)?;
|
||||
unsafe {
|
||||
__android_log_print(level as i32, tag.as_ptr(), message.as_ptr());
|
||||
__android_log_print(level, tag.as_ptr(), message.as_ptr());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -89,10 +86,11 @@ pub fn get_property(name: &str) -> Result<String> {
|
||||
}
|
||||
|
||||
pub fn set_property(name: &str, value: &str) -> Result<()> {
|
||||
Command::new("resetprop")
|
||||
.arg(name)
|
||||
.arg(value)
|
||||
.spawn()?.wait()?;
|
||||
let name = std::ffi::CString::new(name)?;
|
||||
let value = std::ffi::CString::new(value)?;
|
||||
unsafe {
|
||||
__system_property_set(name.as_ptr(), value.as_ptr());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -155,15 +153,18 @@ impl UnixStreamExt for UnixStream {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn abstract_namespace_socket(name: &str) -> Result<UnixListener> {
|
||||
let addr = SocketAddrUnix::new_abstract_name(name.as_bytes())?;
|
||||
pub fn unix_listener_from_path(path: &str) -> Result<UnixListener> {
|
||||
let _ = fs::remove_file(path);
|
||||
let addr = SocketAddrUnix::new(path)?;
|
||||
let socket = socket(AddressFamily::UNIX, SocketType::STREAM, None)?;
|
||||
bind_unix(&socket, &addr)?;
|
||||
listen(&socket, 2)?;
|
||||
chcon(path, "u:object_r:magisk_file:s0")?;
|
||||
Ok(UnixListener::from(socket))
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn __android_log_print(prio: i32, tag: *const c_char, fmt: *const c_char, ...) -> i32;
|
||||
fn __system_property_get(name: *const c_char, value: *mut c_char) -> u32;
|
||||
fn __system_property_set(name: *const c_char, value: *const c_char) -> u32;
|
||||
}
|
||||
|
||||
@@ -1,39 +1,46 @@
|
||||
use crate::{constants, magic, root_impl, utils};
|
||||
use crate::{constants, root_impl, utils};
|
||||
use anyhow::{bail, Result};
|
||||
use std::fs;
|
||||
use std::future::Future;
|
||||
use std::io::{BufRead, BufReader, Write};
|
||||
use std::os::unix::net::UnixListener;
|
||||
use std::pin::Pin;
|
||||
use std::time::Duration;
|
||||
use binder::IBinder;
|
||||
use futures::stream::FuturesUnordered;
|
||||
use futures::StreamExt;
|
||||
use log::info;
|
||||
use rustix::mount::mount_bind;
|
||||
use rustix::process::{getgid, getuid, kill_process, Pid, Signal};
|
||||
use tokio::process::{Child, Command};
|
||||
use crate::utils::LateInit;
|
||||
|
||||
static LOCK: LateInit<UnixListener> = LateInit::new();
|
||||
static PROP_SECTIONS: LateInit<[String; 2]> = LateInit::new();
|
||||
|
||||
pub async fn entry() -> Result<()> {
|
||||
log::info!("Start zygisksu watchdog");
|
||||
pub async fn main() -> Result<()> {
|
||||
let result = run().await;
|
||||
set_prop_hint(constants::STATUS_CRASHED)?;
|
||||
result
|
||||
}
|
||||
|
||||
async fn run() -> Result<()> {
|
||||
info!("Start zygisksu watchdog");
|
||||
check_permission()?;
|
||||
ensure_single_instance()?;
|
||||
mount_prop().await?;
|
||||
if check_and_set_hint()? == false {
|
||||
log::warn!("Requirements not met, exiting");
|
||||
utils::set_property(constants::PROP_NATIVE_BRIDGE, &utils::get_native_bridge())?;
|
||||
return Ok(());
|
||||
}
|
||||
let end = spawn_daemon().await;
|
||||
set_prop_hint(constants::STATUS_CRASHED)?;
|
||||
end
|
||||
spawn_daemon().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn spawn_fuse() -> Result<()> {
|
||||
Command::new("bin/zygisk-fuse").spawn()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_permission() -> Result<()> {
|
||||
log::info!("Check permission");
|
||||
info!("Check permission");
|
||||
let uid = getuid();
|
||||
if !uid.is_root() {
|
||||
bail!("UID is not 0");
|
||||
@@ -53,16 +60,6 @@ fn check_permission() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn ensure_single_instance() -> Result<()> {
|
||||
log::info!("Ensure single instance");
|
||||
let name = format!("zygiskwd{}", magic::MAGIC.as_str());
|
||||
match utils::abstract_namespace_socket(&name) {
|
||||
Ok(socket) => LOCK.init(socket),
|
||||
Err(e) => bail!("Failed to acquire lock: {e}. Maybe another instance is running?")
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn mount_prop() -> Result<()> {
|
||||
let module_prop = if let root_impl::RootImpl::Magisk = root_impl::get_impl() {
|
||||
let magisk_path = Command::new("magisk").arg("--path").output().await?;
|
||||
@@ -74,7 +71,7 @@ async fn mount_prop() -> Result<()> {
|
||||
} else {
|
||||
constants::PATH_MODULE_PROP.to_string()
|
||||
};
|
||||
log::info!("Mount {module_prop}");
|
||||
info!("Mount {module_prop}");
|
||||
let module_prop_file = fs::File::open(&module_prop)?;
|
||||
let mut section = 0;
|
||||
let mut sections: [String; 2] = [String::new(), String::new()];
|
||||
@@ -93,15 +90,13 @@ async fn mount_prop() -> Result<()> {
|
||||
}
|
||||
PROP_SECTIONS.init(sections);
|
||||
|
||||
fs::create_dir(magic::PATH_TMP_DIR.as_str())?;
|
||||
fs::File::create(magic::PATH_TMP_PROP.as_str())?;
|
||||
|
||||
mount_bind(magic::PATH_TMP_PROP.as_str(), &module_prop)?;
|
||||
fs::File::create(constants::PATH_PROP_OVERLAY)?;
|
||||
mount_bind(constants::PATH_PROP_OVERLAY, &module_prop)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_prop_hint(hint: &str) -> Result<()> {
|
||||
let mut file = fs::File::create(magic::PATH_TMP_PROP.as_str())?;
|
||||
let mut file = fs::File::create(constants::PATH_PROP_OVERLAY)?;
|
||||
file.write_all(PROP_SECTIONS[0].as_bytes())?;
|
||||
file.write_all(b"[")?;
|
||||
file.write_all(hint.as_bytes())?;
|
||||
@@ -131,8 +126,8 @@ async fn spawn_daemon() -> Result<()> {
|
||||
let mut futures = FuturesUnordered::<Pin<Box<dyn Future<Output=Result<()>>>>>::new();
|
||||
let mut child_ids = vec![];
|
||||
|
||||
let daemon32 = Command::new(constants::PATH_ZYGISKD32).arg("daemon").spawn();
|
||||
let daemon64 = Command::new(constants::PATH_ZYGISKD64).arg("daemon").spawn();
|
||||
let daemon32 = Command::new(constants::PATH_CP32_BIN).spawn();
|
||||
let daemon64 = Command::new(constants::PATH_CP64_BIN).spawn();
|
||||
async fn spawn_daemon(mut daemon: Child) -> Result<()> {
|
||||
let result = daemon.wait().await?;
|
||||
log::error!("Daemon process {} died: {}", daemon.id().unwrap(), result);
|
||||
@@ -158,8 +153,7 @@ async fn spawn_daemon() -> Result<()> {
|
||||
};
|
||||
};
|
||||
|
||||
log::info!("System server ready, restore native bridge");
|
||||
utils::set_property(constants::PROP_NATIVE_BRIDGE, &utils::get_native_bridge())?;
|
||||
info!("System server ready");
|
||||
|
||||
loop {
|
||||
if binder.ping_binder().is_err() { break; }
|
||||
@@ -185,7 +179,6 @@ async fn spawn_daemon() -> Result<()> {
|
||||
}
|
||||
|
||||
log::error!("Restarting zygote...");
|
||||
utils::set_property(constants::PROP_NATIVE_BRIDGE, constants::ZYGISK_LOADER)?;
|
||||
utils::set_property(constants::PROP_CTL_RESTART, "zygote")?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::ffi::c_void;
|
||||
use crate::constants::{DaemonSocketAction, ProcessFlags};
|
||||
use crate::utils::UnixStreamExt;
|
||||
use crate::{constants, dl, lp_select, magic, root_impl, utils};
|
||||
use crate::{constants, dl, lp_select, root_impl, utils};
|
||||
use anyhow::{bail, Result};
|
||||
use passfd::FdPassingExt;
|
||||
use std::sync::Arc;
|
||||
@@ -14,7 +14,7 @@ use std::os::unix::{
|
||||
};
|
||||
use std::path::PathBuf;
|
||||
use rustix::fs::fstat;
|
||||
use rustix::process::Signal;
|
||||
use rustix::process::{set_parent_process_death_signal, Signal};
|
||||
|
||||
type ZygiskCompanionEntryFn = unsafe extern "C" fn(i32);
|
||||
|
||||
@@ -25,12 +25,11 @@ struct Module {
|
||||
}
|
||||
|
||||
struct Context {
|
||||
native_bridge: String,
|
||||
modules: Vec<Module>,
|
||||
}
|
||||
|
||||
pub fn entry() -> Result<()> {
|
||||
rustix::process::set_parent_process_death_signal(Some(Signal::Kill))?;
|
||||
pub fn main() -> Result<()> {
|
||||
set_parent_process_death_signal(Some(Signal::Kill))?;
|
||||
|
||||
let arch = get_arch()?;
|
||||
log::debug!("Daemon architecture: {arch}");
|
||||
@@ -39,7 +38,6 @@ pub fn entry() -> Result<()> {
|
||||
let modules = load_modules(arch)?;
|
||||
|
||||
let context = Context {
|
||||
native_bridge: utils::get_native_bridge(),
|
||||
modules,
|
||||
};
|
||||
let context = Arc::new(context);
|
||||
@@ -131,10 +129,8 @@ fn create_library_fd(so_path: &PathBuf) -> Result<OwnedFd> {
|
||||
|
||||
fn create_daemon_socket() -> Result<UnixListener> {
|
||||
utils::set_socket_create_context("u:r:zygote:s0")?;
|
||||
let prefix = lp_select!("zygiskd32", "zygiskd64");
|
||||
let name = format!("{}{}", prefix, magic::MAGIC.as_str());
|
||||
let listener = utils::abstract_namespace_socket(&name)?;
|
||||
log::debug!("Daemon socket: {name}");
|
||||
log::debug!("Daemon socket: {}", constants::PATH_CP_SOCKET);
|
||||
let listener = utils::unix_listener_from_path(constants::PATH_CP_SOCKET)?;
|
||||
Ok(listener)
|
||||
}
|
||||
|
||||
@@ -170,9 +166,6 @@ fn handle_daemon_action(mut stream: UnixStream, context: &Context) -> Result<()>
|
||||
utils::log_raw(level as i32, &tag, &message)?;
|
||||
}
|
||||
}
|
||||
DaemonSocketAction::ReadNativeBridge => {
|
||||
stream.write_string(&context.native_bridge)?;
|
||||
}
|
||||
DaemonSocketAction::GetProcessFlags => {
|
||||
let uid = stream.read_u32()? as i32;
|
||||
let mut flags = ProcessFlags::empty();
|
||||
|
||||
Reference in New Issue
Block a user