frida-native-hooks について
Frida Native Hooks は、Frida でネイティブ関数やメモリー動作を調査するスキルです。対象の特定から関数の追跡・置換、安全なメモリー操作までを案内します。
主な機能
- 01モジュールの特定と関数アドレスの解決
- 02Interceptor フックによる呼び出し追跡
- 03ネイティブ関数の動作置換
- 04バックトレースと範囲を絞った Stalker 追跡
- 05メモリーに配慮した引数の置換
活用シーン
- 01ファイルまたはネットワーク API 呼び出しの追跡
- 02シンボルが削除された関数の調査
- 03ネイティブ境界関数の呼び出し元の確認
- 04引数の変更または関数動作の置換
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ rudra-ravi/ frida-skills --skill frida-native-hooksインストール後、Claude Code で/frida-native-hooksを入力して読み込まれたか確認します。
同梱ファイルagents/openai.yamlreferences/native-patterns.md
詳細
Frida ネイティブフック
対象がネイティブ関数またはメモリの動作である場合は、このスキルを使用します。
最初に対象を特定する
- プロセスのアーキテクチャとモジュールを特定します。
console.log(Process.arch, Process.platform, Process.pointerSize); for (const m of Process.enumerateModules()) console.log(m.name, m.base, m.size); - 可能な場合は、Frida API を使ってアドレスを解決します。
const mod = Process.getModuleByName("libtarget.so"); const fn = mod.getExportByName("target_function"); - シンボル名が削除されている場合は、まずインポート/エクスポートを検索し、次にシンボル、文字列、バイトパターンを検索します。
- ARM/Thumb では、命令セットの詳細が適切に処理されるよう、Frida API が返すアドレスを優先します。
フックのパターン
const target = Process.getModuleByName("libc.so").getExportByName("open");
Interceptor.attach(target, {
onEnter(args) {
this.path = args[0].readUtf8String();
console.log("[open] path=", this.path);
},
onLeave(retval) {
console.log("[open] fd=", retval.toInt32());
}
});
置換のルール
- トレースや、引数/戻り値の軽微な変更には
Interceptor.attach()を使用します。 - 動作を完全に置き換える場合は
Interceptor.replace()を使用します。 Interceptor.replaceFast()は、オーバーヘッドの低減が必要なホット関数に限って使用し、返されたポインター経由で元の関数を呼び出します。- 元の関数は、正しい ABI、戻り値の型、引数の型を指定して
NativeFunctionでラップします。 - 同じスクリプトから直ちに呼び出す必要があるフックをインストールした場合に限り、
Interceptor.flush()を呼び出します。
実践的なパターン
- 内部処理よりも境界を先にフックします。エクスポートされた API、インポートされた libc/暗号/TLS 呼び出し、ファイル/ネットワーク/システムコールのラッパー、続いてアプリ固有のシンボル名が削除された関数の順です。
- シンボル名が削除されている場合は、静的文字列、インポート、逆アセンブラーのクロスリファレンス、実行時のモジュール読み込みログ、Stalker/呼び出し元のサマリーを組み合わせます。
open、connect、SSL_write、CCCrypt、strcmp、memcmpなどの汎用的な境界を誰が呼び出したかを特定するため、早い段階でThread.backtrace()を使用します。- Stalker は対象を絞った調査にのみ使用します。特定のスレッドの、特定の関数呼び出し中に限定し、命令レベルのトレースに進む前に呼び出し/ブロックのサマリーを確認します。
/proc、ptrace、読み込み済みモジュールのスキャン、スレッド名、ポート、シンボル/文字列のスキャンが関係する場合は、Frida 対策をネイティブ処理として扱います。
メモリの安全性
- バッファーサイズが確認できていない限り、既存のバッファーに長い文字列を書き込まないでください。
- 新しい文字列を割り当てて、ポインター引数を置き換える方法を優先してください。
- 割り当てた置換文字列は、必要な期間中アクセス可能な状態に保ちます。
const keepalive = []; Interceptor.attach(target, { onEnter(args) { const s = Memory.allocUtf8String("replacement"); keepalive.push(s); args[0] = s; } }); - 後で必要になる場合は、コールバック内で
retval/引数のデータをコピーします。
ネイティブ調査チェックリスト
- アドレスを解決する前にモジュールが読み込まれていること。
- 関数シグネチャが、ヘッダー、デコンパイラー、デバッグシンボル、または観測された呼び出し規約から確認されていること。
- ポインターの読み取りが、null と読み取り可能性を確認したうえで行われること。
- ログに、正しい呼び出し経路を確認するのに十分なコンテキストが含まれていること。
- 変更を元に戻す手段があること。フックの解除、元に戻す処理、再起動、または Gadget 設定の削除などです。
参考資料
エクスポート、インポート、パターンスキャン、バックトレース、置換、パフォーマンスに関するテンプレートは、references/native-patterns.md を参照してください。
コメント
Markdown 対応