本文接上一篇:单机安卓游戏绘制教程10-3:IDA找敌人数组相关函数调用关系(有符号so)
上一篇教程已经找到了GmSceneCampaignUpdate这个函数,继续,打断点,点LR寄存器旁边的箭头之后如图:
上图的蓝色框,是点击LR之后默认选中的地方,但实际上这行代码还没开始执行。可以给这两行以及GmSceneCampaignUpdate函数都打上断点,观察执行顺序。v3+32是GmSceneCampaignUpdate的参数。
1
2
|
v3 = gmc + 40 * *(_DWORD *)(gmc + 288);
v7 = (*(int (__fastcall **)(_DWORD))(v3 + 4))(*(_DWORD *)(v3 + 0x20)); //GmSceneCampaignUpdate
|
现在已经不用再跟了,注意这里出现了个“gmc”,v3和gmc有关,双击它之后:
发现这是bss段的一个数值,在游戏开发过程中,gmc可能是一个全局变量,总之,bss段的地址不会变,这里的gmc相对于libnative.so这个模块的偏移是固定的。可以在未开启debug的状态下直接看到它的偏移(可以参考我前面IDA找矩阵的视频,这里不浪费时间截图了),也可以拿模块加载到内存中的地址算一下,如图:
接下来回顾我们找到的调用栈,写出基址偏移,这个基址直接用gmc表示,写代码的时候再转成libnative.so+0x689cc的形式。
现在要注意的就是先关掉IDA的动态调试,再去用CE附加游戏,否则ceserver会有“没ROOT”之类的提示(我印象中是这样的,感兴趣可以根据ceserver的输出自己解决这个问题)。
1
|
刚才的 gmc + 40 * *(_DWORD *)(gmc + 288),写到CE就是:[gmc] + 0x28 * [ [gmc] + 0x120]
|
GmSceneCampaignUpdate接收到的参数,实际是:[gmc]+0x28*[[gmc]+0x120]+0x20
地址框框为啥不能跟随窗口变宽呢…
于是就有了基址偏移,
调用栈如图,从下往上看,这些函数都是只看参数一就够了。v17看做一个表示地址值的int变量,v17[36]相当于v17 + 36*4(十进制),也就是v17+0x90,这里v18就是GmSceneCampaignCallbackSimEventTankKilled,参数一就是:
1
|
[[[gmc]+0x28*[[gmc]+0x120]+0x20]+0x20]+0xB890
|
1
2
3
|
int __fastcall GmSceneCampaignCallbackSimEventTankKilled(int a1, int a2)
{
result = GmSimGetNumOfDeadAiTanks(*(_DWORD *)(a1 + 32));
|
所以,GmSimGetNumOfDeadAiTanks的参数一是:
1
|
[[[[gmc]+0x28*[[gmc]+0x120]+0x20]+0x20]+0xB890] + 0x20
|
于是:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
int __fastcall GmSimGetNumOfDeadAiTanks(int a1)
{
int v1; // r2
int v2; // r1
int v3; // r3
v1 = 0;
v2 = a1; // [[[[gmc]+0x28*[[gmc]+0x120]+0x20]+0x20]+0xB890] + 0x20
v3 = 0;
while ( v1 < *(_DWORD *)(a1 + 20) )
//所以 循环终止条件这里是: [[[[[gmc]+0x28*[[gmc]+0x120]+0x20]+0x20]+0xB890]+0x20]
{
if ( !*(_BYTE *)(v2 + 72) )
// [[[[gmc]+0x28*[[gmc]+0x120]+0x20]+0x20]+0xB890]+0x724*n + 0x48 表示敌人n已死亡
++v3;
++v1;
v2 += 724;
// [[[[gmc]+0x28*[[gmc]+0x120]+0x20]+0x20]+0xB890]+0x724*n 这个就是每个敌人的结构体地址
}
*(_DWORD *)(a1 + 24) = v3;
return v3;
}
|
现在已经知道敌人最大数量和每个敌人的结构体起始地址的基址偏移是:
1
2
3
|
[[[[ [gmc] + 0x28 * [ [gmc] + 0x120] + 0x20] + 0x20 ]+ 0xB890] + 0x20] + 0x14
[[[[ [gmc] + 0x28 * [ [gmc] + 0x120] + 0x20] + 0x20 ]+ 0xB890] + 0x20] + 0x2d4 * n
|
(这里顺便提一句,有多个基址偏移是很正常的,如果从其他函数下手,基址偏移和我这个不同也是很正常。如果想用GG脚本扫出这个数组的基址偏移,偏移量至少要填写到47248…,况且,目前没证据表明[ [gmc] + 0x120] 是个固定值,说白了就是,指针扫描或许不能通杀所有游戏
接下来要找到敌人坐标的偏移,分析代码,或者直接观察内存都行;一些大型游戏,坐标数值并不在人物结构体当中,而是另一个结构体,而人物结构体保存着另一个结构体的指针(这就是所谓的XX游戏的坐标和XX属性“不在同一层”),这种可以去学学CE结构分析器用法,网上教程很多。
敌人最大数量这个值是大于屏幕所有敌人数量的,但是也没大多少,关注以下地址:
1
2
3
4
5
6
7
8
|
[[[[ [gmc] + 0x28 * [ [gmc] + 0x120] + 0x20] + 0x20 ]+ 0xB890] + 0x20] + 0x2d4 * 0
[[[[ [gmc] + 0x28 * [ [gmc] + 0x120] + 0x20] + 0x20 ]+ 0xB890] + 0x20] + 0x2d4 * 1
[[[[ [gmc] + 0x28 * [ [gmc] + 0x120] + 0x20] + 0x20 ]+ 0xB890] + 0x20] + 0x2d4 * 2
[[[[ [gmc] + 0x28 * [ [gmc] + 0x120] + 0x20] + 0x20 ]+ 0xB890] + 0x20] + 0x2d4 * 3
[[[[ [gmc] + 0x28 * [ [gmc] + 0x120] + 0x20] + 0x20 ]+ 0xB890] + 0x20] + 0x2d4 * 4
[[[[ [gmc] + 0x28 * [ [gmc] + 0x120] + 0x20] + 0x20 ]+ 0xB890] + 0x20] + 0x2d4 * 5
[[[[ [gmc] + 0x28 * [ [gmc] + 0x120] + 0x20] + 0x20 ]+ 0xB890] + 0x20] + 0x2d4 * 6
...
|
用Ctrl+B直接观察就能看到坐标了,直接给出坐标偏移吧:0x19c
血量还没看,明天再说。
本系列教程作者:赶码人