[Rev] 리버싱 · 작성: 2026-07-19 19:34:18 · 조회 4
안드로이드 앱은 자바/코틀린으로 작성되어 바이트코드(DEX)로 컴파일되기 때문에, 네이티브 바이너리보다 디컴파일 결과가 원본 소스에 훨씬 가깝게 나온다. 그래서 입문 난이도가 상대적으로 낮은 편이다.
# jadx: DEX를 자바에 가까운 코드로 바로 보여줌 (읽기용으로 제일 편함)
jadx -d output_dir ./app.apk
# apktool: smali(DEX의 어셈블리 격) + 리소스로 분해, 수정 후 재조립까지 가능
apktool d ./app.apk -o output_dir
읽고 로직을 이해하는 목적이면 jadx, 코드를 직접 수정하고 재조립까지 할 계획이면 apktool을 쓴다.
AndroidManifest.xml에서 exported="true"로 표시된 컴포넌트(Activity, Service, BroadcastReceiver, ContentProvider)는 외부 앱이나 사용자가 직접 호출할 수 있는 진입점이다.
<activity android:name=".DebugActivity" android:exported="true" />
이런 컴포넌트가 있으면 adb로 직접 실행시켜서 인증 없이 접근 가능한 기능이 있는지 확인해본다.
adb shell am start -n com.example.app/.DebugActivity
Burp Suite를 프록시로 잡고 앱의 트래픽을 캡처한다. 최신 앱은 대부분 SSL Pinning(서버 인증서를 하드코딩해서 검증)이 걸려 있어서, 그냥 프록시 인증서를 설치하는 것만으로는 트래픽이 안 잡힌다.
SSL Pinning 우회 (Frida + objection)
objection -g com.example.app explore
> android sslpinning disable
objection이 흔한 Pinning 구현체(OkHttp CertificatePinner, TrustManager 커스텀 구현 등)에 대한 우회 스크립트를 내장하고 있어서, 대부분의 경우 이 한 줄로 해결된다. 안 통하면 jadx로 Pinning 로직을 직접 찾아서 해당 검증 함수를 개별적으로 후킹한다.
앱이 루팅된 기기에서 실행을 거부하는 경우가 많다. 탐지 방식(su 바이너리 존재 확인, 특정 패키지 존재 확인, 빌드 태그 확인 등)에 따라 objection의 android root disable로 해결되기도 하고, 안 되면 jadx로 탐지 함수를 찾아 Frida로 직접 후킹해서 리턴값을 조작한다.
Frida 후킹은 "실행 중에만" 적용되고 앱을 재배포할 수는 없다. 코드 자체를 영구적으로 바꾸고 싶다면 apktool로 분해한 smali 코드를 직접 편집한다.
# 예: 항상 true를 리턴하도록 강제
.method public isValid()Z
.locals 1
const/4 v0, 0x1
return v0
.end method
apktool b output_dir -o patched.apk
# 안드로이드는 서명 안 된 APK를 설치 못 하므로 재서명 필요
apksigner sign --ks my.keystore patched.apk
이 순서를 지키면 불필요하게 smali부터 손대는 시행착오를 줄일 수 있다.