You've already forked ReZygisk
mirror of
https://github.com/PerformanC/ReZygisk.git
synced 2025-09-06 06:37:01 +00:00
add: base for C99 zygiskd
This commit adds the first base for C99 zygiskd, that is not fully working or code-ready.
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
use std::process::{Command, Stdio};
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufRead, BufReader};
|
||||
use serde::Deserialize;
|
||||
use crate::constants::MIN_APATCH_VERSION;
|
||||
|
||||
pub enum Version {
|
||||
Supported,
|
||||
TooOld,
|
||||
Abnormal,
|
||||
}
|
||||
|
||||
fn parse_version(output: &str) -> i32 {
|
||||
let mut version: Option<i32> = None;
|
||||
for line in output.lines() {
|
||||
if let Some(num) = line.trim().split_whitespace().last() {
|
||||
if let Ok(v) = num.parse::<i32>() {
|
||||
version = Some(v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
version.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn read_su_path() -> Result<String, io::Error> {
|
||||
let file = File::open("/data/adb/ap/su_path")?;
|
||||
let mut reader = BufReader::new(file);
|
||||
let mut su_path = String::new();
|
||||
reader.read_line(&mut su_path)?;
|
||||
Ok(su_path.trim().to_string())
|
||||
}
|
||||
|
||||
pub fn get_apatch() -> Option<Version> {
|
||||
let default_su_path = String::from("/system/bin/su");
|
||||
let su_path = read_su_path().ok()?;
|
||||
|
||||
let output = Command::new(&su_path)
|
||||
.arg("-v")
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::null())
|
||||
.output()
|
||||
.ok()?;
|
||||
let stdout = String::from_utf8(output.stdout).ok()?;
|
||||
if !stdout.contains("APatch") {
|
||||
return None;
|
||||
}
|
||||
|
||||
let output1 = Command::new("/data/adb/apd")
|
||||
.arg("-V")
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::null())
|
||||
.output()
|
||||
.ok()?;
|
||||
let stdout1 = String::from_utf8(output1.stdout).ok()?;
|
||||
if su_path == default_su_path {
|
||||
let version = parse_version(&stdout1);
|
||||
const MAX_OLD_VERSION: i32 = MIN_APATCH_VERSION - 1;
|
||||
match version {
|
||||
0 => Some(Version::Abnormal),
|
||||
v if v >= MIN_APATCH_VERSION && v <= 999999 => Some(Version::Supported),
|
||||
v if v >= 1 && v <= MAX_OLD_VERSION => Some(Version::TooOld),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[allow(dead_code)]
|
||||
struct PackageConfig {
|
||||
pkg: String,
|
||||
exclude: i32,
|
||||
allow: i32,
|
||||
uid: i32,
|
||||
to_uid: i32,
|
||||
sctx: String,
|
||||
}
|
||||
|
||||
fn read_package_config() -> Result<Vec<PackageConfig>, std::io::Error> {
|
||||
let file = File::open("/data/adb/ap/package_config")?;
|
||||
let mut reader = csv::Reader::from_reader(file);
|
||||
|
||||
let mut package_configs = Vec::new();
|
||||
for record in reader.deserialize() {
|
||||
match record {
|
||||
Ok(config) => package_configs.push(config),
|
||||
Err(error) => {
|
||||
log::warn!("Error deserializing record: {}", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(package_configs)
|
||||
}
|
||||
|
||||
pub fn uid_granted_root(uid: i32) -> bool {
|
||||
match read_package_config() {
|
||||
Ok(package_configs) => {
|
||||
package_configs
|
||||
.iter()
|
||||
.find(|config| config.uid == uid)
|
||||
.map(|config| config.allow == 1)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
Err(err) => {
|
||||
log::warn!("Error reading package config: {}", err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn uid_should_umount(uid: i32) -> bool {
|
||||
match read_package_config() {
|
||||
Ok(package_configs) => {
|
||||
package_configs
|
||||
.iter()
|
||||
.find(|config| config.uid == uid)
|
||||
.map(|config| {
|
||||
match config.exclude {
|
||||
1 => true,
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
Err(err) => {
|
||||
log::warn!("Error reading package configs: {}", err);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: signature
|
||||
pub fn uid_is_manager(uid: i32) -> bool {
|
||||
if let Ok(s) = rustix::fs::stat("/data/user_de/0/me.bmax.apatch") {
|
||||
return s.st_uid == uid as u32;
|
||||
}
|
||||
false
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
use crate::constants::{MAX_KSU_VERSION, MIN_KSU_VERSION};
|
||||
|
||||
const KERNEL_SU_OPTION: u32 = 0xdeadbeefu32;
|
||||
|
||||
const CMD_GET_VERSION: usize = 2;
|
||||
const CMD_UID_GRANTED_ROOT: usize = 12;
|
||||
const CMD_UID_SHOULD_UMOUNT: usize = 13;
|
||||
|
||||
pub enum Version {
|
||||
Supported,
|
||||
TooOld,
|
||||
Abnormal,
|
||||
}
|
||||
|
||||
pub fn get_kernel_su() -> Option<Version> {
|
||||
let mut version = 0;
|
||||
unsafe {
|
||||
libc::prctl(
|
||||
KERNEL_SU_OPTION as i32,
|
||||
CMD_GET_VERSION,
|
||||
&mut version as *mut i32,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
};
|
||||
const MAX_OLD_VERSION: i32 = MIN_KSU_VERSION - 1;
|
||||
match version {
|
||||
0 => None,
|
||||
MIN_KSU_VERSION..=MAX_KSU_VERSION => Some(Version::Supported),
|
||||
1..=MAX_OLD_VERSION => Some(Version::TooOld),
|
||||
_ => Some(Version::Abnormal),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn uid_granted_root(uid: i32) -> bool {
|
||||
let mut result: u32 = 0;
|
||||
let mut granted = false;
|
||||
unsafe {
|
||||
libc::prctl(
|
||||
KERNEL_SU_OPTION as i32,
|
||||
CMD_UID_GRANTED_ROOT,
|
||||
uid,
|
||||
&mut granted as *mut bool,
|
||||
&mut result as *mut u32,
|
||||
)
|
||||
};
|
||||
if result != KERNEL_SU_OPTION {
|
||||
log::warn!("uid_granted_root failed");
|
||||
}
|
||||
granted
|
||||
}
|
||||
|
||||
pub fn uid_should_umount(uid: i32) -> bool {
|
||||
let mut result: u32 = 0;
|
||||
let mut umount = false;
|
||||
unsafe {
|
||||
libc::prctl(
|
||||
KERNEL_SU_OPTION as i32,
|
||||
CMD_UID_SHOULD_UMOUNT,
|
||||
uid,
|
||||
&mut umount as *mut bool,
|
||||
&mut result as *mut u32,
|
||||
)
|
||||
};
|
||||
if result != KERNEL_SU_OPTION {
|
||||
log::warn!("uid_granted_root failed");
|
||||
}
|
||||
umount
|
||||
}
|
||||
|
||||
// TODO: signature
|
||||
pub fn uid_is_manager(uid: i32) -> bool {
|
||||
if let Ok(s) = rustix::fs::stat("/data/user_de/0/me.weishu.kernelsu") {
|
||||
return s.st_uid == uid as u32;
|
||||
}
|
||||
false
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
use std::fs;
|
||||
use std::os::android::fs::MetadataExt;
|
||||
use crate::constants::MIN_MAGISK_VERSION;
|
||||
use std::process::{Command, Stdio};
|
||||
use log::info;
|
||||
use crate::utils::LateInit;
|
||||
|
||||
const MAGISK_OFFICIAL: &str = "com.topjohnwu.magisk";
|
||||
const MAGISK_THIRD_PARTIES: &[(&str, &str)] = &[
|
||||
("alpha", "io.github.vvb2060.magisk"),
|
||||
("kitsune", "io.github.huskydg.magisk"),
|
||||
];
|
||||
|
||||
pub enum Version {
|
||||
Supported,
|
||||
TooOld,
|
||||
}
|
||||
|
||||
static VARIANT: LateInit<&str> = LateInit::new();
|
||||
|
||||
pub fn get_magisk() -> Option<Version> {
|
||||
if !VARIANT.initiated() {
|
||||
Command::new("magisk")
|
||||
.arg("-v")
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()
|
||||
.ok()
|
||||
.and_then(|child| child.wait_with_output().ok())
|
||||
.and_then(|output| String::from_utf8(output.stdout).ok())
|
||||
.map(|version| {
|
||||
let third_party = MAGISK_THIRD_PARTIES.iter().find_map(|v| {
|
||||
version.contains(v.0).then_some(v.1)
|
||||
});
|
||||
VARIANT.init(third_party.unwrap_or(MAGISK_OFFICIAL));
|
||||
info!("Magisk variant: {}", *VARIANT);
|
||||
});
|
||||
}
|
||||
Command::new("magisk")
|
||||
.arg("-V")
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()
|
||||
.ok()
|
||||
.and_then(|child| child.wait_with_output().ok())
|
||||
.and_then(|output| String::from_utf8(output.stdout).ok())
|
||||
.and_then(|output| output.trim().parse::<i32>().ok())
|
||||
.map(|version| {
|
||||
if version >= MIN_MAGISK_VERSION {
|
||||
Version::Supported
|
||||
} else {
|
||||
Version::TooOld
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn uid_granted_root(uid: i32) -> bool {
|
||||
Command::new("magisk")
|
||||
.arg("--sqlite")
|
||||
.arg(format!(
|
||||
"select 1 from policies where uid={uid} and policy=2 limit 1"
|
||||
))
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()
|
||||
.ok()
|
||||
.and_then(|child| child.wait_with_output().ok())
|
||||
.and_then(|output| String::from_utf8(output.stdout).ok())
|
||||
.map(|output| output.is_empty())
|
||||
== Some(false)
|
||||
}
|
||||
|
||||
pub fn uid_should_umount(uid: i32) -> bool {
|
||||
let output = Command::new("pm")
|
||||
.args(["list", "packages", "--uid", &uid.to_string()])
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()
|
||||
.ok()
|
||||
.and_then(|child| child.wait_with_output().ok())
|
||||
.and_then(|output| String::from_utf8(output.stdout).ok());
|
||||
let line = match output {
|
||||
Some(line) => line,
|
||||
None => return false,
|
||||
};
|
||||
let pkg = line
|
||||
.strip_prefix("package:")
|
||||
.and_then(|line| line.split(' ').next());
|
||||
let pkg = match pkg {
|
||||
Some(pkg) => pkg,
|
||||
None => return false,
|
||||
};
|
||||
Command::new("magisk")
|
||||
.arg("--sqlite")
|
||||
.arg(format!(
|
||||
"select 1 from denylist where package_name=\"{pkg}\" limit 1"
|
||||
))
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()
|
||||
.ok()
|
||||
.and_then(|child| child.wait_with_output().ok())
|
||||
.and_then(|output| String::from_utf8(output.stdout).ok())
|
||||
.map(|output| output.is_empty())
|
||||
== Some(false)
|
||||
}
|
||||
|
||||
// TODO: signature
|
||||
pub fn uid_is_manager(uid: i32) -> bool {
|
||||
let output = Command::new("magisk")
|
||||
.arg("--sqlite")
|
||||
.arg(format!("select value from strings where key=\"requester\" limit 1"))
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()
|
||||
.ok()
|
||||
.and_then(|child| child.wait_with_output().ok())
|
||||
.and_then(|output| String::from_utf8(output.stdout).ok())
|
||||
.map(|output| output.trim().to_string());
|
||||
if let Some(output) = output {
|
||||
if let Some(manager) = output.strip_prefix("value=") {
|
||||
return fs::metadata(format!("/data/user_de/0/{}", manager))
|
||||
.map(|s| s.st_uid() == uid as u32)
|
||||
.unwrap_or(false);
|
||||
}
|
||||
}
|
||||
fs::metadata(format!("/data/user_de/0/{}", *VARIANT))
|
||||
.map(|s| s.st_uid() == uid as u32)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
use std::ptr::addr_of;
|
||||
|
||||
mod kernelsu;
|
||||
mod magisk;
|
||||
mod apatch;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RootImpl {
|
||||
None,
|
||||
TooOld,
|
||||
Abnormal,
|
||||
Multiple,
|
||||
KernelSU,
|
||||
Magisk,
|
||||
APatch,
|
||||
}
|
||||
|
||||
static mut ROOT_IMPL: RootImpl = RootImpl::None;
|
||||
|
||||
pub fn setup() {
|
||||
let apatch_version = apatch::get_apatch();
|
||||
let ksu_version = kernelsu::get_kernel_su();
|
||||
let magisk_version = magisk::get_magisk();
|
||||
|
||||
let impl_ = match (apatch_version, ksu_version, magisk_version) {
|
||||
(None, None, None) => RootImpl::None,
|
||||
(Some(_), Some(_), Some(_)) => RootImpl::Multiple,
|
||||
(Some(apatch_version),None, None) => match apatch_version {
|
||||
apatch::Version::Supported => RootImpl::APatch,
|
||||
apatch::Version::TooOld => RootImpl::TooOld,
|
||||
apatch::Version::Abnormal => RootImpl::Abnormal,
|
||||
},
|
||||
(None,Some(ksu_version), None) => match ksu_version {
|
||||
kernelsu::Version::Supported => RootImpl::KernelSU,
|
||||
kernelsu::Version::TooOld => RootImpl::TooOld,
|
||||
kernelsu::Version::Abnormal => RootImpl::Abnormal,
|
||||
},
|
||||
(None, None, Some(magisk_version)) => match magisk_version {
|
||||
magisk::Version::Supported => RootImpl::Magisk,
|
||||
magisk::Version::TooOld => RootImpl::TooOld,
|
||||
},
|
||||
_ => RootImpl::None,
|
||||
};
|
||||
unsafe {
|
||||
ROOT_IMPL = impl_;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_impl() -> &'static RootImpl {
|
||||
unsafe { &*addr_of!(ROOT_IMPL) }
|
||||
}
|
||||
|
||||
pub fn uid_granted_root(uid: i32) -> bool {
|
||||
match get_impl() {
|
||||
RootImpl::KernelSU => kernelsu::uid_granted_root(uid),
|
||||
RootImpl::Magisk => magisk::uid_granted_root(uid),
|
||||
RootImpl::APatch => apatch::uid_granted_root(uid),
|
||||
_ => panic!("uid_granted_root: unknown root impl {:?}", get_impl()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn uid_should_umount(uid: i32) -> bool {
|
||||
match get_impl() {
|
||||
RootImpl::KernelSU => kernelsu::uid_should_umount(uid),
|
||||
RootImpl::Magisk => magisk::uid_should_umount(uid),
|
||||
RootImpl::APatch => apatch::uid_should_umount(uid),
|
||||
_ => panic!("uid_should_umount: unknown root impl {:?}", get_impl()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn uid_is_manager(uid: i32) -> bool {
|
||||
match get_impl() {
|
||||
RootImpl::KernelSU => kernelsu::uid_is_manager(uid),
|
||||
RootImpl::Magisk => magisk::uid_is_manager(uid),
|
||||
RootImpl::APatch => apatch::uid_is_manager(uid),
|
||||
_ => panic!("uid_is_manager: unknown root impl {:?}", get_impl()),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user