注明:本篇教程需在明白上一篇的基础上才能进行,不清楚的同学请参考这里=》微信小游戏破解(1)之《我要当皇上》

另外我提一下,博主本人并不是专业做破解的,只是这段时间在学习微信小程序开发(老本行是做android开发),并有朋友提出破解需求,我才花时间研究一下的,有些内容我是借鉴了一个专业的破解网站=》吾爱破解 ,有兴趣的同学可以去注册一个账号学习学习,毕竟学无止境,回头是岸[手动滑稽]。

好了,下面进入正题~

先介绍一下《我要猫咪》这个游戏,这款游戏和《我要当皇上》如出一辙,游戏模式一模一样,甚至在我破解完之后,抓到的数据json格式都是一样的,so我感觉要么就是一个人开发的,要么就是你抄我我抄你,因为目前微信官方对小程序上线审核这块要求很低,我之前就抄过一个,竟然也发布成功了,无非就是改改名字换换icon而已,名字叫《戴上圣诞帽》(请允许我无耻的打个广告[手动捂脸])。好了,下面说正经的!怎么越扯越远了...

先上张我破解之后的界面:

老套路,还是先用fiddler抓包https请求,抓包的时候你要留意这个接口:https://www.pongpong.club/cat/dc/user/save

这和《我要当皇上》小游戏一样,都是在游戏过程中或退出游戏的时候会调用这个接口用来向服务器保存用户当前游戏数据的。

你会发现你抓到的都是一堆加密的数据,所以接下来我们只能去寻求解密了。

说到解密对应的一定是加密,所以我们的思路应该是这样,先解密抓取到的数据,进行数据修改之后,再加密去请求https://www.pongpong.club/cat/dc/user/save这个保存数据的接口。

那么如何准确的知道数据的加解密格式呢?采用的是RSA、AES、DES、MD5、BASE64?显然这么乱猜是不可能破解的,况且牵扯到那些公钥私钥的问题就更不可能了;所谓解铃还须系铃人,换个位置思考,如果你是作者你肯定知道怎么加解密,但作者不会告诉你,那怎么办?所以正常的做法就是反编译游戏包,拿到源码,去寻找代码里面加解密的地方,这才是正确的思路!

关于如何反编译微信小程序,这里我就不过多阐述了,网上已经有大佬把脚本都准备好了,请戳这里=》

这是Github作者的源地址       这是CSDN里面一个人写的教程

这里我要提一下,关于如何获得微信小程序源文件的问题,教程里面提到用夜神模拟器可以获得Root权限,但是我测试的时候发现,这个模拟器一打开微信的小程序就会奔溃。。。很尴尬,具体原因不明,所以你最好拥有一台root的手机。如果你实在没有,没关系,文末我会给出这里面所需要的所有工具,包括小游戏源文件!

获取到源文件之后,用以上教程进行反编译,得到的代码文件结构是这样的:

然后下载一个微信小程序开发工具:下载地址 ,安装完成之后打开是这样:

扫码登录,然后选择小程序项目

点击右下角的+号,添加新项目

项目目录选择你之前破解的文件夹的根目录,就是打开展示的是代码文件结构的目录,点击确定会提示你:

Error:登录用户不是该小程序的开发者

不要慌,这时候点击蓝色字体的小游戏(因为这个项目是小游戏类型的项目),系统会自动分配一个小游戏开发的测试号给你,并自动填充在AppID那一栏,然后再点击确定,就可以正常进去阅读源码了。

打开长这个样子。然后点击js文件目录下面的utils会出现RdWXBizDataCrypt.js这个文件,加解密的源码就在这里,如图:

decrypt=》解密  encrypt=》加密

乍一看好像是这么回事,但是我们怎么用呢?每个方法里面又有两个参数,这又是什么含义呢?没有这两个参数是不是就无法执行加解密了?没关系,先打两个断点调试一下看看程序是怎么执行的,如图:

我在加密和解密的地方都打了断点,但是执行的时候只执行了加密的方法,其实也可以理解,因为游戏刚进来的时候会调用登录,所以会先执行加密。如果你想执行解密可以直接将解密的方法体复制到加密方法下面就行了,因为两个方法的参数名称是一样的,而参数t就代表你要加密或者解密的数据,参数r可能是偏移量。所以接下来就明朗了,先把之前我们抓包获取到的加密数据放进去试试看行不行!

nice!成功解密!

这是解密之后的json格式:

{
	"saveTime": 1545205452737,
	"coin": "1e+45",//猫粮数量,越大越好,这个最大值
	"diamon": 125,//爱心数量,不可更改
	"inboxCoin": "2.147483648e+55",
	"inboxDiamon": 708,
	"shopLevel": 37,//主页显示的合成猫的最高等级,最高37级
	"speedup": 1,
	"upStartTime": 1545205451737,
	"loginDays": 1,
	"loginRewardDays": 0,
	"lastLoginTime": 1545204941995,
	"guideStep": 4,
	"friendDraw": 0,
	"shareCoinNum": 0,
	"shareDiamonNum": 0,
	"luckyCount": 0,
	"luckyShareCount": 0,
	"luckyUpTime": 0,
	"dbVersion": 4175,//这个还是一样每次修改的时候记得+1或更多
	"version": "1.3.7",
	"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,//购买是否解锁  1解锁  0未解锁
		"diamonUnlock": 1,//爱心购买是否解锁  1解锁  0未解锁
		"coinUnlock": 1,//猫粮购买是否解锁  1解锁  0未解锁
		"coinCount": 7,//猫粮可购买个数
		"diamonCount": 0,//爱心可购买个数
		"skin": 1,//皮肤代号
		"cps": 1
	}, {
		"id": 2,
		"buyUnlock": 1,
		"diamonUnlock": 1,
		"coinUnlock": 1,
		"coinCount": 0,
		"diamonCount": 0,
		"skin": 2,
		"cps": 0
	}, {
		"id": 3,
		"buyUnlock": 1,
		"diamonUnlock": 1,
		"coinUnlock": 1,
		"coinCount": 19,
		"diamonCount": 0,
		"skin": 3,
		"cps": 0
	}, {
		"id": 37,
		"buyUnlock": 1,
		"diamonUnlock": 0,
		"coinUnlock": 0,
		"coinCount": 259,
		"diamonCount": 0,
		"skin": 37,
		"cps": 1
	}],
	"skins": "1001,1002,1003,1004,1005,1006,1007,1008,1009,10010,10011,10012,10013,10014,2001,2002,2003,2004,2005,2006,2007",//稀有猫的皮肤代号列表,我测试只能显示到第7个稀有皮肤,其他代号就不知道是多少了,反正我都是乱猜的
	"playerLevel": 2147483647,//玩家等级,也就是你现在是多少阶,最大值就是int的最大值2147483647,再大点你调用保存数据接口的时候就500了
	"tasks": "1:1:1,2:17632988245109:1,3:125:0,4:79456894979:1,5:79456894979:1,6:79456894979:1,7:79456894979:1,8:79456894979:1,9:79456894979:1,10:79456894979:1,11:79456894979:1,12:79456894979:1,13:79456894979:1",
	"shareGrop": [],
	"userid": "***",
	"openId": "***"
}

json数据的介绍就在上面了,就不再详细阐述了,基本和上一篇《我要当皇上》的参数含义差不错。

解密的代码如下:


  console.log("执行了解密方法")
  t = "放入你抓取的加密数据"
  var t = Crypto.util.base64ToBytes(t),
    o = Crypto.charenc.UTF8.stringToBytes(this.sessionKey),
    r = Crypto.charenc.UTF8.stringToBytes(r),
    e = new Crypto.mode.CBC(Crypto.pad.pkcs7);
  try {
    var n = Crypto.AES.decrypt(t, o, {
        asBpytes: !0,
        iv: r,
        mode: e
      }),
      s = JSON.parse(n);
  } catch (t) {
    console.log(t);
  }
  console.log("解密之后的数据:" + JSON.stringify(s))
  return s;

将这段代码放入t.prototype.encrypt = function(t, r)

{

上面的代码,记得把其他代码注释掉

}

这个方法体里面,Ctrl+s保存,开发工具会自动编译(或者点击上面工具栏的编译按钮),然后看下面的Console打印的json数据就行了。接下来就剩下加密了!

同理,我们按照上面的方法如法炮制,将参数 t 换成我们修改之后的json数据,放入到加密的方法体里面编译一下看看结果

perfect!大功告成!!加密成功!!!大吉大利,今晚吃鸡!

代码如下:

console.log("执行了加密方法")
  //这里需要用JSON.stringify方法将json数据转成json字符串才能加密
  t = JSON.stringify(
    //这里面放{}这个包裹的完整的json数据
  )
  var o = Crypto.charenc.UTF8.stringToBytes(this.sessionKey),
    r = Crypto.charenc.UTF8.stringToBytes(r),
    e = new Crypto.mode.CBC(Crypto.pad.pkcs7);
  try {
    var res = Crypto.AES.encrypt(t, o, {
      asBpytes: !0,
      iv: r,
      mode: e
    })
    console.log("加密之后的数据:" + res)
    return res;
  } catch (t) {
    console.log(t);
  }
  return "";

将这段代码放入t.prototype.encrypt = function(t, r)

{

上面的代码,记得把其他代码注释掉

}

这个方法体里面,Ctrl+s保存,开发工具会自动编译(或者点击上面工具栏的编译按钮),然后看下面的Console打印的加密之后的数据就行了。

最后将加密之后的数据放到postman里面,请求方式依然是post+application/json,如图:

至此,破解《我要猫咪》小游戏就完美结束了。

最后把上面需要的反编译工具以及小程序的源文件给大家整理好了~

下载链接

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐