首页 > 编程语言 >x-s、x-t、x-s-common、x-b3-traceid 签名算法分析记录(2024/6/20)

x-s、x-t、x-s-common、x-b3-traceid 签名算法分析记录(2024/6/20)

时间:2024-06-22 21:59:45浏览次数:13  
标签:function search traceid return 2024 var 20 encrypt 加密

【作者主页】:小鱼神1024

【擅长领域】:JS逆向、小程序逆向、AST还原、验证码突防、Python开发、浏览器插件开发、React前端开发、NestJS后端开发等等

【学习交流】:知识星球:https://t.zsxq.com/gkn0r;vx:studypy1024

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

前置分析

我们在请求header中发现,有很多请求都带有x-sx-tx-s-commonx-b3-traceid这四个参数的值是动态变化的,所以我们猜测这四个参数应该是加密参数。

vscode-debugger-1

逆向分析

x-b3-traceid

全局搜索 x-b3-traceid,找到位置后打上断点

vscode-debugger-1

可以发现 x-b3-traceidrt() 生成的,找到其位置如下:

vscode-debugger-1

那第一个加密参数就搞定了!

function rt() {
    for (var t = "", e = 0; e < 16; e++)
        t += "abcdef0123456789".charAt(Math.floor(16 * Math.random()));
    return t
}
x-s、x-t

全局搜索 x-s,找到位置后打上断点

vscode-debugger-1

发现 x-sx-twindow._webmsxyw() 生成的。

那问题来了,window._webmsxyw() 又是从哪里来的呢?

当从 window._webmsxyw() 跳转到其位置后,如下:

vscode-debugger-1

经过分析后,window._webmsxyw() 是通过 JSVMP 加密得到的。

处理 JSVMP 加密一般有三种解决方案:

  • 插桩法还原
  • AST还原
  • 补环境

其中补环境方案是最简单的方法,但是补环境的缺点是:网站可能不定期加环境检测点,导致算法不能用。所以我们这里采取插桩法还原。

插桩法很考验技巧性的。

首先我们分析文件,观察 指令集 并选择插桩位置

日志点1如下:

// 打印全部日志点
"函数:", _ace_8712, "调用者:", _ace_25a6._ace_936, "函数形参:", _ace_bdcc

vscode-debugger-1

日志点2如下:

// 打印全部日志点
"_ace_d656a值:", _ace_d656a

vscode-debugger-1

插桩技巧:

  • 从入参开始分析
  • 从返回值开始分析

这两种技巧要结合使用,效果才能最佳。

vscode-debugger-1

以这个为例:
入参是: /api/sns/web/v1/search/hotlist?source=search_box
返回值如下图:
vscode-debugger-1

此时找到第一个生成返回值的位置,如下:

vscode-debugger-1

经分析,加密字符串种,只有payload是动态参数。那现在的任务,就是找到payload的加密算法和被加密字符串。

继续找 payload 的第一个生成位置,如下:

vscode-debugger-1

当我们找到第一个生成 payload 的位置后,惊喜的发现 encrypt 加密关键字。那问题来了,标准算法中,哪个加密算法有它呢?

你猜对了,和我想的一样,就是对称加密算法中的 AES 或者 DES

这也是只是盲猜啊。那继续验证猜想。

继续向上分析日志,发现有好多数组,如下:

vscode-debugger-1

因为这一串数组,在加密和解密之前,这有理由让我相信它是加密算法的一部分,虽然看不懂,但是可以去搜索啊。

vscode-debugger-1

此时,我们再也压不住心中的喜悦了。果然是 DES 加密算法。

vscode-debugger-1

继续往上翻日志,发现它的加密字符串了。

vscode-debugger-1

经过解密后,我们发现,加密字符串是:

"x1=c6b4760e70bae2a23793c905467dc208;x2=0|0|0|1|0|0|1|0|0|0|1|0|0|0|0;x3=18ee0b8eaa14szquw6otb9amxbdj35n5nrhcpqi4j50000360507;x4=1718705093623;"

此时,真相就离我们原来越近了。

  • x1 不确定,不过长度固定位32位
  • x2 固定
  • x3 a1
  • x4 时间戳

此时,此时工作中心已经非常明确了,就是 x1

继续往上翻日志也行。不过,学习技术嘛,就要学会从多个角度分析。

还记得前面说的,插桩的技巧吗?

此时,我们从入参开始分析。入参为:/api/sns/web/v1/search/hotlist?source=search_box

找到入参最后出现的地方,如下:

vscode-debugger-1

此时得到:url=/api/sns/web/v1/search/hotlist?source=search_box

vscode-debugger-1

让我们找到第一个x1出现的位置,再往上翻日志,有一系列加密,再往上翻,就看到了:url=/api/sns/web/v1/search/hotlist?source=search_box

此时,嘴角上扬了。好像知道点什么。估计你们也知道了。

我猜想是:url=/api/sns/web/v1/search/hotlist?source=search_box 经过解密后得到 x1 的值,也就是:c6b4760e70bae2a23793c905467dc208

而且还是得到 32 位的加密字符串,没错,和你想的一样,我也想到了 Md5 加密算法,验证一下吧

vscode-debugger-1

果然不出所料,就是 Md5 加密算法。

至此, x-sx-t 加密字符串已经全部还原。

x-s-common

全局搜索 x-s-common,找打位置后,打上断点,如下:

vscode-debugger-1

 var u = e.headers["X-t"] || ""
    , s = e.headers["X-s"] || ""
    , c = e.headers["X-Sign"] || ""
    , l = getSigCount(u && s || c)
    , f = localStorage.getItem(MINI_BROSWER_INFO_KEY)
    , p = localStorage.getItem(RC4_SECRET_VERSION_KEY) || RC4_SECRET_VERSION
    , h = {
    s0: getPlatformCode(o),
    s1: "",
    x0: p,
    x1: version,
    x2: o || "PC",
    x3: "xhs-pc-web",
    x4: "4.21.0",
    x5: js_cookie.A.get(LOCAL_ID_KEY),
    x6: u,
    x7: s,
    x8: f,
    x9: encrypt_mcr(concat_default()(r = concat_default()(n = "".concat(u)).call(n, s)).call(r, f)),
    x10: l
};
e.headers["X-S-Common"] = encrypt_b64Encode(encrypt_encodeUtf8(stringify_default()(h)))

主要分析 h 的值作为参数,通过 encrypt_b64Encodeencrypt_encodeUtf8 加密即可

那先分析 h 参数:

vscode-debugger-1

{
    "s0": 5, // 定值
    "s1": "", // 定值
    "x0": "1", // 定值
    "x1": "3.6.8", // 定值
    "x2": "Windows", // 定值
    "x3": "xhs-pc-web", // 定值
    "x4": "4.21.0", // 定值
    "x5": "18ee0b8eaa14szquw6otb9amxbdj35n5nrhcpqi4j50000360507", // a1 的值
    "x6": 1718762991893,  // x-t 的值
    // x-s 的值
    "x7":"XYW_eyJzaWduU3ZuIjoiNTEiLCJzaWduVHlwZSI6IngxIiwiYXBwSWQiOiJ4aHMtcGMtd2ViIiwic2lnblZlcnNpb24iOiIxIiwicGF5bG9hZCI6ImQ4M2I2NTY0OTY2ZGQzZDdmYzRlNzM0NTA5M2VlM2U1ZWRiZjc0NjcyMDExOTI5OGU0YjBjMzE1Zjg2MTI0ZDFhMTc4NGQ1NGY4MDc1NWY2NzQzODhlNGU5MGRkYTVkYmM5ZTNiZmRhMWZhYTFlYjkwZDc0YWEzMWI1NGM3MmNkMGQ3NGFhMzFiNTRjNzJjZGFjNDg5YjlkYThjZTVlNDhmNGFmYjlhY2ZjM2VhMjZmZTBiMjY2YTZiNGNjM2NiNTFiYzdiMDlhMTBjNjliZDQzYjgxNTY5ZWQ1ZWRmNjlhYWQ4OGU5MTRiZWY4ZjE3NTVjMzMwYjA2ZGI5YmY3YjAwM2EwZGIxMDhmMTk3OTgyM2I2OGUxNzE5MWRmM2NhZmUzN2YxM2RkZWVjZDJmMTk4YWFkYzBmNmE2MGFjNWVmNjkyODNhZTcwMGYyMWRmOTBkYWMyOTA5NjNlMTRkZWY4YTBlMTEzMjMwYzE3MWQ4NzE4ZGNlOTkwNTkzODkzMSJ9",
    // 浏览器指纹,可以写死
    "x8": "I38rHdgsjopgIvesdVwgIC+oIELmBZ5e3VwXLgFTIxS3bqwErFeexd0ekncAzMFYnqthIhJeSBMDKutRI3KsYorWHPtGrbV0P9WfIi/eWc6eYqtyQApPI37ekmR1QL+5Ii6sdnoeSfqYHqwl2qt5B0DoIvMzOZQqZVw7IxOeTqwr4qtiIkrOIi/skccxICLdI3Oe0utl2ADZsLveDSKsSPw5IEvsiutJOqw8BVwfPpdeTDWOIx4VIiu6ZPwbPut5IvlaLbgs3qtxIxes1VwHIkumIkIyejgsY/WTgeAsjutKrZgedWI9gfKeYIHPI3ge0VtZIk3edqtAmzPjNgDHIxOekPtR/WOex0lyIhYsIE8+qoqjICuPqYGnIiciePt5ICZC4BNsDces6uw1IvKef9de00znIiAe1Mi7yuwuIiKeTf0sxz/e1Vt4ZdvsdutWIxiem9AsdqtEssKsWVw8IxI2I383sqwZgVtQa7zLwLOsD0OexutmIk6eYa/sxpI1IkosWL6sxfhuIk7e6utdIkqIQqwHtPtAI33e1qtWIkNs1VwDIEKsfqtltqwseqwlIvqAIxDc8nqiKWJeiqtIIEq8Ii7eSPw4bzmynjOsWUmdIiPyqPttZPwlIvAexVtjODAeVY5sVLzLIE0s6edsiqt8cPwrICJsWutfIEvsTgDPIkvs173sSPwXIC5e3PwDt9YaIhQgIvNs1p6e6gve0MgsdVtmIiPRI3SEoPtLIC8EIh6skbF3+A/eWutbIE82eut12zAsYzgeWPwboPwGIvZ4ICVyoI==",
    "x9": -1854331133,
    // 请求次数,可以写死
    "x10": 22
}

经过分析,h 的组成主要看 x9,也就是:encrypt_mcr(concat_default()(r = concat_default()(n = "".concat(u)).call(n, s)).call(r, f))

vscode-debugger-1

很明显,concat_default()()的作用就是,将两个字符串相加操作,也就是合并字符串。

那找到 encrypt_mcr 加密函数位置,扣出代码。啥?你说你不会扣代码,那不赶紧加入 小鱼成神之路,一起交流学习。

var encrypt_mcr = function(t) {
    var e = 67
        , r = 15
        , n = 164
        , o = 126
        , i = 137
        , a = 39
        , u = 176
        , s = 72
        , c = 56
        , l = 21
        , f = 35
        , p = 34
        , h = 35
        , d = 18
        , v = 25
        , g = 185
        , m = 1149
        , y = 744
        , w = 1295
        , b = 1248
        , _ = 1310
        , E = 1096
        , x = 1166
        , k = 1095
        , T = 1196
        , S = 1180
        , A = 1039
        , L = 976
        , R = 1347
        , I = 1117
        , O = 1168
        , C = 1233
        , N = 1157
        , P = 1006
        , B = 1122
        , M = 1277
        , j = 1288
        , F = 1271
        , D = 986
        , q = 162
        , U = {};
    function G(t, e) {
        return a0_0x10f4ac(e, t - q)
    }
    U[G(-73, -66)] = function(t, e) {
        return t === e
    }
    ,
    U[G(e, 186)] = function(t, e) {
        return t < e
    }
    ,
    U[G(-r, -n)] = function(t, e) {
        return t ^ e
    }
    ,
    U[G(r, -o)] = function(t, e) {
        return t & e
    }
    ,
    U[G(-i, -a)] = function(t, e) {
        return t < e
    }
    ,
    U[G(-175, -u)] = function(t, e) {
        return t ^ e
    }
    ,
    U[G(-59, s)] = function(t, e) {
        return t ^ e
    }
    ,
    U[G(-c, -l)] = function(t, e) {
        return t >>> e
    }
    ,
    U[G(f, p)] = function(t, e) {
        return t >>> e
    }
    ;
    for (var H, V, W = U, X = 3988292384, z = 256, Y = []; z--; Y[z] = W[G(h, -66)](H, 0))
        for (V = 8,
        H = z; V--; )
            H = W[G(r, d)](H, 1) ? W[G(35, v)](H, 1) ^ X : W[G(h, g)](H, 1);
    return function(t) {
        function e(t, e) {
            return G(e - 1181, t)
        }
        if (W[e(m, 1108)]((0,
        esm_typeof.A)(t), e(y, 914))) {
            for (var r = 0, n = -1; W[e(w, b)](r, t[e(_, 1233)]); ++r)
                n = W[e(E, x)](Y[W[e(k, T)](n, 255) ^ t[e(S, A) + e(1022, L)](r)], n >>> 8);
            return W[e(R, 1166)](n, -1) ^ X
        }
        for (r = 0,
        n = -1; W[e(I, 1044)](r, t[e(O, C)]); ++r)
            n = W[e(N, P)](Y[W[e(1229, B)](W[e(M, T)](n, 255), t[r])], W[e(j, 1125)](n, 8));
        return W[e(F, B)](W[e(D, 1122)](n, -1), X)
    }
}();

到这里,h 就分析完了。

一鼓作气,分析 encrypt_b64Encode(encrypt_encodeUtf8(stringify_default()(h)))

vscode-debugger-1

stringify_default() 的作用很明显了,就是 JSON.stringify 对象转字符串了。

然后,又是扣 encrypt_encodeUtf8 代码了:

function encrypt_encodeUtf8(t) {
    var e = 185
        , r = 410
        , n = 480
        , o = 222
        , i = 194
        , a = 165
        , u = 147
        , s = 290
        , c = 460
        , l = 472
        , f = 497
        , p = 462
        , h = 286
        , d = 209
        , v = 223
        , g = 590
        , m = {
        bIGxm: function(t, e) {
            return t(e)
        },
        MahgM: function(t, e) {
            return t < e
        },
        czxKn: function(t, e) {
            return t === e
        },
        clYIu: function(t, e) {
            return t + e
        }
    }
        , y = m[b(477, 488)](encodeURIComponent, t)
        , w = [];
    function b(t, e) {
        return a0_0x10f4ac(t, e - g)
    }
    for (var _ = 0; m[b(333, e)](_, y[b(r, n)]); _++) {
        var E = y[b(o, 290)](_);
        if (m[b(i, a)](E, "%")) {
            var x = y[b(u, s)](m[b(574, 472)](_, 1)) + y[b(c, 290)](m[b(605, l)](_, 2))
                , k = parse_int_default()(x, 16);
            w[b(592, f)](k),
            _ += 2
        } else
            w[b(p, f)](E[b(217, h) + b(d, v)](0))
    }
    return w
}

再扣代码,encrypt_b64Encode 代码如下:

function encrypt_b64Encode(t) {
    var e = 664
        , r = 634
        , n = 448
        , o = 599
        , i = 315
        , a = 416
        , u = 512
        , s = 361
        , c = 406
        , l = 487
        , f = 496
        , p = 333
        , h = 630
        , d = 639
        , v = 548
        , g = 582
        , m = 447
        , y = 468
        , w = 375
        , b = 331
        , _ = 149
        , E = 382
        , x = 265
        , k = 625
        , T = 570
        , S = 551
        , A = 582
        , L = 581
        , R = 638
        , I = 618
        , O = 606
        , C = 429
        , N = 651
        , P = 667
        , B = 817
        , M = 333
        , j = 567
        , F = 747
        , D = 561
        , q = 570
        , U = 676
        , G = 840
        , H = 240
        , V = {
        udFrB: function(t, e) {
            return t % e
        },
        cCZFe: function(t, e) {
            return t === e
        },
        jevwl: function(t, e) {
            return t - e
        },
        aqlTy: function(t, e) {
            return t + e
        },
        rceYY: function(t, e) {
            return t >> e
        },
        OwjMq: function(t, e) {
            return t & e
        },
        kSGXO: function(t, e) {
            return t << e
        },
        veNiI: function(t, e) {
            return t === e
        },
        QLthP: function(t, e) {
            return t + e
        },
        wDtJz: function(t, e) {
            return t + e
        },
        nYqUQ: function(t, e) {
            return t & e
        },
        TCArD: function(t, e) {
            return t << e
        },
        RHteb: function(t, e) {
            return t - e
        },
        mZPJZ: function(t, e) {
            return t < e
        },
        zDETq: function(t, e, r, n) {
            return t(e, r, n)
        },
        YlZGp: function(t, e) {
            return t > e
        }
    };
    function W(t, e) {
        return a0_0x10f4ac(e, t - -H)
    }
    for (var X = (W(-413, -442) + W(-e, -r) + "7")[W(-n, -o)]("|"), z = 0; ; ) {
        switch (X[z++]) {
        case "0":
            var Y;
            continue;
        case "1":
            var K = [];
            continue;
        case "2":
            var J = V[W(-i, -a)]($, 3);
            continue;
        case "3":
            var $ = t[W(-350, -u)];
            continue;
        case "4":
            V[W(-s, -c)](J, 1) ? (Y = t[V[W(-l, -f)]($, 1)],
            K[W(-p, -346)](V[W(-h, -d)](encrypt_lookup[V[W(-503, -v)](Y, 2)] + encrypt_lookup[V[W(-g, -741)](V[W(-331, -m)](Y, 4), 63)], "=="))) : V[W(-y, -w)](J, 2) && (Y = V[W(-b, -_)](t[$ - 2], 8) + t[V[W(-l, -E)]($, 1)],
            K[W(-333, -x)](V[W(-k, -505)](V[W(-T, -S)](encrypt_lookup[Y >> 10], encrypt_lookup[V[W(-A, -L)](Y >> 4, 63)]) + encrypt_lookup[V[W(-R, -I)](V[W(-O, -C)](Y, 2), 63)], "=")));
            continue;
        case "5":
            var Q = 16383;
            continue;
        case "6":
            for (var Z = 0, tt = V[W(-509, -N)]($, J); V[W(-P, -B)](Z, tt); Z += Q)
                K[W(-M, -153)](V[W(-j, -F)](encrypt_encodeChunk, t, Z, V[W(-D, -413)](Z + Q, tt) ? tt : V[W(-q, -501)](Z, Q)));
            continue;
        case "7":
            return K[W(-U, -G)]("")
        }
        break
    }
}

没啥难度,又搞定了。

参数验证

整理加密参数代码后,再写个小例子,验证一下吧!

vscode-debugger-1

正常返回的结果,说明我们分析对了。晚上吃面给自己奖励一个荷包蛋吧!!

标签:function,search,traceid,return,2024,var,20,encrypt,加密
From: https://blog.csdn.net/studypy1024/article/details/139812528

相关文章

  • 2024-06-22:用go语言,给定一个起始下标为 0 的长度为3的整数数组 nums,根据这些数字构建
    2024-06-22:用go语言,给定一个起始下标为0的长度为3的整数数组nums,根据这些数字构建三角形。如果无法构成三角形,则返回"none";否则根据三角形的边长关系返回对应类型的字符串:equilateral(等边三角形)、isosceles(等腰三角形)或scalene(不等边三角形)。输入:nums=[3,3,3]。输出:"e......
  • P1971 [NOI2011] 兔兔与蛋蛋游戏 题解
    Description这些天,兔兔和蛋蛋喜欢上了一种新的棋类游戏。这个游戏是在一个\(n\)行\(m\)列的棋盘上进行的。游戏开始之前,棋盘上有一个格子是空的,其它的格子中都放置了一枚棋子,棋子或者是黑色,或者是白色。每一局游戏总是兔兔先操作,之后双方轮流操作,具体操作为:兔兔每次操作......
  • 2024华为OD机试真题- 找出作弊的人-(C++/Python)-C卷D卷-100分
     2024华为OD机试题库-(C卷+D卷)-(JAVA、Python、C++) 题目描述公司组织了一次考试,现在考试结果出来了,想看一下有没人存在作弊行为,但是员工太多了,需要先对员工进行一次过滤,再进一步确定是否存在作弊行为。过滤的规则为:找到分差最小的员工ID对(p1,p2)列表,要求p1<......
  • P10538 [APIO2024] 星际列车 题解
    题意:有\(n\)个行星,编号为\(0\simn-1\)。有\(m\)辆星际列车,第\(i\)辆列车在时刻\(a_i\)从行星\(x_i\)出发,在时刻\(b_i\)到达行星\(y_i\),代价为\(c_i\)。换乘条件为上一辆车的终点和下一辆车的起点相同,且上一辆车到达时刻\(\le\)下一辆车出发时刻。你需要吃......
  • 【办公类-50-01】20240620自主游戏观察记录表19周内容打乱
    背景需求:又到了期末,各种班级资料需要提交。有一份自主游戏观察记录需要写19周(每周2次)的观察记录,并根据参考书填写一级、三级、五级的评价指标。去年中六班的时候,我很认真的手写了21周的户外游戏活动内容,主动成为2个需要提交文本资料的班级。今年组长选了中二和中五提交......
  • HDU-4281 Judges' response(2012 ACM/ICPC Asia Regional Tianjin Online)
    HDU-4281Judges'response(2012ACM/ICPCAsiaRegionalTianjinOnline)状态压缩+01背包+区间dp题意:有n个地点,第一个地点是裁判位置,其他n-1个地点是选手的位置。裁判要给选手解决问题,每个选手都有一个时间表示解决这个选手问题所需要的时间。同样的,裁判也有一个时间,表示这......
  • P1072 [NOIP2009 提高组] Hankson 的趣味题【GCD】
    [NOIP2009提高组]Hankson的趣味题题目描述Hanks博士是BT(Bio-Tech,生物技术)领域的知名专家,他的儿子名叫Hankson。现在,刚刚放学回家的Hankson正在思考一个有趣的问题。今天在课堂上,老师讲解了如何求两个正整数......
  • YC307A [ 20240622 CQYC省选模拟赛 T1 ] 划船(boat)
    题意给定一个有向图\(G\),以及将所有边反向重连的无向图\(T\)。你最多可以在\(T\)上连续走\(k\)条边,走过每条边的代价都为\(1\),然后必须在\(G\)的对应点上走一条边以恢复体力。若当前对应点没有出边,则停留在该点\(1\)代价。求每个点到\(n\)的最小代价。Sol考......
  • ICLR2024 | iTransformer: 倒置Transformer,刷新时序预测新纪录
    目录:1、引言---1.1 问题背景---1.2设计思路  2、相关工作---2.1Transformer系预测模型---2.2多变量时序数据的词构建3、iTransformer---3.1模型结构---3.2以变量为主体的特征表示---3.3模块分析4、实验分析---4.1时序预测---4.2框架能力1、引言 近......
  • NOIP2024模拟赛13:拆开未来
    NOIP2024模拟赛13:拆开未来C-重复一句话题意:给定字符串\(S\),问\(S\)的所有子串共有多少种“好的拆分方案”。对于一个字符串\(S\),一个划分是好的当且仅当能把\(S\)划分成6个非空子串\(a,b,c,d,e\),满足\(a=b=e,\c=f\)(一个字符串可能有多种划分方式)标签:......