Skip to content

securevale/android-rasp

Repository files navigation

Android RASP

CI Kotlin Android Android Gradle Maven

An open-source RASP (Runtime Application Self-Protection) solution for protecting Android apps against being run on vulnerable devices.

Note

Android RASP is still in development, meaning that some breaking changes are likely to be introduced in future releases. See Versioning section for more information.

Motivation

In the current threat-rich environment, it is crucial to protect the apps against exploitation of a wide range of vulnerabilities and reverse engineering techniques. Hooking frameworks, man-in-the-middle attacks, app repackaging, rooted devices, just to name a few common threats applicable to mobile applications.

While there are existing solutions for guarding against aforementioned threats, almost all of them are paid. This library is one attempt to provide a robust solution for "regular" teams and devs that cannot afford spending hundreds of dollars per month to defend against this kind of threats, allowing to take control over application execution, security threat detection, and real-time attack prevention.

Note

While adopting this library will shield your app against a number of runtime security threats, you need to remember that no security measure can ever guarantee absolute security. Any motivated and skilled enough attacker will eventually bypass all security protections. For this reason, always keep your threat models up to date.

Getting started

First ensure that you have defined mavenCentral in your Gradle configuration.

repositories {
    mavenCentral()
}

Next, add Android RASP library as a dependency to your project.

dependencies {
    implementation 'com.securevale:rasp-android:{version}'
}

Before first use, the library needs to be initialised with init() method. This method is expected to be called only once per app's lifecycle, so the best place for doing it is inside of your app's Application class.

import com.securevale.rasp.android.native.SecureApp

class SampleApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        SecureApp.init()
    }
}

Then, create a builder with the desired configuration options.

import com.securevale.rasp.android.emulator.CheckLevel
import com.securevale.rasp.android.api.SecureAppChecker

val shouldCheckForEmulator = true
val shouldCheckForDebugger = true

val builder = SecureAppChecker.Builder(
    context,
    checkEmulator = shouldCheckForEmulator,
    checkDebugger = shouldCheckForDebugger
)

Use the builder to create the RASP checks and trigger them to obtain the result.

import com.securevale.rasp.android.api.result.Result

val check = builder.build()
val checkResult = check.check()

when (checkResult) {
    is Result.EmulatorFound -> {} // app is most likely running on emulator
    is Result.DebuggerEnabled -> {} // app is in debug mode
    is Result.Secure -> {} // OK, no threats detected
}

You can also perform more granular checks.

val check = builder.build()
check.subscribe {
    // examine result(s) here
}

Or even subscribe in order to be notified only when a potential threat is detected.

val check = builder.build()
check.subscribeVulnerabilitiesOnly(granular = true) {
  // examine result(s) here
}

You can also choose which checks should be run by passing appropriate list to the checkOnlyFor parameter.

import com.securevale.rasp.android.api.result.DebuggerChecks
import com.securevale.rasp.android.api.result.EmulatorChecks

val check = builder.build()
check.subscribeVulnerabilitiesOnly(
  granular = true,
  checkOnlyFor = arrayOf(
    EmulatorChecks.AvdDevice,
    EmulatorChecks.AvdHardware,
    EmulatorChecks.Genymotion,
    EmulatorChecks.Nox,
    DebuggerChecks.Debuggable,
    DebuggerChecks.DebugField
  )
) {
  // examine result(s) here
}

For more information about available configuration options, see SecureAppChecker class documentation.

Important

A skilled attacker might be able to repackage protected app and remove the checks from the source code. With that said, it is highly recommended to add these checks in multiple places in code, so as to maximize the cost and effort required to successfully bypass all the checks. Additionally, in order to further impede the malicious actors' life, the library checks are written in native code (using Rust language) and distributed with library source code as .so library files.

Supported Checks

Debugger Detection

Includes:

  • Several checks for debug flags;
  • Check for connected debugger;
  • Check for threads waiting for the debugger to be attached.

Emulator Detection

Includes:

  • Check for "basic" emulator indicators (mostly device build configuration fields indicating whether particular device is "real" or not). These fields can be easily faked by the emulator makers or even by the device user (if the device happens to be rooted);
  • More advanced checks (such as device's operator name, telephone number, properties etc.). Recommended when you need to be more certain whether the device is an emulator. Please note that in order to take full advantage of these checks, you need to add android.permission.READ_PHONE_STATE permission to your application manifest file.

All implemented checks were tested on various emulators and devices to decrease both false-positives ( when device that is not an emulator is reported as one) and false-negatives. However, as the detection techniques become more advanced, the emulator detection bypass tools are improving as well. This is a never ending cat and mouse game, so there is no guarantee that all emulators will be correctly and accurately reported as such. The library shall be continuously updated with new emulator detection techniques with the aim of catching the emulators that slip through the existing checks.

ProGuard

Android RASP ships with its own ProGuard rules, except one caveat regarding the DebugField check. The library relies on BuildConfig class which needs to be excluded from obfuscation. In order for this check to return correct results, add the following line to your ProGuard configuration file:

-keep class {your_package}.BuildConfig{ *; }

Alternatively, you can opt out from this check by excluding DebugField from an array of checks passed to checkOnlyFor parameter.

Sample app

Sample allows you to test checks. To run it you need to clone the project and build and run "sample-app" project on device of your choice.

sample-app

Versioning

This project follows semantic versioning. While still in major version 0, source-stability is only guaranteed within minor versions (e.g. between 0.3.0 and 0.3.1). If you want to guard against potentially source-breaking package updates, you can specify your package dependency using exact version as the requirement.

License

This tool and code is released under Apache License v2.0 with Runtime Library Exception. Please see LICENSE for more information.