安卓逆向-修改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

小结

  这样程序就能达到直接胜利的效果了,之后通过回编译、签名游戏、打包就可以把游戏安装到手机了。希望可以帮到对此技术好奇的你们,荣幸与您分享~

猜你喜欢

转载自blog.csdn.net/u010349629/article/details/79953334