1. 逆向工程中的数组生成算法解析
最近在研究某平台JSVMP逆向时,发现其核心算法涉及多组数组的生成与组合运算。经过四天的逆向分析,我成功还原了整个计算流程。本文将详细解析这个算法的实现思路,特别适合有一定JS逆向基础但想深入理解复杂加密流程的开发者。
这个算法的核心特点是通过多个步骤生成不同位数的中间数组,最终组合运算得到目标值。整个过程涉及多种加密算法的魔改版本,包括SM3、RC4和Base64等。下面我将分步骤拆解每个数组的生成逻辑。
2. 基础数组生成过程
2.1 三个32位数组的生成
算法首先需要生成三个关键的32位数组,它们构成了整个计算流程的基础:
-
params_arr:由请求参数中的params字段加上固定盐值作为输入,经过两次魔改SM3运算得到。这里的"魔改"指的是标准SM3算法的修改版本,通常可能修改了初始常量、填充规则或轮函数等。
-
salt_arr:仅使用固定盐值作为输入,同样经过两次相同的魔改SM3运算得到。这个数组在整个流程中作为静态密钥使用。
-
ua_arr:生成逻辑最为复杂:
- 首先将userAgent字符串通过魔改RC4加密
- 将RC4结果进行魔改Base64编码
- 最后对Base64结果再进行一次魔改SM3运算
- 最终输出32位数组
提示:在实际逆向时,建议通过日志记录每个中间步骤的输出,便于验证各阶段的正确性。
2.2 44位数组的生成
这个数组的生成与设备特征相关:
- 输入参数包括屏幕宽度、高度和操作系统信息
- 具体算法可能是将这些值进行某种形式的拼接或哈希运算
- 最终输出固定为44位长度的数组
在实际逆向工程中,这类与设备特征相关的参数往往用于生成设备指纹,增加请求的唯一性和反爬难度。
3. 动态数组的生成与组合
3.1 8位数组和4位数组的生成
这两个数组的特点是长度较短且具有动态性:
-
8位数组:
- 基于随机数生成
- 可能结合了时间戳或其他熵源
- 用于增加请求的不可预测性
-
4位数组:
- 主要由时间戳运算得到
- 有时会退化为3位数组(需要特别注意这种边界情况)
- 可能用于请求时效性验证
3.2 50位数组与1位数组的生成
这一步骤是整个算法中最复杂的部分之一:
-
50位数组:
- 结合时间戳和之前生成的params_arr、salt_arr、ua_arr三个数组
- 运算过程可能涉及多轮哈希或自定义的混淆算法
- 在实际逆向中,这部分花费了我两天时间才完全理清逻辑
-
1位数组:
- 由8位数组与50位数组中的部分值运算得到
- 虽然只有1位,但在最终拼接中起到关键作用
- 可能是某种校验位或标志位
4. 最终数组的拼接与运算
4.1 140/138位数组的生成
这是整个流程的倒数第二步,涉及多个数组的智能拼接:
-
基础拼接:
- 将50位数组、44位数组、4位/3位数组和1位数组按顺序拼接
- 根据4位/3位数组的不同,会得到99位或98位的中间数组
-
中间运算:
- 99位数组经过运算得到132位数组
- 98位数组运算后得到130位数组
- 运算过程可能包括位移、置换或异或等操作
-
最终拼接:
- 将8位数组与132/130位数组拼接(8位在前)
- 最终得到140位或138位的完整数组
4.2 最终值的生成
最后一步将长数组转换为目标字符串:
-
魔改RC4加密:
- 使用自定义的RC4算法对140/138位数组进行加密
- 魔改可能涉及密钥调度或伪随机生成算法的修改
-
魔改Base64编码:
- 对RC4结果进行特殊的Base64编码
- 可能修改了编码表或填充规则
-
长度处理:
- 140位数组运算结果长度为标准的192位
- 138位数组运算结果为190位,需要在末尾补"=="
- 这是Base64编码的常见填充方式
5. 逆向工程中的实战技巧
在实际逆向这类复杂算法时,我总结了以下几点经验:
-
分阶段验证:
- 为每个中间数组设置验证点
- 通过对比正常请求的日志输出,确保每个步骤的正确性
-
算法识别技巧:
- SM3算法通常有固定的初始化常量(如0x7380166F)
- RC4算法有明显的关键字(S-box、KSA、PRGA)
- Base64编码有特征性的编码表和等号填充
-
调试方法:
- 使用console.log在关键位置输出中间值
- 对于混淆严重的代码,可以尝试AST还原或控制流平坦化解除
-
性能优化:
- 对于频繁调用的加密函数,考虑使用WebAssembly重写
- 缓存不变的中间结果(如salt_arr)
6. 常见问题与解决方案
在实现这个算法的过程中,可能会遇到以下典型问题:
-
数组长度不符:
- 检查各阶段输入的编码方式(UTF-8/Hex等)
- 验证魔改算法是否影响了输出长度
-
最终结果验证失败:
- 确认138位和140位数组的分支处理是否正确
- 检查Base64补位逻辑是否与服务器一致
-
跨平台一致性:
- 确保设备特征(如屏幕尺寸)的生成逻辑一致
- 时间戳精度要保持一致(毫秒/秒级)
-
性能瓶颈:
- 多轮哈希是性能热点,考虑使用更高效的实现
- 避免在循环中重复创建加密对象
这个算法虽然复杂,但通过系统性的分析和分阶段验证,完全可以实现可靠的本地计算。在实际应用中,它能够有效绕过平台的反爬机制,获取个人主页和评论等接口的数据。