某付宝APP之某加油小程序对称加解密算法解析

前言


前几天发了一个某付宝小程序的sign参数md5加密拿到明文参数的帖子…
又发现一个别的小程序,好像是用的对称加密,耐不住好奇心,就试了试…结果成功实现了加解密的操作。遂发帖记录一下。

工具

  • fiddler【抓包工具】
  • Drony【转发工具,因为fiddler抓不到小程序的包,所以用Drony转发用fiddler能抓到包】
  • MT(或NP)管理器【文件管理】
  • Nodepad++【JS格式化+分析】

开始操作


Drony的配置和开启


之前就已经讲过了,就不再讲解了。想了解的可以跳转看一下:fiddler+drony抓包

拿到源码


用MT管理器在/data/user/0/com.eg.android.AlipayGphone/files/nebulaInstallApps/目录中直接搜索小程序的名字,找到小程序的目录
某付宝APP之某加油小程序对称加解密算法解析_第1张图片

[ps:随意修改或者用别的小程序的json文件替换改小程序的文件,再次打开小程序的时候会加载网页,通常情况下index.worker.js就是小程序的主要代码逻辑]
某付宝APP之某加油小程序对称加解密算法解析_第2张图片

操作+抓包


小程序端操作:输入手机号,点击获取验证码,FD搜到smsitfs/sendSms的抓包信息
密文为aNrKSihAtEQuPZr8qdxkxspWvzMjXwvunyoWxdKdqj8HPdxkxsxjtwrdtwYMnic8nwv4vzx1nwMuty7NnwqWOZndOsqjxHJ=
某付宝APP之某加油小程序对称加解密算法解析_第3张图片

请求密文JS加密分析


sendSms接口分析

JS中搜索smsitfs/sendSms,找到变量sendSms
某付宝APP之某加油小程序对称加解密算法解析_第4张图片

sendSms: i.default.BASE_QUANGUO_URL + "smsitfs/sendSms",

全词匹配搜索sendSms,发现有4处调用位置,且均为getCode的函数名,看名字就知道我们是找对了,取出其中一个并小小的分析一下

getCode: function () {
    this.countDown();
    var e = {
        phoneNumber: this.data.phoneNumber
    };
    e.sign = f.default.sortAndStringfy(e, !0);//e的值{"phoneNumber": "183xxxx548", sign: "MD5操作之后的值"}
    (0, l.default)(c.default.sendSms, {
        isStr: !0,
        data: f.default.transpositionEncryptNew((0, r.default)({}, e), !1)
    }).then(function (e) {
        var t = f.default.transpositionDecryptNew(e);
        if (t) {
            var a = JSON.parse(t);
            console.log(a),
            1 === a.retCode ? (0, o.default)("获取成功!", "success") : (0, o.default)(a.msg)
        }
    })
},

可得出流程:
某付宝APP之某加油小程序对称加解密算法解析_第5张图片

先分析获取e.sign的sortAndStringfy函数

搜索sortAndStringfy:到

t.default = {
    transpositionEncryptNew: ae,
    transpositionDecryptNew: ie,
    sortAndStringfy: re
},
e.exports = t.default

加密函数transpositionEncryptNew=ae
解密函数transpositionDecryptNew=ie
也就是re函数就是sortAndStringfy函数,如下。

function re(e, t) {//根据传参可得e={'phoneNumber':'手机号'} , t = !0;
    var a = new Array,
    n = Object.keys(e);
    n.sort();
    for (var i = 0, r = n.length; i < r; i++) {
        var o = e[n[i]],
        s = [n[i]] + "=" + o;
        a.push(s)
    }
    return t ? y.default.hexMD5(C.Base64.encode("&" + a.join("&"))) : a.join("&") + "&key=" + L
}

果然是MD5加密,枚举变量e,a = [value + “=” + 手机号],re函数的返回值为md5(base64编码("&" + a.join("&")))

再分析下加密ae函数

拿到sign的加密方法之后,赋值e.sign后拿到完整的参数e:{“phoneNumber”: “手机号”, sign: “re操作之后的值”}

ae函数

搜索function ae(,拿到ae函数:

function ae(e, t) {
    if (t) {
        var a = JSON.stringify(e);
        return X(G(), a)
    }
    var n = C.Base64.encode(JSON.stringify(e));//Base64编码
    return X(G(), n)
}
函数X和函数G

发现一个函数X和函数G
分别搜索function X(function G(,拿到X和G的函数:

function X(e, t) {
    for (var a = Z(t), n = new Array, i = 0; i < a.length; i++) {
        var r = e.get(a[i]);
        r ? n.splice(i, 1, r) : n.splice(i, 1, a[i])
    }
    return ee(n)
}
function G() {
    var e = new Map,
    t = Z(U),
    a = Z(q),
    n = t.length;
    t.length != a.length && console.log("密钥和原字符长度不一致!");
    for (var i = 0; i < n; i++)
        e.set(t[i], a[i]);
    return e
}
函数ee和函数Z

又发现一个函数ee和函数Z,还有变量U和q
继续搜索搜索function ee(function Z(,拿到ee和Z的函数:

function Z(e) {
    var t,
    a = new Array,
    n = void 0;
    t = e.length;
    for (var i = 0; i < t; i++)
        (n = e.charCodeAt(i)) >= 65536 && n <= 1114111 ? (a.push(n >> 18 & 7 | 240), a.push(n >> 12 & 63 | 128), a.push(n >> 6 & 63 | 128), a.push(63 & n | 128)) : n >= 2048 && n <= 65535 ? (a.push(n >> 12 & 15 | 224), a.push(n >> 6 & 63 | 128), a.push(63 & n | 128)) : n >= 128 && n <= 2047 ? (a.push(n >> 6 & 31 | 192), a.push(63 & n | 128)) : a.push(255 & n);
    return a
}
function ee(e) {
    if ("string" === typeof e)
        return e;
    for (var t = "", a = e, n = 0; n < a.length; n++) {
        var i = a[n].toString(2),
        r = i.match(/^1+?(?=0)/);
        if (r && 8 == i.length) {
            for (var o = r[0].length, s = a[n].toString(2).slice(7 - o), l = 1; l < o; l++)
                s += a[l + n].toString(2).slice(2);
            t += String.fromCharCode(parseInt(s, 2)),
            n += o - 1
        } else
            t += String.fromCharCode(a[n])
    }
    return t
}
变量U和q

U = “ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890”,
q = “752wpRiLxrbDvnXgocTyEmZVOtSPqYalf9dsM8IH6GC0FeA3K1Nzuj4WQkBUhJ”;

顺便在附近还拿到了变量J和变量$…顺手牵羊吗?

整合加密代码并在浏览器中执行

由于代码中有md5和base64,而且base64解码用window.atob的时候有中文会乱码,
所以百度搜了一段md5函数和base64编码解码的函数,并替换小程序中的原方法。

执行var t={"phoneNumber":"183XXXX48"};t.sign=re(t,1);ae(t)加密
某付宝APP之某加油小程序对称加解密算法解析_第6张图片

结果为aNrKSihAtEQuPZr8qdxkxspWvzMjXwvunyoWxdKdqj8HPdxkxsxjtwrdtwYMnic8nwv4vzx1nwMuty7NnwqWOZndOsqjxHJ=
和fiddler的抓包结果是一样的,说明加密是有效的。

接口请求返回密文JS解密分析

和加密分析一样,之前我们得出解密函数transpositionDecryptNew=ie,依次找出用到的函数和变量

函数ie

function ie(e, t) {
    if (t)
        return X(Q(t), C.Base64.decode(e));
    var a = X(Q(), e);
    return C.Base64.decode(a)
}

函数X和函数Q

//函数X、函数Z、函数ee,变量U和q,刚才的加密已经有了,所以不再需要了
function Q(e) {
    var t = new Map,
    a = Z(e || U),
    n = Z(q),
    i = a.length;
    a.length != n.length && console.log("密钥和原字符长度不一致!");
    for (var r = 0; r < i; r++)
        t.set(a[r], n[r]);
    return t
}

整合代码,执行解密post返回密文

某付宝APP之某加油小程序对称加解密算法解析_第7张图片

JS加解密源码下载地址


请使用AES/CBC/pkcs7/128位

q = "752wpRiLxrbDvnXgocTyEmZVOtSPqYalf9dsM8IH6GC0FeA3K1Nzuj4WQkBUhJ";
key=q.substr(1,16);iv=q.substr(16,16);
下载地址 :7arhyjZbN3nihvyFZtrJd+N8xXMNL2Ckx4STQfESptLuLPjB/nSBphOi1legar9ZO9SD1fL5CcTshPIj6fdzDvBvy5KXS7x+hgzAA7yVL0o=

你可能感兴趣的:(JavaScript,javascript,算法)