NRF52840 USB Dongle 进行蓝牙抓包

1、可视化抓包

官方的工具 链接:RF Connect for Desktop ,之后使用 bluetooth Low Energy 即可查看抓包数据。不做说明。

在这里插入图片描述

本节主要说明,使用wireshark进行抓包数据的显示。

1.1、硬件

Nordic Semiconductor 官网链接 的截图如下。国内封装的硬件亦可。对于蓝牙抓包,实际只要支持硬件都可,至少可能需要使用不同商家的sdk或者工具。
在这里插入图片描述

1.2、软件

1.2.1、wireshark

下载地址,https://www.wireshark.org/download.html 安装最新版本即可(最低 v3.4.7)。

1.2.2、Nodic官方 nRF Sniffer 工具包

下载Nodic官方解析工具包:nRF Sniffer for Bluetooth LE - Downloads - nordicsemi.com

目前最新版本 v4.1.1 ,主要的目录结构如下所示。其中,文件夹 extcap 是插件工具包,用在wireshark中转发和展示数据;文件夹 hex 是支持 sniffer 硬件的固件包, 常规开发板需要烧录对应固包, 而我们使用的dongle默认已经烧录好了sniffer,不需要额外操作。

/nrf_sniffer_for_bluetooth_le_4.1.1$ tree -L 2
.
├── LICENSE.txt
├── Profile_nRF_Sniffer_Bluetooth_LE
├── doc
├── extcap
│   ├── SnifferAPI
│   ├── nrf_sniffer_ble.bat
│   ├── nrf_sniffer_ble.py
│   ├── nrf_sniffer_ble.sh
│   └── requirements.txt
├── hex
│   ├── sniffer_nrf51dk_nrf51422_4.1.1.hex
│   ├── sniffer_nrf51dongle_nrf51422_4.1.1.hex
│   ├── sniffer_nrf52833dk_nrf52833_4.1.1.hex
│   ├── sniffer_nrf52840dk_nrf52840_4.1.1.hex
│   ├── sniffer_nrf52840dongle_nrf52840_4.1.1.hex
│   └── sniffer_nrf52dk_nrf52832_4.1.1.hex
└── release_notes.txt

1.3、插件安装

1.3.1、python依赖

由于插件使用python,先安装要求的版本(最低 v3.6), 之后安装好运行时需要的依赖包,

cd nrf_sniffer_for_bluetooth_le_4.1.1/extcap
python3 -m pip install -r requirements.txt

1.3.2、拷贝 nRF Sniffer capture tool 到 wireshark 的插件目录中

打开 wireshark, windows/linux下点击 Help ,mac上点击 Wireshark 标签,之后再点击 About Wireshark ,弹出窗口后,在切换到文件 Folder 标签页
在这里插入图片描述

双击 Personal Extcap path 打开对应目录,之后将我们下载的 nrf_sniffer_for_bluetooth_le_4.1.1/extcap 下所有文件拷贝到 该目录中
在这里插入图片描述

1.3.3、确保nRF Sniffer文件能够正常运行

在 Personal Extcap path 目录下打开窗口,根据系统不同选择不用的后缀执行nrf_sniffer_ble 脚本

nrf_sniffer_ble.bat --extcap-interfaces     ## win
./nrf_sniffer_ble.sh --extcap-interfaces	## linux/macos

当出现一下信息时,说明正常

extcap {version=4.1.1}{display=nRF Sniffer for Bluetooth LE}{help=https://www.nordicsemi.com/Software-and-Tools/Development-Tools/nRF-Sniffer-for-Bluetooth-LE}
control {number=0}{type=selector}{display=Device}{tooltip=Device list}
control {number=1}{type=selector}{display=Key}{tooltip=}
control {number=2}{type=string}{display=Value}{tooltip=6 digit passkey or 16 or 32 bytes encryption key in hexadecimal starting with '0x', big endian format.If the entered key is shorter than 16 or 32 bytes, it will be zero-padded in front'}{validation=\b^(([0-9]{6})|(0x[0-9a-fA-F]{1,64})|([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2}) (public|random))$\b}
control {number=3}{type=string}{display=Adv Hop}{default=37,38,39}{tooltip=Advertising channel hop sequence. Change the order in which the sniffer switches advertising channels. Valid channels are 37, 38 and 39 separated by comma.}{validation=^\s*((37|38|39)\s*,\s*){0,2}(37|38|39){1}\s*$}{required=true}
control {number=7}{type=button}{display=Clear}{tooltop=Clear or remove device from Device list}
control {number=4}{type=button}{role=help}{display=Help}{tooltip=Access user guide (launches browser)}
control {number=5}{type=button}{role=restore}{display=Defaults}{tooltip=Resets the user interface and clears the log file}
control {number=6}{type=button}{role=logger}{display=Log}{tooltip=Log per interface}
value {control=0}{value= }{display=All advertising devices}{default=true}
value {control=0}{value=[00,00,00,00,00,00,0]}{display=Follow IRK}
value {control=1}{value=0}{display=Legacy Passkey}{default=true}
value {control=1}{value=1}{display=Legacy OOB data}
value {control=1}{value=2}{display=Legacy LTK}
value {control=1}{value=3}{display=SC LTK}
value {control=1}{value=4}{display=SC Private Key}
value {control=1}{value=5}{display=IRK}
value {control=1}{value=6}{display=Add LE address}
value {control=1}{value=7}{display=Follow LE address}

1.3.4、wireshark上开启nRF Sniffer capture tool抓包功能

刷新 wireshark界面,点击 Capture > Refresh Interfaces 或者按 F5,之后将出现 nRF Sniffer For Bluetooth LE 接口。

在这里插入图片描述

之后,再通过 View > Interface Toolbars > nRF Sniffer for Bluetooth LE 开启功能。

1.4、添加配置文件

在Wireshark中添加profile 配置文件,以方便的方式显示nRF Sniffer 蓝牙LE记录数据。

  • 打开 About Wireshark界面,选择 Folders 标签页
  • 双击 Personal configuration 打开对应目录
  • 拷贝 nrf_sniffer_for_bluetooth_le_4.1.1\Profile_nRF_Sniffer_Bluetooth_LE/ 文件夹到到当前目录
  • 在Wireshark主界面 点击 Edit > Configuration Profiles,弹出页面
  • 选择 Profile_nRF_Sniffer_Bluetooth_LE 并点击 OK.
    在这里插入图片描述

1.5、测试

打开一个蓝牙设备,连接dongle到电脑,打开wireshark。选择 nRF Sniffer For Bluetooth LE 接口,开启抓包。界面截图。
其他筛选选项自己测试。
在这里插入图片描述
以上详细参考 https://wiki.makerdiary.com/nrf52840-connectkit/guides/ble-sniffer/

2、使用python抓包

使用抓包中的脚本代码,抽取进行脚本测试。

#!/usr/bin/env python3

from SnifferAPI import Sniffer, UART, Devices, Pcap, Exceptions
from SnifferAPI import Packet

from SnifferAPI import Logger

import logging

ERROR_USAGE = 0
ERROR_ARG = 1
ERROR_INTERFACE = 2
ERROR_FIFO = 3
ERROR_INTERNAL = 4

CTRL_CMD_INIT = 0
CTRL_CMD_SET = 1
CTRL_CMD_ADD = 2
CTRL_CMD_REMOVE = 3
CTRL_CMD_ENABLE = 4
CTRL_CMD_DISABLE = 5
CTRL_CMD_STATUSBAR = 6
CTRL_CMD_INFO_MSG = 7
CTRL_CMD_WARN_MSG = 8
CTRL_CMD_ERROR_MSG = 9

CTRL_ARG_DEVICE = 0
CTRL_ARG_KEY_TYPE = 1
CTRL_ARG_KEY_VAL = 2
CTRL_ARG_ADVHOP = 3
CTRL_ARG_HELP = 4
CTRL_ARG_RESTORE = 5
CTRL_ARG_LOG = 6
CTRL_ARG_DEVICE_CLEAR = 7
CTRL_ARG_NONE = 255

CTRL_KEY_TYPE_PASSKEY = 0
CTRL_KEY_TYPE_OOB = 1
CTRL_KEY_TYPE_LEGACY_LTK = 2
CTRL_KEY_TYPE_SC_LTK = 3
CTRL_KEY_TYPE_DH_PRIVATE_KEY = 4
CTRL_KEY_TYPE_IRK = 5
CTRL_KEY_TYPE_ADD_ADDR = 6
CTRL_KEY_TYPE_FOLLOW_ADDR = 7

fn_capture = None
fn_ctrl_in = None
fn_ctrl_out = None

extcap_log_handler = None
extcap_version = None

last_used_key_type = CTRL_KEY_TYPE_PASSKEY
last_used_key_val = ""
last_used_advhop = "37,38,39"

zero_addr = "[00,00,00,00,00,00,0]"


# While searching for a selected Device we must not write packets to the pipe until
# the device is found to avoid getting advertising packets from other devices.
write_new_packets = False


# The RSSI capture filter value given from Wireshark.
rssi_filter = 0

# The RSSI filtering is not on when in follow mode.
in_follow_mode = False

# nRF Sniffer for Bluetooth LE interface option to only capture advertising packets
capture_only_advertising = False
capture_only_legacy_advertising = False
capture_scan_response = True
capture_scan_aux_pointer = True
capture_coded = False



def string_address(address):
    """Make a string representation of the address"""
    if len(address) < 7:
        return None

    addr_string = ''

    for i in range(5):
        addr_string += (format(address[i], '02x') + ':')
    addr_string += format(address[5], '02x') + ' '

    if address[6]:
        addr_string += ' random '
    else:
        addr_string += ' public '

    return addr_string

def new_packet(notification):
    """A new Bluetooth LE packet has arrived"""
    packet = notification.msg["packet"]

    if rssi_filter == 0 or in_follow_mode == True or packet.RSSI > rssi_filter:
        p = bytes([packet.boardId] + packet.getList())
        # capture_write(Pcap.create_packet(p, packet.time))

        # logging.info(f"New Packet: {p}")


device_set = {}

def device_added(notification):
    """A device is added or updated"""
    device = notification.msg

    # Only add devices matching RSSI filter
    if rssi_filter == 0 or device.RSSI > rssi_filter:
        # Extcap selector uses \0 character to separate value and display value,
        # therefore the display value cannot contain the \0 character as this
        # would lead to truncation of the display value.
        # display = (device.name.replace('\0', '\\0') +
        #            ("  " + str(device.RSSI) + " dBm  " if device.RSSI != 0 else "  ") +
        #            string_address(device.address))

        # message = str(device.address) + '\0' + display


        message = (device.name +  ("  " + str(device.RSSI) + " dBm  " if device.RSSI != 0 else "  ") + 
                    string_address(device.address))

        logging.info("Added: {}".format(message))


        mac_str = string_address(device.address)[:-8]
        device_set[mac_str] = device.name


def device_updated(notification):
    """A device is added or updated"""
    device = notification.msg

    # Only add devices matching RSSI filter
    if rssi_filter == 0 or device.RSSI > rssi_filter:
        # Extcap selector uses \0 character to separate value and display value,
        # therefore the display value cannot contain the \0 character as this
        # would lead to truncation of the display value.
        display = (device.name.replace('\0', '\\0') +
                   ("  " + str(device.RSSI) + " dBm  " if device.RSSI != 0 else "  ") +
                   string_address(device.address))

        message = str(device.address) + '\0' + display

        # logging.info("Updated: {}".format(message))

       
        # mac_str = string_address(device.address)[:-8]
        # device_set[mac_str] = device.name 


def device_removed(notification):
    """A device is removed"""
    device = notification.msg
    display = device.name + "  " + string_address(device.address)

    message = ""
    message += str(device.address)

    # control_write(CTRL_ARG_DEVICE, CTRL_CMD_REMOVE, message)
    logging.info("Removed: " + display)

    mac_str = string_address(device.address)[:-8]
    del device_set[mac_str]

def devices_cleared(notification):
    """Devices have been cleared"""
    device = notification.msg
    display = device.name + "  " + string_address(device.address)

    message = ""
    message += str(device.address)

    logging.info("Cleared: " + display)


###
def get_supported_protocol_version(extcap_version):
    """Return the maximum supported Packet Protocol Version"""
    if extcap_version == 'None':
        return 2

    (major, minor) = extcap_version.split('.')

    major = int(major)
    minor = int(minor)

    if major > 3 or (major == 3 and minor >= 4):
        return 3
    else:
        return 2



def set_key_value(sniffer, payload):
    """Send key value to device"""
    global last_used_key_val

    payload = payload.decode('utf-8')
    last_used_key_val = payload

    if (last_used_key_type == CTRL_KEY_TYPE_PASSKEY):
        if re.match("^[0-9]{6}$", payload):
            set_passkey(sniffer, payload)
        else:
            logging.info("Invalid key value: " + str(payload))
    elif (last_used_key_type == CTRL_KEY_TYPE_OOB):
        if re.match("^0[xX][0-9A-Za-z]{1,32}$", payload):
            set_OOB(sniffer, payload[2:])
        else:
            logging.info("Invalid key value: " + str(payload))
    elif (last_used_key_type == CTRL_KEY_TYPE_DH_PRIVATE_KEY):
        if (re.match("^0[xX][0-9A-Za-z]{1,64}$", payload)):
            set_dh_private_key(sniffer, payload[2:])
        else:
            logging.info("Invalid key value: " + str(payload))
    elif (last_used_key_type == CTRL_KEY_TYPE_LEGACY_LTK):
        if (re.match("^0[xX][0-9A-Za-z]{1,32}$", payload)):
            set_legacy_ltk(sniffer, payload[2:])
        else:
            logging.info("Invalid key value: " + str(payload))
    elif (last_used_key_type == CTRL_KEY_TYPE_SC_LTK):
        if (re.match("^0[xX][0-9A-Za-z]{1,32}$", payload)):
            set_sc_ltk(sniffer, payload[2:])
        else:
            logging.info("Invalid key value: " + str(payload))
    elif (last_used_key_type == CTRL_KEY_TYPE_IRK):
        if (re.match("^0[xX][0-9A-Za-z]{1,32}$", payload)):
            set_irk(sniffer, payload[2:])
        else:
            logging.info("Invalid key value: " + str(payload))
    elif (last_used_key_type == CTRL_KEY_TYPE_ADD_ADDR):
        if (re.match("^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2}) (public|random)$", payload)):
            add_address(sniffer, payload)
        else:
            logging.info("Invalid key value: " + str(payload))
    elif (last_used_key_type == CTRL_KEY_TYPE_FOLLOW_ADDR):
        if (re.match("^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2}) (public|random)$", payload)):
            follow_address(sniffer, payload)
        else:
            logging.info("Invalid key value: " + str(payload))
    else:
        logging.info("Invalid key type: " + str(last_used_key_type))


def scan_for_devices(sniffer):
    """Start scanning for advertising devices"""
    global in_follow_mode
    if sniffer.state == 2:
        log = "Scanning all advertising devices"
        logging.info(log)
        sniffer.scan(capture_scan_response, capture_scan_aux_pointer, capture_coded)

    in_follow_mode = False

def handle_control_command(sniffer, arg, typ, payload):
    """Handle command from control channel"""
    global last_used_key_type

    if arg == CTRL_ARG_DEVICE:
        if payload == b' ':
            scan_for_devices(sniffer)
        else:
            values = payload
            values = values.replace(b'[', b'')
            values = values.replace(b']', b'')
            device_address = values.split(b',')

            logging.info('follow_device: {}'.format(device_address))
            for i in range(6):
                device_address[i] = int(device_address[i])

            device_address[6] = 1 if device_address[6] == b' 1' else 0

            device = Devices.Device(address=device_address, name='""', RSSI=0)

            follow_device(sniffer, device)

    elif arg == CTRL_ARG_DEVICE_CLEAR:
        clear_devices(sniffer)
    elif arg == CTRL_ARG_KEY_TYPE:
        last_used_key_type = int(payload.decode('utf-8'))
    elif arg == CTRL_ARG_KEY_VAL:
        set_key_value(sniffer, payload)
    elif arg == CTRL_ARG_ADVHOP:
        set_advhop(sniffer, payload)

def control_read_initial_values(sniffer):
    """Read initial control values"""
    initialized = False

    while not initialized:
        arg, typ, payload = control_read()
        if typ == CTRL_CMD_INIT:
            initialized = True
        else:
            handle_control_command(sniffer, arg, typ, payload)

def setup_extcap_log_handler():
    """Add the a handler that emits log messages through the extcap control out channel"""
    global extcap_log_handler
    extcap_log_handler = ExtcapLoggerHandler()
    Logger.addLogHandler(extcap_log_handler)
    # control_write(CTRL_ARG_LOG, CTRL_CMD_SET, "")

class ExtcapLoggerHandler(logging.Handler):
    """Handler used to display all logging messages in extcap"""

    def emit(self, record):
        """Send log message to extcap"""
        message = record.message.replace('\0', '\\0')
        log_message = f"{record.levelname}: {message}\n"
        # control_write(CTRL_ARG_LOG, CTRL_CMD_ADD, log_message)
        print(log_message)


def control_loop(sniffer):
    """Main loop reading control messages"""
    arg_read = CTRL_ARG_NONE
    while arg_read is not None:
        arg_read, typ, payload = control_read()
        handle_control_command(sniffer, arg_read, typ, payload)

if __name__ == "__main__":
    # import time
    # t_start = time.time()
    # s = UART.find_sniffer()
    # tn = time.time()
    # print(s)
    # print("find_sniffer took %f seconds" % (tn - t_start))
    # for p in s:
    #     t = time.time()
    #     print(UART.find_sniffer_baudrates(p))
    #     tn = time.time()
    #     print("find_sniffer_baudrate took %f seconds" % (tn - t))
    # tn = time.time()
    # print("total runtime %f" % (tn - t_start))

    # import serial.tools.list_ports as list_ports
    # open_ports = list_ports.comports()
    # uart = UART.Uart('COM6',1000000)


    # fn_ctrl_in = open('fn_ctrl_in', 'rb', 0)
    fn_ctrl_out = open('fn_ctrl_out', 'wb', 0)
    setup_extcap_log_handler()



    sniffers = UART.find_sniffer()
    # for p in sniffers:
    #     baud = UART.find_sniffer_baudrates(p)['default']
    #     print( f"{p}, {baud}")
    #     break

    p = sniffers[0]
    baud = UART.find_sniffer_baudrates(p)['default']

    sniffer = Sniffer.Sniffer(portnum=p, baudrate=baud)

    sniffer.subscribe("NEW_BLE_PACKET", new_packet)
    sniffer.subscribe("DEVICE_ADDED", device_added)
    sniffer.subscribe("DEVICE_UPDATED", device_updated)
    sniffer.subscribe("DEVICE_REMOVED", device_removed)
    sniffer.subscribe("DEVICES_CLEARED", devices_cleared)
    
    sniffer.setAdvHopSequence([37, 38, 39])
    extcap_version = 'None'
    sniffer.setSupportedProtocolVersion(get_supported_protocol_version(extcap_version))

    sniffer.getFirmwareVersion()
    sniffer.getTimestamp()

    sniffer.start()
    sniffer.scan(capture_scan_response, capture_scan_aux_pointer, capture_coded)


    # # First read initial control values
    # control_read_initial_values(sniffer)
    # # Then write default values
    # control_write_defaults()
    # logging.info("defaults written")
    # # Start receiving packets
    # write_new_packets = True
    # # Start the control loop
    # logging.info("control loop")
    # control_loop(sniffer)
    # logging.info("exiting control loop")

    # scan_for_devices(sniffer)

    while True:
        inp = input()

    # while True:
    #     pass

仅查看扫描到的设备信息

$ ./my_ble_sniffer.py
INFO: Opening serial port COM6
INFO: args: ()
INFO: kwargs: {'callbacks': [('*', <bound method Notifier.passOnNotification of <Sniffer(Thread-9, initial)>>)]}
INFO: board ID: 6
INFO: Using packet compatibility, converting packets to protocol version 2
INFO: starting scan
INFO: Scan flags: 0b11
INFO: Added: ""  -75 dBm  03:5f:a8:dc:c4:5a  random
INFO: Sent TK to sniffer: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
INFO: Added: ""  -60 dBm  45:16:78:25:52:e1  random
INFO: Added: ""  -78 dBm  7b:bc:c1:18:bc:bb  random
INFO: Added: ""  -64 dBm  07:5d:0b:b5:61:fb  random 
INFO: Added: ""  -71 dBm  11:6e:a8:02:7e:a3  random
INFO: Added: ""  -65 dBm  35:ce:f2:1f:b6:a6  random 
INFO: Added: ""  -74 dBm  66:8c:7a:ae:15:af  random
INFO: Added: ""  -72 dBm  49:11:3a:90:dc:33  random 
INFO: Added: ""  -71 dBm  76:cf:a0:31:61:39  random
INFO: Added: ""  -51 dBm  39:33:24:40:83:9d  random
INFO: Added: ""  -61 dBm  4b:f7:cb:64:30:45  random 
INFO: Added: ""  -72 dBm  2d:e2:8f:c8:e5:10  random 
INFO: Added: ""  -63 dBm  50:68:ef:4a:0f:03  random
INFO: Added: ""  -80 dBm  62:49:1d:4c:b6:0d  random 
INFO: Added: ""  -60 dBm  e7:db:7e:4e:e5:a8  random
INFO: Added: ""  -72 dBm  22:77:76:52:29:53  random
INFO: Added: ""  -66 dBm  56:c5:97:0c:41:e0  random
INFO: Added: ""  -66 dBm  45:91:c2:3b:6c:9b  random 
INFO: Added: ""  -80 dBm  39:cc:5e:19:bb:7c  random
INFO: Added: ""  -72 dBm  23:e4:85:da:36:49  random 
INFO: Added: ""  -63 dBm  35:29:4c:a5:1b:72  random
INFO: Added: "Bowie WM01"  -80 dBm  41:bb:00:96:e0:06  public
INFO: Added: ""  -58 dBm  c9:3a:1d:f7:c1:08  random 
INFO: Added: ""  -58 dBm  7b:98:77:9a:cc:f4  random 
INFO: Added: ""  -65 dBm  69:a9:23:8d:70:02  random
INFO: Added: ""  -63 dBm  f3:d0:2d:a6:7f:01  random 
INFO: Added: ""  -52 dBm  50:55:6d:ab:5f:2d  random 
INFO: Added: ""  -61 dBm  78:a0:34:8a:45:d0  random 
INFO: Added: ""  -70 dBm  44:22:72:9c:f8:3e  random
INFO: Added: ""  -81 dBm  20:c9:16:60:48:08  random
INFO: Added: ""  -85 dBm  68:01:fa:1b:dc:a2  random

仅查看广播数据

$ ./my_ble_sniffer.py
INFO: Opening serial port COM6
INFO: args: ()
INFO: kwargs: {'callbacks': [('*', <bound method Notifier.passOnNotification of <Sniffer(Thread-9, initial)>>)]}
INFO: board ID: 6
INFO: Using packet compatibility, converting packets to protocol version 2
INFO: starting scan
INFO: New Packet: b"\x068\x00\x028\x85\x06\n\x01'<\x00\x00\x00\x00\x00\x00\xd6\xbe\x89\x8eB%\x12i\xd9?;\x02\x1e\xff\x06\x00\x01\t \x02\x01\xbb\xf4'B\x86\xbbB\xa5\xf1n\xcft\xba\x86\xa77uu\xbfg\xdb\xed\xa1rg"
INFO: Scan flags: 0b11
INFO: New Packet: b'\x068\x00\x029\x85\x06\n\x01%O\x00\x00\xfa\x08\x00\x00\xd6\xbe\x89\x8eB%\xc6\x17b\x86\x07\x1b\x1e\xff\x06\x00\x01\t "P-\xd3AH\xcb!\xd2\x00\xcd\x05)\xcc\x07iISfg^\xb2\x9f4\xfbc\xd4'
INFO: Sent TK to sniffer: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
INFO: New Packet: b'\x068\x00\x02:\x85\x06\n\x01&R\x00\x00\xb6\x16\x00\x00\xd6\xbe\x89\x8eB%\xf34r\x031\x18\x1e\xff\x06\x00\x01\t "\xc7"\rZc\xd2\x87l\xaf\xaf\x18]\xba\xcf\x80\x08-\xf6\xfc\xa0|\x0b\xe6\xd5\xd7\x9e'
INFO: New Packet: b'\x068\x00\x02;\x85\x06\n\x01\'8\x00\x00\x0c\n\x00\x00\xd6\xbe\x89\x8eB%\xc5o\xf7\xff\xaa&\x1e\xff\x06\x00\x01\t "\x07\xcbO{0\xb6=1\xa3\xa2\x95e\\\xbb#y\xb1\xa1\xe7h\t\x8b\xc4\x0f\xdeO'
INFO: New Packet: b'\x068\x00\x02<\x85\x06\n\x01%@\x00\x00#\x0f\x00\x00\xd6\xbe\x89\x8eB%\xdd\xf7\x07)\x97/\x1e\xff\x06\x00\x01\x0f \x02\xcdKD\xc6\x80\x8f0\xeb\x8d\xb7\x91\x9b\xff\xbc\x88U\xad0\xc251\xc9\x83\xdb\x8d*'
INFO: New Packet: b'\x068\x00\x02=\x85\x06\n\x01&<\x00\x00\xb6\x00\x00\x00\xd6\xbe\x89\x8eB%\xdd\xf7\x07)\x97/\x1e\xff\x06\x00\x01\x0f \x02\xcdKD\xc6\x80\x8f0\xeb\x8d\xb7\x91\x9b\xff\xbc\x88U\xad0\xc251\xc9\x83\xdb\x8d*'
INFO: New Packet: b"\x068\x00\x02>\x85\x06\n\x01'C\x00\x00\xb5\x00\x00\x00\xd6\xbe\x89\x8eB%\xdd\xf7\x07)\x97/\x1e\xff\x06\x00\x01\x0f \x02\xcdKD\xc6\x80\x8f0\xeb\x8d\xb7\x91\x9b\xff\xbc\x88U\xad0\xc251\xc9\x83\xdb\x8d*"
INFO: New Packet: b'\x068\x00\x02?\x85\x06\n\x01%N\x00\x00\x90\x02\x00\x00\xd6\xbe\x89\x8eB%\x18\x1e\xb2g\x048\x1e\xff\x06\x00\x01\x0f "a\xdcc\xb0\xe0\xc7\x8cP\xc3d\x99%<j%\xc6\x0e\xe0\xad\x97\x8f\xe6w\x14\x0f\xcb'
INFO: New Packet: b'\x068\x00\x02@\x85\x06\n\x01&<\x00\x00\xbc\x00\x00\x00\xd6\xbe\x89\x8eB%\x18\x1e\xb2g\x048\x1e\xff\x06\x00\x01\x0f "a\xdcc\xb0\xe0\xc7\x8cP\xc3d\x99%<j%\xc6\x0e\xe0\xad\x97\x8f\xe6w\x14\x0f\xcb'
INFO: New Packet: b'\x068\x00\x02A\x85\x06\n\x01\'G\x00\x00\xbc\x00\x00\x00\xd6\xbe\x89\x8eB%\x18\x1e\xb2g\x048\x1e\xff\x06\x00\x01\x0f "a\xdcc\xb0\xe0\xc7\x8cP\xc3d\x99%<j%\xc6\x0e\xe0\xad\x97\x8f\xe6w\x14\x0f\xcb'
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

aworkholic

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值