Reverse Engineering(리버스 엔지니어링)은 소스 코드에 접근하지 않고 모바일 애플리케이션의 로직과 구조를 복원하는 것입니다. Android 및 iOS의 맥락에서 이는 알고리즘, 암호화 키, API 엔드포인트 및 비즈니스 로직을 추출하기 위해 DEX/APK 및 Mach-O/IPA 바이너리 파일을 역컴파일하는 것을 의미합니다. Veracode Security Research(2025)에 따르면, 상위 200개 모바일 애플리케이션의 60% 이상이 리버스 엔지니어링을 단순화하는 하나 이상의 지표를 포함하고 있습니다. Reverse Engineering은 공격뿐만 아니라 보안 감사, 특허 분석 및 침투 테스트에도 사용됩니다.
핵심 사항
Reverse Engineering(리버스 엔지니어링)은 애플리케이션의 바이너리 표현에서 특성, 로직 및 구조를 복원하는 것을 목표로 하는 소프트웨어 분석 분야입니다. 모바일 애플리케이션의 경우 분석 대상은 APK 파일(Android) 및 IPA 파일(iOS)이며, 컴파일된 코드, 리소스, 매니페스트 및 인증서가 포함되어 있습니다. 리버스 엔지니어링의 결과는 알고리즘, 프로토콜, 암호화 키, API 스키마 및 비즈니스 로직의 추출입니다.
리버스 엔지니어링의 목표는 합법적인 것과 불법적인 것으로 나뉩니다. 합법적: 보안 도구를 만들기 위한 악성코드 분석, 취약점에 대한 자체 애플리케이션 감사, 폐쇄형 프로토콜과의 호환성 보장, 특허 분석 및 교육. 불법적: 지적 재산권 도용, 라이선스 제한 우회, 불법 복제본 생성 및 사용자 데이터 도용을 위한 애플리케이션 수정. Google Play Protect(2025)에 따르면, 은행 애플리케이션의 악성 수정본 78%가 리버스 엔지니어링을 통해 처리된 원본 APK를 기반으로 생성됩니다.
리버스 엔지니어링의 방법론에는 정적 분석(애플리케이션 실행 없이)과 동적 분석(실행 중)의 두 가지 주요 방향이 포함됩니다. 각 접근 방식은 다른 수준의 정보를 제공합니다. 정적 분석은 코드의 전체적인 그림을 제공하지만 런타임 데이터는 없습니다. 동적 분석은 실제 동작, 데이터 흐름, 네트워크 호출을 보여주지만 특정 실행 시나리오 내에서만 가능합니다. 전문적인 리버스 엔지니어링은 항상 두 접근 방식을 결합합니다.
정적 분석은 리버스 엔지니어링의 첫 번째 단계입니다. 원본 APK 또는 IPA의 압축을 풀고 각 구성 요소를 개별적으로 분석합니다. 주요 대상: DEX 바이트코드, 리소스, 매니페스트, 네이티브 라이브러리(.so, .dylib) 및 메타데이터.
jadx는 Android 애플리케이션의 정적 분석을 위한 주요 도구입니다. DEX 바이트코드를 최소한의 손실로 읽을 수 있는 Java 코드로 변환합니다. jadx는 다음을 지원합니다: 멀티덱스 역컴파일, 람다 및 인라인 Kotlin 클래스 인식, Gradle 프로젝트로 내보내기. 난독화된 코드(ProGuard)의 경우 jadx는 a, b, c 이름의 코드를 표시하지만 클래스 구조와 호출 순서는 유지됩니다. 독립적인 테스트에 따르면 jadx는 난독화가 있어도 85~92%의 코드를 올바르게 역컴파일합니다.
apktool은 APK를 smali 코드(DEX 어셈블러)로 디코딩하고 리소스를 읽을 수 있는 형태로 복원합니다: AndroidManifest.xml은 AXML에서 읽을 수 있는 XML로 변환되고, 레이아웃은 XML 마크업으로, strings.xml은 일반 텍스트로 변환됩니다. apktool을 사용하면 리소스를 수정하고 APK를 재구축할 수 있습니다. apktool을 통해 압축을 풀고 리소스를 교체한 후 수정된 콘텐츠로 애플리케이션을 설치할 수 있습니다.
Ghidra(NSA)는 Android의 .so 라이브러리 및 iOS의 .dylib 분석에 필수적인 리버스 엔지니어링 프레임워크입니다. Ghidra는 ARM64 코드를 디스어셈블하고, C 의사 코드를 재구성하며, 호출 그래프를 구축합니다. 모바일 리버스 엔지니어링에서 Ghidra는 암호화 및 DRM 메커니즘의 네이티브 구현을 분석하는 데 사용됩니다. Ghidra는 분석 자동화를 위한 Python 및 Java 스크립팅을 지원합니다.
# APK 압축 풀기 및 역컴파일
$ jadx -d output_dir app.apk
# apktool을 통한 리소스 압축 풀기
$ apktool d app.apk -o app_unpacked
# Ghidra를 통한 네이티브 라이브러리 분석
$ ghidra app.apk/lib/arm64-v8a/libnative.so
# DEX에서 문자열 상수 검색
$ strings classes.dex | grep -i api_key
동적 분석은 실행 중인 애플리케이션에서 수행됩니다. 분석기는 프로세스에 연결하여 실시간으로 함수 호출, 인수 및 반환 값을 가로챕니다.
Frida는 모바일 애플리케이션의 동적 분석을 위한 선도적인 도구입니다. Frida는 애플리케이션 프로세스(Android ART 또는 iOS 앱)에 JavaScript 엔진을 주입하고 Java/Objective-C 및 C/C++ 함수 호출을 모두 가로챌 수 있습니다. Frida를 사용하면 리버스 엔지니어는 다음을 수행할 수 있습니다: 매개변수와 함께 AES.decrypt() 메서드의 모든 호출 로깅, 반환 값을 임의로 대체, Universal Android SSL Unpin을 통한 SSL-pinning 비활성화, Stalker를 통한 네이티브 호출 추적. Frida는 APK/IPA를 수정하지 않고 작동하므로 침투 테스트에 필수적입니다.
Objection은 JavaScript 스크립트를 작성하지 않고 일반적인 리버스 엔지니어링 작업을 위한 준비된 명령을 제공합니다: disable-pinning(SSL pinning 비활성화), dump-keychain(iOS), explore(클래스 계층 구조 탐색), memory search(메모리에서 문자열 검색). Objection은 단 한 줄의 코드도 없이 완전한 동적 분석을 수행할 수 있습니다. iOS 애플리케이션의 경우 Objection은 자동으로 NSURLSession, CFNetwork 및 NSKeyedArchiver 호출을 찾아 로깅합니다.
Xposed는 Zygote에서 app_process 파일을 교체하여 작동하는 Android용 프레임워크입니다. Frida와 달리 Xposed는 설치 후 루트 액세스가 필요하지 않습니다. Xposed 모듈은 모든 애플리케이션에서 메서드 호출을 가로챌 수 있습니다. 리버스 엔지니어링에서 Xposed는 장기 분석에 편리합니다: 모듈이 설치되어 지속적으로 실행되며 다양한 시나리오에서 애플리케이션 동작을 로깅합니다. Xposed는 Android 8.1까지 지원합니다. Android 9+의 경우 SandHook 기반 EdXposed가 사용됩니다.
// Frida: 애플리케이션에서 decrypt() 메서드 가로채기
let aesClass = Java.use("javax.crypto.Cipher");
aesClass.doFinal.overload(
"[B", "int", "int"
).implementation = function(
input, offset, len
) {
console("[AES] decrypt called, len=" + len);
return this.doFinal(input, offset, len);
};
표준 리버스 엔지니어링 워크플로는 순차적 단계로 구성되며, 각 단계는 특정 수준의 정보를 제공합니다.
분석가는 메타데이터 수준에서 APK를 검사합니다: targetSdk, uses-permission(요청된 권한), intent-filter 및 내보내진 구성 요소. 권한을 통해 사용된 API를 확인할 수 있습니다(android.permission.CAMERA → 카메라, android.permission.RECORD_AUDIO → 오디오). 내보내진 활동은 인증 없이 진입점을 식별합니다. 이 단계는 aapt 또는 ApkAnalyzer를 통해 수행되며 1~2분이 소요됩니다.
APK의 압축이 풀리고 classes.dex(또는 멀티덱스)가 jadx에 입력됩니다. 출력은 패키지로 구성된 Java/Kotlin 코드입니다. 분석가는 주요 클래스(CryptoUtils, ApiClient, AuthManager, DatabaseHelper)를 찾고 사용된 알고리즘을 확인합니다. 코드에 AES/CBC/PKCS5Padding과 같은 문자열이 포함된 경우 애플리케이션이 암호화를 사용하며 키를 찾아야 합니다. 이 단계에서 하드코딩된 키, API URL, OAuth 토큰 및 비밀이 식별됩니다. 난독화가 없는 경우 전체 애플리케이션 코드가 일반 Java 프로젝트처럼 읽힙니다.
SSL-pinning을 비활성화하기 위해 Frida 또는 Objection을 설정한 후 분석가는 애플리케이션을 시작하고 Burp Suite 또는 mitmproxy를 통해 네트워크 트래픽을 가로챕니다. 트래픽 데이터는 API 스키마를 드러냅니다: 어떤 엔드포인트, 어떤 매개변수, 어떤 형식인지. 가능한 경우 분석가는 요청을 수정하고 잘못되거나 악의적인 데이터에 대한 서버 응답을 확인합니다. 서버 측 검증 부재는 이 단계에서 발견되는 직접적인 취약점입니다.
분석 결과는 구조화된 형식으로 기록됩니다. 발견된 각 취약점에 대해 클래스 및 메서드, 취약점 설명, 악용 벡터 및 수정 권장 사항이 표시됩니다. 이 데이터 세트는 개발 팀에 전달되거나 침투 테스트 보고서를 작성하는 데 사용됩니다. 자동화된 환경(MobSF)에서는 정적 및 동적 분석 결과를 기반으로 보고서가 자동으로 생성됩니다.
iOS 애플리케이션의 리버스 엔지니어링은 Apple의 엄격한 보안 아키텍처와 표준 기기에서 파일 시스템에 직접 접근할 수 없기 때문에 Android보다 더 어렵습니다. iOS 분석에는 탈옥이 필요합니다.
IPA 아카이브에는 Mach-O 바이너리(Apple의 범용 실행 파일 형식)가 포함되어 있습니다. 역컴파일을 위해 Hopper Disassembler 또는 IDA Pro가 사용됩니다. 최소한의 손실로 Java로 역컴파일되는 Android DEX와 달리 Mach-O는 네이티브 ARM64 코드를 포함하며 C 의사 코드로의 재구성 정확도가 낮습니다. Hopper는 60~70%의 재구성을 달성합니다. 나머지는 어셈블리 수준에서 분석해야 합니다.
iOS에서 Frida를 사용하려면 탈옥과 frida-server 설치가 필요합니다. 연결 후 Frida는 API 메시지 라우팅을 통해 Objective-C 메서드를 가로챕니다. iOS 애플리케이션의 일반적인 시나리오는 다음과 같습니다: HTTP 요청 로깅을 위한 NSURLSession.dataTaskWithRequest 가로채기, 직렬화된 데이터 분석을 위한 NSKeyedUnarchiver 가로채기, frida-trace를 통한 CoreData 쿼리 추적. Frida는 Dopamine 탈옥 출시와 함께 iOS 15~17에서 사용 가능해졌습니다.
리버스 엔지니어링에는 IPA 수정 후 재패키징 및 기기 설치가 포함될 수 있습니다. 도구에는 다음이 포함됩니다: 압축 풀기를 위한 ipatool, 섹션 보기를 위한 MachOView, 코드 주입을 위한 optool. 수정 후 IPA는 탈옥된 기기에 설치하기 위해 ldid 또는 fastlane sigh를 통해 서명됩니다. iOS 16+의 경우 코드 서명이 Secure Enclave 수준에서 검증되며 수정된 IPA는 탈옥되지 않은 기기에서 실행되지 않습니다.
// Frida: iOS 애플리케이션에서 HTTP 요청 가로채기
if (ObjC.available) {
let NSURLSession = ObjC.classes.NSURLSession;
let dataTaskWithRequest = ObjC.protocol("NSURLSessionDelegate")
.method("- URLSession:dataTask:didReceiveData:");
Interceptor.attach(dataTaskWithRequest.implementation, {
onEnter(args) {
let data = ObjC.Object(args[3]);
console("[HTTP Response]", data.toString());
}
});
}
리버스 엔지니어링으로부터의 보호는 계층적 보안 원칙을 따릅니다: 단일 방법으로는 100% 보호를 제공할 수 없지만 조합을 통해 리버스 엔지니어링을 경제적으로 비실용적으로 만듭니다.
기본 수준은 Android용 ProGuard로, 클래스 및 메서드 이름을 단일 문자 이름으로 바꿉니다. 향상된 보호를 위해 DexGuard는 오버로드 유도(다른 서명과 동일한 이름을 가진 여러 메서드) 및 AES-256 문자열 암호화를 추가합니다. 난독화는 수준에 따라 코드 분석 시간을 5분에서 5~20시간으로 증가시킵니다. DexGuard는 추가로 제어 흐름을 난독화하여 jadx에서 코드를 읽을 수 없게 만듭니다.
모든 문자열 상수(URL, 키, 토큰, SQL 쿼리)는 빌드 시 암호화되고 런타임에 복호화됩니다. 이는 DEX 파일의 문자열 정적 분석으로부터 보호합니다. app.apk에서 strings를 실행하는 공격자는 어떤 API 엔드포인트도 볼 수 없습니다. 역컴파일 후에도 모든 문자열이 이진 데이터로 나타납니다. 각 문자열은 별도의 키를 사용할 수 있어 난독화 해제를 복잡하게 만듭니다.
애플리케이션 내부의 RASP 에이전트는 런타임에 Frida 및 디버깅을 감지합니다. APK의 SHA-256 해시를 통한 무결성 검사는 수정된 버전의 애플리케이션 실행을 방지합니다. APK 해시가 참조 해시(네이티브 계층에 저장)와 일치하지 않으면 애플리케이션이 종료됩니다. 이는 재패키징을 포함한 APK 수정 기반 공격을 차단합니다.
중요한 비즈니스 로직은 클라이언트가 아닌 서버에서 실행되어야 합니다. 공격자가 애플리케이션을 완전히 역컴파일하더라도 서버 코드는 접근 불가능합니다. 모든 요청 및 매개변수의 서버 측 검증은 리버스 엔지니어링 중 발견된 취약점 악용을 방지합니다. 서버 증명(Play Integrity API 또는 App Attest를 통해)은 요청이 진정하고 수정되지 않은 애플리케이션에서 오는지 확인합니다.
자주 묻는 질문
미국에서 리버스 엔지니어링은 DMCA에 의해 규제됩니다. 상호 운용성, 보안 테스트 및 보관 목적으로 허용됩니다. 기술적 보호 조치(DRM) 우회는 금지됩니다. 유럽에서 EUCD의 제6조는 DMCA와 유사합니다. 러시아에서 저작권 보유자의 동의 없이 리버스 엔지니어링을 수행하면 저작권 침해로 간주될 수 있습니다. 상업적 리버스 엔지니어링 전에 법률 상담이 필수입니다.
아니요. 공격자의 기기에서 실행되는 모든 코드는 분석될 수 있습니다. 이는 클라이언트 측 보안 모델의 근본적인 한계입니다. 보호의 목표는 리버스 엔지니어링을 경제적으로 매력적이지 않게 만드는 것입니다: 시간과 리소스 비용이 얻은 결과의 가치를 초과해야 합니다. 난독화, RASP 및 서버 측 로직의 조합이 현재 보호 표준입니다.
재패키징은 리버스 엔지니어링을 통한 애플리케이션 수정 후 APK 재구축입니다. 공격자는 apktool을 통해 APK의 압축을 풀고 악성 코드를 추가하거나 API 키를 교체한 후 재구축하고 자체 인증서로 서명합니다. 재패키징은 Kaspersky Threat Report(2025)에 따르면 Android 공격의 86%를 차지합니다. 대응책: 런타임에 디지털 서명을 확인합니다.
Frida 스크립트 Universal Android SSL Unpin은 iOS에서 TrustManager.checkServerTrusted 및 ServerTrustManager 호출을 가로채 구현을 모두 허용으로 대체합니다. OkHttp 및 URLConnection에서 X509TrustManager 메서드의 가로채기도 사용됩니다. SSL-pinning은 준비된 스크립트를 사용하여 Frida로 10초 만에 우회할 수 있습니다. 더 강력한 보호는 서버 측 인증서 검증을 통한 인증서 투명성입니다.
.so/.dylib 라이브러리의 네이티브 C/C++ 코드는 DEX의 Java보다 리버스하기 훨씬 어렵습니다. PGO 및 Osize 컴파일을 사용한 Swift는 Objective-C보다 더 난독화된 바이너리를 생성합니다. Rust는 런타임 메타데이터 없이 그리고 Objective-C의 표준 래퍼 없이 네이티브 코드로 컴파일되므로 현대 모바일 개발 언어 중 리버스 엔지니어링하기 가장 어렵습니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.