1. Akamai参数mst逆向分析概述
作为一名长期从事Web逆向工程的技术人员,我最近对Akamai防护系统中的mst参数进行了深入研究。这个参数在现代Web防护体系中扮演着重要角色,特别是在反爬虫机制中。本文将详细拆解mst参数的生成逻辑,重点分析其中最具挑战性的jsvmp虚拟机保护部分。
mst参数主要包含dd2、jsrf1、jsrf2和dvc四个关键组件,其中dvc的生成涉及复杂的jsvmp虚拟机保护。理解这些参数的生成机制,对于需要处理Akamai防护的开发者来说至关重要。不过需要特别强调的是,本文所有技术细节仅用于学习交流目的。
2. mst参数组成解析
2.1 基础参数结构
mst参数包含多个动态生成的字段,每个字段都有其特定的生成逻辑:
- kevl/mevl/devl/dmvl:这些计数器类参数在第三次请求时会发生变化,与dme、doe等事件监听器相关
- sts:标准的时间戳参数
- tovl:直接取自ajr对象的totVel属性
- kc/mc:初始为0,第三次请求时kc变为1,mc则反映鼠标轨迹组数
- ww8:同样是第三次请求才会变化的动态参数
- jsrf1/jsrf2:基于时间戳计算的2位数组
这些基础参数虽然看似简单,但它们共同构成了mst参数的"指纹"基础,为后续更复杂的验证提供数据支持。
2.2 核心参数生成逻辑
2.2.1 jsrf1和jsrf2生成
这两个参数通过时间戳计算获得,其生成函数XP2实际上并未做混淆处理:
javascript复制var M6T = function(YpT) {
var ck = Math.floor(Math.random() * 100000 + 10000);
var cmT = String(YpT * ck);
var pmT = 0;
var zTT = [];
var vJT = cmT.length >= 18;
while(zTT.length < 6) {
zTT.push(parseInt(cmT.slice(pmT, pmT + 2), 10));
pmT = vJT ? pmT + 3 : pmT + 2;
}
var lCT = SWT(zTT);
return [ck, lCT];
};
这个函数首先生成一个随机数ck,然后将时间戳YpT与ck相乘,对结果字符串进行分段处理,最终通过SWT函数计算出一个校验值。SWT函数实际上计算的是三维向量的模长:
javascript复制var SWT = function(zYT) {
var Y4 = zYT[0] - zYT[1];
var RmT = zYT[2] - zYT[3];
var A4 = zYT[4] - zYT[5];
return Math.floor(Math.sqrt(Y4 * Y4 + RmT * RmT + A4 * A4));
};
2.2.2 dd2参数生成
dd2参数的生成相对直接,基于startTs进行计算:
javascript复制parseInt(parseInt(window.bmak.startTs / 23, 10) / (2016 * 2016), 10)
这种计算方式实际上是对时间戳进行了两次归一化处理,目的是生成一个相对稳定的标识,同时又能随时间缓慢变化。
3. dvc参数深度解析
3.1 dvc整体结构
dvc参数是mst中最复杂的部分,采用jsvmp(JavaScript Virtual Machine Protection)技术保护。其最终输出由两部分拼接而成:
code复制"acigcf9aYkakYf" + "acsw1v"
这种两段式结构是典型的安全设计模式,前段相对简单,后段则包含复杂的验证逻辑。
3.2 第一段生成分析
"acigcf9aYkakYf"的生成基于一个固定字符数组:
javascript复制["a","c","d","9","f","h","i","k","l","7","p","q","s","1","v","w","x","y","B","2"]
生成过程遍历"01761530890985"字符串,将其每个数字作为索引从上述数组中取值。例如:
- 0 → "a"
- 1 → "c"
- 7 → "p"
- ...
这种设计使得输出结果与输入字符串形成非线性的映射关系,增加了逆向难度。
3.3 第二段生成机制
"acsw1v"的生成更为复杂,涉及多层次的位运算和算术运算:
-
基础数值生成:
- 102 = 'f'.charCodeAt()
- 3315 = (102 << 5) | (102 >> 1)
- 714 = (102 << 3) - 102
-
中间计算:
- 2366910 = 3315 * 714
- 2366799 = 2366910 - 111
- 17 = 2366799 % 22
-
最终取值:
- 从22个字符的数组中取第17个字符(0-based索引)
这个计算链条中的关键点在于所有运算都基于最初的字符编码值,通过一系列不可逆的变换得到最终结果。
3.4 二进制字符串的作用
在整个dvc生成过程中,二进制字符串"11010101000010110110011011011001"扮演了重要角色。它实际上是由两个数值相加后通过toString(2)得到的:
javascript复制3574294233 = 181556985 + 3392737248
其中:
- 3392737248 = -902230048 >>> 0
- 181556985 = 181556985 >>> 0
这两个数值又是通过对UA字符串和时间戳等信息的哈希处理得到的。这种设计确保了dvc参数与客户端环境的强关联性。
4. jsvmp虚拟机保护分析
4.1 虚拟机保护原理
jsvmp通过将原始JavaScript代码转换为自定义字节码,在虚拟环境中执行来实现保护。在分析dvc生成逻辑时,我们需要特别关注以下关键点:
-
插桩位置:
- while循环中的epcode指令
- getter/setter方法调用
- String.fromCharCode等关键函数
- this对象的属性操作
- 各种算术和位运算
-
执行流程:
- 初始化阶段准备执行环境
- 指令解码和分发
- 运行时堆栈管理
- 内存访问控制
4.2 逆向工程技巧
针对这种保护,我总结出以下有效的分析方法:
-
日志记录法:
在关键位置插入日志语句,记录:- 指令指针变化
- 堆栈状态
- 内存读写操作
- 重要变量赋值
-
控制流重建:
根据日志信息绘制执行流程图,识别:- 循环结构
- 条件分支
- 函数调用关系
-
数据流追踪:
标记关键数据的产生、传播和消费过程,特别是:- 初始输入参数
- 中间计算结果
- 最终输出值
重要提示:在实际分析过程中,建议使用断点调试而非直接修改代码,以避免触发反调试机制。同时要注意控制日志输出量,过多的日志可能导致浏览器卡死。
5. 完整生成流程总结
基于上述分析,我们可以将mst参数的生成流程归纳为以下步骤:
5.1 初始化阶段
-
收集浏览器环境信息:
- User-Agent字符串
- 屏幕分辨率
- 插件列表
- 时间戳
-
准备基础参数:
- 生成jsrf1/jsrf2
- 计算dd2值
- 初始化事件计数器
5.2 dvc生成阶段
-
预处理输入数据:
javascript复制function preprocess(input) { let hash = 0; for(let i = 0; i < input.length; i++) { hash = (hash * 33) ^ input.charCodeAt(i); } return hash >>> 0; } -
构建字符池:
- 基于二进制字符串筛选字符
- 保留位置为1或能被3整除的字符
-
生成两段字符串:
- 简单索引法生成前段
- 复杂运算生成后段
5.3 最终组装
将所有参数按照固定格式拼接,形成最终的mst值。这个值会被发送到服务器端进行验证,决定是否允许访问后续资源。
6. 常见问题与调试技巧
在实际分析过程中,我遇到了以下几个典型问题及解决方案:
6.1 环境差异问题
问题现象:本地生成的参数与浏览器生成的总是不同。
解决方案:
- 确保收集的环境信息完全一致
- 检查时区、语言等容易被忽视的设置
- 验证随机数生成器是否被重写
6.2 反调试陷阱
问题现象:调试时代码行为异常或浏览器崩溃。
应对策略:
- 使用非侵入式调试方法(如日志输出)
- 延迟调试器附加时间
- 在虚拟机环境中进行分析
6.3 代码混淆干扰
问题现象:变量名无意义,逻辑难以追踪。
处理技巧:
- 关注常量字符串和数字
- 识别重复模式
- 重建控制流程图
6.4 性能优化建议
长时间运行复杂的jsvmp代码可能导致性能问题,建议:
- 缓存中间结果
- 优化热路径代码
- 使用Web Worker分流计算
7. 技术思考与经验分享
经过这次深入分析,我对Akamai的防护策略有了几点新的认识:
-
分层验证机制:mst参数看似简单,实则包含多层验证,从基础环境检查到复杂行为分析,形成了一个完整的防御体系。
-
时间敏感性:很多参数与时间戳强相关,这就要求客户端和服务端的时间必须保持同步,否则验证会失败。
-
环境指纹技术:通过收集各种浏览器特征并转化为数值形式,创建了难以伪造的环境指纹。
在实际应用中,我发现有几个关键点需要特别注意:
-
参数动态性:mst参数不是静态的,即使在同一会话中也会随着请求次数变化,特别是第三次请求时的参数突变。
-
逻辑关联性:各个参数之间并非独立,而是存在复杂的相互影响关系,修改一个参数可能会影响其他参数的验证结果。
-
错误处理:服务器对非法mst参数的处理方式多样,从简单的403拒绝到更隐蔽的行为分析,需要仔细辨别。
这项研究花费了我近两周的时间,期间尝试了多种逆向工程方法。最有效的还是经典的"分而治之"策略——将复杂问题分解为多个小问题,逐个击破。特别是在分析jsvmp部分时,通过精心设计的日志点,逐步重建了虚拟机的执行逻辑。