成都大学JS 逆向

一、报告概述

1.1 分析目标

本次针对新业务系统的前端加密逻辑开展 JS 逆向分析,核心目标为定位并还原 AES 加密函数的实现逻辑、明确加密参数来源,验证加密算法的完整性与正确性,为后续自动化对接、数据解密等场景提供技术支撑。

1.2 分析环境

  • 调试工具:Chrome DevTools(断点调试、调用栈追踪、全局搜索)
  • 运行环境:Node.js v16+
  • 核心依赖:CryptoJS(前端 AES 加密底层库)
  • 分析对象:混淆后的业务加密 JS 文件

二、加密逻辑逆向过程

2.1 加密入口定位

通过 Chrome DevTools 的全局搜索与断点调试

2.1.1 加密函数的位置

在每个文件搜索 encrypt 关键字

在这个位置找到了可疑的函数,去混淆之后发现定位到的是业务层的核心加密函数 aesEncrypt,这正是我们一直在找的加密入口,只是不是我们输入传入的地方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 混淆前的原始逻辑
static aesEncrypt(plaintext, key) {
// 解析明文为 WordArray
const parsedPlaintext = CryptoJS.enc.Utf8.parse(plaintext);
// 解析密钥为 WordArray
const parsedKey = CryptoJS.enc.Utf8.parse(key);
// 执行 AES-CBC 加密
const encrypted = CryptoJS.AES.encrypt(parsedPlaintext, parsedKey, {
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
// 返回 Base64 编码的密文
return encrypted.toString();
}

img

2.1.2 业务逻辑加密

通过调用堆栈找到了业务逻辑加密的地方

img

去混淆之后

1
2
3
4
5
// 原始混淆代码还原
const passwordInput = document.querySelector("input[type='password']");
// 核心加密调用:对密码进行 AES 加密
passwordInput.setAttribute("value", aesEncrypt(_0x3a9405, this['password']));
passwordInput.setAttribute("style", "display:none");

_0x3a9405:加密密钥

this['password']:用户输入的原始明文密码

aesEncrypt: AES-CBC 加密函数

作用:加密后的密码会被设置到隐藏的密码输入框中,最终随表单提交

2.1.3 找到加密函数

现在我们去全局搜索aesEncrypt 这个函数

img

定位到的是业务层的核心加密函数 aesEncrypt,这正是我们一直在找的加密入口。我帮你把这段混淆代码还原成清晰的逻辑:

去混淆后的等价代码

1
// 混淆前的原始逻辑static aesEncrypt(plaintext, key) {// 解析明文为 WordArrayconst parsedPlaintext = CryptoJS.enc.Utf8.parse(plaintext);// 解析密钥为 WordArrayconst parsedKey = CryptoJS.enc.Utf8.parse(key);// 执行 AES-CBC 加密const encrypted = CryptoJS.AES.encrypt(parsedPlaintext, parsedKey, {mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.Pkcs7});// 返回 Base64 编码的密文return encrypted.toString();}

关键参数映射

从调试信息可以看到:

  • 0x4e34ef:明文参数(值为 "111"
  • 0x14850a:密钥参数(值为 "DV9fY1l9silfXu8e+ILxSQ=="
  • 0x35af68:解析后的明文(WordArray 类型)
  • 0x2af56:解析后的密钥(WordArray 类型)
  • 0x5a875CryptoJS 对象的混淆别名

2.1.4 找到了底层加密函数 (AES)

知道了是 AES 加密

img

函数本质这个 aesEncrypt 函数就是封装了 CryptoJS.AES.encrypt 的业务加密逻辑。

  • 0x2d62d8 是明文参数,调试时显示为 BFgVB/F1EFFHfGmQJUS553Cg==
  • 0x1807cf 是加密配置参数,包含了密钥和向量等信息
  • 加密模式:EBC
  • 填充方式:Pkcs7

混淆特征变量名(如 0x4517180x327bac)和函数名都是经过混淆器生成的乱码,这是为了增加逆向难度。但核心调用 CryptoJS.AES.encrypt 是不变的,这是定位的关键。

2.1.5 找到了底层加密逻辑

img

2.2 关键参数解析

通过调试器实时监控,获取到加密函数的核心参数信息:

参数类型 混淆变量名 实际值 说明
明文 0x4e34ef “111” 业务层传入的原始待加密数据
密钥 0x14850a “DV9fY1l9silfXu8e+ILxSQ==” 加密使用的核心密钥(Base64 编码格式)
加密模式 - CBC 固定使用 CBC 模式,无动态切换逻辑
填充方式 - Pkcs7 满足 AES 128 位分组长度要求
初始向量(IV) - 未显式配置 采用 CryptoJS 默认 IV 生成规则

2.3 加密链路验证

2.4.1 断点验证

aesEncrypt函数返回行下断点,执行加密逻辑后获取调试器内加密结果,与抓包获取的密文对比,验证逻辑一致性(差异仅源于随机 IV,属于正常现象)。

2.4.2 本地复现验证

将还原后的加密函数移植到 Node.js 环境,使用相同参数测试:

1
const CryptoJS = require('crypto-js');// 还原后的加密函数function aesEncrypt(plaintext, key) {const parsedPlaintext = CryptoJS.enc.Utf8.parse(plaintext);const parsedKey = CryptoJS.enc.Utf8.parse(key);const encrypted = CryptoJS.AES.encrypt(parsedPlaintext, parsedKey, {mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.Pkcs7});return encrypted.toString();}// 测试执行const plaintext = "111";const key = "DV9fY1l9silfXu8e+ILxSQ==";const encryptedResult = aesEncrypt(plaintext, key);console.log("本地加密结果:", encryptedResult);

验证结论:本地复现结果与调试器内加密结果格式一致、算法逻辑一致,加密函数还原准确。