当前位置: 首页 > news >正文

参数跟丢了之JS生成器和包装器

如需转载请注明出处.欢迎小伙伴一起讨论技术.

逆向网址:aHR0cHM6Ly91bmlvbi5qZC5jb20vcHJvTWFuYWdlci9pbmRleD9wYWdlTm89MQ==

跟踪接口:aHR0cHM6Ly9hcGkubS5qZC5jb20vYXBp

跟踪参数:h5st

本文目标:记录学习下自定义的生成器和包装器,不做具体的参数加密逻辑分析

直接启动器进入,跟战后找到以下代码位置.

问题:跟栈的时候在case20的位置找到最终h5st的结果值,再往上跟栈找不到生成和拼接h5st的位置

那么就尝试理解下这段代码

function X() {return (X = (0,u.Z)(h().mark((function e(t) {var n, o, a, i, r, l, s, c, d, u, p, f, g, v, m, b, x, w, _, y, C;return h().wrap((function (e) {for (; ;)switch (e.prev = e.next) {case 0:return n = t.functionId,o = t.method,a = void 0 === o ? "GET" : o,i = t.params,r = t.isEncode,l = void 0 === r || r,s = t.needCode,c = void 0 !== s && s,d = t.appid,u = void 0 === d ? M.ZP.APP_ID.UNION_PC : d,p = t.payload,f = void 0 === p ? {} : p,g = "https://api.m.jd.com/api?",v = $().get("__jda"),m = null == v ? void 0 : v.split(".")[1],b = {functionId: n,appid: u,_: Date.now(),loginType: "3",uuid: m,"x-api-eid-token": Q},e.prev = 5,x = new window.ParamsSign({appId: "586ae"}),i = H(H({}, i), {}, {clientPageId: "jingfen_pc"}),w = {functionId: n,appid: u,body: F()(k()(i)).toString()},e.next = 12,x.sign(w);case 12:_ = e.sent,y = _.h5st,b = H(H({}, b), {}, {h5st: encodeURI(y)}),e.next = 20;break;case 17:e.prev = 17,e.t0 = e.catch(5),console.log(e.t0);case 20:"POST" === a ? (C = "body=".concat(l ? encodeURIComponent(k()(i)) : k()(i)),f.data = C) : b.body = l ? encodeURIComponent(k()(i)) : i,g += (0,Z.L7)(b),f.extendParams || (f.extendParams = {});try {n && (f.extendParams.functionId = n),i && i.funName && (f.extendParams.funName = i.funName)} catch (e) {console.log("error: ", e)}return e.next = 26,J(H(H({method: a,url: g}, f), {}, {withCredentials: !0,needCode: c})).then((function (e) {return !e.page && e.pageNo && (e.page = {pageNo: e.pageNo,pageSize: e.pageSize,hasNext: e.hasNext,totalCount: e.total || e.totalNum}),e}));case 26:return e.abrupt("return", e.sent);case 27:case "end":return e.stop()}}), e, null, [[5, 17]])})))).apply(this, arguments)
}

知识点1:    (0,u.Z),这种写法;

        作用1,在 JavaScript 中,u.Z 是一个函数。如果你直接调用 u.z(),那么 u将成为函数 Z的上下文(即 this),而 (0, u.Z) 的写法可以确保 u.Z 在全局上下文或其他上下文中被调用,避免 this 被意外改变

        作用2,如果代码经过工具(比如 Babel)处理,它可能将一些较复杂的函数调用转化为 (0, u.Z) 形式。这样做的目的是保证代码在不同环境下都能正常工作,特别是在模块系统中,有时需要显式地调用函数而不是通过方法调用

知识点2:h().mark函数,进入mark函数,扣下主要代码

var h = "suspendedStart", d = "suspendedYield", f = "executing", p = "completed", v = {};
function g() { }
function m() { }
function b() { }
var y = {};
s(y, i, (function () {return this
}
));
//E的原型是一个数组
var w = Object.getPrototypeOf, _ = w && w(w(M([])));
_ && _ !== n && o.call(_, i) && (y = _);
var E = b.prototype = g.prototype = Object.create(y);
//...省略一大段
t.mark = function (t) {return Object.setPrototypeOf ? Object.setPrototypeOf(t, b) : (t.__proto__ = b,s(t, l, "GeneratorFunction")),//返回一个对象,设置该对象继承E的原型t.prototype = Object.create(E),t
}

从上面可以看出,最终t是返回一个生成器函数

知识点3:h().wrap,扣下主要代码

//包装器
function c(t, e, n, o) {var r = e && e.prototype instanceof g ? e : g, i = Object.create(r.prototype), a = new C(o || []);//生成器的核心逻辑return i._invoke = function (t, e, n) {//o为记录状态,next、throw 或 returnvar o = h;return function (r, i) {if (o === f)throw new Error("Generator is already running");if (o === p) {if ("throw" === r)throw i;return A()}for (n.method = r,n.arg = i; ;) {var a = n.delegate;if (a) {var l = O(a, n);if (l) {if (l === v)continue;return l}}if ("next" === n.method)n.sent = n._sent = n.arg;else if ("throw" === n.method) {if (o === h)throw o = p,n.arg;n.dispatchException(n.arg)} else"return" === n.method && n.abrupt("return", n.arg);o = f;//代用传下来的函数,在u中调用var s = u(t, e, n);if ("normal" === s.type) {if (o = n.done ? p : d,s.arg === v)continue;return {value: s.arg,done: n.done}}"throw" === s.type && (o = p,n.method = "throw",n.arg = s.arg)}}}(t, n, a),i
}
function u(t, e, n) {try {return {type: "normal",//最终调用位置,使用call方法arg: t.call(e, n)}} catch (t) {return {type: "throw",arg: t}}
}
//把包装器暴露c函数,让外部使用wrap方法调用
t.wrap = c;

wrap方法是一个包装器,里面封装了一个生成器

那么理解了关键的两个函数mark和wrap,大概就知道wrap里面的参数中的匿名函数什么时候执行

a 使用next方法每次调用生成器,进入生成器i._invoke

b 生成器内部调用u函数,最后使用call方法调用匿名函数

c 在匿名函数中每个case的结尾都会定义下一次执行的case

最后推测h5st参数是在匿名函数中case0位置生成,但是在case0代码块并没有发现拼接h5st参数的位置,而关键点是在window.ParamsSign这个类中,关键的加密逻辑都在里面

最终的生成结果会在s对象的PromiseResult属性中,这也是很坑的,很容易看不到导致跟丢了参数;

就可以回答开始提出的问题,在case20处可以看到h5st的结果,case处没有找到拼接h5st处的地


http://www.mrgr.cn/news/67139.html

相关文章:

  • Day12合并两个有序数组
  • SpringAOP技术
  • Flutter 鸿蒙next版本:自定义对话框与表单验证的动态反馈与错误处理
  • MySQL中的行转列和列转行操作
  • 线程函数和线程启动的几种不同形式
  • 文献组会汇报:Cys响应机理以及核探针设计(一)
  • [ DOS 命令基础 2 ] DOS 命令详解-网络相关命令
  • 【英特尔IA-32架构软件开发者开发手册第3卷:系统编程指南】2001年版翻译,2-15
  • 前端性能优化2
  • hive函数
  • Python小白学习教程从入门到入坑------第二十七课 魔法方法(语法进阶)
  • 【51蛋骗鸡16路电子开关编程CD4067使用switch】2021-12-27
  • leetcode刷题-回溯算法01
  • @Async注解提升Spring Boot项目中API接口并发能力
  • Redis主从复制
  • 华为海思招聘-芯片与器件设计工程师-模拟芯片方向- 机试题-真题套题题目——共8套(每套四十题)
  • 『VUE』20. 组件嵌套关系page(详细图文注释)
  • day-80 长度为 K 的子数组的能量值 I
  • 思维导图工具有哪些?10款思维导图特色介绍
  • ML 系列:机器学习和深度学习的深层次总结( 20)— 离散概率分布 (Bernoulli 分布)
  • 国际版JAVA同城打车源码同城服务线下结账系统源码适配PAD支持Android+IOS+H5
  • LSTM结构原理
  • 自动化测试中使用Pytest Fixture?推荐10种常见用法!
  • 【k8s】ClusterIP能http访问,但是不能ping 的原因
  • SpringAI QuickStart
  • C++练习题(2)