mcpField
R
reverse-engineering-ios-app-with-frida

reverse-engineering-ios-app-with-frida

github.com/mukul975セキュリティ35.2k159 回インストール8 週間前に更新
リポジトリ

reverse-engineering-ios-app-with-frida について

ソースコードのない iOS アプリを認可されたセキュリティ評価で調べるための、Frida を使ったスキルです。ランタイムトレース、メソッドのフック、Swift の解析、セキュリティ機構のテストを扱います。

主な機能

  1. 01ランタイムのクラスとメソッドの列挙
  2. 02Objective-C メソッド呼び出しの追跡
  3. 03メソッドのフックと動作変更
  4. 04Swift ランタイムロジックの解析
  5. 05暗号化とセキュリティ機構の調査

活用シーン

  1. 01認可された評価での iOS アプリ解析
  2. 02難読化された Swift・Objective-C ロジックの追跡
  3. 03暗号化と API データ処理の確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mukul975/anthropic-cybersecurity-skills --skill reverse-engineering-ios-app-with-frida

インストール後、Claude Code で/reverse-engineering-ios-app-with-fridaを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

LICENSE
assets/
template.md
references/
api-reference.md
standards.md
workflows.md
scripts/
agent.py
process.py

詳細

Frida を使用した iOS アプリのリバースエンジニアリング

使用する場面

次の場合にこのスキルを使用します。

  • ソースコードのない iOS アプリを、許可されたセキュリティ評価の一環として解析する
  • 実行中の iOS アプリから暗号鍵、API シークレット、または独自プロトコルの詳細を抽出する
  • ランタイムのメソッドトレースを通じて、難読化された Swift/Objective-C のロジックを理解する
  • 複雑なセキュリティ機構(脱獄検知、改ざん防止、デバッグ防止)を回避する

利用規約または知的財産権法に違反する、許可されていないリバースエンジニアリングには、このスキルを使用しないでください。

前提条件

  • Cydia/Sileo 経由で Frida サーバーをインストールした脱獄済み iOS デバイス、または Frida Gadget を注入した IPA を使用する非脱獄デバイス
  • frida-tools をインストールした Python 3.10 以降(pip install frida-tools)
  • iOS デバイスへの USB 接続
  • Objective-C ヘッダーの抽出用の class-dump または dsdump
  • 静的バイナリ解析用の Hopper Disassembler または Ghidra(補完的に使用)
  • Objective-C ランタイムと Swift の名前マングリングに関する知識

ワークフロー

ステップ 1:バイナリを抽出して解析する
# On jailbroken device, find app binary
ssh root@<device_ip>
find /var/containers/Bundle/Application/ -name "TargetApp" -type f

# Pull decrypted binary (apps from App Store are encrypted with FairPlay)
# Use frida-ios-dump or Clutch for decryption
pip install frida-ios-dump
dump.py com.target.app

# Extract Objective-C class headers
class-dump -H decrypted_binary -o headers/
ls headers/  # Lists all class header files
ステップ 2:ランタイムでクラスとメソッドを列挙する
// enumerate_classes.js - List all loaded classes
Java.perform(function() {});  // N/A for iOS

// iOS uses ObjC runtime
if (ObjC.available) {
    var classes = ObjC.classes;
    for (var className in classes) {
        if (className.indexOf("Target") !== -1 ||
            className.indexOf("Auth") !== -1 ||
            className.indexOf("Crypto") !== -1) {
            console.log("[Class] " + className);

            // List methods
            var methods = classes[className].$ownMethods;
            for (var i = 0; i < methods.length; i++) {
                console.log("  [Method] " + methods[i]);
            }
        }
    }
}
frida -U -n TargetApp -l enumerate_classes.js
ステップ 3:frida-trace でメソッド呼び出しをトレースする
# Trace all methods of a class
frida-trace -U -n TargetApp -m "*[TargetAuth *]"

# Trace specific patterns
frida-trace -U -n TargetApp -m "*[*Crypto* *]"
frida-trace -U -n TargetApp -m "*[*KeyChain* *]"
frida-trace -U -n TargetApp -m "*[*Token* *]"

# Trace Swift methods (mangled names)
frida-trace -U -n TargetApp -m "*[*$s*Auth*]"
ステップ 4:メソッドをフックして動作を変更する
// hook_auth.js - Intercept authentication logic
if (ObjC.available) {
    // Hook Objective-C method
    var AuthManager = ObjC.classes.AuthManager;
    if (AuthManager) {
        Interceptor.attach(AuthManager["- validateToken:"].implementation, {
            onEnter: function(args) {
                // args[0] = self, args[1] = selector, args[2+] = method args
                var token = new ObjC.Object(args[2]);
                console.log("[Auth] validateToken called with: " + token.toString());
            },
            onLeave: function(retval) {
                console.log("[Auth] validateToken returned: " + retval);
                // Optionally modify return value
                // retval.replace(ptr(1));  // Force return true
            }
        });
    }

    // Hook CommonCrypto for encryption analysis
    var CCCrypt = Module.findExportByName("libcommonCrypto.dylib", "CCCrypt");
    if (CCCrypt) {
        Interceptor.attach(CCCrypt, {
            onEnter: function(args) {
                this.operation = args[0].toInt32();  // 0=encrypt, 1=decrypt
                this.algorithm = args[1].toInt32();  // 0=AES128, 1=DES, 2=3DES
                this.keyLength = args[4].toInt32();
                this.key = Memory.readByteArray(args[3], this.keyLength);
                console.log("[CCCrypt] Op:" + (this.operation === 0 ? "Encrypt" : "Decrypt"));
                console.log("[CCCrypt] Key: " + hexify(this.key));
            },
            onLeave: function(retval) {
                console.log("[CCCrypt] Status: " + retval);
            }
        });
    }
}

function hexify(buffer) {
    var bytes = new Uint8Array(buffer);
    var hex = [];
    for (var i = 0; i < bytes.length; i++) {
        hex.push(("0" + bytes[i].toString(16)).slice(-2));
    }
    return hex.join("");
}
ステップ 5:Swift コードを解析する
// swift_analysis.js - Hook Swift methods
// Swift methods use name mangling: $s<module><class><method>
// Use frida-trace to discover actual mangled names first

if (ObjC.available) {
    // Swift classes that inherit from NSObject are accessible via ObjC runtime
    var swiftClasses = Object.keys(ObjC.classes).filter(function(name) {
        return name.indexOf("_TtC") === 0 || name.indexOf("TargetApp.") !== -1;
    });

    swiftClasses.forEach(function(className) {
        console.log("[Swift] " + className);
        var methods = ObjC.classes[className].$ownMethods;
        methods.forEach(function(method) {
            console.log("  " + method);
        });
    });
}

// For pure Swift (non-ObjC-bridged), use Module.enumerateExports
Module.enumerateExports("TargetApp", {
    onMatch: function(exp) {
        if (exp.name.indexOf("Auth") !== -1 || exp.name.indexOf("Crypto") !== -1) {
            console.log("[Export] " + exp.name + " @ " + exp.address);
        }
    },
    onComplete: function() {}
});
ステップ 6:シークレットと独自データを抽出する
// extract_secrets.js
if (ObjC.available) {
    // Hook NSUserDefaults
    var NSUserDefaults = ObjC.classes.NSUserDefaults;
    Interceptor.attach(NSUserDefaults["- objectForKey:"].implementation, {
        onEnter: function(args) {
            this.key = new ObjC.Object(args[2]).toString();
        },
        onLeave: function(retval) {
            if (retval.isNull()) return;
            var value = new ObjC.Object(retval);
            console.log("[NSUserDefaults] " + this.key + " = " + value.toString());
        }
    });

    // Hook Keychain access
    var SecItemCopyMatching = Module.findExportByName("Security", "SecItemCopyMatching");
    Interceptor.attach(SecItemCopyMatching, {
        onEnter: function(args) {
            var query = new ObjC.Object(args[0]);
            console.log("[Keychain] Query: " + query.toString());
        },
        onLeave: function(retval) {
            console.log("[Keychain] Result: " + retval);
        }
    });
}

主な概念

用語定義
Objective-C Runtimeランタイムでのメソッドディスパッチ、クラスのイントロスペクション、メソッドのスウィズリングを可能にする動的ランタイム
Swift Name ManglingSwift 関数のシグネチャをリンカー互換のシンボル名に変換する、コンパイラーによるエンコード
FairPlay DRMApp Store のバイナリに適用される Apple の暗号化方式。静的解析の前に復号する必要があります
class-dumpヘッダーレベルの解析用に、Mach-O バイナリから Objective-C のクラス宣言を抽出するツール
CommonCryptoApple の C レベルの暗号ライブラリ。Frida のフックによる暗号鍵抽出の主な対象です

ツールとシステム

  • Frida:iOS ランタイムのフックとメソッドのインターセプトに使用する動的計装フレームワーク
  • frida-trace:該当するメソッド向けのハンドラースタブを生成する自動トレースユーティリティ
  • frida-ios-dump:メモリダンプを使用して FairPlay で保護された iOS アプリを復号するツール
  • class-dump / dsdump:Mach-O バイナリから Objective-C ヘッダーを抽出するツール
  • Ghidra:iOS アプリの ARM64 バイナリを静的解析するための NSA のリバースエンジニアリングフレームワーク

よくある落とし穴

  • FairPlay 暗号化:App Store からダウンロードしたアプリは暗号化されています。静的解析の前に復号する必要があります。脱獄済みデバイスで frida-ios-dump を使用してください。
  • Swift のみのクラス:@objc アノテーションのない純粋な Swift クラスは、ObjC.classes からは見えません。代わりに Module.enumerateExports() を使用してください。
  • シンボルが削除されたバイナリ:リリースビルドではデバッグシンボルが削除されます。効果的に解析するには、frida-trace と class-dump の出力を組み合わせてください。
  • Frida 対策:高度なアプリは Frida の痕跡(frida-server プロセス、メモリ内の Frida エージェント文字列、dyld に注入されたライブラリ)を検知します。ステルス性の高い Frida ビルド、または Frida Gadget の注入を使用してください。

コメント