> For AI agents: the complete documentation index is available at https://renmori.mewbaka.cn/ja/llms.txt, the full documentation bundle is available at https://renmori.mewbaka.cn/ja/llms-full.txt.

# 既存手法の調査

このページには、本プロジェクトが車輪の再発明をしていないことを示すため、既存の手法を記録しています。調査日：2026-10-29。

## 概要

ビルドごとに多態化し、Ren'Py スクリプト、すべてのアセット、エンジンを同時にカバーする、**商用レベルの汎用的な Ren'Py 向け保護ツールは存在しません**。この空白は現実のものです。公開されているツールはすべ&#x3066;_&#x653B;撃側_（アンパッカーとデコンパイラ）に属しており、わずかな保護の試みもプロトタイプにとどまるか、1 つの層しかカバーしていません。

## Ren'Py 自体の形式の仕組みとその弱さ

- **`.rpa` アーカイブ**はインデックスとファイルを連結したものにすぎず、せいぜい XOR による「難読化」の鍵があるだけで、暗号化はされていない
- **`.rpyc` スクリプト**は、Ren'Py の AST を pickle にして zlib で圧縮したもの
- Ren'Py の公式ガイダンスは、難読化は気軽な閲覧を防ぐにすぎず「ある程度の技術を持つプログラマーなら容易に破れる」としている。主任開発者はアセット暗号化の要望（renpy/renpy#2546）を実現不可能としてクローズした。ゲームは実行時に自身のアセットを読み込まなければならず、アンパックに必要なものはすべてゲームと共に配布されるうえ、アセットはいずれにせよメモリや画面から取得できるためである

## 攻撃側のツール（保護済みビルドが無効化すべき対象）

| ツール       | 機能                                  | 備考                                                        |
| --------- | ----------------------------------- | --------------------------------------------------------- |
| `unrpa`   | `.rpa` アーカイブを展開                     | RPA-1.0 から 4.0 とその派生形式に対応                                 |
| `rpatool` | `.rpa` アーカイブの作成、一覧表示、展開、編集          | 任意の XOR 鍵でパック可能                                           |
| `RenPack` | RPA-2.0/3.0/3.2（XOR を含む）向けの GUI/CLI | アーカイブを読み込み、_書き換え&#x308B;_&#x3053;ともできる                    |
| `RenpyEx` | 純粋な Rust による `.rpa`/`.rpyc` 抽出ツール   | **`options.rpy` から鍵を自動検出**し、SHA-256 で検証して、バイト単位で正確な出力を目指す |
| `unrpyc`  | `.rpyc` をデコンパイル                     | `--try-harder`、および `un.rpyc`/`bytecode.rpyb` によるプロセス内への注入 |
| `rpycdec` | `.rpyc`/`.rpymc` をデコンパイル            | 偽の `renpy`/`store` パッケージを構築し、pickle がデシリアライズできるようにする      |

### unrpyc の難読化解除が実際に扱えるもの

以下は `deobfuscate.py` に基づく内容です。どのような単純な改変が無意味であるかを示すため、重要な情報です。

- **スロット抽出器**（順に試行）：標準の `RENPY RPC2` ヘッダー、ヘッダーのない旧形式（ファイル全体が 1 つの zlib ブロック）、`extract_slot_headerscan`（マジックが変更またはずらされている場合に 36 バイトのヘッダーパターンを走査）、`extract_slot_zlibscan`（**ヘッダーが破壊されている場合に、チェックサムが有効な zlib の開始バイト `0x78` を走査して候補を展開**）
- **多層のペイロードデコーダー**（`DECRYPTORS`）：最大 10 層で、各層の後に pickle の読み込みを再試行する。`decrypt_zlib`、`decrypt_hex`、`decrypt_base64`、`decrypt_string_escape`

**示唆：** マジックバイトの変更、ヘッダーのずらし、ペイロードの zlib/base64/hex/エスケープによるラップは、いずれも unrpyc を阻止**できません**。特に zlib スキャナーはヘッダーに対する小細工を無効化します。本当に無効化するには、標準の pickle/zlib 形式から完全に離れ（独自の AST 形式）、_さら&#x306B;_&#x30AF;ラスとフィールドのレイアウトをビルドごとに変える必要があります。そうすれば「偽の renpy モジュール」という手法は結び付ける対象を失います。

## これまでの保護の試み

- **ichfly/renpy-Asset-Protect**：鍵を用いるローダーと付属の C 実行ファイル（AES + SHA-256）によってアセットのみを保護する。品質はプロトタイプの段階で、鍵テーブルがハードコードされ、デバッグ用のファイル書き出しも含まれる。作者は**DRM ではない**と明言し、この手法は容易に回避されると述べているが、何の工夫もなくそのままダンプされるよりはましだとしている
- **コミュニティの言い伝え**（Lemmasoft、知乎）：`.rpa` の名前の変更、16 進エディタによるヘッダーの編集、画像ファイル内へのスクリプトの隠蔽、エンジンが読み込むアーカイブのホワイトリスト化など。いずれも容易に回避されるか、検証されていない

## 公式とコミュニティの見解

- renpytom（Ren'Py の主任開発者）：アセットの完全な暗号化は「不可能」であるとして機能要望をクローズした。また、エンジンや OS のアップデートでゲームが動かなくなった際に修正が難しくなるため、難読化&#x306F;_&#x884C;わないよ&#x3046;_&#x52E7;めている
- uyjulian（コントリビューター）：複雑なアーカイブ形式であっても、実行中のゲームのメモリのダンプや画面のキャプチャによって破ることができる（NinjaRipper、KrkrExtract を参照）。注入型の抽出ツールを本当に阻止するにはカーネルレベルのアンチチートが必要になる
- unrpyc のメンテナー：「いたちごっこ」であることを明確な理由として、特定のゲームの難読化解除を求める機能要望は受け付け**ない**

この最後の点こそが RenMori の戦略上の突破口です。汎用ツールにゲームごとの対応を組み込む者がいない以上、**「ビルドごとに異なる」ことはそれだけで持続的な優位性となります。**

## 設計に反映された結論

1. RPA と標準の rpyc/pickle 形式から完全に離れる：ヘッダーやエンコードの小細工はすでに `unrpyc` が対処している
2. ビルドごとの多態化が中核となる価値であり、都合のよいことにランタイムのコストがゼロであるため、パフォーマンス優先の方針に合致する
3. ユーザーに誠実であること：成果は「汎用的なアンパッカーが存在せず、ゲームごとに専門家のコストがかかる」ことであり、「解析不可能」であることではない（[脅威モデル](https://renmori.mewbaka.cn/ja/technical/threat-model.md)を参照）

## 出典

- Ren'Py のアセット暗号化の要望（実現不可能としてクローズ）：[https://github.com/renpy/renpy/issues/2546](https://github.com/renpy/renpy/issues/2546)
- Lemmasoft「Protect .rpa and .rpyc from unpackers and decompilers」：[https://lemmasoft.renai.us/forums/viewtopic.php?p=389272](https://lemmasoft.renai.us/forums/viewtopic.php?p=389272)
- 旧 Ren'Py Wiki「Obfuscating Your Game」：[https://renpy.org/wiki/renpy/doc/reference/Obfuscating_Your_Game](https://renpy.org/wiki/renpy/doc/reference/Obfuscating_Your_Game)
- unrpyc：[https://github.com/CensoredUsername/unrpyc（\`master\`](https://github.com/CensoredUsername/unrpyc（`master`) の `deobfuscate.py`）
- rpycdec：[https://github.com/cnfatal/rpycdec](https://github.com/cnfatal/rpycdec)
- unrpa：[https://pypi.org/project/unrpa/](https://pypi.org/project/unrpa/)
- rpatool：[https://github.com/Shizmob/rpatool](https://github.com/Shizmob/rpatool)
- RenPack：[https://github.com/Kroste/RenPack](https://github.com/Kroste/RenPack)
- RenpyEx：[https://github.com/rolanfreeman6-png/RenpyEx](https://github.com/rolanfreeman6-png/RenpyEx)
- ichfly/renpy-Asset-Protect：[https://github.com/ichfly/renpy-Asset-Protect](https://github.com/ichfly/renpy-Asset-Protect)
