init-sigstop-based ptrace zygisk

This commit is contained in:
5ec1cff
2023-10-31 17:18:56 +08:00
parent c249ebe22c
commit f78c217552
16 changed files with 795 additions and 492 deletions

View File

@@ -13,4 +13,9 @@ add_library(zygisk SHARED ${INJECTOR_SRC_LIST})
target_include_directories(zygisk PRIVATE include)
target_link_libraries(zygisk cxx::cxx log common lsplt_static phmap)
aux_source_directory(ptracer PTRACER_SRC_LIST)
add_executable(libptracer.so ${PTRACER_SRC_LIST})
target_include_directories(libptracer.so PRIVATE include)
target_link_libraries(libptracer.so cxx::cxx log common)
add_subdirectory(external)

View File

@@ -284,6 +284,14 @@ DCL_HOOK_FUNC(int, pthread_attr_destroy, void *target) {
return res;
}
DCL_HOOK_FUNC(char *, strdup, const char *s) {
if (s == "com.android.internal.os.ZygoteInit"sv) {
LOGD("strdup %s\n", s);
replace_jni_methods();
}
return old_strdup(s);
}
#undef DCL_HOOK_FUNC
// -----------------------------------------------------------------
@@ -762,6 +770,7 @@ void hook_functions() {
PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, fork);
PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, unshare);
PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, strdup);
PLT_HOOK_REGISTER_SYM(android_runtime_dev, android_runtime_inode, "__android_log_close", android_log_close);
hook_commit();
@@ -770,8 +779,6 @@ void hook_functions() {
std::remove_if(plt_hook_list->begin(), plt_hook_list->end(),
[](auto &t) { return *std::get<3>(t) == nullptr;}),
plt_hook_list->end());
replace_jni_methods();
}
static void hook_unloader() {

View File

@@ -0,0 +1,22 @@
#include <cstdio>
#include <cstdlib>
#include <string_view>
#include <unistd.h>
#include "main.hpp"
#include "utils.hpp"
using namespace std::string_view_literals;
int main(int argc, char **argv) {
if (argc >= 2 && argv[1] == "prop_monitor"sv) {
if (access("/system/lib" LP_SELECT("", "64"), R_OK) == 0) prop_monitor_main();
} else if (argc >= 3 && argv[1] == "trace-zygote"sv) {
auto pid = strtol(argv[2], nullptr, 0);
trace_zygote_main(pid);
} else {
if (argc >= 2) LOGE("unknown command %s", argv[1]);
else LOGE("no command specified");
}
return 0;
}

View File

@@ -0,0 +1,4 @@
#pragma once
void prop_monitor_main();
void trace_zygote_main(int pid);

View File

@@ -0,0 +1,37 @@
#include <sys/system_properties.h>
#include <unistd.h>
#include "main.hpp"
#include "utils.hpp"
void prop_monitor_main() {
LOGI("prop monitor started");
// if service is not running, pid = ""
auto name = "init.svc_debug_pid." LP_SELECT("zygote_secondary", "zygote"); // argv[1];
LOGI("start monitoring %s", name);
auto prop = __system_property_find(name);
if (prop == nullptr) {
__system_property_set(name, "");
prop = __system_property_find(name);
if (prop == nullptr) {
LOGE("failed to create prop");
exit(1);
}
}
char val[PROP_VALUE_MAX];
uint32_t new_serial = 0;
while (true) {
__system_property_wait(prop, new_serial, &new_serial, nullptr);
__system_property_get(name, val);
LOGD("%s(%u): %s\n", name, new_serial, val);
auto pid = strtol(val, nullptr, 0);
if (pid != 0) {
LOGD("start ptrace %ld", pid);
if (fork_dont_care() == 0) {
execl("/proc/self/exe", "zygisk-ptracer", "trace-zygote", val, nullptr);
PLOGE("failed to exec");
exit(1);
}
}
}
}

View File

@@ -0,0 +1,200 @@
#include <sys/ptrace.h>
#include <unistd.h>
#include <sys/uio.h>
#include <sys/auxv.h>
#include <elf.h>
#include <link.h>
#include <vector>
#include <string>
#include <sys/mman.h>
#include <sys/wait.h>
#include <cstdlib>
#include <cstdio>
#include <dlfcn.h>
#include <signal.h>
#include <sys/system_properties.h>
#include <string>
#include "utils.hpp"
bool inject_on_main(int pid, const char *lib_path) {
// parsing KernelArgumentBlock
// https://cs.android.com/android/platform/superproject/main/+/main:bionic/libc/private/KernelArgumentBlock.h;l=30;drc=6d1ee77ee32220e4202c3066f7e1f69572967ad8
struct user_regs_struct regs{}, backup{};
auto map = MapInfo::Scan(std::to_string(pid));
if (!get_regs(pid, regs)) return false;
auto arg = reinterpret_cast<uintptr_t *>(regs.REG_SP);
LOGD("kernel argument %p %s", arg, get_addr_mem_region(map, arg).c_str());
int argc;
auto argv = reinterpret_cast<char **>(reinterpret_cast<uintptr_t *>(arg) + 1);
LOGD("argv %p", argv);
read_proc(pid, arg, &argc, sizeof(argc));
LOGD("argc %d", argc);
auto envp = argv + argc + 1;
LOGD("envp %p", envp);
auto p = envp;
while (true) {
uintptr_t *buf;
read_proc(pid, (uintptr_t *) p, &buf, sizeof(buf));
if (buf != nullptr) ++p;
else break;
}
++p;
auto auxv = reinterpret_cast<ElfW(auxv_t) *>(p);
LOGD("auxv %p %s", auxv, get_addr_mem_region(map, auxv).c_str());
auto v = auxv;
void *entry_addr = nullptr;
void *addr_of_entry_addr = nullptr;
while (true) {
ElfW(auxv_t) buf;
read_proc(pid, (uintptr_t *) v, &buf, sizeof(buf));
if (buf.a_type == AT_ENTRY) {
entry_addr = reinterpret_cast<void *>(buf.a_un.a_val);
addr_of_entry_addr = reinterpret_cast<char *>(v) + offsetof(ElfW(auxv_t), a_un);
LOGD("entry address %p %s (v=%p, entry_addr=%p)", entry_addr,
get_addr_mem_region(map, entry_addr).c_str(), v, addr_of_entry_addr);
break;
}
if (buf.a_type == AT_NULL) break;
v++;
}
if (entry_addr == nullptr) {
LOGE("failed to get entry");
return false;
}
// Replace the program entry with an invalid address
// For arm32 compatibility, we set the last bit to the same as the entry address
uintptr_t break_addr = (-0x05ec1cff & ~1) | ((uintptr_t) entry_addr & 1);
if (!write_proc(pid, (uintptr_t *) addr_of_entry_addr, &break_addr, sizeof(break_addr))) return false;
ptrace(PTRACE_CONT, pid, 0, 0);
int status;
if (waitpid(pid, &status, __WALL) == -1) {
PLOGE("wait");
return false;
}
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGSEGV) {
if (!get_regs(pid, regs)) return false;
if (regs.REG_IP != break_addr) {
LOGE("stopped at unknown addr %p", (void *) regs.REG_IP);
return false;
}
// The linker has been initialized now, we can do dlopen
LOGD("stopped at entry");
// restore entry address
if (!write_proc(pid, (uintptr_t *) addr_of_entry_addr, &entry_addr, sizeof(entry_addr))) return false;
// backup registers
memcpy(&backup, &regs, sizeof(regs));
map = MapInfo::Scan(std::to_string(pid));
auto local_map = MapInfo::Scan();
auto libc_base = find_module_base(map, "libc.so");
// call dlopen
auto dlopen_addr = find_func_addr(local_map, map, "libdl.so", "dlopen");
if (dlopen_addr == nullptr) return false;
std::vector<long> args;
auto str = push_string(pid, regs, lib_path);
args.clear();
args.push_back((long) str);
args.push_back((long) RTLD_NOW);
auto remote_handle = remote_call(pid, regs, (uintptr_t) dlopen_addr, (uintptr_t) libc_base, args);
LOGD("remote handle %p", (void *) remote_handle);
if (remote_handle == 0) {
LOGE("handle is null");
return false;
}
// call dlsym(handle, "entry")
auto dlsym_addr = find_func_addr(local_map, map, "libdl.so", "dlsym");
if (dlsym_addr == nullptr) return false;
args.clear();
str = push_string(pid, regs, "entry");
args.push_back(remote_handle);
args.push_back((long) str);
auto injector_entry = remote_call(pid, regs, (uintptr_t) dlsym_addr, (uintptr_t) libc_base, args);
LOGD("injector entry %p", (void*) injector_entry);
if (injector_entry == 0) {
LOGE("injector entry is null");
return false;
}
// call injector entry(handle)
args.clear();
args.push_back(remote_handle);
remote_call(pid, regs, injector_entry, (uintptr_t) libc_base, args);
// reset pc to entry
backup.REG_IP = (long) entry_addr;
LOGD("invoke entry");
// restore registers
if (!set_regs(pid, backup)) return false;
return true;
/*
ptrace(PTRACE_CONT, pid, 0, 0);
waitpid(pid, &status, __WALL);
if (WIFSTOPPED(status)) {
siginfo_t siginfo;
ptrace(PTRACE_GETSIGINFO, pid, 0, &siginfo);
LOGD("process stopped by signal %d %s si_code=%d si_addr=%p", WSTOPSIG(status),
strsignal(WSTOPSIG(status)), siginfo.si_code, siginfo.si_addr);
pause();
} else {
LOGD("other reason %d", status);
}*/
} else {
LOGE("stopped by other reason: %d", status);
}
return false;
}
#define STOPPED_WITH(sig, event) (WIFSTOPPED(status) && WSTOPSIG(status) == (sig) && (status >> 16) == (event))
void trace_zygote_main(int pid) {
int status;
LOGI("tracing %d (tracer %d)", pid, getpid());
if (ptrace(PTRACE_SEIZE, pid, 0, PTRACE_O_TRACEEXEC) == -1) {
PLOGE("seize");
return;
}
wait_pid(pid, &status, __WALL);
if (STOPPED_WITH(SIGSTOP, PTRACE_EVENT_STOP)) {
// if SIGSTOP is delivered before we seized it
LOGD("process is already stopped");
kill(pid, SIGCONT);
ptrace(PTRACE_CONT, pid, 0, 0);
wait_pid(pid, &status, __WALL);
if (STOPPED_WITH(SIGTRAP, PTRACE_EVENT_STOP)) {
ptrace(PTRACE_CONT, pid, 0, 0);
wait_pid(pid, &status, __WALL);
if (STOPPED_WITH(SIGCONT, 0)) {
LOGD("received SIGCONT");
ptrace(PTRACE_CONT, pid, 0, 0);
}
} else {
LOGE("unknown state %s, not SIGTRAP + EVENT_STOP", parse_status(status).c_str());
}
} else if (STOPPED_WITH(SIGSTOP, 0)) {
// if SIGSTOP is delivered after we seized it
LOGD("process received SIGSTOP, suppress");
ptrace(PTRACE_CONT, pid, 0, 0);
} else {
LOGE("unknown state %s, neither EVENT_STOP nor SIGSTOP", parse_status(status).c_str());
exit(1);
}
wait_pid(pid, &status, __WALL);
// enter the app_process
if (STOPPED_WITH(SIGTRAP, PTRACE_EVENT_EXEC)) {
LOGD("app_process exec-ed");
if (!inject_on_main(pid, "/dev/zygisk/lib" LP_SELECT("", "64") "/libzygisk.so")) {
LOGE("failed to inject");
exit(1);
}
} else {
LOGE("unknown status %d", status);
exit(1);
}
ptrace(PTRACE_DETACH, pid, 0, 0);
}

View File

@@ -0,0 +1,362 @@
#include <vector>
#include <sys/mman.h>
#include <sys/sysmacros.h>
#include <array>
#include <cinttypes>
#include <sys/ptrace.h>
#include <unistd.h>
#include <sys/uio.h>
#include <sys/auxv.h>
#include <elf.h>
#include <link.h>
#include <vector>
#include <string>
#include <sys/mman.h>
#include <sys/wait.h>
#include <cstdlib>
#include <cstdio>
#include <dlfcn.h>
#include <signal.h>
#include <sstream>
#include <ios>
#include <cstring>
#include "utils.hpp"
#include "logging.h"
std::vector<MapInfo> MapInfo::Scan(const std::string& pid) {
constexpr static auto kPermLength = 5;
constexpr static auto kMapEntry = 7;
std::vector<MapInfo> info;
std::string file_name = std::string("/proc/") + pid + "/maps";
auto maps = std::unique_ptr<FILE, decltype(&fclose)>{fopen(file_name.c_str(), "r"), &fclose};
if (maps) {
char *line = nullptr;
size_t len = 0;
ssize_t read;
while ((read = getline(&line, &len, maps.get())) > 0) {
line[read - 1] = '\0';
uintptr_t start = 0;
uintptr_t end = 0;
uintptr_t off = 0;
ino_t inode = 0;
unsigned int dev_major = 0;
unsigned int dev_minor = 0;
std::array<char, kPermLength> perm{'\0'};
int path_off;
if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %4s %" PRIxPTR " %x:%x %lu %n%*s", &start,
&end, perm.data(), &off, &dev_major, &dev_minor, &inode,
&path_off) != kMapEntry) {
continue;
}
while (path_off < read && isspace(line[path_off])) path_off++;
auto &ref = info.emplace_back(MapInfo{start, end, 0, perm[3] == 'p', off,
static_cast<dev_t>(makedev(dev_major, dev_minor)),
inode, line + path_off});
if (perm[0] == 'r') ref.perms |= PROT_READ;
if (perm[1] == 'w') ref.perms |= PROT_WRITE;
if (perm[2] == 'x') ref.perms |= PROT_EXEC;
}
free(line);
}
return info;
}
ssize_t write_proc(int pid, uintptr_t *remote_addr, const void *buf, size_t len) {
LOGD("write to remote addr %p size %zu", remote_addr, len);
struct iovec local{
.iov_base = (void *) buf,
.iov_len = len
};
struct iovec remote{
.iov_base = (void *) remote_addr,
.iov_len = len
};
auto l = process_vm_writev(pid, &local, 1, &remote, 1, 0);
if (l == -1) {
PLOGE("process_vm_writev");
} else if (l != len) {
LOGW("not fully written: %zu, excepted %zu", l, len);
}
return l;
}
ssize_t read_proc(int pid, uintptr_t *remote_addr, void *buf, size_t len) {
struct iovec local{
.iov_base = (void *) buf,
.iov_len = len
};
struct iovec remote{
.iov_base = (void *) remote_addr,
.iov_len = len
};
auto l = process_vm_readv(pid, &local, 1, &remote, 1, 0);
if (l == -1) {
PLOGE("process_vm_readv");
} else if (l != len) {
LOGW("not fully read: %zu, excepted %zu", l, len);
}
return l;
}
bool get_regs(int pid, struct user_regs_struct &regs) {
#if defined(__x86_64__) || defined(__i386__)
if (ptrace(PTRACE_GETREGS, pid, 0, &regs) == -1) {
PLOGE("getregs");
return false;
}
#elif defined(__aarch64__) || defined(__arm__)
struct iovec iov = {
.iov_base = &regs,
.iov_len = sizeof(struct user_regs_struct),
};
if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov) == -1) {
PLOGE("getregs");
return false;
}
#endif
return true;
}
bool set_regs(int pid, struct user_regs_struct &regs) {
#if defined(__x86_64__) || defined(__i386__)
if (ptrace(PTRACE_SETREGS, pid, 0, &regs) == -1) {
PLOGE("setregs");
return false;
}
#elif defined(__aarch64__) || defined(__arm__)
struct iovec iov = {
.iov_base = &regs,
.iov_len = sizeof(struct user_regs_struct),
};
if (ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov) == -1) {
PLOGE("setregs");
return false;
}
#endif
return true;
}
std::string get_addr_mem_region(std::vector<MapInfo> &info, void *addr) {
for (auto &map: info) {
if (map.start <= (uintptr_t) addr && map.end > (uintptr_t) addr) {
auto s = std::string(map.path);
s += ' ';
s += map.perms & PROT_READ ? 'r' : '-';
s += map.perms & PROT_WRITE ? 'w' : '-';
s += map.perms & PROT_EXEC ? 'x' : '-';
return s;
}
}
return "<unknown>";
}
void *find_module_base(std::vector<MapInfo> &info, std::string_view suffix) {
for (auto &map: info) {
if (map.offset == 0 && map.path.ends_with(suffix)) {
return (void *) map.start;
}
}
return nullptr;
}
void *find_func_addr(
std::vector<MapInfo> &local_info,
std::vector<MapInfo> &remote_info,
std::string_view module,
std::string_view func) {
auto lib = dlopen(module.data(), RTLD_NOW);
if (lib == nullptr) {
LOGE("failed to open lib %s: %s", module.data(), dlerror());
return nullptr;
}
auto sym = reinterpret_cast<uint8_t *>(dlsym(lib, func.data()));
if (sym == nullptr) {
LOGE("failed to find sym %s in %s: %s", func.data(), module.data(), dlerror());
dlclose(lib);
return nullptr;
}
LOGD("sym %s: %p", func.data(), sym);
dlclose(lib);
auto local_base = reinterpret_cast<uint8_t *>(find_module_base(local_info, module));
if (local_base == nullptr) {
LOGE("failed to find local base for module %s", module.data());
return nullptr;
}
auto remote_base = reinterpret_cast<uint8_t *>(find_module_base(remote_info, module));
if (remote_base == nullptr) {
LOGE("failed to find remote base for module %s", module.data());
return nullptr;
}
LOGD("found local base %p remote base %p", local_base, remote_base);
auto addr = (sym - local_base) + remote_base;
LOGD("addr %p", addr);
return addr;
}
void align_stack(struct user_regs_struct &regs, long preserve) {
regs.REG_SP = (regs.REG_SP - preserve) & ~0xf;
}
void *push_string(int pid, struct user_regs_struct &regs, const char *str) {
auto len = strlen(str) + 1;
regs.REG_SP -= len;
align_stack(regs);
auto addr = reinterpret_cast<uintptr_t *>(regs.REG_SP);
if (!write_proc(pid, addr, str, len)) {
LOGE("failed to write string %s", str);
}
LOGD("pushed string %p", addr);
return addr;
}
uintptr_t remote_call(int pid, struct user_regs_struct &regs, uintptr_t func_addr, uintptr_t return_addr,
std::vector<long> &args) {
align_stack(regs);
LOGD("call %d args", args.size());
for (auto &a: args) {
LOGD("arg %p", (void *) a);
}
#if defined(__x86_64__)
if (args.size() >= 1) {
regs.rdi = args[0];
}
if (args.size() >= 2) {
regs.rsi = args[1];
}
if (args.size() >= 3) {
regs.rdx = args[2];
}
if (args.size() >= 4) {
regs.rcx = args[3];
}
if (args.size() >= 5) {
regs.r8 = args[4];
}
if (args.size() >= 6) {
regs.r9 = args[5];
}
if (args.size() > 6) {
auto remain = (args.size() - 6) * sizeof(long);
align_stack(regs, remain);
if (!write_proc(pid, (uintptr_t *) regs.REG_SP, args.data(), remain)) {
LOGE("failed to push arguments");
}
}
regs.REG_SP -= sizeof(long);
if (!write_proc(pid, (uintptr_t *) regs.REG_SP, &return_addr, sizeof(return_addr))) {
LOGE("failed to write return addr");
}
regs.REG_IP = func_addr;
#elif defined(__i386__)
if (args.size() > 0) {
auto remain = (args.size()) * sizeof(long);
align_stack(regs, remain);
if (!write_proc(pid, (uintptr_t *)regs.REG_SP, args.data(), remain)) {
LOGE("failed to push arguments");
}
}
regs.REG_SP -= sizeof(long);
if (!write_proc(pid, (uintptr_t*) regs.REG_SP, &return_addr, sizeof(return_addr))) {
LOGE("failed to write return addr");
}
regs.REG_IP = func_addr;
#elif defined(__aarch64__)
for (int i = 0; i < args.size() && i < 8; i++) {
regs.regs[i] = args[i];
}
if (args.size() > 8) {
auto remain = (args.size() - 8) * sizeof(long);
align_stack(regs, remain);
write_proc(pid, (uintptr_t *)regs.REG_SP, args.data(), remain);
}
regs.regs[30] = return_addr;
regs.REG_IP = func_addr;
#elif defined(__arm__)
for (int i = 0; i < args.size() && i < 4; i++) {
regs.uregs[i] = args[i];
}
if (args.size() > 4) {
auto remain = (args.size() - 4) * sizeof(long);
align_stack(regs, remain);
write_proc(pid, (uintptr_t *)regs.REG_SP, args.data(), remain);
}
regs.uregs[14] = return_addr;
regs.REG_IP = func_addr;
constexpr auto CPSR_T_MASK = 1lu << 5;
if ((regs.REG_IP & 1) != 0) {
regs.REG_IP = regs.REG_IP & ~1;
regs.uregs[16] = regs.uregs[16] | CPSR_T_MASK;
} else {
regs.uregs[16] = regs.uregs[16] & ~CPSR_T_MASK;
}
#endif
if (!set_regs(pid, regs)) {
LOGE("failed to set regs");
return 0;
}
ptrace(PTRACE_CONT, pid, 0, 0);
int status;
if (waitpid(pid, &status, __WALL) == -1) {
PLOGE("wait");
}
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGSEGV) {
if (!get_regs(pid, regs)) {
LOGE("failed to get regs after call");
return 0;
}
if (regs.REG_IP != return_addr) {
LOGE("wrong return addr %p", (void *) regs.REG_IP);
return 0;
}
return regs.REG_RET;
} else {
LOGE("stopped by other reason %d", status);
}
return 0;
}
int fork_dont_care() {
auto pid = fork();
if (pid < 0) {
PLOGE("fork 1");
} else if (pid == 0) {
pid = fork();
if (pid < 0) {
PLOGE("fork 2");
} else if (pid > 0) {
exit(0);
}
} else {
int status;
waitpid(pid, &status, __WALL);
}
return pid;
}
int wait_pid(int pid, int* status, int flags) {
while (true) {
auto result = waitpid(pid, status, flags);
if (result == -1 && errno == EINTR) continue;
return result;
}
}
std::string parse_status(int status) {
std::ostringstream os;
os << "status " << std::hex << status;
os << std::dec << " ";
if (WIFEXITED(status)) {
os << "exited with " << WEXITSTATUS(status);
} else if (WIFSIGNALED(status)) {
os << "signaled with " << sigabbrev_np(WTERMSIG(status)) << "(" << WTERMSIG(status) << ")";
} else if (WIFSTOPPED(status)) {
os << "stopped by";
auto stop_sig = WSTOPSIG(status);
os << "signal " << sigabbrev_np(stop_sig) << "(" << stop_sig << "),";
os << "event=" << parse_ptrace_event(status);
} else {
os << "unknown";
}
return os.str();
}

View File

@@ -0,0 +1,114 @@
#pragma once
#include <string>
#include <sys/ptrace.h>
#include "daemon.h"
#ifdef __LP64__
#define LOG_TAG "zygisk-ptracer64"
#else
#define LOG_TAG "zygisk-ptracer32"
#endif
#include "logging.h"
struct MapInfo {
/// \brief The start address of the memory region.
uintptr_t start;
/// \brief The end address of the memory region.
uintptr_t end;
/// \brief The permissions of the memory region. This is a bit mask of the following values:
/// - PROT_READ
/// - PROT_WRITE
/// - PROT_EXEC
uint8_t perms;
/// \brief Whether the memory region is private.
bool is_private;
/// \brief The offset of the memory region.
uintptr_t offset;
/// \brief The device number of the memory region.
/// Major can be obtained by #major()
/// Minor can be obtained by #minor()
dev_t dev;
/// \brief The inode number of the memory region.
ino_t inode;
/// \brief The path of the memory region.
std::string path;
/// \brief Scans /proc/self/maps and returns a list of \ref MapInfo entries.
/// This is useful to find out the inode of the library to hook.
/// \return A list of \ref MapInfo entries.
[[maybe_unused, gnu::visibility("default")]] static std::vector<MapInfo> Scan(const std::string& pid = "self");
};
#if defined(__x86_64__)
#define REG_SP rsp
#define REG_IP rip
#define REG_RET rax
#elif defined(__i386__)
#define REG_SP esp
#define REG_IP eip
#define REG_RET eax
#elif defined(__aarch64__)
#define REG_SP sp
#define REG_IP pc
#define REG_RET regs[0]
#elif defined(__arm__)
#define REG_SP uregs[13]
#define REG_IP uregs[15]
#define REG_RET uregs[0]
#define user_regs_struct user_regs
#endif
ssize_t write_proc(int pid, uintptr_t *remote_addr, const void *buf, size_t len);
ssize_t read_proc(int pid, uintptr_t *remote_addr, void *buf, size_t len);
bool get_regs(int pid, struct user_regs_struct &regs);
bool set_regs(int pid, struct user_regs_struct &regs);
std::string get_addr_mem_region(std::vector<MapInfo> &info, void *addr);
void *find_module_base(std::vector<MapInfo> &info, std::string_view suffix);
void *find_func_addr(
std::vector<MapInfo> &local_info,
std::vector<MapInfo> &remote_info,
std::string_view module,
std::string_view func);
void align_stack(struct user_regs_struct &regs, long preserve = 0);
void *push_string(int pid, struct user_regs_struct &regs, const char *str);
uintptr_t remote_call(int pid, struct user_regs_struct &regs, uintptr_t func_addr, uintptr_t return_addr,
std::vector<long> &args);
int fork_dont_care();
int wait_pid(int pid, int* status, int flags);
std::string parse_status(int status);
#define CASE_CONST_RETURN(x) case x: return #x;
inline const char* parse_ptrace_event(int status) {
status = status >> 16;
switch (status) {
CASE_CONST_RETURN(PTRACE_EVENT_FORK)
CASE_CONST_RETURN(PTRACE_EVENT_VFORK)
CASE_CONST_RETURN(PTRACE_EVENT_CLONE)
CASE_CONST_RETURN(PTRACE_EVENT_EXEC)
CASE_CONST_RETURN(PTRACE_EVENT_VFORK_DONE)
CASE_CONST_RETURN(PTRACE_EVENT_EXIT)
CASE_CONST_RETURN(PTRACE_EVENT_SECCOMP)
CASE_CONST_RETURN(PTRACE_EVENT_STOP)
default:
return "(no event)";
}
}
inline const char* sigabbrev_np(int sig) {
if (sig > 0 && sig < NSIG) return sys_signame[sig];
return "(unknown)";
}

View File

@@ -53,9 +53,9 @@ VERSION=$(grep_prop version "${TMPDIR}/module.prop")
ui_print "- Installing Zygisk Next $VERSION"
# check android
if [ "$API" -lt 29 ]; then
if [ "$API" -lt 30 ]; then
ui_print "! Unsupported sdk: $API"
abort "! Minimal supported sdk is 29 (Android 10)"
abort "! Minimal supported sdk is 30 (Android 11)"
else
ui_print "- Device sdk: $API"
fi
@@ -104,52 +104,53 @@ mv "$TMPDIR/sepolicy.rule" "$MODPATH"
HAS32BIT=false && [ -d "/system/lib" ] && HAS32BIT=true
mkdir "$MODPATH/bin"
mkdir "$MODPATH/system"
mkdir "$MODPATH/system/lib64"
[ "$HAS32BIT" = true ] && mkdir "$MODPATH/system/lib"
mkdir "$MODPATH/lib"
mkdir "$MODPATH/lib64"
if [ "$ARCH" = "x86" ] || [ "$ARCH" = "x64" ]; then
if [ "$HAS32BIT" = true ]; then
ui_print "- Extracting x86 libraries"
extract "$ZIPFILE" 'bin/x86/zygiskd' "$MODPATH/bin" true
mv "$MODPATH/bin/zygiskd" "$MODPATH/bin/zygiskd32"
extract "$ZIPFILE" 'lib/x86/libzygisk.so' "$MODPATH/system/lib" true
extract "$ZIPFILE" 'lib/x86/libzygisk.so' "$MODPATH/lib" true
ln -sf "zygiskd32" "$MODPATH/bin/zygisk-cp32"
ln -sf "zygiskd32" "$MODPATH/bin/zygisk-ptrace32"
extract "$ZIPFILE" 'lib/x86/libptracer.so' "$MODPATH/bin" true
mv "$MODPATH/bin/libptracer.so" "$MODPATH/bin/zygisk-ptracer32"
fi
ui_print "- Extracting x64 libraries"
extract "$ZIPFILE" 'bin/x86_64/zygiskd' "$MODPATH/bin" true
mv "$MODPATH/bin/zygiskd" "$MODPATH/bin/zygiskd64"
extract "$ZIPFILE" 'lib/x86_64/libzygisk.so' "$MODPATH/system/lib64" true
extract "$ZIPFILE" 'lib/x86_64/libzygisk.so' "$MODPATH/lib64" true
ln -sf "zygiskd64" "$MODPATH/bin/zygisk-wd"
ln -sf "zygiskd64" "$MODPATH/bin/zygisk-fuse"
ln -sf "zygiskd64" "$MODPATH/bin/zygisk-cp64"
ln -sf "zygiskd64" "$MODPATH/bin/zygisk-ptrace64"
extract "$ZIPFILE" 'lib/x86_64/libptracer.so' "$MODPATH/bin" true
mv "$MODPATH/bin/libptracer.so" "$MODPATH/bin/zygisk-ptracer64"
else
if [ "$HAS32BIT" = true ]; then
ui_print "- Extracting arm libraries"
extract "$ZIPFILE" 'bin/armeabi-v7a/zygiskd' "$MODPATH/bin" true
mv "$MODPATH/bin/zygiskd" "$MODPATH/bin/zygiskd32"
extract "$ZIPFILE" 'lib/armeabi-v7a/libzygisk.so' "$MODPATH/system/lib" true
extract "$ZIPFILE" 'lib/armeabi-v7a/libzygisk.so' "$MODPATH/lib" true
ln -sf "zygiskd32" "$MODPATH/bin/zygisk-cp32"
ln -sf "zygiskd32" "$MODPATH/bin/zygisk-ptrace32"
extract "$ZIPFILE" 'lib/armeabi-v7a/libptracer.so' "$MODPATH/bin" true
mv "$MODPATH/bin/libptracer.so" "$MODPATH/bin/zygisk-ptracer32"
fi
ui_print "- Extracting arm64 libraries"
extract "$ZIPFILE" 'bin/arm64-v8a/zygiskd' "$MODPATH/bin" true
mv "$MODPATH/bin/zygiskd" "$MODPATH/bin/zygiskd64"
extract "$ZIPFILE" 'lib/arm64-v8a/libzygisk.so' "$MODPATH/system/lib64" true
extract "$ZIPFILE" 'lib/arm64-v8a/libzygisk.so' "$MODPATH/lib64" true
ln -sf "zygiskd64" "$MODPATH/bin/zygisk-wd"
ln -sf "zygiskd64" "$MODPATH/bin/zygisk-fuse"
ln -sf "zygiskd64" "$MODPATH/bin/zygisk-cp64"
ln -sf "zygiskd64" "$MODPATH/bin/zygisk-ptrace64"
extract "$ZIPFILE" 'lib/arm64-v8a/libptracer.so' "$MODPATH/bin" true
mv "$MODPATH/bin/libptracer.so" "$MODPATH/bin/zygisk-ptracer64"
fi
ui_print "- Setting permissions"
set_perm_recursive "$MODPATH/bin" 0 0 0755 0755
set_perm_recursive "$MODPATH/system/lib" 0 0 0755 0644 u:object_r:system_lib_file:s0
set_perm_recursive "$MODPATH/system/lib64" 0 0 0755 0644 u:object_r:system_lib_file:s0
set_perm_recursive "$MODPATH/lib" 0 0 0755 0644 u:object_r:system_lib_file:s0
set_perm_recursive "$MODPATH/lib64" 0 0 0755 0644 u:object_r:system_lib_file:s0
# If Huawei's Maple is enabled, system_server is created with a special way which is out of Zygisk's control
HUAWEI_MAPLE_ENABLED=$(grep_prop ro.maple.enable)

View File

@@ -20,5 +20,27 @@ if [ "$(which magisk)" ]; then
done
fi
[ "$DEBUG" = true ] && export RUST_BACKTRACE=1
unshare -m sh -c "bin/zygisk-fuse &"
create_sys_perm() {
mkdir -p $1
chmod 555 $1
chcon u:object_r:system_file:s0 $1
}
create_sys_perm /dev/zygisk
if [ -f $MODDIR/lib64/libzygisk.so ];then
create_sys_perm /dev/zygisk/lib64
cp $MODDIR/lib64/libzygisk.so /dev/zygisk/lib64/libzygisk.so
chcon u:object_r:system_lib_file:s0 /dev/zygisk/lib64/libzygisk.so
setprop ctl.sigstop_on zygote
unshare -m sh -c "./bin/zygisk-ptracer64 prop_monitor &"
fi
if [ -f $MODDIR/lib/libzygisk.so ];then
create_sys_perm /dev/zygisk/lib
cp $MODDIR/lib/libzygisk.so /dev/zygisk/lib/libzygisk.so
chcon u:object_r:system_lib_file:s0 /dev/zygisk/lib/libzygisk.so
setprop ctl.sigstop_on zygote_secondary
unshare -m sh -c "./bin/zygisk-ptracer32 prop_monitor &"
fi

View File

@@ -23,10 +23,6 @@ proc-maps = "0.3"
rustix = { version = "0.38", features = [ "fs", "process", "mount", "net", "thread"] }
tokio = { version = "1.28", features = ["full"] }
binder = { git = "https://github.com/Kernel-SU/binder_rs", rev = "c9f2b62d6a744fd2264056c638c1b061a6a2932d" }
fuser = { git = "https://github.com/Dr-TSNG/fuser", default-features = false }
ptrace-do = { git = "https://github.com/5ec1cff/ptrace-do" }
[profile.release]
strip = true
opt-level = "z"

View File

@@ -22,8 +22,6 @@ pub const PATH_ZYGISK_LIB: &str = concatcp!(lp_select!("/system/lib", "/system/l
pub const PATH_WORK_DIR: &str = "/dev/zygisk"; // TODO: Replace with /debug_ramdisk/zygisk
pub const PATH_PROP_OVERLAY: &str = concatcp!(PATH_WORK_DIR, "/module.prop");
pub const PATH_CP_SOCKET: &str = concatcp!(PATH_WORK_DIR, lp_select!("/cp32.sock", "/cp64.sock"));
pub const PATH_FUSE_DIR: &str = concatcp!(PATH_WORK_DIR, "/fuse");
pub const PATH_FUSE_PCL: &str = concatcp!(PATH_FUSE_DIR, "/preloaded-classes");
pub const PATH_MODULES_DIR: &str = "..";
pub const PATH_MODULE_PROP: &str = "module.prop";

View File

@@ -1,205 +0,0 @@
use std::cmp::min;
use anyhow::{bail, Result};
use std::ffi::OsStr;
use std::{fs, thread};
use std::io::Read;
use std::process::{Command, Stdio};
use std::sync::{mpsc, Mutex};
use std::time::{Duration, SystemTime};
use fuser::{FileAttr, Filesystem, FileType, ReplyAttr, ReplyData, ReplyDirectory, ReplyEntry, ReplyOpen, Request};
use libc::ENOENT;
use log::{error, info};
use rustix::fs::UnmountFlags;
use rustix::mount::{mount_bind, unmount};
use rustix::path::Arg;
use crate::constants;
use crate::utils::LateInit;
pub struct DelegateFilesystem;
const fn attr(inode: u64, size: u64, kind: FileType) -> FileAttr {
FileAttr {
ino: inode,
size,
blocks: 0,
atime: SystemTime::UNIX_EPOCH,
mtime: SystemTime::UNIX_EPOCH,
ctime: SystemTime::UNIX_EPOCH,
crtime: SystemTime::UNIX_EPOCH,
kind,
perm: 0o644,
nlink: 0,
uid: 0,
gid: 0,
rdev: 0,
blksize: 0,
flags: 0,
}
}
const INO_DIR: u64 = 1;
const INO_PCL: u64 = 2;
static ATTR_DIR: FileAttr = attr(INO_DIR, 0, FileType::Directory);
static ATTR_PCL: LateInit<FileAttr> = LateInit::new();
static PCL_CONTENT: LateInit<Vec<u8>> = LateInit::new();
const ENTRIES: &[(u64, FileType, &str)] = &[
(INO_DIR, FileType::Directory, "."),
(INO_DIR, FileType::Directory, ".."),
(INO_PCL, FileType::RegularFile, "preloaded-classes"),
];
const TTL: Duration = Duration::from_secs(1);
fn ptrace_zygote64(pid: u32) -> Result<()> {
static LAST: Mutex<u32> = Mutex::new(0);
let mut last = LAST.lock().unwrap();
if *last == pid {
return Ok(());
}
*last = pid;
let (sender, receiver) = mpsc::channel::<()>();
let worker = move || -> Result<()> {
let mut child = Command::new(constants::PATH_PTRACE_BIN64).stdout(Stdio::piped()).arg(format!("{}", pid)).spawn()?;
child.stdout.as_mut().unwrap().read_exact(&mut [0u8; 1])?;
info!("child attached");
sender.send(())?;
let result = child.wait()?;
info!("ptrace64 process status {}", result);
Ok(())
};
thread::spawn(move || {
if let Err(e) = worker() {
error!("Crashed: {:?}", e);
}
});
receiver.recv()?;
Ok(())
}
fn ptrace_zygote32(pid: u32) -> Result<()> {
static LAST: Mutex<u32> = Mutex::new(0);
let mut last = LAST.lock().unwrap();
if *last == pid {
return Ok(());
}
*last = pid;
let (sender, receiver) = mpsc::channel::<()>();
let worker = move || -> Result<()> {
let mut child = Command::new(constants::PATH_PTRACE_BIN32).stdout(Stdio::piped()).arg(format!("{}", pid)).spawn()?;
child.stdout.as_mut().unwrap().read_exact(&mut [0u8; 1])?;
info!("child attached");
sender.send(())?;
let result = child.wait()?;
info!("ptrace32 process status {}", result);
Ok(())
};
thread::spawn(move || {
if let Err(e) = worker() {
error!("Crashed: {:?}", e);
}
});
receiver.recv()?;
Ok(())
}
impl Filesystem for DelegateFilesystem {
fn lookup(&mut self, _req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEntry) {
if parent != INO_DIR {
reply.error(ENOENT);
return;
}
match name.as_str().unwrap() {
"preloaded-classes" => reply.entry(&TTL, &ATTR_PCL, 0),
_ => reply.error(ENOENT),
}
}
fn getattr(&mut self, _req: &Request<'_>, ino: u64, reply: ReplyAttr) {
match ino {
INO_DIR => reply.attr(&TTL, &ATTR_DIR),
INO_PCL => reply.attr(&TTL, &ATTR_PCL),
_ => reply.error(ENOENT),
}
}
fn open(&mut self, req: &Request<'_>, ino: u64, _flags: i32, reply: ReplyOpen) {
if ino == INO_PCL {
let pid = req.pid();
let process = format!("/proc/{}/cmdline", pid);
let process = fs::read_to_string(process).unwrap();
let process = &process[..process.find('\0').unwrap()];
info!("Process {} is reading preloaded-classes", process);
match process {
"zygote64" => ptrace_zygote64(pid).unwrap(),
"zygote" => ptrace_zygote32(pid).unwrap(),
_ => (),
}
}
reply.opened(0, 0);
}
fn read(&mut self, _req: &Request<'_>, ino: u64, _fh: u64, offset: i64, size: u32, _flags: i32, _lock_owner: Option<u64>, reply: ReplyData) {
let offset = offset as usize;
let size = size as usize;
if ino == INO_PCL {
let len = PCL_CONTENT.len();
if offset >= len {
reply.data(&[]);
} else {
let end = min(offset + size, len);
reply.data(&PCL_CONTENT[offset..end]);
}
} else {
reply.error(ENOENT);
}
}
fn readdir(&mut self, _req: &Request<'_>, ino: u64, _fh: u64, offset: i64, mut reply: ReplyDirectory) {
if ino != INO_DIR {
reply.error(ENOENT);
return;
}
for (i, entry) in ENTRIES.iter().enumerate().skip(offset as usize) {
if reply.add(entry.0, (i + 1) as i64, entry.1, entry.2) {
break;
}
}
reply.ok();
}
}
pub fn main() -> Result<()> {
info!("Start zygisk fuse");
fs::create_dir(constants::PATH_WORK_DIR)?;
fs::create_dir(constants::PATH_FUSE_DIR)?;
PCL_CONTENT.init(fs::read(constants::PATH_PCL)?);
ATTR_PCL.init(attr(INO_PCL, PCL_CONTENT.len() as u64, FileType::RegularFile));
let options = [
fuser::MountOption::FSName(String::from("zygisk")),
fuser::MountOption::AllowOther,
fuser::MountOption::RO,
];
let session = fuser::spawn_mount2(
DelegateFilesystem,
constants::PATH_FUSE_DIR,
&options,
)?;
mount_bind(constants::PATH_FUSE_PCL, constants::PATH_PCL)?;
let crash = session.guard.join();
unmount(constants::PATH_PCL, UnmountFlags::DETACH)?;
match crash {
Err(e) => bail!("Fuse mount crashed: {:?}", e),
_ => bail!("Fuse mount exited unexpectedly"),
}
}

View File

@@ -1,7 +1,5 @@
mod constants;
mod dl;
mod fuse;
mod ptrace;
mod root_impl;
mod utils;
mod watchdog;
@@ -28,9 +26,7 @@ fn start(name: &str) -> Result<()> {
root_impl::setup();
match name.trim_start_matches("zygisk-") {
"wd" => async_start(watchdog::main())?,
"fuse" => fuse::main()?,
lp_select!("cp32", "cp64") => zygiskd::main()?,
lp_select!("ptrace32", "ptrace64") => ptrace::main()?,
_ => println!("Available commands: wd, fuse, cp, ptrace"),
}
Ok(())

View File

@@ -1,233 +0,0 @@
use log::{debug, info};
use std::ffi::CString;
use std::env;
use std::io::Write;
use rustix::path::Arg;
use proc_maps::{get_process_maps, MapRange, Pid};
use ptrace_do::{RawProcess, TracedProcess};
use rustix::process::getpid;
use crate::{constants, lp_select};
use anyhow::{bail, Result};
const ANDROID_LIBC: &str = "bionic/libc.so";
const ANDROID_LIBDL: &str = "bionic/libdl.so";
fn find_module_for_pid(pid: Pid, library: &str) -> Result<MapRange> {
let maps = get_process_maps(pid)?;
for map in maps.into_iter() {
if let Some(p) = map.filename() {
if p.as_str()?.contains(library) {
return Ok(map);
}
}
}
bail!("Cannot find module {library} for pid {pid}");
}
fn find_remote_procedure(
pid: Pid,
library: &str,
local_addr: usize,
) -> Result<usize> {
let local_module = find_module_for_pid(getpid().as_raw_nonzero().get(), library)?;
debug!(
"Identifed local range {library} ({:?}) at {:x}",
local_module.filename(),
local_module.start()
);
let remote_module = find_module_for_pid(pid, library)?;
debug!(
"Identifed remote range {library} ({:?}) at {:x}",
remote_module.filename(),
remote_module.start()
);
Ok(local_addr - local_module.start() + remote_module.start())
}
fn ptrace_zygote(pid: u32) -> Result<()> {
info!("Injecting into pid {}", pid);
let zygisk_lib = CString::new(constants::PATH_ZYGISK_LIB)?;
let libc_base = find_module_for_pid(pid as i32, ANDROID_LIBC)?.start();
let mmap_remote = find_remote_procedure(
pid as i32,
ANDROID_LIBC,
libc::mmap as usize,
)?;
let munmap_remote = find_remote_procedure(
pid as i32,
ANDROID_LIBC,
libc::munmap as usize,
)?;
let dlopen_remote = find_remote_procedure(
pid as i32,
ANDROID_LIBDL,
libc::dlopen as usize,
)?;
let dlsym_remote = find_remote_procedure(
pid as i32,
ANDROID_LIBDL,
libc::dlsym as usize,
)?;
let errno_remote = find_remote_procedure(
pid as i32,
ANDROID_LIBC,
libc::__errno as usize,
)?;
let dlerror_remote = find_remote_procedure(
pid as i32,
ANDROID_LIBDL,
libc::dlerror as usize,
)?;
let strlen_remote = find_remote_procedure(
pid as i32,
ANDROID_LIBC,
libc::strlen as usize,
)?;
let tracer = TracedProcess::attach(RawProcess::new(pid as i32))?;
std::io::stdout().write(b"1")?;
info!("attached process {}", pid);
std::io::stdout().flush()?;
let frame = tracer.next_frame()?;
debug!("Waited for a frame");
// Map a buffer in the remote process
debug!("remote mmap addr {:x}", mmap_remote);
let mmap_params: [usize; 6] = [
0,
0x1000,
(libc::PROT_READ | libc::PROT_WRITE) as usize,
(libc::MAP_ANONYMOUS | libc::MAP_PRIVATE) as usize,
0,
0,
];
let mut arr: Vec<u8> = Vec::new();
for p in mmap_params {
arr.extend_from_slice(&p.to_le_bytes());
}
arr.as_slice();
let (regs, mut frame) = frame.invoke_remote(
mmap_remote,
libc_base,
&mmap_params,
)?;
let buf_addr = regs.return_value();
debug!("remote stopped at addr {:x}", regs.program_counter());
if regs.program_counter() != libc_base {
let data = std::mem::MaybeUninit::<libc::siginfo_t>::uninit();
let siginfo = unsafe {
libc::ptrace(libc::PTRACE_GETSIGINFO, pid, 0, &data);
data.assume_init()
};
bail!(
"stopped at unexpected addr {:x} signo {} si_code {} si_addr {:?}",
regs.program_counter(),
siginfo.si_signo,
siginfo.si_code,
unsafe { siginfo.si_addr() },
);
}
if buf_addr == usize::MAX {
debug!("errno remote {:x}", errno_remote);
let (regs, frame) = frame.invoke_remote(
errno_remote,
libc_base,
&[],
)?;
debug!("errno called");
if regs.program_counter() != libc_base {
bail!("stopped at unexpected addr {:x} when getting errno", regs.program_counter());
}
let err_addr = regs.return_value();
let mut buf = [0u8; 4];
frame.read_memory_mut(err_addr, &mut buf)?;
let err = i32::from_le_bytes(buf);
bail!("remote failed with {}", err);
}
debug!("Buffer addr: {:x}", buf_addr);
// Load zygisk into remote process
frame.write_memory(buf_addr, zygisk_lib.as_bytes_with_nul())?;
let (regs, mut frame) = frame.invoke_remote(
dlopen_remote,
libc_base,
&[buf_addr, libc::RTLD_NOW as usize],
)?;
let handle = regs.return_value();
debug!("Load zygisk into remote process: {:x}", handle);
if regs.program_counter() != libc_base {
let data = std::mem::MaybeUninit::<libc::siginfo_t>::uninit();
let siginfo = unsafe {
libc::ptrace(libc::PTRACE_GETSIGINFO, pid, 0, &data);
data.assume_init()
};
bail!(
"stopped at unexpected addr {:x} signo {} si_code {} si_addr {:?}",
regs.program_counter(),
siginfo.si_signo,
siginfo.si_code,
unsafe { siginfo.si_addr() },
);
}
if handle == 0 {
debug!("got handle 0");
let (regs, frame) = frame.invoke_remote(
dlerror_remote,
libc_base,
&[],
)?;
let err_addr = regs.return_value();
if err_addr == 0 {
bail!("dlerror err addr 0");
}
debug!("err addr {:x}", err_addr);
let (regs, frame) = frame.invoke_remote(
strlen_remote,
libc_base,
&[err_addr],
)?;
let len = regs.return_value();
if len == 0 {
bail!("dlerror len 0");
}
debug!("err len {}", len);
let mut buf = vec![0u8; len];
frame.read_memory_mut(err_addr, buf.as_mut_slice())?;
bail!("err {:?}", buf);
}
let entry = CString::new("entry")?;
frame.write_memory(buf_addr, entry.as_bytes_with_nul())?;
let (regs, frame) = frame.invoke_remote(
dlsym_remote,
libc_base,
&[handle, buf_addr],
)?;
let entry = regs.return_value();
debug!("Call zygisk entry: {:x}", entry);
let (_, frame) = frame.invoke_remote(
entry,
libc_base,
&[handle],
)?;
// Cleanup
let _ = frame.invoke_remote(
munmap_remote,
libc_base,
&[buf_addr],
)?;
debug!("Cleaned up");
Ok(())
}
pub fn main() -> Result<()> {
info!("Start zygisk ptrace");
let args: Vec<String> = env::args().collect();
let pid = args[1].parse::<u32>().unwrap();
info!("ptracing {} pid {}", lp_select!("zygote32", "zygote64"), pid);
ptrace_zygote(pid)?;
Ok(())
}

View File

@@ -4,8 +4,6 @@ use std::fs;
use std::future::Future;
use std::io::{BufRead, BufReader, Write};
use std::pin::Pin;
use std::time::Duration;
use binder::IBinder;
use futures::stream::FuturesUnordered;
use futures::StreamExt;
use log::{debug, error, info};
@@ -128,27 +126,6 @@ async fn spawn_daemon() -> Result<()> {
futures.push(Box::pin(spawn_daemon(it)));
}
async fn binder_listener() -> Result<()> {
let mut binder = loop {
match binder::get_service("activity") {
Some(binder) => break binder,
None => {
log::trace!("System server not ready, wait for 1s...");
tokio::time::sleep(Duration::from_secs(1)).await;
}
};
};
info!("System server ready");
loop {
if binder.ping_binder().is_err() { break; }
tokio::time::sleep(Duration::from_secs(1)).await;
}
bail!("System server died");
}
futures.push(Box::pin(binder_listener()));
if let Err(e) = futures.next().await.unwrap() {
error!("{}", e);
}