Android リバースエンジニアリング

  • 78
    いいね
  • 0
    コメント

こんにちは、freee でモバイルエンジニアを担当している @laprasDrum です。
この記事は freee Engineers Advent Calendar 2015 20日目です。


アプリ開発に行き詰まったとき、ググっても道が拓けないときなんてよくあることです。
そんなときは手元の端末に入ってるアプリに目を落とすと、意外なヒントが得られることもあったりなかったり。

ということで覚えていて損はない apk ファイルの解析について知見を共有します。

章立てとしては以下の3段です。

  • apk を取り出す
  • apk からアプリの設定をのぞく (AndroidManifest.xml)
  • apk から Java コードをのぞく

今回は Evernote の中身をのぞいてみましょう。

目的の apk を端末から取り出す

Android SDK Tools をインストールして、Android 端末を接続しましょう。
まずは端末にインストールされたアプリをリスト出力します。
今回は Evernote の情報だけがほしいのでよしなにgrepしましょう。

$ adb shell pm list packages -f | grep evernote
package:/data/app/com.evernote.skitch-1/base.apk=com.evernote.skitch
package:/data/app/com.evernote-1/base.apk=com.evernote

1つ目は skitch なので2つ目の/data/app/com.evernote-1/base.apkが目当ての apk となります。

では取り出しましょう。

$ adb pull /data/app/com.evernote-1/base.apk
7655 KB/s (21830042 bytes in 2.784s)
$ ls -l | grep apk
-rw-r--r--   1 laprasDrum  staff  21830042  9 17 20:24 base.apk

複数の端末をPCに接続している場合

PC に 2台以上 (エミュレーター含む) 接続している場合、adbコマンドを実行する端末を指定する必要があります。
実際に2台接続しているときはこんな感じです。

$ adb devices
List of devices attached
192.168.57.101:5555 device
ZX1G524VFK  device

もし2台目にのみコマンドを実行したい場合は-s (端末ID = ZX1G524VFK)オプションを加えましょう。

$ adb -s ZX1G524VFK shell pm list packages -f | grep evernote

コンバート

apk ファイルを解凍しましょう。
拡張子を zip に変更して展開しても OK です。

$ unzip -d evernote base.apk
$ ls -l evernote
total 30776
-rw-r--r--   1 laprasDrum  staff    94024  8 27 17:49 AndroidManifest.xml
drwxr-xr-x   6 laprasDrum  staff      204  9 17 20:33 META-INF
-rw-r--r--   1 laprasDrum  staff        0  8 27 17:49 PullParser2.1.10_VERSION
drwxr-xr-x  23 laprasDrum  staff      782  9 17 20:33 assets
-rw-r--r--   1 laprasDrum  staff  9232936  8 27 17:49 classes.dex
-rw-r--r--   1 laprasDrum  staff     4172  8 27 17:49 contact-note-template.enml
drwxr-xr-x   3 laprasDrum  staff      102  9 17 20:33 dtds
drwxr-xr-x   3 laprasDrum  staff      102  9 17 20:33 lib
drwxr-xr-x   3 laprasDrum  staff      102  9 17 20:33 org
drwxr-xr-x  48 laprasDrum  staff     1632  9 17 20:33 res
-rw-r--r--   1 laprasDrum  staff  6418108  8 27 17:46 resources.arsc

ズラッと出てきましたが、特に大事なのはAndroidManifest.xmlclasses.dexです。
AndroidManifest.xmlはその名の通りアプリのマニフェストで、アプリIDやパーミッション、開発 SDK のバージョン、画面名やサービス名が含まれます。
classes.dexは Dalvik VM 上で起動する実行ファイルです。

XML をのぞく

AXMLPrinter2.jar でバイナリ XML をのぞきましょう。

$ cd evernote
$ java -jar AXMLPrinter2.jar AndroidManifest.xml > ConvertedManifest.xml

ざっと見るだけでもパーミッション多いですね。
android.から始まっていないcom.android.vending.BILLINGは In App Billing に必要なパーミッションです。

ConvertedManifest.xml
<?xml version="1.0" encoding="utf-8"?>
    <manifest
            xmlns:amazon="http://schemas.amazon.com/apk/res/android"
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:versionCode="1071403"
            android:versionName="7.1.4"
            android:installLocation="0"
            package="com.evernote"
            platformBuildVersionCode="21"
            platformBuildVersionName="5.0.1-1624448"
            >
            <uses-sdk
                    android:minSdkVersion="14"
                    android:targetSdkVersion="21"
                    >
            </uses-sdk>
            <uses-permission
                    android:name="com.android.vending.BILLING"
                    >
            </uses-permission>
            <uses-permission
                    android:name="android.permission.INTERNET"
                    >
            </uses-permission>
            <uses-permission
                    android:name="android.permission.RECORD_AUDIO"
                    >
            </uses-permission>
            <uses-permission
                    android:name="android.permission.ACCESS_NETWORK_STATE"
                    >
            </uses-permission>
            <uses-permission
                    android:name="android.permission.ACCESS_COARSE_LOCATION"
                    >
            </uses-permission>
            <uses-permission
                    android:name="android.permission.ACCESS_FINE_LOCATION"
                    >
            ...

dex をのぞく

dex2jar で .class ファイルを取り出します。

$ chmod +x dex2jar-2.0/*
$ ./dex2jar-2.0/d2j-dex2jar.sh classes.dex
dex2jar classes.dex -> ./classes-dex2jar.jar

JD-GUI で jar ファイルを開くと、デコンパイルされた Java のコードが読めます。
難読化されているので若干読みにくいですね。

jdgui.png

試しに、最初に起動する画面のソースでも探してみましょう。
AndroidManifest.xml 上で最初に起動すべき画面 (activity) にandroid.intent.action.MAINという属性を明記する必要があるので、それを頼りに探します。

ConvertedManifest.xml
<application
    android:label="@7F0E014F"
    android:icon="@7F020302"
    android:name="com.evernote.Evernote"
    android:allowBackup="false"
    android:hardwareAccelerated="true"
    android:largeHeap="true"
    >
    ...
    <activity
        android:theme="@7F0F0153"
        android:name="com.evernote.ui.HomeActivity"
        android:configChanges="0x000004A0"
        android:alwaysRetainTaskState="true"
        >
        <intent-filter
            >
            <action
                android:name="android.intent.action.MAIN"
                >
            </action>
            <category
                android:name="android.intent.category.LAUNCHER"
                >
            </category>
            <category
                android:name="android.intent.category.DEFAULT"
                >
            </category>
            <category
                android:name="android.intent.category.MULTIWINDOW_LAUNCHER"
                >
            </category>
        </intent-filter>
    </activity>
...

どうやらHomeActivityがそれらしいですね。
検索してみましょう。

search.png

いましたね。
ここからコードを読んでヒントを探したり、次に起動する画面を辿ったりします。

気になるアプリがあれば是非試してみてください。


freee には技術を熱く語り、体験設計やチームを大事にして、ビジネス向けアプリの未来を創っていこうとするエンジニアだらけです。
そんなワクワクに飛び込んでみたいモバイルエンジニアの方々、是非一度遊びに来てください。∩(・ω・)∩

明日は @ymrl@joe-re と並んでフロントエンドに革命を起こす自称穏健派 ∧ freee ボルダリング部部長 ∧ ラーメンより蕎麦愛の強い @tohashi です。お楽しみに。