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

news2024/11/16 13:25:51

通过逆向分析植物阳光数量的动态地址找到阳光的基址与偏移,从而实现每次启动游戏都能够使用基址加偏移的方式定位阳光数据,最后我们将通过使用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];
		else
			ReadProcessMemory(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.coloradmin.cn/o/134251.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

光缆单盘检测与光缆线路测试需使用双窗口吗?

1 引言 光缆线路和宽带接入工程中&#xff0c;通常会涉及光缆单盘检测与光缆线路的测试工作&#xff0c;光缆线路测试包括&#xff1a;中继段测试、用户光缆测试等。这些测试条目&#xff0c;有的只需采用测试仪表的1个波长进行测试&#xff0c;即单窗口测试&#xff0c;有的则…

代码随想录算法训练营第2天 977. 有序数组的平方、209. 长度最小的子数组

代码随想录算法训练营第2天| 977. 有序数组的平方、209. 长度最小的子数组 有序数组的平方 力扣题目链接(opens new window) 给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。 数组其实是有…

C 语法--编译相关

1&#xff0c; 单下划线和双下划线 #pragma #pragma 用于指示编译器完成一些特定的动作。#pragma 所定义的很多指示字是编译器特有的&#xff0c;在不同的编译器间是不可移植的 #pragma section APP_VERSION //__far const unsigned long version 0x01010101; __far const un…

redis缓存淘汰策略-基于LinkedHashMap实现LRU算法

redis缓存淘汰策略-LRU算法&#xff08;最近最少使用&#xff09; LRU是Least Recently Used的缩写&#xff0c;即最近最少使用&#xff0c;是一种常用的页面置换算法&#xff0c; 选择最近最久未使用的数据予以淘汰。 1&#xff0c;所谓缓存&#xff0c; 必须要有读写两个操作…

【叨叨与总结】2022年总结

如果我记得没错&#xff0c;这个记录时间的软件应该是在6月份或者7月份才开始用的&#xff0c;大概记录的时间有半年。个人觉得还是不错的&#xff0c;下面还是简单的总结一下。   首先睡眠时长是有一定保障的&#xff0c;甚至有好多时候还睡了9、10个小时&#xff0c;当然这…

【Python基础】模块化编程-包调用

datitle: Python Module&&Invoking date: 2020-05-12 00:16:58 img: https://gitee.com/github-25970295/blogImage/raw/master/img/woman-3219507__340.webp categories: 编程语言 reprintPolicy: cc_by cover: false tags: python ​ 无论我们选择用何种语言进行程序…

2022年度总结:凝神聚力 踔厉奋发

2021年底手里握了几份offer&#xff0c;有研究型大学&#xff0c;也有教学型大学。是选择去前者继续拼搏&#xff0c;还是选择去后者直接躺平&#xff1f;二者的权衡和取舍确实不太容易抉择。尽管也咨询了很多前辈&#xff0c;最后还是得自己做决定。尽管我还是很喜欢做研究工作…

spark理论

前言&#xff1a; 本文是之前19年学生时学习林子雨老师《Spark大数据 》网易公开课的中关于spark的理论部分的部分笔记。主要包括大数据产品与spark的一些概念与运行原理介绍。 目录 大数据产品与hadoop生态系统 Spark概念 MapReduce与spark的比较 Spark运行 Spark运行基本流程…

【Spring 系列】Spring Session 深度解析

文章目录Spring Session 架构及应用场景为什么要spring-sessionSR340规范与spring-session的透明继承Spring Session探索特点核心 APIservlet session 与 spring-session 关系webflux 与 spring session 的关系基于 Servlet 的 Spring Session 实现思考题背景1、注册到 Filter …

Pytorch—模型微调(fine-tune)

随着深度学习的发展&#xff0c;在大模型的训练上都是在一些较大数据集上进行训练的&#xff0c;比如Imagenet-1k&#xff0c;Imagenet-11k,甚至是ImageNet-21k等。但我们在实际应用中&#xff0c;我们自己的数据集可能比较小&#xff0c;只有几千张照片&#xff0c;这时从头训…

RHCE——ansible环境配置(1)

配置ansible学习环境实现以下要求&#xff1a; 1.控制主机和受控主机通过root用户通过免密验证方式远程控住受控主机实施对应&#xff08;普通命令&#xff0c;特权命令&#xff09;任务 2.控制主机连接受控主机通过普通用户以免密验证远程控住受控主机实施指定&#xff08;普通…

雪花算法详解

背景 需要选择合适的方案去应对数据规模的增长&#xff0c;以应对逐渐增长的访问压力和数据量。 数据库的扩展方式主要包括&#xff1a;业务分库、主从复制&#xff0c;数据库分表。 数据库分表 将不同业务数据分散存储到不同的数据库服务器&#xff0c;能够支撑百万甚至千万…

计算机网络学习笔记

前言 本篇笔记方便本人用于复习回顾知识点&#xff0c;内容庞杂&#xff0c;见谅。含有目录方便大家跳转复习&#xff01; 此复习笔记总结于 湖科大教书匠出品&#xff1a;深入浅出计算机网络 微课视频 此笔记尚未完结&#xff0c;持续更新中… 文章目录前言第一章 概述1.1 …

数学建模学习笔记-概况

目录 1概况. 数学建模&#xff1a; 数学建模的模块&#xff1a; 一般步骤&#xff1a; 全过程&#xff1a; 论文的基本流程 模块学习&#xff1a; 1.题目备战&#xff1a;掌握固定模式 2.摘要备战&#xff1a;总结归纳能力&#xff0c;通过看高水平论文掌握。 3.问题重…

Mybatis源码分析(五)SqlSession的创建

目录一 SqlSession的创建1.1 获取environments配置元素1.2 获取事务工厂1.3 获取执行器Executor1.4 构建DefaultSqlSession官网&#xff1a;mybatis – MyBatis 3 | 简介 参考书籍&#xff1a;《通用源码阅读指导书&#xff1a;MyBatis源码详解》 易哥 参考文章&#xff1a; M…

彩色图像灰度化

灰度图像能以较少的数据表征图像的大部分特征&#xff0c;因此在某些算法的预处理阶段需要进行彩色图像灰度化&#xff0c;以提高算法的效率。将彩色图像转化为灰度图像的过程称为彩色图像灰度化。 常用RGB图像灰度化&#xff0c;在RGB模型中&#xff0c;位于空间位置(x,y)的像…

MAX78000一些AI例程测试

进入Demo所在目录 cd /E/MAX78000/MAXSDK/Examples/MAX78000/CNN/kws20_demo 执行编译 make 如果之前已经被编译过了&#xff0c;可以先清除&#xff0c;再make make distclean 选择板型 根据自己用的开发板不一样&#xff0c;注释掉BOARDEvKit_V1 To compile code for …

视频处理系列︱利用达摩院ModelScope进行视频人物分割+背景切换(一)

做了一个简单的实验&#xff0c;利用modelscope的人像抠图模型对视频流进行抠像并更换背景。 文章目录1 视频人像抠图&#xff08;Video human matting&#xff09;2 更换背景1 视频人像抠图&#xff08;Video human matting&#xff09; 地址链接&#xff1a;视频人像抠图模型…

2022定格 以史为鉴 擘画未来 砥砺2023

回望2022思绪万千 我们的家国情怀和社会担当&#xff0c;让我们与众不同。 每一个个体&#xff0c;每一天&#xff0c;每一月&#xff0c;每一年&#xff0c;都能且应该成为更好的自己。 我们要做未来的创造者&#xff0c;驱动他人最好的方式是点燃自己。 不放弃就会有光&a…

Js Promise理解和使用

js中的promise是一个异步编程的解决方案&#xff0c;语法层面上他是一个构造函数&#xff0c;名字为Promise()。 它的作用就是将一个任务task封装为一个Promise类的实例对象&#xff0c;这个对象会将任务自动运行并得到任务结果&#xff0c;而且在得到结果的过程中并不会影响到…