From 5635c9f7c5af250e0509b6a510b7db7cddeca740 Mon Sep 17 00:00:00 2001 From: ThePedroo Date: Wed, 17 Jul 2024 17:56:38 -0300 Subject: [PATCH] add: Zygiskd C99 re-write This commit re-writes Zygiskd to be C99. --- {zygiskd => zygiskd-old}/.cargo/config.toml | 0 {zygiskd => zygiskd-old}/Cargo.toml | 0 {zygiskd => zygiskd-old}/build.gradle.kts | 0 {zygiskd => zygiskd-old}/src/companion.rs | 0 {zygiskd => zygiskd-old}/src/constants.rs | 0 {zygiskd => zygiskd-old}/src/dl.rs | 0 {zygiskd => zygiskd-old}/src/main.rs | 0 .../src/root_impl/apatch.rs | 0 .../src/root_impl/kernelsu.rs | 0 .../src/root_impl/magisk.rs | 0 {zygiskd => zygiskd-old}/src/root_impl/mod.rs | 0 {zygiskd => zygiskd-old}/src/utils.rs | 0 {zygiskd => zygiskd-old}/src/zygiskd.rs | 0 zygiskd/LICENSE | 24 ++ zygiskd/Makefile | 19 + zygiskd/companion.c | 96 +++++ zygiskd/constants.h | 70 ++++ zygiskd/dl.c | 58 +++ zygiskd/dl.h | 6 + zygiskd/main.c | 83 ++++ zygiskd/root_impl/common.c | 52 +++ zygiskd/root_impl/common.h | 22 ++ zygiskd/root_impl/kernelsu.c | 54 +++ zygiskd/root_impl/kernelsu.h | 14 + zygiskd/utils.c | 172 +++++++++ zygiskd/utils.h | 16 + zygiskd/zygiskd | Bin 0 -> 13600 bytes zygiskd/zygiskd.c | 353 ++++++++++++++++++ 28 files changed, 1039 insertions(+) rename {zygiskd => zygiskd-old}/.cargo/config.toml (100%) rename {zygiskd => zygiskd-old}/Cargo.toml (100%) rename {zygiskd => zygiskd-old}/build.gradle.kts (100%) rename {zygiskd => zygiskd-old}/src/companion.rs (100%) rename {zygiskd => zygiskd-old}/src/constants.rs (100%) rename {zygiskd => zygiskd-old}/src/dl.rs (100%) rename {zygiskd => zygiskd-old}/src/main.rs (100%) rename {zygiskd => zygiskd-old}/src/root_impl/apatch.rs (100%) rename {zygiskd => zygiskd-old}/src/root_impl/kernelsu.rs (100%) rename {zygiskd => zygiskd-old}/src/root_impl/magisk.rs (100%) rename {zygiskd => zygiskd-old}/src/root_impl/mod.rs (100%) rename {zygiskd => zygiskd-old}/src/utils.rs (100%) rename {zygiskd => zygiskd-old}/src/zygiskd.rs (100%) create mode 100644 zygiskd/LICENSE create mode 100644 zygiskd/Makefile create mode 100644 zygiskd/companion.c create mode 100644 zygiskd/constants.h create mode 100644 zygiskd/dl.c create mode 100644 zygiskd/dl.h create mode 100644 zygiskd/main.c create mode 100644 zygiskd/root_impl/common.c create mode 100644 zygiskd/root_impl/common.h create mode 100644 zygiskd/root_impl/kernelsu.c create mode 100644 zygiskd/root_impl/kernelsu.h create mode 100644 zygiskd/utils.c create mode 100644 zygiskd/utils.h create mode 100755 zygiskd/zygiskd create mode 100644 zygiskd/zygiskd.c diff --git a/zygiskd/.cargo/config.toml b/zygiskd-old/.cargo/config.toml similarity index 100% rename from zygiskd/.cargo/config.toml rename to zygiskd-old/.cargo/config.toml diff --git a/zygiskd/Cargo.toml b/zygiskd-old/Cargo.toml similarity index 100% rename from zygiskd/Cargo.toml rename to zygiskd-old/Cargo.toml diff --git a/zygiskd/build.gradle.kts b/zygiskd-old/build.gradle.kts similarity index 100% rename from zygiskd/build.gradle.kts rename to zygiskd-old/build.gradle.kts diff --git a/zygiskd/src/companion.rs b/zygiskd-old/src/companion.rs similarity index 100% rename from zygiskd/src/companion.rs rename to zygiskd-old/src/companion.rs diff --git a/zygiskd/src/constants.rs b/zygiskd-old/src/constants.rs similarity index 100% rename from zygiskd/src/constants.rs rename to zygiskd-old/src/constants.rs diff --git a/zygiskd/src/dl.rs b/zygiskd-old/src/dl.rs similarity index 100% rename from zygiskd/src/dl.rs rename to zygiskd-old/src/dl.rs diff --git a/zygiskd/src/main.rs b/zygiskd-old/src/main.rs similarity index 100% rename from zygiskd/src/main.rs rename to zygiskd-old/src/main.rs diff --git a/zygiskd/src/root_impl/apatch.rs b/zygiskd-old/src/root_impl/apatch.rs similarity index 100% rename from zygiskd/src/root_impl/apatch.rs rename to zygiskd-old/src/root_impl/apatch.rs diff --git a/zygiskd/src/root_impl/kernelsu.rs b/zygiskd-old/src/root_impl/kernelsu.rs similarity index 100% rename from zygiskd/src/root_impl/kernelsu.rs rename to zygiskd-old/src/root_impl/kernelsu.rs diff --git a/zygiskd/src/root_impl/magisk.rs b/zygiskd-old/src/root_impl/magisk.rs similarity index 100% rename from zygiskd/src/root_impl/magisk.rs rename to zygiskd-old/src/root_impl/magisk.rs diff --git a/zygiskd/src/root_impl/mod.rs b/zygiskd-old/src/root_impl/mod.rs similarity index 100% rename from zygiskd/src/root_impl/mod.rs rename to zygiskd-old/src/root_impl/mod.rs diff --git a/zygiskd/src/utils.rs b/zygiskd-old/src/utils.rs similarity index 100% rename from zygiskd/src/utils.rs rename to zygiskd-old/src/utils.rs diff --git a/zygiskd/src/zygiskd.rs b/zygiskd-old/src/zygiskd.rs similarity index 100% rename from zygiskd/src/zygiskd.rs rename to zygiskd-old/src/zygiskd.rs diff --git a/zygiskd/LICENSE b/zygiskd/LICENSE new file mode 100644 index 0000000..bf86410 --- /dev/null +++ b/zygiskd/LICENSE @@ -0,0 +1,24 @@ +BSD 2-Clause License + +Copyright (c) 2024, The PerformanC Organization + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/zygiskd/Makefile b/zygiskd/Makefile new file mode 100644 index 0000000..da3bc8a --- /dev/null +++ b/zygiskd/Makefile @@ -0,0 +1,19 @@ +CC := ~/Android/Sdk/ndk/27.0.11902837/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android34-clang + +FILES = root_impl/common.c \ + root_impl/kernelsu.c \ + main.c \ + utils.c \ + +CFLAGS = -D_GNU_SOURCE -Wall -Wextra -Werror -O3 -Iroot_impl -llog + +all: CFLAGS += -DDEBUG=0 +all: + $(CC) $(CFLAGS) $(FILES) -o zygiskd + +debug: CFLAGS += -DDEBUG=1 +debug: + $(CC) $(CFLAGS) $(FILES) -o zygiskd + +clean: + rm -f zygiskd \ No newline at end of file diff --git a/zygiskd/companion.c b/zygiskd/companion.c new file mode 100644 index 0000000..df8387e --- /dev/null +++ b/zygiskd/companion.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "dl.h" +#include "utils.h" + +typedef void (*ZygiskCompanionEntryFn)(u_int32_t); + +ZygiskCompanionEntryFn load_module(u_int32_t fd) { + char path[PATH_MAX]; + snprintf(path, sizeof(path), "/proc/self/fd/%d", fd); + + void *handle = android_dlopen(path, RTLD_NOW); + void *entry = dlsym(handle, "zygisk_companion_entry"); + if (entry == NULL) return NULL; + + return (ZygiskCompanionEntryFn)entry; +} + +void *ExecuteNew(void *arg) { + u_int32_t fd = (u_int32_t)arg; + + struct stat st0; + if (fstat(fd) == -1) { + printf("Failed to stat client fd\n"); + + exit(0); + } + entry(fd); + + // Only close client if it is the same file so we don't + // accidentally close a re-used file descriptor. + // This check is required because the module companion + // handler could've closed the file descriptor already. + struct stat st1; + if (fstat(fd) == -1) { + printf("Failed to stat client fd\n"); + + exit(0); + } + + if (st0.st_dev != st1.st_dev || st0.st_ino != st1.st_ino) { + close(fd); + } + + return NULL; +} + +void entry(u_int32_t fd) { + printf("companion entry fd=%d\n", fd); + + char name[256]; + read(fd, name, 256); + + int library_fd; + read(fd, &library_fd, sizeof(library_fd)); + + ZygiskCompanionEntryFn entry = load_module(library_fd); + + close(library_fd); + + if (entry == NULL) { + printf("No companion entry for `%s`\n", name); + + write(fd, (void *)0, 1); + + exit(0); + } + + printf("Companion process created for `%s`\n", name); + + write(fd, (void *)1, 1); + + while (1) { + int client_fd; + read(fd, &client_fd, sizeof(client_fd)); + + printf("New companion request from module `%s` fd=`%d`\n", name, client_fd); + + write(fd, (void *)1, 1); + + pthread_t thread; + pthread_create(&thread, NULL, ExecuteNew, (void *)client_fd); + pthread_detach(thread); + + + } +} diff --git a/zygiskd/constants.h b/zygiskd/constants.h new file mode 100644 index 0000000..a3c7cf4 --- /dev/null +++ b/zygiskd/constants.h @@ -0,0 +1,70 @@ +#ifndef CONSTANTS_H +#define CONSTANTS_H + +#include + +#define bool _Bool +#define true 1 +#define false 0 + +// #define MIN_APATCH_VERSION (atoi(getenv("MIN_APATCH_VERSION"))) +// #define MIN_KSU_VERSION (atoi(getenv("MIN_KSU_VERSION"))) +// #define MAX_KSU_VERSION (atoi(getenv("MAX_KSU_VERSION"))) +// #define MIN_MAGISK_VERSION (atoi(getenv("MIN_MAGISK_VERSION"))) +// #define ZKSU_VERSION (getenv("ZKSU_VERSION")) + +#define MIN_APATCH_VERSION 0 +// val minKsudVersion by extra(11425) +// val maxKsuVersion by extra(20000) +#define MIN_KSU_VERSION 11425 +#define MAX_KSU_VERSION 20000 +#define MIN_MAGISK_VERSION 0 +#define ZKSU_VERSION "1.0.0" + +#if DEBUG == false + #define MAX_LOG_LEVEL ANDROID_LOG_VERBOSE +#else + #define MAX_LOG_LEVEL ANDROID_LOG_INFO +#endif + +#if (defined(__LP64__) || defined(_LP64)) + #define lp_select(a, b) a +#else + #define lp_select(a, b) b +#endif + +#define PATH_MODULES_DIR ".." +#define ZYGOTE_INJECTED (lp_select(5, 4)) +#define DAEMON_SET_INFO (lp_select(7, 6)) +#define DAEMON_SET_ERROR_INFO (lp_select(9, 8)) +#define SYSTEM_SERVER_STARTED 10 + +enum DaemonSocketAction { + PingHeartbeat, + RequestLogcatFd, + GetProcessFlags, + GetInfo, + ReadModules, + RequestCompanionSocket, + GetModuleDir, + ZygoteRestart, + SystemServerStarted +}; + +enum ProcessFlags { + PROCESS_GRANTED_ROOT = 1 << 0, + PROCESS_ON_DENYLIST = 1 << 1, + PROCESS_IS_MANAGER = 1 << 28, + PROCESS_ROOT_IS_APATCH = 1 << 27, + PROCESS_ROOT_IS_KSU = 1 << 29, + PROCESS_ROOT_IS_MAGISK = 1 << 30, + PROCESS_IS_SYSUI = 1 << 31 +}; + +enum RootImplState { + Supported, + TooOld, + Abnormal +}; + +#endif /* CONSTANTS_H */ diff --git a/zygiskd/dl.c b/zygiskd/dl.c new file mode 100644 index 0000000..36582b6 --- /dev/null +++ b/zygiskd/dl.c @@ -0,0 +1,58 @@ +#include + +#include +#include +#include + +#define ANDROID_NAMESPACE_TYPE_SHARED 0x2 +#define ANDROID_DLEXT_USE_NAMESPACE 0x200 + +struct AndroidNamespace { + u_int8_t _unused[0]; +}; + +struct AndroidDlextinfo { + u_int64_t flags; + void *reserved_addr; + size_t reserved_size; + int relro_fd; + int library_fd; + __off64_t library_fd_offset; + struct AndroidNamespace *library_namespace; +}; + +void *android_dlopen_ext(const char *filename, int flags, const struct AndroidDlextinfo *extinfo); + +void *android_dlopen(char *path, u_int32_t flags) { + char *dir = dirname(path); + struct AndroidDlextinfo info = { + .flags = 0, + .reserved_addr = NULL, + .reserved_size = 0, + .relro_fd = 0, + .library_fd = 0, + .library_fd_offset = 0, + .library_namespace = NULL, + }; + + void *android_create_namespace_fn = dlsym(RTLD_DEFAULT, "__loader_android_create_namespace"); + + if (android_create_namespace_fn != NULL) { + void *ns = ((void *(*)(const char *, const char *, const char *, u_int32_t, void *, void *, void *))android_create_namespace_fn)( + path, + dir, + NULL, + ANDROID_NAMESPACE_TYPE_SHARED, + NULL, + NULL, + &android_dlopen + ); + + if (ns != NULL) { + info.flags = ANDROID_DLEXT_USE_NAMESPACE; + info.library_namespace = ns; + } + } + + return android_dlopen_ext(path, flags, &info); +} diff --git a/zygiskd/dl.h b/zygiskd/dl.h new file mode 100644 index 0000000..acdf231 --- /dev/null +++ b/zygiskd/dl.h @@ -0,0 +1,6 @@ +#ifndef DL_H +#define DL_H + +void *android_dlopen(char *path, u_int32_t flags); + +#endif /* DL_H */ \ No newline at end of file diff --git a/zygiskd/main.c b/zygiskd/main.c new file mode 100644 index 0000000..e29411a --- /dev/null +++ b/zygiskd/main.c @@ -0,0 +1,83 @@ +#include +#include + +#include + +#include "root_impl/common.h" + +#include "utils.h" + +// extern "C" { +// fn __android_log_print(prio: i32, tag: *const c_char, fmt: *const c_char, ...) -> i32; +// fn __system_property_get(name: *const c_char, value: *mut c_char) -> u32; +// fn __system_property_set(name: *const c_char, value: *const c_char) -> u32; +// fn __system_property_find(name: *const c_char) -> *const c_void; +// fn __system_property_wait( +// info: *const c_void, +// old_serial: u32, +// new_serial: *mut u32, +// timeout: *const libc::timespec, +// ) -> bool; +// fn __system_property_serial(info: *const c_void) -> u32; +// } + +int __android_log_print(int prio, const char *tag, const char *fmt, ...); + +int main(int argc, char *argv[]) { + /* Initialize android logger */ + __android_log_print(ANDROID_LOG_INFO, "zygiskd", "Hello, world! :3"); + + if (argc > 1) { + if (strcmp(argv[0], "companion") == 0) { + /* WIP */ + + return 0; + } + + else if (strcmp(argv[1], "version") == 0) { + printf("ReZygisk Daemon %s\n", ZKSU_VERSION); + + return 0; + } + + else if (strcmp(argv[1], "root") == 0) { + root_impls_setup(); + enum RootImpl impl = get_impl(); + + switch (impl) { + case None: { + printf("No root implementation found.\n"); + + return 1; + } + + case Multiple: { + printf("Multiple root implementations found.\n"); + + return 1; + } + + case KernelSU: { + printf("KernelSU root implementation found.\n"); + + return 0; + } + } + + + return 0; + } + + else { + printf("Usage: zygiskd [companion|version|root]\n"); + + return 0; + } + } + + switch_mount_namespace((pid_t)1); + root_impls_setup(); + __android_log_print(ANDROID_LOG_INFO, "zygiskd", "Root implementation: %d", get_impl()); + + return 0; +} \ No newline at end of file diff --git a/zygiskd/root_impl/common.c b/zygiskd/root_impl/common.c new file mode 100644 index 0000000..684ca89 --- /dev/null +++ b/zygiskd/root_impl/common.c @@ -0,0 +1,52 @@ +#include "kernelsu.h" + +#include "common.h" + +static enum RootImpl ROOT_IMPL = None; + +void root_impls_setup() { + enum RootImplState ksu_version = ksu_get_kernel_su(); + + enum RootImpl impl = None; + + if (ksu_version == Supported) impl = KernelSU; + + ROOT_IMPL = impl; +} + +enum RootImpl get_impl() { + return ROOT_IMPL; +} + +bool uid_granted_root(int uid) { + switch (get_impl()) { + case KernelSU: { + return ksu_uid_granted_root(uid); + } + default: { + return false; + } + } +} + +bool uid_should_umount(int uid) { + switch (get_impl()) { + case KernelSU: { + return ksu_uid_should_umount(uid); + } + default: { + return false; + } + } +} + +bool uid_is_manager(int uid) { + switch (get_impl()) { + case KernelSU: { + return ksu_uid_is_manager(uid); + } + default: { + return false; + } + } +} diff --git a/zygiskd/root_impl/common.h b/zygiskd/root_impl/common.h new file mode 100644 index 0000000..d1a088a --- /dev/null +++ b/zygiskd/root_impl/common.h @@ -0,0 +1,22 @@ +#ifndef COMMON_H +#define COMMON_H + +#include "../constants.h" + +enum RootImpl { + None, + Multiple, /* INFO: I know. */ + KernelSU +}; + +void root_impls_setup(); + +enum RootImpl get_impl(); + +bool uid_granted_root(int uid); + +bool uid_should_umount(int uid); + +bool uid_is_manager(int uid); + +#endif /* COMMON_H */ diff --git a/zygiskd/root_impl/kernelsu.c b/zygiskd/root_impl/kernelsu.c new file mode 100644 index 0000000..cfa28e3 --- /dev/null +++ b/zygiskd/root_impl/kernelsu.c @@ -0,0 +1,54 @@ +#include + +#include +#include + +#include "../constants.h" + +#include "kernelsu.h" + +#define KERNEL_SU_OPTION 0xdeadbeef + +#define CMD_GET_VERSION 2 +#define CMD_UID_GRANTED_ROOT 12 +#define CMD_UID_SHOULD_UMOUNT 13 + +enum RootImplState ksu_get_kernel_su() { + int version = 0; + prctl(KERNEL_SU_OPTION, CMD_GET_VERSION, &version, 0, 0); + + if (version == 0) return -1; + + if (version >= MIN_KSU_VERSION && version <= MAX_KSU_VERSION) return Supported; + + if (version >= 1 && version <= MIN_KSU_VERSION - 1) return TooOld; + + return Abnormal; +} + +bool ksu_uid_granted_root(int uid) { + uint32_t result = 0; + bool granted = false; + prctl(KERNEL_SU_OPTION, CMD_UID_GRANTED_ROOT, uid, &granted, &result); + + if (result != KERNEL_SU_OPTION) return false; + + return granted; +} + +bool ksu_uid_should_umount(int uid) { + uint32_t result = 0; + bool umount = false; + prctl(KERNEL_SU_OPTION, CMD_UID_SHOULD_UMOUNT, uid, &umount, &result); + + if (result != KERNEL_SU_OPTION) return false; + + return umount; +} + +bool ksu_uid_is_manager(int uid) { + struct stat s; + if (stat("/data/user_de/0/me.weishu.kernelsu", &s) == 0) return s.st_uid == (uid_t)uid; + + return false; +} diff --git a/zygiskd/root_impl/kernelsu.h b/zygiskd/root_impl/kernelsu.h new file mode 100644 index 0000000..a4cd565 --- /dev/null +++ b/zygiskd/root_impl/kernelsu.h @@ -0,0 +1,14 @@ +#ifndef KERNELSU_H +#define KERNELSU_H + +#include "../constants.h" + +enum RootImplState ksu_get_kernel_su(); + +bool ksu_uid_granted_root(int uid); + +bool ksu_uid_should_umount(int uid); + +bool ksu_uid_is_manager(int uid); + +#endif \ No newline at end of file diff --git a/zygiskd/utils.c b/zygiskd/utils.c new file mode 100644 index 0000000..7c98777 --- /dev/null +++ b/zygiskd/utils.c @@ -0,0 +1,172 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +void switch_mount_namespace(pid_t pid) { + char current_path[PATH_MAX]; + if (getcwd(current_path, PATH_MAX) == NULL) { + /* TODO: Improve error messages */ + perror("getcwd"); + + return; + } + + /* INFO: We will NEVER achieve PATH_MAX value, but this is for ensurance. */ + char path[PATH_MAX]; + snprintf(path, PATH_MAX, "/proc/%d/ns/mnt", pid); + + FILE *mnt_ns = fopen(path, "r"); + if (mnt_ns == NULL) { + /* TODO: Improve error messages */ + perror("fopen"); + + return; + } + + if (setns(fileno(mnt_ns), 0) == -1) { + /* TODO: Improve error messages */ + perror("setns"); + + return; + } + + fclose(mnt_ns); + + if (chdir(current_path) == -1) { + /* TODO: Improve error messages */ + perror("chdir"); + + return; + } +} + +int __system_property_get(const char *, char *); + +void get_property(const char *name, char *output) { + __system_property_get(name, output); +} + +void set_socket_create_context(const char *context) { + char path[PATH_MAX]; + snprintf(path, PATH_MAX, "/proc/thread-self/attr/sockcreate"); + + FILE *sockcreate = fopen(path, "w"); + if (sockcreate == NULL) { + perror("fopen"); + + return; + } + + if (fwrite(context, 1, strlen(context), sockcreate) != strlen(context)) { + perror("fwrite"); + + return; + } + + fclose(sockcreate); +} + +void get_current_attr(char *output) { + char path[PATH_MAX]; + snprintf(path, PATH_MAX, "/proc/self/attr/current"); + + FILE *current = fopen(path, "r"); + if (current == NULL) { + perror("fopen"); + + return; + } + + if (fgets(output, PATH_MAX, current) == NULL) { + perror("fgets"); + + return; + } + + fclose(current); +} + +void unix_datagram_sendto(const char *path, const char *buf) { + char current_attr[PATH_MAX]; + get_current_attr(current_attr); + + set_socket_create_context(current_attr); + + struct sockaddr_un addr; + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); + + int socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0); + if (socket_fd == -1) { + perror("socket"); + + return; + } + + if (connect(socket_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + perror("connect"); + + return; + } + + if (sendto(socket_fd, buf, strlen(buf), 0, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + perror("sendto"); + + return; + } + + set_socket_create_context("u:r:zygote:s0"); + + close(socket_fd); +} + +int chcon(const char *path, const char *context) { + char command[PATH_MAX]; + snprintf(command, PATH_MAX, "chcon %s %s", context, path); + + return system(command); +} + +int unix_listener_from_path(char *path) { + remove(path); + + struct sockaddr_un addr; + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); + + int socket_fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (socket_fd == -1) { + perror("socket"); + + return -1; + } + + if (bind(socket_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + perror("bind"); + + return -1; + } + + if (listen(socket_fd, 2) == -1) { + perror("listen"); + + return -1; + } + + if (chcon(path, "u:object_r:magisk_file:s0") == -1) { + perror("chcon"); + + return -1; + } + + return socket_fd; +} \ No newline at end of file diff --git a/zygiskd/utils.h b/zygiskd/utils.h new file mode 100644 index 0000000..b880d4d --- /dev/null +++ b/zygiskd/utils.h @@ -0,0 +1,16 @@ +#ifndef UTILS_H +#define UTILS_H + +#include + +void switch_mount_namespace(pid_t pid); + +void get_property(const char *name, char *output); + +void set_socket_create_context(const char *context); + +void unix_datagram_sendto(const char *path, const char *buf); + +int unix_listener_from_path(char *path); + +#endif /* UTILS_H */ \ No newline at end of file diff --git a/zygiskd/zygiskd b/zygiskd/zygiskd new file mode 100755 index 0000000000000000000000000000000000000000..5baaf306c04f32687c94351a106ffa8fa1e96a09 GIT binary patch literal 13600 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%0A_L1m;oE_$wUt(3&#vO~|W0n5Fwb^bW!f^}!cW zMtwl@h5CSa>Vr0{4|EUUKKQD}gklT>h{}u2*N#H=lqU z@msaLoPX3egTWl07t~lqys?L*^2dWYJc_COreF^H;M*%i-<8yd)NZs(^`Rcq)Q19T z2+tzrc%Hf93oC}p+i%ZVct)Z%jW1dDG|D!sGRc1#{4Rt4EAWR5{sr)-4SpAR?;X;% z)c-p8IR-xfe!0Pa6MVbDzXE=5^Y3eZpXLi=@z9=p zG}3po(*OTL5kHwGL`{DrwdPk>*ViwttFK#R-JI^kzT3_1se}WPaER$n5Y`^f#-bK> z1T#x&YU-Yi?J4>RKnXY#cztu0*_xM~?AH?KRC9Jr}{Hw0G_mGlYMRLLSxy zH-O@iM(}rk9`CnmdHxQvTFbAHbWC2ua<5H@tHk^kMihNelB>sq;Qm-5Wn$3$XaMZf zxaeCOe>dMD<%CE|I)-alWHnyK6I>TOrty*@{Bs)Td9KC9HjS4T$v>y@mLeR_{KD&< zA=-32c|CbrIeS@cM>#G-+p>mdAZhrkC+MS^whs1PT4C1&O13Fo~zm@Wc!(5pe{ZSL5RP?HeFpATjx7raOg=A)$#3$A}6ZmBHUM=Nk zh~OWNw{xAuOGTilUQ6N=+dEI<6YItM4*GEn=YGWd7}6NdwKo!uame328GpzHKTPA; zTQ2x~5X;{I`73E$-J}p6&v@@txQ?^jvxP{v#94cce%%E>I8Wn3w~N=q28}ls$v12K;Uf8VjkguauhsY-E#Ij9 z+#>O@cyaD8T<|Zt;9qvZ|61b4_(Z%Yz2YLj-v!5e$E4?V{@DfpnG1f>1%JZ@KjVVG z?ScY?qRDfMjBc zFsbTXIsr?W6n)$lfmoN_kqLLl?5-#znG*q=uYr^lb(ACwguCMrRDjRL^rK2)Jd?81 z;b=6T>_nZ?YI`;-=y{Mntcw6#cEatTT{sG(a*B#b#%ad^o@5{*=B^J^3mb=YGLGGi z2S}X2NyhDPCKK+p*TtPK8(*TGIDK^&k#Hh`kGxzg=0*cG^ixYeb@a1DQ1nKR0;%W$ z4=P+bDJ9UPn8NU#TO^}vYz`~s+k4`PsGaQTZjWW?TRuL>D^G)>b>+&{_PzJFG*fle z^rKziqX8^fR7_2CDe7_JiL6VRZQs+n?Ebs$yB}z@ZB?a;70w}zMPf3D+9l&T{t%Tq zKxKDffF*FgVO=Ji#wjK-daf#(P3gk%C$7@!OaIt$s}FMki%uBWbkZV=UUYiWVokP( zj!W4pST+t)5JwWCCmyvsGhs}Es4Y(>kn9AIfNWQ)2i?=tjWZjLG&vC^B%Z~9O5*rM zW>m<4Tn>k2G3Fv&wzO^2D9NV7k=RE(Ge(W%<6>?H$RMH)irMP;gpK19ax#uTT1KYy zDHHSsX1O|R){~5{w`q7Igxxe{=!n^eIe?~5hseXXLRwKrNia4#GO2D%aHngs<7sx| zryf{#|GjsqRq&(#(sD`{Zd)?tb%ts2eu-XwwX_hlKQa{;>+|~)Q+|(P1-?%*Pw#>B zsLuNQe#Df{a!{f=sBV6L;rGRP!0~Oz0YZV-EE`qA^dj`TX_ReD-@X%e_5nIx(~*O=(u58pWm}JE1uT+ zeEyT)kNEE!SdM9kGn#${lziv@E!I!#K-2i8#O-H4b^#+1*5`ArLwX~X`*xI>*8d>?X`jNZ zpZAgGTdGEWpHtk#_S1d_)gNR5OO#ff>^Y*Jng~j^+2b?YCwEzGB literal 0 HcmV?d00001 diff --git a/zygiskd/zygiskd.c b/zygiskd/zygiskd.c new file mode 100644 index 0000000..20ae753 --- /dev/null +++ b/zygiskd/zygiskd.c @@ -0,0 +1,353 @@ +#include +#include +#include +#include + +#include "root_impl/common.h" +#include "constants.h" +#include "utils.h" + +struct Module { + char *name; + int lib_fd; +} + +struct Context { + struct Module *modules; +} + +enum Architecture { + ARM32, + ARM64, + X86, + X86_64, +} + +static char TMP_PATH[] = "/data/adb/rezygisk"; +static char CONTROLLER_SOCKET[PATH_MAX]; +static char PATH_CP_NAME[PATH_MAX]; + +enum Architecture get_arch() { + char system_arch[PROP_VALUE_MAX]; + get_property("ro.product.cpu.abi", system_arch); + + if (strstr(system_arch, "arm") != NULL) return lp_select(ARM32, ARM64); + if (strstr(system_arch, "x86") != NULL) return lp_select(ARM64, X86_64); + + printf("Unsupported system architecture: %s\n", system_arch); + exit(1); +} + +int create_library_fd(char *so_path) { + int memfd = memfd_create("jit-cache-zygisk", MFD_ALLOW_SEALING); + if (memfd == -1) { + printf("Failed creating memfd: %s\n", strerror(errno)); + return -1; + } + + int file = open(so_path, O_RDONLY); + if (file == -1) { + printf("Failed opening file: %s\n", strerror(errno)); + return -1; + } + + struct stat st; + fstat(file, &st); + ftruncate(memfd, st.st_size); + + void *addr = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, memfd, 0); + if (addr == MAP_FAILED) { + printf("Failed mapping memory: %s\n", strerror(errno)); + return -1; + } + + read(file, addr, st.st_size); + munmap(addr, st.st_size); + close(file); + + unsigned int seals = F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL; + if (fcntl(memfd, F_ADD_SEALS, seals) == -1) { + printf("Failed adding seals: %s\n", strerror(errno)); + return -1; + } + + return memfd; +} + +/* WARNING: Dynamic memory based */ +struct Module **load_modules(enum Architecture arch) { + struct Module **modules = malloc(sizeof(struct Module *)); + DIR *dir = opendir(PATH_MODULES_DIR); + + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) { + char *name = entry->d_name; + char so_path[PATH_MAX]; + snprintf(so_path, PATH_MAX, "%s/zygisk/%s.so", PATH_MODULES_DIR, name); + + struct stat st; + if (stat(so_path, &st) == -1) continue; + + char disabled[PATH_MAX]; + snprintf(disabled, PATH_MAX, "%s/disable", PATH_MODULES_DIR); + if (stat(disabled, &st) != -1) continue; + + printf("Loading module `%s`...\n", name); + int lib_fd = create_library_fd(so_path); + if (lib_fd == -1) continue; + + struct Module *module = malloc(sizeof(struct Module)); + module->name = name; + module->lib_fd = lib_fd; + modules = realloc(modules, sizeof(modules) + sizeof(module)); + modules[sizeof(modules)] = module; + } + + return modules; +} + +void free_modules(struct Module **modules) { + for (int i = 0; i < sizeof(modules); i++) { + free(modules[i]); + } + + free(modules); +} + +int create_daemon_socket() { + set_socket_create_context("u:r:zygote:s0"); + int socket_fd = unix_listener_from_path(PATH_CP_NAME); + + return socket_fd; +} + +void zygiskd_start() { + printf("Welcome to ReZygisk %s!\n", ZKSU_VERSION); + + snprintf(CONTROLLER_SOCKET, PATH_MAX, "%s/init_monitor", TMP_PATH); + snprintf(PATH_CP_NAME, PATH_MAX, "%s/%s", TMP_PATH, lp_select("/cp32.sock", "/cp64.sock")); + + Architecture arch = get_arch(); + printf("Daemon architecture: %s\n", arch); + + struct Module **modules = load_modules(arch); + + char *msg = malloc(1); + size_t msg_len = 1; + + switch (get_impl()) { + case KernelSU: { + msg[0] = DAEMON_SET_INFO; + + msg = realloc(msg, strlen("Root: KernelSU, Modules: ") + 1); + memcpy(msg + 1, "Root: KernelSU, Modules: ", strlen("Root: KernelSU, Modules: ")); + msg_len += strlen("Root: KernelSU, Modules: "); + + for (int i = 0; i < sizeof(modules); i++) { + msg = realloc(msg, strlen(modules[i]->name) + strlen(", ") + 1); + memcpy(msg + msg_len, modules[i]->name, strlen(modules[i]->name)); + msg_len += strlen(modules[i]->name); + memcpy(msg + msg_len, ", ", strlen(", ")); + msg_len += strlen(", "); + + free(modules[i]); + } + } + default: { + msg[0] = DAEMON_SET_ERROR_INFO; + + msg = realloc(msg, strlen("Invalid root implementation") + 1); + memcpy(msg + 1, "Invalid root implementation", strlen("Invalid root implementation")); + } + } + + msg = realloc(msg, msg_len + 1); + msg[msg_len] = '\0'; + + unix_datagram_sendto(CONTROLLER_SOCKET, msg); + + int socket_fd = create_daemon_socket(); + if (socket_fd == -1) { + printf("Failed creating daemon socket: %s\n", strerror(errno)); + + return; + } + + while (1) { + struct sockaddr_un addr; + socklen_t addr_len = sizeof(addr); + int client_fd = accept(socket_fd, (struct sockaddr *) &addr, &addr_len); + if (client_fd == -1) { + printf("Failed accepting client: %s\n", strerror(errno)); + + return; + } + + char action; + read(client_fd, &action, 1); + + switch (action) { + case DAEMON_PING_HEARTBEAT: { + char value = ZYGOTE_INJECTED; + unix_datagram_sendto(CONTROLLER_SOCKET, &value); + } + case DAEMON_ZYGOTE_RESTART: { + printf("Zygote restarted, clean up companions\n"); + + free_modules(modules); + + /* companion code */ + } + case DAEMON_SYSTEM_SERVER_STARTED: { + char value = SYSTEM_SERVER_STARTED; + unix_datagram_sendto(CONTROLLER_SOCKET, &value); + } + default: { + // WIP + } + } + } +} + +void spawn_companion(char *name, int lib_fd) { + /* Creates 2 connected unix streams */ + int sockets[2]; + socketpair(AF_UNIX, SOCK_STREAM, 0, sockets); + + int daemon_fd = sockets[0]; + int companion_fd = sockets[1]; + + pid_t pid = fork(); + if (pid == -1) { + printf("Failed forking: %s\n", strerror(errno)); + + return; + } else if (pid > 0) { + close(companion_fd); + + int status; + waitpid(pid, &status, 0); + + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { + write(daemon_fd, name, strlen(name)); + write(daemon_fd, &lib_fd, sizeof(lib_fd)); + + int response; + read(daemon_fd, &response, 1); + + if (response == 0) { + printf("No companion spawned for %s because it has no entry\n", name); + } else if (response == 1) { + printf("Spawned companion for %s\n", name); + } else { + printf("Invalid companion response\n"); + } + } else { + printf("Exited with status %d\n", status); + } + } else { + fcntl(companion_fd, F_SETFD, 0); + } + + char *args[] = { "zygiskd", "companion", companion_fd, NULL }; + execv("/system/bin/zygiskd", args); + + exit(0); +} + +void handle_daemon_action(enum DaemonSocketAction action, int stream_fd, struct Context *context) { + switch (action) { + case RequestLogcatFd: { + while (1) { + char level; + read(stream_fd, &level, 1); + + char tag[PATH_MAX]; + read(stream_fd, tag, PATH_MAX); + + char message[PATH_MAX]; + read(stream_fd, message, PATH_MAX); + + __android_log_print(level, tag, message); + } + } + case GetProcessFlags: { + int uid; + read(stream_fd, &uid, sizeof(uid)); + + int flags = 0; + if (uid_is_manager(uid)) { + flags |= PROCESS_IS_MANAGER; + } else { + if (uid_granted_root(uid)) { + flags |= PROCESS_GRANTED_ROOT; + } + if (uid_should_umount(uid)) { + flags |= PROCESS_ON_DENYLIST; + } + } + + switch (get_impl()) { + case KernelSU: { + flags |= PROCESS_ROOT_IS_KSU; + } + // case Magisk: { + // flags |= PROCESS_ROOT_IS_MAGISK; + // } + // case APatch: { + // flags |= PROCESS_ROOT_IS_APATCH; + // } + } + + write(stream_fd, &flags, sizeof(flags)); + } + case GetInfo: { + int flags = 0; + + switch (get_impl()) { + case KernelSU: { + flags |= PROCESS_ROOT_IS_KSU; + } + // case Magisk: { + // flags |= PROCESS_ROOT_IS_MAGISK; + // } + // case APatch: { + // flags |= PROCESS_ROOT_IS_APATCH; + // } + } + + write(stream_fd, &flags, sizeof(flags)); + + int pid = getpid(); + write(stream_fd, &pid, sizeof(pid)); + } + case ReadModules: { + int len = sizeof(context->modules); + write(stream_fd, &len, sizeof(len)); + + for (int i = 0; i < len; i++) { + write(stream_fd, context->modules[i]->name, strlen(context->modules[i]->name)); + send_fd(stream_fd, context->modules[i]->lib_fd); + } + } + case RequestCompanionSocket: { + /* WIP */ + + break; + } + case GetModuleDir: { + int index; + read(stream_fd, &index, sizeof(index)); + + char dir[PATH_MAX]; + snprintf(dir, PATH_MAX, "%s/%s", PATH_MODULES_DIR, context->modules[index]->name); + int dir_fd = open(dir, O_RDONLY); + + send_fd(stream_fd, dir_fd); + } + default: { + // WIP + } + } +} +