最新 京东h5st算法(4.7.4) 附 fp 算法

声明:本文章中所有内容仅供学习交流使用,不用于其他任何目的,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!

1,前言    

        在电商数据分析领域,京东平台的数据具有重要的研究价值。其中,京东 H5ST 相关的加密参数在数据获取过程中扮演着关键的角色。

        当深入研究京东接口时,我们发现 H5ST 参数的生成和加密机制复杂而独特。对其接口进行细致分析以及对加密过程进行逆向推导是获取有效数据的重要途径

2,任选一接口分析

 2.1,上图为评论接口参数,t(时间戳),body(url编码后的对象),这两个个也比较关键,会参与到h5st的算法中,x-api-eid-token跟环境相关。h5st看出是4.7版本,4.7版本又有小版本,目前是4.7.4。

2.2 ,首先把h5st解码下,可以看出有九部分组成,

20240910183448173;
gt99ytggtnmz56t1;
fb5df;
tk03wd0fc1cd218ndFyYrKIQ7yrMsUejJNSH0hfkMdkaDRaty0pBrXHRZnvAFWnd2rWKb1MExGlVDQZZd4gDhIKsZ9fW;
49f4d87c7aa42c3c71789d9bd8fc618d;
4.7;
1725964488173;
VOr4kxyDxBDQQSgbkK8NuLed7aP0kebnM0H4iviCO1P353wYJWBnUeSZBLIGT2zr1yyW1rMJlQGtLYOZCU-u7BhSG4KrJlTA2UsNE7Wddz_ztbjSrSlTRuVTMX81Cxv6DSnroFvfkb1ZouwtSkXNwTgs9TYI2lKbQ1-y9pv58zpgnks8v_YO3q4jjV6hqfECeeTHamie9Fsn9TGoysQG-L-dp_vEK01J5CLWuLuA0-NdSAS0tqvgfoQ-XaIMzvvx_xS9yD1tCsDMNi2mWo6kbPee2ItjaOBQhLh_GYhWcMaAQRu-qToZnCZ6xVwlakrzYp-FjBFvUoDzkg24bpjbIQZw-lPHTkVZr7YNFHPMWqbcWF854ZP1vlRB08xlzN42xf3q1JQsOskd5F5jkwwASX29dGUSITCAa9yuuGa8G1EU1kky2Mx_f2QYzHOJCTWPFwkVDVVK-20HUbttIa0VDRAOzBS9Bkol3tb9YuWdO27575n1vdKXRAhLtiZTYJ7EBKt-uUtkVwBK69r9yIo4lbwdi7VnhUaTeyPp2XQWLE8aDiCFeLpowmDSJ5bqTmNglN_LwfotsiwQ3VIfegficuH8fY_p5xIpUsrVxOLCu7nZggE7nDk8PeheJO0dl8zjLad9Prk3hGJ0DQIeqffFGvzEemLTD52YgeDqWQHLXbk3;
c9d09012cfdbb688fbf85012f5846799

这里我提前说下

第一部分,时间戳转化的时间字符串

第二部分,fp值,由一个初始的种子字符串,不断计算得出的16位字符串,末尾永远是数字

第三部分,appid值,接口不同值不同

第四部分,tk值,接口返回,tk 和随机算法绑定,有效期大约一天

第五部分,此部分值为MD5加密结果,但是再进行md5之前会有一系列操作,过程相对复杂

第六部分,版本号

第七部分,时间戳,与第一部分相关

第八部分,环境等参数经过AES加密后的结果

第九部分,MD5值,跟第五部分生成方式一致,过程字符串不一样

4.7版本的的算法,有的是加了盐,有的是进行了算法魔改,改动交大的是AES和Baes64

3, 定位分析

3.1,这个网站调试起来还是有一定难度,毕竟是大站。直接全局搜索h5st,发现有大量结果,过程还需要异步调试有些小伙伴说不会异步调试,这东西不难,但是不懂JS异步原理确实调试起来挺头疼大,多费些功夫最后定位到如下关键位置这里断下可以看到,body参数经过处理后做了SHA256加密,加密值放进了u对象中, 在下一步就进入了异步,很多小伙伴卡在了这里,始终调试不到关键位置,还是需要点应验和耐心,加油吧

调试过程发现很多vmp化的代码

4,解决方案

4.1,遇到这种情况怎么办呢?RPC,补环境,插桩纯算还原。RPC还是有诸多不便,补环境的话,环境检测点很多,也频繁添加新的,补起来也很费时间,并且花费很大精补完,发现返回403,内心是崩溃的。本人采取纯算还原的方式

4.2,算法还原,需要插桩分析日志,那么如何插桩呢?这是很多小伙伴的疑点难点,网上有很多文章,很多原理介绍,有的小伙伴说看的云里雾里。这东西需要一边学习一边实战才能慢慢有所顿悟。

4.3,扣出fp算法部分,做个简单分析

 e.generateVisitKey = function() {
            for (var e, t, o, s, c, i, u, l, p, v, b, y, x = n, S = a, A = [], E = 0; ; )
                switch (S[E++]) {
                case 5:
                    A.push(p);
                    break;
                case 6:
                    A[A.length - 1] = A[A.length - 1].length;
                    break;
                case 8:
                    A.push(r[S[E++]]);
                    break;
                case 10:
                    A.push(e);
                    break;
                case 11:
                    A.push(s);
                    break;
                case 14:
                    A.push(null);
                    break;
                case 15:
                    A.push({});
                    break;
                case 16:
                    i = A[A.length - 1];
                    break;
                case 17:
                    A.push(m);
                    break;
                case 18:
                    A.push(i);
                    break;
                case 19:
                    A.push(void 0);
                    break;
                case 20:
                    s = A[A.length - 1];
                    break;
                case 22:
                    A.push(new Array(S[E++]));
                    break;
                case 23:
                    A.push(b);
                    break;
                case 24:
                    y = A.pop(),
                    A[A.length - 1] += y;
                    break;
                case 29:
                    A.pop();
                    break;
                case 30:
                    v = A[A.length - 1];
                    break;
                case 31:
                    A.push(h);
                    break;
                case 32:
                    A[A.length - 2][r[S[E++]]] = A[A.length - 1],
                    A.length--;
                    break;
                case 34:
                    t = A[A.length - 1];
                    break;
                case 35:
                    null != A[A.length - 1] ? A[A.length - 2] = x.call(A[A.length - 2], A[A.length - 1]) : (y = A[A.length - 2],
                    A[A.length - 2] = y()),
                    A.length--;
                    break;
                case 37:
                    null != A[A.length - 2] ? (A[A.length - 3] = x.call(A[A.length - 3], A[A.length - 2], A[A.length - 1]),
                    A.length -= 2) : (y = A[A.length - 3],
                    A[A.length - 3] = y(A[A.length - 1]),
                    A.length -= 2);
                    break;
                case 38:
                    A.push(o);
                    break;
                case 39:
                    A.push(S[E++]);
                    break;
                case 44:
                    A.push(f);
                    break;
                case 45:
                    A.push(c);
                    break;
                case 46:
                    y = A.pop(),
                    A[A.length - 1] = A[A.length - 1] > y;
                    break;
                case 48:
                    E += S[E];
                    break;
                case 50:
                    y = A.pop(),
                    A[A.length - 1] -= y;
                    break;
                case 51:
                    A[A.length - 5] = x.call(A[A.length - 5], A[A.length - 4], A[A.length - 3], A[A.length - 2], A[A.length - 1]),
                    A.length -= 4;
                    break;
                case 55:
                    A[A.length - 4] = x.call(A[A.length - 4], A[A.length - 3], A[A.length - 2], A[A.length - 1]),
                    A.length -= 3;
                    break;
                case 57:
                    return;
                case 59:
                    A.push(d);
                    break;
                case 60:
                    A.push(v);
                    break;
                case 64:
                    return A.pop();
                case 65:
                    l = A[A.length - 1];
                    break;
                case 69:
                    A.push(l);
                    break;
                case 70:
                    A[A.length - 1] = A[A.length - 1][r[S[E++]]];
                    break;
                case 73:
                    e = A[A.length - 1];
                    break;
                case 74:
                    u = A[A.length - 1];
                    break;
                case 77:
                    A.push(u);
                    break;
                case 78:
                    A.push(A[A.length - 1]),
                    A[A.length - 2] = A[A.length - 2][r[S[E++]]];
                    break;
                case 80:
                    A.push(_);
                    break;
                case 83:
                    A.push(g);
                    break;
                case 85:
                    A.push(t);
                    break;
                case 86:
                    A.pop() ? E += S[E] : ++E;
                    break;
                case 91:
                    o = A[A.length - 1];
                    break;
                case 92:
                    c = A[A.length - 1];
                    break;
                case 93:
                    A.push(0);
                    break;
                case 94:
                    A.push(k);
                    break;
                case 95:
                    p = A[A.length - 1];
                    break;
                case 96:
                    A.push(w);
                    break;
                case 98:
                    b = A[A.length - 1]
                }
        }

4.4,通过分析上面代码,发现先定义了一些变量,有个A数组,case部分,不断往A里面push东西,然后pop东西,进行不断的入栈出栈操作,A类似于寄存器是插桩的关键点,jsvmp代码中,call或者apply处是关键的插桩点,这里涉及加密过程函数调用,+,-等运算符号处是关键点

5, fp 算法还原

        根据上面输出日志,很容易发现算法逻辑,有一个初始的字符转不断操作得出结果

还原后的算法如下,可以直接运行

function generateVisitKey() {
    // 生成fp
    function k(e, t) {
        let n = [], a = e.length;
        for (let i = 0; i < e.length; i++) {
            let s = e[i];
            if (Math.random() * a < t && (n.push(s), 0 === --t))
                break;
            a--
        }
        ;
        // console.log(n)
        for (var c = "", i = 0; i < n.length; i++) {
            let u = Math.random() * (n.length - i) | 0;
            c += n[u],
                n[u] = n[n.length - i - 1]
        }
        return c
    };

    function w(e) {
        for (var t = e.size, r = e.num, n = ""; t--;)
            n += r[Math.random() * r.length | 0];
        return n
    };

    function d() {
        return 10 * Math.random() | 0
    };
    let str1 = '1uct6d0jhq';
    let t = 5;
    let str2 = k(str1, t);
    let str3 = str1.split('').filter(char => !str2.includes(char)).join('');
    let str3Obj = {'size': d(), 'num': str3};
    let str4 = w(str3Obj);
    let str4Obj = {'size': 15 - (str3Obj.size + str2.length), 'num': str3};
    let str5 = w(str4Obj)
    let str6 = str4 + str2 + str5;
    let atr6Array = str6.split('');
    let lt = [];
    for (let i = 1; i < atr6Array.length + 1; i++) {
        let char = atr6Array[atr6Array.length - i];
        let nu = 35 - parseInt(char, 36);
        let newchar = nu.toString(36);
        lt.push(newchar);
    }
    lt.push(str3Obj.size)
    return lt.join('')
}

6,其他算法

        h5st 生成过程有多个算法参与,接口返回的有(MD5, SHA256, SHA512, HamcSHAMD5,  HamcSHA256, HamcSHA512),这些算法接口随机返回,跟返回的 tk fd是绑定的,也是有过期时间的,并且这些算法有人说魔改了,其实不算吧,就是加了盐值,对入参的时间戳末尾做了处理。。。还有AES加密算是魔改了,以及AES加密结果是Base64格式的,Base64不仅改了初始字符串,还修改了编码逻辑,

        这些都可以通过插桩的方式,分析出具体逻辑,算法还原后如果不对,或者参数过期,接口会返回 403, 601

经过不懈努力算法分析还原正确,就可以稳定的抓取目标数据

7,M端订单信息h5st

        m端获取订单信息接口,目前 h5st 仅为4.2版本,算法没有魔改,结果也是只有八段组合而成,部分代码结构如下全部订单,待付款订单,待收货,已完成,这几个接口算法一致,入参不同,效果如下

最后感觉这篇文章有帮助,麻烦点个赞,有疑问可评论区见

  • 16
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
祝福贺卡小程序 v4.7.4是一款非常实用的小程序,它能够帮助用户快速制作个性化的贺卡并发送给亲朋好友。在这个版本中,开发者对小程序进行了一系列的改进和优化,使得用户的使用体验更加流畅和便捷。 首先,新版本的祝福贺卡小程序增加了更多的贺卡模板供用户选择,包括生日、节日、结婚等不同场景的贺卡模板,用户可以根据自己的需求进行选择。同时,用户也可以自定义贺卡的背景、文字、配图等内容,打造出独一无二的贺卡。 其次,小程序在这个版本中增加了许多实用的功能。比如,用户可以通过小程序上传自己的照片,并将其添加到贺卡中,让贺卡更加个性化;还可以选择不同的字体和颜色,让贺卡的文字更加吸引人;同时,用户还可以选择发送贺卡的方式,可以通过微信、短信或者邮件等方式向亲朋好友发送贺卡。 此外,在这个版本中还修复了一些之前存在的bug,并进行了性能优化,提升了小程序的稳定性和运行速度,用户使用起来更加流畅。 综上所述,祝福贺卡小程序 v4.7.4是一个功能丰富、操作简单、用户体验良好的小程序。它的出现为用户提供了一个方便快捷制作个性化贺卡的平台,让人们在重要的节日或个人特殊日子能够通过贺卡表达真挚的祝福。相信在以后的版本中,开发者还会进一步完善和创新,为用户带来更多惊喜和便利。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值