Android Anti-Instrumentation & SSL Pinning Bypass (Frida/Objection)

Reading time: 6 minutes

tip

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks

This page provides a practical workflow to regain dynamic analysis against Android apps that detect/root‑block instrumentation or enforce TLS pinning. It focuses on fast triage, common detections, and copy‑pasteable hooks/tactics to bypass them without repacking when possible.

Detection Surface (what apps check)

  • Root checks: su binary, Magisk paths, getprop values, common root packages
  • Frida/debugger checks (Java): Debug.isDebuggerConnected(), ActivityManager.getRunningAppProcesses(), getRunningServices(), scanning /proc, classpath, loaded libs
  • Native anti‑debug: ptrace(), syscalls, anti‑attach, breakpoints, inline hooks
  • Early init checks: Application.onCreate() or process start hooks that crash if instrumentation is present
  • TLS pinning: custom TrustManager/HostnameVerifier, OkHttp CertificatePinner, Conscrypt pinning, native pins

Step 1 — Quick win: hide root with Magisk DenyList

  • Enable Zygisk in Magisk
  • Enable DenyList, add the target package
  • Reboot and retest

Many apps only look for obvious indicators (su/Magisk paths/getprop). DenyList often neutralizes naive checks.

References:

  • Magisk (Zygisk & DenyList): https://github.com/topjohnwu/Magisk

Step 2 — 30‑second Frida Codeshare tests

Try common drop‑in scripts before deep diving:

  • anti-root-bypass.js
  • anti-frida-detection.js
  • hide_frida_gum.js

Example:

bash
frida -U -f com.example.app -l anti-frida-detection.js

These typically stub Java root/debug checks, process/service scans, and native ptrace(). Useful on lightly protected apps; hardened targets may need tailored hooks.

  • Codeshare: https://codeshare.frida.re/

Step 3 — Bypass init-time detectors by attaching late

Many detections only run during process spawn/onCreate(). Spawn‑time injection (-f) or gadgets get caught; attaching after UI loads can slip past.

bash
# Launch the app normally (launcher/adb), wait for UI, then attach
frida -U -n com.example.app
# Or with Objection to attach to running process
aobjection --gadget com.example.app explore  # if using gadget

If this works, keep the session stable and proceed to map and stub checks.

Step 4 — Map detection logic via Jadx and string hunting

Static triage keywords in Jadx:

  • "frida", "gum", "root", "magisk", "ptrace", "su", "getprop", "debugger"

Typical Java patterns:

java
public boolean isFridaDetected() {
    return getRunningServices().contains("frida");
}

Common APIs to review/hook:

  • android.os.Debug.isDebuggerConnected
  • android.app.ActivityManager.getRunningAppProcesses / getRunningServices
  • java.lang.System.loadLibrary / System.load (native bridge)
  • java.lang.Runtime.exec / ProcessBuilder (probing commands)
  • android.os.SystemProperties.get (root/emulator heuristics)

Step 5 — Runtime stubbing with Frida (Java)

Override custom guards to return safe values without repacking:

js
Java.perform(() => {
  const Checks = Java.use('com.example.security.Checks');
  Checks.isFridaDetected.implementation = function () { return false; };

  // Neutralize debugger checks
  const Debug = Java.use('android.os.Debug');
  Debug.isDebuggerConnected.implementation = function () { return false; };

  // Example: kill ActivityManager scans
  const AM = Java.use('android.app.ActivityManager');
  AM.getRunningAppProcesses.implementation = function () { return java.util.Collections.emptyList(); };
});

Triaging early crashes? Dump classes just before it dies to spot likely detection namespaces:

js
Java.perform(() => {
  Java.enumerateLoadedClasses({
    onMatch: n => console.log(n),
    onComplete: () => console.log('Done')
  });
});

Log and neuter suspicious methods to confirm execution flow:

js
Java.perform(() => {
  const Det = Java.use('com.example.security.DetectionManager');
  Det.checkFrida.implementation = function () {
    console.log('checkFrida() called');
    return false;
  };
});

Step 6 — Follow the JNI/native trail when Java hooks fail

Trace JNI entry points to locate native loaders and detection init:

bash
frida-trace -n com.example.app -i "JNI_OnLoad"

Quick native triage of bundled .so files:

bash
# List exported symbols & JNI
nm -D libfoo.so | head
objdump -T libfoo.so | grep Java_
strings -n 6 libfoo.so | egrep -i 'frida|ptrace|gum|magisk|su|root'

Interactive/native reversing:

  • Ghidra: https://ghidra-sre.org/
  • r2frida: https://github.com/nowsecure/r2frida

Example: neuter ptrace to defeat simple anti‑debug in libc:

js
const ptrace = Module.findExportByName(null, 'ptrace');
if (ptrace) {
  Interceptor.replace(ptrace, new NativeCallback(function () {
    return -1; // pretend failure
  }, 'int', ['int', 'int', 'pointer', 'pointer']));
}

See also: Reversing Native Libraries

Step 7 — Objection patching (embed gadget / strip basics)

When you prefer repacking to runtime hooks, try:

bash
objection patchapk --source app.apk

Notes:

  • Requires apktool; ensure a current version from the official guide to avoid build issues: https://apktool.org/docs/install
  • Gadget injection enables instrumentation without root but can still be caught by stronger init‑time checks.

References:

  • Objection: https://github.com/sensepost/objection

Step 8 — Fallback: Patch TLS pinning for network visibility

If instrumentation is blocked, you can still inspect traffic by removing pinning statically:

bash
apk-mitm app.apk
# Then install the patched APK and proxy via Burp/mitmproxy
  • Tool: https://github.com/shroudedcode/apk-mitm

  • For network config CA‑trust tricks (and Android 7+ user CA trust), see:

    {{#ref}} make-apk-accept-ca-certificate.md {{#endref}}

    {{#ref}} install-burp-certificate.md {{#endref}}

Handy command cheat‑sheet

bash
# List processes and attach
frida-ps -Uai
frida -U -n com.example.app

# Spawn with a script (may trigger detectors)
frida -U -f com.example.app -l anti-frida-detection.js

# Trace native init
frida-trace -n com.example.app -i "JNI_OnLoad"

# Objection runtime
objection --gadget com.example.app explore

# Static TLS pinning removal
apk-mitm app.apk

Tips & caveats

  • Prefer attaching late over spawning when apps crash at launch
  • Some detections re‑run in critical flows (e.g., payment, auth) — keep hooks active during navigation
  • Mix static and dynamic: string hunt in Jadx to shortlist classes; then hook methods to verify at runtime
  • Hardened apps may use packers and native TLS pinning — expect to reverse native code

References

tip

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks