hacktricks/src/mobile-pentesting/android-app-pentesting/android-anti-instrumentation-and-ssl-pinning-bypass.md

9.1 KiB
Raw Blame History

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:

Step 2 — 30second 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()をスタブします。軽く保護されたアプリに役立ちます; 強化されたターゲットにはカスタマイズされたフックが必要な場合があります。

ステップ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'

インタラクティブ/ネイティブリバース:

例: 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時チェックに捕まる可能性があります。

参考文献:

ステップ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ピンニングを使用する場合がある — ネイティブコードのリバースを期待する

参考文献

{{#include ../../banners/hacktricks-training.md}}