Compare commits
48 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 065cd011be | |||
| aa127b7148 | |||
| 5792bca5b8 | |||
| 4df388c37a | |||
| 733cd9ca56 | |||
| a8a6623658 | |||
| b599213104 | |||
| df5636b9b8 | |||
| 25fa80a416 | |||
| fd7310330b | |||
| 65a8ce61e6 | |||
| 67ec7f5347 | |||
| 8dce7f86a4 | |||
| 692134f748 | |||
| c2166ce384 | |||
| a7266c819d | |||
| f6704f904e | |||
| 9ed9f6e1cc | |||
| efe3614ea5 | |||
| e6b58865dc | |||
| 8d14ab9485 | |||
| f4f51a7952 | |||
| b409207a3e | |||
| fa18727e69 | |||
| 6255023db8 | |||
| 796eb4cc03 | |||
| 6677b86e94 | |||
| ca070290c5 | |||
| bc3d52f00e | |||
| d737068304 | |||
| e8f6e94e1b | |||
| 6e91f9c718 | |||
| 361892bc06 | |||
| 2ce2224421 | |||
| 104a35a79a | |||
| e6b99906c9 | |||
| d3059b01d8 | |||
| a7066170fc | |||
| 748c713f67 | |||
| 0864e96569 | |||
| c6e39cb18f | |||
| 07c5c4c336 | |||
| 01589f8eee | |||
| d9de8f0d83 | |||
| 9b8d5b0740 | |||
| e53edb1ec9 | |||
| b72e12b5a6 | |||
| d7b3b8e7a1 |
@@ -17,9 +17,11 @@ btsnoop.log
|
||||
# xcode
|
||||
xcuserdata
|
||||
*.xcworkspace
|
||||
macos-framework/IOBluetoothExtended.framework/
|
||||
|
||||
# venv
|
||||
venv
|
||||
venv3
|
||||
|
||||
# pycharm
|
||||
*.idea
|
||||
|
||||
@@ -8,6 +8,14 @@ therefore implement monitoring and injection tools for the lower layers of
|
||||
the Bluetooth protocol stack.
|
||||
|
||||
|
||||
Recent Changes
|
||||
--------------
|
||||
* We upgraded from Python 2 to Python 3. If you wrote your own scripts, this might break them. In this case, use
|
||||
the [python2](https://github.com/seemoo-lab/internalblue/releases/tag/python2) release.
|
||||
|
||||
* We reworked the *iOS* implementation.
|
||||
|
||||
|
||||
Publications and Background
|
||||
---------------------------
|
||||
|
||||
@@ -64,6 +72,9 @@ was also recorded and gives a more high level overview.
|
||||
|
||||
We did some work on improving blacklisting performance of BLE data connections. Currently in a separate *blacklisting* branch.
|
||||
|
||||
* **CiderSecCon Talk** (03/2020)
|
||||
|
||||
TROOPERS was canceled, but we did a stream of a talk that was recorded on [YouTube](https://www.youtube.com/watch?v=Nx2ZDLaJ1-0&t=4920).
|
||||
|
||||
|
||||
|
||||
@@ -98,6 +109,7 @@ On selected Broadcom Bluetooth chips:
|
||||
* NiNo example
|
||||
* MAC address filter example
|
||||
* KNOB attack test for various devices, including Raspberry Pi 3+/4
|
||||
* BLE receptoin statistics
|
||||
|
||||
A comprehensive list of chips and which devices have them can be found in the [firmware](internalblue/fw/README.md) module documentation.
|
||||
|
||||
@@ -110,19 +122,20 @@ Requirements
|
||||
Android:
|
||||
* Ideally recompiled `bluetooth.default.so`, but also works on any rooted smartphone, see [Android instructions](android_bluetooth_stack/README.md)
|
||||
* Android device connected via ADB
|
||||
* Best support is currently given for Nexus 5 / BCM4339 and Evaluation Boards
|
||||
* Best support is currently given for Nexus 5 / BCM4339
|
||||
* Optional: Patch for Android driver to support Broadcom H4 forwarding
|
||||
* Optional, if H4: Wireshark [Broadcom H4 Dissector Plugin](https://github.com/seemoo-lab/h4bcm_wireshark_dissector)
|
||||
|
||||
Linux:
|
||||
* BlueZ, instructions see [here](linux_bluez/README.md)
|
||||
* Best support for Raspberry Pi 3/3+/4
|
||||
* Best support for Raspberry Pi 3/3+/4 and Cypress evaluation boards
|
||||
* For most commands: Privileged access
|
||||
|
||||
iOS:
|
||||
* A jailbroken iOS device (tested on iOS 12.1.2/12.4 with iPhone 6, SE, 7, 8, X)
|
||||
* The included `ios-proxy` (instructions in [here](ios-proxy/README.md))
|
||||
* Optional: a Mac with `xcode` to compile the proxy yourself
|
||||
* A jailbroken iOS device (tested on iOS 12 and 13 with iPhone 6, SE, 7, 8, X , does not work on iPhones newer than XR, these devices have a Bluetooth chip connected via PCIe)
|
||||
* `usbmuxd`, which is pre installed on macOS but is available on most Linux distributions as well. Alternatively it can be obtained from [here](https://github.com/libimobiledevice/usbmuxd).
|
||||
* The [``internalblued`` daemon](ios-internalblued/README.md) installed on the iOS device
|
||||
|
||||
* Optional, no jailbreak required: install [iOS Bluetooth Debug Profile](https://developer.apple.com/bug-reporting/profiles-and-logs/) to obtain
|
||||
HCI and diagnostic messages, either via diagnostic report feature (all iOS versions) or live with PacketLogger (since iOS 13)
|
||||
|
||||
@@ -151,7 +164,7 @@ with all dependencies by using pip:
|
||||
|
||||
git clone https://github.com/seemoo-lab/internalblue.git
|
||||
cd internalblue
|
||||
pip2 install .
|
||||
pip install .
|
||||
|
||||
It will install the following dependencies:
|
||||
* pwntools
|
||||
@@ -171,7 +184,7 @@ All steps on a plain Ubuntu 18.04:
|
||||
sudo apt install git python-setuptools binutils-arm-linux-gnueabi adb pip python-dev gcc
|
||||
git clone https://github.com/seemoo-lab/internalblue
|
||||
cd internalblue
|
||||
sudo pip2 install .
|
||||
sudo pip install .
|
||||
cd ..
|
||||
|
||||
sudo apt-get install wireshark-dev wireshark cmake
|
||||
@@ -195,7 +208,7 @@ Usage
|
||||
|
||||
The CLI (Command Line Interface) of InternalBlue can be started by running:
|
||||
|
||||
python2 -m internalblue.cli
|
||||
python -m internalblue.cli
|
||||
|
||||
The setup.py installation will also place a shortcut to the CLI into the $PATH
|
||||
so that it can be started from a command line using:
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
# Get receive statistics on a Nexus 5 for BLE connection events
|
||||
|
||||
from builtins import range
|
||||
from pwn import *
|
||||
from internalblue.adbcore import ADBCore
|
||||
import internalblue.hci as hci
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
# Get receive statistics on a Samsung Galaxy S8 for BLE connection events
|
||||
|
||||
from builtins import range
|
||||
from pwn import *
|
||||
from internalblue.adbcore import ADBCore
|
||||
import internalblue.hci as hci
|
||||
|
||||
+32
-13
@@ -1,25 +1,44 @@
|
||||
from future import standard_library
|
||||
|
||||
standard_library.install_aliases()
|
||||
|
||||
import datetime
|
||||
|
||||
from queue import Queue
|
||||
from typing import (
|
||||
List,
|
||||
Optional,
|
||||
Any,
|
||||
TYPE_CHECKING,
|
||||
Tuple,
|
||||
Union,
|
||||
NewType,
|
||||
Callable,
|
||||
Dict,
|
||||
)
|
||||
|
||||
# Address = NewType("Address", int)
|
||||
Address = int
|
||||
ConnectionNumber = NewType("ConnectionNumber", int)
|
||||
ConnectionIndex = NewType("ConnectionIndex", int)
|
||||
|
||||
BluetoothAddress = NewType("BluetoothAddress", bytes)
|
||||
ConnectionDict = NewType("ConnectionDict", Dict[str, Any])
|
||||
HeapInformation = NewType("HeapInformation", Dict[str, Any])
|
||||
QueueInformation = NewType("QueueInformation", Dict[str, Any])
|
||||
|
||||
try:
|
||||
from Queue import Queue
|
||||
from typing import List, Optional, Any, TYPE_CHECKING, Tuple, Union, NewType, Callable, Dict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import datetime
|
||||
from internalblue.hci import HCI
|
||||
from internalblue.core import InternalBlue
|
||||
Address = NewType("Address", int)
|
||||
|
||||
Record = Tuple[HCI, int, int, int, Any, datetime.datetime]
|
||||
FilterFunction = Callable[[Record], bool]
|
||||
ConnectionNumber = NewType("ConnectionNumber", int)
|
||||
ConnectionIndex = NewType("ConnectionIndex", int)
|
||||
|
||||
BluetoothAddress = NewType("BluetoothAddress", bytes)
|
||||
ConnectionDict = NewType("ConnectionDict", Dict[str,Any])
|
||||
HeapInformation = NewType("HeapInformation", Dict[str, Any])
|
||||
QueueInformation = NewType('QueueInformation', Dict[str, Any])
|
||||
Opcode = NewType('Opcode', int)
|
||||
HCI_CMD = NewType('HCI_CMD', int)
|
||||
Task = Tuple[HCI_CMD, bytes, Queue.Queue, Callable[[Record], bool]]
|
||||
Opcode = NewType("Opcode", int)
|
||||
HCI_CMD = NewType("HCI_CMD", int)
|
||||
Task = Tuple[HCI_CMD, bytes, Queue, Callable[[Record], bool]]
|
||||
|
||||
Device = NewType("Device", Dict[str, Any])
|
||||
"""{"dev_id": dev_id,
|
||||
|
||||
+148
-67
@@ -1,22 +1,48 @@
|
||||
#!/usr/bin/env python2
|
||||
import struct
|
||||
from time import sleep
|
||||
from typing import Optional
|
||||
|
||||
from future import standard_library
|
||||
|
||||
from pwnlib import adb
|
||||
from pwnlib.exception import PwnlibException
|
||||
|
||||
standard_library.install_aliases()
|
||||
from builtins import str
|
||||
import datetime
|
||||
import socket
|
||||
import Queue
|
||||
import queue as queue2k
|
||||
import random
|
||||
from internalblue import hci
|
||||
from internalblue.utils import bytes_to_hex
|
||||
|
||||
from pwn import *
|
||||
|
||||
from internalblue.utils.pwnlib_wrapper import log, context, u32
|
||||
from .core import InternalBlue
|
||||
|
||||
|
||||
class ADBCore(InternalBlue):
|
||||
|
||||
def __init__(self, queue_size=1000, btsnooplog_filename='btsnoop.log', log_level='info', fix_binutils='True', serial=False, data_directory=".", replay=False):
|
||||
super(ADBCore, self).__init__(queue_size, btsnooplog_filename, log_level, fix_binutils, data_directory, replay)
|
||||
self.hciport = None # hciport is the port number of the forwarded HCI snoop port (8872). The inject port is at hciport+1
|
||||
self.serial = serial # use serial su busybox scripting and do not try bluetooth.default.so
|
||||
def __init__(
|
||||
self,
|
||||
queue_size=1000,
|
||||
btsnooplog_filename="btsnoop.log",
|
||||
log_level="info",
|
||||
fix_binutils="True",
|
||||
serial=False,
|
||||
data_directory=".",
|
||||
replay=False,
|
||||
):
|
||||
super(ADBCore, self).__init__(
|
||||
queue_size,
|
||||
btsnooplog_filename,
|
||||
log_level,
|
||||
fix_binutils,
|
||||
data_directory,
|
||||
replay,
|
||||
)
|
||||
self.hciport: Optional[int] = None # hciport is the port number of the forwarded HCI snoop port (8872). The inject port is at hciport+1
|
||||
self.serial = serial # use serial su busybox scripting and do not try bluetooth.default.so
|
||||
self.doublecheck = False
|
||||
|
||||
def device_list(self):
|
||||
@@ -32,16 +58,18 @@ class ADBCore(InternalBlue):
|
||||
return []
|
||||
|
||||
if self.replay:
|
||||
return [(self, "adb_replay", 'adb: ReplayDevice' )]
|
||||
return [(self, "adb_replay", "adb: ReplayDevice")]
|
||||
# Check for connected adb devices
|
||||
try:
|
||||
adb_devices = adb.devices()
|
||||
except ValueError:
|
||||
log.info("Could not find devices with pwnlib. If you see devices with `adb devices`, try to remove the lines 'for field in fields[2:]:... = v' in `pwnlib/adb/adb.py`.")
|
||||
log.info(
|
||||
"Could not find devices with pwnlib. If you see devices with `adb devices`, try to remove the lines 'for field in fields[2:]:... = v' in `pwnlib/adb/adb.py`."
|
||||
)
|
||||
adb_devices = 0
|
||||
except:
|
||||
adb_devices = 0
|
||||
|
||||
|
||||
if adb_devices == 0 or len(adb_devices) == 0:
|
||||
log.info("No adb devices found.")
|
||||
return []
|
||||
@@ -55,7 +83,7 @@ class ADBCore(InternalBlue):
|
||||
# Third index is the label which is shown in options(...)
|
||||
device_list = []
|
||||
for d in adb_devices:
|
||||
device_list.append((self, d.serial, 'adb: %s (%s)' % (d.serial, d.model)))
|
||||
device_list.append((self, d.serial, "adb: %s (%s)" % (d.serial, d.model)))
|
||||
|
||||
return device_list
|
||||
|
||||
@@ -73,7 +101,9 @@ class ADBCore(InternalBlue):
|
||||
if not self.serial:
|
||||
if not self._setupSockets():
|
||||
log.info("Could not connect using Bluetooth module.")
|
||||
log.info("Trying to set up connection for rooted smartphone with busybox installed.")
|
||||
log.info(
|
||||
"Trying to set up connection for rooted smartphone with busybox installed."
|
||||
)
|
||||
else:
|
||||
return True # successfully finished setup with bluetooth.default.so
|
||||
|
||||
@@ -84,7 +114,9 @@ class ADBCore(InternalBlue):
|
||||
# try again
|
||||
if not self._setupSockets():
|
||||
log.critical("No connection to target device.")
|
||||
log.info("Check if:\n -> Bluetooth is active\n -> Bluetooth Stack has Debug Enabled\n -> BT HCI snoop log is activated\n -> USB debugging is authorized\n")
|
||||
log.info(
|
||||
"Check if:\n -> Bluetooth is active\n -> Bluetooth Stack has Debug Enabled\n -> BT HCI snoop log is activated\n -> USB debugging is authorized\n"
|
||||
)
|
||||
return False
|
||||
|
||||
return True
|
||||
@@ -95,13 +127,17 @@ class ADBCore(InternalBlue):
|
||||
"""
|
||||
|
||||
data = self.s_snoop.recv(16)
|
||||
if(len(data) < 16):
|
||||
if len(data) < 16:
|
||||
return None
|
||||
if(self.write_btsnooplog) and self.btsnooplog_file.tell() == 0:
|
||||
if (self.write_btsnooplog) and self.btsnooplog_file.tell() == 0:
|
||||
self.btsnooplog_file.write(data)
|
||||
self.btsnooplog_file.flush()
|
||||
|
||||
btsnoop_hdr = (data[:8], u32(data[8:12],endian="big"),u32(data[12:16],endian="big"))
|
||||
btsnoop_hdr = (
|
||||
data[:8],
|
||||
u32(data[8:12], endian="big"),
|
||||
u32(data[12:16], endian="big"),
|
||||
)
|
||||
log.debug("BT Snoop Header: %s, version: %d, data link type: %d" % btsnoop_hdr)
|
||||
return btsnoop_hdr
|
||||
|
||||
@@ -117,7 +153,9 @@ class ADBCore(InternalBlue):
|
||||
this field as 0x00E03AB44A676000.
|
||||
"""
|
||||
time_betw_0_and_2000_ad = int("0x00E03AB44A676000", 16)
|
||||
time_since_2000_epoch = datetime.timedelta(microseconds=time) - datetime.timedelta(microseconds=time_betw_0_and_2000_ad)
|
||||
time_since_2000_epoch = datetime.timedelta(
|
||||
microseconds=time
|
||||
) - datetime.timedelta(microseconds=time_betw_0_and_2000_ad)
|
||||
return datetime.datetime(2000, 1, 1) + time_since_2000_epoch
|
||||
|
||||
def _recvThreadFunc(self):
|
||||
@@ -137,18 +175,23 @@ class ADBCore(InternalBlue):
|
||||
context.log_level = self.log_level
|
||||
|
||||
# Read the record header
|
||||
record_hdr = b''
|
||||
while(not self.exit_requested and len(record_hdr) < 24):
|
||||
record_hdr = b""
|
||||
while not self.exit_requested and len(record_hdr) < 24:
|
||||
try:
|
||||
recv_data = self.s_snoop.recv(24 - len(record_hdr))
|
||||
log.debug("recvThreadFunc: received bt_snoop data " + recv_data.encode('hex'))
|
||||
log.debug(
|
||||
"recvThreadFunc: received bt_snoop data "
|
||||
+ bytes_to_hex(recv_data)
|
||||
)
|
||||
if len(recv_data) == 0:
|
||||
log.info("recvThreadFunc: bt_snoop socket was closed by remote site. stopping recv thread...")
|
||||
log.info(
|
||||
"recvThreadFunc: bt_snoop socket was closed by remote site. stopping recv thread..."
|
||||
)
|
||||
self.exit_requested = True
|
||||
break
|
||||
record_hdr += recv_data
|
||||
except socket.timeout:
|
||||
pass # this is ok. just try again without error
|
||||
pass # this is ok. just try again without error
|
||||
|
||||
if not record_hdr or len(record_hdr) != 24:
|
||||
if not self.exit_requested:
|
||||
@@ -160,27 +203,31 @@ class ADBCore(InternalBlue):
|
||||
self.btsnooplog_file.write(record_hdr)
|
||||
self.btsnooplog_file.flush()
|
||||
|
||||
orig_len, inc_len, flags, drops, time64 = struct.unpack( ">IIIIq", record_hdr)
|
||||
orig_len, inc_len, flags, drops, time64 = struct.unpack(
|
||||
">IIIIq", record_hdr
|
||||
)
|
||||
|
||||
# Read the record data
|
||||
record_data = b''
|
||||
while(not self.exit_requested and len(record_data) < inc_len):
|
||||
record_data = bytearray()
|
||||
while not self.exit_requested and len(record_data) < inc_len:
|
||||
try:
|
||||
recv_data = self.s_snoop.recv(inc_len - len(record_data))
|
||||
if len(recv_data) == 0:
|
||||
log.info("recvThreadFunc: bt_snoop socket was closed by remote site. stopping..")
|
||||
log.info(
|
||||
"recvThreadFunc: bt_snoop socket was closed by remote site. stopping.."
|
||||
)
|
||||
self.exit_requested = True
|
||||
break
|
||||
record_data += recv_data
|
||||
record_data += bytearray(recv_data)
|
||||
except socket.timeout:
|
||||
pass # this is ok. just try again without error
|
||||
pass # this is ok. just try again without error
|
||||
|
||||
if not record_data or len(record_data) != inc_len:
|
||||
if not self.exit_requested:
|
||||
log.warn("recvThreadFunc: Cannot recv data. stopping.")
|
||||
self.exit_requested = True
|
||||
break
|
||||
|
||||
|
||||
if self.write_btsnooplog:
|
||||
self.btsnooplog_file.write(record_data)
|
||||
self.btsnooplog_file.flush()
|
||||
@@ -191,9 +238,18 @@ class ADBCore(InternalBlue):
|
||||
parsed_time = None
|
||||
|
||||
# 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), orig_len, inc_len, flags, drops, parsed_time)
|
||||
record = (
|
||||
hci.parse_hci_packet(record_data),
|
||||
orig_len,
|
||||
inc_len,
|
||||
flags,
|
||||
drops,
|
||||
parsed_time,
|
||||
)
|
||||
|
||||
log.debug("_recvThreadFunc Recv: [" + str(parsed_time) + "] " + str(record[0]))
|
||||
log.debug(
|
||||
"_recvThreadFunc Recv: [" + str(parsed_time) + "] " + str(record[0])
|
||||
)
|
||||
|
||||
# Put the record into all queues of registeredHciRecvQueues if their
|
||||
# filter function matches.
|
||||
@@ -201,8 +257,10 @@ class ADBCore(InternalBlue):
|
||||
if filter_function == None or filter_function(record):
|
||||
try:
|
||||
queue.put(record, block=False)
|
||||
except Queue.Full:
|
||||
log.warn("recvThreadFunc: A recv queue is full. dropping packets..")
|
||||
except queue2k.Full:
|
||||
log.warn(
|
||||
"recvThreadFunc: A recv queue is full. dropping packets.."
|
||||
)
|
||||
|
||||
# Call all callback functions inside registeredHciCallbacks and pass the
|
||||
# record as argument.
|
||||
@@ -211,9 +269,9 @@ class ADBCore(InternalBlue):
|
||||
|
||||
# Check if the stackDumpReceiver has noticed that the chip crashed.
|
||||
# if self.stackDumpReceiver and self.stackDumpReceiver.stack_dump_has_happend:
|
||||
# A stack dump has happend!
|
||||
# log.warn("recvThreadFunc: The controller sent a stack dump.")
|
||||
# self.exit_requested = True
|
||||
# A stack dump has happend!
|
||||
# log.warn("recvThreadFunc: The controller sent a stack dump.")
|
||||
# self.exit_requested = True
|
||||
|
||||
log.debug("Receive Thread terminated.")
|
||||
|
||||
@@ -229,12 +287,17 @@ class ADBCore(InternalBlue):
|
||||
# (with multiple attached Android devices) we must not hard code the
|
||||
# forwarded port numbers. Therefore we choose the port numbers
|
||||
# randomly and hope that they are not already in use.
|
||||
self.hciport = random.randint(60000, 65534) # minus 1, as we are using hciport + 1
|
||||
log.debug("_setupSockets: Selected random ports snoop=%d and inject=%d" % (self.hciport, self.hciport + 1))
|
||||
self.hciport = random.randint(
|
||||
60000, 65534
|
||||
) # minus 1, as we are using hciport + 1
|
||||
log.debug(
|
||||
"_setupSockets: Selected random ports snoop=%d and inject=%d"
|
||||
% (self.hciport, self.hciport + 1)
|
||||
)
|
||||
|
||||
# Forward ports 8872 and 8873. Ignore log.info() outputs by the adb function.
|
||||
saved_loglevel = context.log_level
|
||||
context.log_level = 'warn'
|
||||
context.log_level = "warn"
|
||||
try:
|
||||
adb.adb(["forward", "tcp:%d" % (self.hciport), "tcp:8872"])
|
||||
adb.adb(["forward", "tcp:%d" % (self.hciport + 1), "tcp:8873"])
|
||||
@@ -247,7 +310,7 @@ class ADBCore(InternalBlue):
|
||||
# Connect to hci injection port
|
||||
self.s_inject = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
self.s_inject.connect(('127.0.0.1', self.hciport + 1))
|
||||
self.s_inject.connect(("127.0.0.1", self.hciport + 1))
|
||||
self.s_inject.settimeout(0.5)
|
||||
except socket.error:
|
||||
log.warn("Could not connect to adb. Is your device authorized?")
|
||||
@@ -255,16 +318,16 @@ class ADBCore(InternalBlue):
|
||||
|
||||
# Connect to hci snoop log port
|
||||
self.s_snoop = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.s_snoop.connect(('127.0.0.1', self.hciport))
|
||||
self.s_snoop.connect(("127.0.0.1", self.hciport))
|
||||
self.s_snoop.settimeout(0.5)
|
||||
|
||||
# Read btsnoop header
|
||||
if (self._read_btsnoop_hdr() == None):
|
||||
if self._read_btsnoop_hdr() == None:
|
||||
log.warn("Could not read btsnoop header")
|
||||
self.s_inject.close()
|
||||
self.s_snoop.close()
|
||||
self.s_inject = self.s_snoop = None
|
||||
context.log_level = 'warn'
|
||||
context.log_level = "warn"
|
||||
adb.adb(["forward", "--remove", "tcp:%d" % (self.hciport)])
|
||||
adb.adb(["forward", "--remove", "tcp:%d" % (self.hciport + 1)])
|
||||
context.log_level = saved_loglevel
|
||||
@@ -276,23 +339,25 @@ class ADBCore(InternalBlue):
|
||||
Close s_snoop and s_inject sockets. Remove port forwarding with adb.
|
||||
"""
|
||||
|
||||
if (self.s_inject != None):
|
||||
if self.s_inject != None:
|
||||
self.s_inject.close()
|
||||
self.s_inject = None
|
||||
if (self.s_snoop != None):
|
||||
if self.s_snoop != None:
|
||||
self.s_snoop.close()
|
||||
self.s_snoop = None
|
||||
|
||||
saved_loglevel = context.log_level
|
||||
context.log_level = 'warn'
|
||||
try:
|
||||
adb.adb(["forward", "--remove", "tcp:%d" % (self.hciport)])
|
||||
adb.adb(["forward", "--remove", "tcp:%d" % (self.hciport + 1)])
|
||||
except PwnlibException as e:
|
||||
log.warn("Removing adb port forwarding failed: " + str(e))
|
||||
return False
|
||||
finally:
|
||||
context.log_level = saved_loglevel
|
||||
context.log_level = "warn"
|
||||
if self.hciport is not None:
|
||||
hciport = self.hciport
|
||||
try:
|
||||
adb.adb(["forward", "--remove", f"tcp:{hciport}"])
|
||||
adb.adb(["forward", "--remove", f"tcp:{hciport + 1}"])
|
||||
except PwnlibException as e:
|
||||
log.warn("Removing adb port forwarding failed: " + str(e))
|
||||
return False
|
||||
finally:
|
||||
context.log_level = saved_loglevel
|
||||
|
||||
def _setupSerialSu(self):
|
||||
"""
|
||||
@@ -316,36 +381,54 @@ class ADBCore(InternalBlue):
|
||||
self.serial = True
|
||||
|
||||
saved_loglevel = context.log_level
|
||||
context.log_level = 'warn'
|
||||
context.log_level = "warn"
|
||||
|
||||
try:
|
||||
# check dependencies
|
||||
if adb.which('su') is None:
|
||||
if adb.which("su") is None:
|
||||
log.critical("su not found, rooted smartphone required!")
|
||||
return False
|
||||
|
||||
if adb.process(['su', '-c', 'which', 'nc']).recvall() == '':
|
||||
|
||||
if adb.process(["su", "-c", "which", "nc"]).recvall() == "":
|
||||
log.critical("nc not found, install busybox!")
|
||||
return False
|
||||
|
||||
# automatically detect the proper serial device with lsof
|
||||
logfile = adb.process(["su", "-c", "lsof | grep btsnoop_hci.log | awk '{print $NF}'"]).recvall().strip()
|
||||
logfile = (
|
||||
adb.process(
|
||||
["su", "-c", "lsof | grep btsnoop_hci.log | awk '{print $NF}'"]
|
||||
)
|
||||
.recvall()
|
||||
.strip()
|
||||
.decode("utf-8")
|
||||
)
|
||||
log.info("Android btsnoop logfile %s...", logfile)
|
||||
interface = adb.process(["su", "-c", "lsof | grep bluetooth | grep tty | awk '{print $NF}'"]).recvall().strip()
|
||||
interface = (
|
||||
adb.process(
|
||||
["su", "-c", "lsof | grep bluetooth | grep tty | awk '{print $NF}'"]
|
||||
)
|
||||
.recvall()
|
||||
.strip()
|
||||
.decode("utf-8")
|
||||
)
|
||||
log.info("Android Bluetooth interface %s...", interface)
|
||||
|
||||
if logfile == '':
|
||||
log.critical("Could not find Bluetooth logfile. Enable Bluetooth snoop logging.")
|
||||
if logfile == "":
|
||||
log.critical(
|
||||
"Could not find Bluetooth logfile. Enable Bluetooth snoop logging."
|
||||
)
|
||||
return False
|
||||
|
||||
if interface == '':
|
||||
if interface == "":
|
||||
log.critical("Could not find Bluetooth interface. Enable Bluetooth.")
|
||||
return False
|
||||
|
||||
# spawn processes
|
||||
adb.process(["su", "-c", 'tail -f -n +0 %s | nc -l -p 8872' % logfile])
|
||||
adb.process(["su", "-c", "tail -f -n +0 %s | nc -l -p 8872" % logfile])
|
||||
adb.process(["su", "-c", "nc -l -p 8873 >/sdcard/internalblue_input.bin"])
|
||||
adb.process(["su", "-c", "tail -f /sdcard/internalblue_input.bin >>%s" % interface])
|
||||
adb.process(
|
||||
["su", "-c", "tail -f /sdcard/internalblue_input.bin >>%s" % interface]
|
||||
)
|
||||
sleep(2)
|
||||
|
||||
except PwnlibException as e:
|
||||
@@ -355,5 +438,3 @@ class ADBCore(InternalBlue):
|
||||
context.log_level = saved_loglevel
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
||||
+137
-79
@@ -28,7 +28,12 @@
|
||||
# Software.
|
||||
|
||||
|
||||
from pwn import *
|
||||
from __future__ import print_function
|
||||
|
||||
import socket
|
||||
import sys
|
||||
from builtins import str
|
||||
import internalblue.utils.pwnlib_wrapper as pwnlib
|
||||
import os
|
||||
import traceback
|
||||
import argparse
|
||||
@@ -50,81 +55,116 @@ except:
|
||||
|
||||
HISTFILE = "_internalblue.hist"
|
||||
|
||||
|
||||
def print_banner():
|
||||
banner = """\
|
||||
banner = r"""
|
||||
____ __ _____ __
|
||||
/ _/__ / /____ _______ ___ _/ / _ )/ /_ _____
|
||||
_/ // _ \/ __/ -_) __/ _ \/ _ `/ / _ / / // / -_)
|
||||
/___/_//_/\__/\__/_/ /_//_/\_,_/_/____/_/\_,_/\__/
|
||||
|
||||
|
||||
type <help> for usage information!\n\n"""
|
||||
type <help> for usage information!
|
||||
"""
|
||||
for line in banner:
|
||||
term.output(text.blue(line))
|
||||
pwnlib.term.output(pwnlib.text.blue(line))
|
||||
|
||||
|
||||
def commandLoop(internalblue, init_commands=None):
|
||||
cmdstack = init_commands.split(';')[::-1] if init_commands else None
|
||||
cmdstack = init_commands.split(";")[::-1] if init_commands else None
|
||||
while internalblue.running and not internalblue.exit_requested:
|
||||
cmd_instance = None
|
||||
try:
|
||||
if cmdstack:
|
||||
cmdline = cmdstack.pop().strip()
|
||||
else:
|
||||
cmdline = term.readline.readline(prompt='> ').strip()
|
||||
cmdword = cmdline.split(' ')[0].split('=')[0]
|
||||
if(cmdword == ''):
|
||||
cmdline = (
|
||||
pwnlib.term.readline.readline(prompt="> ").strip().decode("utf-8")
|
||||
)
|
||||
cmdword = cmdline.split(" ")[0].split("=")[0]
|
||||
if cmdword == "":
|
||||
continue
|
||||
log.debug("Command Line: [[" + cmdword + "]] " + cmdline)
|
||||
pwnlib.log.debug("Command Line: [[" + cmdword + "]] " + cmdline)
|
||||
matching_cmd = cmds.findCmd(cmdword)
|
||||
if matching_cmd == None:
|
||||
log.warn("Command unknown: " + cmdline)
|
||||
pwnlib.log.warn("Command unknown: " + cmdline)
|
||||
continue
|
||||
cmd_instance = matching_cmd(cmdline, internalblue)
|
||||
|
||||
if(not cmd_instance.work()):
|
||||
log.warn("Command failed: " + str(cmd_instance))
|
||||
if not cmd_instance.work():
|
||||
pwnlib.log.warn("Command failed: " + str(cmd_instance))
|
||||
except ValueError as e:
|
||||
log.warn("commandLoop: ValueError: " + str(e))
|
||||
continue
|
||||
pwnlib.log.warn("commandLoop: ValueError: " + str(e))
|
||||
raise
|
||||
except KeyboardInterrupt:
|
||||
if(cmd_instance != None):
|
||||
if cmd_instance != None:
|
||||
cmd_instance.abort_cmd()
|
||||
else:
|
||||
log.info("Got Ctrl-C; exiting...")
|
||||
pwnlib.log.info("Got Ctrl-C; exiting...")
|
||||
internalblue.exit_requested = True
|
||||
break
|
||||
except AssertionError as e:
|
||||
raise
|
||||
except socket.error as e:
|
||||
if e.args == (1, "Operation not permitted"):
|
||||
log.critical("Received an 'Operation not permitted' socket.error, you might need root for the command '{}'".format(cmdline))
|
||||
log.critical(traceback.format_exc())
|
||||
pwnlib.log.critical(
|
||||
"Received an 'Operation not permitted' socket.error, you might need root for the command '{}'".format(
|
||||
cmdline
|
||||
)
|
||||
)
|
||||
pwnlib.log.critical(traceback.format_exc())
|
||||
except Exception as e:
|
||||
internalblue.exit_requested = True # Make sure all threads terminate
|
||||
log.critical("Uncaught exception (%s). Abort." % str(e))
|
||||
internalblue.exit_requested = True # Make sure all threads terminate
|
||||
pwnlib.log.critical("Uncaught exception (%s). Abort." % str(e))
|
||||
print(traceback.format_exc())
|
||||
break
|
||||
raise
|
||||
cmd_instance = None
|
||||
|
||||
|
||||
def _parse_argv(argv):
|
||||
|
||||
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 (i.e., 172.20.10.1:1234).")
|
||||
parser.add_argument("--serialsu", "-s", help="On ADB, directly try su/serial/busybox scripting, if you do not have a special bluetooth.default.so file.", action="store_true")
|
||||
parser.add_argument("--testdevice", "-t", help="Use a dummy test device to execute testcases", action="store_true")
|
||||
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 (i.e., 172.20.10.1:1234).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--serialsu",
|
||||
"-s",
|
||||
help="On ADB, directly try su/serial/busybox scripting, if you do not have a special bluetooth.default.so file.",
|
||||
action="store_true",
|
||||
)
|
||||
parser.add_argument("--trace", help="Trace hci connection")
|
||||
parser.add_argument("--device", help="Specify device/core to be used")
|
||||
parser.add_argument("--commands", "-c", help="CLI command to run before prompting, seperated by ';' (used for easier testing)")
|
||||
parser.add_argument("--replay", help="Intercept and replace every communication with the core with the one in the specified file")
|
||||
parser.add_argument("--save", help="Store a trace into the file that can be used with --replay")
|
||||
parser.add_argument(
|
||||
"--commands",
|
||||
"-c",
|
||||
help="CLI command to run before prompting, seperated by ';' (used for easier testing)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--replay",
|
||||
help="Intercept and replace every communication with the core with the one in the specified file",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--save", help="Store a trace into the file that can be used with --replay"
|
||||
)
|
||||
return parser.parse_args(argv)
|
||||
|
||||
|
||||
|
||||
# Entry point for the `internalblue` command entry point defined in setup.py
|
||||
def internalblue_entry_point():
|
||||
print_banner()
|
||||
return internalblue_cli(sys.argv[1:])
|
||||
|
||||
# Main Program Start
|
||||
def internalblue_cli(argv, args=None):
|
||||
#print_banner()
|
||||
# print_banner()
|
||||
|
||||
args = args or _parse_argv(argv)
|
||||
|
||||
@@ -145,90 +185,108 @@ def internalblue_cli(argv, args=None):
|
||||
for cmd in cmds.getCmdList():
|
||||
for keyword in cmd.keywords:
|
||||
cmd_keywords.append(keyword)
|
||||
readline_completer = term.completer.LongestPrefixCompleter(words=cmd_keywords)
|
||||
term.readline.set_completer(readline_completer)
|
||||
|
||||
|
||||
readline_completer = pwnlib.term.completer.LongestPrefixCompleter(
|
||||
words=cmd_keywords
|
||||
)
|
||||
pwnlib.term.readline.set_completer(readline_completer)
|
||||
|
||||
if args.trace:
|
||||
from .socket_hooks import hook
|
||||
from internalblue import socket_hooks
|
||||
|
||||
HookClass = getattr(socket_hooks, args.trace)
|
||||
hook(HCICore, HookClass)
|
||||
hook(ADBCore, HookClass)
|
||||
elif args.save:
|
||||
from .socket_hooks import hook, TraceToFileHook
|
||||
|
||||
hook(HCICore, TraceToFileHook, filename=args.save)
|
||||
hook(ADBCore, TraceToFileHook, filename=args.save)
|
||||
|
||||
|
||||
# Initalize cores and get devices
|
||||
# As macOS has additional dependencies (objc), only import it here if needed
|
||||
connection_methods = [] # type: List[InternalBlue]
|
||||
connection_methods = [] # type: List[InternalBlue]
|
||||
if args.replay:
|
||||
from .socket_hooks import hook, ReplaySocket
|
||||
from .macoscore import macOSCore
|
||||
replay_devices = ['macos_replay', 'adb_replay', 'hci_replay', 'ios_replay']
|
||||
|
||||
replay_devices = ["macos_replay", "adb_replay", "hci_replay", "ios_replay"]
|
||||
if args.device == "macos_replay":
|
||||
from .macoscore import macOSCore
|
||||
|
||||
hook(macOSCore, ReplaySocket, filename=args.replay)
|
||||
connection_methods = [macOSCore(log_level=log_level, data_directory=data_directory, replay=True)]
|
||||
connection_methods = [
|
||||
macOSCore(
|
||||
log_level=log_level, data_directory=data_directory, replay=True
|
||||
)
|
||||
]
|
||||
elif args.device == "hci_replay":
|
||||
hook(HCICore, ReplaySocket, filename=args.replay)
|
||||
connection_methods = [HCICore(log_level=log_level, data_directory=data_directory, replay=True)]
|
||||
connection_methods = [
|
||||
HCICore(log_level=log_level, data_directory=data_directory, replay=True)
|
||||
]
|
||||
elif args.device == "adb_replay":
|
||||
hook(ADBCore, ReplaySocket, filename=args.replay)
|
||||
connection_methods = [ADBCore(log_level=log_level, data_directory=data_directory, replay=True)]
|
||||
connection_methods = [
|
||||
ADBCore(log_level=log_level, data_directory=data_directory, replay=True)
|
||||
]
|
||||
elif args.device == "ios_replay":
|
||||
raise NotImplementedError("ios replay is not implemented yet")
|
||||
else:
|
||||
raise ValueError("--device is required with --replay and has to be one of {}".format(replay_devices))
|
||||
|
||||
elif args.ios_device:
|
||||
from .ioscore import iOSCore
|
||||
connection_methods = [iOSCore(args.ios_device, log_level=log_level, data_directory=data_directory)]
|
||||
elif args.testdevice:
|
||||
from .testcore import testCore
|
||||
connection_methods = [testCore(log_level=log_level, data_directory=data_directory)]
|
||||
elif platform == "darwin":
|
||||
from .macoscore import macOSCore
|
||||
connection_methods = [
|
||||
macOSCore(log_level=log_level, data_directory=data_directory, replay=(args.replay and args.device == 'mac')),
|
||||
ADBCore(log_level=log_level, data_directory=data_directory)]
|
||||
if args.trace:
|
||||
hook(macOSCore, HookClass)
|
||||
elif args.save:
|
||||
hook(macOSCore, TraceToFileHook, filename=args.save)
|
||||
raise ValueError(
|
||||
"--device is required with --replay and has to be one of {}".format(
|
||||
replay_devices
|
||||
)
|
||||
)
|
||||
else:
|
||||
connection_methods = [
|
||||
ADBCore(log_level=log_level, data_directory=data_directory, serial=args.serialsu),
|
||||
HCICore(log_level=log_level, data_directory=data_directory)]
|
||||
# if /var/run/usbmuxd exists, we can check for iOS devices
|
||||
if os.path.exists("/var/run/usbmuxd"):
|
||||
from .ioscore import iOSCore
|
||||
connection_methods.append(iOSCore(log_level=log_level, data_directory=data_directory))
|
||||
|
||||
devices = [] # type: List[DeviceTuple]
|
||||
if platform == "darwin":
|
||||
try:
|
||||
from .macoscore import macOSCore
|
||||
connection_methods.append(macOSCore(log_level=log_level, data_directory=data_directory, replay=(args.replay and args.device == "mac")))
|
||||
except ImportError:
|
||||
pwnlib.log.warn("Couldn't import macOSCore. Is IOBluetoothExtended.framework installed?")
|
||||
if args.trace:
|
||||
hook(macOSCore, HookClass)
|
||||
elif args.save:
|
||||
hook(macOSCore, TraceToFileHook, filename=args.save)
|
||||
else:
|
||||
connection_methods.append(HCICore(log_level=log_level, data_directory=data_directory))
|
||||
|
||||
# ADB core can always be used
|
||||
connection_methods.append(
|
||||
ADBCore(
|
||||
log_level=log_level, data_directory=data_directory, serial=args.serialsu
|
||||
))
|
||||
|
||||
devices = [] # type: List[DeviceTuple]
|
||||
for connection_method in connection_methods:
|
||||
devices.extend(connection_method.device_list())
|
||||
|
||||
|
||||
device = None # type: Optional[DeviceTuple]
|
||||
device = None # type: Optional[DeviceTuple]
|
||||
if len(devices) > 0:
|
||||
if args.replay:
|
||||
# There should only be one device that was created when --replay was passed
|
||||
device = devices[0]
|
||||
elif args.device:
|
||||
matching_devices = [ dev for dev in devices if dev[1] == args.device]
|
||||
matching_devices = [dev for dev in devices if dev[1] == args.device]
|
||||
if len(matching_devices) > 1:
|
||||
log.critical("Found multiple matching devices")
|
||||
pwnlib.log.critical("Found multiple matching devices")
|
||||
exit(-1)
|
||||
elif len(matching_devices) == 1:
|
||||
log.info("Found device is: {}".format(matching_devices[0]))
|
||||
pwnlib.log.info("Found device is: {}".format(matching_devices[0]))
|
||||
device = matching_devices[0]
|
||||
else:
|
||||
log.critical("No matching devices found")
|
||||
pwnlib.log.critical("No matching devices found")
|
||||
exit(-1)
|
||||
elif len(devices) == 1:
|
||||
device = devices[0]
|
||||
else:
|
||||
i = options('Please specify device:', [d[2] for d in devices], 0)
|
||||
i = pwnlib.options("Please specify device:", [d[2] for d in devices], 0)
|
||||
device = devices[i]
|
||||
|
||||
# Setup device
|
||||
@@ -237,30 +295,30 @@ def internalblue_cli(argv, args=None):
|
||||
|
||||
# Restore readline history:
|
||||
if os.path.exists(reference.data_directory + "/" + HISTFILE):
|
||||
readline_history = read(reference.data_directory + "/" + HISTFILE)
|
||||
term.readline.history = readline_history.split('\n')
|
||||
readline_history = pwnlib.read(reference.data_directory + "/" + HISTFILE)
|
||||
pwnlib.term.readline.history = readline_history.split(b"\n")
|
||||
|
||||
# Connect to device
|
||||
if not reference.connect():
|
||||
log.critical("No connection to target device.")
|
||||
pwnlib.log.critical("No connection to target device.")
|
||||
exit(-1)
|
||||
|
||||
# Enter command loop (runs until user quits)
|
||||
log.info("Starting commandLoop for reference {}".format(reference))
|
||||
pwnlib.log.info("Starting commandLoop for reference {}".format(reference))
|
||||
commandLoop(reference, init_commands=args.commands)
|
||||
|
||||
# shutdown connection
|
||||
reference.shutdown()
|
||||
|
||||
# Save readline history:
|
||||
f = open(reference.data_directory + "/" + HISTFILE, "w")
|
||||
f.write("\n".join(term.readline.history))
|
||||
f.close()
|
||||
# TODO: - This causes issues, have to fix ASAP
|
||||
# f = open(reference.data_directory + "/" + HISTFILE, "w")
|
||||
# f.write("\n".join(term.readline.history))
|
||||
# f.close()
|
||||
|
||||
# Cleanup
|
||||
log.info("Goodbye")
|
||||
pwnlib.log.info("Goodbye")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
internalblue_cli(sys.argv[1:])
|
||||
|
||||
|
||||
+981
-584
File diff suppressed because it is too large
Load Diff
+699
-325
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
from .fw import FirmwareDefinition
|
||||
|
||||
+106
-20
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python
|
||||
|
||||
# fw.py
|
||||
#
|
||||
@@ -23,10 +23,83 @@
|
||||
# out of or in connection with the Software or the use or other dealings in the
|
||||
# Software.
|
||||
|
||||
from builtins import hex
|
||||
from builtins import object
|
||||
from types import ModuleType
|
||||
from typing import List
|
||||
|
||||
|
||||
from internalblue import Address
|
||||
from pwn import log
|
||||
|
||||
|
||||
class Firmware:
|
||||
class MemorySection(object):
|
||||
"""
|
||||
All firmwares have memory sections that can be RAM, ROM or neither of both.
|
||||
"""
|
||||
|
||||
def __init__(self, start_addr, end_addr, is_rom, is_ram):
|
||||
self.start_addr: Address = start_addr
|
||||
self.end_addr: Address = end_addr
|
||||
self.is_rom: bool = is_rom
|
||||
self.is_ram: bool = is_ram
|
||||
|
||||
def size(self) -> int:
|
||||
return self.end_addr - self.start_addr
|
||||
|
||||
|
||||
class FirmwareDefinition:
|
||||
|
||||
DEVICE_NAME: Address
|
||||
|
||||
BD_ADDR: Address
|
||||
|
||||
SECTIONS: List[MemorySection]
|
||||
TRACEPOINT_BODY_ASM_SNIPPET: str
|
||||
TRACEPOINT_HOOKS_LOCATION: int
|
||||
TRACEPOINT_RAM_DUMP_PKT_COUNT = None
|
||||
|
||||
CONNECTION_STRUCT_LENGTH: int
|
||||
|
||||
FW_NAME: str
|
||||
|
||||
QUEUE_NAMES: List[str]
|
||||
QUEUE_HEAD: Address
|
||||
BLOC_HEAD: Address
|
||||
SENDLCP_CODE_BASE_ADDRESS: Address
|
||||
|
||||
SENDLCP_ASM_CODE: str
|
||||
|
||||
SENDLMP_CODE_BASE_ADDRESS: Address
|
||||
SENDLMP_ASM_CODE: str
|
||||
|
||||
FUZZLMP_HOOK_ADDRESS: Address
|
||||
FUZZLMP_CODE_BASE_ADDRESS: Address
|
||||
FUZZLMP_ASM_CODE: str
|
||||
|
||||
CONNECTION_LIST_ADDRESS: Address
|
||||
CONNECTION_ARRAY_ADDRESS: Address
|
||||
CONNECTION_MAX: int
|
||||
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS: Address
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS: Address
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS: Address
|
||||
PATCHRAM_ALIGNED: bool
|
||||
PATCHRAM_NUMBER_OF_SLOTS: int
|
||||
|
||||
LAUNCH_RAM_PAUSE = None
|
||||
|
||||
READ_MEM_ALIGNED_ASM_LOCATION: Address
|
||||
READ_MEM_ALIGNED_ASM_SNIPPET: str
|
||||
|
||||
TRACEPOINT_HOOK_SIZE = None
|
||||
TRACEPOINT_BODY_ASM_LOCATION: Address
|
||||
TRACEPOINT_HOOK_ASM = None
|
||||
|
||||
|
||||
class Firmware(object):
|
||||
firmware: FirmwareDefinition
|
||||
|
||||
def __init__(self, version=None, iOS=False):
|
||||
"""
|
||||
Load and initialize the actual firmware add-ons for Nexus 5, Raspi3, etc.
|
||||
@@ -35,40 +108,53 @@ class Firmware:
|
||||
"""
|
||||
|
||||
self.version = version
|
||||
self.firmware = None
|
||||
|
||||
if version:
|
||||
# get LMP Subversion
|
||||
log.info("Chip identifier: 0x%04x (%03d.%03d.%03d)" %
|
||||
(version, version >> 13, (version & 0xf00) >> 8, version & 0xff))
|
||||
log.info(
|
||||
"Chip identifier: 0x%04x (%03d.%03d.%03d)"
|
||||
% (version, version >> 13, (version & 0xF00) >> 8, version & 0xFF)
|
||||
)
|
||||
|
||||
try:
|
||||
# Fix for duplicate version number of evaluation board / iPhones
|
||||
if iOS and version==0x420e:
|
||||
self.firmware = __import__(__name__ + '_' + hex(version) + '_iphone', fromlist=[''])
|
||||
if iOS and version == 0x420E:
|
||||
self.firmware = self._module_to_firmware_definition(
|
||||
__import__(
|
||||
__name__ + "_" + hex(version) + "_iphone", fromlist=[""]
|
||||
)
|
||||
)
|
||||
log.info("Using fw_" + hex(version) + "_iphone.py")
|
||||
else:
|
||||
self.firmware = __import__(__name__ + '_' + hex(version), fromlist=[''])
|
||||
self.firmware = self._module_to_firmware_definition(
|
||||
__import__(__name__ + "_" + hex(version), fromlist=[""])
|
||||
)
|
||||
log.info("Using fw_" + hex(version) + ".py")
|
||||
except ImportError:
|
||||
self.firmware = None
|
||||
pass
|
||||
|
||||
if not version or not self.firmware:
|
||||
self.firmware = __import__(__name__ + '_default', fromlist=[''])
|
||||
self.firmware = self._module_to_firmware_definition(
|
||||
__import__(__name__ + "_default", fromlist=[""])
|
||||
)
|
||||
|
||||
log.info("Loaded firmware information for " + self.firmware.FW_NAME + ".")
|
||||
|
||||
def _module_to_firmware_definition(self, fw: ModuleType) -> FirmwareDefinition:
|
||||
"""
|
||||
Wrap existing usages where the module was used and extract the new FirmwareDefinition class
|
||||
|
||||
class MemorySection:
|
||||
"""
|
||||
All firmwares have memory sections that can be RAM, ROM or neither of both.
|
||||
"""
|
||||
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
|
||||
:param fw:
|
||||
:return:
|
||||
"""
|
||||
_types = {
|
||||
name: cls
|
||||
for name, cls in fw.__dict__.items()
|
||||
if isinstance(cls, type)
|
||||
and issubclass(cls, FirmwareDefinition)
|
||||
and not cls is FirmwareDefinition
|
||||
}
|
||||
|
||||
def size(self):
|
||||
return self.end_addr - self.start_addr
|
||||
if len(_types) == 1:
|
||||
return list(_types.values())[0]
|
||||
|
||||
+129
-125
@@ -20,138 +20,142 @@
|
||||
# out of or in connection with the Software or the use or other dealings in the
|
||||
# Software.
|
||||
|
||||
from fw import MemorySection
|
||||
|
||||
# Firmware Infos
|
||||
# Samsung S10/S10e/S10+
|
||||
FW_NAME = "BCM4375B1"
|
||||
from __future__ import absolute_import
|
||||
from .fw import MemorySection, FirmwareDefinition
|
||||
|
||||
|
||||
# Device Infos
|
||||
DEVICE_NAME = 0x207f2a
|
||||
BD_ADDR = 0x2026e2
|
||||
class BCM4375B1(FirmwareDefinition):
|
||||
# Firmware Infos
|
||||
# Samsung S10/S10e/S10+
|
||||
FW_NAME = "BCM4375B1"
|
||||
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [ MemorySection(0x00000000, 0x0013ffff, True, False), # Internal ROM
|
||||
MemorySection(0x00160000, 0x0017ffff, False, True), # Patches
|
||||
MemorySection(0x00200000, 0x00288000, False, True), # Internal Memory Cortex M3
|
||||
MemorySection(0x00300000, 0x0037ffff, False, True),
|
||||
]
|
||||
# Device Infos
|
||||
DEVICE_NAME = 0x207F2A
|
||||
BD_ADDR = 0x2026E2
|
||||
|
||||
# Patchram
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310404
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0x160000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 256
|
||||
PATCHRAM_ALIGNED = False
|
||||
|
||||
BLOC_HEAD = 0x20075c
|
||||
BLOC_NG = True
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [
|
||||
MemorySection(0x00000000, 0x0013FFFF, True, False), # Internal ROM
|
||||
MemorySection(0x00160000, 0x0017FFFF, False, True), # Patches
|
||||
MemorySection(0x00200000, 0x00288000, False, True), # Internal Memory Cortex M3
|
||||
MemorySection(0x00300000, 0x0037FFFF, False, True),
|
||||
]
|
||||
|
||||
# Assembler snippet for tracepoints
|
||||
# In contrast to the Nexus 5 patch, we uninstall ourselves automatically and use internal debug functions
|
||||
# TODO S10e does no longer have a patch uninstall function... writemem works to remove patches, but copying
|
||||
# Assembly of the original function from an eval board does not work...
|
||||
#TRACEPOINT_BODY_ASM_LOCATION = 0x00218300
|
||||
#TRACEPOINT_HOOKS_LOCATION = 0x00218500
|
||||
#TRACEPOINT_HOOK_SIZE = 40
|
||||
TRACEPOINT_HOOK_ASM = """
|
||||
push {r0-r12, lr} // save all registers on the stack (except sp and pc)
|
||||
ldr r6, =0x%x // addTracepoint() injects pc of original tracepoint here
|
||||
mov r9, %d // addTracepoint() injects the patchram slot of the hook patch
|
||||
bl 0x%x // addTracepoint() injects TRACEPOINT_BODY_ASM_LOCATION here
|
||||
pop {r0-r12, lr} // restore registers
|
||||
# Patchram
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310404
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0x160000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 256
|
||||
PATCHRAM_ALIGNED = False
|
||||
|
||||
// branch back to the original instruction
|
||||
b 0x%x // addTracepoint() injects the address of the tracepoint
|
||||
"""
|
||||
BLOC_HEAD = 0x20075C
|
||||
BLOC_NG = True
|
||||
|
||||
TRACEPOINT_BODY_ASM_SNIPPET = """
|
||||
# Assembler snippet for tracepoints
|
||||
# In contrast to the Nexus 5 patch, we uninstall ourselves automatically and use internal debug functions
|
||||
# TODO S10e does no longer have a patch uninstall function... writemem works to remove patches, but copying
|
||||
# Assembly of the original function from an eval board does not work...
|
||||
# TRACEPOINT_BODY_ASM_LOCATION = 0x00218300
|
||||
# TRACEPOINT_HOOKS_LOCATION = 0x00218500
|
||||
# TRACEPOINT_HOOK_SIZE = 40
|
||||
TRACEPOINT_HOOK_ASM = """
|
||||
push {r0-r12, lr} // save all registers on the stack (except sp and pc)
|
||||
ldr r6, =0x%x // addTracepoint() injects pc of original tracepoint here
|
||||
mov r9, %d // addTracepoint() injects the patchram slot of the hook patch
|
||||
bl 0x%x // addTracepoint() injects TRACEPOINT_BODY_ASM_LOCATION here
|
||||
pop {r0-r12, lr} // restore registers
|
||||
|
||||
// branch back to the original instruction
|
||||
b 0x%x // addTracepoint() injects the address of the tracepoint
|
||||
"""
|
||||
|
||||
mov r8, lr // save link register in r8
|
||||
|
||||
b delete_slot
|
||||
|
||||
// dump registers like before
|
||||
|
||||
// save status register in r5
|
||||
mrs r5, cpsr
|
||||
|
||||
// malloc HCI event buffer
|
||||
mov r0, 0xff // event code is 0xff (vendor specific HCI Event)
|
||||
mov r1, 76 // buffer size: size of registers (68 bytes) + type and length + 'TRACE_'
|
||||
bl 0x6cfe2 // hci_allocateEventBlockWithLen(0xff, 78) #DONE
|
||||
mov r4, r0 // save pointer to the buffer in r4
|
||||
|
||||
// append our custom header (the word 'TRACE_') after the event code and event length field
|
||||
add r0, 2 // write after the length field
|
||||
ldr r1, =0x43415254 // 'TRAC'
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
ldr r1, =0x5f45 // 'E_'
|
||||
strh r1, [r0]
|
||||
add r0, 2 // advance the pointer. r0 now points to the start of the register values
|
||||
|
||||
// store pc
|
||||
str r6, [r0] // r6 still contains the address of the original pc
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store sp
|
||||
mov r1, 56 // 14 saved registers * 4
|
||||
add r1, sp
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store status register
|
||||
str r5, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store other registers
|
||||
mov r1, sp
|
||||
mov r2, 56
|
||||
bl 0x2774 // memcpy(dst, src, len) #DONE
|
||||
|
||||
// send HCI buffer to the host
|
||||
mov r0, r4 // r4 still points to the beginning of the HCI buffer
|
||||
bl 0x6cfa8 // hci_sendEvent #DONE
|
||||
|
||||
// restore status register
|
||||
msr cpsr_f, r5
|
||||
|
||||
bl 0x6af24 // bthci_event_vs_DBFW_CoreDumpRAMImageEvent #DONE
|
||||
|
||||
// not possible... could not find patch_uninstallPatchEntry(slot)
|
||||
// -> disable TP by hand, we stored in r9
|
||||
// TODO - does not work??
|
||||
delete_slot:
|
||||
mov r0, #0
|
||||
mov r1, r0
|
||||
lsl r0, r0, #0x2
|
||||
ldr r3, =0x00310404
|
||||
sub.w r0, r0, #0x400
|
||||
add r3, #0x3c
|
||||
add r0, r3
|
||||
movw r2, #0xffff
|
||||
str r2, [r0, #0x0]
|
||||
ldr r0,=0x00310404
|
||||
add r0, #0x2c
|
||||
ldr r2, [r0,#0x0]
|
||||
mov r3, #0x1
|
||||
lsl r3, r1
|
||||
bic r2, r3
|
||||
str r2, [r0, #0x0]
|
||||
|
||||
|
||||
mov lr, r8 // restore lr from r8
|
||||
bx lr // return
|
||||
|
||||
.align
|
||||
patchram:
|
||||
.byte 0x04
|
||||
.byte 0x04
|
||||
.byte 0x31
|
||||
.byte 0x00
|
||||
|
||||
"""
|
||||
TRACEPOINT_BODY_ASM_SNIPPET = """
|
||||
|
||||
mov r8, lr // save link register in r8
|
||||
|
||||
b delete_slot
|
||||
|
||||
// dump registers like before
|
||||
|
||||
// save status register in r5
|
||||
mrs r5, cpsr
|
||||
|
||||
// malloc HCI event buffer
|
||||
mov r0, 0xff // event code is 0xff (vendor specific HCI Event)
|
||||
mov r1, 76 // buffer size: size of registers (68 bytes) + type and length + 'TRACE_'
|
||||
bl 0x6cfe2 // hci_allocateEventBlockWithLen(0xff, 78) #DONE
|
||||
mov r4, r0 // save pointer to the buffer in r4
|
||||
|
||||
// append our custom header (the word 'TRACE_') after the event code and event length field
|
||||
add r0, 2 // write after the length field
|
||||
ldr r1, =0x43415254 // 'TRAC'
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
ldr r1, =0x5f45 // 'E_'
|
||||
strh r1, [r0]
|
||||
add r0, 2 // advance the pointer. r0 now points to the start of the register values
|
||||
|
||||
// store pc
|
||||
str r6, [r0] // r6 still contains the address of the original pc
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store sp
|
||||
mov r1, 56 // 14 saved registers * 4
|
||||
add r1, sp
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store status register
|
||||
str r5, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store other registers
|
||||
mov r1, sp
|
||||
mov r2, 56
|
||||
bl 0x2774 // memcpy(dst, src, len) #DONE
|
||||
|
||||
// send HCI buffer to the host
|
||||
mov r0, r4 // r4 still points to the beginning of the HCI buffer
|
||||
bl 0x6cfa8 // hci_sendEvent #DONE
|
||||
|
||||
// restore status register
|
||||
msr cpsr_f, r5
|
||||
|
||||
bl 0x6af24 // bthci_event_vs_DBFW_CoreDumpRAMImageEvent #DONE
|
||||
|
||||
// not possible... could not find patch_uninstallPatchEntry(slot)
|
||||
// -> disable TP by hand, we stored in r9
|
||||
// TODO - does not work??
|
||||
delete_slot:
|
||||
mov r0, #0
|
||||
mov r1, r0
|
||||
lsl r0, r0, #0x2
|
||||
ldr r3, =0x00310404
|
||||
sub.w r0, r0, #0x400
|
||||
add r3, #0x3c
|
||||
add r0, r3
|
||||
movw r2, #0xffff
|
||||
str r2, [r0, #0x0]
|
||||
ldr r0,=0x00310404
|
||||
add r0, #0x2c
|
||||
ldr r2, [r0,#0x0]
|
||||
mov r3, #0x1
|
||||
lsl r3, r1
|
||||
bic r2, r3
|
||||
str r2, [r0, #0x0]
|
||||
|
||||
|
||||
mov lr, r8 // restore lr from r8
|
||||
bx lr // return
|
||||
|
||||
.align
|
||||
patchram:
|
||||
.byte 0x04
|
||||
.byte 0x04
|
||||
.byte 0x31
|
||||
.byte 0x00
|
||||
|
||||
"""
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python
|
||||
|
||||
# fw_0x6119.py
|
||||
#
|
||||
@@ -25,74 +25,68 @@
|
||||
# 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"
|
||||
from __future__ import absolute_import
|
||||
from .fw import MemorySection, FirmwareDefinition
|
||||
|
||||
# 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
|
||||
class BCM43430A1(FirmwareDefinition):
|
||||
# Firmware Infos
|
||||
# This runs on Rasperry Pi 3
|
||||
FW_NAME = "BCM43430A1"
|
||||
|
||||
def size(self):
|
||||
return self.end_addr - self.start_addr
|
||||
# Device Infos
|
||||
DEVICE_NAME = 0x20401C
|
||||
BD_ADDR = 0x201C64
|
||||
|
||||
# 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, 0x21ffff, False, True ),
|
||||
#MemorySection(0x260000, 0x268000, True , False), # might crash? issue 14
|
||||
#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)
|
||||
]
|
||||
# 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, 0x21FFFF, False, True),
|
||||
# MemorySection(0x260000, 0x268000, True , False), # might crash? issue 14
|
||||
# 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_LIST_ADDRESS = 0x204ba8
|
||||
CONNECTION_MAX = 11
|
||||
CONNECTION_STRUCT_LENGTH = 0x150 # TODO
|
||||
# Connection Structure and Table
|
||||
# CONNECTION_LIST_ADDRESS = 0x204ba8
|
||||
CONNECTION_MAX = 11
|
||||
CONNECTION_STRUCT_LENGTH = 0x150 # TODO
|
||||
|
||||
# Patchram
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310204
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0xd0000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 128
|
||||
PATCHRAM_ALIGNED = False
|
||||
# Patchram
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310204
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0xD0000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 128
|
||||
PATCHRAM_ALIGNED = False
|
||||
|
||||
# Heap
|
||||
BLOC_HEAD = 0x200588 # g_dynamic_memory_GeneralUsePools
|
||||
BLOC_NG = True # Next Generation Bloc Buffer
|
||||
|
||||
# Snippet for sendLcpPacket()
|
||||
SENDLCP_CODE_BASE_ADDRESS = 0x21a000
|
||||
SENDLCP_ASM_CODE = """
|
||||
push {r4,lr}
|
||||
|
||||
// we want to call lmulp_sendLcp(conn_index, input, length)
|
||||
|
||||
mov r0, %d // connection index, starts at 0
|
||||
ldr r1, =payload
|
||||
mov r2, %d // length
|
||||
bl 0x8389A // lmulp_sendLcp
|
||||
|
||||
pop {r4,pc} // go back
|
||||
|
||||
.align // The payload (LMP packet) must be 4-byte aligend (memcpy needs aligned addresses)
|
||||
payload: // Note: the payload will be appended here by the sendLmpPacket() function
|
||||
"""
|
||||
# Heap
|
||||
BLOC_HEAD = 0x200588 # g_dynamic_memory_GeneralUsePools
|
||||
BLOC_NG = True # Next Generation Bloc Buffer
|
||||
|
||||
# Snippet for sendLcpPacket()
|
||||
SENDLCP_CODE_BASE_ADDRESS = 0x21A000
|
||||
SENDLCP_ASM_CODE = """
|
||||
push {r4,lr}
|
||||
|
||||
// we want to call lmulp_sendLcp(conn_index, input, length)
|
||||
|
||||
mov r0, %d // connection index, starts at 0
|
||||
ldr r1, =payload
|
||||
mov r2, %d // length
|
||||
bl 0x8389A // lmulp_sendLcp
|
||||
|
||||
pop {r4,pc} // go back
|
||||
|
||||
.align // The payload (LMP packet) must be 4-byte aligend (memcpy needs aligned addresses)
|
||||
payload: // Note: the payload will be appended here by the sendLmpPacket() function
|
||||
"""
|
||||
|
||||
@@ -20,26 +20,27 @@
|
||||
# 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 CYW20706
|
||||
FW_NAME = "CYW20706"
|
||||
from __future__ import absolute_import
|
||||
from .fw import MemorySection, FirmwareDefinition
|
||||
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [ MemorySection(0x00000000, 0x000c7fff, True, False), # Internal ROM
|
||||
MemorySection(0x000d0000, 0x000dffff, False, True ),
|
||||
MemorySection(0x00200000, 0x00247fff, False, True), # Internal Memory Cortex M3
|
||||
]
|
||||
|
||||
# Patchram
|
||||
#PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
#PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310404
|
||||
#PATCHRAM_VALUE_TABLE_ADDRESS = 0x0d0000
|
||||
#PATCHRAM_NUMBER_OF_SLOTS = 256
|
||||
PATCHRAM_ALIGNED = True
|
||||
# only seems to work 4-byte aligned here ...
|
||||
class CYW20706(FirmwareDefinition):
|
||||
# Firmware Infos
|
||||
# Evaluation Kit CYW20706
|
||||
FW_NAME = "CYW20706"
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [
|
||||
MemorySection(0x00000000, 0x000C7FFF, True, False), # Internal ROM
|
||||
MemorySection(0x000D0000, 0x000DFFFF, False, True),
|
||||
MemorySection(0x00200000, 0x00247FFF, False, True), # Internal Memory Cortex M3
|
||||
]
|
||||
|
||||
# Patchram
|
||||
# PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
# PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310404
|
||||
# PATCHRAM_VALUE_TABLE_ADDRESS = 0x0d0000
|
||||
# PATCHRAM_NUMBER_OF_SLOTS = 256
|
||||
PATCHRAM_ALIGNED = True
|
||||
# only seems to work 4-byte aligned here ...
|
||||
|
||||
@@ -20,27 +20,30 @@
|
||||
# out of or in connection with the Software or the use or other dealings in the
|
||||
# Software.
|
||||
|
||||
from fw import MemorySection
|
||||
from __future__ import absolute_import
|
||||
from .fw import MemorySection, FirmwareDefinition
|
||||
|
||||
# Firmware Infos
|
||||
# Evaluation Kit CYW920819
|
||||
FW_NAME = "CYW20819A1"
|
||||
class CYW20819A1(FirmwareDefinition):
|
||||
# Firmware Infos
|
||||
# Evaluation Kit CYW920819
|
||||
FW_NAME = "CYW20819A1"
|
||||
|
||||
|
||||
# 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 ...
|
||||
|
||||
# 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 ...
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# fw_0x220e.py
|
||||
#
|
||||
@@ -23,19 +23,22 @@
|
||||
# out of or in connection with the Software or the use or other dealings in the
|
||||
# Software.
|
||||
|
||||
from fw import MemorySection
|
||||
from .fw import MemorySection, FirmwareDefinition
|
||||
from __future__ import absolute_import
|
||||
|
||||
# Firmware Infos
|
||||
FW_NAME = "BCM20702A1 (USB Bluetooth dongle)"
|
||||
|
||||
# Device Infos
|
||||
#DEVICE_NAME = 0x280CD0 # rm_deviceLocalName, FIXME has no longer a length byte prepended
|
||||
#BD_ADDR = 0x280CA4 # rm_deviceBDAddr
|
||||
class BCM20702A1(FirmwareDefinition):
|
||||
# Firmware Infos
|
||||
FW_NAME = "BCM20702A1" # (USB Bluetooth dongle)
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [ MemorySection(0x00000000, 0x5ffff, True, False), # Internal ROM
|
||||
MemorySection(0x80000, 0x9bfff, False, True), # Internal RAM
|
||||
]
|
||||
BLOC_HEAD = 0x3166c
|
||||
# Device Infos
|
||||
# DEVICE_NAME = 0x280CD0 # rm_deviceLocalName, FIXME has no longer a length byte prepended
|
||||
# BD_ADDR = 0x280CA4 # rm_deviceBDAddr
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [
|
||||
MemorySection(0x00000000, 0x5FFFF, True, False), # Internal ROM
|
||||
MemorySection(0x80000, 0x9BFFF, False, True), # Internal RAM
|
||||
]
|
||||
BLOC_HEAD = 0x3166C
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python
|
||||
|
||||
# fw_default.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
|
||||
@@ -22,26 +18,30 @@
|
||||
# out of or in connection with the Software or the use or other dealings in the
|
||||
# Software.
|
||||
|
||||
from fw import MemorySection
|
||||
from __future__ import absolute_import
|
||||
from .fw import MemorySection, FirmwareDefinition
|
||||
|
||||
# Firmware Infos
|
||||
FW_NAME = "BCM20703A2 (MacBook Pro 2016)"
|
||||
|
||||
# Symbols contained in:
|
||||
# ./WICED-Studio-6.2/20706-A2_Bluetooth/Wiced-BT/BLD_ROM/A_20703A2/20703.symdefs
|
||||
# ./WICED-Studio-6.2/20706-A2_Bluetooth/Wiced-BT/tier2/brcm/wiced_uart/bld/A_20703A2/20703_ram_ext.lst
|
||||
class BCM20703A2(FirmwareDefinition):
|
||||
# Firmware Infos
|
||||
FW_NAME = "BCM20703A2 (MacBook Pro 2016)"
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [ MemorySection(0x0, 0xc7fff, True, False), #0x000c0a97
|
||||
MemorySection(0xd0000, 0xe0000, False, False), #0x000dd78c
|
||||
MemorySection(0x200000, 0x240000, False, True ), #0x00217a38
|
||||
MemorySection(0x260000, 0x268fff, True, False), #0x0026841d
|
||||
MemorySection(0x318000, 0x320000, False, False),
|
||||
MemorySection(0x324000, 0x338000, 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)
|
||||
]
|
||||
# Symbols contained in:
|
||||
# ./WICED-Studio-6.2/20706-A2_Bluetooth/Wiced-BT/BLD_ROM/A_20703A2/20703.symdefs
|
||||
# ./WICED-Studio-6.2/20706-A2_Bluetooth/Wiced-BT/tier2/brcm/wiced_uart/bld/A_20703A2/20703_ram_ext.lst
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [
|
||||
MemorySection(0x0, 0xC7FFF, True, False), # 0x000c0a97
|
||||
MemorySection(0xD0000, 0xE0000, False, False), # 0x000dd78c
|
||||
MemorySection(0x200000, 0x240000, False, True), # 0x00217a38
|
||||
MemorySection(0x260000, 0x268FFF, True, False), # 0x0026841d
|
||||
MemorySection(0x318000, 0x320000, False, False),
|
||||
MemorySection(0x324000, 0x338000, 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),
|
||||
]
|
||||
|
||||
+130
-130
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python
|
||||
|
||||
# fw.py
|
||||
#
|
||||
@@ -25,145 +25,145 @@
|
||||
# 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 Nexus 6P, Samsung Galaxy S6, Samsung Galaxy S6 edge
|
||||
FW_NAME = "BCM4358A3"
|
||||
|
||||
# Device Infos
|
||||
DEVICE_NAME = 0x213994 # [type: 1byte] [len: 1byte] [name: len byte] #works
|
||||
BD_ADDR = 0x201C48 #works
|
||||
from __future__ import absolute_import
|
||||
from .fw import MemorySection, FirmwareDefinition
|
||||
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [ MemorySection(0x0, 0x9ef00, True , False),
|
||||
MemorySection(0xd0000, 0xd8000, False, True ), # Patchram values with actual code / hooks
|
||||
#MemorySection(0xe0000, 0x1e0000, True , False), # all zero
|
||||
MemorySection(0x200000, 0x22a000, False, True ),
|
||||
MemorySection(0x260000, 0x268000, True , False),
|
||||
#MemorySection(0x280000, 0x2a0000, True , False), # all zero
|
||||
MemorySection(0x300000, 0x301000, False, False),
|
||||
MemorySection(0x310000, 0x318000, False, True ), # Patchram addresses
|
||||
MemorySection(0x318000, 0x322000, False, False),
|
||||
MemorySection(0x324000, 0x368000, False, False),
|
||||
MemorySection(0x600000, 0x600800, False, False),
|
||||
MemorySection(0x640000, 0x640800, False, False),
|
||||
MemorySection(0x650000, 0x650800, False, False),
|
||||
#MemorySection(0x680000, 0x800000, False, False)
|
||||
#MemorySection(0x770000, 0x78ffff, False, False), #TODO maybe more, but all zero
|
||||
]
|
||||
class BCM4358A3(FirmwareDefinition):
|
||||
# Firmware Infos
|
||||
# This runs on Nexus 6P, Samsung Galaxy S6, Samsung Galaxy S6 edge
|
||||
FW_NAME = "BCM4358A3"
|
||||
|
||||
# Device Infos
|
||||
DEVICE_NAME = 0x213994 # [type: 1byte] [len: 1byte] [name: len byte] #works
|
||||
BD_ADDR = 0x201C48 # works
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [
|
||||
MemorySection(0x0, 0x9EF00, True, False),
|
||||
MemorySection(
|
||||
0xD0000, 0xD8000, False, True
|
||||
), # Patchram values with actual code / hooks
|
||||
# MemorySection(0xe0000, 0x1e0000, True , False), # all zero
|
||||
MemorySection(0x200000, 0x22A000, False, True),
|
||||
MemorySection(0x260000, 0x268000, True, False),
|
||||
# MemorySection(0x280000, 0x2a0000, True , False), # all zero
|
||||
MemorySection(0x300000, 0x301000, False, False),
|
||||
MemorySection(0x310000, 0x318000, False, True), # Patchram addresses
|
||||
MemorySection(0x318000, 0x322000, False, False),
|
||||
MemorySection(0x324000, 0x368000, False, False),
|
||||
MemorySection(0x600000, 0x600800, False, False),
|
||||
MemorySection(0x640000, 0x640800, False, False),
|
||||
MemorySection(0x650000, 0x650800, False, False),
|
||||
# MemorySection(0x680000, 0x800000, False, False)
|
||||
# MemorySection(0x770000, 0x78ffff, False, False), #TODO maybe more, but all zero
|
||||
]
|
||||
|
||||
# Connection Struct and Table
|
||||
|
||||
# Nexus 6P works differently:
|
||||
# address 0x21AD5C holds a list with pointers to connection structs!
|
||||
# CONNECTION_ARRAY_ADDRESS = 0x21ad88 #potentially the first valid address... but not part of an array
|
||||
# CONNECTION_ARRAY_SIZE = 11 #is still 11 for Nexus 6P, but no longer hard-coded
|
||||
CONNECTION_LIST_ADDRESS = 0x21AD5C
|
||||
CONNECTION_MAX = 11
|
||||
CONNECTION_STRUCT_LENGTH = 0x168 # ??
|
||||
|
||||
# Patchram
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310204
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0xD0000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 192
|
||||
PATCHRAM_ALIGNED = False # we can use standard ReadRAM HCI on Nexus 6P
|
||||
|
||||
LAUNCH_RAM_PAUSE = 8 # bugfix: pause between multiple readMemAligned() calls in seconds
|
||||
# not a problem: doing multiple writeMem in a row
|
||||
# the thing that crashes: executing multiple launchRam() in a row: sendhcicmd 0xfc4e 0x473CC
|
||||
# crashes even when executing 0x5E860 twice, which is just a nullsub
|
||||
# also crashes during the pause if there are other hci events
|
||||
|
||||
# Snippet for sendLmpPacket()
|
||||
SENDLMP_CODE_BASE_ADDRESS = 0xD5130
|
||||
# TODO already works except for correct mac address - so still a problem with the connection #
|
||||
SENDLMP_ASM_CODE = """
|
||||
push {r4,lr}
|
||||
|
||||
// malloc buffer for LMP packet
|
||||
bl 0x3AAA8 // malloc_0x20_bloc_buffer_memzero
|
||||
mov r4, r0 // store buffer for LMP packet inside r4
|
||||
|
||||
// fill buffer
|
||||
add r0, 0xC // The actual LMP packet must start at offset 0xC in the buffer.
|
||||
// The first 12 bytes are (supposely?) unused and remain zero.
|
||||
ldr r1, =payload // LMP packet is stored at the end of the snippet
|
||||
mov r2, 20 // Max. size of an LMP packet is 19 (I guess). The send_LMP_packet
|
||||
// function will use the LMP opcode to lookup the actual size and
|
||||
// use it for actually transmitting the correct number of bytes.
|
||||
bl 0x63900+1 // memcpy
|
||||
|
||||
// load conn struct pointer (needed for determine if we are master or slave)
|
||||
mov r0, %d // connection number is injected by sendLmpPacket()
|
||||
bl 0x473CC // find connection struct from conn nr (r0 will hold pointer to conn struct) //FIXME
|
||||
//FIXME: mac address is always 1f:8d:00:00:00:00
|
||||
|
||||
// set tid bit if we are the slave
|
||||
ldr r1, [r0, 0x1c] // Load a bitmap from the connection struct into r1.
|
||||
lsr r1, 15 // The 'we are master'-bit is at position 15 of this bitmap
|
||||
eor r1, 0x1 // invert and isolate the bit to get the correct value for the TID bit
|
||||
and r1, 0x1
|
||||
ldr r2, [r4, 0xC] // Load the LMP opcode into r2. Note: The opcode was already shifted
|
||||
// left by 1 bit (done by sendLmpPacket()). The TID bit goes into
|
||||
// the LSB (least significant bit) of this shifted opcode byte.
|
||||
orr r2, r1 // insert the TID bit into the byte
|
||||
str r2, [r4, 0xC] // Store the byte back into the LMP packet buffer
|
||||
|
||||
|
||||
# Connection Struct and Table
|
||||
// send LMP packet
|
||||
mov r1, r4 // load the address of the LMP packet buffer into r1.
|
||||
// r0 still contains the connection number.
|
||||
pop {r4,lr} // restore r4 and the lr
|
||||
b 0xAF4C // branch to send_LMP_packet. send_LMP_packet will do the return for us.
|
||||
|
||||
# Nexus 6P works differently:
|
||||
# address 0x21AD5C holds a list with pointers to connection structs!
|
||||
# CONNECTION_ARRAY_ADDRESS = 0x21ad88 #potentially the first valid address... but not part of an array
|
||||
# CONNECTION_ARRAY_SIZE = 11 #is still 11 for Nexus 6P, but no longer hard-coded
|
||||
CONNECTION_LIST_ADDRESS = 0x21AD5C
|
||||
CONNECTION_MAX = 11
|
||||
CONNECTION_STRUCT_LENGTH = 0x168 #??
|
||||
.align // The payload (LMP packet) must be 4-byte aligend (memcpy needs aligned addresses)
|
||||
payload: // Note: the payload will be appended here by the sendLmpPacket() function
|
||||
"""
|
||||
|
||||
# Patchram
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310204
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0xd0000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 192
|
||||
PATCHRAM_ALIGNED = False #we can use standard ReadRAM HCI on Nexus 6P
|
||||
# Assembler snippet for the readMemAligned() function
|
||||
READ_MEM_ALIGNED_ASM_LOCATION = 0xD5030
|
||||
READ_MEM_ALIGNED_ASM_SNIPPET = """
|
||||
push {r4, lr}
|
||||
|
||||
// malloc HCI event buffer
|
||||
mov r1, 0xff // event code is 0xff (vendor specific HCI Event)
|
||||
mov r2, %d // readMemAligned() injects the number of bytes it wants to read here
|
||||
add r2, 4 // + 'READ'
|
||||
mov r0, r2
|
||||
adds r0, #2 // r0 needs to be 2 higher than r2 in all malloc_hci_event_buffer calls
|
||||
bl 0x22C4 // malloc_hci_event_buffer (will automatically copy event code and length into the buffer)
|
||||
mov r4, r0 // save pointer to the buffer in r4
|
||||
|
||||
LAUNCH_RAM_PAUSE = 8 # bugfix: pause between multiple readMemAligned() calls in seconds
|
||||
# not a problem: doing multiple writeMem in a row
|
||||
# the thing that crashes: executing multiple launchRam() in a row: sendhcicmd 0xfc4e 0x473CC
|
||||
# crashes even when executing 0x5E860 twice, which is just a nullsub
|
||||
# also crashes during the pause if there are other hci events
|
||||
// append our custom header (the word 'READ') after the event code and event length field
|
||||
add r0, 10 // write after the length field (offset 10 in event struct)
|
||||
ldr r1, =0x44414552 // 'READ'
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer. r0 now points to the beginning of our read data
|
||||
|
||||
// copy data to buffer
|
||||
ldr r1, =0x%x // readMemAligned() injects the read_address here. r1 will be used as src pointer in the loop
|
||||
mov r2, %d // readMemAligned() injects the number of dwords to read here. r2 will be the loop counter
|
||||
loop:
|
||||
ldr r3, [r1] // read 4 bytes from the read_address
|
||||
str r3, [r0] // store them inside the HCI buffer
|
||||
add r0, 4 // advance the buffer pointer
|
||||
add r1, 4 // advance the read_address
|
||||
subs r2, 1 // decrement the loop variable
|
||||
bne loop // branch if r2 is not zero yet
|
||||
|
||||
# Snippet for sendLmpPacket()
|
||||
SENDLMP_CODE_BASE_ADDRESS = 0xd5130
|
||||
#TODO already works except for correct mac address - so still a problem with the connection #
|
||||
SENDLMP_ASM_CODE = """
|
||||
push {r4,lr}
|
||||
// send HCI buffer to the host
|
||||
mov r0, r4 // r4 still points to the beginning of the HCI buffer
|
||||
|
||||
// malloc buffer for LMP packet
|
||||
bl 0x3AAA8 // malloc_0x20_bloc_buffer_memzero
|
||||
mov r4, r0 // store buffer for LMP packet inside r4
|
||||
pop {r4, lr} // return
|
||||
b 0x20F4 // send_hci_event()
|
||||
|
||||
// fill buffer
|
||||
add r0, 0xC // The actual LMP packet must start at offset 0xC in the buffer.
|
||||
// The first 12 bytes are (supposely?) unused and remain zero.
|
||||
ldr r1, =payload // LMP packet is stored at the end of the snippet
|
||||
mov r2, 20 // Max. size of an LMP packet is 19 (I guess). The send_LMP_packet
|
||||
// function will use the LMP opcode to lookup the actual size and
|
||||
// use it for actually transmitting the correct number of bytes.
|
||||
bl 0x63900+1 // memcpy
|
||||
|
||||
// load conn struct pointer (needed for determine if we are master or slave)
|
||||
mov r0, %d // connection number is injected by sendLmpPacket()
|
||||
bl 0x473CC // find connection struct from conn nr (r0 will hold pointer to conn struct) //FIXME
|
||||
//FIXME: mac address is always 1f:8d:00:00:00:00
|
||||
|
||||
// set tid bit if we are the slave
|
||||
ldr r1, [r0, 0x1c] // Load a bitmap from the connection struct into r1.
|
||||
lsr r1, 15 // The 'we are master'-bit is at position 15 of this bitmap
|
||||
eor r1, 0x1 // invert and isolate the bit to get the correct value for the TID bit
|
||||
and r1, 0x1
|
||||
ldr r2, [r4, 0xC] // Load the LMP opcode into r2. Note: The opcode was already shifted
|
||||
// left by 1 bit (done by sendLmpPacket()). The TID bit goes into
|
||||
// the LSB (least significant bit) of this shifted opcode byte.
|
||||
orr r2, r1 // insert the TID bit into the byte
|
||||
str r2, [r4, 0xC] // Store the byte back into the LMP packet buffer
|
||||
|
||||
|
||||
// send LMP packet
|
||||
mov r1, r4 // load the address of the LMP packet buffer into r1.
|
||||
// r0 still contains the connection number.
|
||||
pop {r4,lr} // restore r4 and the lr
|
||||
b 0xAF4C // branch to send_LMP_packet. send_LMP_packet will do the return for us.
|
||||
|
||||
.align // The payload (LMP packet) must be 4-byte aligend (memcpy needs aligned addresses)
|
||||
payload: // Note: the payload will be appended here by the sendLmpPacket() function
|
||||
"""
|
||||
|
||||
# Assembler snippet for the readMemAligned() function
|
||||
READ_MEM_ALIGNED_ASM_LOCATION = 0xd5030
|
||||
READ_MEM_ALIGNED_ASM_SNIPPET = """
|
||||
push {r4, lr}
|
||||
|
||||
// malloc HCI event buffer
|
||||
mov r1, 0xff // event code is 0xff (vendor specific HCI Event)
|
||||
mov r2, %d // readMemAligned() injects the number of bytes it wants to read here
|
||||
add r2, 4 // + 'READ'
|
||||
mov r0, r2
|
||||
adds r0, #2 // r0 needs to be 2 higher than r2 in all malloc_hci_event_buffer calls
|
||||
bl 0x22C4 // malloc_hci_event_buffer (will automatically copy event code and length into the buffer)
|
||||
mov r4, r0 // save pointer to the buffer in r4
|
||||
|
||||
// append our custom header (the word 'READ') after the event code and event length field
|
||||
add r0, 10 // write after the length field (offset 10 in event struct)
|
||||
ldr r1, =0x44414552 // 'READ'
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer. r0 now points to the beginning of our read data
|
||||
|
||||
// copy data to buffer
|
||||
ldr r1, =0x%x // readMemAligned() injects the read_address here. r1 will be used as src pointer in the loop
|
||||
mov r2, %d // readMemAligned() injects the number of dwords to read here. r2 will be the loop counter
|
||||
loop:
|
||||
ldr r3, [r1] // read 4 bytes from the read_address
|
||||
str r3, [r0] // store them inside the HCI buffer
|
||||
add r0, 4 // advance the buffer pointer
|
||||
add r1, 4 // advance the read_address
|
||||
subs r2, 1 // decrement the loop variable
|
||||
bne loop // branch if r2 is not zero yet
|
||||
|
||||
// send HCI buffer to the host
|
||||
mov r0, r4 // r4 still points to the beginning of the HCI buffer
|
||||
|
||||
pop {r4, lr} // return
|
||||
b 0x20F4 // send_hci_event()
|
||||
|
||||
"""
|
||||
|
||||
|
||||
|
||||
@@ -20,64 +20,70 @@
|
||||
# out of or in connection with the Software or the use or other dealings in the
|
||||
# Software.
|
||||
|
||||
from .fw import MemorySection
|
||||
|
||||
# Firmware Infos
|
||||
# iPhone 6
|
||||
FW_NAME = "BCM4345B0"
|
||||
from __future__ import absolute_import
|
||||
from .fw import MemorySection, FirmwareDefinition
|
||||
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [ MemorySection(0x00000000, 0x000c07ff, True, False), # Internal ROM
|
||||
MemorySection(0x000d0000, 0x000dffff, False, True), # Internal Memory Patchram Contents
|
||||
MemorySection(0x00200400, 0x00201cff, False, True), # Internal Memory Cortex M3
|
||||
]
|
||||
|
||||
# Patchram
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000 # needs to be aligned read
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310204
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0xd0000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 128
|
||||
PATCHRAM_ALIGNED = True
|
||||
class BCM4345B0(FirmwareDefinition):
|
||||
# Firmware Infos
|
||||
# iPhone 6
|
||||
FW_NAME = "BCM4345B0"
|
||||
|
||||
|
||||
# Assembler snippet for the readMemAligned() function
|
||||
READ_MEM_ALIGNED_ASM_LOCATION = 0x215000 # there is nothing free until 0xdffff, but 0x215000 looks okay during runtime
|
||||
READ_MEM_ALIGNED_ASM_SNIPPET = """
|
||||
push {r4, lr}
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [
|
||||
MemorySection(0x00000000, 0x000C07FF, True, False), # Internal ROM
|
||||
MemorySection(
|
||||
0x000D0000, 0x000DFFFF, False, True
|
||||
), # Internal Memory Patchram Contents
|
||||
MemorySection(0x00200400, 0x00201CFF, False, True), # Internal Memory Cortex M3
|
||||
]
|
||||
|
||||
// malloc HCI event buffer
|
||||
mov r0, 0xff // event code is 0xff (vendor specific HCI Event)
|
||||
mov r1, %d // readMemAligned() injects the number of bytes it wants to read here
|
||||
add r1, 6 // + type and length + 'READ'
|
||||
bl 0x15DD4 // hci_sendEvent (will automatically copy event code and length into the buffer)
|
||||
mov r4, r0 // save pointer to the buffer in r4
|
||||
# Patchram
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000 # needs to be aligned read
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310204
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0xD0000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 128
|
||||
PATCHRAM_ALIGNED = True
|
||||
|
||||
// append our custom header (the word 'READ') after the event code and event length field
|
||||
add r0, 2 // write after the length field
|
||||
ldr r1, =0x44414552 // 'READ'
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer. r0 now points to the beginning of our read data
|
||||
|
||||
// copy data to buffer
|
||||
ldr r1, =0x%x // readMemAligned() injects the read_address here. r1 will be used as src pointer in the loop
|
||||
mov r2, %d // readMemAligned() injects the number of dwords to read here. r2 will be the loop counter
|
||||
loop:
|
||||
ldr r3, [r1] // read 4 bytes from the read_address
|
||||
str r3, [r0] // store them inside the HCI buffer
|
||||
add r0, 4 // advance the buffer pointer
|
||||
add r1, 4 // advance the read_address
|
||||
subs r2, 1 // decrement the loop variable
|
||||
bne loop // branch if r2 is not zero yet
|
||||
|
||||
// send HCI buffer to the host
|
||||
mov r0, r4 // r4 still points to the beginning of the HCI buffer
|
||||
bl 0x573B8 // send_hci_event_without_free()
|
||||
|
||||
// free HCI buffer
|
||||
mov r0, r4
|
||||
bl 0x581AE // osapi_blockPoolFree
|
||||
|
||||
pop {r4, pc} // return
|
||||
"""
|
||||
# Assembler snippet for the readMemAligned() function
|
||||
READ_MEM_ALIGNED_ASM_LOCATION = 0x215000 # there is nothing free until 0xdffff, but 0x215000 looks okay during runtime
|
||||
READ_MEM_ALIGNED_ASM_SNIPPET = """
|
||||
push {r4, lr}
|
||||
|
||||
// malloc HCI event buffer
|
||||
mov r0, 0xff // event code is 0xff (vendor specific HCI Event)
|
||||
mov r1, %d // readMemAligned() injects the number of bytes it wants to read here
|
||||
add r1, 6 // + type and length + 'READ'
|
||||
bl 0x15DD4 // hci_sendEvent (will automatically copy event code and length into the buffer)
|
||||
mov r4, r0 // save pointer to the buffer in r4
|
||||
|
||||
// append our custom header (the word 'READ') after the event code and event length field
|
||||
add r0, 2 // write after the length field
|
||||
ldr r1, =0x44414552 // 'READ'
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer. r0 now points to the beginning of our read data
|
||||
|
||||
// copy data to buffer
|
||||
ldr r1, =0x%x // readMemAligned() injects the read_address here. r1 will be used as src pointer in the loop
|
||||
mov r2, %d // readMemAligned() injects the number of dwords to read here. r2 will be the loop counter
|
||||
loop:
|
||||
ldr r3, [r1] // read 4 bytes from the read_address
|
||||
str r3, [r0] // store them inside the HCI buffer
|
||||
add r0, 4 // advance the buffer pointer
|
||||
add r1, 4 // advance the read_address
|
||||
subs r2, 1 // decrement the loop variable
|
||||
bne loop // branch if r2 is not zero yet
|
||||
|
||||
// send HCI buffer to the host
|
||||
mov r0, r4 // r4 still points to the beginning of the HCI buffer
|
||||
bl 0x573B8 // send_hci_event_without_free()
|
||||
|
||||
// free HCI buffer
|
||||
mov r0, r4
|
||||
bl 0x581AE // osapi_blockPoolFree
|
||||
|
||||
pop {r4, pc} // return
|
||||
"""
|
||||
|
||||
@@ -20,28 +20,34 @@
|
||||
# out of or in connection with the Software or the use or other dealings in the
|
||||
# Software.
|
||||
|
||||
from .fw import MemorySection
|
||||
|
||||
# Firmware Infos
|
||||
# Samsung Galaxy S8
|
||||
FW_NAME = "BCM4347B0"
|
||||
from __future__ import absolute_import
|
||||
from .fw import MemorySection, FirmwareDefinition
|
||||
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [ MemorySection(0x00000000, 0x00100000, True, False), # Internal ROM
|
||||
MemorySection(0x00130000, 0x00150000, False, True), # Internal Memory Patchram Contents
|
||||
MemorySection(0x00200000, 0x0023ffff, False, True), # Internal Memory Cortex M3
|
||||
]
|
||||
|
||||
# Patchram
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310404
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0x130000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 256
|
||||
PATCHRAM_ALIGNED = False
|
||||
class BCM4347B0(FirmwareDefinition):
|
||||
# Firmware Infos
|
||||
# Samsung Galaxy S8
|
||||
FW_NAME = "BCM4347B0"
|
||||
|
||||
|
||||
# Heap
|
||||
BLOC_HEAD = 0x20067C # g_dynamic_memory_GeneralUsePools
|
||||
BLOC_NG = True # Next Generation Bloc Buffer
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [
|
||||
MemorySection(0x00000000, 0x00100000, True, False), # Internal ROM
|
||||
MemorySection(
|
||||
0x00130000, 0x00150000, False, True
|
||||
), # Internal Memory Patchram Contents
|
||||
MemorySection(0x00200000, 0x0023FFFF, False, True), # Internal Memory Cortex M3
|
||||
]
|
||||
|
||||
# Patchram
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310404
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0x130000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 256
|
||||
PATCHRAM_ALIGNED = False
|
||||
|
||||
|
||||
# Heap
|
||||
BLOC_HEAD = 0x20067C # g_dynamic_memory_GeneralUsePools
|
||||
BLOC_NG = True # Next Generation Bloc Buffer
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# fw_0x220e.py
|
||||
#
|
||||
@@ -29,13 +29,13 @@ from .fw import MemorySection
|
||||
FW_NAME = "BCM20702A2"
|
||||
|
||||
# Device Infos
|
||||
#DEVICE_NAME = 0x280CD0 # rm_deviceLocalName, FIXME has no longer a length byte prepended
|
||||
#BD_ADDR = 0x280CA4 # rm_deviceBDAddr
|
||||
# DEVICE_NAME = 0x280CD0 # rm_deviceLocalName, FIXME has no longer a length byte prepended
|
||||
# BD_ADDR = 0x280CA4 # rm_deviceBDAddr
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [ MemorySection(0x00000000, 0x5ffff, True, False), # Internal ROM
|
||||
MemorySection(0x80000, 0x9bfff, False, True), # Internal RAM
|
||||
]
|
||||
BLOC_HEAD = 0x3166c
|
||||
|
||||
SECTIONS = [
|
||||
MemorySection(0x00000000, 0x5FFFF, True, False), # Internal ROM
|
||||
MemorySection(0x80000, 0x9BFFF, False, True), # Internal RAM
|
||||
]
|
||||
BLOC_HEAD = 0x3166C
|
||||
|
||||
+204
-189
@@ -20,202 +20,217 @@
|
||||
# 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 CYW920735
|
||||
FW_NAME = "CYW20735B1"
|
||||
|
||||
# Device Infos
|
||||
DEVICE_NAME = 0x280CD0 # rm_deviceLocalName, FIXME has no longer a length byte prepended
|
||||
BD_ADDR = 0x280CA4 # rm_deviceBDAddr
|
||||
|
||||
#Heap
|
||||
BLOC_HEAD = 0x200474 # 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
|
||||
MemorySection(0x00300000, 0x00307fff, False, True), # HW Regs Cortex M3 (readable)
|
||||
MemorySection(0x00310000, 0x00321fff, False, True), # HW Regs Cortex M3 (readable)
|
||||
MemorySection(0x00326000, 0x0032ffff, False, True), # HW Regs Cortex M3 (readable)
|
||||
MemorySection(0x00338000, 0x00367fff, False, True), # HW Regs Cortex M3 (readable) + Pka Top
|
||||
MemorySection(0x00370000, 0x0037ffff, False, True), # RTX FIFO
|
||||
MemorySection(0x00390000, 0x00397fff, False, True), # Power WD
|
||||
#MemorySection(0x00404000, 0x00407fff, False, True), # EF Registers (seem to be sometimes unavailable)
|
||||
MemorySection(0x00410000, 0x00413fff, False, True), # BT Modem Registers
|
||||
MemorySection(0x00420000, 0x00423fff, False, True), # FM Modem Registers
|
||||
MemorySection(0x00430000, 0x00433fff, False, True), # MAC 15.4
|
||||
MemorySection(0x00440000, 0x00443fff, False, True), # SecEng Top
|
||||
MemorySection(0x00450000, 0x00453fff, False, True), # Capscan Top
|
||||
MemorySection(0x00500000, 0x006007ff, False, True), # EPM RAM (readable) + RF Regs
|
||||
MemorySection(0x00640000, 0x006407ff, False, True), # CLB Regs
|
||||
MemorySection(0x00650000, 0x006507ff, False, True), # GCI Regs
|
||||
MemorySection(0x20000000, 0x2024ffff, False, True), # SRAM
|
||||
MemorySection(0x20270000, 0x20283fff, False, True), # SRAM
|
||||
MemorySection(0x20500000, 0x200fffff, False, True), # SRAM
|
||||
MemorySection(0x22000000, 0x2226ffff, False, True), # SRAM Bits?
|
||||
|
||||
MemorySection(0x40000000, 0x40003fff, False, True), # ToRam Alias / Peripherals
|
||||
MemorySection(0x42000000, 0x4207ffff, False, True), # ToRam Bits
|
||||
#MemorySection(0x60000000, 0x60000000, False, True), # Extern BlueRF SRAM (range TBD)
|
||||
#MemorySection(0xa0000000, 0xa0000000, False, True), # Extern Device Address (range TBD)
|
||||
MemorySection(0xe0000000, 0xe0100000, False, True), # Base PPB Address
|
||||
]
|
||||
|
||||
# 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 ...
|
||||
from __future__ import absolute_import
|
||||
from .fw import MemorySection, FirmwareDefinition
|
||||
|
||||
|
||||
# Connection Struct and Table
|
||||
CONNECTION_LIST_ADDRESS = 0x216F98 # pRm_whole_conn = 0x280C9C points to this
|
||||
CONNECTION_MAX = 11 # g_bt_max_connections = 0 in firmware
|
||||
CONNECTION_STRUCT_LENGTH = 0x168 # ??
|
||||
class CYW20735B1(FirmwareDefinition):
|
||||
# Firmware Infos
|
||||
# Evaluation Kit CYW920735
|
||||
FW_NAME = "CYW20735B1"
|
||||
|
||||
# Snippet for fuzzLmp()
|
||||
FUZZLMP_HOOK_ADDRESS = 0xB08D8 # execute standard SendLmpPdu HCI to fill parameters
|
||||
FUZZLMP_CODE_BASE_ADDRESS = 0x271A00 # memory area of other WICED patches
|
||||
FUZZLMP_ASM_CODE = """
|
||||
// This hook is put into the end of bthci_cmd_vs_SendLmpPdu_B08AC,
|
||||
// so command parsing is still performed as normal. We jump in
|
||||
// before bthci_cmd_vs_SendLmpPdu pops and calls DHM_LMPTx.
|
||||
# Device Infos
|
||||
DEVICE_NAME = (
|
||||
0x280CD0 # rm_deviceLocalName, FIXME has no longer a length byte prepended
|
||||
)
|
||||
BD_ADDR = 0x280CA4 # rm_deviceBDAddr
|
||||
|
||||
mov r0, r6 // 4 byte alignment
|
||||
# Heap
|
||||
BLOC_HEAD = 0x200474 # g_dynamic_memory_GeneralUsePools
|
||||
BLOC_NG = True # Next Generation Bloc Buffer
|
||||
|
||||
// put length argument into table_entry
|
||||
// payload[5] holds the size argument
|
||||
ldr r5, =table_entry
|
||||
add r5, #4 // length offset within table entry
|
||||
ldrb r6, [r4, #5] // size is in position r4+5
|
||||
strb r6, [r5]
|
||||
# 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
|
||||
MemorySection(
|
||||
0x00300000, 0x00307FFF, False, True
|
||||
), # HW Regs Cortex M3 (readable)
|
||||
MemorySection(
|
||||
0x00310000, 0x00321FFF, False, True
|
||||
), # HW Regs Cortex M3 (readable)
|
||||
MemorySection(
|
||||
0x00326000, 0x0032FFFF, False, True
|
||||
), # HW Regs Cortex M3 (readable)
|
||||
MemorySection(
|
||||
0x00338000, 0x00367FFF, False, True
|
||||
), # HW Regs Cortex M3 (readable) + Pka Top
|
||||
MemorySection(0x00370000, 0x0037FFFF, False, True), # RTX FIFO
|
||||
MemorySection(0x00390000, 0x00397FFF, False, True), # Power WD
|
||||
# MemorySection(0x00404000, 0x00407fff, False, True), # EF Registers (seem to be sometimes unavailable)
|
||||
MemorySection(0x00410000, 0x00413FFF, False, True), # BT Modem Registers
|
||||
MemorySection(0x00420000, 0x00423FFF, False, True), # FM Modem Registers
|
||||
MemorySection(0x00430000, 0x00433FFF, False, True), # MAC 15.4
|
||||
MemorySection(0x00440000, 0x00443FFF, False, True), # SecEng Top
|
||||
MemorySection(0x00450000, 0x00453FFF, False, True), # Capscan Top
|
||||
MemorySection(
|
||||
0x00500000, 0x006007FF, False, True
|
||||
), # EPM RAM (readable) + RF Regs
|
||||
MemorySection(0x00640000, 0x006407FF, False, True), # CLB Regs
|
||||
MemorySection(0x00650000, 0x006507FF, False, True), # GCI Regs
|
||||
MemorySection(0x20000000, 0x2024FFFF, False, True), # SRAM
|
||||
MemorySection(0x20270000, 0x20283FFF, False, True), # SRAM
|
||||
MemorySection(0x20500000, 0x200FFFFF, False, True), # SRAM
|
||||
MemorySection(0x22000000, 0x2226FFFF, False, True), # SRAM Bits?
|
||||
MemorySection(0x40000000, 0x40003FFF, False, True), # ToRam Alias / Peripherals
|
||||
MemorySection(0x42000000, 0x4207FFFF, False, True), # ToRam Bits
|
||||
# MemorySection(0x60000000, 0x60000000, False, True), # Extern BlueRF SRAM (range TBD)
|
||||
# MemorySection(0xa0000000, 0xa0000000, False, True), # Extern Device Address (range TBD)
|
||||
MemorySection(0xE0000000, 0xE0100000, False, True), # Base PPB Address
|
||||
]
|
||||
|
||||
// we need to do the original pop...
|
||||
pop {r4-r6, lr}
|
||||
# Patchram
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 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 ...
|
||||
|
||||
// now we simply continue like the original DHM_LMPTx_3453E function
|
||||
cmp r1, #0
|
||||
itt eq
|
||||
moveq r0, #4
|
||||
bxeq lr
|
||||
push {r4-r10, lr} // code at 0x34546
|
||||
mov r7, r0
|
||||
# Connection Struct and Table
|
||||
CONNECTION_LIST_ADDRESS = 0x216F98 # pRm_whole_conn = 0x280C9C points to this
|
||||
CONNECTION_MAX = 11 # g_bt_max_connections = 0 in firmware
|
||||
CONNECTION_STRUCT_LENGTH = 0x168 # ??
|
||||
|
||||
// part of the check if hook_LMP_TxFilter is installed
|
||||
ldr r0, =0x203144 //dhmAvLinkAutoDetectEnable
|
||||
mov r4, r1
|
||||
ldr r2, [r0, #12]
|
||||
//cbz r2, loc_34564
|
||||
# Snippet for fuzzLmp()
|
||||
FUZZLMP_HOOK_ADDRESS = 0xB08D8 # execute standard SendLmpPdu HCI to fill parameters
|
||||
FUZZLMP_CODE_BASE_ADDRESS = 0x271A00 # memory area of other WICED patches
|
||||
FUZZLMP_ASM_CODE = """
|
||||
// This hook is put into the end of bthci_cmd_vs_SendLmpPdu_B08AC,
|
||||
// so command parsing is still performed as normal. We jump in
|
||||
// before bthci_cmd_vs_SendLmpPdu pops and calls DHM_LMPTx.
|
||||
|
||||
mov r0, r6 // 4 byte alignment
|
||||
|
||||
// put length argument into table_entry
|
||||
// payload[5] holds the size argument
|
||||
ldr r5, =table_entry
|
||||
add r5, #4 // length offset within table entry
|
||||
ldrb r6, [r4, #5] // size is in position r4+5
|
||||
strb r6, [r5]
|
||||
|
||||
// we need to do the original pop...
|
||||
pop {r4-r6, lr}
|
||||
|
||||
// now we simply continue like the original DHM_LMPTx_3453E function
|
||||
cmp r1, #0
|
||||
itt eq
|
||||
moveq r0, #4
|
||||
bxeq lr
|
||||
push {r4-r10, lr} // code at 0x34546
|
||||
mov r7, r0
|
||||
|
||||
// part of the check if hook_LMP_TxFilter is installed
|
||||
ldr r0, =0x203144 //dhmAvLinkAutoDetectEnable
|
||||
mov r4, r1
|
||||
ldr r2, [r0, #12]
|
||||
//cbz r2, loc_34564
|
||||
|
||||
ldr.w r8, [r7] // code at 0x34564
|
||||
mov r0, r8
|
||||
bl 0x93E60 // rm_getDHMAclPtr
|
||||
movs r5, r0
|
||||
// skip check if we actually got a ptr
|
||||
// continue at 0x3457A
|
||||
ldrb r0, [r4, #12]
|
||||
tst.w r0, #0xfe // test for extended op ...
|
||||
add.w r0, r3, #0xc
|
||||
|
||||
|
||||
// now we regularily would call the opcode conversion table function
|
||||
// however, we do not use lm_getLmpInfoType_86A82 but insert our own table here
|
||||
ldr r1, =table_entry // table_ptr with exactly one entry, so no offsets included here
|
||||
ldr r0, =table_entry
|
||||
|
||||
// branch back to DHM_LMPTx position after bl lm_getLmpInfoType
|
||||
b 0x3458A
|
||||
|
||||
.align
|
||||
table_entry:
|
||||
.byte 0x40 //lm_LmpUnsupportedPdu
|
||||
.byte 0x6A
|
||||
.byte 0x08
|
||||
.byte 0x00
|
||||
.byte 0x20 //length, will be overwritten by us anyways, but can not be longer than one buffer (0x20)
|
||||
.byte 0x00
|
||||
.byte 0x00
|
||||
.byte 0x00
|
||||
"""
|
||||
|
||||
ldr.w r8, [r7] // code at 0x34564
|
||||
mov r0, r8
|
||||
bl 0x93E60 // rm_getDHMAclPtr
|
||||
movs r5, r0
|
||||
// skip check if we actually got a ptr
|
||||
// continue at 0x3457A
|
||||
ldrb r0, [r4, #12]
|
||||
tst.w r0, #0xfe // test for extended op ...
|
||||
add.w r0, r3, #0xc
|
||||
|
||||
# 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_HOOK_SIZE = 40
|
||||
TRACEPOINT_HOOK_ASM = """
|
||||
push {r0-r12, lr} // save all registers on the stack (except sp and pc)
|
||||
ldr r6, =0x%x // addTracepoint() injects pc of original tracepoint here
|
||||
mov r0, %d // addTracepoint() injects the patchram slot of the hook patch
|
||||
bl 0x28794 // patch_uninstallPatchEntry(slot)
|
||||
bl 0x%x // addTracepoint() injects TRACEPOINT_BODY_ASM_LOCATION here
|
||||
pop {r0-r12, lr} // restore registers
|
||||
|
||||
// branch back to the original instruction
|
||||
b 0x%x // addTracepoint() injects the address of the tracepoint
|
||||
"""
|
||||
|
||||
// now we regularily would call the opcode conversion table function
|
||||
// however, we do not use lm_getLmpInfoType_86A82 but insert our own table here
|
||||
ldr r1, =table_entry // table_ptr with exactly one entry, so no offsets included here
|
||||
ldr r0, =table_entry
|
||||
|
||||
// branch back to DHM_LMPTx position after bl lm_getLmpInfoType
|
||||
b 0x3458A
|
||||
|
||||
.align
|
||||
table_entry:
|
||||
.byte 0x40 //lm_LmpUnsupportedPdu
|
||||
.byte 0x6A
|
||||
.byte 0x08
|
||||
.byte 0x00
|
||||
.byte 0x20 //length, will be overwritten by us anyways, but can not be longer than one buffer (0x20)
|
||||
.byte 0x00
|
||||
.byte 0x00
|
||||
.byte 0x00
|
||||
"""
|
||||
|
||||
|
||||
# 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_HOOK_SIZE = 40
|
||||
TRACEPOINT_HOOK_ASM = """
|
||||
push {r0-r12, lr} // save all registers on the stack (except sp and pc)
|
||||
ldr r6, =0x%x // addTracepoint() injects pc of original tracepoint here
|
||||
mov r0, %d // addTracepoint() injects the patchram slot of the hook patch
|
||||
bl 0x28794 // patch_uninstallPatchEntry(slot)
|
||||
bl 0x%x // addTracepoint() injects TRACEPOINT_BODY_ASM_LOCATION here
|
||||
pop {r0-r12, lr} // restore registers
|
||||
|
||||
// branch back to the original instruction
|
||||
b 0x%x // addTracepoint() injects the address of the tracepoint
|
||||
"""
|
||||
|
||||
TRACEPOINT_BODY_ASM_SNIPPET = """
|
||||
mov r8, lr // save link register in r8
|
||||
|
||||
// dump registers like before
|
||||
|
||||
// save status register in r5
|
||||
mrs r5, cpsr
|
||||
|
||||
// malloc HCI event buffer
|
||||
mov r0, 0xff // event code is 0xff (vendor specific HCI Event)
|
||||
mov r1, 76 // buffer size: size of registers (68 bytes) + type and length + 'TRACE_'
|
||||
bl 0x2DEF4 // hci_allocateEventBlockWithLen(0xff, 78)
|
||||
mov r4, r0 // save pointer to the buffer in r4
|
||||
|
||||
// append our custom header (the word 'TRACE_') after the event code and event length field
|
||||
add r0, 2 // write after the length field
|
||||
ldr r1, =0x43415254 // 'TRAC'
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
ldr r1, =0x5f45 // 'E_'
|
||||
strh r1, [r0]
|
||||
add r0, 2 // advance the pointer. r0 now points to the start of the register values
|
||||
|
||||
// store pc
|
||||
str r6, [r0] // r6 still contains the address of the original pc
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store sp
|
||||
mov r1, 56 // 14 saved registers * 4
|
||||
add r1, sp
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store status register
|
||||
str r5, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store other registers
|
||||
mov r1, sp
|
||||
mov r2, 56
|
||||
bl 0xEAB4 // memcpy(dst, src, len)
|
||||
|
||||
// send HCI buffer to the host
|
||||
mov r0, r4 // r4 still points to the beginning of the HCI buffer
|
||||
bl 0x2DEC0 // hci_sendEvent
|
||||
|
||||
// restore status register
|
||||
msr cpsr_f, r5
|
||||
|
||||
bl 0x26C7A // bthci_event_vs_DBFW_CoreDumpRAMImageEvent
|
||||
|
||||
mov lr, r8 // restore lr from r8
|
||||
bx lr // return
|
||||
|
||||
"""
|
||||
TRACEPOINT_BODY_ASM_SNIPPET = """
|
||||
mov r8, lr // save link register in r8
|
||||
|
||||
// dump registers like before
|
||||
|
||||
// save status register in r5
|
||||
mrs r5, cpsr
|
||||
|
||||
// malloc HCI event buffer
|
||||
mov r0, 0xff // event code is 0xff (vendor specific HCI Event)
|
||||
mov r1, 76 // buffer size: size of registers (68 bytes) + type and length + 'TRACE_'
|
||||
bl 0x2DEF4 // hci_allocateEventBlockWithLen(0xff, 78)
|
||||
mov r4, r0 // save pointer to the buffer in r4
|
||||
|
||||
// append our custom header (the word 'TRACE_') after the event code and event length field
|
||||
add r0, 2 // write after the length field
|
||||
ldr r1, =0x43415254 // 'TRAC'
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
ldr r1, =0x5f45 // 'E_'
|
||||
strh r1, [r0]
|
||||
add r0, 2 // advance the pointer. r0 now points to the start of the register values
|
||||
|
||||
// store pc
|
||||
str r6, [r0] // r6 still contains the address of the original pc
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store sp
|
||||
mov r1, 56 // 14 saved registers * 4
|
||||
add r1, sp
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store status register
|
||||
str r5, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store other registers
|
||||
mov r1, sp
|
||||
mov r2, 56
|
||||
bl 0xEAB4 // memcpy(dst, src, len)
|
||||
|
||||
// send HCI buffer to the host
|
||||
mov r0, r4 // r4 still points to the beginning of the HCI buffer
|
||||
bl 0x2DEC0 // hci_sendEvent
|
||||
|
||||
// restore status register
|
||||
msr cpsr_f, r5
|
||||
|
||||
bl 0x26C7A // bthci_event_vs_DBFW_CoreDumpRAMImageEvent
|
||||
|
||||
mov lr, r8 // restore lr from r8
|
||||
bx lr // return
|
||||
|
||||
"""
|
||||
|
||||
+103
-98
@@ -20,109 +20,114 @@
|
||||
# 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 CYW920719
|
||||
FW_NAME = "CYW20739B1 (NOT iPhone X/XR!)"
|
||||
# TODO this is not the iPhone firmware, we need to add a switch in fw.py
|
||||
|
||||
# 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 = 256
|
||||
PATCHRAM_ALIGNED = False
|
||||
# only seems to work 4-byte aligned here ...
|
||||
from .fw import MemorySection, FirmwareDefinition
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
||||
# Assembler snippet for tracepoints
|
||||
# In contrast to the Nexus 5 patch, we uninstall ourselves automatically and use internal debug functions
|
||||
TRACEPOINT_BODY_ASM_LOCATION = 0x00223100
|
||||
TRACEPOINT_HOOKS_LOCATION = 0x00223200
|
||||
TRACEPOINT_HOOK_SIZE = 40
|
||||
TRACEPOINT_HOOK_ASM = """
|
||||
push {r0-r12, lr} // save all registers on the stack (except sp and pc)
|
||||
ldr r6, =0x%x // addTracepoint() injects pc of original tracepoint here
|
||||
mov r0, %d // addTracepoint() injects the patchram slot of the hook patch
|
||||
bl 0x34964 // patch_uninstallPatchEntry(slot)
|
||||
bl 0x%x // addTracepoint() injects TRACEPOINT_BODY_ASM_LOCATION here
|
||||
pop {r0-r12, lr} // restore registers
|
||||
class CYW20739B1(FirmwareDefinition):
|
||||
# Firmware Infos
|
||||
# Evaluation Kit CYW920719
|
||||
FW_NAME = "CYW20739B1 (NOT iPhone X/XR!)"
|
||||
# TODO this is not the iPhone firmware, we need to add a switch in fw.py
|
||||
|
||||
// branch back to the original instruction
|
||||
b 0x%x // addTracepoint() injects the address of the tracepoint
|
||||
"""
|
||||
# Device Infos
|
||||
DEVICE_NAME = (
|
||||
0x280CD0 # rm_deviceLocalName, FIXME has no longer a length byte prepended
|
||||
)
|
||||
BD_ADDR = 0x280CA4 # rm_deviceBDAddr
|
||||
|
||||
TRACEPOINT_BODY_ASM_SNIPPET = """
|
||||
mov r8, lr // save link register in r8
|
||||
# Heap
|
||||
BLOC_HEAD = 0x0200C7C # g_dynamic_memory_GeneralUsePools
|
||||
BLOC_NG = True # Next Generation Bloc Buffer
|
||||
|
||||
// dump registers like before
|
||||
# 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
|
||||
]
|
||||
|
||||
// save status register in r5
|
||||
mrs r5, cpsr
|
||||
|
||||
// malloc HCI event buffer
|
||||
mov r0, 0xff // event code is 0xff (vendor specific HCI Event)
|
||||
mov r1, 76 // buffer size: size of registers (68 bytes) + type and length + 'TRACE_'
|
||||
bl 0xF7B6 // hci_allocateEventBlockWithLen(0xff, 78)
|
||||
mov r4, r0 // save pointer to the buffer in r4
|
||||
|
||||
// append our custom header (the word 'TRACE_') after the event code and event length field
|
||||
add r0, 2 // write after the length field
|
||||
ldr r1, =0x43415254 // 'TRAC'
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
ldr r1, =0x5f45 // 'E_'
|
||||
strh r1, [r0]
|
||||
add r0, 2 // advance the pointer. r0 now points to the start of the register values
|
||||
|
||||
// store pc
|
||||
str r6, [r0] // r6 still contains the address of the original pc
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store sp
|
||||
mov r1, 56 // 14 saved registers * 4
|
||||
add r1, sp
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store status register
|
||||
str r5, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store other registers
|
||||
mov r1, sp
|
||||
mov r2, 56
|
||||
bl 0xAF0BC // memcpy(dst, src, len)
|
||||
|
||||
// send HCI buffer to the host
|
||||
mov r0, r4 // r4 still points to the beginning of the HCI buffer
|
||||
bl 0xF782 // hci_sendEvent
|
||||
|
||||
// restore status register
|
||||
msr cpsr_f, r5
|
||||
|
||||
bl 0x2D702 // bthci_event_vs_DBFW_CoreDumpRAMImageEvent
|
||||
|
||||
mov lr, r8 // restore lr from r8
|
||||
bx lr // return
|
||||
|
||||
"""
|
||||
# Patchram
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = Address(0x310000)
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = Address(0x310404)
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = Address(0x270000)
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 256
|
||||
PATCHRAM_ALIGNED = False
|
||||
# only seems to work 4-byte aligned here ...
|
||||
|
||||
# Assembler snippet for tracepoints
|
||||
# In contrast to the Nexus 5 patch, we uninstall ourselves automatically and use internal debug functions
|
||||
TRACEPOINT_BODY_ASM_LOCATION = 0x00223100
|
||||
TRACEPOINT_HOOKS_LOCATION = 0x00223200
|
||||
TRACEPOINT_HOOK_SIZE = 40
|
||||
TRACEPOINT_HOOK_ASM = """
|
||||
push {r0-r12, lr} // save all registers on the stack (except sp and pc)
|
||||
ldr r6, =0x%x // addTracepoint() injects pc of original tracepoint here
|
||||
mov r0, %d // addTracepoint() injects the patchram slot of the hook patch
|
||||
bl 0x34964 // patch_uninstallPatchEntry(slot)
|
||||
bl 0x%x // addTracepoint() injects TRACEPOINT_BODY_ASM_LOCATION here
|
||||
pop {r0-r12, lr} // restore registers
|
||||
|
||||
// branch back to the original instruction
|
||||
b 0x%x // addTracepoint() injects the address of the tracepoint
|
||||
"""
|
||||
|
||||
TRACEPOINT_BODY_ASM_SNIPPET = """
|
||||
mov r8, lr // save link register in r8
|
||||
|
||||
// dump registers like before
|
||||
|
||||
// save status register in r5
|
||||
mrs r5, cpsr
|
||||
|
||||
// malloc HCI event buffer
|
||||
mov r0, 0xff // event code is 0xff (vendor specific HCI Event)
|
||||
mov r1, 76 // buffer size: size of registers (68 bytes) + type and length + 'TRACE_'
|
||||
bl 0xF7B6 // hci_allocateEventBlockWithLen(0xff, 78)
|
||||
mov r4, r0 // save pointer to the buffer in r4
|
||||
|
||||
// append our custom header (the word 'TRACE_') after the event code and event length field
|
||||
add r0, 2 // write after the length field
|
||||
ldr r1, =0x43415254 // 'TRAC'
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
ldr r1, =0x5f45 // 'E_'
|
||||
strh r1, [r0]
|
||||
add r0, 2 // advance the pointer. r0 now points to the start of the register values
|
||||
|
||||
// store pc
|
||||
str r6, [r0] // r6 still contains the address of the original pc
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store sp
|
||||
mov r1, 56 // 14 saved registers * 4
|
||||
add r1, sp
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store status register
|
||||
str r5, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store other registers
|
||||
mov r1, sp
|
||||
mov r2, 56
|
||||
bl 0xAF0BC // memcpy(dst, src, len)
|
||||
|
||||
// send HCI buffer to the host
|
||||
mov r0, r4 // r4 still points to the beginning of the HCI buffer
|
||||
bl 0xF782 // hci_sendEvent
|
||||
|
||||
// restore status register
|
||||
msr cpsr_f, r5
|
||||
|
||||
bl 0x2D702 // bthci_event_vs_DBFW_CoreDumpRAMImageEvent
|
||||
|
||||
mov lr, r8 // restore lr from r8
|
||||
bx lr // return
|
||||
|
||||
"""
|
||||
|
||||
@@ -20,22 +20,28 @@
|
||||
# out of or in connection with the Software or the use or other dealings in the
|
||||
# Software.
|
||||
|
||||
from .fw import MemorySection
|
||||
from .fw import MemorySection, FirmwareDefinition
|
||||
from __future__ import absolute_import
|
||||
|
||||
# Firmware Infos
|
||||
# iPhone 8/X/XR
|
||||
FW_NAME = "BCM4347B1"
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [ MemorySection(0x00000000, 0x00103fff, True, False), # Internal ROM
|
||||
MemorySection(0x00130000, 0x0014ffff, False, True), # Internal Memory Patchram Contents
|
||||
MemorySection(0x00200000, 0x0024ffff, False, True), # Internal Memory Cortex M3
|
||||
]
|
||||
class BCM4347B1(FirmwareDefinition):
|
||||
# Firmware Infos
|
||||
# iPhone 8/X/XR
|
||||
FW_NAME = "BCM4347B1"
|
||||
|
||||
# Patchram
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310404
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0x130000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 256
|
||||
PATCHRAM_ALIGNED = False
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [
|
||||
MemorySection(0x00000000, 0x00103FFF, True, False), # Internal ROM
|
||||
MemorySection(
|
||||
0x00130000, 0x0014FFFF, False, True
|
||||
), # Internal Memory Patchram Contents
|
||||
MemorySection(0x00200000, 0x0024FFFF, False, True), # Internal Memory Cortex M3
|
||||
]
|
||||
|
||||
# Patchram
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310404
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0x130000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 256
|
||||
PATCHRAM_ALIGNED = False
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python
|
||||
|
||||
# MacBook 15" early 2011 tested with Ubuntu
|
||||
# MacBook 15" early 2011 tested with Ubuntu
|
||||
#
|
||||
# Generic firmware file in case we do not know something...
|
||||
#
|
||||
@@ -22,16 +22,19 @@
|
||||
# out of or in connection with the Software or the use or other dealings in the
|
||||
# Software.
|
||||
|
||||
from .fw import MemorySection
|
||||
from .fw import MemorySection, FirmwareDefinition
|
||||
|
||||
# Firmware Infos
|
||||
FW_NAME = "BCM2070B0 (MacBook Pro 2011)"
|
||||
# Build date: Jul 9 2008
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [ MemorySection(0x0, 0x58000, True , False),
|
||||
MemorySection(0x80000, 0x9b000, False, True ),
|
||||
]
|
||||
class BCM2070B0(FirmwareDefinition):
|
||||
# Firmware Infos
|
||||
FW_NAME = "BCM2070B0 (MacBook Pro 2011)"
|
||||
# Build date: Jul 9 2008
|
||||
|
||||
BLOC_HEAD = 0x88518
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [
|
||||
MemorySection(0x0, 0x58000, True, False),
|
||||
MemorySection(0x80000, 0x9B000, False, True),
|
||||
]
|
||||
|
||||
BLOC_HEAD = 0x88518
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python
|
||||
|
||||
# fw_0x6103.py
|
||||
#
|
||||
@@ -20,35 +20,39 @@
|
||||
# out of or in connection with the Software or the use or other dealings in the
|
||||
# Software.
|
||||
|
||||
from .fw import MemorySection
|
||||
from __future__ import absolute_import
|
||||
from .fw import MemorySection, FirmwareDefinition
|
||||
|
||||
# Firmware Infos
|
||||
# This runs on an iPhone 7
|
||||
FW_NAME = "BCM4355C0"
|
||||
|
||||
# Device Infos
|
||||
DEVICE_NAME = 0x204c60
|
||||
class BCM4355C0(FirmwareDefinition):
|
||||
# Firmware Infos
|
||||
# This runs on an iPhone 7
|
||||
FW_NAME = "BCM4355C0"
|
||||
|
||||
# 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)
|
||||
]
|
||||
# Device Infos
|
||||
DEVICE_NAME = 0x204C60
|
||||
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310204
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0xd0000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 192
|
||||
PATCHRAM_ALIGNED = False
|
||||
# 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)
|
||||
]
|
||||
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310204
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0xD0000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 192
|
||||
PATCHRAM_ALIGNED = False
|
||||
|
||||
+361
-342
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python
|
||||
|
||||
# fw_0x6109.py
|
||||
#
|
||||
@@ -25,362 +25,381 @@
|
||||
# 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 Nexus 5, Xperia Z3, Samsung Galaxy Note 3
|
||||
FW_NAME = "BCM4335C0"
|
||||
|
||||
# Device Infos
|
||||
DEVICE_NAME = 0x2178B4 # [type: 1byte] [len: 1byte] [name: len byte]
|
||||
BD_ADDR = 0x210C2C
|
||||
from __future__ import absolute_import
|
||||
from .fw import MemorySection, FirmwareDefinition
|
||||
|
||||
|
||||
# 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)
|
||||
]
|
||||
class BCM4335C0(FirmwareDefinition):
|
||||
# Firmware Infos
|
||||
# This runs on Nexus 5, Xperia Z3, Samsung Galaxy Note 3
|
||||
FW_NAME = "BCM4335C0"
|
||||
|
||||
# BLOC struct head which points to the first bloc struct (double-linked list)
|
||||
BLOC_HEAD = 0x203094
|
||||
# Device Infos
|
||||
DEVICE_NAME = 0x2178B4 # [type: 1byte] [len: 1byte] [name: len byte]
|
||||
BD_ADDR = 0x210C2C
|
||||
|
||||
# QUEU struct head which points to the first queue struct (double-linked list)
|
||||
QUEUE_HEAD = 0x20307C
|
||||
QUEUE_NAMES = ["tran_HCIEvent", "tran_ACLData", "tran_SCOData", "tran_UartBridgeNonHCIEvent", "tran_DiagData",
|
||||
"tran_HIDUsbKBEvt", "tran_HIDUsbMSEvt", "tran_HIDUsbMSCtrl", "tran_HIDUsbKBCtrl", "tran_HidAuxData",
|
||||
"lm_Cmd", "hci_HciCommand", "lm_deferredAction", "lrmmsm_cmd", "liteHostEvent", "litehostRcvdL2capData"
|
||||
]
|
||||
# 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)
|
||||
]
|
||||
|
||||
# BLOC struct head which points to the first bloc struct (double-linked list)
|
||||
BLOC_HEAD = 0x203094
|
||||
|
||||
# Connection Structure and Table
|
||||
CONNECTION_ARRAY_ADDRESS = 0x002038E8
|
||||
CONNECTION_MAX = 11
|
||||
CONNECTION_STRUCT_LENGTH = 0x14C
|
||||
# QUEU struct head which points to the first queue struct (double-linked list)
|
||||
QUEUE_HEAD = 0x20307C
|
||||
QUEUE_NAMES = [
|
||||
"tran_HCIEvent",
|
||||
"tran_ACLData",
|
||||
"tran_SCOData",
|
||||
"tran_UartBridgeNonHCIEvent",
|
||||
"tran_DiagData",
|
||||
"tran_HIDUsbKBEvt",
|
||||
"tran_HIDUsbMSEvt",
|
||||
"tran_HIDUsbMSCtrl",
|
||||
"tran_HIDUsbKBCtrl",
|
||||
"tran_HidAuxData",
|
||||
"lm_Cmd",
|
||||
"hci_HciCommand",
|
||||
"lm_deferredAction",
|
||||
"lrmmsm_cmd",
|
||||
"liteHostEvent",
|
||||
"litehostRcvdL2capData",
|
||||
]
|
||||
|
||||
# Connection Structure and Table
|
||||
CONNECTION_ARRAY_ADDRESS = 0x002038E8
|
||||
CONNECTION_MAX = 11
|
||||
CONNECTION_STRUCT_LENGTH = 0x14C
|
||||
|
||||
# Patchram
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310204
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0xd0000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 128
|
||||
PATCHRAM_ALIGNED = True #use readMemAligned, not accessible via ReadRAM HCI command on Nexus 5
|
||||
# Patchram
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310204
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0xD0000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 128
|
||||
PATCHRAM_ALIGNED = (
|
||||
True # use readMemAligned, not accessible via ReadRAM HCI command on Nexus 5
|
||||
)
|
||||
|
||||
# Snippet for sendLcpPacket()
|
||||
SENDLCP_CODE_BASE_ADDRESS = 0x00211900
|
||||
SENDLCP_ASM_CODE = """
|
||||
push {r4,lr}
|
||||
|
||||
// we want to call lmulp_sendLcp(conn_index, input, length)
|
||||
|
||||
mov r0, %d // connection index, starts at 0
|
||||
ldr r1, =payload
|
||||
mov r2, %d // length
|
||||
bl 0x66760 // lmulp_sendLcp
|
||||
|
||||
pop {r4,pc} // go back
|
||||
|
||||
.align // The payload (LMP packet) must be 4-byte aligend (memcpy needs aligned addresses)
|
||||
payload: // Note: the payload will be appended here by the sendLmpPacket() function
|
||||
"""
|
||||
|
||||
# Snippet for sendLcpPacket()
|
||||
SENDLCP_CODE_BASE_ADDRESS = 0x00211900
|
||||
SENDLCP_ASM_CODE = """
|
||||
push {r4,lr}
|
||||
|
||||
// we want to call lmulp_sendLcp(conn_index, input, length)
|
||||
|
||||
mov r0, %d // connection index, starts at 0
|
||||
ldr r1, =payload
|
||||
mov r2, %d // length
|
||||
bl 0x66760 // lmulp_sendLcp
|
||||
|
||||
pop {r4,pc} // go back
|
||||
# Snippet for sendLmpPacketLegacy()
|
||||
SENDLMP_CODE_BASE_ADDRESS = 0xD7500
|
||||
SENDLMP_ASM_CODE = """
|
||||
push {r4,lr}
|
||||
|
||||
// malloc buffer for LMP packet
|
||||
bl 0x3F17E // malloc_0x20_bloc_buffer_memzero
|
||||
mov r4, r0 // store buffer for LMP packet inside r4
|
||||
|
||||
// fill buffer
|
||||
add r0, 0xC // The actual LMP packet must start at offset 0xC in the buffer.
|
||||
// The first 12 bytes are (supposely?) unused and remain zero.
|
||||
ldr r1, =payload // LMP packet is stored at the end of the snippet
|
||||
mov r2, 20 // Max. size of an LMP packet is 19 (I guess). The send_LMP_packet
|
||||
// function will use the LMP opcode to lookup the actual size and
|
||||
// use it for actually transmitting the correct number of bytes.
|
||||
bl 0x2e03c // memcpy
|
||||
|
||||
// load conn struct pointer (needed for determine if we are master or slave)
|
||||
mov r0, %d // connection number is injected by sendLmpPacket()
|
||||
bl 0x42c04 // find connection struct from conn nr (r0 will hold pointer to conn struct)
|
||||
|
||||
// set tid bit if we are the slave
|
||||
ldr r1, [r0, 0x1c] // Load a bitmap from the connection struct into r1.
|
||||
lsr r1, 15 // The 'we are master'-bit is at position 15 of this bitmap
|
||||
and r1, 0x1 // isolate the bit to get the correct value for the TID bit
|
||||
ldr r2, [r4, 0xC] // Load the LMP opcode into r2. Note: The opcode was already shifted
|
||||
// left by 1 bit (done by sendLmpPacket()). The TID bit goes into
|
||||
// the LSB (least significant bit) of this shifted opcode byte.
|
||||
orr r2, r1 // insert the TID bit into the byte
|
||||
str r2, [r4, 0xC] // Store the byte back into the LMP packet buffer
|
||||
|
||||
|
||||
// send LMP packet
|
||||
mov r1, r4 // load the address of the LMP packet buffer into r1.
|
||||
// r0 still contains the connection number.
|
||||
pop {r4,lr} // restore r4 and the lr
|
||||
b 0xf81a // branch to send_LMP_packet. send_LMP_packet will do the return for us.
|
||||
|
||||
.align // The payload (LMP packet) must be 4-byte aligend (memcpy needs aligned addresses)
|
||||
payload: // Note: the payload will be appended here by the sendLmpPacket() function
|
||||
"""
|
||||
|
||||
.align // The payload (LMP packet) must be 4-byte aligend (memcpy needs aligned addresses)
|
||||
payload: // Note: the payload will be appended here by the sendLmpPacket() function
|
||||
# Snippet for fuzzLmp()
|
||||
FUZZLMP_HOOK_ADDRESS = 0x1E48C # execute standard SendLmpPdu HCI to fill parameters
|
||||
FUZZLMP_CODE_BASE_ADDRESS = 0xD7500
|
||||
FUZZLMP_ASM_CODE = """
|
||||
// This hook is put into the end of bthci_cmd_vs_SendLmpPdu_1E45A,
|
||||
// so command parsing is still performed as normal. We jump in
|
||||
// before bthci_cmd_vs_SendLmpPdu pops and calls DHM_LMPTx.
|
||||
|
||||
// put length argument into table_entry
|
||||
// payload[5] holds the size argument
|
||||
ldr r7, =table_entry
|
||||
add r7, #4 // length offset within table entry
|
||||
ldrb r6, [r4, #5]
|
||||
strb r6, [r7]
|
||||
|
||||
// we need to do the original pop...
|
||||
pop {r4-r8, lr}
|
||||
|
||||
// now we simply continue like the original DHM_LMPTx function
|
||||
push {r4-r10, lr} // code at 0xF81A
|
||||
mov r8, r0
|
||||
movs r4, r1
|
||||
|
||||
// part of the check if hook_LMP_TxFilter_200D38 is installed
|
||||
ldr.w r9, =0x200D80
|
||||
sub.w r9, r9, #0x50
|
||||
ldr.w r2, [r9, #8]
|
||||
|
||||
mov r1, r4 // code at 0xF840
|
||||
mov r0, r8
|
||||
bl 0x50050 // rm_getDHMAclPtr_50050
|
||||
cmp r0, #1
|
||||
// skip check if we actually got a ptr
|
||||
// get connection struct, code at 0xF850
|
||||
ldr r0, =0x206eac // table_for_bt_tx_structs_206EAC
|
||||
ldr.w r7, [r8]
|
||||
add.w r6, r0, r7, lsl #5
|
||||
ldrb r0, [r6, #0x1f]
|
||||
cmp r0, #1
|
||||
// skip check in conection struct
|
||||
ldrb r0, [r4, #0xc] // ptr_to_opcode = buffer_cpy + 12;
|
||||
lsrs r1, r0, #1 // buffer_cpy[12] >> 1
|
||||
add.w r0, r4, #0x0c
|
||||
|
||||
// enable for debugging: ignore the remaining code and continue like normal opcode
|
||||
//b 0xF870
|
||||
|
||||
// now we regularily would call the opcode conversion table function
|
||||
// however, we do not use lm_getLmpInfoType_3F2D8 but insert our own table here
|
||||
ldr r1, =table_entry // table_ptr with exactly one entry, so no offsets included here
|
||||
ldr r0, =table_entry
|
||||
|
||||
// branch back to DHM_LMPTx position after bl lm_getLmpInfoType
|
||||
b 0xF874
|
||||
|
||||
.align
|
||||
table_entry:
|
||||
.byte 0x35 //nullsub1+1
|
||||
.byte 0xAC
|
||||
.byte 0x00
|
||||
.byte 0x00
|
||||
.byte 0x20 //length, will be overwritten by us anyways, but can not be longer than one buffer (0x20)
|
||||
.byte 0x00
|
||||
.byte 0x00
|
||||
.byte 0x00
|
||||
"""
|
||||
|
||||
# Assembler snippet for the readMemAligned() function
|
||||
READ_MEM_ALIGNED_ASM_LOCATION = 0xD7900
|
||||
READ_MEM_ALIGNED_ASM_SNIPPET = """
|
||||
push {r4, lr}
|
||||
|
||||
// malloc HCI event buffer
|
||||
mov r0, 0xff // event code is 0xff (vendor specific HCI Event)
|
||||
mov r1, %d // readMemAligned() injects the number of bytes it wants to read here
|
||||
add r1, 6 // + type and length + 'READ'
|
||||
bl 0x7AFC // malloc_hci_event_buffer (will automatically copy event code and length into the buffer)
|
||||
mov r4, r0 // save pointer to the buffer in r4
|
||||
|
||||
// append our custom header (the word 'READ') after the event code and event length field
|
||||
add r0, 2 // write after the length field
|
||||
ldr r1, =0x44414552 // 'READ'
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer. r0 now points to the beginning of our read data
|
||||
|
||||
// copy data to buffer
|
||||
ldr r1, =0x%x // readMemAligned() injects the read_address here. r1 will be used as src pointer in the loop
|
||||
mov r2, %d // readMemAligned() injects the number of dwords to read here. r2 will be the loop counter
|
||||
loop:
|
||||
ldr r3, [r1] // read 4 bytes from the read_address
|
||||
str r3, [r0] // store them inside the HCI buffer
|
||||
add r0, 4 // advance the buffer pointer
|
||||
add r1, 4 // advance the read_address
|
||||
subs r2, 1 // decrement the loop variable
|
||||
bne loop // branch if r2 is not zero yet
|
||||
|
||||
// send HCI buffer to the host
|
||||
mov r0, r4 // r4 still points to the beginning of the HCI buffer
|
||||
bl 0x398c1 // send_hci_event_without_free()
|
||||
|
||||
// free HCI buffer
|
||||
mov r0, r4
|
||||
bl 0x3FA36 // free_bloc_buffer_aligned
|
||||
|
||||
pop {r4, pc} // return
|
||||
"""
|
||||
|
||||
# Snippet for sendLmpPacketLegacy()
|
||||
SENDLMP_CODE_BASE_ADDRESS = 0xd7500
|
||||
SENDLMP_ASM_CODE = """
|
||||
push {r4,lr}
|
||||
|
||||
// malloc buffer for LMP packet
|
||||
bl 0x3F17E // malloc_0x20_bloc_buffer_memzero
|
||||
mov r4, r0 // store buffer for LMP packet inside r4
|
||||
|
||||
// fill buffer
|
||||
add r0, 0xC // The actual LMP packet must start at offset 0xC in the buffer.
|
||||
// The first 12 bytes are (supposely?) unused and remain zero.
|
||||
ldr r1, =payload // LMP packet is stored at the end of the snippet
|
||||
mov r2, 20 // Max. size of an LMP packet is 19 (I guess). The send_LMP_packet
|
||||
// function will use the LMP opcode to lookup the actual size and
|
||||
// use it for actually transmitting the correct number of bytes.
|
||||
bl 0x2e03c // memcpy
|
||||
|
||||
// load conn struct pointer (needed for determine if we are master or slave)
|
||||
mov r0, %d // connection number is injected by sendLmpPacket()
|
||||
bl 0x42c04 // find connection struct from conn nr (r0 will hold pointer to conn struct)
|
||||
|
||||
// set tid bit if we are the slave
|
||||
ldr r1, [r0, 0x1c] // Load a bitmap from the connection struct into r1.
|
||||
lsr r1, 15 // The 'we are master'-bit is at position 15 of this bitmap
|
||||
and r1, 0x1 // isolate the bit to get the correct value for the TID bit
|
||||
ldr r2, [r4, 0xC] // Load the LMP opcode into r2. Note: The opcode was already shifted
|
||||
// left by 1 bit (done by sendLmpPacket()). The TID bit goes into
|
||||
// the LSB (least significant bit) of this shifted opcode byte.
|
||||
orr r2, r1 // insert the TID bit into the byte
|
||||
str r2, [r4, 0xC] // Store the byte back into the LMP packet buffer
|
||||
|
||||
|
||||
// send LMP packet
|
||||
mov r1, r4 // load the address of the LMP packet buffer into r1.
|
||||
// r0 still contains the connection number.
|
||||
pop {r4,lr} // restore r4 and the lr
|
||||
b 0xf81a // branch to send_LMP_packet. send_LMP_packet will do the return for us.
|
||||
|
||||
.align // The payload (LMP packet) must be 4-byte aligend (memcpy needs aligned addresses)
|
||||
payload: // Note: the payload will be appended here by the sendLmpPacket() function
|
||||
"""
|
||||
|
||||
|
||||
# Snippet for fuzzLmp()
|
||||
FUZZLMP_HOOK_ADDRESS = 0x1e48c # execute standard SendLmpPdu HCI to fill parameters
|
||||
FUZZLMP_CODE_BASE_ADDRESS = 0xd7500
|
||||
FUZZLMP_ASM_CODE = """
|
||||
// This hook is put into the end of bthci_cmd_vs_SendLmpPdu_1E45A,
|
||||
// so command parsing is still performed as normal. We jump in
|
||||
// before bthci_cmd_vs_SendLmpPdu pops and calls DHM_LMPTx.
|
||||
|
||||
// put length argument into table_entry
|
||||
// payload[5] holds the size argument
|
||||
ldr r7, =table_entry
|
||||
add r7, #4 // length offset within table entry
|
||||
ldrb r6, [r4, #5]
|
||||
strb r6, [r7]
|
||||
|
||||
// we need to do the original pop...
|
||||
pop {r4-r8, lr}
|
||||
|
||||
// now we simply continue like the original DHM_LMPTx function
|
||||
push {r4-r10, lr} // code at 0xF81A
|
||||
mov r8, r0
|
||||
movs r4, r1
|
||||
|
||||
// part of the check if hook_LMP_TxFilter_200D38 is installed
|
||||
ldr.w r9, =0x200D80
|
||||
sub.w r9, r9, #0x50
|
||||
ldr.w r2, [r9, #8]
|
||||
|
||||
mov r1, r4 // code at 0xF840
|
||||
mov r0, r8
|
||||
bl 0x50050 // rm_getDHMAclPtr_50050
|
||||
cmp r0, #1
|
||||
// skip check if we actually got a ptr
|
||||
// get connection struct, code at 0xF850
|
||||
ldr r0, =0x206eac // table_for_bt_tx_structs_206EAC
|
||||
ldr.w r7, [r8]
|
||||
add.w r6, r0, r7, lsl #5
|
||||
ldrb r0, [r6, #0x1f]
|
||||
cmp r0, #1
|
||||
// skip check in conection struct
|
||||
ldrb r0, [r4, #0xc] // ptr_to_opcode = buffer_cpy + 12;
|
||||
lsrs r1, r0, #1 // buffer_cpy[12] >> 1
|
||||
add.w r0, r4, #0x0c
|
||||
|
||||
// enable for debugging: ignore the remaining code and continue like normal opcode
|
||||
//b 0xF870
|
||||
|
||||
// now we regularily would call the opcode conversion table function
|
||||
// however, we do not use lm_getLmpInfoType_3F2D8 but insert our own table here
|
||||
ldr r1, =table_entry // table_ptr with exactly one entry, so no offsets included here
|
||||
ldr r0, =table_entry
|
||||
|
||||
// branch back to DHM_LMPTx position after bl lm_getLmpInfoType
|
||||
b 0xF874
|
||||
|
||||
.align
|
||||
table_entry:
|
||||
.byte 0x35 //nullsub1+1
|
||||
.byte 0xAC
|
||||
.byte 0x00
|
||||
.byte 0x00
|
||||
.byte 0x20 //length, will be overwritten by us anyways, but can not be longer than one buffer (0x20)
|
||||
.byte 0x00
|
||||
.byte 0x00
|
||||
.byte 0x00
|
||||
"""
|
||||
|
||||
|
||||
# Assembler snippet for the readMemAligned() function
|
||||
READ_MEM_ALIGNED_ASM_LOCATION = 0xd7900
|
||||
READ_MEM_ALIGNED_ASM_SNIPPET = """
|
||||
push {r4, lr}
|
||||
|
||||
// malloc HCI event buffer
|
||||
mov r0, 0xff // event code is 0xff (vendor specific HCI Event)
|
||||
mov r1, %d // readMemAligned() injects the number of bytes it wants to read here
|
||||
add r1, 6 // + type and length + 'READ'
|
||||
bl 0x7AFC // malloc_hci_event_buffer (will automatically copy event code and length into the buffer)
|
||||
mov r4, r0 // save pointer to the buffer in r4
|
||||
|
||||
// append our custom header (the word 'READ') after the event code and event length field
|
||||
add r0, 2 // write after the length field
|
||||
ldr r1, =0x44414552 // 'READ'
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer. r0 now points to the beginning of our read data
|
||||
|
||||
// copy data to buffer
|
||||
ldr r1, =0x%x // readMemAligned() injects the read_address here. r1 will be used as src pointer in the loop
|
||||
mov r2, %d // readMemAligned() injects the number of dwords to read here. r2 will be the loop counter
|
||||
loop:
|
||||
ldr r3, [r1] // read 4 bytes from the read_address
|
||||
str r3, [r0] // store them inside the HCI buffer
|
||||
add r0, 4 // advance the buffer pointer
|
||||
add r1, 4 // advance the read_address
|
||||
subs r2, 1 // decrement the loop variable
|
||||
bne loop // branch if r2 is not zero yet
|
||||
|
||||
// send HCI buffer to the host
|
||||
mov r0, r4 // r4 still points to the beginning of the HCI buffer
|
||||
bl 0x398c1 // send_hci_event_without_free()
|
||||
|
||||
// free HCI buffer
|
||||
mov r0, r4
|
||||
bl 0x3FA36 // free_bloc_buffer_aligned
|
||||
|
||||
pop {r4, pc} // return
|
||||
# Assembler snippet for tracepoints
|
||||
TRACEPOINT_BODY_ASM_LOCATION = 0xD7A00
|
||||
TRACEPOINT_HOOKS_LOCATION = 0xD7B00
|
||||
TRACEPOINT_HOOK_SIZE = 28
|
||||
TRACEPOINT_HOOK_ASM = """
|
||||
push {r0-r12, lr} // save all registers on the stack (except sp and pc)
|
||||
ldr r6, =0x%x // addTracepoint() injects pc of original tracepoint here
|
||||
mov r7, %d // addTracepoint() injects the patchram slot of the hook patch
|
||||
bl 0x%x // addTracepoint() injects TRACEPOINT_BODY_ASM_LOCATION here
|
||||
pop {r0-r12, lr} // restore registers
|
||||
|
||||
// branch back to the original instruction
|
||||
b 0x%x // addTracepoint() injects the address of the tracepoint
|
||||
"""
|
||||
|
||||
# Assembler snippet for tracepoints
|
||||
TRACEPOINT_BODY_ASM_LOCATION = 0xd7a00
|
||||
TRACEPOINT_HOOKS_LOCATION = 0xd7b00
|
||||
TRACEPOINT_HOOK_SIZE = 28
|
||||
TRACEPOINT_HOOK_ASM = """
|
||||
push {r0-r12, lr} // save all registers on the stack (except sp and pc)
|
||||
ldr r6, =0x%x // addTracepoint() injects pc of original tracepoint here
|
||||
mov r7, %d // addTracepoint() injects the patchram slot of the hook patch
|
||||
bl 0x%x // addTracepoint() injects TRACEPOINT_BODY_ASM_LOCATION here
|
||||
pop {r0-r12, lr} // restore registers
|
||||
|
||||
// branch back to the original instruction
|
||||
b 0x%x // addTracepoint() injects the address of the tracepoint
|
||||
"""
|
||||
TRACEPOINT_RAM_DUMP_PKT_COUNT = 670 # <ramsize> / <packetsize> where packetsize is 244
|
||||
TRACEPOINT_BODY_ASM_SNIPPET = """
|
||||
mov r8, lr // save link register in r8
|
||||
|
||||
// save status register in r5
|
||||
mrs r5, cpsr
|
||||
|
||||
// malloc HCI event buffer
|
||||
mov r0, 0xff // event code is 0xff (vendor specific HCI Event)
|
||||
mov r1, 76 // buffer size: size of registers (68 bytes) + type and length + 'TRACE_'
|
||||
bl 0x7AFC // malloc_hci_event_buffer (will automatically copy event code and length into the buffer)
|
||||
mov r4, r0 // save pointer to the buffer in r4
|
||||
|
||||
// append our custom header (the word 'TRACE_') after the event code and event length field
|
||||
add r0, 2 // write after the length field
|
||||
ldr r1, =0x43415254 // 'TRAC'
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
ldr r1, =0x5f45 // 'E_'
|
||||
strh r1, [r0]
|
||||
add r0, 2 // advance the pointer. r0 now points to the start of the register values
|
||||
|
||||
// store pc
|
||||
str r6, [r0] // r6 still contains the address of the original pc
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store sp
|
||||
mov r1, 56 // 14 saved registers * 4
|
||||
add r1, sp
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store status register
|
||||
str r5, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store other registers
|
||||
mov r1, sp
|
||||
mov r2, 56
|
||||
bl 0x2e03c+1 // memcpy(dst, src, len)
|
||||
|
||||
// send HCI buffer to the host
|
||||
mov r0, r4 // r4 still points to the beginning of the HCI buffer
|
||||
bl 0x398c1 // send_hci_event_without_free()
|
||||
|
||||
// free HCI buffer
|
||||
mov r0, r4
|
||||
bl 0x3FA36 // free_bloc_buffer_aligned
|
||||
|
||||
mov r0, r7 // r7 still contains the patchram slot number
|
||||
bl 0x311AA // disable_patchram_slot(slot)
|
||||
|
||||
// restore status register
|
||||
msr cpsr_f, r5
|
||||
|
||||
// dump ram
|
||||
bl dump_ram
|
||||
|
||||
mov lr, r8 // restore lr from r8
|
||||
bx lr // return
|
||||
|
||||
|
||||
// function to dump the RAM as multiple HCI packets:
|
||||
dump_ram:
|
||||
push {r4-r6,lr}
|
||||
|
||||
// malloc HCI event buffer
|
||||
mov r0, 0xff // event code is 0xff (vendor specific HCI Event)
|
||||
mov r1, 252 // buffer size
|
||||
bl 0x7AFC // malloc_hci_event_buffer (will automatically copy event code and length into the buffer)
|
||||
mov r4, r0 // save pointer to the buffer in r4
|
||||
|
||||
// append our custom header (the word 'RAM___') after the event code and event length field
|
||||
add r0, 2 // write after the length field
|
||||
ldr r1, =0x5f4d4152 // 'RAM_'
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
ldr r1, =0x5f5f // '__'
|
||||
strh r1, [r0]
|
||||
add r0, 2 // advance the pointer. r0 now points to the start of the actual payload
|
||||
|
||||
mov r5, 0x200000 // start of ram
|
||||
ldr r6, =%d // number of ramdump packets to be sent
|
||||
|
||||
dump_ram_loop:
|
||||
// Set r0 to point to the beginning of the payload in the hci buffer
|
||||
mov r0, r4
|
||||
add r0, 8
|
||||
|
||||
// store current address
|
||||
str r5, [r0] // r5 contains the address in RAM which is send next
|
||||
TRACEPOINT_RAM_DUMP_PKT_COUNT = (
|
||||
670 # <ramsize> / <packetsize> where packetsize is 244
|
||||
)
|
||||
TRACEPOINT_BODY_ASM_SNIPPET = (
|
||||
"""
|
||||
mov r8, lr // save link register in r8
|
||||
|
||||
// save status register in r5
|
||||
mrs r5, cpsr
|
||||
|
||||
// malloc HCI event buffer
|
||||
mov r0, 0xff // event code is 0xff (vendor specific HCI Event)
|
||||
mov r1, 76 // buffer size: size of registers (68 bytes) + type and length + 'TRACE_'
|
||||
bl 0x7AFC // malloc_hci_event_buffer (will automatically copy event code and length into the buffer)
|
||||
mov r4, r0 // save pointer to the buffer in r4
|
||||
|
||||
// append our custom header (the word 'TRACE_') after the event code and event length field
|
||||
add r0, 2 // write after the length field
|
||||
ldr r1, =0x43415254 // 'TRAC'
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
ldr r1, =0x5f45 // 'E_'
|
||||
strh r1, [r0]
|
||||
add r0, 2 // advance the pointer. r0 now points to the start of the register values
|
||||
|
||||
// store pc
|
||||
str r6, [r0] // r6 still contains the address of the original pc
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// copy ram to hci buffer
|
||||
mov r1, r5
|
||||
mov r2, 244
|
||||
bl 0x2e03c // memcpy
|
||||
|
||||
|
||||
// store sp
|
||||
mov r1, 56 // 14 saved registers * 4
|
||||
add r1, sp
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store status register
|
||||
str r5, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// store other registers
|
||||
mov r1, sp
|
||||
mov r2, 56
|
||||
bl 0x2e03c+1 // memcpy(dst, src, len)
|
||||
|
||||
// send HCI buffer to the host
|
||||
mov r0, r4 // r4 still points to the beginning of the HCI buffer
|
||||
bl 0x398c1 // send_hci_event_without_free()
|
||||
|
||||
// delay loop; Workaround: without the delay, a lot of packets are not actually sent
|
||||
// through HCI.
|
||||
mov r0, 0x1000
|
||||
delay_loop:
|
||||
subs r0, 1
|
||||
bne delay_loop
|
||||
|
||||
// increment the RAM pointer; decrement the counter
|
||||
add r5, 244
|
||||
subs r6, 1
|
||||
|
||||
bne dump_ram_loop
|
||||
|
||||
// free HCI buffer
|
||||
mov r0, r4
|
||||
bl 0x3FA36 // free_bloc_buffer_aligned
|
||||
|
||||
pop {r4-r6,pc}
|
||||
""" % TRACEPOINT_RAM_DUMP_PKT_COUNT
|
||||
|
||||
// free HCI buffer
|
||||
mov r0, r4
|
||||
bl 0x3FA36 // free_bloc_buffer_aligned
|
||||
|
||||
mov r0, r7 // r7 still contains the patchram slot number
|
||||
bl 0x311AA // disable_patchram_slot(slot)
|
||||
|
||||
// restore status register
|
||||
msr cpsr_f, r5
|
||||
|
||||
// dump ram
|
||||
bl dump_ram
|
||||
|
||||
mov lr, r8 // restore lr from r8
|
||||
bx lr // return
|
||||
|
||||
|
||||
// function to dump the RAM as multiple HCI packets:
|
||||
dump_ram:
|
||||
push {r4-r6,lr}
|
||||
|
||||
// malloc HCI event buffer
|
||||
mov r0, 0xff // event code is 0xff (vendor specific HCI Event)
|
||||
mov r1, 252 // buffer size
|
||||
bl 0x7AFC // malloc_hci_event_buffer (will automatically copy event code and length into the buffer)
|
||||
mov r4, r0 // save pointer to the buffer in r4
|
||||
|
||||
// append our custom header (the word 'RAM___') after the event code and event length field
|
||||
add r0, 2 // write after the length field
|
||||
ldr r1, =0x5f4d4152 // 'RAM_'
|
||||
str r1, [r0]
|
||||
add r0, 4 // advance the pointer.
|
||||
ldr r1, =0x5f5f // '__'
|
||||
strh r1, [r0]
|
||||
add r0, 2 // advance the pointer. r0 now points to the start of the actual payload
|
||||
|
||||
mov r5, 0x200000 // start of ram
|
||||
ldr r6, =%d // number of ramdump packets to be sent
|
||||
|
||||
dump_ram_loop:
|
||||
// Set r0 to point to the beginning of the payload in the hci buffer
|
||||
mov r0, r4
|
||||
add r0, 8
|
||||
|
||||
// store current address
|
||||
str r5, [r0] // r5 contains the address in RAM which is send next
|
||||
add r0, 4 // advance the pointer.
|
||||
|
||||
// copy ram to hci buffer
|
||||
mov r1, r5
|
||||
mov r2, 244
|
||||
bl 0x2e03c // memcpy
|
||||
|
||||
// send HCI buffer to the host
|
||||
mov r0, r4 // r4 still points to the beginning of the HCI buffer
|
||||
bl 0x398c1 // send_hci_event_without_free()
|
||||
|
||||
// delay loop; Workaround: without the delay, a lot of packets are not actually sent
|
||||
// through HCI.
|
||||
mov r0, 0x1000
|
||||
delay_loop:
|
||||
subs r0, 1
|
||||
bne delay_loop
|
||||
|
||||
// increment the RAM pointer; decrement the counter
|
||||
add r5, 244
|
||||
subs r6, 1
|
||||
|
||||
bne dump_ram_loop
|
||||
|
||||
// free HCI buffer
|
||||
mov r0, r4
|
||||
bl 0x3FA36 // free_bloc_buffer_aligned
|
||||
|
||||
pop {r4-r6,pc}
|
||||
"""
|
||||
% TRACEPOINT_RAM_DUMP_PKT_COUNT
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python
|
||||
|
||||
# fw_0x6119.py
|
||||
#
|
||||
@@ -27,70 +27,67 @@
|
||||
|
||||
# Firmware Infos
|
||||
# This runs on Rasperry Pi 3+
|
||||
FW_NAME = "BCM4345C0"
|
||||
|
||||
# Device Infos
|
||||
DEVICE_NAME = 0x204954
|
||||
|
||||
# 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
|
||||
from __future__ import absolute_import
|
||||
from .fw import MemorySection, FirmwareDefinition
|
||||
|
||||
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)
|
||||
]
|
||||
class BCM4345C0(FirmwareDefinition):
|
||||
FW_NAME = "BCM4345C0"
|
||||
|
||||
# Connection Structure and Table
|
||||
CONNECTION_ARRAY_ADDRESS = 0x204ba8
|
||||
CONNECTION_MAX = 11
|
||||
CONNECTION_STRUCT_LENGTH = 0x150
|
||||
# Device Infos
|
||||
DEVICE_NAME = 0x204954
|
||||
|
||||
# Patchram
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310204
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0xd0000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 128
|
||||
PATCHRAM_ALIGNED = False
|
||||
# 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)
|
||||
]
|
||||
|
||||
# Heap
|
||||
BLOC_HEAD = 0x200490 # g_dynamic_memory_GeneralUsePools
|
||||
BLOC_NG = True # Next Generation Bloc Buffer
|
||||
# Connection Structure and Table
|
||||
CONNECTION_ARRAY_ADDRESS = 0x204BA8
|
||||
CONNECTION_MAX = 11
|
||||
CONNECTION_STRUCT_LENGTH = 0x150
|
||||
|
||||
# Snippet for sendLcpPacket()
|
||||
SENDLCP_CODE_BASE_ADDRESS = 0x21f000
|
||||
SENDLCP_ASM_CODE = """
|
||||
push {r4,lr}
|
||||
# Patchram
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310204
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0xD0000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 128
|
||||
PATCHRAM_ALIGNED = False
|
||||
|
||||
// we want to call lmulp_sendLcp(conn_index, input, length)
|
||||
# Heap
|
||||
BLOC_HEAD = 0x200490 # g_dynamic_memory_GeneralUsePools
|
||||
BLOC_NG = True # Next Generation Bloc Buffer
|
||||
|
||||
mov r0, %d // connection index, starts at 0
|
||||
ldr r1, =payload
|
||||
mov r2, %d // length
|
||||
bl 0x92062 // lmulp_sendLcp
|
||||
|
||||
pop {r4,pc} // go back
|
||||
|
||||
.align // The payload (LMP packet) must be 4-byte aligend (memcpy needs aligned addresses)
|
||||
payload: // Note: the payload will be appended here by the sendLmpPacket() function
|
||||
"""
|
||||
# Snippet for sendLcpPacket()
|
||||
SENDLCP_CODE_BASE_ADDRESS = 0x21F000
|
||||
SENDLCP_ASM_CODE = """
|
||||
push {r4,lr}
|
||||
|
||||
// we want to call lmulp_sendLcp(conn_index, input, length)
|
||||
|
||||
mov r0, %d // connection index, starts at 0
|
||||
ldr r1, =payload
|
||||
mov r2, %d // length
|
||||
bl 0x92062 // lmulp_sendLcp
|
||||
|
||||
pop {r4,pc} // go back
|
||||
|
||||
.align // The payload (LMP packet) must be 4-byte aligend (memcpy needs aligned addresses)
|
||||
payload: // Note: the payload will be appended here by the sendLmpPacket() function
|
||||
"""
|
||||
|
||||
@@ -20,24 +20,30 @@
|
||||
# out of or in connection with the Software or the use or other dealings in the
|
||||
# Software.
|
||||
|
||||
from .fw import MemorySection
|
||||
|
||||
# Firmware Infos
|
||||
# iPhone 6
|
||||
FW_NAME = "BCM4345B0"
|
||||
from .fw import MemorySection, FirmwareDefinition
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [ MemorySection(0x00000000, 0x000c07ff, True, False), # Internal ROM
|
||||
MemorySection(0x000d0000, 0x000dffff, False, True), # Internal Memory Patchram Contents
|
||||
MemorySection(0x00200400, 0x00201cff, False, True), # Internal Memory Cortex M3
|
||||
]
|
||||
class BCM4345B0(FirmwareDefinition):
|
||||
# Firmware Infos
|
||||
# iPhone 6
|
||||
FW_NAME = "BCM4345B0"
|
||||
|
||||
# Patchram
|
||||
#PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000 #TODO needs to be aligned read
|
||||
#PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310204
|
||||
#PATCHRAM_VALUE_TABLE_ADDRESS = 0xd0000
|
||||
#PATCHRAM_NUMBER_OF_SLOTS = 128
|
||||
#PATCHRAM_ALIGNED = True
|
||||
# only seems to work 4-byte aligned here ...
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [
|
||||
MemorySection(0x00000000, 0x000C07FF, True, False), # Internal ROM
|
||||
MemorySection(
|
||||
0x000D0000, 0x000DFFFF, False, True
|
||||
), # Internal Memory Patchram Contents
|
||||
MemorySection(0x00200400, 0x00201CFF, False, True), # Internal Memory Cortex M3
|
||||
]
|
||||
|
||||
# Patchram
|
||||
# PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000 #TODO needs to be aligned read
|
||||
# PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310204
|
||||
# PATCHRAM_VALUE_TABLE_ADDRESS = 0xd0000
|
||||
# PATCHRAM_NUMBER_OF_SLOTS = 128
|
||||
# PATCHRAM_ALIGNED = True
|
||||
# only seems to work 4-byte aligned here ...
|
||||
|
||||
@@ -20,24 +20,30 @@
|
||||
# out of or in connection with the Software or the use or other dealings in the
|
||||
# Software.
|
||||
|
||||
from .fw import MemorySection
|
||||
|
||||
# Firmware Infos
|
||||
# iPhone SE
|
||||
FW_NAME = "BCM4345C1"
|
||||
from __future__ import absolute_import
|
||||
from .fw import MemorySection, FirmwareDefinition
|
||||
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [ MemorySection(0x00000000, 0x000c07ff, True, False), # Internal ROM
|
||||
MemorySection(0x000d0000, 0x000dffff, False, True), # Internal Memory Patchram Contents
|
||||
MemorySection(0x00200400, 0x00201cff, False, True), # Internal Memory Cortex M3
|
||||
]
|
||||
class BCM4345C1(FirmwareDefinition):
|
||||
# Firmware Infos
|
||||
# iPhone SE
|
||||
FW_NAME = "BCM4345C1"
|
||||
|
||||
# Patchram
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310204
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0xd0000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 128
|
||||
PATCHRAM_ALIGNED = False
|
||||
# only seems to work 4-byte aligned here ...
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [
|
||||
MemorySection(0x00000000, 0x000C07FF, True, False), # Internal ROM
|
||||
MemorySection(
|
||||
0x000D0000, 0x000DFFFF, False, True
|
||||
), # Internal Memory Patchram Contents
|
||||
MemorySection(0x00200400, 0x00201CFF, False, True), # Internal Memory Cortex M3
|
||||
]
|
||||
|
||||
# Patchram
|
||||
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
|
||||
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310204
|
||||
PATCHRAM_VALUE_TABLE_ADDRESS = 0xD0000
|
||||
PATCHRAM_NUMBER_OF_SLOTS = 128
|
||||
PATCHRAM_ALIGNED = False
|
||||
# only seems to work 4-byte aligned here ...
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python
|
||||
|
||||
# fw_default.py
|
||||
#
|
||||
@@ -22,14 +22,18 @@
|
||||
# out of or in connection with the Software or the use or other dealings in the
|
||||
# Software.
|
||||
|
||||
from .fw import MemorySection
|
||||
from __future__ import absolute_import
|
||||
from .fw import MemorySection, FirmwareDefinition
|
||||
|
||||
# Firmware Infos
|
||||
FW_NAME = "default (unknown firmware)"
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [ MemorySection(0x0, 0x90000, True , False),
|
||||
MemorySection(0xd0000, 0xd8000, False, True ),
|
||||
MemorySection(0x200000, 0x228000, False, True )
|
||||
]
|
||||
class DefaultFirmware(FirmwareDefinition):
|
||||
# Firmware Infos
|
||||
FW_NAME = "default (unknown firmware)"
|
||||
|
||||
# Memory Sections
|
||||
# start, end, is_rom? is_ram?
|
||||
SECTIONS = [
|
||||
MemorySection(0x0, 0x90000, True, False),
|
||||
MemorySection(0xD0000, 0xD8000, False, True),
|
||||
MemorySection(0x200000, 0x228000, False, True),
|
||||
]
|
||||
|
||||
+869
-814
File diff suppressed because it is too large
Load Diff
+172
-82
@@ -1,42 +1,66 @@
|
||||
#!/usr/bin/env python2
|
||||
|
||||
import subprocess
|
||||
from __future__ import absolute_import
|
||||
|
||||
import socket
|
||||
import struct
|
||||
|
||||
from future import standard_library
|
||||
|
||||
standard_library.install_aliases()
|
||||
from builtins import str
|
||||
from builtins import zip
|
||||
from builtins import range
|
||||
import datetime
|
||||
from pwn import *
|
||||
from internalblue.utils.pwnlib_wrapper import log, context, p32, u16, p16, u32
|
||||
import fcntl
|
||||
from .core import InternalBlue
|
||||
import hci
|
||||
import Queue
|
||||
from . import hci
|
||||
import queue as queue2k
|
||||
import threading
|
||||
|
||||
try:
|
||||
from typing import List
|
||||
from typing import List, cast, TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from internalblue import Device
|
||||
|
||||
|
||||
except:
|
||||
pass
|
||||
|
||||
# from /usr/include/bluetooth/hci.h:
|
||||
#define HCIDEVUP _IOW('H', 201, int)
|
||||
#define HCIGETDEVLIST _IOR('H', 210, int)
|
||||
#define HCIGETDEVINFO _IOR('H', 211, int)
|
||||
# define HCIDEVUP _IOW('H', 201, int)
|
||||
# define HCIGETDEVLIST _IOR('H', 210, int)
|
||||
# define HCIGETDEVINFO _IOR('H', 211, int)
|
||||
|
||||
# ioctl numbers. see http://code.activestate.com/recipes/578225-linux-ioctl-numbers-in-python/
|
||||
def _IOR(type, nr, size):
|
||||
return 2 << 30 | type << 8 | nr << 0 | size << 16
|
||||
def _IOW(type, nr, size):
|
||||
return 1 << 30 | type << 8 | nr << 0 | size << 16
|
||||
def _IOR(_type, nr, size):
|
||||
return 2 << 30 | _type << 8 | nr << 0 | size << 16
|
||||
|
||||
HCIDEVUP = _IOW(ord('H'), 201, 4)
|
||||
HCIGETDEVLIST = _IOR(ord('H'), 210, 4)
|
||||
HCIGETDEVINFO = _IOR(ord('H'), 211, 4)
|
||||
|
||||
def _IOW(_type, nr, size):
|
||||
return 1 << 30 | _type << 8 | nr << 0 | size << 16
|
||||
|
||||
|
||||
HCIDEVUP = _IOW(ord("H"), 201, 4)
|
||||
HCIGETDEVLIST = _IOR(ord("H"), 210, 4)
|
||||
HCIGETDEVINFO = _IOR(ord("H"), 211, 4)
|
||||
|
||||
|
||||
class HCICore(InternalBlue):
|
||||
|
||||
def __init__(self, queue_size=1000, btsnooplog_filename='btsnoop.log', log_level='info', fix_binutils='True', data_directory=".", replay=False):
|
||||
super(HCICore, self).__init__(queue_size, btsnooplog_filename, log_level, fix_binutils, data_directory, replay)
|
||||
def __init__(
|
||||
self,
|
||||
queue_size=1000,
|
||||
btsnooplog_filename="btsnoop.log",
|
||||
log_level="info",
|
||||
fix_binutils="True",
|
||||
data_directory=".",
|
||||
replay=False,
|
||||
):
|
||||
super(HCICore, self).__init__(
|
||||
queue_size,
|
||||
btsnooplog_filename,
|
||||
log_level,
|
||||
fix_binutils,
|
||||
data_directory,
|
||||
replay,
|
||||
)
|
||||
self.btsnooplog_file_lock = threading.Lock()
|
||||
self.serial = False
|
||||
self.doublecheck = False
|
||||
@@ -59,43 +83,66 @@ class HCICore(InternalBlue):
|
||||
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?")
|
||||
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)
|
||||
arg = p32(16) # dl->dev_num = HCI_MAX_DEV which is 16 (little endian)
|
||||
arg += "\x00"*(8*16)
|
||||
arg = p32(16) # dl->dev_num = HCI_MAX_DEV which is 16 (little endian)
|
||||
arg += b"\x00" * (8 * 16)
|
||||
devices_raw = fcntl.ioctl(s.fileno(), HCIGETDEVLIST, arg)
|
||||
num_devices = u16(devices_raw[:2])
|
||||
log.debug("Found %d HCI devices via ioctl(HCIGETDEVLIST)!" % num_devices)
|
||||
|
||||
device_list = []
|
||||
for dev_nr in range(num_devices):
|
||||
dev_struct_start = 4 + 8*dev_nr
|
||||
dev_id = u16(devices_raw[dev_struct_start:dev_struct_start+2])
|
||||
dev_struct_start = 4 + 8 * dev_nr
|
||||
dev_id = u16(devices_raw[dev_struct_start : dev_struct_start + 2])
|
||||
# arg is struct hci_dev_info (/usr/include/bluetooth/hci.h)
|
||||
arg = p16(dev_id) # di->dev_id = <device_id>
|
||||
arg += "\x00"*20 # Enough space for name, bdaddr and flags
|
||||
dev_info_raw = fcntl.ioctl(s.fileno(), HCIGETDEVINFO, arg)
|
||||
dev_name = dev_info_raw[2:10].replace("\x00","")
|
||||
dev_bdaddr = ":".join(["%02X" % ord(x) for x in dev_info_raw[10:16][::-1]])
|
||||
dev_flags = u32(dev_info_raw[16:20])
|
||||
arg = p16(dev_id) # di->dev_id = <device_id>
|
||||
arg += b"\x00" * 20 # Enough space for name, bdaddr and flags
|
||||
dev_info_raw = bytearray(fcntl.ioctl(s.fileno(), HCIGETDEVINFO, arg))
|
||||
dev_name = dev_info_raw[2:10].replace(b"\x00", b"").decode()
|
||||
dev_bdaddr = ":".join(["%02X" % x for x in dev_info_raw[10:16][::-1]])
|
||||
dev_flags = u32(dev_info_raw[16:20])
|
||||
if dev_flags == 0:
|
||||
dev_flags_str = "DOWN"
|
||||
else:
|
||||
dev_flags_str = " ".join([name for flag,name in zip(
|
||||
bin(dev_flags)[2:][::-1],
|
||||
["UP", "INIT", "RUNNING", "PSCAN", "ISCAN", "AUTH",
|
||||
"ENCRYPT" , "INQUIRY" , "RAW" , "RESET"]) if flag=="1"])
|
||||
dev_flags_str = " ".join(
|
||||
[
|
||||
name
|
||||
for flag, name in zip(
|
||||
bin(dev_flags)[2:][::-1],
|
||||
[
|
||||
"UP",
|
||||
"INIT",
|
||||
"RUNNING",
|
||||
"PSCAN",
|
||||
"ISCAN",
|
||||
"AUTH",
|
||||
"ENCRYPT",
|
||||
"INQUIRY",
|
||||
"RAW",
|
||||
"RESET",
|
||||
],
|
||||
)
|
||||
if flag == "1"
|
||||
]
|
||||
)
|
||||
|
||||
device_list.append({"dev_id": dev_id,
|
||||
"dev_name": dev_name,
|
||||
"dev_bdaddr": dev_bdaddr,
|
||||
"dev_flags": dev_flags,
|
||||
"dev_flags_str": dev_flags_str})
|
||||
device_list.append(
|
||||
{
|
||||
"dev_id": dev_id,
|
||||
"dev_name": dev_name,
|
||||
"dev_bdaddr": dev_bdaddr,
|
||||
"dev_flags": dev_flags,
|
||||
"dev_flags_str": dev_flags_str,
|
||||
}
|
||||
)
|
||||
s.close()
|
||||
return device_list
|
||||
return cast("List[Device]", device_list)
|
||||
|
||||
def bringHciDeviceUp(self, dev_id):
|
||||
"""
|
||||
@@ -121,25 +168,36 @@ class HCICore(InternalBlue):
|
||||
log.warn("Error returned by ioctl: %s" % str(e))
|
||||
return False
|
||||
|
||||
|
||||
def device_list(self):
|
||||
"""
|
||||
Return a list of connected hci devices.
|
||||
"""
|
||||
if self.replay:
|
||||
return [(self, "hci_replay", 'hci: ReplaySocket')]
|
||||
return [(self, "hci_replay", "hci: ReplaySocket")]
|
||||
device_list = []
|
||||
for dev in self.getHciDeviceList():
|
||||
log.info("HCI device: %s [%s] flags=%d<%s>" %
|
||||
(dev["dev_name"], dev["dev_bdaddr"],
|
||||
dev["dev_flags"], dev["dev_flags_str"]))
|
||||
device_list.append((self, dev["dev_name"], 'hci: %s (%s) <%s>' %
|
||||
(dev["dev_bdaddr"], dev["dev_name"], dev["dev_flags_str"])))
|
||||
log.info(
|
||||
"HCI device: %s [%s] flags=%d<%s>"
|
||||
% (
|
||||
dev["dev_name"],
|
||||
dev["dev_bdaddr"],
|
||||
dev["dev_flags"],
|
||||
dev["dev_flags_str"],
|
||||
)
|
||||
)
|
||||
device_list.append(
|
||||
(
|
||||
self,
|
||||
dev["dev_name"],
|
||||
"hci: %s (%s) <%s>"
|
||||
% (dev["dev_bdaddr"], dev["dev_name"], dev["dev_flags_str"]),
|
||||
)
|
||||
)
|
||||
|
||||
if len(device_list) == 0:
|
||||
log.info('No connected HCI device found')
|
||||
log.info("No connected HCI device found")
|
||||
|
||||
return device_list
|
||||
return cast("List[Device]", device_list)
|
||||
|
||||
def local_connect(self):
|
||||
"""
|
||||
@@ -148,7 +206,7 @@ class HCICore(InternalBlue):
|
||||
if not self.interface:
|
||||
log.warn("No HCI identifier is set")
|
||||
return False
|
||||
|
||||
|
||||
if not self._setupSockets():
|
||||
log.critical("HCI socket could not be established!")
|
||||
return False
|
||||
@@ -169,8 +227,10 @@ class HCICore(InternalBlue):
|
||||
this field as 0x00E03AB44A676000.
|
||||
"""
|
||||
time_betw_0_and_2000_ad = int("0x00E03AB44A676000", 16)
|
||||
time_since_2000_epoch = time - datetime.datetime(2000,1,1)
|
||||
packed_time = time_since_2000_epoch + datetime.timedelta(microseconds=time_betw_0_and_2000_ad)
|
||||
time_since_2000_epoch = time - datetime.datetime(2000, 1, 1)
|
||||
packed_time = time_since_2000_epoch + datetime.timedelta(
|
||||
microseconds=time_betw_0_and_2000_ad
|
||||
)
|
||||
return int(packed_time.total_seconds() * 1000 * 1000)
|
||||
|
||||
def _recvThreadFunc(self):
|
||||
@@ -192,30 +252,49 @@ class HCICore(InternalBlue):
|
||||
# Read the record data
|
||||
try:
|
||||
record_data = self.s_snoop.recv(1024)
|
||||
record_data = bytearray(record_data)
|
||||
except socket.timeout:
|
||||
continue # this is ok. just try again without error
|
||||
continue # this is ok. just try again without error
|
||||
except Exception as e:
|
||||
log.critical("Lost device interface with exception {}, terminating receive thread...".format(e))
|
||||
log.critical(
|
||||
"Lost device interface with exception {}, terminating receive thread...".format(
|
||||
e
|
||||
)
|
||||
)
|
||||
self.exit_requested = True
|
||||
continue
|
||||
|
||||
# btsnoop record header data:
|
||||
btsnoop_orig_len = len(record_data)
|
||||
btsnoop_inc_len = len(record_data)
|
||||
btsnoop_flags = 0
|
||||
btsnoop_drops = 0
|
||||
btsnoop_time = datetime.datetime.now()
|
||||
btsnoop_inc_len = len(record_data)
|
||||
btsnoop_flags = 0
|
||||
btsnoop_drops = 0
|
||||
btsnoop_time = datetime.datetime.now()
|
||||
|
||||
# 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), btsnoop_orig_len, btsnoop_inc_len,
|
||||
btsnoop_flags, btsnoop_drops, btsnoop_time)
|
||||
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:
|
||||
btsnoop_record_hdr = struct.pack(">IIIIq", btsnoop_orig_len, btsnoop_inc_len, btsnoop_flags,
|
||||
btsnoop_drops, self._btsnoop_pack_time(btsnoop_time))
|
||||
btsnoop_record_hdr = struct.pack(
|
||||
">IIIIq",
|
||||
btsnoop_orig_len,
|
||||
btsnoop_inc_len,
|
||||
btsnoop_flags,
|
||||
btsnoop_drops,
|
||||
self._btsnoop_pack_time(btsnoop_time),
|
||||
)
|
||||
with self.btsnooplog_file_lock:
|
||||
self.btsnooplog_file.write(btsnoop_record_hdr)
|
||||
self.btsnooplog_file.write(record_data)
|
||||
@@ -224,11 +303,13 @@ class HCICore(InternalBlue):
|
||||
# Put the record into all queues of registeredHciRecvQueues if their
|
||||
# filter function matches.
|
||||
for queue, filter_function in self.registeredHciRecvQueues:
|
||||
if filter_function == None or filter_function(record):
|
||||
if filter_function is None or filter_function(record):
|
||||
try:
|
||||
queue.put(record, block=False)
|
||||
except Queue.Full:
|
||||
log.warn("recvThreadFunc: A recv queue is full. dropping packets..")
|
||||
except queue2k.Full:
|
||||
log.warn(
|
||||
"recvThreadFunc: A recv queue is full. dropping packets.."
|
||||
)
|
||||
|
||||
# Call all callback functions inside registeredHciCallbacks and pass the
|
||||
# record as argument.
|
||||
@@ -237,9 +318,9 @@ class HCICore(InternalBlue):
|
||||
|
||||
# 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.")
|
||||
# self.exit_requested = True
|
||||
# A stack dump has happend!
|
||||
# log.warn("recvThreadFunc: The controller send a stack dump.")
|
||||
# self.exit_requested = True
|
||||
|
||||
log.debug("Receive Thread terminated.")
|
||||
|
||||
@@ -250,7 +331,9 @@ class HCICore(InternalBlue):
|
||||
"""
|
||||
|
||||
# Check if hci device is in state "UP". If not, set it to "UP" (requires root)
|
||||
device = [dev for dev in self.getHciDeviceList() if dev["dev_name"] == self.interface]
|
||||
device = [
|
||||
dev for dev in self.getHciDeviceList() if dev["dev_name"] == self.interface
|
||||
]
|
||||
if len(device) == 0:
|
||||
log.warn("Device not found: " + self.interface)
|
||||
return False
|
||||
@@ -266,9 +349,11 @@ class HCICore(InternalBlue):
|
||||
# TODO unload btusb module and check error messages here to give the user some output if sth fails
|
||||
|
||||
# Connect to HCI socket
|
||||
self.s_snoop = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI)
|
||||
self.s_snoop.setsockopt(socket.SOL_HCI, socket.HCI_DATA_DIR,1)
|
||||
self.s_snoop.setsockopt(socket.SOL_HCI, socket.HCI_TIME_STAMP,1)
|
||||
self.s_snoop = socket.socket(
|
||||
socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI
|
||||
)
|
||||
self.s_snoop.setsockopt(socket.SOL_HCI, socket.HCI_DATA_DIR, 1)
|
||||
self.s_snoop.setsockopt(socket.SOL_HCI, socket.HCI_TIME_STAMP, 1)
|
||||
"""
|
||||
struct hci_filter {
|
||||
uint32_t type_mask; -> 4
|
||||
@@ -277,11 +362,14 @@ class HCICore(InternalBlue):
|
||||
};
|
||||
"""
|
||||
# TODO still seems to only forward incoming events?!
|
||||
self.s_snoop.setsockopt(socket.SOL_HCI, socket.HCI_FILTER,
|
||||
'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00') #type mask, event mask, event mask, opcode
|
||||
self.s_snoop.setsockopt(
|
||||
socket.SOL_HCI,
|
||||
socket.HCI_FILTER,
|
||||
b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00",
|
||||
) # type mask, event mask, event mask, opcode
|
||||
|
||||
interface_num = device["dev_id"]
|
||||
log.debug("Socket interface number: %s" % (interface_num))
|
||||
log.debug("Socket interface number: %s" % interface_num)
|
||||
self.s_snoop.bind((interface_num,))
|
||||
self.s_snoop.settimeout(2)
|
||||
log.debug("_setupSockets: Bound socket.")
|
||||
@@ -292,7 +380,9 @@ class HCICore(InternalBlue):
|
||||
# Write Header to btsnoop file (if file is still empty):
|
||||
if self.write_btsnooplog and self.btsnooplog_file.tell() == 0:
|
||||
# BT Snoop Header: btsnoop\x00, version: 1, data link type: 1002
|
||||
btsnoop_hdr = "btsnoop\x00" + p32(1,endian="big") + p32(1002,endian="big")
|
||||
btsnoop_hdr = (
|
||||
b"btsnoop\x00" + p32(1, endian="big") + p32(1002, endian="big")
|
||||
)
|
||||
with self.btsnooplog_file_lock:
|
||||
self.btsnooplog_file.write(btsnoop_hdr)
|
||||
self.btsnooplog_file.flush()
|
||||
@@ -304,9 +394,9 @@ class HCICore(InternalBlue):
|
||||
Close s_snoop and s_inject socket. (equal)
|
||||
"""
|
||||
|
||||
if (self.s_inject != None):
|
||||
if self.s_inject is not None:
|
||||
self.s_inject.close()
|
||||
self.s_inject = None
|
||||
self.s_snoop = None
|
||||
self.s_snoop = None
|
||||
|
||||
return True
|
||||
|
||||
+106
-59
@@ -1,26 +1,41 @@
|
||||
#!/usr/bin/env python2
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import struct
|
||||
|
||||
from future import standard_library
|
||||
|
||||
standard_library.install_aliases()
|
||||
from builtins import str
|
||||
import socket
|
||||
import Queue
|
||||
import hci
|
||||
import queue as queue2k
|
||||
from . import hci
|
||||
|
||||
from pwn import *
|
||||
from internalblue.utils.pwnlib_wrapper import log, context
|
||||
|
||||
from .usbmux import USBMux, MuxError
|
||||
from .core import InternalBlue
|
||||
|
||||
from core import InternalBlue
|
||||
|
||||
class iOSCore(InternalBlue):
|
||||
buffer: bytes
|
||||
|
||||
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 __init__(
|
||||
self,
|
||||
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="."
|
||||
)
|
||||
self.serial = False
|
||||
self.doublecheck = True
|
||||
self.buffer = ""
|
||||
self.buffer = b""
|
||||
self.mux = USBMux()
|
||||
|
||||
def device_list(self):
|
||||
"""
|
||||
@@ -34,9 +49,21 @@ class iOSCore(InternalBlue):
|
||||
log.warn("Already running. Call shutdown() first!")
|
||||
return []
|
||||
|
||||
# assume that a explicitly specified iPhone exists
|
||||
# because we need to call process for every device that is connected
|
||||
# and we don't really know how much are connected, we just call process
|
||||
# 8 times (which should be a reasonable limit for the amount of connected
|
||||
# iOS devices) with a very short timeout.
|
||||
for i in range(0, 8):
|
||||
self.mux.process(0.01)
|
||||
|
||||
self.devices = self.mux.devices
|
||||
if not self.devices:
|
||||
log.info("No iOS devices connected")
|
||||
|
||||
device_list = []
|
||||
device_list.append((self, "iPhone", "iPhone"))
|
||||
for dev in self.devices:
|
||||
dev_id = "iOS Device (" + dev.serial.decode("utf-8") + ")"
|
||||
device_list.append((self, dev, dev_id))
|
||||
|
||||
return device_list
|
||||
|
||||
@@ -49,16 +76,16 @@ class iOSCore(InternalBlue):
|
||||
the command or None if no response was received within the timeout.
|
||||
"""
|
||||
|
||||
queue = Queue.Queue(1)
|
||||
queue = queue2k.Queue(1)
|
||||
|
||||
try:
|
||||
self.sendQueue.put((h4type, data, queue, None), timeout=timeout)
|
||||
ret = queue.get(timeout=timeout)
|
||||
return ret
|
||||
except Queue.Empty:
|
||||
except queue2k.Empty:
|
||||
log.warn("sendH4: waiting for response timed out!")
|
||||
return None
|
||||
except Queue.Full:
|
||||
except queue2k.Full:
|
||||
log.warn("sendH4: send queue is full!")
|
||||
return None
|
||||
|
||||
@@ -69,72 +96,87 @@ class iOSCore(InternalBlue):
|
||||
"""
|
||||
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")
|
||||
log.info(
|
||||
"Check if\n \
|
||||
-> Bluetooth is deactivated in the iOS device's settings\n \
|
||||
-> internalblued is installed on the device\n \
|
||||
-> the device is connected to this computer via USB\n \
|
||||
-> usbmuxd is installed on this computer"
|
||||
)
|
||||
return False
|
||||
return True
|
||||
|
||||
def _setupSockets(self):
|
||||
"""
|
||||
Connect to the iOS bluetooth device over internalblue-ios-proxy
|
||||
Connect to the iOS Bluetooth device over usbmuxd and internalblued
|
||||
"""
|
||||
|
||||
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?")
|
||||
self.s_inject = self.mux.connect(self.interface, 1234)
|
||||
except MuxError:
|
||||
log.warn("Could not connect to iOS proxy. Is internalblued running on the connected device?")
|
||||
return False
|
||||
|
||||
self.s_inject.settimeout(0.5)
|
||||
|
||||
# with ios proxy the send and receive sockets are the same
|
||||
# with on iOS the send and receive sockets are the same
|
||||
self.s_snoop = self.s_inject
|
||||
|
||||
# empty the socket (can sometimes still hold data if the previous execution
|
||||
# of internalblue was cancelled or crashed)
|
||||
try:
|
||||
self.s_inject.recv(1024)
|
||||
except socket.error:
|
||||
pass
|
||||
|
||||
return True
|
||||
|
||||
def _getLatestH4Blob(self, new_data=""):
|
||||
data_out = ""
|
||||
def _getLatestH4Blob(self, new_data: bytes = b""):
|
||||
data_out: bytes = b""
|
||||
self.buffer += new_data
|
||||
if len(self.buffer) > 0:
|
||||
|
||||
|
||||
# if the buffer is too small, wait for more data
|
||||
if len(self.buffer) < 5:
|
||||
return (None, False)
|
||||
else:
|
||||
#log.info(self.buffer[0].encode("hex"))
|
||||
# for ACL data the length field is at offset 3
|
||||
if self.buffer[0] == '\x02':
|
||||
acl_len = struct.unpack_from("h", self.buffer[3:])[0]
|
||||
if self.buffer[0] == 0x2:
|
||||
acl_len = self.buffer[3]
|
||||
required_len = acl_len + 5
|
||||
# for HCI cmd data the length is at offset 3 (but just one byte)
|
||||
elif self.buffer[0] == '\x01':
|
||||
hci_len = struct.unpack_from("b", self.buffer[3:])[0]
|
||||
elif self.buffer[0] == 0x1:
|
||||
hci_len = self.buffer[3]
|
||||
required_len = hci_len + 4
|
||||
# for HCI event data the length is at offset 2 (one byte)
|
||||
elif self.buffer[0] == '\x04':
|
||||
hci_len = struct.unpack_from("b", self.buffer[2:])[0]
|
||||
elif self.buffer[0] == 0x4:
|
||||
hci_len = self.buffer[2]
|
||||
required_len = hci_len + 3
|
||||
# for BCM data the length should always be 64
|
||||
elif self.buffer[0] == '\x07':
|
||||
elif self.buffer[0] == 0x07:
|
||||
required_len = 64
|
||||
else:
|
||||
raise ValueError("Could not derive required_len from buffer")
|
||||
|
||||
# if we don't have all the data we need, we just wait for more
|
||||
if len(self.buffer) < required_len:
|
||||
#log.info("Not enough data, expected %d, got %d", required_len, len(self.buffer))
|
||||
return (None, False)
|
||||
# might be the case that we have too much
|
||||
elif len(self.buffer) > required_len:
|
||||
log.info("Got too much data, expected %d, got %d", required_len, len(self.buffer))
|
||||
surplus = len(self.buffer) - required_len
|
||||
new_buffer = self.buffer[required_len:len(self.buffer)]
|
||||
log.info(
|
||||
"Got too much data, expected %d, got %d",
|
||||
required_len,
|
||||
len(self.buffer),
|
||||
)
|
||||
surplus = len(self.buffer) - required_len
|
||||
new_buffer = self.buffer[required_len : len(self.buffer)]
|
||||
data_out = self.buffer[:-surplus]
|
||||
#log.info("new_buffer: %s, data_out: %s", new_buffer.encode("hex"), data_out.encode("hex"))
|
||||
self.buffer = new_buffer
|
||||
return (data_out, True)
|
||||
# sometimes we even have just the right amout of data
|
||||
else:
|
||||
#log.info("Got exactly the right amount of data")
|
||||
data_out = self.buffer
|
||||
self.buffer = ""
|
||||
self.buffer = b""
|
||||
return (data_out, False)
|
||||
else:
|
||||
return (None, False)
|
||||
@@ -154,27 +196,31 @@ class iOSCore(InternalBlue):
|
||||
try:
|
||||
received_data = self.s_snoop.recv(1024)
|
||||
except socket.timeout:
|
||||
continue # this is ok. just try again without error
|
||||
|
||||
# because the iOS socket is rather unreliable (blame the iOS proxy developer) we
|
||||
# need to do some length checks and get the H4/HCI data in the right format
|
||||
#log.info("H4 Data received")
|
||||
#log.info(received_data.encode('hex'))
|
||||
|
||||
continue # this is ok. just try again without error
|
||||
|
||||
log.debug("H4 Data: %s", received_data)
|
||||
|
||||
(record_data, is_more) = self._getLatestH4Blob(new_data=received_data)
|
||||
while record_data is not None:
|
||||
# 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)
|
||||
record = (hci.parse_hci_packet(record_data), 0, 0, 0, 0, 0)
|
||||
|
||||
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
|
||||
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..")
|
||||
except queue2k.Full:
|
||||
log.warn(
|
||||
"recvThreadFunc: A recv queue is full. dropping packets.."
|
||||
)
|
||||
|
||||
# Call all callback functions inside registeredHciCallbacks and pass the
|
||||
# record as argument.
|
||||
@@ -184,9 +230,11 @@ class iOSCore(InternalBlue):
|
||||
# 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..")
|
||||
log.warn(
|
||||
"recvThreadFunc: The controller send a stack dump. stopping.."
|
||||
)
|
||||
self.exit_requested = True
|
||||
|
||||
|
||||
(record_data, is_more) = self._getLatestH4Blob()
|
||||
if not is_more:
|
||||
break
|
||||
@@ -198,9 +246,8 @@ class iOSCore(InternalBlue):
|
||||
Close s_snoop and s_inject (which are the same)
|
||||
"""
|
||||
|
||||
if (self.s_inject != None):
|
||||
if self.s_inject is not None:
|
||||
self.s_inject.close()
|
||||
self.s_inject = None
|
||||
|
||||
return True
|
||||
|
||||
|
||||
+94
-33
@@ -1,31 +1,62 @@
|
||||
#!/usr/bin/env python2
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import random
|
||||
import time
|
||||
|
||||
from future import standard_library
|
||||
|
||||
standard_library.install_aliases()
|
||||
from builtins import str
|
||||
import socket
|
||||
import Queue
|
||||
import hci
|
||||
import queue as queue2k
|
||||
from . import hci
|
||||
|
||||
from pwn import *
|
||||
|
||||
from core import InternalBlue
|
||||
from internalblue.utils.pwnlib_wrapper import log, context, p8
|
||||
from .core import InternalBlue
|
||||
|
||||
import binascii
|
||||
import os
|
||||
|
||||
filepath = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
class macOSCore(InternalBlue):
|
||||
IOBE = None
|
||||
|
||||
def __init__(self, queue_size=1000, btsnooplog_filename='btsnoop.log', log_level='info', fix_binutils='True', data_directory=".", replay=False):
|
||||
super(macOSCore, self).__init__(queue_size, btsnooplog_filename, log_level, fix_binutils, data_directory=".", replay=replay)
|
||||
|
||||
class macOSCore(InternalBlue):
|
||||
def __init__(
|
||||
self,
|
||||
queue_size=1000,
|
||||
btsnooplog_filename="btsnoop.log",
|
||||
log_level="info",
|
||||
fix_binutils="True",
|
||||
data_directory=".",
|
||||
replay=False,
|
||||
):
|
||||
super(macOSCore, self).__init__(
|
||||
queue_size,
|
||||
btsnooplog_filename,
|
||||
log_level,
|
||||
fix_binutils,
|
||||
data_directory=".",
|
||||
replay=replay,
|
||||
)
|
||||
self.doublecheck = False
|
||||
self.iobe = None
|
||||
self.serial = None
|
||||
if not replay:
|
||||
import objc
|
||||
objc.initFrameworkWrapper("IOBluetoothExtended",
|
||||
frameworkIdentifier="de.tu-darmstadt.seemoo.IOBluetoothExtended",
|
||||
frameworkPath=objc.pathForFramework(
|
||||
filepath + "/../macos-framework/IOBluetoothExtended.framework"),
|
||||
globals=globals())
|
||||
import objc # type: ignore
|
||||
|
||||
objc.initFrameworkWrapper(
|
||||
"IOBluetoothExtended",
|
||||
frameworkIdentifier="de.tu-darmstadt.seemoo.IOBluetoothExtended",
|
||||
frameworkPath=objc.pathForFramework(
|
||||
filepath + "/../macos-framework/IOBluetoothExtended.framework"
|
||||
),
|
||||
globals=globals(),
|
||||
)
|
||||
self.hciport = -1
|
||||
|
||||
def device_list(self):
|
||||
@@ -52,14 +83,20 @@ class macOSCore(InternalBlue):
|
||||
return True
|
||||
|
||||
def _setupSockets(self):
|
||||
self.hciport = random.randint(60000, 65535-1)
|
||||
log.debug("_setupSockets: Selected random ports snoop=%d and inject=%d" % (self.hciport, self.hciport + 1))
|
||||
log.info("Wireshark configuration (on Loopback interface): udp.port == %d || udp.port == %d" % (self.hciport, self.hciport + 1))
|
||||
self.hciport = random.randint(60000, 65535 - 1)
|
||||
log.debug(
|
||||
"_setupSockets: Selected random ports snoop=%d and inject=%d"
|
||||
% (self.hciport, self.hciport + 1)
|
||||
)
|
||||
log.info(
|
||||
"Wireshark configuration (on Loopback interface): udp.port == %d || udp.port == %d"
|
||||
% (self.hciport, self.hciport + 1)
|
||||
)
|
||||
|
||||
# Create s_snoop socket
|
||||
self.s_snoop = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
self.s_snoop.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self.s_snoop.bind(('127.0.0.1', self.hciport))
|
||||
self.s_snoop.bind(("127.0.0.1", self.hciport))
|
||||
self.s_snoop.settimeout(0.5)
|
||||
self.s_snoop.setblocking(True)
|
||||
|
||||
@@ -71,7 +108,9 @@ class macOSCore(InternalBlue):
|
||||
# Create IOBluetoothExtended Object that listens for commands,
|
||||
# sends them to the Bluetooth chip and replies via UDP socket.
|
||||
if not self.replay:
|
||||
self.iobe = IOBE.alloc().initWith_and_(str(self.hciport+1), str(self.hciport))
|
||||
self.iobe = IOBE.alloc().initWith_and_(
|
||||
str(self.hciport + 1), str(self.hciport)
|
||||
)
|
||||
else:
|
||||
self.iobe = None
|
||||
time.sleep(0.5)
|
||||
@@ -89,22 +128,37 @@ class macOSCore(InternalBlue):
|
||||
# read record data
|
||||
try:
|
||||
data, addr = self.s_snoop.recvfrom(1024)
|
||||
record_data = data
|
||||
record_data = bytearray(data)
|
||||
except socket.timeout:
|
||||
continue # this is ok. just try again without error
|
||||
continue # this is ok. just try again without error
|
||||
|
||||
if not self.exit_requested:
|
||||
# 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?
|
||||
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
|
||||
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..>" + record_data)
|
||||
except queue.Full:
|
||||
log.warn(
|
||||
"recvThreadFunc: A recv queue is full. dropping packets..>"
|
||||
+ str(record_data)
|
||||
)
|
||||
|
||||
# Call all callback functions inside registeredHciCallbacks and pass the
|
||||
# record as argument.
|
||||
@@ -122,7 +176,7 @@ class macOSCore(InternalBlue):
|
||||
# Wait for 'send task' in send queue
|
||||
try:
|
||||
task = self.sendQueue.get(timeout=0.5)
|
||||
except Queue.Empty:
|
||||
except queue2k.Empty:
|
||||
continue
|
||||
|
||||
# Extract the components of the task
|
||||
@@ -133,10 +187,17 @@ class macOSCore(InternalBlue):
|
||||
|
||||
# Send command to the chip using IOBluetoothExtended framework
|
||||
h4type, data, queue, filter_function = task
|
||||
opcode = binascii.hexlify(data[1]) + binascii.hexlify(data[0])
|
||||
log.debug("Sending command: 0x" + binascii.hexlify(data) + ", opcode: " + opcode)
|
||||
data = bytearray(data)
|
||||
opcode = format(data[1], "02x") + format(data[0], "02x")
|
||||
|
||||
if not(h4type == 0x01 or h4type == 0x02):
|
||||
log.debug(
|
||||
"Sending command: 0x"
|
||||
+ "".join(format(x, "02x") for x in data)
|
||||
+ ", opcode: "
|
||||
+ opcode
|
||||
)
|
||||
|
||||
if not (h4type == 0x01 or h4type == 0x02):
|
||||
log.warn("H4 Type {0} not supported by macOS Core!".format(str(h4type)))
|
||||
if queue is not None:
|
||||
queue.put(None)
|
||||
@@ -144,11 +205,11 @@ class macOSCore(InternalBlue):
|
||||
|
||||
# if the caller expects a response: register a queue to receive the response
|
||||
if queue is not None and filter_function is not None:
|
||||
recvQueue = Queue.Queue(1)
|
||||
recvQueue = queue2k.Queue(1)
|
||||
self.registerHciRecvQueue(recvQueue, filter_function)
|
||||
|
||||
# Sending command
|
||||
self.s_inject.sendto(out, ('127.0.0.1', self.hciport+1))
|
||||
self.s_inject.sendto(out, ("127.0.0.1", self.hciport + 1))
|
||||
|
||||
# if the caller expects a response:
|
||||
# Wait for the HCI event response by polling the recvQueue
|
||||
@@ -156,8 +217,8 @@ class macOSCore(InternalBlue):
|
||||
try:
|
||||
record = recvQueue.get(timeout=10)
|
||||
hcipkt = record[0]
|
||||
data = hcipkt.data
|
||||
except Queue.Empty:
|
||||
data = hcipkt.data
|
||||
except queue2k.Empty:
|
||||
log.warn("_sendThreadFunc: No response from the firmware.")
|
||||
data = None
|
||||
self.unregisterHciRecvQueue(recvQueue)
|
||||
@@ -182,5 +243,5 @@ class macOSCore(InternalBlue):
|
||||
def shutdown(self):
|
||||
if not self.replay:
|
||||
self.iobe.shutdown()
|
||||
self.s_inject.sendto("", ('127.0.0.1', self.s_snoop.getsockname()[1]))
|
||||
self.s_inject.sendto(b"", ("127.0.0.1", self.s_snoop.getsockname()[1]))
|
||||
super(macOSCore, self).shutdown()
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
from pwnlib.util.packing import u32, u16, u8
|
||||
from builtins import object
|
||||
from internalblue.utils.pwnlib_wrapper import u32, u16, u8
|
||||
from typing import Any
|
||||
|
||||
|
||||
class ConnectionInformation:
|
||||
class ConnectionInformation(object):
|
||||
connection_handle = 0
|
||||
connection_number = 0
|
||||
master_of_connection = False
|
||||
remote_name_address = 0
|
||||
remote_address = None
|
||||
id = None
|
||||
id: bytearray
|
||||
public_rand = None
|
||||
extended_lmp_feat = None
|
||||
link_key = None
|
||||
@@ -15,8 +17,21 @@ class ConnectionInformation:
|
||||
effective_key_len = 0
|
||||
host_supported_feat = None
|
||||
|
||||
def __init__(self, connection_number, remote_address, remote_name_address, master_of_connection, connection_handle,
|
||||
public_rand, effective_key_len, link_key, tx_pwr_lvl_dBm, extended_lmp_feat, host_supported_feat, id):
|
||||
def __init__(
|
||||
self,
|
||||
connection_number,
|
||||
remote_address,
|
||||
remote_name_address,
|
||||
master_of_connection,
|
||||
connection_handle,
|
||||
public_rand,
|
||||
effective_key_len,
|
||||
link_key,
|
||||
tx_pwr_lvl_dBm,
|
||||
extended_lmp_feat,
|
||||
host_supported_feat,
|
||||
id,
|
||||
):
|
||||
self.connection_number = connection_number
|
||||
self.remote_address = remote_address
|
||||
self.remote_name_address = remote_name_address
|
||||
@@ -34,16 +49,20 @@ class ConnectionInformation:
|
||||
def from_connection_buffer(connection):
|
||||
|
||||
# Possible TODO: Convert this to a Katai Struct parser with a proper .ksy grammar.
|
||||
return ConnectionInformation(u32(connection[:4]), connection[0x28:0x2E][::-1],
|
||||
u32(connection[0x4C:0x50]),
|
||||
u32(connection[0x1C:0x20]) & 1 << 15 == 0,
|
||||
u16(connection[0x64:0x66]),
|
||||
connection[0x78:0x88],
|
||||
u8(connection[0xa7:0xa8]),
|
||||
connection[0x68:0x68 + u8(connection[0xa7:0xa8])],
|
||||
u8(connection[0x9c:0x9d]) - 127,
|
||||
connection[0x30:0x38], connection[0x38:0x40],
|
||||
connection[0x0c:0x0d])
|
||||
return ConnectionInformation(
|
||||
u32(connection[:4]),
|
||||
connection[0x28:0x2E][::-1],
|
||||
u32(connection[0x4C:0x50]),
|
||||
u32(connection[0x1C:0x20]) & 1 << 15 == 0,
|
||||
u16(connection[0x64:0x66]),
|
||||
connection[0x78:0x88],
|
||||
u8(connection[0xA7:0xA8]),
|
||||
connection[0x68 : 0x68 + u8(connection[0xA7:0xA8])],
|
||||
u8(connection[0x9C:0x9D]) - 127,
|
||||
connection[0x30:0x38],
|
||||
connection[0x38:0x40],
|
||||
connection[0x0C:0x0D],
|
||||
)
|
||||
# For some reason the following doesn't work because some attributes like link_key end up as one element tuples
|
||||
# connection_number = u32(connection[:4])
|
||||
# remote_address = connection[0x28:0x2E][::-1],
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
class QueueElement:
|
||||
from builtins import object
|
||||
from typing import Any
|
||||
|
||||
|
||||
class QueueElement(object):
|
||||
index = 0
|
||||
next_item = 0
|
||||
prev = 0
|
||||
capacity = 0
|
||||
name = ''
|
||||
name = ""
|
||||
queue_buf_start = 0
|
||||
available_items = 0
|
||||
item_size = 0
|
||||
@@ -15,8 +19,24 @@ class QueueElement:
|
||||
queue_buf_end = 0
|
||||
thread_waitlist = 0
|
||||
|
||||
def __init__(self, index, address, item_size, capacity, available_items, free_slots, queue_buf_start, queue_buf_end,
|
||||
next_item, next_free_slot, thread_waitlist, waitlist_length, next, prev, name):
|
||||
def __init__(
|
||||
self,
|
||||
index,
|
||||
address,
|
||||
item_size,
|
||||
capacity,
|
||||
available_items,
|
||||
free_slots,
|
||||
queue_buf_start,
|
||||
queue_buf_end,
|
||||
next_item,
|
||||
next_free_slot,
|
||||
thread_waitlist,
|
||||
waitlist_length,
|
||||
next,
|
||||
prev,
|
||||
name,
|
||||
):
|
||||
self.index = index
|
||||
self.next_item = next_item
|
||||
self.prev = prev
|
||||
@@ -35,4 +55,4 @@ class QueueElement:
|
||||
|
||||
def __getitem__(self, item):
|
||||
# type: (str) -> Any
|
||||
return vars(self)[item]
|
||||
return vars(self)[item]
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from __future__ import print_function
|
||||
from builtins import object
|
||||
import binascii
|
||||
import time
|
||||
|
||||
@@ -8,7 +10,7 @@ except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
class SocketRecvHook():
|
||||
class SocketRecvHook(object):
|
||||
def __init__(self, socket):
|
||||
# type: (socket.socket) -> None
|
||||
self.snoop_socket = socket
|
||||
@@ -43,12 +45,13 @@ class SocketRecvHook():
|
||||
self.recvfrom_hook(data, addr)
|
||||
return data, addr
|
||||
|
||||
class SocketInjectHook():
|
||||
|
||||
class SocketInjectHook(object):
|
||||
def __init__(self, socket, core):
|
||||
# type: (socket.socket, InternalBlue) -> None
|
||||
self.inject_socket = socket
|
||||
self.replace = False
|
||||
self.core = core # type: InternalBlue
|
||||
self.core = core # type: InternalBlue
|
||||
|
||||
def close(self):
|
||||
if self.inject_socket:
|
||||
@@ -103,7 +106,6 @@ class SocketInjectHook():
|
||||
|
||||
|
||||
class SocketDuplexHook(SocketInjectHook, SocketRecvHook):
|
||||
|
||||
def __init__(self, snoop_socket, inject_socket, core, **kwargs):
|
||||
# type: (socket.socket, socket.socket, InternalBlue, Dict[str, Any]) -> None
|
||||
self.snoop_socket = snoop_socket
|
||||
@@ -114,7 +116,7 @@ class SocketDuplexHook(SocketInjectHook, SocketRecvHook):
|
||||
pass
|
||||
|
||||
|
||||
class HookBase():
|
||||
class HookBase(object):
|
||||
def send_hook(self, data):
|
||||
raise NotImplementedError
|
||||
|
||||
@@ -123,10 +125,10 @@ class HookBase():
|
||||
|
||||
|
||||
class TraceToFileHook(SocketDuplexHook):
|
||||
def __init__(self, snoop_socket, inject_socket, core, filename='/tmp/bt_hci.log'):
|
||||
def __init__(self, snoop_socket, inject_socket, core, filename="/tmp/bt_hci.log"):
|
||||
# type: (socket.socket, socket.socket, InternalBlue, str) -> None
|
||||
SocketDuplexHook.__init__(self, snoop_socket, inject_socket, core)
|
||||
self.file = open(filename, 'a')
|
||||
self.file = open(filename, "a")
|
||||
self.replace = False
|
||||
self.log = []
|
||||
self.closed = False
|
||||
@@ -165,11 +167,11 @@ class TraceToFileHook(SocketDuplexHook):
|
||||
self.file.close()
|
||||
self.closed = True
|
||||
|
||||
|
||||
import socket
|
||||
|
||||
|
||||
class PrintTrace(SocketDuplexHook):
|
||||
|
||||
def send_hook(self, data, **kwargs):
|
||||
print("Sent: {}".format(binascii.hexlify(data)))
|
||||
|
||||
@@ -187,10 +189,13 @@ class PrintTrace(SocketDuplexHook):
|
||||
|
||||
|
||||
class ReplaySocket(SocketDuplexHook):
|
||||
def __init__(self, snoop_socket, inject_socket, core, filename='/tmp/bt_hci.log', debug=False):
|
||||
def __init__(
|
||||
self, snoop_socket, inject_socket, core, filename="/tmp/bt_hci.log", debug=False
|
||||
):
|
||||
SocketDuplexHook.__init__(self, snoop_socket, inject_socket, core)
|
||||
self.replace = True
|
||||
self.log = open(filename).readlines()
|
||||
with open(filename) as f:
|
||||
self.log = f.readlines()
|
||||
self.index = 0
|
||||
self.debug = debug
|
||||
if self.log[0].startswith("#"):
|
||||
@@ -224,8 +229,8 @@ class ReplaySocket(SocketDuplexHook):
|
||||
# Some recieves aren't handled yet, wait a bit so the recv thread takes care of them.
|
||||
time.sleep(0.2)
|
||||
direction, encoded_data = self.log[self.index].split(" ", 1)
|
||||
assert (direction == "TX")
|
||||
log_data = binascii.unhexlify(encoded_data.rstrip('\n'))
|
||||
assert direction == "TX"
|
||||
log_data = binascii.unhexlify(encoded_data.rstrip("\n"))
|
||||
assert data == log_data, "Got {}, expected {}".format(hex_data, encoded_data)
|
||||
self.index += 1
|
||||
ty, data = self.log[self.index].split(" ", 1)
|
||||
@@ -238,7 +243,7 @@ class ReplaySocket(SocketDuplexHook):
|
||||
direction, encoded_data = self.log[self.index].split(" ", 1)
|
||||
if direction == "RX":
|
||||
self.index += 1
|
||||
return binascii.unhexlify(encoded_data.rstrip('\n'))
|
||||
return binascii.unhexlify(encoded_data.rstrip("\n"))
|
||||
else:
|
||||
raise socket.timeout()
|
||||
|
||||
@@ -247,19 +252,20 @@ class ReplaySocket(SocketDuplexHook):
|
||||
direction, encoded_data = self.log[self.index].split(" ", 1)
|
||||
if direction == "RX":
|
||||
self.index += 1
|
||||
return binascii.unhexlify(encoded_data.rstrip('\n')), 1234
|
||||
return binascii.unhexlify(encoded_data.rstrip("\n")), 1234
|
||||
else:
|
||||
raise socket.timeout()
|
||||
|
||||
def getsockname(self):
|
||||
return (None, 0)
|
||||
|
||||
def close(self):
|
||||
assert self.index + 1 == len(self.log)
|
||||
|
||||
|
||||
from internalblue.core import InternalBlue
|
||||
|
||||
|
||||
|
||||
|
||||
def hook(core, socket_hook, **hookkwargs):
|
||||
# type: (Type[InternalBlue], Type[SocketDuplexHook], Any) -> None
|
||||
|
||||
@@ -285,19 +291,18 @@ def hook(core, socket_hook, **hookkwargs):
|
||||
else:
|
||||
self.s_inject.close()
|
||||
self.s_snoop.close()
|
||||
|
||||
return wrapped_teardown_sockets
|
||||
|
||||
core._teardownSockets = wrap_teardown_sockets(core._teardownSockets)
|
||||
|
||||
|
||||
def wrap_device_list(orig_func):
|
||||
def wrapped_device_list(self, *args, **kwargs):
|
||||
if not self.replay:
|
||||
return orig_func(self, *args, **kwargs)
|
||||
else:
|
||||
return [(self, "ReplayDevice", "ReplayDevice")]
|
||||
|
||||
return wrapped_device_list
|
||||
|
||||
|
||||
|
||||
core.device_list = wrap_device_list(core.device_list)
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
#!/usr/bin/env python2
|
||||
|
||||
import socket
|
||||
import Queue
|
||||
import hci
|
||||
|
||||
from pwn import *
|
||||
|
||||
from core import InternalBlue
|
||||
import binascii
|
||||
|
||||
filepath = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
try:
|
||||
import typing
|
||||
from typing import List, Tuple, Any
|
||||
from internalblue.core import InternalBlue
|
||||
|
||||
except:
|
||||
pass
|
||||
|
||||
class testCore(InternalBlue):
|
||||
def __init__(self, queue_size=1000, btsnooplog_filename='btsnoop.log', log_level='info', fix_binutils='True', data_directory="."):
|
||||
super(testCore, self).__init__(queue_size, btsnooplog_filename, log_level, fix_binutils, data_directory=".")
|
||||
file = open(filepath+'/../dummymemdump.bin', mode='rb')
|
||||
self.memory = file.read()
|
||||
file.close()
|
||||
self.doublecheck = False
|
||||
|
||||
def device_list(self):
|
||||
# type: () -> List[Tuple[InternalBlue,str,str]]
|
||||
"""
|
||||
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 = [(self, "Testchip", "Testchip")]
|
||||
|
||||
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):
|
||||
return True
|
||||
|
||||
def _setupSockets(self):
|
||||
self.hciport = random.randint(60000, 65535 - 1)
|
||||
log.debug("_setupSockets: Selected random ports snoop=%d and inject=%d" % (self.hciport, self.hciport + 1))
|
||||
log.info("Wireshark configuration (on Loopback interface): udp.port == %d || udp.port == %d" % (
|
||||
self.hciport, self.hciport + 1))
|
||||
|
||||
# Create s_snoop socket
|
||||
self.s_snoop = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.s_snoop.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self.s_snoop.bind(('127.0.0.1', self.hciport))
|
||||
self.s_snoop.settimeout(0.5)
|
||||
self.s_snoop.setblocking(True)
|
||||
|
||||
# Create s_inject
|
||||
self.s_inject = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.s_inject.settimeout(0.5)
|
||||
self.s_inject.setblocking(True)
|
||||
|
||||
time.sleep(1.5)
|
||||
|
||||
return True
|
||||
|
||||
def _recvThreadFunc(self):
|
||||
log.debug("Receive Thread terminated.")
|
||||
|
||||
def _sendThreadFunc(self):
|
||||
log.debug("Send Thread started.")
|
||||
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
|
||||
|
||||
# Wait for 'send task' in send queue
|
||||
try:
|
||||
task = self.sendQueue.get(timeout=0.5)
|
||||
except Queue.Empty:
|
||||
continue
|
||||
|
||||
# Extract the components of the task
|
||||
h4type, data, queue, filter_function = task
|
||||
|
||||
# Prepend UART TYPE and length.
|
||||
out = p8(h4type) + p8(len(data)) + data
|
||||
|
||||
# Send command to the chip using IOBluetoothExtended framework
|
||||
h4type, data, queue, filter_function = task
|
||||
opcode = binascii.hexlify(data[1]) + binascii.hexlify(data[0])
|
||||
log.debug("Sending command: 0x" + binascii.hexlify(data))
|
||||
|
||||
# if the caller expects a response: register a queue to receive the response
|
||||
if queue is not None and filter_function is not None:
|
||||
recvQueue = Queue.Queue(1)
|
||||
self.registerHciRecvQueue(recvQueue, filter_function)
|
||||
|
||||
# if the caller expects a response:
|
||||
# Wait for the HCI event response by polling the recvQueue
|
||||
|
||||
if queue is not None and filter_function is not None:
|
||||
# Return responses according to the opcode & operands
|
||||
if opcode == '1001':
|
||||
record_data = '040E0C0101100006b415060f000e22'.decode('hex')
|
||||
data = hci.parse_hci_packet(record_data).data
|
||||
elif opcode == 'fc4d':
|
||||
length = int(binascii.hexlify(data[7]), 16)
|
||||
address = int(binascii.hexlify(data[6]+data[5]+data[4]+data[3]), 16)
|
||||
data = '014dfc00'.decode('hex') + self.memory[address:address+length]
|
||||
elif opcode == 'fc4c':
|
||||
log.info(data.encode('hex'))
|
||||
length = int(binascii.hexlify(data[2]), 16)
|
||||
address = int(binascii.hexlify(data[6]+data[5]+data[4]+data[3]), 16)
|
||||
self.memory = self.memory[:address] + data[7:len(data)] + self.memory[address+length:]
|
||||
else:
|
||||
print(opcode)
|
||||
|
||||
queue.put(data)
|
||||
self.unregisterHciRecvQueue(recvQueue)
|
||||
|
||||
log.debug("Send Thread terminated.")
|
||||
|
||||
def enableBroadcomDiagnosticLogging(self, enable):
|
||||
return
|
||||
|
||||
def _teardownSockets(self):
|
||||
return True
|
||||
|
||||
def shutdown(self):
|
||||
return True
|
||||
@@ -0,0 +1,242 @@
|
||||
#
|
||||
# usbmux.py - usbmux client library for Python
|
||||
#
|
||||
# Copyright (C) 2009 Hector Martin "marcan" <hector@marcansoft.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 or version 3.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
import socket, struct, select, sys
|
||||
|
||||
try:
|
||||
import plistlib
|
||||
haveplist = True
|
||||
except:
|
||||
haveplist = False
|
||||
|
||||
class MuxError(Exception):
|
||||
pass
|
||||
|
||||
class MuxVersionError(MuxError):
|
||||
pass
|
||||
|
||||
class SafeStreamSocket:
|
||||
def __init__(self, address, family):
|
||||
self.sock = socket.socket(family, socket.SOCK_STREAM)
|
||||
self.sock.connect(address)
|
||||
def send(self, msg):
|
||||
totalsent = 0
|
||||
while totalsent < len(msg):
|
||||
sent = self.sock.send(msg[totalsent:])
|
||||
if sent == 0:
|
||||
raise MuxError("socket connection broken")
|
||||
totalsent = totalsent + sent
|
||||
def recv(self, size):
|
||||
msg = b''
|
||||
while len(msg) < size:
|
||||
chunk = self.sock.recv(size-len(msg))
|
||||
if chunk == b'':
|
||||
raise MuxError("socket connection broken")
|
||||
msg = msg + chunk
|
||||
return msg
|
||||
|
||||
class MuxDevice(object):
|
||||
def __init__(self, devid, usbprod, serial, location):
|
||||
self.devid = devid
|
||||
self.usbprod = usbprod
|
||||
self.serial = serial
|
||||
self.location = location
|
||||
def __str__(self):
|
||||
return "<MuxDevice: ID %d ProdID 0x%04x Serial '%s' Location 0x%x>"%(self.devid, self.usbprod, self.serial, self.location)
|
||||
|
||||
class BinaryProtocol(object):
|
||||
TYPE_RESULT = 1
|
||||
TYPE_CONNECT = 2
|
||||
TYPE_LISTEN = 3
|
||||
TYPE_DEVICE_ADD = 4
|
||||
TYPE_DEVICE_REMOVE = 5
|
||||
VERSION = 0
|
||||
def __init__(self, socket):
|
||||
self.socket = socket
|
||||
self.connected = False
|
||||
|
||||
def _pack(self, req, payload):
|
||||
if req == self.TYPE_CONNECT:
|
||||
return struct.pack("IH", payload['DeviceID'], payload['PortNumber']) + b'\x00\x00'
|
||||
elif req == self.TYPE_LISTEN:
|
||||
return b""
|
||||
else:
|
||||
raise ValueError("Invalid outgoing request type %d"%req)
|
||||
|
||||
def _unpack(self, resp, payload):
|
||||
if resp == self.TYPE_RESULT:
|
||||
return {'Number':struct.unpack("I", payload)[0]}
|
||||
elif resp == self.TYPE_DEVICE_ADD:
|
||||
devid, usbpid, serial, pad, location = struct.unpack("IH256sHI", payload)
|
||||
serial = serial.split(b'\00')[0]
|
||||
return {'DeviceID': devid, 'Properties': {'LocationID': location, 'SerialNumber': serial, 'ProductID': usbpid}}
|
||||
elif resp == self.TYPE_DEVICE_REMOVE:
|
||||
devid = struct.unpack("I", payload)[0]
|
||||
return {'DeviceID': devid}
|
||||
else:
|
||||
raise MuxError("Invalid incoming request type %d"%req)
|
||||
|
||||
def sendpacket(self, req, tag, payload={}):
|
||||
payload = self._pack(req, payload)
|
||||
if self.connected:
|
||||
raise MuxError("Mux is connected, cannot issue control packets")
|
||||
length = 16 + len(payload)
|
||||
data = struct.pack("IIII", length, self.VERSION, req, tag) + payload
|
||||
self.socket.send(data)
|
||||
def getpacket(self):
|
||||
if self.connected:
|
||||
raise MuxError("Mux is connected, cannot issue control packets")
|
||||
dlen = self.socket.recv(4)
|
||||
dlen = struct.unpack("I", dlen)[0]
|
||||
body = self.socket.recv(dlen - 4)
|
||||
version, resp, tag = struct.unpack("III",body[:0xc])
|
||||
if version != self.VERSION:
|
||||
raise MuxVersionError("Version mismatch: expected %d, got %d"%(self.VERSION,version))
|
||||
payload = self._unpack(resp, body[0xc:])
|
||||
return (resp, tag, payload)
|
||||
|
||||
class PlistProtocol(BinaryProtocol):
|
||||
TYPE_RESULT = "Result"
|
||||
TYPE_CONNECT = "Connect"
|
||||
TYPE_LISTEN = "Listen"
|
||||
TYPE_DEVICE_ADD = "Attached"
|
||||
TYPE_DEVICE_REMOVE = "Detached" #???
|
||||
TYPE_PLIST = 8
|
||||
VERSION = 1
|
||||
def __init__(self, socket):
|
||||
if not haveplist:
|
||||
raise Exception("You need the plistlib module")
|
||||
BinaryProtocol.__init__(self, socket)
|
||||
|
||||
def _pack(self, req, payload):
|
||||
return payload
|
||||
|
||||
def _unpack(self, resp, payload):
|
||||
return payload
|
||||
|
||||
def sendpacket(self, req, tag, payload={}):
|
||||
payload['ClientVersionString'] = 'usbmux.py by marcan'
|
||||
if isinstance(req, int):
|
||||
req = [self.TYPE_CONNECT, self.TYPE_LISTEN][req-2]
|
||||
payload['MessageType'] = req
|
||||
payload['ProgName'] = 'tcprelay'
|
||||
BinaryProtocol.sendpacket(self, self.TYPE_PLIST, tag, plistlib.dumps(payload))
|
||||
def getpacket(self):
|
||||
resp, tag, payload = BinaryProtocol.getpacket(self)
|
||||
if resp != self.TYPE_PLIST:
|
||||
raise MuxError("Received non-plist type %d"%resp)
|
||||
payload = plistlib.loads(payload)
|
||||
return payload['MessageType'], tag, payload
|
||||
|
||||
class MuxConnection(object):
|
||||
def __init__(self, socketpath, protoclass):
|
||||
self.socketpath = socketpath
|
||||
if sys.platform in ['win32', 'cygwin']:
|
||||
family = socket.AF_INET
|
||||
address = ('127.0.0.1', 27015)
|
||||
else:
|
||||
family = socket.AF_UNIX
|
||||
address = self.socketpath
|
||||
self.socket = SafeStreamSocket(address, family)
|
||||
self.proto = protoclass(self.socket)
|
||||
self.pkttag = 1
|
||||
self.devices = []
|
||||
|
||||
def _getreply(self):
|
||||
while True:
|
||||
resp, tag, data = self.proto.getpacket()
|
||||
if resp == self.proto.TYPE_RESULT:
|
||||
return tag, data
|
||||
else:
|
||||
raise MuxError("Invalid packet type received: %d"%resp)
|
||||
def _processpacket(self):
|
||||
resp, tag, data = self.proto.getpacket()
|
||||
if resp == self.proto.TYPE_DEVICE_ADD:
|
||||
# BinaryProtocol returns bytearrays, PlistProtocol returns strings
|
||||
# we convert this here and leave the protocols untouched
|
||||
if self.proto.VERSION == 1:
|
||||
# yeah, no recursion here, we know our dictionary
|
||||
for k in data['Properties']:
|
||||
v = data['Properties'][k]
|
||||
if isinstance(v, str):
|
||||
data['Properties'][k] = v.encode("utf-8")
|
||||
|
||||
self.devices.append(MuxDevice(data['DeviceID'], data['Properties']['ProductID'], data['Properties']['SerialNumber'], data['Properties']['LocationID']))
|
||||
elif resp == self.proto.TYPE_DEVICE_REMOVE:
|
||||
for dev in self.devices:
|
||||
if dev.devid == data['DeviceID']:
|
||||
self.devices.remove(dev)
|
||||
elif resp == self.proto.TYPE_RESULT:
|
||||
raise MuxError("Unexpected result: %d"%resp)
|
||||
else:
|
||||
raise MuxError("Invalid packet type received: %d"%resp)
|
||||
def _exchange(self, req, payload={}):
|
||||
mytag = self.pkttag
|
||||
self.pkttag += 1
|
||||
self.proto.sendpacket(req, mytag, payload)
|
||||
recvtag, data = self._getreply()
|
||||
if recvtag != mytag:
|
||||
raise MuxError("Reply tag mismatch: expected %d, got %d"%(mytag, recvtag))
|
||||
return data['Number']
|
||||
|
||||
def listen(self):
|
||||
ret = self._exchange(self.proto.TYPE_LISTEN)
|
||||
if ret != 0:
|
||||
raise MuxError("Listen failed: error %d"%ret)
|
||||
def process(self, timeout=None):
|
||||
if self.proto.connected:
|
||||
raise MuxError("Socket is connected, cannot process listener events")
|
||||
rlo, wlo, xlo = select.select([self.socket.sock], [], [self.socket.sock], timeout)
|
||||
if xlo:
|
||||
self.socket.sock.close()
|
||||
raise MuxError("Exception in listener socket")
|
||||
if rlo:
|
||||
self._processpacket()
|
||||
def connect(self, device, port):
|
||||
ret = self._exchange(self.proto.TYPE_CONNECT, {'DeviceID':device.devid, 'PortNumber':((port<<8) & 0xFF00) | (port>>8)})
|
||||
if ret != 0:
|
||||
raise MuxError("Connect failed: error %d"%ret)
|
||||
self.proto.connected = True
|
||||
return self.socket.sock
|
||||
def close(self):
|
||||
self.socket.sock.close()
|
||||
|
||||
class USBMux(object):
|
||||
def __init__(self, socketpath=None):
|
||||
if socketpath is None:
|
||||
if sys.platform == 'darwin':
|
||||
socketpath = "/var/run/usbmuxd"
|
||||
else:
|
||||
socketpath = "/var/run/usbmuxd"
|
||||
self.socketpath = socketpath
|
||||
self.listener = MuxConnection(socketpath, BinaryProtocol)
|
||||
try:
|
||||
self.listener.listen()
|
||||
self.version = 0
|
||||
self.protoclass = BinaryProtocol
|
||||
except MuxVersionError:
|
||||
self.listener = MuxConnection(socketpath, PlistProtocol)
|
||||
self.listener.listen()
|
||||
self.protoclass = PlistProtocol
|
||||
self.version = 1
|
||||
self.devices = self.listener.devices
|
||||
def process(self, timeout=None):
|
||||
self.listener.process(timeout)
|
||||
def connect(self, device, port):
|
||||
connector = MuxConnection(self.socketpath, self.protoclass)
|
||||
return connector.connect(device, port)
|
||||
@@ -0,0 +1,7 @@
|
||||
# from pwnlib.util.packing import *
|
||||
from typing import Union
|
||||
|
||||
|
||||
def bytes_to_hex(bytes):
|
||||
# type: (Union[bytes, bytearray]) -> str
|
||||
return "".join(format(x, "02x") for x in bytearray(bytes))
|
||||
@@ -0,0 +1,95 @@
|
||||
"""
|
||||
The following proxies various utilities from pwnlibs by explicitly importing them
|
||||
To replace a "from pwn import *" remove it and let your IDE highlight all missing methods (Hint: F2 in PyCharm goes to next error)
|
||||
import the missing (and only the missing!) methods from this module, e.g. with "from internalblue.utils import term, read, log, text, options"
|
||||
In some cases like "from pwn import socket" this just imports another module.
|
||||
Use an IPython shell to run "from pwn import *" and check where some method/module actually comes from and either import it directly or add it to this module
|
||||
"""
|
||||
|
||||
|
||||
# Imports that used to be imported via 'from pwn import *'
|
||||
import pwnlib
|
||||
from pwnlib import term
|
||||
from pwnlib.util import iters
|
||||
from pwnlib.util.misc import read
|
||||
from pwnlib.context import context
|
||||
|
||||
# TODO: Logging via pwnlib doesn't work yet, so for now it is still used via pwn
|
||||
# import pwnlib.log
|
||||
# pwnlib.log.install_default_handler()
|
||||
# log = pwnlib.log.getLogger('internalbue')
|
||||
|
||||
from pwn import log
|
||||
|
||||
|
||||
from pwnlib.term import text
|
||||
from pwnlib.ui import options, yesno
|
||||
from pwnlib.util.packing import flat
|
||||
from pwnlib.asm import disasm
|
||||
from pwnlib.util.fiddling import isprint, unbits, bits_str, bits
|
||||
|
||||
|
||||
"""
|
||||
The packers like u8 are generated in a fairly convoluted way that breaks IDE introspection.
|
||||
The following code remedies this by:
|
||||
- Explicitly defining a stub function with type annotations
|
||||
- Generating all the packers like pwnlibs would
|
||||
- Only if if the current module already has the name of the packer as an attribute (i.e. has a stub function defined) it will be replaced with the pwnlibs version
|
||||
|
||||
This means:
|
||||
- All import issues in the rest of the code are genuine as the imports are only available if an explicit stub function is added
|
||||
- The functions can be easily replaced by just implementing them and removing the for loop at the end
|
||||
|
||||
"""
|
||||
|
||||
# Imports needed for this hack
|
||||
from pwnlib.util.packing import ops, sizes, make_multi
|
||||
import sys
|
||||
|
||||
try:
|
||||
from typing import Union, Optional, Literal
|
||||
|
||||
endianess = Union[Literal["big"]]
|
||||
|
||||
except ImportError:
|
||||
pass
|
||||
mod = sys.modules[__name__]
|
||||
|
||||
|
||||
_DEFINES = ["u8", "p8", "u32", "u16", "p32"]
|
||||
|
||||
|
||||
def u8(data, endian=None):
|
||||
# type: (bytes, Optional[endianess]) -> int
|
||||
pass
|
||||
|
||||
|
||||
def p8(number, endian=None):
|
||||
# type: (int, Optional[endianess]) -> bytes
|
||||
pass
|
||||
|
||||
|
||||
def u16(data, endian=None):
|
||||
# type: (bytes, Optional[endianess]) -> int
|
||||
pass
|
||||
|
||||
|
||||
def p16(number, endian=None):
|
||||
# type: (int, Optional[endianess]) -> bytes
|
||||
pass
|
||||
|
||||
|
||||
def u32(data, endian=None):
|
||||
# type: (bytes, Optional[endianess]) -> int
|
||||
pass
|
||||
|
||||
|
||||
def p32(number, endian=None):
|
||||
# type: (int, Optional[endianess]) -> bytes
|
||||
pass
|
||||
|
||||
|
||||
for op, size in iters.product(ops, sizes):
|
||||
name, routine = make_multi(op, size)
|
||||
if hasattr(mod, name):
|
||||
setattr(mod, name, routine)
|
||||
@@ -0,0 +1,2 @@
|
||||
.theos
|
||||
.DS_STORE
|
||||
@@ -0,0 +1,14 @@
|
||||
include $(THEOS)/makefiles/common.mk
|
||||
|
||||
TOOL_NAME = internalblued
|
||||
|
||||
internalblued_FILES = main.m ios-proxy.m
|
||||
internalblued_CFLAGS = -fobjc-arc
|
||||
|
||||
include $(THEOS_MAKE_PATH)/tool.mk
|
||||
|
||||
SUBPROJECTS += internalbluedprefs
|
||||
include $(THEOS_MAKE_PATH)/aggregate.mk
|
||||
|
||||
after-internalblued-stage::
|
||||
$(ECHO_NOTHING)$(FAKEROOT) chown root:wheel $(THEOS_STAGING_DIR)/Library/LaunchDaemons/com.ttdennis.internalblued.plist$(ECHO_END)
|
||||
@@ -0,0 +1,25 @@
|
||||
# internalblued
|
||||
This project is a proxy that redirects the *iOS* 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.
|
||||
|
||||
A compiled version of `internalblued` can be found in [`packages/com.ttdennis.internalblued_0.0.1_iphoneos-arm.deb`](packages/com.ttdennis.internalblued_0.0.1_iphoneos-arm.deb).
|
||||
|
||||
## Installing
|
||||
1. Transfer the `.deb` file to your iOS device
|
||||
2. Run `dpkg -i your-deb-file.deb` to install `internalblued` on your device
|
||||
|
||||
## Running internalblued
|
||||
Once installed, `internalblued` runs as a `LaunchDaemon` and is ready to be used. By default it will listen to port 1234 (TCP) on localhost. If `usbmux` is installed, `internalblue` will be able to connect to the phone as the port is passed through `usbmuxd`.
|
||||
|
||||
During usage with `internalblue` Bluetooth has to be disabled in the phones Settings App.
|
||||
|
||||
In case the Bluetooth chip stops responding, Bluetooth has to be turned on and off again in the Settings App.
|
||||
|
||||
There is a Settings App pane for `internalblued` to turn off the daemon and adapt the listening port. However, this is usually not required. As long as `internalblue` is not connected to `internalblued`'s socket, Bluetooth can be used without any restrictions.
|
||||
|
||||
## Building internalblued
|
||||
1. Install [theos](https://github.com/theos/theos)
|
||||
2. Run `make`
|
||||
3. A `.deb` file should be in the `packages` folder now
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#import <Preferences/PSListController.h>
|
||||
|
||||
@interface IBDRootListController : PSListController
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,80 @@
|
||||
#include <xpc/xpc.h>
|
||||
|
||||
#include "IBDRootListController.h"
|
||||
#import <Preferences/PSListController.h>
|
||||
#import <Preferences/PSViewController.h>
|
||||
#import <Preferences/PSSpecifier.h>
|
||||
#include "../xpc_protocol.h"
|
||||
|
||||
#define PREF_FILE @"/var/mobile/Library/Preferences/com.ttdennis.internalblue-prefs.plist"
|
||||
|
||||
@implementation IBDRootListController
|
||||
|
||||
xpc_connection_t get_connection() {
|
||||
xpc_connection_t connection = xpc_connection_create_mach_service(
|
||||
"com.ttdennis.internalblued", NULL, 0);
|
||||
// we don't expect any responses anyway
|
||||
xpc_connection_set_event_handler(connection, ^(xpc_object_t some_object) { });
|
||||
xpc_connection_resume(connection);
|
||||
|
||||
NSLog(@"connection %@", connection);
|
||||
return connection;
|
||||
}
|
||||
|
||||
-(bool) should_stop {
|
||||
for (PSSpecifier *spec in [self specifiers]) {
|
||||
if ([[spec identifier] isEqualToString:@"enabled"]) {
|
||||
bool isEnabled = [[self readPreferenceValue:spec] boolValue];
|
||||
NSLog(@"Toggle is: %d", isEnabled);
|
||||
return !isEnabled;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
- (void)toggle:(NSNotification *)notification {
|
||||
// close the number keyboard
|
||||
[self.view endEditing:YES];
|
||||
// force write the preference file so that the daemon will pick up the correct value
|
||||
CFPreferencesSynchronize(CFSTR("com.ttdennis.internalblue-prefs"), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
|
||||
|
||||
sleep(1);
|
||||
|
||||
xpc_connection_t connection = get_connection();
|
||||
xpc_object_t object = xpc_dictionary_create(NULL, NULL, 0);
|
||||
|
||||
if ([self should_stop]){
|
||||
xpc_dictionary_set_uint64(object, "message", CMD_STOP_PROXY);
|
||||
} else {
|
||||
xpc_dictionary_set_uint64(object, "message", CMD_START_PROXY);
|
||||
}
|
||||
|
||||
xpc_connection_send_message(connection, object);
|
||||
}
|
||||
|
||||
void notify_ns() {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"com.ttdennis.internalblue/toggle" object:nil];
|
||||
}
|
||||
|
||||
|
||||
- (id) init {
|
||||
self = [super init];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(toggle:)
|
||||
name:@"com.ttdennis.internalblue/toggle"
|
||||
object:nil];
|
||||
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), (__bridge const void *)(self), (CFNotificationCallback)notify_ns,
|
||||
CFSTR("com.ttdennis.internalblue/toggle"), NULL, 0);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSArray *)specifiers {
|
||||
if (!_specifiers) {
|
||||
_specifiers = [self loadSpecifiersFromPlistName:@"Root" target:self];
|
||||
}
|
||||
|
||||
return _specifiers;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,15 @@
|
||||
include $(THEOS)/makefiles/common.mk
|
||||
|
||||
BUNDLE_NAME = internalbluedprefs
|
||||
|
||||
internalbluedprefs_FILES = IBDRootListController.m
|
||||
internalbluedprefs_INSTALL_PATH = /Library/PreferenceBundles
|
||||
internalbluedprefs_FRAMEWORKS = UIKit
|
||||
internalbluedprefs_PRIVATE_FRAMEWORKS = Preferences
|
||||
internalbluedprefs_CFLAGS = -fobjc-arc
|
||||
|
||||
include $(THEOS_MAKE_PATH)/bundle.mk
|
||||
|
||||
internal-stage::
|
||||
$(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences$(ECHO_END)
|
||||
$(ECHO_NOTHING)cp entry.plist $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences/internalbluedprefs.plist$(ECHO_END)
|
||||
@@ -0,0 +1,24 @@
|
||||
<?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>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>internalbluedprefs</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.ttdennis.internalblue-prefs</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>IBDRootListController</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,55 @@
|
||||
<?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>items</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>cell</key>
|
||||
<string>PSGroupCell</string>
|
||||
<key>footerText</key>
|
||||
<string>Enable the InternalBlue proxy. For a reliable performance Bluetooth must be disabled in the settings.</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>cell</key>
|
||||
<string>PSSwitchCell</string>
|
||||
<key>default</key>
|
||||
<false/>
|
||||
<key>defaults</key>
|
||||
<string>com.ttdennis.internalblue-prefs</string>
|
||||
<key>key</key>
|
||||
<string>isEnabled</string>
|
||||
<key>label</key>
|
||||
<string>Enable InternalBlue Proxy</string>
|
||||
<key>PostNotification</key>
|
||||
<string>com.ttdennis.internalblue/toggle</string>
|
||||
<key>id</key>
|
||||
<string>enabled</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>cell</key>
|
||||
<string>PSGroupCell</string>
|
||||
<key>footerText</key>
|
||||
<string>This sets the port the proxy is listening on. InternalBlue assumes 1234. Changing this port requires adapting InternalBlue and restarting the proxy.</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>cell</key>
|
||||
<string>PSEditTextCell</string>
|
||||
<key>default</key>
|
||||
<string>1234</string>
|
||||
<key>defaults</key>
|
||||
<string>com.ttdennis.internalblue-prefs</string>
|
||||
<key>key</key>
|
||||
<string>port</string>
|
||||
<key>label</key>
|
||||
<string>Proxy Port</string>
|
||||
<key>isNumeric</key>
|
||||
<true/>
|
||||
<key>id</key>
|
||||
<string>port</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>title</key>
|
||||
<string>InternalBlue Proxy Settings</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?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>entry</key>
|
||||
<dict>
|
||||
<key>bundle</key>
|
||||
<string>internalbluedprefs</string>
|
||||
<key>cell</key>
|
||||
<string>PSLinkCell</string>
|
||||
<key>detail</key>
|
||||
<string>IBDRootListController</string>
|
||||
<key>icon</key>
|
||||
<string>icon.png</string>
|
||||
<key>isController</key>
|
||||
<true/>
|
||||
<key>label</key>
|
||||
<string>InternalBlue Proxy</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// ios-proxy.h
|
||||
// ios-proxy
|
||||
//
|
||||
// Copyright © 2019 ttdennis. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef ios_proxy_h
|
||||
#define ios_proxy_h
|
||||
|
||||
#include <stdio.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 connect_bt_device();
|
||||
int create_server(int port);
|
||||
int wait_for_connection(int server_fd);
|
||||
void proxy_bt_socket(int client, int bt);
|
||||
|
||||
#endif /* ios_proxy_h */
|
||||
+24
-92
@@ -1,12 +1,11 @@
|
||||
//
|
||||
// internalblue-ios-proxy.c
|
||||
// internalblue-ios-proxy
|
||||
// ios-proxy.m
|
||||
// ios-proxy
|
||||
//
|
||||
// Created by ttdennis on 03.05.19.
|
||||
// Copyright © 2019 ttdennis. All rights reserved.
|
||||
//
|
||||
|
||||
#include "internalblue-ios-proxy.h"
|
||||
#include "ios-proxy.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
@@ -24,23 +23,6 @@
|
||||
#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;
|
||||
@@ -50,7 +32,7 @@ int connect_bt_device() {
|
||||
struct termios term;
|
||||
|
||||
if (socket_fd == 0) {
|
||||
printf("[!] Unable to get Bluetooth socket\n");
|
||||
NSLog(@"[!] Unable to get Bluetooth socket\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -58,8 +40,8 @@ int connect_bt_device() {
|
||||
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));
|
||||
NSLog(@"[!] ioctl(CTLIOCGINFO) = %d - errno: %d\n", error, errno);
|
||||
NSLog(@"[!] error: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -67,27 +49,27 @@ int connect_bt_device() {
|
||||
*(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));
|
||||
NSLog(@"[!] connect() = %d - errno: %d\n", ret, errno);
|
||||
NSLog(@"[!] error: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("[*] Connected to Bluetooth chip H4 socket\n");
|
||||
NSLog(@"[*] Connected to Bluetooth chip H4 socket\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));
|
||||
NSLog(@"[!] getsockopt(TIOCGETA) = %d - errno: %d\n", ret, errno);
|
||||
NSLog(@"[!] 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));
|
||||
NSLog(@"[!] cfsetspeed() = %d - errno: %d\n", ret, errno);
|
||||
NSLog(@"[!] error: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -95,8 +77,8 @@ int connect_bt_device() {
|
||||
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));
|
||||
NSLog(@"[!] setsockopt() = %d - errno: %d\n", ret, errno);
|
||||
NSLog(@"[!] error: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -114,28 +96,28 @@ int create_server(int port) {
|
||||
|
||||
server_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (server_fd < 0) {
|
||||
printf("[!] Unable to create server socket\n");
|
||||
NSLog(@"[!] 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_addr.s_addr = inet_addr("127.0.0.1");
|
||||
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");
|
||||
NSLog(@"[!] Error binding socket\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(server_fd, 5) < 0) {
|
||||
printf("[!] Failed listening on port %d, Error: %s\n", port, strerror(errno));
|
||||
NSLog(@"[!] Failed listening on port %d, Error: %s\n", port, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("[*] Listening on port %d\n", port);
|
||||
NSLog(@"[*] Listening on port %d\n", port);
|
||||
|
||||
return server_fd;
|
||||
}
|
||||
@@ -149,7 +131,7 @@ int wait_for_connection(int server_fd) {
|
||||
client_fd = accept(server_fd, (struct sockaddr *)&client, (socklen_t *)&len);
|
||||
|
||||
if (client_fd < 0) {
|
||||
printf("[!] Accepting connection failed\n");
|
||||
NSLog(@"[!] Accepting connection failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -184,7 +166,7 @@ void proxy_bt_socket(int client, int bt) {
|
||||
write(bt, client_buf, n);
|
||||
} else {
|
||||
close(client);
|
||||
printf("[!] Client read failed\n");
|
||||
NSLog(@"[!] Client read failed\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -195,12 +177,12 @@ void proxy_bt_socket(int client, int bt) {
|
||||
write(client, bt_buf, n);
|
||||
} else {
|
||||
close(client);
|
||||
printf("[!] H4 socket read failed\n");
|
||||
NSLog(@"[!] H4 socket read failed\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (x < 0 && errno != EINTR){
|
||||
printf("[!] Select failed with %s\n", strerror(errno));
|
||||
NSLog(@"[!] Select failed with %s\n", strerror(errno));
|
||||
close(client);
|
||||
return;
|
||||
}
|
||||
@@ -208,54 +190,4 @@ void proxy_bt_socket(int client, int bt) {
|
||||
}
|
||||
}
|
||||
|
||||
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]);
|
||||
|
||||
while (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 proxy server\n");
|
||||
return -1;
|
||||
}
|
||||
printf("[*] Created proxy server\n");
|
||||
|
||||
signal(SIGINT, __exit);
|
||||
|
||||
printf("[*] Waiting for remote connection\n");
|
||||
client_fd = wait_for_connection(server_fd);
|
||||
if (client_fd < 0)
|
||||
printf("[!] Unable to connect remote device to proxy\n");
|
||||
|
||||
// currently only one connection is supported
|
||||
proxy_bt_socket(client_fd, bt_fd);
|
||||
close(client_fd);
|
||||
close(server_fd);
|
||||
close(bt_fd);
|
||||
close(btwake_fd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
Package: com.ttdennis.internalblued
|
||||
Name: internalblued
|
||||
Depends:
|
||||
Version: 0.0.1
|
||||
Architecture: iphoneos-arm
|
||||
Description: InternalBlue iOS Proxy Daemon
|
||||
Maintainer: Dennis Heinze
|
||||
Author: Dennis Heinze
|
||||
Section: System
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
launchctl load /Library/LaunchDaemons/com.ttdennis.internalblued.plist
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
launchctl unload /Library/LaunchDaemons/com.ttdennis.internalblued.plist 2>&1 > /dev/null
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
launchctl unload /Library/LaunchDaemons/com.ttdennis.internalblued.plist
|
||||
@@ -0,0 +1,23 @@
|
||||
<?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>Label</key>
|
||||
<string>com.ttdennis.internalblued</string>
|
||||
<key>MachServices</key>
|
||||
<dict>
|
||||
<key>com.ttdennis.internalblued</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/bin/internalblued</string>
|
||||
</array>
|
||||
<key>UserName</key>
|
||||
<string>mobile</string>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,179 @@
|
||||
#include <xpc/xpc.h>
|
||||
#include <pthread.h>
|
||||
#include <spawn.h>
|
||||
|
||||
#include "ios-proxy.h"
|
||||
#include "xpc_protocol.h"
|
||||
|
||||
#define PREF_FILE @"/var/mobile/Library/Preferences/com.ttdennis.internalblue-prefs.plist"
|
||||
|
||||
int manual_port = -1;
|
||||
bool proxy_is_running = false;
|
||||
pthread_t proxy_thread;
|
||||
|
||||
int get_proxy_port() {
|
||||
int port = 0;
|
||||
if (manual_port != -1) {
|
||||
return manual_port;
|
||||
}
|
||||
|
||||
NSMutableDictionary *prefs = [[NSMutableDictionary alloc] initWithContentsOfFile: PREF_FILE];
|
||||
if (prefs) {
|
||||
port = [[prefs objectForKey:@"port"] intValue];
|
||||
} else {
|
||||
NSLog(@"Preference file not found, chosing standard port 1234");
|
||||
}
|
||||
|
||||
if (port == 0)
|
||||
port = 1234;
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
bool proxy_pref_on() {
|
||||
bool res = true;
|
||||
NSMutableDictionary *prefs = [[NSMutableDictionary alloc] initWithContentsOfFile: PREF_FILE];
|
||||
if (prefs) {
|
||||
id obj = [prefs objectForKey:@"isEnabled"];
|
||||
// no object exists, this means the user never toggled the switch
|
||||
// which means the server is on (because it is by default), and we
|
||||
// should stop -> return true
|
||||
if (!obj) {
|
||||
return true;
|
||||
}
|
||||
res = [obj boolValue];
|
||||
} else {
|
||||
NSLog(@"Preference file not found, chosing standard value true");
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void *proxy_fn() {
|
||||
int port = get_proxy_port();
|
||||
int server_fd, client_fd, btwake_fd, bt_fd;
|
||||
|
||||
while (proxy_is_running) {
|
||||
server_fd = create_server(port);
|
||||
if (server_fd < 0) {
|
||||
NSLog(@"Unable to create proxy server: %s", strerror(errno));
|
||||
break;
|
||||
}
|
||||
NSLog(@"Created proxy server, waiting for connection");
|
||||
|
||||
client_fd = wait_for_connection(server_fd);
|
||||
if (client_fd < 0) {
|
||||
NSLog(@"Unable to establish connection: %s", strerror(errno));
|
||||
close(server_fd);
|
||||
}
|
||||
|
||||
// now that a client connection from internalblue is established
|
||||
// we can claim the BT device
|
||||
btwake_fd = open("/dev/btwake", O_RDONLY);
|
||||
bt_fd = connect_bt_device();
|
||||
if (bt_fd < 0) {
|
||||
NSLog(@"Unable to connect to Bluetooth device: %s", strerror(errno));
|
||||
close(server_fd);
|
||||
close(client_fd);
|
||||
close(btwake_fd);
|
||||
}
|
||||
|
||||
// currently only one connection is supported
|
||||
proxy_bt_socket(client_fd, bt_fd);
|
||||
|
||||
close(client_fd);
|
||||
close(server_fd);
|
||||
close(bt_fd);
|
||||
close(btwake_fd);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void start_proxy() {
|
||||
if (proxy_is_running) {
|
||||
NSLog(@"Cannot start proxy, it is already running");
|
||||
} else {
|
||||
pthread_create(&proxy_thread, NULL, &proxy_fn, NULL);
|
||||
proxy_is_running = true;
|
||||
}
|
||||
}
|
||||
|
||||
void stop_proxy() {
|
||||
if (proxy_is_running) {
|
||||
pthread_kill(proxy_thread, SIGKILL);
|
||||
proxy_is_running = false;
|
||||
} else {
|
||||
NSLog(@"Cannot stop proxy, it is not running");
|
||||
}
|
||||
}
|
||||
|
||||
void _ib_xpc_recv_handler(xpc_object_t object) {
|
||||
uint64_t opcode = xpc_dictionary_get_uint64(object, "message");
|
||||
if ((void*)opcode == NULL) {
|
||||
NSLog(@"Received invalid message.");
|
||||
return;
|
||||
}
|
||||
NSLog(@"Got message with opcode %llu", opcode);
|
||||
|
||||
switch(opcode) {
|
||||
case CMD_START_PROXY:
|
||||
start_proxy();
|
||||
break;
|
||||
case CMD_STOP_PROXY:
|
||||
stop_proxy();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[], char *envp[]) {
|
||||
@autoreleasepool {
|
||||
if (argc > 1) {
|
||||
int port = atoi(argv[1]);
|
||||
NSLog(@"Hi, looks like you manually started internalblued on port %d", port);
|
||||
if (proxy_pref_on()) {
|
||||
int _configured_port = get_proxy_port();
|
||||
NSLog(@"internalblued is already running on port %d. Please turn it off in the iPhone's preferences first, before launching it manually.", _configured_port);
|
||||
exit(-1);
|
||||
}
|
||||
manual_port = port;
|
||||
start_proxy();
|
||||
[[NSRunLoop currentRunLoop] run];
|
||||
} else {
|
||||
// Start the proxy if pref allows us to
|
||||
if (proxy_pref_on()) {
|
||||
NSLog(@"Starting proxy because it is enabled.");
|
||||
start_proxy();
|
||||
}
|
||||
|
||||
// Attempt to create the server, exit if this fails
|
||||
xpc_connection_t connection = xpc_connection_create_mach_service("com.ttdennis.internalblued", NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
|
||||
if (!connection) {
|
||||
NSLog(@"Failed to create XPC server. Exiting.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Configure event handler
|
||||
xpc_connection_set_event_handler(connection, ^(xpc_object_t object) {
|
||||
xpc_type_t type = xpc_get_type(object);
|
||||
if (type == XPC_TYPE_CONNECTION) {
|
||||
NSLog(@"XPC server received incoming connection: %s", xpc_copy_description(object));
|
||||
|
||||
xpc_connection_set_event_handler(object, ^(xpc_object_t some_object) {
|
||||
NSLog(@"XPC connection received object: %s", xpc_copy_description(some_object));
|
||||
_ib_xpc_recv_handler(some_object);
|
||||
});
|
||||
xpc_connection_resume(object);
|
||||
} else if (type == XPC_TYPE_ERROR) {
|
||||
NSLog(@"XPC server error: %s", xpc_dictionary_get_string(object, XPC_ERROR_KEY_DESCRIPTION));
|
||||
} else {
|
||||
NSLog(@"XPC server received unknown object: %s", xpc_copy_description(object));
|
||||
}
|
||||
});
|
||||
|
||||
xpc_connection_resume(connection);
|
||||
[[NSRunLoop currentRunLoop] run];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,4 @@
|
||||
#define CMD_RESTART_BLUETOOTHD 0
|
||||
#define CMD_START_PROXY 1
|
||||
#define CMD_STOP_PROXY 2
|
||||
#define CMD_RESTART_PROXY 3
|
||||
@@ -1,38 +0,0 @@
|
||||
# internalblue-ios-proxy
|
||||
This project is a proxy that redirects the *iOS* 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.
|
||||
The precompiled `ios-proxy` binary was tested on the iPhone 6 (12.1.2, 12.4), iPhone SE (12.4),
|
||||
iPhone 7 (12.1.2, 12.4), and iPhone X (12.4).
|
||||
|
||||
## 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.
|
||||
|
||||
If `ldid` was not installed with your jailbreak, try opening [sileo://package/ldid](sileo://package/ldid).
|
||||
|
||||
## 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 Wi-Fi or
|
||||
by proxying the port through USB (using [usbmuxd](https://iphonedevwiki.net/index.php/SSH_Over_USB)).
|
||||
When enabling a personal hotspot, you can also run `dhclient` on *Linux* on the new local ethernet interface.
|
||||
|
||||
A few things to note:
|
||||
- To increase reliability of the proxy, *Bluetooth should be disabled*
|
||||
(either by manually stopping the Bluetooth daemon or by shutting of Bluetooth in the
|
||||
settings on the phone). Despite shutting down Bluetooth, the RAM will still have the same contents
|
||||
as during previous usage, and you can analyze it.
|
||||
- The current implementation sometimes returns wrong results, thus we double-check results of
|
||||
commands that read ROM/RAM. We show warnings, but firmware dumps should complete nonetheless.
|
||||
- To get sufficient performance, access the `ios-proxy` over USB and not using Wi-Fi.
|
||||
- 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.
|
||||
@@ -1,8 +0,0 @@
|
||||
<?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>
|
||||
@@ -1,285 +0,0 @@
|
||||
// !$*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
@@ -1,80 +0,0 @@
|
||||
<?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>
|
||||
@@ -1,14 +0,0 @@
|
||||
//
|
||||
// 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 */
|
||||
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
|
||||
[mypy-internalblue]
|
||||
|
||||
python_version = 3.8
|
||||
warn_return_any = True
|
||||
|
||||
|
||||
[mypy-internalblue.fw.*]
|
||||
|
||||
ignore_errors = True
|
||||
|
||||
[mypy-internalblue.socket_hooks]
|
||||
ignore_errors = True
|
||||
|
||||
[mypy-pwnlib.*]
|
||||
ignore_missing_imports = True
|
||||
|
||||
[mypy-future.*]
|
||||
ignore_missing_imports = True
|
||||
|
||||
[mypy-past.*]
|
||||
ignore_missing_imports = True
|
||||
|
||||
[mypy-IPython]
|
||||
ignore_missing_imports = True
|
||||
@@ -1,2 +0,0 @@
|
||||
pwntools==3.12.2
|
||||
pyelftools==0.24
|
||||
@@ -2,21 +2,25 @@
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
setup(name='internalblue',
|
||||
version='0.3',
|
||||
description='A Bluetooth Experimentation Framework based on the Broadcom Bluetooth Controller Family.',
|
||||
url='http://github.com/seemoo-lab/internalblue',
|
||||
author='Dennis Mantz',
|
||||
author_email='dennis.mantz@googlemail.com',
|
||||
license='MIT',
|
||||
packages=['internalblue', 'internalblue/fw'],
|
||||
install_requires=[
|
||||
'pwntools',
|
||||
],
|
||||
extras_require={
|
||||
"macoscore": ["pyobjc"],
|
||||
},
|
||||
entry_points = {
|
||||
'console_scripts': ['internalblue=internalblue.cli:internalblue_cli']
|
||||
},
|
||||
zip_safe=False)
|
||||
setup(
|
||||
name="internalblue",
|
||||
version="0.4",
|
||||
description="A Bluetooth Experimentation Framework based on the Broadcom Bluetooth Controller Family.",
|
||||
url="http://github.com/seemoo-lab/internalblue",
|
||||
author="The InternalBlue Team",
|
||||
author_email="jiska@bluetooth.lol",
|
||||
license="MIT",
|
||||
packages=[
|
||||
"internalblue",
|
||||
"internalblue/fw",
|
||||
"internalblue/objects",
|
||||
"internalblue/utils",
|
||||
],
|
||||
install_requires=["pwntools>=4.0.1", "pyelftools", "future"],
|
||||
extras_require={"macoscore": ["pyobjc"], "ipython": ["IPython"]},
|
||||
tests_require=["nose", "pytest", "pwntools>=4.2.0.dev0"],
|
||||
entry_points={
|
||||
"console_scripts": ["internalblue=internalblue.cli:internalblue_entry_point"]
|
||||
},
|
||||
zip_safe=False,
|
||||
)
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
import unittest
|
||||
|
||||
from internalblue.testcore import testCore
|
||||
|
||||
|
||||
class DummyCoreTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
t = testCore(log_level='debug', data_directory='/tmp')
|
||||
dev = t.device_list()[0]
|
||||
reference = dev[0]
|
||||
reference.interface = dev[1]
|
||||
self.assert_(reference.connect(), 'Connect failed')
|
||||
self.reference = reference
|
||||
|
||||
def tearDown(self):
|
||||
self.reference.shutdown()
|
||||
@@ -1,3 +1,4 @@
|
||||
from __future__ import print_function
|
||||
from internalblue.cli import _parse_argv
|
||||
from internalblue.hcicore import HCICore
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from __future__ import print_function
|
||||
from internalblue.cli import _parse_argv
|
||||
from internalblue.adbcore import ADBCore
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from __future__ import print_function
|
||||
from internalblue.cli import _parse_argv
|
||||
from internalblue.adbcore import ADBCore
|
||||
from internalblue.objects.connection_information import ConnectionInformation
|
||||
@@ -13,11 +14,11 @@ except ImportError:
|
||||
|
||||
|
||||
def test_info_conn_7():
|
||||
dummy = ConnectionInformation(7, '0023023a1a2e'.decode('hex'), 0, True, 0xc,
|
||||
'e98a5eaaff39ecb5ce4447590dfb73a4'.decode('hex'), 16,
|
||||
'dbea2d9c47bc1aa6afe664ff31591aa6'.decode('hex'), -87,
|
||||
'0a00c821ffff8ffa'.decode('hex'), '9bff598701000000'.decode('hex'),
|
||||
'00'.decode('hex'))
|
||||
dummy = ConnectionInformation(7, bytearray.fromhex('0023023a1a2e'), 0, True, 0xc,
|
||||
bytearray.fromhex('e98a5eaaff39ecb5ce4447590dfb73a4'), 16,
|
||||
bytearray.fromhex('dbea2d9c47bc1aa6afe664ff31591aa6'), -87,
|
||||
bytearray.fromhex('0a00c821ffff8ffa'), bytearray.fromhex('9bff598701000000'),
|
||||
bytearray.fromhex('00'))
|
||||
|
||||
trace = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||
'traces/adbcore/dictionary_tests/info_conn_7.trace')
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from __future__ import print_function
|
||||
from internalblue.cli import _parse_argv
|
||||
from internalblue.adbcore import ADBCore
|
||||
from internalblue.objects.connection_information import ConnectionInformation
|
||||
@@ -12,10 +13,10 @@ except ImportError:
|
||||
|
||||
|
||||
def test_info_conn_9():
|
||||
dummy = ConnectionInformation(9, '000000000000'.decode('hex'), 0, False, 12,
|
||||
'00000000000000000000000000000000'.decode('hex'), 0, '', -87,
|
||||
'0000000000000000'.decode('hex'),
|
||||
'0000000000000000'.decode('hex'), '00'.decode('hex'))
|
||||
dummy = ConnectionInformation(9, bytearray.fromhex('000000000000'), 0, False, 12,
|
||||
bytearray.fromhex('00000000000000000000000000000000'), 0, b'', -87,
|
||||
bytearray.fromhex('0000000000000000'),
|
||||
bytearray.fromhex('0000000000000000'), bytearray.fromhex('00'))
|
||||
|
||||
trace = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||
'traces/adbcore/dictionary_tests/info_conn_9.trace')
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from __future__ import print_function
|
||||
from internalblue.cli import _parse_argv
|
||||
from internalblue.adbcore import ADBCore
|
||||
from internalblue.objects.queue_element import QueueElement
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
|
||||
from testwrapper import trace_test, get_trace_path_cmd_tuple
|
||||
from .testwrapper import trace_test, get_trace_path_cmd_tuple
|
||||
|
||||
|
||||
import os
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from builtins import object
|
||||
import argparse
|
||||
|
||||
from internalblue.cli import internalblue_cli, _parse_argv
|
||||
@@ -13,7 +14,7 @@ except ImportError:
|
||||
tracedir = os.path.dirname(__file__)
|
||||
|
||||
|
||||
class Fakeargs():
|
||||
class Fakeargs(object):
|
||||
def __init__(self):
|
||||
self.data_directory = None
|
||||
self.verbose = False
|
||||
|
||||
Reference in New Issue
Block a user