RPC 为远程过程调用,本文通过在浏览器端(服务端)开启一个WebSocket服务,接收命令,执行浏览器网页的加密代码,得到密文。
CMD端(客户端)也开启一个WebSocket服务与浏览器端交互,通过标准输入把命令发送给浏览器执行。
RPC简单实现
原测试网站
有一个base64的加密函数,是我们要调用的函数。
function encrypt(message){
base64 = btoa(message);
console.log(base64);
return base64;
}
encrypt("abc");
浏览器本地替换:
通过浏览器的“保存并覆盖”本地替换功能,新增WebSocket通信客户端代码。
// test
function 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));
}
}
})()
Python实现websocket客户端
import sys
import asyncio
import websockets
async 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()
最终效果:
JsRpc的封装:github.com/jxhczhl/JsRpc
项目地址:https://github.com/jxhczhl/JsRpc
开启服务
go run main.go
浏览器替换JS
把JsEnv.js代码和一下代码替换。
// 注入环境后连接通信
var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=zzz&name=hlg");
执行
import requests
jscode = """
(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);
})
带多个参获 并且使用post方式 取值
//假设有一个函数 需要传递两个参数
function hlg(User,Status){
return User+"说:"+Status;
}
demo.regAction("hello3", function (resolve,param) {
//这里还是param参数 param里面的key 是先这里写,但到时候传接口就必须对应的上
res=hlg(param["user"],param["status"])
resolve(res);
})
sekiro
说明文档
构建
在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