1.检测是否调试APP
这个原理就是APP的AndroidManifest.xml文件中application是否配置了android:debuggable="true",设置true支持动态调试
public static boolean isAppDebuggable(Context context) {return (context.getApplicationInfo().flags & 2) != 0;}
检测当前APP是否被动态调试中
public static boolean isDebuggerAttached() {return Debug.isDebuggerConnected() || Debug.waitingForDebugger();}
GOLDFISH字符串也属于模拟器public static boolean isEmulator(Context context) {return Build.PRODUCT.contains(SDK) || Build.HARDWARE.contains(GOLDFISH) || Build.HARDWARE.contains(RANCHU) || Settings.Secure.getString(context.getContentResolver(), "android_id") == null;}
检测系统的tags是不是test-keys。
检测是不是安装了supersu的APP,检测su文件是否存在。
public static boolean isRooted(Context context) {boolean isEmulator = isEmulator(context);String str = Build.TAGS;if ((isEmulator || str == null || !str.contains("test-keys")) && !new File("/system/app/Superuser.apk").exists()) {return !isEmulator && new File("/system/xbin/su").exists();}return true;}
判断一些root的APP是否安装
private final boolean a(List<String> list) {PackageManager packageManager = this.b.getPackageManager();boolean z = false;for (String str : list) {try {packageManager.getPackageInfo(str, 0);C0339Io.h.e(str + " ROOT management app detected!");z = true;} catch (PackageManager.NameNotFoundException unused) {}}return z;}
通过which su寻找su文件
public final boolean f() {/*r5 = this;r0 = 0r1 = 0java.lang.Runtime r2 = java.lang.Runtime.getRuntime() // Catch: java.lang.Throwable -> L2fjava.lang.String r3 = "which"java.lang.String r4 = "su"java.lang.String[] r3 = new java.lang.String[]{r3, r4} // Catch: java.lang.Throwable -> L2fjava.lang.Process r1 = r2.exec(r3) // Catch: java.lang.Throwable -> L2fjava.io.BufferedReader r2 = new java.io.BufferedReader // Catch: java.lang.Throwable -> L2fjava.io.InputStreamReader r3 = new java.io.InputStreamReader // Catch: java.lang.Throwable -> L2fjava.io.InputStream r4 = r1.getInputStream() // Catch: java.lang.Throwable -> L2fr3.<init>(r4) // Catch: java.lang.Throwable -> L2fjava.io.Reader r3 = (java.io.Reader) r3 // Catch: java.lang.Throwable -> L2fr2.<init>(r3) // Catch: java.lang.Throwable -> L2fjava.lang.String r2 = r2.readLine() // Catch: java.lang.Throwable -> L2fif (r2 == 0) goto L29r0 = 1L29:if (r1 == 0) goto L32L2b:r1.destroy()goto L32L2f:if (r1 == 0) goto L32goto L2bL32:return r0*/throw new UnsupportedOperationException("Method not decompiled: jmgldvb.C6107cme.f():boolean");}
public final boolean k() {String str;String str2;String[] strArr;int i;boolean z;String str3;String[] e = e();int i2 = 0;if (e == null) {return false;}int i3 = Build.VERSION.SDK_INT;int length = e.length;int i4 = 0;boolean z2 = false;while (i4 < length) {String str4 = e[i4];Object[] array = new Regex(StringUtils.SPACE).split(str4, i2).toArray(new String[i2]);Intrinsics.checkNotNull(array, "null cannot be cast to non-null type kotlin.Array<T of kotlin.collections.ArraysKt__ArraysJVMKt.toTypedArray>");String[] strArr2 = (String[]) array;int i5 = 23;if ((i3 > 23 || strArr2.length >= 4) && (i3 <= 23 || strArr2.length >= 6)) {boolean z3 = true;if (i3 > 23) {str = strArr2[2];str2 = strArr2[5];} else {str = strArr2[1];str2 = strArr2[3];}String[] strArr3 = C4631btu.g;int length2 = strArr3.length;String str5 = str2;int i6 = i2;while (i6 < length2) {String str6 = strArr3[i6];if (StringsKt.equals(str, str6, z3)) {if (Build.VERSION.SDK_INT > i5) {str3 = str6;str5 = StringsKt.replace$default(StringsKt.replace$default(str5, "(", "", false, 4, (Object) null), ")", "", false, 4, (Object) null);} else {str3 = str6;}strArr = e;Object[] array2 = new Regex(",").split(str5, i2).toArray(new String[i2]);Intrinsics.checkNotNull(array2, "null cannot be cast to non-null type kotlin.Array<T of kotlin.collections.ArraysKt__ArraysJVMKt.toTypedArray>");String[] strArr4 = (String[]) array2;int length3 = strArr4.length;int i7 = i2;while (true) {if (i7 >= length3) {i = i3;z = true;break;}String[] strArr5 = strArr4;i = i3;z = true;if (StringsKt.equals(strArr4[i7], "rw", true)) {C0339Io.b(str3 + " path is mounted with rw permissions! " + str4);z2 = true;break;}i7++;strArr4 = strArr5;i3 = i;}} else {strArr = e;i = i3;z = z3;}i6++;z3 = z;e = strArr;i3 = i;i2 = 0;i5 = 23;}} else {C0339Io.h.e("Error formatting mount line: " + str4);}i4++;e = e;i3 = i3;i2 = 0;}return z2;}
which命令查找面具可执行文件。public final boolean m() {return a("magisk");}
通过日志发现每次启动都会检测APP的安装,更新时间。
PackageInfoUtils_generatePackageInfo_1 com.CTION, firstInstallTime: 1701134370160, lastUpdateTime: 17011346264687.ROM检测
如果是开发版的ROM,通常tags都是:test-keys
public final boolean q() {String str = Build.TAGS;return str != null && StringsKt.contains$default((CharSequence) str, (CharSequence) "test-keys", false, 2, (Object) null);}
mount会把挂载信息返回,可以检测挂载信息中是否有magisk或者zygisk字符串等。private final String[] e() {try {InputStream inputStream = Runtime.getRuntime().exec("mount").getInputStream();if (inputStream == null) {return null;}String propVal = new Scanner(inputStream).useDelimiter("\\A").next();Intrinsics.checkNotNullExpressionValue(propVal, "propVal");Object[] array = new Regex(StringUtils.LF).split(propVal, 0).toArray(new String[0]);Intrinsics.checkNotNull(array, "null cannot be cast to non-null type kotlin.Array<T of kotlin.collections.ArraysKt__ArraysJVMKt.toTypedArray>");return (String[]) array;} catch (IOException e) {C0339Io.a((Exception) e);return null;} catch (NoSuchElementException e2) {C0339Io.a((Exception) e2);return null;}}
private final String[] g() {try {InputStream inputStream = Runtime.getRuntime().exec("getprop").getInputStream();if (inputStream == null) {return null;}String propVal = new Scanner(inputStream).useDelimiter("\\A").next();Intrinsics.checkNotNullExpressionValue(propVal, "propVal");Object[] array = new Regex(StringUtils.LF).split(propVal, 0).toArray(new String[0]);Intrinsics.checkNotNull(array, "null cannot be cast to non-null type kotlin.Array<T of kotlin.collections.ArraysKt__ArraysJVMKt.toTypedArray>");return (String[]) array;} catch (IOException e) {C0339Io.a((Exception) e);return null;} catch (NoSuchElementException e2) {C0339Io.a((Exception) e2);return null;}}
判断是不是模拟器:ro.kernel.qemu
获取手机厂商ro.product.manufacturer
品牌:ro.build.product
指纹:ro.build.fingerprint
Settings中获取adb状态。
Settings.Secure
Global getInt : adb_enabled
Secure getInt : adb_wifi_enabled
这里就是可以传递su,magisk等等参数
public final boolean a(String filename) {String[] a;Intrinsics.checkNotNullParameter(filename, "filename");boolean z = false;for (String str : C4631btu.d.a()) {String str2 = str + filename;if (new File(str, filename).exists()) {C0339Io.b(str2 + " binary detected!");z = true;}}return z;}
ro.debuggable这个系统属性,在user版本的系统中是0,如果发现是1可以判断当前系统是可调试状态和root状态。
public final boolean b() {HashMap hashMap = new HashMap();hashMap.put("ro.debuggable", "1");hashMap.put("ro.secure", "0");String[] g = g();if (g == null) {return false;}boolean z = false;for (String str : g) {for (String str2 : hashMap.keySet()) {String str3 = str;if (StringsKt.contains$default((CharSequence) str3, (CharSequence) str2, false, 2, (Object) null)) {String str4 = "[" + ((String) hashMap.get(str2)) + ']';if (StringsKt.contains$default((CharSequence) str3, (CharSequence) str4, false, 2, (Object) null)) {C0339Io.b(str2 + " = " + str4 + " detected!");z = true;}}}}return z;}
getEnabledAccessibilityServiceList获取当前无障碍服务的激活的APP信息,这里拿到了激活了无障碍的APP,只有发现有,APP直接崩溃。
private final List<PackageInfo> getPackageAccessibilityServiceEnabledList(Context context) {PackageInfo packageInfo;List<AccessibilityServiceInfo> enabledAccessibilityServiceList = getAccessibilityService(context).getEnabledAccessibilityServiceList(-1);Intrinsics.checkNotNullExpressionValue(enabledAccessibilityServiceList, "accessibilityManager.get…ceInfo.FEEDBACK_ALL_MASK)");List<AccessibilityServiceInfo> list = enabledAccessibilityServiceList;ArrayList arrayList = new ArrayList(CollectionsKt.collectionSizeOrDefault(list, 10));for (AccessibilityServiceInfo accessibilityServiceInfo : list) {ServiceInfo serviceInfo = accessibilityServiceInfo.getResolveInfo().serviceInfo;try {packageInfo = context.getPackageManager().getPackageInfo(serviceInfo.packageName, 0);} catch (PackageManager.NameNotFoundException unused) {PackageInfo packageInfo2 = new PackageInfo();packageInfo2.packageName = serviceInfo.packageName;packageInfo2.applicationInfo = serviceInfo.applicationInfo;packageInfo = packageInfo2;}arrayList.add(packageInfo);}return arrayList;}
public List<PackageInfo> getInstalledApps(PackageManager packageManager) {Intrinsics.checkNotNullParameter(packageManager, "packageManager");List<PackageInfo> installedPackages = packageManager.getInstalledPackages(0);Intrinsics.checkNotNullExpressionValue(installedPackages, "packageManager.getInstalledPackages(0)");return filterNotSystemApp(installedPackages);}
现在的APP检测环境都挺全