Androidアプリ動的解析ツールFridaを使う
Harekaze Advent Calender21日目の記事です
前日はbanbanさんでした。Harekazeらしいいい記事です!!
それで私が話すのは最近見つけたCTFに使えるツールの使い方です。
Frida
FridaとはAndroidアプリへの動的解析ツールでありアプリの解析やセキュリティに関する調査も行えるツールだそうです。
つい最近知ったのですが今回はそれを使うところまで行こうかなと思います
ちなみにこの記事ではAndroid Emulatorなどは使える前提で進めます。具体的に言うとadb devices
コマンドを打ったときにデバイスが認識されている状況にしてください。
私の試した環境はこんな感じ
$ uname -a Linux durian 3.13.0-121-generic #170-Ubuntu SMP Wed Jun 14 09:04:33 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 14.04.5 LTS Release: 14.04 Codename: trusty $ adb --version Android Debug Bridge version 1.0.39 Version 27.0.0-4455170 Installed as ~/android/android-sdk-linux/platform-tools/adb
Android Emulatorの環境
環境 | |
---|---|
OS | Android7.0.0 |
CPU | ARM(armeabi-v7a) |
Fridaのインストール
基本的にはFridaのページに書いてあるとおりにやれば問題ないです。
Linux側での準備
$ sudo pip install frida
Android側の準備
まずここからfrida-serverをダウンロード展開します。
$ adb root # might be required $ adb push frida-server /data/local/tmp/ $ adb shell "chmod 755 /data/local/tmp/frida-server" $ adb shell "/data/local/tmp/frida-server &"
という感じでfrida-serverを実行しておけば準備完了です。
Fridaを使う
サンプルコードを用いて解説していきます。このサンプルコードですがSECCON2015 reverse-engineering-android-apk-1の問題です。
import frida, sys def on_message(message, data): if message['type'] == 'send': print("[*] {0}".format(message['payload'])) else: print(message) jscode = """ Java.perform(function () { // Function to hook is defined here var MainActivity = Java.use('com.example.seccon2015.rock_paper_scissors.MainActivity'); // Whenever button is clicked MainActivity.onClick.implementation = function (v) { // Show a message to know that the function got called send('onClick'); // Call the original onClick handler this.onClick(v); // Set our values after running the original onClick handler this.m.value = 0; this.n.value = 1; this.cnt.value = 999; // Log to the console that it's done, and we should have the flag! console.log('Done:' + JSON.stringify(this.cnt)); }; }); """ process = frida.get_usb_device().attach('com.example.seccon2015.rock_paper_scissors') script = process.create_script(jscode) script.on('message', on_message) print('[*] Running CTF') script.load() sys.stdin.read()
基本的な使い方ですが
process = frida.get_usb_device().attach(packagename)
のpackageに解析するapkのパッケージを入力することで動的解析ができる環境になり
process.create_script(jscode)
で実行させるJavaScriptを読み込みscript.load()でスクリプト実行させます。Fridaで使えるJavaScriptのメソッドはここを参照してください。
このapkのMainActivityですが下のようになっています。
public class MainActivity extends Activity implements android.view.View.OnClickListener { public MainActivity() { cnt = 0; } public native int calc(); public void onClick(View view) { if(flag == 1) return; flag = 1; ((TextView)findViewById(0x7f0c0052)).setText(""); TextView textview = (TextView)findViewById(0x7f0c0050); TextView textview1 = (TextView)findViewById(0x7f0c0051); m = 0; n = (new Random()).nextInt(3); int i = n; textview1.setText((new String[] { "CPU: Paper", "CPU: Rock", "CPU: Scissors" })[i]); if(view == P) { textview.setText("YOU: Paper"); m = 0; } if(view == r) { textview.setText("YOU: Rock"); m = 1; } if(view == S) { textview.setText("YOU: Scissors"); m = 2; } handler.postDelayed(showMessageTask, 1000L); } protected void onCreate(Bundle bundle) { super.onCreate(bundle); setContentView(0x7f040018); P = (Button)findViewById(0x7f0c004d); S = (Button)findViewById(0x7f0c004f); r = (Button)findViewById(0x7f0c004e); P.setOnClickListener(this); r.setOnClickListener(this); S.setOnClickListener(this); flag = 0; } Button P; Button S; int cnt; int flag; private final Handler handler = new Handler(); int m; int n; Button r; private final Runnable showMessageTask = new Runnable() { public void run() { TextView textview = (TextView)findViewById(0x7f0c0052); if(n - m == 1) { MainActivity mainactivity = MainActivity.this; mainactivity.cnt = mainactivity.cnt + 1; textview.setText((new StringBuilder()).append("WIN! +").append(String.valueOf(cnt)).toString()); } else if(m - n == 1) { cnt = 0; textview.setText("LOSE +0"); } else if(m == n) textview.setText((new StringBuilder()).append("DRAW +").append(String.valueOf(cnt)).toString()); else if(m < n) { cnt = 0; textview.setText("LOSE +0"); } else { MainActivity mainactivity1 = MainActivity.this; mainactivity1.cnt = mainactivity1.cnt + 1; textview.setText((new StringBuilder()).append("WIN! +").append(String.valueOf(cnt)).toString()); } if(1000 == cnt) textview.setText((new StringBuilder()).append("SECCON{").append(String.valueOf((cnt + calc()) * 107)).append("}").toString()); flag = 0; } final MainActivity this$0; { this$0 = MainActivity.this; super(); } }; static { System.loadLibrary("calc"); } }
onClickでじゃんけんが開始されてmとnとcntの値次第でflagが出力されるようです。
m=1
,n=0
,cnt=999
をセットしてrun
関数が実行できればcalcのディスアセンブルをしなくても答えが出そうです
Fridaですが既存のJavaメソッドに拡張を施すことができます。下のは公式で載せられているサンプルです。
Java.perform(function () { var Activity = Java.use("android.app.Activity"); Activity.onResume.implementation = function () { send("onResume() got called! Let's call the original implementation"); this.onResume(); }; });
Java.perform
でJavaを使うことを宣言し、Java.use
で拡張したいJavaのクラスを設定、Activity.---.implementation
でそのクラスの中の関数に拡張を施します。
エクスプロイトコードはcom.example.seccon2015.rock_paper_scissors.MainActivity
のm
とn
とcnt
を変更したいので下のようになります
Java.perform(function () { // Function to hook is defined here var MainActivity = Java.use('com.example.seccon2015.rock_paper_scissors.MainActivity'); // Whenever button is clicked MainActivity.onClick.implementation = function (v) { // Show a message to know that the function got called send('onClick'); // Call the original onClick handler this.onClick(v); // Set our values after running the original onClick handler this.m.value = 0; this.n.value = 1; this.cnt.value = 999; // Log to the console that it's done, and we should have the flag! console.log('Done:' + JSON.stringify(this.cnt)); };
これで実行すると次の画面になります(スクショが死んでたのでsurfaceカメラですいません)
Fridaでできること
現状自分も調べてる真っ最中なのでまだまだできることはあると思いますがCTFですぐ使えそうなのが
- Javaメソッドを拡張する
- 実行中のメモリの中身を見る
あたりかなと....
終わり
ちなみにAndroid Hacking Event 2017 AES-Decrypt Writeup - ごちうさ民の覚え書きもFridaを使っています。個人的には苦渋を飲んでいるHelloDalvikもFridaでいけないかなと考えています。がんばります
明日はうさぎさんです!CBCTFの暗号問の解説ってすごい..
素晴らしい人の前日が自分ですいません.....よいCTFライフを送ってください!!