You've already forked ReZygisk
mirror of
https://github.com/PerformanC/ReZygisk.git
synced 2025-09-06 06:37:01 +00:00
update: some loader/ code to C
This commit changes some code from "loader" folder to use C keywords and not C++ only keywords.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,6 +1,7 @@
|
|||||||
.gradle
|
.gradle
|
||||||
.idea
|
.idea
|
||||||
.cxx
|
.cxx
|
||||||
|
.vscode
|
||||||
build
|
build
|
||||||
local.properties
|
local.properties
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
|
|||||||
@@ -1,55 +1,53 @@
|
|||||||
#include <cstdio>
|
#include "main.h"
|
||||||
#include <cstdlib>
|
|
||||||
#include <string_view>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <sys/system_properties.h>
|
|
||||||
|
|
||||||
#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;
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
zygiskd::Init(getenv("TMP_PATH"));
|
zygiskd::Init(getenv("TMP_PATH"));
|
||||||
if (argc >= 2 && argv[1] == "monitor"sv) {
|
if (argc >= 2 && strcmp(argv[1], "monitor") == 0) {
|
||||||
init_monitor();
|
init_monitor();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} else if (argc >= 3 && argv[1] == "trace"sv) {
|
} else if (argc >= 3 && strcmp(argv[1], "trace") == 0) {
|
||||||
if (argc >= 4 && argv[3] == "--restart"sv) {
|
if (argc >= 4 && strcmp(argv[3], "--restart") == 0) zygiskd::ZygoteRestart();
|
||||||
zygiskd::ZygoteRestart();
|
|
||||||
}
|
long pid = strtol(argv[2], 0, 0);
|
||||||
auto pid = strtol(argv[2], 0, 0);
|
|
||||||
if (!trace_zygote(pid)) {
|
if (!trace_zygote(pid)) {
|
||||||
kill(pid, SIGKILL);
|
kill(pid, SIGKILL);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} else if (argc >= 2 && argv[1] == "ctl"sv) {
|
} else if (argc >= 2 && strcmp(argv[1], "ctl") == 0) {
|
||||||
if (argc == 3) {
|
if (argc == 3) {
|
||||||
if (argv[2] == "start"sv) {
|
if (strcmp(argv[2], "start") == 0) {
|
||||||
send_control_command(START);
|
send_control_command(START);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} else if (argv[2] == "stop"sv) {
|
} else if (strcmp(argv[2], "stop") == 0) {
|
||||||
send_control_command(STOP);
|
send_control_command(STOP);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} else if (argv[2] == "exit"sv) {
|
} else if (strcmp(argv[2], "exit") == 0) {
|
||||||
send_control_command(EXIT);
|
send_control_command(EXIT);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("ReZygisk Tracer %s\n", ZKSU_VERSION);
|
printf("ReZygisk Tracer %s\n", ZKSU_VERSION);
|
||||||
printf("Usage: %s ctl start|stop|exit\n", argv[0]);
|
printf("Usage: %s ctl start|stop|exit\n", argv[0]);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
} else if (argc >= 2 && argv[1] == "version"sv) {
|
} else if (argc >= 2 && strcmp(argv[1], "version") == 0) {
|
||||||
printf("ReZygisk Tracer %s\n", ZKSU_VERSION);
|
printf("ReZygisk Tracer %s\n", ZKSU_VERSION);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
printf("ReZygisk Tracer %s\n", ZKSU_VERSION);
|
printf("ReZygisk Tracer %s\n", ZKSU_VERSION);
|
||||||
printf("usage: %s monitor | trace <pid> | ctl <start|stop|exit> | version\n", argv[0]);
|
printf("usage: %s monitor | trace <pid> | ctl <start|stop|exit> | version\n", argv[0]);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
26
loader/src/ptracer/main.h
Normal file
26
loader/src/ptracer/main.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef MAIN_HPP
|
||||||
|
#define MAIN_HPP
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
void init_monitor();
|
||||||
|
bool trace_zygote(int pid);
|
||||||
|
|
||||||
|
enum Command {
|
||||||
|
START = 1,
|
||||||
|
STOP = 2,
|
||||||
|
EXIT = 3,
|
||||||
|
|
||||||
|
/* sent from daemon */
|
||||||
|
ZYGOTE64_INJECTED = 4,
|
||||||
|
ZYGOTE32_INJECTED = 5,
|
||||||
|
DAEMON64_SET_INFO = 6,
|
||||||
|
DAEMON32_SET_INFO = 7,
|
||||||
|
DAEMON64_SET_ERROR_INFO = 8,
|
||||||
|
DAEMON32_SET_ERROR_INFO = 9,
|
||||||
|
SYSTEM_SERVER_STARTED = 10
|
||||||
|
};
|
||||||
|
|
||||||
|
void send_control_command(enum Command cmd);
|
||||||
|
|
||||||
|
#endif /* MAIN_HPP */
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
void init_monitor();
|
|
||||||
bool trace_zygote(int pid);
|
|
||||||
|
|
||||||
enum Command {
|
|
||||||
START = 1,
|
|
||||||
STOP = 2,
|
|
||||||
EXIT = 3,
|
|
||||||
// sent from daemon
|
|
||||||
ZYGOTE64_INJECTED = 4,
|
|
||||||
ZYGOTE32_INJECTED = 5,
|
|
||||||
DAEMON64_SET_INFO = 6,
|
|
||||||
DAEMON32_SET_INFO = 7,
|
|
||||||
DAEMON64_SET_ERROR_INFO = 8,
|
|
||||||
DAEMON32_SET_ERROR_INFO = 9,
|
|
||||||
SYSTEM_SERVER_STARTED = 10
|
|
||||||
};
|
|
||||||
|
|
||||||
void send_control_command(Command cmd);
|
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include <sys/system_properties.h>
|
#include <sys/system_properties.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <syscall.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/signalfd.h>
|
#include <sys/signalfd.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
@@ -13,17 +11,13 @@
|
|||||||
#include <sys/epoll.h>
|
#include <sys/epoll.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <time.h>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include "main.hpp"
|
#include "main.h"
|
||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
#include "files.hpp"
|
#include "files.hpp"
|
||||||
#include "misc.hpp"
|
#include "misc.hpp"
|
||||||
|
|
||||||
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();
|
static void updateStatus();
|
||||||
@@ -35,7 +29,7 @@ enum TracingState {
|
|||||||
EXITING
|
EXITING
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string monitor_stop_reason;
|
char monitor_stop_reason[32];
|
||||||
|
|
||||||
constexpr char SOCKET_NAME[] = "init_monitor";
|
constexpr char SOCKET_NAME[] = "init_monitor";
|
||||||
|
|
||||||
@@ -95,7 +89,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[maybe_unused]] bool UnregisterHandler(EventHandler &handler) {
|
[[maybe_unused]] bool UnregisterHandler(EventHandler &handler) {
|
||||||
if (epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, handler.GetFd(), nullptr) == -1) {
|
if (epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, handler.GetFd(), NULL) == -1) {
|
||||||
PLOGE("failed to del event handler");
|
PLOGE("failed to del event handler");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -108,7 +102,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
static TracingState tracing_state = TRACING;
|
static TracingState tracing_state = TRACING;
|
||||||
static std::string prop_path;
|
static char prop_path[PATH_MAX];
|
||||||
|
|
||||||
|
|
||||||
struct Status {
|
struct Status {
|
||||||
@@ -116,8 +110,8 @@ struct Status {
|
|||||||
bool zygote_injected = false;
|
bool zygote_injected = false;
|
||||||
bool daemon_running = false;
|
bool daemon_running = false;
|
||||||
pid_t daemon_pid = -1;
|
pid_t daemon_pid = -1;
|
||||||
std::string daemon_info;
|
char *daemon_info;
|
||||||
std::string daemon_error_info;
|
char *daemon_error_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
static Status status64;
|
static Status status64;
|
||||||
@@ -130,18 +124,24 @@ struct SocketHandler : public EventHandler {
|
|||||||
sock_fd_ = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
|
sock_fd_ = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
|
||||||
if (sock_fd_ == -1) {
|
if (sock_fd_ == -1) {
|
||||||
PLOGE("socket create");
|
PLOGE("socket create");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
struct sockaddr_un addr{
|
|
||||||
|
struct sockaddr_un addr = {
|
||||||
.sun_family = AF_UNIX,
|
.sun_family = AF_UNIX,
|
||||||
.sun_path={0},
|
.sun_path = { 0 }
|
||||||
};
|
};
|
||||||
sprintf(addr.sun_path, "%s/%s", zygiskd::GetTmpPath().c_str(), SOCKET_NAME);
|
|
||||||
socklen_t socklen = sizeof(sa_family_t) + strlen(addr.sun_path);
|
size_t sun_path_len = sprintf(addr.sun_path, "%s/%s", zygiskd::GetTmpPath().c_str(), SOCKET_NAME);
|
||||||
if (bind(sock_fd_, (struct sockaddr *) &addr, socklen) == -1) {
|
|
||||||
|
socklen_t socklen = sizeof(sa_family_t) + sun_path_len;
|
||||||
|
if (bind(sock_fd_, (struct sockaddr *)&addr, socklen) == -1) {
|
||||||
PLOGE("bind socket");
|
PLOGE("bind socket");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,125 +151,170 @@ struct SocketHandler : public EventHandler {
|
|||||||
|
|
||||||
void HandleEvent(EventLoop &loop, uint32_t) override {
|
void HandleEvent(EventLoop &loop, uint32_t) override {
|
||||||
struct [[gnu::packed]] MsgHead {
|
struct [[gnu::packed]] MsgHead {
|
||||||
Command cmd;
|
enum Command cmd;
|
||||||
int length;
|
int length;
|
||||||
char data[0];
|
char data[0];
|
||||||
};
|
};
|
||||||
for (;;) {
|
|
||||||
|
while (1) {
|
||||||
std::vector<uint8_t> buf;
|
std::vector<uint8_t> buf;
|
||||||
buf.resize(sizeof(MsgHead), 0);
|
buf.resize(sizeof(MsgHead), 0);
|
||||||
|
|
||||||
MsgHead &msg = *reinterpret_cast<MsgHead*>(buf.data());
|
MsgHead &msg = *reinterpret_cast<MsgHead*>(buf.data());
|
||||||
|
|
||||||
ssize_t real_size;
|
ssize_t real_size;
|
||||||
auto nread = recv(sock_fd_, &msg, sizeof(msg), MSG_PEEK);
|
ssize_t nread = recv(sock_fd_, &msg, sizeof(msg), MSG_PEEK);
|
||||||
if (nread == -1) {
|
if (nread == -1) {
|
||||||
if (errno == EAGAIN) {
|
if (errno == EAGAIN) break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
PLOGE("read socket");
|
PLOGE("read socket");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (static_cast<size_t>(nread) < sizeof(Command)) {
|
if (static_cast<size_t>(nread) < sizeof(Command)) {
|
||||||
LOGE("read %zu < %zu", nread, sizeof(Command));
|
LOGE("read %zu < %zu", nread, sizeof(Command));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg.cmd >= Command::DAEMON64_SET_INFO && msg.cmd != Command::SYSTEM_SERVER_STARTED) {
|
if (msg.cmd >= Command::DAEMON64_SET_INFO && msg.cmd != Command::SYSTEM_SERVER_STARTED) {
|
||||||
if (nread != sizeof(msg)) {
|
if (nread != sizeof(msg)) {
|
||||||
LOGE("cmd %d size %zu != %zu", msg.cmd, nread, sizeof(MsgHead));
|
LOGE("cmd %d size %zu != %zu", msg.cmd, nread, sizeof(MsgHead));
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
real_size = sizeof(MsgHead) + msg.length;
|
real_size = sizeof(MsgHead) + msg.length;
|
||||||
} else {
|
} else {
|
||||||
if (nread != sizeof(Command)) {
|
if (nread != sizeof(Command)) {
|
||||||
LOGE("cmd %d size %zu != %zu", msg.cmd, nread, sizeof(Command));
|
LOGE("cmd %d size %zu != %zu", msg.cmd, nread, sizeof(Command));
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
real_size = sizeof(Command);
|
real_size = sizeof(Command);
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.resize(real_size);
|
buf.resize(real_size);
|
||||||
nread = recv(sock_fd_, &msg, real_size, 0);
|
nread = recv(sock_fd_, &msg, real_size, 0);
|
||||||
|
|
||||||
if (nread == -1) {
|
if (nread == -1) {
|
||||||
if (errno == EAGAIN) {
|
if (errno == EAGAIN) break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
PLOGE("recv");
|
PLOGE("recv");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nread != real_size) {
|
if (nread != real_size) {
|
||||||
LOGE("real size %zu != %zu", real_size, nread);
|
LOGE("real size %zu != %zu", real_size, nread);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (msg.cmd) {
|
switch (msg.cmd) {
|
||||||
case START:
|
case START: {
|
||||||
if (tracing_state == STOPPING) {
|
if (tracing_state == STOPPING) tracing_state = TRACING;
|
||||||
tracing_state = TRACING;
|
else if (tracing_state == STOPPED) {
|
||||||
} else if (tracing_state == STOPPED) {
|
|
||||||
ptrace(PTRACE_SEIZE, 1, 0, PTRACE_O_TRACEFORK);
|
ptrace(PTRACE_SEIZE, 1, 0, PTRACE_O_TRACEFORK);
|
||||||
|
|
||||||
LOGI("start tracing init");
|
LOGI("start tracing init");
|
||||||
|
|
||||||
tracing_state = TRACING;
|
tracing_state = TRACING;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateStatus();
|
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";
|
memcpy(monitor_stop_reason, "user requested", sizeof("user requested"));
|
||||||
|
|
||||||
ptrace(PTRACE_INTERRUPT, 1, 0, 0);
|
ptrace(PTRACE_INTERRUPT, 1, 0, 0);
|
||||||
updateStatus();
|
updateStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case EXIT:
|
}
|
||||||
|
case EXIT: {
|
||||||
LOGI("prepare for exit ...");
|
LOGI("prepare for exit ...");
|
||||||
|
|
||||||
tracing_state = EXITING;
|
tracing_state = EXITING;
|
||||||
monitor_stop_reason = "user requested";
|
memcpy(monitor_stop_reason, "user requested", sizeof("user requested"));
|
||||||
|
|
||||||
updateStatus();
|
updateStatus();
|
||||||
loop.Stop();
|
loop.Stop();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case ZYGOTE64_INJECTED:
|
}
|
||||||
|
case ZYGOTE64_INJECTED: {
|
||||||
status64.zygote_injected = true;
|
status64.zygote_injected = true;
|
||||||
|
|
||||||
updateStatus();
|
updateStatus();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case ZYGOTE32_INJECTED:
|
}
|
||||||
|
case ZYGOTE32_INJECTED: {
|
||||||
status32.zygote_injected = true;
|
status32.zygote_injected = true;
|
||||||
|
|
||||||
updateStatus();
|
updateStatus();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case DAEMON64_SET_INFO:
|
}
|
||||||
|
case DAEMON64_SET_INFO: {
|
||||||
LOGD("received daemon64 info %s", msg.data);
|
LOGD("received daemon64 info %s", msg.data);
|
||||||
status64.daemon_info = std::string(msg.data);
|
|
||||||
|
status64.daemon_info = msg.data;
|
||||||
updateStatus();
|
updateStatus();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case DAEMON32_SET_INFO:
|
}
|
||||||
|
case DAEMON32_SET_INFO: {
|
||||||
LOGD("received daemon32 info %s", msg.data);
|
LOGD("received daemon32 info %s", msg.data);
|
||||||
status32.daemon_info = std::string(msg.data);
|
|
||||||
|
status32.daemon_info = msg.data;
|
||||||
updateStatus();
|
updateStatus();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case DAEMON64_SET_ERROR_INFO:
|
}
|
||||||
|
case DAEMON64_SET_ERROR_INFO: {
|
||||||
LOGD("received daemon64 error info %s", msg.data);
|
LOGD("received daemon64 error info %s", msg.data);
|
||||||
|
|
||||||
status64.daemon_running = false;
|
status64.daemon_running = false;
|
||||||
status64.daemon_error_info = std::string(msg.data);
|
status64.daemon_error_info = msg.data;
|
||||||
updateStatus();
|
updateStatus();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case DAEMON32_SET_ERROR_INFO:
|
}
|
||||||
|
case DAEMON32_SET_ERROR_INFO: {
|
||||||
LOGD("received daemon32 error info %s", msg.data);
|
LOGD("received daemon32 error info %s", msg.data);
|
||||||
|
|
||||||
status32.daemon_running = false;
|
status32.daemon_running = false;
|
||||||
status32.daemon_error_info = std::string(msg.data);
|
status32.daemon_error_info = msg.data;
|
||||||
updateStatus();
|
updateStatus();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case SYSTEM_SERVER_STARTED:
|
}
|
||||||
|
case SYSTEM_SERVER_STARTED: {
|
||||||
LOGD("system server started, mounting prop");
|
LOGD("system server started, mounting prop");
|
||||||
if (mount(prop_path.c_str(), "/data/adb/modules/zygisksu/module.prop", nullptr, MS_BIND, nullptr) == -1) {
|
|
||||||
|
if (mount(prop_path, "/data/adb/modules/zygisksu/module.prop", NULL, MS_BIND, NULL) == -1) {
|
||||||
PLOGE("failed to mount prop");
|
PLOGE("failed to mount prop");
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
~SocketHandler() {
|
~SocketHandler() {
|
||||||
if (sock_fd_ >= 0) close(sock_fd_);
|
if (sock_fd_ >= 0) close(sock_fd_);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr auto MAX_RETRY_COUNT = 5;
|
constexpr int MAX_RETRY_COUNT = 5;
|
||||||
|
|
||||||
#define CREATE_ZYGOTE_START_COUNTER(abi) \
|
#define CREATE_ZYGOTE_START_COUNTER(abi) \
|
||||||
struct timespec last_zygote##abi{.tv_sec = 0, .tv_nsec = 0}; \
|
struct timespec last_zygote##abi{.tv_sec = 0, .tv_nsec = 0}; \
|
||||||
@@ -290,27 +335,35 @@ CREATE_ZYGOTE_START_COUNTER(64)
|
|||||||
CREATE_ZYGOTE_START_COUNTER(32)
|
CREATE_ZYGOTE_START_COUNTER(32)
|
||||||
|
|
||||||
static bool ensure_daemon_created(bool is_64bit) {
|
static bool ensure_daemon_created(bool is_64bit) {
|
||||||
auto &status = is_64bit ? status64 : status32;
|
Status status = is_64bit ? status64 : status32;
|
||||||
if (is_64bit) {
|
if (is_64bit) {
|
||||||
LOGD("new zygote started, unmounting prop ...");
|
LOGD("new zygote started, unmounting prop ...");
|
||||||
|
|
||||||
umount2("/data/adb/modules/zygisksu/module.prop", MNT_DETACH);
|
umount2("/data/adb/modules/zygisksu/module.prop", MNT_DETACH);
|
||||||
}
|
}
|
||||||
|
|
||||||
status.zygote_injected = false;
|
status.zygote_injected = false;
|
||||||
|
|
||||||
if (status.daemon_pid == -1) {
|
if (status.daemon_pid == -1) {
|
||||||
auto pid = fork();
|
pid_t pid = fork();
|
||||||
if (pid < 0) {
|
if (pid < 0) {
|
||||||
PLOGE("create daemon (64=%s)", is_64bit ? "true" : "false");
|
PLOGE("create daemon%s", is_64bit ? "64" : "32");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
} else if (pid == 0) {
|
} else if (pid == 0) {
|
||||||
std::string daemon_name = "./bin/zygiskd";
|
char daemon_name[PATH_MAX] = "./bin/zygiskd";
|
||||||
daemon_name += is_64bit ? "64" : "32";
|
strcat(daemon_name, is_64bit ? "64" : "32");
|
||||||
execl(daemon_name.c_str(), daemon_name.c_str(), nullptr);
|
|
||||||
PLOGE("exec daemon %s failed", daemon_name.c_str());
|
execl(daemon_name, daemon_name, NULL);
|
||||||
|
|
||||||
|
PLOGE("exec daemon %s failed", daemon_name);
|
||||||
|
|
||||||
exit(1);
|
exit(1);
|
||||||
} else {
|
} else {
|
||||||
status.supported = true;
|
status.supported = true;
|
||||||
status.daemon_pid = pid;
|
status.daemon_pid = pid;
|
||||||
status.daemon_running = true;
|
status.daemon_running = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -318,27 +371,73 @@ static bool ensure_daemon_created(bool is_64bit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define CHECK_DAEMON_EXIT(abi) \
|
||||||
|
if (status##abi.supported && pid == status64.daemon_pid) { \
|
||||||
|
char status_str[64]; \
|
||||||
|
parse_status(status, status_str, sizeof(status_str)); \
|
||||||
|
\
|
||||||
|
LOGW("daemon" #abi "pid %d exited: %s", pid, status_str); \
|
||||||
|
status##abi.daemon_running = false; \
|
||||||
|
\
|
||||||
|
if (status##abi.daemon_error_info[0] == '\0') \
|
||||||
|
memcpy(status##abi.daemon_error_info, status_str, strlen(status_str)); \
|
||||||
|
\
|
||||||
|
updateStatus(); \
|
||||||
|
continue; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PRE_INJECT(abi, is_64) \
|
||||||
|
if (strcmp(program, "/system/bin/app_process" # abi) == 0) { \
|
||||||
|
tracer = "./bin/zygisk-ptrace" # abi; \
|
||||||
|
\
|
||||||
|
if (should_stop_inject ## abi()) { \
|
||||||
|
LOGW("zygote" # abi " restart too much times, stop injecting"); \
|
||||||
|
\
|
||||||
|
tracing_state = STOPPING; \
|
||||||
|
memcpy(monitor_stop_reason, "zygote crashed", sizeof("zygote crashed")); \
|
||||||
|
ptrace(PTRACE_INTERRUPT, 1, 0, 0); \
|
||||||
|
\
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
if (!ensure_daemon_created(is_64)) { \
|
||||||
|
LOGW("daemon" #abi " not running, stop injecting"); \
|
||||||
|
\
|
||||||
|
tracing_state = STOPPING; \
|
||||||
|
memcpy(monitor_stop_reason, "daemon not running", sizeof("daemon not running")); \
|
||||||
|
ptrace(PTRACE_INTERRUPT, 1, 0, 0); \
|
||||||
|
\
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
struct SigChldHandler : public EventHandler {
|
struct SigChldHandler : public EventHandler {
|
||||||
private:
|
private:
|
||||||
int signal_fd_;
|
int signal_fd_;
|
||||||
struct signalfd_siginfo fdsi;
|
struct signalfd_siginfo fdsi;
|
||||||
int status;
|
int status;
|
||||||
std::set<pid_t> process;
|
std::set<pid_t> process;
|
||||||
public:
|
|
||||||
|
public:
|
||||||
bool Init() {
|
bool Init() {
|
||||||
sigset_t mask;
|
sigset_t mask;
|
||||||
sigemptyset(&mask);
|
sigemptyset(&mask);
|
||||||
sigaddset(&mask, SIGCHLD);
|
sigaddset(&mask, SIGCHLD);
|
||||||
if (sigprocmask(SIG_BLOCK, &mask, nullptr) == -1) {
|
|
||||||
|
if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {
|
||||||
PLOGE("set sigprocmask");
|
PLOGE("set sigprocmask");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
signal_fd_ = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
|
signal_fd_ = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
|
||||||
if (signal_fd_ == -1) {
|
if (signal_fd_ == -1) {
|
||||||
PLOGE("create signalfd");
|
PLOGE("create signalfd");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptrace(PTRACE_SEIZE, 1, 0, PTRACE_O_TRACEFORK);
|
ptrace(PTRACE_SEIZE, 1, 0, PTRACE_O_TRACEFORK);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,137 +446,152 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HandleEvent(EventLoop &, uint32_t) override {
|
void HandleEvent(EventLoop &, uint32_t) override {
|
||||||
for (;;) {
|
while (1) {
|
||||||
ssize_t s = read(signal_fd_, &fdsi, sizeof(fdsi));
|
ssize_t s = read(signal_fd_, &fdsi, sizeof(fdsi));
|
||||||
if (s == -1) {
|
if (s == -1) {
|
||||||
if (errno == EAGAIN) break;
|
if (errno == EAGAIN) break;
|
||||||
|
|
||||||
PLOGE("read signalfd");
|
PLOGE("read signalfd");
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s != sizeof(fdsi)) {
|
if (s != sizeof(fdsi)) {
|
||||||
LOGW("read %zu != %zu", s, sizeof(fdsi));
|
LOGW("read %zu != %zu", s, sizeof(fdsi));
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fdsi.ssi_signo != SIGCHLD) {
|
if (fdsi.ssi_signo != SIGCHLD) {
|
||||||
LOGW("no sigchld received");
|
LOGW("no sigchld received");
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pid;
|
int pid;
|
||||||
while ((pid = waitpid(-1, &status, __WALL | WNOHANG)) != 0) {
|
while ((pid = waitpid(-1, &status, __WALL | WNOHANG)) != 0) {
|
||||||
if (pid == -1) {
|
if (pid == -1) {
|
||||||
if (tracing_state == STOPPED && errno == ECHILD) break;
|
if (tracing_state == STOPPED && errno == ECHILD) break;
|
||||||
PLOGE("waitpid");
|
PLOGE("waitpid");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pid == 1) {
|
if (pid == 1) {
|
||||||
if (STOPPED_WITH(SIGTRAP, PTRACE_EVENT_FORK)) {
|
if (STOPPED_WITH(SIGTRAP, PTRACE_EVENT_FORK)) {
|
||||||
long child_pid;
|
long child_pid;
|
||||||
|
|
||||||
ptrace(PTRACE_GETEVENTMSG, pid, 0, &child_pid);
|
ptrace(PTRACE_GETEVENTMSG, pid, 0, &child_pid);
|
||||||
|
|
||||||
LOGV("forked %ld", child_pid);
|
LOGV("forked %ld", child_pid);
|
||||||
} else if (STOPPED_WITH(SIGTRAP, PTRACE_EVENT_STOP) &&
|
} else if (STOPPED_WITH(SIGTRAP, PTRACE_EVENT_STOP) && tracing_state == STOPPING) {
|
||||||
tracing_state == STOPPING) {
|
if (ptrace(PTRACE_DETACH, 1, 0, 0) == -1) PLOGE("failed to detach init");
|
||||||
if (ptrace(PTRACE_DETACH, 1, 0, 0) == -1)
|
|
||||||
PLOGE("failed to detach init");
|
|
||||||
tracing_state = STOPPED;
|
tracing_state = STOPPED;
|
||||||
|
|
||||||
LOGI("stop tracing init");
|
LOGI("stop tracing init");
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WIFSTOPPED(status)) {
|
if (WIFSTOPPED(status)) {
|
||||||
if (WPTEVENT(status) == 0) {
|
if (WPTEVENT(status) == 0) {
|
||||||
if (WSTOPSIG(status) != SIGSTOP && WSTOPSIG(status) != SIGTSTP && WSTOPSIG(status) != SIGTTIN && WSTOPSIG(status) != SIGTTOU) {
|
if (WSTOPSIG(status) != SIGSTOP && WSTOPSIG(status) != SIGTSTP && WSTOPSIG(status) != SIGTTIN && WSTOPSIG(status) != SIGTTOU) {
|
||||||
LOGW("inject signal sent to init: %s %d",
|
LOGW("inject signal sent to init: %s %d", sigabbrev_np(WSTOPSIG(status)), WSTOPSIG(status));
|
||||||
sigabbrev_np(WSTOPSIG(status)), WSTOPSIG(status));
|
|
||||||
ptrace(PTRACE_CONT, pid, 0, WSTOPSIG(status));
|
ptrace(PTRACE_CONT, pid, 0, WSTOPSIG(status));
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
LOGW("suppress stopping signal sent to init: %s %d",
|
LOGW("suppress stopping signal sent to init: %s %d", sigabbrev_np(WSTOPSIG(status)), WSTOPSIG(status));
|
||||||
sigabbrev_np(WSTOPSIG(status)), WSTOPSIG(status));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ptrace(PTRACE_CONT, pid, 0, 0);
|
ptrace(PTRACE_CONT, pid, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
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_error_info.empty()) { \
|
|
||||||
status##abi.daemon_error_info = status_str; \
|
|
||||||
} \
|
|
||||||
updateStatus(); \
|
|
||||||
continue; \
|
|
||||||
}
|
|
||||||
CHECK_DAEMON_EXIT(64)
|
CHECK_DAEMON_EXIT(64)
|
||||||
CHECK_DAEMON_EXIT(32)
|
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);
|
||||||
|
|
||||||
process.emplace(pid);
|
process.emplace(pid);
|
||||||
|
|
||||||
ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACEEXEC);
|
ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACEEXEC);
|
||||||
ptrace(PTRACE_CONT, pid, 0, 0);
|
ptrace(PTRACE_CONT, pid, 0, 0);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
if (STOPPED_WITH(SIGTRAP, PTRACE_EVENT_EXEC)) {
|
if (STOPPED_WITH(SIGTRAP, PTRACE_EVENT_EXEC)) {
|
||||||
auto program = get_program(pid);
|
char program[PATH_MAX];
|
||||||
LOGV("%d program %s", pid, program.c_str());
|
if (get_program(pid, program, sizeof(program)) == -1) {
|
||||||
const char* tracer = nullptr;
|
LOGW("failed to get program %d", pid);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGV("%d program %s", pid, program);
|
||||||
|
const char* tracer = NULL;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (tracing_state != TRACING) {
|
if (tracing_state != TRACING) {
|
||||||
LOGW("stop injecting %d because not tracing", pid);
|
LOGW("stop injecting %d because not tracing", pid);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#define PRE_INJECT(abi, is_64) \
|
|
||||||
if (program == "/system/bin/app_process"#abi) { \
|
|
||||||
tracer = "./bin/zygisk-ptrace"#abi; \
|
|
||||||
if (should_stop_inject##abi()) { \
|
|
||||||
LOGW("zygote" #abi " restart too much times, stop injecting"); \
|
|
||||||
tracing_state = STOPPING; \
|
|
||||||
monitor_stop_reason = "zygote crashed"; \
|
|
||||||
ptrace(PTRACE_INTERRUPT, 1, 0, 0); \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
if (!ensure_daemon_created(is_64)) { \
|
|
||||||
LOGW("daemon" #abi " not running, stop injecting"); \
|
|
||||||
tracing_state = STOPPING; \
|
|
||||||
monitor_stop_reason = "daemon not running"; \
|
|
||||||
ptrace(PTRACE_INTERRUPT, 1, 0, 0); \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
PRE_INJECT(64, true)
|
PRE_INJECT(64, true)
|
||||||
PRE_INJECT(32, false)
|
PRE_INJECT(32, false)
|
||||||
if (tracer != nullptr) {
|
|
||||||
|
if (tracer != NULL) {
|
||||||
LOGD("stopping %d", pid);
|
LOGD("stopping %d", pid);
|
||||||
|
|
||||||
kill(pid, SIGSTOP);
|
kill(pid, SIGSTOP);
|
||||||
ptrace(PTRACE_CONT, pid, 0, 0);
|
ptrace(PTRACE_CONT, pid, 0, 0);
|
||||||
waitpid(pid, &status, __WALL);
|
waitpid(pid, &status, __WALL);
|
||||||
|
|
||||||
if (STOPPED_WITH(SIGSTOP, 0)) {
|
if (STOPPED_WITH(SIGSTOP, 0)) {
|
||||||
LOGD("detaching %d", pid);
|
LOGD("detaching %d", pid);
|
||||||
|
|
||||||
ptrace(PTRACE_DETACH, pid, 0, SIGSTOP);
|
ptrace(PTRACE_DETACH, pid, 0, SIGSTOP);
|
||||||
status = 0;
|
status = 0;
|
||||||
auto p = fork_dont_care();
|
auto p = fork_dont_care();
|
||||||
|
|
||||||
if (p == 0) {
|
if (p == 0) {
|
||||||
execl(tracer, basename(tracer), "trace",
|
char pid_str[32];
|
||||||
std::to_string(pid).c_str(), "--restart", nullptr);
|
sprintf(pid_str, "%d", pid);
|
||||||
|
|
||||||
|
execl(tracer, basename(tracer), "trace", pid_str, "--restart", NULL);
|
||||||
|
|
||||||
PLOGE("failed to exec, kill");
|
PLOGE("failed to exec, kill");
|
||||||
|
|
||||||
kill(pid, SIGKILL);
|
kill(pid, SIGKILL);
|
||||||
exit(1);
|
exit(1);
|
||||||
} else if (p == -1) {
|
} else if (p == -1) {
|
||||||
PLOGE("failed to fork, kill");
|
PLOGE("failed to fork, kill");
|
||||||
|
|
||||||
kill(pid, SIGKILL);
|
kill(pid, SIGKILL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (false);
|
} while (false);
|
||||||
|
|
||||||
updateStatus();
|
updateStatus();
|
||||||
} else {
|
} else {
|
||||||
LOGW("process %d received unknown status %s", pid,
|
char status_str[64];
|
||||||
parse_status(status).c_str());
|
parse_status(status, status_str, sizeof(status_str));
|
||||||
|
|
||||||
|
LOGW("process %d received unknown status %s", pid, status_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
process.erase(state);
|
process.erase(state);
|
||||||
if (WIFSTOPPED(status)) {
|
if (WIFSTOPPED(status)) {
|
||||||
LOGV("detach process %d", pid);
|
LOGV("detach process %d", pid);
|
||||||
|
|
||||||
ptrace(PTRACE_DETACH, pid, 0, 0);
|
ptrace(PTRACE_DETACH, pid, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -490,119 +604,145 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string pre_section;
|
static char pre_section[1024];
|
||||||
static std::string post_section;
|
static char post_section[1024];
|
||||||
|
|
||||||
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) \
|
#define WRITE_STATUS_ABI(suffix) \
|
||||||
if (status##suffix.supported) { \
|
if (status ## suffix.supported) { \
|
||||||
status_text += " zygote" #suffix ":"; \
|
strcat(status_text, " zygote" #suffix ":"); \
|
||||||
if (tracing_state != TRACING) status_text += "❓unknown,"; \
|
\
|
||||||
else if (status##suffix.zygote_injected) status_text += "😋injected,"; \
|
if (tracing_state != TRACING) strcat(status_text, "❓ unknown,"); \
|
||||||
else status_text += "❌not injected,"; \
|
else if (status##suffix.zygote_injected) strcat(status_text, "😋 injected,"); \
|
||||||
status_text += " daemon" #suffix ":"; \
|
else strcat(status_text, "❌ not injected,"); \
|
||||||
if (status##suffix.daemon_running) { \
|
\
|
||||||
status_text += "😋running"; \
|
strcat(status_text, " daemon" #suffix ":"); \
|
||||||
if (!status##suffix.daemon_info.empty()) { \
|
if (status ## suffix .daemon_running) { \
|
||||||
status_text += "("; \
|
strcat(status_text, "😋 running"); \
|
||||||
status_text += status##suffix.daemon_info; \
|
\
|
||||||
status_text += ")"; \
|
if (status ## suffix.daemon_info[0] != '\0') { \
|
||||||
|
strcat(status_text, "("); \
|
||||||
|
strcat(status_text, status ## suffix.daemon_info); \
|
||||||
|
strcat(status_text, ")"); \
|
||||||
} \
|
} \
|
||||||
} else { \
|
} else { \
|
||||||
status_text += "❌crashed"; \
|
strcat(status_text, "❌ crashed"); \
|
||||||
if (!status##suffix.daemon_error_info.empty()) { \
|
\
|
||||||
status_text += "("; \
|
if (status ## suffix.daemon_error_info[0] != '\0') { \
|
||||||
status_text += status##suffix.daemon_error_info; \
|
strcat(status_text, "("); \
|
||||||
status_text += ")"; \
|
strcat(status_text, status ## suffix.daemon_error_info); \
|
||||||
|
strcat(status_text, ")"); \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void updateStatus() {
|
||||||
|
FILE *prop = fopen(prop_path, "w");
|
||||||
|
char status_text[64] = "monitor: ";
|
||||||
|
|
||||||
|
switch (tracing_state) {
|
||||||
|
case TRACING: {
|
||||||
|
strcat(status_text, "😋 tracing");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case STOPPING: {
|
||||||
|
[[fallthrough]];
|
||||||
|
}
|
||||||
|
case STOPPED: {
|
||||||
|
strcat(status_text, "❌ stopped");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EXITING: {
|
||||||
|
strcat(status_text, "❌ exited");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tracing_state != TRACING && monitor_stop_reason[0] != '\0') {
|
||||||
|
size_t status_text_len = strlen(status_text);
|
||||||
|
snprintf(status_text + status_text_len, sizeof(status_text) - status_text_len, "(%s)", monitor_stop_reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
strcat(status_text, ", ");
|
||||||
|
|
||||||
WRITE_STATUS_ABI(64)
|
WRITE_STATUS_ABI(64)
|
||||||
WRITE_STATUS_ABI(32)
|
WRITE_STATUS_ABI(32)
|
||||||
fprintf(prop.get(), "%s[%s] %s", pre_section.c_str(), status_text.c_str(), post_section.c_str());
|
|
||||||
|
fprintf(prop, "%s[%s] %s", pre_section, status_text, post_section);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool prepare_environment() {
|
static bool prepare_environment() {
|
||||||
prop_path = zygiskd::GetTmpPath() + "/module.prop";
|
strcat(prop_path, zygiskd::GetTmpPath().c_str());
|
||||||
close(open(prop_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644));
|
strcat(prop_path, "/module.prop");
|
||||||
auto orig_prop = xopen_file("./module.prop", "r");
|
|
||||||
if (orig_prop == nullptr) {
|
close(open(prop_path, O_WRONLY | O_CREAT | O_TRUNC, 0644));
|
||||||
|
|
||||||
|
FILE *orig_prop = fopen("./module.prop", "r");
|
||||||
|
if (orig_prop == NULL) {
|
||||||
PLOGE("failed to open orig prop");
|
PLOGE("failed to open orig prop");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool post = false;
|
|
||||||
file_readline(false, orig_prop.get(), [&](std::string_view line) -> bool {
|
char line[1024];
|
||||||
if (line.starts_with("description=")) {
|
ssize_t len = fread(line, 1, sizeof(line), orig_prop);
|
||||||
post = true;
|
/* TODO: Check if this part translation is correct.
|
||||||
pre_section += "description=";
|
Old approach may be a callback approach that gets called
|
||||||
post_section += line.substr(sizeof("description"));
|
every new line
|
||||||
|
*/
|
||||||
|
if ((unsigned long)len > (sizeof("description") - 1) && strncmp(line, "description=", sizeof("description") - 1) == 0) {
|
||||||
|
strcat(post_section, "description=");
|
||||||
|
strcat(post_section, line + sizeof("description"));
|
||||||
} else {
|
} else {
|
||||||
if (post) {
|
strcat(pre_section, line);
|
||||||
post_section += line;
|
|
||||||
} else {
|
|
||||||
pre_section += line;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
updateStatus();
|
updateStatus();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_monitor() {
|
void init_monitor() {
|
||||||
LOGI("ReZygisk %s", ZKSU_VERSION);
|
LOGI("ReZygisk %s", ZKSU_VERSION);
|
||||||
LOGI("init monitor started");
|
LOGI("init monitor started");
|
||||||
if (!prepare_environment()) {
|
|
||||||
exit(1);
|
if (!prepare_environment()) exit(1);
|
||||||
}
|
|
||||||
SocketHandler socketHandler{};
|
SocketHandler socketHandler{};
|
||||||
socketHandler.Init();
|
socketHandler.Init();
|
||||||
SigChldHandler ptraceHandler{};
|
SigChldHandler ptraceHandler{};
|
||||||
ptraceHandler.Init();
|
ptraceHandler.Init();
|
||||||
EventLoop looper;
|
EventLoop looper;
|
||||||
|
|
||||||
looper.Init();
|
looper.Init();
|
||||||
looper.RegisterHandler(socketHandler, EPOLLIN | EPOLLET);
|
looper.RegisterHandler(socketHandler, EPOLLIN | EPOLLET);
|
||||||
looper.RegisterHandler(ptraceHandler, EPOLLIN | EPOLLET);
|
looper.RegisterHandler(ptraceHandler, EPOLLIN | EPOLLET);
|
||||||
looper.Loop();
|
looper.Loop();
|
||||||
|
|
||||||
LOGI("exit");
|
LOGI("exit");
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_control_command(Command cmd) {
|
void send_control_command(enum Command cmd) {
|
||||||
int sockfd = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
|
int sockfd = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
|
||||||
if (sockfd == -1) err(EXIT_FAILURE, "socket");
|
if (sockfd == -1) err(EXIT_FAILURE, "socket");
|
||||||
struct sockaddr_un addr{
|
|
||||||
|
struct sockaddr_un addr = {
|
||||||
.sun_family = AF_UNIX,
|
.sun_family = AF_UNIX,
|
||||||
.sun_path={0},
|
.sun_path = { 0 }
|
||||||
};
|
};
|
||||||
sprintf(addr.sun_path, "%s/%s", zygiskd::GetTmpPath().c_str(), SOCKET_NAME);
|
|
||||||
socklen_t socklen = sizeof(sa_family_t) + strlen(addr.sun_path);
|
size_t sun_path_len = snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", zygiskd::GetTmpPath().c_str(), SOCKET_NAME);
|
||||||
auto nsend = sendto(sockfd, (void *) &cmd, sizeof(cmd), 0, (sockaddr *) &addr, socklen);
|
socklen_t socklen = sizeof(sa_family_t) + sun_path_len;
|
||||||
if (nsend == -1) {
|
|
||||||
err(EXIT_FAILURE, "send");
|
ssize_t nsend = sendto(sockfd, (void *)&cmd, sizeof(cmd), 0, (sockaddr *)&addr, socklen);
|
||||||
} else if (nsend != sizeof(cmd)) {
|
if (nsend == -1) err(EXIT_FAILURE, "send");
|
||||||
printf("send %zu != %zu\n", nsend, sizeof(cmd));
|
else if (nsend != sizeof(cmd)) {
|
||||||
|
printf("[ReZygisk]: Failed to send data. Tried to send %zu bytes but only %zu were sent.\n", sizeof(cmd), nsend);
|
||||||
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
printf("command sent\n");
|
|
||||||
|
printf("[ReZygisk]: command sent\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,7 +161,10 @@ bool inject_on_main(int pid, const char *lib_path) {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
LOGE("stopped by other reason: %s", parse_status(status).c_str());
|
char status_str[64];
|
||||||
|
parse_status(status, status_str, sizeof(status_str));
|
||||||
|
|
||||||
|
LOGE("stopped by other reason: %s", status_str);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -205,12 +208,18 @@ bool trace_zygote(int pid) {
|
|||||||
ptrace(PTRACE_DETACH, pid, 0, SIGCONT);
|
ptrace(PTRACE_DETACH, pid, 0, SIGCONT);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOGE("unknown state %s, not SIGTRAP + EVENT_STOP", parse_status(status).c_str());
|
char status_str[64];
|
||||||
|
parse_status(status, status_str, sizeof(status_str));
|
||||||
|
|
||||||
|
LOGE("unknown state %s, not SIGTRAP + EVENT_STOP", status_str);
|
||||||
ptrace(PTRACE_DETACH, pid, 0, 0);
|
ptrace(PTRACE_DETACH, pid, 0, 0);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOGE("unknown state %s, not SIGSTOP + EVENT_STOP", parse_status(status).c_str());
|
char status_str[64];
|
||||||
|
parse_status(status, status_str, sizeof(status_str));
|
||||||
|
|
||||||
|
LOGE("unknown state %s, not SIGSTOP + EVENT_STOP", status_str);
|
||||||
ptrace(PTRACE_DETACH, pid, 0, 0);
|
ptrace(PTRACE_DETACH, pid, 0, 0);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -359,7 +359,10 @@ uintptr_t remote_call(int pid, struct user_regs_struct ®s, uintptr_t func_add
|
|||||||
}
|
}
|
||||||
return regs.REG_RET;
|
return regs.REG_RET;
|
||||||
} else {
|
} else {
|
||||||
LOGE("stopped by other reason %s at addr %p", parse_status(status).c_str(), (void*) regs.REG_IP);
|
char status_str[64];
|
||||||
|
parse_status(status, status_str, sizeof(status_str));
|
||||||
|
|
||||||
|
LOGE("stopped by other reason %s at addr %p", status_str, (void*) regs.REG_IP);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -394,42 +397,45 @@ void wait_for_trace(int pid, int* status, int flags) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!WIFSTOPPED(*status)) {
|
if (!WIFSTOPPED(*status)) {
|
||||||
LOGE("process %d not stopped for trace: %s, exit", pid, parse_status(*status).c_str());
|
char status_str[64];
|
||||||
|
parse_status(*status, status_str, sizeof(status_str));
|
||||||
|
|
||||||
|
LOGE("process %d not stopped for trace: %s, exit", pid, status_str);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string parse_status(int status) {
|
void parse_status(int status, char *buf, size_t len) {
|
||||||
std::ostringstream os;
|
snprintf(buf, len, "0x%x ", status);
|
||||||
os << "0x" << std::hex << status << std::dec << " ";
|
|
||||||
if (WIFEXITED(status)) {
|
if (WIFEXITED(status)) {
|
||||||
os << "exited with " << WEXITSTATUS(status);
|
snprintf(buf + strlen(buf), len - strlen(buf), "exited with %d", WEXITSTATUS(status));
|
||||||
} else if (WIFSIGNALED(status)) {
|
} else if (WIFSIGNALED(status)) {
|
||||||
os << "signaled with " << sigabbrev_np(WTERMSIG(status)) << "(" << WTERMSIG(status) << ")";
|
snprintf(buf + strlen(buf), len - strlen(buf), "signaled with %s(%d)", sigabbrev_np(WTERMSIG(status)), WTERMSIG(status));
|
||||||
} else if (WIFSTOPPED(status)) {
|
} else if (WIFSTOPPED(status)) {
|
||||||
os << "stopped by ";
|
snprintf(buf + strlen(buf), len - strlen(buf), "stopped by ");
|
||||||
auto stop_sig = WSTOPSIG(status);
|
auto stop_sig = WSTOPSIG(status);
|
||||||
os << "signal=" << sigabbrev_np(stop_sig) << "(" << stop_sig << "),";
|
snprintf(buf + strlen(buf), len - strlen(buf), "signal=%s(%d),", sigabbrev_np(stop_sig), stop_sig);
|
||||||
os << "event=" << parse_ptrace_event(status);
|
snprintf(buf + strlen(buf), len - strlen(buf), "event=%s", parse_ptrace_event(status));
|
||||||
} else {
|
} else {
|
||||||
os << "unknown";
|
snprintf(buf + strlen(buf), len - strlen(buf), "unknown");
|
||||||
}
|
}
|
||||||
return os.str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_program(int pid) {
|
int get_program(int pid, char *buf, size_t size) {
|
||||||
std::string path = "/proc/";
|
char path[64];
|
||||||
path += std::to_string(pid);
|
snprintf(path, sizeof(path), "/proc/%d/exe", pid);
|
||||||
path += "/exe";
|
|
||||||
constexpr const auto SIZE = 256;
|
ssize_t sz = readlink(path, buf, size);
|
||||||
char buf[SIZE + 1];
|
|
||||||
auto sz = readlink(path.c_str(), buf, SIZE);
|
|
||||||
if (sz == -1) {
|
if (sz == -1) {
|
||||||
PLOGE("readlink /proc/%d/exe", pid);
|
PLOGE("readlink /proc/%d/exe", pid);
|
||||||
return "";
|
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[sz] = 0;
|
buf[sz] = 0;
|
||||||
return buf;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ int fork_dont_care();
|
|||||||
|
|
||||||
void wait_for_trace(int pid, int* status, int flags);
|
void wait_for_trace(int pid, int* status, int flags);
|
||||||
|
|
||||||
std::string parse_status(int status);
|
void parse_status(int status, char *buf, size_t len);
|
||||||
|
|
||||||
#define WPTEVENT(x) (x >> 16)
|
#define WPTEVENT(x) (x >> 16)
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ inline const char* sigabbrev_np(int sig) {
|
|||||||
return "(unknown)";
|
return "(unknown)";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_program(int pid);
|
int get_program(int pid, char *buf, size_t size);
|
||||||
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 fd
|
||||||
|
|||||||
Reference in New Issue
Block a user