From 7afb4d0f412e0e1780d3051d360048e4c195b61d Mon Sep 17 00:00:00 2001 From: Ganapati Date: Wed, 7 Sep 2022 15:38:20 +0200 Subject: [PATCH 1/4] First version of subghz fuzzer --- applications/subbrute/LICENSE.md | 8 + applications/subbrute/README.md | 4 + applications/subbrute/application.fam | 10 + .../scene/subbrute_scene_entrypoint.c | 198 ++++++++++++ .../scene/subbrute_scene_entrypoint.h | 8 + .../subbrute/scene/subbrute_scene_load_file.c | 201 ++++++++++++ .../subbrute/scene/subbrute_scene_load_file.h | 8 + .../scene/subbrute_scene_run_attack.c | 298 ++++++++++++++++++ .../scene/subbrute_scene_run_attack.h | 8 + .../scene/subbrute_scene_select_field.c | 121 +++++++ .../scene/subbrute_scene_select_field.h | 8 + applications/subbrute/subbrute.c | 231 ++++++++++++++ applications/subbrute/subbrute.h | 94 ++++++ applications/subbrute/subbrute_utils.c | 14 + applications/subbrute/subbrute_utils.h | 4 + 15 files changed, 1215 insertions(+) create mode 100644 applications/subbrute/LICENSE.md create mode 100644 applications/subbrute/README.md create mode 100644 applications/subbrute/application.fam create mode 100644 applications/subbrute/scene/subbrute_scene_entrypoint.c create mode 100644 applications/subbrute/scene/subbrute_scene_entrypoint.h create mode 100644 applications/subbrute/scene/subbrute_scene_load_file.c create mode 100644 applications/subbrute/scene/subbrute_scene_load_file.h create mode 100644 applications/subbrute/scene/subbrute_scene_run_attack.c create mode 100644 applications/subbrute/scene/subbrute_scene_run_attack.h create mode 100644 applications/subbrute/scene/subbrute_scene_select_field.c create mode 100644 applications/subbrute/scene/subbrute_scene_select_field.h create mode 100644 applications/subbrute/subbrute.c create mode 100644 applications/subbrute/subbrute.h create mode 100644 applications/subbrute/subbrute_utils.c create mode 100644 applications/subbrute/subbrute_utils.h diff --git a/applications/subbrute/LICENSE.md b/applications/subbrute/LICENSE.md new file mode 100644 index 000000000..a856581c9 --- /dev/null +++ b/applications/subbrute/LICENSE.md @@ -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. + * ---------------------------------------------------------------------------- + */ \ No newline at end of file diff --git a/applications/subbrute/README.md b/applications/subbrute/README.md new file mode 100644 index 000000000..04a0c975d --- /dev/null +++ b/applications/subbrute/README.md @@ -0,0 +1,4 @@ +# FlipFrid + +SubGhz Fuzzer +select your base message, the field to fuzz and let's get fuzzy ! \ No newline at end of file diff --git a/applications/subbrute/application.fam b/applications/subbrute/application.fam new file mode 100644 index 000000000..4002421dd --- /dev/null +++ b/applications/subbrute/application.fam @@ -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, +) diff --git a/applications/subbrute/scene/subbrute_scene_entrypoint.c b/applications/subbrute/scene/subbrute_scene_entrypoint.c new file mode 100644 index 000000000..9cdc83623 --- /dev/null +++ b/applications/subbrute/scene/subbrute_scene_entrypoint.c @@ -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])); + } +} \ No newline at end of file diff --git a/applications/subbrute/scene/subbrute_scene_entrypoint.h b/applications/subbrute/scene/subbrute_scene_entrypoint.h new file mode 100644 index 000000000..af6b3bc49 --- /dev/null +++ b/applications/subbrute/scene/subbrute_scene_entrypoint.h @@ -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); \ No newline at end of file diff --git a/applications/subbrute/scene/subbrute_scene_load_file.c b/applications/subbrute/scene/subbrute_scene_load_file.c new file mode 100644 index 000000000..23a555f06 --- /dev/null +++ b/applications/subbrute/scene/subbrute_scene_load_file.c @@ -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; +} \ No newline at end of file diff --git a/applications/subbrute/scene/subbrute_scene_load_file.h b/applications/subbrute/scene/subbrute_scene_load_file.h new file mode 100644 index 000000000..9e186b1c9 --- /dev/null +++ b/applications/subbrute/scene/subbrute_scene_load_file.h @@ -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); \ No newline at end of file diff --git a/applications/subbrute/scene/subbrute_scene_run_attack.c b/applications/subbrute/scene/subbrute_scene_run_attack.c new file mode 100644 index 000000000..d865588a5 --- /dev/null +++ b/applications/subbrute/scene/subbrute_scene_run_attack.c @@ -0,0 +1,298 @@ +#include "subbrute_scene_run_attack.h" +#include + +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); +} diff --git a/applications/subbrute/scene/subbrute_scene_run_attack.h b/applications/subbrute/scene/subbrute_scene_run_attack.h new file mode 100644 index 000000000..1eb9637d0 --- /dev/null +++ b/applications/subbrute/scene/subbrute_scene_run_attack.h @@ -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(); \ No newline at end of file diff --git a/applications/subbrute/scene/subbrute_scene_select_field.c b/applications/subbrute/scene/subbrute_scene_select_field.c new file mode 100644 index 000000000..82b227f5d --- /dev/null +++ b/applications/subbrute/scene/subbrute_scene_select_field.c @@ -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)); +} diff --git a/applications/subbrute/scene/subbrute_scene_select_field.h b/applications/subbrute/scene/subbrute_scene_select_field.h new file mode 100644 index 000000000..e02a07ee0 --- /dev/null +++ b/applications/subbrute/scene/subbrute_scene_select_field.h @@ -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); \ No newline at end of file diff --git a/applications/subbrute/subbrute.c b/applications/subbrute/subbrute.c new file mode 100644 index 000000000..26aededec --- /dev/null +++ b/applications/subbrute/subbrute.c @@ -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; +} \ No newline at end of file diff --git a/applications/subbrute/subbrute.h b/applications/subbrute/subbrute.h new file mode 100644 index 000000000..29b2f21fe --- /dev/null +++ b/applications/subbrute/subbrute.h @@ -0,0 +1,94 @@ +#pragma once +#include +#include +#include +#include +#include "m-string.h" + +#include +#include +#include +#include +#include +#include +#include + +#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; \ No newline at end of file diff --git a/applications/subbrute/subbrute_utils.c b/applications/subbrute/subbrute_utils.c new file mode 100644 index 000000000..e045eb593 --- /dev/null +++ b/applications/subbrute/subbrute_utils.c @@ -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; +} \ No newline at end of file diff --git a/applications/subbrute/subbrute_utils.h b/applications/subbrute/subbrute_utils.h new file mode 100644 index 000000000..90f7c60ad --- /dev/null +++ b/applications/subbrute/subbrute_utils.h @@ -0,0 +1,4 @@ +#pragma once +#include "subbrute.h" + +bool subbrute_is_frequency_allowed(SubBruteState* context); \ No newline at end of file From 8955388a606de7bde0aa308edaedaefa6d4cce84 Mon Sep 17 00:00:00 2001 From: Ganapati Date: Wed, 7 Sep 2022 15:39:04 +0200 Subject: [PATCH 2/4] add tx region check --- applications/subbrute/subbrute_utils.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/applications/subbrute/subbrute_utils.c b/applications/subbrute/subbrute_utils.c index e045eb593..2aafc7175 100644 --- a/applications/subbrute/subbrute_utils.c +++ b/applications/subbrute/subbrute_utils.c @@ -4,8 +4,7 @@ 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; + 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); From 4588f38ae97ac6302008c2ff72fbf4c30bc4e4d6 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 7 Sep 2022 17:48:24 +0300 Subject: [PATCH 3/4] some fixes --- applications/meta/application.fam | 1 + applications/subbrute/application.fam | 2 +- .../scene/subbrute_scene_run_attack.c | 39 ++++++++----------- applications/subbrute/subbrute.c | 14 ++++++- 4 files changed, 32 insertions(+), 24 deletions(-) diff --git a/applications/meta/application.fam b/applications/meta/application.fam index f12249642..df2286269 100644 --- a/applications/meta/application.fam +++ b/applications/meta/application.fam @@ -78,5 +78,6 @@ App( "wifi_scanner", "multi_converter", "flipfrid", + "subbrute", ], ) \ No newline at end of file diff --git a/applications/subbrute/application.fam b/applications/subbrute/application.fam index 4002421dd..ed39c6c0e 100644 --- a/applications/subbrute/application.fam +++ b/applications/subbrute/application.fam @@ -6,5 +6,5 @@ App( cdefines=["APP_SUB_BRUTE"], requires=["gui","dialogs"], stack_size=2 * 1024, - order=70, + order=11, ) diff --git a/applications/subbrute/scene/subbrute_scene_run_attack.c b/applications/subbrute/scene/subbrute_scene_run_attack.c index d865588a5..40a688c24 100644 --- a/applications/subbrute/scene/subbrute_scene_run_attack.c +++ b/applications/subbrute/scene/subbrute_scene_run_attack.c @@ -39,8 +39,7 @@ void subbrute_emit(SubBruteState* context) { } furi_hal_subghz_stop_async_tx(); - furi_hal_subghz_sleep(); - furi_hal_power_suppress_charge_exit(); + furi_hal_subghz_idle(); } void prepare_emit(SubBruteState* context) { @@ -58,22 +57,19 @@ void prepare_emit(SubBruteState* context) { 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); @@ -117,11 +113,9 @@ void subbrute_send_raw_packet(SubBruteState* context) { 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); @@ -157,17 +151,15 @@ void subbrute_send_packet_parsed(SubBruteState* context) { 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); - } + ///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); } @@ -190,13 +182,14 @@ void subbrute_scene_run_attack_on_enter(SubBruteState* context) { context->environment = subghz_environment_alloc(); context->transmitter = subghz_transmitter_alloc_init(context->environment, string_get_cstr(context->protocol)); + prepare_emit(context); } void subbrute_scene_run_attack_on_exit(SubBruteState* context) { if(is_running) { is_running = false; - clear_emit(context); } + clear_emit(context); } void subbrute_scene_run_attack_on_tick(SubBruteState* context) { @@ -230,21 +223,22 @@ void subbrute_scene_run_attack_on_event(SubBruteEvent event, SubBruteState* cont if(event.input_type == InputTypeShort) { switch(event.key) { case InputKeyDown: + 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 InputKeyUp: + 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 InputKeyLeft: - case InputKeyRight: case InputKeyOk: if(!context->is_attacking) { context->is_attacking = true; @@ -282,8 +276,9 @@ void subbrute_scene_run_attack_on_draw(Canvas* canvas, SubBruteState* context) { 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); + 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); diff --git a/applications/subbrute/subbrute.c b/applications/subbrute/subbrute.c index 26aededec..7da9bc009 100644 --- a/applications/subbrute/subbrute.c +++ b/applications/subbrute/subbrute.c @@ -79,8 +79,11 @@ SubBruteState* subbrute_alloc() { void subbrute_free(SubBruteState* subbrute) { //Dialog furi_record_close(RECORD_DIALOGS); + notification_message(subbrute->notify, &sequence_blink_stop); + furi_record_close(RECORD_NOTIFICATION); + string_clear(subbrute->preset); string_clear(subbrute->candidate); @@ -91,6 +94,10 @@ void subbrute_free(SubBruteState* subbrute) { 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); + // The rest free(subbrute); } @@ -109,9 +116,12 @@ int32_t subbrute_start(void* p) { 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); + 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(); @@ -220,6 +230,8 @@ int32_t subbrute_start(void* p) { furi_timer_stop(timer); furi_timer_free(timer); + furi_hal_power_suppress_charge_exit(); + FURI_LOG_I(TAG, "Cleaning up"); gui_remove_view_port(gui, view_port); view_port_free(view_port); From 18891ade89be3be4d973cf3ccfdcf7668c07925b Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 8 Sep 2022 05:00:53 +0300 Subject: [PATCH 4/4] big upgrade --- applications/flipfrid/application.fam | 2 +- .../scene/flipfrid_scene_run_attack.c | 12 +- .../scene/flipfrid_scene_select_field.c | 2 +- applications/subbrute/application.fam | 2 +- .../scene/subbrute_scene_entrypoint.c | 2 +- .../subbrute/scene/subbrute_scene_load_file.c | 39 +-- .../scene/subbrute_scene_run_attack.c | 125 ++++++---- .../subbrute/scene/subbrute_scene_save_name.c | 222 ++++++++++++++++++ .../subbrute/scene/subbrute_scene_save_name.h | 6 + .../scene/subbrute_scene_select_field.c | 16 +- applications/subbrute/subbrute.c | 34 ++- applications/subbrute/subbrute.h | 13 +- 12 files changed, 390 insertions(+), 85 deletions(-) create mode 100644 applications/subbrute/scene/subbrute_scene_save_name.c create mode 100644 applications/subbrute/scene/subbrute_scene_save_name.h diff --git a/applications/flipfrid/application.fam b/applications/flipfrid/application.fam index 0eee3cc1b..4bcb38139 100644 --- a/applications/flipfrid/application.fam +++ b/applications/flipfrid/application.fam @@ -6,5 +6,5 @@ App( cdefines=["APP_FLIP_FRID"], requires=["gui"], stack_size=1 * 1024, - order=29, + order=13, ) diff --git a/applications/flipfrid/scene/flipfrid_scene_run_attack.c b/applications/flipfrid/scene/flipfrid_scene_run_attack.c index 391943edc..e34cb8986 100644 --- a/applications/flipfrid/scene/flipfrid_scene_run_attack.c +++ b/applications/flipfrid/scene/flipfrid_scene_run_attack.c @@ -1,4 +1,5 @@ #include "flipfrid_scene_run_attack.h" +#include 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); } diff --git a/applications/flipfrid/scene/flipfrid_scene_select_field.c b/applications/flipfrid/scene/flipfrid_scene_select_field.c index 2fafa5c85..03411b2f4 100644 --- a/applications/flipfrid/scene/flipfrid_scene_select_field.c +++ b/applications/flipfrid/scene/flipfrid_scene_select_field.c @@ -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); diff --git a/applications/subbrute/application.fam b/applications/subbrute/application.fam index ed39c6c0e..2608cba8f 100644 --- a/applications/subbrute/application.fam +++ b/applications/subbrute/application.fam @@ -1,6 +1,6 @@ App( appid="subbrute", - name="SubGhz Bruteforcer", + name="SubGHz Bruteforcer", apptype=FlipperAppType.PLUGIN, entry_point="subbrute_start", cdefines=["APP_SUB_BRUTE"], diff --git a/applications/subbrute/scene/subbrute_scene_entrypoint.c b/applications/subbrute/scene/subbrute_scene_entrypoint.c index 9cdc83623..a568ec152 100644 --- a/applications/subbrute/scene/subbrute_scene_entrypoint.c +++ b/applications/subbrute/scene/subbrute_scene_entrypoint.c @@ -163,7 +163,7 @@ void subbrute_scene_entrypoint_on_draw(Canvas* canvas, SubBruteState* context) { // Title canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 64, 6, AlignCenter, AlignTop, "SubGhz Fuzzer"); + canvas_draw_str_aligned(canvas, 64, 6, AlignCenter, AlignTop, "SubGHz Fuzzer"); if(context->menu_index > SubBruteAttackLoadFile) { canvas_set_font(canvas, FontSecondary); diff --git a/applications/subbrute/scene/subbrute_scene_load_file.c b/applications/subbrute/scene/subbrute_scene_load_file.c index 23a555f06..0f6d953f7 100644 --- a/applications/subbrute/scene/subbrute_scene_load_file.c +++ b/applications/subbrute/scene/subbrute_scene_load_file.c @@ -1,6 +1,9 @@ #include "subbrute_scene_load_file.h" #include "subbrute_scene_entrypoint.h" #include "../subbrute_utils.h" +#include + +#define SUBGHZ_APP_PATH_FOLDER "/ext/subghz" bool subbrute_load(SubBruteState* context, const char* file_path) { bool result = false; @@ -61,6 +64,16 @@ bool subbrute_load(SubBruteState* context, const char* file_path) { 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)); @@ -98,9 +111,9 @@ bool subbrute_load(SubBruteState* context, const char* file_path) { // 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; + //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; @@ -119,6 +132,7 @@ bool subbrute_load(SubBruteState* context, const char* file_path) { } 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"); @@ -156,7 +170,9 @@ void subbrute_scene_load_file_on_event(SubBruteEvent event, SubBruteState* conte case InputKeyLeft: case InputKeyRight: case InputKeyOk: + break; case InputKeyBack: + context->current_scene = SceneEntryPoint; break; } } @@ -169,30 +185,25 @@ void subbrute_scene_load_file_on_draw(Canvas* canvas, SubBruteState* 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); - 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"); + 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, - context->file_path, - context->file_path, - SUBGHZ_APP_EXTENSION, - true, - &I_sub1_10px, - true); + context->dialogs, file_path, file_path, SUBGHZ_APP_EXTENSION, true, &I_sub1_10px, true); if(res) { - res = subbrute_load(context, string_get_cstr(context->file_path)); + res = subbrute_load(context, string_get_cstr(file_path)); } string_clear(file_path); diff --git a/applications/subbrute/scene/subbrute_scene_run_attack.c b/applications/subbrute/scene/subbrute_scene_run_attack.c index 40a688c24..4fa8a48ad 100644 --- a/applications/subbrute/scene/subbrute_scene_run_attack.c +++ b/applications/subbrute/scene/subbrute_scene_run_attack.c @@ -1,10 +1,11 @@ #include "subbrute_scene_run_attack.h" #include +#include uint64_t subbrute_counter = 0; uint64_t max_value; -bool is_running = false; bool locked = false; +bool toSave = false; char subbrute_payload_byte[4]; #define SUBBRUTE_DELAY 1 @@ -31,11 +32,11 @@ FuriHalSubGhzPreset str_to_preset(string_t preset) { } void subbrute_emit(SubBruteState* context) { - FURI_LOG_I(TAG, string_get_cstr(context->flipper_format_string)); + //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(50); + furi_delay_ms(5); } furi_hal_subghz_stop_async_tx(); @@ -43,31 +44,22 @@ void subbrute_emit(SubBruteState* context) { } 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_subghz_set_frequency_and_path(context->frequency); } void clear_emit(SubBruteState* context) { furi_hal_subghz_stop_async_tx(); furi_hal_subghz_sleep(); - if(context->attack == SubBruteAttackLoadFile) { - subghz_transmitter_free(context->transmitter); - } subghz_transmitter_free(context->transmitter); - is_running = false; } /* void subbrute_send_raw_packet(SubBruteState* context) { @@ -138,18 +130,43 @@ void subbrute_send_packet_parsed(SubBruteState* context) { } 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); + 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); } @@ -164,32 +181,35 @@ void subbrute_send_packet(SubBruteState* context) { } 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"); + 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); } - 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; } - 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); } void subbrute_scene_run_attack_on_exit(SubBruteState* context) { - if(is_running) { - is_running = false; + if(!toSave) { + clear_emit(context); } - clear_emit(context); } void subbrute_scene_run_attack_on_tick(SubBruteState* context) { @@ -223,6 +243,10 @@ void subbrute_scene_run_attack_on_event(SubBruteEvent event, SubBruteState* cont 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: @@ -254,6 +278,8 @@ void subbrute_scene_run_attack_on_event(SubBruteEvent event, SubBruteState* cont 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 { @@ -270,7 +296,7 @@ void subbrute_scene_run_attack_on_draw(Canvas* canvas, SubBruteState* 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); @@ -284,10 +310,11 @@ void subbrute_scene_run_attack_on_draw(Canvas* canvas, SubBruteState* context) { 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) { - snprintf(start_stop_msg, sizeof(start_stop_msg), " Press OK to stop "); + elements_button_center(canvas, "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, 39, AlignCenter, AlignTop, start_stop_msg); } diff --git a/applications/subbrute/scene/subbrute_scene_save_name.c b/applications/subbrute/scene/subbrute_scene_save_name.c new file mode 100644 index 000000000..e79cf70ed --- /dev/null +++ b/applications/subbrute/scene/subbrute_scene_save_name.c @@ -0,0 +1,222 @@ +#include "../subbrute.h" +#include "m-string.h" +#include "subghz/types.h" +#include +#include +#include + +#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; + } +} \ No newline at end of file diff --git a/applications/subbrute/scene/subbrute_scene_save_name.h b/applications/subbrute/scene/subbrute_scene_save_name.h new file mode 100644 index 000000000..18a931ad8 --- /dev/null +++ b/applications/subbrute/scene/subbrute_scene_save_name.h @@ -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); \ No newline at end of file diff --git a/applications/subbrute/scene/subbrute_scene_select_field.c b/applications/subbrute/scene/subbrute_scene_select_field.c index 82b227f5d..c65cd1663 100644 --- a/applications/subbrute/scene/subbrute_scene_select_field.c +++ b/applications/subbrute/scene/subbrute_scene_select_field.c @@ -61,15 +61,15 @@ void subbrute_scene_select_field_on_tick(SubBruteState* 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); + //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; + /*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: @@ -77,12 +77,12 @@ void subbrute_scene_select_field_on_event(SubBruteEvent event, SubBruteState* co break; case InputKeyLeft: if(context->key_index > 0) { - context->key_index = context->key_index - 1; + context->key_index--; } break; case InputKeyRight: - if(context->key_index < nb_bytes) { - context->key_index = context->key_index + 1; + if(context->key_index < 7) { + context->key_index++; } break; case InputKeyOk: @@ -94,7 +94,7 @@ void subbrute_scene_select_field_on_event(SubBruteEvent event, SubBruteState* co context->current_scene = SceneSelectFile; break; } - FURI_LOG_D(TAG, "Position: %d/%d", context->key_index, nb_bytes); + //FURI_LOG_D(TAG, "Position: %d/%d", context->key_index, nb_bytes); } } } @@ -104,7 +104,7 @@ void subbrute_scene_select_field_on_draw(Canvas* canvas, SubBruteState* 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); diff --git a/applications/subbrute/subbrute.c b/applications/subbrute/subbrute.c index 7da9bc009..9bc4895e5 100644 --- a/applications/subbrute/subbrute.c +++ b/applications/subbrute/subbrute.c @@ -4,6 +4,7 @@ #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); @@ -27,6 +28,8 @@ static void draw_callback(Canvas* const canvas, void* ctx) { case SceneEntryPoint: subbrute_scene_entrypoint_on_draw(canvas, subbrute_state); break; + case SceneSaveName: + break; } release_mutex((ValueMutex*)ctx, subbrute_state); @@ -62,12 +65,16 @@ SubBruteState* subbrute_alloc() { subbrute->current_scene = SceneSelectFile; subbrute->is_running = true; subbrute->is_attacking = false; - subbrute->key_index = 0; + 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); @@ -84,6 +91,8 @@ void subbrute_free(SubBruteState* subbrute) { furi_record_close(RECORD_NOTIFICATION); + view_dispatcher_free(subbrute->view_dispatcher); + string_clear(subbrute->preset); string_clear(subbrute->candidate); @@ -98,6 +107,8 @@ void subbrute_free(SubBruteState* subbrute) { subghz_environment_free(subbrute->environment); subghz_receiver_free(subbrute->receiver); + free(subbrute->preset_def); + // The rest free(subbrute); } @@ -135,8 +146,11 @@ int32_t subbrute_start(void* p) { // 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->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; @@ -156,6 +170,9 @@ int32_t subbrute_start(void* p) { 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; @@ -182,6 +199,9 @@ int32_t subbrute_start(void* p) { case SceneEntryPoint: subbrute_scene_entrypoint_on_exit(subbrute_state); break; + case SceneSaveName: + subbrute_scene_save_name_on_exit(subbrute_state); + break; case NoneScene: break; } @@ -198,6 +218,9 @@ int32_t subbrute_start(void* p) { 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; @@ -220,6 +243,9 @@ int32_t subbrute_start(void* p) { 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); } @@ -233,7 +259,7 @@ int32_t subbrute_start(void* p) { furi_hal_power_suppress_charge_exit(); FURI_LOG_I(TAG, "Cleaning up"); - gui_remove_view_port(gui, view_port); + 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); diff --git a/applications/subbrute/subbrute.h b/applications/subbrute/subbrute.h index 29b2f21fe..dad5787d6 100644 --- a/applications/subbrute/subbrute.h +++ b/applications/subbrute/subbrute.h @@ -12,6 +12,9 @@ #include #include #include +#include +#include +#include #define TAG "SUBBRUTE" @@ -20,7 +23,8 @@ typedef enum { SceneSelectFile, SceneSelectField, SceneAttack, - SceneEntryPoint + SceneEntryPoint, + SceneSaveName } SubBruteScene; typedef enum { @@ -38,6 +42,7 @@ typedef enum { typedef enum { EventTypeTick, EventTypeKey, + EventTypeCustom, } EventType; typedef struct { @@ -54,6 +59,10 @@ typedef struct { SubBruteScene current_scene; SubBruteScene previous_scene; NotificationApp* notify; + Gui* gui; + ViewDispatcher* view_dispatcher; + TextInput* text_input; + Popup* popup; // SubGhz Stuff FlipperFormat* flipper_format; @@ -61,6 +70,7 @@ typedef struct { SubGhzTransmitter* transmitter; SubGhzReceiver* receiver; SubGhzProtocolDecoderBase* decoder_result; + SubGhzPresetDefinition* preset_def; string_t preset; Stream* stream; string_t protocol; @@ -72,6 +82,7 @@ typedef struct { // Context Stuff DialogsApp* dialogs; + char file_name_tmp[64]; string_t file_path; string_t file_path_tmp; string_t notification_msg;