diff --git a/applications/plugins/subbrute/helpers/subbrute_worker.c b/applications/plugins/subbrute/helpers/subbrute_worker.c new file mode 100644 index 000000000..4d7e98fa4 --- /dev/null +++ b/applications/plugins/subbrute/helpers/subbrute_worker.c @@ -0,0 +1,362 @@ +#include "subbrute_worker_private.h" +#include +#include +#include +#include + +#define TAG "SubBruteWorker" +#define SUBBRUTE_TX_TIMEOUT 5 +#define SUBBRUTE_MANUAL_TRANSMIT_INTERVAL 400 + +SubBruteWorker* subbrute_worker_alloc() { + SubBruteWorker* instance = malloc(sizeof(SubBruteWorker)); + + instance->state = SubBruteWorkerStateIDLE; + instance->key_index = 0; + instance->worker_running = false; + instance->initiated = false; + instance->last_time_tx_data = 0; + instance->load_index = 0; + + instance->thread = furi_thread_alloc(); + furi_thread_set_name(instance->thread, "SubBruteAttackWorker"); + furi_thread_set_stack_size(instance->thread, 2048); + furi_thread_set_context(instance->thread, instance); + furi_thread_set_callback(instance->thread, subbrute_worker_thread); + + instance->context = NULL; + instance->callback = NULL; + + instance->decoder_result = NULL; + instance->transmitter = NULL; + instance->environment = subghz_environment_alloc(); + + return instance; +} + +void subbrute_worker_free(SubBruteWorker* instance) { + furi_assert(instance); + + // I don't know how to free this + instance->decoder_result = NULL; + + if(instance->transmitter != NULL) { + subghz_transmitter_free(instance->transmitter); + instance->transmitter = NULL; + } + + subghz_environment_free(instance->environment); + instance->environment = NULL; + + furi_thread_free(instance->thread); + + free(instance); +} + +uint64_t subbrute_worker_get_step(SubBruteWorker* instance) { + return instance->key_index; +} + +bool subbrute_worker_set_step(SubBruteWorker* instance, uint64_t step) { + furi_assert(instance); + if(!subbrute_worker_can_manual_transmit(instance)) { + FURI_LOG_W(TAG, "Cannot set step during running mode"); + return false; + } + + instance->key_index = step; + + return true; +} + +bool subbrute_worker_init_default_attack( + SubBruteWorker* instance, + SubBruteAttacks attack_type, + uint64_t step, + const SubBruteProtocol* protocol) { + furi_assert(instance); + + if(instance->worker_running) { + FURI_LOG_W(TAG, "Init Worker when it's running"); + subbrute_worker_stop(instance); + } + + instance->attack = attack_type; + instance->frequency = protocol->frequency; + instance->preset = protocol->preset; + instance->file = protocol->file; + instance->key_index = step; + instance->bits = protocol->bits; + instance->te = protocol->te; + instance->load_index = 0; + instance->file_key = NULL; + instance->max_value = subbrute_protocol_calc_max_value(instance->attack, instance->bits); + + return true; +} + +bool subbrute_worker_init_file_attack( + SubBruteWorker* instance, + uint64_t step, + uint8_t load_index, + const char* file_key, + SubBruteProtocol* protocol) { + furi_assert(instance); + + if(instance->worker_running) { + FURI_LOG_W(TAG, "Init Worker when it's running"); + subbrute_worker_stop(instance); + } + + instance->attack = SubBruteAttackLoadFile; + instance->frequency = protocol->frequency; + instance->preset = protocol->preset; + instance->file = protocol->file; + instance->key_index = step; + instance->bits = protocol->bits; + instance->te = protocol->te; + instance->load_index = load_index; + instance->file_key = file_key; + instance->max_value = subbrute_protocol_calc_max_value(instance->attack, instance->bits); + + return true; +} + +bool subbrute_worker_start(SubBruteWorker* instance) { + furi_assert(instance); + + if(!instance->initiated) { + FURI_LOG_W(TAG, "Worker not init!"); + return false; + } + + if(instance->worker_running) { + FURI_LOG_W(TAG, "Worker is already running!"); + return false; + } + if(instance->state != SubBruteWorkerStateReady && + instance->state != SubBruteWorkerStateFinished) { + FURI_LOG_W(TAG, "Worker cannot start, invalid device state: %d", instance->state); + return false; + } + + instance->worker_running = true; + furi_thread_start(instance->thread); + + return true; +} + +void subbrute_worker_stop(SubBruteWorker* instance) { + furi_assert(instance); + + instance->worker_running = false; + + furi_thread_join(instance->thread); + + furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate); + furi_hal_subghz_sleep(); +} + +bool subbrute_worker_transmit_current_key(SubBruteWorker* instance, uint64_t step) { + furi_assert(instance); + + if(!instance->initiated) { + FURI_LOG_W(TAG, "Worker not init!"); + return false; + } + if(instance->worker_running) { + FURI_LOG_W(TAG, "Worker in running state!"); + return false; + } + if(instance->state != SubBruteWorkerStateReady && + instance->state != SubBruteWorkerStateFinished) { + FURI_LOG_W(TAG, "Invalid state for running worker! State: %d", instance->state); + return false; + } + + uint32_t ticks = furi_get_tick(); + if((ticks - instance->last_time_tx_data) < SUBBRUTE_MANUAL_TRANSMIT_INTERVAL) { +#if FURI_DEBUG + FURI_LOG_D(TAG, "Need to wait, current: %ld", ticks - instance->last_time_tx_data); +#endif + return false; + } + + instance->last_time_tx_data = ticks; + instance->key_index = step; + + bool result; + FlipperFormat* flipper_format = flipper_format_string_alloc(); + Stream* stream = flipper_format_get_raw_stream(flipper_format); + + FuriString* payload = furi_string_alloc(); + stream_clean(stream); + + if(instance->attack == SubBruteAttackLoadFile) { + payload = subbrute_protocol_file_payload( + step, + instance->bits, + instance->te, + instance->repeat, + instance->load_index, + instance->file_key); + } else { + payload = subbrute_protocol_default_payload( + step, instance->bits, instance->te, instance->repeat); + } + + size_t written = stream_write_string(stream, payload); + if(written <= 0) { + FURI_LOG_W(TAG, "Error creating packet! EXIT"); + result = false; + } else { + subbrute_worker_subghz_transmit(instance, flipper_format); + + result = true; +#if FURI_DEBUG + FURI_LOG_D(TAG, "Manual transmit done"); +#endif + } + + flipper_format_free(flipper_format); + furi_string_free(payload); + + return result; +} + +bool subbrute_worker_is_running(SubBruteWorker* instance) { + return instance->worker_running; +} + +bool subbrute_worker_can_manual_transmit(SubBruteWorker* instance) { + furi_assert(instance); + + if(!instance->initiated) { + FURI_LOG_W(TAG, "Worker not init!"); + return false; + } + + return !instance->worker_running && instance->state != SubBruteWorkerStateIDLE && + instance->state != SubBruteWorkerStateTx && + ((furi_get_tick() - instance->last_time_tx_data) > SUBBRUTE_MANUAL_TRANSMIT_INTERVAL); +} + +void subbrute_worker_set_callback( + SubBruteWorker* instance, + SubBruteWorkerCallback callback, + void* context) { + furi_assert(instance); + + instance->callback = callback; + instance->context = context; +} + +void subbrute_worker_subghz_transmit(SubBruteWorker* instance, FlipperFormat* flipper_format) { + instance->transmitter = subghz_transmitter_alloc_init( + instance->environment, subbrute_protocol_name(instance->attack)); + subghz_transmitter_deserialize(instance->transmitter, flipper_format); + furi_hal_subghz_reset(); + furi_hal_subghz_load_preset(instance->preset); + furi_hal_subghz_set_frequency_and_path(instance->frequency); + furi_hal_subghz_start_async_tx(subghz_transmitter_yield, instance->transmitter); + + while(!furi_hal_subghz_is_async_tx_complete()) { + furi_delay_ms(SUBBRUTE_TX_TIMEOUT); + } + furi_hal_subghz_stop_async_tx(); + + furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate); + furi_hal_subghz_sleep(); + subghz_transmitter_free(instance->transmitter); + instance->transmitter = NULL; +} + +void subbrute_worker_send_callback(SubBruteWorker* instance) { + if(instance->callback != NULL) { + instance->callback(instance->context, instance->state); + } +} + +/** + * Entrypoint for worker + * + * @param context SubBruteWorker* + * @return 0 if ok + */ +int32_t subbrute_worker_thread(void* context) { + furi_assert(context); + SubBruteWorker* instance = (SubBruteWorker*)context; + + if(!instance->worker_running) { + FURI_LOG_W(TAG, "Worker is not set to running state!"); + return -1; + } + if(instance->state != SubBruteWorkerStateReady && + instance->state != SubBruteWorkerStateFinished) { + FURI_LOG_W(TAG, "Invalid state for running worker! State: %d", instance->state); + return -2; + } +#ifdef FURI_DEBUG + FURI_LOG_I(TAG, "Worker start"); +#endif + + SubBruteWorkerState local_state = instance->state = SubBruteWorkerStateTx; + subbrute_worker_send_callback(instance); + + FlipperFormat* flipper_format = flipper_format_string_alloc(); + Stream* stream = flipper_format_get_raw_stream(flipper_format); + + while(instance->worker_running) { + FuriString* payload = furi_string_alloc(); + stream_clean(stream); + + if(instance->attack == SubBruteAttackLoadFile) { + payload = subbrute_protocol_file_payload( + instance->key_index, + instance->bits, + instance->te, + instance->repeat, + instance->load_index, + instance->file_key); + } else { + payload = subbrute_protocol_default_payload( + instance->key_index, instance->bits, instance->te, instance->repeat); + } + + size_t written = stream_write_string(stream, payload); + if(written <= 0) { + FURI_LOG_W(TAG, "Error creating packet! BREAK"); + instance->worker_running = false; + local_state = SubBruteWorkerStateIDLE; + furi_string_free(payload); + break; + } + + subbrute_worker_subghz_transmit(instance, flipper_format); + + if(instance->key_index + 1 > instance->max_value) { +#ifdef FURI_DEBUG + FURI_LOG_I(TAG, "Worker finished to end"); +#endif + local_state = SubBruteWorkerStateFinished; + furi_string_free(payload); + break; + } + instance->key_index++; + + furi_string_free(payload); + furi_delay_ms(SUBBRUTE_TX_TIMEOUT); + } + + flipper_format_free(flipper_format); + + instance->worker_running = false; // Because we have error states + instance->state = local_state == SubBruteWorkerStateTx ? SubBruteWorkerStateReady : + local_state; + subbrute_worker_send_callback(instance); + +#ifdef FURI_DEBUG + FURI_LOG_I(TAG, "Worker stop"); +#endif + return 0; +} diff --git a/applications/plugins/subbrute/helpers/subbrute_worker.h b/applications/plugins/subbrute/helpers/subbrute_worker.h new file mode 100644 index 000000000..3a514272b --- /dev/null +++ b/applications/plugins/subbrute/helpers/subbrute_worker.h @@ -0,0 +1,39 @@ +#pragma once + +#include "../subbrute_protocols.h" + +typedef enum { + SubBruteWorkerStateIDLE, + SubBruteWorkerStateReady, + SubBruteWorkerStateTx, + SubBruteWorkerStateFinished +} SubBruteWorkerState; + +typedef void (*SubBruteWorkerCallback)(void* context, SubBruteWorkerState state); + +typedef struct SubBruteWorker SubBruteWorker; + +SubBruteWorker* subbrute_worker_alloc(); +void subbrute_worker_free(SubBruteWorker* instance); +uint64_t subbrute_worker_get_step(SubBruteWorker* instance); +bool subbrute_worker_set_step(SubBruteWorker* instance, uint64_t step); +bool subbrute_worker_is_running(SubBruteWorker* instance); +bool subbrute_worker_init_default_attack( + SubBruteWorker* instance, + SubBruteAttacks attack_type, + uint64_t step, + const SubBruteProtocol* protocol); +bool subbrute_worker_init_file_attack( + SubBruteWorker* instance, + uint64_t step, + uint8_t load_index, + const char* file_key, + SubBruteProtocol* protocol); +bool subbrute_worker_start(SubBruteWorker* instance); +void subbrute_worker_stop(SubBruteWorker* instance); +bool subbrute_worker_transmit_current_key(SubBruteWorker* instance, uint64_t step); +bool subbrute_worker_can_manual_transmit(SubBruteWorker* instance); +void subbrute_worker_set_callback( + SubBruteWorker* instance, + SubBruteWorkerCallback callback, + void* context); \ No newline at end of file diff --git a/applications/plugins/subbrute/helpers/subbrute_worker_private.h b/applications/plugins/subbrute/helpers/subbrute_worker_private.h new file mode 100644 index 000000000..fd55902bb --- /dev/null +++ b/applications/plugins/subbrute/helpers/subbrute_worker_private.h @@ -0,0 +1,45 @@ +#pragma once + +#include "subbrute_worker.h" +#include +#include +#include +#include + +struct SubBruteWorker { + SubBruteWorkerState state; + volatile bool worker_running; + volatile bool initiated; + + // Current step + uint64_t key_index; + + // SubGhz + FuriThread* thread; + SubGhzProtocolDecoderBase* decoder_result; + SubGhzEnvironment* environment; + SubGhzTransmitter* transmitter; + + // Initiated values + SubBruteAttacks attack; // Attack state + uint32_t frequency; + FuriHalSubGhzPreset preset; + SubBruteFileProtocol file; + uint8_t bits; + uint8_t te; + uint8_t repeat; + uint8_t load_index; // Index of group to bruteforce in loaded file + const char* file_key; + uint64_t max_value; // Max step + + // Manual transmit + uint32_t last_time_tx_data; + + // Callback for changed states + SubBruteWorkerCallback callback; + void* context; +}; + +int32_t subbrute_worker_thread(void* context); +void subbrute_worker_subghz_transmit(SubBruteWorker* instance, FlipperFormat* flipper_format); +void subbrute_worker_send_callback(SubBruteWorker* instance); \ No newline at end of file diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_load_file.c b/applications/plugins/subbrute/scenes/subbrute_scene_load_file.c index dc26403c3..84df3e4e5 100644 --- a/applications/plugins/subbrute/scenes/subbrute_scene_load_file.c +++ b/applications/plugins/subbrute/scenes/subbrute_scene_load_file.c @@ -39,6 +39,14 @@ void subbrute_scene_load_file_on_enter(void* context) { if(load_result == SubBruteFileResultOk) { load_result = subbrute_device_attack_set(instance->device, SubBruteAttackLoadFile); if(load_result == SubBruteFileResultOk) { + if(!subbrute_worker_init_file_attack( + instance->worker, + instance->device->key_index, + instance->device->load_index, + instance->device->file_key, + instance->device->file_protocol_info)) { + furi_crash("Invalid attack set!"); + } // Ready to run! FURI_LOG_I(TAG, "Ready to run"); res = true; @@ -52,7 +60,8 @@ void subbrute_scene_load_file_on_enter(void* context) { FuriString* dialog_msg; dialog_msg = furi_string_alloc(); - furi_string_cat_printf(dialog_msg, "Cannot parse\nfile: %s", subbrute_device_error_get_desc(load_result)); + furi_string_cat_printf( + dialog_msg, "Cannot parse\nfile: %s", subbrute_device_error_get_desc(load_result)); dialog_message_show_storage_error(instance->dialogs, furi_string_get_cstr(dialog_msg)); furi_string_free(dialog_msg); scene_manager_search_and_switch_to_previous_scene( diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_load_select.c b/applications/plugins/subbrute/scenes/subbrute_scene_load_select.c index e9fafd4da..77db3f64b 100644 --- a/applications/plugins/subbrute/scenes/subbrute_scene_load_select.c +++ b/applications/plugins/subbrute/scenes/subbrute_scene_load_select.c @@ -20,7 +20,7 @@ void subbrute_scene_load_select_on_enter(void* context) { instance->current_view = SubBruteViewMain; subbrute_main_view_set_callback(view, subbrute_scene_load_select_callback, instance); - subbrute_main_view_set_index(view, 7, true, subbrute_device_get_file_key(instance->device)); + subbrute_main_view_set_index(view, 7, true, instance->device->file_key); view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view); } @@ -38,8 +38,15 @@ bool subbrute_scene_load_select_on_event(void* context, SceneManagerEvent event) if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubBruteCustomEventTypeIndexSelected) { - subbrute_device_set_load_index( - instance->device, subbrute_main_view_get_index(instance->view_main)); + instance->device->load_index = subbrute_main_view_get_index(instance->view_main); + if(!subbrute_worker_init_file_attack( + instance->worker, + instance->device->key_index, + instance->device->load_index, + instance->device->file_key, + instance->device->file_protocol_info)) { + furi_crash("Invalid attack set!"); + } scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack); consumed = true; } diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_run_attack.c b/applications/plugins/subbrute/scenes/subbrute_scene_run_attack.c index 36b3e3f43..17a3d910a 100644 --- a/applications/plugins/subbrute/scenes/subbrute_scene_run_attack.c +++ b/applications/plugins/subbrute/scenes/subbrute_scene_run_attack.c @@ -11,15 +11,15 @@ static void subbrute_scene_run_attack_callback(SubBruteCustomEvent event, void* } static void - subbrute_scene_run_attack_device_state_changed(void* context, SubBruteDeviceState state) { + subbrute_scene_run_attack_device_state_changed(void* context, SubBruteWorkerState state) { furi_assert(context); SubBruteState* instance = (SubBruteState*)context; - if(state == SubBruteDeviceStateIDLE) { + if(state == SubBruteWorkerStateIDLE) { // Can't be IDLE on this step! view_dispatcher_send_custom_event(instance->view_dispatcher, SubBruteCustomEventTypeError); - } else if(state == SubBruteDeviceStateFinished) { + } else if(state == SubBruteWorkerStateFinished) { view_dispatcher_send_custom_event( instance->view_dispatcher, SubBruteCustomEventTypeTransmitFinished); } @@ -28,7 +28,7 @@ void subbrute_scene_run_attack_on_exit(void* context) { furi_assert(context); SubBruteState* instance = (SubBruteState*)context; - subbrute_worker_stop(instance->device); + subbrute_worker_stop(instance->worker); notification_message(instance->notifications, &sequence_blink_stop); } @@ -42,11 +42,11 @@ void subbrute_scene_run_attack_on_enter(void* context) { subbrute_attack_view_set_callback(view, subbrute_scene_run_attack_callback, instance); view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view); - subbrute_device_set_callback( - instance->device, subbrute_scene_run_attack_device_state_changed, instance); + subbrute_worker_set_callback( + instance->worker, subbrute_scene_run_attack_device_state_changed, instance); - if(!subbrute_device_is_worker_running(instance->device)) { - subbrute_worker_start(instance->device); + if(!subbrute_worker_is_running(instance->worker)) { + subbrute_worker_start(instance->worker); } } @@ -57,7 +57,7 @@ bool subbrute_scene_run_attack_on_event(void* context, SceneManagerEvent event) bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - subbrute_attack_view_set_current_step(view, subbrute_get_step(instance)); + subbrute_attack_view_set_current_step(view, subbrute_worker_get_step(instance->worker)); if(event.event == SubBruteCustomEventTypeTransmitFinished) { notification_message(instance->notifications, &sequence_display_backlight_on); @@ -77,7 +77,7 @@ bool subbrute_scene_run_attack_on_event(void* context, SceneManagerEvent event) } consumed = true; } else if(event.type == SceneManagerEventTypeTick) { - subbrute_attack_view_set_current_step(view, subbrute_get_step(instance)); + subbrute_attack_view_set_current_step(view, subbrute_worker_get_step(instance->worker)); consumed = true; } diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_setup_attack.c b/applications/plugins/subbrute/scenes/subbrute_scene_setup_attack.c index b506a33d5..4984b4931 100644 --- a/applications/plugins/subbrute/scenes/subbrute_scene_setup_attack.c +++ b/applications/plugins/subbrute/scenes/subbrute_scene_setup_attack.c @@ -11,12 +11,12 @@ static void subbrute_scene_setup_attack_callback(SubBruteCustomEvent event, void } static void - subbrute_scene_setup_attack_device_state_changed(void* context, SubBruteDeviceState state) { + subbrute_scene_setup_attack_device_state_changed(void* context, SubBruteWorkerState state) { furi_assert(context); SubBruteState* instance = (SubBruteState*)context; - if(state == SubBruteDeviceStateIDLE) { + if(state == SubBruteWorkerStateIDLE) { // Can't be IDLE on this step! view_dispatcher_send_custom_event(instance->view_dispatcher, SubBruteCustomEventTypeError); } @@ -28,16 +28,24 @@ void subbrute_scene_setup_attack_on_enter(void* context) { SubBruteAttackView* view = instance->view_attack; #ifdef FURI_DEBUG - FURI_LOG_D(TAG, "Enter Attack: %d", subbrute_device_get_attack(instance->device)); + FURI_LOG_D(TAG, "Enter Attack: %d", instance->device->attack); #endif - subbrute_device_set_callback( - instance->device, subbrute_scene_setup_attack_device_state_changed, context); + subbrute_worker_set_callback( + instance->worker, subbrute_scene_setup_attack_device_state_changed, context); - if(subbrute_device_is_worker_running(instance->device)) { - subbrute_worker_stop(instance->device); + if(subbrute_worker_is_running(instance->worker)) { + instance->device->key_index = subbrute_worker_get_step(instance->worker); + subbrute_worker_stop(instance->worker); } + subbrute_attack_view_init_values( + view, + instance->device->attack, + instance->device->max_value, + instance->device->key_index, + false); + instance->current_view = SubBruteViewAttack; subbrute_attack_view_set_callback(view, subbrute_scene_setup_attack_callback, instance); view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view); @@ -49,7 +57,7 @@ void subbrute_scene_setup_attack_on_exit(void* context) { FURI_LOG_D(TAG, "subbrute_scene_setup_attack_on_exit"); #endif SubBruteState* instance = (SubBruteState*)context; - subbrute_worker_stop(instance->device); + subbrute_worker_stop(instance->worker); notification_message(instance->notifications, &sequence_blink_stop); } @@ -65,53 +73,60 @@ bool subbrute_scene_setup_attack_on_event(void* context, SceneManagerEvent event } else if(event.event == SubBruteCustomEventTypeSaveFile) { subbrute_attack_view_init_values( view, - subbrute_device_get_attack(instance->device), - subbrute_device_get_max_value(instance->device), - subbrute_device_get_step(instance->device), + instance->device->attack, + instance->device->max_value, + instance->device->key_index, false); scene_manager_next_scene(instance->scene_manager, SubBruteSceneSaveName); } else if(event.event == SubBruteCustomEventTypeBackPressed) { - subbrute_device_reset_step(instance->device); subbrute_attack_view_init_values( view, - subbrute_device_get_attack(instance->device), - subbrute_device_get_max_value(instance->device), - subbrute_device_get_step(instance->device), + instance->device->attack, + instance->device->max_value, + instance->device->key_index, false); scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart); } else if(event.event == SubBruteCustomEventTypeError) { notification_message(instance->notifications, &sequence_error); } else if(event.event == SubBruteCustomEventTypeTransmitCustom) { // We can transmit only in not working states - if(subbrute_device_can_manual_transmit(instance->device)) { + if(subbrute_worker_can_manual_transmit(instance->worker)) { // MANUAL Transmit! // Blink notification_message(instance->notifications, &sequence_blink_green_100); - subbrute_device_transmit_current_key(instance->device); + subbrute_worker_transmit_current_key( + instance->worker, instance->device->key_index); // Stop notification_message(instance->notifications, &sequence_blink_stop); } } else if(event.event == SubBruteCustomEventTypeChangeStepUp) { // +1 uint64_t step = subbrute_device_add_step(instance->device, 1); + subbrute_worker_set_step(instance->worker, step); subbrute_attack_view_set_current_step(view, step); } else if(event.event == SubBruteCustomEventTypeChangeStepUpMore) { // +50 uint64_t step = subbrute_device_add_step(instance->device, 50); + subbrute_worker_set_step(instance->worker, step); subbrute_attack_view_set_current_step(view, step); } else if(event.event == SubBruteCustomEventTypeChangeStepDown) { // -1 uint64_t step = subbrute_device_add_step(instance->device, -1); + subbrute_worker_set_step(instance->worker, step); subbrute_attack_view_set_current_step(view, step); } else if(event.event == SubBruteCustomEventTypeChangeStepDownMore) { // -50 uint64_t step = subbrute_device_add_step(instance->device, -50); + subbrute_worker_set_step(instance->worker, step); subbrute_attack_view_set_current_step(view, step); } consumed = true; } else if(event.type == SceneManagerEventTypeTick) { - subbrute_attack_view_set_current_step(view, subbrute_device_get_step(instance->device)); + if(subbrute_worker_is_running(instance->worker)) { + instance->device->key_index = subbrute_worker_get_step(instance->worker); + } + subbrute_attack_view_set_current_step(view, instance->device->key_index); consumed = true; } diff --git a/applications/plugins/subbrute/scenes/subbrute_scene_start.c b/applications/plugins/subbrute/scenes/subbrute_scene_start.c index 38441ea30..2d7bc5134 100644 --- a/applications/plugins/subbrute/scenes/subbrute_scene_start.c +++ b/applications/plugins/subbrute/scenes/subbrute_scene_start.c @@ -23,7 +23,7 @@ void subbrute_scene_start_on_enter(void* context) { instance->current_view = SubBruteViewMain; subbrute_main_view_set_callback(view, subbrute_scene_start_callback, instance); - subbrute_main_view_set_index(view, subbrute_device_get_attack(instance->device), false, NULL); + subbrute_main_view_set_index(view, instance->device->attack, false, NULL); view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view); } @@ -46,7 +46,14 @@ bool subbrute_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.event == SubBruteCustomEventTypeMenuSelected) { SubBruteAttacks attack = subbrute_main_view_get_index(instance->view_main); - subbrute_device_attack_set(instance->device, attack); + if(subbrute_device_attack_set(instance->device, attack) != SubBruteFileResultOk || + !subbrute_worker_init_default_attack( + instance->worker, + attack, + instance->device->key_index, + instance->device->protocol_info)) { + furi_crash("Invalid attack set!"); + } scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack); consumed = true; diff --git a/applications/plugins/subbrute/subbrute.c b/applications/plugins/subbrute/subbrute.c index cfb6b337f..aaab3aeb1 100644 --- a/applications/plugins/subbrute/subbrute.c +++ b/applications/plugins/subbrute/subbrute.c @@ -51,6 +51,9 @@ SubBruteState* subbrute_alloc() { // Devices instance->device = subbrute_device_alloc(); + // SubBruteWorker + instance->worker = subbrute_worker_alloc(); + // TextInput instance->text_input = text_input_alloc(); view_dispatcher_add_view( @@ -96,8 +99,11 @@ SubBruteState* subbrute_alloc() { void subbrute_free(SubBruteState* instance) { furi_assert(instance); + // SubBruteWorker + subbrute_worker_stop(instance->worker); + subbrute_worker_free(instance->worker); + // SubBruteDevice - subbrute_worker_stop(instance->device); subbrute_device_free(instance->device); // Notifications @@ -163,13 +169,6 @@ void subbrute_popup_closed_callback(void* context) { instance->view_dispatcher, SubBruteCustomEventTypePopupClosed); } -uint64_t subbrute_get_step(void* context) { - furi_assert(context); - SubBruteState* instance = context; - - return subbrute_device_get_step(instance->device); -} - // ENTRYPOINT int32_t subbrute_app(void* p) { UNUSED(p); diff --git a/applications/plugins/subbrute/subbrute_device.c b/applications/plugins/subbrute/subbrute_device.c index fea298b8a..3e98c469d 100644 --- a/applications/plugins/subbrute/subbrute_device.c +++ b/applications/plugins/subbrute/subbrute_device.c @@ -8,40 +8,14 @@ #define TAG "SubBruteDevice" -#define SUBBRUTE_TX_TIMEOUT 5 -#define SUBBRUTE_MANUAL_TRANSMIT_INTERVAL 400 - -/** - * Values to not use less memory for packet parse operations - */ -static const char* subbrute_key_file_start = - "Filetype: Flipper SubGhz Key File\nVersion: 1\nFrequency: %u\nPreset: %s\nProtocol: %s\nBit: %d"; -static const char* subbrute_key_file_key = "%s\nKey: %s\nRepeat: %d\n"; -static const char* subbrute_key_file_key_with_tail = "%s\nKey: %s\nTE: %d\nRepeat: %d\n"; -static const char* subbrute_key_small_no_tail = "Bit: %d\nKey: %s\nRepeat: %d\nRepeat: %d\n"; -static const char* subbrute_key_small_with_tail = "Bit: %d\nKey: %s\nTE: %d\nRepeat: %d\n"; - SubBruteDevice* subbrute_device_alloc() { SubBruteDevice* instance = malloc(sizeof(SubBruteDevice)); - instance->state = SubBruteDeviceStateIDLE; instance->key_index = 0; - instance->worker_running = false; - instance->last_time_tx_data = 0; - - instance->thread = furi_thread_alloc(); - furi_thread_set_name(instance->thread, "SubBruteAttackWorker"); - furi_thread_set_stack_size(instance->thread, 2048); - furi_thread_set_context(instance->thread, instance); - furi_thread_set_callback(instance->thread, subbrute_worker_thread); - - instance->context = NULL; - instance->callback = NULL; instance->protocol_info = NULL; instance->file_protocol_info = NULL; instance->decoder_result = NULL; - instance->transmitter = NULL; instance->receiver = NULL; instance->environment = subghz_environment_alloc(); @@ -61,137 +35,15 @@ void subbrute_device_free(SubBruteDevice* instance) { instance->receiver = NULL; } - if(instance->transmitter != NULL) { - subghz_transmitter_free(instance->transmitter); - instance->transmitter = NULL; - } - subghz_environment_free(instance->environment); instance->environment = NULL; - furi_thread_free(instance->thread); subbrute_device_free_protocol_info(instance); free(instance); } -/** - * Entrypoint for worker - * - * @param context SubBruteWorker* - * @return 0 if ok - */ -int32_t subbrute_worker_thread(void* context) { - furi_assert(context); - SubBruteDevice* instance = (SubBruteDevice*)context; - - if(!instance->worker_running) { - FURI_LOG_W(TAG, "Worker is not set to running state!"); - return -1; - } - if(instance->state != SubBruteDeviceStateReady && - instance->state != SubBruteDeviceStateFinished) { - FURI_LOG_W(TAG, "Invalid state for running worker! State: %d", instance->state); - return -2; - } -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "Worker start"); -#endif - - SubBruteDeviceState local_state = instance->state = SubBruteDeviceStateTx; - subbrute_device_send_callback(instance); - - FlipperFormat* flipper_format = flipper_format_string_alloc(); - - while(instance->worker_running) { - if(!subbrute_device_create_packet_parsed( - instance, flipper_format, instance->key_index, true)) { - FURI_LOG_W(TAG, "Error creating packet! BREAK"); - instance->worker_running = false; - local_state = SubBruteDeviceStateIDLE; - break; - } - subbrute_device_subghz_transmit(instance, flipper_format); - - if(instance->key_index + 1 > instance->max_value) { -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "Worker finished to end"); -#endif - local_state = SubBruteDeviceStateFinished; - break; - } - instance->key_index++; - - furi_delay_ms(SUBBRUTE_TX_TIMEOUT); - } - - flipper_format_free(flipper_format); - - instance->worker_running = false; // Because we have error states - instance->state = local_state == SubBruteDeviceStateTx ? SubBruteDeviceStateReady : - local_state; - subbrute_device_send_callback(instance); - -#ifdef FURI_DEBUG - FURI_LOG_I(TAG, "Worker stop"); -#endif - return 0; -} - -bool subbrute_worker_start(SubBruteDevice* instance) { - furi_assert(instance); - - if(instance->worker_running) { - FURI_LOG_W(TAG, "Worker is already running!"); - return false; - } - if(instance->state != SubBruteDeviceStateReady && - instance->state != SubBruteDeviceStateFinished) { - FURI_LOG_W(TAG, "Worker cannot start, invalid device state: %d", instance->state); - return false; - } - if((instance->protocol_info == NULL && instance->attack != SubBruteAttackLoadFile) || - (instance->attack == SubBruteAttackLoadFile && instance->file_protocol_info == NULL)) { - FURI_LOG_W(TAG, "Worker cannot start, protocol_info is NULL!"); - return false; - } - - instance->worker_running = true; - furi_thread_start(instance->thread); - - return true; -} - -void subbrute_worker_stop(SubBruteDevice* instance) { - furi_assert(instance); - - instance->worker_running = false; - - furi_thread_join(instance->thread); - - furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate); - furi_hal_subghz_sleep(); -} - -SubBruteAttacks subbrute_device_get_attack(SubBruteDevice* instance) { - return instance->attack; -} -bool subbrute_device_is_worker_running(SubBruteDevice* instance) { - return instance->worker_running; -} -uint64_t subbrute_device_get_max_value(SubBruteDevice* instance) { - return instance->max_value; -} -uint64_t subbrute_device_get_step(SubBruteDevice* instance) { - return instance->key_index; -} -const char* subbrute_device_get_file_key(SubBruteDevice* instance) { - return instance->file_key; -} uint64_t subbrute_device_add_step(SubBruteDevice* instance, int8_t step) { - if(!subbrute_device_can_manual_transmit(instance)) { - return instance->key_index; - } if(step > 0) { if((instance->key_index + step) - instance->max_value == 1) { instance->key_index = 0x00; @@ -220,122 +72,17 @@ uint64_t subbrute_device_add_step(SubBruteDevice* instance, int8_t step) { return instance->key_index; } -void subbrute_device_set_load_index(SubBruteDevice* instance, uint64_t load_index) { - instance->load_index = load_index; -} -void subbrute_device_reset_step(SubBruteDevice* instance) { - instance->key_index = 0x00; -} -void subbrute_device_subghz_transmit(SubBruteDevice* instance, FlipperFormat* flipper_format) { - instance->transmitter = subghz_transmitter_alloc_init( - instance->environment, subbrute_protocol_name(instance->attack)); - subghz_transmitter_deserialize(instance->transmitter, flipper_format); - furi_hal_subghz_reset(); - if(instance->attack == SubBruteAttackLoadFile) { - furi_hal_subghz_load_preset(instance->file_protocol_info->preset); - furi_hal_subghz_set_frequency_and_path(instance->file_protocol_info->preset); - } else { - furi_hal_subghz_load_preset(instance->protocol_info->preset); - furi_hal_subghz_set_frequency_and_path(instance->protocol_info->preset); - } - furi_hal_subghz_start_async_tx(subghz_transmitter_yield, instance->transmitter); - - while(!furi_hal_subghz_is_async_tx_complete()) { - furi_delay_ms(SUBBRUTE_TX_TIMEOUT); - } - furi_hal_subghz_stop_async_tx(); - - furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate); - furi_hal_subghz_sleep(); - subghz_transmitter_free(instance->transmitter); - instance->transmitter = NULL; -} - -bool subbrute_device_transmit_current_key(SubBruteDevice* instance) { - furi_assert(instance); - - if(instance->worker_running) { - FURI_LOG_W(TAG, "Worker in running state!"); - return false; - } - if(instance->state != SubBruteDeviceStateReady && - instance->state != SubBruteDeviceStateFinished) { - FURI_LOG_W(TAG, "Invalid state for running worker! State: %d", instance->state); - return false; - } - - uint32_t ticks = furi_get_tick(); - if((ticks - instance->last_time_tx_data) < SUBBRUTE_MANUAL_TRANSMIT_INTERVAL) { -#if FURI_DEBUG - FURI_LOG_D(TAG, "Need to wait, current: %ld", ticks - instance->last_time_tx_data); -#endif - return false; - } - - instance->last_time_tx_data = ticks; - -#ifdef FURI_DEBUG - if(instance->attack == SubBruteAttackLoadFile) { - FURI_LOG_D( - TAG, - "Protocol: %d, Frequency: %ld", - instance->file_protocol_info->file, - instance->file_protocol_info->frequency); - } else { - FURI_LOG_D( - TAG, - "Protocol: %d, Frequency: %ld", - instance->protocol_info->file, - instance->protocol_info->frequency); - } -#endif - - FlipperFormat* flipper_format = flipper_format_string_alloc(); - - if(!subbrute_device_create_packet_parsed(instance, flipper_format, instance->key_index, true)) { - FURI_LOG_W(TAG, "Error creating packet! EXIT"); - return false; - } - subbrute_device_subghz_transmit(instance, flipper_format); - - flipper_format_free(flipper_format); - - return true; -} - -void subbrute_device_set_callback( - SubBruteDevice* instance, - SubBruteDeviceWorkerCallback callback, - void* context) { - furi_assert(instance); - - instance->callback = callback; - instance->context = context; -} - -bool subbrute_device_can_manual_transmit(SubBruteDevice* instance) { - furi_assert(instance); - - return !instance->worker_running && instance->state != SubBruteDeviceStateIDLE && - instance->state != SubBruteDeviceStateTx && - ((furi_get_tick() - instance->last_time_tx_data) > SUBBRUTE_MANUAL_TRANSMIT_INTERVAL); -} bool subbrute_device_save_file(SubBruteDevice* instance, const char* dev_file_name) { furi_assert(instance); - if(instance->state != SubBruteDeviceStateReady && - instance->state != SubBruteDeviceStateFinished) { - FURI_LOG_W(TAG, "Worker is not set to running state!"); - return false; - } - #ifdef FURI_DEBUG FURI_LOG_D(TAG, "subbrute_device_save_file: %s", dev_file_name); #endif Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* file = flipper_format_file_alloc(storage); + FuriString* file_content = furi_string_alloc(); bool result = false; do { @@ -343,7 +90,32 @@ bool subbrute_device_save_file(SubBruteDevice* instance, const char* dev_file_na break; } - if(!subbrute_device_create_packet_parsed(instance, file, instance->key_index, false)) { + if(instance->attack == SubBruteAttackLoadFile) { + file_content = subbrute_protocol_file_generate_file( + instance->file_protocol_info->frequency, + instance->file_protocol_info->preset, + instance->file_protocol_info->file, + instance->key_index, + instance->file_protocol_info->bits, + instance->file_protocol_info->te, + instance->file_protocol_info->repeat, + instance->load_index, + instance->file_key); + } else { + file_content = subbrute_protocol_default_generate_file( + instance->protocol_info->frequency, + instance->protocol_info->preset, + instance->protocol_info->file, + instance->key_index, + instance->protocol_info->bits, + instance->protocol_info->te, + instance->protocol_info->repeat); + } + + Stream* stream = flipper_format_get_raw_stream(file); + stream_clean(stream); + size_t written = stream_write_string(stream, file_content); + if(written <= 0) { FURI_LOG_E(TAG, "create_packet_parsed failed!"); break; } @@ -352,140 +124,17 @@ bool subbrute_device_save_file(SubBruteDevice* instance, const char* dev_file_na } while(false); if(!result) { - FURI_LOG_E(TAG, "flipper_format_file_open_always failed!"); + FURI_LOG_E(TAG, "subbrute_device_save_file failed!"); } + flipper_format_file_close(file); flipper_format_free(file); furi_record_close(RECORD_STORAGE); + furi_string_free(file_content); return result; } -bool subbrute_device_create_packet_parsed( - SubBruteDevice* instance, - FlipperFormat* flipper_format, - uint64_t step, - bool small) { - furi_assert(instance); - - FuriString* candidate = furi_string_alloc(); - - Stream* stream = flipper_format_get_raw_stream(flipper_format); - stream_clean(stream); - - if(instance->attack == SubBruteAttackLoadFile) { - if(step >= sizeof(instance->file_key)) { - return false; - } - char subbrute_payload_byte[4]; - furi_string_set_str(candidate, instance->file_key); - snprintf(subbrute_payload_byte, 4, "%02X ", (uint8_t)step); - furi_string_replace_at(candidate, instance->load_index * 3, 3, subbrute_payload_byte); - //snprintf(step_payload, sizeof(step_payload), "%02X", (uint8_t)instance->file_key[step]); - - if(small) { - if(instance->file_protocol_info->te) { - stream_write_format( - stream, - subbrute_key_small_with_tail, - instance->file_protocol_info->bits, - furi_string_get_cstr(candidate), - instance->file_protocol_info->te, - instance->file_protocol_info->repeat); - } else { - stream_write_format( - stream, - subbrute_key_small_no_tail, - instance->file_protocol_info->bits, - furi_string_get_cstr(candidate), - instance->file_protocol_info->repeat); - } - } else { - if(instance->file_protocol_info->te) { - stream_write_format( - stream, - subbrute_key_file_key_with_tail, - instance->file_template, - furi_string_get_cstr(candidate), - instance->file_protocol_info->te, - instance->file_protocol_info->repeat); - } else { - stream_write_format( - stream, - subbrute_key_file_key, - instance->file_template, - furi_string_get_cstr(candidate), - instance->file_protocol_info->repeat); - } - } - } else { - //snprintf(step_payload, sizeof(step_payload), "%16X", step); - //snprintf(step_payload, sizeof(step_payload), "%016llX", step); - FuriString* buffer = furi_string_alloc(); - furi_string_printf(buffer, "%16llX", step); - int j = 0; - furi_string_set_str(candidate, " "); - for(uint8_t i = 0; i < 16; i++) { - if(furi_string_get_char(buffer, i) != ' ') { - furi_string_set_char(candidate, i + j, furi_string_get_char(buffer, i)); - } else { - furi_string_set_char(candidate, i + j, '0'); - } - if(i % 2 != 0) { - j++; - } - } - furi_string_free(buffer); - -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "candidate: %s, step: %lld", furi_string_get_cstr(candidate), step); -#endif - - if(small) { - if(instance->protocol_info->te) { - stream_write_format( - stream, - subbrute_key_small_with_tail, - instance->protocol_info->bits, - furi_string_get_cstr(candidate), - instance->protocol_info->te, - instance->protocol_info->repeat); - } else { - stream_write_format( - stream, - subbrute_key_small_no_tail, - instance->protocol_info->bits, - furi_string_get_cstr(candidate), - instance->protocol_info->repeat); - } - } else { - if(instance->protocol_info->te) { - stream_write_format( - stream, - subbrute_key_file_key_with_tail, - instance->file_template, - furi_string_get_cstr(candidate), - instance->protocol_info->te, - instance->protocol_info->repeat); - } else { - stream_write_format( - stream, - subbrute_key_file_key, - instance->file_template, - furi_string_get_cstr(candidate), - instance->protocol_info->repeat); - } - } -#ifdef FURI_DEBUG - FURI_LOG_D(TAG, "candidate: %s", furi_string_get_cstr(candidate)); -#endif - } - - furi_string_free(candidate); - - return true; -} - SubBruteFileResult subbrute_device_attack_set(SubBruteDevice* instance, SubBruteAttacks type) { furi_assert(instance); #ifdef FURI_DEBUG @@ -513,10 +162,18 @@ SubBruteFileResult subbrute_device_attack_set(SubBruteDevice* instance, SubBrute FURI_LOG_E(TAG, "Can't load SubGhzProtocolDecoderBase in phase non-file decoder set"); } else { protocol_check_result = SubBruteFileResultOk; + + // Calc max value + instance->max_value = + subbrute_protocol_calc_max_value(instance->attack, instance->protocol_info->bits); } } else { // And here we need to set preset enum protocol_check_result = SubBruteFileResultOk; + + // Calc max value + instance->max_value = + subbrute_protocol_calc_max_value(instance->attack, instance->file_protocol_info->bits); } subghz_receiver_free(instance->receiver); @@ -526,56 +183,6 @@ SubBruteFileResult subbrute_device_attack_set(SubBruteDevice* instance, SubBrute return SubBruteFileResultProtocolNotFound; } - // Calc max value - if(instance->attack == SubBruteAttackLoadFile) { - instance->max_value = 0x3F; - - // Now we are ready to set file template for using in the future with snprintf - // for sending attack payload ONLY for files! - snprintf( - instance->file_template, - sizeof(instance->file_template), - subbrute_key_file_start, - instance->file_protocol_info->frequency, - subbrute_protocol_preset(instance->file_protocol_info->preset), - subbrute_protocol_file(instance->file_protocol_info->file), - instance->file_protocol_info->bits); - } else { - FuriString* max_value_s; - max_value_s = furi_string_alloc(); - for(uint8_t i = 0; i < instance->protocol_info->bits; i++) { - furi_string_cat_printf(max_value_s, "1"); - } - instance->max_value = (uint64_t)strtol(furi_string_get_cstr(max_value_s), NULL, 2); - furi_string_free(max_value_s); - - // Now we are ready to set file template for using in the future with snprintf - // for sending attack payload - snprintf( - instance->file_template, - sizeof(instance->file_template), - subbrute_key_file_start, - instance->protocol_info->frequency, - subbrute_protocol_preset(instance->protocol_info->preset), - subbrute_protocol_file(instance->protocol_info->file), - instance->protocol_info->bits); -#ifdef FURI_DEBUG - FURI_LOG_D( - TAG, - "tail: %d, file_template: %s", - instance->protocol_info->te, - instance->file_template); -#endif - } - - // Init payload - FlipperFormat* flipper_format = flipper_format_string_alloc(); - if(subbrute_device_create_packet_parsed(instance, flipper_format, instance->key_index, false)) { - instance->state = SubBruteDeviceStateReady; - subbrute_device_send_callback(instance); - } - flipper_format_free(flipper_format); - return SubBruteFileResultOk; } @@ -751,7 +358,6 @@ void subbrute_device_attack_set_default_values( instance->attack = default_attack; instance->key_index = 0x00; instance->load_index = 0x00; - memset(instance->file_template, 0, sizeof(instance->file_template)); memset(instance->current_key, 0, sizeof(instance->current_key)); if(default_attack != SubBruteAttackLoadFile) { @@ -761,12 +367,6 @@ void subbrute_device_attack_set_default_values( } } -void subbrute_device_send_callback(SubBruteDevice* instance) { - if(instance->callback != NULL) { - instance->callback(instance->context, instance->state); - } -} - const char* subbrute_device_error_get_desc(SubBruteFileResult error_id) { const char* result; switch(error_id) { diff --git a/applications/plugins/subbrute/subbrute_device.h b/applications/plugins/subbrute/subbrute_device.h index e3b327b85..b0f136ad2 100644 --- a/applications/plugins/subbrute/subbrute_device.h +++ b/applications/plugins/subbrute/subbrute_device.h @@ -31,19 +31,9 @@ typedef enum { SubBruteFileResultMissingOrIncorrectTe, } SubBruteFileResult; -typedef enum { - SubBruteDeviceStateIDLE, - SubBruteDeviceStateReady, - SubBruteDeviceStateTx, - SubBruteDeviceStateFinished -} SubBruteDeviceState; - -typedef void (*SubBruteDeviceWorkerCallback)(void* context, SubBruteDeviceState state); typedef struct { - SubBruteDeviceState state; const SubBruteProtocol* protocol_info; SubBruteProtocol* file_protocol_info; - volatile bool worker_running; // Current step uint64_t key_index; @@ -51,28 +41,17 @@ typedef struct { uint8_t load_index; // SubGhz - FuriThread* thread; SubGhzReceiver* receiver; SubGhzProtocolDecoderBase* decoder_result; SubGhzEnvironment* environment; - SubGhzTransmitter* transmitter; // Attack state SubBruteAttacks attack; - char file_template[SUBBRUTE_TEXT_STORE_SIZE]; - uint64_t max_value; // Loaded info for attack type char current_key[SUBBRUTE_PAYLOAD_SIZE]; char file_key[SUBBRUTE_MAX_LEN_NAME]; - - // Manual transmit - uint32_t last_time_tx_data; - - // Callback for changed states - SubBruteDeviceWorkerCallback callback; - void* context; } SubBruteDevice; SubBruteDevice* subbrute_device_alloc(); @@ -83,33 +62,9 @@ const char* subbrute_device_error_get_desc(SubBruteFileResult error_id); SubBruteFileResult subbrute_device_attack_set(SubBruteDevice* context, SubBruteAttacks type); uint8_t subbrute_device_load_from_file(SubBruteDevice* context, const char* file_path); -bool subbrute_device_is_worker_running(SubBruteDevice* instance); -SubBruteAttacks subbrute_device_get_attack(SubBruteDevice* instance); -uint64_t subbrute_device_get_max_value(SubBruteDevice* instance); -uint64_t subbrute_device_get_step(SubBruteDevice* instance); uint64_t subbrute_device_add_step(SubBruteDevice* instance, int8_t step); -void subbrute_device_set_load_index(SubBruteDevice* instance, uint64_t load_index); -void subbrute_device_reset_step(SubBruteDevice* instance); -const char* subbrute_device_get_file_key(SubBruteDevice* instance); - -bool subbrute_worker_start(SubBruteDevice* instance); -void subbrute_worker_stop(SubBruteDevice* instance); -bool subbrute_device_transmit_current_key(SubBruteDevice* instance); -bool subbrute_device_can_manual_transmit(SubBruteDevice* instance); -void subbrute_device_set_callback( - SubBruteDevice* instance, - SubBruteDeviceWorkerCallback callback, - void* context); void subbrute_device_free_protocol_info(SubBruteDevice* instance); -int32_t subbrute_worker_thread(void* context); void subbrute_device_attack_set_default_values( SubBruteDevice* context, - SubBruteAttacks default_attack); -bool subbrute_device_create_packet_parsed( - SubBruteDevice* instance, - FlipperFormat* flipper_format, - uint64_t step, - bool small); -void subbrute_device_send_callback(SubBruteDevice* instance); -void subbrute_device_subghz_transmit(SubBruteDevice* instance, FlipperFormat* flipper_format); + SubBruteAttacks default_attack); \ No newline at end of file diff --git a/applications/plugins/subbrute/subbrute_i.h b/applications/plugins/subbrute/subbrute_i.h index 856a0b83d..edd87eb0f 100644 --- a/applications/plugins/subbrute/subbrute_i.h +++ b/applications/plugins/subbrute/subbrute_i.h @@ -23,6 +23,7 @@ #include "subbrute.h" #include "subbrute_device.h" +#include "helpers/subbrute_worker.h" #include "views/subbrute_attack_view.h" #include "views/subbrute_main_view.h" @@ -62,9 +63,10 @@ struct SubBruteState { // SubBruteDevice SubBruteDevice* device; + // SubBruteWorker + SubBruteWorker* worker; }; void subbrute_show_loading_popup(void* context, bool show); void subbrute_text_input_callback(void* context); -void subbrute_popup_closed_callback(void* context); -uint64_t subbrute_get_step(void* context); \ No newline at end of file +void subbrute_popup_closed_callback(void* context); \ No newline at end of file diff --git a/applications/plugins/subbrute/subbrute_protocols.c b/applications/plugins/subbrute/subbrute_protocols.c index 462732937..81e00d02f 100644 --- a/applications/plugins/subbrute/subbrute_protocols.c +++ b/applications/plugins/subbrute/subbrute_protocols.c @@ -1,5 +1,7 @@ #include "subbrute_protocols.h" +#define TAG "SubBruteProtocols" + /** * CAME 12bit 303MHz */ @@ -201,6 +203,16 @@ static const char* subbrute_protocol_file_types[] = { [PrincetonFileProtocol] = "Princeton", [RAWFileProtocol] = "RAW"}; +/** + * Values to not use less memory for packet parse operations + */ +static const char* subbrute_key_file_start_no_tail = + "Filetype: Flipper SubGhz Key File\nVersion: 1\nFrequency: %u\nPreset: %s\nProtocol: %s\nBit: %d\nKey: %s\nRepeat: %d\n"; +static const char* subbrute_key_file_start_with_tail = + "Filetype: Flipper SubGhz Key File\nVersion: 1\nFrequency: %u\nPreset: %s\nProtocol: %s\nBit: %d\nKey: %s\nTE: %d\nRepeat: %d\n"; +static const char* subbrute_key_small_no_tail = "Bit: %d\nKey: %s\nRepeat: %d\nRepeat: %d\n"; +static const char* subbrute_key_small_with_tail = "Bit: %d\nKey: %s\nTE: %d\nRepeat: %d\n"; + const char* subbrute_protocol_name(SubBruteAttacks index) { return subbrute_protocol_names[index]; } @@ -235,4 +247,210 @@ SubBruteFileProtocol subbrute_protocol_file_protocol_name(FuriString* name) { } return RAWFileProtocol; +} + +FuriString* + subbrute_protocol_default_payload(uint64_t step, uint8_t bits, uint8_t te, uint8_t repeat) { + FuriString* candidate = furi_string_alloc_set_str(" "); + + FuriString* buffer = furi_string_alloc_printf("%16llX", step); + int j = 0; + for(uint8_t i = 0; i < 16; i++) { + if(furi_string_get_char(buffer, i) != ' ') { + furi_string_set_char(candidate, i + j, furi_string_get_char(buffer, i)); + } else { + furi_string_set_char(candidate, i + j, '0'); + } + if(i % 2 != 0) { + j++; + } + } + furi_string_free(buffer); + +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "candidate: %s, step: %lld", furi_string_get_cstr(candidate), step); +#endif + FuriString* result; + + if(te) { + result = furi_string_alloc_printf( + subbrute_key_small_with_tail, bits, furi_string_get_cstr(candidate), te, repeat); + } else { + result = furi_string_alloc_printf( + subbrute_key_small_no_tail, bits, furi_string_get_cstr(candidate), repeat); + } +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "result: %s", furi_string_get_cstr(result)); +#endif + + furi_string_free(candidate); + + return result; +} + +FuriString* subbrute_protocol_file_payload( + uint64_t step, + uint8_t bits, + uint8_t te, + uint8_t repeat, + uint8_t load_index, + const char* file_key) { + FuriString* candidate = furi_string_alloc(); + if(step >= sizeof(file_key)) { + return false; + } + char subbrute_payload_byte[4]; + furi_string_set_str(candidate, file_key); + snprintf(subbrute_payload_byte, 4, "%02X ", (uint8_t)step); + furi_string_replace_at(candidate, load_index * 3, 3, subbrute_payload_byte); + +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "candidate: %s, step: %lld", furi_string_get_cstr(candidate), step); +#endif + FuriString* result; + + if(te) { + result = furi_string_alloc_printf( + subbrute_key_small_with_tail, bits, furi_string_get_cstr(candidate), te, repeat); + } else { + result = furi_string_alloc_printf( + subbrute_key_small_no_tail, bits, furi_string_get_cstr(candidate), repeat); + } + +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "result: %s", furi_string_get_cstr(result)); +#endif + + furi_string_free(candidate); + + return result; +} + +FuriString* subbrute_protocol_default_generate_file( + uint32_t frequency, + FuriHalSubGhzPreset preset, + SubBruteFileProtocol file, + uint64_t step, + uint8_t bits, + uint8_t te, + uint8_t repeat) { + FuriString* candidate = furi_string_alloc_set_str(" "); + + FuriString* buffer = furi_string_alloc_printf("%16llX", step); + int j = 0; + for(uint8_t i = 0; i < 16; i++) { + if(furi_string_get_char(buffer, i) != ' ') { + furi_string_set_char(candidate, i + j, furi_string_get_char(buffer, i)); + } else { + furi_string_set_char(candidate, i + j, '0'); + } + if(i % 2 != 0) { + j++; + } + } + furi_string_free(buffer); + +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "candidate: %s, step: %lld", furi_string_get_cstr(candidate), step); +#endif + FuriString* result; + + if(te) { + result = furi_string_alloc_printf( + subbrute_key_file_start_with_tail, + frequency, + preset, + file, + bits, + furi_string_get_cstr(candidate), + te, + repeat); + } else { + result = furi_string_alloc_printf( + subbrute_key_file_start_no_tail, + frequency, + preset, + file, + bits, + furi_string_get_cstr(candidate), + repeat); + } +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "result: %s", furi_string_get_cstr(result)); +#endif + + furi_string_free(candidate); + + return result; +} + +FuriString* subbrute_protocol_file_generate_file( + uint32_t frequency, + FuriHalSubGhzPreset preset, + SubBruteFileProtocol file, + uint64_t step, + uint8_t bits, + uint8_t te, + uint8_t repeat, + uint8_t load_index, + const char* file_key) { + FuriString* candidate = furi_string_alloc(); + if(step >= sizeof(file_key)) { + return false; + } + char subbrute_payload_byte[4]; + furi_string_set_str(candidate, file_key); + snprintf(subbrute_payload_byte, 4, "%02X ", (uint8_t)step); + furi_string_replace_at(candidate, load_index * 3, 3, subbrute_payload_byte); + +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "candidate: %s, step: %lld", furi_string_get_cstr(candidate), step); +#endif + FuriString* result; + + if(te) { + result = furi_string_alloc_printf( + subbrute_key_file_start_with_tail, + frequency, + preset, + file, + bits, + furi_string_get_cstr(candidate), + te, + repeat); + } else { + result = furi_string_alloc_printf( + subbrute_key_file_start_no_tail, + frequency, + preset, + file, + bits, + furi_string_get_cstr(candidate), + repeat); + } + +#ifdef FURI_DEBUG + FURI_LOG_D(TAG, "result: %s", furi_string_get_cstr(result)); +#endif + + furi_string_free(candidate); + + return result; +} + +uint64_t subbrute_protocol_calc_max_value(SubBruteAttacks attack_type, uint8_t bits) { + uint64_t max_value; + if(attack_type == SubBruteAttackLoadFile) { + max_value = 0x3F; + } else { + FuriString* max_value_s; + max_value_s = furi_string_alloc(); + for(uint8_t i = 0; i < bits; i++) { + furi_string_cat_printf(max_value_s, "1"); + } + max_value = (uint64_t)strtol(furi_string_get_cstr(max_value_s), NULL, 2); + furi_string_free(max_value_s); + } + + return max_value; } \ No newline at end of file diff --git a/applications/plugins/subbrute/subbrute_protocols.h b/applications/plugins/subbrute/subbrute_protocols.h index f876ed756..747328d5b 100644 --- a/applications/plugins/subbrute/subbrute_protocols.h +++ b/applications/plugins/subbrute/subbrute_protocols.h @@ -54,4 +54,33 @@ const char* subbrute_protocol_preset(FuriHalSubGhzPreset preset); const char* subbrute_protocol_file(SubBruteFileProtocol protocol); FuriHalSubGhzPreset subbrute_protocol_convert_preset(FuriString* preset_name); SubBruteFileProtocol subbrute_protocol_file_protocol_name(FuriString* name); -const char* subbrute_protocol_name(SubBruteAttacks index); \ No newline at end of file +const char* subbrute_protocol_name(SubBruteAttacks index); + +FuriString* + subbrute_protocol_default_payload(uint64_t step, uint8_t bits, uint8_t te, uint8_t repeat); +FuriString* subbrute_protocol_file_payload( + uint64_t step, + uint8_t bits, + uint8_t te, + uint8_t repeat, + uint8_t load_index, + const char* file_key); +FuriString* subbrute_protocol_default_generate_file( + uint32_t frequency, + FuriHalSubGhzPreset preset, + SubBruteFileProtocol file, + uint64_t step, + uint8_t bits, + uint8_t te, + uint8_t repeat); +FuriString* subbrute_protocol_file_generate_file( + uint32_t frequency, + FuriHalSubGhzPreset preset, + SubBruteFileProtocol file, + uint64_t step, + uint8_t bits, + uint8_t te, + uint8_t repeat, + uint8_t load_index, + const char* file_key); +uint64_t subbrute_protocol_calc_max_value(SubBruteAttacks attack_type, uint8_t bits); \ No newline at end of file diff --git a/applications/plugins/subbrute/views/subbrute_main_view.c b/applications/plugins/subbrute/views/subbrute_main_view.c index 2010e9ae2..bfac24b8b 100644 --- a/applications/plugins/subbrute/views/subbrute_main_view.c +++ b/applications/plugins/subbrute/views/subbrute_main_view.c @@ -227,10 +227,7 @@ bool subbrute_main_view_input(InputEvent* event, void* context) { #ifdef FURI_DEBUG with_view_model( - instance->view, (SubBruteMainViewModel * model) { - index = model->index; - return false; - }); + instance->view, SubBruteMainViewModel * model, { index = model->index; }, false); FURI_LOG_I(TAG, "Index: %d", index); #endif @@ -265,10 +262,7 @@ bool subbrute_main_view_input(InputEvent* event, void* context) { #ifdef FURI_DEBUG with_view_model( - instance->view, (SubBruteMainViewModel * model) { - index = model->index; - return false; - }); + instance->view, SubBruteMainViewModel * model, { index = model->index; }, false); FURI_LOG_I(TAG, "Index: %d", index); #endif