RPC 为远程过程调用,本文通过在浏览器端(服务端)开启一个WebSocket服务,接收命令,执行浏览器网页的加密代码,得到密文。
CMD端(客户端)也开启一个WebSocket服务与浏览器端交互,通过标准输入把命令发送给浏览器执行。
有一个base64的加密函数,是我们要调用的函数。
function encrypt(message){base64 = btoa(message);console.log(base64);return base64;
}
encrypt("abc");
通过浏览器的“保存并覆盖”本地替换功能,新增WebSocket通信客户端代码。
// testfunction encrypt(message) {base64 = btoa(message);console.log(base64);return base64;
}
encrypt("abc");(function () {var ws = new WebSocket("ws://127.0.0.1:5678")ws.onmessage = function (evt) {console.log("收到消息:" + evt.data);if (evt.data == "exit") {wx.close();} else {ws.send(encrypt(evt.data));}}
})()

import sys
import asyncio
import websocketsasync def receive_message(websocket):while True:send_text = input("请输入要加密的字符串:")if send_text == "exit":print("退出!")await websocket.send(send_text)await websocket.close()sys.exit()else:await websocket.send(send_text)response_text =await websocket.recv()print("\n加密结果:", response_text)start_server = websockets.serve(receive_message, "127.0.0.1", 5678)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
最终效果:

项目地址:https://github.com/jxhczhl/JsRpc
go run main.go

把JsEnv.js代码和一下代码替换。
// 注入环境后连接通信
var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=zzz&name=hlg");

import requestsjscode = """
(function(){console.log("test")return "执行成功"
})()
"""url = "http://localhost:12080/execjs"
data = {"group": "zzz","name": "hlg","jscode":jscode
}
res = requests.post(url, data=data)
print(res.text)

或

前端注入:
// 注册一个方法 第一个参数hello为方法名,
// 第二个参数为函数,resolve里面的值是想要的值(发送到服务器的)
demo.regAction("hello", function (resolve) {//这样每次调用就会返回“好困啊+随机整数”var Js_sjz = "好困啊"+parseInt(Math.random()*1000);resolve(Js_sjz);
})
请求http://localhost:12080/go?group=zzz&name=hlg&action=hello查看JS执行结果:

//写一个传入字符串,返回base64值的接口(调用内置函数btoa)
demo.regAction("hello2", function (resolve,param) {//这样添加了一个param参数,http接口带上它,这里就能获得var base666 = btoa(param)resolve(base666);
})

//假设有一个函数 需要传递两个参数
function hlg(User,Status){return User+"说:"+Status;
}demo.regAction("hello3", function (resolve,param) {//这里还是param参数 param里面的key 是先这里写,但到时候传接口就必须对应的上res=hlg(param["user"],param["status"])resolve(res);
})

说明文档
在Linux或者mac上,执行脚本 build_demo_server.sh,之后得到产出发布压缩包:sekiro-service-demo/target/sekiro-release-demo.zip
如果是windows,或者不想自己构建,可以在这里直接下载。
运行客户端:

Sekiro代码:https://sekiro.virjar.com/sekiro-doc/assets/sekiro_web_client.js
function guid() {function S4() {return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);}return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
}var client = new SekiroClient("ws://127.0.0.1:5620/business-demo/register?group=rpc-test&clientId=" + guid());client.registerAction("encrypt", function(request, resolve, reject) {resolve(encrypt(request["data"]));
})
这里SekiroClient是用来与客户端交互的类,第一个参数是WS链接,其中group是业务分组,clientId是分组中的客户端ID。
registerAction用来注册事件,这里是encrypt。
request用来获取客户端发送来的数据,resolve用来返回客户端数据,通过request和resolve事件数据传输交互。
下图是触发rpc-test业务分组的encrypt事件,传输数据abc,返回abc的加密数据。

完整代码:
(function () {var newElement = document.createElement("script");newElement.setAttribute("type", "text/javascript");newElement.setAttribute("src", "https://sekiro.virjar.com/sekiro-doc/assets/sekiro_web_client.js");document.body.appendChild(newElement);window.encrypt= encrypt // 设置成全局函数,避免未定义function guid() {function S4() {return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);}return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());}function startSekiro() {var client = new SekiroClient("ws://127.0.0.1:5620/business-demo/register?group=rpc-test&clientId=" + guid());client.registerAction("encrypt", function (request, resolve, reject) {resolve(window.encrypt(request["data"]));})}setTimeout(startSekiro, 2000) // 等待Document加载完成
})();
https://segmentfault.com/a/1190000041440864
https://github.com/jxhczhl/JsRpc
https://github.com/virjar/sekiro