26 Commits

Author SHA1 Message Date
Michael ec9240e620 First implementation of PDR-based blacklisting 2019-08-14 09:23:04 +01:00
Michael e2fb710f51 Merge branch 'blacklisting' of https://dev.seemoo.tu-darmstadt.de/bcm/internalblue into blacklisting 2019-08-13 18:19:59 +01:00
Michael c84a0cd123 Add file logging for measuring baseline PDR 2019-08-13 18:14:21 +01:00
Jiska Classen 31f6a8d58a rpi3+ blacklisting (todo: test) 2019-07-17 21:55:44 +02:00
Jiska Classen 7bc7a956ea logical color error 2019-07-12 15:20:17 +02:00
Jiska Classen cf51abc428 red/green fix 2019-07-12 15:15:09 +02:00
Michael 1bf8c0c132 checks for channel map blacklisting / length in rpi3 2019-07-12 13:28:52 +01:00
Jiska Classen 2d3ed7f734 raspi len check 2019-07-12 13:58:54 +02:00
Jiska Classen ac1df0b260 some colorful drawings for the blacklisting 2019-07-12 13:40:51 +02:00
Jiska Classen 053ad32297 documentation on how blacklisting debugging works 2019-07-10 17:51:40 +02:00
Jiska 8cb4109e81 raspi3 output: rssi, event counter, transmission fails, current channel. channel map via btmon. 2019-07-10 16:40:24 +01:00
Jiska Classen 8e0f099a83 rpi3 fw 2019-07-10 16:41:47 +02:00
Jiska Classen c842e4ec7d basic blacklisting debug output 2019-07-10 15:35:26 +02:00
Jiska Classen 6ec8badbe5 Error messages for socket issues, REcon 2019-07-05 13:26:57 +02:00
Jiska Classen 8d3e740bad Merge branch 'master' of https://dev.seemoo.tu-darmstadt.de/bcm/internalblue 2019-07-04 16:23:30 +02:00
Jiska Classen b2b3a623dc fw version info 2019-07-04 16:23:22 +02:00
Dennis Heinze 335bca36b9 Add compiled proxy binary (ugh) 2019-06-13 22:29:01 +02:00
Dennis Heinze 95fd621eb7 Some more ios readme 2019-06-13 22:24:36 +02:00
Dennis Heinze 246ca035eb Adapt iPhone7 fw information 2019-06-13 22:24:36 +02:00
Dennis Heinze 1a2e4e90ca Add iOS proxy source code 2019-06-13 22:24:08 +02:00
Dennis Heinze 3b1222e327 Initial support for iOS 2019-06-07 00:52:32 +02:00
Dennis Heinze 7d4dd6a7a7 Add iPhone 7 firmware information 2019-06-07 00:30:54 +02:00
Jiska Classen 6aeeba6545 Merge branch 'master' of https://dev.seemoo.tu-darmstadt.de/bcm/internalblue 2019-06-06 15:46:06 +02:00
Jiska Classen cdbb9f4bae cyw20819 2019-06-06 15:45:35 +02:00
Jan Ruge 0c3430dfaf fw_0x420e.py fixed bloc_hdr 2019-06-04 18:18:43 +02:00
Jiska Classen d233b55042 cyw20719 2019-06-04 17:29:27 +02:00
24 changed files with 1510 additions and 43 deletions
+3
View File
@@ -14,3 +14,6 @@ _internalblue.hist
_internalblue.log
btsnoop.log
# xcode
xcuserdata
*.xcworkspace
+18 -2
View File
@@ -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
View File
@@ -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.
+47
View File
@@ -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'.")
+90
View File
@@ -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'.")
+90
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
----------------------
+75
View File
@@ -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
+46
View File
@@ -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 ...
+3 -3
View File
@@ -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)
+53
View File
@@ -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 ...
+48
View File
@@ -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)
]
+7
View File
@@ -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
+8 -3
View File
@@ -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:
+143
View File
@@ -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
+20
View File
@@ -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.
+8
View File
@@ -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 */;
}
@@ -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 */
BIN
View File
Binary file not shown.