From 2047bdb1bf9c1a4d9462760a32a70462ec3228ba Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 22 Jun 2024 22:13:29 -0400 Subject: [PATCH] add: APatch support (#4) This commit adds support for APatch. --- README.md | 2 +- build.gradle.kts | 1 + loader/src/common/daemon.cpp | 4 +- loader/src/include/daemon.h | 1 + loader/src/injector/hook.cpp | 2 + loader/src/injector/module.hpp | 1 + loader/src/injector/unmount.cpp | 41 ++++++++++++ loader/src/injector/zygisk.hpp | 1 + loader/src/ptracer/main.cpp | 5 ++ module/build.gradle.kts | 14 ++++ module/src/customize.sh | 9 +++ zygiskd/Cargo.toml | 2 + zygiskd/build.gradle.kts | 3 + zygiskd/src/constants.rs | 2 + zygiskd/src/root_impl/apatch.rs | 113 ++++++++++++++++++++++++++++++++ zygiskd/src/root_impl/mod.rs | 22 +++++-- zygiskd/src/zygiskd.rs | 3 +- 17 files changed, 218 insertions(+), 8 deletions(-) create mode 100644 zygiskd/src/root_impl/apatch.rs diff --git a/README.md b/README.md index e89976e..49f2cd5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ReZygisk -ReZygisk is a fork of Zygisk Next by Dr-TSNG, which is a standalone implementation of Zygisk, providing Zygisk API support for KernelSU, Magisk and futurely APatch. +ReZygisk is a fork of Zygisk Next by Dr-TSNG, which is a standalone implementation of Zygisk, providing Zygisk API support for KernelSU, Magisk and APatch. It aims at the re-write of Zygisk Next to C, allowing also a more efficient and faster implementation of the Zygisk API with a more permissive license. diff --git a/build.gradle.kts b/build.gradle.kts index 2e6748f..832c9bf 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -23,6 +23,7 @@ val moduleName by extra("ReZygisk") val verName by extra("v1.0.0") val verCode by extra(gitCommitCount) val commitHash by extra(gitCommitHash) +val minApatchVersion by extra(10655) val minKsuVersion by extra(10940) val minKsudVersion by extra(11425) val maxKsuVersion by extra(20000) diff --git a/loader/src/common/daemon.cpp b/loader/src/common/daemon.cpp index bdb8d1f..fe2de4e 100644 --- a/loader/src/common/daemon.cpp +++ b/loader/src/common/daemon.cpp @@ -153,7 +153,9 @@ namespace zygiskd { int flags = socket_utils::read_u32(fd); - if (flags & (1 << 29)) { + if (flags & (1 << 27)) { + info->root_impl = ZYGOTE_ROOT_IMPL_APATCH; + } else if (flags & (1 << 29)) { info->root_impl = ZYGOTE_ROOT_IMPL_KERNELSU; } else if (flags & (1 << 30)) { info->root_impl = ZYGOTE_ROOT_IMPL_MAGISK; diff --git a/loader/src/include/daemon.h b/loader/src/include/daemon.h index 94b2d52..d667cc1 100644 --- a/loader/src/include/daemon.h +++ b/loader/src/include/daemon.h @@ -44,6 +44,7 @@ private: enum zygote_root_impl { ZYGOTE_ROOT_IMPL_NONE, + ZYGOTE_ROOT_IMPL_APATCH, ZYGOTE_ROOT_IMPL_KERNELSU, ZYGOTE_ROOT_IMPL_MAGISK }; diff --git a/loader/src/injector/hook.cpp b/loader/src/injector/hook.cpp index 16c3f01..9dcfa9a 100644 --- a/loader/src/injector/hook.cpp +++ b/loader/src/injector/hook.cpp @@ -145,6 +145,8 @@ DCL_HOOK_FUNC(int, unshare, int flags) { if (g_ctx->flags[DO_REVERT_UNMOUNT]) { if (g_ctx->info_flags & PROCESS_ROOT_IS_KSU) { revert_unmount_ksu(); + } else if (g_ctx->info_flags & PROCESS_ROOT_IS_APATCH){ + revert_unmount_apatch(); } else if (g_ctx->info_flags & PROCESS_ROOT_IS_MAGISK) { revert_unmount_magisk(); } diff --git a/loader/src/injector/module.hpp b/loader/src/injector/module.hpp index 7454a3a..c4920f9 100644 --- a/loader/src/injector/module.hpp +++ b/loader/src/injector/module.hpp @@ -113,6 +113,7 @@ namespace { PROCESS_ON_DENYLIST = zygisk::StateFlag::PROCESS_ON_DENYLIST, PROCESS_IS_MANAGER = (1u << 28), + PROCESS_ROOT_IS_APATCH = (1u << 27), PROCESS_ROOT_IS_KSU = (1u << 29), PROCESS_ROOT_IS_MAGISK = (1u << 30), PROCESS_IS_SYS_UI = (1u << 31), diff --git a/loader/src/injector/unmount.cpp b/loader/src/injector/unmount.cpp index c7791bc..0fd57ab 100644 --- a/loader/src/injector/unmount.cpp +++ b/loader/src/injector/unmount.cpp @@ -11,6 +11,7 @@ using namespace std::string_view_literals; namespace { constexpr auto MODULE_DIR = "/data/adb/modules"; constexpr auto KSU_OVERLAY_SOURCE = "KSU"; + constexpr auto AP_OVERLAY_SOURCE = "APatch"; const std::vector KSU_PARTITIONS{"/system", "/vendor", "/product", "/system_ext", "/odm", "/oem"}; void lazy_unmount(const char* mountpoint) { @@ -84,3 +85,43 @@ void revert_unmount_magisk() { lazy_unmount(s.data()); } } + +void revert_unmount_apatch() { + std::string ksu_loop; + std::vector targets; + + // Unmount ksu module dir last + targets.emplace_back(MODULE_DIR); + + for (auto& info: parse_mount_info("self")) { + if (info.target == MODULE_DIR) { + ksu_loop = info.source; + continue; + } + // Unmount everything mounted to /data/adb + if (info.target.starts_with("/data/adb")) { + targets.emplace_back(info.target); + } + // Unmount ksu overlays + if (info.type == "overlay" + && info.source == AP_OVERLAY_SOURCE + && std::find(KSU_PARTITIONS.begin(), KSU_PARTITIONS.end(), info.target) != KSU_PARTITIONS.end()) { + targets.emplace_back(info.target); + } + // Unmount temp dir + if (info.type == "tmpfs" && info.source == AP_OVERLAY_SOURCE) { + targets.emplace_back(info.target); + } + } + for (auto& info: parse_mount_info("self")) { + // Unmount everything from ksu loop except ksu module dir + if (info.source == ksu_loop && info.target != MODULE_DIR) { + targets.emplace_back(info.target); + } + } + + // Do unmount + for (auto& s: reversed(targets)) { + lazy_unmount(s.data()); + } +} \ No newline at end of file diff --git a/loader/src/injector/zygisk.hpp b/loader/src/injector/zygisk.hpp index 995a89f..5c06f8b 100644 --- a/loader/src/injector/zygisk.hpp +++ b/loader/src/injector/zygisk.hpp @@ -12,3 +12,4 @@ void revert_unmount_ksu(); void revert_unmount_magisk(); +void revert_unmount_apatch(); diff --git a/loader/src/ptracer/main.cpp b/loader/src/ptracer/main.cpp index 81db568..973e4f5 100644 --- a/loader/src/ptracer/main.cpp +++ b/loader/src/ptracer/main.cpp @@ -108,6 +108,11 @@ int main(int argc, char **argv) { break; } + case ZYGOTE_ROOT_IMPL_APATCH: { + printf("Root implementation: APatch\n"); + + break; + } case ZYGOTE_ROOT_IMPL_KERNELSU: { printf("Root implementation: KernelSU\n"); diff --git a/module/build.gradle.kts b/module/build.gradle.kts index e9d788d..d021293 100644 --- a/module/build.gradle.kts +++ b/module/build.gradle.kts @@ -24,6 +24,7 @@ val moduleId: String by rootProject.extra val moduleName: String by rootProject.extra val verCode: Int by rootProject.extra val verName: String by rootProject.extra +val minApatchVersion: Int by rootProject.extra val minKsuVersion: Int by rootProject.extra val minKsudVersion: Int by rootProject.extra val maxKsuVersion: Int by rootProject.extra @@ -69,6 +70,7 @@ androidComponents.onVariants { variant -> include("customize.sh", "post-fs-data.sh", "service.sh") val tokens = mapOf( "DEBUG" to if (buildTypeLowered == "debug") "true" else "false", + "MIN_APATCH_VERSION" to "$minApatchVersion", "MIN_KSU_VERSION" to "$minKsuVersion", "MIN_KSUD_VERSION" to "$minKsudVersion", "MAX_KSU_VERSION" to "$maxKsuVersion", @@ -214,12 +216,24 @@ androidComponents.onVariants { variant -> } } + val installApatchTask = task("installApatch$variantCapped") { + group = "module" + dependsOn(pushTask) + commandLine("adb", "shell", "su", "-c", "/data/adb/apd module install /data/local/tmp/$zipFileName") + } + val installMagiskTask = task("installMagisk$variantCapped") { group = "module" dependsOn(pushTask) commandLine("adb", "shell", "su", "-M", "-c", "magisk --install-module /data/local/tmp/$zipFileName") } + task("installKpatchAndReboot$variantCapped") { + group = "module" + dependsOn(installApatchTask) + commandLine("adb", "reboot") + } + task("installKsuAndReboot$variantCapped") { group = "module" dependsOn(installKsuTask) diff --git a/module/src/customize.sh b/module/src/customize.sh index 6b8ddff..e5779c1 100644 --- a/module/src/customize.sh +++ b/module/src/customize.sh @@ -6,6 +6,7 @@ MIN_KSU_VERSION=@MIN_KSU_VERSION@ MIN_KSUD_VERSION=@MIN_KSUD_VERSION@ MAX_KSU_VERSION=@MAX_KSU_VERSION@ MIN_MAGISK_VERSION=@MIN_MAGISK_VERSION@ +MIN_APATCH_VERSION=@MIN_APATCH_VERSION@ if [ "$BOOTMODE" ] && [ "$KSU" ]; then ui_print "- Installing from KernelSU app" @@ -34,6 +35,14 @@ if [ "$BOOTMODE" ] && [ "$KSU" ]; then ui_print "! Please uninstall Magisk before installing ReZygisk" abort "*********************************************************" fi + elif [ "$BOOTMODE" ] && [ "$APATCH" ]; then + ui_print "- Installing from Apatch app" + if ! [ "$APATCH_VER_CODE" ] || [ "$APATCH_VER_CODE" -lt "$MIN_APATCH_VERSION" ]; then + ui_print "*********************************************************" + ui_print "! Apatch version is too old!" + ui_print "! Please update Apatch to latest version" + abort "*********************************************************" + fi elif [ "$BOOTMODE" ] && [ "$MAGISK_VER_CODE" ]; then ui_print "- Installing from Magisk app" if [ "$MAGISK_VER_CODE" -lt "$MIN_MAGISK_VERSION" ]; then diff --git a/zygiskd/Cargo.toml b/zygiskd/Cargo.toml index 0afd2d2..bebacf3 100644 --- a/zygiskd/Cargo.toml +++ b/zygiskd/Cargo.toml @@ -6,6 +6,8 @@ edition = "2021" rust-version = "1.69" [dependencies] +csv = "1.3.0" +serde = { version = "1.0.130", features = ["derive"] } android_logger = "0.13" anyhow = { version = "1.0", features = ["backtrace"] } bitflags = { version = "2.3" } diff --git a/zygiskd/build.gradle.kts b/zygiskd/build.gradle.kts index 5781f08..698cefc 100644 --- a/zygiskd/build.gradle.kts +++ b/zygiskd/build.gradle.kts @@ -3,6 +3,7 @@ plugins { alias(libs.plugins.rust.android) } +val minApatchVersion: Int by rootProject.extra val minKsuVersion: Int by rootProject.extra val maxKsuVersion: Int by rootProject.extra val minMagiskVersion: Int by rootProject.extra @@ -17,6 +18,7 @@ android.buildFeatures { cargo { module = "." + pythonCommand = "python3" libname = "zygiskd" targetIncludes = arrayOf("zygiskd") targets = listOf("arm64", "arm", "x86", "x86_64") @@ -25,6 +27,7 @@ cargo { profile = if (isDebug) "debug" else "release" exec = { spec, _ -> spec.environment("ANDROID_NDK_HOME", android.ndkDirectory.path) + spec.environment("MIN_APATCH_VERSION", minApatchVersion) spec.environment("MIN_KSU_VERSION", minKsuVersion) spec.environment("MAX_KSU_VERSION", maxKsuVersion) spec.environment("MIN_MAGISK_VERSION", minMagiskVersion) diff --git a/zygiskd/src/constants.rs b/zygiskd/src/constants.rs index b5d209d..4d8a93f 100644 --- a/zygiskd/src/constants.rs +++ b/zygiskd/src/constants.rs @@ -5,6 +5,7 @@ use konst::unwrap_ctx; use log::LevelFilter; use num_enum::TryFromPrimitive; +pub const MIN_APATCH_VERSION: i32 = unwrap_ctx!(parse_i32(env!("MIN_APATCH_VERSION"))); pub const MIN_KSU_VERSION: i32 = unwrap_ctx!(parse_i32(env!("MIN_KSU_VERSION"))); pub const MAX_KSU_VERSION: i32 = unwrap_ctx!(parse_i32(env!("MAX_KSU_VERSION"))); pub const MIN_MAGISK_VERSION: i32 = unwrap_ctx!(parse_i32(env!("MIN_MAGISK_VERSION"))); @@ -42,6 +43,7 @@ bitflags! { const PROCESS_GRANTED_ROOT = 1 << 0; const PROCESS_ON_DENYLIST = 1 << 1; const PROCESS_IS_MANAGER = 1 << 28; + const PROCESS_ROOT_IS_APATCH = 1 << 27; const PROCESS_ROOT_IS_KSU = 1 << 29; const PROCESS_ROOT_IS_MAGISK = 1 << 30; const PROCESS_IS_SYSUI = 1 << 31; diff --git a/zygiskd/src/root_impl/apatch.rs b/zygiskd/src/root_impl/apatch.rs new file mode 100644 index 0000000..bec3ba6 --- /dev/null +++ b/zygiskd/src/root_impl/apatch.rs @@ -0,0 +1,113 @@ +use std::process::{Command, Stdio}; +use std::fs::File; +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 = None; + for line in output.lines() { + if let Some(num) = line.trim().split_whitespace().last() { + if let Ok(v) = num.parse::() { + version = Some(v); + break; + } + } + } + version.unwrap_or_default() +} + +pub fn get_apatch() -> Option { + 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()?; + 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, + } +} + +#[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, 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 +} \ No newline at end of file diff --git a/zygiskd/src/root_impl/mod.rs b/zygiskd/src/root_impl/mod.rs index 32560d6..7ff6ff1 100644 --- a/zygiskd/src/root_impl/mod.rs +++ b/zygiskd/src/root_impl/mod.rs @@ -2,6 +2,7 @@ use std::ptr::addr_of; mod kernelsu; mod magisk; +mod apatch; #[derive(Debug)] pub enum RootImpl { @@ -11,26 +12,34 @@ pub enum RootImpl { 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 (ksu_version, magisk_version) { - (None, None) => RootImpl::None, - (Some(_), Some(_)) => RootImpl::Multiple, - (Some(ksu_version), None) => match ksu_version { + 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, Some(magisk_version)) => match magisk_version { + (None, None, Some(magisk_version)) => match magisk_version { magisk::Version::Supported => RootImpl::Magisk, magisk::Version::TooOld => RootImpl::TooOld, }, + _ => RootImpl::None, }; unsafe { ROOT_IMPL = impl_; @@ -45,6 +54,7 @@ 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()), } } @@ -53,6 +63,7 @@ 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()), } } @@ -61,6 +72,7 @@ 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()), } } diff --git a/zygiskd/src/zygiskd.rs b/zygiskd/src/zygiskd.rs index 96cf2c0..e593b2b 100644 --- a/zygiskd/src/zygiskd.rs +++ b/zygiskd/src/zygiskd.rs @@ -51,7 +51,7 @@ pub fn main() -> Result<()> { { let mut msg = Vec::::new(); let info = match root_impl::get_impl() { - root_impl::RootImpl::KernelSU | root_impl::RootImpl::Magisk => { + root_impl::RootImpl::KernelSU | root_impl::RootImpl::Magisk | root_impl::RootImpl::APatch => { msg.extend_from_slice(&constants::DAEMON_SET_INFO.to_le_bytes()); let module_names: Vec<_> = modules.iter().map(|m| m.name.as_str()).collect(); format!( @@ -254,6 +254,7 @@ fn handle_daemon_action( match root_impl::get_impl() { root_impl::RootImpl::KernelSU => flags |= ProcessFlags::PROCESS_ROOT_IS_KSU, root_impl::RootImpl::Magisk => flags |= ProcessFlags::PROCESS_ROOT_IS_MAGISK, + root_impl::RootImpl::APatch => flags |= ProcessFlags::PROCESS_ROOT_IS_APATCH, _ => panic!("wrong root impl: {:?}", root_impl::get_impl()), } trace!(