diff --git a/app/src/main/cpp/detector/debug_detector.cpp b/app/src/main/cpp/detector/debug_detector.cpp index c53f245..7905cbb 100644 --- a/app/src/main/cpp/detector/debug_detector.cpp +++ b/app/src/main/cpp/detector/debug_detector.cpp @@ -98,3 +98,91 @@ MultiLayerResult DebugDetector::detectPtrace() { result.syscallResult = false; // Can't check ptrace via syscall reliably return result; } + +// ===================== Suspicious Tool Path Detection ===================== +// Iterates over suspicious tool path array, using access() to check file existence + +// Suspicious tool path entries with descriptions +struct ToolPathEntry { + const char* path; + const char* description; +}; + +static const ToolPathEntry SUSPICIOUS_TOOL_PATHS[] = { + {"/data/local/tmp/android_server", "IDA debugger (32-bit)"}, + {"/data/local/tmp/android_server64", "IDA debugger (64-bit)"}, + {"/data/local/tmp/gdbserver", "GDB debugger"}, + {"/data/local/tmp/inject", "Injection tool"}, + {"/data/local/tmp/libhello.so", "Frida gadget"}, + {"/sdcard/xxxx/", "Unpacker (FART etc.)"}, + {"/sdcard/ooxx/", "Unpacker"}, + {"/sdcard/fart/", "FART unpacker"}, + {"/sdcard/Download/dexDump/", "DEX dump tool"}, + {"/sdcard/Download/top.niunaijun.blackdexa32_logcat.txt", "BlackDex log (32-bit)"}, + {"/sdcard/Download/top.niunaijun.blackdexa64_logcat.txt", "BlackDex log (64-bit)"}, + {"/data/data/top.niunaijun.blackdexa32", "BlackDex app (32-bit)"}, + {"/data/data/top.niunaijun.blackdexa64", "BlackDex app (64-bit)"}, +}; +static const int SUSPICIOUS_TOOL_PATHS_COUNT = sizeof(SUSPICIOUS_TOOL_PATHS) / sizeof(SUSPICIOUS_TOOL_PATHS[0]); + +bool DebugDetector::checkSuspiciousToolPathsNative() { + for (int i = 0; i < SUSPICIOUS_TOOL_PATHS_COUNT; i++) { + if (access(SUSPICIOUS_TOOL_PATHS[i].path, F_OK) == 0) { + LOGD("Suspicious tool path found (native): %s [%s]", + SUSPICIOUS_TOOL_PATHS[i].path, SUSPICIOUS_TOOL_PATHS[i].description); + return true; + } + } + return false; +} + +bool DebugDetector::checkSuspiciousToolPathsSyscall() { + for (int i = 0; i < SUSPICIOUS_TOOL_PATHS_COUNT; i++) { + if (syscall_file_exists(SUSPICIOUS_TOOL_PATHS[i].path)) { + LOGD("Suspicious tool path found (syscall): %s [%s]", + SUSPICIOUS_TOOL_PATHS[i].path, SUSPICIOUS_TOOL_PATHS[i].description); + return true; + } + } + return false; +} + +std::string DebugDetector::getDetectedSuspiciousToolPaths() { + std::string result = "["; + bool first = true; + + for (int i = 0; i < SUSPICIOUS_TOOL_PATHS_COUNT; i++) { + bool nativeExists = (access(SUSPICIOUS_TOOL_PATHS[i].path, F_OK) == 0); + bool syscallExists = syscall_file_exists(SUSPICIOUS_TOOL_PATHS[i].path); + + if (nativeExists || syscallExists) { + if (!first) result += ","; + first = false; + + result += "{\"path\":\""; + result += SUSPICIOUS_TOOL_PATHS[i].path; + result += "\",\"desc\":\""; + result += SUSPICIOUS_TOOL_PATHS[i].description; + result += "\",\"native\":"; + result += nativeExists ? "true" : "false"; + result += ",\"syscall\":"; + result += syscallExists ? "true" : "false"; + result += "}"; + + LOGD("Detected suspicious tool: %s [%s] (native:%d, syscall:%d)", + SUSPICIOUS_TOOL_PATHS[i].path, SUSPICIOUS_TOOL_PATHS[i].description, + nativeExists, syscallExists); + } + } + + result += "]"; + return result; +} + +MultiLayerResult DebugDetector::detectSuspiciousToolPaths() { + MultiLayerResult result; + result.javaResult = false; // Not checked at Java layer + result.nativeResult = checkSuspiciousToolPathsNative(); + result.syscallResult = checkSuspiciousToolPathsSyscall(); + return result; +} diff --git a/app/src/main/cpp/detector/debug_detector.h b/app/src/main/cpp/detector/debug_detector.h index 0fcae8c..6aa08fb 100644 --- a/app/src/main/cpp/detector/debug_detector.h +++ b/app/src/main/cpp/detector/debug_detector.h @@ -22,6 +22,15 @@ class DebugDetector { // Get TracerPid value static int getTracerPid(); + + // Suspicious tool path detection + // Detects debuggers, injection tools, Frida gadgets, unpackers, etc. + static bool checkSuspiciousToolPathsNative(); + static bool checkSuspiciousToolPathsSyscall(); + static std::string getDetectedSuspiciousToolPaths(); + + // Combined detection for suspicious tool paths + static MultiLayerResult detectSuspiciousToolPaths(); }; #endif // LAUNCH_DEBUG_DETECTOR_H diff --git a/app/src/main/cpp/native-lib.cpp b/app/src/main/cpp/native-lib.cpp index 7e227b2..760a62b 100644 --- a/app/src/main/cpp/native-lib.cpp +++ b/app/src/main/cpp/native-lib.cpp @@ -286,6 +286,23 @@ Java_com_xff_launch_detector_NativeDetector_getTracerPid(JNIEnv *env, jobject th return DebugDetector::getTracerPid(); } +// Suspicious tool path detection +JNIEXPORT jboolean JNICALL +Java_com_xff_launch_detector_NativeDetector_checkSuspiciousToolPathsNative(JNIEnv *env, jobject thiz) { + return DebugDetector::checkSuspiciousToolPathsNative(); +} + +JNIEXPORT jboolean JNICALL +Java_com_xff_launch_detector_NativeDetector_checkSuspiciousToolPathsSyscall(JNIEnv *env, jobject thiz) { + return DebugDetector::checkSuspiciousToolPathsSyscall(); +} + +JNIEXPORT jstring JNICALL +Java_com_xff_launch_detector_NativeDetector_getDetectedSuspiciousToolPaths(JNIEnv *env, jobject thiz) { + std::string details = DebugDetector::getDetectedSuspiciousToolPaths(); + return env->NewStringUTF(details.c_str()); +} + // ===================== File Operations via Syscall ===================== JNIEXPORT jboolean JNICALL diff --git a/app/src/main/java/com/xff/launch/detector/DebugDetector.java b/app/src/main/java/com/xff/launch/detector/DebugDetector.java index 0d11dd8..d910b2e 100644 --- a/app/src/main/java/com/xff/launch/detector/DebugDetector.java +++ b/app/src/main/java/com/xff/launch/detector/DebugDetector.java @@ -243,6 +243,44 @@ public DetectionItem detectPtraceSelfProtection() { return item; } + /** + * Detect suspicious tool paths + * Checks for debuggers (IDA/GDB), injection tools, Frida gadgets, + * unpackers (FART/BlackDex/DEX Dump), etc. + */ + public DetectionItem detectSuspiciousToolPaths() { + DetectionItem item = new DetectionItem("可疑工具路径", "检测调试器/脱壳工具/注入工具等文件路径"); + + // Java layer - check via File.exists() + boolean javaResult = checkSuspiciousToolPathsJava(); + item.setLayerResult(DetectionLayer.JAVA, javaResult); + + // Native layer - check via libc access() + boolean nativeResult = nativeDetector.checkSuspiciousToolPathsNative(); + item.setLayerResult(DetectionLayer.NATIVE, nativeResult); + + // Syscall layer - check via direct syscall + boolean syscallResult = nativeDetector.checkSuspiciousToolPathsSyscall(); + item.setLayerResult(DetectionLayer.SYSCALL, syscallResult); + + if (item.getMostTrustworthyResult()) { + item.setStatus(DetectionStatus.RISK); + item.setDetail("检测到可疑工具"); + + // Collect detailed detection info + collectSuspiciousToolPathDetails(item); + } else { + item.setStatus(DetectionStatus.SAFE); + item.setDetail("未检测到"); + } + + if (item.hasInconsistentResults()) { + item.setDetail(item.getDetail() + " (检测层不一致)"); + } + + return item; + } + /** * Get all debug detection items */ @@ -253,6 +291,7 @@ public List getAllDetections() { items.add(detectJdwp()); items.add(detectPtrace()); items.add(detectPtraceSelfProtection()); + items.add(detectSuspiciousToolPaths()); return items; } @@ -381,6 +420,38 @@ private String checkAllThreadsTracerPid() { return result.toString(); } + /** + * Java layer check for suspicious tool paths using File.exists() + * Checks suspicious tool paths via Java File API + */ + private boolean checkSuspiciousToolPathsJava() { + String[] toolPaths = { + "/data/local/tmp/android_server", + "/data/local/tmp/android_server64", + "/data/local/tmp/gdbserver", + "/data/local/tmp/inject", + "/data/local/tmp/libhello.so", + "/sdcard/xxxx/", + "/sdcard/ooxx/", + "/sdcard/fart/", + "/sdcard/Download/dexDump/", + "/sdcard/Download/top.niunaijun.blackdexa32_logcat.txt", + "/sdcard/Download/top.niunaijun.blackdexa64_logcat.txt", + "/data/data/top.niunaijun.blackdexa32", + "/data/data/top.niunaijun.blackdexa64" + }; + + for (String path : toolPaths) { + try { + if (new java.io.File(path).exists()) { + return true; + } + } catch (Exception ignored) { + } + } + return false; + } + // ===================== Detail Collection Methods ===================== /** @@ -639,4 +710,95 @@ private void collectPtraceDetails(DetectionItem item, int javaTracerPid, "PID: " + myPid, DetectionLayer.JAVA, "🆔"); } + + /** + * Collect suspicious tool path detection details + */ + private void collectSuspiciousToolPathDetails(DetectionItem item) { + // Get detected path details from native layer (JSON format) + String detectedJson = null; + try { + detectedJson = nativeDetector.getDetectedSuspiciousToolPaths(); + } catch (Exception ignored) { + } + + // Define all paths with descriptions and categories (consistent with native layer) + String[][] toolPaths = { + // {path, description, icon, category} + {"/data/local/tmp/android_server", "IDA 调试器 (32位)", "🔴", "调试器"}, + {"/data/local/tmp/android_server64", "IDA 调试器 (64位)", "🔴", "调试器"}, + {"/data/local/tmp/gdbserver", "GDB 调试器", "🔴", "调试器"}, + {"/data/local/tmp/inject", "注入工具", "🟠", "注入/Frida"}, + {"/data/local/tmp/libhello.so", "Frida gadget", "🟠", "注入/Frida"}, + {"/sdcard/xxxx/", "脱壳工具", "🟡", "脱壳工具"}, + {"/sdcard/ooxx/", "脱壳工具", "🟡", "脱壳工具"}, + {"/sdcard/fart/", "FART 脱壳工具", "🟡", "脱壳工具"}, + {"/sdcard/Download/dexDump/", "DEX Dump 工具", "🟡", "脱壳工具"}, + {"/sdcard/Download/top.niunaijun.blackdexa32_logcat.txt", "BlackDex 日志 (32位)", "🟡", "脱壳工具"}, + {"/sdcard/Download/top.niunaijun.blackdexa64_logcat.txt", "BlackDex 日志 (64位)", "🟡", "脱壳工具"}, + {"/data/data/top.niunaijun.blackdexa32", "BlackDex 应用 (32位)", "🟡", "脱壳工具"}, + {"/data/data/top.niunaijun.blackdexa64", "BlackDex 应用 (64位)", "🟡", "脱壳工具"}, + }; + + int detectedCount = 0; + StringBuilder detectedNames = new StringBuilder(); + + for (String[] entry : toolPaths) { + String path = entry[0]; + String desc = entry[1]; + String icon = entry[2]; + String category = entry[3]; + + // Check via Java layer + boolean javaExists = false; + try { + javaExists = new java.io.File(path).exists(); + } catch (Exception ignored) { + } + + // Check via native layer (fileExistsNative) + boolean nativeExists = false; + try { + nativeExists = nativeDetector.fileExistsNative(path); + } catch (Exception ignored) { + } + + // Check via syscall layer + boolean syscallExists = false; + try { + syscallExists = nativeDetector.fileExistsSyscall(path); + } catch (Exception ignored) { + } + + if (javaExists || nativeExists || syscallExists) { + detectedCount++; + + StringBuilder detail = new StringBuilder(); + detail.append("路径: ").append(path); + detail.append("\n检测层: "); + if (javaExists) detail.append("Java ✓ "); + if (nativeExists) detail.append("Native ✓ "); + if (syscallExists) detail.append("Syscall ✓ "); + + // Determine which detection layer to report + DetectionLayer reportLayer = syscallExists ? DetectionLayer.SYSCALL : + nativeExists ? DetectionLayer.NATIVE : + DetectionLayer.JAVA; + + item.addDetectionDetail(icon + " " + category, desc, + detail.toString(), reportLayer, icon); + + if (detectedNames.length() > 0) detectedNames.append(", "); + detectedNames.append(desc); + } + } + + // Add detection summary + if (detectedCount > 0) { + item.addDetectionDetail("📊 检测统计", "发现可疑路径", + "数量: " + detectedCount + "/" + toolPaths.length + "\n" + + "发现: " + detectedNames.toString(), + DetectionLayer.SYSCALL, "📈"); + } + } } diff --git a/app/src/main/java/com/xff/launch/detector/NativeDetector.java b/app/src/main/java/com/xff/launch/detector/NativeDetector.java index 922c12c..9ffee2c 100644 --- a/app/src/main/java/com/xff/launch/detector/NativeDetector.java +++ b/app/src/main/java/com/xff/launch/detector/NativeDetector.java @@ -83,6 +83,14 @@ public class NativeDetector { public native int getTracerPid(); + // Suspicious tool path detection + /** Check suspicious tool paths - Native layer (access) */ + public native boolean checkSuspiciousToolPathsNative(); + /** Check suspicious tool paths - Syscall layer */ + public native boolean checkSuspiciousToolPathsSyscall(); + /** Get detected suspicious tool path details (JSON format) */ + public native String getDetectedSuspiciousToolPaths(); + // ===================== File Operations ===================== public native boolean fileExistsNative(String path); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f9350c1..65087ca 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -109,6 +109,7 @@ 调试器连接 JDWP 检测 Ptrace 检测 + 可疑工具路径 设备指纹信息