在之前的一篇博客介绍了怎么找阳光地址:CE和Ollydbg简单介绍,但是那个地址在重启游戏后会变化,这次会讲解为什么这个阳光的地址会变化,以及对于变化的地址怎么处理。
推荐博客:CE找基址原理
1.阳光的地址为什么会变化
首先我们需要知道,在代码编译成可执行文件(如exe),代码段和数据段(全局变量、静态变量等)的虚拟内存地址已经固定,重启后依然不变(重新编译才会改变)。有人可能会有疑问,我同事打开多个程序,那么地址不是重复使用了吗?重合的是虚拟地址,它不是内存上的物理地址,虚拟地址会经过操作系统(主要是mmu)映射到物理内存,所以不用担心这个问题。 验证代码如下:
#include
using namespace std;
int g_var;
int main() {
int var = 1;
g_var = 1;
return 0;
}
打断点然后转到反汇编查看: 可以看到全局变量它的地址是固定的,而局部变量是用寄存器来代替,是变化的。
假如我是植物大战僵尸的程序员,我可能会这样编写阳光相关的代码:
//阳光类
#include
using namespace std;
class Sun { //阳光类
public:
int tmp;
int tmp2; //阳光值前面可能有多个值
int sun_value = 100; //阳光值
int tmp3; //阳光值后面可能有多个值
};
class GameData { //数据类
public:
int tmp;
int tmp2; //前面可能有多个值
Sun* sun; //指向Sun类
int tmp3; //后面可能有多个值
};
GameData* g_game_data;
int main() {
g_game_data = new GameData(); //堆区创建游戏数据
g_game_data-> sun = new Sun(); //堆区创建阳光
return 0;
}
这样除了g_game_data地址是固定的(全局变量),其余都是变化的(堆区数据)。 综上,这个阳光地址就是变化的,只不过代码比上面复杂很多,有可能有多级指针(以上只有两个)。
2.怎么通过某个方式找到变化的阳光值
虽然阳光的地址是变化的,但是它可以由上一级地址来表示,而上级地址也可以由它的上级地址来表示,并且一定有一个地址是固定的(数据段中),这个地址就是常说的基地址。因此一个变化的地址一定可以由基址表示。
上面代码的基地址为&g_game_data ,可以用它来表示阳光的地址(基地址+地址偏移):
(*(*&g_game_data + 8) + 8
&g_game_data:全局变量的地址(固定),即基地址
*&g_game_data即g_game_data:GameData 对象地址
*(*&g_game_data + 8):Sun对象地址
(*(*&g_game_data + 8) + 8:sun_value 阳光地址
CE查找阳光的基地址和偏移地址
下面操作找基址,CE的基础使用可以见最上面的那片博客。先按照以下操作找出基地址和每次的偏移量,然后再解释每个值的含义。 第一次搜索: 这里出现了很多结果,需要缩小范围。改变阳光值然后再搜索。 第二次搜索出现一个地址0x1AD04218,这个地址存的就是阳光值(重启会改变):
右键选择什么访问了这个地址:
可以看到有两个结果,随便打开一个(都一样,它们都是使用相同的偏移量来访问的这个地址): 得到了一个地址0x1ACFECB8,0x1ACFECB8(类似Sun对象地址) + 0x5560(偏移量) == 0x1AD04218(动态阳光地址) 其中偏移大小的固定的(类结构决定,编译后就固定了),而这个地址是动态变化的,因为它通过寄存器来使用。顺着找到的这个地址,用这个地址去搜索它被什么访问了(这个地址可以右键复制):
然后观察结果地址,如果前两位地址有重复,极大概率就不是。这样可以挑选出两个满足条件的地址:
然后继续右键找出上面访问了这个地址,先以前面的这个举例,它被以下地址访问: 看到有很多的0x768偏移量,这说明大概率对了,继续看这个地址:
顺着这个地址操作: 绿色的就是基地址了(4个都可以,有可能有4个全局变量指针),选择第一个006A9EC0,它的第一个偏移量768,第二个偏移量5560,因此动态阳光地址表示为(*(*(006A9EC0) + 768 ) + 5560) == 动态阳光地址 可以用CE验证:
3.怎么理解基地址和偏移量
根据前面假设的代码,这几个可以对应:
006A9EC0 对应于 &g_game_data(基地址,全局指针变量) 02ACA248 对应于 GameData 对象地址 02ACA248+0x768 对应于sun成员变量地址 1ACFECB8 对应于 Sun 对象地址 1AD04218 对应于 动态阳光地址
作图如下:
总结
很多时候要查找的代码相隔很远,比如一次偏移就几百个字节,所以经常会遇到干扰信息,需要总结经验才能提高。最稳妥的方式还是使用OD去看汇编代码,通过调试代码才能准确判断。