本教程面向有C\C++基础的人,最好还要懂一些Windows编程知识
代码一律用Visual Studio 2013编译,如果你还在用VC6请趁早丢掉它...
写这个教程只是为了让玩家更好地体验所爱的单机游戏,顺便学到些逆向知识,我不会用网络游戏做示范,请自重
本章介绍内存与Cheat Engine
计算机程序所有的变量、代码都是储存在内存里的,包括游戏里那些HP、MP、金钱等,那么只要能修改内存就能自由改变玩家的HP、金钱了(当然对于网游是没用的,这些数据都储存在服务器,客户端里的只是一个副本),常见的满血、金钱无限等游戏修改器大部分就是这个原理
想要修改指定的变量你要知道变量在内存里的地址,这时会用到内存搜索工具
Cheat Engine
Cheat Engine(以下简称CE)是最常用的开源的内存搜索软件,它还包括了很多调试工具
虽然看这名字就知道是用来游戏作弊的,但是也可以用于普通程序的内存搜索和调试
你可以在官网或我的网盘下载到CE,我的网盘里的整合了中文补丁和一个中文版练习程序
本文通过CE自带的练习程序介绍用CE搜索内存的方法和常用的作弊手段,现在打开CE的练习程序,点击Next来到Step2
Step 2
这关是查找精确数值的练习,首先在CE中打开练习程序的进程:点击右上角选择进程的按钮,选中练习程序,打开进程
然后看看练习程序里的HP是100,那么搜索精确值100,类型选4字节(也就是int型)
左边会出来一堆内存地址,因为有很多地址的值为100嘛
然后在练习程序里点Hit me,HP变成了95,回到CE里再次扫描95
左边只剩下一个地址了,双击它把它加入下面的列表,然后再双击列表中的值,改为1000
回到练习程序里,Next按钮可以点了,过关~(这时你可以再点Hit me看看HP是多少)
Step3
这关没有给你精确数值了,只有一个血条,只知道HP范围是0到500
因为不知道数值,这次扫描类型选择未知的初始值,假设数值类型为4字节,点首次扫描
然后左边出现检索:365,568个地址,但是不显示在列表里(因为并没有什么用)
在练习程序里点Hit me,闪过个-5
既然知道减了5HP,CE里扫描类型选数值减少了...,值填5(如果连减少了多少值都不知道扫描类型就选减少的数值),再次扫描
只剩下6个地址了(其实可以看出就是第二个,因为HP范围为0到500)
重复上一步直到只剩下一个地址(或者你能看出是哪个地址),然后把值改成5000过关
Step 4
这关是练习浮点数的搜索,方法和Step 2一样,只是把数值类型换成浮点数和双浮点数,我就不重复说了,把HP和子弹都改成5000过关
浮点数运算是有误差的,CE也允许搜索的浮点数的值有一定误差
Step 5
既然代码也是储存在内存的,那么能修改内存就能修改代码了
当然内存里储存的可不是C语言,而是编译后的机器语言,它很难翻译成高级语言但是可以很容易翻译成汇编语言(反汇编),所以修改代码需要学习一些汇编知识
本章可以不用学汇编,照着做留个印象就好了
这关的要求是点击Change value后值不变,也就是把修改值的代码替换成什么也不干(汇编里的nop指令)
首先找到值的地址(同Step 2),然后右键,选择找出是什么改写了这个地址
然后再点一下练习程序里的Change value,指令列表里会出现改写了这个地址的指令
选中它,点右边的替换就会把它换成什么也不干的指令
关闭这个窗口,回到练习程序里点Change value过关
Step 6
有些变量的地址会变,比如动态申请内存的变量 int* p = (int*)malloc(10 * sizeof(int)); int* p = new int[10]; 但是不管怎么变总会有个静态的地址储存它的指针
本关要求是改变指针后值还是5000
首先找到值的地址,然后右键选择找出是什么访问了这个地址
再点击Change value,出现很多条指令,先双击第一条
(其实熟悉汇编的话这里就可以看出指针地址是Tutorial-x86_64.exe+0x2F7A50了,其中Tutorial-x86_64.exe表示这个模块的基址)
这是一条读取0x01250C30的指令,这里显示指针的值可能是0x118,一看就很不靠谱,和0x01250C30差太多了,再看下一条
这是一条写入0x01250C30的指令,显示指针的值可能是0x01250C30,正好和值的地址一样,就是它了
然后搜索十六进制01250C30,出来一个地址,这就是指针的地址,并且地址是绿色的说明它是静态的
点手动添加地址,勾上指针,填指针的地址
然后把值改成5000,勾上锁定
回到练习程序点击Change pointer过关
为什么不直接搜索0x01250C30而要看汇编代码呢?因为指针的值不一定是0x01250C30,比如这个变量在一个struct里而且不是第一个成员,比如是下面这个struct的v2
struct Foo
{
int v1;
int v2;
};
那么应该搜索0x01250C2C并且添加地址时偏移量要填4
如果搜索出来的不是静态地址怎么办?说明这是多级指针,比如p1->p2->p3->p4->v,你要一直找到指针p1...
Step 7
这关要求是点击Hit me你的HP会+2,就是把HP-1的代码换成HP+2
按照Step 5找到写入HP的代码
点击右边的显示反汇编工具,双击这行代码,把前面的sub改成add,后面的01改成02
然后点击Hit me就过关了
不过这里add指令和sub指令的长度刚好一样,如果add的长度大于sub的长度就会破坏后面的指令了,这时要用到CE的代码注入功能
点击菜单里的工具-自动汇编
然后点菜单里的模板-代码注入
填入在哪条地址上跳转,这里是"Tutorial-x86_64.exe"+2C77B,就是那条sub指令的地址
然后把原代码的sub指令去掉,在newmem里写入add指令
点执行,完成代码注入
你可以看到原来的sub指令变成了jmp指令,就是跳到我们的代码
跟过去看看里面是我们的代码,执行完后跳回去继续执行后面的代码
Step 8
这关就是传说中的多级指针,目标是点Change pointer后值还是5000
和Step 6一样先找值的地址,找访问这个地址的指令
(其实会汇编的话看看前面的代码就知道结果了,但不是经常有读取指针的指令连在一起的情况,更多的是某个类中某个方法访问了成员对象中的某个成员...这样)
偏移量为0x18,搜索0x012A3B00得到一级指针,再找访问这个指针的指令
偏移量为0,搜索0x0123CA60得到二级指针,再找访问这个指针的指令
偏移量为0x18,搜索0x0123C220得到三级指针,再找访问这个指针的指令
偏移量为0x10,搜索0x0125B620得到四级指针,显示为绿色,是静态地址,终于不用找了...
点手动添加地址,勾上指针,点三次Add offset,填入顶级指针的地址和各级指针的偏移量
把值改成5000,勾上锁定,点Change pointer过关
Step 9
可能你和你的敌人减血用同一个代码,如果你删除了这个代码你的敌人也会受到影响
这一关你要注入代码分辨出减血的是你的队伍还是敌人,让你的队伍胜利,而且不能用锁定血量
先找出各玩家的HP地址(根据提示HP是浮点数)
其中在找第一个HP的二级指针时出了点问题,CE的反汇编是这样的
估计CE的x64反汇编还不完善,这里我用IDA反汇编是这样的
可以看出偏移量是0x7F8,应该搜索RBX寄存器的值0x0113CB90
(其实知道了后面三个HP的偏移量也能猜出第一个HP的偏移量,这明显是一个指针数组)
然后为了分辨出玩家还要分析一下玩家的数据结构,打开内存浏览器点菜单的工具-分析数据/结构
然后点文件-Add new group添加3个group,每个group填入各HP的地址(准确来说应该填入指向HP指针的值,这里也就是减去偏移量0x08,不过我已经知道前8个字节是没用的)
点击结构-定义新的结构并且让CE尝试填入基本类型
可以看出第一个是HP,第4个是队伍ID,第5个是玩家名字
那么分辨的方法有很多种,可以判断HP>100的是敌人,或者队伍ID不等于1的是敌人,或者判断名字,或者判断指针指向哪个玩家...
这里我就判断队伍ID吧,在减HP的地方注入代码:
点Restart game and autoplay过关~~