Android App环境检测分析
2023-12-1 08:19:55 Author: 哆啦安全(查看原文) 阅读量:6 收藏

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(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");}

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<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;}

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<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;        }}

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<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

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 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;}

14.获取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检测环境都挺全

推荐阅读
Android系统ROM定制汇总篇
Android/iOS安全和车联网安全汇总篇


文章来源: http://mp.weixin.qq.com/s?__biz=Mzg2NzUzNzk1Mw==&mid=2247496563&idx=1&sn=50f567a515b7473bb72335584a99766f&chksm=ceb8b63df9cf3f2b44c11bf5efcca622b8beb2872b9fc6b67a79c8b63cae6fa692a32ecc49b5&scene=0&xtrack=1#rd
如有侵权请联系:admin#unsafe.sh