最近无聊打发时间喜欢玩下消灭病毒,发现后期升级武器金币太高了升不动了。网上搜了下,似乎还没有破解教程,这里记录下我的修改过程,后端代码见后面
PS:2019/04/09 游戏升级,复制出来的ID加密了,工具已删除,不过实际使用的还是openid(老ID)
抓包这里使用的是 Fiddler 4 抓包,电脑开热点,手机电脑处于同一个局域网下
先设置下抓 https 和局域网抓包
手机连上电脑开的 wifi
手机浏览器192.168.201.1:8888下载证书,下载完后再安装
手机 WIFI 设置代理
启动游戏打一关并退出,会看到有个 upload 的接口上传数据
同样的数据放到 postman 中返回{"data":{},"code":0}
修改金币和钻石后在 post 返回{"code":1000}
看到 sign 字段应该是对数据做了校验的,这里需要获取源码分析加密算法
小程序反编译为了获取源码,需要得到小程序的源码包,并反编译获得源码
需要一部 root 权限的手机,同时清空微信数据,登陆我们的账号,只下载这一个小程序。
到达/data/data/com.tencent.mm/MicroMsg/[一长串字母]/appbrand/pkg/
看到有两个 wxapkg 文件和一个文件夹,和文件夹同名的 wxapkg 就是小程序的代码了,另一个 wxapkg 文件应该是小游戏的调试工具包
拿到 wxapkg 文件需要做反编译
这里提供了一下解包工具https://github.com/chenrensong/SS.UnWxapkg
下了 NodeJS 版本的解包失败,Java 版本的成功了,而且要比 NodeJS 版本的简单很多
Java 版本的解包工具,dest 目录有可执行 jar 包下载
# 要有Java环境java -jar unweapp-0.1.jar "xxx.wxapkg"最终得到如下代码
伪造数据包再 game.js 文件中不难找到加密逻辑。就是对 json 排序后拼接,再 md5 加密
不难写出生成 sign 的代码,其中 appid 和 secret 是固定值
把抓包的数据放到 postman 中
修改 record 中的部分数据,生成 sign。同时到 postman 中对应修改下数据,同时修改 sign 为最新值
post 成功
重新打开游戏,发现数据已修改。如若失败是因为服务端数据还没下载到本地,本地的数据覆盖了服务端数据。最简单的办法是,当抓完包后,删除这个小程序,禁止它上传数据,当伪造数据 post 修改数据成功后,在下载下来,肯定是会先向服务端拿数据的
Java 版本的修改工具主程序
public static void main(String[] args) throws Exception { RequestBuilder rb = Requests.post("https://wxwyjh.chiji-h5.com/api/archive/get"); Map header = new HashMap(); header.put("content-type", "application/x-www-form-urlencoded"); header.put("User-Agent", "Mozilla/5.0 (Linux; Android 9; MIX 2S Build/PKQ1.180729.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MicroMessenger/7.0.3.1400(0x2700033B) Process/appbrand2 NetType/WIFI Language/zh_CN"); header.put("Host", "wxwyjh.chiji-h5.com"); rb.headers(header); Map data = new HashMap(); data.put("plat", "wx"); data.put("time", String.valueOf(new Date().getTime())); data.put("openid", "**************"); data.put("sign", sign(data)); rb.body(JSON.toJSONString(data)); Map currentData = rb.send().readToJson(Map.class); if (!currentData.get("code").toString().equals("0")) {throw new Exception("获取当前记录失败"); } System.out.println(currentData); Map data2 = new HashMap(); data2.put("plat", data.get("plat")); data2.put("time", String.valueOf(new Date().getTime())); data2.put("openid", data.get("openid")); Map temp = (Map) currentData.get("data"); // 不要打乱顺序, LinkedHashMap record = JSON.parseObject(temp.get("record").toString(), LinkedHashMap.class); // record.put("money", "9979029121"); data2.put("record", JSON.toJSONString(record)); data2.put("sign", sign(data2)); RequestBuilder rb2 = Requests.post("https://wxwyjh.chiji-h5.com/api/archive/upload"); rb2.headers(header); rb2.body(JSON.toJSONString(data2)); Map updatedData = rb2.send().readToJson(Map.class); if (!updatedData.get("code").toString().equals("0")) {throw new Exception("修改记录失败"); }}加密代码
public static String sign(Map map) { Map newMap = new HashMap(); List keys = new ArrayList(); for (String key : map.keySet()) {keys.add(key);newMap.put(key, map.get(key)); } newMap.put("wx_appid", "wxa2c324b63b2a9e5e"); newMap.put("wx_secret", "8fbd540d0b23197df1d5095f0d6ee46d"); keys.add("wx_appid"); keys.add("wx_secret"); Collections.sort(keys); StringBuilder sb = new StringBuilder(); for (String key : keys) {sb.append(key).append("=").append(newMap.get(key)).append("&"); } return HashKit.md5(sb.substring(0, sb.length() - 1));}