zipzip11/psp2fuse
GitHub: zipzip11/psp2fuse
psp2fuse 是一个 PS Vita 游戏内作弊与插件加载器,提供原生 overlay、VitaCheat 数据库兼容、内存搜索、反汇编查看和 Lua 脚本扩展功能。
Stars: 1 | Forks: 0
# psp2fuse
**状态:Alpha 版。** 核心 cheat/plugin 加载、Lua 脚本层和游戏内 overlay 目前均可正常工作,并已在真实硬件上测试使用,但功能集尚未最终定稿,且并非每款游戏都经过测试。预计会存在一些不稳定之处。
一个 PS Vita cheat/plugin 加载器。内核模块会检测游戏启动并注入一个用户态模块,该模块会解析按游戏配置的文件、应用 cheat、加载 plugin,并运行 Lua 脚本层。
- `psp2fuse.skprx` (内核):游戏启动 hook、注入及特权 syscall。
- `psp2fuse.suprx` (用户态):在游戏内部运行,负责所有的解析和策略执行。
内核/用户态的分离旨在将所有必须运行在 ring-0 的内容(启动 hook、跨进程 patch、模块注入、原始文件 IO)保持在尽可能小且脆弱的状态;解析、策略、脚本编写和 overlay 全部位于用户态模块中,在这些地方可以使用 C 标准库。
## 玩家指南
来自 VitaCheat/FinalCheat?psp2fuse 会按原样读取你现有的 `.psv` cheat 数据库(参见下方的[支持的 cheat 类型](#cheats)),并添加了一个内置的游戏内 overlay —— 无需 PC 或第二个应用即可切换 cheat、编辑内存和阅读反汇编 —— 此外还有一个 Lua 脚本层,用于实现普通代码 patch 无法表达的功能(条件冻结、热键、小型 debug 工具)。
- **获取 plugin**:预构建的 `psp2fuse.skprx`/`psp2fuse.suprx` 附在此仓库 Releases 页面的每个标记版本中,你也可以自己构建(参见[构建](#build))。
- **安装**:参见[在设备上安装](#install-on-device)。
- **添加 cheat/mod**:将文件放入 `ux0:data/psp2fuse/` 目录下 —— 具体的各游戏路径请参见下方的[功能](#features)。
- **游戏内**:L+R+SELECT 打开 overlay 以实时切换 cheat;START 暂停游戏;L/R 切换标签页。
## 构建
需要 VitaSDK。如果未导出 `VITASDK`,请手动设置:
```
export VITASDK=/opt/vitasdk
cmake -S . -B build
cmake --build build -j
```
输出:
- `build/kernel/psp2fuse.skprx`
- `build/user/psp2fuse.suprx`
- `build/kernel/libpsp2fuse_stub.a`
- `build/kubridge/kubridge.skprx`
CI 会通过 GitHub Actions 在每次推送/PR 时进行构建,并自动发布带有标签的 release。
### 通过 FTP 部署
在 VitaShell 的 FTP 服务器运行的情况下:
```
cmake --build build --target deploy # modules -> ux0:/tai/ and ux0:/data/psp2fuse/
cmake --build build --target deploy-config # sample config tree -> ux0:/data/psp2fuse/
```
默认主机为 `192.168.1.100:1337`;可通过 `-DPSVITAIP=... -DPSVITAPORT=...` 覆盖。
你仍需自行在 `ur0:tai/config.txt` 的 `*KERNEL` 下注册 `psp2fuse.skprx`。
## 在设备上安装
1. 将 `psp2fuse.skprx` 复制到 Vita,并在 `ur0:tai/config.txt` 的 `*KERNEL` 下注册。
2. 将 `psp2fuse.suprx` 复制到 `ux0:data/psp2fuse/psp2fuse.suprx`。
3. 在 `ux0:data/psp2fuse/` 下添加各游戏的专属配置(参见 [`config/`](config))。
内核模块会自动将 `psp2fuse.suprx` 注入到每个游戏中;请勿将其列入 taiHEN 配置中。
## 功能
### Cheat
Cheat 来自三个来源 —— **VitaCheat** 的 `.psv` 数据库、**Lua** 的 `pf.cheat` 脚本(见下文),以及在 **overlay 中直接制作**的 cheat。
这三者会一起显示在 overlay 的 Cheat 标签页中,并按来源分组。
**VitaCheat** (`ux0:data/psp2fuse/cheats/.psv`) —— r0ah/vitacheat 使用的 `.psv` 数据库格式。`.psv` cheat 是一个小型的逐帧程序;加载器会将支持的 cheat 注册到一个可切换的列表中(即 overlay 中的 **VitaCheat** 类别),并在专用的约 60 Hz 频率下运行它们。它也会读取 `ux0:vitacheat/db/.psv`,因此现有的 VitaCheat/FinalCheat 数据库无需修改即可直接使用。
系统仅解析 VitaCheat 代码类型中的安全子集;使用任何不受支持代码的 cheat 都会在加载时被整体跳过(绝不会应用一半),并在 `user.log` 中记录对应行指出其名称:
| 代码 | 含义 | 是否支持 |
|------|---------|:---:|
| `$0X00 A V` | 将 `V` 写入 `A` —— 8/16/32 位 —— X:0=8位,1=16位,2=32位(浮点数作为原始 32 位值) | ✅ |
| `$5X00 A B` | MOV:`mem[A] = mem[B]`,指定位宽 —— 常见的 HP/MP 冻结 | ✅ |
| `$DoNN A V` | 条件判断:如果 `mem[A] V` 成立则运行接下来的 `NN` 行,否则跳过 —— o:0-2 `==`,3-5 `!=`,6-8 `>`,9-B `<`,支持 8/16/32 位 | ✅ |
| `$C2NN T M` | 按键触发:当按住手柄掩码 `M` 时运行接下来的 `NN` 行 | ✅ |
| `$4X01 A V` + `$DDDD E F` | 压缩/填充:将 `V` 写入 `A`,然后 `A += E`,`V += F`,重复执行 `D` 次 | ✅ |
| `$3X0L …` | 指针写入:跟随 `L` 级指针链(`p = A; 重复:p = u32[p] + offset`),然后写入 `V` | ✅ |
| `$8[0-2]L … $88 … $8[4-6]L … $89` | 指针 MOV:目标指针链 → 源指针链,将源复制到目标 | ✅ |
| `$AX00 A V` | ARM 写入:启用时将 `V` patch 到地址 `A` 处的代码中,禁用时恢复原始值 | ✅ |
| `$1xxx` / `$2xxx` | 递增 / 递减 | ❌ |
| `$6xxx` | 数值搜索 | ❌ |
| `$7xxx` | 指针压缩(字段布局未公开) | ❌ |
| `$B2xx` | 相对代码(字段布局未公开) | ❌ |
如果你需要的 cheat 属于不支持的类别,通常可以使用 Lua 脚本(见下文)直接实现相同的行为。
### 内存搜索与指针扫描
Cheats 标签页中的 **△ > Search** 会开启一个类似 Cheat Engine 风格的实时内存扫描器,完全在 overlay 内完成 —— 无需 PC 或第二个应用。选择一个值类型(8/16/32/64 位、浮点数或文本/字节模式),然后进行初始扫描:可以是精确数值,或者如果你只知道它发生了变化则可选择“未知”。通过后续扫描(相同/变化/增加/减少,或按具体增减量)不断缩小范围,直到剩下很少的匹配结果。匹配结果可以被**冻结**(每个 tick 重写,不保存)或**提升**为命名的持久化 cheat —— 提升后的条目初始为禁用状态,因此错误的猜测不会导致当前会话崩溃。
被提升的地址通常是堆分配的内存,在下一次游戏启动时会移动。对搜索结果(或现有的自建条目)使用 **△ > Pointer scan** 可将其解析为一个或多个“静态基址 + 偏移量”的指针链:后台线程会从该地址向后遍历区域集,寻找能够到达该地址的固定模块相对基址。找到的指针链会提升为一个每 tick 重新解析的指针 cheat,因此它能在多次重启中持续固定正确的数值,而不是仅固定数值恰好曾经占用过的地址。
### Plugin
`plugins/.txt` —— 每行一个 `.suprx` 路径:
```
ux0:data/psp2fuse/plugins/PCSA00092/mymod.suprx
```
### Lua 脚本编写
`scripts/.lua` 会在游戏内的常驻 VM 中运行。它可以读取和写入内存、patch 代码、hook 函数、搜索/扫描内存等。
如果存在 `scripts/_global.lua`,它会优先在每款游戏中运行。可选的 `scripts/autorun.txt`(每行一个纯脚本文件名,支持 `#`/`;` 注释)会在每次启动时加载额外的脚本。`pf.load(name)` 可根据需要从 `scripts/` 加载更多脚本。
`scripts/.lua` 示例:
```
pf.log("hello from", pf.titleid())
-- direct memory access (script runs in the game process)
pf.write32(0x81234560, 9999)
-- code/RO patches go through the kernel
pf.patch(0x81091D44, "\x01\x00\xA0\xE3") -- mov r0, #1 (ARM)
-- hook a function
pf.hook{ offset = 0x1D44, thumb = true, func = function(orig, a, b)
local r = orig(a, b)
return r + 1
end }
-- register a toggleable cheat -- the overlay's Cheats tab lists and toggles it
-- alongside VitaCheat and authored entries
pf.cheat{
name = "Infinite HP",
enabled = false, -- apply immediately if true
tick = function() pf.write32(0x81234560, 9999) end, -- runs every ~16 ms while enabled
}
-- toggle a registered cheat from a hotkey (fires once per press)
pf.onPress(pf.LTRIGGER | pf.SELECT, function()
for _, c in ipairs(pf.cheats()) do
if c.name == "Infinite HP" then pf.setcheat(c.id, not c.enabled) end
end
end)
-- reload scripts live without relaunching the game
pf.onPress(pf.LTRIGGER | pf.START, pf.reload)
```
`pf` 提供:
- 内存:`read8/16/32/64`、`readfloat`、`readstr`、`readbytes`、`write8/16/32/64`、`writefloat`、`writebytes`、`patch`
- 特征码扫描:`scan(pattern, mask [, module [, segidx]])`
- 内存搜索器:`search(type)` —— 一种类似 Cheat Engine 风格的扫描器,可以通过进一步筛选缩小范围(`:first`/`:next`,精确值或相对于上一次扫描),然后对结果 `:freeze`(冻结)或将其 `:promote`(提升)为命名的持久化 cheat
- 模块信息:`module([name])`
- 文件(作用域限于 `ux0:data/psp2fuse/`):`readfile`、`writefile`
- 日志记录:`log`、`titleid`、`VERSION`
- Hook:`hook`、`unhook`
- 定时器/输入:`every`、`cancel`、`buttons`、`onPress`、`offPress`,以及按键常量(`CROSS`、`CIRCLE`、`START`、`LTRIGGER` 等)
- Cheat 注册表:`cheat`、`setcheat`、`cheats`
- 脚本加载/重载:`load`、`reload`
Hook 回调会接收前四个寄存器参数,并返回整数结果。`pf.every(ms, fn)` 会在后台线程中运行 `fn(id)`,直到它返回 `false` 或调用 `pf.cancel(id)`。`pf.onPress(mask, fn)` 会在每次按下组合键时触发一次。
有关完整的 `pf` API 参考、cheat/mod 模式及注意事项(ASLR 安全地址、Hook 限制、cheat 注册表),请参见 [`docs/SCRIPTING_GUIDE.md`](docs/SCRIPTING_GUIDE.md)。
### 游戏内 overlay
原生 overlay 运行在游戏进程内。使用 L+R+SELECT 打开/关闭。
- **Cheats**:切换 `pf.cheat`、VitaCheat 和在 overlay 中制作的条目,按来源分组 —— 方向键左/右可循环切换 Lua / VitaCheat / 自建类别。自建 cheat 会持久化保存到 `cheats/.pfc`。这里也是内存搜索和指针扫描功能的所在处(参见[内存搜索与指针扫描](#memory-search--pointer-scan))。
- **Hex**:查看/编辑内存;写入操作会路由通过内核,因此适用于代码/只读(RO)页面。
- **Disasm**:ARM/Thumb-2 解码器;使用回溯栈跟踪分支;对指向已知 import/export 的调用或分支会标记其对应的 Sony 函数名。
- **Memory**:列出所有已加载模块的段,并探测遍历堆/CDRAM/栈内存块;可以在此将内存搜索范围限定在某一区域,或从这里直接跳转到 Hex/Disasm。
- **Script**:显示 `user.log` 的末尾内容以及执行 `pf.reload` 操作。
- **Settings**:在游戏中实时编辑 `psp2fuse.ini`(overlay 几何形状/暗化效果、颜色、VitaCheat 强制执行、诊断等设置)。
在 overlay 打开时,按键输入会被屏蔽,因此游戏不会做出反应。START 会暂停游戏(debug 挂起游戏线程,overlay 轮询线程除外),将最后一帧画面冻结在屏幕上;再次按 START 可继续。按键的确认/取消映射遵循系统设置(在日文布局下,O = 确认;在欧美布局下,X = 确认)。
## 日志
运行时日志会输出到 `ux0:data/psp2fuse/`:
- `kernel.log` —— 仅由内核写入;用于确认注入的模块是否达到了特定阶段。
- `user.log` —— 来自 Lua 的 stdout/stderr,以及用户态日志记录行。
两者均为纯文本文件;可通过 FTP 或 VitaShell 将其拉取出来。
## 免责声明
**使用风险自负。本软件按“原样”提供,不附带任何形式的保证(参见 [LICENSE](LICENSE))。对于任何损坏、数据丢失或设备变砖,作者概不负责。**
- **需要 Homebrew/CFW。** psp2fuse 是一个在 taiHEN 下注册的内核 plugin(位于 `ur0:tai/config.txt` 中的 `*KERNEL` 下),仅在安装了 HENkaku/CFW 的 Vita 上运行。行为异常的内核模块可能会导致主机死机或崩溃。
- **内存编辑本质上是不安全的。** Cheat、十六进制编辑器和脚本会直接写入正在运行的游戏内存中。错误的地址或数值可能会导致游戏崩溃并**损坏存档数据**。在你在意的一款游戏中使用 cheat 之前,请务必备份你的存档。
- **Alpha 阶段软件。** 并非所有游戏都经过了测试。有些游戏的输入轮询或画面呈现方式 overlay 尚不能完全处理;行为表现会有所差异。
- **在线游戏。** 在在线或竞技游戏中使用 cheat 可能会违反游戏或平台的服务条款,并可能导致你的账号被封禁。请勿这样做。
- **禁止盗版。** psp2fuse 是一款用于对你拥有的游戏进行 cheat、mod 和 debug 的工具。它不提供、不支持也不纵容盗版行为。
## 致谢
感谢 PS Vita 社区中的每一个人 —— 本项目所依赖的工具、研究和现有成果(VitaCheat/FinalCheat、taiHEN、VitaSDK 等)使这一切成为可能。更详细的致谢名单将在后续更新。
## 许可证
psp2fuse 采用 **GNU General Public License v3.0 或更高版本** (GPL-3.0-or-later) 授权。有关完整文本,请参见 [LICENSE](LICENSE)。
第三方组件(Lua、font8x8、kubridge、taiHEN 以及 VitaCheat 的 `.psv` 格式)受其各自条款的约束;请参见 [THIRD_PARTY.md](THIRD_PARTY.md)。
标签:Bash脚本, C/C++, Lua脚本, PS Vita, rizin, 事务性I/O, 内存修改, 客户端加密, 插件加载器, 游戏, 游戏修改器