以下内容完整转载自:Eiffel2018 原创发布:【金手指教程3】更多调试技巧及数据挖掘
本文主要介绍其他金手指的做法, 增进大家的经验
继续 上次 开发金手指的旅程
话说女主角小勇刚学会了使用技能,火炎斩,
每次扣减 MP4 (游戏中把MP称为体力), 但小勇最大MP才只得4,
每个回合补1点MP
我们分析, 改变MP的地方有2处, 一处是使用MP时, 另一处是补充MP时. 两种金手指都介绍一下吧
先做MP不减
可以打开上次IDA存档, 连接休眠之后的SWITCH
连接之后,在之前的断点双击滑鼠,可跳到小勇之前的内存,不用重新查找
之后可以 在断点前面-8的位置 ALT Q, 应用actor结构, 再CTRL+
这就可回复之前IDA的面貎
今次,我们得在 MP的位置 下断点,
不过这输入是会有点困难, 你按F2的话, 断点位置会变成物件结构的起始, 而不是 偏移值+0x10
所以你需要人手改一下, F1488 改成 F1498 便可以了
(或者你按U取消actor结构struct,下了断点再重新ALTQ应用Struct也可以)
今次的断点也可以只用 [Write], 不用 [Read] 的
(因为修改[Write]找出来的地方比较容易修改; [Read]找出来的地方,需要花时间看很多程序; 遇到[Write]找出来的地方很难修改才使用)
下好了直接F9继续游戏
断点出现在 main+C1678 一句 STR W9, [X8, #0x10] 上
也许, 直接 NOP 可以变成 MP不减
不过今次我们可以往上翻, 看看完整的 MP 扣减流程
把鼠标一直往上,在地址结尾是 0 / 4 / 8 / C 的地方, 尝试按一下C (made code)
我想把整个函式用视图看一遍, 现在好像不足够, 继续往上按C,
原来这个函式很大啊,还是先放弃吧.
点击一下右边 PC旁的箭头, 回到之前触发断点的位置
W9 是个关键(它是准备更新的MP值), 我们需要得知它是如何得出来。
鼠标移到W9, 使所有w9高亮,方便查看
附近就只有一句 MOV X9, XZR, (意思是把MP设成0),
猜测是一些检查如果MP变负数,就设为0的结构. (这个没有用处.)
但在 触发断点位置的 上一行, 多了一个 label(标签), 一个 referer(引用点)
loc_1F982C5678 ; CODE XREF: main:00000000000C15EC↑j
双击那个引用点 C15EC, 跳到了转跳的位置
在这边,看到了几个W9, 正是我们想找的关键所在。
让我针对这几句剖析一下. 这基础必须学懂的
MOV X0, X23
MOV X1, X20
BL unk_1F982C18A0
这三句是呼叫另一个函式 , X0 和 X1 是函式的输入参数 (input parameters)。
函式的地址是 0x1F982C18A0
你也可以 按G, 跳去这个地址标签
去到之后是这样子
按一下P使这位置变成一个函式
然后按一空格, 变成视图模式
从函式的头部, 可看到前面X0,X1是有作用的。
我们去看看函式最末尾, 想了解这函式输出的反回值 (return value)
就是 W0 这句 FCVTZS W0, S0
S0是浮点数, 现在输换成 DWORD双字节 W0 反回
继续函式后接的语句
LDR X8, [X23,#0xC08]
LDR W9, [X8,#0x10]
这个其实是指针, MP = [x23+C08]+10(如果你做指针金手指, 也要选择末尾有个 main+xxxxx]+C08]+10 的指针,会比较准确啊)
X23 可说是一个重要地址 代表角色的基础地址 base address (你可以细心研究这个x23,发掘其他新奇的金手指,暂不剖说)
接下来是
SUBS W9, W9, W0
B.GE loc_1F982C5678
第一句 是把 W9 扣减 W0 然后储存到W9, 而且同时做了一个检查比较 W9 和 W0 的大小
第二句 意思是如果 W9 大于 W0 时, 转跳到 0x1F982C5678 的位置 (正是刚才触发断点的位置)
综合这6句的意思,
前面这函式无疑是用来计算扣减值,
然后扣减MP,再转跳到后面写入内存
这个金手指修改手法有几种,
除了刚才说的把写入那一句改成 nop 之外,
可以把扣减伤害值的 W0 改成 WZR, 例如 SUBS W9, W9, WZR
也可以继续向前摸,把整个扣减MP的函式NOP,连根拔起 (这可看 STACK,一层一层的向上,下断点测试,很大机会找到那个根的)
个人认为,比较好的方法,应该是进入刚才计算扣减值的函式, 把反回值改成零
原因是这是根源,往往可以一劳永逸,
可把显示效果,或是多处扣减地方都变得一拼有效 (前题是你要肯定这个函式是用来计算扣减值的)
就试试这样改一下吧
OK 关了断点,继续F9测试看看
呵,这次有意外收获,
本来需要4的火炎斩, 现在看到变成了需求0
也就是说, 就算小勇身上没有任何MP, 也能够使出所有已经学识的技能, 无视MP需求!
在IDA PRO按ESC 取消 running (或者你可以人手点 Suspend)
这个地方要NO
先记录一下金手指
[Infinite MP]
04000000 000BD99C 2A1F03E0
然后还原刚才的修改
今次我想用 [Read] 断点的方法 看看补加MP时的做法
编辑 edit 刚才的断点, 把 write 改成 read 同时 enabled 激活它
再次F9继续游戏 , 捕捉女主回复MP的一刻 (就是不要使出特技)
但这不太顺利,未能一步到位.
整个流程有多个地方会读取那个MP断点的
先是战斗一开场的地方
这个不好改, 就算改了也没大作用吧, 只能令到战斗一开场MP全满?
若在这里改STR/DEF/SPD/ maxHP/ MaxMP 等, 或许可以.
暂时不理会, 关了断点, 跳到下一行按一下F4, 使PC过了断点, 之后再开启断点, 然后F9
哦,怎么断点又被触发了, 而且仍在之前的地方… main+1047EC
这怎办呢?
先看一看这几句内容干什么的
LDP W9, W8, [X19,#0x10]
CMP W9, W8
B.LE loc_1F983087FC
STR W8, [X19,#0x10]
第一句读取 MP 和 MaxMP 到 W9 及 W8
然后 比较 W9 和 W8 大小,
若 MP<=MaxMP 跳过后面这句
把 MaxMP 写到 MP的位置
程序这样写,是不断检查MP是否大于MaxMP, 一旦MP超出MaxMP就把MP设成MaxMP
这种编程手法….. 或许程序员认为可以比较安全:就算其他地方有错漏令到MP超出最大值,也可以这样修补,让玩家看不见任何疏忽。
但实际这样分分秒秒都做读写检查的话,有少许拖慢流程的.若积累太多这样的设计, 正如没有 Fine Tune 的游戏,玩起来会窒。
但不要理太多了. 这其实也很常见的, 有些时侯会用呼叫SDK的API处理的, 例如 显示HP/MP值 很多时可见到游戏都是分分秒秒的去读写修改重覆内容。
不过,这处正好可以被我们利用.
把 B.LE 那句转跳 NOP, 不就变成每次都让MP最大化吗?
对! 你可以这样做的, 也是一种手法, 但不常见(很少有机会碰到)
但我目的是想找到增加MP那句,
现在断点 分分秒秒都 被触发怎办?
如果不是大气层GDBstub的single step debug做得不好,
这断点可以加设 condition, 添加一个条件 PC != 0x0000001F983087EC (亦即是main+0x1047EC)
但这方法暂时是不行的,断点在这个位置,PC不会前进. (祈望大气层作者发功吧)
暂时解决方法,可以把这段全部nop, 也可以改成读入绝对值(一个固定数字,而不是断点的位置)
懒得想,整段填入NOP
再F9, 又遇到一处
这个W2是后面 函式unk_1F982BEED0 的参数, 猜测这是用来显示的吧,
懒得看, 暂时换成 MOV W2, #88 算数。
继续F9, 终于开场了 (MP真的变了我改的88, 但这个应该是假的,只是显示部分看见是88)
但一下按特技,又触发了断点。
这应该是一个检查是否足够MP吧,
如果 LDR W8, [X8,#0x10] 是现时MP值
那么 LDR W9, [X19,#0x18] 应该是某招式的MP需求值 (如果你想改,也可以把游戏设计的需求4改成需求1的)
后面 W0 应该是一个反回值, CSETW8, LT 改成 MOV W8, WZR 应该可以忽略MP需求
但这里我们不打算改了,价值不大
暂停断点,F4到下一行,开启断点继续F9
反覆试了几次, 每次 X19都是另一个招式, (其实这里有机会发掘出特殊的金手指,例如未学识也可使用的招式)
先略过吧, 取消所有断点, 反回游戏,
其实我刚才不应该点击那个技能。
我只想得到每回合加MP时的触发位置
ok 返回到普通攻击, 再暂停这戏, 打开断点
普通攻击一下, 断点又触发了
今次停顿的位置, 看到一个 spMax 的注释
很明显这位置是关于SP吧 (即是我之前叫MP那东西,其实搞错了,是SP才正确)
那一句 ADRLX1, (aSpmax – unk_1F98204000) ; “spMax”
上面X21, [X23,#0x14] 应该是我们之前定义 MaxMP的位置
按照这铺排, X21是内存位置,X1是变数名称,
那个 unk_1F985C4EF0 岂不是应该叫SP?
我们到 0x1F985C4EF0 看看
再按 a 一下,
对了这确实叫 “sp”
上下翻一翻, 把全部名称a出来看看吧
哦, 原来之前我用来判断敌我那个变数叫 chrId (猜是Character ID吧)
而后面是
X21, [X23,#0x18] atk
X21, [X23,#0x1C] def
X21, [X23,#0x20] agi 敏捷
S8, [X23,#0x24] cri 爆击率
S8, [X23,#0x28] hit 命中率
S8, [X23,#0x2C] free 不明 (闪避率吗?)
后面还有
S8, [X23,#0x30] fireResist 火抗性
S8, [X23,#0x34] iceResist 冰抗性
S8, [X23,#0x38] freezeResist 冻结抗性
S8, [X23,#0x3C] burnResist 燃烧抗性
S8, [X23,#0x40] slowResist 缓慢抗性
S8, [X23,#0x44] sleepResist 睡眠抗性
S8, [X23,#0x48] poisonResist 中毒抗性
S8, [X23,#0x4C] dizzyResist 击晕抗性
S8, [X23,#0x50] fearResist 恐惧抗性
S8, [X23,#0x54] softnessResist 弱化抗性
S8, [X23,#0x58] minimumResist 最小抗性?
S8, [X23,#0x5C] maximumResist 最大抗性?
X21, [X23,#0x64] hate 讨厌值?现时是100
X21, [X23,#0x68] exp 经验值, 现时是49
W21, [X23,#0x6C] enable 不明, 现时是1
就这些了
应该有用的, 留待之后用吧。
这叫 数据挖掘 DataMining, 有时就要靠三分运气和七分努力才得到的
继续,返回PC位置, 暂停断点,F4到下一行,开启断点继续F9
又出现死回圈了, 只好把这句改成绝对值
因为现时是出招中 触发的断点,
所以修改 STR / DEF / AGI / Resist 等,可能有效果的,
就试一试加大AGI看看
F9继续
好像可以哦, 比敌人都先出招
为了确定, 等一下, 连ATK 和 DEF 也改999看看
这回合终告结束了, 断点再次触发
这个应该就是当初要找的地方
LDP W9, W10, [X11,#0x10]
W9 是 MP…. 不, 应该是 SP
W10 是MaxSP
ADD W8, W8, W9
W8 = W8 + W9
可以看出 W9是原本SP值, W8是每回合增加的量
CMP W8, W10
CSEL W8, W8, W10, LT
比较 W8, W10 的大小,
W8 = W8<W10 ? W8 : W10 (即是W8和W10中,选较小的一个)
改成 MOV W8, W10 就是最大值了
这种修改不及上面SP不减的方法, 就不继续用来做金手指. 作为教学, 解说已很足够。
在进一步开发其他金手指前, 要把刚才断点相关的修改, 全部还原,
可以打开修改记录, open Subviews -> show undo history
由底开始看, 反回刚才未做大量修改的地方
(如果乱了, 或者你重启游戏好了)
这游戏的金手指,
已有HP不减, SP消耗0, AGI999,
现在测试一下 STR 999 和 DEF 999 有没有效果
这不似有效, 打击只得23, 敌人伤害扣减2
先 UNDO last Patch 改回之前的样子。
虽然那个位置只是读取数据, 但那个内存是真实的,
除了下断点找到其他代码之外, 还是可以在这里 直接修改内存为999的
不过又要用到code cave了
温习一下, 上次我们是按 CTRL S查看区段, 跳到main最末尾的
输入过都有记录的, 跳回去看看
反译代码没了,要人手按一下C或P
然后在后面的地方加给一个新名称,
但要注意不要太接近, 好习惯是留一些空间,方便修改。
我就在 main+374F20 开始第二个 code cave
随便找个地方开始把。
就这里,胜在 X21, X0, X1, X2 都可用。
这样就可以了,
如果想减少一行 STP W0, W0, [X23, #0x18] 也可
就是没有必要这么悭(节俭)吧
估计 浮点数寄存器 S8 也是可以用的
可以顺手改爆击率和命中率等, 不过好像对游戏没有太大作用. 懒改了。
之后把原本的那句 LDRSW X21, [X23] 补在最后, 就可RET返回了
F9再玩一会, 测试一下吧.
效果是有, 但敌人也变强了!
又要做敌我判断? 可以哦, 既然已做了Code cave,加多句判断有何不可
但现在要加插三句,怎编辑呢? 刚好可以用刚才的空隙!
先把刚才的 BL status_hack 改成 BL status_hack-12 (3句x4就是12bytes了,你也可以用0xC)
先前给的函数名,要如何取消?
直接按N,删了名字,再OK就可以
重新在正确位置给名称
今次要转跳5行, 即是 BNE .+20
(输入时,最好先入20, 再入+, 最后再入. 因为这KEYPATCH有BUG的,很易令IDA崩溃)
又再复检一下, 上面LDR W0,[X23]跟最后的LDR W21,[X23]重覆了,
再改一下, 这样比较简洁
转换成金手指
[999 ATK/DEF/AGI]
04000000 00374F14 B98002F5
04000000 00374F18 F10FA6BF
04000000 00374F1C 540000A1
04000000 00374F20 52807CE0
04000000 00374F24 B9001AE0
04000000 00374F28 B9001EE0
04000000 00374F2C B90022E0
04000000 00374F30 D65F03C0
04000000 001E71A8 9406375B
但这么长, 我想缩短几句, 改成每行64位元不是更好吗?
这得先要解决一个小问题, 要搬移这堆程式码 由地址结尾0或8 开始
这个 Patch program -> Change Byte 很好用, 每次可剪贴最16个字元
为更方便起见, 修改 shortcut
在这画面中间点一下, 再按CTRL F, 输入 bytes 便可把 PatchByte的快捷键修改为 Shift B
下面按一下Record, 然后 Shift B, 便可Save了
我想向下移三行, 便要由尾后开始数4行, 按Shift B, 再Ctrl C把内容Copy
之后下移三行,按Shift B, 再 Ctrl V 贴出来
如是者, 重覆直至完成搬移. 最后改名,改BL那句等。
然后来到 HexView, 按一下8, 这样COPY便方便了
略为编辑一下,删和补空格,前面改成08便可以了
[999 ATK/DEF/AGI]
08000000 00374F20 F10FA6BF B98002F5
08000000 00374F28 52807CE0 540000A1
08000000 00374F30 B9001EE0 B9001AE0
08000000 00374F38 D65F03C0 B90022E0
04000000 001E71A8 9406375B
短了一半, 看起来舒服多了
再玩一会, 按剧情, 应该很快可以领宠物伙伴了
果然不错 (其实已挂机3小时 TMD小游戏……)
需要知道这 小狐狸 的chrID 才可决定敌我部分怎改
就只需要之前的code cave函式,F2下个断点。
抓到了, 它是1002
小勇是1001, 这宠物1002, 再有其他宠物也不会超过1099吧
就先这样改吧, 有问题再修正
还差 EXP 倍率 和 商店免费 , 道具不减, 应该基本齐全了
经验值并不用搜, 翻查前文, EXP是 X21, [X23,#0x68] 当时是49
这49,不清楚是由LV1开始计算,还是现在等级开始计算 (升级会不会清0?)
在小勇的内存位置转跳+68,
简单下个Write硬件断点, Size是1或是4皆可以,无影响断点运作
经过一场战斗, 断点触发了. 是main+262980
这个看起来很容易改。
就只是把 ADD W9, W9, W8 后面的 W8 加大便可以
简单方法是 ADD W9, W9, W8, LSL#倍率(1/2/3/4/5/6等)LSL后面是指数, 以2的次方计算
我习惯改成5倍左右, 是个好选择,LSL 2 就是4倍了
最后金钱, 可以退出 IDA (DETACH), 用EdizonSE找
其实可以在上面得到经验值的代码追查, 金钱和经验都是战斗后获得的. 所以应该可以查到 (掉宝率也可以这样找的)
不过, 金钱确实容易找,用 EdizonSE一下子便找到,
简单下个断点看看
一场战斗之后, 断点在 main+2622F0 触发,
(跟刚才 main+262980 还是有一点距离, 翻一翻代码, 好像又不是两个独立的函式)
看到 触发金钱的位置 上面 有句 MOV W11, #0x3B9AC9FF ,在这数按一下H,改成十进位看看
这肯定是最大值
所以简单把 STR W10, [X8,X9] 改成 STRW11, [X8,X9] 便是 Max Gold 最大金钱 了
要改倍率的话, 也可以加个 ,LSL 2 在 ADD W10, W10, W2 后面
如果想在购物介面做功夫, 金钱不减, 也是可以的
一般使用者也比较容易接受这种金钱不减的修改
回去商店 买东西.
这就轻易的触发了.
又见到 那个 999999999 最大值
还有一句关键的 MSUB W10, W11, W20, W10
这句意思是 乘减, W10 将会等于W10 – ( W11 x W20 )
很明显, W10 是原有金钱, 修改后也是新的金钱值, W11 和 W20 一个是 物品单价 一个是数量
把 鼠标 指到 W20, 看见它的值是1, 所以 W11是物品单价, W20是购买数量
前面那句 [X25,#0x84] 应该就是记录了货品的售价,
前面共有两次出现[X25,#0x84], 应该第一个是用来检查是否足够金钱支付的. 连它也改,可以无视价钱的购买
这游戏的货品不贵,简单改后面扣钱那个就够了. 或者直接把触发点那句NOP算了
往上追踨 X25 更可以获得所有物品
(改一改ID更有可能包括买不到的物品, 买A得到B,也是常见金手指)
货品数量 W20, 也可以追查的, 很大机会找到 物品设置数量的函式
像这样, 我不用看 unk_1F98318770 内容,也能猜测
W1 是 Item ID
W2 是 数量
W3 是一个 boolean, 一种 Flag
这 unk_1F98318770 是用来设置持有物品的数量
入去把 w2 相关的指令, 改成99, 就是无限物品的金手指了.
也不用 EdizonSE 找出 物品数量 再下断点了。
一齐测试吧
测试了,
这物品99 只影响购买时的数量,
不影响使用或出售时的数量,
也不影响只能得到1件的装备.
不错, 就这样玩,
但我真的想改个 物品使用不减 怎办?
其实可以用上面这函式获取物品数量的地址,再下断点
追踨 数量W2 -> W20 -> [SP,#0x80+var_54]
这个写入了 Stack 内, 很难往下追踨,
可以先试一试,在 [SP,#0x80+var_54] 上面按X
认清它是会在后面 ADDX2, SP, #0x80+var_54 使用
这意思就是 用X2作为输入参数,[x2]内容记下了刚才的物品数量, 然后呼叫X8函式
这确有点棘手, 先要知道X8是哪里才可容易追查下去。
把鼠标指到这 BLR X8 再按F4, 游戏动起来,你便去购物
今次我买2件, IDA中 PC停了在刚才BLR X8的位置,
右边寄存器区直接看到X8将会跳去main+1AF280
点一下X8的箭头看看,按P,看到X2
在这按空格, 用视图Flowchart配合F4跟踨一下流程
失败了, 这F4并没有触发. 物品仍然加到99
所以刚才BLR X8不是用来改物品数量的. 返回去看看
原来刚才写到STACK的数量W20,在后面一直没有改变内容, 还有几处读取W20的,用F4追踨一下
下了F4的这串程序也没有触发
按住CTRL,滚动滑鼠缩小视图. 看看还有哪儿用到W20
把出现黄色W20的路线全部下断点,这就不会有漏网之渔
OK 捉到活鱼. 在这儿停顿了
先把刚才的断点全删除,
再 Debugger -> Refresh memory
找到了, 这[X10,#8] 就是刚才那件物品的数量地址。
可以点进去下断点了。
最后步骤, 使用物品
噢,HP是全满,用不到啊!
不要紧,直接在内存改HP, 但不记得之前的位置了。
这有两个方法,可以到 struct 按 X 看看有哪些内容是 define做 actor的
另一方法是找找以前记下,但关闭了的断点
(后者较可取,因为之前DETACH退出过,所以actor的对象都没了)
找到了, 直接在上面用 Shift B (就是刚才加的快捷键)
原本是31, 我直接入28(减少它)可以了
OK, F9, 现在用道具补血.
触发成功!
这很易改, 把 SUBS W11, W11, #1 改为 SUBS W11, W11, #0 可以了
你也可以改成 MOV W11, 99 之类, 不过这样的话,
后面 B.NE 要处理一下 (改成B 或 B.AL 代表必定转跳)
关于 IDA PRO 的技巧实在太多了.我已尽量把不同的技巧写在这篇文章中。
相信会吓坏很多人.
学习要慢慢来, 收藏起来得闲再看吧。
之后的教学会比浅易,
既然金手指做出来了. 这港版可以转成日版及美版使用。
下次教大家把代码升级或转移地区版本。
特别鸣谢
Eiffel2018 原创发布:【金手指教程3】更多调试技巧及数据挖掘
如您从本文得到了有价值的信息或帮助,请考虑扫描文末二维码捐赠和鼓励。
如本文对您有用,捐赠和留言 将是对我最好的支持~(捐赠可转为站内积分)
如愿意,请向朋友推荐本站,谢谢。
尊重他人劳动成果。转载请务必附上原文链接,我将感激不尽。
留言