You've already forked ReZygisk
mirror of
https://github.com/PerformanC/ReZygisk.git
synced 2025-09-06 06:37:01 +00:00
improve: port common code to C
This commit ports even more C++ code to C99, now, the codes available in the "common" folder.
This commit is contained in:
365
loader/src/common/daemon.c
Normal file
365
loader/src/common/daemon.c
Normal file
@@ -0,0 +1,365 @@
|
||||
// #include <unistd.h>
|
||||
// #include <sys/types.h>
|
||||
// #include <sys/stat.h>
|
||||
// #include <dirent.h>
|
||||
// #include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <linux/un.h>
|
||||
|
||||
#include "logging.h"
|
||||
#include "socket_utils.h"
|
||||
|
||||
#include "daemon.h"
|
||||
|
||||
char daemon_path[PATH_MAX];
|
||||
|
||||
void rezygiskd_init(const char *path) {
|
||||
snprintf(daemon_path, sizeof(daemon_path), "%s/%s", path, SOCKET_FILE_NAME);
|
||||
}
|
||||
|
||||
void rezygiskd_get_path(char *buf, size_t buf_size) {
|
||||
size_t fileless_daemon_path = strlen(daemon_path) - strlen("/") - strlen(SOCKET_FILE_NAME);
|
||||
|
||||
strncpy(buf, daemon_path, buf_size > fileless_daemon_path ? fileless_daemon_path : buf_size);
|
||||
buf[fileless_daemon_path] = '\0';
|
||||
}
|
||||
|
||||
int rezygiskd_connect(uint8_t retry) {
|
||||
retry++;
|
||||
|
||||
int fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (fd == -1) {
|
||||
PLOGE("socket create");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct sockaddr_un addr = {
|
||||
.sun_family = AF_UNIX,
|
||||
.sun_path = { 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
INFO: Application must assume that sun_path can hold _POSIX_PATH_MAX characters.
|
||||
|
||||
Sources:
|
||||
- https://pubs.opengroup.org/onlinepubs/009696699/basedefs/sys/un.h.html
|
||||
*/
|
||||
strcpy(addr.sun_path, daemon_path);
|
||||
socklen_t socklen = sizeof(addr);
|
||||
|
||||
while (--retry) {
|
||||
int ret = connect(fd, (struct sockaddr *)&addr, socklen);
|
||||
if (ret == 0) return fd;
|
||||
if (retry) {
|
||||
PLOGE("Retrying to connect to ReZygiskd, sleep 1s");
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool rezygiskd_ping() {
|
||||
int fd = rezygiskd_connect(5);
|
||||
if (fd == -1) {
|
||||
PLOGE("connection to ReZygiskd");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
write_uint8_t(fd, (uint8_t)PingHeartbeat);
|
||||
|
||||
close(fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t rezygiskd_get_process_flags(uid_t uid) {
|
||||
int fd = rezygiskd_connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("connection to ReZygiskd");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
write_uint8_t(fd, (uint8_t)GetProcessFlags);
|
||||
write_uint32_t(fd, (uint32_t)uid);
|
||||
|
||||
uint32_t res = 0;
|
||||
read_uint32_t(fd, &res);
|
||||
|
||||
close(fd);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void rezygiskd_get_info(struct rezygisk_info *info) {
|
||||
int fd = rezygiskd_connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("connection to ReZygiskd");
|
||||
|
||||
info->running = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
info->running = true;
|
||||
|
||||
write_uint8_t(fd, (uint8_t)GetInfo);
|
||||
|
||||
uint32_t flags = 0;
|
||||
read_uint32_t(fd, &flags);
|
||||
|
||||
if (flags & (1 << 27)) info->root_impl = ROOT_IMPL_APATCH;
|
||||
else if (flags & (1 << 29)) info->root_impl = ROOT_IMPL_KERNELSU;
|
||||
else if (flags & (1 << 30)) info->root_impl = ROOT_IMPL_MAGISK;
|
||||
else info->root_impl = ROOT_IMPL_NONE;
|
||||
|
||||
read_uint32_t(fd, (uint32_t *)&info->pid);
|
||||
|
||||
read_size_t(fd, &info->modules->modules_count);
|
||||
if (info->modules->modules_count == 0) {
|
||||
info->modules->modules = NULL;
|
||||
|
||||
close(fd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
info->modules->modules = (char **)malloc(sizeof(char *) * info->modules->modules_count);
|
||||
if (info->modules->modules == NULL) {
|
||||
PLOGE("allocating modules name memory");
|
||||
|
||||
free(info->modules);
|
||||
info->modules = NULL;
|
||||
info->modules->modules_count = 0;
|
||||
|
||||
close(fd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < info->modules->modules_count; i++) {
|
||||
char *module_name = read_string(fd);
|
||||
if (module_name == NULL) {
|
||||
PLOGE("reading module name");
|
||||
|
||||
info->modules->modules_count = i;
|
||||
|
||||
free_rezygisk_info(info);
|
||||
|
||||
info->modules = NULL;
|
||||
info->modules->modules_count = 0;
|
||||
|
||||
close(fd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
char module_path[PATH_MAX];
|
||||
snprintf(module_path, sizeof(module_path), "/data/adb/modules/%s/module.prop", module_name);
|
||||
|
||||
FILE *module_prop = fopen(module_path, "r");
|
||||
if (!module_prop) {
|
||||
PLOGE("failed to open module prop file %s", module_path);
|
||||
|
||||
info->modules->modules_count = i;
|
||||
|
||||
free_rezygisk_info(info);
|
||||
|
||||
info->modules = NULL;
|
||||
info->modules->modules_count = 0;
|
||||
|
||||
close(fd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
char line[1024];
|
||||
while (fgets(line, sizeof(line), module_prop) != NULL) {
|
||||
if (strncmp(line, "name=", strlen("name=")) != 0) continue;
|
||||
|
||||
info->modules->modules[i] = strndup(line + 5, strlen(line) - 6);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
fclose(module_prop);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void free_rezygisk_info(struct rezygisk_info *info) {
|
||||
if (info->modules->modules) {
|
||||
for (size_t i = 0; i < info->modules->modules_count; i++) {
|
||||
free(info->modules->modules[i]);
|
||||
}
|
||||
|
||||
free(info->modules->modules);
|
||||
}
|
||||
|
||||
free(info->modules);
|
||||
}
|
||||
|
||||
bool rezygiskd_read_modules(struct zygisk_modules *modules) {
|
||||
int fd = rezygiskd_connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("connection to ReZygiskd");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
write_uint8_t(fd, (uint8_t)ReadModules);
|
||||
|
||||
size_t len = 0;
|
||||
read_size_t(fd, &len);
|
||||
|
||||
modules->modules = malloc(len * sizeof(char *));
|
||||
if (!modules->modules) {
|
||||
PLOGE("allocating modules name memory");
|
||||
|
||||
close(fd);
|
||||
|
||||
return false;
|
||||
}
|
||||
modules->modules_count = len;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
char *lib_path = read_string(fd);
|
||||
if (!lib_path) {
|
||||
PLOGE("reading module lib_path");
|
||||
|
||||
close(fd);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
modules->modules[i] = lib_path;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void free_modules(struct zygisk_modules *modules) {
|
||||
if (modules->modules) {
|
||||
for (size_t i = 0; i < modules->modules_count; i++) {
|
||||
free(modules->modules[i]);
|
||||
}
|
||||
|
||||
free(modules->modules);
|
||||
}
|
||||
}
|
||||
|
||||
int rezygiskd_connect_companion(size_t index) {
|
||||
int fd = rezygiskd_connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("connection to ReZygiskd");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
write_uint8_t(fd, (uint8_t)RequestCompanionSocket);
|
||||
write_size_t(fd, index);
|
||||
|
||||
uint8_t res = 0;
|
||||
read_uint8_t(fd, &res);
|
||||
|
||||
if (res == 1) return fd;
|
||||
else {
|
||||
close(fd);
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int rezygiskd_get_module_dir(size_t index) {
|
||||
int fd = rezygiskd_connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("connection to ReZygiskd");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
write_uint8_t(fd, (uint8_t)GetModuleDir);
|
||||
write_size_t(fd, index);
|
||||
|
||||
int dirfd = read_fd(fd);
|
||||
|
||||
close(fd);
|
||||
|
||||
return dirfd;
|
||||
}
|
||||
|
||||
void rezygiskd_zygote_restart() {
|
||||
int fd = rezygiskd_connect(1);
|
||||
if (fd == -1) {
|
||||
if (errno == ENOENT) LOGD("Could not notify ZygoteRestart (maybe it hasn't been created)");
|
||||
else PLOGE("Could not notify ZygoteRestart");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!write_uint8_t(fd, (uint8_t)ZygoteRestart))
|
||||
PLOGE("Failed to request ZygoteRestart");
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void rezygiskd_system_server_started() {
|
||||
int fd = rezygiskd_connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("Failed to report system server started");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!write_uint8_t(fd, (uint8_t)SystemServerStarted))
|
||||
PLOGE("Failed to request SystemServerStarted");
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
bool rezygiskd_update_mns(enum mount_namespace_state nms_state, char *buf, size_t buf_size) {
|
||||
int fd = rezygiskd_connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("connection to ReZygiskd");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
write_uint8_t(fd, (uint8_t)UpdateMountNamespace);
|
||||
write_uint32_t(fd, (uint32_t)getpid());
|
||||
write_uint8_t(fd, (uint8_t)nms_state);
|
||||
|
||||
uint32_t target_pid = 0;
|
||||
read_uint32_t(fd, &target_pid);
|
||||
if (target_pid == 0) {
|
||||
close(fd);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int target_fd = read_fd(fd);
|
||||
if (target_fd == -1) {
|
||||
close(fd);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
snprintf(buf, buf_size, "/proc/%u/fd/%u", target_pid, target_fd);
|
||||
|
||||
close(fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,279 +0,0 @@
|
||||
#include <linux/un.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "socket_utils.h"
|
||||
|
||||
namespace zygiskd {
|
||||
static std::string TMP_PATH;
|
||||
void Init(const char *path) {
|
||||
TMP_PATH = path;
|
||||
}
|
||||
|
||||
std::string GetTmpPath() {
|
||||
return TMP_PATH;
|
||||
}
|
||||
|
||||
int Connect(uint8_t retry) {
|
||||
retry++;
|
||||
|
||||
int fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
struct sockaddr_un addr = {
|
||||
.sun_family = AF_UNIX,
|
||||
.sun_path = { 0 }
|
||||
};
|
||||
|
||||
auto socket_path = TMP_PATH + kCPSocketName;
|
||||
strcpy(addr.sun_path, socket_path.c_str());
|
||||
socklen_t socklen = sizeof(addr);
|
||||
|
||||
while (--retry) {
|
||||
int r = connect(fd, (struct sockaddr *)&addr, socklen);
|
||||
if (r == 0) return fd;
|
||||
if (retry) {
|
||||
PLOGE("Retrying to connect to zygiskd, sleep 1s");
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool PingHeartbeat() {
|
||||
int fd = Connect(5);
|
||||
if (fd == -1) {
|
||||
PLOGE("Connect to zygiskd");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::PingHeartBeat);
|
||||
|
||||
close(fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t GetProcessFlags(uid_t uid) {
|
||||
int fd = Connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("GetProcessFlags");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::GetProcessFlags);
|
||||
socket_utils::write_u32(fd, uid);
|
||||
|
||||
uint32_t res = socket_utils::read_u32(fd);
|
||||
|
||||
close(fd);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<ModuleInfo> ReadModules() {
|
||||
std::vector<ModuleInfo> modules;
|
||||
int fd = Connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("ReadModules");
|
||||
|
||||
return modules;
|
||||
}
|
||||
|
||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::ReadModules);
|
||||
size_t len = socket_utils::read_usize(fd);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
std::string lib_path = socket_utils::read_string(fd);
|
||||
std::string name = socket_utils::read_string(fd);
|
||||
modules.emplace_back(lib_path, name);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return modules;
|
||||
}
|
||||
|
||||
int ConnectCompanion(size_t index) {
|
||||
int fd = Connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("ConnectCompanion");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::RequestCompanionSocket);
|
||||
socket_utils::write_usize(fd, index);
|
||||
|
||||
uint8_t res = socket_utils::read_u8(fd);
|
||||
|
||||
if (res == 1) return fd;
|
||||
else {
|
||||
close(fd);
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int GetModuleDir(size_t index) {
|
||||
int fd = Connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("GetModuleDir");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::GetModuleDir);
|
||||
socket_utils::write_usize(fd, index);
|
||||
int nfd = socket_utils::recv_fd(fd);
|
||||
|
||||
close(fd);
|
||||
|
||||
return nfd;
|
||||
}
|
||||
|
||||
void ZygoteRestart() {
|
||||
int fd = Connect(1);
|
||||
if (fd == -1) {
|
||||
if (errno == ENOENT) LOGD("Could not notify ZygoteRestart (maybe it hasn't been created)");
|
||||
else PLOGE("Could not notify ZygoteRestart");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!socket_utils::write_u8(fd, (uint8_t) SocketAction::ZygoteRestart))
|
||||
PLOGE("Failed to request ZygoteRestart");
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void SystemServerStarted() {
|
||||
int fd = Connect(1);
|
||||
if (fd == -1) PLOGE("Failed to report system server started");
|
||||
else {
|
||||
if (!socket_utils::write_u8(fd, (uint8_t) SocketAction::SystemServerStarted))
|
||||
PLOGE("Failed to report system server started");
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void GetInfo(struct zygote_info *info) {
|
||||
/* TODO: Optimize and avoid re-connect twice here */
|
||||
int fd = Connect(1);
|
||||
|
||||
if (fd != -1) {
|
||||
info->running = true;
|
||||
|
||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::GetInfo);
|
||||
|
||||
int flags = socket_utils::read_u32(fd);
|
||||
|
||||
if (flags & (1 << 27)) {
|
||||
info->root_impl = ZYGOTE_ROOT_IMPL_APATCH;
|
||||
} else if (flags & (1 << 29)) {
|
||||
info->root_impl = ZYGOTE_ROOT_IMPL_KERNELSU;
|
||||
} else if (flags & (1 << 30)) {
|
||||
info->root_impl = ZYGOTE_ROOT_IMPL_MAGISK;
|
||||
} else {
|
||||
info->root_impl = ZYGOTE_ROOT_IMPL_NONE;
|
||||
}
|
||||
|
||||
info->pid = socket_utils::read_u32(fd);
|
||||
|
||||
info->modules = (struct zygote_modules *)malloc(sizeof(struct zygote_modules));
|
||||
if (info->modules == NULL) {
|
||||
info->modules->modules_count = 0;
|
||||
|
||||
close(fd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
info->modules->modules_count = socket_utils::read_usize(fd);
|
||||
|
||||
if (info->modules->modules_count == 0) {
|
||||
info->modules->modules = NULL;
|
||||
|
||||
close(fd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
info->modules->modules = (char **)malloc(sizeof(char *) * info->modules->modules_count);
|
||||
if (info->modules->modules == NULL) {
|
||||
free(info->modules);
|
||||
info->modules = NULL;
|
||||
info->modules->modules_count = 0;
|
||||
|
||||
close(fd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < info->modules->modules_count; i++) {
|
||||
/* INFO by ThePedroo: Ugly solution to read with std::string existance (temporary) */
|
||||
std::string name = socket_utils::read_string(fd);
|
||||
|
||||
char module_path[PATH_MAX];
|
||||
snprintf(module_path, sizeof(module_path), "/data/adb/modules/%s/module.prop", name.c_str());
|
||||
|
||||
FILE *module_prop = fopen(module_path, "r");
|
||||
if (module_prop == NULL) {
|
||||
info->modules->modules[i] = strdup(name.c_str());
|
||||
} else {
|
||||
char line[1024];
|
||||
while (fgets(line, sizeof(line), module_prop) != NULL) {
|
||||
if (strncmp(line, "name=", 5) == 0) {
|
||||
info->modules->modules[i] = strndup(line + 5, strlen(line) - 6);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(module_prop);
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
} else info->running = false;
|
||||
}
|
||||
|
||||
std::string UpdateMountNamespace(enum mount_namespace_state nms_state) {
|
||||
int fd = Connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("UpdateMountNamespace");
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::UpdateMountNamespace);
|
||||
socket_utils::write_u32(fd, getpid());
|
||||
socket_utils::write_u8(fd, (uint8_t)nms_state);
|
||||
|
||||
uint32_t target_pid = socket_utils::read_u32(fd);
|
||||
int target_fd = 0;
|
||||
|
||||
if (target_pid == 0) goto error;
|
||||
|
||||
target_fd = (int)socket_utils::read_u32(fd);
|
||||
if (target_fd == 0) goto error;
|
||||
|
||||
close(fd);
|
||||
|
||||
return "/proc/" + std::to_string(target_pid) + "/fd/" + std::to_string(target_fd);
|
||||
|
||||
error:
|
||||
close(fd);
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
#include "files.hpp"
|
||||
#include "misc.hpp"
|
||||
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
void file_readline(bool trim, FILE *fp, const std::function<bool(std::string_view)> &fn) {
|
||||
size_t len = 1024;
|
||||
char *buf = (char *) malloc(len);
|
||||
char *start;
|
||||
ssize_t read;
|
||||
while ((read = getline(&buf, &len, fp)) >= 0) {
|
||||
start = buf;
|
||||
if (trim) {
|
||||
while (read && "\n\r "sv.find(buf[read - 1]) != std::string::npos)
|
||||
--read;
|
||||
buf[read] = '\0';
|
||||
while (*start == ' ')
|
||||
++start;
|
||||
}
|
||||
if (!fn(start))
|
||||
break;
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void file_readline(const char *file, const std::function<bool(std::string_view)> &fn) {
|
||||
FILE *fp = fopen(file, "re");
|
||||
if (!fp) {
|
||||
PLOGE("Failed to open file %s", file);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
file_readline(false, fp, fn);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
std::vector<mount_info> parse_mount_info(const char *pid) {
|
||||
char buf[PATH_MAX] = {};
|
||||
snprintf(buf, sizeof(buf), "/proc/%s/mountinfo", pid);
|
||||
std::vector<mount_info> result;
|
||||
|
||||
file_readline(buf, [&result](std::string_view line) -> bool {
|
||||
int root_start = 0, root_end = 0;
|
||||
int target_start = 0, target_end = 0;
|
||||
int vfs_option_start = 0, vfs_option_end = 0;
|
||||
int type_start = 0, type_end = 0;
|
||||
int source_start = 0, source_end = 0;
|
||||
int fs_option_start = 0, fs_option_end = 0;
|
||||
int optional_start = 0, optional_end = 0;
|
||||
unsigned int id, parent, maj, min;
|
||||
sscanf(line.data(),
|
||||
"%u " // (1) id
|
||||
"%u " // (2) parent
|
||||
"%u:%u " // (3) maj:min
|
||||
"%n%*s%n " // (4) mountroot
|
||||
"%n%*s%n " // (5) target
|
||||
"%n%*s%n" // (6) vfs options (fs-independent)
|
||||
"%n%*[^-]%n - " // (7) optional fields
|
||||
"%n%*s%n " // (8) FS type
|
||||
"%n%*s%n " // (9) source
|
||||
"%n%*s%n", // (10) fs options (fs specific)
|
||||
&id, &parent, &maj, &min, &root_start, &root_end, &target_start,
|
||||
&target_end, &vfs_option_start, &vfs_option_end,
|
||||
&optional_start, &optional_end, &type_start, &type_end,
|
||||
&source_start, &source_end, &fs_option_start, &fs_option_end);
|
||||
|
||||
auto root = line.substr(root_start, root_end - root_start);
|
||||
auto target = line.substr(target_start, target_end - target_start);
|
||||
auto vfs_option =
|
||||
line.substr(vfs_option_start, vfs_option_end - vfs_option_start);
|
||||
++optional_start;
|
||||
--optional_end;
|
||||
auto optional = line.substr(
|
||||
optional_start,
|
||||
optional_end - optional_start > 0 ? optional_end - optional_start : 0);
|
||||
|
||||
auto type = line.substr(type_start, type_end - type_start);
|
||||
auto source = line.substr(source_start, source_end - source_start);
|
||||
auto fs_option =
|
||||
line.substr(fs_option_start, fs_option_end - fs_option_start);
|
||||
|
||||
unsigned int shared = 0;
|
||||
unsigned int master = 0;
|
||||
unsigned int propagate_from = 0;
|
||||
if (auto pos = optional.find("shared:"); pos != std::string_view::npos) {
|
||||
shared = parse_int(optional.substr(pos + 7));
|
||||
}
|
||||
if (auto pos = optional.find("master:"); pos != std::string_view::npos) {
|
||||
master = parse_int(optional.substr(pos + 7));
|
||||
}
|
||||
if (auto pos = optional.find("propagate_from:");
|
||||
pos != std::string_view::npos) {
|
||||
propagate_from = parse_int(optional.substr(pos + 15));
|
||||
}
|
||||
|
||||
result.emplace_back(mount_info {
|
||||
.id = id,
|
||||
.parent = parent,
|
||||
.device = static_cast<dev_t>(makedev(maj, min)),
|
||||
.root {root},
|
||||
.target {target},
|
||||
.vfs_option {vfs_option},
|
||||
.optional {
|
||||
.shared = shared,
|
||||
.master = master,
|
||||
.propagate_from = propagate_from,
|
||||
},
|
||||
.type {type},
|
||||
.source {source},
|
||||
.fs_option {fs_option},
|
||||
});
|
||||
return true;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
14
loader/src/common/misc.c
Normal file
14
loader/src/common/misc.c
Normal file
@@ -0,0 +1,14 @@
|
||||
int parse_int(const char *str) {
|
||||
int val = 0;
|
||||
|
||||
char *c = (char *)str;
|
||||
while (*c) {
|
||||
if (*c > '9' || *c < '0')
|
||||
return -1;
|
||||
|
||||
val = val * 10 + *c - '0';
|
||||
c++;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
#include "misc.hpp"
|
||||
|
||||
int new_daemon_thread(thread_entry entry, void *arg) {
|
||||
pthread_t thread;
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
errno = pthread_create(&thread, &attr, entry, arg);
|
||||
if (errno) {
|
||||
PLOGE("pthread_create");
|
||||
}
|
||||
return errno;
|
||||
}
|
||||
|
||||
int parse_int(std::string_view s) {
|
||||
int val = 0;
|
||||
for (char c : s) {
|
||||
if (!c) break;
|
||||
if (c > '9' || c < '0')
|
||||
return -1;
|
||||
val = val * 10 + c - '0';
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
std::list<std::string> split_str(std::string_view s, std::string_view delimiter) {
|
||||
std::list<std::string> ret;
|
||||
size_t pos = 0;
|
||||
while (pos < s.size()) {
|
||||
auto next = s.find(delimiter, pos);
|
||||
if (next == std::string_view::npos) {
|
||||
ret.emplace_back(s.substr(pos));
|
||||
break;
|
||||
}
|
||||
ret.emplace_back(s.substr(pos, next - pos));
|
||||
pos = next + delimiter.size();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string join_str(const std::list<std::string>& list, std::string_view delimiter) {
|
||||
std::string ret;
|
||||
for (auto& s : list) {
|
||||
if (!ret.empty())
|
||||
ret += delimiter;
|
||||
ret += s;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
95
loader/src/common/socket_utils.c
Normal file
95
loader/src/common/socket_utils.c
Normal file
@@ -0,0 +1,95 @@
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "logging.h"
|
||||
|
||||
#include "socket_utils.h"
|
||||
|
||||
/* TODO: Standardize how to log errors */
|
||||
int read_fd(int fd) {
|
||||
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
||||
|
||||
int cnt = 1;
|
||||
struct iovec iov = {
|
||||
.iov_base = &cnt,
|
||||
.iov_len = sizeof(cnt)
|
||||
};
|
||||
|
||||
struct msghdr msg = {
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = cmsgbuf,
|
||||
.msg_controllen = sizeof(cmsgbuf)
|
||||
};
|
||||
|
||||
ssize_t ret = recvmsg(fd, &msg, MSG_WAITALL);
|
||||
if (ret == -1) {
|
||||
PLOGE("recvmsg");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
|
||||
if (cmsg == NULL) {
|
||||
PLOGE("CMSG_FIRSTHDR");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sendfd;
|
||||
memcpy(&sendfd, CMSG_DATA(cmsg), sizeof(int));
|
||||
|
||||
return sendfd;
|
||||
}
|
||||
|
||||
char *read_string(int fd) {
|
||||
size_t str_len = 0;
|
||||
ssize_t read_bytes = read(fd, &str_len, sizeof(size_t));
|
||||
if (read_bytes != (ssize_t)sizeof(size_t)) {
|
||||
LOGE("Failed to read string length: Not all bytes were read (%zd != %zu).\n", read_bytes, sizeof(size_t));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *buf = malloc(str_len + 1);
|
||||
if (buf == NULL) {
|
||||
PLOGE("allocate memory for string");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
read_bytes = read(fd, buf, str_len);
|
||||
if (read_bytes != (ssize_t)str_len) {
|
||||
LOGE("Failed to read string: Promised bytes doesn't exist (%zd != %zu).\n", read_bytes, str_len);
|
||||
|
||||
free(buf);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (str_len > 0) buf[str_len] = '\0';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
#define write_func(type) \
|
||||
ssize_t write_## type(int fd, type val) { \
|
||||
return write(fd, &val, sizeof(type)); \
|
||||
}
|
||||
|
||||
#define read_func(type) \
|
||||
ssize_t read_## type(int fd, type *val) { \
|
||||
return read(fd, val, sizeof(type)); \
|
||||
}
|
||||
|
||||
write_func(uint8_t)
|
||||
read_func(uint8_t)
|
||||
|
||||
write_func(uint32_t)
|
||||
read_func(uint32_t)
|
||||
|
||||
write_func(size_t)
|
||||
read_func(size_t)
|
||||
@@ -1,137 +0,0 @@
|
||||
#include <cstddef>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "socket_utils.h"
|
||||
|
||||
namespace socket_utils {
|
||||
ssize_t xread(int fd, void* buf, size_t count) {
|
||||
size_t read_sz = 0;
|
||||
ssize_t ret;
|
||||
do {
|
||||
ret = read(fd, (std::byte*) buf + read_sz, count - read_sz);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
PLOGE("read");
|
||||
return ret;
|
||||
}
|
||||
read_sz += ret;
|
||||
} while (read_sz != count && ret != 0);
|
||||
if (read_sz != count) {
|
||||
PLOGE("read (%zu != %zu)", count, read_sz);
|
||||
}
|
||||
return read_sz;
|
||||
}
|
||||
|
||||
size_t xwrite(int fd, const void* buf, size_t count) {
|
||||
size_t write_sz = 0;
|
||||
ssize_t ret;
|
||||
do {
|
||||
ret = write(fd, (std::byte*) buf + write_sz, count - write_sz);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
PLOGE("write");
|
||||
return write_sz;
|
||||
}
|
||||
write_sz += ret;
|
||||
} while (write_sz != count && ret != 0);
|
||||
if (write_sz != count) {
|
||||
PLOGE("write (%zu != %zu)", count, write_sz);
|
||||
}
|
||||
return write_sz;
|
||||
}
|
||||
|
||||
ssize_t xrecvmsg(int sockfd, struct msghdr* msg, int flags) {
|
||||
int rec = recvmsg(sockfd, msg, flags);
|
||||
if (rec < 0) PLOGE("recvmsg");
|
||||
return rec;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T read_exact_or(int fd, T fail) {
|
||||
T res;
|
||||
return sizeof(T) == xread(fd, &res, sizeof(T)) ? res : fail;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool write_exact(int fd, T val) {
|
||||
return sizeof(T) == xwrite(fd, &val, sizeof(T));
|
||||
}
|
||||
|
||||
uint8_t read_u8(int fd) {
|
||||
return read_exact_or<uint8_t>(fd, 0);
|
||||
}
|
||||
|
||||
uint32_t read_u32(int fd) {
|
||||
return read_exact_or<uint32_t>(fd, 0);
|
||||
}
|
||||
|
||||
size_t read_usize(int fd) {
|
||||
return read_exact_or<size_t>(fd, 0);
|
||||
}
|
||||
|
||||
bool write_usize(int fd, size_t val) {
|
||||
return write_exact<size_t>(fd, val);
|
||||
}
|
||||
|
||||
std::string read_string(int fd) {
|
||||
size_t len = read_usize(fd);
|
||||
|
||||
char buf[len + 1];
|
||||
xread(fd, buf, len);
|
||||
|
||||
buf[len] = '\0';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool write_u8(int fd, uint8_t val) {
|
||||
return write_exact<uint8_t>(fd, val);
|
||||
}
|
||||
|
||||
void* recv_fds(int sockfd, char* cmsgbuf, size_t bufsz, int cnt) {
|
||||
iovec iov = {
|
||||
.iov_base = &cnt,
|
||||
.iov_len = sizeof(cnt),
|
||||
};
|
||||
msghdr msg = {
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = cmsgbuf,
|
||||
.msg_controllen = bufsz
|
||||
};
|
||||
|
||||
xrecvmsg(sockfd, &msg, MSG_WAITALL);
|
||||
cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
|
||||
|
||||
if (msg.msg_controllen != bufsz ||
|
||||
cmsg == nullptr ||
|
||||
// TODO: pass from rust: 20, expected: 16
|
||||
// cmsg->cmsg_len != CMSG_LEN(sizeof(int) * cnt) ||
|
||||
cmsg->cmsg_level != SOL_SOCKET ||
|
||||
cmsg->cmsg_type != SCM_RIGHTS) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return CMSG_DATA(cmsg);
|
||||
}
|
||||
|
||||
int recv_fd(int sockfd) {
|
||||
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
||||
|
||||
void* data = recv_fds(sockfd, cmsgbuf, sizeof(cmsgbuf), 1);
|
||||
if (data == nullptr) return -1;
|
||||
|
||||
int result;
|
||||
memcpy(&result, data, sizeof(int));
|
||||
return result;
|
||||
}
|
||||
|
||||
bool write_u32(int fd, uint32_t val) {
|
||||
return write_exact<uint32_t>(fd, val);
|
||||
}
|
||||
|
||||
bool write_string(int fd, std::string_view str) {
|
||||
return write_usize(fd, str.size()) && str.size() == xwrite(fd, str.data(), str.size());
|
||||
}
|
||||
}
|
||||
@@ -1,113 +1,85 @@
|
||||
#pragma once
|
||||
#ifndef DAEMON_H
|
||||
#define DAEMON_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
#if defined(__LP64__)
|
||||
# define LP_SELECT(lp32, lp64) lp64
|
||||
#ifdef __LP64__
|
||||
#define LP_SELECT(lp32, lp64) lp64
|
||||
#else
|
||||
# define LP_SELECT(lp32, lp64) lp32
|
||||
#define LP_SELECT(lp32, lp64) lp32
|
||||
#endif
|
||||
|
||||
constexpr auto kCPSocketName = "/" LP_SELECT("cp32", "cp64") ".sock";
|
||||
#define SOCKET_FILE_NAME LP_SELECT("cp32", "cp64") ".sock"
|
||||
|
||||
class UniqueFd {
|
||||
using Fd = int;
|
||||
public:
|
||||
UniqueFd() = default;
|
||||
|
||||
UniqueFd(Fd fd) : fd_(fd) {}
|
||||
|
||||
~UniqueFd() { if (fd_ >= 0) close(fd_); }
|
||||
|
||||
// Disallow copy
|
||||
UniqueFd(const UniqueFd&) = delete;
|
||||
|
||||
UniqueFd& operator=(const UniqueFd&) = delete;
|
||||
|
||||
// Allow move
|
||||
UniqueFd(UniqueFd&& other) { std::swap(fd_, other.fd_); }
|
||||
|
||||
UniqueFd& operator=(UniqueFd&& other) {
|
||||
std::swap(fd_, other.fd_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Implict cast to Fd
|
||||
operator const Fd&() const { return fd_; }
|
||||
|
||||
private:
|
||||
Fd fd_ = -1;
|
||||
enum rezygiskd_actions {
|
||||
PingHeartbeat,
|
||||
GetProcessFlags,
|
||||
GetInfo,
|
||||
ReadModules,
|
||||
RequestCompanionSocket,
|
||||
GetModuleDir,
|
||||
ZygoteRestart,
|
||||
SystemServerStarted,
|
||||
UpdateMountNamespace
|
||||
};
|
||||
|
||||
struct zygote_modules {
|
||||
struct zygisk_modules {
|
||||
char **modules;
|
||||
size_t modules_count;
|
||||
};
|
||||
|
||||
enum zygote_root_impl {
|
||||
ZYGOTE_ROOT_IMPL_NONE,
|
||||
ZYGOTE_ROOT_IMPL_APATCH,
|
||||
ZYGOTE_ROOT_IMPL_KERNELSU,
|
||||
ZYGOTE_ROOT_IMPL_MAGISK
|
||||
enum root_impl {
|
||||
ROOT_IMPL_NONE,
|
||||
ROOT_IMPL_APATCH,
|
||||
ROOT_IMPL_KERNELSU,
|
||||
ROOT_IMPL_MAGISK
|
||||
};
|
||||
|
||||
struct zygote_info {
|
||||
struct zygote_modules *modules;
|
||||
enum zygote_root_impl root_impl;
|
||||
struct rezygisk_info {
|
||||
struct zygisk_modules *modules;
|
||||
enum root_impl root_impl;
|
||||
pid_t pid;
|
||||
bool running;
|
||||
};
|
||||
|
||||
enum mount_namespace_state {
|
||||
Clean,
|
||||
Rooted,
|
||||
Module
|
||||
Clean,
|
||||
Rooted,
|
||||
Module
|
||||
};
|
||||
|
||||
namespace zygiskd {
|
||||
void rezygiskd_init(const char *path);
|
||||
|
||||
struct ModuleInfo {
|
||||
std::string path;
|
||||
/* TODO: Perhaps we can also remove this and just send paths? */
|
||||
std::string name;
|
||||
void rezygiskd_get_path(char *buf, size_t buf_size);
|
||||
|
||||
inline explicit ModuleInfo(std::string path, std::string name) : path(path), name(name) {}
|
||||
};
|
||||
int rezygiskd_connect(uint8_t retry);
|
||||
|
||||
enum class SocketAction {
|
||||
PingHeartBeat,
|
||||
GetProcessFlags,
|
||||
GetInfo,
|
||||
ReadModules,
|
||||
RequestCompanionSocket,
|
||||
GetModuleDir,
|
||||
ZygoteRestart,
|
||||
SystemServerStarted,
|
||||
UpdateMountNamespace
|
||||
};
|
||||
bool rezygiskd_ping();
|
||||
|
||||
void Init(const char *path);
|
||||
uint32_t rezygiskd_get_process_flags(uid_t uid);
|
||||
|
||||
std::string GetTmpPath();
|
||||
void rezygiskd_get_info(struct rezygisk_info *info);
|
||||
|
||||
bool PingHeartbeat();
|
||||
void free_rezygisk_info(struct rezygisk_info *info);
|
||||
|
||||
std::vector<ModuleInfo> ReadModules();
|
||||
bool rezygiskd_read_modules(struct zygisk_modules *modules);
|
||||
void free_modules(struct zygisk_modules *modules);
|
||||
|
||||
uint32_t GetProcessFlags(uid_t uid);
|
||||
int rezygiskd_connect_companion(size_t index);
|
||||
|
||||
int ConnectCompanion(size_t index);
|
||||
int rezygiskd_get_module_dir(size_t index);
|
||||
|
||||
int GetModuleDir(size_t index);
|
||||
void rezygiskd_zygote_restart();
|
||||
|
||||
void ZygoteRestart();
|
||||
void rezygiskd_system_server_started();
|
||||
|
||||
void SystemServerStarted();
|
||||
bool rezygiskd_update_mns(enum mount_namespace_state nms_state, char *buf, size_t buf_size);
|
||||
|
||||
void GetInfo(struct zygote_info *info);
|
||||
|
||||
std::string UpdateMountNamespace(enum mount_namespace_state mns_state);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* DAEMON_H */
|
||||
@@ -6,8 +6,6 @@
|
||||
#include <linux/elf.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define restrict /* INFO: Temporary measure */
|
||||
|
||||
#define SHT_GNU_HASH 0x6ffffff6
|
||||
|
||||
struct symtabs {
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
#include <dirent.h>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unistd.h>
|
||||
|
||||
struct mount_info {
|
||||
unsigned int id;
|
||||
unsigned int parent;
|
||||
dev_t device;
|
||||
std::string root;
|
||||
std::string target;
|
||||
std::string vfs_option;
|
||||
struct {
|
||||
unsigned int shared;
|
||||
unsigned int master;
|
||||
unsigned int propagate_from;
|
||||
} optional;
|
||||
std::string type;
|
||||
std::string source;
|
||||
std::string fs_option;
|
||||
};
|
||||
|
||||
std::vector<mount_info> parse_mount_info(const char *pid);
|
||||
17
loader/src/include/misc.h
Normal file
17
loader/src/include/misc.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef MISC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*
|
||||
* Bionic's atoi runs through strtol().
|
||||
* Use our own implementation for faster conversion.
|
||||
*/
|
||||
int parse_int(const char *str);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* MISC_H */
|
||||
@@ -1,98 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <pthread.h>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "logging.h"
|
||||
|
||||
#define DISALLOW_COPY_AND_MOVE(clazz) \
|
||||
clazz(const clazz &) = delete; \
|
||||
clazz(clazz &&) = delete;
|
||||
|
||||
class mutex_guard {
|
||||
DISALLOW_COPY_AND_MOVE(mutex_guard)
|
||||
public:
|
||||
explicit mutex_guard(pthread_mutex_t &m): mutex(&m) {
|
||||
pthread_mutex_lock(mutex);
|
||||
}
|
||||
void unlock() {
|
||||
pthread_mutex_unlock(mutex);
|
||||
mutex = nullptr;
|
||||
}
|
||||
~mutex_guard() {
|
||||
if (mutex) pthread_mutex_unlock(mutex);
|
||||
}
|
||||
private:
|
||||
pthread_mutex_t *mutex;
|
||||
};
|
||||
|
||||
using thread_entry = void *(*)(void *);
|
||||
int new_daemon_thread(thread_entry entry, void *arg);
|
||||
|
||||
static inline bool str_contains(std::string_view s, std::string_view ss) {
|
||||
return s.find(ss) != std::string_view::npos;
|
||||
}
|
||||
|
||||
template<typename T, typename Impl>
|
||||
class stateless_allocator {
|
||||
public:
|
||||
using value_type = T;
|
||||
T *allocate(size_t num) { return static_cast<T*>(Impl::allocate(sizeof(T) * num)); }
|
||||
void deallocate(T *ptr, size_t num) { Impl::deallocate(ptr, sizeof(T) * num); }
|
||||
stateless_allocator() = default;
|
||||
stateless_allocator(const stateless_allocator&) = default;
|
||||
stateless_allocator(stateless_allocator&&) = default;
|
||||
template <typename U>
|
||||
stateless_allocator(const stateless_allocator<U, Impl>&) {}
|
||||
bool operator==(const stateless_allocator&) { return true; }
|
||||
bool operator!=(const stateless_allocator&) { return false; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class reversed_container {
|
||||
public:
|
||||
reversed_container(T &base) : base(base) {}
|
||||
decltype(std::declval<T>().rbegin()) begin() { return base.rbegin(); }
|
||||
decltype(std::declval<T>().crbegin()) begin() const { return base.crbegin(); }
|
||||
decltype(std::declval<T>().crbegin()) cbegin() const { return base.crbegin(); }
|
||||
decltype(std::declval<T>().rend()) end() { return base.rend(); }
|
||||
decltype(std::declval<T>().crend()) end() const { return base.crend(); }
|
||||
decltype(std::declval<T>().crend()) cend() const { return base.crend(); }
|
||||
private:
|
||||
T &base;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
reversed_container<T> reversed(T &base) {
|
||||
return reversed_container<T>(base);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static inline void default_new(T *&p) { p = new T(); }
|
||||
|
||||
template<class T>
|
||||
static inline void default_new(std::unique_ptr<T> &p) { p.reset(new T()); }
|
||||
|
||||
struct StringCmp {
|
||||
using is_transparent = void;
|
||||
bool operator()(std::string_view a, std::string_view b) const { return a < b; }
|
||||
};
|
||||
|
||||
/*
|
||||
* Bionic's atoi runs through strtol().
|
||||
* Use our own implementation for faster conversion.
|
||||
*/
|
||||
int parse_int(std::string_view s);
|
||||
|
||||
std::list<std::string> split_str(std::string_view s, std::string_view delimiter);
|
||||
|
||||
std::string join_str(const std::list<std::string>& list, std::string_view delimiter);
|
||||
|
||||
template <typename T>
|
||||
static inline T align_to(T v, int a) {
|
||||
static_assert(std::is_integral<T>::value);
|
||||
return (v + a - 1) / a * a;
|
||||
}
|
||||
@@ -1,31 +1,25 @@
|
||||
#pragma once
|
||||
#ifndef SOCKET_UTILS_H
|
||||
#define SOCKET_UTILS_H
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "logging.h"
|
||||
int read_fd(int fd);
|
||||
|
||||
char *read_string(int fd);
|
||||
|
||||
namespace socket_utils {
|
||||
#define write_func_def(type) \
|
||||
ssize_t write_## type(int fd, type val)
|
||||
|
||||
ssize_t xread(int fd, void *buf, size_t count);
|
||||
#define read_func_def(type) \
|
||||
ssize_t read_## type(int fd, type *val)
|
||||
|
||||
size_t xwrite(int fd, const void *buf, size_t count);
|
||||
write_func_def(uint8_t);
|
||||
read_func_def(uint8_t);
|
||||
|
||||
uint8_t read_u8(int fd);
|
||||
write_func_def(uint32_t);
|
||||
read_func_def(uint32_t);
|
||||
|
||||
uint32_t read_u32(int fd);
|
||||
write_func_def(size_t);
|
||||
read_func_def(size_t);
|
||||
|
||||
size_t read_usize(int fd);
|
||||
|
||||
std::string read_string(int fd);
|
||||
|
||||
bool write_u8(int fd, uint8_t val);
|
||||
|
||||
bool write_u32(int fd, uint32_t val);
|
||||
|
||||
int recv_fd(int fd);
|
||||
|
||||
bool write_usize(int fd, size_t val);
|
||||
|
||||
bool write_string(int fd, std::string_view str);
|
||||
}
|
||||
#endif /* SOCKET_UTILS_H */
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "logging.h"
|
||||
#include "jni_helper.hpp"
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -12,10 +12,11 @@ void entry(void* addr, size_t size, const char* path) {
|
||||
LOGD("Zygisk library injected, version %s", ZKSU_VERSION);
|
||||
start_addr = addr;
|
||||
block_size = size;
|
||||
zygiskd::Init(path);
|
||||
rezygiskd_init(path);
|
||||
|
||||
if (!zygiskd::PingHeartbeat()) {
|
||||
if (!rezygiskd_ping()) {
|
||||
LOGE("Zygisk daemon is not running");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include <lsplt.hpp>
|
||||
|
||||
@@ -16,12 +17,12 @@
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "zygisk.hpp"
|
||||
#include "module.hpp"
|
||||
#include "files.hpp"
|
||||
#include "misc.hpp"
|
||||
#include "misc.h"
|
||||
|
||||
#include "solist.h"
|
||||
|
||||
@@ -121,7 +122,7 @@ struct ZygiskContext {
|
||||
|
||||
// Global variables
|
||||
vector<tuple<dev_t, ino_t, const char *, void **>> *plt_hook_list;
|
||||
map<string, vector<JNINativeMethod>, StringCmp> *jni_hook_list;
|
||||
map<string, vector<JNINativeMethod>> *jni_hook_list;
|
||||
bool should_unmap_zygisk = false;
|
||||
std::vector<lsplt::MapInfo> cached_map_infos = {};
|
||||
|
||||
@@ -139,8 +140,8 @@ DCL_HOOK_FUNC(int, fork) {
|
||||
}
|
||||
|
||||
bool update_mnt_ns(enum mount_namespace_state mns_state, bool dry_run) {
|
||||
std::string ns_path = zygiskd::UpdateMountNamespace(mns_state);
|
||||
if (ns_path.empty()) {
|
||||
char ns_path[PATH_MAX];
|
||||
if (rezygiskd_update_mns(mns_state, ns_path, sizeof(ns_path)) == false) {
|
||||
PLOGE("Failed to update mount namespace");
|
||||
|
||||
return false;
|
||||
@@ -148,16 +149,16 @@ bool update_mnt_ns(enum mount_namespace_state mns_state, bool dry_run) {
|
||||
|
||||
if (dry_run) return true;
|
||||
|
||||
int updated_ns = open(ns_path.data(), O_RDONLY);
|
||||
int updated_ns = open(ns_path, O_RDONLY);
|
||||
if (updated_ns == -1) {
|
||||
PLOGE("Failed to open mount namespace [%s]", ns_path.data());
|
||||
PLOGE("Failed to open mount namespace [%s]", ns_path);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
LOGD("set mount namespace to [%s] fd=[%d]\n", ns_path.data(), updated_ns);
|
||||
LOGD("set mount namespace to [%s] fd=[%d]\n", ns_path, updated_ns);
|
||||
if (setns(updated_ns, CLONE_NEWNS) == -1) {
|
||||
PLOGE("Failed to set mount namespace [%s]", ns_path.data());
|
||||
PLOGE("Failed to set mount namespace [%s]", ns_path);
|
||||
close(updated_ns);
|
||||
|
||||
return false;
|
||||
@@ -180,6 +181,8 @@ DCL_HOOK_FUNC(int, unshare, int flags) {
|
||||
update_mnt_ns(Rooted, false);
|
||||
} else if (!(g_ctx->flags[DO_REVERT_UNMOUNT])) {
|
||||
update_mnt_ns(Module, false);
|
||||
} else {
|
||||
LOGI("Process [%s] is on denylist, skipping unmount", g_ctx->process);
|
||||
}
|
||||
|
||||
old_unshare(CLONE_NEWNS);
|
||||
@@ -389,8 +392,9 @@ void ZygiskContext::plt_hook_register(const char *regex, const char *symbol, voi
|
||||
regex_t re;
|
||||
if (regcomp(&re, regex, REG_NOSUB) != 0)
|
||||
return;
|
||||
mutex_guard lock(hook_info_lock);
|
||||
pthread_mutex_lock(&hook_info_lock);
|
||||
register_info.emplace_back(RegisterInfo{re, symbol, fn, backup});
|
||||
pthread_mutex_unlock(&hook_info_lock);
|
||||
}
|
||||
|
||||
void ZygiskContext::plt_hook_exclude(const char *regex, const char *symbol) {
|
||||
@@ -398,8 +402,9 @@ void ZygiskContext::plt_hook_exclude(const char *regex, const char *symbol) {
|
||||
regex_t re;
|
||||
if (regcomp(&re, regex, REG_NOSUB) != 0)
|
||||
return;
|
||||
mutex_guard lock(hook_info_lock);
|
||||
pthread_mutex_lock(&hook_info_lock);
|
||||
ignore_info.emplace_back(IgnoreInfo{re, symbol ?: ""});
|
||||
pthread_mutex_unlock(&hook_info_lock);
|
||||
}
|
||||
|
||||
void ZygiskContext::plt_hook_process_regex() {
|
||||
@@ -428,11 +433,13 @@ void ZygiskContext::plt_hook_process_regex() {
|
||||
|
||||
bool ZygiskContext::plt_hook_commit() {
|
||||
{
|
||||
mutex_guard lock(hook_info_lock);
|
||||
pthread_mutex_lock(&hook_info_lock);
|
||||
plt_hook_process_regex();
|
||||
register_info.clear();
|
||||
ignore_info.clear();
|
||||
pthread_mutex_unlock(&hook_info_lock);
|
||||
}
|
||||
|
||||
return lsplt::CommitHook(cached_map_infos);
|
||||
}
|
||||
|
||||
@@ -454,12 +461,12 @@ bool ZygiskModule::valid() const {
|
||||
|
||||
/* Zygisksu changed: Use own zygiskd */
|
||||
int ZygiskModule::connectCompanion() const {
|
||||
return zygiskd::ConnectCompanion(id);
|
||||
return rezygiskd_connect_companion(id);
|
||||
}
|
||||
|
||||
/* Zygisksu changed: Use own zygiskd */
|
||||
int ZygiskModule::getModuleDir() const {
|
||||
return zygiskd::GetModuleDir(id);
|
||||
return rezygiskd_get_module_dir(id);
|
||||
}
|
||||
|
||||
void ZygiskModule::setOption(zygisk::Option opt) {
|
||||
@@ -596,21 +603,26 @@ void ZygiskContext::fork_post() {
|
||||
|
||||
/* Zygisksu changed: Load module fds */
|
||||
void ZygiskContext::run_modules_pre() {
|
||||
auto ms = zygiskd::ReadModules();
|
||||
auto size = ms.size();
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
auto &m = ms[i];
|
||||
struct zygisk_modules ms;
|
||||
if (rezygiskd_read_modules(&ms) == false) {
|
||||
LOGE("Failed to read modules from zygiskd");
|
||||
|
||||
void *handle = dlopen(m.path.c_str(), RTLD_NOW);
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ms.modules_count; i++) {
|
||||
char *lib_path = ms.modules[i];
|
||||
|
||||
void *handle = dlopen(lib_path, RTLD_NOW);
|
||||
if (!handle) {
|
||||
LOGE("Failed to load module [%s]: %s", m.path.c_str(), dlerror());
|
||||
LOGE("Failed to load module [%s]: %s", lib_path, dlerror());
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
void *entry = dlsym(handle, "zygisk_module_entry");
|
||||
if (!entry) {
|
||||
LOGE("Failed to find entry point in module [%s]: %s", m.path.c_str(), dlerror());
|
||||
LOGE("Failed to find entry point in module [%s]: %s", lib_path, dlerror());
|
||||
|
||||
dlclose(handle);
|
||||
|
||||
@@ -620,6 +632,8 @@ void ZygiskContext::run_modules_pre() {
|
||||
modules.emplace_back(i, handle, entry);
|
||||
}
|
||||
|
||||
free_modules(&ms);
|
||||
|
||||
for (auto &m : modules) {
|
||||
m.onLoad(env);
|
||||
if (flags[APP_SPECIALIZE]) m.preAppSpecialize(args.app);
|
||||
@@ -648,7 +662,7 @@ void ZygiskContext::run_modules_post() {
|
||||
void ZygiskContext::app_specialize_pre() {
|
||||
flags[APP_SPECIALIZE] = true;
|
||||
|
||||
info_flags = zygiskd::GetProcessFlags(g_ctx->args.app->uid);
|
||||
info_flags = rezygiskd_get_process_flags(g_ctx->args.app->uid);
|
||||
if (info_flags & PROCESS_IS_FIRST_STARTED) {
|
||||
update_mnt_ns(Clean, true);
|
||||
}
|
||||
@@ -707,7 +721,7 @@ void ZygiskContext::nativeForkSystemServer_pre() {
|
||||
fork_pre();
|
||||
if (is_child()) {
|
||||
run_modules_pre();
|
||||
zygiskd::SystemServerStarted();
|
||||
rezygiskd_system_server_started();
|
||||
}
|
||||
|
||||
sanitize_fds();
|
||||
@@ -834,14 +848,11 @@ void clean_trace(const char* path, size_t load, size_t unload, bool spoof_maps)
|
||||
}
|
||||
|
||||
void hook_functions() {
|
||||
default_new(plt_hook_list);
|
||||
default_new(jni_hook_list);
|
||||
plt_hook_list = new vector<tuple<dev_t, ino_t, const char *, void **>>();
|
||||
jni_hook_list = new map<string, vector<JNINativeMethod>>();
|
||||
|
||||
ino_t android_runtime_inode = 0;
|
||||
dev_t android_runtime_dev = 0;
|
||||
/* TODO by ThePedroo: Implement injection via native bridge */
|
||||
// ino_t native_bridge_inode = 0;
|
||||
// dev_t native_bridge_dev = 0;
|
||||
|
||||
cached_map_infos = lsplt::MapInfo::Scan();
|
||||
for (auto &map : cached_map_infos) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#ifndef SOLIST_H
|
||||
#define SOLIST_H
|
||||
|
||||
/* INFO: Temporary */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "daemon.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
zygiskd::Init("/data/adb/rezygisk");
|
||||
rezygiskd_init("/data/adb/rezygisk");
|
||||
|
||||
printf("The ReZygisk Tracer %s\n\n", ZKSU_VERSION);
|
||||
|
||||
@@ -16,7 +16,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
return 0;
|
||||
} else if (argc >= 3 && strcmp(argv[1], "trace") == 0) {
|
||||
if (argc >= 4 && strcmp(argv[3], "--restart") == 0) zygiskd::ZygoteRestart();
|
||||
if (argc >= 4 && strcmp(argv[3], "--restart") == 0) rezygiskd_zygote_restart();
|
||||
|
||||
long pid = strtol(argv[2], 0, 0);
|
||||
if (!trace_zygote(pid)) {
|
||||
@@ -54,28 +54,28 @@ int main(int argc, char **argv) {
|
||||
|
||||
return 0;
|
||||
} else if (argc >= 2 && strcmp(argv[1], "info") == 0) {
|
||||
struct zygote_info info;
|
||||
zygiskd::GetInfo(&info);
|
||||
struct rezygisk_info info;
|
||||
rezygiskd_get_info(&info);
|
||||
|
||||
printf("Daemon process PID: %d\n", info.pid);
|
||||
|
||||
switch (info.root_impl) {
|
||||
case ZYGOTE_ROOT_IMPL_NONE: {
|
||||
case ROOT_IMPL_NONE: {
|
||||
printf("Root implementation: none\n");
|
||||
|
||||
break;
|
||||
}
|
||||
case ZYGOTE_ROOT_IMPL_APATCH: {
|
||||
case ROOT_IMPL_APATCH: {
|
||||
printf("Root implementation: APatch\n");
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
case ZYGOTE_ROOT_IMPL_KERNELSU: {
|
||||
case ROOT_IMPL_KERNELSU: {
|
||||
printf("Root implementation: KernelSU\n");
|
||||
|
||||
break;
|
||||
}
|
||||
case ZYGOTE_ROOT_IMPL_MAGISK: {
|
||||
case ROOT_IMPL_MAGISK: {
|
||||
printf("Root implementation: Magisk\n");
|
||||
|
||||
break;
|
||||
|
||||
@@ -14,8 +14,7 @@
|
||||
|
||||
#include "monitor.h"
|
||||
#include "utils.hpp"
|
||||
#include "files.hpp"
|
||||
#include "misc.hpp"
|
||||
#include "misc.h"
|
||||
|
||||
#define STOPPED_WITH(sig, event) WIFSTOPPED(status) && (status >> 8 == ((sig) | (event << 8)))
|
||||
|
||||
@@ -140,7 +139,10 @@ struct SocketHandler : public EventHandler {
|
||||
.sun_path = { 0 }
|
||||
};
|
||||
|
||||
size_t sun_path_len = sprintf(addr.sun_path, "%s/%s", zygiskd::GetTmpPath().c_str(), SOCKET_NAME);
|
||||
char tmp_path[PATH_MAX];
|
||||
rezygiskd_get_path(tmp_path, sizeof(tmp_path));
|
||||
|
||||
size_t sun_path_len = sprintf(addr.sun_path, "%s/%s", tmp_path, SOCKET_NAME);
|
||||
|
||||
socklen_t socklen = sizeof(sa_family_t) + sun_path_len;
|
||||
if (bind(sock_fd_, (struct sockaddr *)&addr, socklen) == -1) {
|
||||
@@ -747,7 +749,10 @@ static void updateStatus() {
|
||||
}
|
||||
|
||||
static bool prepare_environment() {
|
||||
strcat(prop_path, zygiskd::GetTmpPath().c_str());
|
||||
char tmp_path[PATH_MAX];
|
||||
rezygiskd_get_path(tmp_path, sizeof(tmp_path));
|
||||
|
||||
strcat(prop_path, tmp_path);
|
||||
strcat(prop_path, "/module.prop");
|
||||
|
||||
close(open(prop_path, O_WRONLY | O_CREAT | O_TRUNC, 0644));
|
||||
@@ -817,7 +822,11 @@ int send_control_command(enum Command cmd) {
|
||||
.sun_path = { 0 }
|
||||
};
|
||||
|
||||
size_t sun_path_len = snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", zygiskd::GetTmpPath().c_str(), SOCKET_NAME);
|
||||
char tmp_path[PATH_MAX];
|
||||
rezygiskd_get_path(tmp_path, sizeof(tmp_path));
|
||||
|
||||
size_t sun_path_len = snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", tmp_path, SOCKET_NAME);
|
||||
|
||||
socklen_t socklen = sizeof(sa_family_t) + sun_path_len;
|
||||
|
||||
ssize_t nsend = sendto(sockfd, (void *)&cmd, sizeof(cmd), 0, (sockaddr *)&addr, socklen);
|
||||
|
||||
@@ -240,7 +240,11 @@ bool inject_on_main(int pid, const char *lib_path) {
|
||||
args.clear();
|
||||
args.push_back((uintptr_t) start_addr);
|
||||
args.push_back(block_size);
|
||||
str = push_string(pid, regs, zygiskd::GetTmpPath().c_str());
|
||||
|
||||
char tmp_path[PATH_MAX];
|
||||
rezygiskd_get_path(tmp_path, sizeof(tmp_path));
|
||||
|
||||
str = push_string(pid, regs, tmp_path);
|
||||
args.push_back((long) str);
|
||||
|
||||
remote_call(pid, regs, injector_entry, (uintptr_t)libc_return_addr, args);
|
||||
@@ -287,10 +291,12 @@ bool trace_zygote(int pid) {
|
||||
|
||||
if (STOPPED_WITH(SIGSTOP, PTRACE_EVENT_STOP)) {
|
||||
/* WARNING: C++ keyword */
|
||||
std::string lib_path = zygiskd::GetTmpPath();
|
||||
lib_path += "/lib" LP_SELECT("", "64") "/libzygisk.so";
|
||||
char lib_path[PATH_MAX];
|
||||
rezygiskd_get_path(lib_path, sizeof(lib_path));
|
||||
|
||||
if (!inject_on_main(pid, lib_path.c_str())) {
|
||||
strcat(lib_path,"/lib" LP_SELECT("", "64") "/libzygisk.so");
|
||||
|
||||
if (!inject_on_main(pid, lib_path)) {
|
||||
LOGE("failed to inject");
|
||||
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user