Skip to content

Commit

Permalink
Root detection
Browse files Browse the repository at this point in the history
  • Loading branch information
bmaciejm committed May 7, 2024
1 parent 429cee2 commit 5cd0670
Show file tree
Hide file tree
Showing 44 changed files with 935 additions and 237 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ local.properties
local.keystore

output-metadata.json
*.apk
*.apk

roadmap
36 changes: 32 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,13 @@ import com.securevale.rasp.android.api.SecureAppChecker

val shouldCheckForEmulator = true
val shouldCheckForDebugger = true
val shouldCheckForRoot = true

val builder = SecureAppChecker.Builder(
context,
checkEmulator = shouldCheckForEmulator,
checkDebugger = shouldCheckForDebugger
this,
checkEmulator = shouldCheckForEmulator,
checkDebugger = shouldCheckForDebugger,
checkRoot = shouldCheckForRoot
)
```

Expand All @@ -95,6 +97,7 @@ 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.Rooted -> {} // app is most likely rooted
is Result.Secure -> {} // OK, no threats detected
}
```
Expand Down Expand Up @@ -123,6 +126,7 @@ the `checkOnlyFor` parameter.
```kotlin
import com.securevale.rasp.android.api.result.DebuggerChecks
import com.securevale.rasp.android.api.result.EmulatorChecks
import com.securevale.rasp.android.api.result.RootChecks

val check = builder.build()
check.subscribeVulnerabilitiesOnly(
Expand All @@ -133,7 +137,13 @@ check.subscribeVulnerabilitiesOnly(
EmulatorChecks.Genymotion,
EmulatorChecks.Nox,
DebuggerChecks.Debuggable,
DebuggerChecks.DebugField
DebuggerChecks.DebugField,
RootChecks.SuUser,
RootChecks.TestTags,
RootChecks.RootApps,
RootChecks.RootCloakingApps,
RootChecks.WritablePaths,
RootChecks.SuspiciousProperties
)
) {
// examine result(s) here
Expand Down Expand Up @@ -182,6 +192,24 @@ never ending cat and mouse game, so there is no guarantee that all emulators wil
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.

## Root Detection

Includes:

- Checks for superuser indicators;
- Checks for test tags present on device;
- Checks for rooting and root cloaking apps (still in progress);
- Checks for paths that should not be writable;
- Checks for suspicious properties;

>[!IMPORTANT]
> Since rooting is dynamic domain, checks associated with it must continuously evolve. It's important to understand that these checks are not exhaustive, and
> should be expected to undergo continuous improvement.

> [!NOTE]
> Although some basics checks for Magisk are already applied, "real" Magisk detection is expected to be implemented in future releases.
## ProGuard

Android RASP ships with its own ProGuard rules, except one caveat regarding the `DebugField`
Expand Down
4 changes: 2 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ plugins {
id("com.vanniktech.maven.publish") version "0.25.2"
}

val versionCode by extra { 5 }
val versionName by extra { "0.5.0" }
val versionCode by extra { 6 }
val versionName by extra { "0.6.0" }
val minSdkVersion by extra { 24 }
val compileSdkVersion by extra { 34 }
val targetSdkVersion by extra { 34 }
Expand Down
7 changes: 3 additions & 4 deletions native/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,16 @@ version = "0.1.0"
edition = "2021"

[dependencies]
log = "0.4.19"
log = "0.4.21"
jni = "0.21.1"
android_logger = "0.13.1"
once_cell = "1.18.0"
android_logger = "0.13.3"
once_cell = "1.19.0"

[lib]
name = "native"
crate-type = ["cdylib"]

[profile.release]
strip = true
lto = true

#[profile.release-with-debug]
Expand Down
8 changes: 8 additions & 0 deletions native/src/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
pub mod build;
pub mod files;
pub mod info;
pub mod logging;
pub mod package;
pub mod property;
pub mod system;
pub mod util;
1 change: 1 addition & 0 deletions native/src/build.rs → native/src/common/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub const BRAND: &str = "BRAND";
pub const BOARD: &str = "BOARD";
pub const MANUFACTURER: &str = "MANUFACTURER";
pub const HARDWARE: &str = "HARDWARE";
pub const DISPLAY: &str = "DISPLAY";
pub const FINGERPRINT: &str = "FINGERPRINT";
pub const PRODUCT: &str = "PRODUCT";
pub const TAGS: &str = "TAGS";
Expand Down
61 changes: 58 additions & 3 deletions native/src/files.rs → native/src/common/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ use std::io;
use std::io::{BufRead, BufReader};
use std::path::Path;

#[cfg(debug_assertions)]
use log::LevelFilter::Error;

#[cfg(debug_assertions)]
use crate::logging::log_android;
use crate::common::logging::log_android;

pub fn has_genymotion_files() -> bool {
check_files_present(&GENYMOTION_FILES)
Expand Down Expand Up @@ -40,12 +41,22 @@ pub fn has_phoenix_files() -> bool {
check_files_present(&PHOENIX_FILES)
}

pub fn has_su_files() -> bool {
check_files_present(&SU_FILES)
}

pub fn has_busybox_files() -> bool {
check_files_present(&BUSYBOX_FILES)
}

fn check_files_present(suspicious_file_paths: &[&str]) -> bool {
let mut check_result = false;
for file_path in suspicious_file_paths.iter() {
match Path::new(file_path).try_exists() {
Ok(result) => {
if result {
return true;
check_result = true;
break;
}
}
Err(err) => {
Expand All @@ -58,7 +69,7 @@ fn check_files_present(suspicious_file_paths: &[&str]) -> bool {
}
}

false
check_result
}

pub fn find_in_file(file_path: &str, search_phrases: &[&str]) -> Result<bool, io::Error> {
Expand Down Expand Up @@ -109,6 +120,40 @@ const EMU_FILES: [&str; 19] = [
"/data/data/com.ldmnq.launcher3/files/launcher.preferences",
];

/// Su files (indicates superuser - root privileges)
const SU_FILES: [&str; 15] = [
"/sbin/su",
"su/bin/su",
"/system/bin/su",
"/system/bin/.ext/su",
"/system/xbin/su",
"/data/local/xbin/su",
"/data/local/bin/su",
"/system/sd/xbin/su",
"/system/bin/failsafe/su",
"/system/usr/we-need-root/su",
"/data/local/su",
"/cache/su",
"/dev/su",
"/data/su",
"/system/app/Superuser.apk",
];

/// Busybox files TODO check what is busybox
const BUSYBOX_FILES: [&str; 11] = [
"/sbin/busybox",
"su/bin/busybox",
"/system/bin/busybox",
"/system/bin/.ext/busybox",
"/system/xbin/busybox",
"/data/local/xbin/busybox",
"/data/local/bin/busybox",
"/system/sd/xbin/busybox",
"/system/bin/failsafe/busybox",
"/system/usr/we-need-root/busybox",
"/data/local/busybox",
];

/// Pipes indicate that it is most likely an emulator.
const X86_FILES: [&str; 10] = [
"ueventd.android_x86.rc",
Expand Down Expand Up @@ -167,3 +212,13 @@ const PHOENIX_FILES: [&str; 3] = [
"/data/system/phoenixlog.addr",
"/system/phoenixos",
];

pub const NON_WRITABLE_PATHS: [&str; 7] = [
"/system",
"/system/bin",
"/system/sbin",
"/system/xbin",
"/vendor/bin",
"/sbin",
"/etc",
];
10 changes: 6 additions & 4 deletions native/src/info.rs → native/src/common/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ use jni::objects::{JClass, JObject, JString, JValue};
use jni::sys::jstring;
use jni::JNIEnv;

use crate::build::get_build_config_value;
use crate::{build, emulator, files, system};
use crate::common::build::get_build_config_value;
use crate::common::property::emulator_properties_found;
use crate::{common::build, common::files, common::system};

// TODO add info about root
#[no_mangle]
pub unsafe extern "C" fn Java_com_securevale_rasp_android_util_DeviceInfoKt_deviceInfo(
mut env: JNIEnv,
Expand Down Expand Up @@ -58,7 +60,7 @@ pub unsafe extern "C" fn Java_com_securevale_rasp_android_util_DeviceInfoKt_exte
Genymotion files: {}
Emulator Pipes: {}
Qemu Property ro.kernel.qemu: {}
Qemu Properties count: {}
Qemu Properties found: {}
",
files::has_nox_files(),
files::has_andy_files(),
Expand All @@ -68,7 +70,7 @@ pub unsafe extern "C" fn Java_com_securevale_rasp_android_util_DeviceInfoKt_exte
files::has_genymotion_files(),
files::has_pipes(),
system::get_prop(&mut env, &"ro.kernel.qemu".to_string()) == "1",
emulator::properties::properties_count(&mut env),
emulator_properties_found(&mut env),
);

env.new_string(result)
Expand Down
File renamed without changes.
131 changes: 131 additions & 0 deletions native/src/common/package.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
use jni::JNIEnv;
use jni::objects::{JObject, JValue};

use crate::common::util;

pub fn has_emulator_packages(env: &mut JNIEnv, context: &JObject) -> bool {
is_package_suspicious(env, context, &SUSPICIOUS_EMULATOR_PACKAGES)
}

pub fn has_root_packages(env: &mut JNIEnv, context: &JObject) -> bool {
is_package_suspicious(env, context, &ROOT_APP_PACKAGES)
}

pub fn has_root_cloaking_packages(env: &mut JNIEnv, context: &JObject) -> bool {
is_package_suspicious(env, context, &ROOT_CLOAKING_APP_PACKAGES)
}

fn is_package_suspicious(env: &mut JNIEnv, context: &JObject, suspicious_package: &[&str]) -> bool {
let package_manager = JObject::try_from(
env.call_method(
context,
"getPackageManager",
"()Landroid/content/pm/PackageManager;",
&[],
)
.unwrap(),
)
.unwrap();

let mut result = false;

for package in suspicious_package.iter() {
let package_info = env.call_method(
&package_manager,
"getPackageInfo",
"(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;",
&[
JValue::Object(&JObject::from(env.new_string(package).unwrap())),
JValue::Int(0),
],
);

util::ignore_error(env);

if package_info.is_ok() {
result = true;
break;
}
}

result
}

/**
* Suspicious emulator packages.
*/
const SUSPICIOUS_EMULATOR_PACKAGES: [&str; 10] = [
"com.google.android.launcher.layouts.genymotion",
"com.bluestacks",
"com.vphone.launcher",
"com.bluestacks.appmart",
"com.bignox",
"com.bignox.app",
"com.google.android.launcher.layouts.genymotion",
"com.microvirt.tools",
"com.microvirt.download",
"com.mumu.store",
];

/**
* Known root app packages.
*/
const ROOT_APP_PACKAGES: [&str; 43] = [
"com.noshufou.android.su",
"com.noshufou.android.su.elite",
"com.koushikdutta.superuser",
"com.thirdparty.superuser",
"com.topjohnwu.magisk",
"com.kingo.roo",
"com.zhiqupk.root.global",
"com.smedialink.oneclickroot",
"com.alephzain.framaroo",
"com.yellowes.su",
"com.kingroot.kinguser",
"com.zachspong.temprootremovejb",
"com.ramdroid.appquarantine",
"eu.chainfire.supersu",
"stericson.busybox",
"com.alephzain.framaroot",
"com.kingo.root",
"com.koushikdutta.rommanager",
"com.koushikdutta.rommanager.license",
"com.dimonvideo.luckypatcher",
"com.chelpus.lackypatch",
"com.ramdroid.appquarantinepro",
"com.xmodgame",
"com.cih.game_cih",
"com.charles.lpoqasert",
"catch_.me_.if_.you_.can_",
"org.blackmart.market",
"com.allinone.free",
"com.repodroid.app",
"org.creeplays.hack",
"com.baseappfull.fwd",
"com.zmapp",
"com.dv.marketmod.installer",
"org.mobilism.android",
"com.android.wp.net.log",
"com.android.camera.update",
"cc.madkite.freedom",
"com.solohsu.android.edxp.manager",
"org.meowcat.edxposed.manager",
"com.android.vending.billing.InAppBillingService.COIN",
"com.android.vending.billing.InAppBillingService.LUCK",
"com.chelpus.luckypatcher",
"com.blackmartalpha",
];

/**
* Known root cloaking app packages.
*/
const ROOT_CLOAKING_APP_PACKAGES: [&str; 8] = [
"com.devadvance.rootcloak",
"com.devadvance.rootcloakplus",
"de.robv.android.xposed.installer",
"com.saurik.substrate",
"com.amphoras.hidemyroot",
"com.amphoras.hidemyrootadfree",
"com.formyhm.hiderootPremium",
"com.formyhm.hideroot",
];
Loading

0 comments on commit 5cd0670

Please sign in to comment.