안드로이드 앱(apk) decompile 방법
1. apk 파일 형식 리버싱 툴
apk는 zip으로 압축된 파일이다.
압축을 풀면 여러 리소스 파일들과 실행 파일인 dex(Dalvik Exeutable)파일이 있다.
압출된 파일을 푼다고 볼 수 있는 것이 거이 없다.
AndroidManifest.xml이나 다른 스트링 리소스들은 깨진 것처럼 보인다.
dex(덱스) 파일 또한 사람이 읽을 수 없는 형식으로 되어있기 때문이다.
몇개의 툴을 이용하여 이 파일들을 decompile하면 사람이 읽을 수 있는 코드 형태로 변환이 가능하다.
APK 디컴파일하는 방법은 불편한 방법과 편한 방법이 있다.
다음 3개의 툴을 이용하면 단계적으로 apk를 decompile을 할 수 있다.
- apktool: apk의 리소스를 변환하는데 사용된다.
- dex2jar: dex를 jar로 변환하는데 사용된다.
- jd-cmd: jar를 java 코드로 변환하는데 사용된다.
외의 방법 외에도 명령어 한반에 apk를 쉽게 디컴파일해주는 툴도 있다.
jadx가 그런 툴 중에 하나이다.
- jadx: apk를 decompile하며, GUI와 Command line 툴 모두 제공한다.
가장 먼저 디바이스체서 apk를 추출하는 방법을 알아본다.
그 다음 다른 두개의 방식으로 apk를 decompile하는 방법에 알아보겠다.
1.1 디바이스 에서 APK 추출하는 방법.
분석할 apk가 준비되어있다면 이 단계를 건너뛰어도 된다.
apk 파일이 PlayStore에서만 다운로드 받을 수 있다면 추출을 해야한다.
먼저 PlayStore에서 분석하고 싶은 앱을 설치한다.
그리고 아래 명령어로 설치된 패키지 정보를 추출한다.
추출된 파일을 열어보면 설치된 패키지 정보들이 있다.
컴퓨터에 adb가 설치되어 있어야 한다.
$ adb shell dumpsys package p > package_info.txt
Play Books라는 앱을 다운받았다고 가정한다.
추출한 패키지 정보에서 내가 다운받은 앱의 패키지 이름을 찾아야 한다.
books로 검색해보면 설치한 앱의 패키지 이름은 com.google.android.apps.books 로 추정된다.
Package [com.google.android.apps.books] (7c73afd):
userId=10085
pkg=Package{9df90b0 com.google.android.apps.books}
codePath=/data/app/com.google.android.apps.books-TlsKiNze7ahFgAhZuk2T1Q==
.....
timeStamp=2019-00-00 20:40:13
firstInstallTime=2019-00-00 20:40:14
lastUpdateTime=2019-02-00 20:40:14
패키지 이름을 찾는 쉬운 방법은 없다.
앱 이름을 구글링하면 나올 수 있고, 앱을 실행하고 다른 로그로 확인할 수 있다.
또는 위처럼 설치 시간으로 찾아볼 수 있다.
위의 패키지 정보에서 codePath랄 apk 파일이 위취한 디렉토리이다.
그 디렉토리를 추출하면 그 안에 apk 파일이 있다.
다음 명령어를 사용하여 디렉토리를 추출한다.
$ adb pull /data/app/com.google.android.apps.books-TlsKiNze7ahFgAhZuk2T1Q==
이 명령어를 사용하면 단말의 특정 위치에 있는 파일을 PC로 가지고 올 수 있다.
아래와 같이 단말의 파일을 PC로 가져온걸 확인할 수 있다.
그 디렉토리 안에는 base.apk가 존재한다.
이 apk가 Play Books의 apk이다.
$ ls
'com.google.android.apps.books-TlsKiNze7ahFgAhZuk2T1Q=='
$ cd 'com.google.android.apps.books-TlsKiNze7ahFgAhZuk2T1Q=='/
$ ls
base.apk lib
1.2. APKTool, dex2jar, jd-cmd
Tool 설치 방법
위에서 소개한 Tool들은 Window/Linux 모두 사용가능하다.
여기서는 리눅스 기준으로 설명한다.
sudo apt install default-jre
sudo apt install openjdk-11-jre-headless
sudo apt install openjdk-8-jre-headless
다운로드
Apktool: https://ibotpeaches.github.io/Apktool/
Dex2Jar: https://sourceforge.net/p/dex2jar/wiki/Home/
Jd-cmd: https://github.com/kwart/jd-cmd/releases/tag/jd-cmd-0.9.2.Final
모두 최신 버전으로 다운로드 받는다.
apktools$ ls
apktool_2.3.4.jar dex2jar-2.0.zip jd-cli-0.9.2-dist.zip
압축해제.
매번 명령어를 입력하기 번거롭기 때문에 ~/.basshrc에 등록한다.
vi .bashrc
# tools
alias apktool='java -jar ~/apps/apktools/apktool_2.4.0.jar'
alias dex2jar='~/apps/apktools/dex2jar-2.0/d2j-dex2jar.sh'
alias jd-cli='java -jar ~/apps/apktools/jd-cli-0.9.2-dist/jd-cli.jar'
권한변경
$ chmod 755 ~/apps/apktools/dex2jar-2.0/*
path 확인
$ apktool
Apktool v2.3.4 - a tool for reengineering Android apk files
....
$ dex2jar
d2j-dex2jar -- convert dex to jar
....
$ jd-cli
jd-cli version 0.9.2 - Copyright (C) 2015 Josef Cacek
....
1.3. Apk decompile(소스 추출)
Apk가 있는 파일로 이동한다.
apktool을 이용하여 apk 파일을 decompile 한다.
apktoos은 dex를 java로 변환해주진 못하고 smail라는 파일까지 변환해 준다.
현 필요한 코드는 java 파일이기 때문에, apktool은 dex를 제외한 다른 파일을 변환하는데 사용한다.
dex는 dex2jar과 jd-cli를 사용하여 변환할 것이다.
apktool의 help를 보시면 명령어에 대한 자세한 내용이 나와있다.
여기서는 필요한 명령어만 소개한다.
아래 명려어는 소스파일(dex)은 제외하고 base.apk를 decompiled 디렉토리에 decompile하라는 의미이다.
$apktool d -s -o decompiled base.apk
decompiled 디렉토리가 생성이 되고, 이 디렉토리 내용을 보면 변환된 파일들이 있다.
여기서 리소스들은 모두 decompile되었기 때문에 읽을 수 있다.
소스파일들은 classes.dex에 있고 아직 읽을 수 없다.
$ ls
base.apk decompiled lib
$ cd decompiled/
$ ls
AndroidManifest.xml assets classes3.dex classes.dex res
apktool.yml classes2.dex classes4.dex original unknown
파일들을 보면 classes(숫자).dex라는 이름으로 dex가 4개나 있다.
이것은 앱이 Multi-dex의 형태이기 때문이다.
만약 Multi-dex가 아니라면 classes.dex로 표기된다.
Multi-dex이기 때문에 모든 소스를 보려면 4개의 dex를 모두 java로 변환해야 한다.
지금까지 apktool을 이용하여 apk의 리소스를 모두 읽을 수 있는 형태로 변환했다.
이제 dex만 변환하면 된다.
dex 파일은 아래와 같이 두개의 툴을 이용하여 java 파일로 변환해야 한다.
- dex2jar: dex 파일을 jar 파일로 변환한다.
- jd-cli: jar 파일을 java파일로 변환한다.
먼저 dex 파일을 jar파일로 변환한다.
다음 명령어를 이용하여 classes.dex를 변환한다.
변환된 결과는 입력파일이름-dex2jar.jar 형태로 생성된다.
변환할때 문제가 있었던 것은 classes-error.zip 파일로 리포팅 된다.
decompiled$ dex2jar classes.dex
dex2jar classes.dex -> ./classes-dex2jar.jar
Detail Error Information in File ./classes-error.zip
decompiled$ ls
AndroidManifest.xml assets classes3.dex classes.dex classes-error.zip res
apktool.yml classes2.dex classes4.dex classes-dex2jar.jar original unknown
그 외의 다른 dex 파일들도 decompile 한다.
decompiled$ dex2jar classes2.dex
decompiled$ dex2jar classes3.dex
decompiled$ dex2jar classes4.dex
decompiled$ ls | grep dex2jar
classes2-dex2jar.jar
classes3-dex2jar.jar
classes4-dex2jar.jar
classes-dex2jar.jar
다시 정리해보면 apk의 리소스들은 이미 apktool이 변환하였고, dex파일은 dox2jar를 이용하여 jar 파일로 변환했다.
이제 마지막으로 jar를 java 파일로 변환하면된다.
아래의 jd-cli 명령어는 classes-dex2jar.jar를 src 디렉토리에 java 파일로 decompile하라는 의미있다.
4개의 dex를 모두 src에 decompile한다.
decompile$ jd-cli classes-dex2jar.jar -od src
decompile$ jd-cli classes2-dex2jar.jar -od src
decompile$ jd-cli classes3-dex2jar.jar -od src
decompile$ jd-cli classes4-dex2jar.jar -od src
apk 리소스와 소소들은 decompile 되었다.
소스파일들은 java로 변환되어 사람이 읽을 수 있는 형태이다.
~/test/com.google.android.apps.books-TlsKiNze7ahFgAhZuk2T1Q==/decompiled/src$ tree -L 3
.....
├── com
│ ├── a
│ │ ├── a
│ │ ├── b
│ │ ├── c
│ │ └── d
│ ├── b
│ │ └── a
│ └── google
│ ├── android
│ ├── api
│ ├── common
│ ├── devtools
│ ├── firebase
│ ├── internal
│ ├── ocean
│ ├── play
│ ├── protobuf
.....
파일을 보시면 아시겠지만, 대부분의 앱들이 난독화(Proguard)를 하기 때문에 변수 이름이 간단한 문자로 되어있어 분석하기 어렵다.
2. jadx로 디컴파일하는 방법
jadx는 jadx-release에서 빌드된 파일을 다운로드 할 수 있다.
다운로드 : https://github.com/skylot/jadx/releases
jadx는 command line과 GUI 툴을 모두 제공한다.
툴을 다운받고 압출을 풉다.
bin 디렉토리를 보면 실행 파일이 있다.
jadx는 command line 툴이고, jadx-gui는 GUI 툴이다.
command line을 사용한다.
jadx-0.8.0$ ls
bin lib LICENSE NOTICE README.md
jadx-0.8.0$ ls bin
jadx jadx.bat jadx-gui jadx-gui.bat
path 등록
vi ~/.bashrc
#jadx
alias jadx='/home/user/test/jadx-0.8.0/bin/jadx'
path 확인
$ jadx -h
jadx - dex to java decompiler, version: 0.8.0
usage: jadx [options] <input file> (.apk, .dex, .jar or .class)
...
base.apk를 out 폴더에 decompile하라는 명령어.
$ jadx -d out base.apk
decompile이 끝나면 다음과 같이 파일들이 생성된다.
리소들은 resources 디렉토리에, 소스는 sources 디렉토리에 decompile 된다.
out$ tree -L 2
.
├── resources
│ ├── AndroidManifest.xml
│ ├── assets
│ └── res
└── sources
├── a
├── android
├── androidx
├── b
├── c
├── com
├── d
└── org
3. 결론
apk 파일을 추출하고 apk의 리소스와 소스를 사람이 볼수 있는 형태로 변환하는 방법을 확인했다.
decompile을 도와주는 오픈소스 툴들이 많기 때문에 자신에게 편한 툴을 사용할면 된다.
apk를 분석할 때 jadx가 매우 편하지만 jar로 제공되는 라이브러리를 분석하는 경우 jd-cli가 도움이 된다.
만약 리소스만 decompile하고 싶다면 apktool를 사용하여 빠르게 처리 할 수 있다.
대부분의 앱은 난독화가 되어있기 때문에 java로 변환한다고 해서 읽기 어려울 수 있다.
하지만 이 방법을 통해서 자신이 만든 앱이 난독화가 잘 되었는지, 다른 개발자로 부터 코트를 분석하기 어렵게 만들었는 지 확인할 수 있다.