目录

10-3:IDA找敌人数组相关函数调用关系(有符号so)

目录

单机安卓游戏绘制教程10-3:IDA找敌人数组相关函数调用关系(有符号so)

赶码人

本文接上一篇:单机安卓游戏绘制教程10-2:IDA找敌人数组相关函数思路(有符号so)

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/4adb9255ada5b97061e610b682b8636764fe50ed-20220130110213924.png

目前已知GmSimGetNumOfDeadAiTANKs这个函数的参数就是敌人数组的起始地址,接下来找它的调用栈,通过调用栈上的函数,找到参数的来源。

能对着函数名按X,就按X,如果按X出现的列表没有“BL”指令,就给函数打断点,观察LR寄存器的值,接下来演示操作:

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/27137c7a71f4ec4ec504c0536b3578bfe57f29c5.png@942w_390h_progressive-20220130110210925.png

按X找到了两个函数,我们先进去第一个看看:

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/ef61aa391fc34f981e035a2e17546cfade3dacb1.png@884w_497h_progressive-20220130110221291.png

可以得知,GmSimGetNumOfDeadAiTANKs的参数一,是GmSceneCampaignCallbackSimEventTANKKilled的参数一a1+32得到的地址所指向的数值(注意这个*(_DWORD *)(a1 + 32),把a1+32转为了指针,并读取出了这个指针指向的地址的值)

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/f6ab1f471ebf9ff216b738b7fcf17a758738cf2a.png@942w_305h_progressive-20220130110225336.png

再对着这个函数按X,发现并没有出现BL指令,只有一个GmSceneCampaignResume函数当中用到了该函数的指针,后续游戏会通过函数指针的形式调用这个函数,这种情况IDA不能静态分析出来,

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/82863d2633f2f9be6766bf4a7a1fa4113a7d6fed.png@942w_248h_progressive-20220130110229824.png

所以接下来要回到GmSceneCampaignCallbackSimEventTANKKilled,直接如图所示,给这个函数第一条语句打上断点(点击行号左边的蓝色圆圈):

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/d5e7f5734b1da941a17fed0e9f781fa40d877f68.png@942w_483h_progressive-20220130110234891.png

先回到GmSimGetNumOfDeadAiTANKs函数,这次进入xrefs窗口的第二个函数GmScenePreviewCallbackSimEventTANKKilled,可以看到,这两个函数参数关系是*(_DWORD *)(a1 + 4)

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/b7a43905b723f9addf915c9b4ad8f4de604294a9.png@942w_323h_progressive-20220130110241427.png

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/a0346a4024d8298eef2faeb5fa79dc72c7e2ff1c.png@821w_188h_progressive-20220130110246563.png

对着GmScenePreviewCallbackSimEventTANKKilled函数按X,发现仍然找不到BL指令调用,所以,这里也打个断点

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/0035ae38416c18c5a10dddba8ed23d5a685fda13.png@812w_198h_progressive-20220130110251496.png

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/02db465212d3c374a43c60fa2625cc1caeaab796-20220130110258529.png

现在按X已经遇到阻碍了,接下来要通过LR寄存器继续找调用关系,需要用到IDA目录的dbgsrv文件夹的android_server,这部分教程网络上已经有很多了,推荐一个帖子作参考:https://www.52pojie.cn/thread-1511844-1-2.html (专栏不能设置站外链接)

android_server和ceserver使用方式一样(关于ceserver,可以参考我这个视频教程05-1:免root使用ceserver桥接真机的准备工作:设置debuggable=true,以及这个视频教程05-2:CE查看安卓手机内存中的数据(ceserver桥接教程)),有ROOT直接用;如果没有ROOT,就需要修改安装包debuggable属性,然后run-as启动android_server。

在手机端启动android_server之后,IDA操作如图所示:

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/925dcbb9f46846de4d07333ac8df899b1c1e6a1d.png@942w_702h_progressive-20220130110303824.png

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/906fd5acfb04919d8b1ccc6cdf198f0b889a8c03.png@942w_773h_progressive-20220130110308819-20220130110313087.png

选中游戏进程点OK,然后:

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/889e60c3c5566171d2baac67b01e49f0dde877e8.png@942w_536h_progressive-20220130110317975.png

如果出现上图这个弹窗,是在问你当前打开的so和内存中的so是否一样(就是说 解压的apk和安装的apk是否是同一个版本),选择Same就行了,

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/f1ef430562c95ec5294c4f59e9390c1e96de1de9.png@374w_204h_progressive-20220130110323187.png

然后游戏进程就被暂停掉了,等待上面这张图的窗口消失,

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/4160180954b4ba5fcc3a36d503ba48ae17ba19f2.png@942w_474h_progressive-20220130110327675.png

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/db62a6f278900d1d0428f5612078642c39d63871.png@942w_596h_progressive-20220130110334294.png

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/46cd90562ad2d8efe1fcf3e0d4801ebfda1b1364.png@942w_399h_progressive-20220130110338590.png

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/02db465212d3c374a43c60fa2625cc1caeaab796-20220130110343259.png

刚刚已经打过俩断点了,然后在游戏里面动一动,等待触发断点,然后你会发现,在子弹即将接触到某个角色时,游戏被暂停,此时触发断点,

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/c3dd4b7f31037fed27a3fdbce5b6cba58ade39ca.png@942w_311h_progressive-20220130110354103.png

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/7f611f13f2df77e4b9cef310b4e75964e4e08767.png@942w_339h_progressive-20220130110406819.png

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/da3050285bd11e76e251a1061af6646559426f2a.png@942w_431h_progressive-20220130110414528.png

所以是GmSceneCampaignCallbackSimEventTANKKilled这个函数的断点触发了,并且是GmSimDealDamageToTANK调用了它,参数一是v17[36],

这里先简单记一下这个函数内部和v18的参数一有关的代码:

1
2
3
4
5
int __fastcall GmSimDealDamageToTank(int result, int a2, int a3, int a4)
{
  v4 = (_DWORD *)result;
  v17 = v4 + 0x2E00;
  result = v18(v17[36], a2, a3); 

然后继续,找这个函数是谁调用:

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/bf95d67e446bbd6a17d267a7b1db858546fc2ca8.png@942w_402h_progressive-20220130110428696.png

先点击去第一个看看:

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/6af360a63943f0e53f75ce89f93a1e815cb8fa79.png@942w_537h_progressive-20220130110434990.png

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/db479bdfeaf38e879a54050d4bae690d538e036c.png@942w_651h_progressive-20220130110441137.png

参数一不可能是float,不多解释了,直接改类型:

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/70607c971ebd157d58173bf6e758b7a2d81b11ef.png@809w_458h_progressive-20220130110446924.png

记一下:

1
2
3
4
int __fastcall DealCollateralDamage(int result, float *a2, int a3, int a4)
{
  v4 = (int *)result;
  result = GmSimDealDamageToTank((int)v4, i, a4, (int)(float)((float)((float)a3 * v10) + (float)((float)a3 * v10)));

继续找:

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/6616061a4c59023187f747904e1e510c21266f2a.png@942w_374h_progressive-20220130110451434.png

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/51b5e2b0cfd612d5108e0ae19d7b708e219ec721.png@827w_377h_progressive-20220130110455674.png

记下来:

1
2
3
int __fastcall sub_C956AA28(int result, int a2)
{
    result = DealCollateralDamage(result, (float *)(a2 + 4), *(_DWORD *)(a2 + 56), *(_DWORD *)(a2 + 40));

找:

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/b6ed3859ac854b0370c7cb33b8738fe4020f5a24.png@942w_504h_progressive-20220130110500663.png

这个时候,前两个函数进去按X找不到调用者,打断点并没有遇到他们的触发条件,然后干脆将剩下四个也打断点,最终触发了GmSimProcessInstantProjectile,所以进这个函数:

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/bb5740a95313c7b4a933907e320b571bbd99db49.png@756w_609h_progressive-20220130110505128.png

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/81fbf93c87fafbf7f9773266ef0015d9b3155ffa.png@942w_566h_progressive-20220130110509358.png

该记就记,该找就找,

1
2
3
int __fastcall GmSimProcessInstantProjectile(_DWORD *a1, int a2, float *a3)
{
  return sub_C956AA28((int)a1, a2);

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/182421633830b4b89b13eae6aa72375d03f6aadb.png@942w_408h_progressive-20220130110114026.png

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/668ae8f78679497c758c46afaaa8b97a333ecd02.png@942w_705h_progressive-20220130110125686.png

1
2
3
4
int __fastcall GmSimUpdateProjectiles(int result)
{
  v1 = (_DWORD *)result;
  result = GmSimProcessInstantProjectile(v1, (int)v1 + v3, (float *)v43);

剩下的都是以此类推,看图吧,

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/faf59d1593fe9692757e347d5ebc33b54d628a1f.png@942w_348h_progressive-20220130110132166.png

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/2c69d226a6e1b52ce19f1df078150d868048d492.png@803w_557h_progressive-20220130110138028.png

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/6f8433bf437258df16051e4e7c3bd930a47ed0b2.png@942w_408h_progressive-20220130110149525.png

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/12cf9429e2345d6cf285862a7bdc7dc26f9f4ba3.png@873w_590h_progressive-20220130110154725.png

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/17135ca326484971f3c0d1993241721d75144d52.png@942w_506h_progressive-20220130110158761.png

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/02db465212d3c374a43c60fa2625cc1caeaab796-20220130110202692.png

到目前为止,已经找到的调用栈:(个人习惯这样记录,仅供参考)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
int __fastcall GmSimDealDamageToTank(int result, int a2, int a3, int a4)
{
  v4 = (_DWORD *)result;
  v17 = v4 + 0x2E00;
  result = v18(v17[36], a2, a3); 

int __fastcall DealCollateralDamage(int result, float *a2, int a3, int a4)
{
  v4 = (int *)result;
  result = GmSimDealDamageToTank((int)v4, i, a4, (int)(float)((float)((float)a3 * v10) + (float)((float)a3 * v10)));

int __fastcall sub_C956AA28(int result, int a2)
{
    result = DealCollateralDamage(result, (float *)(a2 + 4), *(_DWORD *)(a2 + 56), *(_DWORD *)(a2 + 40));

int __fastcall GmSimProcessInstantProjectile(_DWORD *a1, int a2, float *a3)
{
  return sub_C956AA28((int)a1, a2);

int __fastcall GmSimUpdateProjectiles(int result)
{
  v1 = (_DWORD *)result;
  result = GmSimProcessInstantProjectile(v1, (int)v1 + v3, (float *)v43);

int *__fastcall GmSimUpdateSim(int *result, int a2)
{
  v2 = (int)result;
  GmSimUpdateProjectiles(v2);

int __fastcall GmSceneCampaignUpdate(int a1)
{
  GmSimUpdateSim(*(int **)(a1 + 0x20), 30);

先到这里吧,写得好累,明天再继续。