转载:https://blog.csdn.net/kalongkaya/article/details/79161734
最近一款佛系养娃(误)蛙的游戏突然爆红,我也试着玩了一下,结果被圈粉了。有蛙当然要晒,但是看朋友圈,别人的蛙出去拍的照片都是光鲜亮丽,呼朋唤友的,自家的蛙却只能单人穷游。说到底是当爹的没钱害的,但是没钱没关系,咱喜欢瞎折腾。下面咱就来搞搞这个小游戏。
首先,得拿到这个小游戏的apk。我这是通过adb pull下来的,你也可以从应用市场下载。
改apk的后缀名为rar,用压缩软件打开。大致看一下,可以看出来就是一个unity游戏。那么就把assets\bin\Data\Managed下的Assembly-CSharp.dll拿出来。咱们后面分析修改的就是这个dll文件了。
网上找了一下,发现dnSpy(dnSpy 是一款针对 .NET 程序的逆向工程工具)十分好用。打开dnSpy,将上面的dll拖入空白界面。主界面如下:
接下来开始分析吧。玩过游戏的知道,游戏的主要货币是三叶草,还有抽奖券也比较常用。
大致就是这种感觉,啥也买不起。另外一点比较尴尬,就是这个游戏不支持中文,不过好在我们还能看懂葉、券、足三个字。这两段日语的意思大致就是三叶草不够、抽奖券不够。
跑题了,反正我们已经知道了分析的切入点(就是那三个字)。dnSpy中Ctrl+Shift+K,出现全局搜索框,选择数字/字符串,搜“足”字。正好出来两个结果,1个对应抽奖券,1个对应三叶草。
首先看PushRollButton方法,双击定位到代码处(dnSpy的好处就在于此,反编译的代码十分接近源代码,很容易看懂)。PushRollButton很明显指按下抽奖券那个转轮按钮的意思。如下就是该方法的反编译代码,可以看到一段熟悉的日语,看来是找对地方了。接下来就是看代码了,这段代码的意思很明确。首先判断券的数量是否小于5(玩过游戏的知道,5张券才能抽1次):小于就弹券不够的日语框并结束这个方法,后面的抽奖的操作就不做了;大于等于就给你扣5张券,接着给你抽奖。
简单地修改的话就是让判断条件恒为假,不进入弹框步骤,并且抽奖不扣奖券。所以,我们可以将5和-5改为0和0。奖券数量最少为0,不会小于0,因此不会去弹框。每回抽奖前扣0张券。
那么,如何改这个dll呢。dnSpy也提供修改dll文件的功能。在要修改的方法中右键选择编辑IL指令。将ldc.i4.5改为ldc.i4.0,将-5改为0,点击确定。再看代码,已经改成功了。
券已经改完了,接下来是三叶草了。定位到SetInfoPanelData方法。方法有点长,我直接copy下来了。前面一堆大致是操作选择物品相关的代码,我们着重看if (SuperGameMaster.CloverPointStock() >= itemDataFormat.price) 后的代码(从该判断开始代表已经确定好要买的物品了)。该判断可以明显地看出就是将三叶草的数量和物品价格比较,不够就弹框,够就扣三叶草,一个套路。继续分析,看到1个BuyItem方法,好了,还是一样,想办法不让程序扣就行了。
-
public void SetInfoPanelData(int shopIndex, Vector3 pos)
-
{
-
if (shopIndex ==
-1)
-
{
-
this.unsetCursor();
-
this.InfoPanel.GetComponent<InfoPanel>().SetInfoPanel(
-1);
-
return;
-
}
-
if (Mathf.Abs(
this.flickMove) >
this.S_FlickChecker.flickMin /
3f)
-
{
-
return;
-
}
-
if (
this.selectShopIndex != shopIndex)
-
{
-
this.InfoPanel.GetComponent<InfoPanel>().SetInfoPanel(shopIndex);
-
this.selectShopIndex = shopIndex;
-
this.setCursor(pos);
-
SuperGameMaster.audioMgr.PlaySE(Define.SEDict[
"SE_Cursor"]);
-
}
-
else
-
{
-
ShopDataFormat shopDataFormat = SuperGameMaster.sDataBase.get_ShopDB(shopIndex);
-
ItemDataFormat itemDataFormat = SuperGameMaster.sDataBase.get_ItemDB_forId(shopDataFormat.itemId);
-
if (itemDataFormat ==
null)
-
{
-
return;
-
}
-
if (!itemDataFormat.spend && SuperGameMaster.FindItemStock(itemDataFormat.id) !=
0)
-
{
-
SuperGameMaster.audioMgr.PlaySE(Define.SEDict[
"SE_Cancel"]);
-
return;
-
}
-
if (SuperGameMaster.CloverPointStock() >= itemDataFormat.price)
-
{
-
if (SuperGameMaster.FindItemStock(shopDataFormat.itemId) <
99)
-
{
-
base.GetComponent<FlickCheaker>().stopFlick(
true);
-
ConfilmPanel confilm =
this.ConfilmUI.GetComponent<ConfilmPanel>();
-
if (itemDataFormat.type == Item.Type.LunchBox)
-
{
-
confilm.OpenPanel_YesNo(
string.Concat(
new
object[]
-
{
-
itemDataFormat.name,
-
"\nを買いますか?\n(所持数\u3000",
-
SuperGameMaster.FindItemStock(shopDataFormat.itemId),
-
")"
-
}));
-
}
-
else
-
{
-
confilm.OpenPanel_YesNo(itemDataFormat.name +
"\nを買いますか?");
-
}
-
confilm.ResetOnClick_Yes();
-
confilm.SetOnClick_Yes(
delegate
-
{
-
confilm.ClosePanel();
-
});
-
confilm.SetOnClick_Yes(
delegate
-
{
-
this.GetComponent<FlickCheaker>().stopFlick(
false);
-
});
-
confilm.SetOnClick_Yes(
delegate
-
{
-
this.BuyItem();
-
});
-
confilm.ResetOnClick_No();
-
confilm.SetOnClick_No(
delegate
-
{
-
confilm.ClosePanel();
-
});
-
confilm.SetOnClick_No(
delegate
-
{
-
this.GetComponent<FlickCheaker>().stopFlick(
false);
-
});
-
}
-
else
-
{
-
base.GetComponent<FlickCheaker>().stopFlick(
true);
-
ConfilmPanel confilm =
this.ConfilmUI.GetComponent<ConfilmPanel>();
-
confilm.OpenPanel(
"もちものがいっぱいです");
-
confilm.ResetOnClick_Screen();
-
confilm.SetOnClick_Screen(
delegate
-
{
-
confilm.ClosePanel();
-
});
-
confilm.SetOnClick_Screen(
delegate
-
{
-
this.GetComponent<FlickCheaker>().stopFlick(
false);
-
});
-
}
-
}
-
else
-
{
-
base.GetComponent<FlickCheaker>().stopFlick(
true);
-
ConfilmPanel confilm =
this.ConfilmUI.GetComponent<ConfilmPanel>();
-
confilm.OpenPanel(
"みつ葉が足りません");
-
confilm.ResetOnClick_Screen();
-
confilm.SetOnClick_Screen(
delegate
-
{
-
confilm.ClosePanel();
-
});
-
confilm.SetOnClick_Screen(
delegate
-
{
-
this.GetComponent<FlickCheaker>().stopFlick(
false);
-
});
-
}
-
}
-
}
BuyItem方法:红框是扣钱的操作,把price前面的负号去掉。买东西,程序给你三叶草,就是任性。
改的方法就是将neg给nop掉。
改完后:负号没了。
Ctrl+Shift+S将更改后的dll文件存起来。
打开ApkIDE,将原始apk拖到APKIDE空白处打开。打开assets文件夹,将修改后的dll覆盖原Assembly-CSharp.dll文件。编译生成APK,安装编译后的APK就可以了。
效果:
后记:文中涉及到的IL指令没有细说,因为我也不会,自己查资料看着改吧。还有一些unity游戏的汉化版可能也是通过这个方法来修改的吧。不过在这提醒一下大家,不要下载来历不明的破解版或汉化版游戏,很容易被人插入恶意代码,窃取个人隐私、恶意扣费等。
所用工具链接:
修改了一下APKIDE的链接地址,我用的是七少月大佬的3.3.3增强版,不过他之后又更新了,有兴趣的看着下吧。
APKIDE:https://www.pd521.com/thread-818-1-2.html
dnSpy:https://down.52pojie.cn/Tools/NET/dnSpy.zip
=============华丽分界线===============
哈哈,更新一下,前面说到改无限抽奖,但实际抽的时候老是抽到白玉,很烦。找了一下,搜“白玉”,可以看到抽奖概率,下面是我改过的概率,之前的是白:青:绿:红:金=60:27:9:3:1。照着之前的办法改吧,哈哈。
还有就是蛙回家时间,我试着找了相关代码,太复杂了,改了几次也没成功。想玩快点的,照着网上说的修改系统时间来弄吧。
声明:小白纯属瞎折腾蹭热度。