Skip to content

Commit

Permalink
feat: Add support for android root detection and frida detection (#3837)
Browse files Browse the repository at this point in the history
new build hints:
android.rootCheck=true|false
android.fridaDetection=true|false
  • Loading branch information
shannah authored Aug 31, 2024
1 parent b28919c commit 97f9b18
Show file tree
Hide file tree
Showing 2 changed files with 177 additions and 13 deletions.
140 changes: 140 additions & 0 deletions Ports/Android/src/com/codename1/impl/android/FridaDetectionUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package com.codename1.impl.android;

import android.content.Context;
import android.util.Log;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class FridaDetectionUtil {

private static final String TAG = "Codename One";

// List of common Frida process names
private static final String[] FRIDA_PROCESSES = {
"frida-server",
"frida-agent",
"frida-injector",
"frida"
};

// List of common Frida libraries
private static final String[] FRIDA_LIBRARIES = {
"libfrida-gadget.so"
};

// Check for known Frida processes
public static boolean isFridaProcessRunning() {
try {
Process process = Runtime.getRuntime().exec("ps");
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
for (String processName : FRIDA_PROCESSES) {
if (line.contains(processName)) {
Log.e(TAG, "Frida process detected: " + processName);
return true;
}
}
}
reader.close();
} catch (Exception e) {
Log.e(TAG, "Error checking for Frida processes: " + e.getMessage());
}
return false;
}

// Check for Frida libraries loaded in the app
public static boolean isFridaLibraryLoaded() {
BufferedReader reader = null;
try {
FileInputStream fis = new FileInputStream(new File("/proc/self/maps"));
reader = new BufferedReader(new InputStreamReader(fis));
String line;
while ((line = reader.readLine()) != null) {
for (String lib : FRIDA_LIBRARIES) {
if (line.contains(lib)) {
Log.e(TAG, "Frida library loaded: " + lib);
return true;
}
}
}
} catch (Exception e) {
Log.e(TAG, "Error checking for Frida libraries: " + e.getMessage());
} finally {
if (reader != null) {
try {
reader.close();
} catch (Exception e) {
Log.e(TAG, "Error closing reader: " + e.getMessage());
}
}
}
return false;
}

// Check for suspicious system properties
public static boolean isFridaPropertySet() {
try {
List<String> suspiciousProperties = new ArrayList<String>();
suspiciousProperties.add(getSystemProperty("ro.debuggable"));
suspiciousProperties.add(getSystemProperty("ro.secure"));

for (String property : suspiciousProperties) {
if ("1".equals(property)) {
Log.e(TAG, "Suspicious system property detected: " + property);
return true;
}
}
} catch (Exception e) {
Log.e(TAG, "Error checking for Frida properties: " + e.getMessage());
}
return false;
}

// Get the value of a system property
private static String getSystemProperty(String propName) {
try {
Class clazz = Class.forName("android.os.SystemProperties");
Method method = clazz.getMethod("get", new Class[] { String.class });
return (String) method.invoke(null, new Object[] { propName });
} catch (Exception e) {
Log.e(TAG, "Error getting system property: " + e.getMessage());
return null;
}
}

// Check for Frida-specific classes
public static boolean isFridaClassDetected() {
try {
Class clazz = Class.forName("re.frida.ServerManager");
if (clazz != null) {
Log.e(TAG, "Frida class detected: re.frida.ServerManager");
return true;
}
} catch (ClassNotFoundException e) {
// Expected if Frida is not present
}
return false;
}

// Comprehensive method to run all checks
public static boolean isFridaDetected() {
return isFridaProcessRunning() || isFridaLibraryLoaded() || isFridaPropertySet() || isFridaClassDetected();
}

// Run the detection checks and log the result
public static void runFridaDetection(Context context) {
if (isFridaDetected()) {
Log.e(TAG, "Frida detected! Exiting app.");
System.exit(0);
} else {
Log.i(TAG, "No Frida detection evidence found.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ public class AndroidGradleBuilder extends Executor {
private String gradle8DistributionUrl = "https://services.gradle.org/distributions/gradle-8.1-bin.zip";
public boolean PREFER_MANAGED_GRADLE=true;

private boolean rootCheck = false;

private boolean fridaDetection = false;

private boolean useGradle8 = true;

// Flag to indicate whether we should strip kotlin from user classes
Expand Down Expand Up @@ -491,6 +495,8 @@ public boolean build(File sourceZip, final BuildRequest request) throws BuildExc
boolean facebookSupported = request.getArg("facebook.appId", null) != null;
newFirebaseMessaging = request.getArg("android.newFirebaseMessaging", "true").equals("true");
useGradle8 = request.getArg("android.useGradle8", ""+(useGradle8 || newFirebaseMessaging || facebookSupported)).equals("true");
rootCheck = request.getArg("android.rootCheck", "false").equals("true");
fridaDetection = request.getArg("android.fridaDetection", "false").equals("true");
extendAppCompatActivity = request.getArg("android.extendAppCompatActivity", "false").equals("true");
// When using gradle 8 we need to strip kotlin files from user classes otherwise we get duplicate class errors
stripKotlinFromUserClasses = useGradle8;
Expand Down Expand Up @@ -1316,11 +1322,11 @@ public void usesClassMethod(String cls, String method) {

debug("-----USING PLAY SERVICES VERSION "+playServicesVersion+"----");

String compile = "compile";
if (useAndroidX || useArrImplementation) {
compile = "implementation";
}
if (useFCM) {
String compile = "compile";
if (useAndroidX || useArrImplementation) {
compile = "implementation";
}
if (!googleServicesJson.exists()) {
error("google-services.json not found. When using FCM for push notifications (i.e. android.messagingService=fcm), you must include valid google-services.json file. Use the Firebase console to add Firebase messaging to your app. https://console.firebase.google.com/u/0/ Then download the google-services.json file and place it in the native/android directory of your project. If you still want to use GCM (which no longer works) define the build hint android.messagingService=gcm", new RuntimeException());
return false;
Expand Down Expand Up @@ -2532,6 +2538,30 @@ public void usesClassMethod(String cls, String method) {

}

String rootCheckCall = "";
if (rootCheck) {
if (!request.getArg("gradleDependencies", "").contains("com.scottyab:rootbeer-lib")) {
String rootbeerVersion = request.getArg("android.rootbeerVersion", "0.1.0");
request.putArgument(
"gradleDependencies",
request.getArg("gradleDependencies", "") +
"\n"+compile+" \"com.scottyab:rootbeer-lib:" + rootbeerVersion + "\"\n"
);
}

rootCheckCall = " com.scottyab.rootbeer.RootBeer rootBeer = new com.scottyab.rootbeer.RootBeer(this);\n"
+ " if (rootBeer.isRooted()) {\n"
+ " android.util.Log.e(\"Codename One\", \"Device is rooted. Exiting app.\");\n"
+ " System.exit(0);\n"
+ " }\n";
}

String fridaDetectionCall = "";
if (fridaDetection) {
fridaDetectionCall = " com.codename1.impl.android.FridaDetectionUtil.runFridaDetection(this);\n";
}


String waitingForPermissionsRequest=
" if (isWaitingForPermissionResult()) {\n" +
" setWaitingForPermissionResult(false);\n" +
Expand Down Expand Up @@ -2588,6 +2618,8 @@ public void usesClassMethod(String cls, String method) {
+ " }\n\n"
+ " public void onCreate(Bundle savedInstanceState) {\n"
+ " super.onCreate(savedInstanceState);\n"
+ fridaDetectionCall
+ rootCheckCall
+ facebookHashCode
+ facebookSupport
+ streamMode
Expand Down Expand Up @@ -2638,7 +2670,6 @@ public void usesClassMethod(String cls, String method) {
throw new BuildException("Failed to generate stub source code", ex);
}


String fcmRegisterPushCode = "";
if (useFCM) {
if (newFirebaseMessaging) {
Expand Down Expand Up @@ -3319,10 +3350,6 @@ public void usesClassMethod(String cls, String method) {
request.putArgument("var.android.playServicesVersion", playServicesVersion);
String additionalDependencies = request.getArg("gradleDependencies", "");
if (facebookSupported) {
String compile = "compile";
if (useAndroidX || useArrImplementation) {
compile = "implementation";
}
minSDK = maxInt("15", minSDK);

if(request.getArg("android.excludeBolts", "false").equals("true")) {
Expand All @@ -3335,10 +3362,7 @@ public void usesClassMethod(String cls, String method) {
facebookSdkVersion + "'\n";
}
}
String compile = "compile";
if (useAndroidX || useArrImplementation) {
compile = "implementation";
}

if (legacyGplayServicesMode) {
additionalDependencies += " "+compile+" 'com.google.android.gms:play-services:6.5.87'\n";
} else {
Expand Down

0 comments on commit 97f9b18

Please sign in to comment.