mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
204 lines
8.0 KiB
Markdown
204 lines
8.0 KiB
Markdown
# 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}}
|