小游戏 Brain Test 3 大脑测试3 破解付费内容 无限内购
本帖最后由 芽衣 于 2022-4-9 19:43 编辑游戏属于il2cpp,现在很多的安卓游戏都采用了这个打包。对于这类游戏,常见的改法是修改dex的入口,在入口处添加一个调用代码,每次启动都自动修改sp的long值,这样就达到了无限金币的目的。还有另一种改法就是直接修改so文件,通过修改底层代码,可以实现的玩法也比较多,比如不减反增、定死数值、免费购物、全部解锁等。但是相对的也比较麻烦,对于没有汇编经验的萌新来说,还是写个Java实在。
软件样品为当前最新版1.50.0。
准备工具
1、IDA32
2、Il2CppDumper
想不到这游戏已经出到第三部了,前两部我还发过帖子如何修改无限提示,不过是改dex的。现在换另一种方法,改so破解游戏。
游戏风格比较适合小朋友,有些关卡我实在想不通为什么是这样……
https://static.52pojie.cn/static/image/hrline/5.gif
游戏有广告,怎么去掉我就不说了,用幸运破解器一键搞定就好了,来来去去都是那几个熟面孔。
先看一下游戏界面,第一次玩游戏的时候会送50个电灯泡,正常情况下会越用越少,那么就会有相减的逻辑,修改so的时候可以利用相反的指令让灯泡越来越多,也就是不减反增。
下好Il2CppDumper后,顺序打开相应的文件,libil2cpp、global-metadata.dat。等待分析完成后打开dump.cs文件备用。
接着ida打开so文件,选择左上角运行如下两个脚本文件,静静等待加载完毕即可。电脑差的会比较久,可以先去喝杯奶茶再回来看看{:17_1088:}
之前说过这类游戏的数值一般储存在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地址读取放入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)即可越用越多,其它的货币也是一样的思路,就不一一举例了。
luodeman 发表于 2022-3-28 10:37
大佬,求个《 Brain Test 3 大脑测试3》原始版本,我也想试试,谢谢
这是谷歌市场的游戏,apk包你去apkpure下载 Gavin5661 发表于 2022-3-28 14:38
那么提示的数量会不会有上限啊?到了上限会报错吗
几个亿不会有问题,几十亿不好说{:17_1088:} 抢个沙发。{:1_918:}{:1_918:} 大佬厉害啊 大神,收藏慢慢学习 有改好的吗?下载试试 大神,666 不会汇编的我,看的津津有味{:301_1009:} 写得很不错,虽然对于程序代码不太了解{:1_921:} 太牛了,羡慕 大佬这工具能发下吗?