9.1 KiB
Android Anti-Instrumentation & SSL Pinning Bypass (Frida/Objection)
{{#include ../../banners/hacktricks-training.md}}
このページでは、インスツルメンテーションを検出/ブロックしたり、TLSピンニングを強制するAndroidアプリに対して動的分析を再取得するための実用的なワークフローを提供します。迅速なトリアージ、一般的な検出、および再パッキングなしでバイパスするためのコピー&ペースト可能なフック/戦術に焦点を当てています。
Detection Surface (アプリがチェックするもの)
- ルートチェック: suバイナリ、Magiskパス、getprop値、一般的なルートパッケージ
- Frida/デバッガーチェック (Java): Debug.isDebuggerConnected(), ActivityManager.getRunningAppProcesses(), getRunningServices(), /procのスキャン、クラスパス、ロードされたライブラリ
- ネイティブアンチデバッグ: ptrace(), システムコール、アンチアタッチ、ブレークポイント、インラインフック
- 初期化チェック: Application.onCreate()またはプロセス開始フックがインスツルメンテーションが存在する場合にクラッシュする
- TLSピンニング: カスタムTrustManager/HostnameVerifier、OkHttp CertificatePinner、Conscryptピンニング、ネイティブピン
Step 1 — Quick win: hide root with Magisk DenyList
- MagiskでZygiskを有効にする
- DenyListを有効にし、ターゲットパッケージを追加
- 再起動して再テスト
多くのアプリは明白な指標(su/Magiskパス/getprop)を探すだけです。DenyListはしばしば単純なチェックを無効化します。
References:
- Magisk (Zygisk & DenyList): https://github.com/topjohnwu/Magisk
Step 2 — 30‑second Frida Codeshare tests
深く掘り下げる前に、一般的なドロップインスクリプトを試してください:
- anti-root-bypass.js
- anti-frida-detection.js
- hide_frida_gum.js
Example:
frida -U -f com.example.app -l anti-frida-detection.js
これらは通常、Javaのroot/debugチェック、プロセス/サービススキャン、およびネイティブptrace()をスタブします。軽く保護されたアプリに役立ちます; 強化されたターゲットにはカスタマイズされたフックが必要な場合があります。
- Codeshare: https://codeshare.frida.re/
ステップ3 — 遅れてアタッチすることでinit-time検出をバイパス
多くの検出はプロセスの生成/onCreate()中にのみ実行されます。生成時のインジェクション(-f)やガジェットは捕まります; 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
もしこれが機能すれば、セッションを安定させ、マッピングとスタブチェックを進めます。
ステップ 4 — Jadxを使用して検出ロジックをマッピングし、文字列をハントする
Jadxでの静的トリアージキーワード:
- "frida", "gum", "root", "magisk", "ptrace", "su", "getprop", "debugger"
典型的なJavaパターン:
public boolean isFridaDetected() {
return getRunningServices().contains("frida");
}
一般的なAPIのレビュー/フック:
- android.os.Debug.isDebuggerConnected
- android.app.ActivityManager.getRunningAppProcesses / getRunningServices
- java.lang.System.loadLibrary / System.load (ネイティブブリッジ)
- java.lang.Runtime.exec / ProcessBuilder (コマンドのプロービング)
- android.os.SystemProperties.get (root/emulator ヒューリスティック)
ステップ5 — Fridaを使用したランタイムスタブ (Java)
カスタムガードをオーバーライドして、安全な値を返すようにし、再パッキングを行わない:
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(); };
});
初期クラッシュのトリアージ?クラッシュする直前にクラスをダンプして、検出される可能性のある名前空間を特定します:
Java.perform(() => {
Java.enumerateLoadedClasses({
onMatch: n => console.log(n),
onComplete: () => console.log('Done')
});
});
疑わしいメソッドをログに記録し、無効化して実行フローを確認します:
Java.perform(() => {
const Det = Java.use('com.example.security.DetectionManager');
Det.checkFrida.implementation = function () {
console.log('checkFrida() called');
return false;
};
});
ステップ 6 — Java フックが失敗した場合は JNI/ネイティブのトレイルをたどる
JNI エントリポイントをトレースして、ネイティブローダーと検出初期化を特定します:
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'
インタラクティブ/ネイティブリバース:
- Ghidra: https://ghidra-sre.org/
- r2frida: https://github.com/nowsecure/r2frida
例: libcのシンプルなアンチデバッグを打破するためにptraceを無効化する:
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: {{#ref}} reversing-native-libraries.md {{#endref}}
ステップ 7 — Objection パッチング (埋め込みガジェット / 基本のストリップ)
ランタイムフックよりもリパッキングを好む場合は、次を試してください:
objection patchapk --source app.apk
ノート:
- apktoolが必要です。ビルドの問題を避けるために、公式ガイドから最新バージョンを確認してください: https://apktool.org/docs/install
- Gadget injectionはrootなしでのインスツルメンテーションを可能にしますが、より強力なinit時チェックに捕まる可能性があります。
参考文献:
- Objection: https://github.com/sensepost/objection
ステップ8 — フォールバック: ネットワークの可視性のためにTLSピンニングをパッチする
インスツルメンテーションがブロックされている場合でも、ピンニングを静的に削除することでトラフィックを検査できます:
apk-mitm app.apk
# Then install the patched APK and proxy via Burp/mitmproxy
- ツール: https://github.com/shroudedcode/apk-mitm
- ネットワーク設定のCAトラストトリック(およびAndroid 7+のユーザーCAトラスト)については、次を参照してください: {{#ref}} make-apk-accept-ca-certificate.md {{#endref}} {{#ref}} install-burp-certificate.md {{#endref}}
便利なコマンドチートシート
# 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
ヒントと注意点
- アプリが起動時にクラッシュする場合は、スパウンするよりも遅延接続を優先する
- 一部の検出は重要なフロー(例:支払い、認証)で再実行される — ナビゲーション中はフックをアクティブに保つ
- 静的と動的を組み合わせる:Jadxで文字列を検索してクラスを絞り込み、その後メソッドをフックしてランタイムで検証する
- ハード化されたアプリはパッカーやネイティブTLSピンニングを使用する場合がある — ネイティブコードのリバースを期待する
参考文献
- Reversing Android Apps: Bypassing Detection Like a Pro
- Frida Codeshare
- Objection
- apk-mitm
- Jadx
- Ghidra
- r2frida
- Apktool install guide
- Magisk
{{#include ../../banners/hacktricks-training.md}}