mirror of
https://github.com/bettercap/bettercap.git
synced 2025-03-12 04:36:03 -07:00
162 lines
3.8 KiB
Go
162 lines
3.8 KiB
Go
package ble
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/bettercap/bettercap/v2/network"
|
|
"github.com/evilsocket/islazy/tui"
|
|
"tinygo.org/x/bluetooth"
|
|
)
|
|
|
|
func parseRawData(raw []byte) string {
|
|
s := ""
|
|
for _, b := range raw {
|
|
if strconv.IsPrint(rune(b)) {
|
|
s += tui.Yellow(string(b))
|
|
} else {
|
|
s += tui.Dim(fmt.Sprintf("%02x", b))
|
|
}
|
|
}
|
|
return s
|
|
}
|
|
|
|
func (mod *BLERecon) startEnumeration(address string) error {
|
|
knownDev, found := mod.Session.BLE.Get(address)
|
|
if !found || knownDev == nil {
|
|
return fmt.Errorf("device with address %s not found", address)
|
|
} else if err := mod.adapter.StopScan(); err != nil {
|
|
mod.Warning("error stopping previous scan: %v", err)
|
|
}
|
|
|
|
mod.current.ResetWrite()
|
|
|
|
defer func() {
|
|
// make sure to restart scan when we're done
|
|
mod.Info("restoring ble scan")
|
|
if err := mod.adapter.Scan(mod.onDevice); err != nil {
|
|
mod.Error("error restoring ble scan: %v", err)
|
|
}
|
|
mod.Info("ble scan restored")
|
|
}()
|
|
|
|
mod.Info("connecting to %s ...", address)
|
|
|
|
addr := bluetooth.Address{}
|
|
addr.Set(address)
|
|
tm := bluetooth.NewDuration(time.Second * time.Duration(mod.connTimeout))
|
|
|
|
device, err := mod.adapter.Connect(addr, bluetooth.ConnectionParams{ConnectionTimeout: tm})
|
|
if err != nil {
|
|
mod.Error("error connecting to %s: %v", address, err)
|
|
return err
|
|
}
|
|
|
|
mod.Session.Events.Add("ble.device.connected", knownDev)
|
|
|
|
mod.Info("connected to %s", address)
|
|
|
|
srvcs, err := device.DiscoverServices(nil)
|
|
if err != nil {
|
|
return fmt.Errorf("could not discover services for %s: %v", address, err)
|
|
}
|
|
|
|
columns := []string{"Service > Characteristics", "Properties", "Data"}
|
|
rows := make([][]string, 0)
|
|
|
|
knownDev.ResetServices()
|
|
|
|
for _, svc := range srvcs {
|
|
service := network.NewBLEService(strings.ToLower(svc.UUID().String()))
|
|
|
|
mod.Session.Events.Add("ble.device.service.discovered", svc)
|
|
|
|
name := ""
|
|
if service.Name == "" {
|
|
name = svc.UUID().String()
|
|
} else {
|
|
name = fmt.Sprintf("%s (%s)", tui.Green(service.Name), tui.Dim(svc.UUID().String()))
|
|
}
|
|
|
|
row := []string{
|
|
name,
|
|
"",
|
|
"",
|
|
}
|
|
|
|
rows = append(rows, row)
|
|
|
|
chars, err := svc.DiscoverCharacteristics(nil)
|
|
if err != nil {
|
|
mod.Error("error while enumerating chars for service %s: %s", svc.UUID(), err)
|
|
} else {
|
|
for _, ch := range chars {
|
|
char := network.NewBLECharacteristic(strings.ToLower(ch.UUID().String()))
|
|
if mtu, err := ch.GetMTU(); err != nil {
|
|
mod.Warning("can't read %v mtu: %v", ch.UUID(), err)
|
|
} else {
|
|
char.MTU = mtu
|
|
}
|
|
|
|
mod.Session.Events.Add("ble.device.characteristic.discovered", ch)
|
|
|
|
name := char.Name
|
|
if name == "" {
|
|
name = " " + ch.UUID().String()
|
|
} else {
|
|
name = fmt.Sprintf(" %s (%s)", tui.Green(name), tui.Dim(ch.UUID().String()))
|
|
}
|
|
|
|
data := ""
|
|
multi := ([]string)(nil)
|
|
raw := make([]byte, 255)
|
|
if n, err := ch.Read(raw); err == nil {
|
|
raw = raw[0:n]
|
|
char.Properties = []string{"READ"}
|
|
data = parseRawData(raw)
|
|
}
|
|
|
|
if multi == nil {
|
|
char.Data = data
|
|
rows = append(rows, []string{
|
|
name,
|
|
strings.Join(char.Properties, ", "),
|
|
data,
|
|
})
|
|
} else {
|
|
char.Data = multi
|
|
for i, m := range multi {
|
|
if i == 0 {
|
|
rows = append(rows, []string{
|
|
name,
|
|
strings.Join(char.Properties, ", "),
|
|
m,
|
|
})
|
|
} else {
|
|
rows = append(rows, []string{"", "", "", m})
|
|
}
|
|
}
|
|
}
|
|
|
|
service.Characteristics = append(service.Characteristics, char)
|
|
}
|
|
// blank row after every service, bleah style
|
|
rows = append(rows, []string{"", "", ""})
|
|
}
|
|
|
|
knownDev.AddService(service)
|
|
}
|
|
|
|
tui.Table(mod.Session.Events.Stdout, columns, rows)
|
|
|
|
if err := device.Disconnect(); err != nil {
|
|
mod.Warning("error disconnecting from %s: %v", address, err)
|
|
} else {
|
|
mod.Info("disconnected from %s", address)
|
|
}
|
|
|
|
return nil
|
|
}
|