微信小程序 【我要猫咪】 抓包分析

原因

最近朋友圈一直在流行一个叫 “我要猫咪的小程序”,主要玩法就是用罐头买猫咪。两只一级猫咪合成一只二级猫咪。每次购买猫咪会导致下次再次购买的时候价格上涨。
罐头主要的主要来源是分享到朋友圈,或者微信聊天群,然后获得罐头。每只猫咪每一秒都有固定的罐头产出。一开始升级很快,但是随着级别的升高和猫咪价格的上涨, 解锁新的猫咪变得越来越困难。

而网上的很多的攻略都是说建很多很多个所谓的“刷猫群”,通过不断的分享来获得足够的罐头。这个方法不是不行,而是太繁琐了。
所以我开始去想,有没有什么方法可以一步满级省去天天挂机的烦恼。

分析

首先, 这是一个微信小程序,而且这个游戏是需要联网的,那么就意味着游戏必须和服务器进行数据交换。为了知道手机和电脑是如何进行数据交换的,我们需要抓包进行分析。

手机的抓包,我一般会使用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再插入到数据表当中。

截图

俗话说得好,无图言屌。

HAPPY HACKING