
Dalvikバイトコード向けのRedexerバイナリインストルメンテーションフレームワーク
Redexer は Android アプリのバイナリを操作するリエンジニアリングツールです。 このツールは DEX ファイルをメモリ上のデータ構造に解析したり、 アプリが特定のパーミッションをどのパラメータで使用しているかを推論したり (この機能を RefineDroid と呼びます)、そのデータ構造を変更して 再出力し DEX ファイルを生成したり(この機能を Dr. Android、 すなわち Android 向け Dalvik 書き換えと呼びます)することができます。
このツールは OCaml 4.09.0 および Ruby 1.8.6(7) でテストされています。 そのため、これら(またはそれ以上のバージョン)をインストールする必要があります。
DEX 形式の SHA-1 シグネチャ(ハッシュ)を操作するために、 OCaml ライブラリマネージャである ocamlfind/findlib を介して OCaml SHA ライブラリ を利用します。両方をインストールする最も簡単な方法は、 両方のパッケージを持つ OCaml パッケージマネージャ OPAM を使用することです (OPAM ocamlfind および OPAM sha)。
両方のパッケージを直接ビルドおよび/またはインストールすることもできます。 Linux マシンを使用している場合、ディストリビューションで簡単に見つけることができます。
そうでない場合、例えば Mac を使用している場合は、自分でビルドする必要があります。
元のソースコードはこちらにあります。
make を実行してビルドし、結果のディレクトリを ocamlfind のルート site-lib ディレクトリにリンクするか、sudo make install を実行してください。
PC を使用している場合は、最初に ocamlfind/findlib と FlexDLL をインストールする必要があります。 環境変数が以下のように正しく設定されていることを確認してください。
OCAMLLIB=C:\OCaml\lib
CAML_LD_LIBRARY_PATH=%OCAMLLIB%\stublibs
FLEXLINKFLAGS=-L%MinGW%\lib -L%MinGW%\lib\gcc\mingw32\N.N.N
OPAM パッケージ:
Android SDK(またはソース)
apk ファイルを展開および再パッケージ化するために、オープンソースの APK リエンジニアリングツール apktool を使用します。
apktool は aapt(Android Asset Packaging Tool)を使用するため、Android SDK またはソースをインストールする必要があります。
さらに、書き換えたアプリを最適化するために、Android SDK に含まれている zipalign を使用します。
プロファイルに以下を追加することで、Android 基本ツールへのパスを設定できます。
ANDROID_HOME=$HOME/android-sdk # ご自身のパスに置き換えてください
export ANDROID_HOME
PATH=$PATH:$ANDROID_HOME/tools
PATH=$PATH:$ANDROID_HOME/platform-tools
PATH=$PATH:$ANDROID_HOME/build-tools/19.0.0 # インストールされているバージョン番号
export PATH
メインスクリプトは Ruby で書かれており、Ruby パッケージマネージャ RubyGems と、 マニフェストファイルを操作する XML ライブラリ Nokogiri が必要です。
グラフ(例:呼び出しグラフ、制御フローグラフ、支配木など)を表示したい場合は、 graphviz dot をインストールする必要があります。
redexer をビルドするには、make を実行するだけです!トップレベルに redexer のバイナリが作成されます。
$ make (clean)
ツールを使用する前に、apktool の最新のプラットフォームファイルをインストールする必要があります。 例えば、以下のように実行します。
$ java -jar tools/apktool.jar if [適切なプラットフォームファイル]
API ドキュメントを HTML 形式で生成することもできます。
$ make api
ツールが提供するすべてのオプションを表示できます。
$ ruby scripts/cmd.rb -h
$ ruby scripts/cmd.rb --help
Android SDK の dexdump のように、redexer は指定された dex ファイルの内部を YAML 形式で表示できます。
$ ruby scripts/cmd.rb target.(apk|dex) --cmd unparse [--to blah.yml]
このオプションは、指定されたメソッドの命令をダンプします。
$ ruby scripts/cmd.rb target.(apk|dex) --cmd dump_method --mtd cls.mtd
この機能は redexer の解析およびダンプモジュールをテストするためのものです。 おそらく同一の dex ファイルが生成されます。
$ ruby scripts/cmd.rb target.(apk|dex) --cmd id [--to blah.dex]
dex ファイルの基本統計(例:命令数)も表示できます。
$ ruby scripts/cmd.rb target.(apk|dex) --cmd info
このオプションは、dex ファイルで定義されているすべてのクラス名を出力します。
$ ruby scripts/cmd.rb target.(apk|dex) --cmd classes
特定のサードパーティライブラリを検索するのに便利です。例:
$ ruby scripts/cmd.rb target.(apk|dex) --cmd classes | egrep 'apache'
このオプションは、dex ファイル内の API 使用状況を出力します。
$ ruby scripts/cmd.rb target.(apk|dex) --cmd api [--sdk android.]
$ ruby scripts/cmd.rb target.(apk|dex) --cmd api --sdk com.facebook.
Dalvik バイトコードで特定のオペコードがどれほどまれに使用されているか気になりませんか? すべてのオペコードのヒストグラムを表示したり、指定されたアプリで特定のオペコードが使用されている頻度を調べたりできます。
$ ruby scripts/cmd.rb target.(apk|dex) --cmd opstat [--op opcode1,opcode2,...]
例えば、
$ ruby scripts/cmd.rb ~/apps/top24/com.whatsapp.apk --cmd opstat
$ ruby scripts/cmd.rb ~/apps/top24/com.whatsapp.apk --cmd opstat --op div-int/lit16,nop
このオプションは伝播ベースの Intent 解決分析を実行し、 Activity クラス間の遷移を出力します。
$ ruby scripts/cmd.rb target.(apk|dex) --cmd intent
このオプションは、指定されたファイルの呼び出しグラフを描画した PDF ファイルを生成します。 PDF 名を指定しない場合は cg.pdf が使用されます。
$ ruby scripts/cmd.rb target.(apk|dex) --cmd cg [--to blah.pdf] [--no-pdf]
このオプションは、指定されたメソッドの制御フローグラフを表示する PDF ファイルを生成します。 クラス名にドットでメソッド名を追加します: class_name.method_name
$ ruby scripts/cmd.rb target.(apk|dex) --cmd cfg --mtd cls.mtd [--to blah.pdf] [--no-pdf]
このオプションは上記の機能と似ていますが、(後続)支配木を描画します。
$ ruby scripts/cmd.rb target.(apk|dex) --cmd (p)dom --mtd cls.mtd [--to blah.pdf] [--no-pdf]
このオプションは、古典的な後方データフロー解析を実行します。
$ ruby scripts/cmd.rb target.(apk|dex) --cmd live --mtd cls.mtd
このオプションは、古典的な前方データフロー解析を実行します。
$ ruby scripts/cmd.rb target.(apk|dex) --cmd const --mtd cls.mtd
このオプションは、古典的な前方データフロー解析を実行します。
$ ruby scripts/cmd.rb target.(apk|dex) --cmd reach --mtd cls.mtd
このオプションは、クラスの依存関係を検出します。
$ ruby scripts/cmd.rb target.(apk|dex) --cmd dependants --mtd cls.mtd
このオプションは、指定された apk の起動アクティビティ名を出力します。
$ ruby scripts/cmd.rb target.apk --cmd launcher
このオプションは、外部に公開されているコンポーネントを教えてくれます。
$ ruby scripts/cmd.rb target.apk --cmd exported
これらのオプションは、マニフェストで宣言された Android 基本コンポーネントを出力します。
$ ruby scripts/cmd.rb target.apk --cmd [activity | service | provider | receiver]
このオプションは、リソース内のレイアウト定義を調査し、カスタムビューを出力します。
$ ruby scripts/cmd.rb target.apk --cmd custom_views
このオプションは、リソース内のレイアウト定義を調査し、Fragment 要素を出力します。
$ ruby scripts/cmd.rb target.apk --cmd fragments
このオプションは、リソース内のレイアウト定義を調査し、ボタンを ID(またはテキスト)とコールバックメソッド(存在する場合)とともに出力します。
$ ruby scripts/cmd.rb target.apk --cmd buttons
このオプションは、apk が使用するパーミッションを出力します。
$ ruby scripts/cmd.rb target.apk --cmd permissions
このオプションは、apk が必要とする SDK バージョンを出力します。
$ ruby scripts/cmd.rb target.apk --cmd sdk
apk ファイルを展開したくない場合は、実際にはコマンドの組み合わせで同じことができます。
$ aapt dump badging target.apk | grep 'targetSdkVersion' | tr -dc 0-9.\\n
このオプションは、シンプルなメッセージを出力する dex ファイルを生成します。 その dex ファイルは redexer の API のみを使用して作成されます。
$ ruby scripts/cmd.rb --cmd hello
内部を確認します。
$ dexdump -d results/classes.dex
興味があれば、次のようにその dex ファイルをテストできます。 ANDROID_SDK へのパスが設定されていることを前提とします。
// dalvik VM に適した一時的な jar を作成
$ aapt add temp.jar results/classes.dex
// (オプション)avd を作成していない場合は作成します。
$ android create avd -n myAVD1 -t android-8
// エミュレータを起動
$ emulator -avd myAVD1 &
// 一時 jar をプッシュ
$ adb push temp.jar /data
// adb shell に接続
$ adb shell
// 最後に dex を実行
# /system/bin/dalvikvm -Xbootclasspath:/system/framework/core.jar \
-classpath /data/temp.jar Hello
Hello, DEX
#
これは書き換え機能のバリエーションです。この機能を使用すると、特定の観点からアプリの動作をログに記録できます。
ロギングライブラリ用のビルド済み dex ファイルが用意されています:data/logging.dex。
さらに機能やユーティリティを追加したい場合は、次のようにビルドします。
$ cd logging
$ gradle copyDex
$ cd ..
次に、以下のコマンドを使用します。
$ ruby scripts/cmd.rb target.apk --cmd logging
trim.py は、インストルメント化されたアプリの呼び出し-戻りシーケンスをキャプチャできます。 (最初に redexer を使用してテスト対象アプリをインストルメント化する必要があります。)
ログが十分に短い場合(つまり、端末(またはエミュレータ)がすべての情報をメモリに保持できる場合)、スクリプトのオフラインモードを使用できます。
$ ./scripts/trim.py -d
すべてのコマンドラインパラメータは adb logcat に渡され、デフォルトでは org.umd.logging:I *:S が関連ログをフィルタリングするために渡されます。
ログがオーバーフローする場合は、オンラインモードを使用する必要があります。
$ ./scripts/trim.py
スクリプトはキー割り込みをキャッチするため、Ctrl+C でロギングを終了できます。
どちらのモードでも、ログは log.txt に保存され、一度に画面に表示されます。 そのため、ログ収集後、そのファイルを移動する必要がある場合があります。例:
$ mv log.txt app.scenario.txt
上記のロギング機能は、メソッドレベルで何をログに記録するかを指定できるという点で一般的です。
(詳細は logging モジュールを参照してください。)
ただし、これは冗長すぎてパフォーマンス低下を引き起こす場合があります。
この機能は、ユーザー操作のみをログに記録するように設計されています。
この機能を使用すると、UI 関連のイベントのみをキャプチャできます。
同様に、ロギングライブラリ用のビルド済み dex ファイルが用意されています:data/logging-ui.dex。
UI 情報の詳細度を変更したい場合は、次のようにビルドします。
$ cd logging-ui
$ gradle copyDex
$ cd ..
次に、以下のコマンドを使用します。
$ ruby scripts/cmd.rb target.apk --cmd logging_ui
ロギングライブラリは、android a11y サービスから継承されており、ユーザーの明示的な同意が必要です。
そのため、書き換えられた apk をインストールした後、設定/アクセシビリティ に移動し、UI Logging サービスをオンにしてください。
(この手順は、デバイスのデバッグモードをオンにすることと同様に考えることができます。)
logcat では、タグ org.umd.logging_ui.* のメッセージが、ユーザーとテスト対象アプリの間の相互作用です。
このオプションは、ターゲットメソッド呼び出しへのコンポーネント遷移パスを見つけます。
$ ruby scripts/cmd.rb target.apk --cmd directed
ターゲットメソッドは data/directed.txt で指定できます。
これらのコンポーネント遷移パスは、アプリを駆動してサードパーティライブラリのセキュリティ脆弱性をテストするために使用されます。 詳細は以下の論文で説明されています。
* Brahmastra: Driving Apps to Test the Security of Third-Party Components.
R. Bhoraskar, et al., In 23rd Usenix Security Symposium (Security '14).
withTimeout.rb はアプリのスキップファイルを自動的にビルドできます。このスクリプトは特定のタイムアウトで cmd.rb を実行し、個々のクラスのインストルメント化にかかる時間を制限します。これは、インストルメント化中にループに陥るまれなクラスに対する一時的な回避策です。このスクリプトはクラッシュするクラスを見つけると、スキップファイルに追加し、中断したところから続行します。withTimeout が終了すると、data ディレクトリに [apk name]-skip.txt というファイルが作成され、その apk の完全インストルメント化アプリをビルドするために使用できます。withTimeout を使用するには、単に以下を呼び出します。
$ ruby scripts/withTimeout.rb TIMEOUT COMMANDS
ここで、TIMEOUT は希望するタイムアウトの長さ(秒単位)(300 が推奨)で、COMMANDS は apk に対して scripts/cmd.rb に渡す通常のコマンドライン入力すべてです。