JS逆向基础
# JS逆向介绍
# 简介
JavaScript 逆向(简称 JS 逆向)指的是对已经上线、经过混淆或加密的前端脚本进行分析、理解并在必要时修改其行为的过程。常用于绕过反爬、获取接口签名、破解验证码或调试前端安全机制。
# 常见应用场景
- 反爬虫/数据抓取:解析页面动态生成的token、签名或加密参数,以实现自动化爬取。
- 验证码/滑块破解:逆向滑块验证码的加密逻辑,模拟合法交互。
- 前端加密/签名:还原AES、RSA、MD5等加密算法,复现前端请求的加密过程。
- 安全审计:检查前端代码中的安全漏洞或后门。
# 基本逆向流程
- 环境准备:打开浏览器开发者工具,可以查看源码、设置断点、监控网络请求。
- 静态分析:使用
Beautifier、JSNice、Unpacker对压缩/混淆代码进行格式化和变量恢复。 - 动态调试:设置
debugger断点,或使用console.log、monitorEvents追踪函数调用。 - 网络抓包:通过
Network、Burp Suite、Fiddler捕获XHR/Fetch请求,定位加密参数。 - 代码解密:识别常见加密(
Base64、AES、RSA、MD5)并在Node.js/Python中复现。 - 重构/复现:编写脚本(
Node、Python)模拟前端加密逻辑,完成数据获取或功能修改。 - 验证:对比原始请求与复现请求的响应,确保逆向成功。
# Python执行JS代码
Python中可以通过模块调用Node.js来执行JS代码。
# 安装PyExecJS库
pip install PyExecJS
# 导入库
import execjs
# 获取一个JS运行时环境,传入JS代码
# 一般会用open()函数打开文件读取代码来传入
ejs = execjs.compile("function add(x, y) {return x + y;}")
# 调用指定JS函数,后面可传入参数
result = ejs.call("add", 1, 2)
print(result)
2
3
4
5
6
7
8
9
10
11
12
13
14
使用PyExecJS库需要确保已安装Node.js环境。
# MD5摘要算法
# 介绍
MD5是摘要算法,并非加密算法,他本质上是一种哈希函数。能把任意长度的输入数据映射为固定的32 个十六进制字符输出(128 位),输出的32位字符就是散列值,也称摘要值。
因此看到32位长度的16进制字符串,就要首先想到MD5。
# 特点
- 单向性:从原始数据可以算出MD5值,但根据MD5值几乎不可能逆推出原始数据。
- 确定性:相同的输入总会得到相同的MD5值。
- 碰撞可能:不同的输入有时会产生相同的MD5值(已被实验证明),因此不适合作为安全加密手段。
# Hashlib模块
Hashlib用于实现常见的哈希算法。
# 常见算法
MD5
最常用的算法,速度很快,它的结果是32位的16进制字符串。
SHA1
比MD5更安全一点,它的结果是40位的16进制字符串。
SHA256和SHA512
比SHA1更安全的算法,但越安全,速度越慢。
注意:算法越安全,速度越慢,摘要长度越长。
# 使用方法
Python使用
# 内置的直接导入模块即可
import hashlib
# 获得MD5散列生成器对象
# sha1等算法也是一样的用法,例如hashlib.sha1("xxx")
# 可以在这里加盐,再调用update前,事先就在其中加上"Test"
hash_obj = hashlib.md5(b'Test')
# 传入Bytes类型,得到MD5散列
hash_obj.update("English中文".encode('utf-8'))
# 传入的值不会清空,下次再update传入值时,则会拼接上次传入的值,所以也可以用来加盐
# 获得产生的hash值
res = hash_obj.hexdigest()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Node.js使用
// 安装crypto-js模块
npm install crypto-js
// 导入模块
const CryptoJS = require("crypto-js");
// 获取MD5散列
let res = CryptoJS.MD5("English中文").toString()
2
3
4
5
6
7
8
# 使用案例
校验文件一致性
import hashlib
mdfive = hashlib.md5()
with open('test.txt', 'rb') as f:
for line in f:
mdfive.update(line)
print(mdfive.hexdigest())
2
3
4
5
6
# Base64编码
# 介绍
Base64的编码表由64个字符组成,Base64编码能将任意二进制数据(如图片、音频、文件等)转换为仅包含ASCII字符的字符串,以便在只能使用文本的环境中传输。
Base64编码表包括26个小写字母、26个大写字母、10个数字、符号"+"和符号"/"。

# 原理
首先将二进制流按6位一组,不足6位的在末尾补0。
6位二进制(2⁶),刚好可以映射64个Base64编码的索引。
然后将每组转为十进制得到编码表索引,去Base64编码表查找对应的字符。
最后若原始字节数(8位=1字节)不是3的倍数,则在末尾填充
=作为占位。填充用于指示实际数据的长度,便于后续正确解码。原始数据
"A"(1 字节) → Base64编码QQ==原始数据
"AB"(2 字节) → 编码QUI=原始数据
"ABC"(3 字节) → 编码QUJD原始数据
"ABCD"(4 字节) → 编码QUJDRA==
# 例如abcd的二进制
# 首先将abcd转为十进制的ASCII码,再将ASCII码转为对应的二进制
a -> 97 -> 0110 0001
b -> 98 -> 0110 0010
c -> 99 -> 0110 0011
d -> 100 -> 0110 0100
# 然后将得到的二进制拼接,并按6位一组进行分组,如果最后不足6位则用0补齐到6位
011000 010110 001001 100011 011001 000000
# 然后将分组后的二进制结果都转为十进制数作为索引
011000 010110 001001 100011 011001 000000
↓ ↓ ↓ ↓ ↓ ↓
24 22 9 35 25 0
# 最后去Base64编码表根据索引找到对应字符即可
24 22 9 35 25 0 -> YWJjZA
# 最后因为原始字节是4个,差几个到3的倍数,就在末尾填充几个=号,得到最终结果
YWJjZA==
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 加密算法
# 介绍
加密算法是把明文(可读信息)转换为密文(不可读信息)的数学方法,只有拥有相应密钥的主体才能恢复原文。按照密钥的使用方式,常把加密算法分为对称加密与非对称加密两大类。
# 分类
对称加密
| 特点 | 说明 |
|---|---|
| 密钥唯一 | 加密和解密使用同一把密钥(或等价的密钥)。发送方和接收方必须事先共享此密钥。 |
| 速度快 | 计算量小,适合大批量数据的加密(如文件、磁盘、网络流)。 |
| 密钥管理挑战 | 随着通信方增多,需要为每对通信方分配独立密钥,密钥分发和存储成为安全瓶颈。 |
| 常见算法 | AES:分 128、192、256 位密钥,分块模式有ECB、CBC、CFB、OFB、CTR、GCM等。 |
非对称加密
| 特点 | 说明 |
|---|---|
| 密钥对 | 每个主体拥有一对密钥:公钥(公开)和 私钥(保密)。公钥用于加密或验证签名,私钥用于解密或生成签名。 |
| 解决密钥分发 | 只需公开公钥,通信双方无需提前共享密钥,适合开放网络环境。 |
| 计算开销大 | 相比对称加密慢得多,通常只用于加密少量数据(如会话密钥、对称密钥)或数字签名。 |
| 常见算法 | RSA:基于大整数分解难题,密钥长度常见2048、3072、4096位。 |
结合使用
实际使用时一般会两者结合使用,以兼顾安全性与性能。
密钥协商:使用非对称算法安全地传输一个随机生成的会话密钥。
数据加密:会话密钥采用高速的对称算法对大量业务数据进行加密。
# JS逆向技巧
如果直接请求无法获取数据,则说明需要JS逆向解密,可以在请求头、请求体中看看有没有疑似口令或加密相关的参数。
源代码中搜索参数关键字时,如果结果太多,可以双引号将其括起来
"参数"。如果搜索结果仍然过多,还可以尝试使用单词边界
\b参数\b来进行搜索,需要打开正则匹配。\b匹配的是单词的边界,而非任何字符。它只是一个位置,这个位置的一侧是单词字符,另一侧为非单词字符。
搜索到的JS代码加上断点,一个一个尝试,就能找到关键的代码,然后可以借助AI来分析关键代码函数,也可以直接丢到JS文件中调用获取加密信息。
如果响应数据是由大小写字母、数字以及符号"
+=/"组成,则很有可能是Base64编码,可以直接尝试Base64解码。如果疑似有加密算法,可以尝试搜索关键字"
decrypt\b"等加密相关的函数或参数,然后加上断点排查找到关键代码。