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