Site icon 时鹏亮的Blog

Switch 金手指制作教程五:让金手指适配不同版本

请知悉:本文最近一次更新为 2年 前,文中内容可能已经过时。

以下内容完整转载自:Eiffel2018 原创发布:【金手指教程4】让金手指适配不同版本

前言

Switch游戏经常更新, 以前开发的金手指,要全部升级确实应付不来。

那,为何PC游戏众多,而Cheat Engine开发的table或Trainner可以应付自如?

答案是 AOB, 意思是 Array Of Bytes , 批次阵列

粗体的字串, 就是AOB

无论游戏是版本升级,或是改地区,

在大多数情况下,程式码并不会大改的。

编译出来的机械码,也有很大机会相同。

用ASM方式做出来的金手指 (如前三篇的金手指教程),

利用AOB的特性, 可以一下子搜寻出对应的位置。


有了它, 任何人皆可搜出 游戏新版本 的对应金手指位址。

不过至今(执笔现时), 暂时未见有任何 Cheat-VM 金手指工具, 可以像 Cheat-Engine般, 利用 AOB 方式去搜, 等待 EdizonSE 吧

然而, 我们利用 IDA PRO, 确实可以用 AOB 搜出代码的

ALT+B 二进搜寻

只是无法在实机进行这样的搜寻吧

(若使用 GDB 也要小心,搜寻功能比较慢的,不要勾选 Find all occurrences)

若你确实需要这样做,又打不开IDA或Ghidra 暂时利用 EdizonSE 的 Multi-Search, 慢慢的输入, 也是可以搜到同一结果的

不过利用 IDA 搜也有好处, 我无须把游戏安装到 SWITCH 就能做金手指了. 呵呵~

(甚至demo版也可以这样做的,游戏正式版还未推出;你就已把金手指做好了,正式版推出后,第一时间用AOB搜寻,换一下地址就可以抢先发表了)


第一步, 需要破解游戏 (解包), 把 NSP/NSZ/XCI 等转成 NSO或ELF (也就是破解出 exefs 内的 main 文件)

方法很多, 常用的包括:

nxDumpTool.nro (可在SWITCH实体机器内, 提取你想要的单一个或多个文件, 最新版本)

niecn 大大的 FFHOME GAME MANAGER (很赞的游戏列表改名工具,内附解包提取功能)

或是用 hactoolnsz 工具, 先提出nca, 再提取 exefs 内 的 main

还可以用模拟器 Ryujinx 把游戏加到列表,就可以看到提取 exeFS 的功能 (Yuzu只能提取romfs,没有exefs)

有了 main, 可以用 IDA PRO 打开, (不过它会帮你的main NSO 在所有地址前面加 71, 你要花时间 Rebase Segment 或者自己去习惯适应它)

也可以用 nx2elf.exe 这个小工具(链接中的附件) 把 LZ4 压缩的 main (NSO) 解压 成 elf, 方便 IDA PRO 读取


用 IDA PRO 打开游戏之后,

可以不用等, 直接操作, 就像 GDB 看到的代码般, 人手C (make code)

但如果你等它完成分析, 最底看左下角看到IDLE时

IDA 则可提供更多功能给你发挥 (最大好处是你可以看到每个 函式, 有哪些 XREF, 这是GDB不能提供的)


回归正题, 怎样制作 AOB 特征码?

其实游戏每次升级, 所有函式地址都会变动,

1. 以 B 及 BL 呼叫其他函式的命令, 都会受到影响。

2. ADRP / ADRL 等远程存取内存的指令, 亦是会改变的。

3. 如果 游戏中定义的 物件 object 加插或删改了 特性 property, 也是会改变 LDR x0, [x19, #??] 等语句的 offset 偏移值, 不过老游戏很少会这样大改了。

AOB 特征码 要做的就是把这些有机会变动的机器码, 用问号?替代, 只要你的特征码够长,可以无视不同版本中的地址变动,搜出唯一的结果


B 和 BL 的机器码, 很多是 14/15/16/17 及 94/95/96/97 开头的,

举个简单例子, 上图中 BL sub_372930 的机器码是 940151D8, 用批次列出来是 D8 51 01 94

94 在大多数情况下是固定不变的, 我们改成 ? ? ? 94 就可搜出这个指令

但为了使搜出的结果只得唯一一个, 我们需要加长搜寻范围, 上例我们用

E0 03 14 AA ? ? ? 94 F7 03 18 AA F8 FD FF B5 便可搜出来,

直接在同一文件试验一下 (ALT B)

出现了两个结果,

这表示这AOB特征码长度不足

再加两句,

E0 03 14 AA ? ? ? 94 F7 03 18 AA F8 FD FF B5 68 F2 04 91 E9 1B 09 32

这就剩下一个结果了


除了 B 或 BL, 另一个常变机器码的指令是 ADRP, 而它4个批次代码都是会变的 (有些游戏版本更新,地址变化很大的)

我们直接用 ? ? ? ? 四个问号替换它便可

置于 ADRL 或是 ADRP后接的那句 LDR/STR , 只是 偏移量 offset 变化

它们只会改变夹在中间的两个批次, 08 21 5F 39 变成 08 ? ? 39 便可以


来看看这个例子

这是一个函数的头部, 最前那些 PUST to STACK 语句, 在很多函式都会这样编写出现, 所以很容易相同, 不是AOB特征码的好对像

如果金手指是在函式第一句RET, 那么要很长的AOB才能作为特征码

以上图为例, 单是前四句肯定不成

F8 0F 1C F8 F7 5B 01 A9F5 53 02 A9 F3 7B 03 A9 (我在HexView抄下来,方便)

再多抄四句

C8 0E 00 D0 08 21 5F 3928 21 00 37 17 50 40 F9

这 ADRP C8 0E 00 D0, 要全变 ? ? ? ? 四个问号

之后 LDRB 08 21 5F 39 只改中间两个,如 08 ? ? 39

这AOB特征码便做好

F8 0F 1C F8 F7 5B 01 A9F5 53 02 A9 F3 7B 03 A9? ? ? ? 08 ? ? 3928 21 00 37 17 50 40 F9

试一下, 只得一个结果, (算得上是幸运, 很多游戏需要更长的)


再来说一说后面 ADRL X22, unk_538B28 这句

这种其实是复合语句,

用 ARM Converter 这种线上工具

可得知, 它拆开成两句

ADRP x22, #0x21a000

ADD x22, x22, #0xb28

你看到这指令是8字节,不是平常的4字节的,

因为4个字节不足够表达 21AB28 这个6位数字

而0x21A000只是一个偏移量

其实应该这样表达 ADRP x22, .+0x21A000

0x21A000 加上该句的地址 0x31E188 就是 0x538188

不过凡是ADRP 最后3个位,不会考虑的, 这个即是 0x538000

后面的三个位B28,便要靠 ADD x22加上去 (或是用 偏移量去存取)

最终,就整合成为 ADRL X22, 0x538B28


平时我们用 keypatch 输入 ADRP 指令时也比较麻烦

例如 我想用 x8 存取 0x538B28

我便要输入 ADRP X8, 0x538000

之后 STR W0, [X8, 0xB28]

如今,我们做AOB时, 要把 ADRP 都变 ? ? ? ?, 而ADD那句的数字也要变

但我不清楚 ADD指令的机器码怎变化,这便要靠Keypatch的帮助

原本是 D6 A2 2C 91


改成 0x1 及 0xFFF 可看到机器码的范围, 只是中间两个数字变动

所以做AOB时, 改成 D6 ? ? 91 便可以了


要改的,记住这 B / BL / ADRP / ADRL 替换相应的问号,就足够了

个别游戏更新时, AOB出问题 就只能到时做修补 (有时更新后,也看过整个函式也消失的,只是,出现这情况的机会比较微吧)

接下来把昨天做的金手指换成其他地区看看

需要各地区最后更新的nsp或nsz版本


港版: 010005C015524000 邪恶国王与出色勇者 v1.0.0

日版: 0100556011C10000 わるい王様とりっぱな勇者 v1.0.2

美版: 0100EBA01548E000 The Cruel King and the Great Hero v1.0.0

可以同时打开三个 nso 或 elf (你也可以只开一个的, 我长开只是为了让他们及早跑完变IDLE, 并非必须的)

第一步骤, 按 CTRL S 看看 main区段 的结尾多少, 也就是 .plt, 标记 X (executable可执行) 的 最后一个

港版是 374CA0 (所以空隙是 374CA0 – 375000)

日版是 373540 (所以空隙是 373540 – 374000)

美版是 3770D0 (所以空隙是 3770D0 – 378000)


我们需要把 .plt加长, 让 code cave 使用

跳到 CTRL S后, 双击 .plt 那一行,

然后 ALT S, 修改 End address 把最尾改到 FF0 就够用了


我用另一个 ipa pro 窗口, 连上 GDB 抓回昨天写的 Code cave

在这个 HexView 画面 copy 较方便, 每次可拷16个字节 (长度8的话是2组, 长度4的话是4组)

Source Code 源码这边, 也是在 HexView 操作比较好。

(这个地方 减少用 Keypatch, 有BUG会令IDA崩溃的, ?? 要先改成0 才可用 keypatch)

我习惯去到末尾 E00 的地方开始, 于是按 G 跳到 374E00

(或者F大用F00, A大用A00, B大用B00, C大用C00,D大用D00 那么大家的金手指就不会相冲了)

用 Shift B (昨天加的快捷键) 这样贴上去, 便可以了 (贴得太长了,没效果)

继续,一行一行的抄过来

拷出来, 也可以用 Shift B 的, 这样子对于拷 00 00 00 01 般的代码, 就不会错乱;

否则的话,你填 00000001, IDA就不知你要多少个批次, 往往做成抄贴错误。

抄好了, 返回 IDA View 按一下C (made Code)


如果不成功, 先按一下U, 把那些 QuadWord 解除定义, 再按 C 便可

(凡是那些自动排版错误,都可以这样子按U,再按C)

不过,如果你已身经百战, 这部分可以省略. 记住两个code cave函式的地址就足够

因为若Code Cave不太复杂, 即是当中没有用 B / BL / ADRP , 所有机器码是不会变动的。

(我做这游戏的日版和美版时,也没有花这时间干这剪贴活)

但后面讲述那些 呼叫 code cave 函式 那句 BL指令, 功夫就不可省了,

要用 Keypatch 输入才能计算好带有偏移地址的机器码


现在实测一下, 把整个游戏做出 AOB 特征码

第一个是 Invincible 无敌

地址在 main+D2058, 用 F2 打个记号

这看似简单,附近的代码不会变动, 直接用 Shift B 拷4行出来

69 0A 00 B9 E9 FA 4B B9 3F 09 00 71 E1 00 00 54

之后用 ALT B 试一试 是否唯一的 (也可以在其他版本测试)

这次很顺利,全都只有一个结果

我也顺便.在其他版本这个地方,按F2打个记号

另外, 把AOB特征码记录 (我已放它在二楼了)

开始改代码,写金手指

在HexView, 按4, column 1, 拷出来就是

00000000000D2058940A8B6A

整合 Code Cave代码

0000000000374E0071112C1FB9400260

0000000000374E08B9000A695400004D

0000000000374E10D503201FD65F03C0

其中最后这行的 D503201F (NOP) 没有用的,可删除

整段变成

[#01. Invincible 无敌]
080E0000 00374E00 71112C1F B9400260
080E0000 00374E08 B9000A69 5400004D
040E0000 00374E10 D65F03C0
040E0000 000D2058 940A8B6A

(第四个字用E只是一个记号,没有特别意思)


第二个金手指之前记录了, 是

[#02. Zero SP moves 特技无须体力]
040E0000 000BD99C 2A1F03E0

这儿没有 B BL ADPR 等, 唯一可能会变动是后面有SP那句

用 Shift B 抄 16批次 出来

00 00 38 1E FF 83 02 91 C0 03 5F D6 F3 03 00 AA

搜寻试试是否唯一的

亦没有问题, 这AOB特征码可用!


[#03 ATK/DEF/AGI 999 攻/防/敏]
080E0000 00374E20 F1112EBF B98002F5
080E0000 00374E28 52807CE0 540000A8
080E0000 00374E30 B9001EE0 B9001AE0
080E0000 00374E38 D65F03C0 B90022E0
040E0000 001E71A8 9406371E

这次应该比较难, 前四句都太平凡

试用16批次搜一下,就出现6个结果

需要再延长来搜. 但第五至七行有2句麻烦的东西,

一句 BL 要抹去三个批次, (变成 ? ? ? 97)

ADRL 要抺去前面四个批次 (变成 ? ? ? ?)

ADRL 后面 21 10 35 91 也要抹去中间2个批次 (变成 21 ? ? 91)

F5 02 80 B9 E0 03 14 AA E1 03 1F 2A E2 03 1F 2A ? ? ? 97 ? ? ? ? 21 ? ? 91 E0 03 14 AA

依然有6个结果!?

只好再延长, 头尾两句BL都要改三个批次,

………. ? ? ? 97 E0 03 14 AA E1 03 15 AA ? ? ? 97

噢,仍然有6个结果!

点击入去看看

晕, 这6个函式过份相似了吧,

目测一个是特技,一个是道具,一个是特技效果,一个可能是其他特效,还有一个是坐标…。

我不想再在这小游戏 Data Mining 了….

没办法, 为方便日后更新, 只能继续延长 AOB 特征码 直至唯一的

(如果你用其他方法,例如对比XREF的内容,就不方便他人了,使用者或其他人很难把金手指升级了)

目测,应该去到 LDRSW X21,[X23,0x4], 这6个函式才开始有差别,

一共16行指令,直接在这边 copy 出来改

F5 02 80 B9 E0 03 14 AAE1 03 1F 2A E2 03 1F 2A? ? ? 97 ? ? ? ?21 ? ? 91 E0 03 14 AA? ? ? 97 E0 03 14 AAE1 03 15 AA ? ? ? 97E0 03 14 AA E1 7B 1E 32? ? ? 97 F5 06 80 B9

这样子再搜…..。

仍然跟物品那个函式相同, 再打开对比一下,

去到 LDRSW X21, [X23,#0x14] 就不同了, 这次可真长

至今我见到最长一个AOB,

正常在PC的话,会用偏移值的,

把一个好搜的结果,叫用户自己加一个offset,

但没所谓,这当练习吧

排列起来,编辑就方便

F5 02 80 B9 E0 03 14 AA E1 03 1F 2A E2 03 1F 2A ? ? ? 97

? ? ? ? 21 ? ? 91 E0 03 14 AA ? ? ? 97 E0 03 14 AA E1 03 15 AA ? ? ? 97 E0 03 14 AA E1 7B 1E 32 ? ? ? 97 F5 06 80 B9

? ? ? ? 21 ? ? 91 E0 03 14 AA ? ? ? 97 E0 03 14 AA E1 03 15 AA ? ? ? 97 E0 03 14 AA E1 7B 1E 32 ? ? ? 97 F5 0A 80 B9

? ? ? ? 21 ? ? 91 E0 03 14 AA ? ? ? 97 E0 03 14 AA E1 03 15 AA ? ? ? 97 E0 03 14 AA E1 7B 1E 32 ? ? ? 97 F5 0E 80 B9

? ? ? ? 21 ? ? 91 E0 03 14 AA ? ? ? 97 E0 03 14 AA E1 03 15 AA ? ? ? 97 E0 03 14 AA E1 7B 1E 32 ? ? ? 97 F5 12 80 B9

? ? ? ? 21 ? ? 91 E0 03 14 AA ? ? ? 97 E0 03 14 AA E1 03 15 AA ? ? ? 97 E0 03 14 AA E1 7B 1E 32 ? ? ? 97 F5 16 80 B9

总算成功.出现唯一的搜寻结果, (而且在其他版本也有效)


[#04. Exp 4x]
040E0000 00262980 0B080929

29 01 08 0B 49 6B 00 B9 49 59 43 B9 3F 01 08 6B

这个AOB不用改,一搜便是唯一的。

通常有这样一个很大的偏移值offset (0x358),都容易作为特征码的,

不过Offset这样大,日后改版也有机会改变,令到AOB无效,搜不到. 保守的话,可以这样改

29 01 08 0B 49 6B 00 B9 49 ? ? B9 3F 01 08 6B


[#05. Free shopping 免费购物]
040E0000 002D04F4 D503201F

2A 01 00 B9 21 03 40 B9 09 CD 88 52 00 01 09 8B

这中间的 0x4668 又是一个大偏移值, 是有少许机会改变的, 这样吧

2A 01 00 B9 21 03 40 B9 09 ? ? 52 00 01 09 8B


[#06. Item never decrease 道具不减]
040E0000 0024C128 7100016B

最后这个AOB, 后面2句虽然是B, 但转跳的位置是很接近的,

(你看 ?? 0? 00 54或14 的前面三个数字很小, 或是 ?? F? FF ?4 般,跳回前面, 都是在同一函式内的local jump)

这其实是可信的特征码. 可直接采用

6B 05 00 71 2B 01 00 B9 01 01 00 54 02 00 00 14


在PC / CE 界,受人推崇的 AOB 完成,

打开其他地区的版本, 试试这AOB效果。

都是一步到位, 马上搜到新地址!


总结

开发金手指之后,日积月累,没人帮忙,升级困难。

科普一下, 或许日后会转变, 不要太多人求更新, 让更多人有能力更新金手指, 对广大玩家有益


附上金手指及日后更新用的AOB特征码:

AOB
0) 替换 Code Cave 地址
1) 69 0A 00 B9 E9 FA 4B B9 3F 09 00 71 E1 00 00 54 (需要改成 BL CodeCave地址)
2) 00 00 38 1E FF 83 02 91 C0 03 5F D6 F3 03 00 AA
3) F5 02 80 B9 E0 03 14 AA E1 03 1F 2A E2 03 1F 2A ? ? ? 97 ? ? ? ? 21 ? ? 91 E0 03 14 AA ? ? ? 97 E0 03 14 AA E1 03 15 AA ? ? ? 97 E0 03 14 AA E1 7B 1E 32 ? ? ? 97 F5 06 80 B9 ? ? ? ? 21 ? ? 91 E0 03 14 AA ? ? ? 97 E0 03 14 AA E1 03 15 AA ? ? ? 97 E0 03 14 AA E1 7B 1E 32 ? ? ? 97 F5 0A 80 B9 ? ? ? ? 21 ? ? 91 E0 03 14 AA ? ? ? 97 E0 03 14 AA E1 03 15 AA ? ? ? 97 E0 03 14 AA E1 7B 1E 32 ? ? ? 97 F5 0E 80 B9 ? ? ? ? 21 ? ? 91 E0 03 14 AA ? ? ? 97 E0 03 14 AA E1 03 15 AA ? ? ? 97 E0 03 14 AA E1 7B 1E 32 ? ? ? 97 F5 12 80 B9 ? ? ? ? 21 ? ? 91 E0 03 14 AA ? ? ? 97 E0 03 14 AA E1 03 15 AA ? ? ? 97 E0 03 14 AA E1 7B 1E 32 ? ? ? 97 F5 16 80 B9 (需要改成 BL CodeCave+0x20的地址)
4) 29 01 08 0B 49 6B 00 B9 49 ? ? B9 3F 01 08 6B
5) 2A 01 00 B9 21 03 40 B9 09 ? ? 52 00 01 09 8B
6) 6B 05 00 71 2B 01 00 B9 01 01 00 54 02 00 00 14

包含三版本金手指及以上升级AOB码:The Cruel King and the Great Hero.rar

包含三个版本的 ELF文件, 可用 IDA PRO查看, 体验教程所说的内容:elf files of 3 versions.rar


特别鸣谢

Eiffel2018 原创发布:【金手指教程4】让金手指适配不同版本


如您从本文得到了有价值的信息或帮助,请考虑扫描文末二维码捐赠和鼓励。

本站资源,请 注册城通账户 后,使用客户端下载,参考教程:城通网盘如何使用客户端下载文件


尊重他人劳动成果。转载请务必附上原文链接,我将感激不尽。


与《Switch 金手指制作教程五:让金手指适配不同版本》相关的博文:

Exit mobile version