#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Add this line #define LOG_TAG "NativeLib" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) // Function to check for common root binaries bool isRooted() { std::string paths[] = { "/system/app/Superuser.apk", "/system/xbin/su", "/system/bin/su", "/system/bin/magisk", "/system/xbin/magisk", "/sbin/magisk"}; for (const auto &path : paths) { std::ifstream file(path); if (file.good()) { return true; } } return false; } // Function to check for the presence of files or directories commonly associated with Frida. bool checkFridaFiles() { std::string fridaFiles[] = { "/data/local/tmp/re.frida.server", // Common Frida server path "/data/local/tmp/frida-server", "/usr/lib/libfrida-gadget.so", // Frida gadget (injected library) "/usr/lib64/libfrida-gadget.so", "/data/local/re.frida.server", }; for (const auto &path : fridaFiles) { if (access(path.c_str(), F_OK) != -1) { LOGE("Frida file detected: %s", path.c_str()); return true; } } return false; } // Checks for open ports commonly used by Frida. This is less reliable, as ports can be changed. bool checkFridaPorts() { int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == -1) { return false; // Couldn't create socket, not a strong indicator. } sockaddr_in sa; memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_port = htons(27042); // Default Frida port inet_pton(AF_INET, "127.0.0.1", &sa.sin_addr); if (connect(sock, (struct sockaddr *)&sa, sizeof(sa)) != -1) { LOGE("Frida default port (27042) is open."); close(sock); return true; } close(sock); return false; } // Check the maps file of the current process for any suspicious entries. bool checkMaps() { std::ifstream mapsFile("/proc/self/maps"); std::string line; if (mapsFile.is_open()) { while (std::getline(mapsFile, line)) { // Look for lines that indicate injected libraries, especially Frida. if (line.find("frida") != std::string::npos || line.find("gum-js-") != std::string::npos) { // Gum is Frida's JavaScript engine LOGE("Suspicious entry in /proc/self/maps: %s", line.c_str()); return true; } } mapsFile.close(); } else { LOGE("Could not open /proc/self/maps"); return false; } return false; } // Check loaded modules. bool checkLoadedModules() { bool found = false; dl_iterate_phdr([](struct dl_phdr_info *info, size_t size, void *data) { bool *found_ptr = static_cast(data); if (std::string(info->dlpi_name).find("frida") != std::string::npos) { LOGE("Frida module detected: %s", info->dlpi_name); *found_ptr = true; return 1; // Stop iterating } return 0; // Continue iterating }, &found); return found; } // This is a simple ptrace check. More sophisticated checks are possible (and necessary for robust detection). // bool checkPtrace() { // // Attempt to ptrace ourselves. If another process is already tracing us, this will fail. // if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) { // LOGE("ptrace failed. Debugger or tracer detected."); // return true; // Likely being traced // } // // Detach. If attached, need to detach to not interfere. // ptrace(PTRACE_DETACH, 0, 0, 0); // return false; //} extern "C" JNIEXPORT jboolean JNICALL Java_com_intaleq_1driver_RootDetection_isNativeRooted(JNIEnv *env, jobject /* this */) { if (isRooted()) { return JNI_TRUE; } if (checkFridaFiles()) { return JNI_TRUE; } if (checkFridaPorts()) { return JNI_TRUE; } if (checkMaps()) { return JNI_TRUE; } if (checkLoadedModules()) { return JNI_TRUE; } // if (checkPtrace()) { // return JNI_TRUE; // } return JNI_FALSE; }