吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5476|回复: 36
上一主题 下一主题
收起左侧

[Web逆向] h5st纯ai补环境+逆向

  [复制链接]
跳转到指定楼层
楼主
过往233 发表于 2026-2-22 08:02 回帖奖励
本帖最后由 过往233 于 2026-2-22 08:04 编辑

大家好我是个逆向小白,一直想搞h5st,但是每次都不知道该怎么搞,总是插桩到一半由于手头有各种事情耽搁了,上个月看到了一个大佬的文章,ai逆向,寻思试一试,没想到补环境1个小时不到就自己补好了,纯算从头来耽搁了两天走了不少弯路
先来说说心路历程,我是直接用补完的环境直接丢给ai让ai去操作,让他把补环境版本改成纯算版本,想法挺好现实给了一记重锤,ai直接去静态分析,然后上下文吃满,直接忘掉了最一开始的要求
算了,别的不多说了直接放总结吧,总之ai确实不错,而且还有待提升的空间,比如利用mcp添加更完善的提示词
哦对了xsh的补环境也搞出来了,直接把两个js一丢给ai他自己就可以搞好
以下是纯算和补环境的总结



h5st 签名本地化 — 完整对话记录


第一轮:补环境,让 JS 能在 Node.js 里跑

我:
底下那段是 ParamsSign 调用接口,我需要你帮我补环境让我可以本地运行 JS。

AI:
分析了 1.js(约 10500 行混淆代码),发现它重度依赖浏览器全局对象:window、document、navigator、localStorage、XMLHttpRequest、screen 等。底部还有 TypeScript 语法(const time: any)在 Node 里跑不了。

创建了两个文件:

  • env.js — 补浏览器环境(window、document、navigator、localStorage、screen、crypto 等)
  • run.js — 入口文件,加载环境后调用 ParamsSign 进行签名

1.js 底部的 TypeScript 调用代码已移除。

运行方式:cd h5stai醇酸 && node run.js


第二轮:用生成的 h5st 发请求,遇到 403

我:
(贴了一段 curl 命令,包含完整的 headers、cookies 和 h5st)
带着生成的 h5st 请求这个试试。

AI:
签名生成成功了,h5st 正常产出。但请求返回了 403。初步判断可能是 cookie 过期。

我:
算了我不要发请求测试了,给我直接生成下 h5st:

{
    "appid": "search-pc-java",
    "functionId": "pc_search_adv_Search",
    "client": "pc",
    "clientVersion": "1.0.0",
    "t": 1771501263005,
    "body": "881e4ddbb37b54759c65772e65dda6cb04433e3b0dd553eb89e698d51c67daf1"
}

AI:
生成成功,run.js 已精简成纯签名模式,改底部参数就能生成不同的 h5st。


第三轮:写 Python 脚本自动调签名

我:
(贴了一段 Python 代码,包含 headers、cookies、body、h5st)
来替换这个的 h5st 试试。

AI:
改造了流程:run.js 接受命令行 JSON 参数输出 h5st,1.py 调用它自动替换。

测试结果还是 403。

我:
现在是没问题的。(把 h5st 注释掉了,不带 h5st 能正常请求)

AI:
看到了,不带 h5st 能通。需要自动生成的时候把 get_h5st 函数加回来就行。

我:
我需要你把 h5st 加过来。

AI:
把自动生成 h5st 的逻辑加到了 1.py 里。


第四轮:排查 403 的真正原因

我:
现在报错 403,body 不应该换。

AI:
开始排查。发现 Python 端用 hashlib.sha256 算的 body hash 和 JS 内部算的不一致。改成直接把原始 body 传给 JS,让 JS 内部统一处理。

还是 403。

我:
2.py 是正常能请求的,也就是说你的 h5st 生成的不对。

AI:
对比发现 2.py 用的是原始抓包的固定 h5st,能正常返回 200。确认 cookie 没问题,问题在 h5st 签名本身。


第五轮:发现 signAppId 和 appid 是两个不同的值

AI:
发现关键区别:

  • ParamsSign({ appId: '01a47' }) — 构造函数用 01a47(h5st 第三段)
  • sign({ appid: 'pc-rate-qa', ... }) — sign 参数里用 pc-rate-qa(POST data 里的 appid)

之前把这两个混在一起了。分开后还是 403。


第六轮:发现 token 问题(tk05 vs tk03)

AI:
通过 hook 内部方法,发现签名流程:

  1. _$cps — 排序参数
  2. _$rds — 获取 token
  3. _$clt — 环境检测(收集浏览器指纹)
  4. _$ms — 主签名逻辑
  5. _$gdk — 用 token 派生密钥
  6. _$gs / _$gsd — 计算签名和摘要
  7. _$gsp — 拼接最终 h5st

关键发现:我们生成的 h5st 里 token 是 tk05(本地生成),但原始抓包的是 tk03(远程获取)。

原因:_onRequestTokenRemotely 是空函数,没有真正去服务端请求 token。token 请求发到 https://cactus.jd.com/request_algo

修复:在 env.js 里实现了真正能发 HTTP 请求的 XMLHttpRequest(基于 Node.js 的 https 模块),让 token 请求能正常工作。

修复后 token 变成了 tk03,但还是 403。


第七轮:找到根本原因 — Node.js 内置 navigator

AI:
用 Proxy 监控 _$clt(环境检测方法)执行时访问的属性:

  • document.cookie
  • navigator.languages
  • navigator.plugins
  • navigator.userAgent
  • document.head
  • document.body
  • document.all
  • navigator.hardwareConcurrency

检查实际值发现:

属性 期望值 实际值
navigator.userAgent Chrome/145 macOS Node.js/25
navigator.languages ["zh-CN", "zh", "en"] ["en-US"]
navigator.plugins 5个 PDF 插件 undefined
document.cookie 完整 cookies
document.all HTMLAllCollection undefined

根本原因:Node.js 18+ 内置了 navigator 对象,且该属性是不可写的(non-writable)。

env.js 中的 global.navigator = navigator 赋值被静默忽略了!

node -e "console.log(navigator.userAgent)"
# 输出: Node.js/25

_$clt 收集到这些 Node.js 环境信息后编码到 expandParams(h5st 第8段),服务端检测到非浏览器环境直接返回 403。


修复

1. env.js — 用 Object.defineProperty 覆盖内置对象

// 之前(无效,被 Node.js 内置 navigator 覆盖)
global.navigator = navigator;

// 之后(有效)
const defineGlobal = (name, value) => {
    Object.defineProperty(global, name, {
        value, writable: true, configurable: true
    });
    Object.defineProperty(globalThis, name, {
        value, writable: true, configurable: true
    });
};
defineGlobal('navigator', navigator);

2. 更新 navigator 属性匹配真实浏览器

  • UA 改为 Chrome/145 macOS
  • languages 改为 ['zh-CN', 'zh', 'en']
  • plugins 补充 5 个 PDF 插件
  • 补充 cookieEnabled、vendor 等属性

3. 修复 document.all

// 之前
all: undefined,
// 之后
all: { length: 0 },

4. run.js / 1.py — 传递 cookies 到 document.cookie

Python 端把 cookies dict 传给 Node.js,设置到 document.cookie,让环境指纹包含正确的 cookie 信息。

修复后测试:返回 200,问题解决。



用 AI 逆向 h5st 5.2 纯算签名 — 当 CryptoJS 不再是标准 CryptoJS

背景

h5st 是某电商平台的前端签名协议,核心逻辑藏在一个多态 VM 混淆的 JS 文件里。目标是把它从"补环境 + 跑 VM"变成纯算实现 — 不依赖任何混淆代码,只用标准 Node.js crypto 模块。

SHA256、HMAC、Base64 编码、fingerprint 生成都已经逆向完成,但最后一步 — tk05 token 的 checksum — 始终和原始 VM 输出对不上,导致 API 返回 403。

定位过程

第一步:对比输出,锁定 checksum

让 AI 做的第一件事不是猜,而是对比。

把原始 VM 的 _$ik(fp) 函数导出,和纯算 generateTk05(fp) 用同一个 fp 调用,逐字段比对输出。结果:

  • token 结构一致 ✓
  • 自定义 Base64 编码一致 ✓
  • 加密密文一致 ✓
  • MD5 checksum ✗ — 每次都不一样

问题锁定在 checksum 计算。纯算代码用的是 crypto.createHash('md5').update(body).digest('hex'),看起来没毛病。

这一步做得很干净。与其猜哪里错了,不如让两个实现并排跑,让差异自己浮出来。

第二步:Hook _doFinalize,发现预处理

AI 的下一步是 hook VM 内部的 CryptoJS,在 _doFinalize 阶段截获实际传入 MD5 的数据。发现:

输入: "tk05w41lMngxWlhiMmQ1f..." (82 bytes)
实际哈希数据: 93 bytes — 多了 11 个字节

多出来的 11 字节 = 5 字节动态后缀 + 6 字节常量 &d74&y

这就是 _seData — 一个挂在 Hasher.prototype 上的预处理钩子。它不改变 CryptoJS 的 API 接口(CJ.MD5(str) 调用方式完全一样),但在内部悄悄修改了输入数据。

这是整个调试过程中最关键的一步。不去读混淆代码,而是在运行时拦截数据流,直接看"进了什么、出了什么"。这种黑盒 + 灰盒结合的方式,在面对多态 VM 时比白盒逆向高效得多。

_seData 算法

1. 对输入的每个字节,通过 BYTE_MAP[byte] 映射到 MAP1 字母表中的一个字符
2. 按位置分成 5 组(chunkSize = floor(len / 5))
3. 每组内用 (idx + idx2 + 51) % 64 累加折叠为一个 MAP1 索引
4. 追加 5 个字符作为后缀
5. 再追加常量 "&d74&y"

有趣的是,pure_crypto.js 里 SHA256 用的 seData 是另一种写法 — (charCode * 19) % 64 — 但数学上完全等价。AI 通过对比验证确认了这一点。

踩坑记录

踩坑 1:试图从混淆代码中逆向 BYTE_MAP

最初尝试阅读 VM 生成的混淆代码来理解字节映射逻辑。多态 VM 的变量名全是 _$xx 格式,控制流被打散,几乎不可读。浪费了不少时间。

转换思路后,直接写脚本对 0x00-0xFF 所有字节值调用 VM 的 _seData,从运行时 dump 出完整的 256 字节查找表。几秒钟搞定。

反思:面对重度混淆代码,"运行时提取"几乎总是比"静态阅读"更高效。AI 特别擅长写这种一次性的 dump 脚本 — 告诉它你要什么数据,让它去 hook。

踩坑 2:分组累加公式的常量偏移

_seData 将映射后的字节分成 5 组,每组内累加折叠。最初以为是简单的 (a + b) % 64,对比发现不对。通过构造不同长度的测试字符串,逐步确认实际公式是 (idx + idx2 + 51) % 64 — 多了一个常量 51。

这个 51 藏得很深。如果只测试短字符串(每组只有 1 个字符,不触发累加),根本发现不了。是在测试较长字符串时才暴露的。

反思:测试用例的多样性很重要。短字符串、长字符串、边界长度(刚好整除 5、不整除 5)都要覆盖。AI 可以批量生成这些测试,但需要人来意识到"我的测试覆盖不够"。

踩坑 3:两种 seData 实现的困惑

pure_crypto.js 里 SHA256 用的 seData(charCode * 19) % 64 + 字母表 UTSRQPONM...。我从 VM dump 出来的是 BYTE_MAP 查找表 + (idx + idx2 + 51) % 64 + MAP1 字母表 hgfedcba...。两种写法看起来完全不同。

一度怀疑 MD5 和 SHA256 用的是不同的 _seData(毕竟 VM 可以给不同 hasher 挂不同钩子)。花了时间去验证,最终证明两种实现数学上完全等价 — 只是同一个映射的不同表达方式。

反思:这是一个典型的"看起来不同但本质相同"的陷阱。在逆向中很常见 — 同一个算法可以有多种等价实现。AI 在这里的价值是快速写出对比测试来证明等价性,而不是靠人肉推导数学关系。

踩坑 4:SHA256 的"多余"验证

担心 pure_crypto.js 的 SHA256 也有问题,花时间 hook SHA256 的 _doFinalize 做对比。结果发现 SHA256 一直是正确的 — 问题只出在 tk05 的 MD5 上。

反思:严格来说这步是"白做"的,但在调试中排除变量是有价值的。当你不确定问题边界时,花一点时间确认"这个没问题"比假设它没问题更安全。不过如果一开始就做了更精确的 diff(只对比 checksum 而不是整个签名链),可以更早缩小范围。

踩坑 5:Windows shell 引号问题

端到端测试时,用 execSync 传 JSON 参数给子进程。在 Windows CMD 下单引号不被识别为字符串定界符,导致 JSON.parse 失败。最终改为直接 require 模块调用函数,完全绕过 shell。

反思:这是一个低级但浪费时间的坑。AI 生成的测试脚本默认用 Unix 风格的 shell 语法,在 Windows 上跑不通。如果一开始就用模块调用而不是子进程,可以避免这个问题。跨平台兼容性是 AI 生成代码时容易忽略的盲区。

修复

// 修复前 — 标准 MD5
const checksum = md5Hex(body).substring(0, 8);

// 修复后 — 带 _seData 预处理的 MD5
const checksum = md5HexStr(body).substring(0, 8);

一行之差,checksum 从 0% 匹配变成 100% 匹配。

验证

  • tk05 checksum: pure vs VM 输出完全一致
  • requestAlgo 请求: 服务器正常返回 token(HTTP 200)
  • 实际 API 调用: pure 实现和原始 VM 行为完全一致

更大的思考

关于 AI 在逆向工程中的角色

这次对话展示了 AI 在逆向工程中最有价值的模式:不是让 AI 直接"读懂"混淆代码(它做不到,至少对多态 VM 级别的混淆做不到),而是让 AI 充当一个高速的"实验助手" — 写 hook 脚本、dump 运行时数据、生成对比测试、批量验证假设。

人的角色是提出假设和判断方向:

  • "checksum 不对,可能是 MD5 输入被修改了" — 这是方向判断
  • "hook _doFinalize 看实际输入" — 这是实验设计
  • "dump 所有 256 个字节的映射" — 这是数据获取策略

AI 的角色是快速执行这些实验:

  • 写 hook 代码、跑测试、格式化输出、对比结果
  • 这些都是机械性但容易出错的工作,AI 做得又快又准

关于"标准库不标准"的陷阱

这次的核心教训是:在混淆 JS 中,CryptoJS.MD5(str) 不一定是标准 MD5。多态 VM 的一个高明手法是在 Hasher.prototype 上挂预处理钩子 — _seData_eData 这类函数。它们不改变 API 接口(调用方式完全一样),但悄悄修改了输入数据。

这种手法之所以有效,恰恰是因为逆向者会假设"CryptoJS.MD5 就是 MD5"。当你看到 CJ.MD5(body).toString() 时,本能反应是用 crypto.createHash('md5').update(body).digest('hex') 替代。99% 的情况下这是对的,但在多态 VM 的场景下,这个假设会害死你。

关于调试效率

回顾整个过程,最高效的步骤是:

  1. 并排对比(2 分钟定位到 checksum)
  2. Hook _doFinalize(5 分钟发现预处理)
  3. 运行时 dump BYTE_MAP(几秒钟)

最低效的步骤是:

  1. 试图阅读混淆代码(浪费时间)
  2. 验证 SHA256 没问题(有价值但非必要)
  3. Windows shell 引号问题(纯粹的环境坑)

如果重来一次,整个过程可以压缩到 30 分钟以内。关键是一开始就建立"对比 → hook → dump"的工作流,而不是试图"读懂"混淆代码。

AI 协作的几个关键点

  1. 让 AI 做对比,不要让它猜。把 VM 函数导出,和纯算函数并排跑,逐字段 diff。AI 擅长写这种一次性的对比脚本。

  2. Hook 内部状态,不要只看输入输出。让 AI patch _doFinalize 截获实际哈希数据,比盯着混淆代码猜逻辑高效得多。

  3. 提取查找表,不要手动推导。BYTE_MAP 有 256 个条目,让 AI 写脚本从 VM 运行时 dump 出来,比逆向混淆代码里的生成逻辑快一个数量级。

  4. 交叉验证等价性。两种不同写法的 seData(查找表 vs 乘法取模)看起来完全不同,但 AI 可以快速写测试证明它们数学等价。



免费评分

参与人数 21威望 +2 吾爱币 +119 热心值 +18 收起 理由
apate + 1 + 1 用心讨论,共获提升!
xzz1203 + 1 + 1 我很赞同!
heartfilia + 1 + 1 我很赞同!
GuClass + 1 + 1 谢谢@Thanks!
lsb2pojie + 1 + 1 我很赞同!
PokerS429 + 1 用心讨论,共获提升!
LoveCode + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
buluo533 + 1 + 1 用心讨论,共获提升!
CodePhantom + 1 用心讨论,共获提升!
xsleaf + 1 我很赞同!
allspark + 1 + 1 用心讨论,共获提升!
四月份 + 1 + 1 谢谢@Thanks!
zxzx307 + 1 我很赞同!
111mz + 1 + 1 论坛禁止求脱求破,求助软件分析思路,务必在主题帖中描述清楚你的分析思路 ...
bfqn123 + 1 + 1 我很赞同!
lyrong2008 + 1 用心讨论,共获提升!
hare32768 + 1 + 1 用心讨论,共获提升!
fengbolee + 1 + 1 用心讨论,共获提升!
涛之雨 + 2 + 100 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
liuxuming3303 + 1 + 1 谢谢@Thanks!
helian147 + 1 + 1 热心回复!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
slslsl 发表于 2026-2-23 11:32
现在有AI能力的加持下,整个请求流程分析以及数据加解密部分的工作确实比以往难度要大大降低了,有些比较猛的模型,甚至能一句话自动完成整个逆向分析过程,包括代码以及文字内容整理输出
推荐
fscc无误 发表于 2026-2-22 14:13
4#
seetheplanet 发表于 2026-2-23 09:34
5#
JMYJ0001 发表于 2026-2-23 09:51
正需要呢,这不就来了
6#
amwquhwqas128 发表于 2026-2-23 13:54
对于AI提问不知道怎么做才好,这文章帮我解惑
7#
bfqn123 发表于 2026-2-23 18:59
感谢大神分享这类ai逆向的东西。
作为有组织犯罪受害人,第一步就是让自己的电子设备
比如手机,电脑免受犯罪黑客入侵,从而保障个人信息安全。

8#
bfqn123 发表于 2026-2-23 19:19
感觉现在ai软件,都是问答式的多,但是自己可以根据使用人自动生成文档或者软件实现某种功能的很少,我目前只知道通义灵码有类似功能,大家有知道其它类型的比较好用的软件吗?
由于我们受害人普遍电脑水平低,所以只能依靠ai了。
我的需求是"把入侵我的黑客的mac给抓出来,并确定入侵者身份"
如果有那种根据这个需求自动设计代码,生成各种软件文档,实现逆向功能,最终满足使用人需求。那就完美了
9#
zdian 发表于 2026-2-24 09:49
感谢大佬分享
10#
zxzx307 发表于 2026-2-24 11:25
感谢分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-9-5 09:15

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表