【CheatEngine基础教程】三、Cheat Engine Tutorial实战

您所在的位置:网站首页 ce指针扫描器结果是0 【CheatEngine基础教程】三、Cheat Engine Tutorial实战

【CheatEngine基础教程】三、Cheat Engine Tutorial实战

2024-07-17 00:31:43| 来源: 网络整理| 查看: 265

终于开始修改的实战了,兴不兴奋?我也很兴奋,因为终于(假装)把烦人的基础知识讲完了。

CE自带的教程循序渐进为读者讲解CE的功能和特性,是非常好的学习CE的途径。本章包括三个主章节,第一节将同读者一起完成CE基础教程的实战。在第二节我们将完成CE自带的小游戏的修改。而到了第三节,我们将针对这些程序进行更高级的玩法,看看一个改派玩家可以无聊无耻到什么程度……

闲话不多说,开始吧。

1 Tutorial 实战

在CE主界面依次点击Help——Cheat Engine Tutorial,会打开CE自带的教程。你可以随意选择X86版或者X64版。

1.1 第1关 090453

这一关主要是告诉我们如何用CE打开要修改的程序,非常简单,一图搞定……

第一关 打开目标程序

另外,在这一关中有一个文本框,我们可以在这里输入一个密码,直接跳转到指定关卡。在下面的子章节中,标题后面的数字就是此关对应的密码。

1.2 第2关 090453

这一关教你如何修改4字节整数的数据。你一开始有100点血。所以我们先试试按4字节整数的格式搜索100.

搜索100

得到了不少地址,我们在教程中点击Hit me,让血减少,然后填入新的值,点Next Scan,重复这个步骤直到最后只剩下一个地址:

搜到了

双击这个地址,可以把它添加到主界面下面的地址列表中,如上图所示。将这个值改成1000后,教程的Next按钮将变成可用状态。点击它我们会进入下一关。

1.3 第3关 419482

这一关是叫我们模糊搜索的,它告诉我们值的范围是0~500,让我们把这个值改成5000。所以我们可以先搜0~500之间的数:

搜索结果

噫,这种内容好无聊,我们略过好不好。OK,没人反对,本节结束。

1.4 第4关 890124

嗯,这关是讲浮点(float)和双浮点(double)类型的,因无人反对所以跳过。

1.5 第5关 888899

这关有点意思了,给你一个四字节整数,你的目标是让它的值保持不变。

教程也说了,直接锁定这个数值是可以的,如果你写入数字的频率够快的话……但这种方法本来就比较笨,所以我们选择另一种方法:直接修改指令。

首先我们还是要找到这个数在内存中的地址,然后右键单击这条地址,选择"Find out what writes to this address"(快捷键F6),然后会弹出一个对话框,问你是将载调试器附加到目标进程,选是,然后会打开一个窗口,用来列出所有修改了此地址的代码。先不要管这个窗口,在教程中点击“Change Value”让这个值发生变动,这个窗口中会出现写入这个地址的指令信息,然后右键单机这个指令,选择用NOP替换代码,如下图所示:

指令列表

一路确定后,在教程中点击“Change Value”,你会发现Next按钮可用了,过关。

简单解释一下。双击上图的代码,或者选中代码后点击右侧的More Infomation,可以看到当前寄存器的状态(当然就像上图所示的,在窗口下方也展示了这些信息):

正如我们所见,eax的值就是目标地址,而edx的值则是新的值,mov [eax],edx的意思,就是将edx的值写入eax的值所表示的地址中。而上面我们所做的工作,是用两个Nop(空指令)替换这条语句,以实现什么都不执行的目的:

另外,点击CE主界面的Advanced Options按钮,可以看到这条被替换的代码,并随时在原指令/nop指令之间切换。

除了代码列表,游戏暂停按钮也在这里

1.6 第6关 098712

如果你理解了第五关,第六关也不成问题。这一关是要我们寻找指针。虽然教程说我们可以用CE提供的指针扫描器来完成这个工作,但是对实际修改游戏来说,这个扫描速度非常慢,再加上扫描结果很多难以排查,又不稳定,所以我根本不推荐也不介绍这个方式。

言归正传,我们开始找指针。照例还是找到目标地址,然后看看是什么改写了这个地址:

有什么感想呢?索然无味,索然无味啊朋友们。连个偏移量都没有,太简单了。还记得上一章提到的指针和偏移量的概念吧?在这里,这种结果表示这个地址是一个数据结构的起始地址,所以没有偏移量。而基于对指针的理解,我们可以确认,存在一个地址,它记录着着目标数值的地址,即edx的值16D1A48。

我们直接在CE里搜索这个地址,记得在Hex上打勾,因为是16进制数字:

最后那个绿色的表示此地址的位置不会变动。也就是说,指针找到了。我们把这个指针添加到代码列表:

将这个值改成5000并锁定,然后点击教程的Change Pointer,如无意外,这一关也就过了。

这就是最基础的指针的找法了。总结一下就是,找到目标地址M,然后查看是什么访问了M,以获知M所在的数据结构的起始地址K和M相对于K的偏移量O,然后在CE中搜索地址K,在搜索得到的结果合集L中进行筛选(),找到目标后T,查看是什么语句访问了T……如此重复直到找到一个绿色的地址,这就是我们的目标了。

注1:筛选有主要两种方式,首先可以看看这些结果,如果变动了,即它的值不再是K了,那么肯定不是指针。另外,如果它是K的指针,那么在程序访问目标地址M的时候,势必会访问它,以定位到K,然后再到M,也就是说,它对应的“是什么访问了此地址”的结果不会为空。两种方式可以结合使用。

不过如果你熟悉汇编代码,也可以尝试另一种方法,直接根据汇编指令来肉眼找指针。比如这里的例子,我们查看附近的汇编代码,可以看到如下内容:

注意mov edx,[Tutorial-i386.exe+2426B0] 一句,Tutorial-i386.exe+2426B这种模块+偏移量的写法一看就是基地址,指针无疑。

1.7 第7关 013370

这一关要求我们修改“游戏”的效果。原来的效果是每挨一下打扣1点血,而教程要求我们改成每次挨打增加2点血。

照例还是找地址看什么改写了它……找到之后,我们点击监视窗口右侧的show disassembler,在Memory Viewer中查看它的反汇编代码:

注意看啊,在这里,我们找到的地址的偏移量是4A4,所以假设我们想找这个地址的指针,不能直接搜这个地址,而应该搜edx的值。

在sub dword ptr [ebx+000004A4],01语句中,sub是减法指令,dword ptr是对于内存地址的修饰,说明这个地址(ebx+000004A4)是一个四字节(dword,double word,1word=2byte)数据的指针。

要完成这关,我们可以双击这条语句,把sub改成add,然后把后面的01改成02,即add dword ptr [ebx+000004A4], 02。先别急着尝试,这种改法并非教程所期待的……教程这一关旨在告诉我们如何进行代码注入。

在Memory Viewer窗口选中这条语句,然后点击菜单Tools——Auto Assembler,或直接使用快捷键Ctrl+A,会弹出自动汇编窗口,让我们可以在这里写一个脚本,以注入自己的代码。

在自动汇编窗口,依次点击Template——Cheat table framework code,或使用快捷键Ctrl+Alt+T,会自动创建一个框架,如无意外,整体应该是这样的:

自动汇编窗口

其中的“[ENABLE]”下面是激活脚本后要做的工作,而[DISABLE]下面是关闭脚本后要做的工作,双斜杠//后面的内容是注释,会被CE的脚本解释器忽略。

接下来我们要进行代码注入了,尽管这个哪怕自己写也非常简单,不过既然CE提供了自动生成功能,我们也没必要浪费时间,点击Template——Code injection,或使用快捷键Ctrl+i,这是会弹出一个窗口,询问是否在指定语句注入代码:

选Ok,整体脚本会变成这样(除了我多加了一点注释):

我们一点点看。

其中alloc是CE脚本语句,表示我们要为自己的脚本分配一段空间,与之对应的是dealloc,取消分配空间。alloc(newmem,2048)是说,我们分配一个2048字节的空间,并将其命名为newmem。

而label则表示一个标签,你可以将它理解成地址的别名,便于我们操作和访问。你看,我们在源代码的位置做一个跳转,转到newmem之后可以做我们的工作,然后再跳转回returnhere的位置。

原始指令有七个字节的长度,而跳转指令(长跳转)有五个字节的长度,所以要补上两个空指令,即nop 2。

为了实现修改效果,我们需要对代码进行编辑。下面的代码就是我的编辑结果:

在这里,我删去了一些没用的标签和注释,可以更好的展现整个过程。写好代码后,点击File——Assign to current cheat table,脚本就被加入到CE的地址列表里了,在这里可以随便启用/关闭脚本。绝对不要直接点击自动汇编窗口下面的Execute,没法还原的。

X64版本教程的这一关中,CE自动生成的注入脚本有微妙的不同,其中分配内存的语句类似这样:

后面多了一个参数,表示我们希望在"Tutorial-x86_64.exe"+2D4F7(要注入的位置)附近分配新的内存区域。这么做的原因在于,即使是64位环境,CPU也只支持32位的寻址,如果不这么做,可能会导致程序错误。

趁着这个机会,我们再多尝试一些有趣的东西。考虑一个情况,我们用过的很多修改器,经常会有一些看似很奇怪的提示,比如无限金钱在金钱变动后生效,或者显示XX地址修改需要我们进行打开物品栏/读档操作才能或许,这些现象是因为,这些功能都是基于代码注入实现的。

先说某些项目需要在数值变动后生效的问题,在这里我们也可以做一个变动后生命最大的功能:

很简单吧?应用这个脚本后,一旦我们点击hit me,则生命会变成100,永远不会减少。不过,如果之前你的生命不满100,你不点击hit me,你的血就不满了,必须“变化后生效”。

再说另一个情况。修改器的某些功能,比如金钱修改,需要在游戏数据更新,或者我们打开状态栏blabla之后才显示。这可能是因为它使用了人造指针功能。

因为种种原因,某些游戏是不一定有稳定指针的,这种情况下我们需要“造”一个指针出来:

这里我没有修改原始指令,而是将ebx的值存入地址addrHealthPointer中。这里又有了两个脚本命令registersymbol和unregistersymbol,前者说说将目标注册成一个全局符号,一旦注册,无论是其他脚本还是CE地址列表,都可以直接用这个注册的符号来表示这个地址。

而脚本中的db,表示后面是一些单字节类型的数据,这里我们先将addrHealthPointer地址起始四个字节初始化为0。当然以字节为单位初始化是我的个人习惯,你可以直接用dd 0 (四字节)、dq 0(八字节,这里用不到)来做,或者选择不初始化(什么都不写)。

激活脚本后,我们可以将addrHealthPointer作为指针添加到地址列表中,并加上偏移量0x4A4:

这就是一个人造指针,不过目前为止这个指针还是无效的,想要让它生效,需要健康数值再次发生变动。

最后再考虑一个问题,有些修改器会说自己支持XX~XX版本,可能也会支持更高版本。游戏更新后代码也会变动,这又是怎么实现的呢?

原理很简单,比如这里我们找到的代码,后来如果教程版本更新了,很有可能出现这段代码本身没有变化(或极微小的变化),但代码在内存中的位置却变动了的情况。这个时候,我们就需要CE的AOB Scan功能,以做到向后兼容。我一直没搞清楚AOB这个缩写是什么意思,不过道理很简单,就是在内存中搜索指令对应的字节代码。显而易见,这要求用来搜索的字节代码必须是唯一的。

我们尝试使用AOB SCAN来更新我们的脚本。首先我们来复制这条指令的代码:

然后在CE中进行搜索:

 注意黑框重点圈出的位置,这里一定不要勾选可写类型,要取消选择(表示不可写)或像我这样设为“方框”,表示可不可写无所谓。

运气很好,它的代码是唯一的,我们可以直接使用这串字节数组。在CE自动汇编窗口里,菜单Template(模版)中有一个AOB Injection子菜单,它用于自动生成AOB注入的代码,一路确定后会自动生成如下代码,我把注释和没用的标签都删了:

aobscanmodule也就是在模块中搜索,第一个参数是搜索结果(如果有的话)的别名,当标签使用,第二个参数是要搜索的模块,第三个参数就是要搜索的字节码。

你会发现这种脚本和我们之前的写法大同小异,只不过原来直接使用"Tutorial-i386.exe"+275E3,而现在是通过搜索其对应的字节代码来定位。

另一个需要注意的是在DISABLE部分,这里直接用了“db 83 AB A4 04 00 00 01”来还原,而非汇编指令。这绝非CE的不足,而是一个相当聪明的设计。

要知道,同样的汇编代码,可能会因为不同的汇编器而生成不同的字节代码。平时无所谓,像这种通过AOB来定位的方式,如果我们激活脚本,然后关闭脚本,一旦在代码还原时生成了不同的字节码,则脚本就无法再次激活了。所以直接写回原来的机器码是更好的选择。实际上,任何时候这都是个更好的选择。

以上就是代码注入的方式了,显而易见的是,通过代码注入,我们可以更自由的实现自己的修改意图。不过,这需要我们尽量多地掌握汇编的相关知识,因为其中有许多风险。比如我们在注入代码时,一定不能破坏寄存器的值,除非你确定它目前的值后面不会被使用,否则就应该做好保存和还原操作,另外栈内存的内容和栈顶指针的维护也是如此。

再加上汇编代码的可读性天生劣于其他高级语言,所以很可能有潜在的风险。比如下面的代码是我跟人开玩笑的时候弄出来的,这段只有24个字节的代码一旦被执行,就会一直复制自身,直到发生越界访问程序崩溃:

最后,CE自动汇编脚本还有其他一些命令,不是很多,你可以在CE的官方维基查看它们:

1.8 第8关 525927

我以为此关必有高论,不曾想竟是多级指针……也罢,那就演示一下。

搜索地址,没问题吧?然后看是什么访问了这个地址:

记下偏移量0x18,然后在CE里搜索esi的值016DBBB0,在我这里得到了四个地址:

在我的机器上得到了四个地址,如果你经验够多,一眼就会意识到前三个都是栈内存的地址,临时的不行,肯定不对。最后一个地址是OK的,这一次,看看是什么访问了这个地址(快捷键F5)。记得,虽然之前都是“改写”,是因为要监视的地址的数值会变动,所以我们看“改写”就足够了。不过这种指正显然不会轻易变的,所以要用“访问”来看。让数值变动一下,在我的机器上,监视到两条地址都访问了这个地址:

这两条指令其实都是正确的,不过第二条指令有个问题,就是esi原始的值被覆盖了,而我们需要的是之前的值,所以要参考第一条。

注:并不是所有游戏都能这么幸运的找到有效的参考,这种情况下我们还是需要查看汇编代码肉眼分析。

记住偏移量0,然后再去CE里搜索Esi的值……如此重复,直到我们找到一个绿色(shai,三声)儿的地址,这就是最终的结果了,添加指针,成功:

很简单吧?OK,不过这毕竟是笨办法,操作繁琐,下面让我们尝试一下更风骚也更快捷的指针找法。

从头开始。查看是什么改写了健康值的地址,得到的结果和本节第一章图完全一样。我们看这条语句附近的反汇编代码:

目前我们知道esi+0x18就是健康值,第一个偏移量是0x18,而我们需要关注的,就是esi的值是怎么得来的。虽然语句mov [esi+18],eax 前面有个call(函数调用),寄存器会变动,但我们已经知道esi是非易失寄存器,所以这个函数并不影响esi的值。

于是我们直接往上看,上一条与esi有关的指令是lea esi, [esi+00]。lea指令的缩写是load effective address,就是将一个地址直接赋予一个操作数,显然这条代码就是个没用的弟弟。因为这条语句的数学描述就是esi=esi+0……这种语句一般都是编译器自己生成的。另外,哪怕不知道这些,也很容易看出这语句的无用,因为我们注意上面的跳转,有很多跳转直接定位到了它后头,作为一个稳定的指针肯定不能这么飘,对吧?

接上图

我们接着往上翻,从下往上看。又一条与esi有关的指令,mov eax,esi,这个也没用,是把esi的值赋给其他寄存器的。然后再往上,mov esi,[esi],OK很好找到了,所以第二个偏移量是0。

再往上看,又是 lea esi, [esi+00],弟弟。再往上,mov esi, esi,这个相当于把自己的值赋给自己,弟中弟,好吧,翻页。

接上图

在这一页我们发现了mov esi, [esi+14],所以第三个偏移量,0x14.

再往上翻,第四个偏移量,0x0C。然后我们终于找到了这样的语句:

看mov esi,[Tutorial-i386.exe+2426E0],多么可爱。虽然这里我发了不少图写了不少东西,但其实道理意外的简单对吧?熟练掌握之后这个过程会非常迅速。请多加练习吧。

通过指针将数值改成5000并锁定,等待3秒后关卡完成。

1.9 第9关 31337157

这一关的描述就复杂了。简单的说就是,不同的数据,可能会用相同的代码来修改。比如我们想要实现无敌模式,可能对敌人来说也有效。这一关就是告诉使用者如何做到相关代码如何只对玩家生效。

这一关有不同的解法,这里只展示其中之一,更多的解法请读者自己尝试。

首先这一关有四个角色(Dave,Eric,HAL,KITT),生命值是浮点类型。我们先不要着急做别的事情,先找到四个角色的生命值,记得是浮点类型。

生命值找到后,我们先以主角Dave为基准,看看是什么改写了这个地址,随后我们发现语句是mov [ebx+04],eax,所以Dave的生命值在这个数据结构中的偏移量是4。好了,让我们记录下ebx的值(其实并不用,显然ebx的值就是生命值地址减4),然后开始结构化浏览。

还是在Memory Viewer窗口,然后点击Tools——Dissect data/structures,或者使用快捷键Ctrl+D,进入结构浏览器,将ebx值地址添到文本框里,然后点击菜单Structure——Define new structure,或使用快捷键Ctrl+N,一路回车之后,我们就可以结构化的浏览主角Dave的数据结构了。

接下来还要做一点重复的工作,在结构浏览器中,点击菜单File——Add extra address,或使用快捷键Ctrl+A,可以增加一些地址,供我们进行比对,增加三个地址框,然后将Eric,HAL,KITT的生命值地址减4填进去,不出意外的话,最终效果应该类似:

这里我们注意到,偏移量0x15的地方是角色的名字,0x4则是角色生命值。剩下的数据就需要大胆猜测和实验了。

不过有一点很清楚,就是偏移量0x10的地方,主角团队的值是1,而敌人团队的值是2,让我们尝试一下在这里动手脚。

随便以哪个角色的生命值为目标,看看是什么改写了这个地址,当然如果刚才你的监视结果还保留着,可以直接用,然后在这条语句上做跳转做代码注入:

注释写的很清楚吧?将脚本加入地址列表,关闭窗口,无敌模式+一击必杀的脚本就完成了。点击Restart game and auto play,到此为止,CE自带的基础教程顺利通关,撒花。

2 Tutorial Games 实战

我不得不道歉了。

说实话写这个系列教程的原因之一,就是我显卡坏了没法玩游戏。但我万万没想到,这破集显竟然连CE自带的小游戏都运行不了(需要OpenGL 1.3)。家里除了台式机,就是几个苹果本,我也懒得装windows双系统,所以这一节先坑了吧,以后补充……希望8月11号的6600XT不是空气卡且价格不飘。

而且我上面讲的内容不算少了,读者应该能接受第三节的阅读难度。

3 制作 Tutorial 急速通关作弊表

教程虽然完成了,不过我们还是按照教程的“规划”一步步走的。作为高(wu)贵(liao)的修改党,怎么可以忍受别人强加我们的繁琐呢。

所以来尝试一下邪道改法,做一个快速通关CE Tutorial的作弊表吧。这次我将以X64版为例。

3.1 保存CE的地址列表

CE的地址列表可以保存为XML格式的文件,在主界面点击File——Save,然后在弹出的文件存储对话框里输入名字路径即可。

嗯,这一节的内容主要是为了占位,否则 “3.1 第2关” 这种标题看起来怪怪的。

3.2 第2关

第2关我们找到地址后,可以尝试找到它的指针,省的下次再搜索了……你以为我会这么说?

错了。我们试试更直接的改法。我们看看是什么访问了这个地址,好家伙,还没做什么呢,直接出现了一条指令……

注意看cmp [rbx+000007F0],000003E8啊,十六进制3E8就是十进制的1000,这一关要求我们把值改成1000,而这里把生命值与1000做比较,jne是不等于则跳转,你想到了什么?

没错!把JNE这条语句nop了呀,这样无论是不是1000都不跳转了。我们可以按之前说的那样,使用CE的功能直接用空指令替换,不过这里我选择用脚本实现这个效果:

启用脚本后,原代码是这样的:

直接过关。

3.3 第3关

第三关神烦,模糊搜索,更得改了,还是像刚才的操作,找到语句blabla,最后我们把刚才的脚本更新一下:

激活后,第三关直接通过。

3.4 第4关

这关我们要找一个float数一个double数,先找float数,找到后看是什么访问了这个地址,发现一条,然后浏览反汇编:

movss是单浮点指令,这条指令的意思是将目标的数赋给xmm0。然后通过comiss进行比较,jb是小于则跳转,JP则有点特殊,表示11区。呸,我从头说起。

先说comiss,这个指令是单浮点数比较指令,其运算结果会影响标志位寄存器。

而其实呢,所有的条件跳转都是通过标志位寄存器判断的,具体可以自己查查,我就不讲啦。然后有个寄存器叫PF,它反应了运行结果(二进制表示)中1的个数是奇数还是偶数。如果是偶数,则PF=1,否则,PF=0。而JP就是当PF=1时就跳转。

糊涂了吧?别急请接着看。浮点数的二进制表示法有个规范,叫IEEE 754,在这个规范里,定义了一系列浮点数异常值,如果一个浮点数等于这个异常值,表示这个数是没意义的,不用理会。而前面说的comiss指令,当两个操作数任意一个是这个异常值的时候,就会把PF标志位设为1。

所以JP其实在这里有点错误处理的意思。尽管说了一大串,但其实跟我们修改关系不大,只是科普,遇见类似的用法无视就好。

圆规正传,几个关键指令的意义都搞清楚了,这些代码就很好理解了吧,除了浮点数,下面一看就知道还搭上一个双浮点数的比较,就是那个movsd和comisd……这里要怎么改不用我说了吧?对,直接无条件跳过去就完了。

应用效果如下图所示:

直接过关。

3.5 第5关

这一关没意思,直接按照教程的改法就可以,只不过要以脚本形式写。

3.6 第6关

这是需要稍微思考才能完成的一关。本关的要求是让我们找指针,我们老老实实找到它之后,很快会就会发现:这一关既不像1~4关那样有个一直访问这个地址的指令,也无法像第五关那样按照教程要求的改法修改即可(至少比较不方便),怎么办呢?

别急,让我们先略微猜测一下这一关的运行逻辑。当我们点击Change Pointer后,教程会修改指针指向的地址,然后在3秒钟里检测这个新的地址的值。只不过CE的地址访问监测功能只对指定的地址生效,而一旦指针指向了新地址,还需要重新对新地址进行监视,这个操作想要在3秒钟内完成太赶了,所以我们需要用到CE的暂停功能。

点击主界面的Advanced Options按钮,弹出的窗口中有一个暂停功能,用它可以暂停目标程序。你也可以参考第二章介绍的那样,为它设置一个快捷键,然后,我们在教程里点击Change Pointer更换指针,然后暂停进程。暂停后就不用着急了,我们看看是什么访问了这个指针指向的地址:

取消暂停后,我们发现了这样的指令:

je的意思是等于则跳转,把它改成无条件跳转即可:

3.7 第7关

这一关按照原教程的方法修改即可,不过这里会再介绍另一种方法。教程让我们修改游戏效果,从挨打生命-1改为挨打生命+2。

我们不用去管那些加啊减的,找到生命值地址,看看是什么访问了这个地址:

看看每个找到的指令,查看相关反汇编代码,找个顺眼的……第四条就很顺眼嘛:

我们都不用关心ebx是怎么来的,看看mov eax,ebx,再看看add rax, 2,还有那个cmp和jne,一下子就知道这段代码是干啥的了,直接把下面直接把jne给nop了就OK:

3.8 第8关

这一关虽然是多级指针,但解法和第6关一样,不再赘述。请尝试肉眼找指针p:)

3.9 第9关

第九关可以按照第二节说的方法来解。不过之前的方法太累赘了。既然第三节中前面所有的修改都很精简,那么这里自然也不能丢掉这个好习惯。让我们试一试。

我们先找到Dave的生命地址(浮点类型),然后看看是什么改写了这个地址,不出意外会找到这样的地址:

先别着急做其他事情,磨刀不误砍柴工,我们先在反汇编窗口点击菜单Tools——Dissect code,或使用快捷键打开代码分析工具,用它把代码分析一遍,这样反汇编可以看得更明确一点:

这条语句是将新值赋给地址的,这个无用质疑,看后面的几条语句,分明是判断新值为0的对吧?教程最后的结算,是通过自动的方式执行的,我们可以猜测,它的机制是四个角色依次打一下,直到有角色的血为0,然后结算。所以可知这里已经有判断是否空血的行为了,尽管不清楚这是为了什么。那我们的目标是什么呢?答案很简单,无论它是怎么设计的,最后肯定会有一个判断,如果成功,则next按钮可用,否则,弹出失败的对话框。我们的目标就是找到这个最关键的结算点。

为了找到结算的关键点,我们可以在这里设一个断点。依次点击菜单Debug——Toggle Break,或使用快捷键F5。然后让教程自动执行,在这里会被断下:

这时候,我们一个用上面的Step Into(步入,F7),或Step Over(步进,F8)一步步跟踪代码,直到找到我们的目标。Step Into和Step Over的差别在于,后者遇到函数时,不会进入函数,而前者会跟进去,逐语句执行每一个指令。

当然这里我们先别着急傻乎乎的一点点的跟踪,很累,我们先尝试投机取巧的办法,不行再下死力气。

内存浏览窗口的右下角区域,显示的是在断点停下后,这一刻的栈的状况,如果你还记得之前的内容,可能能意识到这里会发现当前所在的函数的调用者。

显然第一个黑框就是此函数的调用者,我们在反汇编窗口里跳转到Tutorial-x86_64.exe+FA75,看看这里是什么:

emmmm,感觉很不好,不但短小无力,看不到我们想要的判断,而且还被一坨人呼来换去(调用)。所以它应该是个公共代码,不是我们想要的。

所以我们再看看另一个黑框Tutorial-x86_64.exe+2F3C9附近的代码试试:

先往上看,注意黑框圈起来的东西,像不像指针?这段代码看上去好诱人啊,试一试。

我们先在Tutorial-x86_64.exe+2F3C9处设个断点,然后把之前的断点取消以避免干扰,最后点击工具栏上的Run按钮(快捷键F9),代码将离开单步调试模式继续执行,直到遇见我们的断点中断下来:

注意此时RBX的值,我们在CE里添加个指针型地址看看:

好家伙,找到了呀。

然后我们再看看这条指令后面的代码,发现了什么?连续3块除了偏移量之外一毛一样的代码,加上这一块,初始偏移量分别是0x888(Dave),0x890(Eric),0x898(HAL),0x8A0(KITT):

显而易见这四块代码是判断每个角色的生命值,我们从最后一个开始,往下看之后的代码:

注意看后面又出现的两个主角的比较(Tutorial-x86_64.exe+2F474 ~ Tutorial-x86_64.exe+2F498),这里的代码是说,只要两个主角中任何一个的生命不为0,就跳到Tutorial-x86_64.exe+2F4C0,否则,则继续执行一小段代码。我们可以猜测,这一小段代码就是设置失败和报错。

做个试验吧,我们把Tutorial-x86_64.exe+2F487处的JP Tutorial-x86_64.exe+2F4C0进行修改,改成无条件跳转jmp Tutorial-x86_64.exe+2F4C0,即直接跳过处理失败的代码(如果我们猜测正确的话),然后把之前设置的断点取消,继续执行,然后看看结果:

如图所示,虽然我们的主角和敌人同归于尽了,但我们依然完成了任务……

完整代码如下,这个是CE的地址列表项目(xml格式),复制后可以直接粘贴到CE中:

最后来张动图作为总结吧~第四章里将开始介绍Unity3D游戏的修改,建议读者提前学一下C#,顺便说,我制作GIF用的软件screentogif就是用C#写的~



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭