mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-24 18:45:28 +00:00
Introduce zygisk loader
Use a separate library for 1st stage
This commit is contained in:
parent
6bfe34e5a8
commit
9806b38d8e
51
build.py
51
build.py
@ -203,16 +203,6 @@ def clean_elf():
|
||||
execv(args)
|
||||
|
||||
|
||||
def binary_dump(src, var_name):
|
||||
out_str = f'constexpr unsigned char {var_name}[] = {{'
|
||||
for i, c in enumerate(xz(src.read())):
|
||||
if i % 16 == 0:
|
||||
out_str += '\n'
|
||||
out_str += f'0x{c:02X},'
|
||||
out_str += '\n};\n'
|
||||
return out_str
|
||||
|
||||
|
||||
def run_ndk_build(flags):
|
||||
os.chdir('native')
|
||||
flags = 'NDK_PROJECT_PATH=. NDK_APPLICATION_MK=src/Application.mk ' + flags
|
||||
@ -221,7 +211,7 @@ def run_ndk_build(flags):
|
||||
error('Build binary failed!')
|
||||
os.chdir('..')
|
||||
for arch in archs:
|
||||
for tgt in support_targets + ['libpreload.so']:
|
||||
for tgt in support_targets + ['libinit-ld.so', 'libzygisk-ld.so']:
|
||||
source = op.join('native', 'libs', arch, tgt)
|
||||
target = op.join('native', 'out', arch, tgt)
|
||||
mv(source, target)
|
||||
@ -306,6 +296,16 @@ def write_if_diff(file_name, text):
|
||||
f.write(text)
|
||||
|
||||
|
||||
def binary_dump(src, var_name, compressor=xz):
|
||||
out_str = f'constexpr unsigned char {var_name}[] = {{'
|
||||
for i, c in enumerate(compressor(src.read())):
|
||||
if i % 16 == 0:
|
||||
out_str += '\n'
|
||||
out_str += f'0x{c:02X},'
|
||||
out_str += '\n};\n'
|
||||
return out_str
|
||||
|
||||
|
||||
def dump_bin_header(args):
|
||||
stub = op.join(config['outdir'], f'stub-{"release" if args.release else "debug"}.apk')
|
||||
if not op.exists(stub):
|
||||
@ -315,10 +315,13 @@ def dump_bin_header(args):
|
||||
text = binary_dump(src, 'manager_xz')
|
||||
write_if_diff(op.join(native_gen_path, 'binaries.h'), text)
|
||||
for arch in archs:
|
||||
preload = op.join('native', 'out', arch, 'libpreload.so')
|
||||
preload = op.join('native', 'out', arch, 'libinit-ld.so')
|
||||
with open(preload, 'rb') as src:
|
||||
text = binary_dump(src, 'preload_xz')
|
||||
write_if_diff(op.join(native_gen_path, f'{arch}_binaries.h'), text)
|
||||
text = binary_dump(src, 'init_ld_xz')
|
||||
preload = op.join('native', 'out', arch, 'libzygisk-ld.so')
|
||||
with open(preload, 'rb') as src:
|
||||
text += binary_dump(src, 'zygisk_ld', compressor=lambda x: x)
|
||||
write_if_diff(op.join(native_gen_path, f'{arch}_binaries.h'), text)
|
||||
|
||||
|
||||
def dump_flag_header():
|
||||
@ -363,8 +366,8 @@ def build_binary(args):
|
||||
|
||||
flag = ''
|
||||
|
||||
if 'magisk' in args.target:
|
||||
flag += ' B_MAGISK=1'
|
||||
if 'magisk' in args.target or 'magiskinit' in args.target:
|
||||
flag += ' B_PRELOAD=1'
|
||||
|
||||
if 'magiskpolicy' in args.target:
|
||||
flag += ' B_POLICY=1'
|
||||
@ -383,13 +386,23 @@ def build_binary(args):
|
||||
|
||||
if flag:
|
||||
run_ndk_build(flag)
|
||||
clean_elf()
|
||||
|
||||
# magiskinit and busybox has to be built separately
|
||||
# magiskinit and magisk embeds preload.so
|
||||
|
||||
flag = ''
|
||||
|
||||
if 'magisk' in args.target:
|
||||
flag += ' B_MAGISK=1'
|
||||
|
||||
if 'magiskinit' in args.target:
|
||||
flag += ' B_INIT=1'
|
||||
|
||||
if flag:
|
||||
dump_bin_header(args)
|
||||
run_ndk_build('B_INIT=1')
|
||||
run_ndk_build(flag)
|
||||
clean_elf()
|
||||
|
||||
# BusyBox is built with different libc
|
||||
|
||||
if 'busybox' in args.target:
|
||||
run_ndk_build('B_BB=1')
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user