Compare commits
26 Commits
v0.3
...
blacklisting
| Author | SHA1 | Date | |
|---|---|---|---|
| ec9240e620 | |||
| e2fb710f51 | |||
| c84a0cd123 | |||
| 31f6a8d58a | |||
| 7bc7a956ea | |||
| cf51abc428 | |||
| 1bf8c0c132 | |||
| 2d3ed7f734 | |||
| ac1df0b260 | |||
| 053ad32297 | |||
| 8cb4109e81 | |||
| 8e0f099a83 | |||
| c842e4ec7d | |||
| 6ec8badbe5 | |||
| 8d3e740bad | |||
| b2b3a623dc | |||
| 335bca36b9 | |||
| 95fd621eb7 | |||
| 246ca035eb | |||
| 1a2e4e90ca | |||
| 3b1222e327 | |||
| 7d4dd6a7a7 | |||
| 6aeeba6545 | |||
| cdbb9f4bae | |||
| 0c3430dfaf | |||
| d233b55042 |
@@ -14,3 +14,6 @@ _internalblue.hist
|
||||
_internalblue.log
|
||||
btsnoop.log
|
||||
|
||||
# xcode
|
||||
xcuserdata
|
||||
*.xcworkspace
|
||||
|
||||
@@ -12,8 +12,8 @@ Setup and Installation
|
||||
----------------------
|
||||
|
||||
The framework uses __ADB__ (Android Debug Bridge) to connect to an Android
|
||||
smartphone or __BlueZ__ sockets on Linux. For ADB, either connect
|
||||
the phone via USB or setup ADB over TCP and make sure you
|
||||
smartphone, __BlueZ__ sockets on Linux, or the included __iOS Proxy__ on iOS.
|
||||
For ADB, either connect the phone via USB or setup ADB over TCP and make sure you
|
||||
enable USB debugging in the developer settings of Android.
|
||||
|
||||
The Android device needs to run a Bluetooth stack that was compiled with
|
||||
@@ -59,6 +59,11 @@ All steps on a plain Ubuntu 18.04:
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
|
||||
Packets required on a current (July 2019) Raspian:
|
||||
|
||||
sudo apt-get --allow-releaseinfo-change update
|
||||
sudo apt-get install git python-setuptools binutils-arm-none-eabi adb python-pip python-dev gcc libffi-dev
|
||||
|
||||
|
||||
|
||||
@@ -102,6 +107,11 @@ Linux:
|
||||
* BlueZ
|
||||
* Optional: Privileged access
|
||||
|
||||
iOS:
|
||||
* A jailbroken iOS device
|
||||
* The included ios-proxy (instructions in [here](ios-proxy/README.md))
|
||||
* Optional: a Mac with xcode to compile the proxy yourself
|
||||
|
||||
Common Optional Requirements:
|
||||
* Wireshark [Broadcom H4 Dissector Plugin](https://github.com/seemoo-lab/h4bcm_wireshark_dissector)
|
||||
|
||||
@@ -179,6 +189,12 @@ was also recorded and gives a more high level overview.
|
||||
](https://arxiv.org/abs/1905.00631) on the complete *InternalBlue* ecosystem got accepted.
|
||||
|
||||
|
||||
* **REcon Talk** (06/2019)
|
||||
|
||||
We gave a talk at REcon, [Reversing and Exploiting Broadcom Bluetooth](https://cfp.recon.cx/reconmtl2019/talk/EQTRGU/).
|
||||
It gives a first intuition on how to do binary patching in C with Nexmon to change Bluetooth functionality.
|
||||
|
||||
|
||||
|
||||
|
||||
License
|
||||
|
||||
+10
-2
@@ -1,10 +1,18 @@
|
||||
InternalBlue PoCs and Examples
|
||||
==============================
|
||||
|
||||
All examples were tested on a *Nexus 5* (*BCM4339* chip with firmware *BCM4335C0*) on *Android* and *LineageOS*.
|
||||
The following examples were tested on a *Nexus 5* (*BCM4339* chip with firmware *BCM4335C0*) on *Android* and *LineageOS*.
|
||||
|
||||
* [CVE_2018_5383_Invalid_Curve_Attack_PoC](CVE_2018_5383_Invalid_Curve_Attack_PoC.py)
|
||||
provides tries to set the y-coordinate during ECDH key exchange to zero. If the device under test accepts the pairing (50% probability), it is vulnerable.
|
||||
* [LMP_MAC_Address_Filter](LMP_MAC_Address_Filter.py)
|
||||
replies to all LMP packets with `LMP_not_accepted` if their source is not from a MAC address in the whitelist.
|
||||
* [NiNo_PoC](NiNo_PoC.py) sets the IO capabilities of the *Nexus 5* to no input, no output.
|
||||
* [NiNo_PoC](NiNo_PoC.py) sets the IO capabilities of the *Nexus 5* to no input, no output.
|
||||
|
||||
Examples for the Raspberry Pi 3:
|
||||
|
||||
* [raspi3_rxdn](raspi4_rxdn.py) prints the first bytes of the LE connection struct within the `_connTaskRxDone` callback.
|
||||
For debugging purposes, warnings are shown for packet failures. The full logging can be enabled via `log_level debug` on the
|
||||
*InternalBlue* command line. It contains the current channel, RSSI, and event number for each packet. To blacklist channels
|
||||
from hopping, use `sendhcicmd 0x2014 ff00000000` or similar. Use `wireshark` or `btmon`
|
||||
to see the channel blacklisting live within the connection struct.
|
||||
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/python2
|
||||
|
||||
from pwn import *
|
||||
from internalblue.adbcore import ADBCore
|
||||
from internalblue.bluezcore import BluezCore
|
||||
|
||||
"""
|
||||
Script that shows receive statistics from LE connections over HCI on the CYW20735B1 evaluation board.
|
||||
Generated with Nexmon.
|
||||
"""
|
||||
|
||||
internalblue = ADBCore()
|
||||
try:
|
||||
internalblue.interface = internalblue.device_list()[0][1] # just use the first Android device
|
||||
except IndexError:
|
||||
internalblue = BluezCore()
|
||||
try:
|
||||
internalblue.interface = internalblue.device_list()[0][1] # ...or the first local HCI interface
|
||||
except IndexError:
|
||||
log.critical("Adapt the Python script to use an available Broadcom Bluetooth interface.")
|
||||
exit(-1)
|
||||
|
||||
# setup sockets
|
||||
if not internalblue.connect():
|
||||
log.critical("No connection to target device.")
|
||||
exit(-1)
|
||||
|
||||
progress_log = log.info("Connected to first target, installing patches...")
|
||||
|
||||
# GENERATED PATCHES
|
||||
internalblue.patchRom(0x0008ea46, '\x89\xf1\x5b\xbc')
|
||||
internalblue.patchRom(0x0008edc2, '\x89\xf1\x1d\xbc')
|
||||
internalblue.patchRom(0x0008eec0, '\x89\xf1\x1e\xbb')
|
||||
internalblue.writeMem(0x00218200, '\x10\xb5\xcc\x22\xff\x21\xce\x20\x0c\xf6\x43\xfe\x04\x46\x04\x22\x07\x49\x0a\x30\x50\xf6\x53\xfb\x06\x4b\x04\xf1\x0e\x00\x19\x68\xc8\x22\x50\xf6\x4c\xfb\x20\x46\xbd\xe8\x10\x40\x0c\xf6\x03\xbd\x18\x80\x21\x00\x80\x28\x28\x00')
|
||||
internalblue.writeMem(0x00218300, '\x95\xf6\x70\xfc\xff\xf7\x7c\xff\x76\xf6\x9f\xbb\x00\xbf\x00\xbf')
|
||||
internalblue.writeMem(0x00218500, '\x2d\xe9\xf0\x5f\xfe\xb5\x07\x46\xf3\x22\xff\x21\xf5\x20\x0c\xf6\xc0\xfc\x04\x46\x04\xf1\x0a\x03\x04\x22\x0f\x49\x18\x46\x50\xf6\xce\xf9\x04\xf1\x0e\x03\x4f\xf0\xef\x02\x39\x46\x18\x46\x50\xf6\xc6\xf9\x04\xf1\x0e\x03\x4f\xf0\x01\x02\x07\xf5\xe9\x71\x18\x46\x50\xf6\xbd\xf9\x20\x46\x0c\xf6\x76\xfb\x38\x46\xbd\xe8\xfe\x40\x76\xf6\xb8\xbc\x00\xbf\x00\xbf\x00\x80\x21\x00')
|
||||
internalblue.writeMem(0x00218600, '\x70\xb5\x05\x46\xfe\xb5\x05\x46\xf4\x22\xff\x21\xf6\x20\x0c\xf6\x40\xfc\x04\x46\x04\xf1\x0a\x03\x04\x22\x0b\x49\x18\x46\x50\xf6\x4e\xf9\x04\xf1\x0e\x03\x4f\xf0\xf0\x02\x29\x46\x18\x46\x50\xf6\x46\xf9\x20\x46\x0c\xf6\xff\xfa\x00\xf0\xe2\xf8\xbd\xe8\xfe\x40\x76\xf6\xc1\xbb\x00\xbf\x00\xbf\x08\x80\x21\x00')
|
||||
internalblue.writeMem(0x00218800, '\x10\xb5\x08\x22\x82\xb0\xff\x21\x0a\x20\x0c\xf6\x42\xfb\x04\x22\x04\x46\x0b\x49\x0a\x30\x50\xf6\x52\xf8\x00\x20\x9f\xf6\xec\xff\x95\xf6\x3f\xff\x02\xa9\x41\xf8\x04\x0d\x04\x22\x04\xf1\x0e\x00\x50\xf6\x45\xf8\x20\x46\x0c\xf6\xfe\xf9\x02\xb0\x10\xbd\x00\xbf\x10\x80\x21\x00')
|
||||
internalblue.writeMem(0x00218000, '\x52\x58\x44\x4e\x00\x00\x00\x00\x4c\x45\x50\x52\x00\x00\x00\x00\x52\x53\x53\x49\x00\x00\x00\x00\x52\x42\x55\x46\x00')
|
||||
|
||||
|
||||
# shutdown connection
|
||||
internalblue.shutdown()
|
||||
|
||||
|
||||
log.info("--------------------")
|
||||
log.info("To see statistics, execute 'internalblue' and run 'log_level debug'.")
|
||||
Executable
+90
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env python2
|
||||
|
||||
# Jiska Classen
|
||||
|
||||
# Get receive statistics on a Raspberry Pi 3 for BLE connection events
|
||||
|
||||
from pwn import *
|
||||
from internalblue.hcicore import HCICore
|
||||
|
||||
|
||||
internalblue = HCICore()
|
||||
device_list = internalblue.device_list()
|
||||
if len(device_list) == 0:
|
||||
log.warn("No HCI devices connected!")
|
||||
exit(-1)
|
||||
internalblue.interface = device_list[0][1] # just use the first device
|
||||
|
||||
|
||||
RX_DONE_HOOK_ADDRESS = 0x35fbc # _connTaskRxDone
|
||||
HOOKS_LOCATION = 0x210500
|
||||
ASM_HOOKS = """
|
||||
|
||||
// restore first 4 bytes of _connTaskRxDone
|
||||
push {r4-r6,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 0x3670 // 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 0x45824 // __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, #0x10a // le_conn[0x10a] is position of rssi
|
||||
mov r0, r4
|
||||
add r0, 14
|
||||
bl 0x45824 // __rt_memcpy
|
||||
|
||||
// send hci event
|
||||
mov r0, r4 // back to buffer at offset 0
|
||||
bl 0x358e // send_hci_event
|
||||
|
||||
// undo registers for our own routine
|
||||
mov r0, r7
|
||||
pop {r1-r7, lr}
|
||||
|
||||
// branch back to _connTaskRxDone + 4
|
||||
b 0x35fc0
|
||||
|
||||
"""
|
||||
|
||||
# setup sockets
|
||||
if not internalblue.connect():
|
||||
log.critical("No connection to target device.")
|
||||
exit(-1)
|
||||
|
||||
# Install hooks
|
||||
code = asm(ASM_HOOKS, vma=HOOKS_LOCATION)
|
||||
log.info("Writing hooks to 0x%x..." % HOOKS_LOCATION)
|
||||
if not internalblue.writeMem(HOOKS_LOCATION, code):
|
||||
log.critical("Cannot write hooks at 0x%x" % HOOKS_LOCATION)
|
||||
exit(-1)
|
||||
|
||||
log.info("Installing hook patch...")
|
||||
patch = asm("b 0x%x" % HOOKS_LOCATION, vma=RX_DONE_HOOK_ADDRESS)
|
||||
if not internalblue.patchRom(RX_DONE_HOOK_ADDRESS, patch):
|
||||
log.critical("Installing patch for _connTaskRxDone failed!")
|
||||
exit(-1)
|
||||
|
||||
|
||||
log.info("--------------------")
|
||||
log.info("To see statistics, execute 'internalblue' and run 'log_level debug'.")
|
||||
Executable
+90
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env python2
|
||||
|
||||
# Jiska Classen
|
||||
|
||||
# Get receive statistics on a Raspberry Pi 3 for BLE connection events
|
||||
|
||||
from pwn import *
|
||||
from internalblue.hcicore import HCICore
|
||||
|
||||
|
||||
internalblue = HCICore()
|
||||
device_list = internalblue.device_list()
|
||||
if len(device_list) == 0:
|
||||
log.warn("No HCI devices connected!")
|
||||
exit(-1)
|
||||
internalblue.interface = device_list[0][1] # just use the first device
|
||||
|
||||
|
||||
RX_DONE_HOOK_ADDRESS = 0x56622 # _connTaskRxDone
|
||||
HOOKS_LOCATION = 0x210500
|
||||
ASM_HOOKS = """
|
||||
|
||||
// restore first 4 bytes of _connTaskRxDone
|
||||
push {r4-r6,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 0x2770 // 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 0x775C8 // __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, #0x10a // le_conn[0x10a] is position of rssi
|
||||
mov r0, r4
|
||||
add r0, 14
|
||||
bl 0x775C8 // __rt_memcpy
|
||||
|
||||
// send hci event
|
||||
mov r0, r4 // back to buffer at offset 0
|
||||
bl 0x268E // send_hci_event
|
||||
|
||||
// undo registers for our own routine
|
||||
mov r0, r7
|
||||
pop {r1-r7, lr}
|
||||
|
||||
// branch back to _connTaskRxDone + 4
|
||||
b 0x56626
|
||||
|
||||
"""
|
||||
|
||||
# setup sockets
|
||||
if not internalblue.connect():
|
||||
log.critical("No connection to target device.")
|
||||
exit(-1)
|
||||
|
||||
# Install hooks
|
||||
code = asm(ASM_HOOKS, vma=HOOKS_LOCATION)
|
||||
log.info("Writing hooks to 0x%x..." % HOOKS_LOCATION)
|
||||
if not internalblue.writeMem(HOOKS_LOCATION, code):
|
||||
log.critical("Cannot write hooks at 0x%x" % HOOKS_LOCATION)
|
||||
exit(-1)
|
||||
|
||||
log.info("Installing hook patch...")
|
||||
patch = asm("b 0x%x" % HOOKS_LOCATION, vma=RX_DONE_HOOK_ADDRESS)
|
||||
if not internalblue.patchRom(RX_DONE_HOOK_ADDRESS, patch):
|
||||
log.critical("Installing patch for _connTaskRxDone failed!")
|
||||
exit(-1)
|
||||
|
||||
|
||||
log.info("--------------------")
|
||||
log.info("To see statistics, execute 'internalblue' and run 'log_level debug'.")
|
||||
+7
-1
@@ -35,6 +35,7 @@ import argparse
|
||||
|
||||
from adbcore import ADBCore
|
||||
from hcicore import HCICore
|
||||
from ioscore import iOSCore
|
||||
|
||||
import cmds
|
||||
|
||||
@@ -94,6 +95,7 @@ def internalblue_cli():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--data-directory", "-d", help="Set data directory. Default: ~/.internalblue")
|
||||
parser.add_argument("--verbose", "-v", help="Set log level to DEBUG", action="store_true")
|
||||
parser.add_argument("--ios-device", "-i", help="Tell internalblue to connect to a remote iPhone HCI socket. Specify socket IP address and port")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.data_directory != None:
|
||||
@@ -117,7 +119,11 @@ def internalblue_cli():
|
||||
term.readline.set_completer(readline_completer)
|
||||
|
||||
# Initalize cores and get devices
|
||||
connection_methods = [
|
||||
if args.ios_device:
|
||||
connection_methods = [iOSCore(args.ios_device, log_level=log_level,
|
||||
data_directory=data_directory)]
|
||||
else:
|
||||
connection_methods = [
|
||||
ADBCore(log_level=log_level, data_directory=data_directory),
|
||||
HCICore(log_level=log_level, data_directory=data_directory)]
|
||||
|
||||
|
||||
+146
-21
@@ -33,7 +33,8 @@ import datetime
|
||||
import time
|
||||
import Queue
|
||||
import hci
|
||||
|
||||
import collections
|
||||
import struct
|
||||
|
||||
class InternalBlue:
|
||||
__metaclass__ = ABCMeta
|
||||
@@ -46,6 +47,23 @@ class InternalBlue:
|
||||
self.interface = None # holds the context.device / hci interaface which is used to connect, is set in cli
|
||||
self.fw = None # holds the firmware file
|
||||
|
||||
# RXDN statistics callback variables
|
||||
self.last_nesn_sn = None
|
||||
self.last_success_event = None
|
||||
self.last_event_ctr = 0
|
||||
self.last_channel = 0
|
||||
self.last_channel_map = 0
|
||||
self.last_event_timestamp = 0
|
||||
|
||||
# variables for measuring PDR
|
||||
self.pdr_values = {}
|
||||
for i in range(0, 37):
|
||||
self.pdr_values[i] = collections.deque([1, 1, 1, 1, 1, 1, 1, 1, 1], maxlen=10)
|
||||
|
||||
self.PDR_THRESHOLD = 0.9
|
||||
self.CHAN_COUNT_THRESHOLD = 10
|
||||
|
||||
self.pdr_logfile = open("/home/pi/pdr.log", "w")
|
||||
|
||||
self.data_directory = data_directory
|
||||
self.s_inject = None # This is the TCP socket to the HCI inject port
|
||||
@@ -119,6 +137,7 @@ class InternalBlue:
|
||||
# Register callbacks which handle specific HCI Events:
|
||||
self.registerHciCallback(self.connectionStatusCallback)
|
||||
self.registerHciCallback(self.coexStatusCallback)
|
||||
self.registerHciCallback(self.lereceiveStatusCallback)
|
||||
|
||||
def check_binutils(self, fix=True):
|
||||
"""
|
||||
@@ -207,7 +226,12 @@ class InternalBlue:
|
||||
continue
|
||||
|
||||
# Extract the components of the task
|
||||
h4type, data, queue, filter_function = task
|
||||
try:
|
||||
h4type, data, queue, filter_function = task
|
||||
except ValueError:
|
||||
# might happen if H4 is not supported
|
||||
log.debug("Failed to unpack queue item.")
|
||||
continue
|
||||
|
||||
# Special handling of ADBCore and HCICore
|
||||
# ADBCore: adb transport requires to prepend the H4 data with its length
|
||||
@@ -309,25 +333,6 @@ class InternalBlue:
|
||||
self.tracepoint_memdump_parts = {}
|
||||
|
||||
|
||||
elif hcipkt.data[0:6] == "RAM___": # My custom header (see hook code)
|
||||
dump_address = u32(hcipkt.data[6:10])
|
||||
data = hcipkt.data[10:]
|
||||
|
||||
if self.tracepoint_memdump_address == None:
|
||||
self.tracepoint_memdump_address = dump_address
|
||||
normalized_address = dump_address - self.tracepoint_memdump_address
|
||||
self.tracepoint_memdump_parts[normalized_address] = data
|
||||
|
||||
# Check if this was the last packet
|
||||
if len(self.tracepoint_memdump_parts) == self.fw.TRACEPOINT_RAM_DUMP_PKT_COUNT:
|
||||
dump = fit(self.tracepoint_memdump_parts)
|
||||
#TODO: use this to start qemu
|
||||
filename = self.data_directory + "/" + "internalblue_tracepoint_0x%x_%s.bin" % (self.tracepoint_memdump_address, datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S"))
|
||||
log.info("Captured Ram Dump for Tracepoint 0x%x to %s" % (self.tracepoint_memdump_address, filename))
|
||||
f = open(filename, "wb")
|
||||
f.write(dump)
|
||||
f.close()
|
||||
|
||||
|
||||
def addTracepoint(self, address):
|
||||
# Check if constants are defined in fw.py
|
||||
@@ -1417,6 +1422,126 @@ class InternalBlue:
|
||||
log.info("[Coexistence Statistics: Grant=%d Reject=%d -> Reject Ratio %.4f]" % (coex_grant, coex_reject, coex_reject/float(coex_grant)))
|
||||
return
|
||||
|
||||
def lereceiveStatusCallback(self, 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
|
||||
|
||||
# Only do something when we have the correct firmware
|
||||
if not self.fw:
|
||||
return
|
||||
|
||||
raspi = False
|
||||
eval = False
|
||||
if self.fw.FW_NAME == "BCM43430A1":
|
||||
raspi = True
|
||||
elif self.fw.FW_NAME == "CYW27035B1":
|
||||
eval = True
|
||||
else:
|
||||
return
|
||||
|
||||
if self.fw and hcipkt.data[0:4] == "RXDN":
|
||||
data = hcipkt.data[4:]
|
||||
|
||||
# Raspi 3 gets errors
|
||||
if len(data) < 239:
|
||||
return
|
||||
|
||||
if raspi:
|
||||
packet_curr_nesn_sn = u8(data[0xa0])
|
||||
|
||||
elif eval:
|
||||
packet_curr_nesn_sn = u8(data[0xa4])
|
||||
|
||||
packet_channel_map = data[0x54:0x7b]
|
||||
packet_channel = u8(data[0x83])
|
||||
packet_event_ctr = u16(data[0x8e:0x90])
|
||||
packet_rssi = u8(data[0])
|
||||
|
||||
|
||||
# When looking at the NESN and the SN bit, we check for TX and RX errors
|
||||
# if self.last_nesn_sn and ((self.last_nesn_sn ^ packet_curr_nesn_sn) & 0b1100) !=0b1100:
|
||||
# log.info(" ^----------------------------- ERROR --------------------------------")
|
||||
|
||||
# When looking only at the NESN bit, we check for TX errors -> this is the thing we want in our EWSN paper
|
||||
if self.last_nesn_sn and ((self.last_nesn_sn ^ packet_curr_nesn_sn) & 0b0100) !=0b0100:
|
||||
pdr_current = 0
|
||||
else:
|
||||
pdr_current = 1
|
||||
|
||||
self.pdr_values[packet_channel].appendleft(pdr_current)
|
||||
pdr_avg = sum(self.pdr_values[packet_channel]) / float(len(self.pdr_values[packet_channel]))
|
||||
|
||||
# log.info("%s event: %5d, channel: %2d, channel_map: 0x%010x, PDR: %d, PDR_avg: %f" % (self.last_event_timestamp, self.last_event_ctr, self.last_channel, self.last_channel_map, pdr_current, pdr_avg))
|
||||
self.pdr_logfile.write("%s event: %5d, channel: %2d, channel_map: 0x%010x, PDR: 1\r\n" % (self.last_event_timestamp, self.last_event_ctr, self.last_channel, self.last_channel_map))
|
||||
self.pdr_logfile.flush()
|
||||
|
||||
if pdr_avg < self.PDR_THRESHOLD:
|
||||
active_channels = bin(self.last_channel_map).count('1')
|
||||
if active_channels <= self.CHAN_COUNT_THRESHOLD:
|
||||
# log.info('to few channels active -> whiteliste all')
|
||||
self.pdr_logfile.write('to few channels active -> whiteliste all')
|
||||
self.pdr_logfile.flush()
|
||||
self.sendHciCommand(0x2014, '\xff\xff\xff\xff\xf1', timeout=0)
|
||||
else:
|
||||
self.pdr_logfile.write("going to BLACKLIST channel %2d, %2d channels active" % (self.last_channel, active_channels))
|
||||
new_channel_map = self.last_channel_map & (0x1fffffffff ^ (0b1 << self.last_channel))
|
||||
self.pdr_logfile.write("current_channel_map: 0x%010x, new map: 0x%010x" % (self.last_channel_map, new_channel_map))
|
||||
self.pdr_logfile.flush()
|
||||
|
||||
new_channel_map_bytes = []
|
||||
for i in range (0, 5):
|
||||
new_channel_map_bytes.append(chr(new_channel_map >> (i * 8) & 0xff))
|
||||
|
||||
self.sendHciCommand(0x2014, ''.join(new_channel_map_bytes), timeout=0)
|
||||
|
||||
# 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:
|
||||
# log.info(" ^----------------------------- 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)
|
||||
|
||||
self.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 = u8(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) >> u8(packet_channel_map[channel]) # Use the flipped representation of the channel map to be consistent in my code
|
||||
channel_map |= (0b1 << u8(packet_channel_map[channel]))
|
||||
|
||||
# log.debug("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))
|
||||
|
||||
# Store the following information for the next connection event, because we will know only by then, if the event was successful
|
||||
self.last_event_ctr = packet_event_ctr
|
||||
self.last_channel = packet_channel
|
||||
self.last_channel_map = channel_map
|
||||
self.last_event_timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
|
||||
|
||||
if self.fw and hcipkt.data[0:4] == "LEPR":
|
||||
data = hcipkt.data[4:]
|
||||
self.last_success_event = u16(data[0x8e:0x90])
|
||||
|
||||
def readHeapInformation(self):
|
||||
"""
|
||||
Traverses the double-linked list of BLOC structs and returns them as a
|
||||
|
||||
+27
-11
@@ -7,47 +7,51 @@ Results are based on real world testing, this list is very incomplete. If you kn
|
||||
|
||||
|
||||
|
||||
Vendor | Version | SubVersion | Firmware | Devices
|
||||
-------| ------- | ---------- | ----------- | -------
|
||||
Vendor | Version | SubVersion | Firmware | Devices | Firmware Build Date
|
||||
-------| ------- | ---------- | ----------- | ------- | ----------
|
||||
0x000f | 0x04 | 0x4217 | BCM4329B1 | iPhone 4
|
||||
0x000f | 0x04 | 0x21d0 | BCM2046 | iMac 27" late 2009
|
||||
0x000f | 0x04 | 0x422a | BCM4331 | MacBook Pro early 2011
|
||||
0x000f | 0x05 | 0x4203 | BCM2034B | Thinkpad T420
|
||||
0x000f | 0x05 | 0x610d | | iPad A1395
|
||||
0x000f | 0x06 | 0x220e | BCM20702A1 | Asus USB Bluetooth dongle
|
||||
0x000f | 0x06 | 0x229b | BCM20702A3 | MacBook Pro 13" mid 2012 (A1278)
|
||||
0x000f | 0x06 | 0x4103 | BCM4330B1 | iPhone 4s
|
||||
0x000f | 0x06 | 0x4196 | BCM20702B0 | MacBook Pro mid 2014, iMac (Retina 5k, 27", ultimo 2014)
|
||||
0x000f | 0x07 | 0x220f | BCM20736S | Equiva Radiator Thermostat CC-RT-BLE-EQ
|
||||
0x000f | 0x07 | 0x2203 | BCM43342 | iPhone 5s
|
||||
0x000f | 0x07 | 0x2209 | BCM43430A1 | Raspberry Pi 3
|
||||
0x000f | 0x07 | 0x2209 | BCM43430A1 | Raspberry Pi 3 | Jun 2 2014
|
||||
0x000f | 0x07 | 0x230f | BCM4356A2 | Xperia Z5
|
||||
0x000f | 0x07 | 0x410d | BCM4334 | iPhone 5 (A1429)
|
||||
0x000f | 0x07 | 0x6109 | BCM4335C0 (BCM4339) | Nexus 5, Xperia Z3 Compact, Samsung Galaxy Note 3, LG G4 (LG-h815), Samsung Galaxy Note 10.1 2014 WiFi (SM-P600)
|
||||
0x000f | 0x08 | 0x6119 | BCM4345C0 | Raspberry Pi 3+, Honor 8
|
||||
0x000f | 0x07 | 0x6109 | BCM4335C0 (BCM4339) | Nexus 5, Xperia Z3 Compact, Samsung Galaxy Note 3, LG G4 (LG-h815), Samsung Galaxy Note 10.1 2014 WiFi (SM-P600) | Dec 11 2012
|
||||
0x000f | 0x08 | 0x6119 | BCM4345C0 | Raspberry Pi 3+, Honor 8 | Aug 19 2014
|
||||
0x000f | 0x08 | 0x21a1 | | MacBook Pro Retina 13" early 2015
|
||||
0x000f | 0x08 | 0x21a6 | BCM20703A1 | MacBook Pro early 2015
|
||||
0x000f | 0x08 | 0x21a7 | BCM20703A1 | MacBook Pro early 2015 (with security fix)
|
||||
0x000f | 0x08 | 0x220b | BCM20707 | Fitbit Ionic
|
||||
0x000f | 0x08 | 0x2230 | BCM20703A2 | MacBook Pro 2016 (A1707)
|
||||
0x000f | 0x08 | 0x2230 | BCM20703A2 | MacBook Pro 2016 (A1707) | Oct 22 2015
|
||||
0x000f | 0x08 | 0x2246 | BCM20703A2 | MacBook Pro 2016
|
||||
0x000f | 0x08 | 0x2247 | BCM20703A2 | MacBook Pro 2016 (with security fix)
|
||||
0x000f | 0x08 | 0x224b | BCM20703A2 | MacBook Pro 2016, 2017
|
||||
0x000f | 0x08 | 0x240f | BCM4358A3 | Nexus 6P, Samsung Galaxy S6, Samsung Galaxy S6 edge
|
||||
0x000f | 0x08 | 0x240f | BCM4358A3 | Nexus 6P, Samsung Galaxy S6, Samsung Galaxy S6 edge | Oct 23 2014
|
||||
0x000f | 0x08 | 0x4109 | BCM4345 | iPhone 6
|
||||
0x000f | 0x08 | 0x430a | | iPad Pro 2016 (MLMW2FD/A)
|
||||
0x000f | 0x08 | 0x6103 | | iPhone 7 (A1778)
|
||||
0x000f | 0x08 | 0x6103 | BCM4355C0 | iPhone 7 (A1778) | Sep 14 2015
|
||||
0x000f | 0x08 | 0x6106 | | Samsung Galaxy S7
|
||||
0x000f | 0x08 | 0x617e | BCM4350 | MacBook Pro 2017 (Retina 12"), MacBook Pro (13", 2016)
|
||||
0x000f | 0x08 | 0x6206 | | iPhone SE
|
||||
0x000f | 0x09 | 0x103f | BCM4364 | iMac Pro 2017
|
||||
0x000f | 0x09 | 0x203f | BCM4364 | MacBook Pro (13", 2018)
|
||||
0x000f | 0x09 | 0x2040 | | Apple Watch Series 3
|
||||
0x000f | 0x09 | 0x411a | BCM4347B0 (BCM4361B0) | Samsung Galaxy S8
|
||||
0x0131 | 0x09 | 0x4208 | CYW20735B1 | BLE/BR Bluetooth 5.0 Evaluation Kit
|
||||
0x000f | 0x09 | 0x4208 | BCM4375B1 | Samsung Galaxy S10e, Samsung Galaxy S10, Samsung Galaxy S10+
|
||||
0x0131 | 0x09 | 0x4208 | CYW20819A1 | ULP BLE/BR/EDR Bluetooth 5 Wireless MCU Evaluation Kit CYW920819EVB-02 | May 22 2018
|
||||
0x000f | 0x09 | 0x411a | BCM4347B0 (BCM4361B0) | Samsung Galaxy S8 | Jun 3 2016
|
||||
0x0131 | 0x09 | 0x4208 | CYW20735B1 | BLE/BR Bluetooth 5.0 Evaluation Kit CYW920735Q60EVB-01 | Jan 18 2018
|
||||
0x000f | 0x09 | 0x4208 | BCM4375B1 | Samsung Galaxy S10e, Samsung Galaxy S10, Samsung Galaxy S10+ (local version is 0x1111) | April 13 2018
|
||||
0x000f | 0x09 | 0x420e | | iPhone XR, iPhone X
|
||||
0x0131 | 0x09 | 0x420e | CYW20739B1 | Bluetooth 5.0 BLE Evaluation Kit CYW920719Q40EVB-01 | Jan 17 2017
|
||||
0x000f | 0x09 | 0x4307 | | iPhone XS, iPhone Xs Max
|
||||
0x000f | 0x09 | 0x4309 | | Samsung Galaxy Note 9, Samsung Galaxy S9+
|
||||
0x0131 | 0x09 | 0x6119 | BCM4345C0 | Raspberry Pi 4 with Bluetooth 5 patches, same ROM as 3+ | Aug 19 2014
|
||||
|
||||
|
||||
|
||||
@@ -69,6 +73,18 @@ There is a couple of issues causing trouble running *InternalBlue*, which are re
|
||||
* CYW20735B1
|
||||
* `Launch_RAM` works in principle, but threading seems to be broken if the executed code generates other HCI events.
|
||||
A hook at `0xB0316` is a nice spot to implement a function that generates HCI events and can be called via the HCI command `0xfc19`.
|
||||
|
||||
Firmware Version and Build Date
|
||||
-------------------------------
|
||||
|
||||
Broadcom internally uses different firmware versions than chip names. For example, the *BCM4339* chip in the *Nexus 5*
|
||||
is internally called *BCM4335C0*. It is known to be a revision of the older *BCM4335* chip.
|
||||
|
||||
On newer chips, the build information is located in the beginning of the stack. To see it, simply enter
|
||||
|
||||
hd 0x200400
|
||||
|
||||
|
||||
|
||||
Firmware Related Setup
|
||||
----------------------
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env python2
|
||||
|
||||
# fw_0x6119.py
|
||||
#
|
||||
# All firmware specific data such as address offsets are collected
|
||||
# in the fw.py file. Later versions of the framework will provide
|
||||
# multiple copies of this file in order to target different firmware
|
||||
# and chip versions.
|
||||
#
|
||||
# Copyright (c) 2019 Jiska Classen. (MIT License)
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
# - The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
# - The Software is provided "as is", without warranty of any kind, express or
|
||||
# implied, including but not limited to the warranties of merchantability,
|
||||
# fitness for a particular purpose and noninfringement. In no event shall the
|
||||
# authors or copyright holders be liable for any claim, damages or other
|
||||
# liability, whether in an action of contract, tort or otherwise, arising from,
|
||||
# out of or in connection with the Software or the use or other dealings in the
|
||||
# Software.
|
||||
|
||||
# Firmware Infos
|
||||
# This runs on Rasperry Pi 3
|
||||
FW_NAME = "BCM43430A1"
|
||||
|
||||
# Device Infos
|
||||
DEVICE_NAME = 0x20401C
|
||||
BD_ADDR = 0x201C64
|
||||
|
||||
# Memory Sections
|
||||
class MemorySection:
|
||||
def __init__(self, start_addr, end_addr, is_rom, is_ram):
|
||||
self.start_addr = start_addr
|
||||
self.end_addr = end_addr
|
||||
self.is_rom = is_rom
|
||||
self.is_ram = is_ram
|
||||
|
||||
def size(self):
|
||||
return self.end_addr - self.start_addr
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [ MemorySection(0x0, 0x90000, True , False),
|
||||
MemorySection(0xd0000, 0xd8000, False, True ),
|
||||
#MemorySection(0xe0000, 0x1f0000, True , False),
|
||||
MemorySection(0x200000, 0x228000, False, True ),
|
||||
MemorySection(0x260000, 0x268000, True , False),
|
||||
#MemorySection(0x280000, 0x2a0000, True , False),
|
||||
MemorySection(0x318000, 0x320000, False, False),
|
||||
MemorySection(0x324000, 0x360000, False, False),
|
||||
MemorySection(0x362000, 0x362100, False, False),
|
||||
MemorySection(0x363000, 0x363100, False, False),
|
||||
MemorySection(0x600000, 0x600800, False, False),
|
||||
MemorySection(0x640000, 0x640800, False, False),
|
||||
MemorySection(0x650000, 0x650800, False, False),
|
||||
#MemorySection(0x680000, 0x800000, False, False)
|
||||
]
|
||||
|
||||
# Connection Structure and Table
|
||||
#CONNECTION_ARRAY_ADDRESS = 0x204ba8
|
||||
#CONNECTION_MAX = 11
|
||||
#CONNECTION_STRUCT_LENGTH = 0x150
|
||||
|
||||
# Patchram
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310204
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0xd0000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 128
|
||||
PATCHRAM_ALIGNED = False
|
||||
@@ -0,0 +1,46 @@
|
||||
# fw_0x420e.py
|
||||
#
|
||||
# Generic firmware file in case we do not know something...
|
||||
#
|
||||
# Copyright (c) 2019 Jiska Classen. (MIT License)
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
# - The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
# - The Software is provided "as is", without warranty of any kind, express or
|
||||
# implied, including but not limited to the warranties of merchantability,
|
||||
# fitness for a particular purpose and noninfringement. In no event shall the
|
||||
# authors or copyright holders be liable for any claim, damages or other
|
||||
# liability, whether in an action of contract, tort or otherwise, arising from,
|
||||
# out of or in connection with the Software or the use or other dealings in the
|
||||
# Software.
|
||||
|
||||
from fw import MemorySection
|
||||
|
||||
# Firmware Infos
|
||||
# Evaluation Kit CYW920819
|
||||
FW_NAME = "CYW20819"
|
||||
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [ MemorySection(0x00000000, 0x001fffff, True, False), # Internal ROM
|
||||
MemorySection(0x00200000, 0x0024ffff, False, True), # Internal Memory Cortex M3
|
||||
MemorySection(0x00270000, 0x0027ffff, False, True), # Internal Memory Patchram Contents
|
||||
MemorySection(0x00310000, 0x00321fff, False, True), # HW Regs Cortex M3 (readable)
|
||||
]
|
||||
|
||||
# Patchram
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310404
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0x270000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 256
|
||||
PATCHRAM_ALIGNED = False
|
||||
# only seems to work 4-byte aligned here ...
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ DEVICE_NAME = 0x280CD0 # rm_deviceLocalName, FIXME has no longe
|
||||
BD_ADDR = 0x280CA4 # rm_deviceBDAddr
|
||||
|
||||
#Heap
|
||||
BLOC_HEAD = 0x200474
|
||||
BLOC_HEAD = 0x200474 # g_dynamic_memory_GeneralUsePools
|
||||
BLOC_NG = True # Next Generation Bloc Buffer
|
||||
|
||||
# Memory Sections
|
||||
@@ -149,8 +149,8 @@ FUZZLMP_ASM_CODE = """
|
||||
|
||||
# Assembler snippet for tracepoints
|
||||
# In contrast to the Nexus 5 patch, we uninstall ourselves automatically and use internal debug functions
|
||||
TRACEPOINT_BODY_ASM_LOCATION = 0x00218500
|
||||
TRACEPOINT_HOOKS_LOCATION = 0x00218700
|
||||
TRACEPOINT_BODY_ASM_LOCATION = 0x00218950
|
||||
TRACEPOINT_HOOKS_LOCATION = 0x00218900
|
||||
TRACEPOINT_HOOK_SIZE = 40
|
||||
TRACEPOINT_HOOK_ASM = """
|
||||
push {r0-r12, lr} // save all registers on the stack (except sp and pc)
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
# fw_0x420e.py
|
||||
#
|
||||
# Generic firmware file in case we do not know something...
|
||||
#
|
||||
# Copyright (c) 2019 Jiska Classen. (MIT License)
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
# - The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
# - The Software is provided "as is", without warranty of any kind, express or
|
||||
# implied, including but not limited to the warranties of merchantability,
|
||||
# fitness for a particular purpose and noninfringement. In no event shall the
|
||||
# authors or copyright holders be liable for any claim, damages or other
|
||||
# liability, whether in an action of contract, tort or otherwise, arising from,
|
||||
# out of or in connection with the Software or the use or other dealings in the
|
||||
# Software.
|
||||
|
||||
from fw import MemorySection
|
||||
|
||||
# Firmware Infos
|
||||
# Evaluation Kit CYW927019
|
||||
FW_NAME = "CYW27039B1"
|
||||
|
||||
# Device Infos
|
||||
DEVICE_NAME = 0x280CD0 # rm_deviceLocalName, FIXME has no longer a length byte prepended
|
||||
BD_ADDR = 0x280CA4 # rm_deviceBDAddr
|
||||
|
||||
#Heap
|
||||
BLOC_HEAD = 0x0200c7c # g_dynamic_memory_GeneralUsePools
|
||||
BLOC_NG = True # Next Generation Bloc Buffer
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [ MemorySection(0x00000000, 0x001fffff, True, False), # Internal ROM
|
||||
MemorySection(0x00200000, 0x0024ffff, False, True), # Internal Memory Cortex M3
|
||||
MemorySection(0x00270000, 0x0027ffff, False, True), # Internal Memory Patchram Contents
|
||||
MemorySection(0x00280000, 0x00283fff, False, True), # ToRam
|
||||
]
|
||||
|
||||
# Patchram
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310404
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0x270000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 192
|
||||
PATCHRAM_ALIGNED = False
|
||||
# only seems to work 4-byte aligned here ...
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env python2
|
||||
|
||||
# fw_0x6103.py
|
||||
#
|
||||
# Copyright (c) 2019 Dennis Heinze. (MIT License)
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
# - The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
# - The Software is provided "as is", without warranty of any kind, express or
|
||||
# implied, including but not limited to the warranties of merchantability,
|
||||
# fitness for a particular purpose and noninfringement. In no event shall the
|
||||
# authors or copyright holders be liable for any claim, damages or other
|
||||
# liability, whether in an action of contract, tort or otherwise, arising from,
|
||||
# out of or in connection with the Software or the use or other dealings in the
|
||||
# Software.
|
||||
|
||||
from fw import MemorySection
|
||||
|
||||
# Firmware Infos
|
||||
# This runs on an iPhone 7
|
||||
FW_NAME = "BCM4355C0"
|
||||
|
||||
# Device Infos
|
||||
DEVICE_NAME = 0x204c60
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [ MemorySection(0x0, 0x90000, True , False),
|
||||
MemorySection(0xd0000, 0xd8000, False, True ),
|
||||
#MemorySection(0xe0000, 0x1f0000, True , False),
|
||||
MemorySection(0x200000, 0x228000, False, True ),
|
||||
MemorySection(0x260000, 0x268000, True , False),
|
||||
#MemorySection(0x280000, 0x2a0000, True , False),
|
||||
MemorySection(0x318000, 0x320000, False, False),
|
||||
MemorySection(0x324000, 0x360000, False, False),
|
||||
MemorySection(0x362000, 0x362100, False, False),
|
||||
MemorySection(0x363000, 0x363100, False, False),
|
||||
MemorySection(0x600000, 0x600800, False, False),
|
||||
MemorySection(0x640000, 0x640800, False, False),
|
||||
MemorySection(0x650000, 0x650800, False, False),
|
||||
#MemorySection(0x680000, 0x800000, False, False)
|
||||
]
|
||||
@@ -65,3 +65,10 @@ SECTIONS = [ MemorySection(0x0, 0x90000, True , False),
|
||||
CONNECTION_ARRAY_ADDRESS = 0x204ba8
|
||||
CONNECTION_MAX = 11
|
||||
CONNECTION_STRUCT_LENGTH = 0x150
|
||||
|
||||
# Patchram
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310204
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0xd0000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 128
|
||||
PATCHRAM_ALIGNED = False
|
||||
|
||||
@@ -43,8 +43,13 @@ class HCICore(InternalBlue):
|
||||
dev_flags_str : Device flags as String (e.g. "UP RUNNING" or "DOWN")
|
||||
"""
|
||||
|
||||
# Open bluetooth socket to execute ioctl's:
|
||||
s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI)
|
||||
# Open Bluetooth socket to execute ioctl's:
|
||||
try:
|
||||
s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI)
|
||||
# Ticket 6: does not run on Windows with Kali subsystem
|
||||
except socket.error:
|
||||
log.warn("Opening a local Bluetooth socket failed. Not running on native Linux?")
|
||||
return []
|
||||
|
||||
# Do ioctl(s,HCIGETDEVLIST,arg) to get the number of available devices:
|
||||
# arg is struct hci_dev_list_req (/usr/include/bluetooth/hci.h)
|
||||
@@ -189,7 +194,7 @@ class HCICore(InternalBlue):
|
||||
record = (hci.parse_hci_packet(record_data), btsnoop_orig_len, btsnoop_inc_len,
|
||||
btsnoop_flags, btsnoop_drops, btsnoop_time)
|
||||
|
||||
log.debug("_recvThreadFunc Recv: [" + str(btsnoop_time) + "] " + str(record[0]))
|
||||
#log.debug("_recvThreadFunc Recv: [" + str(btsnoop_time) + "] " + str(record[0]))
|
||||
|
||||
# Write to btsnoop file:
|
||||
if self.write_btsnooplog:
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env python2
|
||||
|
||||
import socket
|
||||
import Queue
|
||||
import hci
|
||||
|
||||
from pwn import *
|
||||
|
||||
from core import InternalBlue
|
||||
|
||||
class iOSCore(InternalBlue):
|
||||
|
||||
def __init__(self, ios_addr, queue_size=1000, btsnooplog_filename='btsnoop.log', log_level='info', fix_binutils='True', data_directory="."):
|
||||
super(iOSCore, self).__init__(queue_size, btsnooplog_filename, log_level, fix_binutils, data_directory=".")
|
||||
parts = ios_addr.split(':')
|
||||
if len(parts) != 2:
|
||||
log.critical("iOS device address should be of format HOSTNAME:PORT")
|
||||
exit(-1)
|
||||
self.ios_addr = parts[0]
|
||||
self.ios_port = parts[1]
|
||||
|
||||
def device_list(self):
|
||||
"""
|
||||
Get a list of connected devices
|
||||
"""
|
||||
|
||||
if self.exit_requested:
|
||||
self.shutdown()
|
||||
|
||||
if self.running:
|
||||
log.warn("Already running. Call shutdown() first!")
|
||||
return []
|
||||
|
||||
# assume that a explicitly specified iPhone exists
|
||||
device_list = []
|
||||
device_list.append((self, "iPhone", "iPhone"))
|
||||
|
||||
return device_list
|
||||
|
||||
def sendH4(self, h4type, data, timeout=2):
|
||||
"""
|
||||
Send an arbitrary HCI packet by pushing a send-task into the
|
||||
sendQueue. This function blocks until the response is received
|
||||
or the timeout expires. The return value is the Payload of the
|
||||
HCI Command Complete Event which was received in response to
|
||||
the command or None if no response was received within the timeout.
|
||||
"""
|
||||
|
||||
queue = Queue.Queue(1)
|
||||
|
||||
try:
|
||||
self.sendQueue.put((h4type, data, queue, None), timeout=timeout)
|
||||
ret = queue.get(timeout=timeout)
|
||||
return ret
|
||||
except Queue.Empty:
|
||||
log.warn("sendH4: waiting for response timed out!")
|
||||
return None
|
||||
except Queue.Full:
|
||||
log.warn("sendH4: send queue is full!")
|
||||
return None
|
||||
|
||||
def local_connect(self):
|
||||
"""
|
||||
Start the framework by connecting to the iOS bluetooth device proxy via
|
||||
TCP
|
||||
"""
|
||||
if not self._setupSockets():
|
||||
log.critical("No connection to iPhone.")
|
||||
log.info("Check if\n -> Bluetooth is deactivated in the iPhone settings\n -> internalblue-ios-proxy is running\n -> the proxied port is accesible from this machine")
|
||||
return False
|
||||
return True
|
||||
|
||||
def _setupSockets(self):
|
||||
"""
|
||||
Connect to the iOS bluetooth device over internalblue-ios-proxy
|
||||
"""
|
||||
|
||||
self.s_inject = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
self.s_inject.connect((self.ios_addr, int(self.ios_port)))
|
||||
self.s_inject.settimeout(0.5)
|
||||
except socket.error:
|
||||
log.warn("Could not connect to iPhone, is internalblue-ios-proxy running?")
|
||||
return False
|
||||
|
||||
# with ios proxy the send and receive sockets are the same
|
||||
self.s_snoop = self.s_inject
|
||||
return True
|
||||
|
||||
def _recvThreadFunc(self):
|
||||
|
||||
log.debug("Receive Thread started.")
|
||||
|
||||
if (self.write_btsnooplog):
|
||||
log.warn("Writing btsnooplog is not supported with iOS.")
|
||||
|
||||
while not self.exit_requested:
|
||||
# Little bit ugly: need to re-apply changes to the global context to the thread-copy
|
||||
context.log_level = self.log_level
|
||||
|
||||
# read record data
|
||||
try:
|
||||
record_data = self.s_snoop.recv(1024)
|
||||
except socket.timeout:
|
||||
continue # this is ok. just try again without error
|
||||
|
||||
# Put all relevant infos into a tuple. The HCI packet is parsed with the help of hci.py.
|
||||
record = (hci.parse_hci_packet(record_data), 0, 0, 0, 0, 0) #TODO not sure if this causes trouble?
|
||||
|
||||
log.debug("Recv: " + str(record[0]))
|
||||
|
||||
# Put the record into all queues of registeredHciRecvQueues if their
|
||||
# filter function matches.
|
||||
for queue, filter_function in self.registeredHciRecvQueues: # TODO filter_function not working with bluez modifications
|
||||
try:
|
||||
queue.put(record, block=False)
|
||||
except Queue.Full:
|
||||
log.warn("recvThreadFunc: A recv queue is full. dropping packets..")
|
||||
|
||||
# Call all callback functions inside registeredHciCallbacks and pass the
|
||||
# record as argument.
|
||||
for callback in self.registeredHciCallbacks:
|
||||
callback(record)
|
||||
|
||||
# Check if the stackDumpReceiver has noticed that the chip crashed.
|
||||
if self.stackDumpReceiver.stack_dump_has_happend:
|
||||
# A stack dump has happend!
|
||||
log.warn("recvThreadFunc: The controller send a stack dump. stopping..")
|
||||
self.exit_requested = True
|
||||
|
||||
log.debug("Receive Thread terminated.")
|
||||
|
||||
def _teardownSockets(self):
|
||||
"""
|
||||
Close s_snoop and s_inject (which are the same)
|
||||
"""
|
||||
|
||||
if (self.s_inject != None):
|
||||
self.s_inject.close()
|
||||
self.s_inject = None
|
||||
|
||||
return True
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# internalblue-ios-proxy
|
||||
This project is a proxy that redirects iOS's bluetooth socket and exposes it as a TCP socket which can be used to send HCI commands to the bluetooth controller of the device. A jailbroken device is required. To compile the project, a Mac with xcode is required.
|
||||
|
||||
## Building internalblue-ios-proxy
|
||||
Open the project with xcode and compile it. Xcode will create a single binary that can then be transferred onto the device.
|
||||
|
||||
## Installing internalblue-ios-proxy
|
||||
1. Right-click the `internalblue-ios-proxy` binary and click "Show in Finder". This will open the location the compiled binary resides in.
|
||||
2. Move the binary onto the device (e.g. with scp) at a location where applications are allowed to be executed (e.g. `/bin` or `/sbin`).
|
||||
3. The binary needs the `platform-application` entitlement. This is achieved by signing the binary with the included `entitlements.xml` file. Sign it using `ldid -Sentitlements.xml internalblue-ios-proxy`. `ldid` should be on a jailbroken device with Cydia by default.
|
||||
|
||||
## Running internalblue-ios-proxy
|
||||
Run the proxy by executing `internalblue-ios-proxy <port-number>`. The phone will then listen on this port and can be accessed either when on the same WiFi or by proxying the port through USB (using [usbmuxd](https://iphonedevwiki.net/index.php/SSH_Over_USB)).
|
||||
|
||||
A few things to note:
|
||||
- to increase reliability of the proxy, bluetooth should be disabled (either by manually stopping the bluetoothd daemon or by shutting of bluetooth in the settings on the phone)
|
||||
- in case the bluetooth chip crashes or does not respond anymore over the proxy, the proxy should be stopped and bluetooth should be turned off and on again in the UI
|
||||
- sometimes the bluetooth socket will not respond anymore after establishing a second connection, just restart the proxy then.
|
||||
|
||||
This project is based on Brandon Azad's [iOS command line tool](https://github.com/bazad/ios-command-line-tool) template.
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>platform-application</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,285 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
BB958F25227BA4580029C2D6 /* internalblue-ios-proxy.c in Sources */ = {isa = PBXBuildFile; fileRef = BB958F24227BA4580029C2D6 /* internalblue-ios-proxy.c */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
551A88C4208E671F0048DFA0 /* internalblue-ios-proxy */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = "internalblue-ios-proxy"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
BB958F23227BA4580029C2D6 /* internalblue-ios-proxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "internalblue-ios-proxy.h"; sourceTree = "<group>"; };
|
||||
BB958F24227BA4580029C2D6 /* internalblue-ios-proxy.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "internalblue-ios-proxy.c"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
551A88C1208E671F0048DFA0 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
551A88BB208E671F0048DFA0 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
551A88C6208E671F0048DFA0 /* internalblue-ios-proxy */,
|
||||
551A88C5208E671F0048DFA0 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
551A88C5208E671F0048DFA0 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
551A88C4208E671F0048DFA0 /* internalblue-ios-proxy */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
551A88C6208E671F0048DFA0 /* internalblue-ios-proxy */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BB958F23227BA4580029C2D6 /* internalblue-ios-proxy.h */,
|
||||
BB958F24227BA4580029C2D6 /* internalblue-ios-proxy.c */,
|
||||
);
|
||||
path = "internalblue-ios-proxy";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
551A88C3208E671F0048DFA0 /* internalblue-ios-proxy */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 551A88CD208E671F0048DFA0 /* Build configuration list for PBXNativeTarget "internalblue-ios-proxy" */;
|
||||
buildPhases = (
|
||||
551A88C0208E671F0048DFA0 /* Sources */,
|
||||
551A88C1208E671F0048DFA0 /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "internalblue-ios-proxy";
|
||||
productName = "ios-command-line-tool";
|
||||
productReference = 551A88C4208E671F0048DFA0 /* internalblue-ios-proxy */;
|
||||
productType = "com.apple.product-type.library.dynamic";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
551A88BC208E671F0048DFA0 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0930;
|
||||
ORGANIZATIONNAME = ttdennis;
|
||||
TargetAttributes = {
|
||||
551A88C3208E671F0048DFA0 = {
|
||||
CreatedOnToolsVersion = 9.3;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 551A88BF208E671F0048DFA0 /* Build configuration list for PBXProject "internalblue-ios-proxy" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
);
|
||||
mainGroup = 551A88BB208E671F0048DFA0;
|
||||
productRefGroup = 551A88C5208E671F0048DFA0 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
551A88C3208E671F0048DFA0 /* internalblue-ios-proxy */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
551A88C0208E671F0048DFA0 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
BB958F25227BA4580029C2D6 /* internalblue-ios-proxy.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
551A88CB208E671F0048DFA0 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
551A88CC208E671F0048DFA0 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
551A88CE208E671F0048DFA0 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = RSU3RMH9UZ;
|
||||
DYLIB_COMPATIBILITY_VERSION = "";
|
||||
DYLIB_CURRENT_VERSION = "";
|
||||
EXECUTABLE_PREFIX = "";
|
||||
EXECUTABLE_SUFFIX = "";
|
||||
MACH_O_TYPE = mh_execute;
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
551A88CF208E671F0048DFA0 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = RSU3RMH9UZ;
|
||||
DYLIB_COMPATIBILITY_VERSION = "";
|
||||
DYLIB_CURRENT_VERSION = "";
|
||||
EXECUTABLE_PREFIX = "";
|
||||
EXECUTABLE_SUFFIX = "";
|
||||
MACH_O_TYPE = mh_execute;
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
551A88BF208E671F0048DFA0 /* Build configuration list for PBXProject "internalblue-ios-proxy" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
551A88CB208E671F0048DFA0 /* Debug */,
|
||||
551A88CC208E671F0048DFA0 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
551A88CD208E671F0048DFA0 /* Build configuration list for PBXNativeTarget "internalblue-ios-proxy" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
551A88CE208E671F0048DFA0 /* Debug */,
|
||||
551A88CF208E671F0048DFA0 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 551A88BC208E671F0048DFA0 /* Project object */;
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "551A88C3208E671F0048DFA0"
|
||||
BuildableName = "internalblue-ios-proxy"
|
||||
BlueprintName = "internalblue-ios-proxy"
|
||||
ReferencedContainer = "container:internalblue-ios-proxy.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "551A88C3208E671F0048DFA0"
|
||||
BuildableName = "internalblue-ios-proxy"
|
||||
BlueprintName = "internalblue-ios-proxy"
|
||||
ReferencedContainer = "container:internalblue-ios-proxy.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "551A88C3208E671F0048DFA0"
|
||||
BuildableName = "internalblue-ios-proxy"
|
||||
BlueprintName = "internalblue-ios-proxy"
|
||||
ReferencedContainer = "container:internalblue-ios-proxy.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -0,0 +1,282 @@
|
||||
//
|
||||
// internalblue-ios-proxy.c
|
||||
// internalblue-ios-proxy
|
||||
//
|
||||
// Created by ttdennis on 03.05.19.
|
||||
// Copyright © 2019 ttdennis. All rights reserved.
|
||||
//
|
||||
|
||||
#include "internalblue-ios-proxy.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
|
||||
#define IOAOSSKYSETCHANNELSPEC 0x800C5414
|
||||
#define IOAOSSKYGETCHANNELUUID 0x40105412
|
||||
|
||||
#define CTLIOCGINFO 0xC0644E03
|
||||
|
||||
typedef struct ctl_info {
|
||||
uint32_t ctl_id;
|
||||
char ctl_name[96];
|
||||
} ctl_info_t;
|
||||
|
||||
int btwake_fd, bt_fd;
|
||||
|
||||
/*
|
||||
This code has been put together by reverse-engineering BlueTool and bluetoothd on
|
||||
iOS. Some of the things that happen here are not completely understood but the goal
|
||||
was to just get it to work.
|
||||
*/
|
||||
int connect_bt_device() {
|
||||
int socket_fd = socket(32, 1, 2);
|
||||
int error = 0;
|
||||
int ret = 0;
|
||||
|
||||
struct sockaddr sock_addr;
|
||||
struct termios term;
|
||||
|
||||
if (socket_fd == 0) {
|
||||
printf("unable to get bluetooth socket\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctl_info_t *ctl_inf = malloc(sizeof(ctl_info_t));
|
||||
ctl_inf->ctl_id = 0;
|
||||
strcpy(ctl_inf->ctl_name, "com.apple.uart.bluetooth");
|
||||
if ((error = ioctl(socket_fd, CTLIOCGINFO, ctl_inf))) {
|
||||
printf("ioctl(CTLIOCGINFO) = %d - errno: %d\n", error, errno);
|
||||
printf("error: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
*(int *)&sock_addr.sa_len = 0x22020;
|
||||
*(int *)&sock_addr.sa_data[2] = ctl_inf->ctl_id;
|
||||
ret = connect(socket_fd, &sock_addr, 0x20);
|
||||
if (ret != 0) {
|
||||
printf("connect() = %d - errno: %d\n", ret, errno);
|
||||
printf("error: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Connected to bt device\n");
|
||||
|
||||
socklen_t len = 72;
|
||||
|
||||
ret = getsockopt(socket_fd, 2, TIOCGETA, &term, &len);
|
||||
if (ret != 0) {
|
||||
printf("getsockopt(TIOCGETA) = %d - errno: %d\n", ret, errno);
|
||||
printf("error: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
cfmakeraw(&term);
|
||||
ret = cfsetspeed(&term, 3000000);
|
||||
if (ret != 0) {
|
||||
printf("cfsetspeed() = %d - errno: %d\n", ret, errno);
|
||||
printf("error: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
term.c_iflag |= 4;
|
||||
term.c_cflag = 232192;
|
||||
ret = setsockopt(socket_fd, 2, TIOCSETA, &term, 0x48);
|
||||
if (ret != 0) {
|
||||
printf("setsockopt() = %d - errno: %d\n", ret, errno);
|
||||
printf("error: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
tcflush(socket_fd, 3);
|
||||
|
||||
free(ctl_inf);
|
||||
|
||||
return socket_fd;
|
||||
}
|
||||
|
||||
int create_server(int port) {
|
||||
int server_fd;
|
||||
struct sockaddr_in server;
|
||||
int on = 1;
|
||||
int addrlen;
|
||||
|
||||
server_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (server_fd < 0) {
|
||||
printf("Unable to create server socket\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
addrlen = sizeof(server);
|
||||
memset(&server, '\0', addrlen);
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_addr.s_addr = INADDR_ANY;
|
||||
server.sin_port = htons(port);
|
||||
|
||||
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &on, 4);
|
||||
if (bind(server_fd, (struct sockaddr *)&server, sizeof(server)) < 0) {
|
||||
printf("Error binding socket\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(server_fd, 5) < 0) {
|
||||
printf("Failed listening: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Listening on port %d\n", port);
|
||||
|
||||
return server_fd;
|
||||
}
|
||||
|
||||
int wait_for_connection(int server_fd) {
|
||||
int client_fd;
|
||||
socklen_t len;
|
||||
struct sockaddr_in client;
|
||||
|
||||
len = sizeof(struct sockaddr_in);
|
||||
client_fd = accept(server_fd, (struct sockaddr *)&client, (socklen_t *)&len);
|
||||
|
||||
if (client_fd < 0) {
|
||||
printf("Accepting connection failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return client_fd;
|
||||
}
|
||||
|
||||
size_t buffered_write(int fd, char *buf, int *len)
|
||||
{
|
||||
size_t x = write(fd, buf, *len);
|
||||
if (x < 0)
|
||||
return x;
|
||||
if (x == 0)
|
||||
return x;
|
||||
if (x != *len)
|
||||
memmove(buf, buf+x, (*len)-x);
|
||||
*len -= x;
|
||||
return x;
|
||||
}
|
||||
|
||||
void proxy_bt_socket(int client, int bt) {
|
||||
char *client_buf, *bt_buf;
|
||||
int nfds;
|
||||
fd_set R;
|
||||
int client_out = 0;
|
||||
int bt_out = 0;
|
||||
int x;
|
||||
size_t n;
|
||||
|
||||
client_buf = malloc(1024);
|
||||
bt_buf = malloc(1024);
|
||||
|
||||
nfds = client > bt ? client : bt;
|
||||
nfds++;
|
||||
|
||||
while(1) {
|
||||
struct timeval to;
|
||||
if (client_out) {
|
||||
buffered_write(bt, client_buf, &client_out);
|
||||
}
|
||||
if (bt_out) {
|
||||
buffered_write(client, bt_buf, &bt_out);
|
||||
}
|
||||
FD_ZERO(&R);
|
||||
if (client_out < 1024)
|
||||
FD_SET(client, &R);
|
||||
if (bt_out < 1024)
|
||||
FD_SET(bt, &R);
|
||||
|
||||
to.tv_sec = 0;
|
||||
to.tv_usec = 1000;
|
||||
x = select(nfds+1, &R, 0, 0, &to);
|
||||
if (x > 0) {
|
||||
if (FD_ISSET(client, &R)) {
|
||||
n = read(client, client_buf+client_out, 1024-client_out);
|
||||
if (n > 0) {
|
||||
client_out += n;
|
||||
} else {
|
||||
close(client);
|
||||
printf("Client read failed\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (FD_ISSET(bt, &R)) {
|
||||
n = read(bt, bt_buf+bt_out, 1024-bt_out);
|
||||
if (n > 0) {
|
||||
bt_out += n;
|
||||
} else {
|
||||
close(client);
|
||||
printf("BT read failed\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (x < 0 && errno != EINTR){
|
||||
printf("Select failed with %s\n", strerror(errno));
|
||||
close(client);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void __exit(int sig) {
|
||||
close(bt_fd);
|
||||
close(btwake_fd);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int server_fd, client_fd;
|
||||
int port;
|
||||
|
||||
if (argc != 2) {
|
||||
printf("Usage: %s <port_number>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
port = atoi(argv[1]);
|
||||
|
||||
// wake BT device
|
||||
btwake_fd = open("/dev/btwake", 0);
|
||||
|
||||
bt_fd = connect_bt_device();
|
||||
if (bt_fd < 0) {
|
||||
printf("Error connecting to bluetooth device\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
server_fd = create_server(port);
|
||||
if (server_fd < 0) {
|
||||
printf("Unable to create server\n");
|
||||
return -1;
|
||||
}
|
||||
printf("Created server\n");
|
||||
|
||||
signal(SIGINT, __exit);
|
||||
|
||||
while (1) {
|
||||
printf("Waiting for connection\n");
|
||||
client_fd = wait_for_connection(server_fd);
|
||||
if (client_fd < 0)
|
||||
continue;
|
||||
// currently only one connection is supported
|
||||
proxy_bt_socket(client_fd, bt_fd);
|
||||
close(client_fd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// internalblue-ios-proxy.h
|
||||
// internalblue-ios-proxy
|
||||
//
|
||||
// Created by ttdennis on 03.05.19.
|
||||
// Copyright © 2019 ttdennis. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef internalblue_ios_proxy_h
|
||||
#define internalblue_ios_proxy_h
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#endif /* internalblue_ios_proxy_h */
|
||||
Executable
BIN
Binary file not shown.
Reference in New Issue
Block a user