You've already forked ReZygisk
mirror of
https://github.com/PerformanC/ReZygisk.git
synced 2025-09-06 06:37:01 +00:00
Update zygiskd
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,4 +3,5 @@
|
||||
.cxx
|
||||
build
|
||||
local.properties
|
||||
target
|
||||
Cargo.lock
|
||||
|
||||
@@ -7,7 +7,7 @@ rust-version = "1.67"
|
||||
|
||||
[dependencies]
|
||||
android_logger = "0.12.0"
|
||||
anyhow = "1.0.68"
|
||||
anyhow = { version = "1.0.68", features = ["backtrace"] }
|
||||
const_format = "0.2.5"
|
||||
log = "0.4.17"
|
||||
memfd = "0.6.2"
|
||||
|
||||
@@ -10,10 +10,6 @@ cargo {
|
||||
targets = listOf("arm64", "arm", "x86", "x86_64")
|
||||
val isDebug = gradle.startParameter.taskNames.any { it.toLowerCase().contains("debug") }
|
||||
profile = if (isDebug) "debug" else "release"
|
||||
targetDirectory = "build/intermediates/rust"
|
||||
exec = { spec, _ ->
|
||||
spec.environment("CARGO_TARGET_DIR", targetDirectory)
|
||||
}
|
||||
}
|
||||
|
||||
androidComponents.onVariants { variant ->
|
||||
@@ -25,11 +21,16 @@ androidComponents.onVariants { variant ->
|
||||
}
|
||||
}
|
||||
|
||||
task<Exec>("pushAndRun$variantCapped") {
|
||||
task("push$variantCapped") {
|
||||
group = "zygiskd"
|
||||
dependsOn("build$variantCapped")
|
||||
dependsOn("cargoBuildArm", "cargoBuildArm64")
|
||||
doLast {
|
||||
commandLine("adb", "push", "target/")
|
||||
val moduleDir = "/data/adb/ksu/modules/zygisksu"
|
||||
exec { commandLine("adb", "push", "build/rustJniLibs/android/armeabi-v7a/zygiskd", "/data/local/tmp/zygiskd32") }
|
||||
exec { commandLine("adb", "push", "build/rustJniLibs/android/arm64-v8a/zygiskd", "/data/local/tmp/zygiskd64") }
|
||||
exec { commandLine("adb", "shell", "su", "-c", "mv /data/local/tmp/zygiskd32 $moduleDir/zygiskd32") }
|
||||
exec { commandLine("adb", "shell", "su", "-c", "mv /data/local/tmp/zygiskd64 $moduleDir/zygiskd64") }
|
||||
exec { commandLine("adb", "shell", "su", "-c", "ln -sf zygiskd64 $moduleDir/zygiskwd") }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@ use num_enum::TryFromPrimitive;
|
||||
|
||||
pub const PROP_NATIVE_BRIDGE: &str = "ro.dalvik.vm.native.bridge";
|
||||
|
||||
pub const KSU_MODULE_DIR: &str = "/data/adb/ksu/modules";
|
||||
pub const ZYGISKSU_DIR: &str = concatcp!(KSU_MODULE_DIR, "/zygisksu");
|
||||
pub const ZYGISKWD: &str = concatcp!(ZYGISKSU_DIR, "/zygiskwd");
|
||||
pub const ZYGISKD32: &str = concatcp!(ZYGISKSU_DIR, "/zygiskd32");
|
||||
pub const ZYGISKD64: &str = concatcp!(ZYGISKSU_DIR, "/zygiskd64");
|
||||
pub const DAEMON_LOCK: &str = concatcp!(ZYGISKSU_DIR, "/zygiskd.lock");
|
||||
pub const PATH_KSU_MODULE_DIR: &str = "/data/adb/ksu/modules";
|
||||
pub const PATH_ZYGISKSU_DIR: &str = concatcp!(PATH_KSU_MODULE_DIR, "/zygisksu");
|
||||
pub const PATH_ZYGISKWD: &str = concatcp!(PATH_ZYGISKSU_DIR, "/zygiskwd");
|
||||
pub const PATH_ZYGISKD32: &str = concatcp!(PATH_ZYGISKSU_DIR, "/zygiskd32");
|
||||
pub const PATH_ZYGISKD64: &str = concatcp!(PATH_ZYGISKSU_DIR, "/zygiskd64");
|
||||
pub const PATH_DAEMON_LOCK: &str = concatcp!(PATH_ZYGISKSU_DIR, "/zygiskd.lock");
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
|
||||
#[repr(u8)]
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
mod watchdog;
|
||||
mod constants;
|
||||
mod zygisk;
|
||||
mod utils;
|
||||
mod watchdog;
|
||||
mod zygisk;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use anyhow::{bail, Result};
|
||||
use log::LevelFilter;
|
||||
use nix::libc;
|
||||
|
||||
@@ -17,7 +17,7 @@ fn init_android_logger(tag: &str) {
|
||||
);
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
fn entry() -> Result<()> {
|
||||
let process = std::env::args().next().unwrap();
|
||||
let process = process.split('/').last().unwrap();
|
||||
init_android_logger(process);
|
||||
@@ -39,7 +39,13 @@ fn main() -> Result<()> {
|
||||
unsafe { libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGKILL); }
|
||||
zygisk::start(true)?;
|
||||
}
|
||||
_ => return Err(anyhow!("Unexpected process name: {process}"))
|
||||
_ => bail!("Unexpected process name: {process}")
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
if let Err(e) = entry() {
|
||||
log::error!("Crashed: {}", e.backtrace());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::constants;
|
||||
use anyhow::{anyhow, Result};
|
||||
use anyhow::{bail, Result};
|
||||
use nix::fcntl::{flock, FlockArg};
|
||||
use nix::unistd::{getgid, getuid};
|
||||
use std::os::unix::prelude::AsRawFd;
|
||||
@@ -13,17 +13,19 @@ pub fn check_permission() -> Result<()> {
|
||||
log::info!("Check permission");
|
||||
let uid = getuid();
|
||||
if uid.as_raw() != 0 {
|
||||
return Err(anyhow!("UID is not 0"));
|
||||
bail!("UID is not 0");
|
||||
}
|
||||
|
||||
let gid = getgid();
|
||||
if gid.as_raw() != 0 {
|
||||
return Err(anyhow!("GID is not 0"));
|
||||
bail!("GID is not 0");
|
||||
}
|
||||
|
||||
let context = fs::read_to_string("/proc/self/attr/current")?;
|
||||
if context != "u:r:su:s0" {
|
||||
return Err(anyhow!("SELinux context is not u:r:su:s0"));
|
||||
let context = context.trim_end_matches('\0');
|
||||
//TODO: remove magisk context after debug finished
|
||||
if context != "u:r:su:s0" && context != "u:r:magisk:s0" {
|
||||
bail!("SELinux context incorrect: {context}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -31,28 +33,26 @@ pub fn check_permission() -> Result<()> {
|
||||
|
||||
pub fn ensure_single_instance() -> Result<()> {
|
||||
log::info!("Ensure single instance");
|
||||
let metadata = fs::metadata(constants::ZYGISKSU_DIR);
|
||||
let metadata = fs::metadata(constants::PATH_ZYGISKSU_DIR);
|
||||
if metadata.is_err() || !metadata.unwrap().is_dir() {
|
||||
return Err(anyhow!("Zygisksu is not installed"));
|
||||
bail!("Zygisksu is not installed");
|
||||
}
|
||||
unsafe {
|
||||
match fs::File::create(constants::DAEMON_LOCK) {
|
||||
match fs::File::create(constants::PATH_DAEMON_LOCK) {
|
||||
Ok(file) => LOCK_FILE = Some(file),
|
||||
Err(e) => return Err(anyhow!("Failed to open lock file: {e}")),
|
||||
Err(e) => bail!("Failed to open lock file: {e}"),
|
||||
};
|
||||
let fd = LOCK_FILE.as_ref().unwrap().as_raw_fd();
|
||||
if let Err(e) = flock(fd, FlockArg::LockExclusiveNonblock) {
|
||||
return Err(anyhow!(
|
||||
"Failed to acquire lock: {e}. Maybe another instance is running?"
|
||||
));
|
||||
bail!("Failed to acquire lock: {e}. Maybe another instance is running?");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn spawn_daemon() -> Result<()> {
|
||||
let daemon32 = Command::new(constants::ZYGISKD32).spawn()?;
|
||||
let daemon64 = Command::new(constants::ZYGISKD64).spawn()?;
|
||||
let daemon32 = Command::new(constants::PATH_ZYGISKD32).spawn()?;
|
||||
let daemon64 = Command::new(constants::PATH_ZYGISKD64).spawn()?;
|
||||
let (sender, receiver) = mpsc::channel();
|
||||
let spawn = |mut daemon: Child| {
|
||||
let sender = sender.clone();
|
||||
@@ -66,5 +66,5 @@ pub fn spawn_daemon() -> Result<()> {
|
||||
spawn(daemon32);
|
||||
spawn(daemon64);
|
||||
let _ = receiver.recv();
|
||||
Err(anyhow!("Daemon process died"))
|
||||
bail!("Daemon process died");
|
||||
}
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
use crate::constants::DaemonSocketAction;
|
||||
use crate::utils::{restore_native_bridge, UnixStreamExt};
|
||||
use crate::{constants, utils};
|
||||
use anyhow::{anyhow, Result};
|
||||
use anyhow::{bail, Result};
|
||||
use memfd::Memfd;
|
||||
use nix::{
|
||||
libc::{self, dlsym},
|
||||
unistd::getppid,
|
||||
};
|
||||
use passfd::FdPassingExt;
|
||||
use std::cell::Cell;
|
||||
use std::io::Write;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::{
|
||||
ffi::c_void,
|
||||
fs,
|
||||
os::unix::{
|
||||
net::{UnixListener, UnixStream},
|
||||
prelude::AsRawFd,
|
||||
},
|
||||
path::PathBuf,
|
||||
use std::ffi::c_void;
|
||||
use std::fs;
|
||||
use std::os::fd::FromRawFd;
|
||||
use std::os::unix::{
|
||||
net::{UnixListener, UnixStream},
|
||||
prelude::AsRawFd,
|
||||
};
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use nix::sys::socket::{AddressFamily, SockFlag, SockType, UnixAddr};
|
||||
|
||||
type ZygiskCompanionEntryFn = unsafe extern "C" fn(i32);
|
||||
|
||||
@@ -33,11 +33,11 @@ struct Module {
|
||||
struct Context {
|
||||
native_bridge: String,
|
||||
modules: Arc<Vec<Module>>,
|
||||
stream: Cell<UnixStream>,
|
||||
listener: UnixListener,
|
||||
}
|
||||
|
||||
pub fn start(is64: bool) -> Result<()> {
|
||||
// check_parent()?;
|
||||
check_parent()?;
|
||||
let arch = get_arch(is64)?;
|
||||
log::debug!("Daemon architecture: {arch}");
|
||||
|
||||
@@ -47,56 +47,44 @@ pub fn start(is64: bool) -> Result<()> {
|
||||
log::info!("Create socket");
|
||||
let listener = create_daemon_socket(is64)?;
|
||||
|
||||
log::info!("Waiting for connection");
|
||||
let (stream, _) = listener.accept()?;
|
||||
drop(listener);
|
||||
|
||||
let context = Context {
|
||||
native_bridge: utils::get_native_bridge(),
|
||||
modules: Arc::new(modules),
|
||||
stream: Cell::new(stream),
|
||||
listener,
|
||||
};
|
||||
|
||||
log::info!("Connection established");
|
||||
restore_native_bridge()?;
|
||||
log::info!("Start to listen zygote connections");
|
||||
handle_daemon_actions(context)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_parent() -> Result<()> {
|
||||
let parent = fs::read_link(format!("/proc/{}/exe", getppid().as_raw()))?;
|
||||
let parent = parent.file_name().unwrap().to_str().unwrap();
|
||||
if parent != constants::ZYGISKWD {
|
||||
return Err(anyhow!("zygiskd is not started by watchdog"));
|
||||
let parent = fs::read_to_string(format!("/proc/{}/cmdline", getppid().as_raw()))?;
|
||||
let parent = parent.split('/').last().unwrap().trim_end_matches('\0');
|
||||
if parent != "zygiskwd" {
|
||||
bail!("Daemon is not started by watchdog: {parent}");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_arch(is64: bool) -> Result<&'static str> {
|
||||
// let output = Command::new("getprop ro.product.cpu.abi").output()?;
|
||||
// let system_arch = String::from_utf8(output.stdout)?;
|
||||
let system_arch = "x86_64"; // DEBUGGING
|
||||
let output = Command::new("getprop").arg("ro.product.cpu.abi").output()?;
|
||||
let system_arch = String::from_utf8(output.stdout)?;
|
||||
let is_arm = system_arch.contains("arm");
|
||||
let is_x86 = system_arch.contains("x86");
|
||||
if is64 {
|
||||
match (is_arm, is_x86) {
|
||||
(true, _) => Ok("arm64-v8a"),
|
||||
(_, true) => Ok("x86_64"),
|
||||
_ => Err(anyhow!("Unsupported system architecture: {}", system_arch)),
|
||||
}
|
||||
} else {
|
||||
match (is_arm, is_x86) {
|
||||
(true, _) => Ok("armeabi-v7a"),
|
||||
(_, true) => Ok("x86"),
|
||||
_ => Err(anyhow!("Unsupported system architecture: {}", system_arch)),
|
||||
}
|
||||
match (is_arm, is_x86, is64) {
|
||||
(true, _, false) => Ok("armeabi-v7a"),
|
||||
(true, _, true) => Ok("arm64-v8a"),
|
||||
(_, true, false) => Ok("x86"),
|
||||
(_, true, true) => Ok("x86_64"),
|
||||
_ => bail!("Unsupported system architecture: {}", system_arch),
|
||||
}
|
||||
}
|
||||
|
||||
fn load_modules(arch: &str) -> Result<Vec<Module>> {
|
||||
let mut modules = Vec::new();
|
||||
let dir = match fs::read_dir(constants::KSU_MODULE_DIR) {
|
||||
let dir = match fs::read_dir(constants::PATH_KSU_MODULE_DIR) {
|
||||
Ok(dir) => dir,
|
||||
Err(e) => {
|
||||
log::warn!("Failed reading modules directory: {}", e);
|
||||
@@ -119,7 +107,7 @@ fn load_modules(arch: &str) -> Result<Vec<Module>> {
|
||||
}
|
||||
};
|
||||
let companion_entry = match preload_module(&memfd) {
|
||||
Ok(companion_entry) => companion_entry,
|
||||
Ok(entry) => entry,
|
||||
Err(e) => {
|
||||
log::warn!(" Failed to preload `{name}`: {e}");
|
||||
continue;
|
||||
@@ -136,7 +124,7 @@ fn load_modules(arch: &str) -> Result<Vec<Module>> {
|
||||
Ok(modules)
|
||||
}
|
||||
|
||||
fn create_memfd(name: &str, so_path: &PathBuf) -> Result<memfd::Memfd> {
|
||||
fn create_memfd(name: &str, so_path: &PathBuf) -> Result<Memfd> {
|
||||
let opts = memfd::MemfdOptions::default().allow_sealing(true);
|
||||
let memfd = opts.create(name)?;
|
||||
|
||||
@@ -164,7 +152,7 @@ fn preload_module(memfd: &Memfd) -> Result<Option<ZygiskCompanionEntryFn>> {
|
||||
let e = std::ffi::CStr::from_ptr(libc::dlerror())
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
return Err(anyhow!("dlopen failed: {}", e));
|
||||
bail!("dlopen failed: {}", e);
|
||||
}
|
||||
let symbol = std::ffi::CString::new("zygisk_companion_entry")?;
|
||||
let entry = dlsym(handle, symbol.as_ptr());
|
||||
@@ -178,17 +166,25 @@ fn preload_module(memfd: &Memfd) -> Result<Option<ZygiskCompanionEntryFn>> {
|
||||
|
||||
fn create_daemon_socket(is64: bool) -> Result<UnixListener> {
|
||||
utils::set_socket_create_context("u:r:zygote:s0")?;
|
||||
let socket_name = if is64 { "zygiskd64" } else { "zygiskd32" };
|
||||
let listener = UnixListener::bind(socket_name)?;
|
||||
let name = if is64 { "zygiskd64" } else { "zygiskd32" };
|
||||
// TODO: Replace with SockAddrExt::from_abstract_name when it's stable
|
||||
let addr = UnixAddr::new_abstract(name.as_bytes())?;
|
||||
let socket = nix::sys::socket::socket(AddressFamily::Unix, SockType::Stream, SockFlag::empty(), None)?;
|
||||
nix::sys::socket::bind(socket, &addr)?;
|
||||
log::debug!("Listening on {}", addr);
|
||||
log::debug!("Socket fd: {}", socket);
|
||||
let listener = unsafe { UnixListener::from_raw_fd(socket) };
|
||||
Ok(listener)
|
||||
}
|
||||
|
||||
fn handle_daemon_actions(mut context: Context) -> Result<()> {
|
||||
let stream = context.stream.get_mut();
|
||||
fn handle_daemon_actions(context: Context) -> Result<()> {
|
||||
loop {
|
||||
let (mut stream, _) = context.listener.accept()?;
|
||||
let action = stream.read_u8()?;
|
||||
match DaemonSocketAction::try_from(action) {
|
||||
// First connection from zygote
|
||||
Ok(DaemonSocketAction::ReadNativeBridge) => {
|
||||
restore_native_bridge()?;
|
||||
stream.write_usize(context.native_bridge.len())?;
|
||||
stream.write_all(context.native_bridge.as_bytes())?;
|
||||
}
|
||||
@@ -210,9 +206,7 @@ fn handle_daemon_actions(mut context: Context) -> Result<()> {
|
||||
}
|
||||
});
|
||||
}
|
||||
Err(_) => {
|
||||
return Err(anyhow!("Invalid action code: {action}"));
|
||||
}
|
||||
Err(_) => bail!("Invalid action code: {action}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -226,15 +220,13 @@ fn create_companion(mut server: UnixStream, modules: &Vec<Module>) -> Result<()>
|
||||
let module = &modules[index];
|
||||
log::debug!("New companion request from module {}", module.name);
|
||||
|
||||
unsafe {
|
||||
match module.companion_entry {
|
||||
Some(entry) => {
|
||||
let (sock_app, sock_companion) = UnixStream::pair()?;
|
||||
server.send_fd(sock_app.as_raw_fd())?;
|
||||
entry(sock_companion.as_raw_fd());
|
||||
}
|
||||
None => (),
|
||||
match module.companion_entry {
|
||||
Some(entry) => {
|
||||
let (sock_app, sock_companion) = UnixStream::pair()?;
|
||||
server.send_fd(sock_app.as_raw_fd())?;
|
||||
unsafe { entry(sock_companion.as_raw_fd()); }
|
||||
}
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user