You've already forked ZygiskNext
mirror of
https://github.com/Dr-TSNG/ZygiskNext.git
synced 2025-08-27 23:46:34 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d0858be7c | ||
|
|
b7bed4ad35 | ||
|
|
80b19c4412 | ||
|
|
a6f455218f | ||
|
|
87cf885070 | ||
|
|
b775d28c23 | ||
|
|
bf72296d33 | ||
|
|
9d648d9aa4 | ||
|
|
843086f6f3 | ||
|
|
49e3ac9d7a | ||
|
|
446ed92f26 |
88
.github/workflows/ci.yml
vendored
Normal file
88
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ master ]
|
||||
tags: [ v* ]
|
||||
pull_request:
|
||||
merge_group:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CCACHE_COMPILERCHECK: "%compiler% -dumpmachine; %compiler% -dumpversion"
|
||||
CCACHE_NOHASHDIR: "true"
|
||||
CCACHE_HARDLINK: "true"
|
||||
CCACHE_BASEDIR: "${{ github.workspace }}"
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: "recursive"
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: "temurin"
|
||||
java-version: "17"
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
gradle-home-cache-cleanup: true
|
||||
|
||||
- name: Setup rust-cache
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: zygiskd/src -> ../build/intermediates/rust
|
||||
cache-targets: false
|
||||
|
||||
- name: Setup Rust
|
||||
run: |
|
||||
rustup target add armv7-linux-androideabi
|
||||
rustup target add aarch64-linux-android
|
||||
rustup target add x86_64-linux-android
|
||||
rustup target add i686-linux-android
|
||||
|
||||
- name: Set up ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
max-size: 2G
|
||||
key: ${{ runner.os }}
|
||||
restore-keys: ${{ runner.os }}
|
||||
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
|
||||
- name: Build with Gradle
|
||||
run: |
|
||||
echo 'org.gradle.parallel=true' >> gradle.properties
|
||||
echo 'org.gradle.vfs.watch=true' >> gradle.properties
|
||||
echo 'org.gradle.jvmargs=-Xmx2048m' >> gradle.properties
|
||||
echo 'android.native.buildOutput=verbose' >> gradle.properties
|
||||
sed -i 's/org.gradle.unsafe.configuration-cache=true//g' gradle.properties
|
||||
./gradlew zipRelease
|
||||
./gradlew zipDebug
|
||||
|
||||
- name: Prepare artifact
|
||||
if: success()
|
||||
id: prepareArtifact
|
||||
run: |
|
||||
releaseName=`ls module/build/outputs/release/Zygisk-on-KernelSU-v*-release.zip | awk -F '(/|.zip)' '{print $5}'` && echo "releaseName=$releaseName" >> $GITHUB_OUTPUT
|
||||
debugName=`ls module/build/outputs/release/Zygisk-on-KernelSU-v*-debug.zip | awk -F '(/|.zip)' '{print $5}'` && echo "debugName=$debugName" >> $GITHUB_OUTPUT
|
||||
unzip module/build/outputs/release/Zygisk-on-KernelSU-v*-release.zip -d zksu-release
|
||||
unzip module/build/outputs/release/Zygisk-on-KernelSU-v*-debug.zip -d zksu-debug
|
||||
|
||||
- name: Upload release
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ steps.prepareArtifact.outputs.releaseName }}
|
||||
path: "./zksu-release/*"
|
||||
|
||||
- name: Upload debug
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ steps.prepareArtifact.outputs.debugName }}
|
||||
path: "./zksu-debug/*"
|
||||
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -1,6 +1,6 @@
|
||||
[submodule "loader/src/external/liblsplt"]
|
||||
path = loader/src/external/liblsplt
|
||||
url = https://github.com/LSPosed/LSPlt
|
||||
[submodule "loader/src/external/lsplt"]
|
||||
path = loader/src/external/lsplt
|
||||
url = https://github.com/LSPosed/lsplt
|
||||
[submodule "loader/src/external/parallel-hashmap"]
|
||||
path = loader/src/external/parallel-hashmap
|
||||
url = https://github.com/greg7mdp/parallel-hashmap
|
||||
|
||||
@@ -13,11 +13,8 @@ Also works as standalone loader for Magisk on purpose of getting rid of LD_PRELO
|
||||
### KernelSU
|
||||
|
||||
+ Minimal KernelSU version: 10654
|
||||
+ Minimal ksud version: 10647
|
||||
+ Minimal ksud version: 10670
|
||||
+ Kernel has full SELinux patch support
|
||||
+ For old kernels, you may need to manually add the following code to `sepolicy.rule`:
|
||||
`allow zygote appdomain_tmpfs file *`
|
||||
`allow zygote appdomain_tmpfs dir *`
|
||||
|
||||
### Magisk
|
||||
|
||||
|
||||
@@ -31,10 +31,10 @@ val gitCommitHash = "git rev-parse --verify --short HEAD".execute()
|
||||
|
||||
val moduleId by extra("zygisksu")
|
||||
val moduleName by extra("Zygisk on KernelSU")
|
||||
val verName by extra("v4-0.6.0")
|
||||
val verName by extra("v4-0.6.4")
|
||||
val verCode by extra(gitCommitCount)
|
||||
val minKsuVersion by extra(10654)
|
||||
val minKsudVersion by extra(10647)
|
||||
val minKsudVersion by extra(10670)
|
||||
val maxKsuVersion by extra(20000)
|
||||
val minMagiskVersion by extra(25208)
|
||||
|
||||
|
||||
@@ -20,4 +20,4 @@ kotlin.code.style=official
|
||||
# Enables namespacing of each library's R class so that its R class includes only the
|
||||
# resources declared in the library itself and none from the library's dependencies,
|
||||
# thereby reducing the size of the R class for that library
|
||||
android.nonTransitiveRClass=true
|
||||
android.nonTransitiveRClass=true
|
||||
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -1,7 +1,26 @@
|
||||
import java.nio.file.Paths
|
||||
import org.gradle.internal.os.OperatingSystem
|
||||
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
}
|
||||
|
||||
fun Project.findInPath(executable: String, property: String): String? {
|
||||
val pathEnv = System.getenv("PATH")
|
||||
return pathEnv.split(File.pathSeparator).map { folder ->
|
||||
Paths.get("${folder}${File.separator}${executable}${if (OperatingSystem.current().isWindows) ".exe" else ""}")
|
||||
.toFile()
|
||||
}.firstOrNull { path ->
|
||||
path.exists()
|
||||
}?.absolutePath ?: properties.getOrDefault(property, null) as? String?
|
||||
}
|
||||
|
||||
val ccachePatch by lazy {
|
||||
project.findInPath("ccache", "ccache.path")?.also {
|
||||
println("loader: Use ccache: $it")
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
buildFeatures {
|
||||
androidResources = false
|
||||
@@ -12,6 +31,16 @@ android {
|
||||
externalNativeBuild.ndkBuild {
|
||||
path("src/Android.mk")
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
ccachePatch?.let {
|
||||
arguments += "NDK_CCACHE=$it"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -8,19 +8,37 @@
|
||||
|
||||
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},
|
||||
};
|
||||
strncpy(addr.sun_path + 1, kZygiskSocket.data(), kZygiskSocket.size());
|
||||
strcpy(addr.sun_path + 1, sSocketName.data());
|
||||
socklen_t socklen = sizeof(sa_family_t) + strlen(addr.sun_path + 1) + 1;
|
||||
|
||||
while (retry--) {
|
||||
int r = connect(fd, reinterpret_cast<struct sockaddr*>(&addr), socklen);
|
||||
if (r == 0) return fd;
|
||||
LOGW("retrying to connect to zygiskd, sleep 1s");
|
||||
LOGW("Retrying to connect to zygiskd, sleep 1s");
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
|
||||
9
loader/src/external/Android.mk
vendored
9
loader/src/external/Android.mk
vendored
@@ -3,18 +3,19 @@ LOCAL_PATH := $(call my-dir)
|
||||
# liblsplt.a
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE:= liblsplt
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/liblsplt/lsplt/src/main/jni/include
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/lsplt/lsplt/src/main/jni/include
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
||||
LOCAL_CFLAGS := -Wall -Wextra -Werror -fvisibility=hidden
|
||||
LOCAL_CFLAGS := -Wall -Wextra -Werror -fvisibility=hidden -DLOG_DISABLED
|
||||
LOCAL_CPPFLAGS := -std=c++20
|
||||
LOCAL_STATIC_LIBRARIES := libcxx
|
||||
LOCAL_SRC_FILES := \
|
||||
liblsplt/lsplt/src/main/jni/elf_util.cc \
|
||||
liblsplt/lsplt/src/main/jni/lsplt.cc
|
||||
lsplt/lsplt/src/main/jni/elf_util.cc \
|
||||
lsplt/lsplt/src/main/jni/lsplt.cc
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# Header only library
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE:= libphmap
|
||||
LOCAL_CFLAGS := -Wno-unused-value
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/parallel-hashmap
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
1
loader/src/external/liblsplt
vendored
1
loader/src/external/liblsplt
vendored
Submodule loader/src/external/liblsplt deleted from b254b5b9a5
1
loader/src/external/lsplt
vendored
Submodule
1
loader/src/external/lsplt
vendored
Submodule
Submodule loader/src/external/lsplt added at 5d2b820cf9
2
loader/src/external/parallel-hashmap
vendored
2
loader/src/external/parallel-hashmap
vendored
Submodule loader/src/external/parallel-hashmap updated: 87ece91c6e...55725dbe70
@@ -26,14 +26,40 @@
|
||||
#define ZYGISK_API_VERSION 4
|
||||
|
||||
/*
|
||||
|
||||
***************
|
||||
* Introduction
|
||||
***************
|
||||
|
||||
On Android, all app processes are forked from a special daemon called "Zygote".
|
||||
For each new app process, zygote will fork a new process and perform "specialization".
|
||||
This specialization operation enforces the Android security sandbox on the newly forked
|
||||
process to make sure that 3rd party application code is only loaded after it is being
|
||||
restricted within a sandbox.
|
||||
|
||||
On Android, there is also this special process called "system_server". This single
|
||||
process hosts a significant portion of system services, which controls how the
|
||||
Android operating system and apps interact with each other.
|
||||
|
||||
The Zygisk framework provides a way to allow developers to build modules and run custom
|
||||
code before and after system_server and any app processes' specialization.
|
||||
This enable developers to inject code and alter the behavior of system_server and app processes.
|
||||
|
||||
Please note that modules will only be loaded after zygote has forked the child process.
|
||||
THIS MEANS ALL OF YOUR CODE RUNS IN THE APP/SYSTEM_SERVER PROCESS, NOT THE ZYGOTE DAEMON!
|
||||
|
||||
*********************
|
||||
* Development Guide
|
||||
*********************
|
||||
|
||||
Define a class and inherit zygisk::ModuleBase to implement the functionality of your module.
|
||||
Use the macro REGISTER_ZYGISK_MODULE(className) to register that class to Zygisk.
|
||||
Please note that modules will only be loaded after zygote has forked the child process.
|
||||
THIS MEANS ALL OF YOUR CODE RUNS IN THE APP/SYSTEM SERVER PROCESS, NOT THE ZYGOTE DAEMON!
|
||||
|
||||
Example code:
|
||||
|
||||
static jint (*orig_logger_entry_max)(JNIEnv *env);
|
||||
static jint my_logger_entry_max(JNIEnv *env) { return orig_logger_entry_max(env); }
|
||||
static void example_handler(int socket) { ... }
|
||||
|
||||
class ExampleModule : public zygisk::ModuleBase {
|
||||
public:
|
||||
void onLoad(zygisk::Api *api, JNIEnv *env) override {
|
||||
@@ -51,8 +77,26 @@ private:
|
||||
zygisk::Api *api;
|
||||
JNIEnv *env;
|
||||
};
|
||||
|
||||
REGISTER_ZYGISK_MODULE(ExampleModule)
|
||||
|
||||
-----------------------------------------------------------------------------------------
|
||||
|
||||
Since your module class's code runs with either Zygote's privilege in pre[XXX]Specialize,
|
||||
or runs in the sandbox of the target process in post[XXX]Specialize, the code in your class
|
||||
never runs in a true superuser environment.
|
||||
|
||||
If your module require access to superuser permissions, you can create and register
|
||||
a root companion handler function. This function runs in a separate root companion
|
||||
daemon process, and an Unix domain socket is provided to allow you to perform IPC between
|
||||
your target process and the root companion process.
|
||||
|
||||
Example code:
|
||||
|
||||
static void example_handler(int socket) { ... }
|
||||
|
||||
REGISTER_ZYGISK_COMPANION(example_handler)
|
||||
|
||||
*/
|
||||
|
||||
namespace zygisk {
|
||||
@@ -84,7 +128,7 @@ namespace zygisk {
|
||||
|
||||
// This method is called after the app process is specialized.
|
||||
// At this point, the process has all sandbox restrictions enabled for this application.
|
||||
// This means that this method runs as the same privilege of the app's own code.
|
||||
// This means that this method runs with the same privilege of the app's own code.
|
||||
virtual void postAppSpecialize([[maybe_unused]] const AppSpecializeArgs *args) {}
|
||||
|
||||
// This method is called before the system server process is specialized.
|
||||
@@ -219,7 +263,16 @@ namespace zygisk {
|
||||
// will be set to nullptr.
|
||||
void hookJniNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int numMethods);
|
||||
|
||||
// For ELFs loaded in memory matching `inode`, replace function `symbol` with `newFunc`.
|
||||
// Hook functions in the PLT (Procedure Linkage Table) of ELFs loaded in memory.
|
||||
//
|
||||
// Parsing /proc/[PID]/maps will give you the memory map of a process. As an example:
|
||||
//
|
||||
// <address> <perms> <offset> <dev> <inode> <pathname>
|
||||
// 56b4346000-56b4347000 r-xp 00002000 fe:00 235 /system/bin/app_process64
|
||||
// (More details: https://man7.org/linux/man-pages/man5/proc.5.html)
|
||||
//
|
||||
// The `dev` and `inode` pair uniquely identifies a file being mapped into memory.
|
||||
// For matching ELFs loaded in memory, replace function `symbol` with `newFunc`.
|
||||
// If `oldFunc` is not nullptr, the original function pointer will be saved to `oldFunc`.
|
||||
void pltHookRegister(dev_t dev, ino_t inode, const char *symbol, void *newFunc, void **oldFunc);
|
||||
|
||||
@@ -243,11 +296,11 @@ void zygisk_module_entry(zygisk::internal::api_table *table, JNIEnv *env) { \
|
||||
//
|
||||
// The function runs in a superuser daemon process and handles a root companion request from
|
||||
// your module running in a target process. The function has to accept an integer value,
|
||||
// which is a socket that is connected to the target process.
|
||||
// which is a Unix domain socket that is connected to the target process.
|
||||
// See Api::connectCompanion() for more info.
|
||||
//
|
||||
// NOTE: the function can run concurrently on multiple threads.
|
||||
// Be aware of race conditions if you have a globally shared resource.
|
||||
// Be aware of race conditions if you have globally shared resources.
|
||||
|
||||
#define REGISTER_ZYGISK_COMPANION(func) \
|
||||
void zygisk_companion_entry(int client) { func(client); }
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
#else
|
||||
# define LP_SELECT(lp32, lp64) lp32
|
||||
#endif
|
||||
constexpr std::string_view kZygiskSocket = LP_SELECT("zygiskd32", "zygiskd64") "socket_placeholder";
|
||||
|
||||
constexpr auto kZygiskMagic = "/system/zygisk_magic";
|
||||
|
||||
class UniqueFd {
|
||||
using Fd = int;
|
||||
|
||||
@@ -331,6 +331,7 @@ bool ZygiskModule::RegisterModuleImpl(ApiTable *api, long *module) {
|
||||
api->v2.getFlags = [](auto) { return ZygiskModule::getFlags(); };
|
||||
}
|
||||
if (api_version >= 4) {
|
||||
api->v4.pltHookCommit = lsplt::CommitHook;
|
||||
api->v4.pltHookRegister = [](dev_t dev, ino_t inode, const char *symbol, void *fn, void **backup) {
|
||||
if (dev == 0 || inode == 0 || symbol == nullptr || fn == nullptr)
|
||||
return;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
namespace {
|
||||
constexpr auto KSU_MODULE_DIR = "/data/adb/ksu/modules";
|
||||
constexpr auto MODULE_DIR = "/data/adb/modules";
|
||||
|
||||
struct overlay_backup {
|
||||
std::string target;
|
||||
@@ -38,10 +38,10 @@ void revert_unmount_ksu() {
|
||||
std::list<overlay_backup> backups;
|
||||
|
||||
// Unmount ksu module dir last
|
||||
targets.emplace_back(KSU_MODULE_DIR);
|
||||
targets.emplace_back(MODULE_DIR);
|
||||
|
||||
for (auto& info: parse_mount_info("self")) {
|
||||
if (info.target == KSU_MODULE_DIR) {
|
||||
if (info.target == MODULE_DIR) {
|
||||
ksu_loop = info.source;
|
||||
continue;
|
||||
}
|
||||
@@ -51,8 +51,7 @@ void revert_unmount_ksu() {
|
||||
}
|
||||
// Unmount ksu overlays
|
||||
if (info.type == "overlay") {
|
||||
LOGV("Overlay: %s (%s)", info.target.data(), info.fs_option.data());
|
||||
if (str_contains(info.fs_option, KSU_MODULE_DIR)) {
|
||||
if (str_contains(info.fs_option, MODULE_DIR)) {
|
||||
targets.emplace_back(info.target);
|
||||
} else {
|
||||
auto backup = overlay_backup{
|
||||
@@ -66,7 +65,7 @@ void revert_unmount_ksu() {
|
||||
}
|
||||
for (auto& info: parse_mount_info("self")) {
|
||||
// Unmount everything from ksu loop except ksu module dir
|
||||
if (info.source == ksu_loop && info.target != KSU_MODULE_DIR) {
|
||||
if (info.source == ksu_loop && info.target != MODULE_DIR) {
|
||||
targets.emplace_back(info.target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +82,10 @@ extract "$ZIPFILE" 'sepolicy.rule' "$TMPDIR"
|
||||
|
||||
if [ "$KSU" ]; then
|
||||
ui_print "- Checking SELinux patches"
|
||||
if [ "$(getprop ro.product.first_api_level)" -lt 31 ]; then
|
||||
echo "allow zygote appdomain_tmpfs file *" >> "$TMPDIR/sepolicy.rule"
|
||||
echo "allow zygote appdomain_tmpfs dir *" >> "$TMPDIR/sepolicy.rule"
|
||||
fi
|
||||
if ! check_sepolicy "$TMPDIR/sepolicy.rule"; then
|
||||
ui_print "*********************************************************"
|
||||
ui_print "! Unable to apply SELinux patches!"
|
||||
@@ -93,8 +97,8 @@ fi
|
||||
ui_print "- Extracting module files"
|
||||
extract "$ZIPFILE" 'module.prop' "$MODPATH"
|
||||
extract "$ZIPFILE" 'post-fs-data.sh' "$MODPATH"
|
||||
extract "$ZIPFILE" 'sepolicy.rule' "$MODPATH"
|
||||
extract "$ZIPFILE" 'service.sh' "$MODPATH"
|
||||
mv "$TMPDIR/sepolicy.rule" "$MODPATH"
|
||||
|
||||
HAS32BIT=false && [ -d "/system/lib" ] && HAS32BIT=true
|
||||
HAS64BIT=false && [ -d "/system/lib64" ] && HAS64BIT=true
|
||||
@@ -142,20 +146,9 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $DEBUG = false ]; then
|
||||
ui_print "- Hex patching"
|
||||
SOCKET_PATCH=$(tr -dc 'a-f0-9' </dev/urandom | head -c 18)
|
||||
if [ "$HAS32BIT" = true ]; then
|
||||
sed -i "s/socket_placeholder/$SOCKET_PATCH/g" "$MODPATH/bin/zygiskd32"
|
||||
sed -i "s/socket_placeholder/$SOCKET_PATCH/g" "$MODPATH/system/lib/libzygisk_injector.so"
|
||||
sed -i "s/socket_placeholder/$SOCKET_PATCH/g" "$MODPATH/system/lib/libzygisk_loader.so"
|
||||
fi
|
||||
if [ "$HAS64BIT" = true ]; then
|
||||
sed -i "s/socket_placeholder/$SOCKET_PATCH/g" "$MODPATH/bin/zygiskd64"
|
||||
sed -i "s/socket_placeholder/$SOCKET_PATCH/g" "$MODPATH/system/lib64/libzygisk_injector.so"
|
||||
sed -i "s/socket_placeholder/$SOCKET_PATCH/g" "$MODPATH/system/lib64/libzygisk_loader.so"
|
||||
fi
|
||||
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"
|
||||
|
||||
@@ -9,7 +9,7 @@ cd "$MODDIR"
|
||||
getprop ro.dalvik.vm.native.bridge > /dev/.native_bridge
|
||||
resetprop ro.dalvik.vm.native.bridge libzygisk_loader.so
|
||||
|
||||
if [ "$(which magisk)" ] && [ ".." -ef "/data/adb/modules" ]; then
|
||||
if [ "$(which magisk)" ]; then
|
||||
for file in ../*; do
|
||||
if [ -d "$file" ] && [ -d "$file/zygisk" ] && ! [ -f "$file/disable" ]; then
|
||||
if [ -f "$file/post-fs-data.sh" ]; then
|
||||
|
||||
@@ -10,6 +10,8 @@ allow * magisk_file lnk_file *
|
||||
allow * magisk_file sock_file *
|
||||
|
||||
allow system_server system_server process execmem
|
||||
allow zygote adb_data_file dir search
|
||||
allow zygote mnt_vendor_file dir search
|
||||
allow zygote system_file dir mounton
|
||||
allow zygote labeledfs filesystem mount
|
||||
allow zygote fs_type filesystem unmount
|
||||
|
||||
@@ -11,7 +11,7 @@ cd "$MODDIR"
|
||||
export NATIVE_BRIDGE=$(cat /dev/.native_bridge)
|
||||
rm /dev/.native_bridge
|
||||
|
||||
if [ "$(which magisk)" ] && [ ".." -ef "/data/adb/modules" ]; then
|
||||
if [ "$(which magisk)" ]; then
|
||||
for file in ../*; do
|
||||
if [ -d "$file" ] && [ -d "$file/zygisk" ] && ! [ -f "$file/disable" ]; then
|
||||
if [ -f "$file/service.sh" ]; then
|
||||
|
||||
@@ -7,8 +7,8 @@ pluginManagement {
|
||||
gradlePluginPortal()
|
||||
}
|
||||
plugins {
|
||||
id("com.android.library") version "7.4.1"
|
||||
id("com.android.application") version "7.4.1"
|
||||
id("com.android.library") version "7.4.2"
|
||||
id("com.android.application") version "7.4.2"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,15 +19,12 @@ 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 SOCKET_PLACEHOLDER: &str = "socket_placeholder";
|
||||
pub const ZYGISK_MAGIC: &str = "/system/zygisk_magic";
|
||||
|
||||
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_TMP_DIR: &str = concatcp!("/dev/", SOCKET_PLACEHOLDER);
|
||||
pub const PATH_TMP_PROP: &str = concatcp!("/dev/", SOCKET_PLACEHOLDER, "/module.prop");
|
||||
|
||||
pub const STATUS_LOADED: &str = "😋 Zygisksu is loaded";
|
||||
pub const STATUS_CRASHED: &str = "❌ Zygiskd has crashed";
|
||||
|
||||
19
zygiskd/src/magic.rs
Normal file
19
zygiskd/src/magic.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
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,6 +3,7 @@
|
||||
mod companion;
|
||||
mod constants;
|
||||
mod dl;
|
||||
mod magic;
|
||||
mod root_impl;
|
||||
mod utils;
|
||||
mod watchdog;
|
||||
@@ -39,6 +40,7 @@ fn init_android_logger(tag: &str) {
|
||||
|
||||
fn start() -> Result<()> {
|
||||
root_impl::setup();
|
||||
magic::setup()?;
|
||||
let cli = Args::parse();
|
||||
match cli.command {
|
||||
Commands::Watchdog => watchdog::entry()?,
|
||||
|
||||
@@ -24,6 +24,7 @@ pub fn get_kernel_su() -> Option<Version> {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn uid_on_allowlist(uid: i32) -> bool {
|
||||
let mut size = 1024u32;
|
||||
let mut uids = vec![0; size as usize];
|
||||
@@ -32,6 +33,7 @@ pub fn uid_on_allowlist(uid: i32) -> bool {
|
||||
uids.contains(&uid)
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn uid_on_denylist(uid: i32) -> bool {
|
||||
let mut size = 1024u32;
|
||||
let mut uids = vec![0; size as usize];
|
||||
|
||||
@@ -23,6 +23,7 @@ pub fn get_magisk() -> Option<Version> {
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn uid_on_allowlist(uid: i32) -> bool {
|
||||
let output: Option<String> = Command::new("magisk")
|
||||
.arg("--sqlite")
|
||||
@@ -40,6 +41,7 @@ pub fn uid_on_allowlist(uid: i32) -> bool {
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn uid_on_denylist(uid: i32) -> bool {
|
||||
// TODO: uid_on_denylist
|
||||
return false;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
mod kernelsu;
|
||||
mod magisk;
|
||||
|
||||
use once_cell::sync::OnceCell;
|
||||
|
||||
pub enum RootImpl {
|
||||
None,
|
||||
TooOld,
|
||||
@@ -12,47 +10,50 @@ pub enum RootImpl {
|
||||
Magisk,
|
||||
}
|
||||
|
||||
static ROOT_IMPL: OnceCell<RootImpl> = OnceCell::new();
|
||||
// FIXME: OnceCell bugs on 32 bit
|
||||
static mut ROOT_IMPL: RootImpl = RootImpl::None;
|
||||
|
||||
pub fn setup() {
|
||||
let ksu_version = kernelsu::get_kernel_su();
|
||||
let magisk_version = magisk::get_magisk();
|
||||
|
||||
let _ = match (ksu_version, magisk_version) {
|
||||
(None, None) => ROOT_IMPL.set(RootImpl::None),
|
||||
(Some(_), Some(_)) => ROOT_IMPL.set(RootImpl::Multiple),
|
||||
let impl_ = match (ksu_version, magisk_version) {
|
||||
(None, None) => RootImpl::None,
|
||||
(Some(_), Some(_)) => RootImpl::Multiple,
|
||||
(Some(ksu_version), None) => {
|
||||
let val = match ksu_version {
|
||||
match ksu_version {
|
||||
kernelsu::Version::Supported => RootImpl::KernelSU,
|
||||
kernelsu::Version::TooOld => RootImpl::TooOld,
|
||||
kernelsu::Version::Abnormal => RootImpl::Abnormal,
|
||||
};
|
||||
ROOT_IMPL.set(val)
|
||||
}
|
||||
}
|
||||
(None, Some(magisk_version)) => {
|
||||
let val = match magisk_version {
|
||||
match magisk_version {
|
||||
magisk::Version::Supported => RootImpl::Magisk,
|
||||
magisk::Version::TooOld => RootImpl::TooOld,
|
||||
};
|
||||
ROOT_IMPL.set(val)
|
||||
}
|
||||
}
|
||||
};
|
||||
unsafe { ROOT_IMPL = impl_; }
|
||||
}
|
||||
|
||||
pub fn get_impl() -> &'static RootImpl {
|
||||
ROOT_IMPL.get().unwrap()
|
||||
unsafe { &ROOT_IMPL }
|
||||
}
|
||||
|
||||
// FIXME: Without #[inline(never)], this function will lag forever
|
||||
#[inline(never)]
|
||||
pub fn uid_on_allowlist(uid: i32) -> bool {
|
||||
match ROOT_IMPL.get().unwrap() {
|
||||
match get_impl() {
|
||||
RootImpl::KernelSU => kernelsu::uid_on_allowlist(uid),
|
||||
RootImpl::Magisk => magisk::uid_on_allowlist(uid),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn uid_on_denylist(uid: i32) -> bool {
|
||||
match ROOT_IMPL.get().unwrap() {
|
||||
match get_impl() {
|
||||
RootImpl::KernelSU => kernelsu::uid_on_denylist(uid),
|
||||
RootImpl::Magisk => magisk::uid_on_denylist(uid),
|
||||
_ => unreachable!(),
|
||||
|
||||
@@ -5,6 +5,7 @@ use std::ffi::c_char;
|
||||
use std::os::fd::FromRawFd;
|
||||
use std::os::unix::net::UnixListener;
|
||||
use nix::sys::socket::{AddressFamily, SockFlag, SockType, UnixAddr};
|
||||
use once_cell::sync::OnceCell;
|
||||
use rand::distributions::{Alphanumeric, DistString};
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
@@ -18,6 +19,27 @@ macro_rules! lp_select {
|
||||
($lp32:expr, $lp64:expr) => { $lp32 };
|
||||
}
|
||||
|
||||
pub struct LateInit<T> {
|
||||
cell: OnceCell<T>,
|
||||
}
|
||||
|
||||
impl<T> LateInit<T> {
|
||||
pub const fn new() -> Self {
|
||||
LateInit { cell: OnceCell::new() }
|
||||
}
|
||||
|
||||
pub fn init(&self, value: T) {
|
||||
assert!(self.cell.set(value).is_ok())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::ops::Deref for LateInit<T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &T {
|
||||
self.cell.get().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn random_string() -> String {
|
||||
Alphanumeric.sample_string(&mut rand::thread_rng(), 8)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{constants, root_impl, utils};
|
||||
use crate::{constants, magic, root_impl, utils};
|
||||
use anyhow::{bail, Result};
|
||||
use nix::unistd::{getgid, getuid, Pid};
|
||||
use std::process::{Child, Command};
|
||||
@@ -12,10 +12,10 @@ use binder::IBinder;
|
||||
use nix::errno::Errno;
|
||||
use nix::libc;
|
||||
use nix::sys::signal::{kill, Signal};
|
||||
use once_cell::sync::OnceCell;
|
||||
use crate::utils::LateInit;
|
||||
|
||||
static LOCK: OnceCell<UnixListener> = OnceCell::new();
|
||||
static PROP_SECTIONS: OnceCell<[String; 2]> = OnceCell::new();
|
||||
static LOCK: LateInit<UnixListener> = LateInit::new();
|
||||
static PROP_SECTIONS: LateInit<[String; 2]> = LateInit::new();
|
||||
|
||||
pub fn entry() -> Result<()> {
|
||||
log::info!("Start zygisksu watchdog");
|
||||
@@ -55,9 +55,9 @@ fn check_permission() -> Result<()> {
|
||||
|
||||
fn ensure_single_instance() -> Result<()> {
|
||||
log::info!("Ensure single instance");
|
||||
let name = String::from("zygiskwd") + constants::SOCKET_PLACEHOLDER;
|
||||
let name = format!("zygiskwd{}", magic::MAGIC.as_str());
|
||||
match utils::abstract_namespace_socket(&name) {
|
||||
Ok(socket) => { let _ = LOCK.set(socket); }
|
||||
Ok(socket) => LOCK.init(socket),
|
||||
Err(e) => bail!("Failed to acquire lock: {e}. Maybe another instance is running?")
|
||||
}
|
||||
Ok(())
|
||||
@@ -91,15 +91,15 @@ fn mount_prop() -> Result<()> {
|
||||
sections[section].push('\n');
|
||||
}
|
||||
}
|
||||
let _ = PROP_SECTIONS.set(sections);
|
||||
PROP_SECTIONS.init(sections);
|
||||
|
||||
fs::create_dir(constants::PATH_TMP_DIR)?;
|
||||
fs::File::create(constants::PATH_TMP_PROP)?;
|
||||
fs::create_dir(magic::PATH_TMP_DIR.as_str())?;
|
||||
fs::File::create(magic::PATH_TMP_PROP.as_str())?;
|
||||
|
||||
// FIXME: sys_mount cannot be compiled on 32 bit
|
||||
unsafe {
|
||||
let r = libc::mount(
|
||||
CString::new(constants::PATH_TMP_PROP)?.as_ptr(),
|
||||
CString::new(magic::PATH_TMP_PROP.as_str())?.as_ptr(),
|
||||
CString::new(module_prop)?.as_ptr(),
|
||||
std::ptr::null(),
|
||||
libc::MS_BIND,
|
||||
@@ -112,13 +112,12 @@ fn mount_prop() -> Result<()> {
|
||||
}
|
||||
|
||||
fn set_prop_hint(hint: &str) -> Result<()> {
|
||||
let mut file = fs::File::create(constants::PATH_TMP_PROP)?;
|
||||
let sections = PROP_SECTIONS.get().unwrap();
|
||||
file.write_all(sections[0].as_bytes())?;
|
||||
let mut file = fs::File::create(magic::PATH_TMP_PROP.as_str())?;
|
||||
file.write_all(PROP_SECTIONS[0].as_bytes())?;
|
||||
file.write_all(b"[")?;
|
||||
file.write_all(hint.as_bytes())?;
|
||||
file.write_all(b"] ")?;
|
||||
file.write_all(sections[1].as_bytes())?;
|
||||
file.write_all(PROP_SECTIONS[1].as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::constants::DaemonSocketAction;
|
||||
use crate::utils::UnixStreamExt;
|
||||
use crate::{constants, lp_select, root_impl, utils};
|
||||
use crate::{constants, lp_select, magic, root_impl, utils};
|
||||
use anyhow::{bail, Result};
|
||||
use memfd::Memfd;
|
||||
use nix::{
|
||||
@@ -135,7 +135,7 @@ fn create_memfd(so_path: &PathBuf) -> Result<Memfd> {
|
||||
fn create_daemon_socket() -> Result<UnixListener> {
|
||||
utils::set_socket_create_context("u:r:zygote:s0")?;
|
||||
let prefix = lp_select!("zygiskd32", "zygiskd64");
|
||||
let name = String::from(prefix) + constants::SOCKET_PLACEHOLDER;
|
||||
let name = format!("{}{}", prefix, magic::MAGIC.as_str());
|
||||
let listener = utils::abstract_namespace_socket(&name)?;
|
||||
log::debug!("Daemon socket: {name}");
|
||||
Ok(listener)
|
||||
@@ -198,7 +198,7 @@ fn handle_daemon_action(mut stream: UnixStream, context: &Context) -> Result<()>
|
||||
match root_impl::get_impl() {
|
||||
root_impl::RootImpl::KernelSU => flags |= constants::PROCESS_ROOT_IS_KSU,
|
||||
root_impl::RootImpl::Magisk => flags |= constants::PROCESS_ROOT_IS_MAGISK,
|
||||
_ => ()
|
||||
_ => unreachable!(),
|
||||
}
|
||||
// TODO: PROCESS_IS_SYSUI?
|
||||
stream.write_u32(flags)?;
|
||||
|
||||
Reference in New Issue
Block a user