吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 10432|回复: 49
收起左侧

[Android 原创] [另类方式破解]支付宝的小程序sign验签参数算法

[复制链接]
闷骚小贱男 发表于 2021-7-26 09:34
本帖最后由 闷骚小贱男 于 2021-7-26 09:42 编辑

前段时间想到支付宝的一个做任务领集分宝的小程序...
挺好的,想要做一个获取到所有任务,然后全自动做任务的工具,抓包发现有sign验签,于是有了本帖
抓完才发现,整个小程序是用https传输数据的。

另类方式破解的目的


小白就要有小白的办法,咱们要让小程序投降,让他自己乖乖的把sign用到的所有参数都告诉我。

0x0手机环境


  • 安卓11
  • K40稳定版/miui12/解锁BL
  • 已刷面具(刷了Move Certificates)
  • LSPosed框架

0x1用到的工具


  • 手机端

    1. Drony 1.3.154  (作用:应该搭建梯子转发请求到指定ip:端口。下载地址:论坛内帖子:https://www.52pojie.cn/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抓包(https://www.52pojie.cn/thread-1358606-1-1.html#36585369_fiddler+drony抓包)

fiddler+drony抓包

配置好drony之后开启转发,电脑打开fd,手机打开支付宝APP,并进入小程序,fd抓到包
sign为6e2edd36a36df5609e71e22a6fb41987
0.1 fd抓包.jpg

任务列表get,就是在headers里面有sign/token/等信息。
直接打开Task/list?会提示{"code":-2001,"msg":"签名错误"},就更加验证了sign是验签的想法,所以接下来我们要想办法得到sign值的算法。

2.从源码入手分析sign

在论坛内搜了以下“支付宝小程序”结果搜到一个19年的源码获取的帖子:
支付宝小程序抓包与源码获取(https://www.52pojie.cn/forum.php?mod=viewthread&tid=1050690
没想到21年了,竟然还有效。。。

拿到源码

于是用MT管理器在/data/user/0/com.eg.android.AlipayGphone/files/nebulaInstallApps/目录中直接搜索小程序的名字,果然搜到了2个文件
0.2 MT搜源码.jpg
按照上贴中的说法.tar文件里面包括了小程序的源码,可恶的是MT竟然打不开(改ZIP后缀也打开失败),所以传到电脑用解压软件打开。
果然是小程序的源码,有html和2个js文件
0.3 解压源码.jpg

解压分析

全部解压到文件夹,搜索Task/list发现2个JS中都包含了。
0.4 搜人物列表.jpg
但是我们依次打开搜索发现index.js中并不是Task,而是task。。未区分大小写字母,所以排除掉。
所以index.worker.js就成为了我们的目标,打开文件,再次搜索发现

upTaskInfo: function () {
    s.default.get({
        url: "Task/list",
        data: {
            is_filter: 0,
            filter: getApp().globalData.filter
        },
        login: !1,
        loading: !0
    }).then((function (e) {
            var t
            //此处省略N多代码
        })).catch((function (e) {}))
}

可以看得到调用了s.default.get方法,由url看出2个参数的值全都是0,所以getApp().globalData.filter=0
然后搜索get:

s.default.get方法

搜索get:,发现其中有一处疑似网络请求的代码

HOST: s,
API_ROOT: s + "/",
API_VERSION: u,
DEVICE_TYPE: r,
APP_ID: c,
get: function (e) {
    return e.method = "GET",this.request(e)
},
post: function (e) {
    return e.method = "POST",this.request(e)
}

再看看this.request

搜索request:找到request函数(其实一开始我是搜索sign,找到的request函数,不过都差不多啦),

request: function (e) {
    var n,u,r,c,l,d,m,p,h,g,
    v = this;
    if (1 == a.default.state.foo ? (this.HOST = "https://a.b.com", this.API_ROOT = "https://a.b.com/") :
        (this.HOST = s, this.API_ROOT = s + "/"), e = Object.assign({
            data: {}
        },e), n = Date.parse(new Date) / 1e3 + "", u = Math.ceil(1e4 * Math.random()) + "", r = f, -1 !== e.url.indexOf("Ad/record") && (e.data.filter = getApp().globalData.filter), c = {}, "string" == typeof(l = e.url.split("?"))[1]) {
        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)(i.Base64.encode(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 == n.data.code ? (v.login((function () {
                                a(v.request(e))
                            })), t.showToast({
                            content: "需要授权登录"
                        })) : a(n)
                },
                fail: function (e) {
                    o(e)
                }
            })
        }))
}

稍微分析一下,可得出
0.5 树状图.jpg

修改JS后放回手机原目录

PS:其实一开始我没想到这么多,我还以为sign就只是简单的字符串拼接然后加一个key,md5一下。。。以上均为小程序投降之后的分析
我一开始不是分析JS来着,index.worker.js修改了JS的代码,在request函数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)(i.Base64.encode(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: "已阅,退下吧"
})

小程序文件校验失败,重新请求了index.worker.js

但是保存index.worker.js放回.tar压缩包,传到小程序目录后,重新打开小程序。小程序竟然重新加载了。(后来一看才发现,目录里面的cert.jsonsign.json可能是验证文件md5之类的文件,发现修改后会重新请求)
0.8 FD抓到js请求.jpg
但是fd中出现了index.worker.js的请求... 那不一个样道理吗,所以用FD的自动响应(AutoResponder),返回修改后的JS。
0.6 FD响应.jpg

那,这不就缴械了吗,sign为6e2edd36a36df5609e71e22a6fb41987
0.7 小程序真乖.jpg

0x3结案小程序已经交出了钥匙


PS:每个接口的h值拼接的字符串不一样,但是直接用js的方法来说。
sign加密的步骤大约就是:每个接口的参数加上参数p的总和按照ascii码值大小顺序,然后value+key拼接,最后base64编码后,md5即为sign值

免费评分

参与人数 11威望 +1 吾爱币 +28 热心值 +9 收起 理由
Tacom + 1 谢谢@Thanks!
qinglin9 + 1 + 1 我很赞同!
chenkeai深蓝 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
侃遍天下无二人 + 2 + 1 --------
qtfreet00 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
20210721 + 1 我很赞同!
Courser + 1 我很赞同!
qc123 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
笙若 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
正己 + 2 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
nan1204 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 闷骚小贱男 发表于 2021-7-26 17:59
本帖最后由 闷骚小贱男 于 2021-7-26 20:45 编辑

帖子可能触发了审核的关键词...所以我现在是能不编辑帖子就不编辑帖子了..
用易语言写了获取任务列表+点击任务+提交任务的一个小程序,运行输出的截图如下。
1.0.jpg
psych1 发表于 2021-12-22 17:06
闷骚小贱男 发表于 2021-12-22 16:58
官方的我也不会,这个不是官方的小程序FD和小黄鸟都能抓到。(低版本)

就是支付宝里面的小程序,比如某某基金号小程序这种类型的,FD和小黄鸟都可以直接抓到对吧
duidui538 发表于 2021-7-26 11:48
正己 发表于 2021-7-26 12:55
大佬tql
唱唱 发表于 2021-7-26 14:00
有点厉害,学习了。
xingqiji321 发表于 2021-7-26 16:31
一脸蒙蔽的进来,满脸蒙蔽的走!不是我玩的
masker_k 发表于 2021-7-26 16:54
大佬牛逼啊
杨辣子 发表于 2021-7-26 17:17
我拷,兄弟,你这操作真刑啊!
qc123 发表于 2021-7-26 17:47
厉害厉害
Tamluo 发表于 2021-7-26 18:20
来了来了,学习中,好东西
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 13:02

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表