[另类⽅式破解]⽀付宝的⼩程序sign验签参数算法
前段时间想到⽀付宝的⼀个做任务领集分宝的⼩程序…
挺好的,想要做⼀个获取到所有任务,然后全⾃动做任务的⼯具,抓包发现有sign验签,于是有了本帖
抓完才发现,整个⼩程序是⽤https传输数据的。
另类⽅式破解的⽬的
⼩⽩就要有⼩⽩的办法,咱们要让⼩程序投降,让他⾃⼰乖乖的把sign⽤到的所有参数都告诉我。
0x0⼿机环境
安卓11
K40稳定版/miui12/解锁BL
已刷⾯具(刷了Move Certificates)
LSPosed框架
0x1⽤到的⼯具
⼿机端
1. Drony 1.3.154 (作⽤:应该搭建梯⼦转发请求到指定ip:端⼝。下载地址:论坛内帖⼦:www.52pojie/thread-
1340770-1-1.html)
2. ⽀付宝
3. ⼩黄鸟抓包
4. MT管理器(搜索⽂件等⼯作)
电脑端
1. fiddler(以下部分地⽅会简称fd)
2. Notepad++(JSTool插件,⼀键美化/缩放JS代码)【可有可⽆】
3. 解压缩软件
0x2实现解密的过程
1.⽀付宝⼩程序抓包
⼩黄鸟抓包⿇烦,所以想换成fiddler+drony抓包
⼀开始⽤的是⼩黄鸟APP抓包,抓的挺全的,但是⽤注⼊器⽐较⿇烦,所以想着⽤电脑FD抓包,之前⽤过Drony,
但是换了安卓11之后旧版本获取不到wifi列表,所以更新了⼀下Drony,Drony怎么⽤之前已经讲过了,需要的话可以⾃⼰跳转:fiddler+drony抓包
配置好drony之后开启转发,电脑打开fd,⼿机打开⽀付宝APP,并进⼊⼩程序,fd抓到包
sign为6e2edd36a36df5609e71e22a6fb41987
任务列表get,就是在headers⾥⾯有sign/token/等信息。直接打开Task/list?会提⽰{"code":-2001,"msg":"签名错误"},就更加验证了sign是验签的想法,所以接下来我们要想办法得到sign值的算法。
2.从源码⼊⼿分析sign
拿到源码
按照上贴中的说法.tar ⽂件⾥⾯包括了⼩程序的源码,可恶的是MT竟然打不开(改ZIP后缀也打开失败),所以传到电脑⽤解压软件打开。果然是⼩程序的源码,有html和2个js⽂件
解压分析
全部解压到⽂件夹,搜索Task/list 发现2个JS中都包含了。但是我们依次打开搜索发现index.js中并不是Task,⽽是task。。未区分⼤⼩写字母,所以排除掉。
所以index.worker.js就成为了我们的⽬标,打开⽂件,再次搜索发现可以看得到调⽤了 ⽅法,由url看出2个参数的值全都是0,所以getApp().globalData.filter=0
然后搜索get: ⽅法
搜索get:,发现其中有⼀处疑似⽹络请求的代码再看看quest
搜索request:到request函数(其实⼀开始我是搜索sign,到的request函数,不过都差不多啦),upTaskInfo: function () { ({ url: "Task/list", data: { is_filter: 0, filter: getApp().globalData.filter }, login: !1, loading: !0 }).then((function (e) { var t //此处省略N 多代码 })).catch((function (e) {}))}
1
2
3
4
5
6
7
89
10
11
12
13
14
15HOST: s,API_ROOT: s + "/",API_VERSION: u,DEVICE_TYPE: r,APP_ID: c,get: function (e) { hod = "GET",quest(e)},post: function (e) { hod = "POST",quest(e)}
1
2
3
4
5
6
7
8
9
10
11
12
稍微分析⼀下,可得出request: function (e) { var n,u,r,c,l,d,m,p,h,g, v = this; if (1 == a.default.state.foo ? (this.HOST = "a.b", this.API_ROOT = "a.b/") : (this.HOST = s, this.API_ROOT = s + "/"), e = Object.assign({ data: {} },e), n = Date.parse(new Date) / 1e3 + "", u = il(1e4 * Math.random()) + "", r = f, -1 !== e.url.indexOf("Ad/record") && (e.data.filter = getApp().gl
假设检验的步骤for (d in l = l[1].split("&")) c[(m = l[d].split("="))[0]] = m[1]; e.url = l[0] } return Object.assign(e.data, c), Object.keys(e.data).forEach((function (t) { void 0 === e.data[t] && (e.data[t] = "") })), p = {}, Object.assign(p, e.data), p.appid = this.APP_ID, p.nonce = u, p.timestamp = n, p.os = this.DEVICE_TYPE, p.v = this.API_VERSION, p.token = r, p._url = this.API_ROOT + e.url.split("?")[0], h = "", Object.keys(p).sort().forEach((function (e) { h += e + p[e] })), g = (0, o.hexMD5)(de(h)), new Promise((function (a, o) { t.request({ url: v.API_ROOT + e.url, data: e.data, method: e.method ? e.method : "POST", header: { "Cache-Control": "no-cache", "Content-Type": "application/x-www-form-urlencoded", os: v.DEVICE_TYPE, appid: v.APP_ID, nonce: u, v: v.API_VERSION, timestamp: n, token: r, sign: g, "Adzone-Id": getApp().globalData.adzoneId
}, success: function (n) { -2e3 == de ? (v.login((function () { quest(e)) })), t.showToast({ content: "需要授权登录" })) : a(n) }, fail: function (e) { o(e) } }) }))}1
2
3
4
激励短信5去拉萨需要注意些什么
6太空人手表
7
8
9
10
11
12
13
14
15
16
17
18
19
20
0511是哪里的区号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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
修改JS 后放回⼿机原⽬录
PS:其实⼀开始我没想到这么多,我还以为sign就只是简单的字符串拼接然后加⼀个key,md5⼀下。。。以上均为⼩程序投降之后的分析我⼀开始不是分析JS来着,index.worker.js 修改了JS的代码,在request函数return之前,把所有的参数全都提⽰了⼀个遍,上代码:⼩程序⽂件校验失败,重新请求了index.worker.js 但是保存index.worker.js
放回.tar 压缩包,传到⼩程序⽬录后,重新打开⼩程序。⼩程序竟然重新加载了。(后来⼀看才发现,⽬录⾥⾯的cert.json
和sign.json 可能是验证⽂件md5之类的⽂件,发现修改后会重新请求)
但是fd中出现了index.worker.js 的请求… 那不⼀个样道理吗,所以⽤FD的⾃动响应(AutoResponder),返回修改后的JS。
那,这不就缴械了吗,sign为6e2edd36a36df5609e71e22a6fb41987
0x3结案⼩程序已经交出了钥匙
PS:每个接⼝的h值拼接的字符串不⼀样,但是直接⽤js的⽅法来说。
sign加密的步骤⼤约就是:每个接⼝的参数加上参数p的总和按照ascii码值⼤⼩顺序,然后value+key拼接,最后base64编码后,md5即为sign值Object.assign(e.data, c), Object.keys(e.data).forEach((fu
nction (t) { void 0 === e.data[t] && (e.data[t] = "") })), p = {}, Object.assign(p, e.data), p.appid = this.APP_ID, p.nonce = u, p.timestamp = n, p.os = this.DEVICE_TYPE, p.v = this.API_VERSION, p.token = r
h += e + p[e] }));g = (0, o.hexMD5)(de(h));//sign 的值g t.showModal({ title: "参数信息提⽰", content: 'request 参数e:' + JSON.stringify(data) + '\n\n 参数p:' + JSON.stringify(p) + '\n\np._url:' + p._url + '\n\nh:' + h + '\n\nbase64后sign 值:' + g, showCancel: !1,//变量data 已经在request 函数⼀开始就⽤e 赋值了 confirmText: "已阅,退下吧"})1披荆斩棘的哥哥成团夜播出时间
2
3
4
5
6
7
8
9
10
11
12
13
14
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论