1. APP 준비
1-1) playstore image에서 app 다운로드
1-2) adb shell pm list packages | grep test
- 설치한 app 이름을 이용한 패키지명 조회
1-3) adb shell pm path com.example.android.test
- 패키지명을 이용한 apk 경로 조회
1-4) APK 추출
1-4-1) 일반 APP
- adb pull /data/app/~~abc123/com.example.android.test-xyz/base.apk
1-4-2) Split APP
- adb shell pm path com.example.android.test | sed 's/package://' | xargs -n 1 adb pull
2. Google APIs image 실행 및 추출된 APK 파일 설치
2-1) 일반 APK
- adb install base.apk
2-2) Split APK
- adb install-multiple
\base.apk
\split_config.en.apk
\split_config.ko.apk
\split_config.x86_64.apk
\split_config.xxhdpi.apk
2-3) 설치 확인 (둘 중의 하나 사용)
- adb shell pm list packages | grep test
- adb shell pm path com.example.android.test
3. 테스트 기기 Frida 설정
3-1) device 내 frida 설정
- adb -s emulator-5554 push frida-server /data/local/tmp/
- adb -s emulator-5554 shell chmod 755 /data/local/tmp/frida-server
- adb -s emulator-5554 root
3-2) frida-server 실행
- adb shell /data/local/tmp/frida-server &
3-3) frida 정상 작동 여부 확인
- frida -U -f com.example.android.test -e "console.log('attached test');"
4. Proxy 설정 - Burp Suite
4-1) Proxy Listeners 설정
- proxy -> proxy Settings -> Tools -> Proxy menu로 이동
- 기본 값인 127.0.0.1:8080을 수정하여 All interface 및 8081 포트로 수정
4-2) CA 인증서 내보내기
- Import / export CA certificate -> Certificate in DER format
- 파일명은 cacert.der로 저장
5. Proxy 설정 - 테스트 기기
- Android 7.0(Nougat) 이상부터는 앱이 사용자 설치 인증서를 기본적으로 신뢰하지 않음.
따라서, Burp 인증서를 시스템 영역에 강제로 삽입해야 함
5-1) 인증서 포맷 변경
- Android의 시스템 인증서는 특정 해쉬값 형태의 파일명을 가져야 함(OpenSSL 사용)
5-1-1) 포맷 변환 (DER(이진 데이터 형식) -> PEM(텍스트 기반))
- openssl x509 -inform DER -in cacert.der -out burp.pem
- Android 시스템 폴더에 들어가는 인증서는 텍스트(PEM) 형식이어야 시스템이 내용을 읽을 수 있음
5-1-2) 해쉬값 확인
- openssl x509 -inform PEM -subject_hash_old -in burp.pem | head -1
- 나오는 결과값(예: 9a5ba575)
5-1-3) 파일 복사 및 이름 변경
- cp burp.pem 9a5ba575.0
5-2) emulator에 인증서 삽입
5-2-1) 기존 에뮬레이터 시스템 종료
- adb shell reboot -p
5-2-2) 기존 에뮬레이터 AVD 이름 확인
- ~/Library/Android/sdk/emulator/emulator -list-avds
5-2-3) writeable-system으로 실행
- ~/Library/Android/sdk/emulator/emulator -avd apis_5554 -writable-system
5-2-4) root/remount
- adb rppt
- adb remount
5-2-5) 인증서 삽입
- adb push 9a5ba575.0 /system/etc/security/cacerts/
5-2-6) 권한 및 소유권 부여
- adb shell chmod 644 /system/etc/security/cacerts/9a5ba575.0
- adb shell chown root:root /system/etc/security/cacerts/9a5ba575.0
5-2-7) 재시동
- adb reboot
5-2-8) 확인
- adb shell ls /system/etc/security/cacerts | grep 9a5ba575
- adb shell ls -l /system/etc/security/cacerts/9a5ba575.0
6. SSL Pinning 적용 및 원리 파악 방법론
6-1) 전제
- app 작동 중 burp suite로 패킷이 잡히지 않는 SSL Pinning이 적용되어 있음을 전제로 함
6-2) Logcat command
- adb shell pidof com.example.android.test
- adb logcat --pid=12717 "*:E" | grep -Ei "ssl|handshake|trust"
6-3) Logcat 기반 Java VS Native 레이어 판별 방법론
6-3-1) Java 레이어 통신 판별
6-3-1-1) 특징
- stacktrace가 java.lang, javax.net, android.net 또는 앱 패키지명(com.example.android.test )로 시작하거나 끝남
6-3-1-2) Logcat 패턴
- javax.net.ssl.SSLHandshakeException
- at okhttp3.internal.connection.RealConnection.connectTls
- at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted
6-3-1-3) 의미
- 앱이 안드로이드 표준 API(HttpURLConnection)나 대중적인 Java 라이브러리(OkHttp, Volley)를 사용하여 통신하고 있음을 뜻함
6-3-2) Native 레이어 통신 판별
6-3-2-1) 특징
- stacktrace에 .so 파일(Shared Object)나 natice 키워드가 포함되며, Java 단 로그 없이 갑자기 통신이 끊기거나 네이티브 라이브러리 주소가 찍힌다.
6-3-2-2) Logcat 패턴
- at com.android.org.conscrypt.NativeCrypto.ENGINE_SSL_read_direct(Native Method)
- at ... /data/app/.../lib/arm64/libflutter.so (offset 0x...)
- Fatal signal 11 (SIGSEGV) (SSL 검증 실패 시 강제 종료 로직이 있는 경우)
6-3-2-3) 의미
- 앱이 성능이나 보안을 위해 OpenSSL/BoringSSL을 직접 호출하거나, Flutter/Unity 등 자체 엔진을 사용하여 Java 프레임워크를 우회하고 있음을 뜻함
6-4) Logcat 분석을 통한 원인 파악 방법론
6-4-1) First Application Frame 찾기
- stackTrace에는 system class가 많이 찍히지만, 중요한 것은 앱의 코드가 개입된 지점임
- 로그 내에 com.example.android.test .C.a(Unknown Source)와 같이 난독화된 앱 코드가 나타난다면, 해당 클래스(C)가 커스텀 SSL 검증을 수행하는 핵심 로직임
6-4-2) Exception Chain 분석
- 'Caused by :' 절을 추적하여 근본 원인을 파악한다.
- Caused by: java.security.cert.CertificateException: 인증서 자체가 신뢰할 수 없음 (프록시 인증서 미설치 등)
- Caused by: SSLPeerUnverifiedException : 핀닝(Pinning)에 의해 인증서 비교 결과가 실패함
6-5) SSL Pinning 및 인증 관련 주요 키워드 분석
- SSLHandshakeException
- 분석 의미 : TLS 연결 단계에서 인증서 검증 실패
- 대응 방향 : SSL Pinning 로직 탐색 및 후킹
- Trust anchor for certification path not found
- 분석 의미 : 시스템/앱이 프록시 인증서를 신뢰하지 않음
- 대응 방향 : TrustManager 우회 스크립트 적용
- CertPathValidatorException
- 분석 의미 : 인증서 체인이 유효하지 않음
- 대응 방향 : X509TrustManagerExtensions 분석
- Certificate pinning failure!
- 분석 의미 : OkHttp 등 라이브러리 레벨의 핀닝 작동
- 대응 방향 : CertificatePinner 클래스 난독화 분석
- onReceivedSslError
- 분석 의미 : WebView 내에서 SSL 에러 발생
- 대응 방향 : WebViewClient 핸들러 우회
7. SSL Pinning Bypass Script
7-1) X509TrustManagerExtensions bypass
7-1-1) 우회 필요성 근거
- TrustManagerImpl만 후킹했을 때, WebView나 특정 광고 SDK가 동작하는 시점에 앱이 즉시 종료(Crash)됨
7-1-2) 발견 근거
7-1-2-1) Logcat
- java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference
- 안드로이드 시스템의 WebView 엔진인 Chromium은 내부적으로 checkServerTrusted method를 호출한 뒤, 그 결과값인 List 객체의 size() 메서드를 호출함.
이 때, 우리가 적절한 리스트를 반환하지 않으면 null 참조 에러가 발생하여 앱이 crash됨
7-1-2-1) 정적 분석
- 대상 소스 : android.net.http.X509TrustManagerExtensions
- method signature : public List\<X509Certificate>checkServerTrusted(X509Certificate\[] chain, String authType, String host)
- 해당 method는 단순 void가 아니라 List 객체를 반환해야 하는 명확한 규격이 존재함 또한 인자로 배열(X509Certificate\[])을 받음
7-1-3) Frida Scrip
var X509TrustManagerExtensions = Java.use('android.net.http.X509TrustManagerExtensions');
var Arrays = Java.use('java.util.Arrays');
X509TrustManagerExtensions.checkServerTrusted.overload('[Ljava.security.cert.X509Certificate;', 'java.lang.String', 'java.lang.String')
.implementation = function (chain, authType, host) {
console.log("[+] Bypassing X509TrustManagerExtensions for: " + host);
var certificateList = Arrays.asList(chain);
return certificateList;
};
7-1-4) 우회 방식
- checkServerTrusted를 후킹하여 검증로직을 무력화 시키고 Arrays.asList(chain)을 통해 Java가 기대하는 java.util.List 인터페이스 규격에 부합하는 인증서 리스트 객체를 생성하여 봔한함
- 이로써 검증은 무시하면서도 WebView엔지이 후속 로직(sizeZ() 호출 등)을 수행할 때 에러 없이 동작하도록 후킹함
7-2) OKHTTP Chain cleaner(application library OkHttp) bypass
7-2-1) 우회 필요성 근거

- checkServerTrusted를 통해 만약 BurpSuite같은 프록시 인증서가 끼어 있다면, 에러(CertificateExeption)가 터짐,
- pc.d.a의 경우 반드시 정리된 List\<X509Certificate>를 반환해야 함
7-2-2) 발견 근거
- Logcat을 통해 확인된 SSLPeerUnverifiedException을 기점으로 역공학을 수행하여 pc.d 클래스가 OkHttp의 CertificateChainCleaner 난독화 구현체임을 식별
- 해당 클래스가 OkHttp 내부 통신 인터페이스 규격을 상속받고 있음
- 내부적으로 X509TrustManagerExtensions를 호출하여 시스템 정책과 연동된 체인 정리를 수행
- 정적 분석을 통해 확인된 로직이 오픈소스 OkHttp의 인증서 검증 알고리즘과 동일
7-2-3) Frida Script
try {
var pc_d = Java.use('pc.d');
pc_d.a.implementation = function (chain, hostname) {
console.log("[+] Bypassing pc.d.a (OkHttp Chain Cleaner) for: " + hostname);
return chain;
};
} catch (e) {
console.log("[-] pc.d class not found, skipping...");
}
7-2-4) 우회 방식
- checkServerTrusted와 exeption 로직을 아얘 실행하지 않게 덮어씌움
- 덮어 씌운 코드의 정상작동을 위해 정돈된 인증서 자체는 return값으로 반환시킴
7-3) Conscrypt system level bypass
7-3-1) 우회 필요성 및 발견 근거
7-3-1-1) Logcat
- Logcat Message
- E Datadog : at com.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:xxx)
- javax.net.ssl.SSLHandshakeException : java.security.cert.CertPathValidatorException: Trust anchor for certification path not found
- Datadog과 같은 외부 SDK나 앱의 공통 통신 모듈이 호출될 때, 안드로이드의 기본 TLS 구현체인 Conscrypt 내부에서 검증 실패가 발생함
xxx번 라인은 서버 인증서를 시스템의 신뢰할 수 있는 루트 CA와 대조하는 로직이 위치한 곳임
7-3-1-2) 정적 분석
- 대상 소스 : com.android.org.conscrypt.TrustManagerImpl
- method signature : public List\<X509Certificate> verifyChain(X509Certificate\[]) unverifyedChain, ....)
- 서버로부터 수신한 인증서 배열(unverifiedChain)을 검사하여, 신뢰할 수 있는 경로(Trust Path)를 찾지 못하면 예외를 던짐.
모든 HttpURLConnection, OkHttp, Retrofit 요청은 결국 이 네이티브 연동 클래스를 거치게 됨
7-3-2) Frida Script
var TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl');
TrustManagerImpl.verifyChain.implementation = function (unverifiedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) {
console.log("[+] Bypassing Conscrypt TrustManagerImpl.verifyChain for: " + host);
return unverifiedChain;
};
7-3-3) 우회 방식
- TrustManagerImpl.verifyChain을 후킹하여 parameter로 받아오는 unverifiedChain을 검증없으 그대로 반환시켜 SSL Handshake를 완료하고 데이터 통신을 혀용시킴
'보안 프로젝트' 카테고리의 다른 글
| [보안 프로젝트] Injection (0) | 2026.04.05 |
|---|---|
| [보안 프로젝트] OSINT 기법 (0) | 2026.03.29 |
| KT Cloud VM 서버 초기 구축 및 SSH 보안 하드닝 정리 (0) | 2025.12.21 |
| 모바일 해킹을 위한 JADX & Frida with FridaLab (0) | 2025.09.21 |
| 커스텀 보안툴 만들기 (1) | 2025.09.03 |