这里直接进入算法查找主题,至于如何逆向小程序可以在GitHub上搜索wxunpack得知。
这里我就不重复展示抓包过程,抓包里面我们看到header里有nonceStr、sign
通过关键字直接搜索小程序源码得到关键部分:
if ("POST" === t) y.sign = r(d, m.url.replace(a.default.HOST, ""), p, v, S), m.data = d; else {
for (var h = m.url + "?", b = 0, w = Object.keys(d); b < w.length; b++) {
var P = w[b];
h += P + "=" + d[P] + "&";
}
h = h.substring(0, h.length - 1), m.url = h, y.sign = r({}, m.url.replace(a.default.HOST, ""), p, v, S);
}
我们看一下这2行代码的区别:
r(d, m.url.replace(a.default.HOST, ""), p, v, S)
r({}, m.url.replace(a.default.HOST, ""), p, v, S)
通过此处分析可以看到,如果t应该是存放的接口访问类型 POST/GET,如果是POST它调用的r函数的第一个参数是d,如果是GET则直接是{},由此得知d是一个post数据,连动态调试都没必要。
而r函数的实现过程则是一个拼接以及md5加密,如下方所示
function r(o, n, r, s, i) {
for (var u = "", c = 0, l = Object.keys(o).sort(); c < l.length; c++) {
var d = l[c], f = o[d];
if ("object" === e(f) && null !== f) {
var g = JSON.stringify(o[d]);
u += d + "=" + (g = g.split("").sort().join("")) + "&";
} else 0 === f || f ? u += d + "=" + o[d] + "&" : (o[d] = "", u += d + "=&");
}
return u += "url=" + n + "&", u += r ? "accessToken=" + r + "&" : "", u += "timestamp=" + s + "&",
u += "nonceStr=" + i + "&", u += "key=" + a.default.PLAM_KEY, t.md5Encrypt(u);
}
可以通过它的拼接猜出了这5个参数
1、post数据,如果是get则提交{}
2、url,但是是把host部分替换成空
3、r参数是accessToken,如果未登录状态应该是空的
4、v参数也很明显是一个timestamp时间戳,head里面也会包含
5、这个就是nonceStr,我们也需要知道这个参数是如何生成的。
nonceStr参数的由来 最后得出成品列子