README.md
hohohololive — 公開版
Unity 手遊資源系統的逆向工程紀錄與格式轉換工具。
命名致敬 sssekai。
⚠️ 先讀這段:這是刻意閹割過的版本
這個版本不包含解密。 完整版有,公開版沒有,而且這不是疏漏,是刻意的。
移除了什麼
| 移除 | 內容 |
|---|---|
hohohololive/crypto.py |
金鑰衍生與解密實作 |
ClaudeDocs/REF_ALGORITHM_MATH.md |
演算法的完整數學規格 |
ClaudeDocs/RE_NOTES_CRYPTO.md |
解密過程的逐步紀錄 |
ClaudeDocs/OVERVIEW.md §3 的虛擬碼 |
可直接實作的填充順序、雜湊種子、白化步驟 |
CLI 的 decrypt-bundle / decrypt-audio |
兩個直接解密的子指令 |
scripts/ 整個目錄 |
混著 Frida 解密 hook 與一次性診斷腳本,逐支審不划算 |
ClaudeDocs/GEMINI_TASK.md、DISPATCH_SUPERVISOR.md |
給代理跑的工單,綁死本機路徑、引用未收錄的腳本 |
為什麼不是「只拿掉金鑰,留下演算法」
一開始的計畫是這樣,但這個切法在這裡不成立,值得寫下來:
一般的密碼系統是「公開演算法 + 秘密金鑰」,遮掉金鑰就夠了(Kerckhoffs 原則)。 這裡不是。 這套機制的金鑰是從資產名推導出來的——輸入是檔名,輸出是金鑰表。 推導程序本身就是金鑰,沒有一個獨立的秘密可以拿掉。
而原始實作裡唯一的魔術常數,是一個單一位元組的雜湊種子。在:
- 已知明文就寫在檔頭(
UnityFS、QUAVMAGIC都是固定前綴) - 演算法結構已公開
這兩個條件下,256 種可能的窮舉是微秒級的事。只遮那個常數,降低的工作量是零, 卻會做出一個「看起來遮過、其實沒有」的東西——那比兩個極端都糟,因為它給假的安心感。
所以整個解密層一起移除,而不是做部分遮蔽。
法律上的考量
台灣著作權法 §80-2 第二項禁止提供「主要用於規避防盜拷措施之設備、器材、零件、 技術或資訊」。注意「資訊」二字——它涵蓋的不只是可執行的程式碼,也涵蓋一份 寫得夠清楚、讀完就能自行實作的規格文件。被移除的那幾份文件正是如此。
同條第三項確實有「為達成資訊間之相互操作性所為之還原工程」的例外,但該例外 一般理解為涵蓋進行還原工程,而非公開發佈規避方法。這是灰色地帶,而 作者不是律師,因此採取保守作法。
保留了什麼(而且它們本身就有用)
留下來的是格式解析那一半:輸入是已經解密的資料,輸出是通用格式。這部分 的性質是互通性工作——把封閉格式轉成開放格式,讓資料能在別的工具裡使用。
hohohololive/
├── catalog.py octo 目錄解析 (hash / address / size / objectName)
├── extract.py AssetBundle 抽取,含跨 bundle 的 CAB 依賴解析
├── model3d.py 3D 模型抽取 (mesh / 貼圖 / 骨架 / 材質)
├── gltf.py Unity 頂點串流 → 有綁定的 glTF 2.0 (含 morph target)
├── motion3d.py mot_define_* 動作曲線解碼 (CRC32 名稱還原)
├── animglb.py 把動作併進模型 .glb
├── live2d_motion.py Live2D 動作 → motion3.json (三次 Bezier 轉檔)
├── live2d_expression.py Live2D 表情 → exp3.json
├── live2d_physics.py Live2D 物理 → physics3.json
└── cdn.py 以 objectName 從 CDN 取資源
sim_swing.py 離線重現 ActorSwing 彈簧骨(純 numpy/scipy)
compare_swing.py 模擬 vs 遊戲真值的逐幀角度比對
extract_swing.py 從 bundle 抽彈簧骨參數
彈簧骨那三支放在根目錄而不是套件裡,是因為文件(RE_NOTES_AVATAR.md)
大量引用它們的檔名。它們不碰解密,但物理還沒解完——誤差仍略差於
「完全不做」,細節見 ClaudeDocs/HANDOFF.md。收錄未完成的東西是刻意的:
沒解完的過程和解完的一樣值得讀。
CLI 子指令:catalog-parse unpack-octo build-live2d extract-3d
extract-motions-3d merge-motion extract-motions extract-expressions
輸入必須是已解密的 AssetBundle。 餵密文進去不會產生垃圾:PlaintextGate
會跳過它、計數,並在指令結束時說明一次。
(它一開始寫成「遇到密文就中止」,那是錯的——這些檢查全在批次迴圈裡,
而 SystemExit 不是 Exception 的子類,外層的 except Exception 攔不住,
一個檔案就會丟掉後面所有位址。跳過並統計才是對的形狀。)
文件
ClaudeDocs/ 是完整的逆向報告,以「每章回答一個問題」的方式寫成,包含走過的
死路與後來被推翻的結論——那些才是重點。
OVERVIEW.md— 主報告(§3 的演算法虛擬碼已移除,形狀描述與過程紀錄保留)RE_NOTES_3D.md/RE_NOTES_LIVE2D.md/RE_NOTES_AVATAR.md— 格式逆向的逐步紀錄REF_CHARACTER_ROSTER.md— 角色名冊與資產統計NEXT_STEPS.md/HANDOFF.md— 未完成的部分
一篇關於這次逆向過程的文章:逆向一個 Unity 6 手遊時,我四次以為自己成功了
免責聲明
- 本庫僅包含作者原創的逆向研究文檔與格式轉換工具。
- 不包含任何遊戲資源。 遊戲的音效、影片、模型、貼圖、Live2D 資產等, 著作權均屬其發行商所有,本庫中沒有任何一個 byte 的遊戲素材,也不提供取得管道。
- 本庫不包含規避技術保護措施的實作或規格。
- 本專案供學習、互通性研究、個人備份用途。使用者須自行確認其使用方式 符合所在地法律與相關服務條款;作者不對任何使用行為負責。
- 工具本身以 MIT 授權釋出(見
LICENSE),此授權僅及於作者原創之程式碼與文件。 - 本專案與遊戲發行商無任何隸屬、合作或背書關係。
授權
MIT — 見 LICENSE。