上周接到这个任务的时候,脑袋有点毛毛的了,u3d自从换了il2cpp之后特别难搞,这个任务催得又紧,跟老板先打好预防针,说了下任务艰巨,不保证能完成,老板表示理解。抱着试试看的心态,下载了游戏,扔到ida分析。分析完的结果出乎意料,这款刚发布的游戏并没有采用il2cpp的编码方式,而是采用了传统的mono虚拟机,心中一块石头落了地。 [player autoplay="1"]

ida静态分析

首先当然是把二进制文件拖进ida分析一下,分析出来的结果不出意料,游戏厂商是会玩的,并不想让人轻易破解,编译的时候开了函数名混肴,完全无法从函数名入手。 01想了想,搜索字符看看有什么突破口。辅助的需求是人物移动加速,当然是搜movespeed。结果并不乐观,虽然有move或speed匹配,但都不是需要的单词。打开游戏,进入猪脚界面,观察发现是有移动速度这一属性的,如图所示。 02在扩展属性这个大类下面有移动速度这一属性,依经验来看,扩展属性应该是个大类,里面的每个属性都是这个类中的一个成员。通常这些成员又会有get或者set属性。

从安卓dll入手

但是函数没有符号名,应该怎么去寻找入口点呢?还是结合经验,u3d的游戏在安卓下是加载dll的,而dll可以很轻松的反编译成c#,而且通常有符号。 拿安卓的dll通过ilspy分析,搜索movespeed,很轻松的搜索到了相关的属性和方法。 03 挨个点开看看感觉就两个getmovespeed的方法挺可疑。 04 返回一个浮点数,符合速度参数的特征,sdActorInterface更像一点,英语翻译过来就是sd(盛大)角色属性,多形象。不过这个乘的0.001又是什么呢。继续翻翻,找到一个角色初始化的函数。05 当然这里有移动速度的初始化,把这个函数对照到ios的程序中,可以对照出对应this.movespeed=prop.m_movespeed的是
*(_DWORD *)(a1 + 160) = *(_DWORD *)(a2 + 88);
06 简单打个log看一下发现打出来的数值是 "————movespeed1=5000,movespeed2=5000————————————" 联系到之前的两个Getmovespeed方法,*0.001f和return 5f这个真相大白了。 这样有两个思路,一个是初始化的时候把5000改成一个比较大的数,比如10000或者20000,getmovespeed方法乘0.001后得出10或者20仍然是比5快几倍的数字,另一个方法就是直接改getmovespeed得返回值,返回指定的数值,实现移动加速。 这里简单说下,初始化那个改完之后刚进游戏移动速度确实有变快,但是没多久就报异常游戏崩溃。原因是这个初始化不只是初始化人物的属性,这是一个父类,很多游戏里怪物或者随从之类的类是从这里继承的,初始化调的异常高之后,会导致游戏里多处继承的子类出现问题,从而导致游戏崩溃。所以选择直接改写getmovespeed的返回值的方法来修改人物的移动速度。

关键函数比对测试

单独看这两个方法存在的类名,明显sdActorInterface_getMoveSpeed更像目标函数,经过实际测试之后,也确实证实了这一点。因为修改sdNetChar_GetMovespeed的返回值并没有发生角色移动加速的现象。要修改函数返回值,首先要在ios的二进制代码中找到这个函数,通常,这一步是最累的。 07 和安卓的c#对照一下,是不是差不多(ios版本无函数名,函数名是为了方便我后期自己加进去的) 另一个函数的对比 08 0.001和5.0都在,是不是很像,如果是u3d引擎又都是使用mono虚拟机的话,安卓和ios的函数基本上是一样的,只是安卓是动态库,ios被编译成了静态库而已。当然现在ios的mono版本已经几乎绝种了,多数游戏厂商选择了il2cpp来获得更高的效率和更好的加密性。 mono和il2cpp的差距可以参考我的另一篇日志:http://myhloli.com/about-il2cpp.html 既然找到了函数,那么我们例行的log打起来 09 这时候观察日志,发现不只输出了我自己角色的速度5,还有很多其他的结果混杂在里面,估计是这个函数也被多次调用了,这个获得速度的方法不仅主角在用,怪物和随从等的速度也是从此方法获得的。

构造hook函数

既然更改速度的方法已经找到,继续一鼓作气搞定这个功能吧。 这个功能实现的关键是如何只hook主角移动时调用的movespeed,我的方法是参数匹配。 根据经验,此函数的参数a1是一个地址,虽然每次打开游戏,主角的这个地址会变,但是在一次游戏进程中,每个角色的这个地址是不变的,那么就可以匹配a1,当且仅当a1等于主角地址的时候进行hook。说起来简单,但是要怎么操作呢,主角的地址又应该怎么获取呢?还是多做测试,在测试中发现每次游戏登陆成功,进入主城,操作角色移动的一瞬间,获取到得地址一定是主角的地址,而且在城里不管走多久,输出的地址一直是主角的,只有进入副本战斗时,才会七七八八输出一堆不同的速度和不同的地址,那么可以简单的写个逻辑。 10 定义两个全局变量,globala1和flag,当第一次调用这个函数的时候,把a1的值赋值给全局变量globala1,flag做一次自减处理。那么再调用这个函数的时候,globala1不会被重新赋值,那么就可以匹配a1和globala1是否相等,从而更改返回值是否乘以变量Speedhook更改主角的移动速度了。 编译完把dylib扔到手机里跑一下,果然像预料中一样 ,不仅可以对角色的移动速度进行buff,同时也不会崩溃了,说明hook的函数没有问题。

写在最后

本次拿一个u3d的小游戏详细讲述了一款简单的角色加速辅助的制作过程,希望能给在走ios逆向这条道路的同学一些启发。ios的游戏制作辅助,最常见的问题就是看不到函数名,找不到下手的入口,我就是明明知道肯定有一个getmovespeed函数,我知道只要更改了他的返回值就可以实现功能,但是,我就是找不到这个函数,怎么办?这时候别忘了安卓,通常安卓的dll是完全没有加密的,可以简单的通过ilspy这个小工具逆向出c#源码,这时候可以通过一些关键的特征再把函数对照ida的分析结果定位到ios上,从而实现了无符号的ios程序hook。 博主自从工作后,也是由于任务繁重,很少有时间更新博客,今天抽出来四个小时的时间,谢了这篇文章,希望能给阅读本文的你一些启发,也欢迎同行在ios逆向和游戏辅助开发上多多探讨和交流技术,感谢看到最后的您,那么,最后祝您身体健康,再见。

love loli,love live!