HOME > android > tips

안드로이드 앱(apk)을 decompile하는 다양한 방법

JSFollow08 Feb 2019

Apk는 zip으로 압축된 파일입니다. 압축을 풀면 여러 리소스 파일들과 실행 파일인 dex(Dalvik Executable)파일이 있습니다. 하지만 압축을 푼다고 볼 수 있는 것이 거의 없습니다. 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하는 방법에 대해서 모두 알아보겠습니다.

디바이스에서 Apk 추출하는 방법

분석할 apk가 준비되어있다면 이 단계를 건너뛰어도 됩니다. 하지만 PlayStore에서만 받을 수 있는 apk라면 여기서 apk 추출 방법을 알려드립니다.

먼저 PlayStore에서 분석하고 싶은 앱을 설치합니다. 그리고 아래 명령어로 설치된 패키지 정보를 추출합니다. 추출된 파일을 열어보면 설치된 패키지 정보들이 있습니다.(PC에 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-02-08 20:40:13
  firstInstallTime=2019-02-08 20:40:14
  lastUpdateTime=2019-02-08 20:40:14

패키지 이름을 찾는 쉬운 방법은 없습니다. 앱 이름을 구글링하면 나올 수 있고, 앱을 실행하고 다른 로그로 확인할 수도 있습니다. 또는 위처럼 설치 시간으로 찾아볼 수도 있겠네요.

위의 패키지 정보에서 codePath는 apk파일이 위치한 폴더 경로입니다. 저 폴더를 추출하면 그 안에 apk가 존재합니다. 다음 명령어를 사용하여 폴더를 추출합니다.

$ adb pull /data/app/com.google.android.apps.books-TlsKiNze7ahFgAhZuk2T1Q==

이 명령어를 사용하면 단말의 특정 위치에 있는 파일을 PC로 가져올 수 있습니다. 아래와 같이 단말의 파일을 PC로 가져왔습니다. 그리고 폴더 안에는 base.apk라는 이름으로 apk가 존재합니다. 이 apk가 Play Books의 apk입니다.

$ ls
'com.google.android.apps.books-TlsKiNze7ahFgAhZuk2T1Q=='
$ cd 'com.google.android.apps.books-TlsKiNze7ahFgAhZuk2T1Q=='/
$ ls
base.apk  lib

Apktool, dex2jar, jd-cmd로 디컴파일하는 방법

Tool 설치 방법

위에서 소개한 Tool들은 Window/Linux 모두 사용가능합니다. 저는 Linux 기준으로 설명하겠습니다.

Apktool은 Apktool에서 버전별로 다운받을 수 있습니다. dex2jar은 Dex2Jar에서 컴파일된 파일을 받을 수 있습니다. 그리고 jd-cmd는 Jd-cmd에서 컴파일된 파일을 받을 수 있습니다. 모두 최신버전으로 받으시면 됩니다.

위의 툴들을 폴더 하나에 모두 다운받아놨습니다.

apktools$ ls
apktool_2.3.4.jar  dex2jar-2.0.zip  jd-cli-0.9.2-dist.zip

압축 파일은 모두 풀고, zip파일은 삭제하였습니다. 모든 작업을 끝낸 저의 파일 상태는 이렇습니다.

$ ls
apktool_2.3.4.jar  dex2jar-2.0  jd-cli-0.9.2-dist

위의 툴 다운로드 사이트에서 사용방법을 읽어보시면, 이 파일들은 jar 또는 쉘스크립트입니다. 매번 명령어를 입력하기 번거롭기 때문에 ~/.bashrc에 아래처럼 명령어를 alias로 등록해두었습니다. (Windows는 d2j-dex2jar.bat 파일을 사용해야 할 것 같습니다)

# tools
alias apktool='java -jar ~/apps/apktools/apktool_2.3.4.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'

이제 설치는 모두 마쳤습니다. 명령어를 쳐보면 실행이 잘 됩니다.

$ 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
....

만약에 명령어를 쉘에서 실행했을 때, 실행할 수 없다는 에러가 출력되면 chmod로 스크립트파일을 실행가능한 파일로 만들어주시면 됩니다.

$ chmod 755 ~/apps/apktools/dex2jar-2.0/*

Apk decompile (소스 추출)

Apk가 있는 파일로 이동합니다. 먼저 Apktool을 이용하여 apk파일을 decompile하겠습니다. Apktool은 dex를 java로 변환해주진 못하고 smali라는 파일까지 변환해줄 수 있습니다. 저희가 필요한 것은 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

이렇게 dex를 모두 jar파일로 변환하였습니다. 총 4개의 jar파일이 생성되었습니다.

decompiled$ ls | grep dex2jar
classes2-dex2jar.jar
classes3-dex2jar.jar
classes4-dex2jar.jar
classes-dex2jar.jar

다시 정리해보면 apk의 리소스들은 이미 apktool이 변환하였고, dex파일은 dex2jar를 이용하여 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)를 하기 때문에 변수 이름이 간단한 문자로 되어있어 분석하기엔 어렵습니다.

Jadx로 디컴파일하는 방법

Jadx는 Jadx-release에서 빌드된 파일을 다운받을 수 있습니다. Jadx는 command line과 GUI 툴을 모두 제공합니다.

툴을 다운받고 압축을 풉니다. bin 폴더를 보면 실행 파일이 있습니다. jadx는 command line 툴이고, jadx-gui는 GUI 툴입니다. 저는 command line을 사용하겠습니다. (Windows 사용자의 경우 jadx-gui.bat을 사용해야 합니다)

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

위와 마찬가지로 ~/.bashrc에 alias로 jadx를 등록하였습니다.

#jadx
alias jadx='/home/user/test/jadx-0.8.0/bin/jadx'

jadx를 실행해보면 설치가 잘 된 것을 확인할 수 있습니다.

$ jadx -h
jadx - dex to java decompiler, version: 0.8.0
usage: jadx [options] <input file> (.apk, .dex, .jar or .class)
...

위에서는 번거롭게 여러번 명령어를 입력해주었지만, jadx는 간단합니다. 아래 명령어는 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

정리

이글에서 우리는 단말에서 apk파일을 추출하고 apk의 리소스와 소스를 사람이 볼 수 있는 형태로 변환하는 방법을 알아보았습니다. decompile을 도와주는 오픈소스 툴들이 많기 때문에 자신에게 편한 툴을 사용하면 됩니다. apk를 분석할 때 Jadx가 매우 편하지만 Jar로 제공되는 라이브러리를 분석하는 경우 jd-cli가 도움이 될 수 있습니다. 또는, 만약 리소스만 decompile하고 싶다면 Apktool를 사용하여 빠르게 처리할 수도 있습니다.

대부분의 앱은 난독화가 되어있기 때문에 java로 변환한다고 해서 읽기 어려울 수 있습니다. 하지만 이 방법을 통해서 자신이 만든 앱이 난독화가 잘 되었는지, 다른 개발자로부터 코드를 분석하기 어렵게 만들었는지 확인할 수 있습니다.

참고