mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-18 05:58:30 +00:00
Add preliminary zygote code injection support
Prototyping the injection setup and a clean "self unloading" mechanism.
This commit is contained in:
parent
cd23d27048
commit
4060c2107c
@ -30,7 +30,9 @@ LOCAL_SRC_FILES := \
|
|||||||
su/su.cpp \
|
su/su.cpp \
|
||||||
su/connect.cpp \
|
su/connect.cpp \
|
||||||
su/pts.cpp \
|
su/pts.cpp \
|
||||||
su/su_daemon.cpp
|
su/su_daemon.cpp \
|
||||||
|
inject/entry.cpp \
|
||||||
|
inject/utils.cpp
|
||||||
|
|
||||||
LOCAL_LDLIBS := -llog
|
LOCAL_LDLIBS := -llog
|
||||||
include $(BUILD_EXECUTABLE)
|
include $(BUILD_EXECUTABLE)
|
||||||
|
@ -8,21 +8,26 @@
|
|||||||
#include <selinux.hpp>
|
#include <selinux.hpp>
|
||||||
#include <utils.hpp>
|
#include <utils.hpp>
|
||||||
|
|
||||||
using namespace std::literals;
|
using namespace std;
|
||||||
|
|
||||||
using main_fun = int (*)(int, char *[]);
|
using main_fun = int (*)(int, char *[]);
|
||||||
|
|
||||||
static main_fun applet_main[] = { su_client_main, resetprop_main, magiskhide_main, nullptr };
|
static main_fun applet_main[] = { su_client_main, resetprop_main, magiskhide_main, nullptr };
|
||||||
|
|
||||||
[[noreturn]] static void call_applet(int argc, char **argv) {
|
static int call_applet(int argc, char *argv[]) {
|
||||||
// Applets
|
// Applets
|
||||||
|
string_view base = basename(argv[0]);
|
||||||
for (int i = 0; applet_names[i]; ++i) {
|
for (int i = 0; applet_names[i]; ++i) {
|
||||||
if (strcmp(basename(argv[0]), applet_names[i]) == 0) {
|
if (base == applet_names[i]) {
|
||||||
exit((*applet_main[i])(argc, argv));
|
return (*applet_main[i])(argc, argv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fprintf(stderr, "%s: applet not found\n", basename(argv[0]));
|
if (str_starts(base, "app_process")) {
|
||||||
exit(1);
|
return app_process_main(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "%s: applet not found\n", base.data());
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
@ -41,6 +46,6 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
call_applet(argc, argv);
|
return call_applet(argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,21 +189,22 @@ static int magisk_log(int prio, const char *fmt, va_list ap) {
|
|||||||
return vfprintf(local_log_file.get(), buf, args);
|
return vfprintf(local_log_file.get(), buf, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void android_logging() {
|
#define mlog(prio) [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_##prio, fmt, ap); }
|
||||||
|
static void magisk_logging() {
|
||||||
auto in_mem_file = make_stream_fp<byte_stream>(log_buf, log_buf_len);
|
auto in_mem_file = make_stream_fp<byte_stream>(log_buf, log_buf_len);
|
||||||
log_file.reset(in_mem_file.release(), [](FILE *) {
|
log_file.reset(in_mem_file.release(), [](FILE *) {
|
||||||
free(log_buf);
|
free(log_buf);
|
||||||
log_buf = nullptr;
|
log_buf = nullptr;
|
||||||
});
|
});
|
||||||
log_cb.d = [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_DEBUG, fmt, ap); };
|
log_cb.d = mlog(DEBUG);
|
||||||
log_cb.i = [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_INFO, fmt, ap); };
|
log_cb.i = mlog(INFO);
|
||||||
log_cb.w = [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_WARN, fmt, ap); };
|
log_cb.w = mlog(WARN);
|
||||||
log_cb.e = [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_ERROR, fmt, ap); };
|
log_cb.e = mlog(ERROR);
|
||||||
log_cb.ex = nop_ex;
|
log_cb.ex = nop_ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void daemon_entry(int ppid) {
|
static void daemon_entry(int ppid) {
|
||||||
android_logging();
|
magisk_logging();
|
||||||
|
|
||||||
int fd = xopen("/dev/null", O_WRONLY);
|
int fd = xopen("/dev/null", O_WRONLY);
|
||||||
xdup2(fd, STDOUT_FILENO);
|
xdup2(fd, STDOUT_FILENO);
|
||||||
|
@ -36,3 +36,4 @@ int magiskhide_main(int argc, char *argv[]);
|
|||||||
int magiskpolicy_main(int argc, char *argv[]);
|
int magiskpolicy_main(int argc, char *argv[]);
|
||||||
int su_client_main(int argc, char *argv[]);
|
int su_client_main(int argc, char *argv[]);
|
||||||
int resetprop_main(int argc, char *argv[]);
|
int resetprop_main(int argc, char *argv[]);
|
||||||
|
int app_process_main(int argc, char *argv[]);
|
||||||
|
124
native/jni/inject/entry.cpp
Normal file
124
native/jni/inject/entry.cpp
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
#include <libgen.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
|
#include <sys/sendfile.h>
|
||||||
|
#include <android/log.h>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
#include <utils.hpp>
|
||||||
|
|
||||||
|
#include "inject.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
static void *self_handle = nullptr;
|
||||||
|
static atomic<int> active_threads = -1;
|
||||||
|
|
||||||
|
#define alog(prio) [](auto fmt, auto ap){ \
|
||||||
|
return __android_log_vprint(ANDROID_LOG_##prio, "Magisk", fmt, ap); }
|
||||||
|
static void inject_logging() {
|
||||||
|
log_cb.d = alog(DEBUG);
|
||||||
|
log_cb.i = alog(INFO);
|
||||||
|
log_cb.w = alog(WARN);
|
||||||
|
log_cb.e = alog(ERROR);
|
||||||
|
log_cb.ex = nop_ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((destructor))
|
||||||
|
static void inject_cleanup() {
|
||||||
|
if (active_threads < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Setup 1ms
|
||||||
|
timespec ts = { .tv_sec = 0, .tv_nsec = 1000000L };
|
||||||
|
|
||||||
|
// Check flag in busy loop
|
||||||
|
while (active_threads)
|
||||||
|
nanosleep(&ts, nullptr);
|
||||||
|
|
||||||
|
// Wait another 1ms to make sure all threads left our code
|
||||||
|
nanosleep(&ts, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void self_unload() {
|
||||||
|
new_daemon_thread(reinterpret_cast<void *(*)(void *)>(&dlclose), self_handle);
|
||||||
|
active_threads--;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *unload_first_stage(void *) {
|
||||||
|
// Setup 1ms
|
||||||
|
timespec ts = { .tv_sec = 0, .tv_nsec = 1000000L };
|
||||||
|
|
||||||
|
while (getenv(INJECT_ENV_2))
|
||||||
|
nanosleep(&ts, nullptr);
|
||||||
|
|
||||||
|
// Wait another 1ms to make sure all threads left our code
|
||||||
|
nanosleep(&ts, nullptr);
|
||||||
|
|
||||||
|
unmap_all(INJECT_LIB_1);
|
||||||
|
active_threads--;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((constructor))
|
||||||
|
static void inject_init() {
|
||||||
|
inject_logging();
|
||||||
|
if (char *env = getenv(INJECT_ENV_1)) {
|
||||||
|
LOGD("zygote: inject 1st stage\n");
|
||||||
|
|
||||||
|
if (env[0] == '1')
|
||||||
|
unsetenv("LD_PRELOAD");
|
||||||
|
else
|
||||||
|
setenv("LD_PRELOAD", env, 1); // Restore original LD_PRELOAD
|
||||||
|
unsetenv(INJECT_ENV_1);
|
||||||
|
|
||||||
|
// Setup second stage
|
||||||
|
setenv(INJECT_ENV_2, "1", 1);
|
||||||
|
cp_afc(INJECT_LIB_1, INJECT_LIB_2);
|
||||||
|
dlopen(INJECT_LIB_2, RTLD_LAZY);
|
||||||
|
} else if (getenv(INJECT_ENV_2)) {
|
||||||
|
LOGD("zygote: inject 2nd stage\n");
|
||||||
|
|
||||||
|
active_threads = 1;
|
||||||
|
|
||||||
|
// Get our own handle
|
||||||
|
self_handle = dlopen(INJECT_LIB_2, RTLD_LAZY);
|
||||||
|
dlclose(self_handle);
|
||||||
|
|
||||||
|
// Cleanup 1st stage maps
|
||||||
|
active_threads++;
|
||||||
|
new_daemon_thread(&unload_first_stage);
|
||||||
|
unsetenv(INJECT_ENV_2);
|
||||||
|
|
||||||
|
// TODO: actually inject stuffs, for now we demonstrate clean self unloading
|
||||||
|
self_unload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int app_process_main(int argc, char *argv[]) {
|
||||||
|
inject_logging();
|
||||||
|
char buf[4096];
|
||||||
|
if (realpath("/proc/self/exe", buf) == nullptr)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
int in = xopen(buf, O_RDONLY);
|
||||||
|
int out = xopen(INJECT_LIB_1, O_CREAT | O_WRONLY | O_TRUNC, 0777);
|
||||||
|
sendfile(out, in, nullptr, INT_MAX);
|
||||||
|
close(in);
|
||||||
|
close(out);
|
||||||
|
|
||||||
|
if (char *ld = getenv("LD_PRELOAD")) {
|
||||||
|
char env[128];
|
||||||
|
sprintf(env, "%s:" INJECT_LIB_1, ld);
|
||||||
|
setenv("LD_PRELOAD", env, 1);
|
||||||
|
setenv(INJECT_ENV_1, ld, 1); // Backup original LD_PRELOAD
|
||||||
|
} else {
|
||||||
|
setenv("LD_PRELOAD", INJECT_LIB_1, 1);
|
||||||
|
setenv(INJECT_ENV_1, "1", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute real app_process
|
||||||
|
xumount2(buf, MNT_DETACH);
|
||||||
|
execve(buf, argv, environ);
|
||||||
|
exit(1);
|
||||||
|
}
|
17
native/jni/inject/inject.hpp
Normal file
17
native/jni/inject/inject.hpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define INJECT_LIB_1 "/dev/tmp/magisk.1.so"
|
||||||
|
#define INJECT_LIB_2 "/dev/tmp/magisk.2.so"
|
||||||
|
#define INJECT_ENV_1 "MAGISK_INJ_1"
|
||||||
|
#define INJECT_ENV_2 "MAGISK_INJ_2"
|
||||||
|
|
||||||
|
// Unmap all pages matching the name
|
||||||
|
void unmap_all(const char *name);
|
||||||
|
|
||||||
|
// Get library name and base address that contains the function
|
||||||
|
uintptr_t get_function_lib(uintptr_t addr, char *lib);
|
||||||
|
|
||||||
|
// Get library base address with name
|
||||||
|
uintptr_t get_remote_lib(int pid, const char *lib);
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include <utils.hpp>
|
#include <utils.hpp>
|
||||||
|
|
||||||
|
#include "inject.hpp"
|
||||||
#include "ptrace.hpp"
|
#include "ptrace.hpp"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@ -43,80 +44,6 @@ using namespace std;
|
|||||||
#define ARM_r0 regs[0]
|
#define ARM_r0 regs[0]
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct map_info {
|
|
||||||
uintptr_t start;
|
|
||||||
uintptr_t end;
|
|
||||||
int perms;
|
|
||||||
char *path;
|
|
||||||
|
|
||||||
map_info() : start(0), end(0), perms(0), path(nullptr) {}
|
|
||||||
|
|
||||||
enum {
|
|
||||||
EXEC = (1 << 0),
|
|
||||||
WRITE = (1 << 1),
|
|
||||||
READ = (1 << 2),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Func signature: bool(map_info&)
|
|
||||||
template <typename Func>
|
|
||||||
static void parse_maps(int pid, Func fn) {
|
|
||||||
char file[32];
|
|
||||||
|
|
||||||
// format: start-end perms offset dev inode path
|
|
||||||
sprintf(file, "/proc/%d/maps", pid);
|
|
||||||
file_readline(true, file, [=](string_view l) -> bool {
|
|
||||||
char *pos = (char *) l.data();
|
|
||||||
map_info info;
|
|
||||||
|
|
||||||
// Parse address hex strings
|
|
||||||
info.start = strtoul(pos, &pos, 16);
|
|
||||||
info.end = strtoul(++pos, &pos, 16);
|
|
||||||
|
|
||||||
// Parse permissions
|
|
||||||
if (*(++pos) != '-')
|
|
||||||
info.perms |= map_info::READ;
|
|
||||||
if (*(++pos) != '-')
|
|
||||||
info.perms |= map_info::WRITE;
|
|
||||||
if (*(++pos) != '-')
|
|
||||||
info.perms |= map_info::EXEC;
|
|
||||||
pos += 3;
|
|
||||||
|
|
||||||
// Skip everything except path
|
|
||||||
int path_off;
|
|
||||||
sscanf(pos, "%*s %*s %*s %n%*s", &path_off);
|
|
||||||
pos += path_off;
|
|
||||||
info.path = pos;
|
|
||||||
|
|
||||||
return fn(info);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t get_function_lib(uintptr_t addr, char *lib) {
|
|
||||||
uintptr_t base = 0;
|
|
||||||
parse_maps(getpid(), [=, &base](map_info &info) -> bool {
|
|
||||||
if (addr >= info.start && addr < info.end) {
|
|
||||||
strcpy(lib, info.path);
|
|
||||||
base = info.start;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
return base;
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t get_remote_lib(int pid, const char *lib) {
|
|
||||||
uintptr_t base = 0;
|
|
||||||
parse_maps(pid, [=, &base](map_info &info) -> bool {
|
|
||||||
if (strcmp(info.path, lib) == 0 && (info.perms & map_info::EXEC)) {
|
|
||||||
base = info.start;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
return base;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _remote_read(int pid, uintptr_t addr, void *buf, size_t len) {
|
bool _remote_read(int pid, uintptr_t addr, void *buf, size_t len) {
|
||||||
for (size_t i = 0; i < len; i += sizeof(long)) {
|
for (size_t i = 0; i < len; i += sizeof(long)) {
|
||||||
long data = xptrace(PTRACE_PEEKTEXT, pid, reinterpret_cast<void*>(addr + i));
|
long data = xptrace(PTRACE_PEEKTEXT, pid, reinterpret_cast<void*>(addr + i));
|
||||||
@ -165,7 +92,7 @@ static void _remote_setregs(int pid, pt_regs *regs) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static uintptr_t remote_call_abi(int pid, uintptr_t func_addr, int nargs, va_list va) {
|
uintptr_t remote_call_abi(int pid, uintptr_t func_addr, int nargs, va_list va) {
|
||||||
pt_regs regs, regs_bak;
|
pt_regs regs, regs_bak;
|
||||||
|
|
||||||
// Get registers and save a backup
|
// Get registers and save a backup
|
||||||
@ -300,7 +227,11 @@ static uintptr_t remote_call_abi(int pid, uintptr_t func_addr, int nargs, va_lis
|
|||||||
uintptr_t remote_call_vararg(int pid, uintptr_t addr, int nargs, ...) {
|
uintptr_t remote_call_vararg(int pid, uintptr_t addr, int nargs, ...) {
|
||||||
char lib_name[4096];
|
char lib_name[4096];
|
||||||
auto local = get_function_lib(addr, lib_name);
|
auto local = get_function_lib(addr, lib_name);
|
||||||
|
if (local == 0)
|
||||||
|
return 0;
|
||||||
auto remote = get_remote_lib(pid, lib_name);
|
auto remote = get_remote_lib(pid, lib_name);
|
||||||
|
if (remote == 0)
|
||||||
|
return 0;
|
||||||
addr = addr - local + remote;
|
addr = addr - local + remote;
|
||||||
va_list va;
|
va_list va;
|
||||||
va_start(va, nargs);
|
va_start(va, nargs);
|
||||||
|
@ -2,12 +2,6 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// Get library name and base address that contains the function
|
|
||||||
uintptr_t get_function_lib(uintptr_t addr, char *lib);
|
|
||||||
|
|
||||||
// Get library base address with name
|
|
||||||
uintptr_t get_remote_lib(int pid, const char *lib);
|
|
||||||
|
|
||||||
// Write bytes to the remote process at addr
|
// Write bytes to the remote process at addr
|
||||||
bool _remote_write(int pid, uintptr_t addr, const void *buf, size_t len);
|
bool _remote_write(int pid, uintptr_t addr, const void *buf, size_t len);
|
||||||
#define remote_write(...) _remote_write(pid, __VA_ARGS__)
|
#define remote_write(...) _remote_write(pid, __VA_ARGS__)
|
||||||
@ -19,6 +13,9 @@ bool _remote_read(int pid, uintptr_t addr, void *buf, size_t len);
|
|||||||
// Call a remote function
|
// Call a remote function
|
||||||
// Arguments are expected to be only integer-like or pointer types
|
// Arguments are expected to be only integer-like or pointer types
|
||||||
// as other more complex C ABIs are not implemented.
|
// as other more complex C ABIs are not implemented.
|
||||||
|
uintptr_t remote_call_abi(int pid, uintptr_t func_addr, int nargs, va_list va);
|
||||||
|
|
||||||
|
// Find remote offset and invoke function
|
||||||
uintptr_t remote_call_vararg(int pid, uintptr_t addr, int nargs, ...);
|
uintptr_t remote_call_vararg(int pid, uintptr_t addr, int nargs, ...);
|
||||||
|
|
||||||
// C++ wrapper for auto argument counting and casting function pointers
|
// C++ wrapper for auto argument counting and casting function pointers
|
||||||
|
101
native/jni/inject/utils.cpp
Normal file
101
native/jni/inject/utils.cpp
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
#include <utils.hpp>
|
||||||
|
|
||||||
|
#include "inject.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct map_info {
|
||||||
|
uintptr_t start;
|
||||||
|
uintptr_t end;
|
||||||
|
int perms;
|
||||||
|
char *path;
|
||||||
|
|
||||||
|
map_info() : start(0), end(0), perms(0), path(nullptr) {}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
EXEC = (1 << 0),
|
||||||
|
WRITE = (1 << 1),
|
||||||
|
READ = (1 << 2),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
template<typename Func>
|
||||||
|
static void parse_maps(int pid, Func fn) {
|
||||||
|
char file[32];
|
||||||
|
|
||||||
|
// format: start-end perms offset dev inode path
|
||||||
|
sprintf(file, "/proc/%d/maps", pid);
|
||||||
|
file_readline(true, file, [=](string_view l) -> bool {
|
||||||
|
char *pos = (char *) l.data();
|
||||||
|
map_info info;
|
||||||
|
|
||||||
|
// Parse address hex strings
|
||||||
|
info.start = strtoul(pos, &pos, 16);
|
||||||
|
info.end = strtoul(++pos, &pos, 16);
|
||||||
|
|
||||||
|
// Parse permissions
|
||||||
|
if (*(++pos) != '-')
|
||||||
|
info.perms |= map_info::READ;
|
||||||
|
if (*(++pos) != '-')
|
||||||
|
info.perms |= map_info::WRITE;
|
||||||
|
if (*(++pos) != '-')
|
||||||
|
info.perms |= map_info::EXEC;
|
||||||
|
pos += 3;
|
||||||
|
|
||||||
|
// Skip everything except path
|
||||||
|
int path_off;
|
||||||
|
sscanf(pos, "%*s %*s %*s %n%*s", &path_off);
|
||||||
|
pos += path_off;
|
||||||
|
info.path = pos;
|
||||||
|
|
||||||
|
return fn(info);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void unmap_all(const char *name) {
|
||||||
|
vector<map_info> unmaps;
|
||||||
|
parse_maps(getpid(), [=, &unmaps](map_info &info) -> bool {
|
||||||
|
if (strcmp(info.path, name) == 0)
|
||||||
|
unmaps.emplace_back(info);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
for (map_info &info : unmaps) {
|
||||||
|
void *addr = reinterpret_cast<void *>(info.start);
|
||||||
|
size_t size = info.end - info.start;
|
||||||
|
munmap(addr, size);
|
||||||
|
if (info.perms & map_info::READ) {
|
||||||
|
// Make sure readable pages are still readable
|
||||||
|
xmmap(addr, size, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t get_function_lib(uintptr_t addr, char *lib) {
|
||||||
|
uintptr_t base = 0;
|
||||||
|
parse_maps(getpid(), [=, &base](map_info &info) -> bool {
|
||||||
|
if (addr >= info.start && addr < info.end) {
|
||||||
|
if (lib)
|
||||||
|
strcpy(lib, info.path);
|
||||||
|
base = info.start;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t get_remote_lib(int pid, const char *lib) {
|
||||||
|
uintptr_t base = 0;
|
||||||
|
parse_maps(pid, [=, &base](map_info &info) -> bool {
|
||||||
|
if (strcmp(info.path, lib) == 0 && (info.perms & map_info::EXEC)) {
|
||||||
|
base = info.start;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
return base;
|
||||||
|
}
|
@ -339,7 +339,6 @@ static void new_zygote(int pid) {
|
|||||||
xptrace(PTRACE_CONT, pid);
|
xptrace(PTRACE_CONT, pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define WEVENT(s) (((s) & 0xffff0000) >> 16)
|
|
||||||
#define DETACH_AND_CONT { detach_pid(pid); continue; }
|
#define DETACH_AND_CONT { detach_pid(pid); continue; }
|
||||||
|
|
||||||
void proc_monitor() {
|
void proc_monitor() {
|
||||||
|
@ -113,12 +113,12 @@ int exec_command_sync(exec_t &exec) {
|
|||||||
return WEXITSTATUS(status);
|
return WEXITSTATUS(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
int new_daemon_thread(thread_entry entry, void *arg, const pthread_attr_t *attr) {
|
int new_daemon_thread(thread_entry entry, void *arg) {
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
int ret = xpthread_create(&thread, attr, entry, arg);
|
pthread_attr_t attr;
|
||||||
if (ret == 0)
|
pthread_attr_init(&attr);
|
||||||
pthread_detach(thread);
|
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||||
return ret;
|
return xpthread_create(&thread, &attr, entry, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *proxy_routine(void *fp) {
|
static void *proxy_routine(void *fp) {
|
||||||
|
@ -59,7 +59,7 @@ static inline int parse_int(const std::string &s) { return parse_int(s.data());
|
|||||||
static inline int parse_int(std::string_view s) { return parse_int(s.data()); }
|
static inline int parse_int(std::string_view s) { return parse_int(s.data()); }
|
||||||
|
|
||||||
using thread_entry = void *(*)(void *);
|
using thread_entry = void *(*)(void *);
|
||||||
int new_daemon_thread(thread_entry entry, void *arg = nullptr, const pthread_attr_t *attr = nullptr);
|
int new_daemon_thread(thread_entry entry, void *arg = nullptr);
|
||||||
int new_daemon_thread(std::function<void()> &&entry);
|
int new_daemon_thread(std::function<void()> &&entry);
|
||||||
|
|
||||||
static inline bool str_contains(std::string_view s, std::string_view ss) {
|
static inline bool str_contains(std::string_view s, std::string_view ss) {
|
||||||
|
@ -64,3 +64,4 @@ long xptrace(int request, pid_t pid, void *addr = nullptr, void *data = nullptr)
|
|||||||
static inline long xptrace(int request, pid_t pid, void *addr, uintptr_t data) {
|
static inline long xptrace(int request, pid_t pid, void *addr, uintptr_t data) {
|
||||||
return xptrace(request, pid, addr, reinterpret_cast<void *>(data));
|
return xptrace(request, pid, addr, reinterpret_cast<void *>(data));
|
||||||
}
|
}
|
||||||
|
#define WEVENT(s) (((s) & 0xffff0000) >> 16)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user