dogtopus/willplus-jig
GitHub: dogtopus/willplus-jig
基于 Frida 的 WillPlus 老版 ADV 游戏引擎动态操控工具,提供脚本 VM 控制、内存标志位操作和存档管理等功能。
Stars: 10 | Forks: 1
# willplus-jig

用于探索和操作较旧的 WillPlus ADV(AdvHD 之前)游戏的 Jig 工具。
## 构建
```
npm install
npm run build
```
要在修改时启用自动构建,请使用
```
npm run watch
```
## 用法
### 在 frida REPL 内部
```
# 生成新进程,附加到该进程并立即恢复执行,使用 V8 runtime。
frida -l willplus-jig.js -f path\to\game.exe --no-pause --runtime=v8
```
所有导出的函数都可以通过 REPL 访问。
### 作为 RPC 代理
将 `willplus-jig.js` 与您的自定义宿主脚本一起加载,然后使用 RPC 访问所有导出的函数。
## 导出函数
- `flagbank_peek(addr)` 和 `flagbank_poke(addr, value)`
- 查看或修改(peek/poke)标志库(flag bank)。
- `flagbank_list_non_zero(from_addr, to_addr)`
- 返回一个 `Map`,包含从 `from_addr` 到 `to_addr` 的所有非零标志及其当前值。
- `rio_traceback()`
- 返回一个包含 RIO 脚本回溯信息的数组(可在脚本执行(sic)错误且未关闭 msgbox 之前使用)。
- `rio_goto(label)`
- 跳转到一个 RIO 脚本。返回值取决于游戏(通常失败为 0,成功为 1)。
- `rio_call(label)`
- 调用一个 RIO 脚本。返回值取决于游戏(通常失败为 0,成功为 1)。
- `rio_register_script(addr, name)`
- 将 `addr` 注册为内存脚本并标记为 `name`。与 `Memory.alloc` 配合使用,以实现临时脚本注入和执行。
- `rio_delete_script(name)`
- 删除(注销)一个内存脚本(**不会显式**释放脚本缓冲区)。如果操作成功则返回 `true`。
- `rio_list_registered_script()`
- 返回所有已注册内存脚本标签的数组。
- `rio_set_pc(pc)`
- 设置 RIO 脚本虚拟机的程序计数器(相对于脚本起始位置)。
- `rio_get_pc()`
- 返回 RIO 脚本虚拟机的程序计数器。
- `rio_get_current_script_buffer()`
- 返回指向当前脚本缓冲区的 `NativePointer`。适用于临时脚本修补。
- `save_persistent()` 和 `load_persistent()`
- 立即保存/加载持久化数据。与标志库操作函数结合使用,以确保修改被保存到磁盘。
- `save_game(index, is_auto)` 和 `load_game(index, is_auto)`
- 立即保存/加载游戏存档。请注意,由于某些未知原因,加载可能会使游戏卡顿一段时间。与标志库操作函数结合使用,以确保修改被保存到磁盘。
- `quick_save()` 和 `quick_load()`
- `{save,load}_game(qsave_index, false)` 的快捷方式
## 支持的游戏
- Haruka ni Aogi, Uruwashi no (Future-Digi zh_TW release)
- Laughter Land (Future-Digi zh_TW release)
- Yume Miru Kusuri (Peach Princess en_US release)
- I/O Revision II (original Japanese release)
### 为新游戏添加支持
通过逆向工程找到一些关键函数和结构的偏移量,并在 `offsets.ts` 文件中添加条目,应该可以支持其他使用类似引擎的 WillPlus 游戏。以下是所有用到的结构和函数列表。
- `will_flagbank`
- 标志库(flag bank)的基地址,用于保存所有临时/持久化标志和寄存器(改变引擎行为的魔法标志)。通常可以通过在 `memset` 存根中搜索 `c=0` 且 `n=2000` 的用法来找到(用于清除所有临时标志)。
- `rio_goto`
- 加载并跳转到特定 RIO 脚本的函数。可以通过搜索解释器并查找 `goto` 指令(操作码 `0x07`)的实现来找到。
- `rio_call`
- 将当前 PC 保存到 RIO 调用栈并调用 `rio_goto` 加载(调用)另一个脚本的函数。可以通过查看 `call` 指令(操作码 `0x09`)的实现,或者交叉引用内部调用 `rio_goto` 的函数来找到。
- `rio_current_script`
- 指向当前加载脚本的指针。可以通过查看 `rio_goto` 的实现来找到(提示:它通常在做任何其他事情之前会 `free()` 先前加载的脚本)。
- `rio_pc`
- RIO 脚本虚拟机的程序计数器。包含指向 `*rio_current_script` 内部某处的指针。可以通过查看解释器中递增的指针来找到。
- `rio_sp`
- RIO 脚本虚拟机的调用栈指针。通常包含一个 0 到 7 之间的数字(因为栈大小通常为 8)。可以通过查看 `rio_call` 的实现来找到。
- `rio_stack_base`
- 调用栈的基地址。可以通过查看 `rio_call` 的实现来找到。
- `rio_event_id`
- 当前正在执行脚本的“Event ID”。会在 `rio_traceback()` 中打印。可能被引擎用作标记已读文本的方式。可以通过查看 `event_id` 指令(操作码 `0x8c`)的实现来找到。
- `rio_current_label`
- 脚本的当前名称(标签)。可以通过查看 `rio_goto` 实现中的 `memcpy`(可能被内联)来找到。
- `save_persistent` 和 `load_persistent`
- 持久化数据操作。搜索关于 `save00` 或 `save000` 的引用。
- `save_game` 和 `load_game`
- 存档操作。搜索关于 `save` 和 `asave` 的引用。
- `engine_malloc_stub` 和 `engine_free_stub`
- 引擎的 `malloc` 和 `free` 实现。
- `qsave_index`
- 快速存档文件的硬编码槽位索引。搜索带有硬编码槽位索引的 `save_game` 和 `load_game` 调用。
标签:ADV游戏, CMS安全, CTF安全工具, DNS 反向解析, Docker支持, Frida, Hook技术, JARM, JavaScript, MITM代理, RIO脚本, Runtime Manipulation, Visual Novel, WillPlus引擎, Windows游戏, 云资产清单, 作弊工具, 内存修改, 内存分析, 数据可视化, 游戏修改, 游戏逆向, 脚本注入, 自动化攻击, 逆向工程, 高性能