SaoMoLa
VRChat Avatar extraction and upload platform
- 语言:
C· ★ 1 · 创建于 2026-07-14 - 仓库:https://github.com/dwgx/SaoMoLa
VRChat Avatar/World 一键提取工具。从 VRChat 崩溃转储中恢复 AES-256 加密密钥,解密 Unity 6 DWR 缓存文件,导出 FBX/PNG/JSON。
快速开始
首次配置(一次性,需管理员)
# 配置 Windows 在 VRChat 崩溃时自动写完整内存转储
saomola dump-config --enable
提取流程
# 1. 正常启动 VRChat → 进公开房间 → 等 avatar 加载(30秒)
# 2. 管理员 cmd 杀掉 EAC:
taskkill /F /IM EasyAntiCheat_EOS.exe
# 3. 等 30-60 秒 VRChat 自行崩溃
# 4. 扫描崩溃转储提取密钥:
saomola dump-scan D:\Project\SaoMoLa\dumps\ --verify
# 5. 解密 + 提取所有缓存的 avatar:
saomola grab --all-cached -o ./output
提取结果
output/
├── Mesh/ ← FBX 模型(含骨骼、BlendShapes)
├── Texture2D/ ← PNG 贴图(diffuse、normal、emission)
├── Material/ ← JSON 材质参数
└── AnimationClip/ ← 动画文件
构建
D:\Software\dotnet\dotnet.exe build src\SaoMoLa\SaoMoLa.csproj
D:\Software\dotnet\dotnet.exe run --project src\SaoMoLa\SaoMoLa.csproj -- --help
全部命令
| 命令 | 功能 |
|---|---|
saomola dump-config --enable |
配置 WER 自动写崩溃转储 |
saomola dump-scan <path> --verify |
扫描 dump 文件找加密密钥 |
saomola dump-watch --auto-grab |
监控 dump 目录,自动扫描+提取 |
saomola grab --all-cached |
用已有密钥解密提取所有缓存 |
saomola grab <avatar_id> |
提取指定 avatar |
saomola grab --latest -n 10 |
提取最近 10 个缓存 |
saomola extract <file> |
提取单个已解密 bundle |
saomola watch |
实时监控 VRChat 缓存目录 |
saomola keys |
从运行中的 VRChat 读取密钥(需内核驱动) |
saomola key-status |
查看密钥缓存状态 |
saomola mcp-server |
启动 MCP 服务器(AI 驱动) |
工作原理
┌─────────────────────────────────────────────────────────────┐
│ VRChat 运行中(公开房间,avatar 已加载) │
└────────────────────────────┬────────────────────────────────┘
│ taskkill /F /IM EasyAntiCheat_EOS.exe
▼
┌─────────────────────────────────────────────────────────────┐
│ VRChat 崩溃 → Windows WER 写完整进程 dump(~10GB) │
│ EAC 已死 → WER 可以正常读取进程内存 │
└────────────────────────────┬────────────────────────────────┘
│ saomola dump-scan
▼
┌─────────────────────────────────────────────────────────────┐
│ 扫描 dump 找 AES-256 密钥 │
│ 算法:UTF-16 Base64 + UTF-8 JSON + 高熵 byte[] 扫描 │
│ 验证:AES-GCM tag 认证(对缓存 bundle 试解密) │
└────────────────────────────┬────────────────────────────────┘
│ saomola grab --all-cached
▼
┌─────────────────────────────────────────────────────────────┐
│ AES-GCM 解密缓存 → Unity AssetBundle 解析 → 导出资产 │
│ Mesh → FBX | Texture → PNG | Material → JSON | Anim → YAML │
└─────────────────────────────────────────────────────────────┘
技术细节
加密方案(VRChat Unity 6 DWR)
- Bundle 格式:UnityFS header(明文)+ AES-GCM 加密的数据块
- 块结构:
[12B IV][4B plaintext_length][ciphertext][16B auth_tag] - 每块 ~64KB
- 密钥:服务器下发的 32 字节 AES-256 key(Base64 编码存在内存中)
密钥在内存中的形态
- IL2CPP String 对象:44 字符 UTF-16 Base64
- 位于
VRCPlayer对象附近(DecryptPlayerEncryptionKey方法 RVA: 0x180D4C7F0) - 堆扫描模式:连续 88 字节 UTF-16,每 char ∈ [A-Za-z0-9+/=],decode 后正好 32 字节
为什么 dump 方法有效
EAC 保护机制:
- ✅ 阻止 ReadProcessMemory(usermode hook on NtReadVirtualMemory)
- ✅ 阻止 MiniDumpWriteDump(ACCESS_DENIED)
- ✅ 阻止 Task Manager dump(0 字节)
- ✅ 检测 testsigning 模式(拒绝启动游戏)
- ✅ Certificate pinning(阻止 MITM)
- ❌ 无法阻止 WER crash dump(当 EAC 进程已被杀死)
项目结构
D:\Project\SaoMoLa\
├── README.md ← 本文件
├── src\
│ ├── SaoMoLa\ ← 主项目
│ │ ├── SaoMoLa.csproj
│ │ ├── Program.cs ← CLI 入口
│ │ ├── DumpKeyScanner.cs ← dump 文件密钥扫描器
│ │ ├── BundleExtractor.cs ← AssetBundle 解析+导出
│ │ ├── VrcCacheDecryptor.cs ← AES-GCM/CBC 解密
│ │ ├── GrabCommand.cs ← grab 命令实现
│ │ ├── WerConfig.cs ← WER 注册表配置
│ │ ├── KeyResolver.cs ← 多路 key 获取调度
│ │ ├── Export\ ← FBX/PNG/JSON 导出器
│ │ └── ...
│ ├── AnimeStudio\ ← Unity AssetBundle 解析引擎
│ ├── AnimeStudio.Utility\ ← 模型转换工具
│ └── AnimeStudio.Libraries\ ← Native DLL
└── dumps\ ← WER 写入的 crash dump
依赖
- .NET 8 SDK
- Windows 10/11(WER 功能)
- VRChat(Steam 版)
已验证成果
- 24 个 AES-GCM 加密 bundle 成功解密
- 30 个 bundle 成功提取
- 21,414 个文件,4.49 GB 总输出
- 1,440 FBX + 4,631 PNG + 1,632 JSON + 13,711 动画