Returned to Worker model

This commit is contained in:
DerSkythe
2022-10-10 00:35:44 +04:00
parent b4a3ac468f
commit 500456b03d
15 changed files with 818 additions and 537 deletions

View File

@@ -0,0 +1,362 @@
#include "subbrute_worker_private.h"
#include <string.h>
#include <toolbox/stream/stream.h>
#include <flipper_format.h>
#include <flipper_format_i.h>
#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;
}

View File

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

View File

@@ -0,0 +1,45 @@
#pragma once
#include "subbrute_worker.h"
#include <lib/subghz/protocols/base.h>
#include <lib/subghz/transmitter.h>
#include <lib/subghz/receiver.h>
#include <lib/subghz/environment.h>
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);

View File

@@ -39,6 +39,14 @@ void subbrute_scene_load_file_on_enter(void* context) {
if(load_result == SubBruteFileResultOk) { if(load_result == SubBruteFileResultOk) {
load_result = subbrute_device_attack_set(instance->device, SubBruteAttackLoadFile); load_result = subbrute_device_attack_set(instance->device, SubBruteAttackLoadFile);
if(load_result == SubBruteFileResultOk) { 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! // Ready to run!
FURI_LOG_I(TAG, "Ready to run"); FURI_LOG_I(TAG, "Ready to run");
res = true; res = true;
@@ -52,7 +60,8 @@ void subbrute_scene_load_file_on_enter(void* context) {
FuriString* dialog_msg; FuriString* dialog_msg;
dialog_msg = furi_string_alloc(); 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)); dialog_message_show_storage_error(instance->dialogs, furi_string_get_cstr(dialog_msg));
furi_string_free(dialog_msg); furi_string_free(dialog_msg);
scene_manager_search_and_switch_to_previous_scene( scene_manager_search_and_switch_to_previous_scene(

View File

@@ -20,7 +20,7 @@ void subbrute_scene_load_select_on_enter(void* context) {
instance->current_view = SubBruteViewMain; instance->current_view = SubBruteViewMain;
subbrute_main_view_set_callback(view, subbrute_scene_load_select_callback, instance); 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); 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.type == SceneManagerEventTypeCustom) {
if(event.event == SubBruteCustomEventTypeIndexSelected) { if(event.event == SubBruteCustomEventTypeIndexSelected) {
subbrute_device_set_load_index( instance->device->load_index = subbrute_main_view_get_index(instance->view_main);
instance->device, 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); scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack);
consumed = true; consumed = true;
} }

View File

@@ -11,15 +11,15 @@ static void subbrute_scene_run_attack_callback(SubBruteCustomEvent event, void*
} }
static 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); furi_assert(context);
SubBruteState* instance = (SubBruteState*)context; SubBruteState* instance = (SubBruteState*)context;
if(state == SubBruteDeviceStateIDLE) { if(state == SubBruteWorkerStateIDLE) {
// Can't be IDLE on this step! // Can't be IDLE on this step!
view_dispatcher_send_custom_event(instance->view_dispatcher, SubBruteCustomEventTypeError); view_dispatcher_send_custom_event(instance->view_dispatcher, SubBruteCustomEventTypeError);
} else if(state == SubBruteDeviceStateFinished) { } else if(state == SubBruteWorkerStateFinished) {
view_dispatcher_send_custom_event( view_dispatcher_send_custom_event(
instance->view_dispatcher, SubBruteCustomEventTypeTransmitFinished); instance->view_dispatcher, SubBruteCustomEventTypeTransmitFinished);
} }
@@ -28,7 +28,7 @@ void subbrute_scene_run_attack_on_exit(void* context) {
furi_assert(context); furi_assert(context);
SubBruteState* instance = (SubBruteState*)context; SubBruteState* instance = (SubBruteState*)context;
subbrute_worker_stop(instance->device); subbrute_worker_stop(instance->worker);
notification_message(instance->notifications, &sequence_blink_stop); 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); subbrute_attack_view_set_callback(view, subbrute_scene_run_attack_callback, instance);
view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view); view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view);
subbrute_device_set_callback( subbrute_worker_set_callback(
instance->device, subbrute_scene_run_attack_device_state_changed, instance); instance->worker, subbrute_scene_run_attack_device_state_changed, instance);
if(!subbrute_device_is_worker_running(instance->device)) { if(!subbrute_worker_is_running(instance->worker)) {
subbrute_worker_start(instance->device); subbrute_worker_start(instance->worker);
} }
} }
@@ -57,7 +57,7 @@ bool subbrute_scene_run_attack_on_event(void* context, SceneManagerEvent event)
bool consumed = false; bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { 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) { if(event.event == SubBruteCustomEventTypeTransmitFinished) {
notification_message(instance->notifications, &sequence_display_backlight_on); 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; consumed = true;
} else if(event.type == SceneManagerEventTypeTick) { } 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; consumed = true;
} }

View File

@@ -11,12 +11,12 @@ static void subbrute_scene_setup_attack_callback(SubBruteCustomEvent event, void
} }
static 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); furi_assert(context);
SubBruteState* instance = (SubBruteState*)context; SubBruteState* instance = (SubBruteState*)context;
if(state == SubBruteDeviceStateIDLE) { if(state == SubBruteWorkerStateIDLE) {
// Can't be IDLE on this step! // Can't be IDLE on this step!
view_dispatcher_send_custom_event(instance->view_dispatcher, SubBruteCustomEventTypeError); 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; SubBruteAttackView* view = instance->view_attack;
#ifdef FURI_DEBUG #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 #endif
subbrute_device_set_callback( subbrute_worker_set_callback(
instance->device, subbrute_scene_setup_attack_device_state_changed, context); instance->worker, subbrute_scene_setup_attack_device_state_changed, context);
if(subbrute_device_is_worker_running(instance->device)) { if(subbrute_worker_is_running(instance->worker)) {
subbrute_worker_stop(instance->device); 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; instance->current_view = SubBruteViewAttack;
subbrute_attack_view_set_callback(view, subbrute_scene_setup_attack_callback, instance); subbrute_attack_view_set_callback(view, subbrute_scene_setup_attack_callback, instance);
view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view); 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"); FURI_LOG_D(TAG, "subbrute_scene_setup_attack_on_exit");
#endif #endif
SubBruteState* instance = (SubBruteState*)context; SubBruteState* instance = (SubBruteState*)context;
subbrute_worker_stop(instance->device); subbrute_worker_stop(instance->worker);
notification_message(instance->notifications, &sequence_blink_stop); 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) { } else if(event.event == SubBruteCustomEventTypeSaveFile) {
subbrute_attack_view_init_values( subbrute_attack_view_init_values(
view, view,
subbrute_device_get_attack(instance->device), instance->device->attack,
subbrute_device_get_max_value(instance->device), instance->device->max_value,
subbrute_device_get_step(instance->device), instance->device->key_index,
false); false);
scene_manager_next_scene(instance->scene_manager, SubBruteSceneSaveName); scene_manager_next_scene(instance->scene_manager, SubBruteSceneSaveName);
} else if(event.event == SubBruteCustomEventTypeBackPressed) { } else if(event.event == SubBruteCustomEventTypeBackPressed) {
subbrute_device_reset_step(instance->device);
subbrute_attack_view_init_values( subbrute_attack_view_init_values(
view, view,
subbrute_device_get_attack(instance->device), instance->device->attack,
subbrute_device_get_max_value(instance->device), instance->device->max_value,
subbrute_device_get_step(instance->device), instance->device->key_index,
false); false);
scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart); scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart);
} else if(event.event == SubBruteCustomEventTypeError) { } else if(event.event == SubBruteCustomEventTypeError) {
notification_message(instance->notifications, &sequence_error); notification_message(instance->notifications, &sequence_error);
} else if(event.event == SubBruteCustomEventTypeTransmitCustom) { } else if(event.event == SubBruteCustomEventTypeTransmitCustom) {
// We can transmit only in not working states // 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! // MANUAL Transmit!
// Blink // Blink
notification_message(instance->notifications, &sequence_blink_green_100); 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 // Stop
notification_message(instance->notifications, &sequence_blink_stop); notification_message(instance->notifications, &sequence_blink_stop);
} }
} else if(event.event == SubBruteCustomEventTypeChangeStepUp) { } else if(event.event == SubBruteCustomEventTypeChangeStepUp) {
// +1 // +1
uint64_t step = subbrute_device_add_step(instance->device, 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); subbrute_attack_view_set_current_step(view, step);
} else if(event.event == SubBruteCustomEventTypeChangeStepUpMore) { } else if(event.event == SubBruteCustomEventTypeChangeStepUpMore) {
// +50 // +50
uint64_t step = subbrute_device_add_step(instance->device, 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); subbrute_attack_view_set_current_step(view, step);
} else if(event.event == SubBruteCustomEventTypeChangeStepDown) { } else if(event.event == SubBruteCustomEventTypeChangeStepDown) {
// -1 // -1
uint64_t step = subbrute_device_add_step(instance->device, -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); subbrute_attack_view_set_current_step(view, step);
} else if(event.event == SubBruteCustomEventTypeChangeStepDownMore) { } else if(event.event == SubBruteCustomEventTypeChangeStepDownMore) {
// -50 // -50
uint64_t step = subbrute_device_add_step(instance->device, -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); subbrute_attack_view_set_current_step(view, step);
} }
consumed = true; consumed = true;
} else if(event.type == SceneManagerEventTypeTick) { } 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; consumed = true;
} }

View File

@@ -23,7 +23,7 @@ void subbrute_scene_start_on_enter(void* context) {
instance->current_view = SubBruteViewMain; instance->current_view = SubBruteViewMain;
subbrute_main_view_set_callback(view, subbrute_scene_start_callback, instance); 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); 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) { if(event.event == SubBruteCustomEventTypeMenuSelected) {
SubBruteAttacks attack = subbrute_main_view_get_index(instance->view_main); 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); scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack);
consumed = true; consumed = true;

View File

@@ -51,6 +51,9 @@ SubBruteState* subbrute_alloc() {
// Devices // Devices
instance->device = subbrute_device_alloc(); instance->device = subbrute_device_alloc();
// SubBruteWorker
instance->worker = subbrute_worker_alloc();
// TextInput // TextInput
instance->text_input = text_input_alloc(); instance->text_input = text_input_alloc();
view_dispatcher_add_view( view_dispatcher_add_view(
@@ -96,8 +99,11 @@ SubBruteState* subbrute_alloc() {
void subbrute_free(SubBruteState* instance) { void subbrute_free(SubBruteState* instance) {
furi_assert(instance); furi_assert(instance);
// SubBruteWorker
subbrute_worker_stop(instance->worker);
subbrute_worker_free(instance->worker);
// SubBruteDevice // SubBruteDevice
subbrute_worker_stop(instance->device);
subbrute_device_free(instance->device); subbrute_device_free(instance->device);
// Notifications // Notifications
@@ -163,13 +169,6 @@ void subbrute_popup_closed_callback(void* context) {
instance->view_dispatcher, SubBruteCustomEventTypePopupClosed); 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 // ENTRYPOINT
int32_t subbrute_app(void* p) { int32_t subbrute_app(void* p) {
UNUSED(p); UNUSED(p);

View File

@@ -8,40 +8,14 @@
#define TAG "SubBruteDevice" #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* subbrute_device_alloc() {
SubBruteDevice* instance = malloc(sizeof(SubBruteDevice)); SubBruteDevice* instance = malloc(sizeof(SubBruteDevice));
instance->state = SubBruteDeviceStateIDLE;
instance->key_index = 0; 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->protocol_info = NULL;
instance->file_protocol_info = NULL; instance->file_protocol_info = NULL;
instance->decoder_result = NULL; instance->decoder_result = NULL;
instance->transmitter = NULL;
instance->receiver = NULL; instance->receiver = NULL;
instance->environment = subghz_environment_alloc(); instance->environment = subghz_environment_alloc();
@@ -61,137 +35,15 @@ void subbrute_device_free(SubBruteDevice* instance) {
instance->receiver = NULL; instance->receiver = NULL;
} }
if(instance->transmitter != NULL) {
subghz_transmitter_free(instance->transmitter);
instance->transmitter = NULL;
}
subghz_environment_free(instance->environment); subghz_environment_free(instance->environment);
instance->environment = NULL; instance->environment = NULL;
furi_thread_free(instance->thread);
subbrute_device_free_protocol_info(instance); subbrute_device_free_protocol_info(instance);
free(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) { 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(step > 0) {
if((instance->key_index + step) - instance->max_value == 1) { if((instance->key_index + step) - instance->max_value == 1) {
instance->key_index = 0x00; instance->key_index = 0x00;
@@ -220,122 +72,17 @@ uint64_t subbrute_device_add_step(SubBruteDevice* instance, int8_t step) {
return instance->key_index; 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) { bool subbrute_device_save_file(SubBruteDevice* instance, const char* dev_file_name) {
furi_assert(instance); 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 #ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_device_save_file: %s", dev_file_name); FURI_LOG_D(TAG, "subbrute_device_save_file: %s", dev_file_name);
#endif #endif
Storage* storage = furi_record_open(RECORD_STORAGE); Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* file = flipper_format_file_alloc(storage); FlipperFormat* file = flipper_format_file_alloc(storage);
FuriString* file_content = furi_string_alloc();
bool result = false; bool result = false;
do { do {
@@ -343,7 +90,32 @@ bool subbrute_device_save_file(SubBruteDevice* instance, const char* dev_file_na
break; 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!"); FURI_LOG_E(TAG, "create_packet_parsed failed!");
break; break;
} }
@@ -352,140 +124,17 @@ bool subbrute_device_save_file(SubBruteDevice* instance, const char* dev_file_na
} while(false); } while(false);
if(!result) { 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); flipper_format_free(file);
furi_record_close(RECORD_STORAGE); furi_record_close(RECORD_STORAGE);
furi_string_free(file_content);
return result; 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) { SubBruteFileResult subbrute_device_attack_set(SubBruteDevice* instance, SubBruteAttacks type) {
furi_assert(instance); furi_assert(instance);
#ifdef FURI_DEBUG #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"); FURI_LOG_E(TAG, "Can't load SubGhzProtocolDecoderBase in phase non-file decoder set");
} else { } else {
protocol_check_result = SubBruteFileResultOk; protocol_check_result = SubBruteFileResultOk;
// Calc max value
instance->max_value =
subbrute_protocol_calc_max_value(instance->attack, instance->protocol_info->bits);
} }
} else { } else {
// And here we need to set preset enum // And here we need to set preset enum
protocol_check_result = SubBruteFileResultOk; 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); subghz_receiver_free(instance->receiver);
@@ -526,56 +183,6 @@ SubBruteFileResult subbrute_device_attack_set(SubBruteDevice* instance, SubBrute
return SubBruteFileResultProtocolNotFound; 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; return SubBruteFileResultOk;
} }
@@ -751,7 +358,6 @@ void subbrute_device_attack_set_default_values(
instance->attack = default_attack; instance->attack = default_attack;
instance->key_index = 0x00; instance->key_index = 0x00;
instance->load_index = 0x00; instance->load_index = 0x00;
memset(instance->file_template, 0, sizeof(instance->file_template));
memset(instance->current_key, 0, sizeof(instance->current_key)); memset(instance->current_key, 0, sizeof(instance->current_key));
if(default_attack != SubBruteAttackLoadFile) { 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* subbrute_device_error_get_desc(SubBruteFileResult error_id) {
const char* result; const char* result;
switch(error_id) { switch(error_id) {

View File

@@ -31,19 +31,9 @@ typedef enum {
SubBruteFileResultMissingOrIncorrectTe, SubBruteFileResultMissingOrIncorrectTe,
} SubBruteFileResult; } SubBruteFileResult;
typedef enum {
SubBruteDeviceStateIDLE,
SubBruteDeviceStateReady,
SubBruteDeviceStateTx,
SubBruteDeviceStateFinished
} SubBruteDeviceState;
typedef void (*SubBruteDeviceWorkerCallback)(void* context, SubBruteDeviceState state);
typedef struct { typedef struct {
SubBruteDeviceState state;
const SubBruteProtocol* protocol_info; const SubBruteProtocol* protocol_info;
SubBruteProtocol* file_protocol_info; SubBruteProtocol* file_protocol_info;
volatile bool worker_running;
// Current step // Current step
uint64_t key_index; uint64_t key_index;
@@ -51,28 +41,17 @@ typedef struct {
uint8_t load_index; uint8_t load_index;
// SubGhz // SubGhz
FuriThread* thread;
SubGhzReceiver* receiver; SubGhzReceiver* receiver;
SubGhzProtocolDecoderBase* decoder_result; SubGhzProtocolDecoderBase* decoder_result;
SubGhzEnvironment* environment; SubGhzEnvironment* environment;
SubGhzTransmitter* transmitter;
// Attack state // Attack state
SubBruteAttacks attack; SubBruteAttacks attack;
char file_template[SUBBRUTE_TEXT_STORE_SIZE];
uint64_t max_value; uint64_t max_value;
// Loaded info for attack type // Loaded info for attack type
char current_key[SUBBRUTE_PAYLOAD_SIZE]; char current_key[SUBBRUTE_PAYLOAD_SIZE];
char file_key[SUBBRUTE_MAX_LEN_NAME]; 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;
SubBruteDevice* subbrute_device_alloc(); 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); SubBruteFileResult subbrute_device_attack_set(SubBruteDevice* context, SubBruteAttacks type);
uint8_t subbrute_device_load_from_file(SubBruteDevice* context, const char* file_path); 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); 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); void subbrute_device_free_protocol_info(SubBruteDevice* instance);
int32_t subbrute_worker_thread(void* context);
void subbrute_device_attack_set_default_values( void subbrute_device_attack_set_default_values(
SubBruteDevice* context, SubBruteDevice* context,
SubBruteAttacks default_attack); 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);

View File

@@ -23,6 +23,7 @@
#include "subbrute.h" #include "subbrute.h"
#include "subbrute_device.h" #include "subbrute_device.h"
#include "helpers/subbrute_worker.h"
#include "views/subbrute_attack_view.h" #include "views/subbrute_attack_view.h"
#include "views/subbrute_main_view.h" #include "views/subbrute_main_view.h"
@@ -62,9 +63,10 @@ struct SubBruteState {
// SubBruteDevice // SubBruteDevice
SubBruteDevice* device; SubBruteDevice* device;
// SubBruteWorker
SubBruteWorker* worker;
}; };
void subbrute_show_loading_popup(void* context, bool show); void subbrute_show_loading_popup(void* context, bool show);
void subbrute_text_input_callback(void* context); void subbrute_text_input_callback(void* context);
void subbrute_popup_closed_callback(void* context); void subbrute_popup_closed_callback(void* context);
uint64_t subbrute_get_step(void* context);

View File

@@ -1,5 +1,7 @@
#include "subbrute_protocols.h" #include "subbrute_protocols.h"
#define TAG "SubBruteProtocols"
/** /**
* CAME 12bit 303MHz * CAME 12bit 303MHz
*/ */
@@ -201,6 +203,16 @@ static const char* subbrute_protocol_file_types[] = {
[PrincetonFileProtocol] = "Princeton", [PrincetonFileProtocol] = "Princeton",
[RAWFileProtocol] = "RAW"}; [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) { const char* subbrute_protocol_name(SubBruteAttacks index) {
return subbrute_protocol_names[index]; return subbrute_protocol_names[index];
} }
@@ -235,4 +247,210 @@ SubBruteFileProtocol subbrute_protocol_file_protocol_name(FuriString* name) {
} }
return RAWFileProtocol; 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;
} }

View File

@@ -54,4 +54,33 @@ const char* subbrute_protocol_preset(FuriHalSubGhzPreset preset);
const char* subbrute_protocol_file(SubBruteFileProtocol protocol); const char* subbrute_protocol_file(SubBruteFileProtocol protocol);
FuriHalSubGhzPreset subbrute_protocol_convert_preset(FuriString* preset_name); FuriHalSubGhzPreset subbrute_protocol_convert_preset(FuriString* preset_name);
SubBruteFileProtocol subbrute_protocol_file_protocol_name(FuriString* name); SubBruteFileProtocol subbrute_protocol_file_protocol_name(FuriString* name);
const char* subbrute_protocol_name(SubBruteAttacks index); 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);

View File

@@ -227,10 +227,7 @@ bool subbrute_main_view_input(InputEvent* event, void* context) {
#ifdef FURI_DEBUG #ifdef FURI_DEBUG
with_view_model( with_view_model(
instance->view, (SubBruteMainViewModel * model) { instance->view, SubBruteMainViewModel * model, { index = model->index; }, false);
index = model->index;
return false;
});
FURI_LOG_I(TAG, "Index: %d", index); FURI_LOG_I(TAG, "Index: %d", index);
#endif #endif
@@ -265,10 +262,7 @@ bool subbrute_main_view_input(InputEvent* event, void* context) {
#ifdef FURI_DEBUG #ifdef FURI_DEBUG
with_view_model( with_view_model(
instance->view, (SubBruteMainViewModel * model) { instance->view, SubBruteMainViewModel * model, { index = model->index; }, false);
index = model->index;
return false;
});
FURI_LOG_I(TAG, "Index: %d", index); FURI_LOG_I(TAG, "Index: %d", index);
#endif #endif