当前位置: 首页 > news >正文

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 python3from SnifferAPI import Sniffer, UART, Devices, Pcap, Exceptions
from SnifferAPI import Packetfrom SnifferAPI import Loggerimport loggingERROR_USAGE = 0
ERROR_ARG = 1
ERROR_INTERFACE = 2
ERROR_FIFO = 3
ERROR_INTERNAL = 4CTRL_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 = 9CTRL_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 = 255CTRL_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 = 7fn_capture = None
fn_ctrl_in = None
fn_ctrl_out = Noneextcap_log_handler = None
extcap_version = Nonelast_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 = Falsedef string_address(address):"""Make a string representation of the address"""if len(address) < 7:return Noneaddr_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_stringdef 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 filterif 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' + displaymessage = (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.namedef device_updated(notification):"""A device is added or updated"""device = notification.msg# Only add devices matching RSSI filterif 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.msgdisplay = 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.msgdisplay = 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 3else:return 2def set_key_value(sniffer, payload):"""Send key value to device"""global last_used_key_valpayload = payload.decode('utf-8')last_used_key_val = payloadif (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_modeif 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 = Falsedef handle_control_command(sniffer, arg, typ, payload):"""Handle command from control channel"""global last_used_key_typeif arg == CTRL_ARG_DEVICE:if payload == b' ':scan_for_devices(sniffer)else:values = payloadvalues = 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 0device = 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 = Falsewhile not initialized:arg, typ, payload = control_read()if typ == CTRL_CMD_INIT:initialized = Trueelse: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_handlerextcap_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_NONEwhile 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}")#     breakp = 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'

相关文章:

NRF52840 USB Dongle 进行蓝牙抓包

1、可视化抓包 官方的工具 链接&#xff1a;RF Connect for Desktop &#xff0c;之后使用 bluetooth Low Energy 即可查看抓包数据。不做说明。 本节主要说明&#xff0c;使用wireshark进行抓包数据的显示。 1.1、硬件 Nordic Semiconductor 官网链接 的截图如下。国内封装…...

【C++】详细讲解继承(下)

本篇来继续说说继承。上篇可移步至【C】详细讲解继承&#xff08;上&#xff09; 1.继承与友元 友元关系不能继承 &#xff0c;也就是说基类友元不能访问派⽣类私有和保护成员。 class Student;//前置声明class Same //基类 { public:friend void Fun(const Same& p, con…...

OS Copilot功能测评:智能助手的炫彩魔法

简介&#xff1a; OS Copilot 是一款融合了人工智能技术的智能助手&#xff0c;专为Linux系统设计&#xff0c;旨在提升系统管理和运维效率。本文详细介绍了在阿里云ECS实例上安装和体验OS Copilot的过程&#xff0c;重点评测了其三个核心参数&#xff1a;-t&#xff08;模式…...

Gin 学习笔记

教程地址&#xff1a;https://www.bilibili.com/video/BV1FV4y1C72M?spm_id_from333.788.videopod.sections&vd_source707ec8983cc32e6e065d5496a7f79ee6 01-项目搭建 各常用目录的说明&#xff1a; https://github.com/golang-standards/project-layout/blob/master/REA…...

windows在命令行中切换盘符

一、问题描述 我们在使用windows的cmd&#xff08;命令行&#xff09;时&#xff0c;经常需要用cd命令在不同盘之间切换路径。但有时在不同盘之间切换时&#xff0c;会发现命令不起作用。 如下图所示&#xff0c;直接切换目录还是停留在原来的位置。 二、解决方法 首先切换盘符…...

OpenAI模块重构

文章目录 1.common-openai-starter1.目录结构2.OpenAiProperties.java 新增apiUrl3.OpenAIAutoConfiguration.java4.OpenAiClient.java 使用gson重构 2.common-openai-starter-demo1.目录结构2.application.yml 新增api-url3.OpenAiController.java4.OpenAiApplication.java5.测…...

表的增删改查(MySQL)

1. 表的增删改查 CRUD : Create(创建), Retrieve(读取)&#xff0c;Update(更新)&#xff0c;Delete&#xff08;删除&#xff09; 1.1 Create 语法&#xff1a; INSERT [INTO] table_name [(column [, column] ...)] VALUES (value_list) [, (value_list)] ...value_list:…...

Go 不可重复协程安全队列

代码实现 package dataStructimport ("errors""sync" )// GenericQueue 是一个支持泛型的不可重复队列&#xff0c;具有最大长度限制 // T 是泛型参数 type GenericQueue[T comparable] struct {items map[T]struct{} // 使用 map 来存储元素order []…...

每日一题 419. 棋盘上的战舰

419. 棋盘上的战舰 简单 class Solution { public:int countBattleships(vector<vector<char>>& board) {int ans 0;for(int i0;i<board.size();i){for(int j0;j<board[0].size();j){if(board[i][j] X){dfs(board,i,j);ans;}}}return ans;}void dfs(…...

spring cloud alibaba 使用示例

spring cloud alibaba example spring cloud alibaba nacos 配置中心、spring cloud alibaba nacos 服务注册与发现、openfeign 服务调用、spring cloud loadbalancer 负载均衡、spring cloud alibaba sentinel 限流降级、spring cloud alibaba seata 分布式事务、spring clou…...

Python数据分析-Python语法基础,IPython和Jupyter-Notebooks(二)

title: ‘Python数据分析:Python语法基础&#xff0c;IPython和Jupyter Notebooks&#xff08;二&#xff09;’ tags: python数据分析 categories:python数据分析 keywords:python数据分析 cover: …/img/404_icecream_whale.png description: 本文介绍python的基础语法和jup…...

领域驱动设计(DDD)Spring Boot 3 实现 二

使用 Spring Boot 3 实现领域驱动设计&#xff08;DDD&#xff09;是一种很自然的选择&#xff0c;因为 Spring 提供了良好的生态支持&#xff0c;特别是在分层架构、依赖管理、事件驱动等方面。以下是如何在 Spring Boot 3 中结合 DDD 进行开发的详细指南&#xff1a; 项目结构…...

Vue.js 高级组件开发

Vue.js 高级组件开发&#xff1a;构建一个智能动态表单生成器 ——从可复用架构到性能优化的全链路实践 引言&#xff1a;为什么需要高级组件&#xff1f; 在现代前端开发中&#xff0c;组件不仅是UI的封装&#xff0c;更是业务逻辑的载体。一个“高级”Vue组件应当具备&…...

wangEditor富文本编辑器,Laravel上传图片配置和使用

文章目录 前言步骤1. 构造好前端模版2. 搭建后端存储3. 调试 前言 由于最近写项目需要使用富文本编辑器&#xff0c;使用的是VUE3.0版本所以很多不兼容&#xff0c;实际测试以后推荐使用wangEditor 步骤 构造好前端模版搭建后端存储调试 1. 构造好前端模版 安装模版 模版安…...

Hive之加载csv格式数据到hive

场景&#xff1a; 今天接了一个需求&#xff0c;将测试环境的hive数据导入到正式环境中。但是不需要整个流程的迁移&#xff0c;只需要迁移ads表 解决方案&#xff1a; 拿到这个需求首先想到两个方案&#xff1a; 1、将数据通过insert into语句导出&#xff0c;然后运行脚本 …...

0164__【GNU】gcc -O编译选项 -Og -O0 -O1 -O2 -O3 -Os

【GNU】gcc -O编译选项 -Og -O0 -O1 -O2 -O3 -Os_gcc -o0-CSDN博客...

《DiffIR:用于图像修复的高效扩散模型》学习笔记

paper&#xff1a;2303.09472 GitHub&#xff1a;GitHub - Zj-BinXia/DiffIR: This project is the official implementation of Diffir: Efficient diffusion model for image restoration, ICCV2023 目录 摘要 1、介绍 2、相关工作 2.1 图像恢复&#xff08;Image Rest…...

[Datawheel]利用Zigent框架编写智能体-2

书接上回 1. Zigent实现教程编写智能体 本节将通过 Zigent 框架实现一个教程编写智能体&#xff0c;其主要功能是输入教程主题&#xff0c;然后自动生成完整的教程内容。 设计思路&#xff1a; 先通过 LLM 大模型生成教程的目录&#xff0c;再对目录按照二级标题进行分块&…...

cursor重构谷粒商城05——docker容器化技术快速入门【番外篇】

前言&#xff1a;这个系列将使用最前沿的cursor作为辅助编程工具&#xff0c;来快速开发一些基础的编程项目。目的是为了在真实项目中&#xff0c;帮助初级程序员快速进阶&#xff0c;以最快的速度&#xff0c;效率&#xff0c;快速进阶到中高阶程序员。 本项目将基于谷粒商城…...

Django项目的创建及运行——Django学习日志(一)

1.命令行创建 &#xff08;1&#xff09;创建项目 django-admin startproject HelloWorld&#xff08;这里的名称任意&#xff09; &#xff08;2&#xff09;创建应用&#xff08;app&#xff09; 首先要进入到项目目录&#xff0c;比如我这里的项目目录为HelloWorld cd …...

gesp(C++六级)(1)洛谷:P10250:[GESP样题 六级] 下楼梯

gesp(C六级)&#xff08;1&#xff09;洛谷&#xff1a;P10250&#xff1a;[GESP样题 六级] 下楼梯 题目描述 顽皮的小明发现&#xff0c;下楼梯时每步可以走 1 1 1 个台阶、 2 2 2 个台阶或 3 3 3 个台阶。现在一共有 N N N 个台阶&#xff0c;你能帮小明算算有多少种方案…...

1.23学习

misc buuctf-小明的保险箱 打开附件是一个在线图片首先将其另存为&#xff0c;然后仅仅只是一个图片&#xff0c;而无其他信息&#xff0c;那么我们再进行binwalk或者foremost文件分离&#xff0c;得到了一个文件夹&#xff0c;其中含有一个压缩包但是是一个加密的&#xff0…...

atheris从安装到fuzz输入输出解读

1. 引入 模糊测试是一种自动化的软件测试技术&#xff0c;它通过自动生成大量随机数据作为输入来测试程序&#xff0c;以发现潜在的错误、漏洞或崩溃。atheris是一个专门用于CPython&#xff08;Python的C语言实现&#xff09;的模糊测试框架。 2. 安装atheris 参考1&#x…...

基于自然语言处理的垃圾短信识别系统

基于自然语言处理的垃圾短信识别系统 &#x1f31f; 嗨&#xff0c;我是LucianaiB&#xff01; &#x1f30d; 总有人间一两风&#xff0c;填我十万八千梦。 &#x1f680; 路漫漫其修远兮&#xff0c;吾将上下而求索。 目录 设计题目设计目的设计任务描述设计要求输入和输出…...

PAT甲级-1022 Digital Libiary

题目 题目大意 一个图书有图书id&#xff0c;书名&#xff0c;作者&#xff0c;关键字&#xff0c;出版商&#xff0c;出版时间6个信息。现要查询图书的ID&#xff0c;1对应通过书名查询&#xff0c;2对应作者&#xff0c;3对应关键字&#xff08;不需要完全一致&#xff0c;包…...

GD32F470 USB虚拟串口

1. 硬件连接 确保GD32F470开发板的USB接口连接到PC的USB端口。开发板通常提供USB FS&#xff08;全速&#xff09;接口&#xff0c;可以直接使用。 2. 配置USB功能 需要配置USB时钟、GPIO和中断&#xff0c;以支持全速USB设备模式。 2.1 配置USB时钟 c复制 void usb_rcu_…...

25美赛ABCDEF题详细建模过程+可视化图表+参考论文+写作模版+数据预处理

详情见该链接&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 25美国大学生数学建模如何准备&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;-CSDN博客文章浏览阅读791次&#xff0c;点赞13次&#xff0c;收藏7次。通过了解比赛基本…...

【转帖】eclipse-24-09版本后,怎么还原原来版本的搜索功能

【1】原贴地址&#xff1a;eclipse - 怎么还原原来版本的搜索功能_eclipse打开类型搜索类功能失效-CSDN博客 https://blog.csdn.net/sinat_32238399/article/details/145113105 【2】原文如下&#xff1a; 更新eclipse-24-09版本后之后&#xff0c;新的搜索功能&#xff08;CT…...

Elasticsearch 性能测试工具 Loadgen 之 002——命令行及参数详解

上一讲&#xff0c;我们讲解了 Loadgen 的极简部署方式、配置文件、快速使用从 0 到 1 方式。 本讲&#xff0c;我们主要解读一下 Loadgen 的丰富的命令行及参数含义。 有同学可能会说&#xff0c;上面不是介绍很清楚了吗&#xff1f;但&#xff0c;咱们还是有必要详细中文解读…...

DRG/DIP 2.0时代下基于PostgreSQL的成本管理实践与探索(下)

五、数据处理与 ETL 流程编程实现 5.1 数据抽取与转换(ETL) 在 DRG/DIP 2.0 时代的医院成本管理中,数据抽取与转换(ETL)是将医院各个业务系统中的原始数据转化为可供成本管理分析使用的关键环节。这一过程涉及从医院 HIS 系统中抽取患者诊疗数据,并对其进行格式转换、字…...

【设计模式-行为型】状态模式

一、什么是状态模式 什么是状态模式呢&#xff0c;这里我举一个例子来说明&#xff0c;在自动挡汽车中&#xff0c;挡位的切换是根据驾驶条件&#xff08;如车速、油门踏板位置、刹车状态等&#xff09;自动完成的。这种自动切换挡位的过程可以很好地用状态模式来描述。状态模式…...

想品客老师的第六天:函数

函数基础的部分写在这里 函数声明 在js里万物皆对象&#xff0c;函数也可以用对象的方式定义 let func new Function("title", "console.log(title)");func(我是参数title); 也可以对函数赋值&#xff1a; let cms function (title) {console.log(tit…...

hedfs和hive数据迁移后校验脚本

先谈论校验方法&#xff0c;本人腾讯云大数据工程师。 1、hdfs的校验 这个通常就是distcp校验&#xff0c;hdfs通过distcp迁移到另一个集群&#xff0c;怎么校验你的对不对。 有人会说&#xff0c;默认会有校验CRC校验。我们关闭了&#xff0c;为什么关闭&#xff1f;全量迁…...

面向通感一体化的非均匀感知信号设计

文章目录 1 非均匀信号设计的背景分析1.1 基于OFDM波形的感知信号1.2 非均匀信号设计的必要性和可行性1.2 非均匀信号设计的必要性和可行性 3 通感一体化系统中的非均匀信号设计方法3.1 非均匀信号的设计流程&#xff08;1&#xff09;均匀感知信号设计&#xff08;2&#xff0…...

React将props传递给一个组件

React 组件通讯&#xff1a;从单向数据流到跨层级交互的深度实践 ——基于 Props 的通讯机制解析与高阶模式探索 一、Props 的本质&#xff1a;不可变数据管道 React 的 props&#xff08;properties&#xff09;机制构建了单向数据流的核心范式。每个父组件通过 props 向子…...

头歌实训作业 算法设计与分析-贪心算法(第2关:最优装载问题)

任务描述 有一批集装箱要装上一艘载重量为C的轮船&#xff0c;共有n个集装箱&#xff0c;其中集装箱i的重量为Wi。 最优装载问题要求确定在装载体积不受限制的情况下&#xff0c;将尽可能多的集装箱装上轮船。 测试说明 输入和输出说明&#xff1a; 第1行为集装箱数目n和载重限…...

HarmonyOS基于ArkTS卡片服务

卡片服务 前言 Form Kit&#xff08;卡片开发框架&#xff09;提供了一种在桌面、锁屏等系统入口嵌入显示应用信息的开发框架和API&#xff0c;可以将应用内用户关注的重要信息或常用操作抽取到服务卡片&#xff08;以下简称“卡片”&#xff09;上&#xff0c;通过将卡片添加…...

Elasticsearch 性能测试工具 Loadgen 之 001——部署及应用详解

在现代软件开发中&#xff0c;性能测试是确保应用程序稳定性和响应速度的关键环节。 今天&#xff0c;我们就来深入了解一款国产化功能强大的 Elasticsearch 负载测试工具——INFINI Loadgen。 一、INFINI Loadgen 简介 Github地址&#xff1a;https://github.com/infinilabs/l…...

Python算法详解:动态规划

动态规划&#xff08;Dynamic Programming&#xff0c;简称 DP&#xff09;是计算机科学中一种高效解决问题的算法思想。它通过将复杂问题分解为更小的子问题&#xff0c;记录中间结果&#xff0c;避免重复计算&#xff0c;从而提升效率。本文将从动态规划的基础思想出发&#…...

python3+TensorFlow 2.x(二) 回归模型

目录 回归算法 1、线性回归 (Linear Regression) 一元线性回归举例 2、非线性回归 3、回归分类 回归算法 回归算法用于预测连续的数值输出。回归分析的目标是建立一个模型&#xff0c;以便根据输入特征预测目标变量&#xff0c;在使用 TensorFlow 2.x 实现线性回归模型时&…...

lombok 没生效 java: 找不到符号 符号: 方法 setName(java.lang.String)

今天使用lombok 添加了 Data注解 set方法却没起效 解决方法 1 给lombok 添加版本号 再maven刷新下 <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.8</version><optional>…...

uiautomator2教程

一、简介 uiautomator2 是一个 Python 库&#xff0c;用于 Android 的 UI 自动化测试&#xff0c;底层基于 Google uiautomator。 二、安装 1、安装adb 2、pip install uiautomator2 3、设备安装 atx - agent&#xff0c;python -m uiautomator2 init 4、安装weditor&…...

旅游风景的代码项目

敦煌莫高窟&#xff1a;用代码打开千年艺术的大门 ——一个零基础也能看懂的神奇项目 前言&#xff1a;当古老艺术遇上现代代码 想象一下&#xff0c;你坐在电脑前&#xff0c;指尖轻轻一点&#xff0c;就能穿越到敦煌莫高窟——看飞天的衣袂飘飘、听千年的驼铃声声。这不是科…...

【后端开发】字节跳动青训营之性能分析工具pprof

性能分析工具pprof 一、测试程序介绍二、pprof工具安装与使用2.1 pprof工具安装2.2 pprof工具使用 资料链接&#xff1a; 项目代码链接实验指南pprof使用指南 一、测试程序介绍 package mainimport ("log""net/http"_ "net/http/pprof" // 自…...

【测试】-- 认识测试

1. 软件测试定义 软件测试就是验证软件产品特性&#xff08;功能、性能、界面、易用性等&#xff09;是否满足用户的需求。 2. 测试的岗位 软件测试开发工程师&#xff08;测开&#xff09; 开发&#xff1a;开发测试效率工具&#xff08;自动化、性能测试、覆盖率等&#x…...

浏览器hid 和蓝牙bluetooth技术区别

HID与蓝牙技术区别 引言 在前端开发中&#xff0c;与外部设备的交互越来越重要&#xff0c;尤其是在移动设备和物联网设备日益普及的今天。HID&#xff08;Human Interface Device&#xff09;和蓝牙&#xff08;Bluetooth&#xff09;是两种常用的技术&#xff0c;用于实现设备…...

PCIE模式配置

对于VU系列FPGA&#xff0c;当DMA/Bridge Subsystem for PCI Express IP配置为Bridge模式时&#xff0c;等同于K7系列中的AXI Memory Mapped To PCI Express IP。...

mysql 学习3 SQL语句--整体概述。SQL通用语法;DDL创建数据库,查看数据库,删除数据库,使用数据库;

SQL通用语法 SQL语句分类 DDL data definition language : 用来创建数据库&#xff0c;创建表&#xff0c;创建表中的字段&#xff0c;创建索引。因此成为 数据定义语言 DML data manipulation language 有了数据库和表以及字段后&#xff0c;那么我们就需要给这个表中 添加数…...

Swing使用MVC模型架构

什么是MVC模式? MVC是一组英文的缩写,其全名是Model-View-Controller,也就是“模型-视图-控制器”这三个部分组成。这三个部分任意一个部分发生变化都会引起另外两个发生变化。三者之间的关系示意图如下所示: MVC分为三个部分,所以在MVC模型中将按照此三部分分成三…...

Java定时任务实现方案(二)——ScheduledExecutorService

这篇笔记&#xff0c;我们要来介绍实现Java定时任务的第二个方案&#xff0c;使用ScheduledExecutorService&#xff0c;以及该方案的优点和缺点。 ScheduledExecutorService是Java并发包java.util.concurrent中用于执行定时任务和周期性任务的接口&#xff0c;它拓展了Executo…...