You've already forked ReZygisk
mirror of
https://github.com/PerformanC/ReZygisk.git
synced 2025-09-06 06:37:01 +00:00
Add injector
This commit is contained in:
@@ -14,6 +14,7 @@ memfd = "0.6.2"
|
||||
nix = "0.26.2"
|
||||
num_enum = "0.5.9"
|
||||
passfd = "0.1.5"
|
||||
rand = "0.8.5"
|
||||
|
||||
[profile.release]
|
||||
strip = true
|
||||
|
||||
@@ -3,17 +3,22 @@ use num_enum::TryFromPrimitive;
|
||||
|
||||
pub const PROP_NATIVE_BRIDGE: &str = "ro.dalvik.vm.native.bridge";
|
||||
|
||||
pub const SOCKET_PLACEHOLDER: &str = "placeholder123456";
|
||||
|
||||
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_INJECTOR: &str = concatcp!(PATH_ZYGISKSU_DIR, "/libinjector.so");
|
||||
pub const PATH_DAEMON_LOCK: &str = concatcp!(PATH_ZYGISKSU_DIR, "/zygiskd.lock");
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum DaemonSocketAction {
|
||||
PingHeartbeat,
|
||||
ReadNativeBridge,
|
||||
ReadInjector,
|
||||
ReadModules,
|
||||
RequestCompanionSocket,
|
||||
}
|
||||
|
||||
@@ -2,6 +2,14 @@ use crate::constants;
|
||||
use anyhow::Result;
|
||||
use nix::unistd::gettid;
|
||||
use std::{fs, io::{Read, Write}, os::unix::net::UnixStream, process::Command};
|
||||
use std::os::fd::FromRawFd;
|
||||
use std::os::unix::net::UnixListener;
|
||||
use nix::sys::socket::{AddressFamily, SockFlag, SockType, UnixAddr};
|
||||
use rand::distributions::{Alphanumeric, DistString};
|
||||
|
||||
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";
|
||||
@@ -16,7 +24,7 @@ pub fn set_socket_create_context(context: &str) -> Result<()> {
|
||||
}
|
||||
|
||||
pub fn get_native_bridge() -> String {
|
||||
std::env::var("NATIVE_BRIDGE").unwrap_or("0".to_string())
|
||||
std::env::var("NATIVE_BRIDGE").unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn restore_native_bridge() -> Result<()> {
|
||||
@@ -29,6 +37,7 @@ pub trait UnixStreamExt {
|
||||
fn read_u8(&mut self) -> Result<u8>;
|
||||
fn read_u32(&mut self) -> Result<u32>;
|
||||
fn read_usize(&mut self) -> Result<usize>;
|
||||
fn write_u8(&mut self, value: u8) -> Result<()>;
|
||||
fn write_usize(&mut self, value: usize) -> Result<()>;
|
||||
}
|
||||
|
||||
@@ -51,8 +60,23 @@ impl UnixStreamExt for UnixStream {
|
||||
Ok(usize::from_ne_bytes(buf))
|
||||
}
|
||||
|
||||
fn write_u8(&mut self, value: u8) -> Result<()> {
|
||||
self.write_all(&value.to_ne_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_usize(&mut self, value: usize) -> Result<()> {
|
||||
self.write_all(&value.to_ne_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Replace with SockAddrExt::from_abstract_name when it's stable
|
||||
pub fn abstract_namespace_socket(name: &str) -> Result<UnixListener> {
|
||||
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)?;
|
||||
nix::sys::socket::listen(socket, 2)?;
|
||||
let listener = unsafe { UnixListener::from_raw_fd(socket) };
|
||||
Ok(listener)
|
||||
}
|
||||
|
||||
@@ -13,14 +13,13 @@ use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::ffi::c_void;
|
||||
use std::fs;
|
||||
use std::os::fd::FromRawFd;
|
||||
use std::os::fd::IntoRawFd;
|
||||
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);
|
||||
|
||||
@@ -32,8 +31,7 @@ struct Module {
|
||||
|
||||
struct Context {
|
||||
native_bridge: String,
|
||||
modules: Arc<Vec<Module>>,
|
||||
listener: UnixListener,
|
||||
modules: Vec<Module>,
|
||||
}
|
||||
|
||||
pub fn start(is64: bool) -> Result<()> {
|
||||
@@ -44,17 +42,25 @@ pub fn start(is64: bool) -> Result<()> {
|
||||
log::info!("Load modules");
|
||||
let modules = load_modules(arch)?;
|
||||
|
||||
let context = Context {
|
||||
native_bridge: utils::get_native_bridge(),
|
||||
modules,
|
||||
};
|
||||
let context = Arc::new(context);
|
||||
|
||||
log::info!("Create socket");
|
||||
let listener = create_daemon_socket(is64)?;
|
||||
|
||||
let context = Context {
|
||||
native_bridge: utils::get_native_bridge(),
|
||||
modules: Arc::new(modules),
|
||||
listener,
|
||||
};
|
||||
|
||||
log::info!("Start to listen zygote connections");
|
||||
handle_daemon_actions(context)?;
|
||||
log::info!("Handle zygote connections");
|
||||
for stream in listener.incoming() {
|
||||
let stream = stream?;
|
||||
let context = Arc::clone(&context);
|
||||
thread::spawn(move || {
|
||||
if let Err(e) = handle_daemon_action(stream, &context) {
|
||||
log::warn!("Error handling daemon action: {e}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -166,68 +172,52 @@ 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 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)?;
|
||||
nix::sys::socket::listen(socket, 2)?;
|
||||
log::debug!("Listening on {}", addr);
|
||||
log::debug!("Socket fd: {}", socket);
|
||||
let listener = unsafe { UnixListener::from_raw_fd(socket) };
|
||||
let suffix = if is64 { "zygiskd64" } else { "zygiskd32" };
|
||||
let name = String::from(suffix) + constants::SOCKET_PLACEHOLDER;
|
||||
let listener = utils::abstract_namespace_socket(&name)?;
|
||||
Ok(listener)
|
||||
}
|
||||
|
||||
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())?;
|
||||
fn handle_daemon_action(mut stream: UnixStream, context: &Context) -> Result<()> {
|
||||
let action = stream.read_u8()?;
|
||||
match DaemonSocketAction::try_from(action) {
|
||||
Ok(DaemonSocketAction::PingHeartbeat) => {
|
||||
// Do nothing
|
||||
}
|
||||
Ok(DaemonSocketAction::ReadNativeBridge) => {
|
||||
restore_native_bridge()?;
|
||||
stream.write_usize(context.native_bridge.len())?;
|
||||
stream.write_all(context.native_bridge.as_bytes())?;
|
||||
}
|
||||
Ok(DaemonSocketAction::ReadInjector) => {
|
||||
let so_path = PathBuf::from(constants::PATH_INJECTOR);
|
||||
let memfd = create_memfd("injector", &so_path)?;
|
||||
stream.send_fd(memfd.into_raw_fd())?;
|
||||
}
|
||||
Ok(DaemonSocketAction::ReadModules) => {
|
||||
stream.write_usize(context.modules.len())?;
|
||||
for module in context.modules.iter() {
|
||||
stream.write_usize(module.name.len())?;
|
||||
stream.write_all(module.name.as_bytes())?;
|
||||
stream.send_fd(module.memfd.as_raw_fd())?;
|
||||
}
|
||||
Ok(DaemonSocketAction::ReadModules) => {
|
||||
stream.write_usize(context.modules.len())?;
|
||||
for module in context.modules.iter() {
|
||||
stream.write_usize(module.name.len())?;
|
||||
stream.write_all(module.name.as_bytes())?;
|
||||
stream.send_fd(module.memfd.as_raw_fd())?;
|
||||
}
|
||||
Ok(DaemonSocketAction::RequestCompanionSocket) => {
|
||||
let index = stream.read_usize()?;
|
||||
let module = &context.modules[index];
|
||||
log::debug!("New companion request from module {}", module.name);
|
||||
|
||||
match module.companion_entry {
|
||||
Some(entry) => {
|
||||
stream.write_u8(1)?;
|
||||
unsafe { entry(stream.as_raw_fd()); }
|
||||
}
|
||||
None => {
|
||||
stream.write_u8(0)?;
|
||||
}
|
||||
}
|
||||
Ok(DaemonSocketAction::RequestCompanionSocket) => {
|
||||
let (server, client) = UnixStream::pair()?;
|
||||
stream.send_fd(client.as_raw_fd())?;
|
||||
let modules_ref = Arc::clone(&context.modules);
|
||||
thread::spawn(move || {
|
||||
if let Err(e) = create_companion(server, modules_ref.as_ref()) {
|
||||
log::warn!("Companion thread exited: {e}");
|
||||
}
|
||||
});
|
||||
}
|
||||
Err(_) => bail!("Invalid action code: {action}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_companion(mut server: UnixStream, modules: &Vec<Module>) -> Result<()> {
|
||||
loop {
|
||||
let index = match server.read_usize() {
|
||||
Ok(index) => index,
|
||||
Err(_) => return Ok(()), // EOF
|
||||
};
|
||||
let module = &modules[index];
|
||||
log::debug!("New companion request from module {}", module.name);
|
||||
|
||||
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 => (),
|
||||
}
|
||||
Err(_) => bail!("Invalid action code: {action}")
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user