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

参数跟丢了之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 或 return
        var 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.kler.cn/a/383656.html

相关文章:

  • LeetCode:1387. 将整数按权重排序(记忆化搜索 Java)
  • 03.01、三合一
  • Android 常用布局
  • 【C++读写.xlsx文件】OpenXLSX开源库在 Ubuntu 18.04 的编译、交叉编译与使用教程
  • ECharts柱状图-柱图42,附视频讲解与代码下载
  • 固定电话采用的是模拟信号还是数字信号?如果通话两端采用不同的信号会发生什么?
  • PostgreSQL核心揭秘(三)-元组结构
  • 【科普】conda、virtualenv, venv分别是什么?它们之间有什么区别?
  • 讲讲RabbitMQ 性能优化
  • Qt中弹出窗口的实现与鼠标事件处理
  • ctfshow(91,96,97)--PHP特性
  • Spring Boot 中Nacos的用法及流程
  • lua入门教程 :模块和包
  • 【C++】vector 类深度解析:探索动态数组的奥秘
  • Hive面试题-- hive中查询用户连续三天登录记录的实现与解析
  • 【码农日常】Vscode Clangd初始化失败(Win10)
  • M1M2 MAC安装windows11 虚拟机的全过程
  • CSS中常见的两列布局、三列布局、百分比和多行多列布局!
  • 13.React useTimeout
  • 服务器虚拟化:现代IT基础设施的基石
  • 【660】基于SSM+Vue的在线学习系统设计与实现
  • 数据库_SQLite3
  • 防止事件冒泡和防止触发子元素
  • Oracle视频基础1.4.4练习
  • python数据结构基础(6)
  • elementui中的新增弹窗在新增数据成功后再新增 发现数据无法清除解决方法