本帖最后由 zhoucn9999 于 2026-9-14 19:02 编辑
Switch 内存大师:普通人也能懂的“代码洞挂钩”实战
——以《勇者斗恶龙怪物仙境3(DQM4)试玩版:全物品+100》为例
【导读指引】
适合人群:觉得十六进制金手指像天书、不懂底层汇编,但想搞清楚高阶金手指原理的游戏玩家。
核心目标:搞懂什么是“半路截胡(Hook)”、什么是“违建密室(代码洞)”,以及为什么高手修改游戏从不自己强填数据。
|
1. 核心思想:不要自己造轮子,让游戏自己干活
很多人在最开始接触修改时,往往以为修改背包就是“在内存里找到背包地址,把里面的数字挨个改成 99”。但这在现代复杂游戏里非常容易导致游戏闪退。
原因其实很简单:你还没见过的稀有物品,在游戏背包的数据结构中很可能连一个“空位(节点)”都尚未创建!如果你强行往对应的未知内存地址写入数据,破坏了内部的数据链表结构,游戏读取时就会直接报错崩溃。
高手的做法是“借刀杀人”: 游戏中原本就有一段官方开发人员写好的原生功能函数——“给背包添加指定数量的某物品”。官方的原生函数本身具有极其严密的防御机制:物品已存在就自动累加数量;物品不存在,它会自动在内部动态申请空间并新建格子,绝不会破坏数据结构。
【生活化比喻】
原版流程:你在商店买了 1 个草药 → 游戏执行官方函数:“给背包添加(背包指针, 草药编号, 数量 1)”。
金手指截胡后:你在商店买了 1 个草药 → 动作暂停!跳进我们的秘密脚本:
1. 循环执行:从 0 号到 64 号物品,借用游戏自己的原生函数,把所有物品全部 +100;
2. 善后处理:再让游戏把刚才买草药的那次正常购买完成;
3. 安全收尾:悄悄返回游戏,神不知鬼不觉。
|
2. 核心概念拆解:比喻化理解专业术语
① 什么是半路截胡(Hook / 挂钩)?
游戏的代码执行起来就像一条平稳运转的高速流水线传送带。Hook(挂钩)相当于你在传送带的某个必经之路(比如加物品函数的入口)拆掉了一块原装地砖,装上了一个带有感应开关的“转向传送带”。当数据流传送到这里时,就会不由自主地被强制拐弯,送入你专属的秘密车间。
② 什么是违建密室(Code Cave / 代码洞)?
原版游戏那行被你拆掉的地砖只有 4 个字节大小(一条 AArch64 基础指令的空间),根本装不下我们写的一长串“循环 65 次加物品”的复杂逻辑。但是,游戏程序在打包进内存时,各个模块为了按规定尺寸对齐,末尾往往会留下一大片完全空置、全为 0 的无人区。Code Cave(代码洞)就是我们找到的这块合法的空白地皮。我们在里面盖了一间“违建密室”,把我们自定义的大段脚本指令悄悄码在里面。
③ 什么是安全传送门(Gateway / 中转跳板)?
在违建密室里,我们需要命令游戏执行原生函数。但是如果你直接调用原函数的开头,原函数门口已经被我们换成了“转向传送带”,这就会导致刚跑过去又被拐回密室,形成永无止境的死循环,机器瞬间卡死闪退!Gateway(跳板)就是一扇隐蔽的员工侧门:它先在侧门补上被我们拆掉的那块地砖的动作,然后把你从原函数的“第二行”直接送进去。这样既能享受原版功能,又完全不会再次误踩门口的跳转陷阱。
3. 完整业务流程图解
玩家在商店购买 1 个草药
↓
触发原版“增加物品”函数入口(已被改造成传送带:强制跳转到代码洞)
↓
【代码洞密室 - 我们的自定义逻辑】
[步骤 1] 保护现场:给当前 CPU 各寄存器拍个快照存入堆栈,防止数据弄乱
[步骤 2] 循环批量发放:遍历 0 ~ 64 号物品
调用【Gateway 侧门跳板】执行原版逻辑 -> 每个物品自动 +100
[步骤 3] 补回原行为:调用【Gateway 侧门跳板】补上玩家真正购买的草药
[步骤 4] 现场恢复:从堆栈把各寄存器恢复如初,假装什么都没发生
↓
从密室优雅走出,返回主游戏,游戏流程丝滑如常
|
4. 拆解那串“天书”金手指代码
很多玩家看到一大串十六进制代码就头晕,其实原金手指的 28 行代码在逻辑上仅仅划分为三个清晰的部分:
第一部分:密室核心脚本(地址 071062C0 ~ 07106320)
用高级语言写出来,它其实就是一个最基础的 for 循环:
// 翻译成 C/C++ 伪代码
for (int i = 0; i <= 64; i++) {
AddItemCount_Original(inventory, i, 100); // 借用游戏原生函数加 100
}
AddItemCount_Original(inventory, itemIndex, amount); // 结算本次真正购买的物品
|
代码中的机器码 52800C82 其实就是对应将数字 100 写入寄存器;而 710106DF 则是与十进制 65(十六进制 0x41)做大小比对,控制循环跳出。
第二部分:安全传送门 Gateway(地址 07106324 ~ 07106328)
负责将原本入口被覆盖掉的“备份栈帧”指令补执行一次,然后通过一条跳转指令(B 0x04C11404)直接跳回原函数的第二行,完美避开入口机关。
第三部分:机关触发开关 Hook(地址 04C11400)
全段金手指只有这一行是真正写入游戏原代码区域的:04000000 04C11400 1493D3B0。它的作用极其纯粹——将原版加物品函数的入口第一条指令,硬生生替换为“跳转到代码洞 071062C0”。
5. 制作高阶金手指的“侦探排查法”
不论给什么游戏做类似修改,高手的思考路线都可以归纳为以下 5 步:
• 第 1 步:锁定结果(搜数值)
草药有 5 个,买 1 个变 6 个。使用内存搜索工具搜 5 变 6,直到锁定具体存放数量的那个内存格子。
• 第 2 步:顺藤摸瓜(查元凶)
给这个格子挂上“写入监视断点”(相当于装个隐形探头)。再去商店买一次东西,游戏在写入数字的瞬间会被定格,直接定位到改写数据的代码行。
• 第 3 步:确认总指挥(确定函数入口与参数)
顺着代码往上翻,找到这段逻辑的开头(函数入口),摸清其接口定义(哪个寄存器传背包指针、哪个传道具 ID、哪个传增减数量)。
• 第 4 步:找空地盖密室(寻找代码洞)
在主程序可执行区域尾部扫描全 0 或填充用的空白地皮,把写好的“循环派发”逻辑注入进去。
• 第 5 步:换锁接线(挂钩与测试)
把原函数入口换成跳转指令引向密室。进游戏买一次东西触发效果,确认全物品到手后停用金手指,存档重启即可。
6. 拓展延伸:《马里奥奥德赛》扔帽子攻击变身任意物体
我曾提出想做“马里奥扔帽子击中任意物体都能直接变身/附身”,用上面的底层思维来看就变得非常直观:
普通改法: 如果游戏原版逻辑仅仅是一个简单的 if (target->CanBeCaptured) 判断,那只需要顺藤摸瓜把这个判定改成永远为 true(NOP 或条件分支强制跳转)即可。
代码洞改法: 但如果目标是一块石头或不可附身杂兵,它内部压根没有被马里奥控制的动作组件与骨骼挂点。如果盲目调用官方变身函数,游戏一执行移动逻辑找不到指针就会瞬间闪退!因此必须在代码洞里对受击目标做防御性拦截、动态绑定傀儡控制器与摄像机焦点,再强行调用变身接口。这也正是代码洞技术的真正威力所在。
现实问题: 游戏中并不会在每个场景都把所有人物模型都加载,只是简单处理帽子攻击逻辑会导致金手指在这个场景变身好好的下个场景可能就会崩溃。这个问题就更为复杂和棘手了。暂时还是算了吧。
【一句话精髓】
简单修改是在“偷改试卷答案”(直接改数值);
高级修改是“混进导演组借用原版道具”(代码洞挂钩,复用原生逻辑)。
学会调用游戏自身已有的成熟代码,你就能在不损坏存档与数据结构的前提下,实现任何看似不可能的作弊效果。
|
系列相关: https://www.tekqart.com/thread-472140-1-1.html https://www.tekqart.com/thread-471674-1-1.html
|