Files
TrickyStore/module/src/main/cpp/inject/main.cpp
2024-07-11 22:00:39 +08:00

301 lines
11 KiB
C++

#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 <sys/socket.h>
#include <sys/un.h>
#include <android/dlext.h>
#include <fcntl.h>
#include <csignal>
#include <sys/system_properties.h>
#include <string>
#include <cinttypes>
#include "lsplt.hpp"
#include "logging.hpp"
#include "utils.hpp"
using namespace std::string_literals;
// zygote inject
bool inject_library(int pid, const char *lib_path, const char* entry_name) {
LOGI("injecting %s and calling %s in %d", lib_path, entry_name, pid);
struct user_regs_struct regs{}, backup{};
std::vector<lsplt::MapInfo> map;
if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
PLOGE("attach");
}
int status;
{
wait_for_trace(pid, &status, __WALL);
}
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP) {
if (!get_regs(pid, regs)) return false;
// The linker has been initialized now, we can do dlopen
LOGD("stopped at entry");
// backup registers
memcpy(&backup, &regs, sizeof(regs));
{
map = lsplt::MapInfo::Scan(std::to_string(pid));
}
auto local_map = lsplt::MapInfo::Scan();
auto libc_return_addr = find_module_return_addr(map, "libc.so");
LOGD("libc return addr %p", libc_return_addr);
std::vector<uintptr_t> args;
uintptr_t str, remote_handle, injector_entry;
auto close_addr = find_func_addr(local_map, map, "libc.so", "close");
if (!close_addr) return false;
int lib_fd = -1;
// prepare fd
{
set_sockcreate_con("u:object_r:system_file:s0");
UniqueFd local_socket = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (local_socket == -1) {
PLOGE("create local socket");
return false;
}
if (setfilecon(lib_path, "u:object_r:system_file:s0") == -1) {
PLOGE("set context of lib");
}
UniqueFd local_lib_fd = open(lib_path, O_RDONLY | O_CLOEXEC);
if (local_lib_fd == -1) {
PLOGE("open lib");
return false;
}
auto socket_addr = find_func_addr(local_map, map, "libc.so", "socket");
auto bind_addr = find_func_addr(local_map, map, "libc.so", "bind");
auto recvmsg_addr = find_func_addr(local_map, map, "libc.so", "recvmsg");
auto errno_addr = find_func_addr(local_map, map, "libc.so", "__errno");
auto get_remote_errno = [&]() -> int {
if (!errno_addr) {
LOGE("could not get errno!");
return 0;
}
auto addr = remote_call(pid, regs, (uintptr_t) errno_addr, 0, args);
int err = 0;
if (!read_proc(pid, addr, &err, sizeof(err))) return 0;
return err;
};
if (!socket_addr || !bind_addr || !recvmsg_addr) return false;
args.clear();
args.push_back(AF_UNIX);
args.push_back(SOCK_DGRAM | SOCK_CLOEXEC);
args.push_back(0);
int remote_fd = (int) remote_call(pid, regs, (uintptr_t) socket_addr, 0, args);
if (remote_fd == -1) {
errno = get_remote_errno();
PLOGE("remote socket");
return false;
}
auto close_remote = [&](int fd) -> void {
args.clear();
args.push_back(fd);
if (remote_call(pid, regs, (uintptr_t) close_addr, 0, args) != 0) {
LOGE("remote not closed: %d", fd);
}
};
auto magic = generateMagic(16);
struct sockaddr_un addr{
.sun_family = AF_UNIX,
.sun_path = {0}
};
LOGD("socket name %s", magic.c_str());
memcpy(addr.sun_path + 1, magic.c_str(), magic.size());
socklen_t len = sizeof(addr.sun_family) + 1 + magic.size();
auto remote_addr = push_memory(pid, regs, &addr, sizeof(addr));
args.clear();
args.push_back(remote_fd);
args.push_back(remote_addr);
args.push_back(len);
auto bind_result = remote_call(pid, regs, (uintptr_t) bind_addr, 0, args);
if (bind_result == (uintptr_t) -1) {
errno = get_remote_errno();
PLOGE("remote bind");
close_remote(remote_fd);
return false;
}
char cmsgbuf[CMSG_SPACE(sizeof(int))] = {0};
auto remote_cmsgbuf = push_memory(pid, regs, &cmsgbuf, sizeof(cmsgbuf));
struct msghdr hdr{};
hdr.msg_control = (void*) remote_cmsgbuf;
hdr.msg_controllen = sizeof(cmsgbuf);
auto remote_hdr = push_memory(pid, regs, &hdr, sizeof(hdr));
args.clear();
args.push_back(remote_fd);
args.push_back(remote_hdr);
args.push_back(MSG_WAITALL);
if (!remote_pre_call(pid, regs, (uintptr_t) recvmsg_addr, 0, args)) {
// we can't do anything more
LOGE("pre call remote recvmsg");
return false;
}
hdr.msg_control = &cmsgbuf;
hdr.msg_name = &addr;
hdr.msg_namelen = len;
{
cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr);
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = AF_UNIX;
*(int *) CMSG_DATA(cmsg) = local_lib_fd;
}
if (sendmsg(local_socket, &hdr, 0) == -1) {
PLOGE("send to remote");
close_remote(remote_fd);
return false;
}
auto recvmsg_result = (ssize_t) remote_post_call(pid, regs, 0);
if (recvmsg_result == -1) {
errno = get_remote_errno();
PLOGE("post call recvmsg");
close_remote(remote_fd);
return false;
}
if (read_proc(pid, remote_cmsgbuf, &cmsgbuf, sizeof(cmsgbuf)) != sizeof(cmsgbuf)) {
LOGE("failed to read proc");
close_remote(remote_fd);
return false;
}
cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr);
if (cmsg == nullptr || cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
LOGE("remote recv fd failed!");
close_remote(remote_fd);
return false;
}
lib_fd = *(int*) CMSG_DATA(cmsg);
LOGD("remote lib fd: %d", lib_fd);
close_remote(remote_fd);
}
// call dlopen
{
auto dlopen_addr = find_func_addr(local_map, map, "libdl.so", "android_dlopen_ext");
if (dlopen_addr == nullptr) return false;
android_dlextinfo info{};
info.flags = ANDROID_DLEXT_USE_LIBRARY_FD;
info.library_fd = lib_fd;
uintptr_t remote_info = push_memory(pid, regs, &info, sizeof(info));
str = push_string(pid, regs, lib_path);
args.clear();
args.push_back((long) str);
args.push_back((long) RTLD_NOW);
args.push_back(remote_info);
remote_handle = remote_call(pid, regs, (uintptr_t) dlopen_addr,
(uintptr_t) libc_return_addr, args);
LOGD("remote handle %p", (void *) remote_handle);
if (remote_handle == 0) {
LOGE("handle is null");
// call dlerror
auto dlerror_addr = find_func_addr(local_map, map, "libdl.so", "dlerror");
if (dlerror_addr == nullptr) {
LOGE("find dlerror");
return false;
}
args.clear();
auto dlerror_str_addr = remote_call(pid, regs, (uintptr_t) dlerror_addr,
(uintptr_t) libc_return_addr, args);
LOGD("dlerror str %p", (void *) dlerror_str_addr);
if (dlerror_str_addr == 0) return false;
auto strlen_addr = find_func_addr(local_map, map, "libc.so", "strlen");
if (strlen_addr == nullptr) {
LOGE("find strlen");
return false;
}
args.clear();
args.push_back(dlerror_str_addr);
auto dlerror_len = remote_call(pid, regs, (uintptr_t) strlen_addr,
(uintptr_t) libc_return_addr, args);
if (dlerror_len <= 0) {
LOGE("dlerror len <= 0");
return false;
}
std::string err;
err.resize(dlerror_len + 1, 0);
read_proc(pid, (uintptr_t) dlerror_str_addr, err.data(), dlerror_len);
LOGE("dlerror info %s", err.c_str());
return false;
}
args.clear();
args.push_back(lib_fd);
if (remote_call(pid, regs, (uintptr_t) close_addr, 0, args) != 0) {
LOGE("remote lib not closed: %d", lib_fd);
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);
injector_entry = remote_call(pid, regs, (uintptr_t) dlsym_addr,
(uintptr_t) libc_return_addr, 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_return_addr, args);
}
LOGD("restore context");
// restore registers
if (!set_regs(pid, backup)) return false;
if (ptrace(PTRACE_DETACH, pid, 0, 0) == -1) {
PLOGE("failed to detach");
return false;
}
return true;
} else {
LOGE("stopped by other reason: %s", parse_status(status).c_str());
}
return false;
}
int main(int argc, char **argv) {
#ifndef NDEBUG
logging::setPrintEnabled(true);
#endif
auto pid = strtol(argv[1], nullptr, 0);
char buf[4096];
realpath(argv[2], buf);
return !inject_library(pid, buf, argv[3]);
}