Skip to content

Commit

Permalink
Merge pull request RogueMaster#57 from Ganapati/dev
Browse files Browse the repository at this point in the history
Add SubGhz Fuzzer
xMasterX authored Sep 8, 2022

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
2 parents 6decd6f + 18891ad commit 7de9c95
Showing 21 changed files with 1,534 additions and 7 deletions.
2 changes: 1 addition & 1 deletion applications/flipfrid/application.fam
Original file line number Diff line number Diff line change
@@ -6,5 +6,5 @@ App(
cdefines=["APP_FLIP_FRID"],
requires=["gui"],
stack_size=1 * 1024,
order=29,
order=13,
)
12 changes: 7 additions & 5 deletions applications/flipfrid/scene/flipfrid_scene_run_attack.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "flipfrid_scene_run_attack.h"
#include <gui/elements.h>

uint8_t counter = 0;
#define TIME_BETWEEN_CARDS 5
@@ -182,7 +183,7 @@ void flipfrid_scene_run_attack_on_draw(Canvas* canvas, FlipFridState* context) {
canvas_set_color(canvas, ColorBlack);

// Frame
canvas_draw_frame(canvas, 0, 0, 128, 64);
//canvas_draw_frame(canvas, 0, 0, 128, 64);

// Title
canvas_set_font(canvas, FontPrimary);
@@ -202,11 +203,12 @@ void flipfrid_scene_run_attack_on_draw(Canvas* canvas, FlipFridState* context) {
canvas_draw_str_aligned(canvas, 64, 24, AlignCenter, AlignTop, uid);

canvas_set_font(canvas, FontSecondary);
char start_stop_msg[20];
//char start_stop_msg[20];
if(context->is_attacking) {
snprintf(start_stop_msg, sizeof(start_stop_msg), " Press OK to stop ");
elements_button_center(canvas, "Stop");
//snprintf(start_stop_msg, sizeof(start_stop_msg), " Press OK to stop ");
} else {
snprintf(start_stop_msg, sizeof(start_stop_msg), " Press OK to start ");
elements_button_center(canvas, "Start");
}
canvas_draw_str_aligned(canvas, 64, 44, AlignCenter, AlignTop, start_stop_msg);
//canvas_draw_str_aligned(canvas, 64, 44, AlignCenter, AlignTop, start_stop_msg);
}
2 changes: 1 addition & 1 deletion applications/flipfrid/scene/flipfrid_scene_select_field.c
Original file line number Diff line number Diff line change
@@ -104,7 +104,7 @@ void flipfrid_scene_select_field_on_draw(Canvas* canvas, FlipFridState* context)
canvas_set_color(canvas, ColorBlack);

// Frame
canvas_draw_frame(canvas, 0, 0, 128, 64);
//canvas_draw_frame(canvas, 0, 0, 128, 64);

// Title
canvas_set_font(canvas, FontPrimary);
1 change: 1 addition & 0 deletions applications/meta/application.fam
Original file line number Diff line number Diff line change
@@ -78,5 +78,6 @@ App(
"wifi_scanner",
"multi_converter",
"flipfrid",
"subbrute",
],
)
8 changes: 8 additions & 0 deletions applications/subbrute/LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* @G4N4P4T1 wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return.
* ----------------------------------------------------------------------------
*/
4 changes: 4 additions & 0 deletions applications/subbrute/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# FlipFrid

SubGhz Fuzzer
select your base message, the field to fuzz and let's get fuzzy !
10 changes: 10 additions & 0 deletions applications/subbrute/application.fam
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
App(
appid="subbrute",
name="SubGHz Bruteforcer",
apptype=FlipperAppType.PLUGIN,
entry_point="subbrute_start",
cdefines=["APP_SUB_BRUTE"],
requires=["gui","dialogs"],
stack_size=2 * 1024,
order=11,
)
198 changes: 198 additions & 0 deletions applications/subbrute/scene/subbrute_scene_entrypoint.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
#include "subbrute_scene_entrypoint.h"
#include "../subbrute_utils.h"

string_t subbrute_menu_items[9];

void subbrute_scene_entrypoint_menu_callback(SubBruteState* context, uint32_t index) {
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
string_set_str(context->protocol, "RAW");
context->repeat = 5;
context->te = 0;
context->attack = index;
switch(index) {
case SubBruteAttackLoadFile:
context->current_scene = SceneSelectFile;
break;
case SubBruteAttackCAME12bit433:
context->frequency = 433920000;
context->bit = 12;
string_set_str(context->protocol, "CAME");
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
if(!subbrute_is_frequency_allowed(context)) {
return;
}
context->current_scene = SceneAttack;
break;
case SubBruteAttackCAME12bit868:
context->frequency = 868350000;
context->bit = 12;
string_set_str(context->protocol, "CAME");
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
if(!subbrute_is_frequency_allowed(context)) {
return;
}
context->current_scene = SceneAttack;
break;
case SubBruteAttackChamberlain9bit315:
context->frequency = 315000000;
context->bit = 9;
string_set_str(context->protocol, "Cham_Code");
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");

if(!subbrute_is_frequency_allowed(context)) {
return;
}
context->current_scene = SceneAttack;
break;
case SubBruteAttackChamberlain9bit390:
context->frequency = 390000000;
context->bit = 9;
string_set_str(context->protocol, "Cham_Code");
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");

if(!subbrute_is_frequency_allowed(context)) {
return;
}
context->current_scene = SceneAttack;
break;
case SubBruteAttackLinear10bit300:
context->frequency = 300000000;
context->bit = 10;
string_set_str(context->protocol, "Linear");
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
if(!subbrute_is_frequency_allowed(context)) {
return;
}
context->current_scene = SceneAttack;
break;
case SubBruteAttackLinear10bit310:
context->frequency = 310000000;
context->bit = 10;
string_set_str(context->protocol, "Linear");
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
if(!subbrute_is_frequency_allowed(context)) {
return;
}
context->current_scene = SceneAttack;
break;
case SubBruteAttackNICE12bit433:
context->frequency = 433920000;
context->bit = 12;
string_set_str(context->protocol, "Nice FLO");
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
if(!subbrute_is_frequency_allowed(context)) {
return;
}
context->current_scene = SceneAttack;
break;
case SubBruteAttackNICE12bit868:
context->frequency = 868350000;
context->bit = 12;
string_set_str(context->protocol, "Nice FLO");
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
if(!subbrute_is_frequency_allowed(context)) {
return;
}
context->current_scene = SceneAttack;
break;
default:
break;
}
}

void subbrute_scene_entrypoint_on_enter(SubBruteState* context) {
// Clear the previous payload
context->menu_index = 0;
for(uint32_t i = 0; i < 9; i++) {
string_init(subbrute_menu_items[i]);
}

string_set(subbrute_menu_items[0], "BF existing dump");
string_set(subbrute_menu_items[1], "CAME 12bit 433mhz");
string_set(subbrute_menu_items[2], "CAME 12bit 868mhz");
string_set(subbrute_menu_items[3], "Chamberlain 9bit 315mhz");
string_set(subbrute_menu_items[4], "Chamberlain 9bit 390mhz");
string_set(subbrute_menu_items[5], "Linear 10bit 300mhz");
string_set(subbrute_menu_items[6], "Linear 10bit 310mhz");
string_set(subbrute_menu_items[7], "NICE 12bit 433mhz");
string_set(subbrute_menu_items[8], "NICE 12bit 868mhz");
}

void subbrute_scene_entrypoint_on_exit(SubBruteState* context) {
UNUSED(context);
for(uint32_t i = 0; i < 9; i++) {
string_clear(subbrute_menu_items[i]);
}
}

void subbrute_scene_entrypoint_on_tick(SubBruteState* context) {
UNUSED(context);
}

void subbrute_scene_entrypoint_on_event(SubBruteEvent event, SubBruteState* context) {
if(event.evt_type == EventTypeKey) {
if(event.input_type == InputTypeShort) {
switch(event.key) {
case InputKeyDown:
if(context->menu_index < SubBruteAttackNICE12bit868) {
context->menu_index++;
}
break;
case InputKeyUp:
if(context->menu_index > SubBruteAttackLoadFile) {
context->menu_index--;
}
break;
case InputKeyLeft:
case InputKeyRight:
break;
case InputKeyOk:
subbrute_scene_entrypoint_menu_callback(context, context->menu_index);
break;
case InputKeyBack:
context->is_running = false;
break;
}
}
}
}

void subbrute_scene_entrypoint_on_draw(Canvas* canvas, SubBruteState* context) {
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);

// Title
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 64, 6, AlignCenter, AlignTop, "SubGHz Fuzzer");

if(context->menu_index > SubBruteAttackLoadFile) {
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas,
64,
24,
AlignCenter,
AlignTop,
string_get_cstr(subbrute_menu_items[context->menu_index - 1]));
}

canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(
canvas,
64,
36,
AlignCenter,
AlignTop,
string_get_cstr(subbrute_menu_items[context->menu_index]));

if(context->menu_index < SubBruteAttackNICE12bit868) {
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas,
64,
48,
AlignCenter,
AlignTop,
string_get_cstr(subbrute_menu_items[context->menu_index + 1]));
}
}
8 changes: 8 additions & 0 deletions applications/subbrute/scene/subbrute_scene_entrypoint.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once
#include "../subbrute.h"

void subbrute_scene_entrypoint_on_enter(SubBruteState* context);
void subbrute_scene_entrypoint_on_exit(SubBruteState* context);
void subbrute_scene_entrypoint_on_tick(SubBruteState* context);
void subbrute_scene_entrypoint_on_event(SubBruteEvent event, SubBruteState* context);
void subbrute_scene_entrypoint_on_draw(Canvas* canvas, SubBruteState* context);
212 changes: 212 additions & 0 deletions applications/subbrute/scene/subbrute_scene_load_file.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
#include "subbrute_scene_load_file.h"
#include "subbrute_scene_entrypoint.h"
#include "../subbrute_utils.h"
#include <lib/subghz/protocols/registry.h>

#define SUBGHZ_APP_PATH_FOLDER "/ext/subghz"

bool subbrute_load(SubBruteState* context, const char* file_path) {
bool result = false;

Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);

string_t temp_str;
string_init(temp_str);
uint32_t temp_data32;

do {
if(!flipper_format_file_open_existing(fff_data_file, file_path)) {
FURI_LOG_E(TAG, "Error open file %s", file_path);
string_reset(context->notification_msg);
string_set_str(context->notification_msg, "Error open file");
break;
}
if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) {
FURI_LOG_E(TAG, "Missing or incorrect header");
string_reset(context->notification_msg);
string_set_str(context->notification_msg, "Missing or incorrect header");
break;
}
// Frequency
if(flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) {
FURI_LOG_I(TAG, "Frequency: %d", temp_data32);
context->frequency = temp_data32;
if(!subbrute_is_frequency_allowed(context)) {
break;
}
} else {
FURI_LOG_E(TAG, "Missing or incorrect Frequency");
string_reset(context->notification_msg);
string_set_str(context->notification_msg, "Missing or incorrect Frequency");
break;
}
// Preset
if(!flipper_format_read_string(fff_data_file, "Preset", context->preset)) {
FURI_LOG_E(TAG, "Preset FAIL");
string_reset(context->notification_msg);
string_set_str(context->notification_msg, "Preset FAIL");
}
// Protocol
if(!flipper_format_read_string(fff_data_file, "Protocol", context->protocol)) {
FURI_LOG_E(TAG, "Missing Protocol");
string_reset(context->notification_msg);
string_set_str(context->notification_msg, "Missing Protocol");
break;
} else {
FURI_LOG_I(TAG, "Protocol: %s", string_get_cstr(context->protocol));
}

if(strcmp(string_get_cstr(context->protocol), "RAW") == 0) {
FURI_LOG_E(TAG, "RAW unsupported");
string_reset(context->notification_msg);
string_set_str(context->notification_msg, "RAW unsupported");
break;
}

const SubGhzProtocol* registry =
subghz_protocol_registry_get_by_name(string_get_cstr(context->protocol));

if(registry && registry->type == SubGhzProtocolTypeDynamic) {
FURI_LOG_D(TAG, "Protocol is dynamic - not supported");
string_reset(context->notification_msg);
string_set_str(context->notification_msg, "Dynamic protocol unsupported");
break;
}

context->decoder_result = subghz_receiver_search_decoder_base_by_name(
context->receiver, string_get_cstr(context->protocol));

if(context->decoder_result) {
FURI_LOG_I(TAG, "Found decoder");
} else {
FURI_LOG_E(TAG, "Protocol not found");
string_reset(context->notification_msg);
string_set_str(context->notification_msg, "Protocol not found");
break;
}

// Bit
if(!flipper_format_read_uint32(fff_data_file, "Bit", &temp_data32, 1)) {
FURI_LOG_E(TAG, "Missing or incorrect Bit");
string_reset(context->notification_msg);
string_set_str(context->notification_msg, "Missing or incorrect Bit");
break;
} else {
FURI_LOG_I(TAG, "Bit: %d", temp_data32);
context->bit = temp_data32;
}

// Key
if(!flipper_format_read_string(fff_data_file, "Key", temp_str)) {
FURI_LOG_E(TAG, "Missing or incorrect Key");
string_reset(context->notification_msg);
string_set_str(context->notification_msg, "Missing or incorrect Key");
break;
} else {
FURI_LOG_I(TAG, "Key: %s", string_get_cstr(temp_str));
string_set(context->key, string_get_cstr(temp_str));
}

// TE
if(!flipper_format_read_uint32(fff_data_file, "TE", &temp_data32, 1)) {
FURI_LOG_E(TAG, "Missing or incorrect TE");
//string_reset(context->notification_msg);
//string_set_str(context->notification_msg, "Missing or incorrect TE");
//break;
} else {
FURI_LOG_I(TAG, "TE: %d", temp_data32);
context->te = temp_data32;
}

// Repeat
if(flipper_format_read_uint32(fff_data_file, "Repeat", &temp_data32, 1)) {
FURI_LOG_I(TAG, "Repeat: %d", temp_data32);
context->repeat = temp_data32;
} else {
FURI_LOG_I(TAG, "Repeat: 3 (default)");
context->repeat = 3;
}

result = true;
} while(0);

string_clear(temp_str);
flipper_format_file_close(fff_data_file);
flipper_format_free(fff_data_file);
if(result) {
FURI_LOG_I(TAG, "Loaded successfully");
string_reset(context->notification_msg);
string_set_str(context->notification_msg, "File looks ok.");
}

return result;
}

void subbrute_scene_load_file_on_enter(SubBruteState* context) {
if(subbrute_load_protocol_from_file(context)) {
context->current_scene = SceneSelectField;
} else {
subbrute_scene_entrypoint_on_enter(context);
context->current_scene = SceneEntryPoint;
}
}

void subbrute_scene_load_file_on_exit(SubBruteState* context) {
UNUSED(context);
}

void subbrute_scene_load_file_on_tick(SubBruteState* context) {
UNUSED(context);
}

void subbrute_scene_load_file_on_event(SubBruteEvent event, SubBruteState* context) {
UNUSED(context);
if(event.evt_type == EventTypeKey) {
if(event.input_type == InputTypeShort) {
switch(event.key) {
case InputKeyDown:
case InputKeyUp:
case InputKeyLeft:
case InputKeyRight:
case InputKeyOk:
break;
case InputKeyBack:
context->current_scene = SceneEntryPoint;
break;
}
}
}
}

void subbrute_scene_load_file_on_draw(Canvas* canvas, SubBruteState* context) {
UNUSED(context);
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);

// Frame
//canvas_draw_frame(canvas, 0, 0, 128, 64);

// Title
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 64, 16, AlignCenter, AlignTop, "SubGHz Fuzzer");
canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignTop, "Error: Press back");
}

bool subbrute_load_protocol_from_file(SubBruteState* context) {
string_t file_path;
string_init(file_path);
string_set_str(file_path, SUBGHZ_APP_PATH_FOLDER);

// Input events and views are managed by file_select
bool res = dialog_file_browser_show(
context->dialogs, file_path, file_path, SUBGHZ_APP_EXTENSION, true, &I_sub1_10px, true);

if(res) {
res = subbrute_load(context, string_get_cstr(file_path));
}

string_clear(file_path);

return res;
}
8 changes: 8 additions & 0 deletions applications/subbrute/scene/subbrute_scene_load_file.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include "../subbrute.h"

void subbrute_scene_load_file_on_enter(SubBruteState* context);
void subbrute_scene_load_file_on_exit(SubBruteState* context);
void subbrute_scene_load_file_on_tick(SubBruteState* context);
void subbrute_scene_load_file_on_event(SubBruteEvent event, SubBruteState* context);
void subbrute_scene_load_file_on_draw(Canvas* canvas, SubBruteState* context);
bool subbrute_load_protocol_from_file(SubBruteState* context);
320 changes: 320 additions & 0 deletions applications/subbrute/scene/subbrute_scene_run_attack.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,320 @@
#include "subbrute_scene_run_attack.h"
#include <lib/subghz/transmitter.h>
#include <gui/elements.h>

uint64_t subbrute_counter = 0;
uint64_t max_value;
bool locked = false;
bool toSave = false;
char subbrute_payload_byte[4];
#define SUBBRUTE_DELAY 1

FuriHalSubGhzPreset str_to_preset(string_t preset) {
if(string_cmp_str(preset, "FuriHalSubGhzPresetOok270Async") == 0) {
return FuriHalSubGhzPresetOok270Async;
}
if(string_cmp_str(preset, "FuriHalSubGhzPresetOok650Async") == 0) {
return FuriHalSubGhzPresetOok650Async;
}
if(string_cmp_str(preset, "FuriHalSubGhzPreset2FSKDev238Async") == 0) {
return FuriHalSubGhzPreset2FSKDev238Async;
}
if(string_cmp_str(preset, "FuriHalSubGhzPreset2FSKDev476Async") == 0) {
return FuriHalSubGhzPreset2FSKDev476Async;
}
if(string_cmp_str(preset, "FuriHalSubGhzPresetMSK99_97KbAsync") == 0) {
return FuriHalSubGhzPresetMSK99_97KbAsync;
}
if(string_cmp_str(preset, "FuriHalSubGhzPresetMSK99_97KbAsync") == 0) {
return FuriHalSubGhzPresetMSK99_97KbAsync;
}
return FuriHalSubGhzPresetCustom;
}

void subbrute_emit(SubBruteState* context) {
//FURI_LOG_D(TAG, string_get_cstr(context->flipper_format_string));

furi_hal_subghz_start_async_tx(subghz_transmitter_yield, context->transmitter);
while(!(furi_hal_subghz_is_async_tx_complete())) {
furi_delay_ms(5);
}

furi_hal_subghz_stop_async_tx();
furi_hal_subghz_idle();
}

void prepare_emit(SubBruteState* context) {
furi_hal_subghz_init();

context->transmitter =
subghz_transmitter_alloc_init(context->environment, string_get_cstr(context->protocol));

furi_hal_subghz_reset();
furi_hal_subghz_load_preset(str_to_preset(context->preset));

furi_hal_subghz_set_frequency_and_path(context->frequency);
}

void clear_emit(SubBruteState* context) {
furi_hal_subghz_stop_async_tx();
furi_hal_subghz_sleep();

subghz_transmitter_free(context->transmitter);
}
/*
void subbrute_send_raw_packet(SubBruteState* context) {
string_reset(context->candidate);
// Payload to padded binary string
int* binaryNum = (int*)malloc(sizeof(int) * context->bit);
uint32_t i = 0;
for(i = 0; i < context->bit; i++) {
binaryNum[i] = 0;
}
i = 0;
uint64_t counter = context->payload;
while(counter > 0) {
binaryNum[i] = counter % 2;
counter = counter / 2;
i++;
}
// printing binary array in reverse order and build raw payload
for(uint32_t loop = 0; loop < context->repeat; loop++) {
for(int j = (int)context->bit - 1; j >= 0; j--) {
if(binaryNum[j] == 1) {
string_cat(context->candidate, context->subbrute_raw_one);
} else {
string_cat(context->candidate, context->subbrute_raw_zero);
}
}
string_cat(context->candidate, context->subbrute_raw_stop);
}
free(binaryNum);
string_init_printf(
context->flipper_format_string,
"Filetype: Flipper SubGhz RAW File\n"
"Version: 1\n"
"Frequency: %d\n"
"Preset: %s\n"
"Protocol: RAW\n"
"RAW_Data: %s",
context->frequency,
string_get_cstr(context->preset),
string_get_cstr(context->candidate));
subbrute_emit(context);
}
*/
void subbrute_send_packet_parsed(SubBruteState* context) {
if(context->attack == SubBruteAttackLoadFile) {
snprintf(subbrute_payload_byte, 4, "%02X ", (uint8_t)context->payload);
string_replace_at(context->candidate, context->str_index, 3, subbrute_payload_byte);
} else {
string_t buffer;
string_init(buffer);
string_init_printf(buffer, "%16X", context->payload);
int j = 0;
string_set_str(context->candidate, " ");
for(uint8_t i = 0; i < 16; i++) {
if(string_get_char(buffer, i) != ' ') {
string_set_char(context->candidate, i + j, string_get_char(buffer, i));
} else {
string_set_char(context->candidate, i + j, '0');
}
if(i % 2 != 0) {
j++;
}
}
string_clear(buffer);
}
if(strcmp(string_get_cstr(context->protocol), "Princeton") == 0) {
string_init_printf(
context->flipper_format_string,
"Filetype: Flipper SubGhz Key File\n"
"Version: 1\n"
"Frequency: %u\n"
"Preset: %s\n"
"Protocol: %s\n"
"Bit: %d\n"
"Key: %s\n"
"TE: %d\n",
context->frequency,
string_get_cstr(context->preset),
string_get_cstr(context->protocol),
context->bit,
string_get_cstr(context->candidate),
context->te);
} else {
string_init_printf(
context->flipper_format_string,
"Filetype: Flipper SubGhz Key File\n"
"Version: 1\n"
"Frequency: %u\n"
"Preset: %s\n"
"Protocol: %s\n"
"Bit: %d\n"
"Key: %s\n",
context->frequency,
string_get_cstr(context->preset),
string_get_cstr(context->protocol),
context->bit,
string_get_cstr(context->candidate));
}

stream_clean(context->stream);
stream_write_string(context->stream, context->flipper_format_string);
subghz_transmitter_deserialize(context->transmitter, context->flipper_format);

subbrute_emit(context);
}

void subbrute_send_packet(SubBruteState* context) {
///if(string_cmp_str(context->protocol, "RAW") == 0) {
// subbrute_send_raw_packet(context);
//} else {
subbrute_send_packet_parsed(context);
//}
string_clear(context->flipper_format_string);
}

void subbrute_scene_run_attack_on_enter(SubBruteState* context) {
if(!toSave) {
if(context->attack == SubBruteAttackLoadFile) {
max_value = 0xFF;
} else {
string_t max_value_s;
string_init(max_value_s);
for(uint8_t i = 0; i < context->bit; i++) {
string_cat_printf(max_value_s, "1");
}
max_value = (uint64_t)strtol(string_get_cstr(max_value_s), NULL, 2);
string_clear(max_value_s);
}
context->str_index = (context->key_index * 3);
string_init_set(context->candidate, context->key);
context->flipper_format = flipper_format_string_alloc();
context->stream = flipper_format_get_raw_stream(context->flipper_format);
context->environment = subghz_environment_alloc();
context->transmitter = subghz_transmitter_alloc_init(
context->environment, string_get_cstr(context->protocol));
prepare_emit(context);
} else {
toSave = false;
}
}

void subbrute_scene_run_attack_on_exit(SubBruteState* context) {
if(!toSave) {
clear_emit(context);
}
}

void subbrute_scene_run_attack_on_tick(SubBruteState* context) {
if(!context->is_attacking || locked) {
return;
}
if(0 != subbrute_counter) {
locked = true;
subbrute_send_packet(context);

if(context->payload == max_value) {
context->payload = 0x00;
subbrute_counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
} else {
context->payload++;
}
locked = false;
}
if(subbrute_counter > SUBBRUTE_DELAY) {
subbrute_counter = 0;
} else {
subbrute_counter++;
}
}

void subbrute_scene_run_attack_on_event(SubBruteEvent event, SubBruteState* context) {
if(event.evt_type == EventTypeKey) {
if(event.input_type == InputTypeShort) {
switch(event.key) {
case InputKeyDown:
if(!context->is_attacking) {
toSave = true;
context->current_scene = SceneSaveName;
}
case InputKeyUp:
break;
case InputKeyLeft:
if(!context->is_attacking && context->payload > 0x00) {
context->payload--;
subbrute_send_packet(context);
notification_message(context->notify, &sequence_blink_blue_10);
}
break;
case InputKeyRight:
if(!context->is_attacking && context->payload < max_value) {
context->payload++;
subbrute_send_packet(context);
notification_message(context->notify, &sequence_blink_blue_10);
}
break;
case InputKeyOk:
if(!context->is_attacking) {
context->is_attacking = true;
notification_message(context->notify, &sequence_blink_start_blue);
} else {
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
}
break;
case InputKeyBack:
locked = false;
context->is_attacking = false;
string_reset(context->notification_msg);
context->payload = 0x00;
subbrute_counter = 0;
notification_message(context->notify, &sequence_blink_stop);
if(context->attack == SubBruteAttackLoadFile) {
context->current_scene = SceneSelectField;
} else {
context->current_scene = SceneEntryPoint;
}
break;
}
}
}
}

void subbrute_scene_run_attack_on_draw(Canvas* canvas, SubBruteState* context) {
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);

// Frame
//canvas_draw_frame(canvas, 0, 0, 128, 64);

// Title
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 64, 8, AlignCenter, AlignTop, "Fire in the hole!");

char msg_index[26];
snprintf(
msg_index, sizeof(msg_index), "< %04d / %04d >", (int)context->payload, (int)max_value);

canvas_draw_str_aligned(canvas, 64, 24, AlignCenter, AlignTop, msg_index);

canvas_set_font(canvas, FontSecondary);
char start_stop_msg[20];
snprintf(start_stop_msg, sizeof(start_stop_msg), " Press (V) to save ");
if(context->is_attacking) {
elements_button_center(canvas, "Stop");
} else {
elements_button_center(canvas, "Start");
}
canvas_draw_str_aligned(canvas, 64, 39, AlignCenter, AlignTop, start_stop_msg);
}
8 changes: 8 additions & 0 deletions applications/subbrute/scene/subbrute_scene_run_attack.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include "../subbrute.h"

void subbrute_scene_run_attack_on_enter(SubBruteState* context);
void subbrute_scene_run_attack_on_exit(SubBruteState* context);
void subbrute_scene_run_attack_on_tick(SubBruteState* context);
void subbrute_scene_run_attack_on_event(SubBruteEvent event, SubBruteState* context);
void subbrute_scene_run_attack_on_draw(Canvas* canvas, SubBruteState* context);
void send_packet();
222 changes: 222 additions & 0 deletions applications/subbrute/scene/subbrute_scene_save_name.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
#include "../subbrute.h"
#include "m-string.h"
#include "subghz/types.h"
#include <lib/toolbox/random_name.h>
#include <gui/modules/validators.h>
#include <lib/toolbox/path.h>

#define MAX_TEXT_INPUT_LEN 22

bool backpressed = false;

bool subbrute_path_is_file(string_t path) {
return string_end_with_str_p(path, ".sub");
}
// method modified from subghz_i.c
// https://github.com/flipperdevices/flipperzero-firmware/blob/b0daa601ad5b87427a45f9089c8b403a01f72c2a/applications/subghz/subghz_i.c#L417-L456
bool subbrute_save_protocol_to_file(Stream* flipper_format_stream, const char* dev_file_name) {
furi_assert(dev_file_name);

Storage* storage = furi_record_open(RECORD_STORAGE);

bool saved = false;
string_t file_dir;
string_init(file_dir);

path_extract_dirname(dev_file_name, file_dir);
do {
if(!storage_simply_mkdir(storage, string_get_cstr(file_dir))) {
FURI_LOG_E(TAG, "(save) Cannot mkdir");
break;
}

if(!storage_simply_remove(storage, dev_file_name)) {
FURI_LOG_E(TAG, "(save) Cannot remove");
break;
}

stream_seek(flipper_format_stream, 0, StreamOffsetFromStart);
stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS);

saved = true;
FURI_LOG_D(TAG, "(save) OK Save");
} while(0);
string_clear(file_dir);
furi_record_close(RECORD_STORAGE);
return saved;
}

void custom_callback(SubBruteState* context) {
if(strcmp(context->file_name_tmp, "")) {
string_cat_printf(context->file_path, "/%s%s", context->file_name_tmp, ".sub");
if(subbrute_path_is_file(context->file_path_tmp)) {
context->current_scene = SceneAttack;
return; //false;

} else {
subbrute_save_protocol_to_file(context->stream, string_get_cstr(context->file_path));
}

string_set_str(context->file_path, EXT_PATH("subghz"));
string_reset(context->file_path_tmp);

//scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveSuccess);
context->current_scene = SceneAttack;
return; //true;
} else {
//error no file name
context->current_scene = SceneAttack;
return; //true;
}
}

void subbrute_scene_save_name_text_input_callback(void* context) {
furi_assert(context);
SubBruteState* statee = context;
custom_callback(statee);
}

void subbrute_scene_save_name_on_tick(SubBruteState* context) {
if(backpressed) {
void* validator_context = text_input_get_validator_callback_context(context->text_input);
text_input_set_validator(context->text_input, NULL, NULL);
validator_is_file_free(validator_context);

// Clear view
text_input_reset(context->text_input);

// TextInput
view_dispatcher_remove_view(context->view_dispatcher, 0);
text_input_free(context->text_input);

// Popup
view_dispatcher_remove_view(context->view_dispatcher, 1);
popup_free(context->popup);

context->current_scene = SceneAttack;
}
}

bool subbrute_back_event_callback(void* context) {
UNUSED(context);
backpressed = true;
return true;
}

void subbrute_scene_save_name_on_enter(SubBruteState* context) {
// Text Input
context->text_input = text_input_alloc();
view_dispatcher_add_view(
context->view_dispatcher, 0, text_input_get_view(context->text_input));

// Popup
context->popup = popup_alloc();
view_dispatcher_add_view(context->view_dispatcher, 1, popup_get_view(context->popup));

// Setup view
TextInput* text_input = context->text_input;
bool dev_name_empty = false;

string_t file_name;
string_t dir_name;
string_init(file_name);
string_init(dir_name);

if(!subbrute_path_is_file(context->file_path)) {
char file_name_buf[64] = {0};
set_random_name(file_name_buf, 64);
string_set_str(file_name, file_name_buf);
string_set_str(context->file_path, EXT_PATH("subghz"));
//highlighting the entire filename by default
dev_name_empty = true;
} else {
string_set(context->file_path_tmp, context->file_path);
path_extract_dirname(string_get_cstr(context->file_path), dir_name);
path_extract_filename(context->file_path, file_name, true);
string_set(context->file_path, dir_name);
}

strncpy(context->file_name_tmp, string_get_cstr(file_name), 64);
text_input_set_header_text(text_input, "Name signal");
text_input_set_result_callback(
text_input,
subbrute_scene_save_name_text_input_callback,
context,
context->file_name_tmp,
MAX_TEXT_INPUT_LEN, // buffer size
dev_name_empty);

ValidatorIsFile* validator_is_file =
validator_is_file_alloc_init(string_get_cstr(context->file_path), ".sub", "");
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);

string_clear(file_name);
string_clear(dir_name);

view_dispatcher_set_navigation_event_callback(
context->view_dispatcher, subbrute_back_event_callback);

view_dispatcher_switch_to_view(context->view_dispatcher, 0);
}

void subbrute_scene_save_name_on_event(SubBruteEvent event, SubBruteState* context) {
UNUSED(context);
if(event.evt_type == EventTypeKey) {
if(event.input_type == InputTypeShort) {
switch(event.key) {
case InputKeyDown:
case InputKeyUp:
case InputKeyLeft:
case InputKeyRight:
case InputKeyOk:
break;
case InputKeyBack:
//context->current_scene = SceneAttack;
break;
}
}
}
}

void subbrute_scene_save_name_on_exit(SubBruteState* context) {
if(!backpressed) {
// Clear validator
void* validator_context = text_input_get_validator_callback_context(context->text_input);
text_input_set_validator(context->text_input, NULL, NULL);
validator_is_file_free(validator_context);

// Clear view
text_input_reset(context->text_input);

// Setup view
Popup* popup = context->popup;
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
popup_set_header(popup, "Saved!", 13, 22, AlignLeft, AlignBottom);
popup_set_timeout(popup, 1500);
popup_set_context(popup, context);
popup_set_callback(popup, NULL);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(context->view_dispatcher, 1);

furi_delay_ms(1050);
// Clear view
//Popup* popup = subghz->popup;
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_set_callback(popup, NULL);
popup_set_context(popup, NULL);
popup_set_timeout(popup, 0);
popup_disable_timeout(popup);

// TextInput
view_dispatcher_remove_view(context->view_dispatcher, 0);
text_input_free(context->text_input);

// Popup
view_dispatcher_remove_view(context->view_dispatcher, 1);
popup_free(context->popup);
} else {
backpressed = false;
}
}
6 changes: 6 additions & 0 deletions applications/subbrute/scene/subbrute_scene_save_name.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include "../subbrute.h"

void subbrute_scene_save_name_on_enter(SubBruteState* context);
void subbrute_scene_save_name_on_exit(SubBruteState* context);
void subbrute_scene_save_name_on_event(SubBruteEvent event, SubBruteState* context);
void subbrute_scene_save_name_on_tick(SubBruteState* context);
121 changes: 121 additions & 0 deletions applications/subbrute/scene/subbrute_scene_select_field.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#include "subbrute_scene_select_field.h"

void center_displayed_key(SubBruteState* context, uint8_t index) {
const char* key_cstr = string_get_cstr(context->key);
uint8_t str_index = (index * 3);

char display_menu[17] = {
'X', 'X', ' ', 'X', 'X', ' ', '<', 'X', 'X', '>', ' ', 'X', 'X', ' ', 'X', 'X', '\0'};

if(index > 1) {
display_menu[0] = key_cstr[str_index - 6];
display_menu[1] = key_cstr[str_index - 5];
} else {
display_menu[0] = ' ';
display_menu[1] = ' ';
}

if(index > 0) {
display_menu[3] = key_cstr[str_index - 3];
display_menu[4] = key_cstr[str_index - 2];
} else {
display_menu[3] = ' ';
display_menu[4] = ' ';
}

display_menu[7] = key_cstr[str_index];
display_menu[8] = key_cstr[str_index + 1];

if((str_index + 4) <= (uint8_t)strlen(key_cstr)) {
display_menu[11] = key_cstr[str_index + 3];
display_menu[12] = key_cstr[str_index + 4];
} else {
display_menu[11] = ' ';
display_menu[12] = ' ';
}

if((str_index + 8) <= (uint8_t)strlen(key_cstr)) {
display_menu[14] = key_cstr[str_index + 6];
display_menu[15] = key_cstr[str_index + 7];
} else {
display_menu[14] = ' ';
display_menu[15] = ' ';
}

string_reset(context->notification_msg);
string_set_str(context->notification_msg, display_menu);
}

void subbrute_scene_select_field_on_enter(SubBruteState* context) {
string_clear(context->notification_msg);
}

void subbrute_scene_select_field_on_exit(SubBruteState* context) {
UNUSED(context);
}

void subbrute_scene_select_field_on_tick(SubBruteState* context) {
UNUSED(context);
}

void subbrute_scene_select_field_on_event(SubBruteEvent event, SubBruteState* context) {
if(event.evt_type == EventTypeKey) {
if(event.input_type == InputTypeShort) {
//const char* key_cstr = string_get_cstr(context->key);

// don't look, it's ugly but I'm a python dev so...
/*uint8_t nb_bytes = 0;
for(uint8_t i = 0; i < strlen(key_cstr); i++) {
if(' ' == key_cstr[i]) {
nb_bytes++;
}
}*/

switch(event.key) {
case InputKeyDown:
case InputKeyUp:
break;
case InputKeyLeft:
if(context->key_index > 0) {
context->key_index--;
}
break;
case InputKeyRight:
if(context->key_index < 7) {
context->key_index++;
}
break;
case InputKeyOk:
string_reset(context->notification_msg);
context->current_scene = SceneAttack;
break;
case InputKeyBack:
string_reset(context->notification_msg);
context->current_scene = SceneSelectFile;
break;
}
//FURI_LOG_D(TAG, "Position: %d/%d", context->key_index, nb_bytes);
}
}
}

void subbrute_scene_select_field_on_draw(Canvas* canvas, SubBruteState* context) {
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);

// Frame
//canvas_draw_frame(canvas, 0, 0, 128, 64);

// Title
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 64, 10, AlignCenter, AlignTop, "use < > to select field");

char msg_index[18];
snprintf(msg_index, sizeof(msg_index), "Field index : %d", context->key_index);
canvas_draw_str_aligned(canvas, 64, 26, AlignCenter, AlignTop, msg_index);

center_displayed_key(context, context->key_index);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas, 64, 40, AlignCenter, AlignTop, string_get_cstr(context->notification_msg));
}
8 changes: 8 additions & 0 deletions applications/subbrute/scene/subbrute_scene_select_field.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include "../subbrute.h"

void subbrute_scene_select_field_on_enter(SubBruteState* context);
void subbrute_scene_select_field_on_exit(SubBruteState* context);
void subbrute_scene_select_field_on_tick(SubBruteState* context);
void subbrute_scene_select_field_on_event(SubBruteEvent event, SubBruteState* context);
void subbrute_scene_select_field_on_draw(Canvas* canvas, SubBruteState* context);
void center_displayed_key(SubBruteState* context, uint8_t index);
269 changes: 269 additions & 0 deletions applications/subbrute/subbrute.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
#include "subbrute.h"

#include "scene/subbrute_scene_load_file.h"
#include "scene/subbrute_scene_select_field.h"
#include "scene/subbrute_scene_run_attack.h"
#include "scene/subbrute_scene_entrypoint.h"
#include "scene/subbrute_scene_save_name.h"

static void draw_callback(Canvas* const canvas, void* ctx) {
SubBruteState* subbrute_state = (SubBruteState*)acquire_mutex((ValueMutex*)ctx, 100);

if(subbrute_state == NULL) {
return;
}

// Draw correct Canvas
switch(subbrute_state->current_scene) {
case NoneScene:
case SceneSelectFile:
subbrute_scene_load_file_on_draw(canvas, subbrute_state);
break;
case SceneSelectField:
subbrute_scene_select_field_on_draw(canvas, subbrute_state);
break;
case SceneAttack:
subbrute_scene_run_attack_on_draw(canvas, subbrute_state);
break;
case SceneEntryPoint:
subbrute_scene_entrypoint_on_draw(canvas, subbrute_state);
break;
case SceneSaveName:
break;
}

release_mutex((ValueMutex*)ctx, subbrute_state);
}

void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
furi_assert(event_queue);

SubBruteEvent event = {
.evt_type = EventTypeKey, .key = input_event->key, .input_type = input_event->type};
furi_message_queue_put(event_queue, &event, 100);
}

static void timer_callback(FuriMessageQueue* event_queue) {
furi_assert(event_queue);
SubBruteEvent event = {
.evt_type = EventTypeTick, .key = InputKeyUp, .input_type = InputTypeRelease};
furi_message_queue_put(event_queue, &event, 100);
}

SubBruteState* subbrute_alloc() {
SubBruteState* subbrute = malloc(sizeof(SubBruteState));

string_init(subbrute->protocol);
string_init(subbrute->preset);
string_init(subbrute->file_path);
string_init(subbrute->file_path_tmp);
string_init_set(subbrute->notification_msg, "");
string_init(subbrute->candidate);
string_init(subbrute->flipper_format_string);

subbrute->previous_scene = NoneScene;
subbrute->current_scene = SceneSelectFile;
subbrute->is_running = true;
subbrute->is_attacking = false;
subbrute->key_index = 7;
subbrute->notify = furi_record_open(RECORD_NOTIFICATION);

subbrute->view_dispatcher = view_dispatcher_alloc();

//Dialog
subbrute->dialogs = furi_record_open(RECORD_DIALOGS);

subbrute->preset_def = malloc(sizeof(SubGhzPresetDefinition));

subbrute->flipper_format = flipper_format_string_alloc();
subbrute->environment = subghz_environment_alloc();
subbrute->receiver = subghz_receiver_alloc_init(subbrute->environment);
subghz_receiver_set_filter(subbrute->receiver, SubGhzProtocolFlag_Decodable);

return subbrute;
}

void subbrute_free(SubBruteState* subbrute) {
//Dialog
furi_record_close(RECORD_DIALOGS);

notification_message(subbrute->notify, &sequence_blink_stop);

furi_record_close(RECORD_NOTIFICATION);

view_dispatcher_free(subbrute->view_dispatcher);

string_clear(subbrute->preset);
string_clear(subbrute->candidate);

// Path strings
string_clear(subbrute->file_path);
string_clear(subbrute->file_path_tmp);
string_clear(subbrute->notification_msg);
string_clear(subbrute->candidate);
string_clear(subbrute->flipper_format_string);

flipper_format_free(subbrute->flipper_format);
subghz_environment_free(subbrute->environment);
subghz_receiver_free(subbrute->receiver);

free(subbrute->preset_def);

// The rest
free(subbrute);
}

// ENTRYPOINT
int32_t subbrute_start(void* p) {
UNUSED(p);
// Input
FURI_LOG_I(TAG, "Initializing input");
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(SubBruteEvent));
SubBruteState* subbrute_state = subbrute_alloc();
ValueMutex subbrute_state_mutex;

// Mutex
FURI_LOG_I(TAG, "Initializing flipfrid mutex");
if(!init_mutex(&subbrute_state_mutex, subbrute_state, sizeof(SubBruteState))) {
FURI_LOG_E(TAG, "cannot create mutex\r\n");
furi_message_queue_free(event_queue);
subbrute_free(subbrute_state);
return 255;
}

furi_hal_power_suppress_charge_enter();

// Configure view port
FURI_LOG_I(TAG, "Initializing viewport");
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, draw_callback, &subbrute_state_mutex);
view_port_input_callback_set(view_port, input_callback, event_queue);

// Configure timer
FURI_LOG_I(TAG, "Initializing timer");
FuriTimer* timer = furi_timer_alloc(timer_callback, FuriTimerTypePeriodic, event_queue);
furi_timer_start(timer, furi_kernel_get_tick_frequency() / 10); // 10 times per second

// Register view port in GUI
FURI_LOG_I(TAG, "Initializing gui");
subbrute_state->gui = furi_record_open(RECORD_GUI);
gui_add_view_port(subbrute_state->gui, view_port, GuiLayerFullscreen);

view_dispatcher_attach_to_gui(
subbrute_state->view_dispatcher, subbrute_state->gui, ViewDispatcherTypeFullscreen);

subbrute_state->current_scene = SceneEntryPoint;

// Init values
SubBruteEvent event;
while(subbrute_state->is_running) {
// Get next event
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 25);
if(event_status == FuriStatusOk) {
if(event.evt_type == EventTypeKey) {
//Handle event key
FURI_LOG_D(TAG, "EVENT ###");
switch(subbrute_state->current_scene) {
case SceneSelectFile:
subbrute_scene_load_file_on_event(event, subbrute_state);
break;
case SceneSelectField:
subbrute_scene_select_field_on_event(event, subbrute_state);
break;
case SceneSaveName:
subbrute_scene_save_name_on_event(event, subbrute_state);
break;
case SceneAttack:
subbrute_scene_run_attack_on_event(event, subbrute_state);
break;
case NoneScene:
case SceneEntryPoint:
subbrute_scene_entrypoint_on_event(event, subbrute_state);
break;
}

} else if(event.evt_type == EventTypeTick) {
//Handle event tick
if(subbrute_state->current_scene != subbrute_state->previous_scene) {
// Trigger Exit Scene
switch(subbrute_state->previous_scene) {
case SceneSelectFile:
subbrute_scene_load_file_on_exit(subbrute_state);
break;
case SceneSelectField:
subbrute_scene_select_field_on_exit(subbrute_state);
break;
case SceneAttack:
subbrute_scene_run_attack_on_exit(subbrute_state);
break;
case SceneEntryPoint:
subbrute_scene_entrypoint_on_exit(subbrute_state);
break;
case SceneSaveName:
subbrute_scene_save_name_on_exit(subbrute_state);
break;
case NoneScene:
break;
}

// Trigger Entry Scene
switch(subbrute_state->current_scene) {
case NoneScene:
case SceneSelectFile:
subbrute_scene_load_file_on_enter(subbrute_state);
break;
case SceneSelectField:
subbrute_scene_select_field_on_enter(subbrute_state);
break;
case SceneAttack:
subbrute_scene_run_attack_on_enter(subbrute_state);
break;
case SceneSaveName:
subbrute_scene_save_name_on_enter(subbrute_state);
break;
case SceneEntryPoint:
subbrute_scene_entrypoint_on_enter(subbrute_state);
break;
}
subbrute_state->previous_scene = subbrute_state->current_scene;
}

// Trigger Tick Scene
switch(subbrute_state->current_scene) {
case NoneScene:
case SceneSelectFile:
subbrute_scene_load_file_on_tick(subbrute_state);
break;
case SceneSelectField:
subbrute_scene_select_field_on_tick(subbrute_state);
break;
case SceneAttack:
subbrute_scene_run_attack_on_tick(subbrute_state);
break;
case SceneEntryPoint:
subbrute_scene_entrypoint_on_tick(subbrute_state);
break;
case SceneSaveName:
subbrute_scene_save_name_on_tick(subbrute_state);
break;
}
view_port_update(view_port);
}
}
}

// Cleanup
furi_timer_stop(timer);
furi_timer_free(timer);

furi_hal_power_suppress_charge_exit();

FURI_LOG_I(TAG, "Cleaning up");
gui_remove_view_port(subbrute_state->gui, view_port);
view_port_free(view_port);
furi_message_queue_free(event_queue);
furi_record_close(RECORD_GUI);
subbrute_free(subbrute_state);

return 0;
}
105 changes: 105 additions & 0 deletions applications/subbrute/subbrute.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#pragma once
#include <furi.h>
#include <furi_hal.h>
#include <input/input.h>
#include <gui/gui.h>
#include "m-string.h"

#include <toolbox/stream/stream.h>
#include <lib/subghz/transmitter.h>
#include <lib/subghz/receiver.h>
#include <flipper_format/flipper_format_i.h>
#include <dialogs/dialogs.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include <gui/view_dispatcher.h>
#include <gui/modules/text_input.h>
#include <gui/modules/popup.h>

#define TAG "SUBBRUTE"

typedef enum {
NoneScene,
SceneSelectFile,
SceneSelectField,
SceneAttack,
SceneEntryPoint,
SceneSaveName
} SubBruteScene;

typedef enum {
SubBruteAttackLoadFile,
SubBruteAttackCAME12bit433,
SubBruteAttackCAME12bit868,
SubBruteAttackChamberlain9bit315,
SubBruteAttackChamberlain9bit390,
SubBruteAttackLinear10bit300,
SubBruteAttackLinear10bit310,
SubBruteAttackNICE12bit433,
SubBruteAttackNICE12bit868,
} SubBruteAttacks;

typedef enum {
EventTypeTick,
EventTypeKey,
EventTypeCustom,
} EventType;

typedef struct {
EventType evt_type;
InputKey key;
InputType input_type;
} SubBruteEvent;

// STRUCTS
typedef struct {
// Application stuff
bool is_running;
bool is_attacking;
SubBruteScene current_scene;
SubBruteScene previous_scene;
NotificationApp* notify;
Gui* gui;
ViewDispatcher* view_dispatcher;
TextInput* text_input;
Popup* popup;

// SubGhz Stuff
FlipperFormat* flipper_format;
SubGhzEnvironment* environment;
SubGhzTransmitter* transmitter;
SubGhzReceiver* receiver;
SubGhzProtocolDecoderBase* decoder_result;
SubGhzPresetDefinition* preset_def;
string_t preset;
Stream* stream;
string_t protocol;
uint32_t frequency;
uint32_t repeat;
uint32_t bit;
string_t key;
uint32_t te;

// Context Stuff
DialogsApp* dialogs;
char file_name_tmp[64];
string_t file_path;
string_t file_path_tmp;
string_t notification_msg;
uint8_t key_index;
uint64_t payload;
string_t candidate;
uint8_t str_index;
string_t flipper_format_string;

SubBruteAttacks attack;

//Menu stuff
uint8_t menu_index;

// RAW stuff
string_t subbrute_raw_one;
string_t subbrute_raw_zero;
string_t subbrute_raw_stop;

} SubBruteState;
13 changes: 13 additions & 0 deletions applications/subbrute/subbrute_utils.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include "subbrute_utils.h"

bool subbrute_is_frequency_allowed(SubBruteState* context) {
// I know you don't like it but laws are laws
// It's opensource so do whatever you want, but remember the risks :)
// (Yes, this comment is the only purpose of this function)
bool r = furi_hal_subghz_is_tx_allowed(context->frequency);
if(!r) {
FURI_LOG_E(TAG, "Frequency %d is not allowed in your region", context->frequency);
notification_message(context->notify, &sequence_single_vibro);
}
return r;
}
4 changes: 4 additions & 0 deletions applications/subbrute/subbrute_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#pragma once
#include "subbrute.h"

bool subbrute_is_frequency_allowed(SubBruteState* context);

0 comments on commit 7de9c95

Please sign in to comment.