油猴脚本+JSRPC远程调用浏览器原生函数,逆向免扣js
作者:YXN-python 阅读量:76 发布日期:2025-04-02
JSRPC 技术通过远程调用浏览器原生函数,可绕过逆向分析直接获取加密结果。
此文只做简单讲解,详情可以移步官方文档
开源地址:https://github.com/jxhczhl/JsRpc
1、启动服务
下载编译后的可执行文件后运行,地址:https://github.com/jxhczhl/JsRpc/releases
2、启动 web 连接
两种方式:直接在浏览器控制台输入脚本代码或者添加油猴脚本。
脚本地址:https://github.com/jxhczhl/JsRpc/blob/main/resouces/JsEnv_Dev.js
注意:启动之后,控制台可以关,但是注入的网页不要关
添加油猴脚本如下:
// ==UserScript==
// @name JSRPC
// @namespace http://tampermonkey.net/
// @version 0.1
// @description JSRPC
// @author jxhczhl
// @match http*://*/*
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
var rpc_client_id, Hlclient = function (wsURL) {
this.wsURL = wsURL;
this.handlers = {
_execjs: function (resolve, param) {
var res = eval(param)
if (!res) {
resolve("没有返回值")
} else {
resolve(res)
}
}
};
this.socket = undefined;
if (!wsURL) {
throw new Error('wsURL不能为空!!')
}
this.connect()
}
Hlclient.prototype.connect = function () {
if (this.wsURL.indexOf("clientId=") === -1 && rpc_client_id) {
this.wsURL += "&clientId=" + rpc_client_id
}
console.log('开始连接到wsURL: ' + this.wsURL);
var _this = this;
try {
this.socket = new WebSocket(this.wsURL);
this.socket.onmessage = function (e) {
_this.handlerRequest(e.data)
}
} catch (e) {
console.log("连接失败,10s后重新连接...");
setTimeout(function () {
_this.connect()
}, 10000)
}
this.socket.onclose = function () {
console.log('rpc已关闭');
setTimeout(function () {
_this.connect()
}, 10000)
}
this.socket.addEventListener('open', (event) => {
console.log("rpc连接成功");
});
this.socket.addEventListener('error', (event) => {
console.error('rpc连接出错,请检查是否打开服务端:', event.error);
})
};
Hlclient.prototype.send = function (msg) {
this.socket.send(msg)
}
Hlclient.prototype.regAction = function (func_name, func) {
if (typeof func_name !== 'string') {
throw new Error("func_name必须是字符串");
}
if (typeof func !== 'function') {
throw new Error("必须是函数");
}
console.log("register func_name: " + func_name);
this.handlers[func_name] = func;
return true
}
Hlclient.prototype.handlerRequest = function (requestJson) {
var _this = this;
try {
var result = JSON.parse(requestJson)
} catch (error) {
console.log("请求信息解析错误", requestJson);
return
}
if (result["registerId"]) {
rpc_client_id = result['registerId']
return
}
if (!result['action'] || !result["message_id"]) {
console.warn('没有方法或者消息id,不处理');
return
}
var action = result["action"], message_id = result["message_id"]
var theHandler = this.handlers[action];
if (!theHandler) {
this.sendResult(action, message_id, 'action没找到');
return
}
try {
if (!result["param"]) {
theHandler(function (response) {
_this.sendResult(action, message_id, response);
})
return
}
var param = result["param"]
try {
param = JSON.parse(param)
} catch (e) {
}
theHandler(function (response) {
_this.sendResult(action, message_id, response);
}, param)
} catch (e) {
console.log("error: " + e);
_this.sendResult(action, message_id, e);
}
}
Hlclient.prototype.sendResult = function (action, message_id, e) {
if (typeof e === 'object' && e !== null) {
try {
e = JSON.stringify(e)
} catch (v) {
console.log(v)//不是json无需操作
}
}
this.send(JSON.stringify({"action": action, "message_id": message_id, "response_data": e}));
}
window.Hlclient = Hlclient;
console.log('jsrpc!');
var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=zzz");
})();
如果是控制台注入的,则还需要在控制台建立连接,如果是油猴脚本,上面代码添加了就不需要了
var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=zzz");
3、连接测试
import requests
js_code = """
(function(){
console.log("测试执行")
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"}
4、实战测试
执行完后可以在网站看到一个一秒钟的消息弹窗
import requests
js_code = """
(function(){
console.log(showMessage('测试弹窗'));
return '执行弹窗成功'
})()
"""
url = "http://localhost:12080/execjs"
data = {
"group": "zzz",
"code": js_code
}
res = requests.post(url, data=data)
print(res.text)
5、api 简介
- /list :查看当前连接的ws服务 (get)
- /ws :浏览器注入ws连接的接口 (ws | wss)
- /wst :ws测试使用-发啥回啥 (ws | wss)
- /go :获取数据的接口 (get | post)
- /execjs :传递jscode给浏览器执行 (get | post)
- /page/cookie :直接获取当前页面的cookie (get)
- /page/html :获取当前页面的html (get)
YXN-python
2025-04-02