推荐
关注
TOP
Message

基于Sekiro的jsRPC的使用和安装

什么是jsRPC

说实话在介绍 JSRPC 我向大家推荐一个库 Selenium-wire 感觉和JSrpc的原理很像
RPC指远程过程调用,APP里面的RPC大家比较熟悉了。
那什么是jsRPC,顾名思义,就是指利用js手段实现代码远程控制浏览器控制台的一种手段,需要借助websocket实现。
下面我们先简单的写一个小例子

var ws = require('nodejs-websocket');
console.log('开始建立连接...');

var cached = {}

var server = ws.createServer(function (conn) {
  conn.on('text', function (msg) {
    var key = conn.key
    console.log("将要发送代码:【" + msg + "】至浏览器/python");
    server.connections.forEach(conn => {
      conn.send(msg);
    })
  })
  conn.on('close', function (code, reason) {
    console.log('关闭连接', code, reason)
  });
  conn.on('error', function (code, reason) {
    console.log('异常关闭', code, reason)
  });
}).listen(8015)
console.log('WebSocket建立完毕');

python

# -*- coding: utf-8 -*-
# @Time    : 2022/12/2 14:17
# @Author  : lzc
# @Email   : hybpjx@163.com
# @Software: PyCharm
# @blog    : https://www.cnblogs.com/zichliang

import websocket

ws = websocket.WebSocketApp("ws://127.0.0.1:8015")

def on_message(ws,message):
    if message.split("_")[0]!= 'js':
        print(message)


ws.on_message = on_message
ws.run_forever()

在浏览器中注入

(function () {
    if (window.WebSocket) {
        ws = new WebSocket("ws://localhost:8015");
        ws.onopen = function (e) {
        };
        ws.onclose = function (e) {
            console.log("server closed", e)
        }
        ws.onerror = function (e) {
            "connection error"
        }
        ws.onmessage = function (e) {
            console.log(e)
        }
    }
})()

在浏览器中对其进行操作
比如发送什么数据


在python代码中就能接收到这些数据

基于sekiro的isRPC应用

简介: sekiro是基于长链接和代码注入的Android private API暴露框架

github: https://github.com/virjar/sekiro 作者:邓维佳 virjar 渣总[都是一个人]
sekiro 在 web方向,使用 websocket协议注入
官方文档内容:
Sekiro 已支持 websocket 协议,使用本功能可以支持注入js 到浏览器后,调用浏览器环境的is 代码
Web 环境基于 WebSocket 实现
文档:https://sekiro.iinti.cn/sekiro-doc/01_user_manual/1.quickstart.html
下载地址:Go HTTP File Server (iinti.cn)
下载这个 到本地
并且下载好 JDK java的编译器


然后运行响应版本
注意:

使用

使用方法:将js文件 sekiroWebMini.js 注入到浏览器环境 ,

function SekiroClient(e){if(this.wsURL=e,this.handlers={},this.socket={},!e)throw new Error("wsURL can not be empty!!");this.webSocketFactory=this.resolveWebSocketFactory(),this.connect()}SekiroClient.prototype.resolveWebSocketFactory=function(){if("object"==typeof window){var e=window.WebSocket?window.WebSocket:window.MozWebSocket;return function(o){function t(o){this.mSocket=new e(o)}return t.prototype.close=function(){this.mSocket.close()},t.prototype.onmessage=function(e){this.mSocket.onmessage=e},t.prototype.onopen=function(e){this.mSocket.onopen=e},t.prototype.onclose=function(e){this.mSocket.onclose=e},t.prototype.send=function(e){this.mSocket.send(e)},new t(o)}}if("object"==typeof weex)try{console.log("test webSocket for weex");var o=weex.requireModule("webSocket");return console.log("find webSocket for weex:"+o),function(e){try{o.close()}catch(e){}return o.WebSocket(e,""),o}}catch(e){console.log(e)}if("object"==typeof WebSocket)return function(o){return new e(o)};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 e=this;try{this.socket=this.webSocketFactory(this.wsURL)}catch(o){return console.log("sekiro: create connection failed,reconnect after 2s:"+o),void setTimeout(function(){e.connect()},2e3)}this.socket.onmessage(function(o){e.handleSekiroRequest(o.data)}),this.socket.onopen(function(e){console.log("sekiro: open a sekiro client connection")}),this.socket.onclose(function(o){console.log("sekiro: disconnected ,reconnection after 2s"),setTimeout(function(){e.connect()},2e3)})},SekiroClient.prototype.handleSekiroRequest=function(e){console.log("receive sekiro request: "+e);var o=JSON.parse(e),t=o.__sekiro_seq__;if(o.action){var n=o.action;if(this.handlers[n]){var s=this.handlers[n],i=this;try{s(o,function(e){try{i.sendSuccess(t,e)}catch(e){i.sendFailed(t,"e:"+e)}},function(e){i.sendFailed(t,e)})}catch(e){console.log("error: "+e),i.sendFailed(t,":"+e)}}else this.sendFailed(t,"no action handler: "+n+" defined")}else this.sendFailed(t,"need request param {action}")},SekiroClient.prototype.sendSuccess=function(e,o){var t;if("string"==typeof o)try{t=JSON.parse(o)}catch(e){(t={}).data=o}else"object"==typeof o?t=o:(t={}).data=o;(Array.isArray(t)||"string"==typeof t)&&(t={data:t,code:0}),t.code?t.code=0:(t.status,t.status=0),t.__sekiro_seq__=e;var n=JSON.stringify(t);console.log("response :"+n),this.socket.send(n)},SekiroClient.prototype.sendFailed=function(e,o){"string"!=typeof o&&(o=JSON.stringify(o));var t={};t.message=o,t.status=-1,t.__sekiro_seq__=e;var n=JSON.stringify(t);console.log("sekiro: response :"+n),this.socket.send(n)},SekiroClient.prototype.registerAction=function(e,o){if("string"!=typeof e)throw new Error("an action must be string");if("function"!=typeof o)throw new Error("a handler must be function");return console.log("sekiro: register action: "+e),this.handlers[e]=o,this};

之后通过当前接口访问自己的浏览器服务:

ws://127.0.0.1:5612

切记 不需要什么多余的操作 直接打开网站注入即可,也不需要开启什么断点

然后注入我们的代码

var client = new SekiroClient("ws://127.0.0.1:5612/business/register?group=demo-ws&clientId="+Math.random());
client.registerAction("get_cookie",function(request, resolve,reject ){
            resolve(""+document.cookie);
})


请注意,Sekiro JS RPC是Sekiro的扩展,依然需要遵循Sekiro的各种规则定义。

注入完成之后 使用我们的浏览器访问
http://127.0.0.1:5612/business/invoke?group=demo-ws&action=get_cookie

必须与我们注入的代码相对应 不然就会失败 成功之后是这样的

可以看到 这里返回的就是我们resolve(""+document.cookie);这段代码 也就意味着可以进行任何的操作。

对于sekiro jsRPC的理解

提供了一种浏览器与代码以及接口交互的一种可行性理论上只要是网站都可以通过这种方案在is层面突破反爬限制,且稳定性要优于目前的一切自动化框架

使用描述:
可能性1:针对解密函数的接口暴露
可能性2:针对数据接口的接口暴露
可能性3:针对自动化采集的接口暴露
可能性4:其他的一切想你所想....

sekiro驱动jsRPC的优势与缺陷分析

优势

  1. 与传统自动化框架相比,稳定性更高且不需要考虑浏览器指纹。操作得当的话,性能不在一个数量级
  2. 可以通过js直接获取加密参数,对于全局变量的参数暴露具有极佳的体验。[一剑破光阴]
  3. 可以直接获取接口数据,对于获取数据接口暴露明显的网站具有极佳的体验。
  4. 不考虑风控的情况下,能达到高并发。

缺陷

  1. 内置不可更改的浏览器环境不可更改,对于风控突破而言是个极大的隐患[浏览器沙箱可能会解决这个问题]
  2. 需要对js有较深理解,需要寻找合适的注入时机和注入位置[这个算缺陷么? 菜是原罪]。
  3. 需要注入脚本,所以要依托于油猴脚本/autoResponse/手动注入[如果使用抓包工具需要注意端口问题]
  4. 对于全局js混淆、风控严格、is参数分布散乱、鼠标轨迹指纹、变量作用域复杂的网址的支持较差。
  5. 需要保持浏览器开启,所以多少会占用些资源。
  6. 如果不取参数,而是只取接口内容 或者 参数与IP绑定的加密,对代理池接入的支持不佳。
posted @ 2023-03-15 17:29  始識  阅读(413)  评论(0编辑  收藏  举报