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

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

Bu sayfa, instrumentation tespit/engelleme veya TLS pinning uygulayan Android uygulamalarına karşı dinamik analiz yeteneğini geri kazanmak için pratik bir iş akışı sunar. Hızlı triage, yaygın tespitler ve mümkün olduğunda repacking yapmadan atlatmak için kopyala‑yapıştır yapılabilir hook’lar/taktiklere odaklanır.

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() veya process başlatma hook’ları, eğer instrumentation varsa crash yaptıran kontroller
  • TLS pinning: custom TrustManager/HostnameVerifier, OkHttp CertificatePinner, Conscrypt pinning, native pins

Bypassing Anti-Frida Detection / Stealth Frida Servers

phantom-frida Frida’yı kaynak koddan yeniden inşa eder ve yaygın Frida parmak izlerinin kaybolması için ~90 patch uygular, aynı zamanda stock Frida protokolü uyumlu kalır (frida-tools hâlâ bağlanabilir). Hedef: /proc (cmdline, maps, task comm, fd readlink) grep’leyen, D-Bus servis isimlerini, varsayılan portları veya exported symbol’leri kontrol eden uygulamalar.

Aşamalar:

  • Source patches: frida identifier’larının global olarak yeniden adlandırılması (server/agent/helper) ve yeniden adlandırılmış Java paketi ile helper DEX’in yeniden inşası.
  • Targeted build/runtime patches: meson ayarları, memfd label’ının jit-cache olarak değiştirilmesi, SELinux label’larının (ör. frida_file) yeniden adlandırılması, libc üzerinde exit/signal hook’larının tespit edicileri tetiklememesi için devre dışı bırakılması.
  • Post-build rename: exported symbol frida_agent_main ilk derlemeden sonra yeniden adlandırılır (Vala bunu emit eder), bu da ikinci bir incremental build gerektirir.
  • Binary hex patches: thread isimleri (gmain, gdbus, pool-spawner) değiştirilir; isteğe bağlı sweep kalan frida/Frida string’lerini kaldırır.

Kapsanan tespit vektörleri:

  • Base (1–8): process name frida-server, mapped libfrida-agent.so, thread names, memfd label, exported frida_agent_main, SELinux labels, libc hook yan-etkileri, ve D-Bus service re.frida.server yeniden adlandırılarak/neutralize edilerek kapatılır.
  • Extended (9–16): dinleme portunu değiştirme (--port), D-Bus interface’lerini/dahili C symbol’leri/GType isimlerini yeniden adlandırma, .frida/frida- gibi temp path’leri değiştirme, ikili içindeki string’leri süpürme, build-time define’ları ve asset path’lerini (libdir/frida) yeniden adlandırma. Wire protokolünün bir parçası olan D-Bus interface isimleri, stock client’ları kırmamak için base modda değişmeden bırakılır.

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

Bayraklar: --skip-build (patch only), --skip-clone, --arch, --ndk-path, --temp-fixes; WSL yardımcısı: wsl -d Ubuntu bash build-wsl.sh.

Adım 1 — Hızlı çözüm: root’u Magisk DenyList ile gizle

  • Magisk içinde Zygisk’i etkinleştir
  • DenyList’i etkinleştir, hedef paketi ekle
  • Yeniden başlat ve tekrar test et

Birçok uygulama yalnızca bariz göstergelere bakar (su/Magisk paths/getprop). DenyList genellikle yüzeysel kontrolleri nötralize eder.

Referanslar:

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

Play Integrity / Zygisk tespitleri (SafetyNet sonrası)

Yeni banka/kimlik uygulamaları çalışma zamanı kontrollerini Google Play Integrity (SafetyNet’in yerine) bağlar ve Zygisk mevcutsa çökebilir. Hızlı ilk değerlendirme ipuçları:

  • Geçici olarak Zygisk’i devre dışı bırak (toggle off + reboot) ve tekrar dene; bazı uygulamalar Zygote injection yüklendiği anda çöker.
  • Eğer attestation girişleri engelliyorsa, Google Play Services’ı PlayIntegrityFix/Fork + TrickyStore ile yamala veya yalnızca test ederken ReZygisk/Zygisk‑Next kullan. Hedefi DenyList’te tut ve props’ları leak eden LSPosed modüllerinden kaçın.
  • Tek seferlik çalıştırmalar için KernelSU/APatch kullan (no Zygote injection) böylece Zygisk heuristiklerinin altında kal, sonra Frida’yı bağla.

Adım 2 — 30 saniyelik Frida Codeshare testleri

Derinlemesine incelemeden önce yaygın drop‑in script’leri dene:

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

Örnek:

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

Bunlar tipik olarak Java root/debug checks, process/service scans ve native ptrace() işlevlerini stub’lar. Hafif korumalı uygulamalarda kullanışlıdır; sertleştirilmiş hedefler için özel hook’lar gerekebilir.

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

Medusa ile otomatikleştirme (Frida framework)

Medusa, SSL unpinning, root/emulator detection bypass, HTTP comms logging, crypto key interception ve daha fazlası için 90+ hazır modül sağlar.

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

İpucu: Medusa, custom hooks yazmadan önce hızlı kazanımlar için mükemmeldir. Ayrıca modules’ı cherry-pick edip kendi scripts’lerinizle birleştirebilirsiniz.

Adım 3 — Bypass init-time detectors by attaching late

Birçok tespit yalnızca process spawn/onCreate() sırasında çalışır. Spawn‑time injection (-f) veya gadgets yakalanır; UI yüklendikten sonra attaching yapmak tespitleri atlatabilir.

# 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

Adım 4 — Jadx ile tespit mantığını haritalama ve string araması

Eğer bu işe yararsa, oturumu sabit tutun ve haritalama ve stub kontrollerine devam edin.

Static triage keywords in Jadx:

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

Tipik Java desenleri:

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

Gözden geçirilecek/hook için yaygın API’ler:

  • 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)

Adım 5 — Frida ile çalışma zamanı stub’lama (Java)

Özel guard’ları, yeniden paketlemeye gerek kalmadan güvenli değerler döndürecek şekilde geçersiz kılın:

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

Erken çökmeleri triage mı ediyorsunuz? Çökmeden hemen önce Dump classes yaparak muhtemel detection namespaces’lerini tespit edin:

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

Hızlı root detection stub örneği (hedef package/class isimlerine göre uyarlayın):

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

Şüpheli yöntemleri loglayın ve nötralize ederek yürütme akışını doğrulayın:

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)

Yaygın heuristikler: Build.FINGERPRINT/MODEL/MANUFACTURER/HARDWARE alanlarının generic/goldfish/ranchu/sdk içermesi; QEMU artefaktları (ör. /dev/qemu_pipe, /dev/socket/qemud); varsayılan MAC 02:00:00:00:00:00; 10.0.2.x NAT; telephony/sensors eksikliği.

Build alanlarının hızlı sahtelemesi:

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

Dosya varlık kontrolleri ve kimlikler (TelephonyManager.getDeviceId/SubscriberId, WifiInfo.getMacAddress, SensorManager.getSensorList) için gerçekçi değerler döndürecek stub’larla tamamlayın.

SSL pinning bypass quick hook (Java)

Özel TrustManagers’ı etkisizleştir ve permissive SSL contexts kullanmaya zorla:

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

Notlar

  • OkHttp için genişletin: gerekli olduğunda okhttp3.CertificatePinner ve HostnameVerifier üzerine hook uygulayın veya CodeShare’den evrensel bir unpinning script’i kullanın.
  • Çalıştırma örneği: frida -U -f com.target.app -l ssl-bypass.js --no-pause

OkHttp4 / gRPC / Cronet pinning (2024+)

Modern yığınlar daha yeni API’lerin içinde pin yapar (OkHttp4+, gRPC over Cronet/BoringSSL). Temel SSLContext hook’u takıldığında bu hook’ları ekleyin:

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 hâlâ başarısız oluyorsa, native’e geçin ve Cronet/gRPC tarafından kullanılan BoringSSL doğrulama giriş noktalarını patch’leyin:

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

Adım 6 — Java hooks başarısız olduğunda JNI/native izini takip edin

Native loaders ve detection init’i bulmak için JNI giriş noktalarını izleyin:

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

Paketlenmiş .so dosyalarının hızlı yerel triyajı:

# 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

Örnek: ptrace’i devre dışı bırakarak libc’deki basit anti‑debug’i atlatma:

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

Ayrıca bakınız: Reversing Native Libraries

Adım 7 — Objection yaması (embed gadget / strip basics)

Eğer runtime hooks yerine repacking’i tercih ediyorsanız, şunu deneyin:

objection patchapk --source app.apk

Notlar:

  • apktool gerektirir; derleme sorunlarını önlemek için resmi kılavuzdan güncel bir sürüm kullanın: https://apktool.org/docs/install
  • Gadget injection root olmadan instrumentation sağlar, ancak daha güçlü init‑time kontrolleri tarafından yine de tespit edilebilir.

İsteğe bağlı olarak, Zygisk ortamlarında daha güçlü root gizleme için LSPosed modüllerini ve Shamiko’yu ekleyin ve alt süreçleri kapsayacak şekilde DenyList’i düzenleyin.

Tam iş akışı için, script-mode Gadget yapılandırması ve Frida 17+ agent’ınızı APK’ye paketlemeyi içeren süreç için bkz:

Frida Tutorial — Self-contained agent + Gadget embedding

Referanslar:

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

Adım 8 — Fallback: Ağ görünürlüğü için TLS pinning’i yama

Eğer instrumentation engellenmişse, pinning’i statik olarak kaldırarak trafiği yine de inceleyebilirsiniz:

apk-mitm app.apk
# Then install the patched APK and proxy via Burp/mitmproxy
  • Araç: https://github.com/shroudedcode/apk-mitm
  • Ağ yapılandırması CA‑trust hileleri (ve Android 7+ kullanıcı CA trust) için bakınız:

Make APK Accept CA Certificate

Install Burp Certificate

Kullanışlı komut hile‑sayfası

# 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

Universal proxy forcing + TLS unpinning (HTTP Toolkit Frida hooks)

Modern apps often ignore system proxies and enforce multiple layers of pinning (Java + native), making traffic capture painful even with user/system CAs installed. Pratik bir yaklaşım, hazır Frida hook’ları ile universal TLS unpinning’i proxy forcing ile birleştirip tüm trafiği mitmproxy/Burp üzerinden yönlendirmektir.

Workflow

  • Host’unuzda mitmproxy (veya Burp) çalıştırın. Cihazın host IP/port’a erişebildiğinden emin olun.
  • HTTP Toolkit’in birleştirilmiş Frida hook’larını yükleyin; bunlar hem TLS unpinning hem de proxy forcing’i yaygın stack’lerde (OkHttp/OkHttp3, HttpsURLConnection, Conscrypt, WebView, vb.) sağlar. Bu, CertificatePinner/TrustManager kontrollerini atlar ve proxy selectors’ı / proxy seçicilerini geçersiz kılar; böylece uygulama proxy’leri açıkça devre dışı bıraktığında bile trafik her zaman proxy’niz üzerinden gönderilir.
  • Hedef uygulamayı Frida ve hook script’i ile başlatın ve istekleri mitmproxy’de yakalayın.

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

Notlar

  • Mümkünse sistem çapında bir proxy ile birleştirin: adb shell settings put global http_proxy <host>:<port>. Frida hooks, uygulamalar global ayarları atlatıyor olsa bile proxy kullanımını zorlayacaktır.
  • Bu teknik, pinning/proxy kaçınmasının yaygın olduğu ve mobile-to-IoT onboarding akışlarında MITM yapmanız gerektiğinde idealdir.
  • Hooks: https://github.com/httptoolkit/frida-interception-and-unpinning

Referanslar

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin