一、引言
游戏数据的修改,就是某个函数对某个变量的值的修改。一般来说a=6
,就是在内存中申请一片4个字节大小的空间给a,并把6的十六进制格式写入这片空间,而“地址”就是辨别不同的空间的标识。也就是说地址和数据是一一对应的关系,通过地址就能直接进行读取和修改数据。
指针实际上也是一个地址,一级指针就是地址c里存着地址b,而地址b里存着数据a。
1. 为何在游戏逆向中要去寻找指针呢?
1)游戏是运行在内存中的,假如内存空间的分配是根据先来先分配的方法,由此可知每次游戏获得的内存空间都是不同的,所以基址也不同(游戏开始的地方)。
2)构成程序的语句都是以程序开始的地方为基址,以一种相对地址方式保持语句有序。如果基址是0x400000,某个指令的相对地址是0x200,那么它的实际内存地址就是0x400200。
3)因为每次运行游戏基址不同,所以根据相对地址得到的实际地址也不同。这就导致我们如果在某次游戏运行中找到了血量的地址a并修改成功,等下次运行该游戏时再根据地址a进行数据修改时就会失败,因为此时的血量地址可能变成了b。
4)我们知道语句的地址=基址+偏移量,其实这正是指针的组成。现有一句 a=10
,显然a的地址在每次运行游戏的时候都会发生变化,但是我们只要找到了基址和偏移量,我们就可以定点修改。
--基址:程序开始的地方
--code 块
-- 全局变量
A={a={1,2},b={3,4}}
lua中数组的第一个元素的索引是1,而不是0,所以第二个元素索引是2
显然我们如果要执行A.a[2]=3
,我们必须要知道A的地址=基址+偏移1,a的地址=A的地址+偏移2,以及a[1]的地址=a的地址+偏移3,即A.a[1]
的地址=基址+偏移1+偏移2+偏移3
打个比方:一个班上有50名学生,你是新来的老师并不知道每个学生的名字,你通过学委做的座位表你知晓了所有学生的名字,例如你记住了第三排第一个是小明,但是如果明天换了座位那第三排第一个还是小明吗?虽然只是但是你如果记得学号010325(表示初一三班第25个学生)就是小明,那么下次你可以就叫学号即可。过了一年,小明的学号变成了020325,显然这里的02就是基址而0325就是偏移量。
2. 游戏的基址每次运行游戏都会发生变化,用指针真的方便吗?
确实, 游戏的基址在每次运行游戏都会不同,如果是对于普通玩家来说直接通过搜索数据得到数据地址要更加方便。但是如果我们要写脚本去实现比较复杂的功能,需要利用到游戏里的多种数据,我们不可能再一个一个去测试游戏数据的地址。
只要够耐心显然可以找出所有你要用到的数据位置,并且为你所用。而基址可以通过多种方法找到:
编写注入代码进行基址查找:
-
使用C++或其他语言编写DLL,注入到游戏进程中。
在DLL中实现基址查找和记录功能。
在游戏运行时,自动记录基址并调整指针。
实现符号搜索: -
分析游戏的可执行文件,找到目标函数或数据块的特征码。
编写代码在游戏启动时进行内存扫描,找到特征码对应的内存地址,确定 基址。
二、实战
目的:从尾找头即从数据地址找到基址,通过基址+偏移量设置指针。
基址的特征:CE中地址栏为绿色的一行,或者地址栏以程序名.exe开头
1.找到健康值的地址
能到步骤8我默认步骤1-步骤7的技巧你都会了,我就不细讲。这里我们找到了健康值的地址019CC528。
2. 找到谁修在改了健康值,得到一级指针
想要修改这个数据那么其必然要访问这个地址并修改这个地址的数据,因为查询修改会比查询访问来的更加精确,所以我查询哪句汇编代码在对这个地址进行修改。
图上可以看出 mov [esi+18],eax
这句汇编代码修改了健康值,而esi+18
就是健康值的地址019CC528,18是偏移量,esi的值:019CC510,所以我们找到了一级指针【019CC510+18=019CC528】,指向数据49。根据基址特征,判断地址019CC510不是基址。
3. 二级指针
这里我们找到了数据019CC510的地址:0199FCB0 ,并且通过查谁在访问这个地址得到汇编代码mov esi,[esi],esi=019CC510,这里是把地址[esi]的数据传给esi,且指令执行完的结果为esi=19CC510 ,自然[esi]=0199FCB0,所以这是一个偏移量为0的二级指针【0199FCB0+0=19CC510 】。
以为相对地址的原因,指针只是用来表示一个地址,所以作为地址指针只有被访问的功能,而函数修改的是一级指针指向的数据。所以在找更高级的指针时应该找谁在访问数据019605C8。画重点:是访问数据19CC510,即要有地址0199FCB0才能访问
显然通过基址的特征判断,0199FCB0仍然不是基址,所以我们推测还有三级指针。
4. 三级指针
我们搜索0199FCB0得出值为0199FCB0的地址019CC4A4我们通过查看谁在访问数据0199FCB0,得到汇编指令mov esi,[esi+14],偏移量:14,esi=019CC490。得到三级指针【019CC490+14=0199FCB0】,但是019CC490仍然不是基址。
5.四级指针
我们搜索019CC490得出值为019CC490的地址019A58F4我们通过查看谁在访问数据019CC490
得到汇编指令:mov esi,[esi+0C],偏移值:0C,esi=019A58E8,得到四级指针【019A58E8+0C】
6.得到基址
搜索019A58E8 得到其就是基址
7.设置指针
地址 | 数据 | 备注 |
---|---|---|
00400000即Tutorial-i386.exe | - | 程序运行地址 |
006566E0也是 Tutorial-i386.exe+2566E0 | 019A58E8 | 基址 |
019A58E8+0C | 019CC490 | 四级指针 |
019CC490+14 | 0199FCB0 | 三级指针 |
0199FCB0+0 | 019CC510 | 二级指针 |
019CC510+18 | 健康值 | 一级指针 |