之前分享了一款很好玩的海戰游戲,上一次分析它,是因為在玩耍過程中遇到了一個可以連續開炮的變態修改版,嚴重的破壞了公平性。所以本著研究的態度,開始接觸分析unity3d相關方面的知識。
最近的更新中,加入了許多新的戰艦,并且采用了il2cpp的方式,這點從游戲的目錄中就能看的出來。
一、獲取il2cpp信息
首先利用Il2CppDumper從il2cpp中獲取types, methods, fields等等數據。步驟很簡單,運行Il2CppDumper.exe并依次選擇il2cpp的可執行文件(ELF或者Mach-O文件)和global-metadata.dat文件,然后選擇運行的模式,將生成dump.cs文件和script.py腳本。具體的細節可以參照il2cpp使用方法說明。
打開dump.cs文件,不同于使用dnSpy直接分析dll,這里我們能看到的是類名、方法名等數據以及其對應的偏移地址。
二、IDA分析il2cpp
導入il2cpp.so到IDA中,等待自動分析完畢。
之前我們用Il2CppDumper生成了兩個文件,其中有一個script.py腳本,在IDA中File-Script file選擇script.py運行即可,會重命名methodName,添加stringLiteral注釋和MakeFunction。
三、找到關鍵地址并進行修改
1、耐久度的修改
我們在dump.cs文件中,查找到獲取耐久度的代碼對應著地址為0x115EFE8
復制這個值到IDA中,Jump to address : 0x115EFE8,然后我們就能定位到具體的方法邏輯。
根據方法名public int GetDurability(string ship)可知耐久度是一個int類型的值。通過分析,看到在.text:0115F264這里使用了Unity Mathf的Clamp限制操作,值在R2 - 0和R3 - 0x64之間,換成十進制就是0 ~ 100,也就是在游戲中耐久度的體現,接著把值傳給了R5寄存器。
到這里,我們就有思路了,為了不讓耐久度降低,我們強制讓該方法返回100就可以了。修改.text:0115F280處,替換R5的值為100。修改后如下:
這樣就達到了耐久度永遠為100%了。
2、艦船解鎖
同樣是先找到對應的地址,我們可以看到一個布爾型的IsPurchasedByDefault(),方法地址為0x1015630。
public class ShipData : MonoBehaviour // TypeDefIndex: 5313
{
...
public bool IsPurchasedByDefault(); // 0x1015630
...
拷貝地址帶IDA:
我們直接給R0賦值1,代表一直返回true。
3、高級賬戶
同樣的原理,我們找類似IsPremium 這樣的字段,然后到IDA中進行修改。在.text:00FEC070直接給R4寄存器賦值為1,或者在.text:00FEC060修改也可以。
同時這個高級賬戶是有時間限制的,我們找到相關的位置:
public class Premium // TypeDefIndex: 4827
{
...
// Methods
...
public int DaysLeft(); // 0x11675C0
public bool IsActive(); // 0x11675F8
}
直接在.text:011675DC改變其邏輯賦值為3,表示還剩余3天。同時IsActive的返回改為1,表示處于激活狀態。
4、戰斗獎勵
LevelEndScreenRewardPage中找到更新數據的Update()方法
private void Update(); // 0x10E4A1C
通過分析,我們發現戰斗的獎勵分別通過GetGoldBonus、GetPlatinumBonus、GetDollarsBonus計算,那么我們在最后更改其值即可。
調整獎勵數值,R5原本代表黃金,R6代表鉑,R7代表美元。
四、重新打包app
重新打包app并運行,查看效果:
耐久度永遠不會降低,戰斗獎勵棒棒的。
雖然才等級4,卻解鎖了所有戰艦。