得物小程序sign、data参数加密、响应体解密算法还原

一、声明


本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!

二、逆向目标


目标:得物小程序

目标接口:1.分类接口、2.分类接口商品信息



三、逆向分析

1、小程序抓包

推荐WeChatOpenDevToolsWeChatOpenDevToolswindow wechat历史版本相比之前的微信开发者工具,方便了很多,可以直接用浏览器调试

提醒:用微信小号进行测试

目前自用版本:

2.小程序接口分析

2.1分类接口分析

只有一个加密参数sign

长度:32位

猜测:md5加密

验证

1. 最快的方式在全局搜索sign,但是搜索过程中卡住,一直没有出现搜索结果,在后续分析验证是有sign这个关键字

2. 搜索方式不行,我们直接堆栈追踪

case 3 加密参数sign还没有生成

case 5 已有响应数据生成

所以加密生成位置

 i.postRequest("/api/v1/h5/commodity/fire/search/doCategoryDetail", {
                                    catId: n
                                }

进入postRequest函数内部

进入 w.fetch(r)

简单说明一下代码含义

是一个处理HTTP请求和响应拦截器的逻辑

this.interceptors.request.reducer 和 this.interceptors.response.reducer 是两个函数,分别用于处理请求拦截器和响应拦截器。

u 是一个数组,用于存储处理成功(fulfilled)和处理失败(rejected)的回调函数。这些回调函数将会在拦截器处理时添加到数组中。

在请求拦截器中,成功和失败的回调函数被分别放到 u 数组的前两个位置(使用 unshift 方法),而在响应拦截器中,它们被放到 u 数组的末尾两个位置(使用 push 方法)。

接下来的循环 while (u.length) 确保在 u 数组中还有回调函数时继续执行。在每次循环中,从 u 数组中依次取出两个回调函数,并将它们依次应用到变量 s 上,这个变量最初可能是一个 Promise 或者一个初始的状态。

s = s.then(u.shift(), u.shift()) 这一行代码的作用是,通过 then 方法将两个回调函数注册到 Promise 链中,u.shift() 会从 u 数组中取出并移除第一个元素(即成功回调),u.shift() 取出并移除第二个元素(即失败回调)。

最后,返回变量 s,这个变量代表了一个最终的 Promise 对象,它可能已经包含了一系列经过请求和响应拦截器处理后的结果。

综上所述,这段代码主要作用是使用拦截器函数来处理HTTP请求和响应,在这些操作中注册了一系列的处理函数,并且通过 Promise 链式调用确保了每个处理函数的顺序执行。

进入请求拦截中对应的函数,所有的参数加密都在其中,包含sign,data请求体加密,都打上断点

拦截器的使用形式xxx.interceptors.request.use,xxx.interceptors.response.use

有的时候我们为了更快更好的定位可以直接搜索相关关键词

sign加密参数分析

sign加密值:固定salt:19bc545a393a25177083d4a748807cc0 + 将字典按照key排序和对应的处理后的值拼接成一个字符串做md5

def get_sign(params):
    # MD5加密,params字典参数列表
    # 排序后的键列表
    sorted_keys = sorted(params.keys())
    # 拼接排序后的键和值
    kv = ''.join(f"{key}{params[key]}" for key in sorted_keys)
    salt = '19bc545a393a25177083d4a748807cc0'
    str1 = f"{kv}{salt}"
    md5_str = hashlib.md5(str1.encode("utf-8")).hexdigest()
    return md5_str

data加密参数分析

Fun110: function (t, e, n) {
                            var i = function (t, e) {
                                    return t === e
                                },
                                o = function (t, e, n) {
                                    return t(e, n)
                                },
                                a = function (t, e) {
                                    return t / e
                                },
                                c = function (t, e) {
                                    return t >> e
                                },
                                s = function (t, e) {
                                    return t & e
                                },
                                u = function (t, e) {
                                    return t + e
                                },
                                f = function (t, e) {
                                    return t << e
                                };
                            n === "xw".split("").reverse().join("") ? wx : "qq" === n ? qq : i(n, "dy") ? tt : i(n, "bd") ? swan : n === g(193, -6, 289, -185, 244) && my;
                            var l = o(L, 48, 16),
                                d = "",
                                p = "",
                                h = "0",
                                v = t;

                            function g(t, e, n, r, i) {
                                return H(i - -695, e)
                            }
                            if ((e || g(-18, -816, -279, 6, -617)).toLocaleLowerCase() === H(971 - 75, 928))
                                try {
                                    var _ = [],
                                        y = JSON.parse(t);
                                    Object.keys(y).map((function (t) {
                                            return _.push(t + "=" + encodeURIComponent(y[t])),
                                                t
                                        })),
                                        v = _.join("&")
                                } catch (t) {}
                            if ("0" === String($t))
                                return {
                                    a: l,
                                    b: o(L, 48, 16),
                                    c: $t + "," + Ht,
                                    d: t,
                                    e: L(48, 16)
                                };
                            try {
                                if (v) {
                                    var m = q.enc.Utf8.parse(v);
                                    d = q.MM.encrypt(m, q.enc.Utf8.parse(l.substr(10, 16)), {
                                            iv: q.enc.Utf8.parse(l.substr(20, 16)),
                                            mode: q.mode.CBC,
                                            padding: q.pad.Pkcs7
                                        }),
                                        h = "1"
                                }
                                var b = l.split(""),
                                    k = Number(a((new Date).valueOf(), 1e3).toFixed(0)).toString(16).toUpperCase().split("");
                                b.splice.apply(b, [40, 8].concat(r(k)));
                                var w = 0;
                                k.forEach((function (t, e) {
                                        e > 3 && (w += t.charCodeAt())
                                    })),
                                    b.splice(w % 10, 1, 2);
                                var S, x, O = St.getKey(Kt).encrypt(b.join("")),
                                    C = "";
                                for (S = 0; S + 3 <= O.length; S += 3)
                                    x = parseInt(O.substring(S, S + 3), 16),
                                    C += "" + Nt.charAt(c(x, 6)) + Nt.charAt(s(x, 63));
                                S + 1 == O.length ? (x = parseInt(O.substring(S, u(S, 1)), 16),
                                        C += Nt.charAt(x << 2)) : u(S, 2) == O.length && (x = o(parseInt, O.substring(S, u(S, 2)), 16),
                                        C += u(Nt.charAt(x >> 2), Nt.charAt(f(3 & x, 4)))),
                                    p = C
                            } catch (t) {
                                console.log(t),
                                    d = v,
                                    h = 2
                            }
                            var W = d ? d.ciphertext ? d.ciphertext.toString().toUpperCase() : d : "";
                            return {
                                a: l,
                                b: L(48, 16),
                                c: h + "," + Ht,
                                d: JSON.stringify({
                                    data: p + "​" + W
                                }),
                                e: o(L, 48, 16)
                            }
                        }

分析p  和 w的值

p值

C赋值给p,C是通过O进行运算得到的

     var S, x, O = St.getKey(Kt).encrypt(b.join("")), C = "";
                        for (S = 0; S + 3 <= O.length; S += 3)
                            x = parseInt(O.substring(S, S + 3), 16),
                            C += "" + Nt.charAt(c(x, 6)) + Nt.charAt(s(x, 63));
                        S + 1 == O.length ? (x = parseInt(O.substring(S, u(S, 1)), 16),
                        C += Nt.charAt(x << 2)) : u(S, 2) == O.length && (x = o(parseInt, O.substring(S, u(S, 2)), 16),
                        C += u(Nt.charAt(x >> 2), Nt.charAt(f(3 & x, 4)))),
                        p = C

 O是通过rsa加密得到的,传入参数是经过一系列运算的随机生成的48位16进制数


RSA公钥的 modulus:00ca8d9830ba538887a4a19d88c1d93b2f6a228dcb61cfb05672d5efd20c5ee1b3492458e4b65091350fc0ce874d6f404c99e26c282f8765d2ede9b266160e7763

公钥的指数:010001

w值
   d = q.MM.encrypt(m, q.enc.Utf8.parse(l.substr(10, 16)), {
                                iv: q.enc.Utf8.parse(l.substr(20, 16)),
                                mode: q.mode.CBC,
                                padding: q.pad.Pkcs7
                            }),

w值是经过aes 加密得到的

l 是 随机生成的48位16进制字符串

key:是从l中截取10至10+16

iv:是从l中截取20至20+16

p的值保持固定不变也没有关系

只需要注意请求参数data中aes中加密的key和iv的值和响应体解密aes中key和iv的值保持一直就可以

响应体解密

key 和 iv与aes加密保持一致

四、效果 


  • 33
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
RSA 加解密算法和 RSA 签名验证算法都是基于公钥加密算法,需要使用 OpenSSL 库中提供的 RSA 函数来实现。以下是使用 OpenSSL 编写 RSA 加解密算法和 RSA 签名验证算法的步骤: 1. 生成 RSA 密钥对 使用 OpenSSL 的 RSA_generate_key 函数可以生成 RSA 密钥对,示例代码如下: ```c RSA *rsa = RSA_new(); BIGNUM *e = BN_new(); int bits = 2048; unsigned long exponent = RSA_F4; BN_set_word(e, exponent); RSA_generate_key_ex(rsa, bits, e, NULL); ``` 2. RSA 加密 使用 OpenSSL 的 RSA_public_encrypt 函数可以对数据进行 RSA 公钥加密,示例代码如下: ```c int len = RSA_public_encrypt(data_len, data, encrypted, rsa, RSA_PKCS1_PADDING); ``` 其中,data 是要加密的数据,data_len 是数据长度,encrypted 是加密后的数据缓冲区,rsa 是 RSA 公钥。 3. RSA 解密 使用 OpenSSL 的 RSA_private_decrypt 函数可以对数据进行 RSA 私钥解密,示例代码如下: ```c int len = RSA_private_decrypt(encrypted_len, encrypted, decrypted, rsa, RSA_PKCS1_PADDING); ``` 其中,encrypted 是加密后的数据,encrypted_len 是数据长度,decrypted 是解密后的数据缓冲区,rsa 是 RSA 私钥。 4. RSA 签名 使用 OpenSSL 的 RSA_sign 函数可以对数据进行 RSA 签名,示例代码如下: ```c unsigned int sig_len; unsigned char sig[256]; int ret = RSA_sign(NID_sha256, data, data_len, sig, &sig_len, rsa); ``` 其中,data 是要签名的数据,data_len 是数据长度,sig 是签名后的数据缓冲区,rsa 是 RSA 私钥。 5. RSA 验证签名 使用 OpenSSL 的 RSA_verify 函数可以对数据进行 RSA 验证签名,示例代码如下: ```c int ret = RSA_verify(NID_sha256, data, data_len, sig, sig_len, rsa); ``` 其中,data 是要验证签名的数据,data_len 是数据长度,sig 是签名数据,sig_len 是签名数据长度,rsa 是 RSA 公钥。 需要注意的是,以上示例代码仅为参考,实际使用时需要根据具情况进行修改和完善。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CgfFan

感谢看官老爷赏的咖啡钱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值