This commit is contained in:
Sil333033
2023-10-25 21:32:31 +02:00
28 changed files with 763 additions and 305 deletions

View File

@@ -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 (

View File

@@ -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

View File

@@ -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"]

View File

@@ -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 }}

View File

@@ -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: |

View File

@@ -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: |

View File

@@ -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",

View File

@@ -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, "<Send");
canvas_draw_str_aligned(canvas, 122, 22, AlignRight, AlignBottom, str);
canvas_invert_color(canvas);
} else {
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), 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);

View File

@@ -10,12 +10,12 @@
#include <core/core_defines.h>
#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;

View File

@@ -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[];

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -5,7 +5,7 @@
// Research by @Spooks4576
typedef enum {
EasysetupTypeBuds,
EasysetupTypeBuds = 0x01, // Skip 0 as it means unset
EasysetupTypeWatch,
EasysetupTypeCOUNT,
} EasysetupType;

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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) {

11
fbt
View File

@@ -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 "$@"

12
fbt.cmd
View File

@@ -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
)
)

View File

@@ -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) {

View File

@@ -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

View File

@@ -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):

View File

@@ -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

View File

@@ -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")

View File

@@ -270,6 +270,11 @@ vars.AddVariables(
"clangd",
],
),
BoolVariable(
"STRICT_FAP_IMPORT_CHECK",
help="Enable strict import check for .faps",
default=True,
),
)
Return("vars")