mcpField
R
re-frida

re-frida

github.com/dslsdzcセキュリティ20660 回インストール2 週間前に更新
リポジトリ

re-frida について

re-fridaは、Fridaを使ったモバイルおよびデスクトップ対象の許可済み動的解析スキルです。関数のフック、実行時の列挙、隔離環境での分析手順を扱います。

主な機能

  1. 01関数のフックと引数・戻り値の変更
  2. 02実行時クラス、モジュール、エクスポートの列挙
  3. 03Javaメソッド呼び出しのトレース
  4. 04Android、iOS、デスクトップ対象の分析
  5. 05objectionによる簡易インストルメンテーション

活用シーン

  1. 01関数の実行時の入出力を調べる
  2. 02アプリ起動時の動作を追跡する
  3. 03ロード済みクラスやネイティブモジュールを調べる
  4. 04管理されたテスト環境で証明書検証を調べる

インストール

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

$npx skills add https://github.com/dslsdzc/rev-skills --skill re-frida

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

同梱ファイルreferences/frida-scripts.md

詳細

Frida 動的計装

使用する場合/しない場合

  • 使用する:関数をフックする必要がある場合(インターセプト/引数の変更/戻り値の変更)、モジュールやクラスの列挙、証明書検証/root 検出の回避、ランタイムの呼び出しチェーンの観察
  • 使用する:モバイル(Android/iOS)とデスクトップ(Linux/macOS/Windows)で統一された計装が必要な場合
  • 使用しない:静的解析のみで十分な場合(Android は [[re-apk]]、フォーマットは [[re-format-elf]]/[[re-format-macho]] シリーズを使用)
  • 使用しない:システムコールレベルのトレースが必要な場合([[re-tracing]] を使用)
  • 使用しない:完全なデバッガーの使用感(ブレークポイント/ステップ実行/メモリ)が必要な場合([[re-gdb]]/[[re-lldb]]/[[re-x64dbg]] を使用)

ツールの準備

動的解析では、[[re-analyze/platform-tips]] の最優先原則に従います。モバイル端末では管理下のデバイス/エミュレーターのスナップショット内で実行し、デスクトップでは計装の前にサンドボックス環境を確認します。すべてのツールは使用前に検証してください。

frida-tools —— ホスト側のコマンドラインツール
  • クロスプラットフォーム(Linux/macOS/Windows):pip install frida-tools(Python 3.8+。venv の使用を推奨:python3 -m venv venv && venv/bin/pip install frida-tools)
  • 検証:frida --version(frida のバージョン番号が出力されます);frida-ps -U/frida-trace -h が使用できること
frida-server —— モバイル端末用の計装プロキシ
  • ダウンロード:GitHub release https://github.com/frida/frida/releases から frida-server-<バージョン>-android-<アーキテクチャ> を選びます(arm64 は -arm64、32 ビットは -arm、エミュレーターの x86_64 は -x86_64)
  • クライアントと frida-server は、少なくとも major が一致している必要があります(frida --version と照合)。機能/API の差異を避けるため、完全に同じ最新バージョンの使用を推奨します。アーキテクチャがデバイスと一致しない場合、接続時にプロトコルエラーが発生します(落とし穴 1 を参照)
  • Android へのプッシュと起動:
    adb push frida-server-xxx /data/local/tmp/frida-server
    adb shell "chmod 755 /data/local/tmp/frida-server"
    adb shell "su -c /data/local/tmp/frida-server" &   # 或 adb root 后直接运行
    
  • 脱獄済み iOS デバイス:Sileo/Cydia にソース https://build.frida.re を追加して frida deb をインストールするか、ssh root@<設備IP> で接続してインストールします
  • 検証:ホストで frida-ps -U を実行し、デバイスのプロセスが表示されること(-U = USB デバイス、-R = リモート ip:port)
objection —— JS を書かずにすばやく計装
  • Python >=3.10 が必要です(frida 自身の binding の下限 >=3.7 とは異なるため、別途満たす必要があります):python -m pip install -U objection。Python 3.10 以上の venv を別途作成するか、pipx による分離を推奨します
  • 検証:objection --version
  • 使用方法:objection -n <アプリまたは Bundle ID> start。android hooking/ios hooking サブコマンドが組み込まれています(例:android hooking list activities、ios sslpinning disable)
  • 1.12.x 以降、-g/explore は非推奨です(CLI では非表示になり、非推奨の警告のみ表示されます。旧形式でも引き続き実行できます)。新しい記述では -n と start を使用します

操作手順

順番に実行し、各ステップの結果を記録します。

  1. spawn と attach の選択:

    frida -U -f com.target.app              # spawn:从零启动应用,能抓启动早期逻辑(解密 / 初始化)
    frida -U com.target.app                 # attach:附加到已运行进程(不重启)
    frida-trace -U -f com.target.app -i "Java!*"   # 启动即跟踪 Java 方法调用
    

    ルール:起動時のロジックを捕捉する/早期検出を回避する場合は spawn を使用します。現在の状態を観察するだけの場合は attach を使用します。attach は起動後に行われるため、実行済みの早期ロジックを見逃す可能性があります(落とし穴 2 を参照)。

  2. JS hook の作成(インターセプト/引数の変更/戻り値):

    // hook.js —— 拦截、改参数、改返回值(Android Java 层)
    Java.perform(function () {
      var cls = Java.use("com.example.Target");
      cls.doLogin.implementation = function (user, pass) {
        console.log("doLogin(" + user + ", " + pass + ")");
        return this.doLogin("hacked", "pass123");   // 改参
      };
      cls.isLicensed.implementation = function () {
        return true;                                // 改返回值
      };
    });
    
    frida -U -f com.target.app -l hook.js
    

    ネイティブ関数は Interceptor.attach(Process.getModuleByName("libfoo.so").findExportByName("func"), { onEnter: ..., onLeave: ... }) でインターセプトします(onEnter で引数を変更し、onLeave で retval.replace() を使って戻り値を変更します)。デスクトップでも同じスクリプトを使用できます:frida -p <pid> -l hook.js。

  3. 列挙と呼び出し(enumerateModules / Java.perform):

    Java.perform(function () {
      Java.enumerateLoadedClasses({
        onMatch: function (c) { if (c.indexOf("target") >= 0) console.log(c); },
        onComplete: function () {}
      });
    });
    
    // 模块与导出枚举(原生层)
    Process.enumerateModules().forEach(function (m) { console.log(m.name + " " + m.base); });
    Process.getModuleByName("libfoo.so").enumerateExports().forEach(function (e) { console.log(e.name); });
    

    実行:frida -U -f com.target.app -l enum.js。対象を特定したら、直接呼び出します:Java.use("com.x").method(...)/ネイティブのエクスポート関数。

  4. 証明書検証/検出の回避(一般的なテンプレート):

    // Android SSL 绕过模板(配合抓包工具)
    Java.perform(function () {
      var X509TrustManager = Java.use("javax.net.ssl.X509TrustManager");
      var TrustAll = Java.registerClass({
        name: "com.bypass.TrustAll",
        implements: [X509TrustManager],
        methods: { checkClientTrusted: function () {}, checkServerTrusted: function () {},
                   getAcceptedIssuers: function () { return []; } }
      });
      var SSLContext = Java.use("javax.net.ssl.SSLContext");
      SSLContext.init.implementation = function (km, tm, sr) {
        this.init(km, [TrustAll.$new()], sr);
      };
    });
    
    // iOS 证书绕过:hook SecTrustEvaluateWithError 返回值
    var SecTrust = Module.findGlobalExportByName("SecTrustEvaluateWithError");   // Frida 17+:全局符号静态查找
    Interceptor.attach(SecTrust, { onLeave: function (r) { this.context.x0 = 0; } }); // arm64 返回寄存器 x0;x86_64 用 rdi 场景先验证
    

    既成のコマンド:objection -n com.target.app start → android sslpinning disable/ios sslpinning disable。

  5. 検出対策(frida-server の隠蔽、名前の変更):

    • 一般的な検出箇所:frida-server のデフォルトポート 27042、/data/local/tmp/frida-server のパス、gum-js-loop/gmain のスレッド名、/proc/self/maps 内の frida の特徴、frida 文字列
    • 対策:
      # 1) バイナリの名前を変更してから起動(パス検出を回避)
      cp frida-server-xxx /data/local/tmp/fridad
      adb shell "su -c 'chmod 755 /data/local/tmp/fridad && /data/local/tmp/fridad' &"
      # 2) ポートを変更し、adb のポートフォワーディングを設定。ホストからは -H で接続
      adb shell "su -c '/data/local/tmp/fridad -l 0.0.0.0:27142' &"
      adb forward tcp:27142 tcp:27142
      frida -H 127.0.0.1:27142 -f com.target.app
      
    • root 検出への対策:検出関数をフックして戻り値を変更してから、対象を計装します:Java.use("com.target.rootcheck").isRooted.implementation = function () { return false; };
    • それでも検出される場合 → frida-gadget を App プロセスに注入します(gadget の listen(interactive)モード)。[[re-apk]] の smali パッチと組み合わせて libgadget.so を読み込みます
  6. スクリプトテンプレートと対策の方法論:よく使うスクリプトの骨組みは [[frida-scripts]] を参照してください(TLS keylog/DEX/SO ダンプ/JNI 登録の復元/暗号化のインターセプト/検出回避一覧)。クラッシュを繰り返す方法と検出対策の比較表は [[re-analyze/anti-dynamic-workflow]] を参照してください。まずベースラインを実行して通常のクラッシュを確認し、その後に対象を絞って hook します。あらゆる回避策をあらかじめ一括で適用しないでください。

分野横断の連携

  • [[re-address-space]]:ランタイムのベースアドレス換算(Process.getModuleByName(...).base とリンクアドレスの対応)

  • [[re-mobile]]:ワークフローのステップ 3 では、動的計装に本スキルを固定で使用します

  • [[re-apk]]/[[re-ios]]:静的解析後にランタイムの動作(復号/hook/回避/パッケージ解除して実行)が必要な場合は、本スキルを使用します

  • システムコールレベルのトレースとの相互補完 → [[re-tracing]];ランタイムメモリの抽出 → [[re-memdump]]

  • 本スキルは [[re-analyze]] の triage「モバイル App 解析」パスから呼び出されます(re-mobile → re-frida)

  • スクリプト生成:対象の特徴 → テンプレートの選択 → 書き換えと検証 → [[re-frida-script-author]](テンプレート素材 [[frida-scripts]])

よくある落とし穴と注意点

  • 版本不匹配 → 协议错误:现象——frida-ps -U 报 unable to communicate with the frida server / 协议错误;原因——客户端与 frida-server major 不一致,或所用的功能在目标版本上不存在;对策——先查 major 是否匹配(frida --version 对照 frida-server 版本,见工具准备),再确认该功能是否被对应版本支持;升级侧用 pip install -U frida-tools
  • Frida 17 移除静态 Module 查找/枚举 API:现象——脚本报 TypeError: Module.findExportByName is not a function(或 getExportByName / enumerateExports / findBaseAddress 同类);原因——17.0.0 起静态查找与枚举 API 全部移除,静态只余 Module.load / Module.findGlobalExportByName / Module.getGlobalExportByName,其余改为模块实例方法;对策——先取实例再查:Process.getModuleByName("libfoo.so").findExportByName("func")(find 返 null,get 抛异常)、基址用 .base、枚举用 .enumerateExports();全局符号(原 null 模块参数)改用 Module.findGlobalExportByName(...);注意 Process.getModuleByName 在模块未加载时抛异常(旧 Module.findExportByName 返 null)——不确定时先用 Process.findModuleByName 判空再查;动笔前 frida --version 确认版本再选写法(迁移清单见 [[re-frida-script-author]] 版本相关组)
  • spawn 时机晚 → 错过早期逻辑:现象——attach 后 hook 不触发或早期解密已完成;原因——应用启动即解密 / 校验,attach 时已过;对策——用 -f spawn 模式起步即插桩;仍错过则 hook dlopen / ClassLoader.loadClass 这类更早的执行点
  • 目标检测 frida(端口 / 特征):现象——spawn 后应用闪退 / 卡死 / 行为异常;原因——应用扫描 27042 端口、frida-server 路径、frida 线程名或 maps 特征;对策——步骤 5 改名 + 换端口;仍检测用 frida-gadget 注入(隐藏于进程内)
  • root 检测拦插桩:现象——frida 可连接但 hook 不生效或直接退出;原因——应用先做 root / 越狱检测,检测到环境直接退出;对策——先 hook 检测函数返回值(步骤 5 模板),过了检测再 hook 目标函数
  • JS 脚本静默失败:现象——脚本加载无报错但 hook 无输出;原因——类名写错、Java.perform 外调用 Java API、模块名大小写不符;对策——用步骤 3 的枚举先核对名称,脚本内 console.log 打桩定位
  • hook 导出 API 被壳绕过(直 syscall / API 名哈希):现象——成功 hook 了 IsDebuggerPresent/NtQueryInformationProcess 等导出,反调试照样触发、进程退出;原因——加壳/加固目标不走导入表:自实现 GetProcAddress、API 名存哈希,或直接 syscall(内联 Nt* 直调),hook 点根本没经过;对策——hook 更深一层(ntdll 的 syscall 包装点)、跟踪 GetProcAddress/哈希解析处反推真实调用点,反调试与反 VM(RegOpenKeyExA/GetSystemFirmwareTable)API 一并 hook(Arkana 项目实战模板),先用 Process.enumerateModules()/enumerateExports 确认实际调用目标再插桩
  • 检测点升级(memfd/JIT 池/内存字符串/管道名):现象——改名、换端口启动 frida-server 后仍被检测;原因——新版检测不止端口与路径:扫描 /proc/self/fd 的 memfd 名称、JIT 缓存池(pool-frida)、frida_agent.so/frida_rpc 等内存字符串与导出符号、管道/linjector 名称,甚至非标准端口也会被扫(Promon 式扫描);对策——用 undetected-frida 补丁集(字符串/符号/线程/协议/memfd/JIT 池全量混淆,Magisk/KSU 模块形态),或 frida-gadget + 自编译隐藏版,缩小指纹面
  • 强加固(Pairipcore 类)整体对抗 Frida:现象——常见 hook 脚本(证书绕过/反检测/解密)全部失效,spawn 即闪退或行为异常,社区报告 frida-interception 类脚本无法绕过;原因——商业加固做 C++/Java 双层完整性校验 + 伪 VM 指令 + 自定义 dlopen/dlsym/syscall 动态导入混淆 + prctl/clone/waitpid/ptrace 反调试 + /proc/self/maps+/proc/self/status 进程监控 + 非标准端口扫描,整体防线而非单点;对策——先处理完整性校验与进程监控(hook 校验函数返回、patch 监控点)再过反调试,hook 落到自定义导入解析处而非导出 API,必要时结合 [[re-apk]] 静态改 smali + Native 层插桩配合
  • hook 出口函数多进程/多实现排查:现象——hook SocketOutputStream 无结果,抓包却看到流量;原因——应用多进程(发流量的逻辑在子进程)或使用 Netty 的 SocketChannelImpl(不走 OutputStream 路径);对策——排查顺序:hook 最外层出口 → 无果 ps -e 查子进程分别 hook → 再试 SocketChannelImpl 等替代实现;hook 成功后打印堆栈(Netty 的 MessageToByteEncoder 链)定位组装/加密代码;从"编解码器链"逐层向上追明文对象与加密产物
  • 对称加密密钥传输追踪:现象——抓到 RC4/AES 密文包,但密钥每次会话都变、静态搜不到;原因——对称加密密钥动态生成且在线传输(明文/加密后携带/协商);对策——hook 密钥传入处(加密函数参数 bArr 类)拿当前密钥,再向上追踪密钥来源与传输路径,配合抓包对照(首包固定头如 89 04 01 01 可作协议锚点)
  • 多层 TLS 校验栈:现象——单点 hook 后部分请求仍 SSL 错误;原因——App 同时用 OkHttp/原生 HttpsURLConnection/Conscrypt 多套栈;对策——分层覆盖(OkHttp CertificatePinner + TrustManagerImpl.verifyChain + HostnameVerifier 同时 hook),全栈覆盖才算绕过完成
  • ProGuard 混淆后定位目标类:现象——类名被改成短名;原因——混淆;对策——jadx 里 Find Usages 反查谁实例化关键 Builder,从实例化点反推原类 (来源:reverse-skill field-journal,MIT)
  • 测试环境选错 → 动态假阴性 / 交付假阳性:现象——同一环境里 hook 不触发、内存 patch 无效果,或模拟器一切正常但换真机就出问题;原因——x86 翻译层模拟器上 live Frida 不可用(Process.arch==x64 且找不到目标原生 so),运行时从未执行你的字节;部分目标在模拟器上校验宽松,「模拟器能跑」可能是降级假象;对策——按阶段选环境:静态 patch 与渲染回归可用任意模拟器(含 x86 翻译层),动态插桩必须原生 ARM,交付验证必须与目标匹配的真机;翻译层假象可证伪:把已知必需函数首指令 patch 成裸 ret,UI 照常渲染即运行时没执行你的字节,立即停掉该环境的 live 工作(盘上静态 patch 下次启动重新翻译仍可用);真机采集前 svc power stayon true 并唤醒,防睡眠屏造成「空白」假截图 (来源:reverse-skills(inliver233),MIT)
  • redroid 容器搭建与使用坑:现象——guest 静默挂死 / servicemanager 空转、vold 崩溃、adb 反复掉线、容器无法重启;原因——binder 挂载方式错误(必须 bind-mount /dev/binder,不能用 --device 或 binderfs)、新内核无 ashmem 时未加 androidboot.use_memfd=1、设了 ro.secure=1 ro.debuggable=0 杀掉 root adb、停掉的容器 binder 已消失无法 docker restart、adbd 高负载下崩溃;对策——binder 用 bind-mount、新内核强制 use_memfd、保留 root adb(防篡改用保持签名有效而非藏 root)、重建容器后重注入 adb 公钥(echo $PUBKEY > /data/misc/adb/adb_keys)、大文件用 docker cp 而非 adb push、动态分析用 spawn 模式(frida -U -f,attach 在防篡改下常 0 命中);定位认知——它是数据采集工具而非迭代环境,采完动态数据回稳定环境做静态 patch 回归 (来源:reverse-skills(inliver233),MIT)
  • AOT 目标上 hook 静默不触发 / 找不到调用者:现象——hook 无输出、目标函数静态 callers=0、门字段未知无法下针;原因——目标 so 晚于引擎加载(attach 时未加载)、虚方法经 cid 分派墙(不经 BL 调用,静态无捷径)、guard 字段位置未知;对策——等目标 so 加载后再 hook:200ms 轮询 findModuleByName 的 waitForLibapp 包装器,起步优先 spawn 模式;破 cid 墙:目标函数 onEnter 记 lr(returnAddress)+ Thread.backtrace(Backtracer.ACCURATE) 前 20 帧,一次回溯定位分派点;guard 定位三件套:Stalker.follow transform 里对 ldr 类指令放 putCallout(首个命中 PC = guard)、MemoryAccessMonitor.enable 等重建触发(arm64 支持不一需回退)、候选 hook 扫射;运行时翻转验证前置:live writePointer 翻转候选门字段 → 触发重建 → 组件消失即确认门字段,确认后再投静态 patch,省掉反复重打包;frida 17 起 Java bridge 不再内置于底层 GumJS runtime,但 frida CLI/REPL 与 frida-trace 仍自带三个 bridge,普通 frida -l 脚本无需改动;仅自建 agent / 走 bindings 注入脚本时需显式安装 frida-java-bridge(必要时用 frida-compile 打包) (来源:reverse-skills(inliver233),MIT)

コメント