【Python模拟websocket登陆-拆包封包】

Python模拟websocket登陆-拆包封包

解析一个网站

这里所用的网站是我一个内测的网站,主要手段是chrome devtools,用得很多,但我玩的不深,这次上了点干货.

  • 首先在网络那一块,找到js或者index.html,右键点击,选择替换内容,在需要分析的地方写上自己的代码。
  • 对于ajax加载的js模块,把js在加载地址,换成离线下载到本地的地址,存入本地的服务,原来是http的,还还用http。原来https的必须也在https,本地web开启跨域允许。然后ajax加载部分js也就替换成可定制的了。
  • 虽然代码很难读,但是在适合的地方,可以随便写cosole.log.
  • 对于js的调试和中断不太懂,还没用,
  • 界面的记录器标签,可以记录一组点击,然后能看到json代码,用于回放。
  • 记录的动作可以用js实现插入在任何位置,只要调试通过就行。

获取wss原始数据

获取数据的两种方式,各种优缺点:

  • 在上一章中,可以看到websocket建立和sendBytes,onMessage之类的函数,在这里启动cosole.log就能得到逐条纪录。不论ws还是wss。这里可以看到语义,并可定制测试代码。
  • 在devtools网络标签下的wss://server:port/url地址,对应的respone可以取得全部的来往数据,和代码块所收发的字节按道理是完全一致的,可以做为一个验证和参考。

拆包wss数据

所谓的拆包是理解数据的意义,我还没有修炼到靠数据读含义的深度,只能靠代码,也就js,顺眼化处理的代码,比如以下的登陆数据代码,从1万行里拽出来的。

  • 消息头4表字节
c 复制代码
    u.prototype.addHeader = function(e, t, n, a) {
        return void 0 === n && (n = 0),
        void 0 === a && (a = 0),
        e | t << 4 | n << 12 | a << 23
    

4个参数在长度 e->4bit, t ->,8bit,n->11bit a->9bit.

含义e=command ,t=action, n=length,a=ext

  • 登陆消息的主体
js 复制代码
           
        var a = new z.SyncLogonDto;
        a.account = e.account,
        a.sn = e.sn,
        a.token = e.token,
        a.uid = e.userID,
        a.localHost = 0,
        4 == a.sn.length && 0 < a.uid && "" != a.token ? this.sendMsg(a.getBody(), 
        z.ServiceType.HALL_CMD, z.ServiceType.HALL_LOGIN_ACT, 2 =            
          
                      o.prototype.getBody = function() {
        var e = new t.BGByteArray;
        return e.writeUnsignedInt(this.major),
        e.writeUnsignedInt(this.minor),
        e.writeUTFBytes(this.sn),
        e.writeUnsignedInt(this.localHost),
        e.writeLongUint(this.uid),
                  
        var a = new z.SyncLogonDto;
        a.account = e.account,
        a.sn = e.sn,
        a.token = e.token,
        a.uid = e.userID,
        a.localHost = 0,
        4 == a.sn.length && 0 < a.uid && "" != a.token ? this.sendMsg(a.getBody(), 
        z.ServiceType.HALL_CMD, z.ServiceType.HALL_LOGIN_ACT, 2 =            
          
                      o.prototype.getBody = function() {
        var e = new t.BGByteArray;
        return e.writeUnsignedInt(this.major),
        e.writeUnsignedInt(this.minor),
        e.writeUTFBytes(this.sn),
        e.writeUnsignedInt(this.localHost),
        e.writeLongUint(this.uid),
        e.writeFixedLenthString(this.account, 32),
        e.writeFixedLenthString(this.token, 32),
        e
    }
    ,
    a = o,
    t.SyncLogonDto = a
        e.writeFixedLenthString(this.token, 32),
        e
    }
    ,
    a = o,
    t.SyncLogonDto = a

主要的处理逻辑在·o.prototype.getBody = function()

这里的writeUnsigedInt是四字节无符号整数,而且是小头的。就是低位在前,高位在后,相同还有,

writeFixedLenthString(this.account, 32),补充位,也是先写入数据,后填充'\x00',在python的bytes使用bytes.ljust(),后面有详细介绍。

这是消息的主体

封包wss数据

根据上面在js可以生成一些python代码用于数据组织

python 复制代码
def addHeader(bodyl,command,action=0,ext=0):
    # Data---\x3e command:" + t + " action:" + n + "   size: 4+len(e),ext:a
           
    num=   command | action << 4 | bodyl << 12 | ext << 23
    #num.to_bytes(length=32,byteorder='little')
    return num.to_bytes(length=4,byteorder='little')

def parseHeader(hex4='11c08500'):
   
 #   little_byte = b'\x01\x00\x00\x00\x00\x00\x00\x00'
    hex4=int.from_bytes(bytes.fromhex(hex4),byteorder='little')
    command=hex4 &int('F',16)
    action=hex4>>4 & int('FF',16)
    l=hex4>>12 &  int('7FF',16)  #only 11bit
    ext=hex4>>23 
    print (f'command:{command},action:{action},len:{l},ext:{ext}')
    

def loginbytes(sn,lh,uid,account,token):
    re=bytes()
    re+=int(b'01',16).to_bytes(4,byteorder='little')
    re+=int(b'01',16).to_bytes(4,byteorder='little')
    re+=sn.encode()
    re+=int(lh).to_bytes(4,byteorder='little')
    re+=int(uid).to_bytes(8,byteorder='little')
    re+=account.encode().ljust(32,b'\x00')
    re+=token.encode().ljust(32,b'\x00')
   # print(len(re))
   # print (re.hex())
    return re

解释

addHeader使用按位或,在返回时byteorder='little')这是比较原始数据得出的。

parseHeader用按位与,移位来排除前,与来排除后,只留对照有用的。

这两个函数处理4字节32位的头部信息。

loginbytes 是改写的js中的SyncLogonDto getBody其中account.encode().ljust(32,b'\x00')是对account补足32,int(uid).to_bytes(8,byteorder='little')是将uid转为长整数8字节长,低位在前高位在后的bytes。

发送接收websocket的常驻后台脚本

本段代码,pip install websocket-client, 版本号1.18,websocket协议13

python 复制代码
import websocket
import threading
import time
import os
import login
#os.path+=['../']
# 定义当接收到消息时调用的回调函数
def on_message(ws, message):
    print(f"Received message: {message}")
 
# 定义当连接关闭时调用的回调函数
def on_close(ws, close_status_code, close_msg):
    print(f"### Closed ###")
 
# 定义当出现错误时调用的回调函数
def on_error(ws, error):
    print(f"### Error ### {error}")

if __name__ == "__main__":
    # websocket服务地址
    ws_service_address = "ws://your_websocket_server"
    ws_service_address = "wss://alidr-311.klwgt.com/data"

 
    # 创建websocket应用实例
    websocket.enableTrace(True)
    ws = websocket.WebSocketApp(ws_service_address,
                                on_message=on_message,
                                on_close=on_close,
                                on_error=on_error)
 
    # 创建一个线程用于运行websocket客户端
    wst = threading.Thread(target=ws.run_forever)
    wst.daemon = True
    wst.start()
    time.sleep(3)
    mss=login.getlogin()
    ws.send_bytes(mss)
 
    # 主线程做其他事情...
    # 例如,主线程可以发送消息到websocket服务器
    # ws.send("Your message here")
 
    # 主线程在此处等待,否则程序会立即退出
    # 如果你的程序需要在后台运行,则不需要这一行
    wst.join()

其实主要就是来自百度AI的一段代码。稍加调整假入了延时的登陆调用。然后就成功登陆了。实现和浏览器js登陆websocket的一样的效果。

总结

虽然这段代码,没有什么业务功能,细节也是基本的类型转换,但是它是从怀疑中不断产生的。因为我开始时怀疑python在websocket库是否能完全仿真js在websocket。在查看js的建立连接的请求头时,发现协议版本是2011年的13,然后查看了websocket-client在pypi,也是支持到这个版本,只是还没有实现gzip功能的扩展。

既然如此,wss的 建立也没要求cookie和其实token。那就用python跑一下。基于开始处对于网站数据的整理,要是没有原本的js脚本,这也是一个不可能完成的事情了。但是虽然登陆成了,以后的业务逻辑还不知道怎么处理。最少,分步骤,实现批处理,是可以的。这就由python建立 了 一个,js代码的客户端。

好吧纯属有病。

再见

相关推荐
2401_832131951 分钟前
Python单元测试(unittest)实战指南
jvm·数据库·python
猷咪26 分钟前
C++基础
开发语言·c++
IT·小灰灰27 分钟前
30行PHP,利用硅基流动API,网页客服瞬间上线
开发语言·人工智能·aigc·php
快点好好学习吧29 分钟前
phpize 依赖 php-config 获取 PHP 信息的庖丁解牛
android·开发语言·php
秦老师Q30 分钟前
php入门教程(超详细,一篇就够了!!!)
开发语言·mysql·php·db
烟锁池塘柳030 分钟前
解决Google Scholar “We‘re sorry... but your computer or network may be sending automated queries.”的问题
开发语言
是誰萆微了承諾30 分钟前
php 对接deepseek
android·开发语言·php
vx_BS8133034 分钟前
【直接可用源码免费送】计算机毕业设计精选项目03574基于Python的网上商城管理系统设计与实现:Java/PHP/Python/C#小程序、单片机、成品+文档源码支持定制
java·python·课程设计
2601_9498683634 分钟前
Flutter for OpenHarmony 电子合同签署App实战 - 已签合同实现
java·开发语言·flutter
gzxx2007sddx40 分钟前
windows vnpy运行过程及问题记录
python·量化·vnpy