MASTG-TOOL-0039 Frida for iOS

Frida は ObjC API を通じて Objective-C ランタイムとのインタラクションをサポートしています。プロセスとそのネイティブライブラリ内で Objective-C とネイティブの両方の関数をフックして呼び出すことができます。JavaScript スニペットはメモリにフルアクセスでき、たとえば任意の構造化データを読み書きできます。

Frida API が提供するタスクのうち、iOS に関連するものや iOS 専用のものをいくつか紹介します。

  • Objective-C オブジェクトをインスタンス化し、静的および非静的クラスメソッドを呼び出します (ObjC API)。

  • Objective-C メソッド呼び出しをトレースしたり、その実装を置き換えます (Interceptor API)。

  • ヒープをスキャンして、特定のクラスのライブインスタンスを列挙します (ObjC API)。

  • プロセスメモリをスキャンして文字列の存在を探します (Memory API)。

  • ネイティブ関数呼び出しをインターセプトして、関数の開始時と終了時に独自のコードを実行します (Interceptor API)。

iOS では、Frida CLI (frida)、frida-psfrida-ls-devicesfrida-trace など、Frida のインストール時に提供されるビルトインツールも利用できることを心に留めてください。

iOS 専用の frida-trace 機能は注目に値します。-m フラグとワイルドカードを使用して Objective-C API をトレースします。たとえば、名前が "NSURL" で始まるクラスに属し、名前に "HTTP" を含むすべてのメソッドをトレースするには、以下を実行するだけであり簡単です。

frida-trace -U YourApp -m "*[NSURL* *HTTP*]"

手っ取り早く始めるには iOS examples をご覧ください。

iOS に Frida をインストールする

Frida を iOS アプリに接続するには、そのアプリに Frida ランタイムを注入する方法が必要です。脱獄済みデバイスでは Sileo などのサードパーティアプリストアから frida-server をインストールできるため、これは簡単に実行できます。Sileo を開き、Manage -> Sources -> Edit -> Add に移動して https://build.frida.re と入力し、Frida のリポジトリを追加します。それ後 Frida パッケージを見つけてインストールできるようになります。

デフォルトでは、frida-server はローカルインタフェースでのみ listen するため、デバイスを USB で接続する必要があります。frida-server をパブリックインタフェースで公開したい場合には、/var/jb/Library/LaunchDaemons/re.frida.server.plist を修正し、ProgramArguments の二つの項目を以下のようにします。

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <d>
        <key>Label</key>
        <string>re.frida.server</string>
        <key>Program</key>
        <string>/var/jb/usr/sbin/frida-server</string>
        <key>ProgramArguments</key>
        <array>
                <string>/var/jb/usr/sbin/frida-server</string>
                <string>-l</string>
                <string>0.0.0.0</string>
        </array>
        <key>UserName</key>
        <string>root</string>
        <key>POSIXSpawnType</key>
        <string>Interactive</string>
        <key>RunAtLoad</key>
        <true/>
        <key>KeepAlive</key>
        <true/>
        <key>ThrottleInterval</key>
        <integer>5</integer>
        <key>ExecuteAllowed</key>
        <true/>
</dict>
</plist>

一旦インストールされると、Frida サーバーが自動的にルート権限で実行し、任意のプロセスに簡単にコードを注入できるようになります。

!!! 危険

frida-server をパブリックインタフェースで公開すると、同じネットワークに接続する誰もが、デバイス上で実行している任意のプロセスにコードを注入できるようになります。これは管理されたラボ環境でのみ実行すべきです。

iOS で Frida を使用する

デバイスを USB で接続し、frida-ps コマンドを -U フラグと実行して、Frida が動作することを確認します。これはデバイス上で動作しているプロセスのリストを返すはずです。

$ frida-ps -U
PID  Name
---  ----------------
963  Mail
952  Safari
416  BTServer
422  BlueTool
791  CalendarWidget
451  CloudKeychainPro
239  CommCenter
764  ContactsCoreSpot
(...)

Frida バインディング

スクリプト体験を拡張するために、Frida は Python、C、NodeJS、Swift などのプログラミング言語へのバインディングを提供します。

Python を例にとると、まず注目すべき点はそれ以上のインストール手順は必要ないということです。Python スクリプトを import frida で開始すれば準備完了です。先ほどの JavaScript スニペットを実行するだけの以下のスクリプトをご覧ください。

# frida_python.py
import frida

session = frida.get_usb_device().attach('com.android.chrome')

source = """
Java.perform(function () {
    var view = Java.use("android.view.View");
    var methods = view.class.getMethods();
    for(var i = 0; i < methods.length; i++) {
        console.log(methods[i].toString());
    }
});
"""

script = session.create_script(source)
script.load()

session.detach()

この場合、Python スクリプトを実行 (python3 frida_python.py) すると、先ほどの例と同じ結果になります。つまり、android.view.View クラスのすべてのメソッドをターミナルに出力します。しかし、Python からデータを操作したいかもしれません。console.log の代わりに send を使用すると、JavaScript から Python に JSON 形式でデータを送信します。以下の例のコメントをお読みください。

# python3 frida_python_send.py
import frida

session = frida.get_usb_device().attach('com.android.chrome')

# 1. メソッド名をリスト内に格納したい
android_view_methods = []

source = """
Java.perform(function () {
    var view = Java.use("android.view.View");
    var methods = view.class.getMethods();
    for(var i = 0; i < methods.length; i++) {
        send(methods[i].toString());
    }
});
"""

script = session.create_script(source)

# 2. これはコールバック関数であり、"Text" を含むメソッド名のみがリストに追加されます
def on_message(message, data):
    if "Text" in message['payload']:
        android_view_methods.append(message['payload'])

# 3. メッセージを受信するたびにコールバックを実行するようにスクリプトに指示します
script.on('message', on_message)

script.load()

# 4. 収集したデータで何かを行います。この場合は単に表示するだけです
for method in android_view_methods:
    print(method)

session.detach()

これは効果的にメソッドをフィルタし、文字列 "Text" を含むものだけを表示します。

$ python3 frida_python_send.py
public boolean android.view.View.canResolveTextAlignment()
public boolean android.view.View.canResolveTextDirection()
public void android.view.View.setTextAlignment(int)
public void android.view.View.setTextDirection(int)
public void android.view.View.setTooltipText(java.lang.CharSequence)
...

最終的に、どこでデータを扱うかはあなた次第です。JavaScript から行う方が便利なこともあれば、Python が最適な選択肢となることもあるでしょう。もちろん script.post を使用して Python から JavaScript にメッセージを送信することもできます。送信 および 受信 メッセージの詳細については Frida のドキュメントを参照してください。

Last updated

Was this helpful?