文章目录
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'