欢迎光临散文网 会员登陆 & 注册

关于PVZ1的撑杆土豆偏移bug的浅析

2021-07-31 12:50 作者:Ghastasaucey  | 我要投稿

特别声明:我是用汉化一进行分析的,英原、汉化一等同理,年度版依旧可用

对于这个bug,具体的描述是:

在一行有四只落地的撑杆的情况下,本行的小鬼僵尸可以啃食到土豆雷而土豆雷不爆炸,并且啃不死

这个bug首先由碳酸(贴吧名见下文)于2021.7.30发现(同样原理的4杆引雷最晚发现于2020.7.11,所以这里的发现是指这个bug的发现日期,而不是指这个bug的原理产生的任意bug的发现日期),由零度、恶魂(贴吧名见下文)研究,本专栏为该bug具体的分析,涉及到一定的汇编知识。

正文

原版土豆地雷的函数为

0045FE20 > Plant_UpdatePotatoMine

如果从这个函数向下看,找到对于状态0x10的处理(0x10为土豆冒出后),可以发现这样的代码:

0045FFFE   cmp eax,10 { 16 }

00460001   jne 00460053

00460003   mov eax,[edi+1C]

00460006   push eax

00460007   push edi

00460008   xor ecx,ecx

0046000A   call 004675C0

0046000F   test eax,eax

00460011   je 0046001F

00460013   push edi

00460014   call 004666A0

00460019   pop edi

0046001A   pop esi

0046001B   pop ebp

0046001C   pop ebx

0046001D   pop ecx

0046001E   ret 

这段代码比较让人注意的两个call,004666A0控制着爆炸,而这里的重点在于

004675C0 > Plant_SearchZombie

我们看一下这个call的内部内容,会发现一个循环结构,而在循环结构中,有这样一段代码:

00467731   cmp edx,04

00467734   jne 00467794

00467736   mov ecx,[esi+24]

00467739   cmp ecx,12

0046773C   jne 0046774B

0046773E   cmp byte ptr [esi+000000BC],00

00467745   jne 00467884

0046774B   mov eax,[esi+28]

0046774E   cmp eax,0C

00467751   je 00467884

00467757   cmp eax,0B

0046775A   je 00467884

00467760   cmp ecx,03

00467763   jne 00467772

00467765   mov eax,00000028

0046776A   add [esp+28],eax

0046776E   sub [esp+30],eax

00467772   cmp ecx,14

00467775   jne 00467786

00467777   mov eax,[esi+00000080]

0046777D   cmp eax,[edi+28]

00467780   jne 00467884

00467786   cmp byte ptr [esi+51],00

0046778A   je 00467794

0046778C   mov [esp+14],0000001E

这里,edx是植物类型,0x4就是土豆雷,首先检测是否为跳跳,撑杆显然不是,跳过,而后面检测撑杆是不是撑着杆的状态或跳起的状态,都不是则检测是不是已落地的撑杆,是则将esp+28加40,esp+30减40,问题就出在这里。

esp+28和esp+30控制着偏移量,但是esp+28和esp+30在每次循环的开始不会清空,所以会导致下一个僵尸依旧拥有这个偏移。

当偏移量大到一定量的时候,小鬼虽然在范围内,但是偏移的太远了,所以不会导致爆炸。

需要注意的是,这个bug和僵尸的序号(栈位)有关。

遍历的顺序是从[[[6a9ec0]+768]+90]开始,到[[[6a9ec0]+768]+90]+n*15C(颜色为方便指针的阅读),如果小鬼的序号在撑杆之前,还没有偏移就已经搜索到小鬼了,依旧会导致爆炸(所以不是一旦有4个就炸不到,还得看情况)。

对于,为何要求是同行:

004676C0中ebx为植物僵尸行数差,土豆没有什么特殊的判断(其实有一个如果僵尸是濒死的则跳过),所以按照正常的运行。

00467614   mov ebx,[esi+1C]

00467617   sub ebx,[ebp+0C]

……

004676C0   test ebx,ebx

004676C2   jne 00467884

所以如果不在同行会直接跳过,不影响偏移。

至于啃不死,就更好解释了,涉及到这个函数:

0052FB40->Zombie_EatPlant

扣血的地址在:

0052FCF0   add dword ptr [esi+40],-04

但是,有这样的代码:

0052FC31   cmp ecx,04

0052FC34   jne 0052FC40

0052FC36   cmp dword ptr [esi+3C],00

0052FC3A   jne 0052FDEE

0052FC40   xor al,al

是非预备状态的土豆雷则直接跳走,不执行之后的扣血,所以才会无敌

另外,这个具体的偏移量是40px

其实,大嘴花也有类似的现象,但是是对于右行矿工而言的,具体代码:

004676DD   cmp edx,06

004676E0   mov [esp+14],00000000

004676E8   jne 00467731

004676EA   mov eax,[esi+28]

004676ED   cmp eax,25

004676F0   jne 004676FF

004676F2   mov ecx,00000014

004676F7   add [esp+28],ecx

004676FB   sub [esp+30],ecx

右行矿工会让本行的大嘴花产生20像素的偏移

改版如何修复这个bug

很简单,添加一个初始化。

可以在00467609跳出,然后加入初始化解决

实战运用

由于本人更多的是一个改版作者,EL、IZE是偶尔玩玩啥的,所以这里就不提出什么运用了(多半是无尽养僵尸,IZ自制关之类的)

这就不是我擅长的领域了(笑)

结语

简单的bug的分析而已,没什么其他的。

但是我很期待利用这个bug做出的一些优秀作品

本文涉及到的人名对于的贴吧名

碳酸->111111和1

零度->失控的指令

恶魂->Ghastasaucey

参考资料与文献

PVZ指针表

Hope_20121221_(贴吧名)等人于2011年、zjfaok(贴吧名)等人于2014年研究发布

崇明人家123(贴吧名)于2017、2018年收集整合

Dr丶小黑、康师傅豆腐、4573去、Ghastasaucey、六三enjoy(均为贴吧名)先后于2019到2021增添修补

PVZ函数表

失控的指令(贴吧名)于2020、2021年收集整理

文章作者:Ghastasaucey

关于PVZ1的撑杆土豆偏移bug的浅析的评论 (共 条)

分享到微博请遵守国家法律