抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

JS 前端逆向解密

最近学习的时候,遇到一个网站,因为手动输入邀请码觉得很麻烦,就想写个小脚本去处理,在实践的过程中,发现它对后端返回的内容进行了加密。遂,开始研究,对算法进行解密

思路说明

  1. 先发包,抓包,发现了被加密的内容

  2. JS前端进行断点调试

  3. 找到_encrypteData 参数

  4. 根据堆栈内提到的文件,去筛选decrypt文件。

  5. 分析decrypt文件,确认加密模式:AES-CBC 的加密方式【GPT辅助分析】

  6. 在decrypt JS 中,去寻找固定密钥(字节数组)【GPT辅助分析,让它去找到密钥】

  7. 根据密钥和加密算法,写对应的解密python脚本

具体实践

JS前端进行断点调试

F12,打开开发者,在控制台输入以下代码,进行断点调试

1
2
3
4
5
6
7
8
(function(){
var parse_ = JSON.parse;
JSON.parse = function(arg){
console.log('断住了');
debugger;
return parse_(arg);
}
})()

点击想要调试的位置,会自动断点

最右是打开/关闭断点的按钮,最左是放行/拦截,中间是跳入下一个函数、跳入上一个函数,调试按钮。

先点击想要破解数据包的那个功能键,让数据产生的过程“暂停”。在达到这个功能点之前,可以先不开启断点功能。在准备点击这个功能点的时候,再打开断点。点击打开/关闭断点的按钮,让它处于正在断点的过程。
比如我准备发的包,是在点击确认之后产生的,我整个调试界面,就是停在了,确认已经被点击下去的页面。

找到_encrypteData 参数

我们在准备点击确认的时候,开启了断点调试。然后点击确认,再放行,断点就会直接跑到加密的那个地方。

此时我们调试的意义就是,开始探究:从点击确认之后 到 产生想要破解的数据包,这个过程,函数的调用和数据的流向。

根据堆栈内提到的文件,去筛选decrypt文件

右边是整个函数调用的堆栈,既然已经找到加密后的数据,那就一定可以在这个调用的堆栈中找到解密的过程。我在这里直接开始输入关键词decrypt进行搜索

分析decrypt文件,确认加密模式:AES-CBC 的加密方式【GPT辅助分析】

在这里我们就可以清晰的看到它的整个加解密过程了,我直接发给GPT让它给我分析加密算法了。 分析过后,发现是采用的AES-CBC的加密方式。 并且找到了固定密钥就在JS文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
e.prototype.encrypt = function(e) {
if (16 != e.length)
throw new Error("invalid size ");
for (var t = this._Ke.length - 1, r = [0, 0, 0, 0], n = M(e), o = 0; o < 4; o++)
n[o] ^= this._Ke[0][o];
for (var a = 1; a < t; a++) {
for (o = 0; o < 4; o++)
r[o] = l[n[o] >> 24 & 255] ^ d[n[(o + 1) % 4] >> 16 & 255] ^ h[n[(o + 2) % 4] >> 8 & 255] ^ p[255 & n[(o + 3) % 4]] ^ this._Ke[a][o];
n = r.slice()
}
var s, c = i(16);
for (o = 0; o < 4; o++)
s = this._Ke[t][o],
c[4 * o] = 255 & (u[n[o] >> 24 & 255] ^ s >> 24),
c[4 * o + 1] = 255 & (u[n[(o + 1) % 4] >> 16 & 255] ^ s >> 16),
c[4 * o + 2] = 255 & (u[n[(o + 2) % 4] >> 8 & 255] ^ s >> 8),
c[4 * o + 3] = 255 & (u[255 & n[(o + 3) % 4]] ^ s);
return c
}
,
e.prototype.decrypt = function(e) {
if (16 != e.length)
throw new Error("invalid size");
for (var t = this._Kd.length - 1, r = [0, 0, 0, 0], n = M(e), o = 0; o < 4; o++)
n[o] ^= this._Kd[0][o];
for (var a = 1; a < t; a++) {
for (o = 0; o < 4; o++)
r[o] = v[n[o] >> 24 & 255] ^ _[n[(o + 3) % 4] >> 16 & 255] ^ y[n[(o + 2) % 4] >> 8 & 255] ^ g[255 & n[(o + 1) % 4]] ^ this._Kd[a][o];
n = r.slice()
}
var s, c = i(16);
for (o = 0; o < 4; o++)
s = this._Kd[t][o],
c[4 * o] = 255 & (f[n[o] >> 24 & 255] ^ s >> 24),
c[4 * o + 1] = 255 & (f[n[(o + 3) % 4] >> 16 & 255] ^ s >> 16),
c[4 * o + 2] = 255 & (f[n[(o + 2) % 4] >> 8 & 255] ^ s >> 8),
c[4 * o + 3] = 255 & (f[255 & n[(o + 1) % 4]] ^ s);
return c
}
,
e
}()
, k = function() {
function e(e, t) {
this.description = "Cipher Block Chaining",
this.name = "cbc",
this._lastCipherblock = n(t, !0),
this._aes = new P(e)
}
return e.prototype.encrypt = function(e) {
if (e = n(e),
e.length % 16 !== 0)
throw new Error("invalid size ");
for (var t = i(e.length), r = i(16), o = 0; o < e.length; o += 16) {
a(e, r, 0, o, o + 16);
for (var s = 0; s < 16; s++)
r[s] ^= this._lastCipherblock[s];
this._lastCipherblock = this._aes.encrypt(r),
a(this._lastCipherblock, t, o)
}
return t
}

找到固定密钥:

根据密钥和加密算法,写对应的解密python脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad


def decrypt_encrypted_data(encrypted_base64):
# 固定密钥(字节数组)
key_bytes = [121, 118, 106, 67, 75, 77, 48, 89, 38, 122, 59, 33, 50, 111, 108, 97]
key = bytes(key_bytes)

# Base64解码
encrypted_data = base64.b64decode(encrypted_base64)

# 取前16字节作为IV
iv = encrypted_data[:16]
# 剩余部分作为密文
ciphertext = encrypted_data[16:]

# 创建AES-CBC解密器
cipher = AES.new(key, AES.MODE_CBC, iv)

# 解密并去除填充
decrypted = unpad(cipher.decrypt(ciphertext), AES.block_size)

# 返回解密后的字符串
return decrypted.decode('utf-8')


# 解密
if __name__ == "__main__":
encrypted_data = "EZacB6qmYPlTsOQ8U4AQuZFt/E0sRXzQU9wdmyU5O73XJutsiHuoPVGA7/+ycALt+t6+MoNYfbNL6qVLYSw4EW+VDhazOwGJm9lTlaw4VivSkV+O3Nqjj6Pk8jqRf5dsUwM7itBDMz2oVjFTVrgvfT4Cl+7QgarNX9MHinXQShKLfHhLzyM2z+46O7GDWFSr0JwO3J8ggUnN/m3JD4peOhYrCCKtKFbhxm0gj5aob8fSR8OU+yp2S/bSROcCuOd02MTeX/qX7BBbh6xX2Z29MYPVNp9zKy0ttnsX6fsiMFA="

try:
decrypted_text = decrypt_encrypted_data(encrypted_data)
print("解密后的内容:", decrypted_text)
except Exception as e:
print("解密失败:", str(e))

碎碎念

真的好喜欢GPT的时代,我给他提供思路和我的需求,它来实现具体细节。它分析的过程,也可以给我思路启发,更快的上手学会一个东西。我不用去纠结那些事情的细节,代码的细节,不用去操心具体的实现,只需要专注于事情的主体框架。我真的好喜欢这样的感觉,这才是我的价值。

我的价值不是去死扣细节和缓慢的学习代码,我的价值是我的大脑和我的思维。

我以前的劣势就是,有点强迫症,在学技术细节的时候,会钻牛角,而偏离我的主体框架核心。最后导致事情无法完成,现在就不会这样了,我有想法就去和GPT探讨,根据它给我的思路,我就有了开始学习的方向,在每一个大方向上往前走,再也没有以前那种被困住手脚无法施展的限制感了。

评论