APK 소스코드 분석하기
스토어에 등록된 다양한 앱들을 보며, "와! 이 앱은 코드를 어떻게 구현했을까?" 궁금했던적이 있었나요?
필자의 경우엔 "앱 소스코드", "앱 디컴파일" 등 키워드로 구글 검색을 해가며 하나씩 호기심을 해결했고, 마침내 iOS 앱은 IPA (Ios app store PAckage) [1] 를 맥북에 다운로드 해서 파인더로 패키지 내용 보기를 하면 사용된 아이콘, 이미지 등의 리소스 정도는 확인이 가능하고, Android 앱은 툴을 사용해 APK (Android app PacKage) [2] 추출 및 디컴파일 방식을 통해 대부분은 소스코드 까지 살펴볼 수 있다는걸 알게 되었습니다.
여러 시행착오를 겪으며 필자는 편의를 도모코자 딱 필요한 기능만으로 구성된 개인 툴을 만들어 사용하고 있는데, 최근 이를 "캡틴 APK" 란 앱으로 플레이 스토어에 배포했고, 개발자 사회에 콘트리뷰션? 하고자 소스코드 공개 (GitHub) 및 "APK 소스코드 분석하기", "캡틴 APK 소스코드 톺아보기", 총 2편의 글을 연재하여 이러한 주제에 관심있는 개발자, 특히 Android 앱 개발자에게 짧은 지식으로나마 도움을 드리고자 합니다.
연재글 중 첫번째로 이번 글에서는 Android 앱, 즉 APK 에 포함된 소스코드를 분석하기 위한 작업 과정 및 관련 툴에 대한 소개를 주제로 다루겠습니다.
APK 란?
APK 는 Android app PacKage 의 약어로 Android 가상머신 (a.k.a. Dalvik) [3] 에서 실행되는 소프트웨어 배포용 패키지 파일이며 ".apk" 확장자를 사용합니다.
개발자가 구현한 앱을 APK 로 빌드하여 플레이 스토어에 배포하고, 사용자가 이를 다운로드 받으면 스마트폰의 "system/*" 과 같은 시스템 영역에 해당 앱의 APK 가 설치되는데, 이 경로는 스마트폰에서 기본 제공되는 파일 탐색기로는 접근 할 수 없으며, 사용자는 단지 바탕화면에 링크된 아이콘을 터치하여 실행되는 앱에서 제공하는 기능만을 사용하게 됩니다.
APK 는 기존부터 사용되고 있는 Java 소프트웨어 배포용 패키지인 JAR (Java ARchive) [4] 에 기반한 ZIP [5] 형태의 압축 파일인데, 그 내부는 "AndroidManifest.xml", "classes.dex" 및 "res/*", "assets/*" 등으로 구성됩니다.
여기서 "classes.dex" 이 개발자가 구현한 Java 코드를 컴파일하면 생성되는 "*.class" 및 사용된 라이브러리를 Android 가상머신에서 실행되는 형태로 재구성한 파일이고, ".dex" 확장자를 사용하는 일명 DEX [6] 은 Dalvik EXecutable 의 약어입니다.
Dalvik 이란 명칭은 Android 가상머신을 개발한 댄 본스타인이란 개발자가 자신의 고향인 아이슬란드 달비크란 어촌 마을에서 따와 이름 지었다고 합니다. 네이밍이 마치 제주 에일, 대동강 맥주 그리고 필자가 사랑하는 강릉의 하슬라 IPA [7] 같은 느낌!
APK 소스코드 보는 방법
APK 에 포함된 소스코드를 보기 위해서 보통은 다음과 같이 "APK 추출하기", "JAR 변환하기", "JAR 디컴파일" 순으로 3단계 작업을 진행합니다.
Step #1 : APK 추출하기
"이 앱은 코드를 어떻게 구현했을까?" 이런 호기심 해결의 시작이 바로 해당 앱의 APK 를 직접 다뤄 볼 수 있는 경로에 추출하는 작업입니다.
스마트폰을 USB 로 연결해 내장 스토리지를 구석구석 탐색해봐도 APK 가 얻어 걸리듯이 나오지는 않기에 별도의 툴이 필요한데, 필자의 경우 직접 개인 툴을 만들어 사용하기 전까지는, APK 추출은 "APK Extractor" [8], "AndroidManifest.xml" 및 사용된 리소스를 분석하기 위해서는 "APK Parser" [9] 를 주로 사용했고, 이번 글에서는 필자가 개발한 "캡틴 APK" [10] 를 활용해 보겠습니다.
"캡틴 APK" 설치 후 실행하면 다음과 같이 스마트폰에 설치 되어 있는 앱 전체 목록을 볼 수 있습니다.
"captain" 등 으로 직접 키 입력 또는 편의상 음성 검색하여 SAVE 합니다.
SAVE 완료 후, 스마트폰의 파일 탐색기로 다운로드 경로를 확인하면 "app.apk", "app.dex", "meta.zip" 3개의 파일이 생성되어 있고, 이는 각각 APK, DEX 및 개발시 사용된 리소스를 ZIP 으로 압축한 파일입니다.
스마트폰을 USB 로 연결 후, 생성된 파일을 맥북의 Android 파일 전송 [11] 앱을 사용해 작업 경로인 "~/decompile" 쪽으로 복사합니다.
Step #2 : JAR 변환하기
이미 위에서 언급한 대로, 개발자가 구현한 Java 코드 및 사용한 라이브러리는 APK 로 빌드시 컴파일 되어 Android 가상머신에서 실행되는 DEX "classes.dex" 으로 저장되는데, DEX 을 직접 디컴파일 하기보다는, 이를 Java 디컴파일러로 열어보기 위해서 JAR 로 변환하는 작업을 진행합니다.
필자의 경우엔 APK 또는 DEX 을 JAR 로 변환하기 위해 "DEX2JAR" [12] 를 사용했고 사용 방법은 다음과 같습니다.
APK 를 JAR 로 변환하는 방법
1
dex2jar -f -o app.jar app.apk
DEX 을 JAR 로 변환하는 방법
1
dex2jar -f -o app.jar app.dex
실행을 위해 먼저 DEX2JAR (dex2jar-2.0.zip) 을 다운로드 받아, ZIP 압축을 풀어 "~/decompile" 밑으로 옮기고, 해당 경로에서 다음 명령을 실행합니다. (캡틴 APK 2.5.0 현재 버전 기준)
1
sh dex2jar-2.0/d2j-dex2jar.sh -f -o com.cafewill.apk_2.5.0_Captain_APK.jar com.cafewill.apk_2.5.0_Captain_APK.apk
Permission denied 오류가 발생하면 chmod u+x dex2jar-2.0/d2j_invoke.sh 등으로 필요한 권한을 설정하고, 명령을 재실행후 JAR 가 변환되어 생성 되었는지 여부를 확인합니다.
Step #3 : JAR 디컴파일
이제 마지막 단계로 변환된 JAR 을 Java 디컴파일러 [13] 로 열어 분석하는 작업을 진행합니다.
Java 는 비교적 디컴파일이 용이한 개발 언어라서인지 다수의 Java 디컴파일러가 존제하는데, 필자는 맥북에서도 훌륭하게 실행되고 꾸준하게 버전 관리도 잘 되고 있는 JD-GUI [14] 를 사용합니다.
JD-GUI (jd-gui-osx-1.6.5.tar) 를 다운로드 받아, TAR [15] 묶음을 풀어 "~/decompile" 밑에 옮기고, JD-GUI 를 실행합니다.
필자의 경우 맥북용 "~/decompile/jd-gui-osx-1.6.5/JD-GUI" 를 실행하여 변환된 JAR 를 열어 보겠습니다.
좌측 트리뷰에서 MainActivity.class 등을 선택하면, 우측 코드뷰쪽에는 개발자가 구현한 Java 소스코드 형태 그대로 볼 수 있거나, 일부는 Java Bytecode [16] 로 보여질 수도 있습니다. 또한 개발자가 APK 빌드시 난독화 (minifyEnabled) 설정을 했다면, 클래스, 메소드 및 변수명은 "a, a.a.a, b, c" 등으로 처리된 형태로 보여지게 됩니다.
이런 작업이 처음이라면 익숙하지 않을 수도 있겠지만, 소프트웨어 리버스 엔지니어링 [17] 하는 느낌으로 "meta.zip" 에 포함된 "AndroidManifest.xml" 에서 퍼미션 설정과 엑티비티, 서비스 및 리시버의 구성을 파악하고, "/res/layout/*.xml" 의 UI 레이아웃도 살펴보고, JAR 를 디컴파일러로 열어 소스코드를 리뷰하며 직접 유사한 코드를 구현해서 APK 빌드후, 다시 JAR 로 변환해서 디컴파일러로 열어 비교 분석하다보면, 해당 앱의 소스코드가 어떤 방식으로 구현 되었는지 감을 잡을 수 있을 겁니다. :-)
필자 개인적인 의견을 덧붙이자면 다양한 Java 디컴파일러로 자신이 구현한 Android 앱뿐만 아니라 Java 코드를 직접 디컴파일해서 들여다보면 Self 코드 리뷰하는 느낌도 나고 재밌습니다!
소스코드 분석을 위한 소소한 팁!
소스코드를 분석 할 때 사용된 라이브러리, import 로 추가된 패키지나 클래스, 사용된 메소드에 대한 구글 검색시 site:github.com 또는 site:stackoverflow.com 등 주요 개발자 커뮤니티나 각자 신뢰하는 서비스를 기준으로 필터해서 검색하면 대부분은 많은 도움을 얻을 수 있습니다.
(아이폰을 만들어 판매하는 모컴퍼니가 제공하는 해당 플랫폼 가이드 및 개발자 커뮤니티의 경우, 구글에서 site:[모컴퍼니] 로 필터해서 나오는 검색 결과의 퀄리티가 훨씬 더 좋기도..)
그냥 검색해서 나오는 링크를 타고 들어가서 보다보면 일부 블로그나 개인 미디어의 경우 퍼온 콘텐츠로 도배해 놓거나, 아님 말고식의 검증되지 않은 코드나 오래된 스니펫만 적어 놓는 경우가 많아서 시간을 낭비하거나 혼란만 가중시키는 경험을 하게 될 수도 있을 겁니다.
글을 마치며
이번 글에서는 Android 앱, 즉 APK 에 포함된 소스코드를 분석하기 위한 일련의 작업 과정과 사용하는 툴을 살펴봤고, 다음에 연재되는 글에서는 필자가 개발한 앱, "캡틴 APK" 의 주요 비즈니스 로직 및 기술적인 이슈를 톺아보도록 하겠습니다.
각주 및 참고 자료
1. IPA, iOS App Store Package
https://en.wikipedia.org/wiki/.ipa
(글을 쓰며 Apple 기술지원쪽에 다시 확인해 본 바로는 앱 보안강화의 이유로 iOS, iTunes, MacOS 등 최근 버전에서는 IPA 추출이 보다 어렵게 되었고, 다음에 기회가 된다면 포스팅 주제로 다뤄 보겠습니다)
2. APK, Android App Package
https://en.wikipedia.org/wiki/Android_application_package
(APK 에서 추출된 "res/*" 리소스를 살펴보면 개발자가 추가한 것외, 빌드시 추가되는 기본 리소스가 상당히 많습니다. 최근에는 최적화 등의 이유로 AAB, Android App Bundle 방식으로 배포를 권장하는 추세이니 아래 링크도 함께 참고 바랍니다)
https://developer.android.com/platform/technology/app-bundle
https://support.google.com/googleplay/android-developer/answer/9006925
3. Dalvik
https://en.wikipedia.org/wiki/Dalvik_(software)
https://source.android.com/devices/tech/dalvik
4. JAR, Java Archive
https://en.wikipedia.org/wiki/JAR_(file_format)
5. ZIP
https://en.wikipedia.org/wiki/Zip_(file_format)
6. DEX, Dalvik Executable
https://en.wikipedia.org/wiki/Dalvik_(software)
https://source.android.com/devices/tech/dalvik/dex-format
7. IPA, India Pale Ale
https://en.wikipedia.org/wiki/India_pale_ale
8. APK Extractor
https://play.google.com/store/apps/details?id=com.ext.ui
9. APK Parser
https://play.google.com/store/apps/details?id=com.gmail.heagoo.apkeditor.parser
10. Captain APK
https://github.com/cafewill/captain-apk
11. Android File Transfer
https://www.android.com/filetransfer
12. DEX2JAR
https://sourceforge.net/projects/dex2jar
13. Java Decompiler
https://en.wikipedia.org/wiki/Java_Decompiler
14. JD-GUI
https://github.com/java-decompiler/jd-gui
https://github.com/java-decompiler/jd-gui/releases
15. TAR, Tape Archive
https://en.wikipedia.org/wiki/Tar_(computing)
16. Java Bytecode
https://en.wikipedia.org/wiki/Java_bytecode
17. (Software) Reverse Engineering