dogtopus/willplus-jig

GitHub: dogtopus/willplus-jig

基于 Frida 的 WillPlus 老版 ADV 游戏引擎动态操控工具,提供脚本 VM 控制、内存标志位操作和存档管理等功能。

Stars: 10 | Forks: 1

# willplus-jig ![Quick frida-compile check](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/e132b8e1b9232537.svg) 用于探索和操作较旧的 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游戏, 云资产清单, 作弊工具, 内存修改, 内存分析, 数据可视化, 游戏修改, 游戏逆向, 脚本注入, 自动化攻击, 逆向工程, 高性能