前言
其实这篇文章也没有太多的技术含量,主要是试一试Android上面Unity3D游戏C#脚本的分析与修改,话不多说先准备好旅行青蛙的apk就开始吧。
C#脚本
首先将Android apk安装包解压,查看assets/bin/Data/Managed
文件夹下面的dll文件,其中Assembly-CSharp.dll
便是游戏中的C#脚本,使用Reflector或者dnSpy进行反编译都可以,如何出现反编译出错的情况,那可能就是脚本被加密了,一般在尝试在libmono.so
中的mono_image_open_from_data_with_name
中获取解密后的dll脚本,而当前分析的游戏C#脚本并没有加密。在dnSpy中的反编译结果如下:
左侧就可以看到对应的类,点击类就可以看到反编译出来的代码,下面先跟游戏里面的一些特征来分析反编译出来的脚本。
汉化
首先使用adb install tabikaeru.apk
命令安装apk文件,然后打开游戏可以看到如下界面:
首先来看看怎么修改显示的文字以达到汉化的效果,使用dnSpy点击编辑->搜索程序集
搜索右边选择数字/字符串
然后搜索名前
:
点击CallTutorial
可以找到刚刚在屏幕上面显示的文字:
鼠标点击右键选择编辑IL指令
,修改刚刚看到的文字为汉字:
然后点击应用即可看到修改后的效果:
点击文件->全部保存
替换assets/bin/Data/Managed
文件夹下面对应的文件即可,然后将文件打包成apk使用jarsinger、signapk.jar或Android助手重签名安装到手机就能看到修改后的效果了。
修改三叶草数
要修改三叶草数可以从购买的时候入手,比如提示三叶草不足的时候:
直接搜索足
找到目标代码:
根据找到的如下代码来分析:
1 | if (SuperGameMaster.CloverPointStock() >= itemDataFormat.price) |
当三叶草的存储小于当前商品的价格的时候就会弹出这个提示,点击SuperGameMaster.CloverPointStock()
得到如下代码:
1 | public static int CloverPointStock() |
这里返回的是一个从saveData.CloverPoint
中获取的整数,可以尝试将其修改成返回一个特定的数字每次查询三叶草的数目都是这么多,右键点击编辑IL指令
,然后点击重置并右键删除第一条指令,因为只是返回一个数字的话两条指令就够了:
然后修改第二条指令为一个数字,具体的指令代表的类型可以查看IL指令说明:
点击确定后就能看到修改代码的效果:
1 | public static int CloverPointStock() |
重新签名安装之后每次购买商品之后三叶草的数目也不会减少,一直是9999。
修改抽奖券
修改抽奖券也是同样的套路,搜索足
找到目标代码,其实刚刚搜索的时候就已经看到了。
1 | if (SuperGameMaster.TicketStock() < 5) |
点击SuperGameMaster.TicketStock()
也是差不多的代码同样修改返回数字即可:
1 | public static int TicketStock() |
1 | public static int TicketStock() |
修改抽奖概率
每次抽奖都是抽到白球就不是很开心了,怎么能够提供抽奖的概率呢?抽到其它颜色的球的时候会提示:
搜索白玉
找到如下代码:
1 | public static readonly Dictionary<Rank, string> PrizeBallName = new Dictionary<Rank, string> |
右键点击PrizeBallName
选择分析找到在那里被使用的:
双击PrizeBallName
得到如下代码:
1 | public void PushRollButton() |
从代码来看就是刚刚抽奖结果提示的地方,来分析下这个结果是怎么生成的,可以看到Define.PrizeBallName[this.result]
这个result决定了抽到的是什么颜色的球,那么看看这个result是在哪里生成的。在当前文件中看到了两处赋值:
1 | public void LotteryCheck() |
下面是在UIMaster_raffle.UI_Start
中调用的,判断之前的奖品有没有领取,LotteryCheck
这个刚好是在显示结果之前调用的,猜测就是这里控制的不同颜色的球的出现概率,分析下这段代码:
1 | public void LotteryCheck() |
从上面代码分析PrizeBalls中就定义了不同颜色的球摇出概率:
1 | public static readonly Dictionary<Rank, int> PrizeBalls = new Dictionary<Rank, int> |
所以直接修改这里的数字就控制摇出的概率了,比如不出白球,其它球的概率都一样:
1 | public static readonly Dictionary<Rank, int> PrizeBalls = new Dictionary<Rank, int> |
修改农场四叶草数
农场里面大部分都是三叶草、四叶草的概率是很小的,那么怎么修改这个呢?在界面上面好像不太好找关联,先试试搜索三叶草的英语clover
,点击checkCloverCreate
看起来就是控制生成的函数:
1 | public void checkCloverCreate() |
首先看this.NewCloverObject(j, this.cloverList[j], list)
这个内部调用就是四个参数的,只不过第四个参数是false:
1 | public GameObject NewCloverObject(int index, CloverDataFormat cloverData, List<GameObject> cloversObj) |
也就是第四个参数为true就是四叶草,点进去看看:
1 | public GameObject NewCloverObject(int index, CloverDataFormat cloverData, List<GameObject> cloversObj, bool fourLeafFlag) |
那么这里既可以修改四叶草生成的概率也可以修改fourLeafFlag
这个为true,第一种方式和上面一样,看看第二种。右键fourLeafFlag
编辑IL指令:
这里首先取fourLeafFlag
判断然后跳转,所以修改为true即可。修改ldarg.s fourLeafFlag
为ldc.i4 1
,修改后的代码如下:
1 | if (true) |
总结
今天修改的部分就到这里了,其它的大家可以自己去尝试,总结下分析Unity3D游戏过程,当然这篇文章讲的是最简单的情况,还有使用保护将dll脚本加密的,就需要hook函数或者从内存查找dump,还有通过C#脚本调用lua脚本来实现的,逻辑在lua脚本里面,lua脚本又加密了的情况等等。那么没保护的情况的话,一般可以从界面显示搜索来分析,然后根据一些特定单词去搜索查找关键代码部分。这篇主要是Android上面使用mono模式的情况,如果是使用IL2CPP的话比如iOS上面,C#脚本都转成了cpp文件c代码的形式的话分析起来就会麻烦很多,后面会有在iOS上面修改代码以及在非越狱平台也能修改运行的文章。