原因
最近朋友圈一直在流行一个叫 “我要猫咪的小程序”,主要玩法就是用罐头买猫咪。两只一级猫咪合成一只二级猫咪。每次购买猫咪会导致下次再次购买的时候价格上涨。
罐头主要的主要来源是分享到朋友圈,或者微信聊天群,然后获得罐头。每只猫咪每一秒都有固定的罐头产出。一开始升级很快,但是随着级别的升高和猫咪价格的上涨, 解锁新的猫咪变得越来越困难。
而网上的很多的攻略都是说建很多很多个所谓的“刷猫群”,通过不断的分享来获得足够的罐头。这个方法不是不行,而是太繁琐了。
所以我开始去想,有没有什么方法可以一步满级省去天天挂机的烦恼。
分析
首先, 这是一个微信小程序,而且这个游戏是需要联网的,那么就意味着游戏必须和服务器进行数据交换。为了知道手机和电脑是如何进行数据交换的,我们需要抓包进行分析。
手机的抓包,我一般会使用charles。具体的使用教程google一下就会出来很多, 这里就不赘述了。
发现
通过charles,发现这个小程序通信的域名是 https://pongpong.club/
。接口是/cat/user/save
。 故名思议,这个接口是用来保存用户游戏进度的。要一步到满级,我们就要使用这个接口。下面来看看包里有什么内容。
{
"saveTime": 1540314176994,
"coin": "6.831565647269006e+50",
"diamon": 199761747,
"shopLevel": 37,
"speedup": 5,
"upStartTime": 1540314175994,
"loginDays": 2,
"loginRewardDays": 2,
"lastLoginTime": 1540311140890,
"guideStep": 4,
"friendDraw": 0,
"shareCoinNum": 0,
"shareDiamonNum": 0,
"luckyCount": 0,
"luckyShareCount": 0,
"luckyUpTime": 0,
"dbVersion": 15767,
"version": "1.0.9",
"slots": [{
"id": 37,
"pos": 0
}, {
"id": 37,
"pos": 1
}, {
"id": 37,
"pos": 2
}, {
"id": 37,
"pos": 3
}, {
"id": 37,
"pos": 4
}, {
"id": 37,
"pos": 5
}, {
"id": 37,
"pos": 6
}, {
"id": 37,
"pos": 7
}, {
"id": 37,
"pos": 8
}, {
"id": 37,
"pos": 9
}, {
"id": 37,
"pos": 10
}, {
"id":37,
"pos":11
}],
"items": [{
"id": 1,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 64,
"diamonCount": 0
}, {
"id": 2,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 52,
"diamonCount": 0
}, {
"id": 3,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 16,
"diamonCount": 0
}, {
"id": 4,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 14,
"diamonCount": 0
}, {
"id": 5,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 12,
"diamonCount": 0
}, {
"id": 6,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 9,
"diamonCount": 0
}, {
"id": 7,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 1,
"diamonCount": 0
}, {
"id": 8,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 5,
"diamonCount": 0
}, {
"id": 9,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 19,
"diamonCount": 0
}, {
"id": 10,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 16,
"diamonCount": 0
}, {
"id": 11,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 15,
"diamonCount": 0
}, {
"id": 12,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 11,
"diamonCount": 0
}, {
"id": 13,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 19,
"diamonCount": 0
}, {
"id": 14,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 20,
"diamonCount": 0
}, {
"id": 15,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 18,
"diamonCount": 0
}, {
"id": 16,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 16,
"diamonCount": 0
}, {
"id": 17,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 15,
"diamonCount": 0
}, {
"id": 18,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 12,
"diamonCount": 0
}, {
"id": 19,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 16,
"diamonCount": 0
}, {
"id": 20,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 12,
"diamonCount": 0
}, {
"id": 21,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 12,
"diamonCount": 0
}, {
"id": 22,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 12,
"diamonCount": 0
}, {
"id": 23,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 9,
"diamonCount": 0
}, {
"id": 24,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 11,
"diamonCount": 0
}, {
"id": 25,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 4,
"diamonCount": 0
}, {
"id": 26,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 0,
"diamonCount": 0
}, {
"id": 27,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 0,
"diamonCount": 0
}, {
"id": 28,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 3,
"diamonCount": 0
}, {
"id": 29,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 69,
"diamonCount": 0
}, {
"id": 30,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 12,
"diamonCount": 0
}, {
"id": 31,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 12,
"diamonCount": 0
}, {
"id": 32,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 13,
"diamonCount": 0
}, {
"id": 33,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 1,
"coinCount": 97,
"diamonCount": 0
}, {
"id": 34,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 0,
"coinCount": 12,
"diamonCount": 0
}, {
"id": 35,
"buyUnlock": 1,
"diamonUnlock": 1,
"coinUnlock": 0,
"coinCount": 12,
"diamonCount": 20
}, {
"id": 36,
"buyUnlock": 1,
"diamonUnlock": 0,
"coinUnlock": 0,
"coinCount": 12,
"diamonCount": 0
}, {
"id": 37,
"buyUnlock": 1,
"diamonUnlock": 0,
"coinUnlock": 0,
"coinCount": 12,
"diamonCount": 0
}],
"shareGrop": [],
"userid": "[马赛克]",
"openId": "[马赛克]"
}
根据charles抓下来的网络包的内容,我们可以得知要修改那些地方了。
savetime
- 保存时间。coind
- 金钱。 也就是罐头数量diamond
- 爱心数量。另外一种更难获得的罐头。shoplevel
- 等级。(要修改这个)slot
- 面板上的猫咪信息item
- 商店可以出售的猫咪等级。
修改后
当把修改过的包发送到服务器上的时候,发现服务器并米有处理,而且还返回了一个错误。我猜测,可能是savetime
不正确,可能比最后一次的savetime
小,所以出错。当这个错误被改正过来以后,服务器开始正常处理我的包了。
一些Bug
当我满心欢喜的想打开游戏欣赏一下成果的时候,发现什么都没有变。我就纳闷了,从charles的抓包结果来说,进入游戏后query玩家信息的时候query到的数据都是我修改后的数据,怎么就没有体现在游戏上呢。猜测一下,可能是微信有缓存之类的机制。
所以我就将小程序游戏彻底删除了一遍。再次进入游戏的时候,就发现数据已经是修改后的数据了。
除了修改数据成功,我还发现了游戏里的一些bug。比如说,shoplevel
字段应该是商店等级,或者是玩家等级。我是从29级修改至37级。虽然我的等级变了,商店里可以购买的猫咪并没有随着这个等级的变化而变化。
如果想要商店里面的东西变化,就必须要修改item
字段。
再比如diamond
字段,json里面是int,因为开发者认为这个应该是一个小于int范围的一个数字。当我把这个数字填成int范围之外的数字,我猜大概率会overflow。相反,开发者意识到coin
字段是会超出int的范围的,所以在这里用了String而不是简单的int。
我猜测在服务器端,会将这个string转换成Big Integer再插入到数据表当中。
截图
俗话说得好,无图言屌。