-
Notifications
You must be signed in to change notification settings - Fork 103
Expand file tree
/
Copy pathBLE_Reception_PoC.py
More file actions
179 lines (138 loc) · 6.15 KB
/
BLE_Reception_PoC.py
File metadata and controls
179 lines (138 loc) · 6.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#!/usr/bin/env python3
# Jiska Classen
# Get receive statistics on a Samsung Galaxy S8 for BLE connection events
import sys
from argparse import Namespace
from pwnlib.asm import asm
import internalblue.hci as hci
from internalblue.adbcore import ADBCore
from internalblue.cli import InternalBlueCLI
from internalblue.utils.packing import u8, u16
internalblue = ADBCore(serial=True)
device_list = internalblue.device_list()
if len(device_list) == 0:
internalblue.logger.warn("No HCI devices connected!")
exit(-1)
internalblue.interface = device_list[0][1] # just use the first device
"""
# _connTaskRxDone has a Patchram position, S8 fixed almost everything in BLE, because
# they had to for Bluetooth 5 compliance.
# The base address is 0x5E324, and this will jump into the Patchram.
# You need to adjust the RX_DONE_HOOK_ADDRESS in the beginning.
"""
# RX_DONE_HOOK_ADDRESS = 0x1344D0 # on S8 with Patchlevel May 1 2019 on stock ROM
# RX_DONE_HOOK_ADDRESS = 0x134500 # on S8 with Lineage OS Nightly from August 30 2019
RX_DONE_HOOK_ADDRESS = 0x134514 # on S8 with Patchlevel September 1 2019 on stock ROM
HOOKS_LOCATION = 0x210500
ASM_HOOKS = """
// restore first 4 bytes of _connTaskRxDone
push {r4-r12,lr}
mov r4, r0
// fix registers for our own routine
push {r1-r7, lr}
mov r7, r0
// allocate vendor specific hci event
mov r2, 243
mov r1, 0xff
mov r0, 245
bl 0xE628 // bthci_event_AllocateEventAndFillHeader(4+239+2, 0xff, 4+239);
mov r4, r0 // save pointer to the buffer in r4
// append buffer with "RXDN"
add r0, 10 // buffer starts at 10 with data
ldr r1, =0x4e445852 // RXDN
str r1, [r0]
add r0, 4 // advance buffer by 4
// copy 239 bytes of le_conn to buffer
mov r2, #238
mov r1, r7 // le_conn[0]
bl 0x857B4 // __rt_memcpy
// for debugging purposes, we overwrite the first byte
// (which is the connTaskCallback anyway) with RSSI info
mov r2, #1 // 1 rssi byte
add.w r1, r7, #0x1ca // le_conn[0x1ca] is position of rssi
mov r0, r4
add r0, 14
bl 0x857B4 // __rt_memcpy
// send hci event
mov r0, r4 // back to buffer at offset 0
bl 0xE418 // bthci_event_AttemptToEnqueueEventToTransport
// undo registers for our own routine
mov r0, r7
pop {r1-r7, lr}
// branch back to _connTaskRxDone + 4
//b 0x1344D4 // on S8 with Patchlevel May 1 2019 on stock ROM
//b 0x134504 // August 30 Nightly Build
b 0x%x
""" % (RX_DONE_HOOK_ADDRESS + 4)
# setup sockets
if not internalblue.connect():
internalblue.logger.critical("No connection to target device.")
exit(-1)
# Install hooks
code = asm(ASM_HOOKS, vma=HOOKS_LOCATION)
internalblue.logger.info("Writing hooks to 0x%x..." % HOOKS_LOCATION)
if not internalblue.writeMem(HOOKS_LOCATION, code):
internalblue.logger.critical("Cannot write hooks at 0x%x" % HOOKS_LOCATION)
exit(-1)
internalblue.logger.info("Installing hook patch...")
patch = asm("b 0x%x" % HOOKS_LOCATION, vma=RX_DONE_HOOK_ADDRESS)
if not internalblue.writeMem(RX_DONE_HOOK_ADDRESS, patch):
internalblue.logger.critical("Installing patch for _connTaskRxDone failed!")
exit(-1)
# RXDN statistics callback variables
internalblue.last_nesn_sn = None
internalblue.last_success_event = None
def lereceiveStatusCallback(record):
"""
RXDN Callback Function
Depends on the raspi3_rxdn.py or eval_rxdn.py script,
which patches the _connTaskRxDone() function and copies
info from the LE connection struct to HCI.
"""
hcipkt = record[0] # get HCI Event packet
if not issubclass(hcipkt.__class__, hci.HCI_Event):
return
if hcipkt.data[0:4] == "RXDN":
data = hcipkt.data[4:]
# Raspi 3 gets errors
if len(data) < 239:
return
# if raspi or s8:
packet_curr_nesn_sn = u8(data[0xa0])
# elif eval:
# packet_curr_nesn_sn = u8(data[0xa4])
packet_channel_map = data[0x54:0x7b]
packet_channel = data[0x83]
packet_event_ctr = u16(data[0x8e:0x90])
packet_rssi = data[0]
if internalblue.last_nesn_sn and ((internalblue.last_nesn_sn ^ packet_curr_nesn_sn) & 0b1100) != 0b1100:
internalblue.logger.info(" ^----------------------------- ERROR --------------------------------")
# currently only supported by eval board: check if we also went into the process payload routine,
# which probably corresponds to a correct CRC
# if self.last_success_event and (self.last_success_event + 1) != packet_event_ctr:
# internalblue.logger.debug(" ^----------------------------- MISSED -------------------------------")
# TODO example for setting the channel map
# timeout needs to be zero, because we are already in an event reception routine!
# self.sendHciCommand(0x2014, '\x00\x00\xff\x00\x00', timeout=0)
internalblue.last_nesn_sn = packet_curr_nesn_sn
# draw channel with rssi color
color = '\033[92m' # green
if 0xc8 > packet_rssi >= 0xc0:
color = '\033[93m' # yellow
elif packet_rssi < 0xc0:
color = '\033[91m' # red
channels_total = packet_channel_map[37]
channel_map = 0x0000000000
if channels_total <= 37: # raspi 3 messes up with this during blacklisting
for channel in range(0, channels_total):
channel_map |= (0b1 << 39) >> packet_channel_map[channel]
internalblue.logger.info("LE event %5d, map %10x, RSSI %d: %s%s*\033[0m " % (packet_event_ctr, channel_map,
(packet_rssi & 0x7f) - (128 * (packet_rssi >> 7)),
color, ' ' * packet_channel))
internalblue.logger.info("--------------------")
internalblue.logger.info("Entering InternalBlue CLI to display statistics.")
# add RXDN callback
internalblue.registerHciCallback(lereceiveStatusCallback)
# enter CLI
cli = InternalBlueCLI(Namespace(data_directory=None, verbose=False, trace=None, save=None), internalblue)
sys.exit(cli.cmdloop())