植物大战僵尸:代码实现无限阳光

news/2024/11/8 16:48:19/

通过逆向分析植物阳光数量的动态地址找到阳光的基址与偏移,从而实现每次启动游戏都能够使用基址加偏移的方式定位阳光数据,最后我们将通过使用C语言编写通用辅助实现简单的无限阳光辅助,在教程开始之前我们先来说一下为什么会有动态地址与基址的概念!

大部分编程语言都会有局部变量和全局变量,相对于局部变量来说是在游戏运行后动态分配的默认由堆栈存储,而全局变量则是我们所说的基址其默认存储在全局数据区,全局数据区里面的数据则是在编译的时候就写入到程序里了,所以不会变化,而游戏的开发都会使用面向对象技术,我们可以推测游戏中的阳光很可能就是类中的一个数据成员,而数据成员的地址就是通过new动态分配的,如下代码:

  #include <stdio.h>class SunClass{public:int SunTime;int SunValue;int SunAttr;};int main(){SunClass *Sun=new SunClass;Sun->SunValue=100;printf("SunValue: %d",Sun->SunValue);return 0;}

如上代码定义了SunClass类,在主函数中我们为Sun实例指针动态分配了内存,分配的内存存储在栈中,而栈地址每次都会发生变化,所以分配的内存地址是不固定的,从而导致阳光的地址是动态的

好!现在我们就进入正题,开始挖掘游戏数据,先从最简单的阳光地址找起来吧,首先你需要运行游戏并附加植物大战僵尸进程,然后我们开启新的游戏,首次扫描我们先来遍历4字节的50,也就是搜索当前阳光的数量,当然你也可以尝试搜索金钱数量等,道理都是一样的,这里就拿阳光的搜索方法作为演示目标。

接着我们需要让阳光发生变化,这样才可以让我们继续更加精确的确定这个局部变量在内存中的地址是多少,此处我手动种植了一颗向日葵则阳光变为了0,我们就输入0然后再次扫描,由于这款游戏比较简单,基本上经过两次筛选就能定位到阳光的内存地址了,在遍历一些大型游戏的时候,读者应该有耐心,经过多次筛查直到最终找到正确的(动态)内存地址为止。

观察上图13C66448地址,会发现CE显示该地址是一个灰色地址,在CE中灰色就表示是动态地址而绿色则表示基址,此处的动态地址则相当于我们上方代码中给一个类动态new开辟的内存空间的首地址,由于该地址是系统为我们动态开辟的,所以每次重启游戏该地址都会发生变化,为了能够制作辅助我们必须要找到阳光的基址。

我们继续将地址栏中的地址双击加入到最底部的地址栏,然后在地址上右键,选择查找改写地址当我们选择查找改写地址的时候,其实CE就为我们在这个地址上下了硬件写入断点,这个下断点的功能我们同样可以使用X64dbg来完成,此时回到游戏等待阳光出现并点击阳光,则此时会出现以下汇编指令。

上图中我们可以得知add [eax+5560],ecx这条指令是加法运算,最右侧ECX里面就是我们当前需要增加的阳光数,将ECX中的阳光数赋值给[eax+5560]这个内存地址,那么我们的阳光就会增加,此时我们需要知道EAX寄存器指向的地址是多少,CE中已经为我们分析出了EAX寄存器当前值是13C60EE8我们此时需要记下它的一级偏移5560,然后去搜索13C60EE8这个内存地址。

上图搜索结果可以看到有非常多的数据,那我们该如何判断应该选择那一个呢?这里就是一个技巧的问题了,我们需要尽量选择地址不同的,比如标红处的位置是我们重点关注的对象,其中13C60EE8这个内存地址就相当于我们SunClass类实例化的基地址,而5560则是阳光在类中的偏移地址,此处我们需要分析谁给EAX赋值了,直接在00FE82E8右键,查找访问地址,然后会看到以下截图内容:

此处会出现一大堆指令,这里也需要一个遍历技巧,我们可以排除CMP之类的对比指令,因为我们是增加阳光所以不可能出现对比的代码,此外我们需要关注操作数左侧是EAX的,因为我们要找的是谁给EAX赋值的,我们选择mov eax,[ecx+00000768]这条汇编指令,然后发现二级偏移是768,我们继续查找谁给ECX赋值的,这里直接记下ECX寄存器中的地址00FE7B80

继续搜索十六进制数00FE7B80如下搜索结果可以看到有绿色的地址,这些绿色的地址都属于全局变量,到此说明我们已经找到了这个阳光的基地址了,这里我们可以随意选择绿色的地址作为基址使用,此处我选择的是006A9EC0来当作基址使用,前面找到的地址每次启动游戏都会发生变化,而这个基址是永远不会变化的。

最后我们通过查找到的基址与偏移相加的形式,就可以定位到动态地址了,具体公式应该是阳光= [[[006a9ec0]+768]+5560],我们可以直接在CE中添加这个指针,用于进行测试,如下图所示:

最后我们再来总结一下查找思路,其基址查找过程可以描述为以下流程,如果用正向的思路来理解的话应该从后向前来看,会发现正向思路来看会非常的清晰,而我们找基址则是从逆向的角度来分析,也就是从前向后来理解这个过程。

已知阳光的动态地址ECX的值就是增加的阳光 将增加值ECX赋值给 [eax+5560] 我们就得到了阳光
00430A11 - 01 88 60550000 - add [eax+00005560],ecx <<

我们需要继续找出EAX是多少? 由第二条汇编指令可知EAX的值来自于[ecx+768]这个地址
0045B6FD - 8B 81 68070000 - mov eax,[ecx+00000768] <<

最后我们继续跟随查找ECX里面存储的数据得到 [006A9EC0] 该数据明显属于全局数据区
00467B00 - 8B 0D C09E6A00 - mov ecx,[006A9EC0] <<

最后总结出定位静态基址公式 【阳光= [[[006a9ec0]+768]+5560]】

通过编程的方式读取并修改我们的阳光数量,如下这样一段代码,它可以实现读取动态地址并修改阳光数量。

  #include <iostream>#include <Windows.h>int GetDyAddr(int Pid,int Base, int Offset[], int len){int temp;HANDLE Process;Process = OpenProcess(PROCESS_ALL_ACCESS, false, Pid);ReadProcessMemory(Process, (LPVOID)Base, &temp, 4, NULL);for (int i = 0; i < len; i++){if (i == len - 1)temp += Offset[i];elseReadProcessMemory(Process, (LPVOID)(temp + Offset[i]), &temp, 4, NULL);}return temp;}int main(){int base;int offset[3];int PID = 5772;base = 0x006a9ec0;offset[0] = 0x768;offset[1] = 0x5560;int addr = GetDyAddr(PID, base, offset, 2);printf("进程地址:%x", addr);HANDLE Process = OpenProcess(PROCESS_ALL_ACCESS, false, PID);WriteProcessMemory(Process, (LPVOID)addr,&PID,4,0);}

http://www.ppmy.cn/news/9016.html

相关文章

[项目说明]-基于人工智能博弈树,极大极小(Minimax)搜索算法并使用Alpha-Beta剪枝算法优化实现的可人机博弈的AI智能五子棋游戏。

个人选题项目 基于人工智能博弈树&#xff0c;极大极小(Minimax)搜索算法并使用Alpha-Beta剪枝算法优化实现的可人机博弈的AI智能五子棋游戏。 设计目标及主要内容 本系统是根据传统五子棋游戏的功能编写&#xff0c;其功能实现了基于AI人工智能算法实现智能的人机对弈五子棋…

如何用LightningChart创建Android图表数据可视化应用程序?(下)

LightningChart JS 是一款高性能的 JavaScript 图表工具&#xff0c;专注于性能密集型、实时可视化图表解决方案。 LightningChart .JS | 下载试用&#xff08;qun&#xff1a;740060302&#xff09;https://www.evget.com/product/4189/download 在上一篇&#xff0c;我们介…

如何避免无效外贸邮件营销?

如何避免无效的邮件营销&#xff0c;米贸搜为您整理如下&#xff0c;希望对您有所帮助:1 .和邮件正文一样重视主题主题对于电子邮件就像标题对于文章或博客一样重要。即使你有全宇宙最吸引人的散文诗&#xff0c;或者最吸引人的求婚&#xff0c;如果根本没有人打开这封邮件&…

S32K144—什么是SBC系统基础芯片?

SBC&#xff08;System Basis Chip&#xff09;芯片在汽车电子领域可谓占一席之地了。那么什么是SBC&#xff1f;怎么用&#xff1f;用在哪里&#xff1f;主要特性&#xff1f; 可以简单理解成&#xff1a;SBC是一类拥有特出功能&#xff08;电源、通信、监控诊断、安全&#…

B树的原理及代码实现、B+树和B*树介绍及应用

目录 一.B树介绍 &#xff08;一&#xff09;.B树存在意义 &#xff08;二&#xff09;.B树的规则 二.B树实现原理及代码 &#xff08;一&#xff09;.实现原理 &#xff08;二&#xff09;.代码 三.B树 &#xff08;一&#xff09;.概念 &#xff08;二&#xff09;.应…

头歌:Ping服务端创建UDP套接字(底部附全关完整答案)

头歌实践教学平台 (educoder.net)在 Ping 的 服务程序中 创建一个使用 UDP 协议的 套接字数据包套接字类型套接字三种类型:流式套接字(SOCK_STREAM)&#xff0c;数据包套接字(SOCK_DGRAM)及原始套接字&#xff08;SOCK_RAW&#xff09;数据包格式套接字&#xff08;Datagram So…

10天,几万字,源码深度解析之 Spring IOC

历时 10 天&#xff0c;终于把 Sping 源码系列写完了&#xff0c;该系列一共 5 篇&#xff0c;后续会整理成 PDF 教程&#xff0c;本文是最后一篇。 这篇文章主要讲解 IOC 容器的创建过程&#xff0c;让你对整体有一个全局的认识&#xff0c;文章没有复杂嵌套的 debug 流程&am…

【算法基础】算法的时间复杂度

一个语句的频度是指该语句在算法中被重复执行的次数。 算法中所有语句的频度之和记为T(n)&#xff0c;它是该算法问题规模 的函数 时间复杂度主要分析 T(n)的数量级 算法中基本运算 (最深层循环内的语句)的频度与 T(n)同数量级&#xff0c;因此通常采用算法中基本运算的频度f(n…