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

Tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Μάθετε & εξασκηθείτε στο Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το 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.

Επιφάνεια Ανίχνευσης (τι ελέγχουν οι εφαρμογές)

  • 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

Παράκαμψη Anti‑Frida Detection / Stealth Frida Servers

phantom-frida rebuilds Frida from source and applies ~90 patches so common Frida fingerprints disappear while the stock Frida protocol remains compatible (frida-tools can still connect). Target: apps that grep /proc (cmdline, maps, task comm, fd readlink), D-Bus service names, default ports, or exported symbols.

Phases:

  • Source patches: global rename of frida identifiers (server/agent/helper) and rebuilt helper DEX with a renamed Java package.
  • Targeted build/runtime patches: meson tweaks, memfd label changed to jit-cache, SELinux labels (e.g., frida_file) renamed, libc hooks on exit/signal disabled to avoid hook-detectors.
  • Post-build rename: exported symbol frida_agent_main renamed after the first compile (Vala emits it), requiring a second incremental build.
  • Binary hex patches: thread names (gmain, gdbus, pool-spawner) replaced; optional sweep removes leftover frida/Frida strings.

Καλυπτόμενα διανύσματα ανίχνευσης:

  • Base (1–8): process name frida-server, mapped libfrida-agent.so, thread names, memfd label, exported frida_agent_main, SELinux labels, libc hook side-effects, and D-Bus service re.frida.server are renamed/neutralized.
  • Extended (9–16): change listening port (--port), rename D-Bus interfaces/internal C symbols/GType names, temp paths like .frida/frida-, sweep binary strings, rename build-time defines and asset paths (libdir/frida). D-Bus interface names that are part of the wire protocol stay unchanged in base mode to avoid breaking stock clients.

Build/usage (Android arm64 example):

python3 build.py --version 17.7.2 --name myserver --port 27142 --extended --verify
adb push output/myserver-server-17.7.2-android-arm64 /data/local/tmp/myserver-server
adb shell chmod 755 /data/local/tmp/myserver-server
adb shell /data/local/tmp/myserver-server -D &
adb forward tcp:27142 tcp:27142
frida -H 127.0.0.1:27142 -f com.example.app

Flags: --skip-build (patch only), --skip-clone, --arch, --ndk-path, --temp-fixes; WSL helper: wsl -d Ubuntu bash build-wsl.sh.

Step 1 — Quick win: hide root with Magisk DenyList

  • Ενεργοποιήστε το Zygisk στο Magisk
  • Ενεργοποιήστε το DenyList, προσθέστε το πακέτο-στόχο
  • Επανεκκινήστε και δοκιμάστε ξανά

Πολλές εφαρμογές ψάχνουν μόνο για εμφανείς ενδείξεις (su/Magisk paths/getprop). Το DenyList συχνά εξουδετερώνει απλούς ελέγχους.

References:

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

Play Integrity / Zygisk detections (post‑SafetyNet)

Οι νεότερες τραπεζικές/εφαρμογές ταυτοποίησης συνδέουν τους ελέγχους σε χρόνο εκτέλεσης με το Google Play Integrity (αντικαταστάτης του SafetyNet) και μπορούν επίσης να κρασάρουν αν το ίδιο το Zygisk είναι παρόν. Γρήγορες συμβουλές για πρώτες ενέργειες:

  • Απενεργοποιήστε προσωρινά το Zygisk (toggle off + reboot) και δοκιμάστε ξανά· μερικές εφαρμογές κρασάρουν μόλις φορτωθεί η Zygote injection.
  • Αν η attestation μπλοκάρει το login, κάντε patch τα Google Play Services με PlayIntegrityFix/Fork + TrickyStore ή χρησιμοποιήστε ReZygisk/Zygisk‑Next μόνο κατά τη δοκιμή. Κρατήστε τον στόχο στο DenyList και αποφύγετε LSPosed modules που leak props.
  • Για μεμονωμένες εκτελέσεις, χρησιμοποιήστε KernelSU/APatch (no Zygote injection) για να παραμένετε κάτω από τις heuristics του Zygisk, και μετά επισυνάψτε Frida.

Step 2 — 30‑second Frida Codeshare tests

Δοκιμάστε κοινά drop‑in scripts πριν εμβαθύνετε:

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

Example:

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

Αυτά συνήθως stub Java root/debug checks, process/service scans, και native ptrace(). Χρήσιμα σε ελαφρώς προστατευμένες εφαρμογές· hardened targets μπορεί να χρειαστούν tailored hooks.

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

Αυτοματοποιήστε με Medusa (Frida framework)

Medusa παρέχει 90+ έτοιμα modules για SSL unpinning, root/emulator detection bypass, HTTP comms logging, crypto key interception, και άλλα.

git clone https://github.com/Ch0pin/medusa
cd medusa
pip install -r requirements.txt
python medusa.py

# Example interactive workflow
show categories
use http_communications/multiple_unpinner
use root_detection/universal_root_detection_bypass
run com.target.app

Συμβουλή: Η Medusa είναι ιδανική για quick wins πριν γράψετε custom hooks. Μπορείτε επίσης να cherry-pick modules και να τα συνδυάσετε με τα δικά σας scripts.

Βήμα 3 — Παράκαμψη των init-time detectors με late attaching

Πολλές ανιχνεύσεις τρέχουν μόνο κατά τη διάρκεια του process spawn/onCreate(). Spawn‑time injection (-f) ή gadgets συλλαμβάνονται; το attaching μετά το φόρτωμα του UI μπορεί να περάσει απαρατήρητο.

# 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

Αν αυτό λειτουργήσει, διατήρησε τη συνεδρία σταθερή και προχώρα σε ελέγχους map και stub.

Βήμα 4 — Χαρτογράφησε τη λογική ανίχνευσης μέσω Jadx και αναζήτησης συμβολοσειρών

Στατικές λέξεις-κλειδιά για triage στο Jadx:

  • “frida”, “gum”, “root”, “magisk”, “ptrace”, “su”, “getprop”, “debugger”

Τυπικά patterns σε Java:

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

Συνηθισμένα APIs για 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)

Βήμα 5 — Runtime stubbing με Frida (Java)

Παρακάμψτε custom guards ώστε να επιστρέφουν ασφαλείς τιμές χωρίς repacking:

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(); };
});

Διαχειρίζεσαι πρώιμα crashes; Dump classes λίγο πριν τερματίσει για να εντοπίσεις πιθανές detection namespaces:

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

Γρήγορο παράδειγμα stub ανίχνευσης root (προσαρμόστε στα ονόματα package/class του στόχου):

Java.perform(() => {
try {
const RootChecker = Java.use('com.target.security.RootCheck');
RootChecker.isDeviceRooted.implementation = function () { return false; };
} catch (e) {}
});

Καταγράψτε και αδρανοποιήστε ύποπτες μεθόδους για να επιβεβαιώσετε τη ροή εκτέλεσης:

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

Bypass emulator/VM detection (Java stubs)

Συνήθεις ευρετικές: Build.FINGERPRINT/MODEL/MANUFACTURER/HARDWARE που περιέχουν generic/goldfish/ranchu/sdk; ενδείξεις QEMU όπως /dev/qemu_pipe, /dev/socket/qemud; προεπιλεγμένη MAC 02:00:00:00:00:00; 10.0.2.x NAT; απουσία telephony/sensors.

Γρήγορο spoof των Build fields:

Java.perform(function(){
var Build = Java.use('android.os.Build');
Build.MODEL.value = 'Pixel 7 Pro';
Build.MANUFACTURER.value = 'Google';
Build.BRAND.value = 'google';
Build.FINGERPRINT.value = 'google/panther/panther:14/UP1A.231105.003/1234567:user/release-keys';
});

Συμπληρώστε με stubs για ελέγχους ύπαρξης αρχείων και για αναγνωριστικά (TelephonyManager.getDeviceId/SubscriberId, WifiInfo.getMacAddress, SensorManager.getSensorList) ώστε να επιστρέφουν ρεαλιστικές τιμές.

SSL pinning bypass quick hook (Java)

Εξουδετερώστε προσαρμοσμένους TrustManagers και επιβάλετε permissive SSL contexts:

Java.perform(function(){
var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
var SSLContext = Java.use('javax.net.ssl.SSLContext');

// No-op validations
X509TrustManager.checkClientTrusted.implementation = function(){ };
X509TrustManager.checkServerTrusted.implementation = function(){ };

// Force permissive TrustManagers
var TrustManagers = [ X509TrustManager.$new() ];
var SSLContextInit = SSLContext.init.overload('[Ljavax.net.ssl.KeyManager;','[Ljavax.net.ssl.TrustManager;','java.security.SecureRandom');
SSLContextInit.implementation = function(km, tm, sr){
return SSLContextInit.call(this, km, TrustManagers, sr);
};
});

Σημειώσεις

  • Επεκτείνετε για OkHttp: hook okhttp3.CertificatePinner και HostnameVerifier όπως χρειάζεται, ή χρησιμοποιήστε ένα universal unpinning script από CodeShare.
  • Παράδειγμα εκτέλεσης: frida -U -f com.target.app -l ssl-bypass.js --no-pause

OkHttp4 / gRPC / Cronet pinning (2024+)

Τα σύγχρονα stacks κάνουν pin μέσα σε νεότερα APIs (OkHttp4+, gRPC over Cronet/BoringSSL). Προσθέστε αυτά τα hooks όταν το βασικό SSLContext hook παγώνει:

Java.perform(() => {
try {
const Pinner = Java.use('okhttp3.CertificatePinner');
Pinner.check.overload('java.lang.String', 'java.util.List').implementation = function(){};
Pinner.check$okhttp.implementation = function(){};
} catch (e) {}

try {
const CronetB = Java.use('org.chromium.net.CronetEngine$Builder');
CronetB.enablePublicKeyPinningBypassForLocalTrustAnchors.overload('boolean').implementation = function(){ return this; };
CronetB.setPublicKeyPins.overload('java.lang.String', 'java.util.Set', 'boolean').implementation = function(){ return this; };
} catch (e) {}
});

Αν το TLS εξακολουθεί να αποτυγχάνει, κατεβείτε σε native και patch τα σημεία εισόδου επαλήθευσης του BoringSSL που χρησιμοποιούνται από Cronet/gRPC:

const customVerify = Module.findExportByName(null, 'SSL_CTX_set_custom_verify');
if (customVerify) {
Interceptor.attach(customVerify, {
onEnter(args){
// arg0 = SSL_CTX*, arg1 = mode, arg2 = callback
args[1] = ptr(0); // SSL_VERIFY_NONE
args[2] = NULL;  // disable callback
}
});
}

Βήμα 6 — Ακολουθήστε το μονοπάτι JNI/native όταν τα Java hooks αποτύχουν

Ιχνηλατήστε τα σημεία εισόδου JNI για να εντοπίσετε native loaders και detection init:

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

Γρήγορη αρχική αξιολόγηση των ενσωματωμένων αρχείων .so:

# 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

Παράδειγμα: αδρανοποιήστε το ptrace για να παρακάμψετε ένα απλό anti‑debug στο libc:

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

Δείτε επίσης: Reversing Native Libraries

Βήμα 7 — Objection patching (embed gadget / strip basics)

Όταν προτιμάτε repacking αντί για runtime hooks, δοκιμάστε:

objection patchapk --source app.apk

Σημειώσεις:

  • Απαιτεί apktool· βεβαιώσου ότι έχεις μια τρέχουσα έκδοση από τον επίσημο οδηγό για να αποφύγεις προβλήματα κατά τη μεταγλώττιση: https://apktool.org/docs/install
  • Gadget injection επιτρέπει instrumentation χωρίς root, αλλά μπορεί ακόμα να εντοπιστεί από πιο ισχυρούς init‑time ελέγχους.

Προαιρετικά, πρόσθεσε LSPosed modules και Shamiko για πιο ισχυρό root hiding σε Zygisk περιβάλλοντα, και διαμόρφωσε τη DenyList ώστε να καλύπτει child processes.

Για ένα ολοκληρωμένο workflow που περιλαμβάνει script-mode Gadget configuration και το bundling του Frida 17+ agent στο APK, δες:

Frida Tutorial — Self-contained agent + Gadget embedding

Αναφορές:

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

Βήμα 8 — Εναλλακτική λύση: Patch TLS pinning για ορατότητα δικτύου

Αν η instrumentation μπλοκαριστεί, μπορείς ακόμα να ελέγξεις την κίνηση αφαιρώντας το pinning στατικά:

apk-mitm app.apk
# Then install the patched APK and proxy via Burp/mitmproxy
  • Εργαλείο: https://github.com/shroudedcode/apk-mitm
  • Για κόλπα εμπιστοσύνης CA στη διαμόρφωση δικτύου (και για την εμπιστοσύνη CA από χρήστη σε Android 7+), δείτε:

Make APK Accept CA Certificate

Install Burp Certificate

Χρήσιμη σύνοψη εντολών

# 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

Καθολική επιβολή proxy + TLS unpinning (HTTP Toolkit Frida hooks)

Οι σύγχρονες εφαρμογές συχνά αγνοούν τους system proxies και επιβάλλουν πολλαπλά επίπεδα pinning (Java + native), κάνοντας τη σύλληψη κίνησης επίπονη ακόμη και με εγκατεστημένα user/system CAs. Μια πρακτική προσέγγιση είναι να συνδυάσετε universal TLS unpinning με proxy forcing μέσω έτοιμων Frida hooks, και να δρομολογήσετε τα πάντα μέσω mitmproxy/Burp.

Workflow

  • Τρέξτε mitmproxy στον host σας (ή Burp). Βεβαιωθείτε ότι η συσκευή μπορεί να προσπελάσει το host IP/port.
  • Φορτώστε τα συγκεντρωμένα Frida hooks του HTTP Toolkit για να κάνετε τόσο unpin TLS όσο και να επιβάλλετε τη χρήση proxy σε κοινές στοίβες (OkHttp/OkHttp3, HttpsURLConnection, Conscrypt, WebView, κ.λπ.). Αυτό παρακάμπτει τους ελέγχους CertificatePinner/TrustManager και αντικαθιστά τους proxy selectors, έτσι ώστε η κίνηση να αποστέλλεται πάντα μέσω του proxy σας ακόμη κι αν η εφαρμογή απενεργοποιεί ρητά τους proxies.
  • Ξεκινήστε την στοχευόμενη εφαρμογή με Frida και το hook script, και καταγράψτε τα αιτήματα στο mitmproxy.

Example

# Device connected via ADB or over network (-U)
# See the repo for the exact script names & options
frida -U -f com.vendor.app \
-l ./android-unpinning-with-proxy.js \
--no-pause

# mitmproxy listening locally
mitmproxy -p 8080

Σημειώσεις

  • Συνδυάστε με ένα συστημικό proxy μέσω adb shell settings put global http_proxy <host>:<port> όταν είναι δυνατόν. Τα Frida hooks θα επιβάλουν τη χρήση του proxy ακόμα και όταν οι εφαρμογές παρακάμπτουν τις ρυθμίσεις συστήματος.
  • Αυτή η τεχνική είναι ιδανική όταν χρειάζεται να κάνετε MITM ροές onboarding από mobile προς IoT όπου το pinning/αποφυγή proxy είναι συνηθισμένο.
  • Hooks: https://github.com/httptoolkit/frida-interception-and-unpinning

Αναφορές

Tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Μάθετε & εξασκηθείτε στο Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks