You've already forked ReZygisk
mirror of
https://github.com/PerformanC/ReZygisk.git
synced 2025-09-06 06:37:01 +00:00
daemon launched by monitor & show daemon status in module.prop
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
#include "main.hpp"
|
#include "main.hpp"
|
||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
#include "daemon.h"
|
#include "daemon.h"
|
||||||
|
#include <sys/mount.h>
|
||||||
|
|
||||||
using namespace std::string_view_literals;
|
using namespace std::string_view_literals;
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,9 @@
|
|||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <sys/epoll.h>
|
#include <sys/epoll.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include "main.hpp"
|
#include "main.hpp"
|
||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
@@ -24,13 +26,17 @@ using namespace std::string_view_literals;
|
|||||||
|
|
||||||
#define STOPPED_WITH(sig, event) WIFSTOPPED(status) && (status >> 8 == ((sig) | (event << 8)))
|
#define STOPPED_WITH(sig, event) WIFSTOPPED(status) && (status >> 8 == ((sig) | (event << 8)))
|
||||||
|
|
||||||
|
static void updateStatus();
|
||||||
|
|
||||||
enum TracingState {
|
enum TracingState {
|
||||||
TRACING = 1,
|
TRACING = 1,
|
||||||
STOPPING,
|
STOPPING,
|
||||||
STOPPED
|
STOPPED,
|
||||||
|
EXITING
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::string monitor_stop_reason;
|
||||||
|
|
||||||
constexpr char SOCKET_NAME[] = "init_monitor";
|
constexpr char SOCKET_NAME[] = "init_monitor";
|
||||||
|
|
||||||
std::string GetControlSocketName() {
|
std::string GetControlSocketName() {
|
||||||
@@ -158,16 +164,22 @@ struct SocketHandler : public EventHandler {
|
|||||||
LOGI("start tracing init");
|
LOGI("start tracing init");
|
||||||
tracing_state = TRACING;
|
tracing_state = TRACING;
|
||||||
}
|
}
|
||||||
|
updateStatus();
|
||||||
break;
|
break;
|
||||||
case STOP:
|
case STOP:
|
||||||
if (tracing_state == TRACING) {
|
if (tracing_state == TRACING) {
|
||||||
LOGI("stop tracing requested");
|
LOGI("stop tracing requested");
|
||||||
tracing_state = STOPPING;
|
tracing_state = STOPPING;
|
||||||
|
monitor_stop_reason = "user requested";
|
||||||
ptrace(PTRACE_INTERRUPT, 1, 0, 0);
|
ptrace(PTRACE_INTERRUPT, 1, 0, 0);
|
||||||
|
updateStatus();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EXIT:
|
case EXIT:
|
||||||
LOGI("prepare for exit ...");
|
LOGI("prepare for exit ...");
|
||||||
|
tracing_state = EXITING;
|
||||||
|
monitor_stop_reason = "user requested";
|
||||||
|
updateStatus();
|
||||||
loop.Stop();
|
loop.Stop();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -181,35 +193,61 @@ struct SocketHandler : public EventHandler {
|
|||||||
|
|
||||||
constexpr auto MAX_RETRY_COUNT = 5;
|
constexpr auto MAX_RETRY_COUNT = 5;
|
||||||
|
|
||||||
struct timespec last_zygote64{.tv_sec = 0, .tv_nsec = 0};
|
#define CREATE_ZYGOTE_START_COUNTER(abi) \
|
||||||
int count_zygote64 = 0;
|
struct timespec last_zygote##abi{.tv_sec = 0, .tv_nsec = 0}; \
|
||||||
bool should_stop_inject64() {
|
int count_zygote##abi = 0; \
|
||||||
struct timespec now{};
|
bool should_stop_inject##abi() { \
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
struct timespec now{}; \
|
||||||
if (now.tv_sec - last_zygote64.tv_sec < 30) {
|
clock_gettime(CLOCK_MONOTONIC, &now); \
|
||||||
count_zygote64++;
|
if (now.tv_sec - last_zygote##abi.tv_sec < 30) { \
|
||||||
} else {
|
count_zygote##abi++; \
|
||||||
count_zygote64 = 0;
|
} else { \
|
||||||
}
|
count_zygote##abi = 0; \
|
||||||
last_zygote64 = now;
|
} \
|
||||||
return count_zygote64 >= MAX_RETRY_COUNT;
|
last_zygote##abi = now; \
|
||||||
|
return count_zygote##abi >= MAX_RETRY_COUNT; \
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timespec last_zygote32{.tv_sec = 0, .tv_nsec = 0};
|
CREATE_ZYGOTE_START_COUNTER(64)
|
||||||
int count_zygote32 = 0;
|
CREATE_ZYGOTE_START_COUNTER(32)
|
||||||
bool should_stop_inject32() {
|
|
||||||
struct timespec now{};
|
struct Status {
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
bool supported = false;
|
||||||
if (now.tv_sec - last_zygote32.tv_sec < 30) {
|
bool zygote_injected = false;
|
||||||
count_zygote32++;
|
bool daemon_running = false;
|
||||||
|
pid_t daemon_pid = -1;
|
||||||
|
std::string daemon_crash_reason;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Status status64;
|
||||||
|
static Status status32;
|
||||||
|
|
||||||
|
static bool ensure_daemon_created(bool is_64bit) {
|
||||||
|
auto &status = is_64bit ? status64 : status32;
|
||||||
|
if (status.daemon_pid == -1) {
|
||||||
|
auto pid = fork();
|
||||||
|
if (pid < 0) {
|
||||||
|
PLOGE("create daemon (64=%s)", is_64bit ? "true" : "false");
|
||||||
|
return false;
|
||||||
|
} else if (pid == 0) {
|
||||||
|
std::string daemon_name = "./bin/zygisk-cp";
|
||||||
|
daemon_name += is_64bit ? "64" : "32";
|
||||||
|
execl(daemon_name.c_str(), basename(daemon_name.c_str()), nullptr);
|
||||||
|
PLOGE("exec daemon %s failed", daemon_name.c_str());
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
status.supported = true;
|
||||||
|
status.daemon_pid = pid;
|
||||||
|
status.daemon_running = true;
|
||||||
|
updateStatus();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
count_zygote32 = 0;
|
return status.daemon_running;
|
||||||
}
|
}
|
||||||
last_zygote32 = now;
|
|
||||||
return count_zygote32 >= MAX_RETRY_COUNT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PtraceHandler : public EventHandler {
|
struct SigChldHandler : public EventHandler {
|
||||||
private:
|
private:
|
||||||
int signal_fd_;
|
int signal_fd_;
|
||||||
struct signalfd_siginfo fdsi;
|
struct signalfd_siginfo fdsi;
|
||||||
@@ -288,6 +326,19 @@ public:
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
#define CHECK_DAEMON_EXIT(abi) \
|
||||||
|
if (status##abi.supported && pid == status64.daemon_pid) { \
|
||||||
|
auto status_str = parse_status(status); \
|
||||||
|
LOGW("daemon" #abi "pid %d exited: %s", pid, status_str.c_str()); \
|
||||||
|
status##abi.daemon_running = false; \
|
||||||
|
if (status##abi.daemon_crash_reason.empty()) { \
|
||||||
|
status##abi.daemon_crash_reason = status_str; \
|
||||||
|
} \
|
||||||
|
updateStatus(); \
|
||||||
|
continue; \
|
||||||
|
}
|
||||||
|
CHECK_DAEMON_EXIT(64)
|
||||||
|
CHECK_DAEMON_EXIT(32)
|
||||||
auto state = process.find(pid);
|
auto state = process.find(pid);
|
||||||
if (state == process.end()) {
|
if (state == process.end()) {
|
||||||
LOGV("new process %d attached", pid);
|
LOGV("new process %d attached", pid);
|
||||||
@@ -305,23 +356,28 @@ public:
|
|||||||
LOGW("stop injecting %d because not tracing", pid);
|
LOGW("stop injecting %d because not tracing", pid);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (program == "/system/bin/app_process64") {
|
#define PRE_INJECT(abi, is_64) \
|
||||||
tracer = "./bin/zygisk-ptrace64";
|
if (program == "/system/bin/app_process"#abi) { \
|
||||||
if (should_stop_inject64()) {
|
tracer = "./bin/zygisk-ptrace"#abi; \
|
||||||
LOGW("zygote64 restart too much times, stop injecting");
|
if (should_stop_inject##abi()) { \
|
||||||
tracing_state = STOPPING;
|
LOGW("zygote" #abi " restart too much times, stop injecting"); \
|
||||||
ptrace(PTRACE_INTERRUPT, 1, 0, 0);
|
tracing_state = STOPPING; \
|
||||||
break;
|
monitor_stop_reason = "zygote crashed"; \
|
||||||
}
|
updateStatus(); \
|
||||||
} else if (program == "/system/bin/app_process32") {
|
ptrace(PTRACE_INTERRUPT, 1, 0, 0); \
|
||||||
tracer = "./bin/zygisk-ptrace32";
|
break; \
|
||||||
if (should_stop_inject32()) {
|
} \
|
||||||
LOGW("zygote32 restart too much times, stop injecting");
|
if (!ensure_daemon_created(is_64)) { \
|
||||||
tracing_state = STOPPING;
|
LOGW("daemon" #abi " not running, stop injecting"); \
|
||||||
ptrace(PTRACE_INTERRUPT, 1, 0, 0);
|
tracing_state = STOPPING; \
|
||||||
break;
|
monitor_stop_reason = "daemon not running"; \
|
||||||
}
|
updateStatus(); \
|
||||||
|
ptrace(PTRACE_INTERRUPT, 1, 0, 0); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
}
|
}
|
||||||
|
PRE_INJECT(64, true)
|
||||||
|
PRE_INJECT(32, false)
|
||||||
if (tracer != nullptr) {
|
if (tracer != nullptr) {
|
||||||
LOGD("stopping %d", pid);
|
LOGD("stopping %d", pid);
|
||||||
kill(pid, SIGSTOP);
|
kill(pid, SIGSTOP);
|
||||||
@@ -345,7 +401,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (false);
|
} while (false);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
LOGE("process %d received unknown status %s", pid,
|
LOGE("process %d received unknown status %s", pid,
|
||||||
parse_status(status).c_str());
|
parse_status(status).c_str());
|
||||||
@@ -360,17 +415,119 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~PtraceHandler() {
|
~SigChldHandler() {
|
||||||
if (signal_fd_ >= 0) close(signal_fd_);
|
if (signal_fd_ >= 0) close(signal_fd_);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static std::string prop_path;
|
||||||
|
static std::string pre_section;
|
||||||
|
static std::string post_section;
|
||||||
|
|
||||||
|
static void updateStatus() {
|
||||||
|
auto prop = xopen_file(prop_path.c_str(), "w");
|
||||||
|
std::string status_text = "monitor:";
|
||||||
|
switch (tracing_state) {
|
||||||
|
case TRACING:
|
||||||
|
status_text += "tracing";
|
||||||
|
break;
|
||||||
|
case STOPPING:
|
||||||
|
[[fallthrough]];
|
||||||
|
case STOPPED:
|
||||||
|
status_text += "stopped";
|
||||||
|
break;
|
||||||
|
case EXITING:
|
||||||
|
status_text += "exited";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (tracing_state != TRACING && !monitor_stop_reason.empty()) {
|
||||||
|
status_text += "(";
|
||||||
|
status_text += monitor_stop_reason;
|
||||||
|
status_text += ")";
|
||||||
|
}
|
||||||
|
status_text += ", ";
|
||||||
|
#define WRITE_STATUS_ABI(suffix) \
|
||||||
|
if (status##suffix.supported) { \
|
||||||
|
status_text += " zygote" #suffix ":"; \
|
||||||
|
if (status##suffix.zygote_injected) status_text += "injected,"; \
|
||||||
|
else status_text += "not injected,"; \
|
||||||
|
status_text += " daemon" #suffix ":"; \
|
||||||
|
if (status##suffix.daemon_running) status_text += "running"; \
|
||||||
|
else { \
|
||||||
|
status_text += "crashed"; \
|
||||||
|
if (!status##suffix.daemon_crash_reason.empty()) { \
|
||||||
|
status_text += "("; \
|
||||||
|
status_text += status##suffix.daemon_crash_reason; \
|
||||||
|
status_text += ")"; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
WRITE_STATUS_ABI(64)
|
||||||
|
WRITE_STATUS_ABI(32)
|
||||||
|
fprintf(prop.get(), "%s[%s]%s", pre_section.c_str(), status_text.c_str(), post_section.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool prepare_environment() {
|
||||||
|
auto path = getenv(MAGIC_PATH_ENV);
|
||||||
|
if (path == nullptr) {
|
||||||
|
LOGE("path is null, is MAGIC_PATH_ENV specified?");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
prop_path = std::string(path) + "/module.prop";
|
||||||
|
close(open(prop_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644));
|
||||||
|
auto orig_prop = xopen_file("./module.prop", "r");
|
||||||
|
if (orig_prop == nullptr) {
|
||||||
|
PLOGE("failed to open orig prop");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool post = false;
|
||||||
|
file_readline(false, orig_prop.get(), [&](std::string_view line) -> bool {
|
||||||
|
if (line.starts_with("description=")) {
|
||||||
|
post = true;
|
||||||
|
pre_section += "description=";
|
||||||
|
post_section += line.substr(sizeof("description"));
|
||||||
|
} else {
|
||||||
|
if (post) {
|
||||||
|
post_section += line;
|
||||||
|
} else {
|
||||||
|
pre_section += line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
int old_ns;
|
||||||
|
char wd[128];
|
||||||
|
if (getcwd(wd, sizeof(wd)) == nullptr) {
|
||||||
|
PLOGE("get cwd");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!switch_mnt_ns(1, &old_ns)) return false;
|
||||||
|
if (chdir(wd) == -1) {
|
||||||
|
PLOGE("chdir %s", wd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mount(prop_path.c_str(), "/data/adb/modules/zygisksu/module.prop", nullptr, MS_BIND, nullptr) == -1) {
|
||||||
|
PLOGE("failed to mount prop");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!switch_mnt_ns(0, &old_ns)) return false;
|
||||||
|
if (chdir(wd) == -1) {
|
||||||
|
PLOGE("chdir %s", wd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
updateStatus();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void init_monitor() {
|
void init_monitor() {
|
||||||
LOGI("Zygisk Next %s", ZKSU_VERSION);
|
LOGI("Zygisk Next %s", ZKSU_VERSION);
|
||||||
LOGI("init monitor started");
|
LOGI("init monitor started");
|
||||||
|
if (!prepare_environment()) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
SocketHandler socketHandler{};
|
SocketHandler socketHandler{};
|
||||||
socketHandler.Init();
|
socketHandler.Init();
|
||||||
PtraceHandler ptraceHandler{};
|
SigChldHandler ptraceHandler{};
|
||||||
ptraceHandler.Init();
|
ptraceHandler.Init();
|
||||||
EventLoop looper;
|
EventLoop looper;
|
||||||
looper.Init();
|
looper.Init();
|
||||||
|
|||||||
@@ -24,6 +24,45 @@
|
|||||||
|
|
||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
|
#include <sched.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
bool switch_mnt_ns(int pid, int *fd) {
|
||||||
|
int nsfd, old_nsfd = -1;
|
||||||
|
std::string path;
|
||||||
|
if (pid == 0) {
|
||||||
|
if (fd != nullptr) {
|
||||||
|
nsfd = *fd;
|
||||||
|
*fd = -1;
|
||||||
|
} else return false;
|
||||||
|
path = "/proc/self/fd/";
|
||||||
|
path += std::to_string(nsfd);
|
||||||
|
} else {
|
||||||
|
if (fd != nullptr) {
|
||||||
|
old_nsfd = open("/proc/self/ns/mnt", O_RDONLY | O_CLOEXEC);
|
||||||
|
if (old_nsfd == -1) {
|
||||||
|
PLOGE("get old nsfd");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*fd = old_nsfd;
|
||||||
|
}
|
||||||
|
path = std::string("/proc/") + std::to_string(pid) + "/ns/mnt";
|
||||||
|
nsfd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
|
||||||
|
if (nsfd == -1) {
|
||||||
|
PLOGE("open nsfd %s", path.c_str());
|
||||||
|
close(old_nsfd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (setns(nsfd, CLONE_NEWNS) == -1) {
|
||||||
|
PLOGE("set ns to %s", path.c_str());
|
||||||
|
close(nsfd);
|
||||||
|
close(old_nsfd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
close(nsfd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<MapInfo> MapInfo::Scan(const std::string& pid) {
|
std::vector<MapInfo> MapInfo::Scan(const std::string& pid) {
|
||||||
constexpr static auto kPermLength = 5;
|
constexpr static auto kPermLength = 5;
|
||||||
|
|||||||
@@ -119,3 +119,6 @@ inline const char* sigabbrev_np(int sig) {
|
|||||||
std::string get_program(int pid);
|
std::string get_program(int pid);
|
||||||
void *find_module_return_addr(std::vector<MapInfo> &info, std::string_view suffix);
|
void *find_module_return_addr(std::vector<MapInfo> &info, std::string_view suffix);
|
||||||
|
|
||||||
|
// pid = 0, fd != nullptr -> set to fd
|
||||||
|
// pid != 0, fd != nullptr -> set to pid ns, give orig ns in fd
|
||||||
|
bool switch_mnt_ns(int pid, int *fd);
|
||||||
|
|||||||
@@ -24,7 +24,3 @@ if [ "$(which magisk)" ]; then
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[ "$DEBUG" = true ] && export RUST_BACKTRACE=1
|
|
||||||
unshare -m sh -c "bin/zygisk-cp64 &"
|
|
||||||
unshare -m sh -c "bin/zygisk-cp32 &"
|
|
||||||
|
|||||||
Reference in New Issue
Block a user