Use magiskd to setup files

This commit is contained in:
topjohnwu 2021-08-18 03:44:32 -07:00
parent 003fea52b1
commit 9b3efffba9
6 changed files with 118 additions and 62 deletions

View File

@ -68,6 +68,9 @@ static void handle_request_async(int client, int code, ucred cred) {
close(client); close(client);
reboot(); reboot();
break; break;
case ZYGISK_REQUEST:
zygisk_handler(client, &cred);
break;
default: default:
close(client); close(client);
break; break;
@ -116,6 +119,7 @@ static void handle_request(int client) {
case BOOT_COMPLETE: case BOOT_COMPLETE:
case SQLITE_CMD: case SQLITE_CMD:
case GET_PATH: case GET_PATH:
case MAGISKHIDE:
if (!is_root) { if (!is_root) {
write_int(client, ROOT_REQUIRED); write_int(client, ROOT_REQUIRED);
goto done; goto done;
@ -127,9 +131,9 @@ static void handle_request(int client) {
goto done; goto done;
} }
break; break;
case MAGISKHIDE: // accept hide request from zygote case ZYGISK_REQUEST:
if (!is_root && !is_zygote) { if (!is_zygote) {
write_int(client, ROOT_REQUIRED); write_int(client, DAEMON_ERROR);
goto done; goto done;
} }
break; break;
@ -260,7 +264,7 @@ int connect_daemon(bool create) {
if (connect(fd, (sockaddr*) &sun, len)) { if (connect(fd, (sockaddr*) &sun, len)) {
if (!create || getuid() != UID_ROOT) { if (!create || getuid() != UID_ROOT) {
LOGE("No daemon is currently running!\n"); LOGE("No daemon is currently running!\n");
exit(1); return 1;
} }
if (fork_dont_care() == 0) { if (fork_dont_care() == 0) {

View File

@ -158,6 +158,16 @@ void magisk_logging() {
log_cb.ex = nop_ex; log_cb.ex = nop_ex;
} }
#define alog(prio) [](auto fmt, auto ap){ \
return __android_log_vprint(ANDROID_LOG_##prio, "Magisk", fmt, ap); }
void android_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;
}
void start_log_daemon() { void start_log_daemon() {
int fds[2]; int fds[2];
if (pipe2(fds, O_CLOEXEC) == 0) { if (pipe2(fds, O_CLOEXEC) == 0) {

View File

@ -25,6 +25,7 @@ enum : int {
MAGISKHIDE, MAGISKHIDE,
SQLITE_CMD, SQLITE_CMD,
REMOVE_MODULES, REMOVE_MODULES,
ZYGISK_REQUEST,
DAEMON_CODE_END, DAEMON_CODE_END,
}; };
@ -47,12 +48,15 @@ enum : int {
int connect_daemon(bool create = false); int connect_daemon(bool create = false);
void android_logging();
// Daemon handlers // Daemon handlers
void post_fs_data(int client); void post_fs_data(int client);
void late_start(int client); void late_start(int client);
void boot_complete(int client); void boot_complete(int client);
void magiskhide_handler(int client, ucred *cred); void magiskhide_handler(int client, ucred *cred);
void su_daemon_handler(int client, ucred *credential); void su_daemon_handler(int client, ucred *credential);
void zygisk_handler(int client, ucred *cred);
// MagiskHide // MagiskHide
void check_enable_hide(); void check_enable_hide();

View File

@ -3,9 +3,10 @@
#include <sys/mount.h> #include <sys/mount.h>
#include <sys/sendfile.h> #include <sys/sendfile.h>
#include <sys/prctl.h> #include <sys/prctl.h>
#include <android/log.h>
#include <utils.hpp> #include <utils.hpp>
#include <daemon.hpp>
#include <magisk.hpp>
#include "inject.hpp" #include "inject.hpp"
@ -14,16 +15,6 @@ using namespace std;
static void *self_handle = nullptr; static void *self_handle = nullptr;
static atomic<int> active_threads = -1; 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;
}
void self_unload() { void self_unload() {
LOGD("hook: Request to self unload\n"); LOGD("hook: Request to self unload\n");
// If unhook failed, do not unload or else it will cause SIGSEGV // If unhook failed, do not unload or else it will cause SIGSEGV
@ -33,7 +24,7 @@ void self_unload() {
active_threads--; active_threads--;
} }
static void *unload_first_stage(void *) { static void *unload_first_stage(void *v) {
// Setup 1ms // Setup 1ms
timespec ts = { .tv_sec = 0, .tv_nsec = 1000000L }; timespec ts = { .tv_sec = 0, .tv_nsec = 1000000L };
@ -43,7 +34,8 @@ static void *unload_first_stage(void *) {
// Wait another 1ms to make sure all threads left our code // Wait another 1ms to make sure all threads left our code
nanosleep(&ts, nullptr); nanosleep(&ts, nullptr);
unmap_all(INJECT_LIB_1); char *path = static_cast<char *>(v);
unmap_all(path);
active_threads--; active_threads--;
return nullptr; return nullptr;
} }
@ -87,66 +79,108 @@ static void inject_cleanup_wait() {
__attribute__((constructor)) __attribute__((constructor))
static void inject_init() { static void inject_init() {
if (getenv(INJECT_ENV_2)) { if (char *env = getenv(INJECT_ENV_2)) {
inject_logging(); android_logging();
LOGD("zygote: inject 2nd stage\n"); LOGD("zygote: inject 2nd stage\n");
active_threads = 1; active_threads = 1;
unsetenv(INJECT_ENV_2); unsetenv(INJECT_ENV_2);
// Get our own handle // Get our own handle
self_handle = dlopen(INJECT_LIB_2, RTLD_LAZY); self_handle = dlopen(env, RTLD_LAZY);
dlclose(self_handle); dlclose(self_handle);
unlink(INJECT_LIB_2);
hook_functions(); hook_functions();
// Update path to 1st stage lib
*(strrchr(env, '.') - 1) = '1';
// Some cleanup // Some cleanup
sanitize_environ(); sanitize_environ();
active_threads++; active_threads++;
new_daemon_thread(&unload_first_stage); new_daemon_thread(&unload_first_stage, env);
} else if (char *env = getenv(INJECT_ENV_1)) { } else if (getenv(INJECT_ENV_1)) {
inject_logging(); android_logging();
LOGD("zygote: inject 1st stage\n"); LOGD("zygote: inject 1st stage\n");
if (env[0] == '1') char *ld = getenv("LD_PRELOAD");
char *path;
if (char *c = strrchr(ld, ':')) {
*c = '\0';
setenv("LD_PRELOAD", ld, 1); // Restore original LD_PRELOAD
path = c + 1;
} else {
unsetenv("LD_PRELOAD"); unsetenv("LD_PRELOAD");
else path = ld;
setenv("LD_PRELOAD", env, 1); // Restore original LD_PRELOAD }
// Update path to 2nd stage lib
*(strrchr(path, '.') - 1) = '2';
// Setup second stage // Setup second stage
setenv(INJECT_ENV_2, "1", 1); setenv(INJECT_ENV_2, path, 1);
cp_afc(INJECT_LIB_1, INJECT_LIB_2); dlopen(path, RTLD_LAZY);
dlopen(INJECT_LIB_2, RTLD_LAZY);
unlink(INJECT_LIB_1);
unsetenv(INJECT_ENV_1); unsetenv(INJECT_ENV_1);
} }
} }
int app_process_main(int argc, char *argv[]) { int app_process_main(int argc, char *argv[]) {
inject_logging(); android_logging();
char buf[4096];
if (realpath("/proc/self/exe", buf) == nullptr)
return 1;
int in = xopen(buf, O_RDONLY); if (int fd = connect_daemon(); fd >= 0) {
int out = xopen(INJECT_LIB_1, O_WRONLY | O_CREAT, 0644); write_int(fd, ZYGISK_REQUEST);
sendfile(out, in, nullptr, INT_MAX); write_int(fd, ZYGISK_SETUP);
close(in);
close(out);
if (char *ld = getenv("LD_PRELOAD")) { if (read_int(fd) == 0) {
char env[128]; string path = read_string(fd);
sprintf(env, "%s:" INJECT_LIB_1, ld); string lib = path + ".1.so";
setenv("LD_PRELOAD", env, 1); if (char *ld = getenv("LD_PRELOAD")) {
setenv(INJECT_ENV_1, ld, 1); // Backup original LD_PRELOAD char env[256];
} else { sprintf(env, "%s:%s", ld, lib.data());
setenv("LD_PRELOAD", INJECT_LIB_1, 1); setenv("LD_PRELOAD", env, 1);
setenv(INJECT_ENV_1, "1", 1); } else {
setenv("LD_PRELOAD", lib.data(), 1);
}
setenv(INJECT_ENV_1, "1", 1);
}
close(fd);
} }
// Execute real app_process // Execute real app_process
xumount2(buf, MNT_DETACH); char buf[256];
xreadlink("/proc/self/exe", buf, sizeof(buf));
xumount2("/proc/self/exe", MNT_DETACH);
execve(buf, argv, environ); execve(buf, argv, environ);
return 1; return 1;
} }
// The following code runs in magiskd
static void setup_files(int client, ucred *cred) {
LOGD("zygisk: setup files\n");
char buf[PATH_MAX];
sprintf(buf, "/proc/%d/exe", cred->pid);
if (realpath(buf, buf) == nullptr) {
write_int(client, 1);
return;
}
write_int(client, 0);
string path = MAGISKTMP + "/zygisk." + basename(buf);
cp_afc(buf, (path + ".1.so").data());
cp_afc(buf, (path + ".2.so").data());
write_string(client, path);
}
void zygisk_handler(int client, ucred *cred) {
int code = read_int(client);
switch (code) {
case ZYGISK_SETUP:
setup_files(client, cred);
break;
}
close(client);
}

View File

@ -3,11 +3,13 @@
#include <stdint.h> #include <stdint.h>
#include <jni.h> #include <jni.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_1 "MAGISK_INJ_1"
#define INJECT_ENV_2 "MAGISK_INJ_2" #define INJECT_ENV_2 "MAGISK_INJ_2"
enum : int {
ZYGISK_SETUP,
};
// Unmap all pages matching the name // Unmap all pages matching the name
void unmap_all(const char *name); void unmap_all(const char *name);

View File

@ -23,7 +23,7 @@ abort() {
mount_sbin() { mount_sbin() {
mount -t tmpfs -o 'mode=0755' tmpfs /sbin mount -t tmpfs -o 'mode=0755' tmpfs /sbin
$SELINUX && chcon u:object_r:rootfs:s0 /sbin chcon u:object_r:rootfs:s0 /sbin
} }
if [ ! -f /system/build.prop ]; then if [ ! -f /system/build.prop ]; then
@ -56,14 +56,14 @@ fi
pgrep magiskd >/dev/null && pkill -9 magiskd pgrep magiskd >/dev/null && pkill -9 magiskd
[ -f /sbin/magisk ] && umount -l /sbin [ -f /sbin/magisk ] && umount -l /sbin
[ -f /system/bin/magisk ] && umount -l /system/bin [ -f /system/bin/magisk ] && umount -l /system/bin
if [ -d /dev/magisk ]; then
umount -l /dev/magisk 2>/dev/null
rm -rf /dev/magisk
fi
# SELinux stuffs # SELinux stuffs
SELINUX=false ln -sf ./magiskinit magiskpolicy
[ -e /sys/fs/selinux ] && SELINUX=true ./magiskpolicy --live --magisk
if $SELINUX; then
ln -sf ./magiskinit magiskpolicy
./magiskpolicy --live --magisk
fi
BINDIR=/sbin BINDIR=/sbin
@ -99,12 +99,14 @@ elif [ -e /sbin ]; then
done done
else else
# Android Q+ without sbin, use overlayfs # Android Q+ without sbin, use overlayfs
BINDIR=/system/bin BINDIR=/dev/magisk/upper
rm -rf /dev/magisk mkdir /dev/magisk
mkdir -p /dev/magisk/upper mount -t tmpfs -o 'mode=0755' tmpfs /dev/magisk
chcon u:object_r:system_file:s0 /dev/magisk
mkdir /dev/magisk/upper
mkdir /dev/magisk/work mkdir /dev/magisk/work
./magisk --clone-attr /system/bin /dev/magisk/upper ./magisk --clone-attr /system/bin /dev/magisk/upper
mount -t overlay overlay -olowerdir=/system/bin,upperdir=/dev/magisk/upper,workdir=/dev/magisk/work /system/bin mount -t overlay overlay -o lowerdir=/system/bin,upperdir=/dev/magisk/upper,workdir=/dev/magisk/work /system/bin
fi fi
# Magisk stuffs # Magisk stuffs