안드로이드 앱 컴파일/디컴파일 과정 (DVM/ART/JADX)
안드로이드 앱(.apk) 생성과정과 디컴파일 과정을 알아보자.
컴파일 : 소스 코드(개발자가 코딩한 코드)를 CPU가 이해할 수 있는 형식(기계어)으로 변환하는 과정
디컴파일 : CPU가 이해하는 코드(기계어) 를 사람이 읽을 수 있는 소스 코드로 변환하는 행위
기계어 (Machine Code)
- CPU가 이해하고 실행할 수 있는 명령어를 말한다.
- CPU는 0과 1로 이루어진 이진 데이터만 인식 가능하다.
- 즉, CPU가 이해하는 모든 명령어와 데이터는 2진수(0과 1)로 이루어져 있다.
ex) 0101 0011
안드로이드 컴파일 방식(DalvikVM, ART)
Dalvik VM(달빅 가상머신) / Android Runtime(ART)
안드로이드 앱은 두가지의 실행 환경을 가진다.
Dalvik VM(달빅 가상머신)
- 안드로이드 초창기 실행 환경으로, JVM과 유사하게, 안드로이드 앱이 Dalvik VM(달빅 가상머신) 위에서 실행 한다. 즉, 가상 실행 환경이다.
- 달빅은 컴파일을 하는 시점이 런타임 시점(앱 실행 중)
- Just-In-Time(JIT) 컴파일을 사용하여 앱 실행 중에 필요한 부분만 컴파일하고 실행
- 설치 속도가 빠르고, 초기 실행 속도가 느리다.(캐시 메모리 사용으로 점차 최적화)
- 필요한 부분을 저장하는 캐시가 존재하므로, 많은 메모리가 필요하다.
■Dalvik VM은 컴파일 환경이며 설치 시 별도의 컴파일은 수행되지 않는다. 런타임(앱 실행) 시 .dex 파일을 해석(Interpretation)하거나 JIT 컴파일을 통해 실행한다. 앱 실행 중 필요한 부분만 JIT 컴파일하여 기계어로 변환하며, 이를 캐싱해 성능을 점진적으로 향상시킵니다.
Android Runtime(ART)
- Dalvik VM을 대체하기 위해 설계 된 실행 방식으로, 가상머신으로 동작하는게 아닌, 런타임 환경이다.
- ART는 컴파일을 하는 시점이 앱 설치 시점이다.
- 애플리케이션 설치 시 전체 미리 컴파일하여 실행 시 더 빠른 성능 제공.(AOT 컴파일)
- 미리 전체를 컴파일 해놓기 때문에. 초기 설치 속도는 느리지만, 초기 실행 속도는 빠르다.
- 네이티브코드(기계어) 수준에서 실행 되므로, 적은 메모리 사용
■ ART(Android Runtime) 는 앱 설치 시 AOT(Ahead-Of-Time) 컴파일을 통해 .dex 파일(Dalvik 바이트코드)을 네이티브 코드(기계어) 로 전체를 미리 컴파일한다.
Dalvik VM(달빅 가상머신)
가상 머신이 뭐지? 먼저 대표 가상머신인 JVM을 이해해보자.
JVM(Java Virtual Machine) 이란?
JVM은 OS위에 올라가는 소프트웨어로 구현된 "가상 환경" 이다.
Java 기반 웹/앱 어플리케이션은 JVM 이라는 가상 머신 위에서 동작한다.
이게 왜 필요하냐?
OS의 다양성 때문이다. OS(운영체제)는 여러가지가 있다. 각 제조사도 다르고, 정책도 다르고, 동작 방식도 다르다.
그렇기 때문에 소프트웨어를 개발하고, 실행 시키려면 각 OS마다 다르게 설정하고 동작하도록 해야한다.
이게 너무 비효율적...
JVM은 Java 애플리케이션들이 각 운영체제마다 다르게 동작하지 않고, 하나의 가상머신을 실제 OS위에 만들어서
서로다른 OS 위에서 실행 시키더라도 동일하게 동작하도록 만든 소프트웨어이다.
즉, Java 애플리케이션이 동일하게 동작하도록 만들어주는 가상화된 실행 환경을 제공한다.
JVM(자바가상머신)은 동일하게 세팅하고, 동작하도록 해주는 아~주 편한 소프트웨어이다.
이런 느낌이다.
달빅VM을 사용하는 이유 또한 JVM과 동일하다.
안드로이드 생태계는 다양한 하드웨어 및 CPU 아키텍처를 지원해야한다.
안드로이드는 ARM, x86, MIPS 등 여러 프로세서 아키텍처를 사용하는 다양한 디바이스에서 실행된다.
JVM이건 달빅VM이건 가상머신을 사용하는 이유가 이것만 있는 것은 아니지만, 독립적인 실행 환경을 제공 하는것이 가장 큰 이유이다.
정리를 하자면, JVM 과 달빅VM의 공통점은?
플랫폼 독립적인 실행 환경을 제공한다는 것.
정확하게는 둘 다 바이트코드를 실행하기 위한 가상화된 환경 이다.
바이트코드(Bytecode) 란?
- 고수준 언어(예: Java, Kotlin 등)로 작성된 소스 코드를 가상 머신이 실행할 수 있도록 변환한 중간 코드이다.
- 바이트코드는 사람이 작성한 소스 코드와 CPU가 직접 실행하는 기계어(Machine Code) 사이의 중간 단계로, 주로 플랫폼 독립성을 제공하기 위해 사용된다.
- 0과 1로 이루어진 데이터이지만, CPU가 이해하는 기계어는 아니라, 가상머신(VM)이 이해하는 이진 데이터(바이너리파일) 이다.
- 그렇기 때문에 JVM이건, 달빅VM 이건 바이트코드만을 해석하고 실행하기 때문에 독립된 환경이라고 할 수 있다.
- 다만, 어느 OS 이건 간에 가상머신이 먼저 설치가 되어있어야 한다.
- 자바의 바이트코드는 .class 확장자를 가진다.
안드로이드 앱(.apk) 생성 과정
ⓐHelloWorld.java 소스코드를 javac.exe(자바컴파일러)로 컴파일하여 HelloWorld.class( 바이트코드 ) 변환
ⓑHelloWorld.class( 바이트코드 )를 DX(Android DX tool)변환 도구를 이용하여 HelloWorld.dex 파일로 변환
ⓒHelloWorld.dex 파일을 AAPT(리소스 처리 및 패키징 도구) 이용하여 HelloWorld.apk 파일 생성
좀 더 디테일 하게는
소스코드는 하나의 파일이 아니라, 여러 파일인 경우가 대부분이다.
javac 컴파일러로 컴파일을 할때, .java 파일 하나당 하나의 .class 바이트 코드로 컴파일이 된다.
.class 파일은 DX Tool 변환도구에 의해서 Dalvik 바이트코드 형식의 .dex 파일로 변환을 되는데, DX Tool 변환도구는 여러 .class 파일을 하나의 .dex 파일에 병합 한다.
AAPT 는 패키징 도구로써, .dex 파일 + resource files + AndroidManifest.xml + META-INF 을 패키징하여 하나의 .apk 파일로 생성한다.
resource files : 각종 리소스 파일들( UI 관련 XML, 이미지, 문자열, 애니메이션 등등), 보통 res/ 디렉토리에 포함된 리소스들이 패키징 된다.
AndroidManifest.xml : 앱 데이터(설정) 및 권한정보 파일, .apk에 포함될 때 바이너리 형식으로 변환됩니다.
META-INF 디렉토리: 디지털 서명 및 인증서 정보.( 선택 )
그외 Resources.arsc( 리소스 색인 파일 ), 네이티브 라이브러리 파일이 더 있지만, 딥하게 안들어가고 대략 이정도로 마무리 하려고 한다.
이렇게 생성 된 .apk 파일이 달빅VM(또는 ARM)에 의해 컴파일되어, 실행이 되는 것!!
달빅VM(또는 ART)가 .apk 파일 내 .dex 파일을 메모리에 로드하여 읽고, 실행한다
(실행 되는 과정은 나중에 따로 기술 하겠다. 내용이 살짝 방대..)
안드로이드 앱 디컴파일 과정
디컴파일이란?
[그림]
apk-tool :
JADX :
■정확한 디컴파일 과정 흐름
APK → DEX 파일 → Smali 파일 → Java(또는 Kotlin) 소스코드
일반적으로 APK 파일을 디컴파일할 때, 중간에 .class 파일이 직접적으로 생성되지 않습니다. 대신, .dex 파일에서 바로 Smali 파일로 변환되며, 이후 Java 또는 Kotlin 소스 코드로 역변환됩니다.
.smali 파일이 나오는 시점
앱이 DEX 파일(.dex)로 변환된 이후, 디컴파일 도구를 사용해 분석할 때 나타납니다.
즉, 개발 단계에서는 등장하지 않고, APK를 디컴파일할 때 생성됩니다.
■ 디컴파일 도구
Java 코드 복원: JADX, Dex2Jar + JD-GUI.
Smali 코드 및 리소스 복원: Apktool.
■디컴파일 과정
디컴파일 과정에서는 Smali 파일이 사용됩니다.
APK 파일을 디컴파일하여 소스 코드를 복원하려면 다음 단계를 거칩니다:
ⓐAPK 파일 추출
APK 파일의 압축을 해제하여 DEX 파일(.dex)과 리소스 파일을 추출합니다.
DEX → Smali 변환
ⓑDEX 파일을 **Smali 파일(.smali)**로 변환합니다.
Smali 파일은 Dalvik 바이트코드를 어셈블리 언어 형식으로 표현한 것입니다.
Smali → Java (선택적)
ⓒSmali 파일을 분석하거나, Java 소스 코드로 역컴파일할 수 있습니다.
도구: JADX, Dex2Jar + JD-GUI.