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加載完成
})();