You've already forked ZygiskNext
mirror of
https://github.com/Dr-TSNG/ZygiskNext.git
synced 2025-08-27 23:46:34 +00:00
Add injector
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
#include <linux/un.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "dl.h"
|
||||
#include "socket_utils.h"
|
||||
|
||||
namespace zygiskd {
|
||||
|
||||
UniqueFd Connect(uint8_t retry) {
|
||||
UniqueFd fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
struct sockaddr_un addr{
|
||||
.sun_family = AF_UNIX,
|
||||
.sun_path={0},
|
||||
};
|
||||
strncpy(addr.sun_path + 1, kZygiskSocket.data(), kZygiskSocket.size());
|
||||
socklen_t socklen = sizeof(sa_family_t) + strlen(addr.sun_path + 1) + 1;
|
||||
|
||||
while (retry--) {
|
||||
int r = connect(fd, reinterpret_cast<struct sockaddr*>(&addr), socklen);
|
||||
if (r != -1) return r;
|
||||
LOGW("retrying to connect to zygiskd, sleep 1s");
|
||||
sleep(1);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool PingHeartbeat() {
|
||||
auto fd = Connect(5);
|
||||
if (fd == -1) {
|
||||
PLOGE("Connect to zygiskd");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string ReadNativeBridge() {
|
||||
auto fd = Connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("ReadNativeBridge");
|
||||
return "";
|
||||
}
|
||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::ReadNativeBridge);
|
||||
return socket_utils::read_string(fd);
|
||||
}
|
||||
|
||||
UniqueFd ReadInjector() {
|
||||
auto fd = Connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("ReadInjector");
|
||||
return -1;
|
||||
}
|
||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::ReadInjector);
|
||||
return socket_utils::recv_fd(fd);
|
||||
}
|
||||
|
||||
std::vector<Module> ReadModules() {
|
||||
std::vector<Module> modules;
|
||||
auto fd = Connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("ReadModules");
|
||||
return modules;
|
||||
}
|
||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::ReadModules);
|
||||
size_t len = socket_utils::read_usize(fd);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
std::string name = socket_utils::read_string(fd);
|
||||
UniqueFd module_fd = socket_utils::recv_fd(fd);
|
||||
auto handle = DlopenMem(module_fd, RTLD_NOW);
|
||||
if (handle == nullptr) {
|
||||
LOGW("Failed to dlopen module %s: %s", name.data(), dlerror());
|
||||
continue;
|
||||
}
|
||||
modules.emplace_back(name, handle);
|
||||
}
|
||||
return modules;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
#include <cstdio>
|
||||
#include <dlfcn.h>
|
||||
#include <libgen.h>
|
||||
#include <climits>
|
||||
#include <cstring>
|
||||
#include <android/dlext.h>
|
||||
|
||||
#include "dl.h"
|
||||
#include "logging.h"
|
||||
|
||||
extern "C" [[gnu::weak]] struct android_namespace_t*
|
||||
//NOLINTNEXTLINE
|
||||
__loader_android_create_namespace([[maybe_unused]] const char* name,
|
||||
[[maybe_unused]] const char* ld_library_path,
|
||||
[[maybe_unused]] const char* default_library_path,
|
||||
[[maybe_unused]] uint64_t type,
|
||||
[[maybe_unused]] const char* permitted_when_isolated_path,
|
||||
[[maybe_unused]] android_namespace_t* parent,
|
||||
[[maybe_unused]] const void* caller_addr);
|
||||
|
||||
void* DlopenExt(const char* path, int flags) {
|
||||
auto info = android_dlextinfo{};
|
||||
auto* dir = dirname(path);
|
||||
auto* ns = &__loader_android_create_namespace == nullptr ? nullptr :
|
||||
__loader_android_create_namespace(path, dir, nullptr,
|
||||
2, /* ANDROID_NAMESPACE_TYPE_SHARED */
|
||||
nullptr, nullptr,
|
||||
reinterpret_cast<void*>(&DlopenExt));
|
||||
if (ns) {
|
||||
info.flags = ANDROID_DLEXT_USE_NAMESPACE;
|
||||
info.library_namespace = ns;
|
||||
|
||||
LOGD("Open %s with namespace %p", path, ns);
|
||||
} else {
|
||||
LOGD("Cannot create namespace for %s", path);
|
||||
}
|
||||
|
||||
auto* handle = android_dlopen_ext(path, flags, &info);
|
||||
if (handle) {
|
||||
LOGD("dlopen %s: %p", path, handle);
|
||||
} else {
|
||||
LOGE("dlopen %s: %s", path, dlerror());
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
void* DlopenMem(int memfd, int flags) {
|
||||
char path[PATH_MAX];
|
||||
sprintf(path, "/proc/self/fd/%d", memfd);
|
||||
return DlopenExt(path, flags);
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
#include <cstddef>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "socket_utils.h"
|
||||
|
||||
namespace socket_utils {
|
||||
|
||||
ssize_t xread(int fd, void* buf, size_t count) {
|
||||
size_t read_sz = 0;
|
||||
ssize_t ret;
|
||||
do {
|
||||
ret = read(fd, (std::byte*) buf + read_sz, count - read_sz);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
PLOGE("read");
|
||||
return ret;
|
||||
}
|
||||
read_sz += ret;
|
||||
} while (read_sz != count && ret != 0);
|
||||
if (read_sz != count) {
|
||||
PLOGE("read (%d != %d)", count, read_sz);
|
||||
}
|
||||
return read_sz;
|
||||
}
|
||||
|
||||
ssize_t xwrite(int fd, const void* buf, size_t count) {
|
||||
size_t write_sz = 0;
|
||||
ssize_t ret;
|
||||
do {
|
||||
ret = write(fd, (std::byte*) buf + write_sz, count - write_sz);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
PLOGE("write");
|
||||
return ret;
|
||||
}
|
||||
write_sz += ret;
|
||||
} while (write_sz != count && ret != 0);
|
||||
if (write_sz != count) {
|
||||
PLOGE("write (%d != %d)", count, write_sz);
|
||||
}
|
||||
return write_sz;
|
||||
}
|
||||
|
||||
ssize_t xrecvmsg(int sockfd, struct msghdr* msg, int flags) {
|
||||
int rec = recvmsg(sockfd, msg, flags);
|
||||
if (rec < 0) PLOGE("recvmsg");
|
||||
return rec;
|
||||
}
|
||||
|
||||
void* recv_fds(int sockfd, char* cmsgbuf, size_t bufsz, int cnt) {
|
||||
iovec iov = {
|
||||
.iov_base = &cnt,
|
||||
.iov_len = sizeof(cnt),
|
||||
};
|
||||
msghdr msg = {
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = cmsgbuf,
|
||||
.msg_controllen = bufsz
|
||||
};
|
||||
|
||||
xrecvmsg(sockfd, &msg, MSG_WAITALL);
|
||||
cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
|
||||
|
||||
if (msg.msg_controllen != bufsz ||
|
||||
cmsg == nullptr ||
|
||||
cmsg->cmsg_len != CMSG_LEN(sizeof(int) * cnt) ||
|
||||
cmsg->cmsg_level != SOL_SOCKET ||
|
||||
cmsg->cmsg_type != SCM_RIGHTS) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return CMSG_DATA(cmsg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T read_exact(int fd) {
|
||||
T res;
|
||||
return sizeof(T) == xread(fd, &res, sizeof(T)) ? res : -1;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool write_exact(int fd, T val) {
|
||||
return sizeof(T) == xwrite(fd, &val, sizeof(T));
|
||||
}
|
||||
|
||||
size_t read_usize(int fd) {
|
||||
return read_exact<size_t>(fd);
|
||||
}
|
||||
|
||||
std::string read_string(int fd) {
|
||||
auto len = read_exact<size_t>(fd);
|
||||
char buf[len + 1];
|
||||
buf[len] = '\0';
|
||||
xread(fd, buf, len);
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool write_u8(int fd, uint8_t val) {
|
||||
return write_exact<uint8_t>(fd, val);
|
||||
}
|
||||
|
||||
int recv_fd(int sockfd) {
|
||||
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
||||
|
||||
void* data = recv_fds(sockfd, cmsgbuf, sizeof(cmsgbuf), 1);
|
||||
if (data == nullptr) return -1;
|
||||
|
||||
int result;
|
||||
memcpy(&result, data, sizeof(int));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user