项目实战——外挂开发(30小时精通C++和外挂实战)

项目实战——外挂开发(30小时精通C++和外挂实战)

  • 外挂开发1-监控游戏
  • 外挂开发2-秒杀僵尸
  • 外挂开发3-阳光地址分析
  • 外挂开发4-模拟阳光
  • 外挂开发5-无限阳光

外挂开发1-监控游戏

外挂的本质
有两种方式
1,修改内存中的数据
2,更改内存中的代码
找到内存地址,从此地址开始写入4个字节90909090

改代码和改数据是一样的,改阳光找到一个内存地址,将想改的数值填充到内存空间去
改代码,找到内存地址,将想要填充的数据填到内存空间

数据和代码没有本质区别

在这里插入图片描述

该内存改代码都是找到内存地址,像内存地址填充数据

明白这些后开始写代码
有个细节监控植物大战僵尸是否打开

创建一个新的线程

While(1){
If(植物大战僵尸打开){
可以点击按钮
}else{
不可以点击按钮
}
Sleep(1000);//为了不让其太过于频繁,此处隔着1秒检测一次
}

此循环是死循环,跳不出,会堵塞进程,导致其他事情干不了

所有这个代码要放到子线程去执行

打开上次写的程序创建线程
线程只需创建一次,我们在外挂程序一打开就创建线程,在初始化的地方创建

BOOL CPVZCheaterDlg::OnInitDialog()此为初始化对话框
// TODO:  在此添加额外的初始化代码
CreateThread();创建线程,返回handle句柄,通过线程句柄可以操控线程
CreateThread(
    _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
    _In_ SIZE_T dwStackSize,
    _In_ LPTHREAD_START_ROUTINE lpStartAddress,		函数地址,我们可以右击转到定义看此参数含义
    _In_opt_ __drv_aliasesMem LPVOID lpParameter,
    _In_ DWORD dwCreationFlags,
    _Out_opt_ LPDWORD lpThreadId
);
HANDLE WINAPI CreateThread
( 
  __in_opt   LPSECURITY_ATTRIBUTES lpThreadAttributes, // 指向SECURITY_ATTRIBUTES 的指针,为新线程指定安全描述 
  __in       SIZE_T dwStackSize, // 初始化线程堆栈尺寸 
  __in       LPTHREAD_START_ROUTINE lpStartAddress, //线程函数所指向的地址起始函数   
__in_opt   LPVOID lpParameter, // 给线程函数传递的参数   
__in       DWORD dwCreationFlags, // 有关线程的标志  
 __out_opt  LPDWORD lpThreadId //系统分配给线程的ID
 );  

要在dlg.h中创建句柄对象

	//子线程句柄
	HANDLE m_monitorThread;

m_monitorThread = CreateThread(NULL, NULL, func, NULL, NULL, NULL);
Func返回的应该是下面的类型值需要在全局区声明
 DWORD (WINAPI *PTHREAD_START_ROUTINE)(
    LPVOID lpThreadParameter
);

//用来监控游戏的线程
DWORD WINAPI monitorThreadFunc(LPVOID lpThreadParameter){
return NULL;
}

FindWindow();//查看窗口是否打开,两个参数窗口类名,窗口名称
FindWindowW(
    _In_opt_ LPCWSTR lpClassName,
_In_opt_ LPCWSTR lpWindowName);

都是字符串类型故使用
使用工具spy++,查找窗口的望远镜,拖到游戏窗口上去,
类型MainWindow
窗口名称Plants vs. Zombies GOTY

外挂开发2-秒杀僵尸

	//当游戏窗口关闭后,不仅禁止点击还要将之前打钩的去掉
	g_dlg->m_bnKill.SetCheck(FALSE);
	g_dlg->m_bnSun.SetCheck(FALSE);

接下来就是真正的秒杀僵尸了。

真的要秒杀僵尸该如何实现此功能
打开OD,将exe载入

CTR+G	找到修改内存的地址
00566D10  |.  89B5 C8000000 mov dword ptr ss:[ebp+0xC8],esi       

;

向上找到其生命值减少的代码

00566D06      2B7424 20     sub esi,dword ptr ss:[esp+0x20]

要想将其变成下方

00566D06      2BF6          sub esi,esi   
00566D08      90            nop
00566D09      90            nop

我们看的是其机器码就是将此内存地址00566D06开始的4个字节变成后面四个字节

00566D06      2B742420    

要想将其变成下方

00566D06      2BF69090      

这样就达到了秒杀僵尸的功能了,我们发现第一个字节都是一样的,我们改后面三个字节就可以了

00566D07     742420 	//原版不需要秒杀僵尸
00566D07     F69090   //需要秒杀僵尸

不需要秒杀僵尸就将742420 覆盖地址00566D07 的内存空间
需要秒杀僵尸就将F69090 覆盖地址00566D07 的内存空间,这两者来回切换,将内存的代码换来换去

这就牵扯到一个跨进程的问题,当勾选了秒杀僵尸后,就要将这3个字节写在植物大战僵尸的内存中。
这里有个函数

static HANDLE g_processHandle;//定义一个全局句柄,可以右击OpenProcess转到定义,发现返回是HANDLEWINAPI,OpenProcess,不需要指针

//这里封装的是全局函数
// 将某个值写入植物大战僵尸内存(后面的可变参数是地址链,要以-1结尾)
void WriteMemory(void *value, DWORD valueSize, ...)				//第一个参数传数据,第二个是数据有多大,如数据只有3个字节,...是个地址链
{
	if (value == NULL || valueSize == 0 || g_processHandle == NULL) return;

	DWORD tempValue = 0;

	va_list addresses;
	va_start(addresses, valueSize);
	DWORD offset = 0;
	DWORD lastAddress = 0;
	while ((offset = va_arg(addresses, DWORD)) != -1)
	{
		lastAddress = tempValue + offset;
		::ReadProcessMemory(g_processHandle, (LPCVOID)lastAddress, &tempValue, sizeof(DWORD), NULL);
	}
	va_end(addresses);

	::WriteProcessMemory(g_processHandle, (LPVOID)lastAddress, value, valueSize, NULL);
}
//下面是重载的函数比较简单,告诉写数据,数据占的字节,数据所在地址
void WriteMemory(void *value, DWORD valueSize, DWORD address) {
	WriteMemory(value, valueSize, address, -1);
}

	//下面三句代码放在此处是,肯定发现了游戏的窗口,句柄不为空,则进程句柄也不为空
			//获得植物大战僵尸的进程id
			DWORD processPid;
			GetWindowThreadProcessId(windowHandle, &processPid);//此处通过植物大战僵尸的窗口句柄拿到进程id
			//获得植物大战僵尸的进程句柄
			g_processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processPid);//PROCESS_ALL_ACCESS访问内存,传权限访问内存数据,
			//此时进程句柄拿到了,我们就可以秒杀僵尸了等操作


void CPVZCheaterDlg::OnBnClickedKill()
{
	if (m_bnKill.GetCheck()){//需要秒杀僵尸
		BYTE data[] = {0xF6,0x90,0x90};//F69090 ,此处详情看Word,这是我们要写进内存的数据
		WriteMemory(data,sizeof(data),0x00566D07);//写入内存,需要进程句柄,具体内容如上所示,参数比较多相对复杂,这里直接封装了一些写内存的在上面
		//注意上面的写内存函数是我们自定义封装好的WriteMemory,而不是系统的WriteProcessMemory,在程序开头有,这里只需传三个参数,地址
	}
	else{//不需要秒杀僵尸
		BYTE data[] = { 0x74, 0x24, 0x20 };//742420 ,此处详情看Word,这是我们要写进内存的数据
		WriteMemory(data, sizeof(data), 0x00566D07);
	}
}

外挂开发就这么简单,步骤
先分析对应汇编在哪里,再搞清楚将汇编改成什么,搞清楚将汇编改成什么就能搞清楚将机器码换成什么,已经搞清楚将机器码换成什么到时候将内存地址写入对应机器码就可以了

外挂就是将内存中的数据或者机器码给换掉,这里其他僵尸如安全帽的秒杀就得靠自己找了,都是一样的

外挂开发3-阳光地址分析

#include <iostream>
using namespace std;

int g_age;

int main(){
	int a = 10;

	g_age = 20;

	//局部变量地址变来变去
	//cout << &a << endl;//00AFFA1C	00A3FBE0

	/*cout << &g_age << endl;*/

	getchar();
	return 0;
}

使用CE找到阳光内存地址
发现每次打开游戏阳光内存地址是不一样的

阳光是个类的成员变量,局部变量调用是在栈空间的,所以每次打开游戏内存地址不同
而全局变量只要编译之后,内存地址都是固定的

    7: 	int a = 10;
0076530E  mov         dword ptr [ebp-8],0Ah  
     8: 
     9: 	g_age = 20;
00765315  mov         dword ptr ds:[0076F354h],14h  

局部变量a的地址是ebp-8

全局变量g_age的值是0076F354h,它的地址是写死的,只要编译完了,最终机器码里就是这个
只要编译完了,那么之后无论打开多少次程序,执行的机器码都是那个机器码,那个机器码中的地址固定死的不会变

局部变量是会变的,a的地址是ebp-8,ebp寄存器中的值是会变的
但全局变量的地址0076F354h是固定死的。

大家都有的误区

内存是什么是虚拟内存,不是内存条上的地址,真正内存条上的东西是不允许你访问的,只允许操作系统访问,操作系统会将物理内存(真正内存条的内存)和虚拟内存挂钩

举例,32位系统没打开一个exe,都会为这个exe(也可以认为是进程)分配4GB的虚拟内存,如果再打开一个exe它也有4GB的虚拟内存。设这两个虚拟内存都有相同的内存地址0X110,但此内存地址对应的真正的物理内存地址是不同的,这个由操作系统管理。

我们程序员面对的都是虚拟内存,不管是什么开发,操作系统都是这样管理内存的。
我们讲的内存地址都是虚拟内存地址,不是内存条的物理内存地址,这就是操作系统内存管理的环节了。

向内存地址里面写代码,这个游戏无论打开还是关掉,这个外挂都是好使的,还有这个游戏和外挂放到被的电脑上打开,游戏和外挂都是好使的。这说明植物大战僵尸这个游戏它不管在谁的电脑上打开多少次,它的每句代码内存地址都是固定死的。

外挂开发4-模拟阳光

我们观察到阳光的地址值是发生变化的,证明阳光不是直接一个简单的全局变量,也不是局部变量内存,局部变量调用完就没了,我们发现游戏玩了很久阳光一直都在,不能说一个函数调用完这个阳光就没了。
阳光不是局部变量,那它可能是这样
有很多类,阳光是个类

#include <iostream>
using namespace std;

//int g_age;
struct Sun{
	int temp1;
	int value;//阳光值
};

//游戏数据可能会弄成全局
struct GameData{
	int temp;
	Sun *sun;
};

GameData *g_data;

int main(){

	g_data = new GameData();
	g_data->sun = new Sun();//首先创建一个阳光对象
	//程序每次打开都要new阳光,地址值变换

	g_data->sun->value = 20;
	cout << &g_data->sun->value << endl;

	getchar();
	return 0;
}

既然阳光地址值每次都不一样,那我们怎么去写外挂呢?
我们可以从GameData *g_data;入手,这个指针变量地址值是不变的,这是个全局变量,意味着内存地址不会变。

g_data指针指向GameData()对象,GameData()对象里的sun指针会指向Sun()对象,这个就是模拟的结构。

全局变量的地址值是不变的。
在这里插入图片描述

全局指针变量g_data的地址值是固定死的,它存储的是gamedata的地址,我们可以通过这个找到g_data的存储空间里存储的地址(new出来的是变化的),就能找到gamedata的存储空间,找到了gamedata的存储空间就能找到成员变量sun指针(跳过前面4个字节地址)变量的存储空间,知道它里面存储的值(阳光存储空间的地址值)就能找到阳光存储空间,就能找到阳光存储空间中的阳光值value(跳过前面8个字节地址)。

只要顺着这固定死的g_data的地址值就能一直找到最后。

无论new多少次都有办法找到value在哪里,虽然每次new的对象地址发生变化了。
只要结构是这样的,我们只要找到固定死的就能找到最后的value。

New出来的地址每次是不一样的。

使用汇编来表示

0x100	是全局变量g_data的地址值
[0x100]	这是gamedata对象的地址值(中括号是取出0x100地址所存储的值)
[0x100]  是变量temp的地址值
[0x100]+0x4	这是sun指针变量的地址值
[[0x100]+0x4]	这是sun对象的地址值(sun指针变量的地址所存的东西)
[[0x100]+0x4]	+ 0X8	这就是value阳光之的内存地址

尽管阳光之value是放到堆空间的,内存地址不断的变,但我仍然可以通过一些固定的数值找到value的存储空间。

我们在使用CE时,右下角有个手动添加地址(add address manual),这里可以添加地址(此处地址为 固定地址)

先添加地址为0080F354先勾选指针,有个偏移先偏移4,后偏移8.点击确定

外挂开发5-无限阳光

关键是找阳光的上级的固定地址值全局变量

不太好找,结构非常复杂

需要不断调试,找到

到此就讲完了
无CD是可以自己找的

每个游戏不一样,代码不同,主要难点在于分析代码,这个外挂就是改内存改代码仅此而已。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/870137.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Stable Diffusion】AI生成新玩法:图像风格迁移

【Stable Diffusion】 AI生成新玩法&#xff1a;图像风格迁移 1 背景导入 你是否曾梦想过让自己融入梵高的星空之中 或是将一幅风景画赋予毕加索的立体主义之魂 还是把人物送进宫崎骏的动画世界&#xff1f; 下面让我们来看看如何通过 Stable Diffusion 实现在图像中玩…

Java面试八股之什么是声明式事务管理,spring怎么实现声明式事务管理?

什么是声明式事务管理&#xff0c;spring怎么实现声明式事务管理&#xff1f; 声明式事务管理是一种编程范式&#xff0c;它允许开发人员通过声明性的配置或注解&#xff0c;而不是硬编码事务处理逻辑&#xff0c;来指定哪些方法或类应该在其上下文中执行事务。这种方法将事务…

【Gin】深度解析:在Gin框架中优化应用程序流程的责任链设计模式(上)

【Gin】深度解析&#xff1a;在Gin框架中优化应用程序流程的责任链设计模式(上) 大家好 我是寸铁&#x1f44a; 【Gin】深度解析&#xff1a;在Gin框架中优化应用程序流程的责任链设计模式(上)✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 前言 本次文章分为上下两部分&#xf…

学习React(描述 UI)

React 是一个用于构建用户界面&#xff08;UI&#xff09;的 JavaScript 库&#xff0c;用户界面由按钮、文本和图像等小单元内容构建而成。React 帮助你把它们组合成可重用、可嵌套的 组件。从 web 端网站到移动端应用&#xff0c;屏幕上的所有内容都可以被分解成组件。在本章…

MongoDB教程(二十一):MongoDB大文件存储GridFS

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; 文章目录 引言一、GridFS…

Windows版MySQL5.7解压直用(如何卸载更换位置重新安装)

文章目录 停止mysql进程及服务迁移整个mysql文件夹删除data重启计算机重新安装 停止mysql进程及服务 net stop mysql mysqld -remove mysql迁移整个mysql文件夹 删除data 重启计算机 shutdown -r -t 0重新安装 https://blog.csdn.net/xzzteach/article/details/137723185

H3CNE(vlan的基础配置)

目录 9.1 传统以太网的问题 9.2 VLAN基础实现的原理 示例一&#xff08;vlan配置的基础实现&#xff09;&#xff1a; 示例二&#xff08;交换机间配置trunk&#xff09;&#xff1a; 9.3 hybrid接口类型与打标签的原理 示例三&#xff08;配置hybrid接口&#xff09;&#x…

【深度学习】LLaMA-Factory 大模型微调工具, 大模型GLM-4-9B Chat ,微调与部署 (2)

文章目录 数据准备chat评估模型导出模型部署总结 资料&#xff1a; https://github.com/hiyouga/LLaMA-Factory/blob/main/README_zh.md https://www.53ai.com/news/qianyanjishu/2015.html 代码拉取&#xff1a; git clone https://github.com/hiyouga/LLaMA-Factory.git cd …

STM32串口(串口基础)

串口整个东西可以说但凡你要碰单片机&#xff0c;想做点上点档次的东西的话那你就包用它的。32的串口配置并不难&#xff0c;哪怕是比起51其实也难不到哪去。 目录 一.通信基础 1.通信方式 2.通信速率 二.串口基础 1.串口的数据帧结构&#xff08;协议&#xff09; 2.ST…

【Godot4.2】GodotXML插件 - 解析和生成XML

概述 近期在研究Godot的XML和SVG解析&#xff0c;Godot提供了XMLParser类型&#xff0c;但本身只提供了低级的XML解析接口和功能&#xff0c;想要完成完整的XML文档解析和存储可能还需要在其基础上编写类或功能&#xff0c;就像我在昨天&#xff08;2024年7月20日&#xff09;…

Web开发:图片九宫格与非九宫格动态切换效果(HTML、CSS、JavaScript)

目录 一、业务需求 二、实现思路 三、实现过程 1、基础页面 2、图片大小调整 3、图片位置调整 4、鼠标控制切换 5、添加过渡 四、完整代码 一、业务需求 默认显示基础图片&#xff1b; 当鼠标移入&#xff0c;使用九宫格效果展示图片&#xff1b; 当鼠标离开&#…

基于Cobbler实现多版本系统批量部署

一、实验题目 基于Cobbler实现多版本系统批量部署 二、实验目的 通过Cobbler&#xff0c;实验旨在实现无需人工干预即可自动安装多个版本的操作系统。这可以大大提高机房设备或服务器集群的部署效率&#xff0c;减少人力成本和操作错误。 三、实验环境 centos7.9并安装Cob…

机器学习 | 回归算法原理——多重回归

Hi&#xff0c;大家好&#xff0c;我是半亩花海。接着上次的多项式回归继续更新《白话机器学习的数学》这本书的学习笔记&#xff0c;在此分享多重回归这一回归算法原理。本章的回归算法原理基于《基于广告费预测点击量》项目&#xff0c;欢迎大家交流学习&#xff01; 目录 一…

【Django】anaconda环境变量配置及配置python虚拟环境

文章目录 配置环境变量配置python虚拟环境查看conda源并配置国内源在虚拟环境中安装django 配置环境变量 control sysdm.cpl,,3笔者anaconda安装目录为C:\ProgramData\anaconda3 那么需要加入path中的有如下三个 C:\ProgramData\anaconda3 C:\ProgramData\anaconda3\Scripts C:…

【数据结构】搜索二叉树

二叉搜索树 二叉树的博客 在之前的数据结构的文章中已经基本对二叉树有一定的了解&#xff0c;二叉搜索树也是一种数据结构&#xff0c;下面将对二叉搜索树进行讲解。 二叉搜索树的概念 二叉搜索树又称为二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有下面性…

【微软蓝屏】微软Windows蓝屏问题汇总与应对解决策略

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

HTML常见标签——超链接a标签

一、a标签简介 二、a标签属性 href属性 target属性 三、a标签的作用 利用a标签进行页面跳转 利用a标签返回页面顶部以及跳转页面指定区域 利用a标签实现文件下载 一、a标签简介 <a>标签用于做跳转、导航&#xff0c;是双标签&#xff0c;记作<a></a>&#…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第三十九章 Linux MISC驱动

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

MongoDB教程(十八):MongoDB MapReduce

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; 文章目录 引言一、MapRed…

上传项目到GitHub

上传项目到GitHub 前期工作&#xff1a;创建GitHub仓库 1.使用git命令初始化文件夹 git init2.将文件夹里面所有的文件添加到本地仓库&#xff0c;如果想添加单个文件&#xff0c;将.换成文件名就好。 git add .3.给文件备注&#xff0c;双引号里面是文件备注的内容 git c…