安卓逆向-修改APK-戰鬥直接勝利
前言
很久沒有總結過關於逆向程式設計的文章了,來寫一篇實踐分享給大家。主要來說說如何通過逆向修改APK來實現遊戲進入後直接獲得勝利領取獎勵。為了學習發展就不分享遊戲名稱了。下面我們開始吧:
使用到工具
AndroidKiller / IDE 3.1.0.0 (用來反彙編APK)
.NET Reflector 9.0 (用來查詢修改)
過程
首先通過AndroidKiller將遊戲APK安裝包反彙編出來,使用.NET Reflector 開啟目錄下的Assembly-CSharp.dll檔案。
F3(調查查詢介面) → ctrl + m(查詢方法型別) → win(查詢關鍵字) → 選擇精準匹配(如下圖所示)。
我們鎖定(上圖中倒數第四個)Menber = win,Declaring Type = BattleState(戰鬥狀態)這行,雙擊進去,順便看看BattleState這個類都有些什麼相關的資訊。
(單詞含義不太確定的可以百度翻譯,平時多記多查點滴積累。)
AllEnemiesDead() : Boolean 批註:(所有敵人死亡)Boolean在這裡叫做布林值,代表返回的資料型別:True 或為 False
AllHeroDead() : Boolean (所有英雄死亡)
EndBattle() : Void 批註:(結束戰鬥)Void 當看到這個型別時要明白方法返回值為空 或 不返回值
這裡我們把直接勝利,比喻成我們想新增的toast,想讓toast在啟動的時候顯示,就要找到主啟動的activity新增進去。
在Win() : Void → 右鍵Analyze / ctrl + r (進入分析器介面) →雙擊 展開列表 → 展開 Used By 。如下圖:
批註:Depends On:執行Win()方法時所需要內容。 Used By : Win()方法 被哪些過程使用
BattleState.Win() : Void
Depends On
Used By
BattleState.Update() : Void
PlayerCmder.Reconnect(FullPlayerWrap) : Void
批註:我在這裡看出 Win()方法 與 Update() 是屬於BattleState類下的方法也可以說Reconnect()方法屬於 PlayerCmder類
分析來看:發現遊戲在執行 有檢視 戰鬥狀態(BattleState)的過程,而遊戲在執行這個過程中會用到 勝利(Win()) 和 重新整理(Update())的命令。 所以在這裡只要我們把勝利的命令放在重新整理命令的第一行,讓玩家進入遊戲時,系統就會檢視戰鬥狀態-重新整理-玩家勝利。這就是程式碼之後執行的邏輯。
下面我們接著操作:
先來看看Update() : Void
對於程式碼看不明白的可以直接看下方文字即可:
public override void Update()
{
base.Update();
if ((this.m_status == Status.Init) && (BattleApp.aBattle != null))
{
this.m_status = Status.Runing;
}
if (BattleApp.aBattle != null)
{
if (this.m_status == Status.BattleEndTutorial)
{
if (Singleton<TutorialManager>.Get().IsTutorialFinishOp(this.m_battleEndTutorial))
{
if (this.m_result == BattleResult.Win)
{
this.Win();
}
else if (this.m_result == BattleResult.Lose)
{
this.Loss();
}
}
}
else
{
if (!this.m_bTriggerStartEvent && (this.ElapseTime > 0x9c4L))
{
this.m_bTriggerStartEvent = true;
Singleton<TutorialManager>.Get().SendEvent(new BattleStart());
}
if (!this.m_bTrriggerWaveStartEvent && (this.ElapseTime > 0x9c4L))
{
this.m_bTrriggerWaveStartEvent = true;
Singleton<TutorialManager>.Get().SendEvent(new WaveStart(this._curWave));
}
bool flag = false;
if (!this.PauseTime && !this.WaveCleared)
{
this.RemainTime -= App.Clock.DeltaMillis;
if ((this.RemainTime <= 0L) || this.AllHeroDead())
{
flag = true;
this.m_result = BattleResult.Lose;
}
if (this.AllEnemiesDead())
{
this._waveCleared = true;
if (this.CurWave == this.MaxWave)
{
flag = true;
this.m_result = BattleResult.Win;
}
else
{
this.ClearWave();
}
}
if (flag)
{
this.OnBattleEnd();
if (this.m_status != Status.BattleEndTutorial)
{
if (this.m_result == BattleResult.Win)
{
this.Win();
}
else if (this.m_result == BattleResult.Lose)
{
this.Loss();
}
}
}
if ((this.m_helpAddEpDataList != null) && (this.m_helpAddEpDataList.Count > 0))
{
HelpAddEpData data = this.m_helpAddEpDataList[0];
if ((data.Tick * 1000f) < this.ElapseTime)
{
this.m_helpAddEpDataList.RemoveAt(0);
BevUnit bevUnitByHeroID = BattleApp.aBattle.GetBevUnitByHeroID(data.HeroID);
if (bevUnitByHeroID != null)
{
bevUnitByHeroID.aUnitAttribute.aUnitProp.CurEP = UnitProp.MAX_EP;
}
}
}
}
}
}
}
通過分析程式碼可以看到勝利、失敗、所有敵人死亡、所有英雄死亡。
想讓遊戲直接勝利,就在第一行Update() : Void上面呼叫Win() : Void方法。
在選單Tools → Reflexil v1.6 →如下面兩張圖。
修改後:
小結
這樣程式就能達到直接勝利的效果了,之後通過回編譯、簽名遊戲、打包就可以把遊戲安裝到手機了。希望可以幫到對此技術好奇的你們,榮幸與您分享~