1. 程式人生 > >安卓逆向-修改APK-戰鬥直接勝利

安卓逆向-修改APK-戰鬥直接勝利

前言

  很久沒有總結過關於逆向程式設計的文章了,來寫一篇實踐分享給大家。主要來說說如何通過逆向修改APK來實現遊戲進入後直接獲得勝利領取獎勵。為了學習發展就不分享遊戲名稱了。下面我們開始吧:

使用到工具

AndroidKiller / IDE 3.1.0.0 (用來反彙編APK)
.NET Reflector 9.0 (用來查詢修改)

過程

  首先通過AndroidKiller將遊戲APK安裝包反彙編出來,使用.NET Reflector 開啟目錄下的Assembly-CSharp.dll檔案。
  F3(調查查詢介面) → ctrl + m(查詢方法型別) → win(查詢關鍵字) → 選擇精準匹配(如下圖所示)。
1


  我們鎖定(上圖中倒數第四個)Menber = win,Declaring Type = BattleState(戰鬥狀態)這行,雙擊進去,順便看看BattleState這個類都有些什麼相關的資訊。
2
(單詞含義不太確定的可以百度翻譯,平時多記多查點滴積累。)

AllEnemiesDead() : Boolean    批註:(所有敵人死亡)Boolean在這裡叫做布林值,代表返回的資料型別:True 或為 False

AllHeroDead() : Boolean     (所有英雄死亡)

EndBattle() : Void         批註:(結束戰鬥)Void 當看到這個型別時要明白方法返回值為空 或 不返回值

  這裡我們把直接勝利,比喻成我們想新增的toast,想讓toast在啟動的時候顯示,就要找到主啟動的activity新增進去。
在Win() : Void → 右鍵Analyze / ctrl + r (進入分析器介面) →雙擊 展開列表 → 展開 Used By 。如下圖:
3
批註: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 →如下面兩張圖。
4

修改後:
5

小結

  這樣程式就能達到直接勝利的效果了,之後通過回編譯、簽名遊戲、打包就可以把遊戲安裝到手機了。希望可以幫到對此技術好奇的你們,榮幸與您分享~