fix: zygiskd c99 building process

This commit fixes building process of new zygiskd.
This commit is contained in:
ThePedroo
2024-07-26 02:37:31 -03:00
parent 42a5ab989f
commit 7d29fd821f
22 changed files with 131 additions and 1698 deletions

View File

@@ -28,8 +28,10 @@ val ccachePath by lazy {
val defaultCFlags = arrayOf(
"-Wall", "-Wextra",
"-fno-rtti", "-fno-exceptions",
"-fvisibility=hidden", "-fvisibility-inlines-hidden",
"-fno-stack-protector", "-fomit-frame-pointer",
"-Wno-builtin-macro-redefined", "-D__FILE__=__FILE_NAME__"
"-Wno-builtin-macro-redefined", "-D__FILE__=__FILE_NAME__",
"-O0", "-g"
)
val releaseFlags = arrayOf(

View File

@@ -80,7 +80,7 @@ androidComponents.onVariants { variant ->
filter<FixCrLfFilter>("eol" to FixCrLfFilter.CrLf.newInstance("lf"))
}
into("bin") {
from(project(":zygiskd").layout.buildDirectory.file("rustJniLibs/android"))
from(project(":zygiskd").layout.buildDirectory.getAsFile().get())
include("**/zygiskd")
}
into("lib") {

View File

@@ -1,2 +0,0 @@
zygiskd64
zygiskd32

View File

@@ -1,24 +0,0 @@
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.

View File

@@ -1,33 +0,0 @@
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 \
# companion.c \
# dl.c \
# main.c \
# utils.c \
# zygiskd.c
FILES = root_impl/*.c \
*.c
CFLAGS = -D_GNU_SOURCE -std=c99 -Wpedantic -Wall -Wextra -Werror -Wformat -Wuninitialized -Wshadow -Wno-zero-length-array -Wno-fixed-enum-extension -Iroot_impl -llog
all: CFLAGS += -DDEBUG=0 -O3 -flto=thin -Wl,--strip-all
all:
$(CC) $(CFLAGS) $(FILES) -o zygiskd64
debug: CFLAGS += -DDEBUG=1 -g -O0
debug:
$(CC) $(CFLAGS) $(FILES) -o zygiskd64
32bit: CFLAGS += -m32 -DDEBUG=0 -O3 -flto=thin -Wl,--strip-all
32bit:
$(CC) $(CFLAGS) $(FILES) -o zygiskd32
32bit-debug: CFLAGS += -m32 -DDEBUG=1 -g -O0
32bit-debug:
$(CC) $(CFLAGS) $(FILES) -o zygiskd32
clean:
rm -f zygiskd

View File

@@ -1,125 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <dlfcn.h>
#include <errno.h>
#include <unistd.h>
#include <linux/limits.h>
#include <pthread.h>
#include <android/log.h>
#include "companion.h"
#include "dl.h"
#include "utils.h"
typedef void (*ZygiskCompanionEntryFn)(int);
ZygiskCompanionEntryFn load_module(int 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) {
int fd = *((int *)arg);
struct stat st0;
if (fstat(fd, &st0) == -1) {
LOGE("Failed to stat client fd\n");
free(arg);
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, &st1) == -1) {
LOGE("Failed to stat client fd\n");
free(arg);
exit(0);
}
if (st0.st_dev != st1.st_dev || st0.st_ino != st1.st_ino) {
close(fd);
}
free(arg);
return NULL;
}
void entry(int fd) {
LOGI("companion entry fd: |%d|\n", fd);
char name[256 + 1];
/* INFO: Getting stuck here */
ssize_t ret = read_string(fd, name, sizeof(name) - 1);
if (ret == -1) return;
name[ret] = '\0';
LOGI("Companion process requested for `%s`\n", name);
int library_fd;
recv_fd(fd, &library_fd);
LOGI("Library fd: %d\n", library_fd);
ZygiskCompanionEntryFn entry = load_module(library_fd);
LOGI("Library loaded\n");
close(library_fd);
LOGI("Library closed\n");
if (entry == NULL) {
LOGI("No companion entry for: %s\n", name);
write(fd, (void *)0, 1);
return;
}
LOGI("Companion process created for: %s\n", name);
uint8_t response = 1;
write(fd, &response, sizeof(response));
while (1) {
int client_fd;
recv_fd(fd, &client_fd);
LOGI("New companion request from module \"%s\" with fd \"%d\"\n", name, client_fd);
write(fd, &response, sizeof(response));
int *client_fd_ptr = malloc(sizeof(int));
*client_fd_ptr = client_fd;
LOGI("Creating new thread for companion request\n");
pthread_t thread;
pthread_create(&thread, NULL, ExecuteNew, (void *)client_fd_ptr);
pthread_detach(thread);
}
}

View File

@@ -1,6 +0,0 @@
#ifndef COMPANION_H
#define COMPANION_H
void entry(int fd);
#endif /* COMPANION_H */

View File

@@ -1,70 +0,0 @@
#ifndef CONSTANTS_H
#define CONSTANTS_H
#include <android/log.h>
#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) b
#else
#define lp_select(a, b) a
#endif
#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: uint32_t {
PROCESS_GRANTED_ROOT = (1u << 0),
PROCESS_ON_DENYLIST = (1u << 1),
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),
PROCESS_IS_SYSUI = (1u << 31)
};
enum RootImplState {
Supported,
TooOld,
Abnormal
};
#endif /* CONSTANTS_H */

View File

@@ -1,58 +0,0 @@
#include <stdlib.h>
#include <sys/types.h>
#include <libgen.h>
#include <dlfcn.h>
#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,
(void *)&android_dlopen
);
if (ns != NULL) {
info.flags = ANDROID_DLEXT_USE_NAMESPACE;
info.library_namespace = ns;
}
}
return android_dlopen_ext(path, flags, &info);
}

View File

@@ -1,6 +0,0 @@
#ifndef DL_H
#define DL_H
void *android_dlopen(char *path, u_int32_t flags);
#endif /* DL_H */

View File

@@ -1,86 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <android/log.h>
#include "root_impl/common.h"
#include "companion.h"
#include "zygiskd.h"
#include "utils.h"
int __android_log_print(int prio, const char *tag, const char *fmt, ...);
int main(int argc, char *argv[]) {
errno = 0;
/* Initialize android logger */
LOGI("Initializing zygiskd\n");
LOGI("Argc: %d\n", argc);
for (int i = 0; i < argc; i++) {
LOGI("argv[%d] = %s\n", i, argv[i]);
}
if (argc > 1) {
if (strcmp(argv[1], "companion") == 0) {
if (argc < 3) {
LOGI("Usage: zygiskd companion <fd>\n");
return 1;
}
int fd = atoi(argv[2]);
entry(fd);
return 0;
}
else if (strcmp(argv[1], "version") == 0) {
LOGI("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: {
LOGI("No root implementation found.\n");
return 1;
}
case Multiple: {
LOGI("Multiple root implementations found.\n");
return 1;
}
case KernelSU: {
LOGI("KernelSU root implementation found.\n");
return 0;
}
}
return 0;
}
else {
LOGI("Usage: zygiskd [companion|version|root]\n");
return 0;
}
}
switch_mount_namespace((pid_t)1);
root_impls_setup();
zygiskd_start();
return 0;
}

View File

@@ -1,54 +0,0 @@
#include <sys/types.h>
#include "kernelsu.h"
#include "common.h"
static enum RootImpl ROOT_IMPL = None;
void root_impls_setup(void) {
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(void) {
return ROOT_IMPL;
}
bool uid_granted_root(uid_t uid) {
switch (get_impl()) {
case KernelSU: {
return ksu_uid_granted_root(uid);
}
default: {
return false;
}
}
}
bool uid_should_umount(uid_t uid) {
switch (get_impl()) {
case KernelSU: {
return ksu_uid_should_umount(uid);
}
default: {
return false;
}
}
}
bool uid_is_manager(uid_t uid) {
switch (get_impl()) {
case KernelSU: {
return ksu_uid_is_manager(uid);
}
default: {
return false;
}
}
}

View File

@@ -1,22 +0,0 @@
#ifndef COMMON_H
#define COMMON_H
#include "../constants.h"
enum RootImpl {
None,
Multiple, /* INFO: I know. */
KernelSU
};
void root_impls_setup(void);
enum RootImpl get_impl(void);
bool uid_granted_root(uid_t uid);
bool uid_should_umount(uid_t uid);
bool uid_is_manager(uid_t uid);
#endif /* COMMON_H */

View File

@@ -1,68 +0,0 @@
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/prctl.h>
#include <errno.h>
#include "../constants.h"
#include "../utils.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(void) {
int version = 0;
prctl(KERNEL_SU_OPTION, CMD_GET_VERSION, &version, 0, 0);
errno = 0;
if (version == 0) return Abnormal;
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(uid_t uid) {
uint32_t result = 0;
bool granted = false;
prctl(KERNEL_SU_OPTION, CMD_UID_GRANTED_ROOT, uid, &granted, &result);
LOGI("ksu_uid_granted_root: %d", granted);
if (result != KERNEL_SU_OPTION) return false;
return granted;
}
bool ksu_uid_should_umount(uid_t uid) {
uint32_t result = 0;
bool umount = false;
prctl(KERNEL_SU_OPTION, CMD_UID_SHOULD_UMOUNT, uid, &umount, &result);
LOGI("ksu_uid_should_umount: %d", umount);
if (result != KERNEL_SU_OPTION) return false;
return umount;
}
bool ksu_uid_is_manager(uid_t uid) {
struct stat s;
if (stat("/data/user_de/0/me.weishu.kernelsu", &s) == 0) {
LOGI("ksu_uid_is_manager: %d", uid);
return s.st_uid == uid;
}
LOGI("ksu_uid_is_manager: false");
return false;
}

View File

@@ -1,14 +0,0 @@
#ifndef KERNELSU_H
#define KERNELSU_H
#include "../constants.h"
enum RootImplState ksu_get_kernel_su(void);
bool ksu_uid_granted_root(uid_t uid);
bool ksu_uid_should_umount(uid_t uid);
bool ksu_uid_is_manager(uid_t uid);
#endif

View File

@@ -1,295 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <unistd.h>
#include <linux/limits.h>
#include <sched.h>
#include <pthread.h>
#include <android/log.h>
#include "utils.h"
void switch_mount_namespace(pid_t pid) {
char current_path[PATH_MAX];
if (getcwd(current_path, PATH_MAX) == NULL) {
/* TODO: Improve error messages */
LOGE("getcwd: %s\n", strerror(errno));
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 */
LOGE("fopen: %s\n", strerror(errno));
return;
}
if (setns(fileno(mnt_ns), 0) == -1) {
/* TODO: Improve error messages */
LOGE("setns: %s\n", strerror(errno));
return;
}
fclose(mnt_ns);
if (chdir(current_path) == -1) {
/* TODO: Improve error messages */
LOGE("chdir: %s\n", strerror(errno));
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) {
LOGE("fopen: %s\n", strerror(errno));
return;
}
if (fwrite(context, 1, strlen(context), sockcreate) != strlen(context)) {
LOGE("fwrite: %s\n", strerror(errno));
return;
}
fclose(sockcreate);
}
static 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) {
LOGE("fopen: %s\n", strerror(errno));
return;
}
if (fgets(output, PATH_MAX, current) == NULL) {
LOGE("fgets: %s\n", strerror(errno));
return;
}
fclose(current);
}
void unix_datagram_sendto(const char *path, void *buf, size_t len) {
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) {
LOGE("socket: %s\n", strerror(errno));
return;
}
if (connect(socket_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
LOGE("connect: %s\n", strerror(errno));
return;
}
if (sendto(socket_fd, buf, len, 0, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
LOGE("sendto: %s\n", strerror(errno));
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) {
if (remove(path) == -1 && errno != ENOENT) {
LOGE("remove: %s\n", strerror(errno));
return -1;
}
int socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (socket_fd == -1) {
LOGE("socket: %s\n", strerror(errno));
return -1;
}
struct sockaddr_un addr;
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
if (bind(socket_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) == -1) {
LOGE("bind: %s\n", strerror(errno));
return -1;
}
if (listen(socket_fd, 2) == -1) {
LOGE("listen: %s\n", strerror(errno));
return -1;
}
if (chcon(path, "u:object_r:magisk_file:s0") == -1) {
LOGE("chcon: %s\n", strerror(errno));
return -1;
}
return socket_fd;
}
ssize_t send_fd(int sockfd, int fd) {
char control_buf[CMSG_SPACE(sizeof(int))];
memset(control_buf, 0, sizeof(control_buf));
int cnt = 1;
struct iovec iov = {
.iov_base = &cnt,
.iov_len = sizeof(cnt)
};
struct msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = control_buf,
.msg_controllen = sizeof(control_buf)
};
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
ssize_t sent_bytes = sendmsg(sockfd, &msg, 0);
if (sent_bytes == -1) {
LOGE("Failed to send fd: %s\n", strerror(errno));
return -1;
}
return sent_bytes;
}
ssize_t recv_fd(int sockfd, int *fd) {
char control_buf[CMSG_SPACE(sizeof(int))];
memset(control_buf, 0, sizeof(control_buf));
int cnt = 1;
struct iovec iov = {
.iov_base = &cnt,
.iov_len = sizeof(cnt)
};
struct msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = control_buf,
.msg_controllen = sizeof(control_buf)
};
ssize_t received_bytes = recvmsg(sockfd, &msg, 0);
if (received_bytes == -1) {
LOGE("Failed to read fd: %s\n", strerror(errno));
return -1;
}
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
memcpy(fd, CMSG_DATA(cmsg), sizeof(int));
return received_bytes;
}
ssize_t write_string(int fd, const char *str) {
size_t len = strlen(str);
ssize_t written_bytes = write(fd, &len, sizeof(len));
if (written_bytes != sizeof(len)) {
LOGE("Failed to write string length: %s\n", strerror(errno));
return -1;
}
written_bytes = write(fd, str, len);
if ((size_t)written_bytes != len) {
LOGE("Failed to write string: Not all bytes were written.\n");
return -1;
}
return written_bytes;
}
ssize_t read_string(int fd, char *str, size_t len) {
size_t str_len_buf[1];
ssize_t read_bytes = read(fd, &str_len_buf, sizeof(str_len_buf));
if (read_bytes != (ssize_t)sizeof(str_len_buf)) {
LOGE("Failed to read string length: %s\n", strerror(errno));
return -1;
}
size_t str_len = str_len_buf[0];
if (str_len > len) {
LOGE("Failed to read string: Buffer is too small (%zu > %zu).\n", str_len, len);
return -1;
}
read_bytes = read(fd, str, str_len);
if (read_bytes != (ssize_t)str_len) {
LOGE("Failed to read string: Not all bytes were read (%zd != %zu).\n", read_bytes, str_len);
return -1;
}
return read_bytes;
}

View File

@@ -1,36 +0,0 @@
#ifndef UTILS_H
#define UTILS_H
#include <sys/types.h>
#include "constants.h"
#define LOGI(...) \
__android_log_print(ANDROID_LOG_INFO, lp_select("zygiskd32", "zygiskd64"), __VA_ARGS__); \
printf(__VA_ARGS__)
#define LOGE(...) \
__android_log_print(ANDROID_LOG_INFO , lp_select("zygiskd32", "zygiskd64"), __VA_ARGS__); \
printf(__VA_ARGS__)
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, void *buf, size_t len);
int chcon(const char *path, const char *context);
int unix_listener_from_path(char *path);
ssize_t send_fd(int sockfd, int fd);
ssize_t recv_fd(int sockfd, int *fd);
ssize_t write_string(int fd, const char *str);
ssize_t read_string(int fd, char *str, size_t len);
#endif /* UTILS_H */

View File

@@ -1,690 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/sendfile.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <linux/limits.h>
#include <pthread.h>
#include "root_impl/common.h"
#include "constants.h"
#include "utils.h"
struct Module {
char *name;
int lib_fd;
int companion;
};
struct Context {
struct Module *modules;
int len;
};
enum Architecture {
ARM32,
ARM64,
X86,
X86_64,
};
#define PATH_MODULES_DIR "/data/adb/modules"
#define TMP_PATH "/data/adb/rezygisk"
#define CONTROLLER_SOCKET TMP_PATH "/init_monitor"
#define PATH_CP_NAME TMP_PATH "/" lp_select("cp32.sock", "cp64.sock")
#define ZYGISKD_FILE "zygiskd" lp_select("32", "64")
#define ZYGISKD_PATH "/data/adb/modules/zygisksu/bin/zygiskd" lp_select("32", "64")
#define ASSURE_SIZE_WRITE(area_name, subarea_name, sent_size, expected_size) \
if (sent_size != (ssize_t)(expected_size)) { \
LOGE("Failed to sent " subarea_name " in " area_name ": Expected %zu, got %zd\n", expected_size, sent_size); \
\
return; \
}
#define ASSURE_SIZE_READ(area_name, subarea_name, sent_size, expected_size) \
if (sent_size != (ssize_t)(expected_size)) { \
LOGE("Failed to read " subarea_name " in " area_name ": Expected %zu, got %zd\n", expected_size, sent_size); \
\
return; \
}
#define ASSURE_SIZE_WRITE_BREAK(area_name, subarea_name, sent_size, expected_size) \
if (sent_size != (ssize_t)(expected_size)) { \
LOGE("Failed to sent " subarea_name " in " area_name ": Expected %zu, got %zd\n", expected_size, sent_size); \
\
break; \
}
#define ASSURE_SIZE_READ_BREAK(area_name, subarea_name, sent_size, expected_size) \
if (sent_size != (ssize_t)(expected_size)) { \
LOGE("Failed to read " subarea_name " in " area_name ": Expected %zu, got %zd\n", expected_size, sent_size); \
\
break; \
}
#define ASSURE_SIZE_WRITE_WR(area_name, subarea_name, sent_size, expected_size) \
if (sent_size != (ssize_t)(expected_size)) { \
LOGE("Failed to sent " subarea_name " in " area_name ": Expected %zu, got %zd\n", expected_size, sent_size); \
\
return -1; \
}
#define ASSURE_SIZE_READ_WR(area_name, subarea_name, sent_size, expected_size) \
if (sent_size != (ssize_t)(expected_size)) { \
LOGE("Failed to read " subarea_name " in " area_name ": Expected %zu, got %zd\n", expected_size, sent_size); \
\
return -1; \
}
static enum Architecture get_arch(void) {
char system_arch[32];
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(X86, X86_64);
LOGE("Unsupported system architecture: %s\n", system_arch);
exit(1);
}
int create_library_fd(const char *so_path) {
int memfd = memfd_create("jit-cache-zygisk", MFD_ALLOW_SEALING);
if (memfd == -1) {
perror("memfd_create");
return -1;
}
int so_fd = open(so_path, O_RDONLY);
if (so_fd == -1) {
perror("open");
close(memfd);
return -1;
}
struct stat st;
if (fstat(so_fd, &st) == -1) {
perror("fstat");
close(so_fd);
close(memfd);
return -1;
}
if (sendfile(memfd, so_fd, NULL, st.st_size) == -1) {
perror("sendfile");
close(so_fd);
close(memfd);
return -1;
}
close(so_fd);
if (fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL) == -1) {
perror("fcntl");
close(memfd);
return -1;
}
return memfd;
}
/* WARNING: Dynamic memory based */
static void load_modules(enum Architecture arch, struct Context *context) {
context->len = 0;
context->modules = malloc(1);
DIR *dir = opendir(PATH_MODULES_DIR);
if (dir == NULL) {
LOGE("Failed opening modules directory: %s.", PATH_MODULES_DIR);
return;
}
char arch_str[32];
switch (arch) {
case ARM32: {
strcpy(arch_str, "armeabi-v7a");
break;
}
case ARM64: {
strcpy(arch_str, "arm64-v8a");
break;
}
case X86: {
strcpy(arch_str, "x86");
break;
}
case X86_64: {
strcpy(arch_str, "x86_64");
break;
}
}
LOGI("Loading modules for architecture: %s\n", arch_str);
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
if (entry->d_type != DT_DIR) continue; /* INFO: Only directories */
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0 || strcmp(entry->d_name, "zygisksu") == 0) continue;
char *name = entry->d_name;
char so_path[PATH_MAX];
snprintf(so_path, PATH_MAX, "/data/adb/modules/%s/zygisk/%s.so", name, arch_str);
struct stat st;
if (stat(so_path, &st) == -1) {
errno = 0;
continue;
}
char disabled[PATH_MAX];
snprintf(disabled, PATH_MAX, "/data/adb/modules/%s/disable", name);
if (stat(disabled, &st) != -1) {
errno = 0;
continue;
}
LOGI("Loading module `%s`...\n", name);
int lib_fd = create_library_fd(so_path);
if (lib_fd == -1) {
LOGE("Failed loading module `%s`\n", name);
continue;
}
LOGI("Loaded module lib fd: %d\n", lib_fd);
context->modules = realloc(context->modules, ((context->len + 1) * sizeof(struct Module)));
context->modules[context->len].name = strdup(name);
context->modules[context->len].lib_fd = lib_fd;
context->modules[context->len].companion = -1;
context->len++;
}
}
static void free_modules(struct Context *context) {
for (int i = 0; i < context->len; i++) {
free(context->modules[i].name);
if (context->modules[i].companion != -1) close(context->modules[i].companion);
}
}
static int create_daemon_socket(void) {
set_socket_create_context("u:r:zygote:s0");
return unix_listener_from_path(PATH_CP_NAME);
}
static int spawn_companion(char *name, int lib_fd) {
int sockets[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) {
LOGE("Failed creating socket pair.\n");
return -1;
}
int daemon_fd = sockets[0];
int companion_fd = sockets[1];
LOGI("Companion fd: %d\n", companion_fd);
LOGI("Daemon fd: %d\n", daemon_fd);
pid_t pid = fork();
LOGI("Forked: %d\n", pid);
if (pid < 0) {
LOGE("Failed forking companion: %s\n", strerror(errno));
close(companion_fd);
close(daemon_fd);
exit(1);
} else if (pid > 0) {
close(companion_fd);
LOGI("Waiting for companion to start (%d)\n", pid);
int status = 0;
// waitpid(pid, &status, 0);
LOGI("Companion exited with status %d\n", status);
// if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
if (write_string(daemon_fd, name) == -1) return -1;
if (send_fd(daemon_fd, lib_fd) == -1) return -1;
LOGI("Sent module name and lib fd\n");
uint8_t response_buf[1];
ssize_t ret = read(daemon_fd, &response_buf, sizeof(response_buf));
ASSURE_SIZE_READ_WR("companion", "response", ret, sizeof(response_buf));
uint8_t response = response_buf[0];
LOGI("Companion response: %hhu\n", response);
if (response == 0) return -2;
else if (response == 1) return daemon_fd;
else return -2;
// } else {
// LOGE("Exited with status %d\n", status);
// close(daemon_fd);
// return -1;
// }
/* INFO: if pid == 0: */
} else {
LOGI("Companion started (%d)\n", pid);
/* INFO: There is no case where this will fail with a valid fd. */
fcntl(companion_fd, F_SETFD, 0);
}
char companion_fd_str[32];
snprintf(companion_fd_str, 32, "%d", companion_fd);
LOGI("Executing companion...\n");
char *argv[] = { ZYGISKD_FILE, "companion", companion_fd_str, NULL };
if (execv(ZYGISKD_PATH, argv) == -1) {
LOGE("Failed executing companion: %s\n", strerror(errno));
close(companion_fd);
exit(1);
}
exit(0);
}
/* TODO: Is packed attribute really necessary? */
struct __attribute__((__packed__)) MsgHead {
unsigned int cmd;
int length;
char data[0];
};
void zygiskd_start(void) {
LOGI("Welcome to ReZygisk %s!", ZKSU_VERSION);
enum Architecture arch = get_arch();
struct Context context;
load_modules(arch, &context);
struct MsgHead *msg = NULL;
size_t msg_sz = 0;
switch (get_impl()) {
case None: {
/* INFO: Stop, compiler. */
break;
}
case Multiple: {
/* INFO: Stop, compiler. */
break;
}
case KernelSU: {
if (context.len == 0) {
msg_sz = sizeof(struct MsgHead) + strlen("Root: KernelSU, Modules: None") + 1;
msg = malloc(msg_sz);
msg->cmd = DAEMON_SET_INFO;
msg->length = strlen("Root: KernelSU, Modules: None") + 1;
memcpy(msg->data, "Root: KernelSU, Modules: None", strlen("Root: KernelSU, Modules: None"));
} else {
char *module_list = malloc(1);
size_t module_list_len = 0;
for (int i = 0; i < context.len; i++) {
if (i != context.len - 1) {
module_list = realloc(module_list, module_list_len + strlen(context.modules[i].name) + strlen(", ") + 1);
memcpy(module_list + module_list_len, context.modules[i].name, strlen(context.modules[i].name));
module_list_len += strlen(context.modules[i].name);
memcpy(module_list + module_list_len, ", ", strlen(", "));
module_list_len += strlen(", ");
} else {
module_list = realloc(module_list, module_list_len + strlen(context.modules[i].name) + 1);
memcpy(module_list + module_list_len, context.modules[i].name, strlen(context.modules[i].name));
module_list_len += strlen(context.modules[i].name);
}
}
msg_sz = sizeof(struct MsgHead) + strlen("Root: KernelSU, Modules: ") + module_list_len + 1;
msg = malloc(msg_sz);
msg->cmd = DAEMON_SET_INFO;
msg->length = strlen("Root: KernelSU, Modules: ") + module_list_len + 1;
memcpy(msg->data, "Root: KernelSU, Modules: ", strlen("Root: KernelSU, Modules: "));
memcpy(msg->data + strlen("Root: KernelSU, Modules: "), module_list, module_list_len);
free(module_list);
}
break;
}
default: {
msg_sz = sizeof(struct MsgHead) + strlen("Invalid root implementation") + 1;
msg = malloc(msg_sz);
msg->cmd = DAEMON_SET_ERROR_INFO;
msg->length = strlen("Invalid root implementation") + 1;
memcpy(msg->data, "Invalid root implementation", strlen("Invalid root implementation"));
break;
}
}
unix_datagram_sendto(CONTROLLER_SOCKET, (void *)msg, msg_sz);
free(msg);
int socket_fd = create_daemon_socket();
if (socket_fd == -1) {
LOGE("Failed creating daemon socket\n");
return;
}
while (1) {
int client_fd = accept(socket_fd, NULL, NULL);
if (client_fd == -1) {
LOGE("accept: %s\n", strerror(errno));
return;
}
LOGI("Accepted client: %d\n", client_fd);
unsigned char buf[1];
ssize_t len = read(client_fd, buf, sizeof(buf));
if (len == -1) {
LOGE("read: %s\n", strerror(errno));
return;
} else if (len == 0) {
LOGI("Client disconnected\n");
return;
}
LOGI("Action: %hhu\n", (uint8_t)buf[0]);
enum DaemonSocketAction action = (enum DaemonSocketAction)buf[0];
switch (action) {
case PingHeartbeat: {
enum DaemonSocketAction msgr = ZYGOTE_INJECTED;
unix_datagram_sendto(CONTROLLER_SOCKET, &msgr, sizeof(enum DaemonSocketAction));
break;
}
case ZygoteRestart: {
LOGI("Zygote restart\n");
for (int i = 0; i < context.len; i++) {
if (context.modules[i].companion != -1) {
close(context.modules[i].companion);
context.modules[i].companion = -1;
}
}
break;
}
case SystemServerStarted: {
enum DaemonSocketAction msgr = SYSTEM_SERVER_STARTED;
unix_datagram_sendto(CONTROLLER_SOCKET, &msgr, sizeof(enum DaemonSocketAction));
break;
}
case RequestLogcatFd: {
char level_buf[1];
ssize_t ret = read(client_fd, &level_buf, sizeof(level_buf));
ASSURE_SIZE_READ_BREAK("RequestLogcatFd", "level", ret, sizeof(level_buf));
char level = level_buf[0];
char tag[128 + 1];
ret = read_string(client_fd, tag, sizeof(tag) - 1);
if (ret == -1) break;
tag[ret] = '\0';
char message[1024];
ret = read_string(client_fd, message, sizeof(message));
if (ret == -1) break;
__android_log_print(level, tag, "%.*s", (int)ret, message);
break;
}
case GetProcessFlags: {
LOGI("Getting process flags\n");
uid_t uid_buf[1];
ssize_t ret = read(client_fd, &uid_buf, sizeof(uid_buf));
ASSURE_SIZE_READ_BREAK("GetProcessFlags", "uid", ret, sizeof(uid_buf));
uid_t uid = uid_buf[0];
LOGI("Checking flags for uid: %d\n", uid);
uint32_t 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;
}
}
LOGI("Flags for uid %d: %d\n", uid, flags);
switch (get_impl()) {
case None: {
break;
}
case Multiple: {
break;
}
case KernelSU: {
flags |= PROCESS_ROOT_IS_KSU;
}
}
// LOGI("Flags for uid %d: %d\n", uid, flags);
LOGI("Sending flags\n");
ret = write(client_fd, &flags, sizeof(flags));
// ASSURE_SIZE_WRITE_BREAK("GetProcessFlags", "flags", ret, sizeof(flags));
LOGI("Sent flags\n");
break;
}
case GetInfo: {
uint32_t flags = 0;
LOGI("Getting info\n");
switch (get_impl()) {
case None: {
break;
}
case Multiple: {
break;
}
case KernelSU: {
flags |= PROCESS_ROOT_IS_KSU;
}
}
LOGI("Flags: %d\n", flags);
ssize_t ret = write(client_fd, &flags, sizeof(flags));
ASSURE_SIZE_WRITE_BREAK("GetInfo", "flags", ret, sizeof(flags));
pid_t pid = getpid();
LOGI("Getting pid: %d\n", pid);
ret = write(client_fd, &pid, sizeof(pid));
ASSURE_SIZE_WRITE_BREAK("GetInfo", "pid", ret, sizeof(pid));
LOGI("Sent pid\n");
break;
}
case ReadModules: {
LOGI("Reading modules to stream\n");
size_t clen = context.len;
ssize_t ret = write(client_fd, &clen, sizeof(clen));
ASSURE_SIZE_WRITE_BREAK("ReadModules", "len", ret, sizeof(clen));
for (int i = 0; i < (int)clen; i++) {
LOGI("Hey, we're talking about: %d\n", i);
LOGI("Writing module `%s` to stream\n", context.modules[i].name);
LOGI("Lib fd: %d\n", context.modules[i].lib_fd);
size_t name_len = strlen(context.modules[i].name);
LOGI("Name length: %zu\n", name_len);
ret = write(client_fd, &name_len, sizeof(name_len));
ASSURE_SIZE_WRITE_BREAK("ReadModules", "name length", ret, sizeof(name_len));
LOGI("Writing name: %s\n", context.modules[i].name);
ret = write(client_fd, context.modules[i].name, name_len);
ASSURE_SIZE_WRITE_BREAK("ReadModules", "name", ret, name_len);
LOGI("Writing lib fd: %d\n", context.modules[i].lib_fd);
if (send_fd(client_fd, context.modules[i].lib_fd) == -1) break;
}
LOGI("Finished reading modules to stream\n");
break;
}
case RequestCompanionSocket: {
LOGI("Requesting companion socket\n");
size_t index_buf[1];
ssize_t ret = read(client_fd, &index_buf, sizeof(index_buf));
ASSURE_SIZE_READ_BREAK("RequestCompanionSocket", "index", ret, sizeof(index_buf));
size_t index = index_buf[0];
struct Module *module = &context.modules[index];
int companion_fd = module->companion;
if (companion_fd != -1) {
LOGI("Companion for module `%s` already exists\n", module->name);
if (fcntl(companion_fd, F_GETFD) == -1) {
LOGE("Poll companion for module `%s` crashed\n", module->name);
close(companion_fd);
module->companion = -1;
}
}
if (companion_fd == -1) {
LOGI("Spawning companion for `%s`\n", module->name);
companion_fd = spawn_companion(module->name, module->lib_fd);
if (companion_fd != -1) {
LOGI("Spawned companion for `%s`\n", module->name);
module->companion = companion_fd;
if (send_fd(client_fd, companion_fd) == -1) break;
} else if (companion_fd == -2) {
LOGI("Could not spawn companion for `%s` as it has no entry\n", module->name);
/* TODO: Avoid duplicated code -- Merge this and the one below. */
uint8_t response = 0;
ret = write(client_fd, &response, sizeof(response));
ASSURE_SIZE_WRITE_BREAK("RequestCompanionSocket", "response", ret, sizeof(response));
} else {
LOGE("Failed to spawn companion for `%s`\n", module->name);
uint8_t response = 0;
ret = write(client_fd, &response, sizeof(response));
ASSURE_SIZE_WRITE_BREAK("RequestCompanionSocket", "response", ret, sizeof(response));
}
LOGI("Companion fd: %d\n", companion_fd);
}
break;
}
case GetModuleDir: {
LOGI("Getting module directory\n");
size_t index_buf[1];
ssize_t ret = read(client_fd, &index_buf, sizeof(index_buf));
ASSURE_SIZE_READ_BREAK("GetModuleDir", "index", ret, sizeof(index_buf));
size_t index = index_buf[0];
LOGI("Index: %zu\n", index);
char dir[PATH_MAX];
snprintf(dir, PATH_MAX, "%s/%s", PATH_MODULES_DIR, context.modules[index].name);
LOGI("Module directory: %s\n", dir);
int dir_fd = open(dir, O_RDONLY);
LOGI("Module directory fd: %d\n", dir_fd);
if (send_fd(client_fd, dir_fd) == -1) break;
LOGI("Sent module directory fd\n");
break;
}
close(client_fd);
}
continue;
}
close(socket_fd);
free_modules(&context);
}

View File

@@ -1,6 +0,0 @@
#ifndef ZYGISKD_H
#define ZYGISKD_H
void zygiskd_start(void);
#endif /* ZYGISKD_H */

127
zygiskd/build.gradle.kts Normal file
View File

@@ -0,0 +1,127 @@
import java.nio.file.Paths
import org.gradle.internal.os.OperatingSystem
fun getLatestNDKPath(): String {
val android_home = System.getenv("ANDROID_HOME")
if (android_home == null) {
throw Exception("ANDROID_HOME not set")
}
val ndkPath = android_home + "/ndk"
val ndkDir = Paths.get(ndkPath)
if (!ndkDir.toFile().exists()) {
throw Exception("NDK not found at $ndkPath")
}
val ndkVersion = ndkDir.toFile().listFiles().filter { it.isDirectory }.map { it.name }.sorted().last()
return ndkPath + "/" + ndkVersion
}
val minAPatchVersion: Int by rootProject.extra
val minKsuVersion: Int by rootProject.extra
val maxKsuVersion: Int by rootProject.extra
val minMagiskVersion: Int by rootProject.extra
val verCode: Int by rootProject.extra
val verName: String by rootProject.extra
val commitHash: String by rootProject.extra
val CFlagsRelease = arrayOf(
"-D_GNU_SOURCE", "-std=c99", "-Wpedantic", "-Wall", "-Wextra", "-Werror",
"-Wformat", "-Wuninitialized", "-Wshadow", "-Wno-zero-length-array",
"-Wno-fixed-enum-extension", "-Iroot_impl", "-llog"
)
val CFlagsDebug = arrayOf(
"-D_GNU_SOURCE", "-std=c99", "-Wpedantic", "-Wall", "-Wextra", "-Werror",
"-Wformat", "-Wuninitialized", "-Wshadow", "-Wno-zero-length-array",
"-Wno-fixed-enum-extension", "-Iroot_impl", "-llog", "-g"
)
val Files = arrayOf(
"root_impl/common.c",
"root_impl/kernelsu.c",
"companion.c",
"dl.c",
"main.c",
"utils.c",
"zygiskd.c"
)
task<Task>("buildAndStrip") {
group = "build"
description = "Build the native library and strip the debug symbols."
val isDebug = gradle.startParameter.taskNames.any { it.lowercase().contains("debug") }
doLast {
val ndkPath = getLatestNDKPath()
val aarch64Compiler = Paths.get(ndkPath, "toolchains", "llvm", "prebuilt", "linux-x86_64", "bin", "aarch64-linux-android34-clang").toString()
val armv7aCompiler = Paths.get(ndkPath, "toolchains", "llvm", "prebuilt", "linux-x86_64", "bin", "armv7a-linux-androideabi34-clang").toString()
if (!Paths.get(aarch64Compiler).toFile().exists()) {
throw Exception("aarch64 compiler not found at $aarch64Compiler")
}
if (!Paths.get(armv7aCompiler).toFile().exists()) {
throw Exception("armv7a compiler not found at $armv7aCompiler")
}
val Files = Files.map { Paths.get(project.projectDir.toString(), "src", it).toString() }.toTypedArray()
val buildDir = getLayout().getBuildDirectory().getAsFile().get()
buildDir.mkdirs()
val compileArgs = if (isDebug) CFlagsDebug else CFlagsRelease
val execFile = { command: Array<String> ->
val process = Runtime.getRuntime().exec(command)
val output = process.inputStream.bufferedReader().readText()
process.waitFor()
output
}
val aarch64OutputDir = Paths.get(buildDir.toString(), "arm64-v8a").toFile()
aarch64OutputDir.mkdirs()
/* INFO: Compile for aarch64 */
val aarch64Command = arrayOf(aarch64Compiler, "-o", Paths.get(aarch64OutputDir.toString(), "zygiskd").toString(), *compileArgs, *Files)
val aarch64CommandResult = execFile(aarch64Command)
if (aarch64CommandResult.isNotEmpty()) {
println(aarch64CommandResult)
}
val armv7aOutputDir = Paths.get(buildDir.toString(), "armeabi-v7a").toFile()
armv7aOutputDir.mkdirs()
/* INFO: Compile for armv7a */
val armv7aCommand = arrayOf(armv7aCompiler, "-o", Paths.get(armv7aOutputDir.toString(), "zygiskd").toString(), *compileArgs, *Files)
val armv7aCommandResult = execFile(armv7aCommand)
if (armv7aCommandResult.isNotEmpty()) {
println(armv7aCommandResult)
}
val x86OutputDir = Paths.get(buildDir.toString(), "x86").toFile()
x86OutputDir.mkdirs()
/* INFO: Compile for x86 */
val x86Compiler = Paths.get(ndkPath, "toolchains", "llvm", "prebuilt", "linux-x86_64", "bin", "i686-linux-android34-clang").toString()
val x86Command = arrayOf(x86Compiler, "-o", Paths.get(x86OutputDir.toString(), "zygiskd").toString(), *compileArgs, *Files)
val x86CommandResult = execFile(x86Command)
if (x86CommandResult.isNotEmpty()) {
println(x86CommandResult)
}
val x86_64OutputDir = Paths.get(buildDir.toString(), "x86_64").toFile()
x86_64OutputDir.mkdirs()
/* INFO: Compile for x86_64 */
val x86_64Compiler = Paths.get(ndkPath, "toolchains", "llvm", "prebuilt", "linux-x86_64", "bin", "x86_64-linux-android34-clang").toString()
val x86_64Command = arrayOf(x86_64Compiler, "-o", Paths.get(x86_64OutputDir.toString(), "zygiskd").toString(), *compileArgs, *Files)
val x86_64CommandResult = execFile(x86_64Command)
if (x86_64CommandResult.isNotEmpty()) {
println(x86_64CommandResult)
}
}
}

View File

@@ -1,85 +0,0 @@
import java.nio.file.Paths
import org.gradle.internal.os.OperatingSystem
plugins {
alias(libs.plugins.agp.lib)
}
val verCode: Int by rootProject.extra
val verName: String by rootProject.extra
val commitHash: String by rootProject.extra
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 ccachePath by lazy {
project.findInPath("ccache", "ccache.path")?.also {
println("loader: Use ccache: $it")
}
}
val defaultCFlags = arrayOf(
"-Wall", "-Wextra",
"-fno-rtti", "-fno-exceptions",
"-fno-stack-protector", "-fomit-frame-pointer",
"-Wno-builtin-macro-redefined", "-D__FILE__=__FILE_NAME__",
"-O0", "-g"
)
val releaseFlags = arrayOf(
"-Oz", "-flto",
"-Wno-unused", "-Wno-unused-parameter",
"-fvisibility=hidden", "-fvisibility-inlines-hidden",
"-fno-unwind-tables", "-fno-asynchronous-unwind-tables",
"-Wl,--exclude-libs,ALL", "-Wl,--gc-sections", "-Wl,--strip-all"
)
android {
buildFeatures {
androidResources = false
buildConfig = false
prefab = true
}
externalNativeBuild.cmake {
path("src/CMakeLists.txt")
}
defaultConfig {
externalNativeBuild.cmake {
arguments += "-DANDROID_STL=none"
arguments += "-DLSPLT_STANDALONE=ON"
cFlags("-std=c18", *defaultCFlags)
cppFlags("-std=c++20", *defaultCFlags)
ccachePath?.let {
arguments += "-DNDK_CCACHE=$it"
}
}
}
buildTypes {
debug {
externalNativeBuild.cmake {
arguments += "-DZKSU_VERSION=$verName-$verCode-$commitHash-debug"
}
}
release {
externalNativeBuild.cmake {
cFlags += releaseFlags
cppFlags += releaseFlags
arguments += "-DZKSU_VERSION=$verName-$verCode-$commitHash-release"
}
}
}
}
dependencies {
implementation("dev.rikka.ndk.thirdparty:cxx:1.2.0")
}

View File

@@ -1,16 +0,0 @@
cmake_minimum_required(VERSION 3.22.1)
project("zygiskd")
find_package(cxx REQUIRED CONFIG)
add_definitions(-DZKSU_VERSION=\"${ZKSU_VERSION}\")
aux_source_directory(common COMMON_SRC_LIST)
add_library(common STATIC ${COMMON_SRC_LIST})
target_include_directories(common PRIVATE include)
target_link_libraries(log)
aux_source_directory(ptracer PTRACER_SRC_LIST)
add_executable(libzygisk_ptrace.so ${PTRACER_SRC_LIST})
target_include_directories(libzygisk_ptrace.so PRIVATE include)
target_link_libraries(libzygisk_ptrace.so cxx::cxx log common)