先交代一下背景。前段时间排查一个接口偶发 429 的问题,随手打开开发者工具把请求都过了一遍,结果在某几个核心接口的请求头里,发现了一个以前没见过的参数:hexin-v。值是一长串的字符串,很像 Base64,但结尾又没有常见的等号,中间还混着减号和下划线。第一反应是后端那边加的,但问了同事,都说没加过。再一看,同一个页面里其他普通接口根本不会带这个字段,只有几个敏感的核心接口会带——这基本可以断定,是页面里的 JavaScript 在请求发送前动态生成的一个签名参数。
后面花了两个晚上把它的生成逻辑整套逆向了出来,整个过程走了一遍“抓包 → 定位 → 还原 → 复现”的完整链路。这篇文章就记录这个 hexin-v 逆向小案例,也顺便分享一些 Web 逆向里通用的思路和工具,希望能给想入门前端逆向的朋友一点参考。为了表述方便,下面把目标站点统一叫“某顺”,懂的都懂,不点名,也不去碰任何具体接口数据。
1. 先摸清hexin-v这个参数的老底
1.1 用开发者工具把它的“长相”看清楚
遇到这种不明参数,第一件事不是急着搜代码,而是把它的表现观察清楚。我当时用的是 Chrome DevTools,直接切到 Network 面板,找到那几个带 hexin-v 的请求,把请求头完整展开,记录下关键字段。
| 请求头 | 示例值 | 特征 |
|---|---|---|
| hexin-v | dGhpcyBpcyBhIHNhbXBsZSBzaWdu... |
每次请求都不同 |
| Cookie | 省略不展示 | 部分接口必须携带 |
| User-Agent | Mozilla/5.0 ... |
与浏览器环境一致 |
| Referer | 站点页面地址 | 用于来源校验 |
只看单个值是完全看不出规则的,所以我把同一次会话内的多个请求、以及不同时间刷新后的请求分别抓了几组。默认情况下 Network 里的请求列表会被新请求刷掉,我习惯把 Preserve log 打开,这样刷新页面时之前的请求不会消失,方便对比。
1.2 多次刷新,观察参数变化规律
抓了几次请求之后,我总结出几个规律:
- 正常刷新页面,
hexin-v每次都变,没有固定值。 - 清掉 localStorage 之后再用无痕窗口刷新,
hexin-v的值变了,而且请求体里还会额外多出一个deviceId字段。 - 换一个浏览器内核访问,生成的
hexin-v也是不一样的。 - 同一个页面连续点击,短时间内生成的
hexin-v并不连续,看不到类似 +1 或时间戳那种肉眼可读的递增关系。
这些现象基本能说明两件事:第一,hexin-v 不是纯随机数,因为它能和某个设备标识产生关联;第二,它大概率依赖时间戳或随机因子,否则同一个浏览器每次请求的值应该是一样的。到这里我已经可以初步判断:算法里至少同时用到了“设备标识”和“时间相关量”,再叠加一层不可逆的摘要算法。
1.3 全局搜索源码,遇到第一道坎
接下来就是常规操作,在 Sources 面板里点击 Ctrl+Shift+F 全局搜索 hexin-v。搜索命中了十多个文件,但全部是压缩过后的 JS——整个文件就一行,变量名全是 _0x1a2b3c 这种格式。这就是典型的 JS 混淆特征,说明站点在构建时对前端代码做了保护。
新手到这里容易慌,其实不用。Chrome DevTools 的 Sources 面板里有个格式化按钮(就是那个 {} 图标),点一下之后压缩代码会展开成可读的多行结构,然后就能继续搜索和阅读了。当然,格式化之后变量名依然是 _0x 开头,可读性依然有限,但至少能找到字符串引用位置和函数边界。
另外一个非常实用的技巧是:搜索关键词时不要只搜 hexin-v,还可以搜 hexin、sign、timestamp、deviceId 相关字段。加密参数的名字可能会被拼接进字符串数组里,直接搜完整字符串可能搜不到,但搜关键子串往往命中的更多。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 从XHR断点到JS加密函数:调用链追踪
2.1 用XHR断点直接卡住发请求的位置
找到加密函数最直接的方式不是读代码,而是让浏览器把“正在发请求”这个动作暂停下来,然后顺着调用栈往上找。Chrome DevTools 里有个 XHR/fetch Breakpoints 功能,在 Sources 面板右侧,可以针对某个 URL 子串添加断点。
我当时的操作是:
- 切换到 Sources → XHR/fetch Brea
