잘 짜여진 실제 앱 해부해보기: 안드로이드 리버스 엔지니어링

개발자들은 많은 시간을 들여 앱을 개발하고 있죠. 그렇다면 마지막으로 앱 하나를 분리해본 적은 언제인가요? 컴파일된 애플리케이션의 내부를 보는 과정을 간소화할 수 있다면, 업무에 적용하고 의문점을 해결할 수 있는 중요한 교훈을 더욱 잘 얻을 수 있을 겁니다. 이 강연은 간단한 실제 예제를 통해 안드로이드에 대한 리버스 엔지니어링 툴 세트를 사용해서 최대한 실질적인 이익을 얻을 방법을 보여줍니다. 어떤 것을 해부해보면 배울 수 있는 것이 정말 많습니다!


소개 (0:00)

저는 Jon Reeve이고 이 강연은 “안드로이드 리버스 엔지니어링은 해커만을 위한 것이 아닙니다”라는 주제입니다. 포토 스톡을 제공하는 사이트에 가서 해킹을 검색하면 악성 또는 멀웨어 연구에 대한 이미지가 나오죠. 하지만 제가 말하고자 하는 내용은 이런 이미지의 해커를 위한 것이 아닙니다.

왜 앱을 해부해봐야 할까요? (1:19)

세계에서 가장 큰 단일 머신인 유럽물리입자연구소의 강입자 가속기(LHC)를 생각해 보세요. 빅뱅을 재현하는 실험장치인 이 기계는 입자를 분리해서 내부를 볼 수 있게 합니다. 그것이 세탁기이든 최첨단 기술이든 분리해보는 것에서 많은 것을 얻을 수 있습니다. 애플리케이션도 마찬가지입니다. 소스 코드를 보기 위해서 꼭 소스 코드 자체가 필요하지는 않습니다.

예를 들어 왜 어떤 앱이 특정 권한을 요구하는지 궁금할 수 있습니다. 아마도 카메라로 희한한 일을 하거나 연락처를 모두 읽어서 어딘가로 보낼지도 모릅니다. SMS를 멋대로 보내서 비용이 나가게 할 수도 있습니다. 하지만 그 이유를 파악할 수는 없죠.

개발한 앱에 크래시가 난 경우를 생각해 볼까요? 우리 앱 때문일지도 모르지만 분석 도구나 광고 네트워크 같은 서드 파티 라이브러리 때문일 수도 있는데 이런 경우 소스가 없습니다. 혹은 크래시하는 앱이 직접 만든 앱이 아닐지라도, 개발자로서 새 안드로이드 OS 릴리즈를 사용하다가 맘에 드는 앱이 죽어버린다면 좀 더 많은 정보를 제작사에 줘서 좀 더 빠르게 버그를 픽스하도록 돕고 싶은 생각이 들 수도 있겠죠. 아니면 그 앱의 멋진 기능을 좀 더 들여다 보고 싶을 수도 있습니다.

프리랜서이자 전임 개발자로서 프로젝트를 참여할 때 다른 앱을 보고 비슷한 것을 만들고 싶다고 요청하는 경우가 많았습니다. 물론 앱을 카피할 생각은 없겠지만, 앱이 구성된 내용은 볼 가치가 큽니다.

좋은 시각적 효과가 있을 수도 있습니다. 어쩌면 가능하리라 생각하지도 못한 것을 해냈을지도 모르죠. 예를 들어 삼성 기기에서만 작동하는 카메라 API를 만들었을 수도 있습니다. 아니면 생각해왔던 그대로를 구현했을 수도 있습니다. 관련 라이브러리가 참 많은데, 가장 유명한 것은 무엇일까요? 사람들은 어떤 것을 사용하고 있을까요?

유명한 애플리케이션을 실제로 볼 수 있습니다. 앱을 열고 패키지 구조를 파악하고 어떤 라이브러리를 사용하는지 확인할 수 있죠. 다른 이들의 앱을 리버스 엔지니어링해서 훔치라는 뜻은 아닙니다. 하지만 직접 모든 것을 처음부터 다시 만들어내는 것보다 다른 사람들이 하고 있는 일을 참고하는 것은 유익할 수 있습니다.

APK 얻기 (4:19)

처음으로 해야할 일은 Android Package Kit, 즉 APK를 얻는 일입니다.

$ adb shell pm list packages -f -3

이 명렁어는 기기의 모든 패키지를 간단히 나열해 줍니다. -f는 APK 파일의 위치를 보여주는 파일 이름이고, -3은 서드 파티를 의미합니다.

$ adb pull "$(adb shell pm path $1 | cut -d : -f 2 | tr -d ‘\015’)"

ADB 뉴라인 때문에 불편하고 해석이 필요하긴 하지만, 앞서 말한 명령어 대신 위 명령어를 사용하면 특정 애플리케이션의 APK를 가져올 수 있습니다. Bash Script 사용에 유용합니다.

다른 곳에서 APK를 가져올 수도 있습니다. 단, APK를 호스팅하는 사이트처럼 인터넷에서 받은 APK는 실제로 무엇이 설치될지 알 수가 없습니다. 구글 플레이 스토어와 같이 확실한 곳을 통하는 것이 좋습니다. APK가 사인 됐는지, 그리고 서비스 약관을 위반하지는 않는지 확인해야 합니다.

Realm이 메일로 뉴스와 업데이트를 보내드립니다

AAPT (5:45)

APK를 얻은 다음에는 안드로이드 SDK에 포함된 aapt를 써서 가장 기본적인 작업을 할 수 있습니다. 이를 통해 매우 많은 정보를 알 수 있습니다.

$ aapt
Android Asset Packaging Tool
Usage:
 aapt l[ist] [-v] [-a] file.{zip,jar,apk}
 	List contents of Zip-compatible archive.
 aapt d[ump] [--values] [--include-meta-data] WHAT file.{apk} [asset [asset ...]]
 strings 		Print the contents of the resource table string pool in the APK.
 badging 		Print the label and icon for the app declared in APK.
 permissions 	Print the permissions from the APK.
 resources 		Print the resource table from the APK.
 configurations Print the configurations in the APK.
 xmltree 		Print the compiled xmls in the given assets.
 xmlstrings 	Print the strings of the given compiled xml assets.
aapt p[ackage] [-d][-f][-m][-u][-v][-x][-z][-M AndroidManifest.xml] \
	...
 Package the android resources. It will read assets and resources that are supplied with the -M -A -S or raw-files-dir arguments. The -J -P -F and -R options control which files are output.
aapt r[emove] [-v] file.{zip,jar,apk} file1 [file2 ...]
 Delete specified files from Zip-compatible archive.
aapt a[dd] [-v] file.{zip,jar,apk} file1 [file2 ...]
 Add specified files to Zip-compatible archive.

위와 같이 정말 많은 일을 할 수 있습니다. 특히 dump 부분에서는 APK에 대한 많은 정보를 얻을 수 있고, GUI 도구를 사용할 수도 있습니다.

저게는 특히 strings 같은 것이 유용했습니다. 자신의 앱에서 이 프로그램을 실행한다면 열어 둔 상태로 놔둔 것이 뭔지 확인할 수 있습니다. 쉽게 앱의 모든 스트링 목록을 가져올 수 있습니다. private API 키를 놔뒀다면 바로 읽을 수 있겠죠. 앱이 사용하고 있는 기본 권한이 뭔지도 볼 수 있습니다. badging과 permissions를 차례로 사용하면 됩니다. 정말 편리하죠.

AAPT Examples

$ aapt dump badging Mysterious.apk

badging과 같은 기본 정보를 알려주는 명령어입니다.

$ aapt dump strings Mysterious.apk

이 명령어로는 앞서 말씀드린 것처럼 흥미로운 스트링들을 볼 수 있습니다.

$ aapt dump xmltree Mysterious.apk AndroidManifest.xml

이 명령어는 전체 manifest를 XML 트리로 덤프합니다. manifest는 XML에서 바이너리 표현으로 바뀌므로 XML 트리를 다시 만들지만, 안드로이드는 이를 읽습니다.

APK (7:17)

APK에는 또 무엇이 들어 있을까요? 다음과 같은 공통 디렉터리도 있습니다.

  • assets/ Raw 파일, 동적으로 적재된 코드 포함 다양한 파일
  • lib/ 네이티브 코드 라이브러리
  • META-INF/ 출처와 무결성 확인을 위한 인증서, 서명, 파일 해시
  • res/ 컴파일되지 않은 리소스
  • AndroidManifest.xml manifest 바이너리 XML 버전
  • classes.dex Dalvik 실행 파일 - VM을 위한 모든 파일
  • resources.arsc 컴파일된 리소스
  • * (기타)

META-INF

META-INF 디렉터리에는 많은 것을 넣을 수 있습니다. 특히 APK의 서명을 나타내는 서명 파일이 위치하는 곳입니다.

여기서 재귀적인 문제가 발생합니다. 만약 APK를 서명하면 서명 파일을 이 디렉터리에 넣어야 하는데 이런 행동을 통해 APK의 서명이 다시 변경되면 곤란하겠죠. 따라서 이 디렉터리는 서명될 때 제외돼야 하죠. 즉, 이 디렉터리의 내용을 수정할 수 있지만 이것이 APK의 서명을 수정하지 않습니다.

서명을 무효로 하지 않고 이 디렉터리의 파일을 변경할 수 있습니다. 기본적으로 이 디렉터리는 서명을 포함하며 이를 통해 서드 파티 APK를 다운로드해서 제대로 된 것인지 확인할 수 있습니다.

다른 컨텐츠

무엇이든 assets 이 될 수 있습니다. 멀웨어를 다루는 경우 실제로 코드처럼 보이지 않도록 조금 난독화되는데 거의 스테가노그래피(Steganography) 항목 수준의 것이 숨겨져 있을 수도 있습니다. 여기에 동적으로 코드를 불러오는 것이 있을 수도 있죠. 멀웨어가 종종 이런 형식을 취합니다.

Classes.dex 에는 Dalvik 클래스로 바뀐 모든 Java 클래스가 포함됩니다. 최근에는 안드로이드 런타임(ART)와 미리 컴파일해주는 AOT(ahead-of-time) compilation으로 전체 전환되거나, 부분적으로 just-in-time(JIT) 방식을 사용하므로 이들 몇몇은 같은 방식으로 사용되지 않을 수도 있지만, 해당 형식이 고정돼 있으므로 모두 APK에 있어야 합니다. 그래서 실제로 이를 제거할 수는 없습니다. 비록 전체가 아니더라도 필요한 파일이며 리버스 엔지니어링을 하는 동안 계속 존재해야 합니다.

lib/ 디렉터리에는 네이티브 코드 라이브러리가 있습니다. 다루기 까다로운 심화 리버스 엔지니어링 내용이므로 이번 글에서는 다루지 않을 예정입니다.

다른 도구 (10:30)

이전에 저는 AAPT에 더해 다른 흥미로운 도구도 사용해 봤습니다.

#!/bin/bash
unzip -d zip-out "$1"
java -jar AXMLPrinter2.jar zip-out/AndroidManifest.xml > AndroidManifest.xml
/opt/dex2jar-0.0.9.15/d2j-dex2jar.sh “$1" # creates “${1%.apk}-dex2jar.jar”
mkdir cfr-extracted && /opt/cfr/cfr.sh “${1%.apk}-dex2jar.jar” --outputdir java-out
java -jar /opt/smali/baksmali-2.0.6.jar -o smali-out zip-out/classes.dex

명령어가 너무 복잡하죠? 예전에는 저런 명령어로 전체 코드 묶음을 돌렸는데 dex2jar와 같은 일을 하는 것은 아주 불완전했습니다. 이렇게 사용하면 디컴파일하는 것을 망가뜨릴 수 있으므로 가장 좋은 버전을 보지 못할지도 모릅니다.

요즘은 제가 Java 1.5, Cupcake 등과 같은 초기 안드로이드 버전에서 작업한 이런 방식을 사용할 필요가 없습니다. 최근에는 Apktool을 사용하면 됩니다.

Apktool

다음과 같은 명령어로 실행할 수 있습니다.

$ apktool d target.apk

d는 “덤프”를 의미합니다. 기본적으로 앞서 보여드린 엄청난 양의 스크립트가 하는 일을 해주며, 덤프부터 시작하는 것을 추천합니다. manifest, 리소스, 여러 XML과 Baksmaling classes.dex를 얻을 수 있습니다.

Smali 에 대해 모르는 분을 위해 설명해 드리면 Dalvik 바이트 코드를 위한 어셈블리 언어입니다. 바이트 코드를 읽는 것보다 가독성은 높지만 바이트 코드와 거의 비슷하다고 볼 수 있습니다. 즉 아주 쉽게 Smali로 되돌릴 수 있죠. Baksmali 는 되돌려서 읽을 수 있는 형태로 바꿉니다.

이런 형태에 익숙해지는 데는 시간이 필요하지만, 점점 읽기 쉬워질 겁니다. 또한 이를 수정하고 다시 컴파일해서 앱을 다시 만들어내는 것도 가능합니다. 사실 Java 상에서 이런 변경을 하면 그 내용을 다시 앱으로 되돌리기에 한계가 있습니다.

reverse-engineering-apktool

리버스 엔지니어링을 하려면 apktool을 쓰면 됩니다. 모든 기본 리소스를 준비했다면 모방하려는 효과를 살펴볼 수 있습니다. 예를 들어 둥근 이미지 뷰를 찾을 수도 있겠죠. 이 예제에서는 라이브러리를 사용했다는 것이 보이므로 같은 효과를 내기 위해 처음부터 다시 만들지 않고 이 라이브러리를 사용할 수 있을 겁니다.

앞서 말한 대로 Smali는 아주 가독성이 뛰어나지는 않지만, 필드와 상속 등을 볼 수 있습니다.

디버깅

기본적으로는 왜 크래시가 나는지 보고 싶으실테죠. 그렇다면 이 방법이 효과있을지도 모릅니다. APK가 얼마나 엉망인지에 달려있고 제작자는 자신의 앱에 이런 디버깅을 하는 것을 원하지 않겠지만, 이 방법이 통한다면 놀라운 것들을 볼 수 있습니다.

디버그 버전이 아닌 버전으로 빌드된 앱을 가져와서 재빌드할 수 있습니다. Apktoll을 사용해서 다시 사인하고 자신의 디바이스에 설치해서 디버거를 붙여서 실행해볼 수 있습니다. 사인에는 기존 키가 아닌 자신의 키를 써도 됩니다. 여기까지 됐다면 아무 문제없이 마음껏 디버거를 쓸 수 있죠.

좀 사기같긴 하지만 여러분 앱의 릴리즈 버전이 이상하게 동작하는데 디버거를 붙일 수 없다면 디버깅이 가능한 릴리즈 버전이 필요할 수도 있습니다. 만약 쉽게 다시 만들 수 없는 예전 빌드라면 다음과 같은 것을 시도해볼 수도 있습니다.

$ apktool d -d -o SomeApp SomeApp.apk
...
$ apktool b -d SomeApp
...
$ jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore release-key.keystore SomeApp.apk release_key_alias_name

Androguard (15:02)

더 훌륭한 도구도 있습니다. 대화식 도구 모음인 Androguard입니다. Python 기반이므로 스트립팅이 가능하고 모듈화도 잘 돼 있으며 작은 도구의 라이브러리인 플러그 방식도 가능합니다. 또한 대화형 Python 셸 형식으로도 사용할 수 있습니다. 자체 Dalvik 디컴파일러를 포함하는 점도 인상적입니다. 사이트가 업데이트되지 않는 것 같지만 GitHub 프로젝트는 계속 업데이트되고 있으므로 API의 새 문제 등을 해결해줍니다.

$ python androlyze.py -s

이런 명령어로 대화식 작업을 시작할 수 있습니다. AnalyzeAPK라는 명령어를 입력하면 a, d,dx 세 가지의 결과를 출력합니다.

$ python androlyze.py -s
Androlyze version 3.0
In [1]: a, d, dx = AnalyzeAPK(“/Users/jon/Desktop/target.apk")
In [2]:

APK를 나타내는 객체가 있고 .dex 파일과 본질적으로 같은 Dalvik VM 형식을 나타내는 객체가 있으며 분석을 나타내는 객체가 있습니다. 거의 모든 것을 분석해주는 미리 분석된 객체입니다.

이제 APK의 메인 액티비티가 뭔지 확인해 볼 수도 있습니다. 간단한 예제이지만 이런 방식으로 여러 가지를 확인해볼 수 있습니다.

$ python androlyze.py -s
Androlyze version 3.0
In [1]: a, d, dx = AnalyzeAPK(“/Users/jon/Desktop/target.apk")
In [2]: a, d, dx
Out [2]:
(<androguard.core.bytecodes.apk.APK at 0x10a62c350>,
 <androguard.core.bytecodes.dvm.DalvikVMFormat at 0x10d7e7850>,
 <androguard.core.analysis.analysis.uVMAnalysis at 0x11b80dad0>)
In [3]: a.get_main_activity()
Out [3]: u'com.example.app.ui.MainHomeActivity'

좀 더 복잡한 예제의 경우 dex를 나타내는 객체에 클래스와 소스코드를 달라고 요청할 수도 있습니다. 이 경우 내장된 디컴파일러를 사용해서 디컴파일해줍니다. 다른 디컴파일러로 바꿀 수도 있지만 내장된 것이 가장 좋은 것 같습니다.

In [4]: d.CLASS_Lcom_example_app_ui_MainHomeActivity.source()

또한 권한을 표시하도록 할 수도 있고 이들 메서드의 다큐멘테이션을 얻을 수도 있습니다. 물음표는 매개 변수가 무엇인지 알려주고 어떤 매개 변수가 필요한지 알려주므로 대화식으로 편리하게 쓸 수 있습니다.

권한을 보는 경우 어디에 이들이 사용되는지도 알려줍니다. 소스 코드의 해당 위치로 가서 둘러볼 수도 있습니다. androquard는 구체적으로 보고 싶은 것이 있을 때 APK를 살펴보는 데도 유용합니다. 대화형 세션도 잘 돼 있습니다.

In [5]: show_Permissions?
Signature: show_Permissions(dx)
Docstring:
Show where permissions are used in a specific application
:param dx : the analysis virtual machine
:type dx: a :class:`VMAnalysis` object
File: 	/opt/androguard-2.0/androguard/core/analysis/analysis.py
Type: 	function

In [6]: show_Permissions(dx)
android.permission.READ_CONTACTS :
R ['Landroid/provider/ContactsContract;', 'AUTHORITY_URI', 'Landroid/net/Uri;'] (0x0) --->
Lcom/android/ex/chips/BaseRecipientAdapter$DirectoryListQuery;-><clinit>()V
R ['Landroid/provider/ContactsContract$CommonDataKinds$Email;', 'CONTENT_FILTER_URI',
'Landroid/net/Uri;'] (0x118) ---> Lcom/android/ex/chips/Queries;-><clinit>()V
R ['Landroid/provider/ContactsContract$CommonDataKinds$Phone;', 'CONTENT_FILTER_URI',
'Landroid/net/Uri;'] (0x88) ---> Lcom/android/ex/chips/Queries;-><clinit>()V
R ['Landroid/provider/ContactsContract$CommonDataKinds$Email;', 'CONTENT_URI', 'Landroid/net/
Uri;'] (0x11c) ---> Lcom/android/ex/chips/Queries;-><clinit>()V
R ['Landroid/provider/ContactsContract$CommonDataKinds$Phone;', 'CONTENT_URI', 'Landroid/net/
Uri;'] (0x8c) ---> Lcom/android/ex/chips/Queries;-><clinit>()V

ClassyShark (17:49)

최근에는 ClassyShark도 많이 쓰입니다. 구글 엔지니어가 배포한 유용한 도구인데 UI가 아주 멋지진 않지만 커맨드 라인 인터페이스가 있어서 편리합니다. 빌드 도구에서 사용할 수도 있고 그 안에서 스크립트를 작성해서 빌드 시점에 정보를 알 수도 있습니다.

자신의 프로젝트에서 사용할 수 있는데 APK를 열고 메서드 카운트가 무엇인지와 같은 기본적인 정보를 쉽게 볼 수 있습니다. .dex, 메서드 카운트를 점검할 수 있고 패키지 구조를 살펴보고 난독화가 잘 작동하는지도 금세 확인할 수 있습니다. 이것 저것 크기를 측정할 수도 있습니다.

또한, 이 도구로 무엇이든 열 수 있다는 점도 편리합니다. APK 안의 .dex 파일을 넣거나, 자주 사용되지는 않는 파일이긴 하지만 라이브러리나 열린 네이티브 라이브러리의 .aar 파일도 넣을 수 있습니다. APK는 물론 .jar, 클래스 파일 등 무엇이든 열어서 정보를 볼 수 있어서 정말 좋습니다.

raredare2 (19:20)

Raredare2는 스크립트가 가능한 16진수 에디터입니다. 친숙하지는 않지만 많은 사람들의 기여로 전반적인 프레임워크로 진화했습니다.

거의 무엇이든 지원할 수 있으며 안드로이드뿐만 아니라 모든 종류의 아키텍처를 지원하는 오픈 소스 프로젝트입니다. 이 도구를 기기에서 실행해서 APK를 묶어서 만들어진 결과물을 확인할 수 있습니다.

분석을 담은 웹페이지 등 여러 웹 컨텐츠를 보여주므로 그다지 익숙한 모습은 아니지만 기기에서 사용할 수 있다는 점이 좋습니다.

추가 도구 (20:15)

플레이 스토어에는 JaDX 등의 여러 도구가 있습니다. 좀 오래됐고 UI도 썩 훌륭하지는 않지만 유용한 도구입니다. 한편 Show Java 는 JaDX나 다른 자바 디컴파일러를 사용할 수 있습니다. Dexplorer 도 비슷한 일을 해줍니다. 이들 도구는 플레이 스토어에서 받을 수 있는 애플리케이션으로 APK를 노트북을 거칠 필요 없이 기기에서 열 수 있도록 해줍니다.

노트북 얘기로 돌아가서 Santoku라는 것도 있습니다. 이는 우분투의 더 가벼운 버전은 루분투를 기반으로 한 리눅스 배포판으로 안드로이드를 포함한 일반적인 프로그램들의 보안 점검 혹은 리버스 엔지니어링을 위한 여러 도구들이 미리 설치돼 있습니다. 따라서 Androguard와 같은 여러 도구가 미리 설치돼서 설정도 끝나 있어서 커맨드 라인에서 바로 실행할 수 있습니다. 자신의 기기에 여러 도구를 설치하지 않아도 좋다는 점이 편리하죠. VM이나 부팅 가능한 USB로 Santoku를 실행하고 필요한 도구 목록을 찾아서 실행하는 것만으로 직접 컴퓨터에 깔지 않고도 안드로이드 리버스 엔지니어링을 위한 훌륭한 도구를 사용할 수 있습니다.

IDA와 같이 가격이 비싼 전문가용 도구도 있습니다. 리버스 엔지니어링을 심층적으로 하고 싶거나 큰 회사에서 일하면서 보안이 앱에 큰 이슈가 되는 경우라면 이런 도구를 사용하는 것도 좋습니다. IDA Pro는 안드로이드에서 뿐만이 아니라 여러 분야에서 사용됐으며, 디스어셈블리나 디버깅 도구의 제왕격으로 디스어셈블리를 위한 IDE와 같습니다. 따라서 노트를 만들고 변경하고 다시 작성할 수 있긴 하지만 아쉽게도 유료로 가격이 저렴하지는 않습니다.

CodeInspect는 최근 알파 버전까지 무료였지만 현재는 유료이며 Jimple 이라는 것을 사용합니다. 앞서 Smali와 Baksmali가 Dalvik을 디스어셈블한다고 언급했는데, Jasmin 은 Java에서 널리 사용되는 유명한 어셈블러 언어입니다. CodeInspect는 Jimple이라는 것을 사용하는데 정적 분석을 위한 아이디어로 만들어졌으므로 Soot이라는 프레임워크를 사용해서 Jimple 내용을 분석해줍니다. 이론 상으로는 APK를 분석하는 도구를 플러그해서 특정 취약성이나 특정 패턴 등 코드를 정적으로 분석할 수 있습니다. 앱을 디버그할 수 있게 하고 런타임 상에 분석하거나 둘러보면서 필드나 메서드 등의 이름을 다시 지을 수 있으므로 앱이 난독화되는 경우 아주 유용합니다. 아쉽게도 Eclipse 기반이므로 예쁘지는 않습니다.

다른 유료 도구로 JEB / JEB2도 있습니다. Dalvik에서 Java로의 소스 디컴파일러로 대화형이므로 원하는 위치로 접근해서 이름을 다시 지정할 수 있습니다. 구독 기반 도구입니다.

보안 (25:08)

보안에 대한 유명한 인용문을 먼저 소개하겠습니다.

“정말 안전한 시스템은 전원이 꺼지고 콘크리트 블록에 넣어서 무장한 경비원이 지키는 방에 봉인된 시스템이지만, 이것마저 불안합니다.” – Eugene H. Spafford

앱을 완벽하게 보호할 수는 없습니다. 투입할 수 있는 시간의 양과 보안 정도와 공격자 수 사이에 절충해야 합니다. 앱에서 정말 보안이 필요한 것이 있다면 앱에 넣지 마세요.

자신의 앱을 포함해서 여러 앱을 리버스 엔지니어링을 해보는 것이 좋습니다. 많은 것을 배울 수 있고, 자신의 앱에서 다른 사람들이 어떤 정보를 볼 수 있는지도 알 수 있습니다. 뭔가 정말 보안이 필요한 것이 있다면 배포 이후에 되돌릴 방법이 없으니 앱에 있지 않는 것이 좋습니다.

적어도 보안을 신경 쓴다면 난독화와 사이즈 축소를 적용할 수 있습니다. 여기에는 실제로 큰 노력이 들어가지 않지만 때때로 결과를 확인하는 것이 좋습니다. 훌륭한 일을 했다고 생각해도 확인하지 않으면 생각보다 난독화가 성공적이지 않을 경우가 있기 때문입니다.

예산이 충분하고 중요한 이슈라면 특정 사안을 보호하기 위해 비용을 사용할 가치가 있습니다. DexGuard](https://www.guardsquare.com/en/dexguard)와 같은 경우 유료이지만 ProGuard 보다 높은 레벨을 제공합니다. DexGuard에 여러 트릭을 적용해서 APK를 리버스 엔지니어링하기 매우 어렵게 해줍니다. 물론 유명한 도구라서 이를 풀 도구가 생겨날지도 모르지만, 보통의 개발자들이 엿보는 것은 대부분 막을 수 있을 겁니다.

SQLCipher는 데이터를 암호화하기 위한 도구로 내부를 보기 어렵게 만듭니다. 하지만 다시 강조하는데 정말 중요한 것이라면 앱에 넣지 마세요.

앱을 리버스 엔지니어링해서 어떤 것을 볼 수 있는지 확인해보고 쉽게 수행할 수 있는지 점검하세요. 사적인 것을 스트링에 넣는다면 누구나 쉽게 볼 수 있을 테니, 이를 남들보다 먼저 확인해 보시는 게 좋을 겁니다.

보안 예제

reverse-engineering-example

위 이미지는 ProGuard로 난독화된 앱의 구조입니다. 액티비티와 액티비티의 전체 이름, 그리고 패키지를 유지해야 합니다.

이제 흔히 하는 것처럼 액티비티를 기능별 패키지로 묶을 수 있을 텐데, 그 경우 액티비티 이름을 유지하기 위해 전체 패키지 구조를 그대로 유지할 겁니다. 누군가 이 난독화된 앱을 열어보면 앱의 구조에 대해 꽤 많은 정보를 얻을 수 있고 어디서부터 둘러봐야 할지 알아차릴 수 있습니다.

예제는 아주 단순해서 모든 액티비티를 분리된 패키지에 넣었지만, 우선 순위에 따라 난독화되지 않을 것들이 전체 미러링 된 패키지 구조 안에 포함될 수도 있으니 알아둘 필요가 있습니다. 따라서 퍼블릭인 것은 완전히 다른 패키지 구조에 그룹화할 수 있습니다. 이렇게 할 경우 실제로 어떻게 보이게 되는지 직접 뜯어서 확인해보고 더 좋은 방법을 찾는 것이 좋습니다.

마무리 (29:58)

Android Hacker’s Handbook에서 제가 말한 것 이외에도 많은 것을 배울 수 있습니다.

Droidcon Berlin에서 제가 말한 CodeInspect 도구를 볼 수 있습니다. 어떤 것을 할 수 있는지 확인해 보세요.

DEFCON23의 GitHub 링크에서는 리버스 엔지니어링에 대한 심화 내용을 볼 수 있습니다.

Androguard 사용법은 문서에서 확인하세요.

감사합니다!

관련 뉴스 Realm Java를 사용하면 안드로이드 앱 모델 레이어를 효과적으로 작성할 수 있습니다.

General link arrow white

Jon Reeve

JEE와 Swing, C, C++에 이르기까지 십 년 이상 다양한 개발 경력이 있으며, 7년 이상 안드로이드를 개발한 경력을 쌓은 프리랜서 모바일 개발자이자 아마추어 커피 팬입니다. 이전에는 자동차 및 방송 부문에서 일했고, Shazam에서 일했으며, 최근에는 여러 도전을 하고 있습니다. 클린 코드, 테스트와 TDD, 그리고 여러 가지를 분리해서 작동 방식을 파악하는 것을 좋아합니다.

기록 Joseph Buelow
에디터 Curtis Chen
번역 Eunjoo Im