# Android Anti-Instrumentation & SSL Pinning Bypass (Frida/Objection) {{#include ../../banners/hacktricks-training.md}} 이 페이지는 Android 앱이 감지/루트 차단 기법을 탐지하거나 TLS 핀닝을 강제할 때 동적 분석을 재개하기 위한 실용적인 워크플로를 제공합니다. 빠른 분류, 일반적인 탐지 및 가능한 경우 재포장 없이 우회하기 위한 복사-붙여넣기 가능한 훅/전술에 중점을 둡니다. ## Detection Surface (앱이 확인하는 것) - 루트 확인: su 바이너리, Magisk 경로, getprop 값, 일반적인 루트 패키지 - Frida/디버거 확인 (Java): Debug.isDebuggerConnected(), ActivityManager.getRunningAppProcesses(), getRunningServices(), /proc 스캔, classpath, 로드된 라이브러리 - 네이티브 안티-디버그: ptrace(), 시스템 호출, anti-attach, 중단점, 인라인 훅 - 초기화 확인: Application.onCreate() 또는 기기가 존재할 경우 충돌하는 프로세스 시작 훅 - TLS 핀닝: 사용자 정의 TrustManager/HostnameVerifier, OkHttp CertificatePinner, Conscrypt 핀닝, 네이티브 핀 ## Step 1 — 빠른 승리: Magisk DenyList로 루트 숨기기 - Magisk에서 Zygisk 활성화 - DenyList 활성화, 대상 패키지 추가 - 재부팅 및 재테스트 많은 앱은 명백한 지표(su/Magisk 경로/getprop)만 확인합니다. DenyList는 종종 단순한 확인을 무력화합니다. References: - Magisk (Zygisk & DenyList): https://github.com/topjohnwu/Magisk ## Step 2 — 30초 Frida Codeshare 테스트 깊이 파고들기 전에 일반적인 드롭인 스크립트를 시도해 보세요: - anti-root-bypass.js - anti-frida-detection.js - hide_frida_gum.js 예: ```bash frida -U -f com.example.app -l anti-frida-detection.js ``` 이들은 일반적으로 Java 루트/디버그 검사, 프로세스/서비스 스캔 및 네이티브 ptrace()를 스텁합니다. 보호가 약한 앱에서 유용하며, 강화된 타겟은 맞춤형 후크가 필요할 수 있습니다. - Codeshare: https://codeshare.frida.re/ ## Step 3 — 초기 탐지기를 늦게 연결하여 우회하기 많은 탐지는 프로세스 생성/onCreate() 중에만 실행됩니다. 생성 시 주입(-f) 또는 가젯이 포착되며, UI 로드 후에 연결하면 우회할 수 있습니다. ```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 ``` 이 작업이 성공하면 세션을 안정적으로 유지하고 매핑 및 스텁 검사를 진행합니다. ## 4단계 — Jadx 및 문자열 검색을 통한 탐지 로직 매핑 Jadx의 정적 분류 키워드: - "frida", "gum", "root", "magisk", "ptrace", "su", "getprop", "debugger" 일반적인 Java 패턴: ```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(); }; }); ``` 조기 크래시를 분류하나요? 죽기 직전에 클래스 덤프를 생성하여 감지 가능성이 높은 네임스페이스를 찾아보세요: ```js Java.perform(() => { Java.enumerateLoadedClasses({ onMatch: n => console.log(n), onComplete: () => console.log('Done') }); }); ``` 의심스러운 메서드를 기록하고 중립화하여 실행 흐름을 확인합니다: ```js Java.perform(() => { const Det = Java.use('com.example.security.DetectionManager'); Det.checkFrida.implementation = function () { console.log('checkFrida() called'); return false; }; }); ``` ## Step 6 — Java 훅이 실패할 때 JNI/native 경로를 따라가세요 JNI 진입점을 추적하여 네이티브 로더와 탐지 초기화를 찾습니다: ```bash frida-trace -n com.example.app -i "JNI_OnLoad" ``` 번들된 .so 파일의 빠른 네이티브 트리아지: ```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' ``` 인터랙티브/네이티브 리버싱: - Ghidra: https://ghidra-sre.org/ - r2frida: https://github.com/nowsecure/r2frida 예시: libc에서 간단한 안티 디버그를 무력화하기 위해 ptrace를 중립화: ```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: {{#ref}} reversing-native-libraries.md {{#endref}} ## Step 7 — Objection 패칭 (임베드 가젯 / 스트립 기본) 런타임 훅보다 리패킹을 선호할 때, 시도해 보세요: ```bash objection patchapk --source app.apk ``` 노트: - apktool이 필요합니다; 빌드 문제를 피하기 위해 공식 가이드에서 최신 버전을 확인하세요: https://apktool.org/docs/install - Gadget injection은 루트 없이도 instrumentation을 가능하게 하지만, 더 강력한 init‑time 체크에 의해 여전히 감지될 수 있습니다. 참조: - Objection: https://github.com/sensepost/objection ## 8단계 — 대체: 네트워크 가시성을 위한 TLS pinning 패치 instrumentation이 차단된 경우, pinning을 정적으로 제거하여 여전히 트래픽을 검사할 수 있습니다: ```bash apk-mitm app.apk # Then install the patched APK and proxy via Burp/mitmproxy ``` - 도구: https://github.com/shroudedcode/apk-mitm - 네트워크 구성 CA‑trust 트릭(및 Android 7+ 사용자 CA 신뢰)에 대한 내용은 다음을 참조하세요: {{#ref}} make-apk-accept-ca-certificate.md {{#endref}} {{#ref}} install-burp-certificate.md {{#endref}} ## 유용한 명령어 치트 시트 ```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 - 앱이 시작할 때 충돌할 경우, 생성하는 것보다 늦게 연결하는 것을 선호하세요. - 일부 탐지는 중요한 흐름(예: 결제, 인증)에서 다시 실행됩니다 — 탐색 중에 후크를 활성 상태로 유지하세요. - 정적 및 동적 혼합: Jadx에서 문자열 검색으로 클래스를 선별한 후, 런타임에서 검증하기 위해 메서드를 후킹하세요. - 강화된 앱은 패커와 네이티브 TLS 핀닝을 사용할 수 있습니다 — 네이티브 코드를 리버스 엔지니어링할 것으로 예상하세요. ## References - [Reversing Android Apps: Bypassing Detection Like a Pro](https://www.kayssel.com/newsletter/issue-12/) - [Frida Codeshare](https://codeshare.frida.re/) - [Objection](https://github.com/sensepost/objection) - [apk-mitm](https://github.com/shroudedcode/apk-mitm) - [Jadx](https://github.com/skylot/jadx) - [Ghidra](https://ghidra-sre.org/) - [r2frida](https://github.com/nowsecure/r2frida) - [Apktool install guide](https://apktool.org/docs/install) - [Magisk](https://github.com/topjohnwu/Magisk) {{#include ../../banners/hacktricks-training.md}}