有时候遇到一些加密参数,我们不想知道它是怎么生成的,只想取它的值,这种情况下就适合使用RPC了 第一种使用websocket的方式,通过油猴脚本把浏览器生成好的加密参数通过socket通信方式发送到本地 以这个网址为例,这是一个rs的网址 http://www.nhc.gov.cn/ 查看一下源代码,懂得都懂
油猴脚本代码
(function() {
window.ws = new WebSocket('ws://127.0.0.1:8010/');
ws.onopen = function(){
console.log("连接服务器成功");
ws.send("Browser start");
};
ws.onclose = function(){
console.log("服务器关闭");
};
ws.onerror = function(){
console.log("连接出错");
};
ws.onmessage = function(evt){
console.log(evt.data)
console.log(document.cookie);
}
})();
本地使用python去连接
import asyncio
import websockets
async def recv_msg(websocket):
while True:
recv_text = await websocket.recv()
print(recv_text)
await websocket.send(recv_text)
async def main(websocket, path):
await recv_msg(websocket)
start_server = websockets.serve(main, 'localhost', 8010)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
先运行python,再刷新对应的网址 在控制台输入ws.send(document.cookie) python就可以接受到cookie 效果如下
发现只有一个sVoELocvxVW0T,应该有三个cookie的才对 这里需要在浏览器上设置一下
打了勾的是无法获取,需要双击后点击取消掉 现在三个cookie都能拿到 试下能不能拿到网页数据
上面的方式虽然可以拿到cookie,但是每次都需要去控制台send 能不能做成api的形式 请求一下就可以拿到cookie的 当然有了,这里大力推荐渣总的Sekrio框架
Sekrio
渣总开发的框架,现成轮子使用、更简单的接入rpc github: https://github.com/virjar/sekiro 官方文档:https://sekiro.virjar.com/sekiro-doc/index.html 我用的是window,操作以window为例
安装
先把代码下载下来 然后双击运行 build_demo_server.sh 它会自动构建
构建完成之后 在sekiro-service-demo\target\sekiro-release-demo\bin下有两个启动文件,bat结尾的win,sh是linux 运行sekiro.bat
可以链接查看是否正常启动 http://127.0.0.1:5620/business-demo/groupList
样例
先把案例跑通, 把https://sekiro.virjar.com/sekiro-doc/assets/sekkiro_js_demo.html页面源码都复制下来 创建一个html文件粘贴进去 然后把其中代码修改一下
<script type="text/javascript" src="sekiro_web_client.js"></script>
改为
<script type="text/javascript" src="https://sekiro.virjar.com/sekiro-doc/assets/sekiro_web_client.js"></script>
它里面连接的是自己的服务器 如果要把服务器改为自己的话,就把
var client = new SekiroClient("wss://sekiro.virjar.com/business/register?group=ws-group&clientId=" + guid());
改为
var client = new SekiroClient("ws://127.0.0.1:5620/business-demo/register?group=ws-group&clientId=" + guid());
运行,在浏览器打开控制台可以看到
浏览器访问 http://127.0.0.1:5620/business-demo/groupList 看到服务已开启
{"data":["test","ws-group"],"ok":true,"status":0}
用python测试一下
import requests
params ={
"group":"ws-group",
"action":"executeJs",
}
res = requests.get("http://127.0.0.1:5620/business-demo/invoke", params=params)
print(res.text)
修改端口
Sekrio默认的端口是5620 需要修改的话 在项目根目录下\sekiro-service-demo\target\sekiro-release-demo\conf\config.properties进行修改即可
rs网站实战
这里的话还是用上面的网址 这里我们需要油猴来做服务
编辑脚本
新建油猴脚本
访问https://sekiro.virjar.com/sekiro-doc/assets/sekiro_web_client.js 把sekrio依赖的js脚本复制放到油猴里 并上面样例的html里的这几行也复制进油猴里
修改下executeJs接口,获取cookie后把值传出来
完整的油猴脚本:
(function() {
function SekiroClient(wsURL) {
this.wsURL = wsURL;
this.handlers = {};
this.socket = {};
if (!wsURL) {
throw new Error('wsURL can not be empty!!')
}
this.webSocketFactory = this.resolveWebSocketFactory();
this.connect()
}
SekiroClient.prototype.resolveWebSocketFactory = function () {
if (typeof window === 'object') {
var theWebSocket = window.WebSocket ? window.WebSocket : window.MozWebSocket;
return function (wsURL) {
function WindowWebSocketWrapper(wsURL) {
this.mSocket = new theWebSocket(wsURL);
}
WindowWebSocketWrapper.prototype.close = function () {
this.mSocket.close();
};
WindowWebSocketWrapper.prototype.onmessage = function (onMessageFunction) {
this.mSocket.onmessage = onMessageFunction;
};
WindowWebSocketWrapper.prototype.onopen = function (onOpenFunction) {
this.mSocket.onopen = onOpenFunction;
};
WindowWebSocketWrapper.prototype.onclose = function (onCloseFunction) {
this.mSocket.onclose = onCloseFunction;
};
WindowWebSocketWrapper.prototype.send = function (message) {
this.mSocket.send(message);
};
return new WindowWebSocketWrapper(wsURL);
}
}
if (typeof weex === 'object') {
try {
console.log("test webSocket for weex");
var ws = weex.requireModule('webSocket');
console.log("find webSocket for weex:" + ws);
return function (wsURL) {
try {
ws.close();
} catch (e) {
}
ws.WebSocket(wsURL, '');
return ws;
}
} catch (e) {
console.log(e);
}
}
if (typeof WebSocket === 'object') {
return function (wsURL) {
return new theWebSocket(wsURL);
}
}
throw new Error("the js environment do not support websocket");
};
SekiroClient.prototype.connect = function () {
console.log('sekiro: begin of connect to wsURL: ' + this.wsURL);
var _this = this;
try {
this.socket = this.webSocketFactory(this.wsURL);
} catch (e) {
console.log("sekiro: create connection failed,reconnect after 2s");
setTimeout(function () {
_this.connect()
}, 2000)
}
this.socket.onmessage(function (event) {
_this.handleSekiroRequest(event.data)
});
this.socket.onopen(function (event) {
console.log('sekiro: open a sekiro client connection')
});
this.socket.onclose(function (event) {
console.log('sekiro: disconnected ,reconnection after 2s');
setTimeout(function () {
_this.connect()
}, 2000)
});
};
SekiroClient.prototype.handleSekiroRequest = function (requestJson) {
console.log("receive sekiro request: " + requestJson);
var request = JSON.parse(requestJson);
var seq = request['__sekiro_seq__'];
if (!request['action']) {
this.sendFailed(seq, 'need request param {action}');
return
}
var action = request['action'];
if (!this.handlers[action]) {
this.sendFailed(seq, 'no action handler: ' + action + ' defined');
return
}
var theHandler = this.handlers[action];
var _this = this;
try {
theHandler(request, function (response) {
try {
_this.sendSuccess(seq, response)
} catch (e) {
_this.sendFailed(seq, "e:" + e);
}
}, function (errorMessage) {
_this.sendFailed(seq, errorMessage)
})
} catch (e) {
console.log("error: " + e);
_this.sendFailed(seq, ":" + e);
}
};
SekiroClient.prototype.sendSuccess = function (seq, response) {
var responseJson;
if (typeof response == 'string') {
try {
responseJson = JSON.parse(response);
} catch (e) {
responseJson = {};
responseJson['data'] = response;
}
} else if (typeof response == 'object') {
responseJson = response;
} else {
responseJson = {};
responseJson['data'] = response;
}
if (Array.isArray(responseJson)) {
responseJson = {
data: responseJson,
code: 0
}
}
if (responseJson['code']) {
responseJson['code'] = 0;
} else if (responseJson['status']) {
responseJson['status'] = 0;
} else {
responseJson['status'] = 0;
}
responseJson['__sekiro_seq__'] = seq;
var responseText = JSON.stringify(responseJson);
console.log("response :" + responseText);
this.socket.send(responseText);
};
SekiroClient.prototype.sendFailed = function (seq, errorMessage) {
if (typeof errorMessage != 'string') {
errorMessage = JSON.stringify(errorMessage);
}
var responseJson = {};
responseJson['message'] = errorMessage;
responseJson['status'] = -1;
responseJson['__sekiro_seq__'] = seq;
var responseText = JSON.stringify(responseJson);
console.log("sekiro: response :" + responseText);
this.socket.send(responseText)
};
SekiroClient.prototype.registerAction = function (action, handler) {
if (typeof action !== 'string') {
throw new Error("an action must be string");
}
if (typeof handler !== 'function') {
throw new Error("a handler must be function");
}
console.log("sekiro: register action: " + action);
this.handlers[action] = handler;
return this;
};
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=ws-group&clientId=" + guid());
client.registerAction("clientTime", function (request, resolve, reject) {
resolve("SekiroMessage:" + new Date());
});
client.registerAction("executeJs", function (request, resolve, reject) {
var code = request['code'];
if (!code) {
reject("need param:{code}");
return;
}
console.log("executeJs: " + code);
try {
var result = document.cookie;
resolve(result);
} catch (e) {
reject("error: " + e);
}
});
})();
保存运行
保存脚本,刷新页面 这样显示表示脚本注入成功
服务注册也是成功的
接口调用
import requests
params ={
"group":"ws-group",
"action":"executeJs",
"code": "document.cookie"
}
res = requests.get("http://127.0.0.1:5620/business-demo/invoke", params=params)
print(res.text)
经过测试正常拿到页面数据 再也不用当心逆向js代码而掉头发了
|