First version of subghz fuzzer

This commit is contained in:
Ganapati 2022-09-07 15:38:20 +02:00
parent 1a4d928e5c
commit 7afb4d0f41
15 changed files with 1215 additions and 0 deletions

View file

@ -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.
* ----------------------------------------------------------------------------
*/

View file

@ -0,0 +1,4 @@
# FlipFrid
SubGhz Fuzzer
select your base message, the field to fuzz and let's get fuzzy !

View file

@ -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=70,
)

View file

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

View file

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

View file

@ -0,0 +1,201 @@
#include "subbrute_scene_load_file.h"
#include "subbrute_scene_entrypoint.h"
#include "../subbrute_utils.h"
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;
}
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_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:
case InputKeyBack:
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, "Press OK to choose file");
}
bool subbrute_load_protocol_from_file(SubBruteState* context) {
string_t file_path;
string_init(file_path);
// Input events and views are managed by file_select
bool res = dialog_file_browser_show(
context->dialogs,
context->file_path,
context->file_path,
SUBGHZ_APP_EXTENSION,
true,
&I_sub1_10px,
true);
if(res) {
res = subbrute_load(context, string_get_cstr(context->file_path));
}
string_clear(file_path);
return res;
}

View file

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

View file

@ -0,0 +1,298 @@
#include "subbrute_scene_run_attack.h"
#include <lib/subghz/transmitter.h>
uint64_t subbrute_counter = 0;
uint64_t max_value;
bool is_running = false;
bool locked = 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_I(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(50);
}
furi_hal_subghz_stop_async_tx();
furi_hal_subghz_sleep();
furi_hal_power_suppress_charge_exit();
}
void prepare_emit(SubBruteState* context) {
is_running = true;
furi_hal_subghz_init();
stream_clean(context->stream);
stream_write_string(context->stream, context->flipper_format_string);
context->transmitter =
subghz_transmitter_alloc_init(context->environment, string_get_cstr(context->protocol));
subghz_transmitter_deserialize(context->transmitter, context->flipper_format);
furi_hal_subghz_reset();
furi_hal_subghz_load_preset(str_to_preset(context->preset));
context->frequency = furi_hal_subghz_set_frequency_and_path(context->frequency);
furi_hal_power_suppress_charge_enter();
}
void clear_emit(SubBruteState* context) {
furi_hal_subghz_stop_async_tx();
furi_hal_subghz_sleep();
furi_hal_power_suppress_charge_exit();
if(context->attack == SubBruteAttackLoadFile) {
subghz_transmitter_free(context->transmitter);
}
subghz_transmitter_free(context->transmitter);
is_running = false;
}
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));
prepare_emit(context);
subbrute_emit(context);
clear_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);
}
string_init_printf(
context->flipper_format_string,
"Filetype: Flipper SubGhz Key File\n"
"Version: 1\n"
"Protocol: %s\n"
"Bit: %d\n"
"Key: %s\n"
"TE: %d\n",
string_get_cstr(context->protocol),
context->bit,
string_get_cstr(context->candidate),
context->te);
prepare_emit(context);
subbrute_emit(context);
clear_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(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));
}
void subbrute_scene_run_attack_on_exit(SubBruteState* context) {
if(is_running) {
is_running = false;
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 && context->payload > 0x00) {
context->payload--;
subbrute_send_packet(context);
notification_message(context->notify, &sequence_blink_blue_10);
}
break;
case InputKeyUp:
if(!context->is_attacking && context->payload < max_value) {
context->payload++;
subbrute_send_packet(context);
notification_message(context->notify, &sequence_blink_blue_10);
}
break;
case InputKeyLeft:
case InputKeyRight:
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;
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[22];
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];
if(context->is_attacking) {
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 ");
}
canvas_draw_str_aligned(canvas, 64, 44, AlignCenter, AlignTop, start_stop_msg);
}

View file

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

View file

@ -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 = context->key_index - 1;
}
break;
case InputKeyRight:
if(context->key_index < nb_bytes) {
context->key_index = context->key_index + 1;
}
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));
}

View file

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

View file

@ -0,0 +1,231 @@
#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"
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;
}
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 = 0;
subbrute->notify = furi_record_open(RECORD_NOTIFICATION);
//Dialog
subbrute->dialogs = furi_record_open(RECORD_DIALOGS);
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);
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);
// 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);
free(subbrute_state);
}
// 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");
Gui* gui = (Gui*)furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
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 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 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 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;
}
view_port_update(view_port);
}
}
}
// Cleanup
furi_timer_stop(timer);
furi_timer_free(timer);
FURI_LOG_I(TAG, "Cleaning up");
gui_remove_view_port(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;
}

View file

@ -0,0 +1,94 @@
#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>
#define TAG "SUBBRUTE"
typedef enum {
NoneScene,
SceneSelectFile,
SceneSelectField,
SceneAttack,
SceneEntryPoint
} SubBruteScene;
typedef enum {
SubBruteAttackLoadFile,
SubBruteAttackCAME12bit433,
SubBruteAttackCAME12bit868,
SubBruteAttackChamberlain9bit315,
SubBruteAttackChamberlain9bit390,
SubBruteAttackLinear10bit300,
SubBruteAttackLinear10bit310,
SubBruteAttackNICE12bit433,
SubBruteAttackNICE12bit868,
} SubBruteAttacks;
typedef enum {
EventTypeTick,
EventTypeKey,
} 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;
// SubGhz Stuff
FlipperFormat* flipper_format;
SubGhzEnvironment* environment;
SubGhzTransmitter* transmitter;
SubGhzReceiver* receiver;
SubGhzProtocolDecoderBase* decoder_result;
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;
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;

View file

@ -0,0 +1,14 @@
#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_region_is_frequency_allowed(context->frequency);
bool r = true;
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;
}

View file

@ -0,0 +1,4 @@
#pragma once
#include "subbrute.h"
bool subbrute_is_frequency_allowed(SubBruteState* context);