RASP Feature Overview
RASP (runtime application self-protection) features protect the app against several attack vectors at runtime. Here is a list of available features:
- 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 VPN
- Detection of usage of system screen lock
- Obtaining Play Protect status
- Changing app process name
- Detection of ADB status
- Detection of developer options status
- Detection of biometry enrollment status
- Activity protection
Configuration
RASP features can be initially configured by building a RaspConfig
instance and passing it to the raspConfig
method in the general AppProtectionConfig
:
val config = AppProtectionConfig.Builder(appContext)
.raspConfig(
RaspConfig.Builder()
// RASP feature configuration
.build()
)
// other Malwarelytics configuration
.build()
When no RaspConfig
instance is provided, all RASP features are turned off. When a RaspConfig
instance is provided, all RASP configurations are enabled by default. However, the repackaging detection feature requires a signatureHash
to be set.
A minimum RASP configuration with all features enabled requires only signatureHash
to be set:
val config = AppProtectionConfig.Builder(appContext)
.raspConfig(
RaspConfig.Builder()
.signatureHash(SIGNATURE_HASH)
.build()
)
// …
.build()
Available Configuration Items
val raspConfig = RaspConfig.Builder()
.checkEmulator(Boolean)
.exitOnEmulator(Boolean)
.exitOnEmulatorUrl(String)
.checkRoot(Boolean)
.exitOnRoot(Boolean)
.exitOnRootUrl(String)
.exitOnRootMinConfidence(Float) // value from 0.0 to 1.0
.checkDebugger(Boolean)
.exitOnDebugger(Boolean)
.exitOnDebuggerUrl(String)
.checkRepackaging(Boolean)
.exitOnRepackaging(Boolean)
.exitOnRepackagingUrl(String)
.signatureHash(String) // SHA-1 of signing certificate(s)
.checkScreenSharing(Boolean)
.exitOnScreenSharing(Boolean)
.exitOnScreenSharingUrl(String)
.blockScreenshots(Boolean)
.blockScreenReaders(Boolean)
.allowedScreenReaders(Collection<RaspConfig.ApkAllowlistItem>)
.customProcessName(String) // when set, turns off useStealthyProcessName
.useStealthyProcessName(Boolean)
.blockTapjacking(Boolean)
.ignoreTapjackingSystemApps(Boolean)
.blockTapjackingSensitivity(ThreatIndex)
.allowedTapjackingApps(Collection<RaspConfig.ApkAllowlistItem>)
.checkHttpProxy(Boolean)
.exitOnHttpProxy(Boolean)
.exitOnHttpProxyUrl(String)
.checkVpn(Boolean)
.exitOnVpn(Boolean)
.exitOnVpnUrl(String)
.exitOnAdbEnabled(Boolean)
.exitOnAdbEnabledUrl(String)
.build()
Method | Description |
---|---|
checkEmulator(Boolean) |
indicates whether emulators should be detected automatically. Defaults to true . |
exitOnEmulator(Boolean) |
indicates whether the app should be terminated when an emulator is automatically detected. Defaults to false . |
exitOnEmulatorUrl(String) |
defines a URL to be opened when the app is terminated because of emulator detection. Defaults to null . |
checkRoot(Boolean) |
indicates whether rooted device should be detected automatically. Defaults to true . |
exitOnRoot(Boolean) |
indicates whether the app should be terminated when a rooted device is automatically detected. Defaults to false . |
exitOnRootUrl(String) |
defines a URL to be opened when the app is terminated because of root detection. Defaults to null . |
exitOnRootMinConfidence(Float) |
gives the minimum confidence value of a heuristic root detection that triggers app termination. Works only if exitOnRoot is true . Possible values are between 0.0 (inclusive) and 1.0 (inclusive). The default value is 1.0 . |
checkDebugger(Boolean) |
indicates whether debuggers should be detected automatically. Defaults to true . |
exitOnDebugger(Boolean) |
indicates whether the app should be terminated when a debugger is automatically detected. Defaults to false . |
exitOnDebuggerUrl(String) |
defines a URL to be opened when the app is terminated because of debugger detection. Defaults to null . |
signatureHash(String) |
SHA-1 of signing certificate(s). One or more values can be set. A lowercase hex value without any byte separators is expected. No default value is set. |
checkRepackaging(Boolean) |
indicates whether repackaging should be detected automatically. Defaults to true but works only if signatureHash is set. |
exitOnRepackaging(Boolean) |
indicates whether the app should be terminated when repackaging is automatically detected. Defaults to true but works only if signatureHash is set. |
exitOnRepackagingUrl(String) |
defines a URL to be opened when the app is terminated because of repackaging detection. Defaults to null . |
checkScreenSharing(Boolean) |
indicates whether screen sharing should be detected automatically. Defaults to true . |
exitOnScreenSharing(Boolean) |
indicates whether the app should be terminated when screen sharing is automatically detected. Defaults to false . |
exitOnScreenSharingUrl(String) |
defines a URL to be opened when the app is terminated because of screen sharing detection. Defaults to null . |
blockScreenshots(Boolean) |
indicates whether taking screenshots and screen recordings should be blocked. Defaults to true . |
allowedScreenReaders( Collection<RaspConfig.ApkAllowlistItem>) |
defines a collection of allowed screen readers. It is empty by default. |
blockScreenReaders(Boolean) |
indicates whether screen readers should be blocked. Defaults to true . However, screen readers are only blocked if Malwarelytics detects an enabled screen reader that is not whitelisted in allowedScreenReaders . |
customProcessName(String) |
sets a custom name which will be used for the app process. When the name is set, the useStealthyProcessName option is automatically turned off. |
useStealthyProcessName(Boolean) |
indicates whether a stealthy name should be used for the app process. Defaults to true . |
blockTapjacking(Boolean) |
indicates whether tapjacking should be blocked. Defaults to true . However, tapjacking is not blocked unless a “problematic” app is installed on the device. An app is deemed “problematic” when it meets sensitivity criteria defined by blockTapjackingSensitivity . |
ignoreTapjackingSystemApps(Boolean) |
indicates whether tapjacking protection should ignore system apps in the checks. Defaults to false . |
blockTapjackingSensitivity(ThreatIndex) |
defines tapjacking protection sensitivity. Defaults to ThreatIndex.HIGHLY_DANGEROUS . |
allowedTapjackingApps(Collection<RaspConfig.ApkAllowlistItem>) |
defines a collection of allowed app capable of tapjacking. It is empty by default. |
checkHttpProxy(Boolean) |
indicates whether HTTP proxy use should be detected automatically. Defaults to true . |
exitOnHttpProxy(Boolean) |
indicates whether the app should be terminated when the use of an HTTP proxy is detected. Defaults to false . |
exitOnHttpProxyUrl(String) |
defines a URL to be opened when the app is terminated because of detection of HTTP proxy. Defaults to null . |
checkVpn(Boolean) |
indicates whether VPN use should be detected automatically. Defaults to true . |
exitOnVpn(Boolean) |
indicates whether the app should be terminated when the use of a VPN is detected. Defaults to false . |
exitOnVpnUrl(String) |
defines a URL to be opened when the app is terminated because of detection of a VPN. Defaults to null . |
exitOnAdbEnabled(Boolean) |
indicates whether the app should be terminated when ADB (Android Debug Bridge) is enabled on the device. Defaults to false . |
exitOnAdbEnabledUrl(String) |
defines a URL to be opened when the app is terminated because of detection of enabled ADB. Defaults to null . |
The check-
methods turn certain features on or off. The exit-
methods cause the app to exit when the corresponding detection is triggered. The block-
methods block certain system features to shield the app against the related vulnerability.
Detailed information about these configuration items can be found on the documentation pages of individual features.
Obtaining Detection Results
After Malwarelytics for Android has been initialized with certain configurations, RASP features can be accessed with RaspManager
. You can obtain an instance from AppProtection
by calling:
val raspManager = appProtection.getRaspManager()
When RaspConfig
is not provided, all RASP features are turned off and the RaspManager
instance cannot be used to access RASP features.
You can use the RaspManager
instance to register and unregister a RASP observer or to trigger RASP checks manually.
Observing RASP Detections
An observer can be registered in RaspManager
to notify the app about any RASP detections. This is an example of registering an observer in which all available detections are handled:
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
}
override fun onVpnDetected(vpnEnabled: Boolean) {
// handle VPN detection
}
override fun onAdbStatusDetected(adbStatus: Boolean) {
// handle ADB status detection
}
}
raspManager.registerRaspObserver(raspObserver)
The observer can be unregistered when it is no longer necessary:
raspManager.unregisterRaspObserver(raspObserver)
The observer callbacks are always called on a background thread before the app exits. It’s recommended to perform only a quick lightweight processing in the callback as any heavy processing or threading is not guaranteed to be completed.
Any detections that are manually triggered via RaspManager
(see section below) are not propagated into the observer.
Triggering RASP Checks Manually
All RASP checks can be triggered manually with RaspManager
. There are two types of manual checks: the is-
methods give a simple boolean answer whereas the get-
methods provide 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()
val httpProxyDetection = raspManager.getHttpProxyDetection()
// VPN
val isVpnEnabled = raspManager.isVpnEnabled()
// ADB status
val isAdbEnabled = raspManager.isAdbEnabled()
// developer options status
val isDeveloperOptionsEnabled = raspManager.isDeveloperOptionsEnabled()
// biometry enrollment status
val biometryDetection = raspManager.getBiometryDetection()