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(); }
2.检测是否模拟器
这里获取了Android id,如果Android id是null,就是模拟器?如果包含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; }
3.Root检测
检测系统的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(Listlist) { 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 = 0 r1 = 0 java.lang.Runtime r2 = java.lang.Runtime.getRuntime() // Catch: java.lang.Throwable -> L2f java.lang.String r3 = "which" java.lang.String r4 = "su" java.lang.String[] r3 = new java.lang.String[]{r3, r4} // Catch: java.lang.Throwable -> L2f java.lang.Process r1 = r2.exec(r3) // Catch: java.lang.Throwable -> L2f java.io.BufferedReader r2 = new java.io.BufferedReader // Catch: java.lang.Throwable -> L2f java.io.InputStreamReader r3 = new java.io.InputStreamReader // Catch: java.lang.Throwable -> L2f java.io.InputStream r4 = r1.getInputStream() // Catch: java.lang.Throwable -> L2f r3.(r4) // Catch: java.lang.Throwable -> L2f java.io.Reader r3 = (java.io.Reader) r3 // Catch: java.lang.Throwable -> L2f r2. (r3) // Catch: java.lang.Throwable -> L2f java.lang.String r2 = r2.readLine() // Catch: java.lang.Throwable -> L2f if (r2 == 0) goto L29 r0 = 1 L29: if (r1 == 0) goto L32 L2b: r1.destroy() goto L32 L2f: if (r1 == 0) goto L32 goto L2b L32: return r0 */ throw new UnsupportedOperationException("Method not decompiled: jmgldvb.C6107cme.f():boolean"); }
4.分区读写检测
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"); 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 "); 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; }
5.面具检测
通过which命令查找面具可执行文件。
public final boolean m() { return a("magisk"); }
6.APP安装时间检测
通过日志发现每次启动都会检测APP的安装,更新时间。
PackageInfoUtils_generatePackageInfo_1 com.CTION, firstInstallTime: 1701134370160, lastUpdateTime: 1701134626468
7.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); }
8.挂载信息获取
这个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"); return (String[]) array; } catch (IOException e) { C0339Io.a((Exception) e); return null; } catch (NoSuchElementException e2) { C0339Io.a((Exception) e2); return null; } }
9.读取系统属性
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"); 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
10.开发者模式adb检测
Settings中获取adb状态。
Settings.Secure
Global getInt : adb_enabled
Secure getInt : adb_wifi_enabled
11.可疑的二进制文件
这里就是可以传递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; }
12.ro.debuggable检测
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; }
13.无障碍检测
getEnabledAccessibilityServiceList
获取当前无障碍服务的激活的APP信息,这里拿到了激活了无障碍的APP,只有发现有,APP直接崩溃。
private final ListgetPackageAccessibilityServiceEnabledList(Context context) { PackageInfo packageInfo; List enabledAccessibilityServiceList = getAccessibilityService(context).getEnabledAccessibilityServiceList(-1); Intrinsics.checkNotNullExpressionValue(enabledAccessibilityServiceList, "accessibilityManager.get…ceInfo.FEEDBACK_ALL_MASK)"); List 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; }
14.获取APP安装列表
获取了用户安装的所有APP,应该是收集上传,判断是否装了一些root有关的APP。
public ListgetInstalledApps(PackageManager packageManager) { Intrinsics.checkNotNullParameter(packageManager, "packageManager"); List installedPackages = packageManager.getInstalledPackages(0); Intrinsics.checkNotNullExpressionValue(installedPackages, "packageManager.getInstalledPackages(0)"); return filterNotSystemApp(installedPackages); }
现在的APP检测环境都挺全
审核编辑:汤梓红
-
Android
+关注
关注
12文章
3927浏览量
127197 -
APP
+关注
关注
33文章
1570浏览量
72401 -
调试
+关注
关注
7文章
574浏览量
33906 -
环境检测
+关注
关注
0文章
19浏览量
7525
原文标题:Android App环境检测分析
文章出处:【微信号:哆啦安全,微信公众号:哆啦安全】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论