JSRPC实战:油猴脚本+JSRPC 带你秒杀 JS 加密

大家好,今天来分享使用 JSRPC+油猴脚本轻松破解 JS 加密的方法。

JSRPC 示例

还不知道 JSRPC 是什么的小伙伴,可以先看看上篇文章

本篇文章使用到的开源代码都来自于这里

首先找一个网站作为今天的例子,这里就使用猿人学内部练习平台第一题吧,比较简单并且有 header 数据加密,网站长这样:

image-20250323215616414

没有混淆,可以看到 header 加密就是一个 base64MD5,我们使用 JSRPC 来实现 header 加密数据的计算。

启动本地服务

首先需要配置 Go 环境,因为不是重点,我这里就跳过了。然后 clone 上面仓库的代码到本地,执行命令 go mod vendor 下载依赖,也可以让它自动下载,好久没用 Go 了,手动下载一下依赖,编译 macOS 平台的可执行文件。

如果大家不会配置 Go 环境也可以直接下载编译后的可执行文件,地址在这里

下载好以后,本地直接运行可执行文件,启动 websocket 服务。

image-20250323220735873

启动 web 连接

本地服务启动后,会自动监听本地的 12080 端口,等待 web 端的连接。下面新建一个油猴脚本,将仓库中的 JsEnv_Dev.js 文件内容复制出来,放到新建好油猴脚本中。

image-20250323225636754

脚本粘贴好是这样的。注意看,我在脚本的最后添加了两行代码,因为油猴脚本的执行环境不在全局,此时执行完的代码在控制台是无法访问的,所以要通过倒数第二行将 Hlclient 暴露到全局。在最后一行我打印了日志,用来判断 web 端代码是否正常执行并且生效了。

此时只是将 JSRPC 的 web 端代码提前放到了页面环境中,还没有启动 web 的连接。

全部完成后,刷新目标网页,让 JSRPC 的 web 代码生效,然后使用下面的命令启动 web 端的连接。

1
var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=zzz");

image-20250323221610468

别忘了确认一下日志是否打印,如果没有注入成功的话执行上面的代码会报错的。

image-20250323222520874

image-20250323222535820

执行完成后,可以看到,web 端打印了连接成功的日志,并且在服务端也可以看到有一个客户端上线了。此时 JSRPC 的所有准备工作就全部完成了。

连接测试

准备工作完成以后,接下来就是实际的调用测试了。准备下面的 Python 代码,发送 Post 请求,并且传入需要执行的 JS 代码,即可获取传入的 JS 代码在 web 端的执行结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests

js_code = """
(function(){
console.log("test")
return "执行成功"
})()
"""

url = "http://localhost:12080/execjs"
data = {
"group": "zzz",
"code": js_code
}
res = requests.post(url, data=data)
print(res.text)
# {"data":"执行成功","group":"zzz","name":"1bb0a0f5-c0c5-4ec3-92c2-8293b8d45eb6","status":"200"}

image-20250323223101885

查看 web 端,发现已经打印了 test 日志。

实战测试

接下来调用实际的 JS 加密代码试试,修改 Python 代码中的 JS,调用 JS 的加密函数,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import time

import requests

js_code = """
(function(){
console.log("test")
console.log(hex_md5(window.btoa(xxx + zzz)))
return hex_md5(window.btoa(xxx + zzz));
})()
"""

url = "http://localhost:12080/execjs"
data = {
"group": "zzz",
"code": js_code.replace('xxx', '1').replace('zzz', str(int(time.time())))
}
res = requests.post(url, data=data)
print(res.text)
# {"data":"75d6dd2263ea30421aa9e9a859be77fb","group":"zzz","name":"1bb0a0f5-c0c5-4ec3-92c2-8293b8d45eb6","status":"200"}

image-20250323223734792

可以看到 web 端打印了日志,并且 Python 也获取到了调用 hex_md5 的结果。

接下来将获取到的 sign 值传入服务端获取数据试试,修改代码,将获取 sign 值和抓取数据的代码放到一起运行:

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
import time

import requests

url = "https://www.xxxxx/api/challenge1"
js_code = """
(function(){
console.log("test")
console.log(hex_md5(window.btoa(xxx + zzz)))
return hex_md5(window.btoa(xxx + zzz));
})()
"""
t = str(int(time.time()))
data = {
"group": "zzz",
"code": js_code.replace('xxx', '1').replace('zzz', t)
}
res = requests.post('http://localhost:12080/execjs', data=data).json()
print(res)
headers = {
'accept': 'application/json, text/javascript, */*; q=0.01',
'accept-language': 'zh-CN,zh;q=0.9',
'cache-control': 'no-cache',
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
'cookie': 'no-alert=true; sessionid=xxxxx1ynp',
'safe': res['data'],
'timestamp': t,
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'x-requested-with': 'XMLHttpRequest'
}
payload = "page=1"
response = requests.request("POST", url, headers=headers, data=payload).json()
print(response)

image-20250323224345099

image-20250323224403761

可以看到,web 端打印了对应的日志,并且 Python 代码也获取到了正确的结果。

总结

整个过程中除了搭建环境,我们并没有对具体的 JS 加密代码进行逆向,只是将 JSRPC 的代码注入到了浏览器中,并且动态的调用加密函数输出结果。

此方案几乎可以在任何网站上使用,只要能找到加密函数即可动态调用。当然了,并不是所有的加密函数都是导出到全局的,如果遇到只能在某段代码内部调用的加密函数,可以通过动态 AST+动态注入 JSRPC 代码的方式来强制将其暴露到全局,方便通过 JSRPC 来调用。

执行完 JSRPC 代码注入,还要手动执行连接 websocket 服务器,这里其实也可以一步到位的,直接在注入代码后启动 websocket 的连接,感兴趣的小伙伴可以自己试试。

本文章首发于个人博客 LLLibra146’s blog

本文作者:LLLibra146

更多文章请关注公众号 (LLLibra146):LLLibra146

版权声明:本博客所有文章除特别声明外,均采用 © BY-NC-ND 许可协议。非商用转载请注明出处!严禁商业转载!

本文链接
https://blog.d77.xyz/archives/ae6ce577.html