爬虫websocket与RPC逆向案例:某建筑市场监管

声明:
该文章为学习使用,严禁用于商业用途和非法用途,违者后果自负,由此产生的一切后果均与作者无关

一、websocket简介

WebSocket是一种在Web浏览器和服务器之间进行全双工通信的协议。它允许在客户端和服务器之间建立持久的连接,使得双方可以通过这个连接实时地交换数据。
与传统的HTTP请求-响应模式不同,WebSocket提供了一个长时间运行的连接,可以在客户端和服务器之间进行双向通信。这意味着服务器可以主动向客户端发送数据,而不需要客户端发起请求。这种实时性和双向通信的特性使得WebSocket在许多应用场景下非常有用,如实时聊天应用、在线游戏、股票市场报价等。
WebSocket协议建立在HTTP协议之上,使用HTTP的握手过程来建立连接,然后协议切换到WebSocket协议进行数据交换。WebSocket使用了一种轻量级的帧格式来传输数据,可以发送文本和二进制数据。它还支持心跳机制,以保持连接的活跃状态。
在Web开发中,通常使用WebSocket API来实现WebSocket通信。浏览器提供了WebSocket API,可以在JavaScript中使用它来创建WebSocket对象,建立连接并发送和接收数据。
总结起来,WebSocket是一种在Web浏览器和服务器之间实现实时、双向通信的协议,它允许长时间运行的连接,支持服务器主动推送数据,适用于许多实时性要求较高的应用场景。

二、websocket实现方式
  1. javascript websocket实现方式
//与服务器约定的连接 以及端口本机的   hosts
const socket = new WebSocket('ws://127.0.0.1:8080/')

//连接发生错误的回调方法
socket.onerror = () => {
    console.log("WebSocket连接发生错误");
};

//连接成功建立的回调方法
socket.onopen = function () {
    console.log("WebSocket连接成功");
}

//接收到消息的回调方法  接收服务器的数据
socket.onmessage = function (event) {
    console.log(event.data);
    socket.send('浏览器')
}

//连接关闭的回调方法
socket.onclose = function () {
    console.log("WebSocket连接关闭");
}
  1. python websocket实现方式
import asyncio
import websockets


async def echo(websocket):
    # 使用WebSocket在客户端和服务器之间建立全双工双向连接后,就可以在连接打开时调用send()方法。
    message = 'hello world'
    # 发送数据
    await websocket.send(message)
    return True


async def recv_msg(websocket):
    while 1:
        # 接收数据
        recv_text = await websocket.recv()
        print(recv_text)


async def main_logic(websocket, path):
    await echo(websocket)
    await recv_msg(websocket)


start_server = websockets.serve(main_logic, '127.0.0.1', 8080)
loop = asyncio.get_event_loop()
loop.run_until_complete(start_server)
# 创建了一个连接对象之后,需要不断监听返回的数据,则调用 run_forever 方法,要保持长连接即可
loop.run_forever()
三、websocket爬虫应用
  1. js运行 atob(‘aHR0cHM6Ly9qenNjLm1vaHVyZC5nb3YuY24vZGF0YS9jb21wYW55’) 拿到网址,F12打开调试工具,点击分页,找到dataservice/query/comp/list请求,分别切换headers、payload、preview会发现只有响应结果加密
    爬虫websocket与RPC逆向案例:某建筑市场监管_第1张图片
  2. 打开网站:https://spidertools.cn/#/curl2Request,把拷贝好的curl转成python代码,新建jzsc.py,把代码复制到该文件
  3. XHR定位响应结果解密位置,调试工具切换到Sources,添加 dataservice/query/comp/list 请求拦截
    爬虫websocket与RPC逆向案例:某建筑市场监管_第2张图片
  4. 点击分页重新发送请求,一直点击跳过当前函数执行,看到响应拦截器打个断点
    爬虫websocket与RPC逆向案例:某建筑市场监管_第3张图片
  5. 结束调试,点击分页重新发送请求,点击跳过断点,找到刚才打的断点,在控制台输出 b(t.data),会发现响应结果已解密
    爬虫websocket与RPC逆向案例:某建筑市场监管_第4张图片
  6. 结束调试,添加文件夹
    爬虫websocket与RPC逆向案例:某建筑市场监管_第5张图片
  7. 右击刚才断点的文件,点击 override content,会在刚才的文件夹下生成一个相同的文件,并刷新页面
    爬虫websocket与RPC逆向案例:某建筑市场监管_第6张图片
    爬虫websocket与RPC逆向案例:某建筑市场监管_第7张图片
  8. 在刚才的文件内找到 b(t.data),打上断点,点击分页发送请求,如果进入该断点,说明本地文件替换成功
    爬虫websocket与RPC逆向案例:某建筑市场监管_第8张图片
  9. 修改本地替换的文件 window.reponse_decrypt = b;,保存该文件,并刷新页面
    爬虫websocket与RPC逆向案例:某建筑市场监管_第9张图片
  10. 新建 websocket.py,添加以下代码,并运行
import asyncio
import websockets


async def echo(websocket):
    # 使用WebSocket在客户端和服务器之间建立全双工双向连接后,就可以在连接打开时调用send()方法。
    message = 'socket连接成功'
    # 发送数据
    await websocket.send(message)
    return True


async def recv_msg(websocket):
    while 1:
        # 接收数据
        recv_text = await websocket.recv()
        print(recv_text)


async def main_logic(websocket, path):
    await echo(websocket)
    await recv_msg(websocket)


start_server = websockets.serve(main_logic, '127.0.0.1', 8080)
loop = asyncio.get_event_loop()
loop.run_until_complete(start_server)
# 创建了一个连接对象之后,需要不断监听返回的数据,则调用 run_forever 方法,要保持长连接即可
loop.run_forever()

  1. 新建 websocket hook,添加以下代码,并运行,控制台看到websocket连接成功说明,已经和python启动的websocket服务建立起连接
(function () {

    const websocket = new WebSocket('ws://127.0.0.1:8080');

    websocket.onopen = function () {
        console.log("WebSocket连接成功");
    };

    //  接收服务端发送的信息
    websocket.onmessage = function (event) {
        const data = window.reponse_decrypt(event.data);
        console.log("发送数据")
        // 发送解密数据给服务端
        websocket.send(data)
    }

})();

爬虫websocket与RPC逆向案例:某建筑市场监管_第10张图片

  1. 关闭所有soucket连接,修改 jzsh.py,并运行
    爬虫websocket与RPC逆向案例:某建筑市场监管_第11张图片
  2. 运行 websocket hook,看 jzsh.py 控制台,会发现响应结果已解密
    爬虫websocket与RPC逆向案例:某建筑市场监管_第12张图片
四、RPC逆向

RPC 在逆向中,简单来说就是将本地和浏览器,看做是服务端和客户端,二者之间通过 WebSocket 协议进行 RPC 通信,在浏览器中将加密函数暴露出来,在本地直接调用浏览器中对应的加密函数,从而得到加密结果,不必去在意函数具体的执行逻辑,也省去了扣代码、补环境等操作,可以省去大量的逆向调试时间。
这里使用 Sekiro-RPC 说明RPC在爬虫中的应用, Sekiro-RPC 官网:https://sekiro.iinti.cn/sekiro-doc/,

  1. Sekiro-RPC安装:https://sekiro.iinti.cn/sekiro-doc/01_manual/4.server_install.html#%E5%90%AF%E5%8A%A8-sekiro,访问该链接找到手动部署下载
  • Linux & Mac:bin/sekiro.sh 双击打开服务端
  • Windows:bin/sekiro.bat 双击打开服务端
  1. Sekiro-RPC需要java环境:https://repo.huaweicloud.com/java/jdk/8u201-b09/,下载对应系统的安装即可
  2. 客户端环境:http://file.virjar.com/sekiro_web_client.js?_=123
  3. 使用参数说明
// 生成唯一标记uuid编号
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(""+new Date());
})
  • group:业务类型(接口组),每个业务一个 group,group 下面可以注册多个终端(SekiroClient),同时group 可以挂载多个 Action;
  • clientId:指代设备,多个设备使用多个机器提供 API 服务,提供群控能力和负载均衡能力;
  • SekiroClient:服务提供者客户端,主要场景为手机/浏览器等。最终的 Sekiro 调用会转发到 SekiroClient。每个 client 需要有一个惟一的 clientId;
  • registerAction:接口,同一个 group 下面可以有多个接口,分别做不同的功能;
  • resolve:将内容传回给服务端的方法;
  • request:服务端传过来的请求,如果请求里有多个参数,可以以键值对的方式从里面提取参数然后再做处理。
  1. Sekiro API
  • 查看分组列表:http://127.0.0.1:5620/business-demo/groupList
  • 查看队列状态:http://127.0.0.1:5620/business-demo/clientQueue?group=rpc-test
  • 调用转发:http://127.0.0.1:5620/business-demo/invoke?group=rpc-test&action=clientTime
五、RPC爬虫应用
  1. 以websocket爬虫应用中的网站为例,直到webscoket的部分不同,其他步骤相同
  2. 打开油猴,https://extfans.com/ 可通过该网站安装油猴
  3. 新建油猴脚本
  • @name:UserScript的名称。
  • @namespace:UserScript的命名空间。
  • @version:UserScript的版本号。
  • @description:UserScript的描述信息。
  • @author:UserScript的作者。
  • @homepage:UserScript的主页。
  • @icon:UserScript的图标。
  • @include:适用于UserScript的网页地址模式。
  • @exclude:排除不适用于UserScript的网页地址模式。
  • @match:适用于UserScript的网页地址正则表达式。
  • @grant:UserScript请求的权限,比如访问某个特定的API。
  • @require:UserScript所依赖的其他脚本文件。
  • @resource:UserScript所使用的资源文件,比如图像、样式表等。
  • @run-at:UserScript的执行时机,比如document-start(页面加载前)或document-end(页面加载后)。
  • @noframes:指定UserScript不在框架(iframe)中执行。
// ==UserScript==
// @name         Sekiro-RPC
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Sekiro-RPC爬虫应用
// @author       You
// @match        https://extfans.com/
// @icon         https://www.google.com/s2/favicons?sz=64&domain=extfans.com
// @grant        none
// @require   http://file.virjar.com/sekiro_web_client.js?_=123
// @run-at       document-start
// @author       CC11001100
// @match       *://*/*
// ==/UserScript==

(function() {
    'use strict';

    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=sekiro&clientId=" + guid());

    client.registerAction("rpc", function (request, resolve, reject) {
        resolve(window.reponse_decrypt(request.param));
    })
})();
  1. 启动Sekiro-RPC服务端,bin/sekiro.bat 双击打开服务端(windows)
    爬虫websocket与RPC逆向案例:某建筑市场监管_第13张图片
  2. 在网站中启动油猴,并刷新页面,控制台显示这些信息说明Sekiro-RPC连接成功
    爬虫websocket与RPC逆向案例:某建筑市场监管_第14张图片
  3. 修改 jzsc.py,并运行,会发现响应结果已解密
    爬虫websocket与RPC逆向案例:某建筑市场监管_第15张图片

你可能感兴趣的:(python,爬虫,websocket,rpc)