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

诗林  金牌会员 | 2024-10-29 02:35:26 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 516|帖子 516|积分 1548

一、声明


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

二、逆向目标


目标:得物小程序
目标接口:1.分类接口、2.分类接口商品信息


三、逆向分析


1、小程序抓包

保举WeChatOpenDevTools,WeChatOpenDevTools,window wechat历史版本相比之前的微信开发者工具,方便了许多,可以直接用浏览器调试
提醒:用微信小号举行测试

现在自用版本:





2.小程序接口分析


2.1分类接口分析



只有一个加密参数sign
长度:32位
猜测:md5加密

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


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


case 3 加密参数sign还没有生成
case 5 已有响应数据生成
以是加密生成位置
  1. i.postRequest("/api/v1/h5/commodity/fire/search/doCategoryDetail", {
  2.                                     catId: n
  3.                                 }
复制代码
进入postRequest函数内部

进入 w.fetch(r)

  1. 简单说明一下代码含义
  2. 是一个处理HTTP请求和响应拦截器的逻辑
  3. this.interceptors.request.reducer 和 this.interceptors.response.reducer 是两个函数,分别用于处理请求拦截器和响应拦截器。
  4. u 是一个数组,用于存储处理成功(fulfilled)和处理失败(rejected)的回调函数。这些回调函数将会在拦截器处理时添加到数组中。
  5. 在请求拦截器中,成功和失败的回调函数被分别放到 u 数组的前两个位置(使用 unshift 方法),而在响应拦截器中,它们被放到 u 数组的末尾两个位置(使用 push 方法)。
  6. 接下来的循环 while (u.length) 确保在 u 数组中还有回调函数时继续执行。在每次循环中,从 u 数组中依次取出两个回调函数,并将它们依次应用到变量 s 上,这个变量最初可能是一个 Promise 或者一个初始的状态。
  7. s = s.then(u.shift(), u.shift()) 这一行代码的作用是,通过 then 方法将两个回调函数注册到 Promise 链中,u.shift() 会从 u 数组中取出并移除第一个元素(即成功回调),u.shift() 取出并移除第二个元素(即失败回调)。
  8. 最后,返回变量 s,这个变量代表了一个最终的 Promise 对象,它可能已经包含了一系列经过请求和响应拦截器处理后的结果。
  9. 综上所述,这段代码主要作用是使用拦截器函数来处理HTTP请求和响应,在这些操作中注册了一系列的处理函数,并且通过 Promise 链式调用确保了每个处理函数的顺序执行。
复制代码
进入哀求拦截中对应的函数,所有的参数加密都在其中,包含sign,data哀求体加密,都打上断点


拦截器的利用情势xxx.interceptors.request.use,xxx.interceptors.response.use
有的时候我们为了更快更好的定位可以直接搜索相干关键词





sign加密参数分析


sign加密值:固定salt:19bc545a393a25177083d4a748807cc0 + 将字典按照key排序和对应的处理后的值拼接成一个字符串做md5
  1. def get_sign(params):
  2.     # MD5加密,params字典参数列表
  3.     # 排序后的键列表
  4.     sorted_keys = sorted(params.keys())
  5.     # 拼接排序后的键和值
  6.     kv = ''.join(f"{key}{params[key]}" for key in sorted_keys)
  7.     salt = '19bc545a393a25177083d4a748807cc0'
  8.     str1 = f"{kv}{salt}"
  9.     md5_str = hashlib.md5(str1.encode("utf-8")).hexdigest()
  10.     return md5_str
复制代码


data加密参数分析



  1. Fun110: function (t, e, n) {
  2.                             var i = function (t, e) {
  3.                                     return t === e
  4.                                 },
  5.                                 o = function (t, e, n) {
  6.                                     return t(e, n)
  7.                                 },
  8.                                 a = function (t, e) {
  9.                                     return t / e
  10.                                 },
  11.                                 c = function (t, e) {
  12.                                     return t >> e
  13.                                 },
  14.                                 s = function (t, e) {
  15.                                     return t & e
  16.                                 },
  17.                                 u = function (t, e) {
  18.                                     return t + e
  19.                                 },
  20.                                 f = function (t, e) {
  21.                                     return t << e
  22.                                 };
  23.                             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;
  24.                             var l = o(L, 48, 16),
  25.                                 d = "",
  26.                                 p = "",
  27.                                 h = "0",
  28.                                 v = t;
  29.                             function g(t, e, n, r, i) {
  30.                                 return H(i - -695, e)
  31.                             }
  32.                             if ((e || g(-18, -816, -279, 6, -617)).toLocaleLowerCase() === H(971 - 75, 928))
  33.                                 try {
  34.                                     var _ = [],
  35.                                         y = JSON.parse(t);
  36.                                     Object.keys(y).map((function (t) {
  37.                                             return _.push(t + "=" + encodeURIComponent(y[t])),
  38.                                                 t
  39.                                         })),
  40.                                         v = _.join("&")
  41.                                 } catch (t) {}
  42.                             if ("0" === String($t))
  43.                                 return {
  44.                                     a: l,
  45.                                     b: o(L, 48, 16),
  46.                                     c: $t + "," + Ht,
  47.                                     d: t,
  48.                                     e: L(48, 16)
  49.                                 };
  50.                             try {
  51.                                 if (v) {
  52.                                     var m = q.enc.Utf8.parse(v);
  53.                                     d = q.MM.encrypt(m, q.enc.Utf8.parse(l.substr(10, 16)), {
  54.                                             iv: q.enc.Utf8.parse(l.substr(20, 16)),
  55.                                             mode: q.mode.CBC,
  56.                                             padding: q.pad.Pkcs7
  57.                                         }),
  58.                                         h = "1"
  59.                                 }
  60.                                 var b = l.split(""),
  61.                                     k = Number(a((new Date).valueOf(), 1e3).toFixed(0)).toString(16).toUpperCase().split("");
  62.                                 b.splice.apply(b, [40, 8].concat(r(k)));
  63.                                 var w = 0;
  64.                                 k.forEach((function (t, e) {
  65.                                         e > 3 && (w += t.charCodeAt())
  66.                                     })),
  67.                                     b.splice(w % 10, 1, 2);
  68.                                 var S, x, O = St.getKey(Kt).encrypt(b.join("")),
  69.                                     C = "";
  70.                                 for (S = 0; S + 3 <= O.length; S += 3)
  71.                                     x = parseInt(O.substring(S, S + 3), 16),
  72.                                     C += "" + Nt.charAt(c(x, 6)) + Nt.charAt(s(x, 63));
  73.                                 S + 1 == O.length ? (x = parseInt(O.substring(S, u(S, 1)), 16),
  74.                                         C += Nt.charAt(x << 2)) : u(S, 2) == O.length && (x = o(parseInt, O.substring(S, u(S, 2)), 16),
  75.                                         C += u(Nt.charAt(x >> 2), Nt.charAt(f(3 & x, 4)))),
  76.                                     p = C
  77.                             } catch (t) {
  78.                                 console.log(t),
  79.                                     d = v,
  80.                                     h = 2
  81.                             }
  82.                             var W = d ? d.ciphertext ? d.ciphertext.toString().toUpperCase() : d : "";
  83.                             return {
  84.                                 a: l,
  85.                                 b: L(48, 16),
  86.                                 c: h + "," + Ht,
  87.                                 d: JSON.stringify({
  88.                                     data: p + "​" + W
  89.                                 }),
  90.                                 e: o(L, 48, 16)
  91.                             }
  92.                         }
复制代码
分析p  和 w的值

p值

C赋值给p,C是通过O举行运算得到的
  1.      var S, x, O = St.getKey(Kt).encrypt(b.join("")), C = "";
  2.                         for (S = 0; S + 3 <= O.length; S += 3)
  3.                             x = parseInt(O.substring(S, S + 3), 16),
  4.                             C += "" + Nt.charAt(c(x, 6)) + Nt.charAt(s(x, 63));
  5.                         S + 1 == O.length ? (x = parseInt(O.substring(S, u(S, 1)), 16),
  6.                         C += Nt.charAt(x << 2)) : u(S, 2) == O.length && (x = o(parseInt, O.substring(S, u(S, 2)), 16),
  7.                         C += u(Nt.charAt(x >> 2), Nt.charAt(f(3 & x, 4)))),
  8.                         p = C
复制代码
 O是通过rsa加密得到的,传入参数是颠末一系列运算的随机生成的48位16进制数


RSA公钥的 modulus:00ca8d9830ba538887a4a19d88c1d93b2f6a228dcb61cfb05672d5efd20c5ee1b3492458e4b65091350fc0ce874d6f404c99e26c282f8765d2ede9b266160e7763
公钥的指数:010001

w值

  1.    d = q.MM.encrypt(m, q.enc.Utf8.parse(l.substr(10, 16)), {
  2.                                 iv: q.enc.Utf8.parse(l.substr(20, 16)),
  3.                                 mode: q.mode.CBC,
  4.                                 padding: q.pad.Pkcs7
  5.                             }),
复制代码
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加密保持一致



四、效果 




免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

诗林

金牌会员
这个人很懒什么都没写!

标签云

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