├── DetectZ.apk ├── DetectZygisk.cpp └── README.md /DetectZ.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apkunpacker/DetectZygisk/3502d5038e7c612489dcca1451af414b92c44de4/DetectZ.apk -------------------------------------------------------------------------------- /DetectZygisk.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define LOG_TAG "DetectZygisk" 12 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) 13 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) 14 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) 15 | 16 | bool detectZygisk() { 17 | LOGI("Starting Zygisk detection"); 18 | 19 | pid_t child_pid = fork(); 20 | LOGD("fork() returned: %d", child_pid); 21 | 22 | if (child_pid == 0) { 23 | LOGD("Child process started"); 24 | 25 | pid_t parent_pid = getppid(); 26 | LOGD("Parent PID: %d", parent_pid); 27 | 28 | LOGD("Attempting ptrace(PTRACE_ATTACH, %d, 0, 0)", parent_pid); 29 | if (ptrace(PTRACE_ATTACH, parent_pid, 0, 0) == -1) { 30 | LOGE("ptrace(PTRACE_ATTACH) failed, errno: %d", errno); 31 | _exit(0); 32 | } 33 | LOGD("ptrace(PTRACE_ATTACH) successful"); 34 | 35 | int status; 36 | LOGD("Calling waitpid(%d, &status, 0)", parent_pid); 37 | if (waitpid(parent_pid, &status, 0) == -1) { 38 | LOGE("waitpid() failed, errno: %d", errno); 39 | ptrace(PTRACE_DETACH, parent_pid, 0, 0); 40 | _exit(0); 41 | } 42 | LOGD("waitpid() successful, status: %d", status); 43 | 44 | unsigned long msg = 0; 45 | LOGD("Calling ptrace(PTRACE_GETEVENTMSG, %d, 0, &msg)", parent_pid); 46 | if (ptrace(PTRACE_GETEVENTMSG, parent_pid, 0, &msg) == -1) { 47 | LOGE("ptrace(PTRACE_GETEVENTMSG) failed, errno: %d", errno); 48 | ptrace(PTRACE_DETACH, parent_pid, 0, 0); 49 | _exit(0); 50 | } 51 | LOGI("ptrace(PTRACE_GETEVENTMSG) successful, msg: %lu", msg); 52 | 53 | LOGD("Calling ptrace(PTRACE_DETACH, %d, 0, 0)", parent_pid); 54 | if (ptrace(PTRACE_DETACH, parent_pid, 0, 0) == -1) { 55 | LOGE("ptrace(PTRACE_DETACH) failed, errno: %d", errno); 56 | } 57 | LOGD("ptrace(PTRACE_DETACH) completed"); 58 | 59 | if (msg > 0 && msg < 65536) { 60 | LOGI("Zygisk DETECTED - ptrace have zygote64 pid: %lu", msg); 61 | _exit(1); 62 | } else { 63 | LOGI("Zygisk NOT DETECTED - ptrace message: %lu", msg); 64 | _exit(0); 65 | } 66 | } else if (child_pid > 0) { 67 | LOGD("Parent process waiting for child: %d", child_pid); 68 | 69 | int status; 70 | pid_t wait_result = waitpid(child_pid, &status, 0); 71 | LOGD("waitpid returned: %d, status: %d", wait_result, status); 72 | 73 | if (WIFEXITED(status)) { 74 | int exit_code = WEXITSTATUS(status); 75 | LOGD("Child exited normally with exit code: %d", exit_code); 76 | bool result = (exit_code == 1); 77 | LOGI("Final detection result: %s", result ? "ZYGISK DETECTED" : "ZYGISK NOT DETECTED"); 78 | return result; 79 | } else if (WIFSIGNALED(status)) { 80 | int signal_num = WTERMSIG(status); 81 | LOGE("Child process killed by signal: %d", signal_num); 82 | LOGE("Child was terminated abnormally"); 83 | } else { 84 | LOGE("Child process status unknown: %d", status); 85 | } 86 | } else { 87 | LOGE("fork() failed, errno: %d", errno); 88 | } 89 | 90 | LOGI("Detection failed or error occurred"); 91 | return false; 92 | } 93 | 94 | extern "C" JNIEXPORT jstring JNICALL 95 | Java_com_test_detectz_MainActivity_stringFromJNI( 96 | JNIEnv* env, 97 | jobject /* this */) { 98 | 99 | LOGI("JNI function called - starting detection"); 100 | 101 | if (detectZygisk()) { 102 | LOGI("Returning: Detected Zygisk"); 103 | return env->NewStringUTF("Zygisk Detected"); 104 | } else { 105 | LOGI("Returning: Zygisk Not Detected"); 106 | return env->NewStringUTF("Zygisk Not Detected"); 107 | } 108 | 109 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DetectZygisk 2 | A POC to detect zygisk 3 | 4 | Idea of detection is taken from this github issue https://github.com/PerformanC/ReZygisk/issues/171 5 | 6 | Writing here in case issue is deleted or removed - 7 | 8 | --------------------------------------------------------------------------------------------------------------------------------------------- 9 | 10 | # Description 11 | 12 | YONO SBI forks a child process where it will do something like this: 13 | 14 | ```cpp 15 | ptrace(PTRACE_ATTACH, getppid(), 0, 0); 16 | int status; 17 | waitpid(getppid(), &status, 0); 18 | unsigned long msg = 0; 19 | ptrace(PTRACE_GETEVENTMSG, getppid(), 0, &msg); 20 | ``` 21 | 22 | If ReZygisk is active, then msg will be the pid of zygote. I think this is because when init forks into zygote, Linux will put the pid of zygote as the ptrace message of the ptrace fork stop event. Then apparently in the absence of another ptrace stop that would overwrite it, it will propagate into the child processes. YONO SBI then detects this leftover value. 23 | 24 | Running something like this just once on zygote makes YONO SBI work fine on my device: 25 | ```cpp 26 | ptrace(PTRACE_ATTACH, zygote_pid, 0, 0); 27 | int status; 28 | waitpid(zygote_pid, &status, 0); 29 | ptrace(PTRACE_SYSCALL, zygote_pid, 0, 0); 30 | waitpid(zygote_pid, &status, 0); 31 | ptrace(PTRACE_DETACH, zygote_pid, 0, 0); 32 | ``` 33 | The syscall ptrace stop will set the ptrace event message to zero. 34 | 35 | --------------------------------------------------------------------------------------------------------------------------------------------- 36 | 37 | 38 | # Implementation 39 | 40 | Core idea is written by ChatGPT deep research ( Good use of AI ) 41 | 42 | ```sh 43 | DetectZygisk: JNI function called - starting detection 44 | DetectZygisk: Starting Zygisk detection 45 | DetectZygisk: fork() returned: 22137 46 | DetectZygisk: Parent process waiting for child: 22137 47 | DetectZygisk: fork() returned: 0 48 | DetectZygisk: Child process started 49 | DetectZygisk: Parent PID: 22098 50 | DetectZygisk: Attempting ptrace(PTRACE_ATTACH, 22098, 0, 0) 51 | DetectZygisk: ptrace(PTRACE_ATTACH) successful 52 | DetectZygisk: Calling waitpid(22098, &status, 0) 53 | DetectZygisk: waitpid() successful, status: 4991 54 | DetectZygisk: Calling ptrace(PTRACE_GETEVENTMSG, 22098, 0, &msg) 55 | DetectZygisk: ptrace(PTRACE_GETEVENTMSG) successful, msg: 1456 56 | DetectZygisk: Calling ptrace(PTRACE_DETACH, 22098, 0, 0) 57 | DetectZygisk: ptrace(PTRACE_DETACH) completed 58 | DetectZygisk: Zygisk DETECTED - ptrace have zygote64 pid: 1456 59 | DetectZygisk: waitpid returned: 22137, status: 256 60 | DetectZygisk: Child exited normally with exit code: 1 61 | DetectZygisk: Final detection result: ZYGISK DETECTED 62 | DetectZygisk: Returning: Detected Zygisk 63 | ``` 64 | 65 | 66 | # ✅ Testing 67 | 68 | | Repository | Status | 69 | |--------------------------------------------------------------------------------------------------|-------------| 70 | | [PerformanC/ReZygisk](https://github.com/PerformanC/ReZygisk) | ✅ Detected | 71 | | [Dr-TSNG/ZygiskNext](https://github.com/Dr-TSNG/ZygiskNext) | ✅ Detected | 72 | | [JingMatrix/NeoZygisk](https://github.com/JingMatrix/NeoZygisk) | ✅ Detected | 73 | | [topjohnwu/Magisk - zygisk core](https://github.com/topjohnwu/Magisk/tree/master/native/src/core/zygisk) | ❌ Not Detected | 74 | 75 | 76 | --------------------------------------------------------------------------------