1.檢測是否調試APP
這個原理就是APP的AndroidManifest.xml文件中application是否配置了android:debuggable="true",設置true支持動態(tài)調試
public static boolean isAppDebuggable(Context context) { return (context.getApplicationInfo().flags & 2) != 0; }
檢測當前APP是否被動態(tài)調試中
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檢測
檢測系統(tǒng)的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.分區(qū)讀寫檢測
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命令查找面具可執(zhí)行文件。
public final boolean m() { return a("magisk"); }
6.APP安裝時間檢測
通過日志發(fā)現(xiàn)每次啟動都會檢測APP的安裝,更新時間。
PackageInfoUtils_generatePackageInfo_1 com.CTION, firstInstallTime: 1701134370160, lastUpdateTime: 1701134626468
7.ROM檢測
如果是開發(fā)版的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.讀取系統(tǒng)屬性
讀取了系統(tǒng)的全部屬性,應該手機手機型號,廠商等等信息。
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.開發(fā)者模式adb檢測
Settings中獲取adb狀態(tài)。
Settings.Secure
Global getInt : adb_enabled
Secure getInt : adb_wifi_enabled
11.可疑的二進制文件
這里就是可以傳遞su,magisk等等參數(shù)
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這個系統(tǒng)屬性,在user版本的系統(tǒng)中是0,如果發(fā)現(xiàn)是1可以判斷當前系統(tǒng)是可調試狀態(tài)和root狀態(tài)。
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,只有發(fā)現(xiàn)有,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); }
?
?現(xiàn)在的APP檢測環(huán)境都挺全
審核編輯:湯梓紅
-
Android
+關注
關注
12文章
3936瀏覽量
127397 -
APP
+關注
關注
33文章
1573瀏覽量
72482 -
調試
+關注
關注
7文章
578瀏覽量
33936 -
環(huán)境檢測
+關注
關注
0文章
20瀏覽量
7531
原文標題:Android App環(huán)境檢測分析
文章出處:【微信號:哆啦安全,微信公眾號:哆啦安全】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論