一、声明
本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于贸易用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!
二、逆向目标
目标:得物小程序
目标接口:1.分类接口、2.分类接口商品信息
三、逆向分析
1、小程序抓包
保举WeChatOpenDevTools,WeChatOpenDevTools,window 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加密保持一致
四、效果
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |