├── LICENSE.txt ├── Makefile ├── README.md ├── patch.elf ├── patch.ld ├── patch.py └── src ├── patch.c └── version.c /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Romain Cayre 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GIT_VERSION := $(shell git describe --abbrev=4 --dirty --always --tags) 2 | include ../version.mk 3 | include $(FW_PATH)/definitions.mk 4 | 5 | LOCAL_SRCS=$(wildcard src/*.c) 6 | COMMON_SRCS=$(wildcard $(NEXMON_ROOT)/patches/common/wrapper.c) 7 | FW_SRCS=$(wildcard $(FW_PATH)/*.c) 8 | 9 | #FIXME wrapper is missing in objects that need to be built! 10 | # todo maybe make our own common package for bluetooth... 11 | OBJS=$(addprefix obj/,$(notdir $(LOCAL_SRCS:.c=.o)) $(notdir $(COMMON_SRCS:.c=.o)) $(notdir $(FW_SRCS:.c=.o))) 12 | 13 | CFLAGS= \ 14 | -fplugin=$(CCPLUGIN) \ 15 | -fplugin-arg-nexmon-objfile=$@ \ 16 | -fplugin-arg-nexmon-prefile=gen/nexmon.pre \ 17 | -fplugin-arg-nexmon-chipver=$(NEXMON_CHIP_NUM) \ 18 | -fplugin-arg-nexmon-fwver=$(NEXMON_FW_VERSION_NUM) \ 19 | -fno-strict-aliasing \ 20 | -DNEXMON_CHIP=$(NEXMON_CHIP) \ 21 | -DNEXMON_FW_VERSION=$(NEXMON_FW_VERSION) \ 22 | -DPATCHSTART=$(PATCHSTART) \ 23 | -DUCODESIZE=$(UCODESIZE) \ 24 | -DGIT_VERSION=\"$(GIT_VERSION)\" \ 25 | -DBUILD_NUMBER=\"$$(cat BUILD_NUMBER)\" \ 26 | -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding -mthumb -march=$(NEXMON_ARCH) \ 27 | -Wno-unused-label \ 28 | -ffunction-sections -fdata-sections \ 29 | -I$(NEXMON_ROOT)/patches/include \ 30 | -Iinclude \ 31 | -I$(FW_PATH) 32 | 33 | all: bcm20735b1.hcd 34 | 35 | python: clean bcm4375b1.py 36 | 37 | internalblue: python 38 | @printf "\033[0;31m EXECUTING INTERNALBLUE\033[0m\n" 39 | $(Q)python bcm4375b1.py 40 | 41 | init: FORCE 42 | $(Q)if ! test -f BUILD_NUMBER; then echo 0 > BUILD_NUMBER; fi 43 | $(Q)echo $$(($$(cat BUILD_NUMBER) + 1)) > BUILD_NUMBER 44 | $(Q)touch src/version.c 45 | $(Q)make -s -f $(NEXMON_ROOT)/patches/common/header.mk 46 | $(Q)mkdir -p obj gen log 47 | 48 | obj/%.o: src/%.c 49 | @printf "\033[0;31m COMPILING\033[0m %s => %s (details: log/compiler.log)\n" $< $@ 50 | $(Q)cat gen/nexmon.pre 2>>log/error.log | gawk '{ if ($$3 != "$@") print; }' > tmp && mv tmp gen/nexmon.pre 51 | $(Q)$(CC)gcc $(CFLAGS) -c $< -o $@ >>log/compiler.log 52 | 53 | obj/%.o: $(NEXMON_ROOT)/patches/common/%.c 54 | @printf "\033[0;31m COMPILING\033[0m %s => %s (details: log/compiler.log)\n" $< $@ 55 | $(Q)cat gen/nexmon.pre 2>>log/error.log | gawk '{ if ($$3 != "$@") print; }' > tmp && mv tmp gen/nexmon.pre 56 | $(Q)$(CC)gcc $(CFLAGS) -c $< -o $@ >>log/compiler.log 57 | 58 | obj/%.o: $(FW_PATH)/%.c 59 | @printf "\033[0;31m COMPILING\033[0m %s => %s (details: log/compiler.log)\n" $< $@ 60 | $(Q)cat gen/nexmon.pre 2>>log/error.log | gawk '{ if ($$3 != "$@") print; }' > tmp && mv tmp gen/nexmon.pre 61 | $(Q)$(CC)gcc $(CFLAGS) -c $< -o $@ >>log/compiler.log 62 | 63 | gen/nexmon2.pre: $(OBJS) 64 | @printf "\033[0;31m PREPARING\033[0m %s => %s\n" "gen/nexmon.pre" $@ 65 | $(Q)cat gen/nexmon.pre | awk '{ if ($$3 != "obj/flashpatches.o" && $$3 != "obj/wrapper.o") { print $$0; } }' > tmp 66 | $(Q)cat gen/nexmon.pre | awk '{ if ($$3 == "obj/flashpatches.o" || $$3 == "obj/wrapper.o") { print $$0; } }' >> tmp 67 | $(Q)cat tmp | awk '{ if ($$1 ~ /^0x/) { if ($$3 != "obj/flashpatches.o" && $$3 != "obj/wrapper.o") { if (!x[$$1]++) { print $$0; } } else { if (!x[$$1]) { print $$0; } } } else { print $$0; } }' > gen/nexmon2.pre 68 | 69 | gen/nexmon.ld: gen/nexmon2.pre $(OBJS) 70 | @printf "\033[0;31m GENERATING LINKER FILE\033[0m gen/nexmon.pre => %s\n" $@ 71 | $(Q)sort gen/nexmon2.pre | gawk -f $(NEXMON_ROOT)/buildtools/scripts/nexmon.ld.awk > $@ 72 | 73 | gen/nexmon.mk: gen/nexmon2.pre $(OBJS) $(FW_PATH)/definitions.mk 74 | @printf "\033[0;31m GENERATING MAKE FILE\033[0m gen/nexmon.pre => %s\n" $@ 75 | $(Q)rm -r gen/hcd_extracted || true 76 | $(Q)cp -r $(FW_PATH)/hcd_extracted gen/ 77 | $(Q)rm gen/hcd_extracted/10_writeram_0x00218000.bin 78 | # Printing the content of the nexmon.mk file 79 | $(Q)printf "bcm20735b1.hcd: bcm20735b1.bin\n" > $@ 80 | $(Q)printf "\t$(Q)cat gen/hcd_extracted/rompatches/*.bin > gen/hcd_extracted/00_writeram_0x00218000.bin\n" >> $@ 81 | $(Q)printf "\t$(Q)$(NEXMON_ROOT)/buildtools/hcd_generator/bthcd_generate -i gen/hcd_extracted -o bcm20735b1.hcd\n\n" >> $@ 82 | $(Q)printf "bcm20735b1.bin: gen/patch.elf FORCE\n" >> $@ 83 | $(Q)sort gen/nexmon2.pre | \ 84 | gawk -v src_file=gen/patch.elf -f $(NEXMON_ROOT)/buildtools/scripts/nexmon.mk.1.awk | \ 85 | gawk -v ramstart=0x0 -v initial_patch_nr=$(INITIAL_PATCH_NR) -v rom_area_below=$(ROM_AREA_BELOW) --non-decimal-data -f $(NEXMON_ROOT)/buildtools/scripts/nexmon.mk.2_bt.awk >> $@ 86 | $(Q)printf "\nFORCE:\n" >> $@ 87 | $(Q)gawk '!a[$$0]++' $@ > tmp && mv tmp $@ 88 | 89 | gen/nexmon.py: gen/nexmon2.pre $(OBJS) $(FW_PATH)/definitions.mk 90 | @printf "\033[0;31m GENERATING INTERNALBLUE PYTHON SCRIPT\033[0m gen/nexmon.pre => %s\n" $@ 91 | sort gen/nexmon2.pre | \ 92 | gawk -v src_file=gen/patch.elf -f $(NEXMON_ROOT)/buildtools/scripts/nexmon.mk.1.awk | \ 93 | gawk -v ramstart=0x0 -v rom_area_below=$(ROM_AREA_BELOW) -v objcopy=$(NEXMON_ROOT)/buildtools/gcc-arm-none-eabi-5_4-2016q2-linux-x86/bin/arm-none-eabi-objcopy --non-decimal-data -f $(NEXMON_ROOT)/buildtools/scripts/nexmon.mk.2_bt_py.awk | sed "s/bytes.fromhex('')/bytes.fromhex('00000000')/g" > $@ 94 | 95 | gen/memory.ld: $(FW_PATH)/definitions.mk 96 | @printf "\033[0;31m GENERATING LINKER FILE\033[0m %s\n" $@ 97 | $(Q)printf "patch : ORIGIN = 0x%08x, LENGTH = 0x%08x\n" $(PATCHSTART) $(PATCHSIZE) >> $@ 98 | 99 | gen/patch.elf: patch.ld gen/nexmon.ld gen/memory.ld $(OBJS) 100 | @printf "\033[0;31m LINKING OBJECTS\033[0m => %s (details: log/linker.log, log/linker.err)\n" $@ 101 | $(Q)$(CC)ld -T $< -o $@ --gc-sections --print-gc-sections -M >>log/linker.log 2>>log/linker.err 102 | 103 | bcm20735b1.hcd: init gen/patch.elf $(FW_PATH)/$(BIN_FILE) gen/nexmon.mk 104 | $(Q)cp $(FW_PATH)/$(BIN_FILE) $@ 105 | @printf "\033[0;31m APPLYING PATCHES\033[0m gen/nexmon.mk => %s (details: log/patches.log)\n" $@ 106 | $(Q)make -f gen/nexmon.mk >>log/patches.log 2>>log/flashpatches.log 107 | 108 | bcm4375b1.py: init gen/patch.elf gen/nexmon.py 109 | @printf "\033[0;31m GENERATING INTERNALBLUE SCRIPT\033[0m $@\n" 110 | $(Q)sed -e "/# GENERATED PATCHES/r gen/nexmon.py" $(NEXMON_ROOT)/buildtools/scripts/bt_install_patch_adb.py > $@ 111 | 112 | check-nexmon-setup-env: 113 | ifndef NEXMON_SETUP_ENV 114 | $(error run 'source setup_env.sh' first in the repository\'s root directory) 115 | endif 116 | 117 | backup-hcd: FORCE 118 | adb shell 'su -c "cp /vendor/firmware/bcm20735b1.hcd /sdcard/bcm20735b1.orig.hcd"' 119 | adb pull /sdcard/bcm20735b1.orig.hcd 120 | ls -l bcm20735b1.orig.hcd 121 | 122 | install-patch: bcm20735b1.hcd 123 | @printf "\033[0;31m INSTALLING PATCHES\033[0m %s => device (details: log/patches.log)\n" $< 124 | @if [ -f bcm20735b1.orig.hcd ]; then echo "Copying patched HCD file to device..."; else printf "\033[0;31m ERROR: NO HCD BACKUP FOUND. PLEASE RUN make backup-hcd FIRST!\033[0m \n"; false; fi; 125 | adb shell 'su -c "mount -o rw,remount /system"' && \ 126 | adb push $< /sdcard/ && \ 127 | adb shell 'su -c "cp /sdcard/bcm20735b1.hcd /vendor/firmware/bcm20735b1.hcd"' 128 | adb shell 'su -c "service call bluetooth_manager 8"' 129 | adb shell 'su -c "service call bluetooth_manager 6"' 130 | 131 | install-backup: bcm20735b1.orig.hcd 132 | @printf "\033[0;31m INSTALLING HCD BACKUP\033[0m %s => device (details: log/patches.log)\n" $< 133 | adb shell 'su -c "mount -o rw,remount /system"' && \ 134 | adb push $< /sdcard/ && \ 135 | adb shell 'su -c "cp /sdcard/bcm20735b1.orig.hcd /vendor/firmware/bcm20735b1.hcd"' 136 | adb shell 'su -c "service call bluetooth_manager 8"' 137 | adb shell 'su -c "service call bluetooth_manager 6"' 138 | 139 | clean-firmware: FORCE 140 | @printf "\033[0;31m CLEANING\033[0m\n" 141 | $(Q)rm -fr bcm20735b1.hcd bcm20735b1.bin obj gen log patchout_complete.bin 142 | 143 | clean: clean-firmware 144 | $(Q)rm -f BUILD_NUMBER 145 | 146 | FORCE: 147 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | RadioSploit 1.0 - Patches 2 | ========================= 3 | 4 | This repository contains a set of [InternalBlue](https://github.com/seemoo-lab/internalblue) patches for the BCM4375B1 Bluetooth controller, allowing to sniff and inject Zigbee, Mosart and Enhanced ShockBurst packets from a Samsung Galaxy S20 smartphone. This patches add two new HCI commands allowing to interact with the previously mentioned protocols by diverting the BCM4375 Bluetooth controller. An Android application named [RadioSploit](https://github.com/RCayre/radiosploit) provides a Graphical User Interface (GUI) to manipulate these new commands. 5 | 6 | This project is a Proof of Concept developed in the context of a research work aiming at exploring the feasibility of cross-protocol pivoting attacks. If you need additional details, we have published multiple papers about it: 7 | 8 | * Romain Cayre, Florent Galtier, Guillaume Auriol, Vincent Nicomette, Mohamed Kaâniche, Géraldine Marconato. POSTER: Cross-protocol attacks : weaponizing a smartphone by diverting its Bluetooth controller. *14th ACM Conference on Security and Privacy in Wireless and Mobile Networks (WiSec 2021)*, Jun 2021, Abu Dhabi (virtual), UAE. **\[en\]** 9 | 10 | * Romain Cayre, Florent Galtier. [Attaques inter-protocolaires par détournement du contrôleur Bluetooth d'un téléphone mobile](https://hal.laas.fr/hal-03221148). *GT Sécurité des Systèmes, Logiciels et Réseaux*, May 2021, En ligne, France. **\[fr\]** 11 | 12 | * Romain Cayre, Florent Galtier, Guillaume Auriol, Vincent Nicomette, Mohamed Kaâniche, et al. [WazaBee: attacking Zigbee networks by diverting Bluetooth Low Energy chips](https://hal.laas.fr/hal-03193299). *IEEE/IFIP International Conference on Dependable Systems and Networks (DSN)*, Jun 2021, Taipei (virtual), Taiwan. **\[en\]** 13 | 14 | * Romain Cayre, Florent Galtier, Guillaume Auriol, Vincent Nicomette, Geraldine Marconato. [WazaBee : attaque de réseaux Zigbee par détournement de puces Bluetooth Low Energy](https://hal.laas.fr/hal-02778262). *Symposium sur la Sécurité des Technologies de l'Information et des Communications (SSTIC 2020)*, Jun 2020, Rennes, France. pp.381-418.**\[fr\]** 15 | 16 | The patches have been generated using the [Nexmon framework](https://github.com/seemoo-lab/nexmon) (especially the "bluetooth-wip" branch). Please refer to the corresponding documentation if you want to compile it by yourself. 17 | 18 | This application is released as an opensource software using the MIT License. 19 | 20 | How to patch the Bluetooth controller ? 21 | --------------------------------------- 22 | * First, you need to root your Samsung Galaxy S20 smartphone. The patches should also work with Samsung Galaxy S10, but it has not been tested. 23 | * Install **adb** and [InternalBlue framework](https://github.com/seemoo-lab/internalblue) on your computer. 24 | * Apply the **Read_Ram** bypass described [here](https://github.com/seemoo-lab/internalblue/blob/master/doc/android.md#bypass-broadcom-read_ram-fix) to enable vendor-specific commands allowing to read, write and launch RAM. 25 | * Install the patches using the following command: 26 | ``` 27 | sudo python3 patch.py 28 | ``` 29 | * Install the [RadioSploit Android application](https://github.com/RCayre/radiosploit) or use [InternalBlue](https://github.com/seemoo-lab/internalblue) Command Line Interface to interact with the patched controller. 30 | 31 | HCI Commands 32 | ------------- 33 | 34 | These patches add two new HCI commands to the controller: **Start\_RX** (opcode = 0x2060) and **Start\_TX** (opcode = 0x2061). The received packets are transmitted to the Host using custom HCI events with opcode **0xFF**. 35 | 36 | * If you want to enable Zigbee RX mode, launch the following command : 37 | ``` 38 | > sendhcicmd 0x2060 01 39 | ``` 40 | 41 | For example, if you want to select channel 13: 42 | ``` 43 | > sendhcicmd 0x2060 010d 44 | ``` 45 | 46 | * If you want to enable Mosart scan mode, launch the following command: 47 | ``` 48 | > sendhcicmd 0x2060 02 49 | ``` 50 | 51 | For example, if you want to select channel 3 without allowing the reception of dongle packets: 52 | ``` 53 | > sendhcicmd 0x2060 020300 54 | ``` 55 | 56 | * If you want to enable Mosart keylogger mode, launch the following command: 57 | ``` 58 | > sendhcicmd 0x2060 03 59 | ``` 60 | 61 | For example, if you want to select channel 3 and receive keystrokes from the keyboard using address F0:BF:1E:86: 62 | ``` 63 | > sendhcicmd 0x2060 0303F0BF1E86 64 | ``` 65 | 66 | * If you want to enable Mosart RX mode, launch the following command: 67 | ``` 68 | > sendhcicmd 0x2060 04 69 | ``` 70 | 71 | For example, if you want to select channel 3 and receive packets from the device using address F0:BF:1E:86: 72 | ``` 73 | > sendhcicmd 0x2060 0403F0BF1E86 74 | ``` 75 | 76 | * If you want to enable Enhanced ShockBurst Scan mode, launch the following command: 77 | ``` 78 | > sendhcicmd 0x2060 05 79 | ``` 80 | 81 | For example, if you want to scan channel 8, launch the following command: 82 | ``` 83 | > sendhcicmd 0x2060 0508 84 | ``` 85 | 86 | * If you want to enable Enhanced ShockBurst RX mode, launch the following command: 87 | ``` 88 | > sendhcicmd 0x2060 06 89 | ``` 90 | 91 | For example, if want to receive packets on channel 8 from device using address 11:22:33:44:55: 92 | ``` 93 | > sendhcicmd 0x2060 06081122334455 94 | ``` 95 | 96 | * If you want to transmit a Zigbee packet, launch the following command: 97 | ``` 98 | > sendhcicmd 0x2061 01 99 | ``` 100 | 101 | For example, if you want to transmit the packet **010d14a7126188f9323300000000d30068656c6c6f9ee0** on channel 13: 102 | ``` 103 | > sendhcicmd 0x2061 010d14a7126188f9323300000000d30068656c6c6f9ee0 104 | ``` 105 | 106 | * If you want to transmit a Mosart packet, launch the following command: 107 | ``` 108 | > sendhcicmd 0x2061 02 109 | ``` 110 | 111 | For example, if you want to transmit the packet **f0f0f0bf1e8645fcfbfafc7a23** on channel 4: 112 | ``` 113 | > sendhcicmd 0x2061 02040df0f0f0bf1e8645fcfbfafc7a23 114 | ``` 115 | 116 | * If you want to transmit an Enhanced ShockBurst packet, launch the following command: 117 | ``` 118 | > sendhcicmd 0x2061 05 119 | ``` 120 | 121 | For example, if you want to transmit the packet **aacae906eca4280061010000000000001e748a00** on channel 71: 122 | ``` 123 | > sendhcicmd 0x2061 054714aacae906eca4280061010000000000001e748a00 124 | ``` 125 | 126 | 127 | -------------------------------------------------------------------------------- /patch.elf: -------------------------------------------------------------------------------- 1 | :00000001FF 2 | -------------------------------------------------------------------------------- /patch.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | INCLUDE gen/memory.ld 4 | } 5 | 6 | SECTIONS 7 | { 8 | INCLUDE gen/nexmon.ld 9 | } 10 | -------------------------------------------------------------------------------- /patch.py: -------------------------------------------------------------------------------- 1 | from pwnlib.asm import asm 2 | from internalblue import Address 3 | from internalblue.adbcore import ADBCore 4 | from struct import pack 5 | import os 6 | 7 | # setup ADB Core 8 | internalblue = ADBCore(serial=True) 9 | internalblue.interface = internalblue.device_list()[0][1] # just use the first device 10 | 11 | # connect internalblue to the device 12 | if not internalblue.connect(): 13 | print("No connection to the device !") 14 | exit(-1) 15 | 16 | # Data / variables 17 | print("Installing data / variables...") 18 | internalblue.writeMem(0x00203124, bytes.fromhex('10022800')) 19 | internalblue.writeMem(0x00210500, bytes.fromhex('00000000')) 20 | internalblue.writeMem(0x00210504, bytes.fromhex('00000000')) 21 | internalblue.writeMem(0x00210508, bytes.fromhex('00000000')) 22 | internalblue.writeMem(0x0021050c, bytes.fromhex('00000000')) 23 | internalblue.writeMem(0x00210510, bytes.fromhex('ff')) 24 | internalblue.writeMem(0x00210514, bytes.fromhex('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')) 25 | internalblue.writeMem(0x0021053c, bytes.fromhex('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')) 26 | internalblue.writeMem(0x0021063b, bytes.fromhex('00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')) 27 | internalblue.writeMem(0x00210670, bytes.fromhex('00000000')) 28 | internalblue.writeMem(0x00210674, bytes.fromhex('00000000')) 29 | internalblue.writeMem(0x00210678, bytes.fromhex('00000000')) 30 | internalblue.writeMem(0x0021067c, bytes.fromhex('03f73a1b3970af339a03f73ab239702f3b9b0377aeb33970f73a9b0370afb339fc08c564c68f504c65fc08454dc68f50c464fc08514cc60f08c5647c8f504c46')) 31 | internalblue.writeMem(0x002106c0, bytes.fromhex('00000000')) 32 | internalblue.writeMem(0x002106c4, bytes.fromhex('00000000')) 33 | internalblue.writeMem(0x002106c8, bytes.fromhex('00000000')) 34 | internalblue.writeMem(0x002106cc, bytes.fromhex('526164696f53706c6f6974')) 35 | 36 | # Functions and callbacks 37 | print("Installing function and callbacks...") 38 | internalblue.writeMem(0x00210700, bytes.fromhex('2de9f04fa54b1b68002b00f0e281a44b1b6803f48073002b00f0d881a14b1b68002b40f0d381ff2200219f48f0f5f4f8ff229e499c48f0f5cdf8984b1b68012b35d1994a9a499b4808f05af9984b1b68002b00f0b781964b1b683b2b00f2b281934b1b68dbb20433d8b2914b1b68dbb20233dbb21a46ff2158f6b3ff044604f10a03864a1268d2b21a7004f10b038a4a1268d2b21a7004f10c00854b1b681a468449f1f5e9ff204658f67cfe8ae17b4b1b68022b47d17c4a7d497e4808f020fc7b4b1b68dbb27d4a19467a4808f098fb0346002b00f07681754b1b68dab2774b1b78d31adbb20833d8b2714b1b68dab2724b1b78d31adbb20633dbb21a46ff2158f66fff044604f10a03644a1268d2b21a7004f10b03684a1268d2b21a7004f10c00664b1b78043b624a9918604b1b68624a12789b1a04331a46f1f59dff204658f630fe3ee1554b1b68032b22d15c4b1a465749574808f0d3fb0322ff21052058f63fff044604f10a034c4a1268d2b21a7004f10b03504a1268d2b21a7004f10c0301224b491846f1f576ff204658f609fe17e1414b1b68042b79d1424a4449444808f0adfb424b1b68dbb2434a1946404808f025fb0346002b00f003813f4b1b78043b3b4ad35c1a463e4b1b68dbb29a4240f0f780394b1b78033b354ad35c1a46384b1b681b0adbb29a4240f0ea80324b1b78023b2f4ad35c1a46314b1b681b0cdbb29a4240f0dd802c4b1b78013b284ad35c1a462b4b1b681b0e9a4240f0d180234b1b68dab2244b1b78d31adbb20833d8b21e4b1b68dab2204b1b78d31adbb20633dbb21a46ff2158f6cafe044604f10a03114a1268d2b21a7004f10b03154a1268d2b21a7004f10c00134b1b78043b104a99180e4b1b68104a12789b1a04331a46f1f5f8fe204658f68bfd99e0024b1b68052b55d100241fe000052100ac8b3100780621003c05210000243700700621003c06210004052100100521003d052100c0062100454b1b5d184608f017f903461a46424b1a550134c72cf3dd0722ff21092058f67cfe044604f10a033c4a1268d2b21a7004f10b033a4a1268d2b21a7004f10c05384b1b68dbb2184608f0f6f803462b7004f10d05334b1b681b0adbb2184608f0ebf803462b7004f10e0303222a491846f1f59efe204658f631fd3fe0274b1b68062b3bd1002409e0234b1b5d184608f0d3f803461a46204b1a550134c72cf3dd21491d4808f048fc03461a461f4b1a601e4b1b68dbb20433d8b21c4b1b68dbb20233dbb21a46ff2158f627fe044604f10a03124a1268d2b21a7004f10b03104a1268d2b21a7004f10c00104b1b681a460d49f1f55dfe204658f6f0fc0c4b01221a6002e00a4b00221a60bde8f04f2de9f0416bf6d9be00bf3c0521000005210004052100c80621003c0621007006210078062100')) 39 | internalblue.writeMem(0x00210c00, bytes.fromhex('074b1b68002b03d1064b1b68002b01d0002301e0044b1b6860f6cebc00bf00bf000521000805210050312000')) 40 | internalblue.writeMem(0x00210d00, bytes.fromhex('1a4b1b68002b2ad0184b1b68012b03d117487ff685b928e0144b1b68022b03d0124b1b68042b04d14ff033307ff678b91be00e4b1b68052b04d14ff0aa407ff66fb912e0094b1b68032b03d0074b1b68062b0ad1074800687ff662b905e010b108467ff65db97ff68db900bf0005210003f73a9bc0062100')) 41 | internalblue.writeMem(0x00210e00, bytes.fromhex('0fb4094b1b68002b09d008480068084940f0800008600fbc69f6cfb902e00fbc69f6b9b900bf00bf0005210004052100a4863100')) 42 | internalblue.writeMem(0x00210f00, bytes.fromhex('2de9f04f0746042283b0ff21062058f6e8fb634e3b7bdff890b1012bcbf80030814633467a7bdff8948106bf02eb8202343a023ac8f8002006f12804002203f8012f9c424ff00005f9d1564a0121422311725372202106231046d372157355739573d573157455749172019283f638f9dbf800309bb9dbf80030d8f80000522189f80d004846582289f80c3089f80a1089f80b2003b0bde8f04f58f683ba019a531e03f8015f9c424ff0000af9d10123137213739373d37341202021082350729172d37299211923364882f80da0117491745374d374019283f6a0f8019a06f801afb4424ff00005f9d101234220137213732021062350722a48d37255739573d57315745574917283f6eaf8dbf80030254e022b06d1ba7b2449521b18bf01220a60aae7032b1fd0042b32d0062ba2d11f4d052207f10e012846f1f59dfba87807f0defd0446687807f0dafd0304287843ea046407f0d4fd44f05504154a44ea00203368106088e7114c134d07f10e0104222046f1f580fb7023214605222846237108f03df8d5f805100a4a3368116073e7d7f80e000749044a086015606ce7130521001405210000052100c40621003c052100c00621003c06210004052100')) 43 | internalblue.writeMem(0x00214400, bytes.fromhex('08480068002807d007487bf609fe0023064a136060f6cabc7bf630fe60f6c6bc00bf00000805210003f73a9ba5790200')) 44 | internalblue.writeMem(0x00214500, bytes.fromhex('06480068002803d0054a126860f643bdd4f8882260f63fbd00bf0000080521000c052100')) 45 | internalblue.writeMem(0x00214600, bytes.fromhex('80b588b000af78609e4b01221a607b680c331b78012b08d17b680d331b78184604f06ef903461a4604e07b680d331b78023b1a46944b1a607b680e331b781a46924b1a607b680c331b78012b40f08c800023fb6107e08e4afb69134400221a70fb690133fb61fb69032bf4dd7b6803f10f01864b1b681a468648eef57df80023bb6107e0844abb69134400221a70bb690133bb61bb69fe2bf4dd00237b615ce07b4a7b6913441b781b09fb72784a7b6913441b7803f00f03bb727b69db00ba7a764911f82210744ad1547b69db005a1cbb7a72499b000b4459786f4b99547b69db009a1cbb7a6d499b000b4499786a4b99547b69db00da1cbb7a68499b000b44d978654b99547b69db000433fa7a634911f82210604ad1547b69db005a1dfb7a5e499b000b4459785b4b99547b69db009a1dfb7a59499b000b449978564b99547b69db00da1dfb7a54499b000b44d978514b99547b6901337b614c4b1b681a1d7b699a429cd84ce07b680c331b78022b09d07b680c331b78032b04d07b680c331b78042b11d17b6803f10f013f4b1b681a463f48edf5f0ff3c4b1b68dbb21a463b493d4804f0acfc2be07b680c331b78052b04d07b680c331b78062b21d17b6803f10f01314b1b681a463148edf5d4ff00233b6110e02e4a3b6913441b78184604f00efa034619462b4a3b6913440a461a703b6901333b613a69244b1b689a42e9d3274b4ff4ba621a60264b05221a60254b10221a607b680c331b78012b0fd11a4b1b680433db001a461b491f48edf5a3ff1f4a154b1b680433db0013601de07b680c331b78042b0dd8104b1b685b001a4611491548edf58fff154a0b4b1b685b0013600ae0094b1b681a460a490f48edf582ff0e4b054a12681a600023fb6020e000bf080521000c052100700621003c062100400621003c0521007c062100382123004021230044212300c02e2300c0322300174afb68134400221a70fb680133fb60fb68272bf4dd124b01221a72104b39225a720f4b20229a720d4b0622da720c4b01221a730a4b01225a73094b00229a73074b0022da73064b00221a74044b00225a7403487ff6b6f900bf2037bd4680bd14052100')) 46 | internalblue.writeMem(0x00214f00, bytes.fromhex('2de9ff4f214b1b68002b37d00422ff21062054f6e6fb0546002403e01c4b00221a550134272cf9dd194b01221a72184b3c225a72164b20229a72154b0122da72134b00221a7312487ef670fe0f4b00221a6005f10a0354221a7005f10b0358221a7005f10c0301221a7005f10d03094a1268d2b21a70284654f694fabde8ff4f23689a425cf654bf00bf00bf08052100140521000c052100')) 47 | internalblue.writeMem(0x00218700, bytes.fromhex('2de9f041002600f1ff3c304601391cf8017f11f801ef07f07f08012200e00132c2f1080447fa04f34efa04f56b404eb1dc0700d50130082af1d10136042ee6d1bde8f081012af3d148fa04f46c40e307f0d4e4e7')) 48 | internalblue.writeMem(0x00218800, bytes.fromhex('002912dd10b4002207e032b110f8013c047843ead41300f8013c037801325b00914200f8013bf0d110bc7047')) 49 | internalblue.writeMem(0x00218900, bytes.fromhex('00eb800034387047')) 50 | internalblue.writeMem(0x00218a00, bytes.fromhex('2de9f04f054683b001919346431e00f13101002203f8012f8b42fbd12b78cbf1010643f007032b7034495846fff768fe082814d90bf1ff3301210ae058781a78440042ead012ff291a705c70ecd001310133de42f2d15a7852005a70f7e700231e46012700930bf1ff3acbeb0704dff88c804ff0000941465846fff741fe082808f1040809d909f10109b9f1100ff2d1019b1e6003b0bde8f08f009b53b3ab5db90009fa01f21343ab5587f00103012f1f464ff0010308bf013600934ff0200c5346012001e001300133dc420ed059781a784fea410eff2842ead111197083f801e0f0d1bcf1010cead1c0e75a7852005a70e8e7b9f10a0fe0d1d0e77c062100')) 51 | internalblue.writeMem(0x00218c00, bytes.fromhex('c109430141eac01103f04003c200194302f020024300114303f010034210194302f00802c3100a4303f004034011134300f002001843c0b2704700bf')) 52 | internalblue.writeMem(0x00218d00, bytes.fromhex('1b68034a13605a0661f650b900bf0000c8062100')) 53 | internalblue.writeMem(0x00218e00, bytes.fromhex('013910b44ff0000216d410f8014b082382ea042212f4004f4fea420418bf84f4815203f1ff3314bf82f00102520013f0ff03efd10139e8d590b210bc704700bf')) 54 | internalblue.writeMem(0x00218f00, bytes.fromhex('2de9f0470026a1f1020eb645167047dd8046074630460139dff88c9008eb010cf044c6eb0e05013dba464ff0000116d41af8014b082381ea042111f4004f4fea410418bf84f4815103f1ff3314bf81f00101490013f0ff03efd1013de8d59cf8004098f8003089b243ea0423994213d0d9f80030012b06d00136764507f10107cfdbbde8f08739781129f5d17978222904bf18461670efe716700120bde8f0873046bde8f08700bfc4062100')) 55 | internalblue.writeMem(0x00219000, bytes.fromhex('f8b504460d461746002601e0322e31d0b95dbb19c8108a105b7800f0080002f00402024301f001004910024301f00201580011434fea830e20f07f0008430ef0400eda0040ea0e0002f020021b0103f0100310431843c0b2fff7d2fd80f05a00c0b2c6f34603a52806f10206e054cdd12b60f8bd19232b60f8bd00bf')) 56 | internalblue.writeMem(0x00219100, bytes.fromhex('002a56d02de9f041074601f1ff3800eb420618f8010f023780f05a00fff770fd044645b205f00400a101e310621040eac41001f0400103f0010e0843510140ea0e0001f020011201014302f0100260000a435b0000f0080003f0020310431843c0b2fff74dfd05f02003c4f3c71522112b4343eac213920143ea450502f040026308a411154303f01002e300154303f00803a4001d4304f004042c4307f8020ce0b2fff72dfd07f8010cbe42b1d1bde8f0817047')) 57 | internalblue.writeMem(0x00219200, bytes.fromhex('2de9f0411d4b1b6813f0ff072ad0c3f30728b8f1000f25d0c3f3074cbcf1000f20d0a1f1030e4feace0ebef1000fc8bf002617dd81b10346002406e013f8012c1d7842ead51203f8012c1a78013452008c4203f8012bf1d18378bb4205d001367645e7d10020bde8f081c3784345f6d103796345f3d10120bde8f081c0062100')) 58 | internalblue.writeMem(0x00219300, bytes.fromhex('30b4044600788008431e1c2b0bd80d1814f8012fd30943ea420301f8013b8d42f6d130bc7047002030bc7047')) 59 | 60 | # Hooks 61 | print("Installing Hooks...") 62 | internalblue.patchRom(0x000715b4, bytes.fromhex('9ff124bb')) 63 | internalblue.patchRom(0x00071e2c, bytes.fromhex('a3f168b8')) 64 | internalblue.patchRom(0x00074da8, bytes.fromhex('9ff12abb')) 65 | internalblue.patchRom(0x00074f92, bytes.fromhex('9ff1b5ba')) 66 | internalblue.patchRom(0x00079fa8, bytes.fromhex('9ef1aabe')) 67 | internalblue.patchRom(0x0007a192, bytes.fromhex('96f135be')) 68 | internalblue.patchRom(0x0007c88c, bytes.fromhex('93f138bf')) 69 | internalblue.patchRom(0x0009002e, bytes.fromhex('2022fff7')) 70 | internalblue.patchRom(0x0009007c, bytes.fromhex('80f140be')) 71 | internalblue.patchRom(0x000f2398, bytes.fromhex('010f2100')) 72 | internalblue.patchRom(0x000f239c, bytes.fromhex('00000800')) 73 | internalblue.patchRom(0x000f23a0, bytes.fromhex('01462100')) 74 | internalblue.patchRom(0x000f23a4, bytes.fromhex('00000800')) 75 | 76 | print("Terminated :)") 77 | # shutdown connection 78 | internalblue.shutdown() 79 | os._exit(0) 80 | -------------------------------------------------------------------------------- /src/patch.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * * 3 | * ########### ########### ########## ########## * 4 | * ############ ############ ############ ############ * 5 | * ## ## ## ## ## ## ## * 6 | * ## ## ## ## ## ## ## * 7 | * ########### #### ###### ## ## ## ## ###### * 8 | * ########### #### # ## ## ## ## # # * 9 | * ## ## ###### ## ## ## ## # # * 10 | * ## ## # ## ## ## ## # # * 11 | * ############ ##### ###### ## ## ## ##### ###### * 12 | * ########### ########### ## ## ## ########## * 13 | * * 14 | * S E C U R E M O B I L E N E T W O R K I N G * 15 | * * 16 | * This file is part of NexMon. * 17 | * * 18 | * Copyright (c) 2018 NexMon Team * 19 | * * 20 | * NexMon is free software: you can redistribute it and/or modify * 21 | * it under the terms of the GNU General Public License as published by * 22 | * the Free Software Foundation, either version 3 of the License, or * 23 | * (at your option) any later version. * 24 | * * 25 | * NexMon is distributed in the hope that it will be useful, * 26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 28 | * GNU General Public License for more details. * 29 | * * 30 | * You should have received a copy of the GNU General Public License * 31 | * along with NexMon. If not, see . * 32 | * * 33 | **************************************************************************/ 34 | 35 | #pragma NEXMON targetregion "patch" 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | 42 | /*Allows to write a specific function to the BLE HCI commands table */ 43 | #define REGISTER_HCI_FUNCTION(opcode,parameters,name) __attribute__((at((0xF20A0 + (opcode << 3) - 8), "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) \ 44 | GenericPatch4(callback_ ## name,name) \ 45 | __attribute__((at((0xF20A0 + (opcode << 3)) - 4, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) \ 46 | GenericPatch4(params_ ## name,parameters) 47 | 48 | 49 | /* 50 | RX mode: 51 | - 0x00 (disabled, normal BLE mode) 52 | - 0x01: Zigbee 53 | - 0x02: Mosart packet (CRC check) 54 | - 0x03: Mosart keylogger 55 | - 0x04: Mosart packet (CRC check + address filtering) 56 | - 0x05: Enhanced ShockBurst address 57 | - 0x06: Enhanced ShockBurst payload 58 | - */ 59 | __attribute__((at(0x00210500, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 60 | uint32_t rx_enabled = 0x00000000; 61 | 62 | /* 63 | Frequency offset for RX mode 64 | */ 65 | __attribute__((at(0x00210504, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 66 | uint32_t rx_frequency = 0x00000000; 67 | 68 | /* 69 | TX mode: 70 | 0x00: disabled 71 | 0x01: Zigbee 72 | 0x02/0x03/0x04: Mosart 73 | 0x05/0x06: Enhanced ShockBurst 74 | */ 75 | __attribute__((at(0x00210508, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 76 | uint32_t tx_enabled = 0x00000000; 77 | 78 | /* 79 | Frequency offset for TX mode 80 | */ 81 | __attribute__((at(0x0021050c, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 82 | uint32_t tx_frequency = 0x00000000; 83 | 84 | /* 85 | Position of the beginning of the mosart frame in the buffer 86 | */ 87 | __attribute__((at(0x00210510, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 88 | uint8_t start_mosart_frame = 0xFF; 89 | 90 | /* 91 | Buffer allowing to send HCI commands from patches 92 | */ 93 | __attribute__((at(0x00210514, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 94 | uint8_t fake_hci_buffer[40] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; 95 | 96 | /* 97 | Buffer used to store the demodulator output / modulator input 98 | */ 99 | __attribute__((at(0x21053c, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 100 | uint8_t raw_buffer[255] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; 101 | 102 | /* 103 | Buffer used to store the decoded/encoded version of a frame 104 | */ 105 | __attribute__((at(0x21063b, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 106 | uint8_t buffer_decoded[50] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; 107 | 108 | /* 109 | Size of the decoded/encoded version of a frame 110 | */ 111 | __attribute__((at(0x210670, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 112 | uint32_t buffer_decoded_size = 0x00000000; 113 | 114 | /* 115 | Flag indicating if a frame has been received 116 | */ 117 | __attribute__((at(0x210678, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 118 | uint32_t rx_done = 0x00000000; 119 | 120 | /* 121 | Correspondance table linking Zigbee symbols to the corresponding MSK representation 122 | */ 123 | __attribute__((at(0x21067c, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 124 | uint8_t SYMBOL_TO_CHIP_MAPPING[16][4] = { 125 | {0x03,0xf7,0x3a,0x1b}, 126 | {0x39,0x70,0xaf,0x33}, 127 | {0x9a,0x03,0xf7,0x3a}, 128 | {0xb2,0x39,0x70,0x2f}, 129 | {0x3b,0x9b,0x03,0x77}, 130 | {0xae,0xb3,0x39,0x70}, 131 | {0xf7,0x3a,0x9b,0x03}, 132 | {0x70,0xaf,0xb3,0x39}, 133 | {0xfc,0x08,0xc5,0x64}, 134 | {0xc6,0x8f,0x50,0x4c}, 135 | {0x65,0xfc,0x08,0x45}, 136 | {0x4d,0xc6,0x8f,0x50}, 137 | {0xc4,0x64,0xfc,0x08}, 138 | {0x51,0x4c,0xc6,0x0f}, 139 | {0x08,0xc5,0x64,0x7c}, 140 | {0x8f,0x50,0x4c,0x46}, 141 | }; 142 | 143 | /* 144 | Preamble (used by Enhanced ShockBurst and Mosart RX mode to filter by address) 145 | */ 146 | __attribute__((at(0x2106c0, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 147 | uint32_t preamble = 0x00000000; 148 | 149 | /* 150 | Boolean indicating if the dongle frames must be transmitted to Host (Mosart only) 151 | */ 152 | __attribute__((at(0x2106c4, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 153 | uint32_t dongle_mode = 0x00000000; 154 | 155 | /* 156 | Integer used to store the first two bytes of the received packet (not in the demodulator output) 157 | */ 158 | __attribute__((at(0x2106c8, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 159 | uint32_t rx_header = 0x00000000; 160 | 161 | /* 162 | Buffer used to check the presence of the patches by the Android app 163 | */ 164 | __attribute__((at(0x2106cc, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 165 | uint8_t patch_installed[11] = {0x52,0x61,0x64,0x69,0x6f,0x53,0x70,0x6c,0x6f,0x69,0x74}; 166 | 167 | /* 168 | Function allowing to return the hamming distance between two buffers 169 | */ 170 | __attribute__((at(0x00218700, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 171 | int hamming(uint8_t *demod_buffer,uint8_t *pattern) { 172 | int count = 0; 173 | for (int i=0;i<4;i++) { 174 | for (int j=0;j<8;j++) { 175 | if (((pattern[i] >> (7-j)) & 0x01) != (((demod_buffer[i] & (i==0 && j==0 ? 0x7F : 0xFF)) >> (7-j)) & 0x01)) { 176 | count++; 177 | } 178 | } 179 | } 180 | return count; 181 | } 182 | 183 | /* 184 | Function allowing to shift a buffer by a given number of bits 185 | */ 186 | __attribute__((at(0x00218800, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 187 | void shift_buffer(uint8_t *demod_buffer,int size) { 188 | for (int i=0;i> 7) | demod_buffer[i-1]; 191 | } 192 | demod_buffer[i] = demod_buffer[i] << 1; 193 | } 194 | } 195 | 196 | /* 197 | Function allowing to convert a channel to the corresponding frequency (finalFreq = 2402MHz + returnedFreq) 198 | */ 199 | __attribute__((at(0x00218900, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 200 | int channelToFrequency(int channel) { 201 | return 3 + 5 * (channel - 11); 202 | } 203 | 204 | 205 | /* 206 | Function allowing to convert a GFSK frame to the corresponding Zigbee frame (see WazaBee attack: https://hal.archives-ouvertes.fr/hal-03193299/) 207 | */ 208 | __attribute__((at(0x00218A00, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 209 | void decode(uint8_t *output_buffer, uint32_t *length, uint8_t * packet) { 210 | 211 | for (int i=0;i<50;i++) output_buffer[i] = 0; 212 | // index of the current Zigbee symbol 213 | uint32_t index = 0; 214 | // indicator of current 4 bits position (1 = 4 MSB, 0 = 4 LSB) 215 | uint32_t part = 1; 216 | // indicator of start frame delimiter 217 | uint32_t sfd = 0; 218 | // Hamming distance 219 | uint32_t hamming_dist = 0; 220 | // Thresold Hamming distance 221 | uint32_t hamming_thresold = 8; 222 | 223 | // Align the buffer with the SFD 224 | output_buffer[0] |= (0x0F & 0x07); 225 | hamming_dist = 32; 226 | while (hamming_dist > hamming_thresold) { 227 | hamming_dist = hamming(packet,SYMBOL_TO_CHIP_MAPPING[0]); 228 | if (hamming_dist > hamming_thresold) { 229 | shift_buffer(packet,255); 230 | } 231 | } 232 | 233 | hamming_dist = 0; 234 | while (hamming_dist <= hamming_thresold) { 235 | int symbol = -1; 236 | // Compute the hamming distance for every zigbee symbol 237 | for (int i=0;i<16;i++) { 238 | hamming_dist = hamming(packet,SYMBOL_TO_CHIP_MAPPING[i]); 239 | if (hamming_dist <= hamming_thresold) { 240 | symbol = i; 241 | break; 242 | } 243 | } 244 | 245 | // If a zigbee symbol has been found ... 246 | if (symbol != -1) { 247 | // If it matches the SFD next symbol, start the frame decoding 248 | if (sfd == 0 && symbol == 10) { 249 | sfd = 1; 250 | } 251 | 252 | // If we are in the frame decoding state ... 253 | if (sfd == 1) { 254 | // Fill the output buffer with the selected symbol 255 | output_buffer[index] |= (symbol & 0x0F) << 4*part; 256 | 257 | // Select the next 4 bits free space in the output buffer 258 | part = part == 1 ? 0 : 1; 259 | if (part == 0) index++; 260 | } 261 | // Shift the buffer (31 bits shift) 262 | for (int i=0;i<32;i++) shift_buffer(packet,255); 263 | } 264 | } 265 | 266 | // Export of the effective length of the Zigbee frame 267 | *length = index; 268 | } 269 | 270 | /* 271 | Function allowing to convert a little endian byte to big endian 272 | */ 273 | __attribute__((at(0x00218C00, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 274 | uint8_t swap_bits(uint8_t byte) { 275 | return (uint8_t)(((byte & 0x01) << 7) | 276 | ((byte & 0x02) << 5) | 277 | ((byte & 0x04) << 3) | 278 | ((byte & 0x08) << 1) | 279 | ((byte & 0x10) >> 1) | 280 | ((byte & 0x20) >> 3) | 281 | ((byte & 0x40) >> 5) | 282 | ((byte & 0x80) >> 7)); 283 | } 284 | 285 | /* 286 | Function allowing to save the RX header in rx_header variable 287 | */ 288 | __attribute__((at(0x00218D00, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 289 | __attribute__((optimize("O0"))) 290 | __attribute__((naked)) 291 | void get_rx_header() { 292 | __asm__( 293 | "ldr r3,[r3]\n\t" 294 | "ldr r2,=rx_header\n\t" 295 | "str r3,[r2]\n\t" 296 | "lsls r2,r3,#0x19\n\t" 297 | "b 0x79fac\n\t" 298 | ); 299 | } 300 | 301 | /* Redirect the flow of scanTaskRxHeaderDone to get_rx_header */ 302 | __attribute__((at(0x79FA8, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 303 | BPatch(rx_header_patch, get_rx_header); 304 | 305 | /* 306 | Function allowing to calculate a Mosart CRC 307 | */ 308 | __attribute__((at(0x00218E00, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 309 | unsigned short crc16(uint8_t *ptr, int count) 310 | { 311 | int crc; 312 | uint8_t i; 313 | crc = 0; 314 | while (--count >= 0) 315 | { 316 | crc = crc ^ (int) *ptr++ << 8; 317 | i = 8; 318 | do 319 | { 320 | if (crc & 0x8000) 321 | crc = crc << 1 ^ 0x1021; 322 | else 323 | crc = crc << 1; 324 | } while(--i); 325 | } 326 | return (crc); 327 | } 328 | 329 | /* 330 | Function allowing to check if a Mosart frame includes a valid CRC 331 | */ 332 | __attribute__((at(0x00218F00, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 333 | int check_frame(uint8_t *frame,uint8_t size,uint8_t *start) { 334 | int valid = 0; 335 | *start = 0; 336 | for (int i=0;i> 3) | 359 | ((packet[index] & 0x10) >> 2) | 360 | ((packet[index] & 0x04) >> 1) | 361 | ((packet[index] & 0x01)) | 362 | ((packet[index+1] & 0x40) << 1) | 363 | ((packet[index+1] & 0x10) << 2) | 364 | ((packet[index+1] & 0x04) << 3) | 365 | ((packet[index+1] & 0x01) << 4)) ^ 0x5a; 366 | if (output_buffer[index/2] == 0xa5) { 367 | break; 368 | } 369 | index += 2; 370 | } 371 | *length = index/2; 372 | } 373 | 374 | 375 | /* 376 | Function allowing to encode a Mosart frame (duplicates every bit + performs whitening ) 377 | */ 378 | __attribute__((at(0x00219100, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 379 | void encode_mosart(uint8_t *output_buffer,uint8_t *data, uint8_t size) { 380 | 381 | for (int i=0;i> 0) << 7) | 384 | (((current & 0x01) >> 0) << 6) | 385 | (((current & 0x02) >> 1) << 5) | 386 | (((current & 0x02) >> 1) << 4) | 387 | (((current & 0x04) >> 2) << 3) | 388 | (((current & 0x04) >> 2) << 2) | 389 | (((current & 0x08) >> 3) << 1) | 390 | (((current & 0x08) >> 3) << 0)); ; 391 | output_buffer[i*2+1] = swap_bits((((current & 0x10) >> 4) << 7) | 392 | (((current & 0x10) >> 4) << 6) | 393 | (((current & 0x20) >> 5) << 5) | 394 | (((current & 0x20) >> 5) << 4) | 395 | (((current & 0x40) >> 6) << 3) | 396 | (((current & 0x40) >> 6) << 2) | 397 | (((current & 0x80) >> 7) << 1) | 398 | (((current & 0x80) >> 7) << 0)); 399 | } 400 | } 401 | 402 | /* 403 | This function is not used anymore 404 | */ 405 | __attribute__((at(0x00219200, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 406 | int find_esb_address(uint8_t *buffer, uint8_t size) { 407 | uint8_t patterna = preamble & 0xFF; 408 | uint8_t patternb = (preamble & 0xFF00) >> 8; 409 | uint8_t patternc = (preamble & 0xFF0000) >> 16; 410 | int found = 0; 411 | if (patterna != 0 && patternb != 0 && patternc != 0) { 412 | for (int i=0;i<8*size-24;i++) { 413 | shift_buffer(buffer,size); 414 | if (buffer[2] == patterna && buffer[3] == patternb && buffer[4] == patternc) { 415 | found = 1; 416 | break; 417 | } 418 | } 419 | } 420 | return found; 421 | } 422 | 423 | /* 424 | This function extracts the payload of an Enhanced ShockBurst frame 425 | */ 426 | __attribute__((at(0x00219300, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 427 | uint8_t extract_payload_esb(uint8_t *buffer, uint8_t *dest) { 428 | uint8_t size = buffer[0] >> 2; 429 | if (size > 0 && size < 30) { 430 | for (int i=0;i> 7); 432 | } 433 | } 434 | else { 435 | size = 0; 436 | } 437 | return size; 438 | } 439 | 440 | /* 441 | Main RX callback : handles every RX mode, applies the different operations allowing to decode / convert the received frames, tranmits to the Host 442 | */ 443 | __attribute__((at(0x00210700, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 444 | __attribute__((optimize("O0"))) 445 | __attribute__((naked)) 446 | void rx_callback(int* func) { 447 | __asm__("push {r4-r11,lr}\n\t"); 448 | if (rx_enabled != 0) { 449 | 450 | if ((*((int*)0x318bac) & 256) && (rx_done == 0)){ 451 | memsetbt(raw_buffer,0,255); 452 | memcpybt_8(raw_buffer,(void*)(0x372400),255); 453 | 454 | if (rx_enabled == 1) { 455 | decode(buffer_decoded,&buffer_decoded_size,raw_buffer); 456 | if (buffer_decoded_size > 0 && buffer_decoded_size < 60) { 457 | char* buffer = bthci_event_AllocateEventAndFillHeader(buffer_decoded_size+2+2, 0xff, buffer_decoded_size+2); 458 | buffer[10] =(uint8_t)rx_enabled; 459 | buffer[11] =(uint8_t)rx_frequency; 460 | memcpybt(&buffer[12],buffer_decoded,buffer_decoded_size); 461 | // Forge HCI response and send it to host 462 | bthci_event_AttemptToEnqueueEventToTransport(buffer); 463 | } 464 | } 465 | else if (rx_enabled == 2 ) { 466 | decode_mosart(buffer_decoded,&buffer_decoded_size,raw_buffer); 467 | 468 | if (check_frame(buffer_decoded,buffer_decoded_size,&start_mosart_frame)) { 469 | char* buffer = bthci_event_AllocateEventAndFillHeader(buffer_decoded_size-start_mosart_frame+4+2+2, 0xff, buffer_decoded_size-start_mosart_frame+4+2); 470 | buffer[10] =(uint8_t)rx_enabled; 471 | buffer[11] =(uint8_t)rx_frequency; 472 | memcpybt(&buffer[12],buffer_decoded+start_mosart_frame-4,buffer_decoded_size-start_mosart_frame+4); 473 | // Forge HCI response and send it to host 474 | bthci_event_AttemptToEnqueueEventToTransport(buffer); 475 | } 476 | } 477 | else if (rx_enabled == 3) { 478 | decode_mosart(buffer_decoded,&buffer_decoded_size,raw_buffer+1); 479 | char* buffer = bthci_event_AllocateEventAndFillHeader(1+2+2, 0xff, 1+2); 480 | buffer[10] =(uint8_t)rx_enabled; 481 | buffer[11] =(uint8_t)rx_frequency; 482 | memcpybt(&buffer[12],buffer_decoded,1); 483 | // Forge HCI response and send it to host 484 | bthci_event_AttemptToEnqueueEventToTransport(buffer); 485 | 486 | } 487 | else if (rx_enabled == 4) { 488 | decode_mosart(buffer_decoded,&buffer_decoded_size,raw_buffer); 489 | 490 | if (check_frame(buffer_decoded,buffer_decoded_size,&start_mosart_frame)) { 491 | if ((buffer_decoded[start_mosart_frame-4+0] == (preamble & 0xFF) && buffer_decoded[start_mosart_frame-4+1] == ((preamble & 0xFF00) >> 8) && buffer_decoded[start_mosart_frame-4+2] == ((preamble & 0xFF0000) >> 16) && buffer_decoded[start_mosart_frame-4+3] == ((preamble & 0xFF000000) >> 24))) { 492 | char* buffer = bthci_event_AllocateEventAndFillHeader(buffer_decoded_size-start_mosart_frame+4+2+2, 0xff, buffer_decoded_size-start_mosart_frame+4+2); 493 | buffer[10] =(uint8_t)rx_enabled; 494 | buffer[11] =(uint8_t)rx_frequency; 495 | memcpybt(&buffer[12],buffer_decoded+start_mosart_frame-4,buffer_decoded_size-start_mosart_frame+4); 496 | // Forge HCI response and send it to host 497 | bthci_event_AttemptToEnqueueEventToTransport(buffer); 498 | } 499 | } 500 | } 501 | else if (rx_enabled == 5) { 502 | for (int i=0;i<200;i++) raw_buffer[i] = swap_bits(raw_buffer[i]); 503 | 504 | char* buffer = bthci_event_AllocateEventAndFillHeader(5+2+2, 0xff,5+2); 505 | buffer[10] =(uint8_t)rx_enabled; 506 | buffer[11] =(uint8_t)rx_frequency; 507 | buffer[12] = swap_bits((rx_header & 0xFF)); 508 | buffer[13] = swap_bits((rx_header & 0xFF00) >> 8); 509 | memcpybt(&buffer[14],raw_buffer,3); 510 | // Forge HCI response and send it to host 511 | bthci_event_AttemptToEnqueueEventToTransport(buffer); 512 | } 513 | else if (rx_enabled == 6) { 514 | for (int i=0;i<200;i++) raw_buffer[i] = swap_bits(raw_buffer[i]); 515 | 516 | buffer_decoded_size = extract_payload_esb(raw_buffer,buffer_decoded); 517 | 518 | char* buffer = bthci_event_AllocateEventAndFillHeader(buffer_decoded_size+2+2, 0xff,buffer_decoded_size+2); 519 | buffer[10] =(uint8_t)rx_enabled; 520 | buffer[11] =(uint8_t)rx_frequency; 521 | 522 | 523 | memcpybt(&buffer[12],buffer_decoded,buffer_decoded_size); 524 | // Forge HCI response and send it to host 525 | bthci_event_AttemptToEnqueueEventToTransport(buffer); 526 | } 527 | rx_done = 1; 528 | } 529 | else { 530 | rx_done = 0; 531 | } 532 | } 533 | __asm__("pop {r4-r11,lr}\n\t" 534 | "push.w {r4-r8,lr}\n\t" 535 | "b 0x7C890\n\t" 536 | ); 537 | } 538 | /* 539 | Redirects the flow of extendedScanTaskRxDone to rx_callback 540 | */ 541 | __attribute__((at(0x7C88C, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 542 | BPatch(rx_callback_patch, rx_callback); 543 | 544 | /* 545 | Function used to disable the whitening / dewhitening if a RX or a TX is selected 546 | */ 547 | __attribute__((at(0x00210c00, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 548 | __attribute__((optimize("O0"))) 549 | __attribute__((naked)) 550 | void disable_whitening(int* func) { 551 | if (rx_enabled != 0 || tx_enabled != 0) { 552 | __asm__("ldr r3,=0x00000000\n\t"); 553 | } 554 | else { 555 | __asm__("ldr r3,=0x00203150\n\t" 556 | "ldr r3,[r3]\n\t"); 557 | 558 | 559 | } 560 | __asm__("b 0x715B8\n\t"); 561 | } 562 | /* 563 | Redirect the flow of bcsulp_setupWhitening to disable_whitening 564 | */ 565 | __attribute__((at(0x715B4, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 566 | BPatch(disable_whitening_patch, disable_whitening); 567 | 568 | /* 569 | Function used to configure the RX preamble and LE 2M physical layer in RX mode according to the selected protocol 570 | */ 571 | __attribute__((at(0x00210d00, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 572 | __attribute__((optimize("O0"))) 573 | __attribute__((naked)) 574 | 575 | void set_preamble(int* func) { 576 | if (rx_enabled != 0) { 577 | if (rx_enabled == 1) { 578 | __asm__("ldr r0,=0x9b3af703\n\t" 579 | "b.w 0x90020\n\t"); 580 | } 581 | else if (rx_enabled == 2 || rx_enabled == 4) { 582 | __asm__("ldr r0,=0x33333333\n\t" 583 | "b.w 0x90020\n\t"); 584 | } 585 | else if (rx_enabled == 5) { 586 | __asm__("ldr r0,=0x55000000\n\t" 587 | "b.w 0x90020\n\t"); 588 | } 589 | else if (rx_enabled == 3 || rx_enabled == 6) { 590 | __asm__("ldr r0,=preamble\n\t" //3f cc 0c 0c // marche pour les calviers mais pas aligné : 0x300fcf0c 591 | "ldr r0,[r0]\n\t" 592 | "b.w 0x90020\n\t"); 593 | } 594 | } 595 | else { 596 | __asm__("cbz r0,le1m_mode\n\t" 597 | "mov r0,r1\n\t" 598 | "b.w 0x90020\n\t" 599 | "le1m_mode:\n\t" 600 | "b.w 0x90084\n\t"); 601 | 602 | 603 | } 604 | } 605 | /* 606 | Redirects the flow of le2m_setupAdvChannelFor2M to set_preamble 607 | */ 608 | __attribute__((at(0x9007C, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 609 | BPatch(set_preamble_patch, set_preamble); 610 | 611 | /* 612 | Function allowing to select the RX frequency 613 | */ 614 | __attribute__((at(0x00210e00, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 615 | __attribute__((optimize("O0"))) 616 | __attribute__((naked)) 617 | 618 | void set_rx_frequency(int* func) { 619 | __asm__("push {r0-r3}\n\t"); 620 | if (rx_enabled != 0) { 621 | __asm__("ldr r0,=rx_frequency\n\t" 622 | "ldr r0,[r0]\n\t" 623 | "ldr r1,=0x3186a4\n\t" 624 | "orr.w r0,r0,#0x80\n\t" 625 | "str r0,[r1]\n\t" 626 | "pop {r0-r3}\n\t" 627 | "b 0x7A1BA\n\t" 628 | ); 629 | } 630 | else { 631 | __asm__("pop {r0-r3}\n\t" 632 | "b 0x7A196\n\t"); 633 | } 634 | } 635 | /* 636 | Redirects the flow of _scanTaskLcuCmdCommon to set_rx_frequency 637 | */ 638 | __attribute__((at(0x7A192, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 639 | BPatch(set_rx_frequency_patch, set_rx_frequency); 640 | 641 | 642 | 643 | /* 644 | Function allowing to enable and configure RX mode 645 | */ 646 | __attribute__((at(0x00210f00, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 647 | void bthci_cmd_start_rx(uint8_t *hci_cmd_buffer) { 648 | char* buffer = bthci_event_AllocateEventAndFillHeader(4+2, 0xFF, 4); 649 | 650 | // save Zigbee RX mode 651 | rx_enabled = hci_cmd_buffer[12]; 652 | 653 | // save Zigbee channel 654 | // TODO: I should check the interval and trigger an error if needed 655 | rx_frequency = (rx_enabled == 0x01 ? channelToFrequency(hci_cmd_buffer[13]) : hci_cmd_buffer[13]-2); 656 | 657 | // Reset fake HCI buffer 658 | for (int i=0;i<40;i++) fake_hci_buffer[i] = 0; 659 | fake_hci_buffer[8] = 0x01; 660 | fake_hci_buffer[9] = 0x42; 661 | fake_hci_buffer[10] = 0x20; 662 | fake_hci_buffer[11] = 0x06; 663 | fake_hci_buffer[12] = 0x00; 664 | fake_hci_buffer[13] = 0x00; 665 | fake_hci_buffer[14] = 0x00; 666 | fake_hci_buffer[15] = 0x00; 667 | fake_hci_buffer[16] = 0x00; 668 | fake_hci_buffer[17] = 0x00; 669 | bthci_cmd_ble_HandleSet_Extended_Scan_Enable(fake_hci_buffer); 670 | if (rx_enabled != 0) { 671 | // Reset fake HCI buffer 672 | for (int i=0;i<40;i++) fake_hci_buffer[i] = 0; 673 | fake_hci_buffer[8] = 0x01; 674 | fake_hci_buffer[9] = 0x41; 675 | fake_hci_buffer[10] = 0x20; 676 | fake_hci_buffer[11] = 0x08; 677 | fake_hci_buffer[12] = 0x01; 678 | fake_hci_buffer[13] = 0x00; 679 | fake_hci_buffer[14] = 0x01; 680 | fake_hci_buffer[15] = 0x01; 681 | fake_hci_buffer[16] = 0x99; 682 | fake_hci_buffer[17] = 0x19; 683 | fake_hci_buffer[18] = 0x99; 684 | fake_hci_buffer[19] = 0x19; 685 | bthci_cmd_ble_HandleSet_Extended_Scan_Parameters(fake_hci_buffer); 686 | 687 | // Configure fake HCI buffer to enable or disable LE scan 688 | 689 | 690 | for (int i=0;i<40;i++) fake_hci_buffer[i] = 0; 691 | fake_hci_buffer[8] = 0x01; 692 | fake_hci_buffer[9] = 0x42; 693 | fake_hci_buffer[10] = 0x20; 694 | fake_hci_buffer[11] = 0x06; 695 | fake_hci_buffer[12] = 0x01; 696 | fake_hci_buffer[13] = 0x00; 697 | fake_hci_buffer[14] = 0x00; 698 | fake_hci_buffer[15] = 0x00; 699 | fake_hci_buffer[16] = 0x00; 700 | fake_hci_buffer[17] = 0x00; 701 | 702 | bthci_cmd_ble_HandleSet_Extended_Scan_Enable(fake_hci_buffer); 703 | } 704 | if (rx_enabled == 2) { 705 | dongle_mode = (hci_cmd_buffer[14] == 0 ? 0x00 : 0x01); 706 | } 707 | if (rx_enabled == 3) { 708 | memcpybt(raw_buffer,&hci_cmd_buffer[14],4); 709 | raw_buffer[4] = 0x70; 710 | encode_mosart(buffer_decoded,raw_buffer,5); 711 | preamble = (buffer_decoded[8] << 24) | (buffer_decoded[7] << 16) | (buffer_decoded[6] << 8) | (buffer_decoded[5]); 712 | } 713 | else if (rx_enabled == 4) { 714 | dongle_mode = 0x00; 715 | preamble = (hci_cmd_buffer[17] << 24) | (hci_cmd_buffer[16] << 16) | ((hci_cmd_buffer[15]) << 8) | hci_cmd_buffer[14]; 716 | } 717 | else if (rx_enabled == 5) { 718 | /* 719 | dongle_mode = (hci_cmd_buffer[14] == 0 ? 0x00 : 0x01); 720 | preamble = (hci_cmd_buffer[17] << 16)|(hci_cmd_buffer[16] << 8)| hci_cmd_buffer[15]; 721 | */ 722 | } 723 | else if (rx_enabled == 6) { 724 | memcpybt(raw_buffer,&hci_cmd_buffer[14],5); 725 | preamble = ((swap_bits(raw_buffer[2]) << 24) |(swap_bits(raw_buffer[1]) << 16) | (swap_bits(raw_buffer[0]) << 8) | (swap_bits(0xAA))); 726 | } 727 | // Forge HCI response and send it to host 728 | buffer[10] = 0x52; 729 | buffer[11] = 0x58; 730 | buffer[12] = (uint8_t)rx_enabled; 731 | buffer[13] = (uint8_t)rx_frequency; 732 | bthci_event_AttemptToEnqueueEventToTransport(buffer); 733 | } 734 | 735 | 736 | /* 737 | bthci_cmd_start_rx is registered as a BLE HCI address (opcode = 0x2060) 738 | Adds the bthci_cmd_start_rx address to the BLE HCI commands table 739 | */ 740 | REGISTER_HCI_FUNCTION(0x60,0x00080000,bthci_cmd_start_rx); 741 | 742 | __attribute__((at(0x214400, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 743 | __attribute__((optimize("O0"))) 744 | __attribute__((naked)) 745 | 746 | /* 747 | This function allows to select the LE 2M physical layer if TX mode is enabled. 748 | */ 749 | void set_tx_le2m(int* func) { 750 | 751 | __asm__( 752 | "ldr r0,=tx_enabled\n\t" 753 | "ldr r0,[r0]\n\t" 754 | "cmp r0,#0\n\t" 755 | "beq normal_behaviour_txle2m\n\t" 756 | "ldr r0,=0x9b3af703\n\t" 757 | "bl 0x90020\n\t" 758 | "ldr r3,=0x00000000\n\t" 759 | "ldr r2,=0x000279a5\n\t" 760 | "str r3,[r2]\n\t" 761 | "b 0x74DAC\n\t" 762 | "normal_behaviour_txle2m:\n\t" 763 | "bl 0x9007C\n\t" 764 | "b 0x74DAC\n\t"); 765 | 766 | } 767 | /* 768 | Redirects the flow of extendedAdvTaskProgHw to set_tx_le2M 769 | */ 770 | __attribute__((at(0x74DA8, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 771 | BPatch(set_tx_le2m_patch, set_tx_le2m); 772 | 773 | /* 774 | Function setting the TX frequency. 775 | */ 776 | __attribute__((at(0x214500, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 777 | __attribute__((optimize("O0"))) 778 | __attribute__((naked)) 779 | void set_tx_frequency(int* func) { 780 | __asm__( 781 | "ldr r0,=tx_enabled\n\t" 782 | "ldr r0,[r0]\n\t" 783 | "cmp r0,#0\n\t" 784 | "beq normal_behaviour_txfreq\n\t" 785 | "ldr r2,=tx_frequency\n\t" 786 | "ldr r2,[r2]\n\t" 787 | "b 0x74F96\n\t" 788 | "normal_behaviour_txfreq:\n\t" 789 | "ldr.w r2,[r4,#0x288]\n\t" 790 | "b 0x74F96\n\t"); 791 | 792 | } 793 | 794 | /* 795 | Redirects the flow of extendedAdvTaskProgHW to set_tx_frequency 796 | */ 797 | __attribute__((at(0x74F92, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 798 | BPatch(set_tx_frequency_patch, set_tx_frequency); 799 | 800 | /* 801 | Function allowing to enable and configure TX mode. 802 | */ 803 | __attribute__((at(0x214600, "", CHIP_VER_BCM4375B1_BT, FW_VER_S20))) 804 | __attribute__((optimize("O0"))) 805 | void bthci_cmd_start_tx(uint8_t *hci_cmd_buffer) { 806 | 807 | tx_enabled = 0x01; 808 | tx_frequency = (hci_cmd_buffer[12] == 0x01 ? channelToFrequency(hci_cmd_buffer[13]) : hci_cmd_buffer[13]-2); 809 | 810 | 811 | buffer_decoded_size = hci_cmd_buffer[14]; 812 | if (hci_cmd_buffer[12] == 0x01) { 813 | 814 | for (int i=0;i<4;i++) { 815 | buffer_decoded[i] = 0; 816 | } 817 | // Save decoded packet in RAM 818 | memcpybt(&buffer_decoded[4],&hci_cmd_buffer[15],buffer_decoded_size); 819 | 820 | // Generate GMSK representation of Zigbee packet 821 | for (int i=0;i<255;i++) raw_buffer[i] = 0; 822 | for (int i=0;i> 4; 824 | uint8_t lsb = buffer_decoded[i] & 0x0F; 825 | 826 | raw_buffer[i*8+0] = (SYMBOL_TO_CHIP_MAPPING[lsb][0]); 827 | raw_buffer[i*8+1] = (SYMBOL_TO_CHIP_MAPPING[lsb][1]); 828 | raw_buffer[i*8+2] = (SYMBOL_TO_CHIP_MAPPING[lsb][2]); 829 | raw_buffer[i*8+3] = (SYMBOL_TO_CHIP_MAPPING[lsb][3]); 830 | 831 | raw_buffer[i*8+4] = (SYMBOL_TO_CHIP_MAPPING[msb][0]); 832 | raw_buffer[i*8+5] = (SYMBOL_TO_CHIP_MAPPING[msb][1]); 833 | raw_buffer[i*8+6] = (SYMBOL_TO_CHIP_MAPPING[msb][2]); 834 | raw_buffer[i*8+7] = (SYMBOL_TO_CHIP_MAPPING[msb][3]); 835 | } 836 | } 837 | else if (hci_cmd_buffer[12] == 0x02 || hci_cmd_buffer[12] == 0x03 || hci_cmd_buffer[12] == 0x04 ) { 838 | memcpybt(buffer_decoded,&hci_cmd_buffer[15],buffer_decoded_size); 839 | encode_mosart(raw_buffer,buffer_decoded,buffer_decoded_size); 840 | } 841 | else if (hci_cmd_buffer[12] == 0x05 || hci_cmd_buffer[12] == 0x06 ) { 842 | memcpybt(buffer_decoded,&hci_cmd_buffer[15],buffer_decoded_size); 843 | for (int i=0;i