检测是否调试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();
}
检测是否模拟器
这里获取了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;
}
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(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 = 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.<init>(r4) // Catch: java.lang.Throwable -> L2f
java.io.Reader r3 = (java.io.Reader) r3 // Catch: java.lang.Throwable -> L2f
r2.<init>(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");
}
分区读写检测
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安装时间检测
通过日志发现每次启动都会检测APP的安装,更新时间。
PackageInfoUtils_generatePackageInfo_1 com.CTION, firstInstallTime: 1701134370160, lastUpdateTime: 1701134626468
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
开发者模式adb检测
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检测
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;
}
获取APP安装列表
获取了用户安装的所有APP,应该是收集上传,判断是否装了一些root有关的APP。
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检测环境都挺全(离谱)的~