Apk 디컴파일 툴 - apk dikeompail tul

apk를 압축 프로그램으로 열어보면 크게 AndroidManifest.xml, resources.arsc, classes.dex의 정보에 의해 앱이 실행되며, 때에 따라서는 Asset, lib 폴더도 존재하여 ndk를 이용한 Native Code나, Java Library, 그 밖의 리소스와 같은 부가적인 사용이 가능하다.

 

Apk 디컴파일 툴 - apk dikeompail tul

 


이 중, 가장 핵심적인 소스코드의 정보는 classes.dex 파일에 담겨져 있다.

이번 글에서는 apktool를 이용하여 apk를 디컴파일하고, 디컴파일된 Smali 코드와 실제 Java 코드를 간략하게 비교를 한다.
그리고 다시 apk로 리패키징하는 방법에 대해 간략히 설명한다.

 

apktool을 다운받는 URL은 다음과 같다.

APKTool : http://ibotpeaches.github.io/Apktool/

 

apktool은 Java기반으로 만들어졌으며, jar 형태로 배포하고 있다.

apktool를 이용하여 test.apk를 디컴파일을 수행하면 아래와 같은 절차를 따라 디컴파일이 수행된다.
명령어는 다음과 같다.

$ java -jar apktool_2.0.3.jar d 디컴파일할 앱.apk 


Apk 디컴파일 툴 - apk dikeompail tul

 


아래는 apk 파일을 apktool을 이용하여 디컴파일 후 생성되는 파일들이다. 이 중 smali 폴더가 생성된 것을 확인할 수 있는데 이는 classes.dex를 디스어셈블링한 결과의 파일들이며 Android 환경에서 Java 기반의 소스코드가 dalvik 가상 머신 환경에서 동작하기 위한 코드이며, 마치 형태가 C언어 기반의 Assembly와 비슷한 형태의 코드를 얻을 수 있다.

 

Apk 디컴파일 툴 - apk dikeompail tul

 


smali 폴더 내부로 들어가면 class 단위의 smali 코드로 된 파일들을 확인할 수 있으며, 이를 열어보면 다음과 같은 형태의 코드가 존재한다. C언어 기반의 Assembly 코드보다 가독성은 좋지만 기존의 Java 코드와는 동떨어진 코드 형태를 보여준다.

 

Apk 디컴파일 툴 - apk dikeompail tul

 


Smali 코드와 원본 Java 코드를 비교한 그림이 아래에 있다. 일반 Java 코드에 비해 Smali는 그 양이 많은 것을 알 수 있다. 또한, 이 Smali 코드를 이용하여 수정하는 것이 가능하며, 이는 기존의 원본 apk의 기능을 사용자의 목적에 맞게 조작이 가능하다는 것을 의미한다.

 

Apk 디컴파일 툴 - apk dikeompail tul



리패키징 방법은 아래와 같다.

 $ java -jar apktool_2.0.3.jar b 디컴파일한 apk 폴더 Path -o 리패키징할 파일 이름.apk

 

Apk 디컴파일 툴 - apk dikeompail tul

 

리패키징이 완료되고 파일이 생성되었지만, 해당 파일을 서명없이 바로 설치를 하게 되면, 다음과 같은 에러 메시지와 함께 패키지 설치가 실패된다.

 

Apk 디컴파일 툴 - apk dikeompail tul

 

signapk.jar 를 이용하여 리패키징 앱을 Test키로 서명하자. signapk.jar는 아래의 URL에서 다운 받을 수 있다.
signapk : https://github.com/appium/sign

 

서명 방법은 아래와 같다.

 - java -jar signapk.jar 서명키.pem 서명키.pk8 리패키징.apk 서명된 리패키징 이름.apk

 

Apk 디컴파일 툴 - apk dikeompail tul

 


다음과 같이 서명 절차를 거치면 해당 앱이 정상적으로 기기에 설치되며, 앱 실행시 문제 없이 동작하는 것을 확인할 수 있다.

 

Apk 디컴파일 툴 - apk dikeompail tul

 


마지막으로 원본 앱과 Test키를 이용한 리패키징 앱에 대한 서명을 비교하여 서명 값이 변경된 것을 확인할 수 있는 방법을 소개한다.
해당 파일은 설치된 jdk의 bin 폴더에 존재하며, 앱의 서명 정보를 보는 명령어는 아래와 같다.

$ jarsigner -verbose -verify -certs 앱.apk

 

  - 리패키징 전, 서명 값

 

Apk 디컴파일 툴 - apk dikeompail tul


 

  - 리패키징 후, 서명 값

 

Apk 디컴파일 툴 - apk dikeompail tul

 


원본의 서명 키를 원본 앱을 만든 개발자에게서 구하지 않는 이상 동일한 키를 이용하여 리패키징 된 앱을 서명할 수는 없을 것이며, 따라서 원본 앱과 리패키징 앱을 구분 시, 다음과 같이 서명 값을 확인해서 비교하는 방법으로도 앱의 리패키지 여부를 알 수 있는 방법이 된다.

안드로이드와 같이 VM(Virtual Machine)환경에서 동작되는 프로그램들은 디컴파일(Decompile)이 비교적 용이하다는 특징이있다. 소스코드를 컴파일 할 때, C/C++ 과 같이 바로 기계어로 번역되는게 아니라, VM이 이해할 수 있는 바이트코드(Bytecode)로 컴파일이 되고, VM에서 실행될 때 내부에 있는 컴파일러로 한번 더 컴파일해서 기계어로 번역하게된다. 즉, VM내부에서 한번 더 컴파일이 되어야하기 때문에 소스코드에 있는 각종 심볼들이 바이트코드에 담기게 되고, 이를 활용하면 원시코드를 쉽게 유추할 수 있게된다. 

 

자바를 이용해서 안드로이드 앱을 개발할 경우, 컴파일하면 *.java -> *.class -> *.dex  순으로 컴파일된다. 본래 class 파일은 JVM(Java Virtual Machine)에서 실행하기 위한 바이트코드이지만 이대로 안드로이드에서 실행할 순 없기 때문에, 안드로이드 VM(Dalvik 혹은 ART)을 위한 dex 바이트코드로 변환하는 과정이 필요하다. 그래서 안드로이드 앱을 디컴파일하기 위해서는 *.dex 파일을 *.class 파일로 변환해주고, java로 디컴파일하면 원본 소스가 어느 정도 복원된다. 이 때 복원된 소스는 바이트코드를 보고 일종의 유추를 한 것이기 때문에, 디컴파일러마다 소스코드가 다르게 번역될 수 있고, 이렇게 복원된 소스를 수정해서 다시 재 컴파일하기에는 무리가 있다. 

 

앱 디컴파일에 사용되는 툴은 정말 다양하며, 무료로 제공되는 툴 뿐만 아니라, IDA 처럼 정척 & 동적 분석이 모두가능하며, 많은 기능을 제공해주는 JEB와 같은 프로그램도 존재한다. JEB가 정말 강력한 툴이지만, 어마어마한 라이센스 비용을 지불해야하기 때문에, 해당 포스트에서는 무료로 제공되는 툴들을 엮어서 쉽게 앱 디컴파일을 할 수 있도록 해주는 ApkStudio라는 프로그램에 대해 소개한다.

 

1. 설치(Installation)

다운로드 링크 : https://github.com/vaibhavpandeyvpz/apkstudio/releases

 

vaibhavpandeyvpz/apkstudio

Open-source, cross platform Qt based IDE for reverse-engineering Android application packages. - vaibhavpandeyvpz/apkstudio

github.com

해당 링크로 들어가서 컴퓨터에 맞는 버전을 다운받고, 압축을 풀면된다.

 

Apk 디컴파일 툴 - apk dikeompail tul
[그림 1] apkstudio 설정

 

처음 실행시키면 [그림 1]과 같이 초기설정을 해줘야한다. 앞에서 설명했던 것 처럼, ApkStudio는 여러 무료 툴들을 엮어주는 프로그램이기 때문에 해당 툴들을 다운받고, 경로 지정을 해줘야한다. 오른쪽에 "Get it here!"을 클릭하면, 툴 별로 다운로드 할 수 있는 페이지로 연결되며, [그림 1]처럼 해당 툴의 실행파일을 연결해주면 된다. Java의 경우, 설치한 다음 환경변수로 JAVA_HOME 을 JDK가 설치된 경로로 설정해줘야 Jadx가 정상적으로 실행된다. 

 

Apk 디컴파일 툴 - apk dikeompail tul
[그림 2] console

보면 알겠지만, 각자 역할이 다른 툴들을 ApkStudio가 클릭 한번으로 명령어를 연속적으로 실행시켜서 사용자가 번거롭게, 각 툴들을 따로 실행하지 않아도 되게끔 해준다. 그렇게 대단한건 아니지만, 클릭 한번으로 명령어를 타이핑해야 하는 귀찮음을 해소해주기에 상당히 편리하다. 혹여 에러가 발생했다면 아래의 [그림 2]와 같이 ApkStudio 아래에 있는 Console 창을 보면, 어떤 명령어에서 어떤 에러가 발생했는지 각 툴에서 출력을 해주기 때문에 참고하면 된다. 

 

2. 앱 디컴파일(Application Decompile)

 

Apk 디컴파일 툴 - apk dikeompail tul
[그림 3] Apk Open

설정이 완료되었다면, 아래 [그림 3]의 왼쪽에 보이는 안드로이드 아이콘을 클릭하면 apk를 열 수 있다. 

 

Apk 디컴파일 툴 - apk dikeompail tul
[그림 4] decompile options

apk 파일을 선택하고 나면 [그림 4]와 같이 디컴파일 옵션을 선택할 수 있다. 아무것도 체크를 하지 않을 경우, *.dex 파일까지만 추출이 된다. 원하는 옵션을 선택한 뒤, Decompile 버튼을 클릭하면 된다.

 

Apk 디컴파일 툴 - apk dikeompail tul
[그림 5] decompile complete

디컴파일이 완료되면, [그림 5]와 같이 프로젝트가 생성된다. smali는 dex의 바이트코드를 사람이 읽을 수 있도록 변환해둔 코드로, 어셈블리어와 형태가 유사하다. bytecode와 1:1로 mapping이 되어있기 때문에, 만약 코드를 수정해서 리패키징 하고싶다면, 이 smali를 수정하면 된다.

smali bytecode : https://source.android.com/devices/tech/dalvik/dalvik-bytecode#instructions

 

Dalvik 바이트 코드  |  Android Open Source Project

resources는 *.xml 파일들을 말하고, Decompile java에 체크를 하면, *.dex -> *.java로 디컴파일까지 해서 sources 디렉토리에 저장한다. 앞에서 말했듯이, 디컴파일러가 일종의 유추를 한 것이기 때문에, 디컴파일러마다 다른 결과가 나오기도 한다. 따라서 해당 코드를 수정하는 것엔 무리가 있고, 분석용으로만 사용해야 한다. 

 

3. 앱 리패키징(Application Repackaging)

Apk 디컴파일 툴 - apk dikeompail tul
[그림 6] build

디컴파일한 앱을 수정하고, 다시 리패키징해서 apk 파일로 만들고 싶을 경우, [그림 6]과 같이 Project->Build 를 클릭하면 된다. 

 

Apk 디컴파일 툴 - apk dikeompail tul
[그림 7] build complete

문제없이 빌드가 됐으면, 같은 디렉토리에 dist라는 디렉토리가 생성되고 거기에 base.apk 라는 파일이 생성된다. 이렇게 apk가 만들어졌지만, 스마트폰에 설치하기 위해서는 앱 사이닝(Siging)을 해줘야 한다. 

 

Apk 디컴파일 툴 - apk dikeompail tul
[그림 9] Sign

base.apk 파일을 마우스로 클릭한 상태에서, Project->Sign/Export 를 클릭하고, 빈 칸을 채워주면 된다. 사전에 저장해둔 Keystore가 있다면 Browse 버튼을 눌러서 불러오면 되고, 없다면 그냥 비워두고, 아래 빈칸들을 채워주면 된다. 해당 앱을 배포할 목적이라면 해당 내용이 굉장히 중요하겠지만, 단순히 분석하기 위해서는 대충 적당한 것들로 채워두면 된다. 그리고 Sign 버튼을 누르면 최종적으로 apk 파일에 서명이 된다. 

 

이렇게 만들어진 apk를 스마트폰에 설치하는 것 역시 ApkStudio에서 되는데, Project->Install 을 클릭해주면 현재 컴퓨터에 연결되어 있는 기기에 adb 명령어를 이용해서 자동으로 설치가 된다. 하지만, 기기가 2대 이상이거나 에뮬레이터가 같이 설치되어 있을 경우 잘 동작하지 않기 때문에, 그럴 경우 따로 명령프롬프트로 adb 명령어를 입력해서 수동으로 설치해주면 된다.