Tracking side-loaded accessibility services

      Technique summary
    Technique Tracking side-loaded accessibility services
    Against Malicious accessibility services
    Limitations Requires QUERY_ALL_PACKAGES privilege
    Side effects This technique may restrict third-party app stores if they are not included in the installer list
    Recommendations Recommended for use combined with other techniques for older devices

    This technique is an extension of accessibility services allow-listing.

    Yet another criterion for considering applications as suspicious is whether they have enabled accessibility services and they are side-loaded. The implementation is shown in the snippet below:

    private List<String> getListOfSideLoadedAppsWithEnabledAccessibilityServices( Context context) { Set<String> installerAllowList = Set.of( "com.android.vending", "com.sec.android.app.samsungapps", // ... "com.huawei.appmarket"); List<AccessibilityServiceInfo> a11yServiceList = getListOfEnabledA11yServices(context); List<String> sideLoadedA11yAppList = new ArrayList<>(); PackageManager packageManager = context.getPackageManager(); String packageName; String installer; for (AccessibilityServiceInfo asi : a11yServiceList) { packageName = asi.getId().split("/")[0]; try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { installer = packageManager. getInstallSourceInfo(packageName). getInstallingPackageName(); } else { installer = packageManager.getInstallerPackageName(packageName); } if (installer == null || !installerAllowList.contains(installer)) { Log.d("APP_INSPECTOR", "[!] app '" + packageName + "' has a11y enabled and is side-loaded"); sideLoadedA11yAppList.add(packageName); } } catch(PackageManager.NameNotFoundException e) { // (...) } } return sideLoadedA11yAppList; } private fun getListOfSideLoadedAppsWithEnabledAccessibilityServices( context: Context ): List<String> { val installerAllowList = setOf( "com.android.vending", "com.sec.android.app.samsungapps", // ... "com.huawei.appmarket" ) val a11yServiceList = getListOfEnabledA11yServices(context) val sideLoadedA11yAppList: MutableList<String> = ArrayList() val packageManager = context.packageManager var packageName: String var installer: String? for (asi in a11yServiceList) { packageName = asi.id.split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0] try { installer = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { packageManager.getInstallSourceInfo(packageName) .installingPackageName } else { packageManager.getInstallerPackageName(packageName) } if (installer == null || !installerAllowList.contains(installer)) { Log.d( "APP_INSPECTOR", "[!] app '" + packageName + "' has a11y enabled and is side-loaded" ) sideLoadedA11yAppList.add(packageName) } } catch (e: PackageManager.NameNotFoundException) { // (...) } } return sideLoadedA11yAppList }

     

    Other mobile app stores to consider in your detection code:

    • Google
    • Samsung
    • Amazon
    • Huawei
    • Xiaomi
    • OPPO
    • Vivo

    Guardsquare

    Table of contents