使用 Python 模块 bluepy 玩转 BLE

python 提供的蓝牙模块

  • pybluez: Python code to access the host machine’s Bluetooth resources. 用于经典蓝牙
  • bluepy: Python interface to Bluetooth LE on Linux. 用于低功耗蓝牙

强烈推荐官方文档,简单易懂

0x10 快速入门

bluepy 是一个用 python 封装的库,提供了 BLE 的 API,使用起来非常方便。

安装 bluepy

sudo pip3 install bluepy 
  • 扫描 BLE 设备 - Scanner
scanner = Scanner()
    devices = scanner.scan(timeout=3)
    print("%-30s %-10s" % ("Name", "Address"))
    for dev in devices:
        print("%-30s %-20s" % (dev.getValueText(9), dev.addr))
  • 建立连接(Just Works 模式)- Peripheral
addr = "7c:ad:8f:db:ba:75"
conn = Peripheral(addr)			# Peripheral 构造函数
  • 获取 Service
services = conn.getServices()	# Service 类的对象
for svc in services:
    print(svc.uuid)	
  • 获取每个 Service 包含的 Characteristic
# 1. 获取所有 Characteristic
characteristics = conn.getCharacteristics()
for charac in characteristics:	# Characteristic 类的对象
    print(charac.uuid)
    
# 2. 获取特定 Service 下的 Characteristic
characteristics = svc.getCharacteristics()
  • 读/写 Characteristic
data = charac.read() 			# 得到一个字节数组
print('Get data:',data[0])

charac.write([b'A']) 			# 写入一个字节数组

0x20 实际案例

0x21 获取当前设备所有服务和特征

# Connect
addr = "7c:ad:8f:xx:xx:xx"
conn = Peripheral(addr)

# Get service & characteristic
services = conn.getServices()
for svc in services:
    print("[+] Service: ", svc.uuid)
    characteristics = svc.getCharacteristics()
    for charac in characteristics:
        print("    Characteristic: ", charac.uuid)
        print("        Properties: ", charac.propertiesToString())
    print("")

结果

                                                          
┌──(root💀kali)-[/home/lys/Documents]
└─# /bin/python3 /home/lys/Documents/ble_test.py
[+] Service:  00001801-0000-1000-8000-00805f9b34fb
    Characteristic:  00002a05-0000-1000-8000-00805f9b34fb
        Properties:  INDICATE

[+] Service:  00001800-0000-1000-8000-00805f9b34fb
    Characteristic:  00002a00-0000-1000-8000-00805f9b34fb
        Properties:  READ 
    Characteristic:  00002a01-0000-1000-8000-00805f9b34fb
        Properties:  READ 
    Characteristic:  00002a04-0000-1000-8000-00805f9b34fb
        Properties:  READ 

[+] Service:  15f1e600-a277-43fc-a484-dd39ef8a9100
    Characteristic:  15f1e601-a277-43fc-a484-dd39ef8a9100
        Properties:  NOTIFY INDICATE 
    Characteristic:  15f1e602-a277-43fc-a484-dd39ef8a9100
        Properties:  WRITE 

[+] Service:  15f1e500-a277-43fc-a484-dd39ef8a9100
    Characteristic:  15f1e501-a277-43fc-a484-dd39ef8a9100
        Properties:  WRITE NOTIFY INDICATE 

charac = conn.getCharacteristics(uuid="00002a00-0000-1000-8000-00805f9b34fb")
response = charac[0].read()
print(response)

结果

b'Hi-VIATON-XXXXX'

写(同步接收反回的确认消息)

charac = conn.getCharacteristics(uuid="15f1e602-a277-43fc-a484-dd39ef8a9100")
data = binascii.unhexlify("00c504000001xxxx")
try:
    response = charac[0].write(data, withResponse=True)
    print(response)
except BTLEException:
    print("No response!")

0x22 异步接收消息

Peripheral.withDelegate(delegate), 将一个 delegate 实例关联至此 Perioheral 实例,当异步事件(eg.通知)发生时,调用其中的相关函数

如扫描

from bluepy.btle import Scanner, DefaultDelegate

class ScanDelegate(DefaultDelegate):
    def __init__(self):
        DefaultDelegate.__init__(self)

    def handleDiscovery(self, dev, isNewDev, isNewData):
        if isNewDev:
            print "Discovered device", dev.addr
        elif isNewData:
            print "Received new data from", dev.addr

scanner = Scanner().withDelegate(ScanDelegate())
devices = scanner.scan(10.0)

异步接收

class ReceiveDelegate(DefaultDelegate):
    def __init__(self):
        super().__init__()
    
    def handleNotification(self, cHandle, data):
        print("[<--] ", data)

addr = "xx:xx:xx:xx:aa:9d"
conn = Peripheral(addr)
conn.setDelegate(ReceiveDelegate())
conn.setMTU(500)

charac = conn.getCharacteristics(uuid="xxxx-xxxx-xxxx-xxxx-xxxxxxxx")
conn.writeCharacteristic(charac[0].valHandle + 1, b"\x02\x00")

while True:        
    if conn.waitForNotifications(1.0):
        # handleNotification() 被调用
        continue

        print("Waiting...")

0x30 Fuzzing

指定长度的随机数据

'''
return \x31\x32\x33 -> 123
'''
def random_data(size):
    return binascii.unhexlify("".join(random.choices("0123456789abcdef", k=size*2)))

任意长度的随机数据

data = binascii.unhexlify("00c5040000") + random_data(random.randint(1, 1000))

在进行 fuzzing 的时候,如果被测应用在 GATT 基础之上又封装了自己的协议,这是最容易发现问题的。

参考文献

  • https://ianharvey.github.io/bluepy-doc/notifications.html
  • https://stackoverflow.com/questions/32807781/ble-subscribe-to-notification-using-gatttool-or-bluepy
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

江下枫

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

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

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

打赏作者

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

抵扣说明:

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

余额充值