reversing-react-native-apps について
React Native モバイルアプリを分析するための実践的なスキルです。JavaScript バンドルの読解、Hermes バイトコード、実行時の挙動を扱い、セキュリティテスターによるアプリロジックや API、シークレット、ネイティブブリッジの調査を支援します。
主な機能
- 01バンドル形式の識別
- 02JavaScript バンドルの読解と検索
- 03Hermes バイトコードの逆コンパイル
- 04Frida による実行時ブリッジ呼び出しの確認
- 05バイトコードのパッチと再パッケージ
活用シーン
- 01アプリバンドルから API エンドポイントやキーを発見
- 02JavaScript からネイティブモジュールへの呼び出しを確認
- 03許可された評価でバンドルの挙動を変更
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ trilwu/ secskills --skill reversing-react-native-appsインストール後、Claude Code で/reversing-react-native-appsを入力して読み込まれたか確認します。
詳細
React Native アプリのリバースエンジニアリング
React Native アプリは、ネイティブのシェルをまとった JavaScript です。アプリケーションロジックが読み取り可能なバンドルとして含まれているため、これは朗報です。ただし、バンドルが Hermes バイトコードにコンパイルされている場合は、デコンパイラーが必要になり、バージョン互換性の問題が作業の大半を占めます。
使用する場面
jadxにReactActivityやReactNativeHostが表示され、アプリケーションロジックがほとんど見当たらない- APK に
assets/index.android.bundleまたはlib/*/libhermes.soが含まれている - IPA に
main.jsbundleが含まれている - RN アプリ内の API エンドポイント、シークレット、ビジネスロジックを見つける必要がある
- JavaScript レベルの動作をパッチまたはフックする必要がある
使用しない場面
- Flutter(
libapp.so、libflutter.so)—reversing-flutter-appsを使用してください - Unity(
global-metadata.dat)—reversing-unity-il2cppを使用してください - ネイティブ Java/Kotlin アプリ —
testing-mobile-applicationsを使用してください - C/C++ で記述されたネイティブモジュール —
analyzing-binariesを使用してください
バンドル形式の特定
この確認ひとつで、作業が 10 分で終わるか 1 日かかるかが決まります。
unzip -j target.apk 'assets/index.android.bundle' -d ./out
file ./out/index.android.bundle
xxd ./out/index.android.bundle | head -2
| 先頭のバイト | 形式 | パス |
|---|---|---|
読み取り可能な JS(var __BUNDLE_START、__d(function) | プレーンな JavaScript | 整形して直接読み取る |
バイナリ、Hermes マジック(リトルエンディアンで c6 1f bc 03) | Hermes バイトコード | デコンパイルする — 下記を参照 |
# Plain bundle: beautify, then it reads like any minified web app
npx js-beautify index.android.bundle -o bundle.js
rg -n 'https?://|api[_-]?key|Bearer |secret|token' bundle.js | head -50
プレーンなバンドルはありがたいものです。__d(function(...) の登録情報からモジュールの境界を特定できます。ソースマップが誤って同梱されていることもあるため(index.android.bundle.map — 必ず確認してください)、アプリケーションロジック全体を確認できます。
Hermes バイトコード
Hermes は JS を独自のバイトコード(HBC)にコンパイルします。バイトコードのバージョンはヘッダーに埋め込まれており、React Native のリリースごとに変わります。これが実務上、最大の障害です。HBC 74 に対応するツールは、HBC 96 を拒否するか、誤って解析します。
# Read the version out of the header before choosing a tool
hbctool disasm index.android.bundle ./disasm # HBC 59, 62, 74 ONLY
hermes-dec ... # decompiler; wider version support
上流の hbctool が対応しているバイトコードバージョンは、59、62、74 の 3 つだけです。それ以外のバージョンでは解析に失敗します。解析エラーを「バンドルが保護されている」と判断する前に、まずヘッダーのバージョンを確認してください。最近の React Native リリースでは通常 74 より新しいため、hermes-dec を使うか、対応する Hermes タグからビルドした hermesc を使用してください。
| ツール | 得られるもの | 注意点 |
|---|---|---|
hbctool | 逆アセンブルと再アセンブル — パッチを適用して再パッケージできます | 対応する HBC バージョンが限られています |
hermes-dec | デコンパイルされた疑似 JavaScript | 読み取り専用で、出力は近似的です |
hasmer | 逆アセンブル/アセンブル、別のバージョン対応範囲 | hbctool がバージョンを拒否した場合に試してください |
どのツールもバージョンを受け付けない場合は、アプリが使用している React Native リリースに対応する hermesc をビルドし、そのツールを使うのが確実です。時間はかかりますが、バージョンが一致します。
出力の活用方法。 不完全なデコンパイルでも、重要な疑問に答えるには十分です。文字列テーブルはそのまま保持されるため、エンドポイント、キー、機能フラグを直接復元できます。
strings -n 6 index.android.bundle | rg -i 'https?://|api|token|secret|firebase' | sort -u
Hermes の文字列テーブルは、ファイル内にある平坦で読み取り可能な領域です。デコンパイルする前に確認してください。多くの場合、それだけで答えが見つかります。
ランタイム解析
RN では、静的解析より Frida を使うほうが早いことがよくあります。注目すべき境界は、JavaScript からネイティブへ呼び出す部分だからです。
# Enumerate the native modules the JS side can reach
frida -U -f com.target.app -l rn-enumerate-modules.js
# Hook the bridge: every JS↔native call, with arguments
# (target the ReactNative bridge / TurboModule dispatch)
objection -g com.target.app explore
有用なフックポイントは、JS ランタイムの fetch/XMLHttpRequest、ネイティブのネットワーキングモジュール(Android の OkHttp — 標準的なピンニング回避手法でフック可能)、AsyncStorage の読み書き、およびアプリが定義する NativeModules.* です。
ここでの TLS インターセプトは一般的です。Flutter と異なり、RN はプラットフォームの HTTP スタックを使用するため、通常のシステム CA とプロキシの設定が機能し、標準的なピンニング回避手法も適用できます。インターセプトに失敗した場合は、独立したトラストストアではなく、ネイティブモジュールのピンニングを疑ってください。
発見事項がよく見つかる場所
React Native アプリでは、いくつかのよくある問題が集中しています。
- バンドル内のシークレット。 API キー、Firebase の設定、サードパーティーの トークンが「コンパイルされているから」という理由で JS に含まれたまま配布されています。Hermes は暗号化ではありません。
- クライアント側の認可。 ロールチェックや機能制限が JS に実装されており、 簡単にパッチを適用できるか、API を直接呼び出すだけで無視できます。
- 認証情報の保存先としての
AsyncStorage。 デフォルトでは暗号化されません。トークンや個人情報が 日常的にここへ保存されています。 - 権限が広すぎるネイティブモジュール。 ファイルシステムやシェルへのアクセスを JS に公開するカスタムブリッジメソッドは、 あらゆるインジェクションスクリプトから到達可能です。
- デバッグ用の残存物。 ソースマップ、開発モードのバンドル、
console.logの出力が リリースビルドに残されています。
パッチの適用と再パッケージ化
hbctool disasm index.android.bundle ./work
# edit ./work/instruction.hasm and ./work/metadata.json
hbctool asm ./work index.android.bundle.patched
# replace in the APK, then re-sign
apktool b target -o patched.apk && apksigner sign --ks debug.keystore patched.apk
必要な箇所に限り、許可を得たうえでパッチを適用してください。再パッケージ化すると、 セキュリティ強化されたアプリでは整合性チェックに引っかかります。アプリが自身のバンドルを検証する場合は、編集によって検証を無効化するのではなく、 チェックをフックしてください。
退けるべき言い訳
- 「バンドルはバイナリだから、ロジックは保護されている。」 Hermes はコンパイラーであり、 保護機能ではありません。文字列テーブルだけで API が明らかになることもよくあります。
- 「jadx で何も見つからなかったので、難読化されている。」 dex には何もありません。
assets/を確認してください。 - 「この HBC バージョンに対応するツールがないので、行き詰まった。」 対応する React Native リリースから
hermescをビルドするか、文字列テーブルを読み取ってください。 - 「キーはクライアント側でしか使われない。」 バンドルに含まれているため、公開されています。 バンドル内のシークレットはすべて開示済みとして扱ってください。
- 「アプリがロールチェックを強制している。」 アプリはクライアントです。ロールチェックなしで API を呼び出し、 サーバー側でチェックされることを確認してください。
参考資料
testing-mobile-applications— より広範な評価、ストレージ、プラットフォームに関する問題testing-apis— バックエンド。実際の発見事項がある場所ですreversing-flutter-apps— もう一つの一般的なクロスプラットフォームフレームワーク- hbctool、hermes-dec、hasmer、Frida/objection、jadx、apktool