RASP Feature Overview
RASP (runtime application self-protection) features protect the app against several attack vectors.
Currently, Malwarelytics for Android covers the following problems:
- Detection of rooted devices
- Detection of emulators
- Detection of attached debuggers
- Detection of app repackaging
- Detection of screen sharing (screen mirroring)
- Blocking screenshots of app screens
- Blocking screen readers from reading app screens
- Tapjacking protection
- Detection of HTTP proxy
- Detection of usage of system screen lock
- Obtaining Play Protect status
- Changing of app’s process name
The RASP features are configured as part of Malwarelytics for Android configurations during its initialization.
Later, the RASP features can be accessed through RaspManager
instance.
Configuring Detections
RASP detections are configured via RaspConfig
that is a part of the AppProtectionConfig
.
To configure RASP detections, use:
val config = AppProtectionConfig.Builder(appContext)
.raspConfig(
RaspConfig.Builder()
// …
.build()
)
// …
.build()
When no RaspConfig
is provided, all RASP features are turned off.
When a RaspConfig
is provided, all RASP configurations are enabled by default.
Repackaging is checked only if signatureHash
is set and by default the app exits if repackaging is detected.
A minimum RASP configuration enabling all the features requires only signatureHash
to be set:
val config = AppProtectionConfig.Builder(appContext)
.raspConfig(
RaspConfig.Builder()
.signatureHash(SIGNATURE_HASH)
.build()
)
// …
.build()
The configuration of RaspConfig
offers two basic settings for the RASP detections.
- Turning certain detections on or off.
- Automatically exiting the app when a certain problem is detected.
Available Configuration Items
The RASP configuration contains the following detections:
val raspConfig = RaspConfig.Builder()
.checkEmulator(Boolean)
.exitOnEmulator(Boolean)
.checkRoot(Boolean)
.exitOnRoot(Boolean)
.exitOnRootMinConfidence(Float) // value from 0.0 to 1.0
.checkDebugger(Boolean)
.exitOnDebugger(Boolean)
.checkRepackaging(Boolean)
.exitOnRepackaging(Boolean)
.signatureHash(String) // SHA-1 of signing certificate(s)
.checkScreenSharing(Boolean)
.exitOnScreenSharing(Boolean)
.blockScreenshots(Boolean)
.blockScreenReaders(Boolean)
.allowedScreenReaders(Collection<RaspConfig.ApkAllowlist>)
.customProcessName(String) // when set, turns off useStealthyProcessName
.useStealthyProcessName(Boolean)
.blockTapjacking(Boolean)
.blockTapjackingSensitivity(ThreatIndex)
.checkHttpProxy(Boolean)
.exitOnHttpProxy(Boolean)
.build()
The check*
methods turn certain features on or off. The exit*
methods cause app exit when the corresponding detection is triggered.
The block*
methods blocks certain system features to shield the app from the related vulnerability.
Configuration Items Effects
Below are listed the effects and default values of all the RASP configuration items:
checkEmulator(Boolean)
- Turn on/off automatic emulation detection. It is on by default.exitOnEmulator(Boolean)
- Whether to terminate the app when emulator is automatically detected. It is off by default.checkRoot(Boolean)
- Turns on/off automatic root detection. It is on by default.exitOnRoot(Boolean)
- Whether to terminate the app when rooted device is automatically detected. It is off by default.exitOnRootMinConfidence(Float)
- Minimum confidence value of heuristic root detections that triggers app termination. Works only ifexitOnRoot
is true. Possible values are between0.0
(inclusive) and1.0
(inclusive). The default value is1.0
.checkDebugger(Boolean)
- Turns on/off automatic detection of attached debuggers. It is on by default.exitOnDebugger(Boolean)
- Whether to terminate the app when an attached debugger is automatically detected. It is off by default.checkRepackaging(Boolean)
- Turns on/off automatic repackaging detection. It is on by default but works only ifsignatureHash
is set.exitOnRepackaging(Boolean)
- Whether to terminate the app when repackaging is automatically detected. It is on by default but works only ifsignatureHash
is set.signatureHash(String)
- SHA-1 of signing certificate(s). One or more values can be set. Expecting lowercase hex value without any byte separators. No default value is set.checkScreenSharing(Boolean)
- Turns on/off automatic screen sharing detection. It is on by default.exitOnScreenSharing(Boolean)
- Whether to terminate teh app when screen sharing is automatically detected. It is off by default.blockScreenshots(Boolean)
- Turns on/off blocking taking screenshots and screen recording. It is on by default.blockScreenReaders(Boolean)
- Turn on/off blocking screen readers. It is on by default. Screen readers are blocked only when an enabled screen reader is detected that is not allowed inallowedScreenReaders
.allowedScreenReaders(Collection<RaspConfig.ApkAllowlist>)
- Defines collection of allowed screen readers. It is empty by default.customProcessName(String)
- Sets custom name to be used for the app process. When set, turns offuseStealthyProcessName
.useStealthyProcessName(Boolean)
- Whether to use a stealthy name for the app’s process. It is on by default. When true a name is selected randomly from a list of stealthy process names. It is turned off whencustomProcessName
is set.blockTapjacking(Boolean)
- Turn on/off blocking tapjacking. It is on by default. Tapjacking is blocked only when problematic apps meeting sensitivity criteria defined byblockTapjackingSensitivity
are present.blockTapjackingSensitivity(ThreatIndex)
- Defines sensitivity for blocking tapjacking. The default value isThreatIndex.HIGHLY_DANGEROUS
.checkHttpProxy(Boolean)
- Whether to check if the device is using HTTP proxy. It is on by default.exitOnHttpProxy(Boolean)
- Whether to exit if the device is using HTTP proxy. It is off by default.
Obtaining Detection Results
When Malwarelytics for Android is initialized with certain configurations,
the RASP features can be accessed through RaspManager
. You can obtain the instance from AppProtection
by calling:
val raspManager = appProtection.getRaspManager()
The RaspManager
instance then offers to:
- Register a RASP Observer
- Trigger RASP Checks Manually
When no RaspConfig
is provided, all RASP features are turned off
and RaspManager
instance cannot be used to access RASP features.
Observing RASP Detections
An observer can be registered in RaspManager
to notify the app about any RASP detection.
val raspObserver = object : RaspObserver {
override fun onEmulatorDetected(emulatorDetection: EmulatorDetection) {
// handle emulator detection
}
override fun onRootDetected(rootDetection: RootDetection) {
// handle root detection
}
override fun onDebuggerDetected(debuggerDetected: Boolean) {
// handle debugger detection
}
override fun onRepackagingDetected(repackagingResult: RepackagingResult) {
// handle repackaging detection
}
override fun onScreenSharingDetected(screenSharingDetected: Boolean) {
// handle screen sharing detection
}
override fun onTapjackingDetected(tapjackingDetection: TapjackingDetection) {
// handle tapjacking detection
}
override fun onHttpProxyDetected(httpProxyDetected: Boolean) {
// handle http proxy detection
}
}
raspManager.registerRaspObserver(raspObserver)
The observer can be unregistered when no longer necessary:
raspManager.unregisterRaspObserver(raspObserver)
The observer callbacks are always called on a background thread and before the app exits. It’s recommended to perform only a quick lightweight processing in the callback as any heavy processing or threading are not guaranteed to be completed.
Any detections that are manually triggered via RaspManager
are not propagated into the observer.
Triggering RASP Checks Manually
All the RASP checks can be triggered manually in RaspManager
.
There are usually two methods for the checks. One for simple boolean answer
and one for a more detailed information.
// root detection
val rootDetection = raspManager.getRootDetection()
val isRooted = raspManager.isDeviceRooted()
// emulator detection
val emulatorDetection = raspManager.getEmulatorDetection()
val isDeviceEmulator = raspManager.isDeviceEmulator()
// debugger
val debuggerDetection = raspManager.getDebuggerDetection()
val isDebuggerAttached = raspManager.isDebuggerAttached()
// repackaging
val repackagingResult = raspManager.isAppRepackaged()
// screen sharing
val screenSharingDetection = raspManager.getScreenSharingDetection()
val isScreenShared = raspManager.isScreenShared()
// screen lock usage
val isDeviceUsingScreenLock = raspManager.isDeviceUsingScreenLock()
// Play Protect status
val isPlayProtectEnabled = raspManager.isPlayProtectEnabled()
// tapjacking
val isBadTapjackingCapableAppPresent = raspManager.isBadTapjackingCapableAppPresent()
val tapjackingDetection = raspManager.getTapjackingDetection()
// http proxy detection
val isHttpProxyEnabled = raspManager.isHttpProxyEnabled()