静态基址
静态基址是指程序中实现定义好的数据(全局数据或局部数据),这种地址在程序每一次加载时都是唯一的不会变化(不考虑ALSR,如果存在ALSR则静态地址相对于程序基地址的偏移不会变)。
动态基址
动态基址是指程序中通过new或者malloc从堆中申请返回的地址,这种地址在程序每一次加载时都可能会变化。
通过动态基址寻找静态基址
静态基址一般通过多级指针指向动态基址,我们先找到动态基址后回溯得到多级指针,最后得到静态基址。
通过CE搜索功能回溯
以植物大战僵尸为例,我们先找到阳光的动态基址。
接着我们找到哪个地方访问的这个地址,发现add eax,[edx+00005560]这条指令访问了这个地址,而edx的值为0x1A761CD8
接着搜0x1a761cd8的值,并查看谁访问的他。发现cmp dword ptr [eax+00000768],00指令访问了这个地址,eax值为0x02859C70
接着搜0x02859C70的值,并查看谁访问的他。发现静态地址0x006A9EC0的值为0x02859c70。
最后总结得出:0x1A767238 = [0x006A9EC0 + 0x768] + 0x5560,即阳光静态基址为0x006A9EC0,一级偏移为0x768,二级偏移为0x5560。
通过汇编代码回溯
我们寻找第一个卡槽植物的CD时间的动态基址。
我们搜索谁访问的这个地址,发现指令add dword ptr [edi+24],01访问了这个地址,edi等于0x1778CA98。
接着搜0x1778CA98的值发现搜索不到,我们查看add dword ptr [edi+24],01地址处对应的反汇编代码, 发现edi值来源于eax,而eax的值来源上层函数。
我们返回上层函数发现,eax值等于 edi + eax + 28。我们发现此处为一个循环,edi每次增加50,而当eax等于0x1778ca98时,edi等于0。因为eax = edi + eax + 0x28,所以原来的eax = 0x1778ca98 - 0x28 = 0x1778ca70。
那么为什么我们在CE中没有搜索到0x1778CA98的值呢,因为我们在CE中搜索时鼠标的焦点在CE中游戏被暂停了,而当游戏被暂停后下图中更新植物CD时间的函数代码就不会执行了,导致无法搜索到谁访问的地址。
接着搜0x1778ca70的值,并查看谁访问的他。发现指令mov eax,[ebx+00000144]指令访问了这个地址,ebx = 0x1A761CD8.
接着搜0x1A761CD8的值,并查看谁访问的他。发现指令cmp dword ptr [eax+00000768],00指令访问了这个地址,eax = 0x02859c70.
接着搜0x02859c70的值,并查看谁访问的他。发现静态地址0x006A9EC0的值为0x02859c70。
最后总结得出:0x1778CA98 = [[0x006A9EC0 + 0x768] + 0x144] + 0x28,而0x1778CA98 + 0x24处为第一个卡槽植物的CD时间。
并且由上述分析循环处代码可得,卡槽植物对象数组基地址为 [[0x006A9EC0 + 0x768] + 0x144] + 0x28 + 50 * i;