Skip to content

Latest commit

 

History

History
407 lines (339 loc) · 17.6 KB

File metadata and controls

407 lines (339 loc) · 17.6 KB

Client-Side Protections Bypass - Android

Getting protection details:

STEP 1: Debugging with Logcat, stack trace analysis

  • Use Logcat to monitor logs in real time while your application is running. This helps identify suspicious behavior such as root checks, attempts to detect debugging tools, or failures caused by protection mechanisms. While the application is running, perform normal interactions and watch the log for messages that contain terms such as "root", "debugger", "frida", "magisk", "xposed", or any other indications of protections checking. If the application crashes, analyze the stack trace to understand which methods were being executed at the time of the crash. This can reveal active protections (such as checks for isDebuggerConnected(), Build.TAGS, su, and others) and direct dynamic reverse engineering to the correct points in the code.

STEP 2: Analysis of classes and methods with Frida and Objection

  • Use tools like Frida and Objection to inspect and manipulate application behavior in real time. These tools allow you to locate and interact with methods responsible for protections such as Anti-Root, Anti-Debug and TLS Pinning. With Frida, it is possible to intercept and modify methods at runtime, while Objection can be used to execute pre-defined commands to disable or test protections. This makes it easier to identify where blocks occur and how the app reacts to the presence of analysis tools.

STEP 3: Static Reverse Engineering

  • Perform static reverse engineering by searching the code for signs of protections such as Anti-Root, Anti-Debug and TLS Pinning. Use tools like Jadx to decompile the APK and convert the .dex files into readable Java classes, making manual code analysis easier. Look for suspicious strings, method names, and libraries, such as su command calls, system file checks (/system/xbin/su, /sbin/su, etc.), or use of CertificatePinner for TLS Pinning. If necessary, supplement with disassemblers such as Ghidra or IDA Pro to examine Dalvik or native bytecode.

Some indications of the existence of protections:

  • Anti-Root: The app terminates when trying to launch it on a rooted device

  • Anti-Emulator: The app terminates when trying to launch it in an emulated environment

  • Anti-Hook: The app terminates when attempting to inject or run Frida scripts

  • TLS Pinning: You are unable to intercept proxy requests through tools like Burp Suite.

Anti-Root Bypass

Although it can be easily circumvented when applied in isolation, its effectiveness increases significantly when checks are distributed across different parts of the code, making the protection more robust and more difficult to circumvent. According to the OWASP MASTG topic Root Detection and Common Root Detection Methods, the main approaches for identifying rooted devices include:

  • File existence checks: Search for typical root binaries and files (su, Superuser.apk, etc.).
  • Executing commands (such as su and others): Attempt to execute commands that indicate root.
  • Checking running processes: Search for processes related to root (su, magiskd, etc.).
  • Checking installed app packages: Identification of installed root management apps (Magisk, SuperSU, etc.).
  • Checking for writable partitions and system directories: Checking whether partitions like /system are mounted read-write.
  • Checking custom Android builds: Detection of custom ROMs or modified builds that facilitate rooting.

-> After discovering the class, method and expected return of the protection you can create a script in frida (Creating Scripts in Frida) or use known scripts for this (https://codeshare.frida.re/)
-> Note: stack trace collection, possible errors, debugging with logcat are also appreciated to discover the class, method and expected return of the Anti-Root

-> Root Detection Example

public boolean checkRoot() {
        String[] path = {"/sbin/", "/system/bin/", "/system/xbin/", "/data/local/xbin/", "/data/local/bin/", "/system/sd/xbin/", "/system/bin/failsafe/", "/data/local/"};
        for (int i2 = 0; i2 < 8; i2++) {
            if (new File(<somefunction>(path[i2], "su")).exists()) {
                return true;
            }
        }
        return false;
    }

-> Example frida script

'use strict'

if(Java.available){
    Java.perform(function(){
        try{
            var target = Java.use("<package_name>.<class_name>");
            target.isDeviceRooted.implementation = function() {
            return false;
            };
        }catch(error){
            console.log("[-] An exception occured");
            console.log(String(error.stack));
        }
    });
}else{
    console.log("[-] Java unavailable");
}

-> execute

frida -U -f <package_name> -l bypass_root_detection.js

Since Android is based on the Linux architecture, we can directly connect to libc.so when the access function is called when checking a root file:

Interceptor.attach(Module.findExportByName("libc.so","access"), {
    onEnter: function(args) {
        this.path = args[0].readUtf8String()
        this.mode = args[1]
    },
    onLeave: function (retval) {
        var paths = [
            "/system/app/Superuser.apk",
            "/sbin/su",
            "/system/bin/su",
            "/system/xbin/su",
            "/data/local/xbin/su",
            "/data/local/bin/su",
            "/system/sd/xbin/su",
            "/system/bin/failsafe/su",
            "/data/local/su",
        ]
        
        for(var i = 0; i < paths.length; i++) {
            if(this.path.includes(paths[i])) {
                console.log(`access(${this.path}, ${this.mode})`)
                retval.replace(-1)
            }
        }
    }
})

Reverse engineering example for Anti-Root bypass

-> decompile the apk to smali

apktool d app.apk -o app

-> Look for references related to root protection and edit

grep -r -i '"su"' ./app
vim <path>.<file>.smali

-> reference to root validation identified "const-string v5, "su""

-> change to

const-string v5, "anything"

-> Recompile the app

apktool b app

-> Sign the app
Creating a Keystore

keytool -genkey -v -keystore mysigning.keystore -alias <app_alias> -keyalg RSA -keysize 2048 --validity 10000

Using the created keystore and sign the apk

jarsigner --verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore mysigning.keystore <app.apk> <app_alias>

Anti-Root Bypass with Objection

-> bypassing Anti-Root

objection --gadget <package_name> explore -s "android root disable"

-> Another example

objection --gadget <package_name> explore -s "android hooking set return_value <package_name>.<class_name>.<method_name> false"

Anti-Root Bypass with Frida Scripts

frida -U -f <package_name> -l <script>.js

https://codeshare.frida.re/@KaiserBloo/ssl-and-root-bypass/
https://codeshare.frida.re/@KishorBal/multiple-root-detection-bypass/

Broken JailMonkey Detection

If you have found JailMonkey in your tests, you can use this Frida script: jailmonkey.js to bypass Android

/*
by F0x - Mateus Tesser
*/
console.log("----------------------");
console.log('> JailMonkey Bypass!!!');
console.log("----------------------");

Java.perform(function() {
	var HookDetect = Java.use("com.gantix.JailMonkey.HookDetection.HookDetectionCheck");
	HookDetect.hookDetected.implementation = function() {
		console.log("[+] Hook Detect bypassed!")
		return true;
	}
	HookDetect.advancedHookDetection.implementation = function() {
		console.log("[+] Advanced Hook Detect bypassed!");
		return true;
	}
	HookDetect.checkFrida.implementation = function() {
		console.log("[+] Anti-Frida Bypassed!");
		return false;
	}

	const adb_check = Java.use("com.gantix.JailMonkey.AdbEnabled.AdbEnabled");
	adb_check.AdbEnabled.implementation = function() {
		console.log("[+] AdbEnabled bypassed!!!");
		return false;
	}

	const jail_proc = Java.use("com.gantix.JailMonkey.JailMonkeyModule");
	const hashmap_proc = Java.use("java.util.HashMap");
	const false_obj = Java.use("java.lang.Boolean").FALSE.value;

	jail_proc.getConstants.implementation = function() {
		var h = hashmap_proc.$new();
		h.put("isJailBroken",false_obj);
		h.put("hookDetected", false_obj);
		h.put("canMockLocation",false_obj);
		h.put("isOnExternalStorage",false_obj);
		h.put("AdbEnabled",false_obj);
		return h;
		console.log("[+] JailMonkey Protection bypassed!");
	}

	jail_proc.isDevelopmentSettingsMode.implementation = function() {
		return false;
	}
	jail_proc.isDebbugedMode.implementation = function() {
		return false;
	}
});

Android freeRasp Bypass

https://codeshare.frida.re/@luca-regne/android-freerasp-bypass/

Anti-Emulator Bypass

​Among the ways that anti-emulator protections use to detect emulated access on Android are:

-> Runtime execution​
It consists of creating a new instance at runtime and executing commands such as getprop to check information from the android.os.SystemProperties class, analyzing whether the application is running on an emulated device.​

​-> Java reflection​
Using accessor methods within the android.os.SystemProperties class to return values ​​that indicate that the application is running in an emulated environment.

-> After discovering the class, method and expected return of the protection you can create a script in frida (Creating Scripts in Frida) or use known scripts for this (https://codeshare.frida.re/)
-> Note: stack trace collection, possible errors, debugging with logcat are also appreciated to discover the class, method and expected return of the Anti-Root

Anti-Emulator Bypass with Frida Scripts

frida -U -f <package_name> -l <script>.js

https://codeshare.frida.re/@khantsithu1998/bypass-react-native-emulator-detection/

SSL Pinning Bypass

-> Frida
-> Objection
-> Reverse engineering with apktool and Replacing Hard-Coded Certificate, Sha 256 Hash, etc

SSL Pinning Bypass with Frida Scripts

frida -U -f <package_name> -l <script>.js --no-pause

image https://codeshare.frida.re/@akabe1/frida-multiple-unpinning/%20%E2%80%8B https://github.com/httptoolkit/frida-interception-and-unpinning https://codeshare.frida.re/@pcipolloni/universal-android-ssl-pinning-bypass-with-frida/

SSL Pinning Bypass with Objection

objection --gadget <package_name> explore -s 'android sslpinning disable'

Bypassing NetworkSecurityConfig Android >=7 & targetSdkVersion >= 24 only system certificates are trusted

-> decompiling

apktool d app.apk

-> AndroidManifest.xml Analysis

cat AndroidManifest.xml  

-> identified that exists "android:networkSecurityConfig="xml/network_security_config"

-> Edit Network Security Configuration File:

vim /res/xml/network_security_config.xml

-> Add in network_security_config.xml (instruct the application to accept user-added certificates during SSL/TLS verification. This is a commonly used technique to bypass SSL pinning because it allows custom certificates to be trusted independently of the original application-defined certificates.)

<certificates src="user" />

-> recompiling

apktool b app

-> Sign the app
Creating a Keystore

keytool -genkey -v -keystore mysigning.keystore -alias <app_alias> -keyalg RSA -keysize 2048 --validity 10000

Using the created keystore and sign the apk

jarsigner --verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore mysigning.keystore <app.apk> <app_alias>

End-to-End Encryption Bypass

image

It is responsible for preventing the visualization of parameters in the request in clear text, Data sent is encrypted before leaving the device and can only be decrypted by the server.

Understand how the application is encrypting the data and decrypting it to obtain their encryption keys and tamper with the decrypted data.
If end-to-end encryption is used, even if the certificate is installed, and bypassing the SSL pinning, and managing to intercept the traffic using a proxy (burp), we will not be able to see clear text data during the interception of HTTP /HTTPS traffic , end-to-end encryption prevents request tampering.

-> Static analysis
-> Perform at runtime tracing
Case:
-> AES 256 being used for encrypt/decrypt data
-> Client and server with the same encryption key

objection --gadget explore -s "android hooking watch class <package_name>.<AESclass> --dump-args --dump-return

endtoend.js

'use strict'
if(Java.available){
    Java.perform(function(){
        try{
            var aes_class = Java.use("<package_name>.<class_name>");
            aes_class.<method_name>.overload("[B").implementation = function (gk) {
                var key_value = this.bytesToHex(gk);
                console.log(returnvalue);
                return key_value;
            };
        }catch(error){
            console.log("[-] Exception");
            console.log(String(error.stack));
        }
    });
}else{
    console.log("[-] Java unavailable");
}

frida -U -f <package_name> -l bypass_root_decetion.js -l endtoend.js

There are more complex cases in which asymmetric cryptography will also be used to transfer the key and data.

Anti-Debugging Bypass

Debuggers can be useful for our analysis of the application, in order to increase our attack surface during a Pentest.
An anti-debug mechanism will block our debugging.

or you can run the command below as root (It's bypass Anti-Debugging and USB Debugging detection):

settings put global adb_enabled 2

Script Anti-Debugging Bypass

-> script universal-android-debugging-bypass
https://codeshare.frida.re/@meerkati/universal-android-debugging-bypass/
https://codeshare.frida.re/@Raphkitue/android-debug-mode-bypass/ https://codeshare.frida.re/@voker2311/android-common-security-bypasses/

Anti-Hook Bypass

Anti-Frida is a specific type of Anti-Hook that blocks analysis through instrumentation detection via Frida. Below are some examples of detection that can be carried out by these mechanisms:

  • Process memory analysis, including scanning mappings (/proc/self/maps or /proc//maps) to detect strings typical of tools such as Frida (e.g.: LIBFRIDA), in addition to detecting modifications to instructions in memory by comparing the .text section loaded in memory with the original version of the .so file stored on disk, especially in native libraries such as libc;
  • Checking open TCP ports, especially the default port 27042, used by frida-server;
  • Sending D-Bus authentication messages to open ports, as frida-server responds to this protocol;
  • Presence of artifacts related to Frida, such as the frida-server binary, libraries such as frida-gadget or frida-agent, or dynamically created structures (pipes, sockets, threads), identified via /proc or by the name of the loaded libraries;
  • APK signature verification, as including Frida requires repackaging and re-signing. The app can validate its own signature at runtime (e.g. with GET_SIGNING_CERTIFICATES from API 28).

Info+: Detection of Reverse Engineering Tools - Android Anti-Reversing Defenses - MASTG: OWASP

Script Anti-Frida Bypass

https://codeshare.frida.re/@fdciabdul/frida-multiple-bypass/ https://codeshare.frida.re/@enovella/anti-frida-bypass/

Port detection bypass

-> bypass for change port

./frida-server -l 0.0.0.0:19991

-> communicating with Frida on a different port

frida -H 192.168.0.22:19991 -f <package_name> -l <script>.js

Flag Secure Bypass

-> check if it is possible to print critical information in the app

adb shell screencap –p /sdcard/download/print.png
adb exec-out screencap –p > print.png

-> check if you can view this critical data with the application in the background

-> perform bypass with script in Frida to see the application even in the background and take screenshots

frida -U -f <package-name> -l screenshot.js

https://gist.githubusercontent.com/su-vikas/36410f67c9e0127961ae344010c4c0ef/raw/a05b9aee83d1edcd78d8aa4d69f32c660404e0af/screenshot.js

-> perform bypass with Objection to see the application even in the background and take screenshots

-> See the application even in the background and take screenshots

objection -g <package_name> explore -s "android ui FLAG_SECURE false"

Exploring activity/application termination control methods

Many applications react to suspicious activity, such as root detection, use of emulators or debugging mode, by closing themselves automatically using specific shutdown methods.

However, it is possible to take advantage of these methods used when running hooking to prevent the application from not closing and remaining running.

Java.perform(function() {
    let System = Java.use("java.lang.System")
    let exit = System.exit.overload('int');
    exit.implementation = function() {
        console.log("Bypass...");
    }
})