思路比较简单,实现方法也不难,我这里大概说一下流程:
♦ 用 CheatEngine 或者类似的内存搜索工具定位要修改的数值的内存地址;
♦ 确定要修改的数值所占的字节数;
♦ 提升修改器进程自身的 Privilege(特权);
♦ 查找并打开目标进程,获取目标进程句柄;
♦ 读取目标进程内存地址上的值;
♦ 把值写入目标进程的内存地址上;
第一第二步不属于本文的讨论范围,我们从第三步开始吧;
微软从 Windows Vista 开始,引入了新的安全机制,一个进程如果没有足够的权限,是无法读写或者查询另外一个进程的内容与信息的,而我们要做的内存修改器需要读写另外一个进程的内存,所以必须要提升修改器进程自身的权限;
每个新启动的进程,都会被系统分配一个 Access Token ,里面包含一个 Privilege 列表,Privilege 列表描述了该进程拥有哪些特权,我们如果要对另外一个进程进行读写操作,则可以为修改器进程增加一个 Debug Privilege,这个 Privilege 允许我们的进程去调试以及调整另外一个进程的内存,是微软为调试器专门开放的 Privilege,正好可以为我们所用;
Privilege 包含两个属性,一个叫做 Name,是以字符串形式来表示的特权名称,一个叫做 LUID,用于保证特权的本地唯一性,要调节进程特权,需要先获取 Name 所对应的 LUID,LookupPrivilegeValue( ) 函数可以查询一个 Privilege Name 所对应的 Privilege LUID;
通过 OpenProcessToken( ) 函数打开进程的 Access Token,随后把查询到的 Privilege LUID 填充到特定的结构体,然后通过这个结构体,调用 AdjustTokenPrivileges( ) 函数来调节进程特权,至此,进程特权调节完毕,我们看下面代码:
接下来,我们要查找并打开游戏进程,目前的状况是这样的,我们只知道游戏的 exe 文件名称,但是我们需要的是游戏的进程句柄,对此,我们可以通过 Win32 SDK API 提供的 Tool Help Library 里面的函数来实现;
首先,调用 CreateToolhelp32Snapshot( ) 函数创建一个进程快照,然后使用 Process32First( ) 和 Process32Next( ) 函数来枚举所有进程,这两个函数会返回一个 PROCESSENTRY32 结构体,里面包含了被枚举的进程的 exe 文件名以及进程 ID,我们可以通过对比进程的 exe 文件名来获取进程的 ID,代码如下:
有了游戏的进程 ID,我们就可以通过 OpenProcess( ) 函数打开游戏进程,并且得到游戏的进程句柄,为最后两布做准备,代码如下图所示:
OK,万事俱备,只欠东风,我们的最后一步,就是通过 ReadProcessMemory( ) 函数与 WriteProcessMemory( ) 函数来读写游戏进程的内存数据,这里的内存,明确上来讲,应该是虚拟内存,也就是所谓的 4GB 内存,这是微软自己的定义,Windows 规定,任何一个进程都拥有自己的虚拟内存,在运行时会把虚拟内存映射到真实的物理内存上;
因此,我们打开游戏进程的时候,需要指明 PROCESS_VM_OPERATION、PROCESS_VM_READ 与 PROCESS_VM_WRITE 三个标志,用以向系统说明我们的意图是要操作和读写游戏进程的虚拟内存的内容;
内存的读写操作都需要四个参数,进程句柄、内存地址、数据内容、数据大小(所占字节数),进程句柄有了,内存地址与数据大小我们在第一步已经查明了(笑),所以,我们只需要安心地写出下面代码即可:
以下代码读取游戏中 Leon 的血量、最大血量以及金钱数目:
以下代码把数值写入到游戏中 Leon 的血量、最大血量以及金钱数目:
最后,我用对话框简单地做了一个界面程序,我们来看一看最终成果图:
刚运行游戏的时候,Leon 的血量等数据没有被载入,所以皆显示为 0;
New Game 之后,Leon 默认血量以及最大血上限皆为 1200,并且没有任何金钱;
打死一个乌鸦,捡到 400 pts 之后,修改器显示 400 pts,数据正确;
被游戏中第一个敌人攻击之后,剩下 630 血,随后敌人被愤怒的 Leon 一阵乱揍,惨死街头;
然而敌人的牺牲只是白费的,因为我点击【Full HP】 按钮之后,Leon 又恢复到了满血状态,我的血满了,而你,却永远站不起来了;
随后我点击了【PTS + 2000】 ,即使不用上战场,也能够得到一大堆金钱奖励;