Blocking Screen Readers
Screen readers are apps that use the Android accessibility API to read the contents of other apps. This API was designed to facilitate mobile device use for disabled people.
Unfortunately, this feature is frequently misused for other purposes. Some are helpful, such as automation tools, device cleaners, battery savers, or AVs. However, the Accessibility API is often abused by malware, especially by apps targeting banking software. Accessibility enables malware to grant itself excessive permissions and to read the screen contents of other apps.
Malwarelytics for Android provides a screen reader blocking feature.
The screen reader blocking feature is applied to the app’s activities. Details about behavior and APIs relevant to activity protection can be found in Activity protection.
Limitations
Blocking screen readers has certain limitations arising from the Accessibility API design.
An application can specify which data it sends to the accessibility API to be available for screen readers. However, it is impossible to choose to send data only to one specific screen reader. Screen readers have to be either allowed or blocked all at once.
Configuration
More information on general RASP feature configuration and usage can be found in this overview.
This feature bases its decision on whether screen readers should be universally allowed or blocked on two factors: on the action
item of the SDK configuration and a provided list of allowed screen readers. Screen reading is only allowed if all screen readers enabled in the system appear on the list of allowed screen readers.
To simplify usage of the feature Malwarelytics for Android contains a built-in list of allowed screen readers. The list contains several frequently used apps that are designed to help disabled people. The list is used by default and can be found in the property ScreenReaderBlockConfig.DEFAULT_ALLOWED_SCREEN_READERS
. If an app developer wishes to use a different list, it can be provided in the SDK configuration:
val allowList = listOf(
// Specify an allowed app by its package name and signature hash (recommended approach)
RaspConfig.ApkAllowlistItem("com.google.android.marvin.talkback", "9b424c2d27ad51a42a337e0bb6991c76eca44461"),
// Specify an allowed app only by its package name (less secure)
RaspConfig.ApkAllowlistItem("com.samsung.accessibility")
)
val raspConfig = RaspConfig.Builder()
.screenReader(
ScreenReaderBlockConfig.Builder()
.action(BlockConfig.Block)
.allowedScreenReaders(allowList)
.build()
)
.build()
Method | Description |
---|---|
action(BlockConfig) |
specifies the automatic behavior of the screen reader blocking feature. Defaults to BlockConfig.Block . |
allowedScreenReaders( Collection<RaspConfig.ApkAllowlistItem>) |
defines a collection of allowed screen readers. The default value is ScreenReaderBlockConfig.DEFAULT_ALLOWED_SCREEN_READERS . |
Available values of BlockConfig
:
Value | Description |
---|---|
NoAction |
indicates that screen readers will not be automatically blocked and changes in the set of enabled screen readers will not be automatically detected. A manual check for not allowed screen readers is still possible. |
Block |
indicates that screen readers will be automatically blocked, changes in the set of enabled screen readers will be automatically detected and observers will be notified. |
Configuring Allowed Screen Readers
Allowed screen readers can be specified either by their package name and signature or by their package name only. However, the former is recommended to avoid allowing fake (and often malicious) apps.
Obtaining Package Name
Obtaining the app package name is simple – it is listed as a query param id
in the URL of the app page on Google Play. For example, the package name of the Android Accessibility Suite is com.google.android.marvin.talkback
as can be seen in this Google Play URL: https://play.google.com/store/apps/details?id=com.google.android.marvin.talkback.
Obtaining App Signature
Obtaining the correct app signature is more complicated because a signed APK is necessary. Installing the app from Google Play is recommended. Next, the APK must be pulled from the device.
Find the APK location on the device:
adb shell pm list packages -f | grep "$PACKAGE$" | sed "s/package://" | sed "s/=$PACKAGE//"
Pull the APK from the device:
adb pull "$APK_LOCATION"
Obtain the signature hash in the right format:
apksigner verify --print-certs ${SOME_APK} | grep "SHA-1" | sed "s/.*: //"
The result is the app signature that can be used as the second argument for RaspConfig.ApkAllowlistItem(String, String)
.
Frequently Used Accessibility Apps
This is a list of some frequently used legitimate apps that make Android devices more accessible, though by no means exhaustive:
-
RaspConfig.ApkAllowlistItem("com.google.android.marvin.talkback", "9b424c2d27ad51a42a337e0bb6991c76eca44461")
-
RaspConfig.ApkAllowlistItem("com.google.android.apps.accessibility.voiceaccess", "9dda347424376a377f78c4f2966f247270e16974")
-
RaspConfig.ApkAllowlistItem("com.google.android.accessibility.soundamplifier", "26710bdb08f6463b1f5842e2775169e31dd07301")
-
Live Transcribe & Sound Notifications
RaspConfig.ApkAllowlistItem("com.google.audio.hearing.visualization.accessibility.scribe", "16e7d81dbd9baec338e32a5d7e13eec6af87b6d0")
Usage
After initialization, the screen reader blocking feature can be accessed via RaspManager
. This can be used to trigger a manual check for active screen readers that were not allowed in the configuration.
Registering an Observer
The screen reader blocking feature also detects changes in the set of enabled screen readers and can trigger a certain action. To achieve that, an observer needs to be configured and registered.
Observer configuration:
val raspObserver = object : RaspObserver {
override fun onScreenReaderDetected(screenReaderDetection: ScreenReaderDetection) {
// handle screen reader detection
}
// handle detection of other RASP features
}
The observer can be registered in RaspManager
. When it is no longer needed, it can be unregistered again.
raspManager.registerRaspObserver(raspObserver)
raspManager.unregisterRaspObserver(raspObserver)
Triggering a Manual Check
Check for not allowed screen readers can be triggered manually in RaspManager
. Two methods are available. isNotAllowedScreenReaderEnabled()
indicates whether there’s any active screen reader, that is not allowed in the configuration. Method getScreenReaderDetection()
provides more details, it returns a list of all the active screen readers that are not allowed configuration.
val isNotAllowedScreenReaderEnabled = raspManager.isNotAllowedScreenReaderEnabled()
val screenReaderDetection = raspManager.getScreenReaderDetection()