add: Zygiskd C99 re-write

This commit re-writes Zygiskd to be C99.
This commit is contained in:
ThePedroo
2024-07-17 17:56:38 -03:00
parent 3d2125d6c0
commit 5635c9f7c5
28 changed files with 1039 additions and 0 deletions

24
zygiskd/LICENSE Normal file
View File

@@ -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.

19
zygiskd/Makefile Normal file
View File

@@ -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

96
zygiskd/companion.c Normal file
View File

@@ -0,0 +1,96 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <dlfcn.h>
#include <unistd.h>
#include <linux/limits.h>
#include <pthread.h>
#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);
}
}

70
zygiskd/constants.h Normal file
View File

@@ -0,0 +1,70 @@
#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) 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 */

58
zygiskd/dl.c Normal file
View File

@@ -0,0 +1,58 @@
#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,
&android_dlopen
);
if (ns != NULL) {
info.flags = ANDROID_DLEXT_USE_NAMESPACE;
info.library_namespace = ns;
}
}
return android_dlopen_ext(path, flags, &info);
}

6
zygiskd/dl.h Normal file
View File

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

83
zygiskd/main.c Normal file
View File

@@ -0,0 +1,83 @@
#include <stdio.h>
#include <string.h>
#include <android/log.h>
#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;
}

View File

@@ -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;
}
}
}

View File

@@ -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 */

View File

@@ -0,0 +1,54 @@
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/prctl.h>
#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;
}

View File

@@ -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

172
zygiskd/utils.c Normal file
View File

@@ -0,0 +1,172 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <linux/limits.h>
#include <sched.h>
#include <pthread.h>
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;
}

16
zygiskd/utils.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef UTILS_H
#define UTILS_H
#include <sys/types.h>
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 */

BIN
zygiskd/zygiskd Executable file

Binary file not shown.

353
zygiskd/zygiskd.c Normal file
View File

@@ -0,0 +1,353 @@
#include <unistd.h>
#include <linux/limits.h>
#include <sys/mman.h>
#include <sys/socket.h>
#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
}
}
}