微信小游戏-海盗来了打金初体验

引子

假期在家空余时间, 发现微信小游戏突然火了, 群友推荐一款名为: 海盗来了 的小游戏
稍微体验了一把感觉很不错, 真正实现了微信对小程序的期望 —- 取代原生 app
得益于日益强大的 js 引擎, 在手机端也能做出很华丽的效果, 而且性能也不算很差
回到正题: 此款游戏有所谓金币的概念, 而获取金币的一个方式是不断的点击转动转盘
寻思如何让脚本来代替我们来干苦力, 便有此文

思路

我首先尝试用 fiddler 对目标进行刺探, 发现所有关键请求均做了 sign 签名机制
加入了时间戳来防止重放攻击, 可见通过简单的黑盒测试已经没办法获取更多信息了
便考虑从白盒角度来找问题, 而白盒的首要条件是拿到所谓源代码
这里我尝试了很多网上的解决方法, 一些说构造 url 进行下载的均以失败告终
只好用笨办法, 在 root 过的安卓机上去微信安装目录找小游戏缓存的源代码
顺利拿到源代码后就结合前面的一些信息进行继续查找
在前面我获得了请求的一些特定的参数 sign, t 等等
便以此为关键词全局搜索 js 文件, 找到疑似签名算法的方法, 这里贴一下具体代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function(e) {
e += "&secret=" + InitMark.secret;
// 这里的 InitMark.secret 是硬编码在 js 中的
// e = "clientVer=v2.0.78&isWxGame=true&t=1525007445&secret=418785a803d8e0d9"
var t = ""
, i = e.split("&");
i.sort();
for (var n = 0; n < i.length; n++)
t += i[n];
// dictionary order
// t = "clientVer=v2.0.78isWxGame=truesecret=418785a803d8e0d9t=1525007445"
1e4 == InitMark.uid && console.log("data = " + t);
var a = new md5;
return t = a.hex_md5(t)
}

不难看出是常规的 md5 加密, 快速写出 Python 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import requests
from collections import OrderedDict
from hashlib import md5
from time import time

uid = '183826980'


def get_signed_data(data):
data['secret'] = '418785a803d8e0d9'
data['isWxGame'] = 'true'
data['t'] = int(time())
data['sign'] = md5(''.join([
'{0}={1}'.format(index, value) for index, value in OrderedDict(sorted(data.items())).items()
]).encode()).hexdigest()
return data


while True:
res = requests.post('https://pirate-api.hortor002.com/game/roller/roll', get_signed_data({
'uid': uid,
'bet': '1'
})).json()
if res['errcode'] != 0:
if res['errcode'] == 20005:
# 体力透支
exit()
res = requests.post('https://pirate-api.hortor002.com/game/basic/player', get_signed_data({
'uid': uid
})).json()
if res['data']['lastRollerType'] == 3:
# 找出哪个是土豪
res = requests.post('https://pirate-api.hortor002.com/game/pvp/steal', get_signed_data({
'uid': uid,
'idx': '1'
})).json()
print(res)
elif res['data']['lastRollerType'] == 2:
# 攻击他人
res = requests.post('https://pirate-api.hortor002.com/game/pvp/attack', get_signed_data({
'uid': uid,
'puid': '165330045',
'building': '1'
})).json()
print(res)

其中 uid 是你自己的游戏 id, puid 是你想攻击的小伙伴的游戏 id

后记

其实整个流程并不难, 就是在找签名方法这一步花了很多时间
包括各种下断点, 运行, 再下断点, 运行……
很享受这种吃透游戏原理的过程 XD