Android アプリ解析基礎 その2 -PC編-

こんにちは。eeic2017erの@totemです。
この記事は[eeic advent calendar その2](http://qiita.com/advent-calendar/2016/eeic2)の 2日目の記事です。
- - -
[Android アプリ解析基礎 その1 -スマフォ編-](http://qiita.com/totem/items/e5ad1da5662f06d359ca)の続編としてPCで行うAndroidアプリ解析方法の基礎部分を紹介します。

今回は実際に解析を実践してもらう用のアプリを作りました。
[AnalyzeQuiz](https://play.google.com/store/apps/details?id=com.totem.analyze_app_quiz) です
![icon_xxhdpi.png](https://qiita-image-store.s3.amazonaws.com/0/147125/4b47818a-e5e6-c78a-3a52-5b503bfc5cb3.png)
解析するためだけのアプリなので、見た目とか機能とか一切凝ってないですごめんなさい。

アプリ内にフラグ形式flag{1234567890abcde}といった形のフラグを5つ持っていますので、リバースエンジニアリングや通信の解析を駆使してflagを探してみてください。
なお、あくまでも解析の基礎なので、ネイティブコードの解析は必要ありません。
というか、むしろ避けてください。アセンブラが読めればとても簡単に解けてしまいます。
また、プログラミングを一切することなく全てのフラグを入手出来る作りになっています。プログラミング初心者でも問題ありません。

では以下でPCでの解析の手法を説明していきます。
CTFの勉強などをされている方は、この先の記事を読む前に実際に上のアプリを解析してみてください。
RTAを行ってタイムを報告していただけると嬉しいです。

# お約束
本記事で得た情報は絶対に悪用しないでください。
法律で保護されたプログラムに対してリバースエンジニアリングなどを行うことは法律に違反する可能性があります。

# リバースエンジニアリング
PCでapk内のJavaコードをリバースエンジニアリングを行う際には、以下の手順で行っていきます。

* スマートフォンからapkファイルを抽出する
* apkファイルを解凍する
* dexファイルからjarファイルを生成する
* jarファイルをビューアーを用いて見る

## 下準備
リバースエンジニアリングに必要なソフトウェアは以下の通りです

* [Android Studio](https://developer.android.com/studio/index.html?hl=ja)
* [dex2jar](https://sourceforge.net/projects/dex2jar/)
* [Java](https://java.com/ja/download/)
* [JD-GUI](http://jd.benow.ca/)

リンク先に従ってそれぞれインストールしておきましょう。
またAndroid Studioがインストール出来たら、AndroidStudioのPreferenceを開き、Appearance & Behavior->System Settings->AndroidSDKを見てAndroidSDKの場所を確かめてください。
確かめたらターミナル上で

```
export PATH=PATH:${sdkのパス}/platform-tools 
```
を行い、adbをターミナル上で使えるようにします。
Windowsの方は、コントロールパネル->システムとセキュリティ->システムを開き、システムの詳細設定から環境変数のタブを開き、Pathにplatform-toolsを追加してください。
[windowsでadbコマンドを使えるようにする方法](http://sozoen.com/yuichiro/adb-command) のページが役に立ちます。

## スマートフォンからapkファイルを抽出する
スマートフォンからapkファイルを抽出するにはまず、スマートフォンの開発者オプションからUSBデバッグを有効にする必要があります。
本体設定のシステムの端末情報から、ソフトウェア情報を開きビルド番号を7回タップすると、開発者オプションが設定画面に出現します。
開発者オプションからUSBデバッグにチェックを入れます。

スマフォをUSBでPCに接続し、ターミナルを開き(Windowsだったらcmdなりなんなり)、

```
adb shell pm list packages -f
```
上のコマンドでインストールされているアプリのapkファイルのpathのリストが表示されます。
自分が解析したいアプリを見つけたら、その絶対pathをコピーして

```
adb pull ${解析対象アプリのapkの絶対パス}
```
とすると、カレントディレクトリにapkファイルが抽出されます。

## apkファイルを解凍する
apkファイルはただの署名付きzipなので、拡張子をapkからzipに変更することによって、解凍できるようになります。
解凍するとこんな感じになります。
<img width="436" alt="スクリーンショット 2016-11-29 23.52.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/147125/5f91e029-7dd3-e9cc-60f1-e819a9e16863.png">
これらはそれぞれ

* AndroidManifest.xml - アプリのコンポーネントやパーミッションを記述するファイル
* classes.dex - 実行ファイル本体
* META-INF - apkファイルの署名情報
* res - アプリのリソース(画像等)
* resources.arsc - リソースのメタ情報

といった情報を持ちます


## dexファイルからjarファイルを生成する。
dexからjarファイルを生成するには先ほどダウンロードしたdex2jarを用います。
解凍してchmod +x *で実行権限を与えてください。
windowsは何もしなくて大丈夫です。

mac,linuxならば

```
d2j-dex2jar.sh classes.dex
```
でdexファイルからjarファイルを生成できます。
windowsならば

```
d2j-dex2jar.bat classes.dex
```
でjarファイルを生成できます。

もし出来なかったら、d2j-dex2jarとclasses.dexのファイルの位置を確認してください。
なお、jarファイルはd2j-dex2jarを実行したディレクトリに生成されます。

## jarファイルをビューアーを用いて見る
JD-GUIを開き、左上のフォルダアイコンをクリックしてjarファイルを開きます。
<img width="1016" alt="スクリーンショット 2016-11-30 18.42.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/147125/45aaf8b1-e126-f39b-d22c-9a13e8cadfd1.png">

するとこんな感じに、中身を閲覧することができます。

# その他のファイルのリバースエンジニアリング
resフォルダにあるリソースファイルなどはそのまま閲覧することが出来ますが、AndroidManifest.xmlやresources.arscなどはそのままでは閲覧できません。
スクリプトをダウンロードしてきてもいいのですが、今回はAndroid StudioのAnalyze APK機能を用いてAndroidManifest.xmlなどを閲覧したいと思います
AndroidStudioを開きツールバーからBuild->Analyze APKをクリックし、閲覧したいapkファイルを選択すると、下のような画面が開かれます。
なおプロジェクトの画面でないと、ツールバーが現れないので、適当なプロジェクトを開くなり新規作成してください。
<img width="1057" alt="スクリーンショット 2016-11-30 19.15.44.png" src="https://qiita-image-store.s3.amazonaws.com/0/147125/392b4316-e483-2c01-63cd-a208f9ab66c0.png">

これらのAndroidManifest.xmlやresources.arscを選択することで中身を閲覧できます。
<img width="1056" alt="スクリーンショット 2016-11-30 19.17.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/147125/fd04cad5-a9bf-9358-f1da-4e2050f1a56c.png">

また、classes.dexを選択するとクラスと関数名までは把握できます。

# リバースエンジニアリング対策
さて、ここまでで簡単にAndroidアプリはソースコードまで復元されてしまうということがわかりました。

このリバースエンジニアリングへの対策として日頃言われているのはProGuardです。
ProGuardは変数名やクラス名を意味のない文字に変えてくれる難読化をしてくれます。
AndroidStudioではデフォルトでProGuardを利用して、リリースビルドで難読化してくれます。

ちなみに上で紹介したAnalyzeQuizはProGuardを使用しています。
実際にAnalyzeQuizをデコンパイルすると難読化が「難読化」に過ぎないことがわかります。
正直小さなアプリでは問題なく読めてしまいます。
大きなアプリでも時間をかければ読めます。(もちろんそれでも難読化したほうがいいです)

対策として出来るのは[NDK](https://developer.android.com/ndk/index.html)を用いてC++でコードを記述することです。
C++で記述したコードは機械語にコンパイルされるので、アセンブラの段階までしか復元できません。
これは解析のコストを格段に増加させます。
全体をC++で記述していくことは難しいので、守るべきところでNDKを利用していくべきだと思います。

# リバースエンジニアリングの悪用例 - 偽アプリ
2016年の夏、PokemonGoの偽アプリがニュースになりました。
全然別物のアプリがPokemonGoを騙っている例もありましたが、そうではない例もあります。
ここまでリバースエンジニアリングの手法や実際を見ていただいてわかったと思いますが、リバースエンジニアリングを行えばJavaのソースコードを抽出することが出来ます。
つまり、本物のソースコードを流用し、情報を盗みとるコードを付加した偽アプリを作ることが可能ということです。
本物のソースコードを流用している分、利用者は信用してしまうかもしれません。
署名検証などでアプリとゲーム鯖との通信を阻止出来るかもしれませんが、アプリ起動からしばらくしないうちに端末から情報は盗みとられてしまいます。
__正規のストア以外からアプリを極力ダウンロードしないでください__

# ログの解析
インストールしたアプリですが、まれにログを出力している場合があります。
その場合はログからアプリの情報を入手することができます。
ログの閲覧はadbの機能で提供されています
ターミナルなどで

```
adb logcat
```
とすることで出力されるログを見ることが出来ます。

またAndroidStudioのAndroid Monitorの機能でもlogcatが利用できます。
ターミナルよりこちらの方が個人的には見やすくてオススメです。
<img width="871" alt="スクリーンショット 2016-12-01 0.09.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/147125/48e152fa-2bcd-1391-0749-1306c8bfa15f.png">


# ログの解析対策
不要なログ出力は消しましょう(それはそう)

# 通信の解析
通信の解析では以下の2つのステップで解析を行います。

* 通信を抽出する
* 通信を解析する

## 下準備
* [tPacketCapture](https://play.google.com/store/apps/details?id=jp.co.taosoftware.android.packetcapture&hl=ja)
* [WireShark](https://www.wireshark.org/download.html)

tPacketCaptureをスマフォに、WireSharkをPCにインストールしてください

## 通信を抽出する
[Androidアプリ解析基礎 その１ -スマフォ編-](http://qiita.com/totem/items/e5ad1da5662f06d359ca) で紹介したtPacketCaptureを用いて通信をキャプチャします。
キャプチャしたファイルはpcap形式で保存され、多くの場合
/Android/data/jp.co.taosoftware.android.packetcapture/files/ に保存されます
これをAndroid File Transferなり、ターミナル上から

```
adb pull /Android/data/jp.co.taosoftware.android.packetcapture/files/${ファイル名}
```
でPC上に落としてきてください
これで抽出は完了です

## 通信を解析する
PCに落としてきたpcapファイルをWiresharkで開きます
<img width="1181" alt="スクリーンショット 2016-12-01 1.08.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/147125/8c01c613-379a-b244-14f6-039de2f380b6.png">
あとは適当に気になるパケットを見ていくだけです

# 通信の解析対策
通信の解析ですが、SSLによる暗号化は効果がありません。
第三者の通信の盗聴は防ぐことができますが、この場合第２者による通信の解析なので、見れてしまいます。
(基礎範囲を逸脱するので具体的手法の説明はしません)
通信の改ざんを防ぐ場合にはhmacによる検証やSSL暗号化+HPKPなどを行うとよいです。
秘匿したい情報がある場合には、アプリケーション内で通信の暗号化を行ったほうがよいです。
また、通信の暗号化しているコードもリバースエンジニアリングで解読されて復号される可能性もあるので、この部分はリバースエンジニアリング対策もしっかりと行った方がよいかもしれません。

# ローカルファイルの解析
ローカルファイルは
/Android/data/\${アプリのパッケージ名}/files に保存されています。
また、SharedPreferencesというアプリの設定を保存するファイルは
/data/data/\${アプリのパッケージ名}/shared_prefs に保存されます。
SharedPreferencesの方はroot端末ではないと閲覧できません。

## 下準備

* Android Virtual Device

AndroidStudioを起動し、Tools->Android->AVDManagerと開くと、Androidの仮想マシンを立ち上げることができます。新規作成は左下のCreate Virtual Deviceから作成できます。
<img width="622" alt="スクリーンショット 2016-12-01 2.17.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/147125/2be734fa-92b3-e50c-02ea-396d1b4ef6ff.png">
AVDではroot権限が使えるので、こちらでちょっとしたローカルファイルの解析を行うことになります。
__なお、実機のroot化は絶対にオススメしません。__
セキュリティ的なリスクが結構増加します。

## ローカルファイルの解析
ターミナルから

```
adb shell
```
コマンドを入力するとAndroidの仮想マシンにシェルログインすることができます。
シェルログインしたら

```
cd /data/data/${パッケージ名}/shared_prefs
```
で移動し、物色できます。
shellでsedコマンドが使えるので、shell上でローカルファイルの書き換えなども行えます。

shellログインせずとも

```
adb shell ls /data/data/${パッケージ名}/shared_prefs
```
で設定ファイルを確認し、

```
adb pull ${ファイルパス}
```
でローカルにダウンロードして編集し、

```
adb push ${ローカルファイル} ${Androidでのファイルパス}
```
でAndroidにファイルを送ってやるという手法でローカルファイルを書きかえ、挙動の変化などを解析することも可能です。

## ローカルファイルの解析対策
root化端末で起動できないようにする(効果は限定的)、SharedPrefsに保存する値にはアプリ内で暗号化をかけてから保存するといった手があります。

# メモリの解析
場合によってはアプリのメモリイメージをダンプして解析したくなる時もあります。
いくつかメモリダンプを取得する方法はありますが、今回はAndroidStudioに付属するAndroid Device Monitorを利用してメモリダンプを取得します。

今回もroot権限が必要となります。AVDを利用しましょう。
正確にはDebuggableなアプリであればメモリダンプを取得できますが、DebuggableなアプリはPlay Storeに置けないことになっているので、実質root権限が必要です。
自分で開発しているアプリでDebugビルドであればAVDを通さずともメモリダンプを取得することができます。

## 下準備

* Android Virtual Device
* [foremost](http://foremost.sourceforge.net/)

AVDは先ほど同様なので省略します。
foremostはフォレンジックツールです。tarを解凍してmakeすれば使えます。(windowsでももちろん使えます)
ターミナルからforemostのtarファイルのあるディレクトリに移動し、

```
tar zxvf foremost-1.5.7.tar.gz && cd foremost-1.5.7 && make
```
でforemostがビルドできます。

## ヒープメモリのダンプ
まずはAVDからAndroid仮想マシンを起動します。
AndroidStudioのツールバーからTools->Android->Android Device Monitorを開きます
<img width="605" alt="スクリーンショット 2016-12-01 13.16.11.png" src="https://qiita-image-store.s3.amazonaws.com/0/147125/5a8e8f34-417c-e447-fc40-799117037a5c.png">

するとこのようなDevicesのタブに、接続されているAndroid(仮想)マシンと、その上で動いているプロセスの一覧が表示されます。
root化していない実機を接続した場合はプロセスの一覧は表示されません。
プロセス一覧からヒープメモリのダンプをしたいアプリのパッケージ名を選択します。
プロセス一覧にあるアイコン群の内、下のアイコンをクリックするとヒープメモリダンプをhprofファイルに保存できます。
<img width="26" alt="スクリーンショット.png" src="https://qiita-image-store.s3.amazonaws.com/0/147125/a87ab5c6-e54a-d773-daa4-591d6ba79ccf.png">

## ヒープメモリの解析等
AndroidStudioにはhprofファイルのビューアー機能もあります。
AndroidStudioのツールバーでFile->Openからhprofファイルを開くとhprofファイルの中身を見ていくことができます
<img width="1030" alt="スクリーンショット 2016-12-01 13.49.11.png" src="https://qiita-image-store.s3.amazonaws.com/0/147125/cfa7cf83-6300-69ef-4dc4-adbd645749ef.png">
このように、ヒープメモリの状態を確認することができます。

また、hprofファイルはメモリダンプであるので、メモリ上に展開されたファイルなどはフォレンジックツールを用いて抽出することができます。
先ほどビルドしたforemostを用いて

```
./foremost ${メモリダンプファイル} 
```

としてやるとカレントディレクトリにouputディレクトリが生成され、その中にメモリダンプより抽出されたファイルが出力されます。
エラーが出た場合はforemostとメモリダンプファイルの場所を確認してください。

# まとめ
今回はAndroidアプリ解析の内

* リバースエンジニアリング
* ログの解析
* 通信の解析
* ローカルファイルの解析
* メモリの解析

について書きました。
誤りがあれば指摘してください。 
明日のeeic advent calendarその2は@hakatashiさんの「eeic2017botについて」です