8.0 KiB
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
예:
frida -U -f com.example.app -l anti-frida-detection.js
이들은 일반적으로 Java 루트/디버그 검사, 프로세스/서비스 스캔 및 네이티브 ptrace()를 스텁합니다. 보호가 약한 앱에서 유용하며, 강화된 타겟은 맞춤형 후크가 필요할 수 있습니다.
- Codeshare: https://codeshare.frida.re/
Step 3 — 초기 탐지기를 늦게 연결하여 우회하기
많은 탐지는 프로세스 생성/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");
}
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:
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;
};
});
Step 6 — Java 훅이 실패할 때 JNI/native 경로를 따라가세요
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}}
Step 7 — Objection 패칭 (임베드 가젯 / 스트립 기본)
런타임 훅보다 리패킹을 선호할 때, 시도해 보세요:
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을 정적으로 제거하여 여전히 트래픽을 검사할 수 있습니다:
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}}
유용한 명령어 치트 시트
# 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
- Frida Codeshare
- Objection
- apk-mitm
- Jadx
- Ghidra
- r2frida
- Apktool install guide
- Magisk
{{#include ../../banners/hacktricks-training.md}}