mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-12-10 05:03:14 +00:00
Introduce zygisk loader
Use a separate library for 1st stage
This commit is contained in:
@@ -47,6 +47,7 @@ LOCAL_SRC_FILES := \
|
||||
zygisk/deny/revert.cpp
|
||||
|
||||
LOCAL_LDLIBS := -llog
|
||||
LOCAL_LDFLAGS := -Wl,--dynamic-list=src/exported_sym.txt
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -55,10 +56,15 @@ endif
|
||||
ifdef B_PRELOAD
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := preload
|
||||
LOCAL_MODULE := init-ld
|
||||
LOCAL_SRC_FILES := init/preload.c
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := zygisk-ld
|
||||
LOCAL_SRC_FILES := zygisk/loader.c
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
endif
|
||||
|
||||
ifdef B_INIT
|
||||
|
||||
@@ -28,5 +28,5 @@ LOCAL_MODULE := libcompat
|
||||
LOCAL_SRC_FILES := compat/compat.cpp
|
||||
# Fix static variables' ctor/dtor when using LTO
|
||||
# See: https://github.com/android/ndk/issues/1461
|
||||
LOCAL_EXPORT_LDLIBS := -static -T src/lto_fix.lds
|
||||
LOCAL_EXPORT_LDFLAGS := -static -T src/lto_fix.lds
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
13
native/src/base/include/embed.hpp
Normal file
13
native/src/base/include/embed.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#include <binaries.h>
|
||||
|
||||
#if defined(__arm__)
|
||||
#include <armeabi-v7a_binaries.h>
|
||||
#elif defined(__aarch64__)
|
||||
#include <arm64-v8a_binaries.h>
|
||||
#elif defined(__i386__)
|
||||
#include <x86_binaries.h>
|
||||
#elif defined(__x86_64__)
|
||||
#include <x86_64_binaries.h>
|
||||
#else
|
||||
#error Unsupported ABI
|
||||
#endif
|
||||
@@ -567,19 +567,13 @@ int app_process_64 = -1;
|
||||
if (access("/system/bin/app_process" #bit, F_OK) == 0) { \
|
||||
app_process_##bit = xopen("/system/bin/app_process" #bit, O_RDONLY | O_CLOEXEC); \
|
||||
string zbin = zygisk_bin + "/app_process" #bit; \
|
||||
string dbin = zygisk_bin + "/magisk" #bit; \
|
||||
string mbin = MAGISKTMP + "/magisk" #bit; \
|
||||
int src = xopen(mbin.data(), O_RDONLY | O_CLOEXEC); \
|
||||
int out = xopen(zbin.data(), O_CREAT | O_WRONLY | O_CLOEXEC, 0); \
|
||||
xsendfile(out, src, nullptr, INT_MAX); \
|
||||
close(out); \
|
||||
out = xopen(dbin.data(), O_CREAT | O_WRONLY | O_CLOEXEC, 0); \
|
||||
lseek(src, 0, SEEK_SET); \
|
||||
xsendfile(out, src, nullptr, INT_MAX); \
|
||||
close(out); \
|
||||
close(src); \
|
||||
clone_attr("/system/bin/app_process" #bit, zbin.data()); \
|
||||
clone_attr("/system/bin/app_process" #bit, dbin.data()); \
|
||||
bind_mount(zbin.data(), "/system/bin/app_process" #bit); \
|
||||
}
|
||||
|
||||
|
||||
3
native/src/exported_sym.txt
Normal file
3
native/src/exported_sym.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
zygisk_inject_entry;
|
||||
};
|
||||
@@ -6,19 +6,7 @@
|
||||
#include <xz.h>
|
||||
|
||||
#include <base.hpp>
|
||||
#include <binaries.h>
|
||||
|
||||
#if defined(__arm__)
|
||||
#include <armeabi-v7a_binaries.h>
|
||||
#elif defined(__aarch64__)
|
||||
#include <arm64-v8a_binaries.h>
|
||||
#elif defined(__i386__)
|
||||
#include <x86_binaries.h>
|
||||
#elif defined(__x86_64__)
|
||||
#include <x86_64_binaries.h>
|
||||
#else
|
||||
#error Unsupported ABI
|
||||
#endif
|
||||
#include <embed.hpp>
|
||||
|
||||
#include "init.hpp"
|
||||
|
||||
@@ -78,7 +66,7 @@ int dump_manager(const char *path, mode_t mode) {
|
||||
}
|
||||
|
||||
int dump_preload(const char *path, mode_t mode) {
|
||||
return dump_bin(preload_xz, sizeof(preload_xz), path, mode);
|
||||
return dump_bin(init_ld_xz, sizeof(init_ld_xz), path, mode);
|
||||
}
|
||||
|
||||
class RecoveryInit : public BaseInit {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <base.hpp>
|
||||
#include <daemon.hpp>
|
||||
#include <magisk.hpp>
|
||||
#include <selinux.hpp>
|
||||
|
||||
#include "zygisk.hpp"
|
||||
#include "module.hpp"
|
||||
@@ -51,30 +52,9 @@ static void *unload_first_stage(void *) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if defined(__LP64__)
|
||||
// Use symlink to workaround linker bug on old broken Android
|
||||
// https://issuetracker.google.com/issues/36914295
|
||||
#define SECOND_STAGE_PATH "/system/bin/app_process"
|
||||
#else
|
||||
#define SECOND_STAGE_PATH "/system/bin/app_process32"
|
||||
#endif
|
||||
|
||||
static void second_stage_entry() {
|
||||
extern "C" void zygisk_inject_entry(void *handle) {
|
||||
zygisk_logging();
|
||||
ZLOGD("inject 2nd stage\n");
|
||||
|
||||
MAGISKTMP = getenv(MAGISKTMP_ENV);
|
||||
self_handle = dlopen(SECOND_STAGE_PATH, RTLD_NOLOAD);
|
||||
dlclose(self_handle);
|
||||
|
||||
unsetenv(MAGISKTMP_ENV);
|
||||
sanitize_environ();
|
||||
hook_functions();
|
||||
new_daemon_thread(&unload_first_stage, nullptr);
|
||||
}
|
||||
|
||||
static void first_stage_entry() {
|
||||
ZLOGD("inject 1st stage\n");
|
||||
ZLOGD("load success\n");
|
||||
|
||||
char *ld = getenv("LD_PRELOAD");
|
||||
if (char *c = strrchr(ld, ':')) {
|
||||
@@ -84,31 +64,13 @@ static void first_stage_entry() {
|
||||
unsetenv("LD_PRELOAD");
|
||||
}
|
||||
|
||||
// Load second stage
|
||||
android_dlextinfo info {
|
||||
.flags = ANDROID_DLEXT_FORCE_LOAD
|
||||
};
|
||||
setenv(INJECT_ENV_2, "1", 1);
|
||||
if (android_dlopen_ext(SECOND_STAGE_PATH, RTLD_LAZY, &info) == nullptr) {
|
||||
// Android 5.x doesn't support ANDROID_DLEXT_FORCE_LOAD
|
||||
ZLOGI("ANDROID_DLEXT_FORCE_LOAD is not supported, fallback to dlopen\n");
|
||||
if (dlopen(SECOND_STAGE_PATH, RTLD_LAZY) == nullptr) {
|
||||
ZLOGE("Cannot load the second stage\n");
|
||||
unsetenv(INJECT_ENV_2);
|
||||
}
|
||||
}
|
||||
}
|
||||
MAGISKTMP = getenv(MAGISKTMP_ENV);
|
||||
self_handle = handle;
|
||||
|
||||
[[gnu::constructor]] [[maybe_unused]]
|
||||
static void zygisk_init() {
|
||||
android_logging();
|
||||
if (getenv(INJECT_ENV_1)) {
|
||||
unsetenv(INJECT_ENV_1);
|
||||
first_stage_entry();
|
||||
} else if (getenv(INJECT_ENV_2)) {
|
||||
unsetenv(INJECT_ENV_2);
|
||||
second_stage_entry();
|
||||
}
|
||||
unsetenv(MAGISKTMP_ENV);
|
||||
sanitize_environ();
|
||||
hook_functions();
|
||||
new_daemon_thread(&unload_first_stage, nullptr);
|
||||
}
|
||||
|
||||
// The following code runs in zygote/app process
|
||||
@@ -239,7 +201,7 @@ static int zygote_start_counts[] = { 0, 0 };
|
||||
static void setup_files(int client, const sock_cred *cred) {
|
||||
LOGD("zygisk: setup files for pid=[%d]\n", cred->pid);
|
||||
|
||||
char buf[256];
|
||||
char buf[4096];
|
||||
if (!get_exe(cred->pid, buf, sizeof(buf))) {
|
||||
write_int(client, 1);
|
||||
return;
|
||||
@@ -278,22 +240,31 @@ static void setup_files(int client, const sock_cred *cred) {
|
||||
}
|
||||
}
|
||||
|
||||
// Hijack some binary in /system/bin to host 1st stage
|
||||
// Ack
|
||||
write_int(client, 0);
|
||||
|
||||
// Hijack some binary in /system/bin to host loader
|
||||
const char *hbin;
|
||||
string mbin;
|
||||
int app_fd;
|
||||
if (is_64_bit) {
|
||||
hbin = HIJACK_BIN64;
|
||||
mbin = MAGISKTMP + "/" ZYGISKBIN "/magisk64";
|
||||
mbin = MAGISKTMP + "/" ZYGISKBIN "/loader64.so";
|
||||
app_fd = app_process_64;
|
||||
} else {
|
||||
hbin = HIJACK_BIN32;
|
||||
mbin = MAGISKTMP + "/" ZYGISKBIN "/magisk32";
|
||||
mbin = MAGISKTMP + "/" ZYGISKBIN "/loader32.so";
|
||||
app_fd = app_process_32;
|
||||
}
|
||||
|
||||
// Receive and bind mount loader
|
||||
int ld_fd = xopen(mbin.data(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0755);
|
||||
string ld_data = read_string(client);
|
||||
xwrite(ld_fd, ld_data.data(), ld_data.size());
|
||||
close(ld_fd);
|
||||
setfilecon(mbin.data(), "u:object_r:" SEPOL_FILE_TYPE ":s0");
|
||||
xmount(mbin.data(), hbin, nullptr, MS_BIND, nullptr);
|
||||
|
||||
write_int(client, 0);
|
||||
send_fd(client, app_fd);
|
||||
write_string(client, MAGISKTMP);
|
||||
}
|
||||
|
||||
27
native/src/zygisk/loader.c
Normal file
27
native/src/zygisk/loader.c
Normal file
@@ -0,0 +1,27 @@
|
||||
#include <dlfcn.h>
|
||||
#include <android/dlext.h>
|
||||
|
||||
#if defined(__LP64__)
|
||||
// Use symlink to workaround linker bug on old broken Android
|
||||
// https://issuetracker.google.com/issues/36914295
|
||||
#define SECOND_STAGE_PATH "/system/bin/app_process"
|
||||
#else
|
||||
#define SECOND_STAGE_PATH "/system/bin/app_process32"
|
||||
#endif
|
||||
|
||||
__attribute__((constructor))
|
||||
static void zygisk_loader() {
|
||||
android_dlextinfo info = {
|
||||
.flags = ANDROID_DLEXT_FORCE_LOAD
|
||||
};
|
||||
// Android 5.x doesn't support ANDROID_DLEXT_FORCE_LOAD
|
||||
void *handle =
|
||||
android_dlopen_ext(SECOND_STAGE_PATH, RTLD_LAZY, &info) ?:
|
||||
dlopen(SECOND_STAGE_PATH, RTLD_LAZY);
|
||||
if (handle) {
|
||||
void(*entry)(void*) = dlsym(handle, "zygisk_inject_entry");
|
||||
if (entry) {
|
||||
entry(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <socket.hpp>
|
||||
#include <daemon.hpp>
|
||||
#include <selinux.hpp>
|
||||
#include <embed.hpp>
|
||||
|
||||
#include "zygisk.hpp"
|
||||
|
||||
@@ -73,6 +74,10 @@ int app_process_main(int argc, char *argv[]) {
|
||||
if (read_int(socket) != 0)
|
||||
break;
|
||||
|
||||
// Send over zygisk loader
|
||||
write_int(socket, sizeof(zygisk_ld));
|
||||
xwrite(socket, zygisk_ld, sizeof(zygisk_ld));
|
||||
|
||||
int app_proc_fd = recv_fd(socket);
|
||||
if (app_proc_fd < 0)
|
||||
break;
|
||||
@@ -86,7 +91,6 @@ int app_process_main(int argc, char *argv[]) {
|
||||
} else {
|
||||
setenv("LD_PRELOAD", HIJACK_BIN, 1);
|
||||
}
|
||||
setenv(INJECT_ENV_1, "1", 1);
|
||||
setenv(MAGISKTMP_ENV, tmp.data(), 1);
|
||||
|
||||
close(socket);
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
#include <vector>
|
||||
#include <daemon.hpp>
|
||||
|
||||
#define INJECT_ENV_1 "MAGISK_INJ_1"
|
||||
#define INJECT_ENV_2 "MAGISK_INJ_2"
|
||||
#define MAGISKTMP_ENV "MAGISKTMP"
|
||||
|
||||
#define HIJACK_BIN64 "/system/bin/appwidget"
|
||||
@@ -55,7 +53,6 @@ extern void *self_handle;
|
||||
|
||||
void hook_functions();
|
||||
int remote_get_info(int uid, const char *process, uint32_t *flags, std::vector<int> &fds);
|
||||
int remote_request_unmount();
|
||||
|
||||
inline int zygisk_request(int req) {
|
||||
int fd = connect_daemon(MainRequest::ZYGISK);
|
||||
|
||||
Reference in New Issue
Block a user