吞食鱼2(FeedingFrenzyTwo) 修改器

童年回忆系列。小时候特别喜欢玩这类游戏,软件不大,很慢的网速也不会下载太久,然后对配置要求不高,很破的电脑也可以玩得很开心。不过也有糟心的时候啊,大鱼太多,无数次死于挑战咬梭子鱼的尾巴……今年最后一天,就休闲一小会吧。

小时候看不懂是啥意思,现在知道了,我来翻译下第一段。

警告!

发现梭子鱼在珊瑚礁附近游荡。留意警告标志,远离它张开的大嘴!要是你有迷之自信,可以试着咬它的尾巴。咬 4 次就会有惊喜……如果到那时候你还活着……

现在再玩已经没有当年的感觉了——鼠标换了……其实我老早就想,为什么到了下一关,我的鱼就变小了??太不爽了。游戏里各种对玩家不利的设定:小鱼不能吃大鱼、被大鱼追、被贝壳吃掉、被乌贼喷、被水母电、被大嘴鸟吞、被鱼类炸、被河豚刺、吸水还要 CD、跳出水面翻滚的话进水眩晕……所以只有修改内存数据才是称霸海洋的秘诀!

工具:Cheat Engine 6.4 (以前搞的汉化版,其实翻译不完全,建议用英文版)

大,大,大

这个游戏的规则是吃小鱼,躲大鱼,等长大了以后就可以吃遍全图。成长值进度条在左上角,前面的关卡都是 3 个成长阶段,到了后面还有更多的级别。

好的,按照程序员的思路,姑且猜测 growth 数据用整型存储,每种鱼的加成不一样,小鱼少些,大鱼多些,初始值为 0,打开 CE ,开始搜索,每吃一条鱼就搜一次“增加的数值”。

好的,没搜几次,轻松搜到 2 个值。尝试修改第一个,发现鱼没反应;再尝试第二个,鱼长大了!然后自然是一顿操作:找出改写 -> 显示反汇编,然后看到了如下代码:

这也太舒服了,直接找到静态地址005AC624,省的找基址了,直接手动添加地址,growth 就有了。基址005AC624偏移+3C, +40(跟基址写成 "FeedingFrenzyTwo.exe"+001AC624 是一样的)

四两吃千斤

修改 growth 的数值,就可以瞬间变大,通关,但是这一点也不爽啊,我一定要把被吃的仇报了才行!

还是刚才的进度条,用通常思路来猜,成长阶段数值分别是 0, 1, 2 ,姑且先试一下。借助修改 growth 值快速长大,搜索这几个值就很快了。

先尝试修改第一个,图中我修改 0245AE24 的值为 0 以后,我 2 阶的大鱼被比我小的鱼吃掉了,那应该就是它了。观察了一会发现,这个值就是用来确定会不会被吃的,但是查找访问它的代码并没找到什么关键判定,代码太多了,我也懒得看,反正只要不被吃复位,这个值就不会变,直接把它改大点就行了。

在鱼变大的时候查找改写它的地址,可以找到偏移量 EC

00496B47 - 89 99 EC000000 - mov [ecx+000000EC],ebx

再稍微调试跟踪下,找到基址。基址005AC624偏移+40, +344, +0, +EC,类型我选了 byte ,不过应该没啥影响。

然而事实是,我不会被大鱼吃掉了,但是在大鱼旁边的时候也不会触发吃鱼的动作了……是太难吃了吗?哈哈……不过,离成功不远了。经过一番探索,我用“增大的数值”搜索前边的成长阶段,找到了另一个数值。简单点来说,这两个值一个是玩家鱼在电脑鱼面前的大小,一个是电脑鱼在玩家鱼面前的小大。<- 我说小大,因为第二个值数值越大判定电脑鱼越小。

基址005AC624偏移+40, +344, +0, +F8,就在上一个值旁边,很狡猾啊,这个值是从 1 到 3 的,之前搜精确数值的时候没找到,早知道就先去看看数据结构了。

把这两个值同时改成 5 ,终于报了当年的血海深仇,啊哈哈哈哈哈哈哈……

速度和位置

吸取刚才的教训,现在来看看数据结构。

嘿嘿,果然有了意外收获。仔细观察鱼的状态和数值,可以发现上面的 4 组浮点数分别代表鱼的位置和速度,修改这些值可以让鱼瞬移到地图任何地方。

然后我就有了一个大胆的想法——能不能把地图里的其他鱼瞬移到我嘴边呢?省的乱跑了。事实是——YES! 首先要找到存放地图上所有鱼的地方。

拿玩家鱼的位置来说,地址是 基址005AC624偏移+40, +344, +0, +98,按照程序的对象模型来想,+344指针应该是玩家指针,里面存放了很多和玩家相关的数据,刚才做四两吃千斤的时候,数据也在这个对象下,那么看下+0指针应该就是玩家的鱼的指针了,我这次游戏的指针是 09397280 。好的现在假设有这么个全局鱼数组,那么这个 09397280 也一定在里面,直接搜索这个指针:

嘿嘿,我为什么单独标出来这个 07EDC488 呢?因为看数据结构,在之前的 +344 指针前面,在 +324 指针的地方,指向的数据不就是 07EDC488 嘛,这应该是个数组首地址,展开一看,果然全都是鱼!

鱼是有了,可是数量不知道……这个数组没有结束标识,貌似是像vector那样管理的,有固定大小,靠整数标记结束的位置,而游戏本身可能不记录实时的鱼数量,所以我找了一遍,一直没找到数据,也可能是我找的方法不对。鱼在不同状态的时候地图上的鱼数量会变,但是因为不知道具体值,非常难找,我猜测是一些常数,规定了不同关卡鱼的数量上限。

我还强行试了下移动所有鱼直到空指针,会访问销毁过的鱼对象而导致访问越界崩溃,问题应该出在这里 mov ebx,[eax+edi]//4*nedi 的值增大以后,eax+edi 就不一定是有效地址了。然而令人惊奇的是,只要不点错误窗口上的确定键,就还可以继续游戏!真神奇……脚本如下:

[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
//0051A002
alloc(newm,512)
label(nextfish)
label(exit)
newm:
pushad
mov eax,["FeedingFrenzyTwo.exe"+001AC624]
mov eax,[eax+40]
//GetPlayersFish
mov esi,[eax+344]
mov esi,[esi]//ThisIsThePlayersFishClass
//PlayerPosition
mov ecx,[esi+98]
mov edx,[esi+9C]
//GetYou(heiheihei)
mov eax,[eax+324]
mov edi,0
nextfish:
mov ebx,[eax+edi]//4*n
cmp ebx,0//NoNextFish
je exit
add edi,4
cmp ebx,esi//IsPlayer?
je nextfish
mov [ebx+98],ecx
mov [ebx+9C],edx
jmp nextfish exit:
popad
ret
createthread(newm)
LdrInitializeThunk:
DB 8B FF 55 8B EC [DISABLE]
//code from here till the end of the code will be used to disable the cheat
dealloc(newm)

可以不理它,别点确定,直接返回游戏:

如果想稳妥一点,就去掉 jmp nextfish 这句,这样就每次只移动 1 只鱼,因为地图上一直会有一堆鱼,所以低频调用移动 1 只鱼的脚本是没事的,也可以轻松叠满 FRENZY

因为已经可以四两吃千斤了,所以继续搞这个功能也没啥必要了,就到此一游吧,不找鱼总数了。

变小魔法

游戏里有很多有意思的道具,比如蘑菇,可以让周围的大鱼变小;还有个红色的疯狂鱼,可以时间停止然后自动吃掉屏幕里的鱼,如果能找到对应的 call 就爽了。下面就来试一试。

首先我大概想了个思路,因为之前得到了存储鱼 growth 数值的地方,电脑鱼与玩家鱼用的是同一个类,所以存储的偏移应该也是一样的,所以查看数据结构里全局鱼数组,随便找条大鱼,查找改写 growth 数值的地方,然后去吃个蘑菇。之后代码断在了 0041D744 ,这里没什么有用信息,返回到上层函数,发现了有意思的东西。

0042863F - 68 08B35500 - push 0055B308 : ["shrinkBurstFx"]

这个单词 "shrink" 就是缩小的意思,再继续向上返回查找,又发现了一个位置:

0049AA93 - 68 B8E65400 - push 0054E6B8 : ["fishShrink"]

然后我再继续返回,发现到了外层大循环,而函数内部的断点是在魔法光球打在鱼身上的时候才会中断,我们需要的函数却是吃蘑菇的事件函数。好的,现在先暂停一下,缕缕思路:

  1. 玩家吃蘑菇
  2. 触发吃蘑菇事件函数,发出光球,目标是电脑大鱼
  3. 电脑大鱼被光球打中,触发缩小事件,缩小

我们刚才找的 "shrink" 相关的函数应该是步骤 3 ,需要找的是步骤 2 ,而步骤 2 到步骤 3 应该不在同一个函数中,它们之间应该只是消息传递的过程,所以这个线索就断了。

不过,嘿嘿,代码注释里已经给我们提供了新的线索——"shrink" 字符串。每次触发事件的时候,就会引用和 "shrink" 相关的字符串,所以新的思路有了——搜索 "shrink" 字符串,然后查找什么访问了字符串,看看吃蘑菇的时候会断在哪里。首先找到 078BBCF8 的位置是我们刚才找到的 "fishShrink" ,而就在它下面不远的位置,发现了 "shrinkPickup" ,地址是 078BBE10!!!哇,运气好到爆炸!

查找什么访问了 078BBE10 ,然后查看堆栈,在这个字符串附近的函数一个一个进去看,终于在 004747CD 的地方找到了线索。

004747CD 下断点,然后吃东西就会中断,再向上返回,发现返回的位置和吃的东西有关。

吃蘑菇返回到这里

吃鱼返回到这里

试了几次,吃什么就会返回到什么地方,所以附近应该就有吃的函数了,传入的指针就是吃的东西,用多态的思想,吃什么就执行什么的事件函数,所以离胜利不远了……

经过一番调试,终于找到了吃东西的函数——call [eax+90] ,就在 0042A98C 的地方,esi 是被吃的对象,+90 大概是虚函数表里执行被吃事件的函数指针,参数是 edi ,储存发起吃东西事件对象的指针,还有个寄存器参数 ecx ,储存的是被吃对象指针。一个以吃东西为游戏内容的游戏,把吃东西的函数找到了,游戏结束!

后面的工作就轻而易举了,下断点在每次吃掉蘑菇的时候步入,就到了 004A249D ,这个 call 00493BD0 就是我们苦苦寻找的吃蘑菇的事件函数了,这个函数只有一个寄存器参数,就是 esi 储存发起事件的对象指针,这里我们把玩家填进去就好。还记得玩家指针在哪吗?没错,就是之前找四两吃千斤的时候找到的对象:基址005AC624偏移+40, +344, +0

然后写出脚本,只要执行这个脚本,就相当于吃了蘑菇,变小魔法就会触发了,大功告成。

[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
//004A249D
alloc(newm,512)
label(exit)
newm:
pushad
mov eax,["FeedingFrenzyTwo.exe"+001AC624]
mov eax,[eax+40]
//GetPlayersFish
mov esi,[eax+344]
mov esi,[esi]//ThisIsThePlayersFishClass
call 00493BD0 exit:
popad
ret
createthread(newm)
LdrInitializeThunk:
DB 8B FF 55 8B EC [DISABLE]
//code from here till the end of the code will be used to disable the cheat
dealloc(newm)

狂吃

还是按照上面的思路,在0042A98C 的吃东西函数 call [eax+90] 下断点,然后吃个 "FEEDING FURY" 道具,找到对应的代码。很轻松就找到了,然后写出下面的脚本。

[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
//0053D05D
alloc(newm,512)
label(exit)
newm:
pushad
mov eax,["FeedingFrenzyTwo.exe"+001AC624]
mov eax,[eax+40]
//GetPlayersFish
mov esi,[eax+344]
mov esi,[esi]//ThisIsThePlayersFishClass
//feeding fury 00502399
add esi,00000154
mov eax,[esi]
mov ecx,esi
call [eax+20]
test eax,eax
je exit
mov eax,[esi]
mov ecx,esi
call [eax+20]
mov edx,[eax]
mov ecx,eax
call [edx+70] exit:
popad
ret
createthread(newm)
LdrInitializeThunk:
DB 8B FF 55 8B EC [DISABLE]
//code from here till the end of the code will be used to disable the cheat
dealloc(newm)

防雷

直接找出是什么访问了玩家鱼指针,然后去撞水雷。查询过程非常卡,所以到了水雷旁边再开始查询。撞到水雷时,会出现一些新的代码,一个一个找。运气很不错,找第一个就发现了关键跳转。

0050B773 - 75 30 - jne 0050B7A5 有鱼死掉时的关键跳转

再向下找,就在下面找到了鱼撞雷死亡调用的函数

0050B798 - FF 90 DC000000 - call dword ptr [eax+000000DC]

当玩家单位触发时步入,里面只有 3 行汇编。

只要在玩家触发水雷的时候跳过这个函数就可以了

[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
alloc(newmem,2048)
label(returnhere)
label(originalcode)
label(exit) newmem: //this is allocated memory, you have read,write,execute access
//place your code here
push eax
mov eax,["FeedingFrenzyTwo.exe"+001AC624]
mov eax,[eax+40]
//GetPlayersFish
mov eax,[eax+344]
mov eax,[eax]//ThisIsThePlayersFishClass
//if player hit a mine
//then jump
cmp eax,ecx
pop eax
je exit originalcode:
mov eax,[ecx]
call dword ptr [eax+000000EC] exit:
jmp returnhere "FeedingFrenzyTwo.exe"+102BE3:
jmp newmem
nop
nop
nop
returnhere: [DISABLE]
//code from here till the end of the code will be used to disable the cheat
dealloc(newmem)
"FeedingFrenzyTwo.exe"+102BE3:
mov eax,[ecx]
call dword ptr [eax+000000EC]
//Alt: db 8B 01 FF 90 EC 00 00 00

因为这里的函数在其他事件触发时也有被调用到,所以不知道这么改有什么副作用,暂且先这样,等以后出了问题再回来看……(懒)

另外还发现了销毁玩家对象的函数,不知道以后用不用得上。

00438EBD - FF 50 1C - call dword ptr [eax+1C] 玩家鱼对象销毁

其他

  • 吸水能量条 基址"FeedingFrenzyTwo.exe"+001AC624 偏移 +40, +344, +0, +20C 类型是 float 从 0 到 1
  • 吸水持久度 基址 005A7314 浮点数 float,数值越小持续时间越长
  • 吸水恢复速度 基址 005A7318 浮点数 float,数值越大恢复速度越快
  • 直接过关 基址 005AC624 偏移 +40, +8C 字节 byte ,改成 1 即可。大部分时候好用,个别关不行,不知道为啥

从空中翻滚后落到水里会晕一会,这个脚本可以防止眩晕。其实功能非常简单,就是跳过 mov byte ptr [ebx+0000019D],01 这一句。

[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
alloc(newmem,2048)
label(returnhere)
label(originalcode)
label(exit) newmem: //this is allocated memory, you have read,write,execute access
//place your code here
jmp exit originalcode:
mov byte ptr [ebx+0000019D],01 exit:
jmp returnhere "FeedingFrenzyTwo.exe"+13FC74:
jmp newmem
nop
nop
returnhere: [DISABLE]
//code from here till the end of the code will be used to disable the cheat
dealloc(newmem)
"FeedingFrenzyTwo.exe"+13FC74:
mov byte ptr [ebx+0000019D],01
//Alt: db C6 83 9D 01 00 00 01

结语

权当是休闲娱乐,没做太多复杂的东西,想做成品修改器的小伙伴也可以写一个。

今年最后一天了,祝大家玩得开心。

吞食鱼2(FeedingFrenzyTwo) 修改器的更多相关文章

  1. CE修改器修改DNF 测试视频 阿修罗提升智力增加攻击力

    使用CE修改器来修改网络游戏,如DNF 测试视频: CE修改器:指的是Cheat Engine,字面上的意思指的是作弊引擎的意思,是一款内存修改编辑工具.通过修改游戏的内存数据来得到一些原本无法实现的 ...

  2. tp5 中 model 的修改器

    修改器可以在数据赋值的时候自动进行转换处理 class User extends Model { public function setNameAttr($value){ return strtolo ...

  3. Blender 之修改器代码分析

                           Blender的修改器(modifier)模块,默认界面右下块(Property)面板的扳手,分类(修改.生成.形变.模拟)列出所有的修改器.也可以空格键 ...

  4. mongodb的修改器

    在mongodb中通常文档只会有一部分要更新,利用原子的更新修改器,可以做到只更新文档的一部分键值,而且更新极为高效,更新修改器是种特殊的键,用来指定复杂的更新操作,比如调整.增加.或者删除键,还可以 ...

  5. 【MongoDB】4.MongoDB 原子修改器的 极速修改

    文档转自:http://blog.csdn.net/mcpang/article/details/7752736 对于文档的更新除替换外,针对某个或多个文档只需要部分更新可使用原子的更新修改器,能够高 ...

  6. MongoDB修改器的使用1

    为什么要使用修改器?     通常我们只会修改文档的一部分,这时候更新整个文档就显得很麻烦,通常是通过原子性的更新修改器来完成. 1."$set"修改器    "$set ...

  7. UWP游戏防内存修改器的方法

    最近我一直在编写适用于Windows 10商店的游戏.这款游戏比较怕玩家用修改器改金钱,因为这种修改会导致某些内购失效并且损害公平性.于是我把自己见过的三种反修改器的方法给网友们介绍一下. 首先说明一 ...

  8. mongodb_修改器($inc/$set/$unset/$push/$pop/upsert......)

    主从复制:http://blog.csdn.net/drifterj/article/details/7833883 对于文档的更新除替换外,针对某个或多个文档只需要部分更新可使用原子的更新修改器,能 ...

  9. ce游戏内存修改器(Cheat Engine)

    ce修改器(Cheat Engine)一款专门修改内存修改编辑的游戏工具它包括16进制编辑,反汇编程序,内存查找工具新版6.1 版的CE与6.0 最大的区别就是添加了修改器制作工具,比之前 5.6.1 ...

随机推荐

  1. 【GDKOI2014】JZOJ2020年8月13日提高组T1 阶乘

    [GDKOI2014]JZOJ2020年8月13日提高组T1 阶乘 题目 Description Input 第一行有一个正整数T,表示测试数据的组数. 接下来的T行,每行输入两个十进制整数n和bas ...

  2. CSDN-markdown编辑器使用方法

    这里写自定义目录标题 欢迎使用Markdown编辑器 新的改变 功能快捷键 合理的创建标题,有助于目录的生成 如何改变文本的样式 插入链接与图片 如何插入一段漂亮的代码片 生成一个适合你的列表 创建一 ...

  3. 第15.22节 PyQt(Python+Qt)入门学习:Model/View架构详解

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 一.简介 在PyQt和Qt中,Model/View架构是图形界面开发时用于管理数据和界面展现方式的关 ...

  4. PyQt(Python+Qt)学习随笔:Qt Designer中部件的toolTip、toolTipDuration、statusTip、whatsThis属性

    toolTip属性 toolTip属性设置部件的toolTip提示信息,toolTip提示信息在鼠标放到控件上会浮动出一个小框显示提示信息.默认情况下,仅显示活动窗口子部件的toolTip,可以通过在 ...

  5. Shell命令和流程控制[linux常用命令的使用]

    在shell脚本中使用三类命令: unix命令 概念:管道.重定向.backtick 流程控制 1 unix命令 echo "some text":在屏幕上输出信息 ls:文件列表 ...

  6. google colab 杂谈

    需要一个GPU服务器,找到了免费的Google Colab 一.切换tensorflow版本: %tensorflow_version 1.x import tensorflow as tf tf._ ...

  7. linux替换项目jar包

    查看服务是否启动,如果启动,则需要根据 pid 停止服务: # ps -ef | grep xxx.jar 杀掉该项目进程 # kill -9 pid号 再次查看进程 # ps -ef | grep ...

  8. go学习49天

    写文件操作 func OpenFile(name string,flag int,perm FileMode) (file *File,err error)

  9. 团队展示——Part I

    1. 团队简介 队名:非专业团队

  10. 移动端H5开发中的常见问题处理

    1.问题之合成海报: 功能技术:http://html2canvas.hertzen.com 问题描述:合成模糊.合成区域内容错位,合成不完整,合成边缘白条等. 解决方案:如有页面布局正常合成错位的, ...