Commit b278d07b authored by topjohnwu's avatar topjohnwu

Switch to Zygote ptrace-ing

No matter if we use the old, buggy, error prone am_proc_start monitoring,
or the new APK inotify method, both methods rely on MagiskHide 'reacting'
fast enough to hijack the process before any detection has been done.

However, this is not reliable and practical. There are apps that utilize
native libraries to start detects and register SIGCONT signal handlers
to mitigate all existing MagiskHide process monitoring mechanism. So
our only solution is to hijack an app BEFORE it is started.

All Android apps' process is forked from zygote, so it is easily the
target to be monitored. All forks will be notified, and subsequent
thread spawning (Android apps are heaviliy multithreaded) from children
are also closely monitored to find the earliest possible point to
identify what the process will eventually be (before am_proc_bound).

ptrace is extremely complicated and very difficult to get right. The
current code is heaviliy tested on a stock Android 9.0 Pixel system,
so in theory it should work fine on most devices, but more tests and
potentially fixes are expected to follow this commit.
parent 6c389607
...@@ -5,14 +5,14 @@ ...@@ -5,14 +5,14 @@
* execution, load modules, install Magisk Manager etc. * execution, load modules, install Magisk Manager etc.
*/ */
#include <sys/mount.h>
#include <sys/wait.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <string.h> #include <string.h>
#include <dirent.h> #include <dirent.h>
#include <sys/mount.h>
#include <sys/wait.h>
#include <vector> #include <vector>
#include <string> #include <string>
...@@ -589,16 +589,6 @@ static void dump_logs() { ...@@ -589,16 +589,6 @@ static void dump_logs() {
unblock_boot_process(); unblock_boot_process();
} }
void zygote_notify(int client, struct ucred *cred) {
/* TODO: notify services that need zygote PIDs */
char *path = read_string(client);
LOGD("%s PID=[%d]\n", path, cred->pid);
close(client);
usleep(100000);
bind_mount(MAGISKTMP "/app_process", path);
free(path);
}
void post_fs_data(int client) { void post_fs_data(int client) {
// ack // ack
write_int(client, 0); write_int(client, 0);
......
...@@ -61,7 +61,6 @@ void write_key_token(int fd, const char *key, int tok); ...@@ -61,7 +61,6 @@ void write_key_token(int fd, const char *key, int tok);
***************/ ***************/
void unlock_blocks(); void unlock_blocks();
void zygote_notify(int client, struct ucred *cred);
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);
...@@ -80,6 +79,8 @@ void install_apk(const char *apk); ...@@ -80,6 +79,8 @@ void install_apk(const char *apk);
**************/ **************/
void magiskhide_handler(int client); void magiskhide_handler(int client);
void zygote_notify(int client, struct ucred *cred);
void zygote_notify(int pid);
/************* /*************
* Superuser * * Superuser *
......
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
...@@ -5,8 +8,6 @@ ...@@ -5,8 +8,6 @@
#include <dirent.h> #include <dirent.h>
#include <string.h> #include <string.h>
#include <libgen.h> #include <libgen.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <magisk.h> #include <magisk.h>
#include <utils.h> #include <utils.h>
...@@ -136,7 +137,7 @@ static int add_list(const char *pkg, const char *proc = "") { ...@@ -136,7 +137,7 @@ static int add_list(const char *pkg, const char *proc = "") {
// Critical region // Critical region
{ {
MutexGuard lock(map_lock); MutexGuard lock(monitor_lock);
hide_map[proc] = pkg; hide_map[proc] = pkg;
} }
...@@ -150,14 +151,14 @@ int add_list(int client) { ...@@ -150,14 +151,14 @@ int add_list(int client) {
int ret = add_list(pkg, proc); int ret = add_list(pkg, proc);
free(pkg); free(pkg);
free(proc); free(proc);
update_inotify_mask(); update_uid_map();
return ret; return ret;
} }
static int rm_list(const char *pkg, const char *proc = "") { static int rm_list(const char *pkg, const char *proc = "") {
{ {
// Critical region // Critical region
MutexGuard lock(map_lock); MutexGuard lock(monitor_lock);
bool remove = false; bool remove = false;
if (proc[0] == '\0') { if (proc[0] == '\0') {
auto next = hide_map.begin(); auto next = hide_map.begin();
...@@ -200,7 +201,7 @@ int rm_list(int client) { ...@@ -200,7 +201,7 @@ int rm_list(int client) {
free(pkg); free(pkg);
free(proc); free(proc);
if (ret == DAEMON_SUCCESS) if (ret == DAEMON_SUCCESS)
update_inotify_mask(); update_uid_map();
return ret; return ret;
} }
...@@ -243,7 +244,7 @@ bool init_list() { ...@@ -243,7 +244,7 @@ bool init_list() {
rm_list(SAFETYNET_COMPONENT); rm_list(SAFETYNET_COMPONENT);
init_list(SAFETYNET_PKG, SAFETYNET_PROCESS); init_list(SAFETYNET_PKG, SAFETYNET_PROCESS);
update_inotify_mask(); update_uid_map();
return true; return true;
} }
...@@ -300,7 +301,7 @@ void launch_magiskhide(int client) { ...@@ -300,7 +301,7 @@ void launch_magiskhide(int client) {
hide_sensitive_props(); hide_sensitive_props();
// Initialize the mutex lock // Initialize the mutex lock
pthread_mutex_init(&map_lock, nullptr); pthread_mutex_init(&monitor_lock, nullptr);
// Initialize the hide list // Initialize the hide list
if (!init_list()) if (!init_list())
...@@ -325,7 +326,7 @@ int stop_magiskhide() { ...@@ -325,7 +326,7 @@ int stop_magiskhide() {
hide_enabled = false; hide_enabled = false;
set_hide_config(); set_hide_config();
pthread_kill(proc_monitor_thread, TERM_THREAD); pthread_kill(proc_monitor_thread, SIGTERMTHRD);
return DAEMON_SUCCESS; return DAEMON_SUCCESS;
} }
...@@ -340,3 +341,22 @@ void auto_start_magiskhide() { ...@@ -340,3 +341,22 @@ void auto_start_magiskhide() {
}); });
} }
} }
int next_zygote = -1;
void zygote_notify(int pid) {
if (hide_enabled) {
MutexGuard lock(monitor_lock);
next_zygote = pid;
pthread_kill(proc_monitor_thread, SIGZYGOTE);
}
}
void zygote_notify(int client, struct ucred *cred) {
char *path = read_string(client);
close(client);
zygote_notify(cred->pid);
usleep(100000);
xmount(MAGISKTMP "/app_process", path, nullptr, MS_BIND, nullptr);
free(path);
}
...@@ -5,31 +5,30 @@ ...@@ -5,31 +5,30 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <vector>
#include <string> #include <string>
#include <set>
#include <functional> #include <functional>
#include <map> #include <map>
#include "daemon.h" #include "daemon.h"
#define TERM_THREAD SIGUSR1 #define SIGTERMTHRD SIGUSR1
#define SIGZYGOTE SIGUSR2
#define SAFETYNET_COMPONENT "com.google.android.gms/.droidguard.DroidGuardService" #define SAFETYNET_COMPONENT "com.google.android.gms/.droidguard.DroidGuardService"
#define SAFETYNET_PROCESS "com.google.android.gms.unstable" #define SAFETYNET_PROCESS "com.google.android.gms.unstable"
#define SAFETYNET_PKG "com.google.android.gms" #define SAFETYNET_PKG "com.google.android.gms"
// Daemon entries #define WEVENT(s) (((s) & 0xffff0000) >> 16)
// CLI entries
void launch_magiskhide(int client); void launch_magiskhide(int client);
int stop_magiskhide(); int stop_magiskhide();
int add_list(int client); int add_list(int client);
int rm_list(int client); int rm_list(int client);
void ls_list(int client); void ls_list(int client);
// Update APK list for inotify // Process monitoring
void update_inotify_mask(); void *update_uid_map(void * p = nullptr);
// Process monitor
void proc_monitor(); void proc_monitor();
// Utility functions // Utility functions
...@@ -38,18 +37,6 @@ void clean_magisk_props(); ...@@ -38,18 +37,6 @@ void clean_magisk_props();
void crawl_procfs(const std::function<bool (int)> &fn); void crawl_procfs(const std::function<bool (int)> &fn);
bool proc_name_match(int pid, const char *name); bool proc_name_match(int pid, const char *name);
static inline int get_uid(const int pid) {
char path[16];
struct stat st;
sprintf(path, "/proc/%d", pid);
if (stat(path, &st) == -1)
return -1;
// We don't care about multiuser
return st.st_uid % 100000;
}
/* /*
* Bionic's atoi runs through strtol(). * Bionic's atoi runs through strtol().
* Use our own implementation for faster conversion. * Use our own implementation for faster conversion.
...@@ -66,8 +53,9 @@ static inline int parse_int(const char *s) { ...@@ -66,8 +53,9 @@ static inline int parse_int(const char *s) {
} }
extern bool hide_enabled; extern bool hide_enabled;
extern pthread_mutex_t map_lock; extern pthread_mutex_t monitor_lock;
extern std::map<std::string, std::string> hide_map; extern std::map<std::string, std::string> hide_map;
extern int next_zygote;
enum { enum {
LAUNCH_MAGISKHIDE, LAUNCH_MAGISKHIDE,
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment