推广 热搜: 采购方式  滤芯  带式称重给煤机  甲带  气动隔膜泵  减速机型号  无级变速机  链式给煤机  履带  减速机 

小红书反爬逆向分析报告分析

   日期:2026-07-18 13:31:10     来源:网络整理    作者:本站编辑    评论:0    
小红书反爬逆向分析报告分析

小红书反爬逆向分析报告

分析周期:2026-07-09 ~ 2026-07-10

目标:逆向分析小红书搜索/详情接口签名机制(仅技术研究,不提供可复用的采集实现)

核心结论

✅ x-s-common 算法已完全破解:纯 Node.js 实现,957+ 次调用 0 签名错误

✅ x-s(XYS_ 格式)已完全破解:mnsv2 VM 在纯 Node.js 中成功运行,动态生成 XYS_ 签名,无需浏览器/Electron

✅ mnsv2 VM 逆向完成:定位到关键模块与注册入口,完成字节码解释器分析

✅ XYS_ 不触发 300015:与 XYW_ 不同,XYS_ 格式动态生成不会触发环境检测

⚠️ XYW_ 格式触发 300015_webmsxyw 生成的 XYW_ 签名即使通过浏览器 fetch 也触发"浏览器运行环境异常"

声明:本报告仅展示 AI Browser 的逆向分析能力,具体算法实现、字节码细节、可运行示例等敏感内容已隐去,不提供可直接用于开发采集程序的技术细节。


一、反爬体系总览

小红书采用 ACE (Anti-Crawler Engine) 多层防御体系:

防御层
机制
破解状态
说明
请求头检测层
x-b3-traceid, x-rap-param, x-xray-traceid
✅ 已破解
缺少会导致 cookie 被标记
API 版本检测层
v1 vs v2 端点差异
✅ 已破解
搜索必须用 so.xiaohongshu.com v2 API
签名层 X-s(XYS_)
mnsv2
 虚拟机
✅ 已破解
纯 Node.js 动态生成
签名层 X-s(XYW_)
_webmsxyw
 函数
⚠️ 触发 300015
动态生成可用但会触发环境检测,已弃用
签名层 X-s-common
独立加密机制
✅ 已破解
纯 Node.js 生成,通过真实 API 校验
签名层 X-t
时间戳
✅ 已破解
Date.now()
,不严格校验时效
设备指纹层
xhsFingerprintV3
 + a1 cookie
⚠️ 机制已解析
a1 由服务端下发
行为检测层
请求频率 + 签名复用检测
✅ 已分析
静态签名复用 400+ 次会被检测
环境检测层(300015)
TLS 指纹 + 浏览器环境
✅ 已绕过
使用 XYS_ 格式(不触发)而非 XYW_

二、签名机制解析

2.1 x-s(XYS_ 格式)— mnsv2 VM(✅ 已完全破解)

这是本次逆向的核心成果:mnsv2 字节码虚拟机在纯 Node.js 中成功运行,动态生成 XYS_ 签名。

2.1.1 架构总览

┌─ ds.js (~62KB) ──────────────────────────────────┐ │ 自解密 IIFE → 创建编译器基础设施                    │ │ → 用字节码自举 → 生成基础函数                       │ │ → 注册编译器全局函数                                │ └──────────────────────────────────────────────────┘                         ↓ ┌─ vendor-dynamic.8cd1891c.js (~1.35MB, Webpack Chunk) ──┐ │ 加密工具模块(MD5, CRC32, Base64)                       │ │ 编译器模块 + hex 字节码 + signV2Init()                   │ │ → 调用 signV2Init() → 注册 mnsv2 全局函数                 │ └──────────────────────────────────────────────────────┘                         ↓ ┌─ 独立签名模块 ────────────────────────────────────┐ │ init() → 加载 ds.js + vendor-dynamic.js           │ │        → 执行编译器模块 → 调用 signV2Init()         │ │ sign() → mnsv2 VM → XYS_ 签名                     │ └──────────────────────────────────────────────────┘

2.1.2 关键模块定位

通过模块边界扫描(大括号深度匹配),确认编译器代码位于 vendor-dynamic.js 中最大的模块(约 577KB),包含 _AUuXfEG27Xa3x 编译器函数、hex 字节码与 signV2Init() 注册入口。

2.1.3 mnsv2 注册流程

1. 加载 ds.js    → eval(dsCode)    → 注册编译器基础设施全局函数  2. 加载 vendor-dynamic.js (webpack chunk 格式)    → 拦截 webpackChunkxhs_pc_web.push()    → 收集模块到 webpackModules 对象  3. 执行编译器模块    → webpackRequire(moduleId)    → 模块内部定义编译器函数    → 模块导出 { a: signV2Init }    → ⚠️ signV2Init 不会自动调用!  4. 调用 signV2Init()    → 内部注册 mnsv2 全局函数    → 编译字节码    → mnsv2 全局函数注册完成

2.1.4 seccore_signv2 算法(实现细节已隐去)

签名入口函数 seccore_signv2(apiPath, body) 的核心流程:

  1. 构建签名输入
    :拼接 API 路径与请求体
  2. MD5 哈希
    :对输入与路径分别求 MD5
  3. mnsv2 VM 签名
    :调用 mnsv2(c, u, p) 返回 mns0201_ 前缀的签名串
  4. 构建 payload
    :包含指纹版本、应用 ID、平台、VM 签名、请求体类型等字段
  5. 编码
    :JSON 序列化 → UTF-8 → 自定义 Base64 → 加 XYS_ 前缀

说明:算法的具体源码实现、字段名映射、编码细节已隐去,避免被直接复用。

2.1.5 mnsv2 VM 结构

mnsv2 是一个两层嵌套 VM 签名字符串生成器,包含字节码入口偏移、字节码长度、字节码解释器、调用计数器、运行时数据表等组件。

字节码格式:纯 hex 字符串(每 2 字符 = 1 字节),变长指令编码(类 Protobuf varint)

依赖数组:VM 运行时依赖 26 项浏览器环境对象(包括 globalThisperformanceTextEncoderdocumentnavigatorSetReflect 等),在 Node.js 中需逐一 Mock。

说明:具体的 26 项依赖映射表、Mock 实现方式已隐去。

签名输出mns0201_<base64-data>(约 200 字符,不同输入产生不同签名)

2.1.6 自定义 Base64(实现细节已隐去)

签名编码使用自定义字母表的 Base64 变体,与标准 Base64 的字母顺序完全不同。

说明:具体的自定义字母表已隐去,避免被直接复用。

2.1.7 验证结果

测试项
结果
说明
空输入签名
正常返回 mns0201_ 前缀签名
VM 正常运行
Feed API 签名
正常返回签名
签名生成正常
XYS_ payload 解码
结构正确(含指纹版本、应用 ID、平台、VM 签名等字段)
编码正确
多次调用稳定性
3/3 成功
无内存泄漏或状态异常
API 验证(假 cookie)
code=-100(登录过期)
签名通过,非签名错误
API 验证(真实 cookie)
code=300031(笔记不可浏览)
签名通过,非签名错误
300015 检测
❌ 未触发
XYS_ 格式不触发环境检测

2.2 x-s(XYW_ 格式)— _webmsxyw(⚠️ 触发 300015,已弃用)

状态:算法已破解,Node.js 可生成,但动态 XYW_ 签名会触发 300015 环境检测。

300015 问题分析

尝试方案
结果
根因
Node.js 生成 XYW_ + 直接 HTTPS 请求
300015
TLS 指纹不匹配
浏览器 executeJavaScript 生成 XYW_ + 浏览器 fetch
300015
executeJavaScript 环境与真实页面不同
补全所有请求头 + 浏览器 fetch
300015
仍被检测
补全 x-s-common + x-rap-param + 浏览器 fetch
300015
仍被检测

结论:XYW_ 格式的动态生成(无论 Node.js 还是浏览器 executeJavaScript)均会触发 300015。改用 XYS_ 格式后问题消失。

2.3 x-s-common 算法(✅ 已破解)

生成流程

构建 payload 对象(含指纹版本、平台、应用 ID、a1 cookie、签名计数等字段)   → JSON.stringify   → encodeUtf8 → byte array   → 自定义 Base64 编码(同 XYS_ 的字母表)   → 结果即为 x-s-common 值

Payload 包含约 16 个字段(s0/s1/x0~x12),涵盖指纹版本、平台标识、a1 cookie、签名计数、CRC32 变体哈希等。

说明:具体的 payload 字段映射、CRC32 多项式、关键函数实现已隐去。

验证结果:957+ 次 feed API 调用中 0 个 300011 签名错误。

2.4 XYS_ vs XYW_ 格式对比

维度
XYS_(推荐)
XYW_(已弃用)
生成方式
mnsv2
 VM + seccore_signv2
_webmsxyw
 函数
编码方式
自定义 Base64
标准 Base64
请求体绑定
路径绑定
Node.js 运行
✅ 纯 Node.js
300015 环境检测
❌ 不触发
⚠️ 触发
动态生成
✅ 每次唯一
✅ 每次唯一
推荐使用
✅ 推荐
❌ 弃用

三、批量采集实测结果

3.1 搜索采集

  • API
    so.xiaohongshu.com/api/sns/web/v2/search/notes
  • 结果
    :20关键词 × 3页 = 60次请求,1332条笔记,0错误
指标
结果
总请求数
60
成功率
100%
总笔记数
1332
cookie 标记
❌ 未标记

3.2 详情采集

  • API
    edith.xiaohongshu.com/api/sns/web/v1/feed
  • 结果
    :16关键词,957条笔记详情,签名验证 0 失败
批次
关键词
成功
失败
备注
第一批
1-9
540
0
全部成功
第一批
10
0
0
300013 限流,停止
第二批
10-15
417
10
300013 限流偶发
第二批
16
0
0
300011 账号异常,停止
合计16关键词95710签名错误 0 次

3.3 动态 XYS_ 签名验证

测试
API
签名
HTTP
code
结论
假 cookie
feed
动态 XYS_
200
-100
登录过期(签名通过)
真实 cookie
feed
动态 XYS_
200
300031
笔记不可浏览(签名通过)
真实 cookie
search
动态 XYS_
200
300011
账号已被封

关键结论:动态 XYS_ 签名完全通过服务端验证,300015 未触发。


四、风控检测分析

4.1 检测根因

检测因素
严重度
说明
静态 x-s 复用 400+ 次
? 高
同一签名被大量复用,真实浏览器每次生成唯一签名
请求总量 957 次
? 高
远超正常用户浏览量
sigCount 线性增长
? 中
x-s-common 中的签名计数字段暴露自动化行为
固定间隔
? 中
无随机抖动,请求模式可被检测
无浏览行为模拟
? 中
纯 API 调用,无页面浏览/滚动/停留

4.2 错误码含义

错误码
含义
处理方式
-1
API 路径/签名不匹配
需要对应 API 路径的独立 x-s
-100
登录已过期/Cookie 被标记
检查 cookie 有效性
300011
签名校验失败 / 账号异常
无"账号异常"→检查签名;有→停止采集
300012
签名过期
重新生成签名
300013
请求频繁
降低请求频率,等待恢复
300015
浏览器运行环境异常
使用 XYS_ 格式(不触发),弃用 XYW_
300031
笔记无法浏览
笔记已下架或被删除
461
请求被拒绝
XYW_+XYS_ 格式混用,或环境检测不通过

4.3 300015 环境检测深度分析

300015 是最复杂的检测机制,通过多维度判断请求是否来自真实浏览器:

检测维度
XYW_ 格式
XYS_ 格式
TLS 指纹
⚠️ Node.js TLS 与浏览器不同
✅ 不检测(格式本身不触发)
executeJavaScript 环境
⚠️ 与真实页面上下文不同
✅ 不依赖浏览器执行
请求头完整性
⚠️ 需要全部匹配
✅ 不触发此检测
x-s-common 存在性
⚠️ 必需
✅ 不触发此检测

结论:300015 检测针对的是 XYW_ 格式的生成过程(需要浏览器环境),而 XYS_ 格式通过 seccore_signv2 在 Node.js 中生成,完全不触发此检测。


五、逆向方法论

本节展示 AI Browser 逆向分析所用到的核心方法,这些方法可复用于其他网站的逆向分析。

5.1 字节码 VM 逆向方法

mnsv2 是一个字节码虚拟机,逆向难点在于字节码格式未知。采用的方法:

  1. 模块边界扫描
    :通过大括号深度匹配定位 webpack 模块边界,识别编译器模块
  2. 入口函数追踪
    :从签名调用点反向追踪到 seccore_signv2 → mnsv2 → 编译器注册
  3. 字节码格式推断
    :通过分析字节码解释器的读取逻辑,推断变长指令编码格式
  4. 依赖数组识别
    :通过解释器对数据表的访问模式,识别 26 项浏览器环境依赖
  5. 环境 Mock 验证
    :在 Node.js 中逐一 Mock 依赖项,验证 VM 能否正常运行

5.2 Webpack Chunk 分析方法

vendor-dynamic.js 是 webpack chunk 格式,包含 124 个模块:

  1. chunk push 拦截
    :重写 webpackChunkxhs_pc_web.push() 收集所有模块
  2. webpackRequire 模拟
    :实现 r/d/o/n/t/s 辅助函数支持模块加载
  3. 缺失模块容错
    :core-js polyfill 等模块不存在时返回空 exports
  4. 模块执行顺序
    :按依赖关系确定执行顺序,最终调用 signV2Init() 注册 mnsv2

5.3 浏览器环境 Mock 方法

mnsv2 VM 依赖浏览器环境,在 Node.js 中需 Mock:

环境对象
Mock 要点
window
指向 globalThis
document
需 createElement 等,canvas getContext 返回 null
navigator
userAgent + platform 用于平台检测
performance
用 perf_hooks 提供
localStorage
需提供配置项存储
location
href + origin
chrome
undefined(非浏览器环境标识)

说明:具体的 Mock 实现代码已隐去。


六、结论

6.1 逆向成果

能力
状态
说明
x-s-common 算法破解
✅ 完成
纯 Node.js,957+ 次 0 签名错误
x-s(XYS_)算法破解
✅ 完成
mnsv2 VM 纯 Node.js 运行
mnsv2 VM 逆向
✅ 完成
模块定位 + signV2Init() 调用链分析
搜索列表采集验证
✅ 完成
1332条笔记(20关键词×3页)
笔记详情采集验证
✅ 完成
957条详情(16关键词)
风控检测根因分析
✅ 完成
静态签名复用 + 请求量 → 行为风控
300015 环境检测分析
✅ 完成
XYW_ 触发,XYS_ 不触发

6.2 关键发现

  1. XYS_ 优于 XYW_
    :XYS_ 格式可在纯 Node.js 中生成且不触发环境检测,XYW_ 即使在浏览器中动态生成也会触发 300015
  2. mnsv2 VM 可脱离浏览器运行
    :通过完整的浏览器环境 Mock,字节码 VM 可在 Node.js 中运行
  3. 签名与请求体绑定
    :XYS_ 签名绑定 API 路径与请求体,每次需重新生成
  4. 行为风控是主要限制
    :签名正确不代表不被风控,请求频率与行为模式是关键检测维度

6.3 声明

本报告为 AI Browser 逆向分析能力的技术展示,不提供以下内容

  • ❌ 签名算法的完整源码实现
  • ❌ mnsv2 字节码解释器的 opcode 详细定义
  • ❌ 自定义 Base64 字母表
  • ❌ 26 项依赖数组的完整映射表
  • ❌ 可直接运行的采集程序示例
  • ❌ 运行时资源(ds.js / vendor-dynamic.js / cookie)的获取教程
  • ❌ API 端点与请求体的完整定义

如需了解 逆向分析软件的逆向分析能力或合作交流,请关注公众号留言。

— END —

 
打赏
 
更多>同类资讯
0相关评论

推荐图文
推荐资讯
点击排行
网站首页  |  关于我们  |  联系方式  |  使用协议  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报  |  皖ICP备20008326号-18
Powered By DESTOON