(小游戏!)简易游戏修改!!!新手看过来!

3 篇文章 2 订阅
2 篇文章 0 订阅

相信大家都用过游戏fuzhu,我也不例外,学生时期嘛总是贪玩的,以前玩一些单机的游戏总是用一些修改,我小的时候就总是在手机上用什么hulux,电脑上就是CE
近些日子,本学渣在看windows设计相关的书,里面就讲到了内存修改器,很感兴趣,所以参考了书之后,今天本学渣来给大家分享一下
那么我今天给大家的就是一个简易的修改qi,用的都是一些windows中的一些API函数,

那么首先我们来了解下我们要修改的游戏数值,到底是在修改什么?
修改游戏中显示的数据就是要修改游戏所在进程的内存
进程的地址空间是相互隔离的所以我们要用到API函数

接下来给大家介绍几个函数
1.ReadProcessMemory
函数功能:该函数从指定的进程中读入内存信息,被读取的区域必须具有访问权限。
函数原型:BOOL ReadProcessMemory(HANDLE hProcess,LPCVOID lpBaseAddress,LPVOID lpBuffer,DWORD nSize,LPDWORD lpNumberOfBytesRead);
參数:
hProcess:进程句柄
lpBaseAddress:读出数据的地址
lpBuffer:存放读取数据的地址
nSize:读出的数据大小
lpNumberOfBytesRead:数据的实际大小

可能有点多,要好好的看一看我刚开始看书的时候也很懵哈哈哈哈
仔细看完之后相信你没问题的!

2.WriteProcessMemory
BOOL WriteProcessMemory(
  HANDLE hProcess, 进程句柄
  LPVOID lpBaseAddress,要写的内存首地址
  LPVOID lpBuffer,数据当前存放地址
  DWORD nSize,写入数据的大小
  LPDWORD lpNumberOfBytesWritten实际数据的大小
  );

接下来如果我们自己有CE 的话就可以找出地址,利用ReadProcessMemory函数和WriteProcessMemory函数来修改内存空间了
但是!我们不用!接下来才是我们的主要代码,如果你对进程,和线程以前有过了解(没准儿比我好哈哈哈)那么就更容易理解下面写的东西,如过没了解过呢,也没关系!谁还不是从头开始呢!

那么我们究竟要怎么样找到游戏数据所在的内存呢?
像我们的游戏数据都是会有一些什么生命值啦,分数了之类的,我们在游戏的过程中这些值会进行改变,所以对应内存空间的值也会改变,那么为什么这个查找的过程比较复杂呢,比如我们分数是100分,在内存中,就可能有很多存放着100的数值的内存地址,所以我们要不断的更改分数的值来筛选真正的是我们要的那个内存地址

在这里给大家放几张图来看一下
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201217122319938

自己原来写的飞机大战小游戏 有很多能改动的地方,大家可以去看看 传送门
大家可以看到这里是17得分,那么我们就来搜索
在这里插入图片描述
可以看到这里有非常多的地址,所以我们改变得分来筛选,这个查找的过程是有点慢的 需要等一会
在这里插入图片描述
这就是我们修改之后的得分了,如果你的电脑上有360的话它会阻止你操作的,不用担心,允许就好了。

运行图看完了咱们就要写代码了

#include<stdio.h>
#include<windows.h>

这是我们的头文件千万不要忘记!

DWORD g_arlist[1024];//地址列表  如果不清楚DWORD等,可以去查一下你就明白了
int address;//有效地址的个数
HANDLE g_hprocess;//目标进程句柄

这里大体都和书上的一样,,我开始也不习惯这么命名,但总要有个规范不是。咱们继续
咱们是在一页上查找,如果不清楚页,大家可以去搜一下windows的分页机制,看一下一页是多大(4KB)。

bool compareAPage(DWORD dwBaseaddr, DWORD dwValue)
{
	//读取一页内存
	BYTE arBytes[4096]; 这里如果不清楚4096 提示一下(1024和它的关系)
	if (!::ReadProcessMemory((g_hprocess), (LPVOID)dwBaseaddr, arBytes, 4096, NULL))
		return FALSE;//此页不可读
	DWORD* pdw;
	for (int i = 0; i < (int)4 * 1024 - 3; i++)-3这里要思考一下 (注意它的类型))
	{
		pdw = (DWORD*)&arBytes[i];   (这步如果不懂的话,先把指针方面弄好)
		if (pdw[0] == dwValue)//等于要查找的值
		{
			if (address >= 1024)
				return FALSE;
			g_arlist[address++] = dwBaseaddr + i;
		}
	}
	return TRUE;
}


在页中查找就完成了,接下来我们就来写搜索函数了(Find)

bool FindFirst(DWORD dwValue)
{
	const DWORD oneGB = 1024 * 1024 * 1024;
	const DWORD onepage = 4 * 1024;


	if (g_hprocess == NULL) (这里还是要提一下吧,进程句柄开始有写)
		return  FALSE;
	//查看系统 以决定开始地址
	DWORD dwbase;
	OSVERSIONINFO vi = { sizeof(vi) };
	::GetVersionEx(&vi);
	if (vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
		dwbase = 4 * 1024 * 1024;
	else
		dwbase = 640 * 1024;
	//从开始的地址到2gb地址空间进行查找   为什么是2gb?
	for (; dwbase < 2 * oneGB; dwbase += onepage)
	{
		
		compareAPage(dwbase, dwValue);


	}
	return TRUE;
}

DWORD dwbase; 查看系统的函数,
OSVERSIONINFO vi = { sizeof(vi) };
::GetVersionEx(&vi); 这个函数在vs上编译可能会警告,但是能运行,应该是太老了,弃用了
if (vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
dwbase = 4 * 1024 * 1024;
else
dwbase = 640 * 1024;

这只是我们的第一个查找函数,要明白我们这个查找函数是来干嘛的,我们这个第一个find只是用来查找有效地址!关于有效地址我在开始已经声明了,所以我们接下来就要在有效的地址中去查找,然后来进行修改

bool FindNext(DWORD dwValue)
{
	//将那些有效地址保存
	int newaddress = address;
	address = 0;
	bool P = FALSE;//假设失败
	DWORD dwreadValue;
	for (int i = 0; i < newaddress; i++)
	{
		if (::ReadProcessMemory(g_hprocess, (LPVOID)g_arlist[i], &dwreadValue, sizeof(DWORD), NULL))
		{
			if (dwreadValue == dwValue)
			{
				g_arlist[address++] = g_arlist[i];
				bRet = TRUE;
			}
		}
	}
	return P;

}

如果你看懂了前面,逻辑其实很简单,就是函数里的变量比较多,多看就好理解了。

void showlist() 显示函数
{
	for (int i = 0; i < address; i++)
	{
		printf("%08IX\n", g_arlist[i]);
	}
}

关于此函数就是输出格式需要自己注意一下;
最后就是我们的主函数了

char FileName[] = “G:\编程\飞机huhuhu\Debug\飞机huhuhu.exe”; 这里你要改你自己游戏的绝对路径
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
::CreateProcess(NULL,FileName, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
//关闭线程句柄
::CloseHandle(pi.hThread);
g_hprocess = pi.hProcess;

STARTUPINFO si = { sizeof(si) };  //这是一个结构体类型,很复杂,
//我看的时候只是会用书上的,查了一下定义感觉很多,
//具体想了解可以自己去查一下,
PROCESS_INFORMATION pi;//也是一个结构体类型,调用Createprocess()函数后,会自动地对该结构进行填充。也可以自己去查一下

剩下的就没什么了。

char FileName[] = "G:\\编程\\飞机huhuhu\\Debug\\飞机huhuhu.exe";
	STARTUPINFO si = { sizeof(si) };
	PROCESS_INFORMATION pi;
	::CreateProcess(NULL,FileName, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
	::CloseHandle(pi.hThread);//关闭线程句柄
	g_hprocess = pi.hProcess;
	//输入要修改的值
	int v;
	printf("Input v=");
	scanf_s("%d", &v);
	FindFirst(v);
	showlist();
	while (address > 1)
	{
		printf("input=");
		scanf_s("%d", &v);
		//进行下次搜索
		FindNext(v);
		showlist();
		if (address ==1) {
			printf("new=");
			scanf_s("%d", &v);
			::WriteProcessMemory(g_hprocess, (LPVOID)g_arlist[0], (LPCVOID)&v, sizeof(int), NULL);
			break;
		}
	}
	::CloseHandle(g_hprocess);
	return 0;
}

当时看书觉得很有意思,所以就和大家分享一下。毕竟我也在学,可能有的地方说的不好,讲的不细致,请大神们见谅!

学渣一枚,迷茫过,堕落过,所以还请大家加油啊!
我们要去更远的未来呢!
加油!少年!
最后附上源码 https://pan.baidu.com/s/1U9ZRYdedvpVJFGw1NOE_hw
提取码 xlad
也可以关注我后续的文章哦!

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值