小游戏 Brain Test 3 大脑测试3 跳过付费内容 无限内购
小游戏 Brain Test 3 大脑测试3 跳过付费内容 无限内购
游戏属于il2cpp,现在很多的安卓游戏都采用了这个打包。对于这类游戏,常见的改法是修改dex的入口,在入口处添加一个调用代码,每次启动都自动修改sp的long值,这样就打到了无限金币的目的。还有另一种改法就是直接修改so文件,通过修改底层代码,可以实现的玩法也比较多,比如不减反增、定死数值、免费购物、全部解锁等。但是相对的也比较麻烦,对于没有汇编经验的萌新来说,还是写个Java实在。
软件样品为当前最新版1.50.0。
准备工具
1、IDA32
2、Il2CppDumper
想不到这游戏已经出到第三部了,前两部我还发过帖子如何修改无限提示,不过是改dex的。现在换另一种方法,改so破解游戏。
游戏风格比较适合小朋友,有些关卡我实在想不通为什么是这样……
游戏有广告,怎么去掉我就不说了,用幸运破解器一键搞定就好了,来来去去都是那几个熟面孔。
先看一下游戏界面,第一次玩游戏的时候会送50个电灯泡,正常情况下会越用越少,那么就会有相减的逻辑,修改so的时候可以利用相反的指令让灯泡越来越多,也就是不减反增。
下好Il2CppDumper后,顺序打开相应的文件,libil2cpp、global-metadata.dat。等待分析完成后打开dump.cs文件备用。
接着ida打开so文件,选择左上角运行如下两个脚本文件,静静等待加载完毕即可。电脑差的会比较久,可以先去喝杯奶茶再回来看看
之前说过这类游戏的数值一般储存在sp里面,位于com.unicostudio.braintest3.v2.playerprefs.xml,打开后他是长这样的:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?> <map> <int name="cross_promo_id" value="61" /> <string name="unity.player_session_count">5</string> <int name="Screenmanager%20Resolution%20Height" value="2220" /> <string name="unity.player_sessionid">4976473052650692822</string> <int name="Gdpr_Control" value="1" /> <string name="NotificationHelper.Scheduled">273129443%7C1094985734</string> <int name="__UNITY_PLAYERPREFS_VERSION__" value="1" /> <int name="Screenmanager%20Resolution%20Width" value="1080" /> <string name="unity.cloud_userid">95a0dbb4b1309fcf094060f513e8d42d</string> <string name="playerData">%7B%22coins%22%3A5%2C%22OnCoinsChanged%22%3A%7B%7D%2C%22gems%22%3A0%2C%22OnGemsChanged%22%3A%7B%7D%2C%22hammers%22%3A0%2C%22OnHammersChanged%22%3A%7B%7D%2C%22adsRemoved%22%3Afalse%2C%22OnAdsRemovedChanged%22%3A%7B%7D%2C%22completedLevels%22%3A%5B1%2C2%2C3%2C4%2C5%2C7%2C8%2C9%2C10%2C11%2C12%5D%2C%22lastReachedLevel%22%3A13%2C%22lastPlayedLevel%22%3A13%2C%22hintsOpened%22%3A%7B%226%22%3A%5B0%5D%2C%227%22%3A%5B0%2C1%5D%7D%2C%22OnHintsOpenedChanged%22%3A%7B%7D%2C%22flags%22%3A%5B%22new_level_popup_showed%22%2C%22bonus_Bonus1_skipped%22%2C%22hint_LevelTricky1_0%22%2C%22hint_LevelTricky1_1%22%2C%22tricky_LevelTricky1_played%22%2C%22hint_Make_Potion_1%22%2C%22hint_Alchemy_1%22%5D%2C%22selectedPets%22%3A%7B%22cat%22%3A-1%2C%22dog%22%3A-1%2C%22bird%22%3A-1%2C%22frog%22%3A-1%7D%2C%22unlockedPets%22%3A%7B%22cat%22%3A%5B%5D%2C%22dog%22%3A%5B%5D%2C%22bird%22%3A%5B%5D%2C%22frog%22%3A%5B%5D%7D%2C%22activeActionLevel%22%3A1%2C%22LastReachedLevel%22%3A13%7D</string> <int name="Screenmanager%20Fullscreen%20mode" value="-1" /> <int name="rate_shown" value="1" /> <int name="shareClaimed" value="1" /> </map>
playerData里的coins就是电灯泡的数量,gems应该是钻石。coins%22%3A5,这个5就是数量,当前为5。
然后搜索dump.cs里的playerData,只有一个结果,那么这里就是就是破解的关键入口。其中get_Coins、get_Gems这两个都是比较常见的代码,如果你不知道关键字可以先搜这两个,看看有没有相关信息。
// Methods // RVA: 0x13D954C Offset: 0x13D954C VA: 0x13D954C public int get_Coins() { } // RVA: 0x13D14DC Offset: 0x13D14DC VA: 0x13D14DC public void set_Coins(int value) { } // RVA: 0x13D9554 Offset: 0x13D9554 VA: 0x13D9554 public int get_Gems() { } // RVA: 0x13D75B4 Offset: 0x13D75B4 VA: 0x13D75B4 public void set_Gems(int value) { } // RVA: 0x13D955C Offset: 0x13D955C VA: 0x13D955C public int get_Hammers() { } // RVA: 0x13D9564 Offset: 0x13D9564 VA: 0x13D9564 public void set_Hammers(int value) { } // RVA: 0x13D9604 Offset: 0x13D9604 VA: 0x13D9604 public bool get_AdsRemoved() { } // RVA: 0x13D960C Offset: 0x13D960C VA: 0x13D960C public void set_AdsRemoved(bool value) { } // RVA: 0x13D96B8 Offset: 0x13D96B8 VA: 0x13D96B8 public int get_LastReachedLevel() { } // RVA: 0x13D96C0 Offset: 0x13D96C0 VA: 0x13D96C0 public void set_LastReachedLevel(int value) { } // RVA: 0x13D974C Offset: 0x13D974C VA: 0x13D974C public void SetHintOpen(int level, int hintIndex) { } // RVA: 0x13D998C Offset: 0x13D998C VA: 0x13D998C public bool GetHintOpen(int level, int hintIndex) { } // RVA: 0x13D9A88 Offset: 0x13D9A88 VA: 0x13D9A88 public void .ctor() { }
先来看Coins(),有两个结果,public int get_Coins()和public void set_Coins(int value),get_Coins根据地址跳转到0x13D954C,我查看了一下引用,结果为0,没有函数引用这个地方,如果修改这里的话十有八九是没什么用的。
接着继续看set_Coins,跳转到地址0x13D14DC。英文意思是设置、显示数值。破解过java的应该知道,方法名中有set_xx,get_xx,应该是改get,而不是set,set这个函数基本上有传入参数,所以不能直接修改这里,这里只是用来显示数值的。但是刚才的get找不到引用,所以只能另寻方法。
通过查看set_Coins的交叉引用,可以确定是哪里调用了显示,如上图红框,分别是几种扣费地址。随便选一个,汇编如下:
il2cpp:01324714 ; --------------------------------------------------------------------------- il2cpp:01324714 MOV R0, #8 //函数地址 il2cpp:01324718 LDR R7, [R0] //r0地址读取放入r7,此时r7是剩余的电灯泡 il2cpp:0132471C BL HintPanel$$get_cost //获取商品价格,需要花费多少电灯泡 il2cpp:01324720 MOV R6, R0 //把价格存入r6 il2cpp:01324724 BL sub_2B6FD4 il2cpp:01324728 ; --------------------------------------------------------------------------- il2cpp:01324728 il2cpp:01324728 loc_1324728 ; CODE XREF: sub_1324350+C4↑j il2cpp:01324728 SUB R1, R7, R6 //r1=r7-r6,此时r1是剩余的电灯泡 il2cpp:0132472C MOV R0, R5 //r5传入r0,然后进入BL il2cpp:01324730 MOV R2, #0 //初始化 il2cpp:01324734 BL PlayerData$$set_Coins //进行显示 il2cpp:01324738 MOV R0, #0 il2cpp:0132473C BL DataManager$$get_playerData il2cpp:01324740 MOV R5, R0 il2cpp:01324744 CMP R0, #0 il2cpp:01324748 BNE loc_1324750 il2cpp:0132474C BL sub_2B6FD4
v13 = DataManager__get_playerData(0); v14 = v13; if ( !v13 ) sub_2B6FD4(); v15 = *(v13 + 8); cost = HintPanel__get_cost(); PlayerData__set_Coins(v14, v15 - cost, 0); v17 = DataManager__get_playerData(0); if ( !v17 ) sub_2B6FD4();
伪代码比较容易理解,有个减号,很容易看出这是扣费的地方。
所以把5个函数的调用,全部由减法改成加法指令(add)即可越用越多,其它的货币也是一样的思路,就不一一举例了。
小游戏 Brain Test 3 大脑测试3 跳过付费内容 无限内购标题图片
感觉确实不错,下载
zqyku评论Re:小游戏 Brain Test 3 大脑测试3 跳过付费内容 无限内购
分享的很多都是不错的
xixfr评论Re:小游戏 Brain Test 3 大脑测试3 跳过付费内容 无限内购