TTShop x-bogus JSVMP 纯算
引言
- 痛点场景:很多大佬都发了x-bogus的文章,但是都是GET请求的版本,本人遇到POST请求的版本。补环境是最快的方法,但是插桩分析也很快。
- 本文价值:本文将通过静态文本分析+动态调试,还原参数生成。
技术背景
-
JSVMP(JavaScript Virtual Machine Protection):是一种基于虚拟机保护机制的前端代码混淆与加密方案,主要用于提升 JavaScript 代码的安全性 。
通过代码虚拟化将原始 JavaScript 逻辑转换为自定义字节码,由专用解释器动态解密和执行,从而隐藏原始代码逻辑。
JSVMP 运行时模型 ┌───────────────┐ ┌──────────────┐ │ 原始JavaScript代码 │ → │ 字节码转换 & 加密 │ └───────────────┘ └──────────────┘ ↓ ┌───────────────────┐ │ 虚拟机解释器(动态解密执行) │ └───────────────────┘
-
插桩(Instrumentation):是一种通过向目标程序中植入额外监控代码或探针,动态捕获程序运行时状态的技术手段,其核心价值在于非侵入式动态分析。
-
插桩与 JSVMP 的关联性分析:通过插桩记录跳转指令的目标地址,重建扁平化后的真实执行路径。
插桩技术通过动态注入探针,实现在不破解虚拟机架构的前提下,直接提取 JSVMP 保护的加密算法核心逻辑。其与 JSVMP 的对抗本质是信息透明度与隐蔽性的技术博弈。JSVMP 插桩追踪模型 输入参数 → 解释器(插桩点) → 输出加密值 ↓ 日志输出(寄存器值、操作码)
x-bogus 入口函数
-
跟栈插条件断点确认入口函数
根据x-bogus的长度使用条件断点进行断点
断点断住,单步调试下一步
定位到入口函数 _0x178927
x-bogus 算法还原
插桩获取日志信息
-
插桩:对 _0x4a1158[‘apply’](_0x46d86a, _0x538008) 进行日志输出
console.log("apply1","值",JSON.stringify( _0x4a1158['apply'](_0x46d86a, _0x538008)),'参数',_0x538008,'函数',_0x4a1158.name,'对象',_0x46d86a)
webmssdk.js 中的两处都要打印日志
console.log("apply2","值",JSON.stringify( _0x4a1158['apply'](_0x46d86a, _0x538008)),'参数',_0x538008,'函数',_0x4a1158.name,'对象',_0x46d86a)
生成日志后存储本地
-
分析日志: 通过日志可以看到 x-bogus 的值 DFSzswSO8ENyr/hJCGXTP7sNhyMr 是通过 Dkdpgh4ZKsQB80/Mfvw36XI1R25-WUAlEi7NLboqYTOPuzmFjJnryx9HVGcaStCe= 的获取的
根据日志还原一下
function getXb(s) {
const charset = "Dkdpgh4ZKsQB80/Mfvw36XI1R25-WUAlEi7NLboqYTOPuzmFjJnryx9HVGcaStCe=";
let x_b = '';
for (let i = 0; i < 21; i += 3) {
const str1 = s.charCodeAt(i);
const str2 = s.charCodeAt(i + 1);
const str3 = s.charCodeAt(i + 2);
const num = (str1 << 16) | (str2 << 8) | str3;
x_b += charset[(num & 0xFC0000) >> 18];
x_b += charset[(num & 0x3F000) >> 12];
x_b += charset[(num & 0xFC0) >> 6];
x_b += charset[num & 0x3F];
}
return x_b;
}
验算,结果一致,接下来就是看 \u0002ÿ-%/*2\bôÌáqû�i®"c\u0017Có 是怎么样生成的
\u0002ÿ-%/*2\bôÌáqû�i®"c\u0017Có 是通过 数组 经过一系列方法生成。
[64, 0, 66, 239, 216, 104, 173, 255, 255, 3, 0, 14, 91, 124, 58, 33, 193, 255, 255]
缺什么扣什么,就能解决数组到乱码的过程。
多点耐心就能出结果