京东电商数据批量采集 h5st 逆向实战

实战案例网址:https://www.jd.com/

概述

h5st 是京东网页端(PC/H5 通用基础框架生成的变体,本案例以 PC 端为主)用于保护核心接口的「签名通行证」。它通过动态混淆的 JavaScript、多种算法组合(如哈希、签名)以及环境指纹绑定等技术,有效屏蔽没有真实浏览器上下文的机器请求。

本实战将以京东首页无限滚动 Feed 流接口为目标,分析 h5st 的生成链路,快速定位关键代码并理清实现思路。


网页分析

首先打开京东首页,按下 F12 进入开发者工具,切换到 网络(Network) 面板:

  1. 刷新页面,向下滚动触发无限加载。
  2. 在筛选栏输入 functionId=pc_home_feedfunctionId 是接口的固定标识)。
  3. 找到返回 Feed 内容的请求,查看请求参数。

关键请求参数如截图所示:

请求参数截图1 请求参数截图2


核心技术要点

反调试与代码混淆

  • 变量/函数名混淆:所有标识符替换为 _$ 开头的无意义名称。
  • 控制流平坦化:打乱代码的正常顺序与分支逻辑,大幅提升阅读难度。
  • 代码强压缩:移除空格、换行、注释,一行到底。
  • 反动态调试:检测 debugger 和开发者工具状态,干扰断点调试(本次 Feed 接口相关逻辑的反调试相对较弱)。

关键加密参数

从请求中提取到的核心参数及作用:

参数名说明
appid固定应用标识,PC 端核心接口通常为 www-jd-com
body请求体的 SHA256 哈希值,用于校验数据完整性
functionId固定功能标识,Feed 流为 pc_home_feed
t毫秒级时间戳,有效期约 30~60 秒,用于防重放
h5st最终生成的签名参数,综合了环境指纹、算法组合与参数校验的结果

环境补全与关键定位

基础环境快速补全

在 Node.js 等非浏览器环境中运行混淆 JS 时,第一步必须补全浏览器核心全局对象,否则代码无法执行。不必一开始就补全所有属性,后续可借助代理监控定位缺失的关键属性。

// 快速补全基础全局对象框架
globalThis.navigator = {
  userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36",
  platform: "Win32",
  // 其他属性可根据代理监控补充
};
globalThis.window = globalThis; // Node.js 下全局对象对齐
globalThis.document = {
  cookie: "", // 后续可按需绑定 Cookie
};
globalThis.location = {
  href: "https://www.jd.com/",
  host: "www.jd.com",
};

代理监控系统(必用技巧)

代理监控能帮我们快速定位混淆代码访问了哪些环境对象/属性,避免盲目补全。这里我们重点监控 window 以及可能用于环境指纹的 canvas

下面代码虽在 Node 环境下运行,但原理是 JavaScript 的 Proxy 机制。

// 通用代理监控函数
function setProxy(proxyObjArr) {
    for (let i = 0; i < proxyObjArr.length; i++) {
        const objName = proxyObjArr[i];
        const handler = {
            get: function(target, property, receiver) {
                console.log(`[GET] 对象: ${objName} | 属性: ${property} | 类型: ${typeof property} | 值: ${target[property]}`);
                return Reflect.get(...arguments);
            },
            set: function(target, property, value, receiver) {
                console.log(`[SET] 对象: ${objName} | 属性: ${property} | 类型: ${typeof property} | 原值: ${target[property]} | 新值: ${value}`);
                return Reflect.set(...arguments);
            }
        };

        try {
            globalThis[objName];
            globalThis[objName] = new Proxy(globalThis[objName], handler);
        } catch (e) {
            globalThis[objName] = {};
            globalThis[objName] = new Proxy(globalThis[objName], handler);
        }
    }
}

// 配置需监控的对象
const proxyArray = ['window', 'canvas'];
setProxy(proxyArray);

将代理脚本与混淆库一同载入,运行后控制台会打印所有访问记录,方便发现未补全的属性。


关键代码定位与分析

定位思路

  1. 关键词全局搜索:在开发者工具的 Sources 面板搜索 h5stParamsSign(观察到的全局对象关键字)。
  2. XHR/fetch 断点:在 网络 面板右键点击目标接口,选择「在 Fetch/XHR 中断点」,向下滚动触发断点,然后查看调用栈。
  3. Hook 关键对象:若全局搜索直接找到暴露的对象,直接 Hook 即可。

核心参数与调用流程

本次实战通过关键词搜索直接找到了全局暴露的 ParamsSign 构造函数,剩余工作就是调用并传入参数:

// 构造请求参数(body 部分先用固定测试值)
const reqParams = {
    "appid": "www-jd-com",
    "body": "224029fa85a1a3b9d6e229f4d578057f080a2f6738837120a79a91934252476f",
    "clientVersion": "1.0.0",
    "client": "pc",
    "functionId": "pc_home_feed",
    "t": Date.now()
};

// 浏览器控制台或补全环境后直接运行
const signer = new window.ParamsSign();
const h5stResult = signer.sign(reqParams);
console.log("生成的 h5st:", h5stResult);

至此,我们就获得了能够通过服务端校验的 h5st 签名。


其他补全思路

如果混淆代码没有暴露全局构造函数,或者环境指纹绑定较深,还可以使用浏览器插件一键补全环境(需要的朋友可私信获取)。插件可以自动模拟浏览器上下文,直接输出可用的签名逻辑。

插件示例图: 插件截图1 插件截图2


常见问题解决

环境补全不完整

现象:Node.js 运行混淆代码时报错 Cannot read properties of undefined (reading 'xxx')

解决步骤

  1. 将报错涉及的对象/属性加入 proxyArray 重新运行。
  2. 观察控制台打印的 [GET] 记录,找到缺失的属性。
  3. 在基础环境配置中添加相应的模拟值(通常不需要完全真实的指纹,只需通过混淆库的「弱校验」即可)。

总结

本次实战遵循 “请求参数观察 → 基础环境补全 → 代理监控定位 → 关键词搜索 / Hook 关键对象” 的标准流程,快速定位了京东 PC Feed 流接口的 h5st 生成入口。

对于更深层的算法还原(如 AES 密钥提取、SHA256 组合规则等),还需要进一步分析混淆后的 sign() 方法内部逻辑,这部分内容将在后续笔记中更新。