Rename plugins to external

This commit is contained in:
Willy-JL
2023-03-17 22:50:23 +00:00
parent b3c64d0428
commit b34a4f2468
1706 changed files with 15 additions and 15 deletions

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Der Skythe
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,13 @@
App(
appid="SubGHz_Bruteforcer",
name="Sub-GHz Bruteforcer",
apptype=FlipperAppType.EXTERNAL,
entry_point="subbrute_app",
cdefines=["APP_SUB_BRUTE"],
requires=["gui", "dialogs"],
stack_size=2 * 1024,
order=11,
fap_icon="images/subbrute_10px.png",
fap_category="Sub-GHz",
fap_icon_assets="images",
)

View File

@@ -0,0 +1,59 @@
#include "gui_top_buttons.h"
void elements_button_top_left(Canvas* canvas, const char* str) {
const Icon* icon = &I_ButtonUp_7x4;
const uint8_t button_height = 12;
const uint8_t vertical_offset = 3;
const uint8_t horizontal_offset = 3;
const uint8_t string_width = canvas_string_width(canvas, str);
const uint8_t icon_h_offset = 3;
const uint8_t icon_width_with_offset = icon_get_width(icon) + icon_h_offset;
const uint8_t icon_v_offset = icon_get_height(icon) + vertical_offset;
const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset;
const uint8_t x = 0;
const uint8_t y = 0 + button_height;
uint8_t line_x = x + button_width;
uint8_t line_y = y - button_height;
canvas_draw_box(canvas, x, line_y, button_width, button_height);
canvas_draw_line(canvas, line_x + 0, line_y, line_x + 0, y - 1);
canvas_draw_line(canvas, line_x + 1, line_y, line_x + 1, y - 2);
canvas_draw_line(canvas, line_x + 2, line_y, line_x + 2, y - 3);
canvas_invert_color(canvas);
canvas_draw_icon(canvas, x + horizontal_offset, y - icon_v_offset, icon);
canvas_draw_str(
canvas, x + horizontal_offset + icon_width_with_offset, y - vertical_offset, str);
canvas_invert_color(canvas);
}
void elements_button_top_right(Canvas* canvas, const char* str) {
const Icon* icon = &I_ButtonDown_7x4;
const uint8_t button_height = 12;
const uint8_t vertical_offset = 3;
const uint8_t horizontal_offset = 3;
const uint8_t string_width = canvas_string_width(canvas, str);
const uint8_t icon_h_offset = 3;
const uint8_t icon_width_with_offset = icon_get_width(icon) + icon_h_offset;
const uint8_t icon_v_offset = icon_get_height(icon) + vertical_offset + 1;
const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset;
const uint8_t x = canvas_width(canvas);
const uint8_t y = 0 + button_height;
uint8_t line_x = x - button_width;
uint8_t line_y = y - button_height;
canvas_draw_box(canvas, line_x, line_y, button_width, button_height);
canvas_draw_line(canvas, line_x - 1, line_y, line_x - 1, y - 1);
canvas_draw_line(canvas, line_x - 2, line_y, line_x - 2, y - 2);
canvas_draw_line(canvas, line_x - 3, line_y, line_x - 3, y - 3);
canvas_invert_color(canvas);
canvas_draw_str(canvas, x - button_width + horizontal_offset, y - vertical_offset, str);
canvas_draw_icon(
canvas, x - horizontal_offset - icon_get_width(icon), y - icon_v_offset, icon);
canvas_invert_color(canvas);
}

View File

@@ -0,0 +1,21 @@
#pragma once
#include <input/input.h>
#include <gui/elements.h>
#include <gui/icon.h>
#include <gui/icon_animation.h>
#include <assets_icons.h>
/**
* Thanks to the author of metronome
* @param canvas
* @param str
*/
void elements_button_top_left(Canvas* canvas, const char* str);
/**
* Thanks to the author of metronome
* @param canvas
* @param str
*/
void elements_button_top_right(Canvas* canvas, const char* str);

View File

@@ -0,0 +1,437 @@
#include "subbrute_worker_private.h"
#include <string.h>
#include <toolbox/stream/stream.h>
#include <flipper_format.h>
#include <flipper_format_i.h>
#include <lib/subghz/protocols/protocol_items.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->step = 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();
subghz_environment_set_protocol_registry(
instance->environment, (void*)&subghz_protocol_registry);
instance->transmit_mode = false;
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->step;
}
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->step = step;
return true;
}
bool subbrute_worker_init_default_attack(
SubBruteWorker* instance,
SubBruteAttacks attack_type,
uint64_t step,
const SubBruteProtocol* protocol,
uint8_t extra_repeats) {
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->step = step;
instance->bits = protocol->bits;
instance->te = protocol->te;
instance->repeat = protocol->repeat + extra_repeats;
instance->load_index = 0;
instance->file_key = 0;
instance->two_bytes = false;
instance->max_value =
subbrute_protocol_calc_max_value(instance->attack, instance->bits, instance->two_bytes);
instance->initiated = true;
instance->state = SubBruteWorkerStateReady;
subbrute_worker_send_callback(instance);
#ifdef FURI_DEBUG
FURI_LOG_I(
TAG,
"subbrute_worker_init_default_attack: %s, bits: %d, preset: %s, file: %s, te: %ld, repeat: %d, max_value: %lld",
subbrute_protocol_name(instance->attack),
instance->bits,
subbrute_protocol_preset(instance->preset),
subbrute_protocol_file(instance->file),
instance->te,
instance->repeat,
instance->max_value);
#endif
return true;
}
bool subbrute_worker_init_file_attack(
SubBruteWorker* instance,
uint64_t step,
uint8_t load_index,
uint64_t file_key,
SubBruteProtocol* protocol,
uint8_t extra_repeats,
bool two_bytes) {
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->step = step;
instance->bits = protocol->bits;
instance->te = protocol->te;
instance->load_index = load_index;
instance->repeat = protocol->repeat + extra_repeats;
instance->file_key = file_key;
instance->two_bytes = two_bytes;
instance->max_value =
subbrute_protocol_calc_max_value(instance->attack, instance->bits, instance->two_bytes);
instance->initiated = true;
instance->state = SubBruteWorkerStateReady;
subbrute_worker_send_callback(instance);
#ifdef FURI_DEBUG
FURI_LOG_I(
TAG,
"subbrute_worker_init_file_attack: %s, bits: %d, preset: %s, file: %s, te: %ld, repeat: %d, max_value: %lld, key: %llX",
subbrute_protocol_name(instance->attack),
instance->bits,
subbrute_protocol_preset(instance->preset),
subbrute_protocol_file(instance->file),
instance->te,
instance->repeat,
instance->max_value,
instance->file_key);
#endif
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);
if(!instance->worker_running) {
return;
}
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->step = step;
bool result;
instance->protocol_name = subbrute_protocol_file(instance->file);
FlipperFormat* flipper_format = flipper_format_string_alloc();
Stream* stream = flipper_format_get_raw_stream(flipper_format);
stream_clean(stream);
if(instance->attack == SubBruteAttackLoadFile) {
subbrute_protocol_file_payload(
stream,
step,
instance->bits,
instance->te,
instance->repeat,
instance->load_index,
instance->file_key,
instance->two_bytes);
} else {
subbrute_protocol_default_payload(
stream, instance->file, 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) {
while(instance->transmit_mode) {
furi_delay_ms(SUBBRUTE_TX_TIMEOUT);
}
instance->transmit_mode = true;
if(instance->transmitter != NULL) {
subghz_transmitter_free(instance->transmitter);
instance->transmitter = NULL;
}
instance->transmitter =
subghz_transmitter_alloc_init(instance->environment, instance->protocol_name);
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;
instance->transmit_mode = false;
}
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);
instance->protocol_name = subbrute_protocol_file(instance->file);
FlipperFormat* flipper_format = flipper_format_string_alloc();
Stream* stream = flipper_format_get_raw_stream(flipper_format);
while(instance->worker_running) {
stream_clean(stream);
if(instance->attack == SubBruteAttackLoadFile) {
subbrute_protocol_file_payload(
stream,
instance->step,
instance->bits,
instance->te,
instance->repeat,
instance->load_index,
instance->file_key,
instance->two_bytes);
} else {
subbrute_protocol_default_payload(
stream,
instance->file,
instance->step,
instance->bits,
instance->te,
instance->repeat);
}
#ifdef FURI_DEBUG
//FURI_LOG_I(TAG, "Payload: %s", furi_string_get_cstr(payload));
//furi_delay_ms(SUBBRUTE_MANUAL_TRANSMIT_INTERVAL / 4);
#endif
// size_t written = stream_write_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->step + 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->step++;
// 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,42 @@
#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,
uint8_t extra_repeats);
bool subbrute_worker_init_file_attack(
SubBruteWorker* instance,
uint64_t step,
uint8_t load_index,
uint64_t file_key,
SubBruteProtocol* protocol,
uint8_t extra_repeats,
bool two_bytes);
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,48 @@
#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;
volatile bool transmit_mode;
// Current step
uint64_t step;
// SubGhz
FuriThread* thread;
SubGhzProtocolDecoderBase* decoder_result;
SubGhzEnvironment* environment;
SubGhzTransmitter* transmitter;
const char* protocol_name;
// Initiated values
SubBruteAttacks attack; // Attack state
uint32_t frequency;
FuriHalSubGhzPreset preset;
SubBruteFileProtocol file;
uint8_t bits;
uint32_t te;
uint8_t repeat;
uint8_t load_index; // Index of group to bruteforce in loaded file
uint64_t file_key;
uint64_t max_value; // Max step
bool two_bytes;
// 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);

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 B

View File

@@ -0,0 +1 @@
3

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,29 @@
#pragma once
#include <gui/scene_manager.h>
// Generate scene id and total number
#define ADD_SCENE(prefix, name, id) SubBruteScene##id,
typedef enum {
#include "subbrute_scene_config.h"
SubBruteSceneNum,
} SubBruteScene;
#undef ADD_SCENE
extern const SceneManagerHandlers subbrute_scene_handlers;
// Generate scene on_enter handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
#include "subbrute_scene_config.h"
#undef ADD_SCENE
// Generate scene on_event handlers declaration
#define ADD_SCENE(prefix, name, id) \
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
#include "subbrute_scene_config.h"
#undef ADD_SCENE
// Generate scene on_exit handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
#include "subbrute_scene_config.h"
#undef ADD_SCENE

View File

@@ -0,0 +1,7 @@
ADD_SCENE(subbrute, load_file, LoadFile)
ADD_SCENE(subbrute, load_select, LoadSelect)
ADD_SCENE(subbrute, run_attack, RunAttack)
ADD_SCENE(subbrute, save_name, SaveName)
ADD_SCENE(subbrute, save_success, SaveSuccess)
ADD_SCENE(subbrute, setup_attack, SetupAttack)
ADD_SCENE(subbrute, start, Start)

View File

@@ -0,0 +1,91 @@
#include "../subbrute_i.h"
#include "subbrute_scene.h"
#define TAG "SubBruteSceneLoadFile"
void subbrute_scene_load_file_on_enter(void* context) {
furi_assert(context);
SubBruteState* instance = (SubBruteState*)context;
// Input events and views are managed by file_browser
FuriString* app_folder;
FuriString* load_path;
load_path = furi_string_alloc();
app_folder = furi_string_alloc_set(SUBBRUTE_PATH);
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, SUBBRUTE_FILE_EXT, &I_sub1_10px);
SubBruteFileResult load_result = SubBruteFileResultUnknown;
// TODO: DELETE IT
#ifdef SUBBRUTE_FAST_TRACK
bool res = true;
furi_string_printf(load_path, "%s", "/ext/subghz/princeton.sub");
#else
bool res =
dialog_file_browser_show(instance->dialogs, load_path, app_folder, &browser_options);
#endif
#ifdef FURI_DEBUG
FURI_LOG_D(
TAG,
"load_path: %s, app_folder: %s",
furi_string_get_cstr(load_path),
furi_string_get_cstr(app_folder));
#endif
if(res) {
load_result =
subbrute_device_load_from_file(instance->device, furi_string_get_cstr(load_path));
if(load_result == SubBruteFileResultOk) {
uint8_t extra_repeats = subbrute_main_view_get_extra_repeats(instance->view_main);
load_result = subbrute_device_attack_set(
instance->device, SubBruteAttackLoadFile, extra_repeats);
if(load_result == SubBruteFileResultOk) {
if(!subbrute_worker_init_file_attack(
instance->worker,
instance->device->current_step,
instance->device->bit_index,
instance->device->key_from_file,
instance->device->file_protocol_info,
extra_repeats,
instance->device->two_bytes)) {
furi_crash("Invalid attack set!");
}
// Ready to run!
FURI_LOG_I(TAG, "Ready to run");
res = true;
}
}
if(load_result == SubBruteFileResultOk) {
scene_manager_next_scene(instance->scene_manager, SubBruteSceneLoadSelect);
} else {
FURI_LOG_E(TAG, "Returned error: %d", load_result);
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));
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(
instance->scene_manager, SubBruteSceneStart);
}
} else {
scene_manager_search_and_switch_to_previous_scene(
instance->scene_manager, SubBruteSceneStart);
}
furi_string_free(app_folder);
furi_string_free(load_path);
}
void subbrute_scene_load_file_on_exit(void* context) {
UNUSED(context);
}
bool subbrute_scene_load_file_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
return false;
}

View File

@@ -0,0 +1,82 @@
#include "../subbrute_i.h"
#include "subbrute_scene.h"
#define TAG "SubBruteSceneStart"
void subbrute_scene_load_select_callback(SubBruteCustomEvent event, void* context) {
furi_assert(context);
SubBruteState* instance = (SubBruteState*)context;
view_dispatcher_send_custom_event(instance->view_dispatcher, event);
}
void subbrute_scene_load_select_on_enter(void* context) {
furi_assert(context);
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "subbrute_scene_load_select_on_enter");
#endif
SubBruteState* instance = (SubBruteState*)context;
SubBruteMainView* view = instance->view_main;
instance->current_view = SubBruteViewMain;
subbrute_main_view_set_callback(view, subbrute_scene_load_select_callback, instance);
subbrute_main_view_set_index(
view, 7, true, instance->device->two_bytes, instance->device->key_from_file);
view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view);
}
void subbrute_scene_load_select_on_exit(void* context) {
UNUSED(context);
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "subbrute_scene_load_select_on_exit");
#endif
}
bool subbrute_scene_load_select_on_event(void* context, SceneManagerEvent event) {
SubBruteState* instance = (SubBruteState*)context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubBruteCustomEventTypeIndexSelected) {
/*#ifdef FURI_DEBUG && !SUBBRUTE_FAST_TRACK
view_dispatcher_stop(instance->view_dispatcher);
consumed = true;
#else*/
instance->device->current_step = 0;
instance->device->bit_index = subbrute_main_view_get_index(instance->view_main);
instance->device->two_bytes = subbrute_main_view_get_two_bytes(instance->view_main);
uint8_t extra_repeats = subbrute_main_view_get_extra_repeats(instance->view_main);
instance->device->max_value = subbrute_protocol_calc_max_value(
instance->device->attack,
instance->device->bit_index,
instance->device->two_bytes);
if(!subbrute_worker_init_file_attack(
instance->worker,
instance->device->current_step,
instance->device->bit_index,
instance->device->key_from_file,
instance->device->file_protocol_info,
extra_repeats,
instance->device->two_bytes)) {
furi_crash("Invalid attack set!");
}
scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack);
/*#endif*/
consumed = true;
} /* else if(event.event == SubBruteCustomEventTypeChangeStepUp) {
instance->device->two_bytes = true;
} else if(event.event == SubBruteCustomEventTypeChangeStepDown) {
instance->device->two_bytes = false;
}*/
} else if(event.type == SceneManagerEventTypeBack) {
if(!scene_manager_search_and_switch_to_previous_scene(
instance->scene_manager, SubBruteSceneStart)) {
scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart);
}
consumed = true;
}
return consumed;
}

View File

@@ -0,0 +1,104 @@
#include "../subbrute_i.h"
#include "subbrute_scene.h"
#define TAG "SubBruteSceneRunAttack"
static void subbrute_scene_run_attack_callback(SubBruteCustomEvent event, void* context) {
furi_assert(context);
SubBruteState* instance = (SubBruteState*)context;
view_dispatcher_send_custom_event(instance->view_dispatcher, event);
}
static void
subbrute_scene_run_attack_device_state_changed(void* context, SubBruteWorkerState state) {
furi_assert(context);
SubBruteState* instance = (SubBruteState*)context;
if(state == SubBruteWorkerStateIDLE) {
// Can't be IDLE on this step!
view_dispatcher_send_custom_event(instance->view_dispatcher, SubBruteCustomEventTypeError);
} else if(state == SubBruteWorkerStateFinished) {
view_dispatcher_send_custom_event(
instance->view_dispatcher, SubBruteCustomEventTypeTransmitFinished);
}
}
void subbrute_scene_run_attack_on_exit(void* context) {
furi_assert(context);
SubBruteState* instance = (SubBruteState*)context;
notification_message(instance->notifications, &sequence_blink_stop);
subbrute_worker_stop(instance->worker);
}
void subbrute_scene_run_attack_on_enter(void* context) {
furi_assert(context);
SubBruteState* instance = (SubBruteState*)context;
SubBruteAttackView* view = instance->view_attack;
instance->current_view = SubBruteViewAttack;
subbrute_attack_view_set_callback(view, subbrute_scene_run_attack_callback, instance);
view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view);
subbrute_worker_set_callback(
instance->worker, subbrute_scene_run_attack_device_state_changed, instance);
if(!subbrute_worker_is_running(instance->worker)) {
subbrute_worker_set_step(instance->worker, instance->device->current_step);
if(!subbrute_worker_start(instance->worker)) {
view_dispatcher_send_custom_event(
instance->view_dispatcher, SubBruteCustomEventTypeError);
} else {
notification_message(instance->notifications, &sequence_single_vibro);
notification_message(instance->notifications, &sequence_blink_start_yellow);
}
}
}
bool subbrute_scene_run_attack_on_event(void* context, SceneManagerEvent event) {
SubBruteState* instance = (SubBruteState*)context;
SubBruteAttackView* view = instance->view_attack;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
uint64_t step = subbrute_worker_get_step(instance->worker);
instance->device->current_step = step;
subbrute_attack_view_set_current_step(view, step);
if(event.event == SubBruteCustomEventTypeTransmitFinished) {
notification_message(instance->notifications, &sequence_display_backlight_on);
notification_message(instance->notifications, &sequence_double_vibro);
scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack);
} else if(
event.event == SubBruteCustomEventTypeTransmitNotStarted ||
event.event == SubBruteCustomEventTypeBackPressed) {
if(subbrute_worker_is_running(instance->worker)) {
// Notify
notification_message(instance->notifications, &sequence_single_vibro);
}
// Stop transmit
scene_manager_search_and_switch_to_previous_scene(
instance->scene_manager, SubBruteSceneSetupAttack);
} else if(event.event == SubBruteCustomEventTypeError) {
notification_message(instance->notifications, &sequence_error);
// Stop transmit
scene_manager_search_and_switch_to_previous_scene(
instance->scene_manager, SubBruteSceneSetupAttack);
} else if(event.event == SubBruteCustomEventTypeUpdateView) {
//subbrute_attack_view_set_current_step(view, instance->device->current_step);
}
consumed = true;
} else if(event.type == SceneManagerEventTypeTick) {
uint64_t step = subbrute_worker_get_step(instance->worker);
instance->device->current_step = step;
subbrute_attack_view_set_current_step(view, step);
consumed = true;
}
return consumed;
}

View File

@@ -0,0 +1,84 @@
#include "../subbrute_i.h"
#include "subbrute_scene.h"
#include <lib/toolbox/random_name.h>
#define TAG "SubBruteSceneSaveFile"
void subbrute_scene_save_name_on_enter(void* context) {
SubBruteState* instance = (SubBruteState*)context;
// Setup view
TextInput* text_input = instance->text_input;
set_random_name(instance->text_store, sizeof(instance->text_store));
text_input_set_header_text(text_input, "Name of file");
text_input_set_result_callback(
text_input,
subbrute_text_input_callback,
instance,
instance->text_store,
SUBBRUTE_MAX_LEN_NAME,
true);
furi_string_reset(instance->file_path);
furi_string_set_str(instance->file_path, SUBBRUTE_PATH);
ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
furi_string_get_cstr(instance->file_path), SUBBRUTE_FILE_EXT, "");
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
view_dispatcher_switch_to_view(instance->view_dispatcher, SubBruteViewTextInput);
}
bool subbrute_scene_save_name_on_event(void* context, SceneManagerEvent event) {
SubBruteState* instance = (SubBruteState*)context;
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
scene_manager_previous_scene(instance->scene_manager);
return true;
} else if(
event.type == SceneManagerEventTypeCustom &&
event.event == SubBruteCustomEventTypeTextEditDone) {
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Saving: %s", instance->text_store);
#endif
bool success = false;
if(strcmp(instance->text_store, "")) {
furi_string_reset(instance->file_path);
furi_string_cat_printf(
instance->file_path,
"%s/%s%s",
SUBBRUTE_PATH,
instance->text_store,
SUBBRUTE_FILE_EXT);
if(subbrute_device_save_file(
instance->device, furi_string_get_cstr(instance->file_path))) {
scene_manager_next_scene(instance->scene_manager, SubBruteSceneSaveSuccess);
success = true;
consumed = true;
}
}
if(!success) {
dialog_message_show_storage_error(instance->dialogs, "Error during saving!");
consumed = scene_manager_search_and_switch_to_previous_scene(
instance->scene_manager, SubBruteSceneSetupAttack);
}
}
return consumed;
}
void subbrute_scene_save_name_on_exit(void* context) {
SubBruteState* instance = (SubBruteState*)context;
// Clear view
void* validator_context = text_input_get_validator_callback_context(instance->text_input);
text_input_set_validator(instance->text_input, NULL, NULL);
validator_is_file_free(validator_context);
text_input_reset(instance->text_input);
furi_string_reset(instance->file_path);
}

View File

@@ -0,0 +1,51 @@
#include "../subbrute_i.h"
#include "subbrute_scene.h"
void subbrute_scene_save_success_on_enter(void* context) {
furi_assert(context);
SubBruteState* instance = context;
// Setup view
Popup* popup = instance->popup;
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
popup_set_header(popup, "Saved!", 13, 22, AlignLeft, AlignBottom);
popup_set_timeout(popup, 1500);
popup_set_context(popup, instance);
popup_set_callback(popup, subbrute_popup_closed_callback);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(instance->view_dispatcher, SubBruteViewPopup);
}
bool subbrute_scene_save_success_on_event(void* context, SceneManagerEvent event) {
furi_assert(context);
SubBruteState* instance = (SubBruteState*)context;
//SubBruteMainView* view = instance->view_main;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubBruteCustomEventTypePopupClosed) {
if(!scene_manager_search_and_switch_to_previous_scene(
instance->scene_manager, SubBruteSceneSetupAttack)) {
scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart);
}
return true;
}
}
return false;
}
void subbrute_scene_save_success_on_exit(void* context) {
furi_assert(context);
SubBruteState* instance = (SubBruteState*)context;
// Clear view
Popup* popup = instance->popup;
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_set_callback(popup, NULL);
popup_set_context(popup, NULL);
popup_set_timeout(popup, 0);
popup_disable_timeout(popup);
}

View File

@@ -0,0 +1,138 @@
#include "../subbrute_i.h"
#include "subbrute_scene.h"
#define TAG "SubBruteSceneSetupAttack"
static void subbrute_scene_setup_attack_callback(SubBruteCustomEvent event, void* context) {
furi_assert(context);
SubBruteState* instance = (SubBruteState*)context;
view_dispatcher_send_custom_event(instance->view_dispatcher, event);
}
static void
subbrute_scene_setup_attack_device_state_changed(void* context, SubBruteWorkerState state) {
furi_assert(context);
SubBruteState* instance = (SubBruteState*)context;
if(state == SubBruteWorkerStateIDLE) {
// Can't be IDLE on this step!
view_dispatcher_send_custom_event(instance->view_dispatcher, SubBruteCustomEventTypeError);
}
}
void subbrute_scene_setup_attack_on_enter(void* context) {
furi_assert(context);
SubBruteState* instance = (SubBruteState*)context;
SubBruteAttackView* view = instance->view_attack;
notification_message(instance->notifications, &sequence_reset_vibro);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Enter Attack: %s", subbrute_protocol_name(instance->device->attack));
#endif
subbrute_worker_set_callback(
instance->worker, subbrute_scene_setup_attack_device_state_changed, context);
if(subbrute_worker_is_running(instance->worker)) {
subbrute_worker_stop(instance->worker);
instance->device->current_step = subbrute_worker_get_step(instance->worker);
}
subbrute_attack_view_init_values(
view,
instance->device->attack,
instance->device->max_value,
instance->device->current_step,
false,
instance->device->extra_repeats);
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);
}
void subbrute_scene_setup_attack_on_exit(void* context) {
furi_assert(context);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_scene_setup_attack_on_exit");
#endif
SubBruteState* instance = (SubBruteState*)context;
subbrute_worker_stop(instance->worker);
notification_message(instance->notifications, &sequence_blink_stop);
notification_message(instance->notifications, &sequence_reset_vibro);
}
bool subbrute_scene_setup_attack_on_event(void* context, SceneManagerEvent event) {
SubBruteState* instance = (SubBruteState*)context;
SubBruteAttackView* view = instance->view_attack;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubBruteCustomEventTypeTransmitStarted) {
scene_manager_next_scene(instance->scene_manager, SubBruteSceneRunAttack);
} else if(event.event == SubBruteCustomEventTypeSaveFile) {
subbrute_attack_view_init_values(
view,
instance->device->attack,
instance->device->max_value,
instance->device->current_step,
false,
instance->device->extra_repeats);
scene_manager_next_scene(instance->scene_manager, SubBruteSceneSaveName);
} else if(event.event == SubBruteCustomEventTypeBackPressed) {
subbrute_attack_view_init_values(
view,
instance->device->attack,
instance->device->max_value,
instance->device->current_step,
false,
instance->device->extra_repeats);
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_worker_can_manual_transmit(instance->worker)) {
// MANUAL Transmit!
// Blink
notification_message(instance->notifications, &sequence_blink_green_100);
subbrute_worker_transmit_current_key(
instance->worker, instance->device->current_step);
// 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) {
if(subbrute_worker_is_running(instance->worker)) {
instance->device->current_step = subbrute_worker_get_step(instance->worker);
}
subbrute_attack_view_set_current_step(view, instance->device->current_step);
consumed = true;
}
return consumed;
}

View File

@@ -0,0 +1,89 @@
#include "../subbrute_i.h"
#include "subbrute_scene.h"
#define TAG "SubBruteSceneStart"
void subbrute_scene_start_callback(SubBruteCustomEvent event, void* context) {
furi_assert(context);
SubBruteState* instance = (SubBruteState*)context;
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_scene_start_callback");
#endif
view_dispatcher_send_custom_event(instance->view_dispatcher, event);
}
void subbrute_scene_start_on_enter(void* context) {
furi_assert(context);
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "subbrute_scene_start_on_enter");
#endif
SubBruteState* instance = (SubBruteState*)context;
SubBruteMainView* view = instance->view_main;
instance->current_view = SubBruteViewMain;
subbrute_main_view_set_callback(view, subbrute_scene_start_callback, instance);
subbrute_main_view_set_index(
view, instance->device->attack, false, instance->device->two_bytes, 0);
view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view);
// TODO: DELETE IT
#ifdef SUBBRUTE_FAST_TRACK
scene_manager_next_scene(instance->scene_manager, SubBruteSceneLoadFile);
#endif
}
void subbrute_scene_start_on_exit(void* context) {
UNUSED(context);
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "subbrute_scene_start_on_exit");
#endif
}
bool subbrute_scene_start_on_event(void* context, SceneManagerEvent event) {
SubBruteState* instance = (SubBruteState*)context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
#ifdef FURI_DEBUG
FURI_LOG_D(
TAG,
"Event: %ld, SubBruteCustomEventTypeMenuSelected: %s, SubBruteCustomEventTypeLoadFile: %s",
event.event,
event.event == SubBruteCustomEventTypeMenuSelected ? "true" : "false",
event.event == SubBruteCustomEventTypeLoadFile ? "true" : "false");
#endif
if(event.event == SubBruteCustomEventTypeMenuSelected) {
SubBruteAttacks attack = subbrute_main_view_get_index(instance->view_main);
uint8_t extra_repeats = subbrute_main_view_get_extra_repeats(instance->view_main);
if((subbrute_device_attack_set(instance->device, attack, extra_repeats) !=
SubBruteFileResultOk) ||
(!subbrute_worker_init_default_attack(
instance->worker,
attack,
instance->device->current_step,
instance->device->protocol_info,
instance->device->extra_repeats))) {
furi_crash("Invalid attack set!");
}
scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack);
consumed = true;
} else if(event.event == SubBruteCustomEventTypeLoadFile) {
//uint8_t extra_repeats = subbrute_main_view_get_extra_repeats(instance->view_main);
//instance->device->extra_repeats = extra_repeats;
scene_manager_next_scene(instance->scene_manager, SubBruteSceneLoadFile);
consumed = true;
}
} else if(event.type == SceneManagerEventTypeBack) {
//exit app
scene_manager_stop(instance->scene_manager);
view_dispatcher_stop(instance->view_dispatcher);
consumed = true;
}
return consumed;
}

View File

@@ -0,0 +1,30 @@
#include "subbrute_scene.h"
// Generate scene on_enter handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
void (*const subbrute_on_enter_handlers[])(void*) = {
#include "subbrute_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_event handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
bool (*const subbrute_on_event_handlers[])(void* context, SceneManagerEvent event) = {
#include "subbrute_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_exit handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
void (*const subbrute_on_exit_handlers[])(void* context) = {
#include "subbrute_scene_config.h"
};
#undef ADD_SCENE
// Initialize scene handlers configuration structure
const SceneManagerHandlers subbrute_scene_handlers = {
.on_enter_handlers = subbrute_on_enter_handlers,
.on_event_handlers = subbrute_on_event_handlers,
.on_exit_handlers = subbrute_on_exit_handlers,
.scene_num = SubBruteSceneNum,
};

View File

@@ -0,0 +1,199 @@
#include "subbrute_i.h"
#include "subbrute_custom_event.h"
#include "scenes/subbrute_scene.h"
#define TAG "SubBruteApp"
static bool subbrute_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
SubBruteState* instance = context;
return scene_manager_handle_custom_event(instance->scene_manager, event);
}
static bool subbrute_back_event_callback(void* context) {
furi_assert(context);
SubBruteState* instance = context;
return scene_manager_handle_back_event(instance->scene_manager);
}
static void subbrute_tick_event_callback(void* context) {
furi_assert(context);
SubBruteState* instance = context;
scene_manager_handle_tick_event(instance->scene_manager);
}
SubBruteState* subbrute_alloc() {
SubBruteState* instance = malloc(sizeof(SubBruteState));
memset(instance->text_store, 0, sizeof(instance->text_store));
instance->file_path = furi_string_alloc();
instance->scene_manager = scene_manager_alloc(&subbrute_scene_handlers, instance);
instance->view_dispatcher = view_dispatcher_alloc();
instance->gui = furi_record_open(RECORD_GUI);
view_dispatcher_enable_queue(instance->view_dispatcher);
view_dispatcher_set_event_callback_context(instance->view_dispatcher, instance);
view_dispatcher_set_custom_event_callback(
instance->view_dispatcher, subbrute_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
instance->view_dispatcher, subbrute_back_event_callback);
view_dispatcher_set_tick_event_callback(
instance->view_dispatcher, subbrute_tick_event_callback, 100);
//Dialog
instance->dialogs = furi_record_open(RECORD_DIALOGS);
// Notifications
instance->notifications = furi_record_open(RECORD_NOTIFICATION);
// Devices
instance->device = subbrute_device_alloc();
// SubBruteWorker
instance->worker = subbrute_worker_alloc();
// TextInput
instance->text_input = text_input_alloc();
view_dispatcher_add_view(
instance->view_dispatcher,
SubBruteViewTextInput,
text_input_get_view(instance->text_input));
// Custom Widget
instance->widget = widget_alloc();
view_dispatcher_add_view(
instance->view_dispatcher, SubBruteViewWidget, widget_get_view(instance->widget));
// Popup
instance->popup = popup_alloc();
view_dispatcher_add_view(
instance->view_dispatcher, SubBruteViewPopup, popup_get_view(instance->popup));
// ViewStack
instance->view_stack = view_stack_alloc();
view_dispatcher_add_view(
instance->view_dispatcher, SubBruteViewStack, view_stack_get_view(instance->view_stack));
// SubBruteMainView
instance->view_main = subbrute_main_view_alloc();
view_dispatcher_add_view(
instance->view_dispatcher,
SubBruteViewMain,
subbrute_main_view_get_view(instance->view_main));
// SubBruteAttackView
instance->view_attack = subbrute_attack_view_alloc();
view_dispatcher_add_view(
instance->view_dispatcher,
SubBruteViewAttack,
subbrute_attack_view_get_view(instance->view_attack));
//instance->flipper_format = flipper_format_string_alloc();
//instance->environment = subghz_environment_alloc();
return instance;
}
void subbrute_free(SubBruteState* instance) {
furi_assert(instance);
// SubBruteWorker
subbrute_worker_stop(instance->worker);
subbrute_worker_free(instance->worker);
// SubBruteDevice
subbrute_device_free(instance->device);
// Notifications
notification_message(instance->notifications, &sequence_blink_stop);
furi_record_close(RECORD_NOTIFICATION);
instance->notifications = NULL;
// View Main
view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewMain);
subbrute_main_view_free(instance->view_main);
// View Attack
view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewAttack);
subbrute_attack_view_free(instance->view_attack);
// TextInput
view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewTextInput);
text_input_free(instance->text_input);
// Custom Widget
view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewWidget);
widget_free(instance->widget);
// Popup
view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewPopup);
popup_free(instance->popup);
// ViewStack
view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewStack);
view_stack_free(instance->view_stack);
//Dialog
furi_record_close(RECORD_DIALOGS);
instance->dialogs = NULL;
// Scene manager
scene_manager_free(instance->scene_manager);
// View Dispatcher
view_dispatcher_free(instance->view_dispatcher);
// GUI
furi_record_close(RECORD_GUI);
instance->gui = NULL;
furi_string_free(instance->file_path);
// The rest
free(instance);
}
void subbrute_text_input_callback(void* context) {
furi_assert(context);
SubBruteState* instance = context;
view_dispatcher_send_custom_event(
instance->view_dispatcher, SubBruteCustomEventTypeTextEditDone);
}
void subbrute_popup_closed_callback(void* context) {
furi_assert(context);
SubBruteState* instance = context;
view_dispatcher_send_custom_event(
instance->view_dispatcher, SubBruteCustomEventTypePopupClosed);
}
// ENTRYPOINT
int32_t subbrute_app(void* p) {
UNUSED(p);
SubBruteState* instance = subbrute_alloc();
view_dispatcher_attach_to_gui(
instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen);
scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart);
// Enable power for External CC1101 if it is connected
furi_hal_subghz_enable_ext_power();
// Auto switch to internal radio if external radio is not available
if(!furi_hal_subghz_check_radio()) {
furi_hal_subghz_set_radio_type(SubGhzRadioInternal);
}
furi_hal_power_suppress_charge_enter();
notification_message(instance->notifications, &sequence_display_backlight_on);
view_dispatcher_run(instance->view_dispatcher);
furi_hal_power_suppress_charge_exit();
// Disable power for External CC1101 if it was enabled and module is connected
furi_hal_subghz_disable_ext_power();
subbrute_free(instance);
return 0;
}

View File

@@ -0,0 +1,3 @@
#pragma once
typedef struct SubBruteState SubBruteState;

View File

@@ -0,0 +1,26 @@
#pragma once
typedef enum {
// Reserve first 100 events for button types and indexes, starting from 0
SubBruteCustomEventTypeReserved = 100,
SubBruteCustomEventTypeBackPressed,
SubBruteCustomEventTypeIndexSelected,
SubBruteCustomEventTypeTransmitStarted,
SubBruteCustomEventTypeError,
SubBruteCustomEventTypeTransmitFinished,
SubBruteCustomEventTypeTransmitNotStarted,
SubBruteCustomEventTypeTransmitCustom,
SubBruteCustomEventTypeSaveFile,
SubBruteCustomEventTypeUpdateView,
SubBruteCustomEventTypeChangeStepUp,
SubBruteCustomEventTypeChangeStepDown,
SubBruteCustomEventTypeChangeStepUpMore,
SubBruteCustomEventTypeChangeStepDownMore,
SubBruteCustomEventTypeMenuSelected,
SubBruteCustomEventTypeTextEditDone,
SubBruteCustomEventTypePopupClosed,
SubBruteCustomEventTypeLoadFile,
} SubBruteCustomEvent;

View File

@@ -0,0 +1,460 @@
#include "subbrute_device.h"
#include <stdint.h>
#include <storage/storage.h>
#include <lib/toolbox/stream/stream.h>
#include <lib/flipper_format/flipper_format.h>
#include <lib/flipper_format/flipper_format_i.h>
#include <lib/subghz/protocols/protocol_items.h>
#define TAG "SubBruteDevice"
SubBruteDevice* subbrute_device_alloc() {
SubBruteDevice* instance = malloc(sizeof(SubBruteDevice));
instance->current_step = 0;
instance->protocol_info = NULL;
instance->file_protocol_info = NULL;
instance->decoder_result = NULL;
instance->receiver = NULL;
instance->environment = subghz_environment_alloc();
subghz_environment_set_protocol_registry(
instance->environment, (void*)&subghz_protocol_registry);
#ifdef FURI_DEBUG
subbrute_device_attack_set_default_values(instance, SubBruteAttackLoadFile);
#else
subbrute_device_attack_set_default_values(instance, SubBruteAttackCAME12bit433);
#endif
return instance;
}
void subbrute_device_free(SubBruteDevice* instance) {
furi_assert(instance);
// I don't know how to free this
instance->decoder_result = NULL;
if(instance->receiver != NULL) {
subghz_receiver_free(instance->receiver);
instance->receiver = NULL;
}
subghz_environment_free(instance->environment);
instance->environment = NULL;
subbrute_device_free_protocol_info(instance);
free(instance);
}
uint64_t subbrute_device_add_step(SubBruteDevice* instance, int8_t step) {
if(step > 0) {
if((instance->current_step + step) - instance->max_value == 1) {
instance->current_step = 0x00;
} else {
uint64_t value = instance->current_step + step;
if(value == instance->max_value) {
instance->current_step = value;
} else {
instance->current_step = value % instance->max_value;
}
}
} else {
if(instance->current_step + step == 0) {
instance->current_step = 0x00;
} else if(instance->current_step == 0) {
instance->current_step = instance->max_value;
} else {
uint64_t value = ((instance->current_step + step) + instance->max_value);
if(value == instance->max_value) {
instance->current_step = value;
} else {
instance->current_step = value % instance->max_value;
}
}
}
return instance->current_step;
}
bool subbrute_device_save_file(SubBruteDevice* instance, const char* dev_file_name) {
furi_assert(instance);
#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);
bool result = false;
do {
if(!flipper_format_file_open_always(file, dev_file_name)) {
FURI_LOG_E(TAG, "Failed to open file: %s", dev_file_name);
break;
}
Stream* stream = flipper_format_get_raw_stream(file);
if(instance->attack == SubBruteAttackLoadFile) {
subbrute_protocol_file_generate_file(
stream,
instance->file_protocol_info->frequency,
instance->file_protocol_info->preset,
instance->file_protocol_info->file,
instance->current_step,
instance->file_protocol_info->bits,
instance->file_protocol_info->te,
instance->file_protocol_info->repeat,
instance->bit_index,
instance->key_from_file,
instance->two_bytes);
} else {
subbrute_protocol_default_generate_file(
stream,
instance->protocol_info->frequency,
instance->protocol_info->preset,
instance->protocol_info->file,
instance->current_step,
instance->protocol_info->bits,
instance->protocol_info->te,
instance->protocol_info->repeat);
}
result = true;
} while(false);
if(!result) {
FURI_LOG_E(TAG, "subbrute_device_save_file failed!");
}
flipper_format_file_close(file);
flipper_format_free(file);
furi_record_close(RECORD_STORAGE);
return result;
}
SubBruteFileResult subbrute_device_attack_set(
SubBruteDevice* instance,
SubBruteAttacks type,
uint8_t extra_repeats) {
furi_assert(instance);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_device_attack_set: %d, extra_repeats: %d", type, extra_repeats);
#endif
subbrute_device_attack_set_default_values(instance, type);
if(type != SubBruteAttackLoadFile) {
subbrute_device_free_protocol_info(instance);
instance->protocol_info = subbrute_protocol(type);
}
instance->extra_repeats = extra_repeats;
// For non-file types we didn't set SubGhzProtocolDecoderBase
instance->receiver = subghz_receiver_alloc_init(instance->environment);
subghz_receiver_set_filter(instance->receiver, SubGhzProtocolFlag_Decodable);
furi_hal_subghz_reset();
uint8_t protocol_check_result = SubBruteFileResultProtocolNotFound;
#ifdef FURI_DEBUG
uint8_t bits;
uint32_t te;
uint8_t repeat;
FuriHalSubGhzPreset preset;
SubBruteFileProtocol file;
#endif
if(type != SubBruteAttackLoadFile) {
instance->decoder_result = subghz_receiver_search_decoder_base_by_name(
instance->receiver, subbrute_protocol_file(instance->protocol_info->file));
if(!instance->decoder_result ||
instance->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) {
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, instance->two_bytes);
}
#ifdef FURI_DEBUG
bits = instance->protocol_info->bits;
te = instance->protocol_info->te;
repeat = instance->protocol_info->repeat + instance->extra_repeats;
preset = instance->protocol_info->preset;
file = instance->protocol_info->file;
#endif
} 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, instance->two_bytes);
#ifdef FURI_DEBUG
bits = instance->file_protocol_info->bits;
te = instance->file_protocol_info->te;
repeat = instance->file_protocol_info->repeat + instance->extra_repeats;
preset = instance->file_protocol_info->preset;
file = instance->file_protocol_info->file;
#endif
}
subghz_receiver_free(instance->receiver);
instance->receiver = NULL;
if(protocol_check_result != SubBruteFileResultOk) {
return SubBruteFileResultProtocolNotFound;
}
#ifdef FURI_DEBUG
FURI_LOG_I(
TAG,
"subbrute_device_attack_set: %s, bits: %d, preset: %s, file: %s, te: %ld, repeat: %d, max_value: %lld",
subbrute_protocol_name(instance->attack),
bits,
subbrute_protocol_preset(preset),
subbrute_protocol_file(file),
te,
repeat,
instance->max_value);
#endif
return SubBruteFileResultOk;
}
uint8_t subbrute_device_load_from_file(SubBruteDevice* instance, const char* file_path) {
furi_assert(instance);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_device_load_from_file: %s", file_path);
#endif
SubBruteFileResult result = SubBruteFileResultUnknown;
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
subbrute_device_free_protocol_info(instance);
instance->file_protocol_info = malloc(sizeof(SubBruteProtocol));
FuriString* temp_str;
temp_str = furi_string_alloc();
uint32_t temp_data32;
instance->receiver = subghz_receiver_alloc_init(instance->environment);
subghz_receiver_set_filter(instance->receiver, SubGhzProtocolFlag_Decodable);
furi_hal_subghz_reset();
do {
if(!flipper_format_file_open_existing(fff_data_file, file_path)) {
FURI_LOG_E(TAG, "Error open file %s", file_path);
result = SubBruteFileResultErrorOpenFile;
break;
}
if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) {
FURI_LOG_E(TAG, "Missing or incorrect header");
result = SubBruteFileResultMissingOrIncorrectHeader;
break;
}
// Frequency
if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) {
FURI_LOG_E(TAG, "Missing or incorrect Frequency");
result = SubBruteFileResultMissingOrIncorrectFrequency;
break;
}
instance->file_protocol_info->frequency = temp_data32;
if(!furi_hal_subghz_is_tx_allowed(instance->file_protocol_info->frequency)) {
result = SubBruteFileResultFrequencyNotAllowed;
break;
}
// Preset
if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) {
FURI_LOG_E(TAG, "Preset FAIL");
result = SubBruteFileResultPresetInvalid;
break;
}
instance->file_protocol_info->preset = subbrute_protocol_convert_preset(temp_str);
const char* protocol_file = NULL;
// Protocol
if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) {
FURI_LOG_E(TAG, "Missing Protocol");
result = SubBruteFileResultMissingProtocol;
break;
}
instance->file_protocol_info->file = subbrute_protocol_file_protocol_name(temp_str);
protocol_file = subbrute_protocol_file(instance->file_protocol_info->file);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Protocol: %s", protocol_file);
#endif
instance->decoder_result = subghz_receiver_search_decoder_base_by_name(
instance->receiver, furi_string_get_cstr(temp_str));
if((!instance->decoder_result) || (strcmp(protocol_file, "RAW") == 0) ||
(strcmp(protocol_file, "Unknown") == 0)) {
FURI_LOG_E(TAG, "Protocol unsupported");
result = SubBruteFileResultProtocolNotSupported;
break;
}
if(instance->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) {
FURI_LOG_E(TAG, "Protocol is dynamic - not supported");
result = SubBruteFileResultDynamicProtocolNotValid;
break;
}
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Decoder: %s", instance->decoder_result->protocol->name);
#endif
// Bit
if(!flipper_format_read_uint32(fff_data_file, "Bit", &temp_data32, 1)) {
FURI_LOG_E(TAG, "Missing or incorrect Bit");
result = SubBruteFileResultMissingOrIncorrectBit;
break;
}
instance->file_protocol_info->bits = temp_data32;
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Bit: %d", instance->file_protocol_info->bits);
#endif
uint8_t key_data[sizeof(uint64_t)] = {0};
if(!flipper_format_read_hex(fff_data_file, "Key", key_data, sizeof(uint64_t))) {
FURI_LOG_E(TAG, "Missing Key");
result = SubBruteFileResultMissingOrIncorrectKey;
break;
}
uint64_t data = 0;
for(uint8_t i = 0; i < sizeof(uint64_t); i++) {
data = (data << 8) | key_data[i];
}
#if FURI_DEBUG
FURI_LOG_D(TAG, "Key: %.16llX", data);
#endif
instance->key_from_file = data;
// TE
if(!flipper_format_read_uint32(fff_data_file, "TE", &temp_data32, 1)) {
FURI_LOG_E(TAG, "Missing or incorrect TE");
//result = SubBruteFileResultMissingOrIncorrectTe;
//break;
} else {
instance->file_protocol_info->te = temp_data32 != 0 ? temp_data32 : 0;
}
// Repeat
if(flipper_format_read_uint32(fff_data_file, "Repeat", &temp_data32, 1)) {
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Repeat: %ld", temp_data32);
#endif
instance->file_protocol_info->repeat = (uint8_t)temp_data32;
} else {
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Repeat: 3 (default)");
#endif
instance->file_protocol_info->repeat = 3;
}
result = SubBruteFileResultOk;
} while(0);
furi_string_free(temp_str);
flipper_format_file_close(fff_data_file);
flipper_format_free(fff_data_file);
furi_record_close(RECORD_STORAGE);
subghz_receiver_free(instance->receiver);
instance->decoder_result = NULL;
instance->receiver = NULL;
if(result == SubBruteFileResultOk) {
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Loaded successfully");
#endif
} else {
subbrute_device_free_protocol_info(instance);
}
return result;
}
void subbrute_device_attack_set_default_values(
SubBruteDevice* instance,
SubBruteAttacks default_attack) {
furi_assert(instance);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_device_attack_set_default_values");
#endif
instance->attack = default_attack;
instance->current_step = 0x00;
instance->bit_index = 0x00;
instance->extra_repeats = 0;
instance->two_bytes = false;
if(default_attack != SubBruteAttackLoadFile) {
instance->max_value = subbrute_protocol_calc_max_value(
instance->attack, instance->bit_index, instance->two_bytes);
}
}
const char* subbrute_device_error_get_desc(SubBruteFileResult error_id) {
const char* result;
switch(error_id) {
case(SubBruteFileResultOk):
result = "OK";
break;
case(SubBruteFileResultErrorOpenFile):
result = "invalid name/path";
break;
case(SubBruteFileResultMissingOrIncorrectHeader):
result = "Missing or incorrect header";
break;
case(SubBruteFileResultFrequencyNotAllowed):
result = "Invalid frequency!";
break;
case(SubBruteFileResultMissingOrIncorrectFrequency):
result = "Missing or incorrect Frequency";
break;
case(SubBruteFileResultPresetInvalid):
result = "Preset FAIL";
break;
case(SubBruteFileResultMissingProtocol):
result = "Missing Protocol";
break;
case(SubBruteFileResultProtocolNotSupported):
result = "Protocol unsupported";
break;
case(SubBruteFileResultDynamicProtocolNotValid):
result = "Dynamic protocol unsupported";
break;
case(SubBruteFileResultProtocolNotFound):
result = "Protocol not found";
break;
case(SubBruteFileResultMissingOrIncorrectBit):
result = "Missing or incorrect Bit";
break;
case(SubBruteFileResultMissingOrIncorrectKey):
result = "Missing or incorrect Key";
break;
case(SubBruteFileResultMissingOrIncorrectTe):
result = "Missing or incorrect TE";
break;
case SubBruteFileResultUnknown:
default:
result = "Unknown error";
break;
}
return result;
}
void subbrute_device_free_protocol_info(SubBruteDevice* instance) {
furi_assert(instance);
instance->protocol_info = NULL;
if(instance->file_protocol_info) {
free(instance->file_protocol_info);
}
instance->file_protocol_info = NULL;
}

View File

@@ -0,0 +1,75 @@
#pragma once
#include "subbrute_protocols.h"
#include <lib/subghz/protocols/base.h>
#include <lib/subghz/transmitter.h>
#include <lib/subghz/receiver.h>
#include <lib/subghz/environment.h>
#define SUBBRUTE_TEXT_STORE_SIZE 256
#define SUBBRUTE_MAX_LEN_NAME 64
#define SUBBRUTE_PATH EXT_PATH("subghz")
#define SUBBRUTE_FILE_EXT ".sub"
#define SUBBRUTE_PAYLOAD_SIZE 16
typedef enum {
SubBruteFileResultUnknown,
SubBruteFileResultOk,
SubBruteFileResultErrorOpenFile,
SubBruteFileResultMissingOrIncorrectHeader,
SubBruteFileResultFrequencyNotAllowed,
SubBruteFileResultMissingOrIncorrectFrequency,
SubBruteFileResultPresetInvalid,
SubBruteFileResultMissingProtocol,
SubBruteFileResultProtocolNotSupported,
SubBruteFileResultDynamicProtocolNotValid,
SubBruteFileResultProtocolNotFound,
SubBruteFileResultMissingOrIncorrectBit,
SubBruteFileResultMissingOrIncorrectKey,
SubBruteFileResultMissingOrIncorrectTe,
} SubBruteFileResult;
typedef struct {
const SubBruteProtocol* protocol_info;
SubBruteProtocol* file_protocol_info;
// Current step
uint64_t current_step;
// SubGhz
SubGhzReceiver* receiver;
SubGhzProtocolDecoderBase* decoder_result;
SubGhzEnvironment* environment;
// Attack state
SubBruteAttacks attack;
uint64_t max_value;
uint8_t extra_repeats;
// Loaded info for attack type
uint64_t key_from_file;
uint64_t current_key_from_file;
bool two_bytes;
// Index of group to bruteforce in loaded file
uint8_t bit_index;
} SubBruteDevice;
SubBruteDevice* subbrute_device_alloc();
void subbrute_device_free(SubBruteDevice* instance);
bool subbrute_device_save_file(SubBruteDevice* instance, const char* key_name);
const char* subbrute_device_error_get_desc(SubBruteFileResult error_id);
SubBruteFileResult subbrute_device_attack_set(
SubBruteDevice* context,
SubBruteAttacks type,
uint8_t extra_repeats);
uint8_t subbrute_device_load_from_file(SubBruteDevice* context, const char* file_path);
uint64_t subbrute_device_add_step(SubBruteDevice* instance, int8_t step);
void subbrute_device_free_protocol_info(SubBruteDevice* instance);
void subbrute_device_attack_set_default_values(
SubBruteDevice* context,
SubBruteAttacks default_attack);

View File

@@ -0,0 +1,80 @@
#pragma once
#include <furi.h>
#include <furi_hal.h>
#include <input/input.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include <gui/gui.h>
#include <gui/view_dispatcher.h>
#include <gui/view_stack.h>
#include <gui/scene_manager.h>
#include <gui/modules/text_input.h>
#include <gui/modules/popup.h>
#include <gui/modules/widget.h>
#include <gui/modules/loading.h>
#include "SubGHz_Bruteforcer_icons.h"
#include <dialogs/dialogs.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include "subbrute.h"
#include "subbrute_device.h"
#include "helpers/subbrute_worker.h"
#include "views/subbrute_attack_view.h"
#include "views/subbrute_main_view.h"
#define SUBBRUTEFORCER_VER "Sub-GHz BruteForcer 3.5"
#ifdef FURI_DEBUG
//#define SUBBRUTE_FAST_TRACK false
#endif
typedef enum {
SubBruteViewNone,
SubBruteViewMain,
SubBruteViewAttack,
SubBruteViewTextInput,
SubBruteViewDialogEx,
SubBruteViewPopup,
SubBruteViewWidget,
SubBruteViewStack,
} SubBruteView;
struct SubBruteState {
// GUI elements
NotificationApp* notifications;
Gui* gui;
ViewDispatcher* view_dispatcher;
ViewStack* view_stack;
TextInput* text_input;
Popup* popup;
Widget* widget;
DialogsApp* dialogs;
// Text store
char text_store[SUBBRUTE_MAX_LEN_NAME];
FuriString* file_path;
// Views
SubBruteMainView* view_main;
SubBruteAttackView* view_attack;
SubBruteView current_view;
// Scene
SceneManager* scene_manager;
// 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);

View File

@@ -0,0 +1,881 @@
#include "subbrute_protocols.h"
#include "math.h"
#include <string.h>
#define TAG "SubBruteProtocols"
/**
* CAME 12bit 303MHz
*/
const SubBruteProtocol subbrute_protocol_came_12bit_303 = {
.frequency = 303875000,
.bits = 12,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = CAMEFileProtocol};
/**
* CAME 12bit 307MHz
*/
const SubBruteProtocol subbrute_protocol_came_12bit_307 = {
.frequency = 307800000,
.bits = 12,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = CAMEFileProtocol};
/**
* CAME 12bit 315MHz
*/
const SubBruteProtocol subbrute_protocol_came_12bit_315 = {
.frequency = 315000000,
.bits = 12,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = CAMEFileProtocol};
/**
* CAME 12bit 433MHz
*/
const SubBruteProtocol subbrute_protocol_came_12bit_433 = {
.frequency = 433920000,
.bits = 12,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = CAMEFileProtocol};
/**
* CAME 12bit 868MHz
*/
const SubBruteProtocol subbrute_protocol_came_12bit_868 = {
.frequency = 868350000,
.bits = 12,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = CAMEFileProtocol};
/**
* NICE 12bit 433MHz
*/
const SubBruteProtocol subbrute_protocol_nice_12bit_433 = {
.frequency = 433920000,
.bits = 12,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = NICEFileProtocol};
/**
* NICE 12bit 868MHz
*/
const SubBruteProtocol subbrute_protocol_nice_12bit_868 = {
.frequency = 868350000,
.bits = 12,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = NICEFileProtocol};
/**
* Ansonic 12bit 433.075MHz
*/
const SubBruteProtocol subbrute_protocol_ansonic_12bit_433075 = {
.frequency = 433075000,
.bits = 12,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPreset2FSKDev238Async,
.file = AnsonicFileProtocol};
/**
* Ansonic 12bit 433.92MHz
*/
const SubBruteProtocol subbrute_protocol_ansonic_12bit_433 = {
.frequency = 433920000,
.bits = 12,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPreset2FSKDev238Async,
.file = AnsonicFileProtocol};
/**
* Ansonic 12bit 434.075MHz
*/
const SubBruteProtocol subbrute_protocol_ansonic_12bit_434 = {
.frequency = 434075000,
.bits = 12,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPreset2FSKDev238Async,
.file = AnsonicFileProtocol};
/**
* Chamberlain 9bit 300MHz
*/
const SubBruteProtocol subbrute_protocol_chamberlain_9bit_300 = {
.frequency = 300000000,
.bits = 9,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = ChamberlainFileProtocol};
/**
* Chamberlain 9bit 315MHz
*/
const SubBruteProtocol subbrute_protocol_chamberlain_9bit_315 = {
.frequency = 315000000,
.bits = 9,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = ChamberlainFileProtocol};
/**
* Chamberlain 9bit 390MHz
*/
const SubBruteProtocol subbrute_protocol_chamberlain_9bit_390 = {
.frequency = 390000000,
.bits = 9,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = ChamberlainFileProtocol};
/**
* Chamberlain 9bit 433MHz
*/
const SubBruteProtocol subbrute_protocol_chamberlain_9bit_433 = {
.frequency = 433920000,
.bits = 9,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = ChamberlainFileProtocol};
/**
* Chamberlain 8bit 300MHz
*/
const SubBruteProtocol subbrute_protocol_chamberlain_8bit_300 = {
.frequency = 300000000,
.bits = 8,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = ChamberlainFileProtocol};
/**
* Chamberlain 8bit 315MHz
*/
const SubBruteProtocol subbrute_protocol_chamberlain_8bit_315 = {
.frequency = 315000000,
.bits = 8,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = ChamberlainFileProtocol};
/**
* Chamberlain 8bit 390MHz
*/
const SubBruteProtocol subbrute_protocol_chamberlain_8bit_390 = {
.frequency = 390000000,
.bits = 8,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = ChamberlainFileProtocol};
/**
* Chamberlain 7bit 300MHz
*/
const SubBruteProtocol subbrute_protocol_chamberlain_7bit_300 = {
.frequency = 300000000,
.bits = 7,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = ChamberlainFileProtocol};
/**
* Chamberlain 7bit 315MHz
*/
const SubBruteProtocol subbrute_protocol_chamberlain_7bit_315 = {
.frequency = 315000000,
.bits = 7,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = ChamberlainFileProtocol};
/**
* Chamberlain 7bit 390MHz
*/
const SubBruteProtocol subbrute_protocol_chamberlain_7bit_390 = {
.frequency = 390000000,
.bits = 7,
.te = 0,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = ChamberlainFileProtocol};
/**
* Linear 10bit 300MHz
*/
const SubBruteProtocol subbrute_protocol_linear_10bit_300 = {
.frequency = 300000000,
.bits = 10,
.te = 0,
.repeat = 5,
.preset = FuriHalSubGhzPresetOok650Async,
.file = LinearFileProtocol};
/**
* Linear 10bit 310MHz
*/
const SubBruteProtocol subbrute_protocol_linear_10bit_310 = {
.frequency = 310000000,
.bits = 10,
.te = 0,
.repeat = 5,
.preset = FuriHalSubGhzPresetOok650Async,
.file = LinearFileProtocol};
/**
* Linear Delta 3 8bit 310MHz
*/
const SubBruteProtocol subbrute_protocol_linear_delta_8bit_310 = {
.frequency = 310000000,
.bits = 8,
.te = 0,
.repeat = 5,
.preset = FuriHalSubGhzPresetOok650Async,
.file = LinearDeltaFileProtocol};
/**
* UNILARM 24bit 330MHz
*/
const SubBruteProtocol subbrute_protocol_unilarm_24bit_330 = {
.frequency = 330000000,
.bits = 25,
.te = 209,
.repeat = 4,
.preset = FuriHalSubGhzPresetOok650Async,
.file = UNILARMFileProtocol};
/**
* UNILARM 24bit 433MHz
*/
const SubBruteProtocol subbrute_protocol_unilarm_24bit_433 = {
.frequency = 433920000,
.bits = 25,
.te = 209,
.repeat = 4,
.preset = FuriHalSubGhzPresetOok650Async,
.file = UNILARMFileProtocol};
/**
* SMC5326 24bit 330MHz
*/
const SubBruteProtocol subbrute_protocol_smc5326_24bit_330 = {
.frequency = 330000000,
.bits = 25,
.te = 320,
.repeat = 4,
.preset = FuriHalSubGhzPresetOok650Async,
.file = SMC5326FileProtocol};
/**
* SMC5326 24bit 433MHz
*/
const SubBruteProtocol subbrute_protocol_smc5326_24bit_433 = {
.frequency = 433920000,
.bits = 25,
.te = 320,
.repeat = 4,
.preset = FuriHalSubGhzPresetOok650Async,
.file = SMC5326FileProtocol};
/**
* PT2260 (Princeton) 24bit 315MHz
*/
const SubBruteProtocol subbrute_protocol_pt2260_24bit_315 = {
.frequency = 315000000,
.bits = 24,
.te = 286,
.repeat = 4,
.preset = FuriHalSubGhzPresetOok650Async,
.file = PT2260FileProtocol};
/**
* PT2260 (Princeton) 24bit 330MHz
*/
const SubBruteProtocol subbrute_protocol_pt2260_24bit_330 = {
.frequency = 330000000,
.bits = 24,
.te = 286,
.repeat = 4,
.preset = FuriHalSubGhzPresetOok650Async,
.file = PT2260FileProtocol};
/**
* PT2260 (Princeton) 24bit 390MHz
*/
const SubBruteProtocol subbrute_protocol_pt2260_24bit_390 = {
.frequency = 390000000,
.bits = 24,
.te = 286,
.repeat = 4,
.preset = FuriHalSubGhzPresetOok650Async,
.file = PT2260FileProtocol};
/**
* PT2260 (Princeton) 24bit 433MHz
*/
const SubBruteProtocol subbrute_protocol_pt2260_24bit_433 = {
.frequency = 433920000,
.bits = 24,
.te = 286,
.repeat = 4,
.preset = FuriHalSubGhzPresetOok650Async,
.file = PT2260FileProtocol};
/**
* Holtek FM 12bit 433MHz
*/
const SubBruteProtocol subbrute_protocol_holtek_12bit_433 = {
.frequency = 433920000,
.bits = 12,
.te = 204,
.repeat = 4,
.preset = FuriHalSubGhzPreset2FSKDev476Async,
.file = HoltekFileProtocol};
/**
* Holtek AM 12bit 433MHz
*/
const SubBruteProtocol subbrute_protocol_holtek_12bit_am_433 = {
.frequency = 433920000,
.bits = 12,
.te = 433,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = HoltekFileProtocol};
/**
* Holtek AM 12bit 315MHz
*/
const SubBruteProtocol subbrute_protocol_holtek_12bit_am_315 = {
.frequency = 315000000,
.bits = 12,
.te = 433,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = HoltekFileProtocol};
/**
* Holtek AM 12bit 868MHz
*/
const SubBruteProtocol subbrute_protocol_holtek_12bit_am_868 = {
.frequency = 868350000,
.bits = 12,
.te = 433,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = HoltekFileProtocol};
/**
* Holtek AM 12bit 915MHz
*/
const SubBruteProtocol subbrute_protocol_holtek_12bit_am_915 = {
.frequency = 915000000,
.bits = 12,
.te = 433,
.repeat = 3,
.preset = FuriHalSubGhzPresetOok650Async,
.file = HoltekFileProtocol};
/**
* BF existing dump
*/
const SubBruteProtocol subbrute_protocol_load_file =
{0, 0, 0, 3, FuriHalSubGhzPresetOok650Async, UnknownFileProtocol};
static const char* subbrute_protocol_names[] = {
[SubBruteAttackCAME12bit303] = "CAME 12bit 303MHz",
[SubBruteAttackCAME12bit307] = "CAME 12bit 307MHz",
[SubBruteAttackCAME12bit315] = "CAME 12bit 315MHz",
[SubBruteAttackCAME12bit433] = "CAME 12bit 433MHz",
[SubBruteAttackCAME12bit868] = "CAME 12bit 868MHz",
[SubBruteAttackNICE12bit433] = "NICE 12bit 433MHz",
[SubBruteAttackNICE12bit868] = "NICE 12bit 868MHz",
[SubBruteAttackAnsonic12bit433075] = "Ansonic 12bit 433.07MHz",
[SubBruteAttackAnsonic12bit433] = "Ansonic 12bit 433.92MHz",
[SubBruteAttackAnsonic12bit434] = "Ansonic 12bit 434.07MHz",
[SubBruteAttackHoltek12bitFM433] = "Holtek FM 12bit 433MHz",
[SubBruteAttackHoltek12bitAM433] = "Holtek AM 12bit 433MHz",
[SubBruteAttackHoltek12bitAM315] = "Holtek AM 12bit 315MHz",
[SubBruteAttackHoltek12bitAM868] = "Holtek AM 12bit 868MHz",
[SubBruteAttackHoltek12bitAM915] = "Holtek AM 12bit 915MHz",
[SubBruteAttackChamberlain9bit300] = "Chamberlain 9bit 300MHz",
[SubBruteAttackChamberlain9bit315] = "Chamberlain 9bit 315MHz",
[SubBruteAttackChamberlain9bit390] = "Chamberlain 9bit 390MHz",
[SubBruteAttackChamberlain9bit433] = "Chamberlain 9bit 433MHz",
[SubBruteAttackChamberlain8bit300] = "Chamberlain 8bit 300MHz",
[SubBruteAttackChamberlain8bit315] = "Chamberlain 8bit 315MHz",
[SubBruteAttackChamberlain8bit390] = "Chamberlain 8bit 390MHz",
[SubBruteAttackChamberlain7bit300] = "Chamberlain 7bit 300MHz",
[SubBruteAttackChamberlain7bit315] = "Chamberlain 7bit 315MHz",
[SubBruteAttackChamberlain7bit390] = "Chamberlain 7bit 390MHz",
[SubBruteAttackLinear10bit300] = "Linear 10bit 300MHz",
[SubBruteAttackLinear10bit310] = "Linear 10bit 310MHz",
[SubBruteAttackLinearDelta8bit310] = "LinearDelta3 8bit 310MHz",
[SubBruteAttackUNILARM24bit330] = "UNILARM 25bit 330MHz",
[SubBruteAttackUNILARM24bit433] = "UNILARM 25bit 433MHz",
[SubBruteAttackSMC532624bit330] = "SMC5326 25bit 330MHz",
[SubBruteAttackSMC532624bit433] = "SMC5326 25bit 433MHz",
[SubBruteAttackPT226024bit315] = "PT2260 24bit 315MHz",
[SubBruteAttackPT226024bit330] = "PT2260 24bit 330MHz",
[SubBruteAttackPT226024bit390] = "PT2260 24bit 390MHz",
[SubBruteAttackPT226024bit433] = "PT2260 24bit 433MHz",
[SubBruteAttackLoadFile] = "BF existing dump",
[SubBruteAttackTotalCount] = "Total Count",
};
static const char* subbrute_protocol_presets[] = {
[FuriHalSubGhzPresetIDLE] = "FuriHalSubGhzPresetIDLE",
[FuriHalSubGhzPresetOok270Async] = "FuriHalSubGhzPresetOok270Async",
[FuriHalSubGhzPresetOok650Async] = "FuriHalSubGhzPresetOok650Async",
[FuriHalSubGhzPreset2FSKDev238Async] = "FuriHalSubGhzPreset2FSKDev238Async",
[FuriHalSubGhzPreset2FSKDev476Async] = "FuriHalSubGhzPreset2FSKDev476Async",
[FuriHalSubGhzPresetMSK99_97KbAsync] = "FuriHalSubGhzPresetMSK99_97KbAsync",
[FuriHalSubGhzPresetGFSK9_99KbAsync] = "FuriHalSubGhzPresetGFSK9_99KbAsync",
};
const SubBruteProtocol* subbrute_protocol_registry[] = {
[SubBruteAttackCAME12bit303] = &subbrute_protocol_came_12bit_303,
[SubBruteAttackCAME12bit307] = &subbrute_protocol_came_12bit_307,
[SubBruteAttackCAME12bit315] = &subbrute_protocol_came_12bit_315,
[SubBruteAttackCAME12bit433] = &subbrute_protocol_came_12bit_433,
[SubBruteAttackCAME12bit868] = &subbrute_protocol_came_12bit_868,
[SubBruteAttackNICE12bit433] = &subbrute_protocol_nice_12bit_433,
[SubBruteAttackNICE12bit868] = &subbrute_protocol_nice_12bit_868,
[SubBruteAttackAnsonic12bit433075] = &subbrute_protocol_ansonic_12bit_433075,
[SubBruteAttackAnsonic12bit433] = &subbrute_protocol_ansonic_12bit_433,
[SubBruteAttackAnsonic12bit434] = &subbrute_protocol_ansonic_12bit_434,
[SubBruteAttackHoltek12bitFM433] = &subbrute_protocol_holtek_12bit_433,
[SubBruteAttackHoltek12bitAM433] = &subbrute_protocol_holtek_12bit_am_433,
[SubBruteAttackHoltek12bitAM315] = &subbrute_protocol_holtek_12bit_am_315,
[SubBruteAttackHoltek12bitAM868] = &subbrute_protocol_holtek_12bit_am_868,
[SubBruteAttackHoltek12bitAM915] = &subbrute_protocol_holtek_12bit_am_915,
[SubBruteAttackChamberlain9bit300] = &subbrute_protocol_chamberlain_9bit_300,
[SubBruteAttackChamberlain9bit315] = &subbrute_protocol_chamberlain_9bit_315,
[SubBruteAttackChamberlain9bit390] = &subbrute_protocol_chamberlain_9bit_390,
[SubBruteAttackChamberlain9bit433] = &subbrute_protocol_chamberlain_9bit_433,
[SubBruteAttackChamberlain8bit300] = &subbrute_protocol_chamberlain_8bit_300,
[SubBruteAttackChamberlain8bit315] = &subbrute_protocol_chamberlain_8bit_315,
[SubBruteAttackChamberlain8bit390] = &subbrute_protocol_chamberlain_8bit_390,
[SubBruteAttackChamberlain7bit300] = &subbrute_protocol_chamberlain_7bit_300,
[SubBruteAttackChamberlain7bit315] = &subbrute_protocol_chamberlain_7bit_315,
[SubBruteAttackChamberlain7bit390] = &subbrute_protocol_chamberlain_7bit_390,
[SubBruteAttackLinear10bit300] = &subbrute_protocol_linear_10bit_300,
[SubBruteAttackLinear10bit310] = &subbrute_protocol_linear_10bit_310,
[SubBruteAttackLinearDelta8bit310] = &subbrute_protocol_linear_delta_8bit_310,
[SubBruteAttackUNILARM24bit330] = &subbrute_protocol_unilarm_24bit_330,
[SubBruteAttackUNILARM24bit433] = &subbrute_protocol_unilarm_24bit_433,
[SubBruteAttackSMC532624bit330] = &subbrute_protocol_smc5326_24bit_330,
[SubBruteAttackSMC532624bit433] = &subbrute_protocol_smc5326_24bit_433,
[SubBruteAttackPT226024bit315] = &subbrute_protocol_pt2260_24bit_315,
[SubBruteAttackPT226024bit330] = &subbrute_protocol_pt2260_24bit_330,
[SubBruteAttackPT226024bit390] = &subbrute_protocol_pt2260_24bit_390,
[SubBruteAttackPT226024bit433] = &subbrute_protocol_pt2260_24bit_433,
[SubBruteAttackLoadFile] = &subbrute_protocol_load_file};
static const char* subbrute_protocol_file_types[] = {
[CAMEFileProtocol] = "CAME",
[NICEFileProtocol] = "Nice FLO",
[ChamberlainFileProtocol] = "Cham_Code",
[LinearFileProtocol] = "Linear",
[LinearDeltaFileProtocol] = "LinearDelta3",
[PrincetonFileProtocol] = "Princeton",
[RAWFileProtocol] = "RAW",
[BETTFileProtocol] = "BETT",
[ClemsaFileProtocol] = "Clemsa",
[DoitrandFileProtocol] = "Doitrand",
[GateTXFileProtocol] = "GateTX",
[MagellanFileProtocol] = "Magellan",
[IntertechnoV3FileProtocol] = "Intertechno_V3",
[AnsonicFileProtocol] = "Ansonic",
[SMC5326FileProtocol] = "SMC5326",
[UNILARMFileProtocol] = "SMC5326",
[PT2260FileProtocol] = "Princeton",
[HoneywellFileProtocol] = "Honeywell",
[HoltekFileProtocol] = "Holtek_HT12X",
[UnknownFileProtocol] = "Unknown"};
/**
* 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\n";
//static const char* subbrute_key_small_raw =
// "Filetype: Flipper SubGhz Key File\nVersion: 1\nFrequency: %u\nPreset: %s\nProtocol: %s\nBit: %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];
}
const SubBruteProtocol* subbrute_protocol(SubBruteAttacks index) {
return subbrute_protocol_registry[index];
}
uint8_t subbrute_protocol_repeats_count(SubBruteAttacks index) {
return subbrute_protocol_registry[index]->repeat;
}
const char* subbrute_protocol_preset(FuriHalSubGhzPreset preset) {
return subbrute_protocol_presets[preset];
}
const char* subbrute_protocol_file(SubBruteFileProtocol protocol) {
return subbrute_protocol_file_types[protocol];
}
FuriHalSubGhzPreset subbrute_protocol_convert_preset(FuriString* preset_name) {
for(size_t i = FuriHalSubGhzPresetIDLE; i < FuriHalSubGhzPresetCustom; i++) {
if(furi_string_cmp_str(preset_name, subbrute_protocol_presets[i]) == 0) {
return i;
}
}
return FuriHalSubGhzPresetIDLE;
}
SubBruteFileProtocol subbrute_protocol_file_protocol_name(FuriString* name) {
for(size_t i = CAMEFileProtocol; i < TotalFileProtocol - 1; i++) {
if(furi_string_cmp_str(name, subbrute_protocol_file_types[i]) == 0) {
return i;
}
}
return UnknownFileProtocol;
}
void subbrute_protocol_create_candidate_for_existing_file(
FuriString* candidate,
uint64_t step,
uint8_t bit_index,
uint64_t file_key,
bool two_bytes) {
uint8_t p[8];
for(int i = 0; i < 8; i++) {
p[i] = (uint8_t)(file_key >> 8 * (7 - i)) & 0xFF;
}
uint8_t low_byte = step & (0xff);
uint8_t high_byte = (step >> 8) & 0xff;
size_t size = sizeof(uint64_t);
for(uint8_t i = 0; i < size; i++) {
if(i == bit_index - 1 && two_bytes) {
furi_string_cat_printf(candidate, "%02X %02X", high_byte, low_byte);
i++;
} else if(i == bit_index) {
furi_string_cat_printf(candidate, "%02X", low_byte);
} else if(p[i] != 0) {
furi_string_cat_printf(candidate, "%02X", p[i]);
} else {
furi_string_cat_printf(candidate, "%s", "00");
}
if(i < size - 1) {
furi_string_push_back(candidate, ' ');
}
}
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "file candidate: %s, step: %lld", furi_string_get_cstr(candidate), step);
#endif
}
void subbrute_protocol_create_candidate_for_default(
FuriString* candidate,
SubBruteFileProtocol file,
uint64_t step) {
uint8_t p[8];
if(file == SMC5326FileProtocol) {
const uint8_t lut[] = {0x00, 0x02, 0x03}; // 00, 10, 11
const uint64_t gate1 = 0x01D5; // 111010101
//const uint8_t gate2 = 0x0175; // 101110101
uint64_t total = 0;
for(size_t j = 0; j < 8; j++) {
total |= lut[step % 3] << (2 * j);
double sub_step = step / 3;
step = (uint64_t)floor(sub_step);
}
total <<= 9;
total |= gate1;
for(int i = 0; i < 8; i++) {
p[i] = (uint8_t)(total >> 8 * (7 - i)) & 0xFF;
}
} else if(file == UNILARMFileProtocol) {
const uint8_t lut[] = {0x00, 0x02, 0x03}; // 00, 10, 11
const uint64_t gate1 = 3 << 7;
//const uint8_t gate2 = 3 << 5;
uint64_t total = 0;
for(size_t j = 0; j < 8; j++) {
total |= lut[step % 3] << (2 * j);
double sub_step = step / 3;
step = (uint64_t)floor(sub_step);
}
total <<= 9;
total |= gate1;
for(int i = 0; i < 8; i++) {
p[i] = (uint8_t)(total >> 8 * (7 - i)) & 0xFF;
}
} else if(file == PT2260FileProtocol) {
const uint8_t lut[] = {0x00, 0x01, 0x03}; // 00, 01, 11
const uint64_t button_open = 0x03; // 11
//const uint8_t button_lock = 0x0C; // 1100
//const uint8_t button_stop = 0x30; // 110000
//const uint8_t button_close = 0xC0; // 11000000
uint64_t total = 0;
for(size_t j = 0; j < 8; j++) {
total |= lut[step % 3] << (2 * j);
double sub_step = step / 3;
step = (uint64_t)floor(sub_step);
}
total <<= 8;
total |= button_open;
for(int i = 0; i < 8; i++) {
p[i] = (uint8_t)(total >> 8 * (7 - i)) & 0xFF;
}
} else {
for(int i = 0; i < 8; i++) {
p[i] = (uint8_t)(step >> 8 * (7 - i)) & 0xFF;
}
}
size_t size = sizeof(uint64_t);
for(uint8_t i = 0; i < size; i++) {
if(p[i] != 0) {
furi_string_cat_printf(candidate, "%02X", p[i]);
} else {
furi_string_cat_printf(candidate, "%s", "00");
}
if(i < size - 1) {
furi_string_push_back(candidate, ' ');
}
}
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "candidate: %s, step: %lld", furi_string_get_cstr(candidate), step);
#endif
}
void subbrute_protocol_default_payload(
Stream* stream,
SubBruteFileProtocol file,
uint64_t step,
uint8_t bits,
uint32_t te,
uint8_t repeat) {
FuriString* candidate = furi_string_alloc();
subbrute_protocol_create_candidate_for_default(candidate, file, step);
#ifdef FURI_DEBUG
FURI_LOG_D(
TAG,
"candidate: %s, step: %lld, repeat: %d, te: %s",
furi_string_get_cstr(candidate),
step,
repeat,
te ? "true" : "false");
#endif
stream_clean(stream);
if(te) {
stream_write_format(
stream,
subbrute_key_small_with_tail,
bits,
furi_string_get_cstr(candidate),
te,
repeat);
} else {
stream_write_format(
stream, subbrute_key_small_no_tail, bits, furi_string_get_cstr(candidate), repeat);
}
furi_string_free(candidate);
}
void subbrute_protocol_file_payload(
Stream* stream,
uint64_t step,
uint8_t bits,
uint32_t te,
uint8_t repeat,
uint8_t bit_index,
uint64_t file_key,
bool two_bytes) {
FuriString* candidate = furi_string_alloc();
subbrute_protocol_create_candidate_for_existing_file(
candidate, step, bit_index, file_key, two_bytes);
#ifdef FURI_DEBUG
FURI_LOG_D(
TAG,
"candidate: %s, step: %lld, repeat: %d, te: %s",
furi_string_get_cstr(candidate),
step,
repeat,
te ? "true" : "false");
#endif
stream_clean(stream);
if(te) {
stream_write_format(
stream,
subbrute_key_small_with_tail,
bits,
furi_string_get_cstr(candidate),
te,
repeat);
} else {
stream_write_format(
stream, subbrute_key_small_no_tail, bits, furi_string_get_cstr(candidate), repeat);
}
furi_string_free(candidate);
}
void subbrute_protocol_default_generate_file(
Stream* stream,
uint32_t frequency,
FuriHalSubGhzPreset preset,
SubBruteFileProtocol file,
uint64_t step,
uint8_t bits,
uint32_t te,
uint8_t repeat) {
FuriString* candidate = furi_string_alloc();
subbrute_protocol_create_candidate_for_default(candidate, file, step);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "candidate: %s, step: %lld", furi_string_get_cstr(candidate), step);
#endif
stream_clean(stream);
if(te) {
stream_write_format(
stream,
subbrute_key_file_start_with_tail,
frequency,
subbrute_protocol_preset(preset),
subbrute_protocol_file(file),
bits,
furi_string_get_cstr(candidate),
te,
repeat);
} else {
stream_write_format(
stream,
subbrute_key_file_start_no_tail,
frequency,
subbrute_protocol_preset(preset),
subbrute_protocol_file(file),
bits,
furi_string_get_cstr(candidate),
repeat);
}
furi_string_free(candidate);
}
void subbrute_protocol_file_generate_file(
Stream* stream,
uint32_t frequency,
FuriHalSubGhzPreset preset,
SubBruteFileProtocol file,
uint64_t step,
uint8_t bits,
uint32_t te,
uint8_t repeat,
uint8_t bit_index,
uint64_t file_key,
bool two_bytes) {
FuriString* candidate = furi_string_alloc();
// char subbrute_payload_byte[8];
//furi_string_set_str(candidate, file_key);
subbrute_protocol_create_candidate_for_existing_file(
candidate, step, bit_index, file_key, two_bytes);
stream_clean(stream);
if(te) {
stream_write_format(
stream,
subbrute_key_file_start_with_tail,
frequency,
subbrute_protocol_preset(preset),
subbrute_protocol_file(file),
bits,
furi_string_get_cstr(candidate),
te,
repeat);
} else {
stream_write_format(
stream,
subbrute_key_file_start_no_tail,
frequency,
subbrute_protocol_preset(preset),
subbrute_protocol_file(file),
bits,
furi_string_get_cstr(candidate),
repeat);
}
furi_string_free(candidate);
}
uint64_t
subbrute_protocol_calc_max_value(SubBruteAttacks attack_type, uint8_t bits, bool two_bytes) {
uint64_t max_value;
if(attack_type == SubBruteAttackLoadFile) {
max_value = two_bytes ? 0xFFFF : 0xFF;
} else if(
attack_type == SubBruteAttackSMC532624bit330 ||
attack_type == SubBruteAttackSMC532624bit433 ||
attack_type == SubBruteAttackUNILARM24bit330 ||
attack_type == SubBruteAttackUNILARM24bit433 ||
attack_type == SubBruteAttackPT226024bit315 ||
attack_type == SubBruteAttackPT226024bit330 ||
attack_type == SubBruteAttackPT226024bit390 ||
attack_type == SubBruteAttackPT226024bit433) {
max_value = 6561;
} 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

@@ -0,0 +1,128 @@
#pragma once
#include <furi.h>
#include <furi_hal_subghz.h>
#include <core/string.h>
#include <toolbox/stream/stream.h>
typedef enum {
CAMEFileProtocol,
NICEFileProtocol,
ChamberlainFileProtocol,
LinearFileProtocol,
LinearDeltaFileProtocol,
PrincetonFileProtocol,
RAWFileProtocol,
BETTFileProtocol,
ClemsaFileProtocol,
DoitrandFileProtocol,
GateTXFileProtocol,
MagellanFileProtocol,
IntertechnoV3FileProtocol,
AnsonicFileProtocol,
SMC5326FileProtocol,
UNILARMFileProtocol,
PT2260FileProtocol,
HoneywellFileProtocol,
HoltekFileProtocol,
UnknownFileProtocol,
TotalFileProtocol,
} SubBruteFileProtocol;
typedef enum {
SubBruteAttackCAME12bit303,
SubBruteAttackCAME12bit307,
SubBruteAttackCAME12bit315,
SubBruteAttackCAME12bit433,
SubBruteAttackCAME12bit868,
SubBruteAttackNICE12bit433,
SubBruteAttackNICE12bit868,
SubBruteAttackAnsonic12bit433075,
SubBruteAttackAnsonic12bit433,
SubBruteAttackAnsonic12bit434,
SubBruteAttackHoltek12bitFM433,
SubBruteAttackHoltek12bitAM433,
SubBruteAttackHoltek12bitAM315,
SubBruteAttackHoltek12bitAM868,
SubBruteAttackHoltek12bitAM915,
SubBruteAttackChamberlain9bit300,
SubBruteAttackChamberlain9bit315,
SubBruteAttackChamberlain9bit390,
SubBruteAttackChamberlain9bit433,
SubBruteAttackChamberlain8bit300,
SubBruteAttackChamberlain8bit315,
SubBruteAttackChamberlain8bit390,
SubBruteAttackChamberlain7bit300,
SubBruteAttackChamberlain7bit315,
SubBruteAttackChamberlain7bit390,
SubBruteAttackLinear10bit300,
SubBruteAttackLinear10bit310,
SubBruteAttackLinearDelta8bit310,
SubBruteAttackUNILARM24bit330,
SubBruteAttackUNILARM24bit433,
SubBruteAttackSMC532624bit330,
SubBruteAttackSMC532624bit433,
SubBruteAttackPT226024bit315,
SubBruteAttackPT226024bit330,
SubBruteAttackPT226024bit390,
SubBruteAttackPT226024bit433,
SubBruteAttackLoadFile,
SubBruteAttackTotalCount,
} SubBruteAttacks;
typedef struct {
uint32_t frequency;
uint8_t bits;
uint32_t te;
uint8_t repeat;
FuriHalSubGhzPreset preset;
SubBruteFileProtocol file;
} SubBruteProtocol;
const SubBruteProtocol* subbrute_protocol(SubBruteAttacks index);
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);
uint8_t subbrute_protocol_repeats_count(SubBruteAttacks index);
const char* subbrute_protocol_name(SubBruteAttacks index);
void subbrute_protocol_default_payload(
Stream* stream,
SubBruteFileProtocol file,
uint64_t step,
uint8_t bits,
uint32_t te,
uint8_t repeat);
void subbrute_protocol_file_payload(
Stream* stream,
uint64_t step,
uint8_t bits,
uint32_t te,
uint8_t repeat,
uint8_t bit_index,
uint64_t file_key,
bool two_bytes);
void subbrute_protocol_default_generate_file(
Stream* stream,
uint32_t frequency,
FuriHalSubGhzPreset preset,
SubBruteFileProtocol file,
uint64_t step,
uint8_t bits,
uint32_t te,
uint8_t repeat);
void subbrute_protocol_file_generate_file(
Stream* stream,
uint32_t frequency,
FuriHalSubGhzPreset preset,
SubBruteFileProtocol file,
uint64_t step,
uint8_t bits,
uint32_t te,
uint8_t repeat,
uint8_t bit_index,
uint64_t file_key,
bool two_bytes);
uint64_t
subbrute_protocol_calc_max_value(SubBruteAttacks attack_type, uint8_t bits, bool two_bytes);

View File

@@ -0,0 +1,341 @@
#include "subbrute_attack_view.h"
#include "../subbrute_i.h"
#include "../subbrute_protocols.h"
#include "../helpers/gui_top_buttons.h"
#include <input/input.h>
#include <gui/elements.h>
#include <gui/icon.h>
#include <gui/icon_animation.h>
#include <assets_icons.h>
#define TAG "SubBruteAttackView"
struct SubBruteAttackView {
View* view;
SubBruteAttackViewCallback callback;
void* context;
SubBruteAttacks attack_type;
uint64_t max_value;
uint64_t current_step;
bool is_attacking;
uint8_t extra_repeats;
};
typedef struct {
SubBruteAttacks attack_type;
uint64_t max_value;
uint64_t current_step;
uint8_t extra_repeats;
bool is_attacking;
IconAnimation* icon;
} SubBruteAttackViewModel;
void subbrute_attack_view_set_callback(
SubBruteAttackView* instance,
SubBruteAttackViewCallback callback,
void* context) {
furi_assert(instance);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
}
bool subbrute_attack_view_input(InputEvent* event, void* context) {
furi_assert(event);
furi_assert(context);
SubBruteAttackView* instance = context;
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "InputKey: %d", event->key);
#endif
if(event->key == InputKeyBack && event->type == InputTypeShort) {
instance->is_attacking = false;
with_view_model(
instance->view,
SubBruteAttackViewModel * model,
{ model->is_attacking = false; },
true);
instance->callback(SubBruteCustomEventTypeBackPressed, instance->context);
return true;
}
bool update = false;
if(!instance->is_attacking) {
if(event->type == InputTypeShort && event->key == InputKeyOk) {
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "InputKey: %d OK", event->key);
#endif
instance->is_attacking = true;
instance->callback(SubBruteCustomEventTypeTransmitStarted, instance->context);
update = true;
} else if(event->key == InputKeyUp) {
instance->callback(SubBruteCustomEventTypeSaveFile, instance->context);
update = true;
} else if(event->key == InputKeyDown) {
instance->callback(SubBruteCustomEventTypeTransmitCustom, instance->context);
update = true;
} else if(event->type == InputTypeShort) {
if(event->key == InputKeyLeft) {
instance->callback(SubBruteCustomEventTypeChangeStepDown, instance->context);
} else if(event->key == InputKeyRight) {
instance->callback(SubBruteCustomEventTypeChangeStepUp, instance->context);
}
update = true;
} else if(event->type == InputTypeRepeat) {
if(event->key == InputKeyLeft) {
instance->callback(SubBruteCustomEventTypeChangeStepDownMore, instance->context);
} else if(event->key == InputKeyRight) {
instance->callback(SubBruteCustomEventTypeChangeStepUpMore, instance->context);
}
update = true;
}
} else {
// ATTACK Mode!
if((event->type == InputTypeShort || event->type == InputTypeRepeat) &&
(event->key == InputKeyOk || event->key == InputKeyBack)) {
instance->is_attacking = false;
instance->callback(SubBruteCustomEventTypeTransmitNotStarted, instance->context);
update = true;
}
}
if(update) {
with_view_model(
instance->view,
SubBruteAttackViewModel * model,
{
if(model->is_attacking != instance->is_attacking) {
if(instance->is_attacking) {
icon_animation_stop(model->icon);
icon_animation_start(model->icon);
} else {
icon_animation_stop(model->icon);
}
}
model->attack_type = instance->attack_type;
model->max_value = instance->max_value;
model->current_step = instance->current_step;
model->is_attacking = instance->is_attacking;
},
true);
}
return true;
}
SubBruteAttackView* subbrute_attack_view_alloc() {
SubBruteAttackView* instance = malloc(sizeof(SubBruteAttackView));
instance->view = view_alloc();
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubBruteAttackViewModel));
view_set_context(instance->view, instance);
with_view_model(
instance->view,
SubBruteAttackViewModel * model,
{
model->icon = icon_animation_alloc(&A_Sub1ghz_14);
view_tie_icon_animation(instance->view, model->icon);
},
true);
view_set_draw_callback(instance->view, (ViewDrawCallback)subbrute_attack_view_draw);
view_set_input_callback(instance->view, subbrute_attack_view_input);
view_set_enter_callback(instance->view, subbrute_attack_view_enter);
view_set_exit_callback(instance->view, subbrute_attack_view_exit);
instance->attack_type = SubBruteAttackTotalCount;
instance->max_value = 0x00;
instance->current_step = 0;
instance->is_attacking = false;
return instance;
}
void subbrute_attack_view_enter(void* context) {
furi_assert(context);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_attack_view_enter");
#endif
}
void subbrute_attack_view_free(SubBruteAttackView* instance) {
furi_assert(instance);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_attack_view_free");
#endif
with_view_model(
instance->view,
SubBruteAttackViewModel * model,
{ icon_animation_free(model->icon); },
false);
view_free(instance->view);
free(instance);
}
View* subbrute_attack_view_get_view(SubBruteAttackView* instance) {
furi_assert(instance);
return instance->view;
}
void subbrute_attack_view_set_current_step(SubBruteAttackView* instance, uint64_t current_step) {
furi_assert(instance);
#ifdef FURI_DEBUG
//FURI_LOG_D(TAG, "Set step: %d", current_step);
#endif
instance->current_step = current_step;
with_view_model(
instance->view,
SubBruteAttackViewModel * model,
{ model->current_step = current_step; },
true);
}
// We need to call init every time, because not every time we calls enter
// normally, call enter only once
void subbrute_attack_view_init_values(
SubBruteAttackView* instance,
uint8_t index,
uint64_t max_value,
uint64_t current_step,
bool is_attacking,
uint8_t extra_repeats) {
#ifdef FURI_DEBUG
FURI_LOG_I(
TAG,
"INIT, attack_type: %d, max_value: %lld, current_step: %lld, extra_repeats: %d",
index,
max_value,
current_step,
extra_repeats);
#endif
instance->attack_type = index;
instance->max_value = max_value;
instance->current_step = current_step;
instance->is_attacking = is_attacking;
instance->extra_repeats = extra_repeats;
with_view_model(
instance->view,
SubBruteAttackViewModel * model,
{
model->max_value = max_value;
model->attack_type = index;
model->current_step = current_step;
model->is_attacking = is_attacking;
model->extra_repeats = extra_repeats;
if(is_attacking) {
icon_animation_start(model->icon);
} else {
icon_animation_stop(model->icon);
}
},
true);
}
void subbrute_attack_view_exit(void* context) {
furi_assert(context);
SubBruteAttackView* instance = context;
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_attack_view_exit");
#endif
with_view_model(
instance->view,
SubBruteAttackViewModel * model,
{ icon_animation_stop(model->icon); },
false);
}
void subbrute_attack_view_draw(Canvas* canvas, void* context) {
furi_assert(context);
SubBruteAttackViewModel* model = (SubBruteAttackViewModel*)context;
char buffer[64];
const char* attack_name = NULL;
attack_name = subbrute_protocol_name(model->attack_type);
// Title
if(model->is_attacking) {
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, attack_name);
}
// Current Step / Max value
const uint8_t y_frequency = 17;
if(model->max_value > 9999) {
canvas_set_font(canvas, FontBigNumbers);
snprintf(buffer, sizeof(buffer), "%05d/", (int)model->current_step);
canvas_draw_str_aligned(canvas, 5, y_frequency, AlignLeft, AlignTop, buffer);
// Second part with another font, because BigNumber is out of screen bounds
canvas_set_font(canvas, FontPrimary);
snprintf(buffer, sizeof(buffer), "%05d", (int)model->max_value);
canvas_draw_str_aligned(canvas, 107, y_frequency + 13, AlignRight, AlignBottom, buffer);
} else if(model->max_value <= 0xFF) {
canvas_set_font(canvas, FontBigNumbers);
snprintf(
buffer, sizeof(buffer), "%03d/%03d", (int)model->current_step, (int)model->max_value);
canvas_draw_str_aligned(canvas, 64, y_frequency, AlignCenter, AlignTop, buffer);
} else {
canvas_set_font(canvas, FontBigNumbers);
snprintf(
buffer, sizeof(buffer), "%04d/%04d", (int)model->current_step, (int)model->max_value);
canvas_draw_str_aligned(canvas, 64, y_frequency, AlignCenter, AlignTop, buffer);
}
canvas_set_font(canvas, FontSecondary);
memset(buffer, 0, sizeof(buffer));
if(!model->is_attacking) {
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(canvas, 64, 44, AlignCenter, AlignBottom, attack_name);
snprintf(
buffer,
sizeof(buffer),
"x%d",
model->extra_repeats + subbrute_protocol_repeats_count(model->attack_type));
canvas_draw_str_aligned(canvas, 60, 6, AlignCenter, AlignCenter, buffer);
elements_button_left(canvas, "-1");
elements_button_right(canvas, "+1");
elements_button_center(canvas, "Start");
elements_button_top_left(canvas, "Save");
elements_button_top_right(canvas, "Resend");
} else {
// canvas_draw_icon_animation
const uint8_t icon_h_offset = 0;
const uint8_t icon_width_with_offset =
icon_animation_get_width(model->icon) + icon_h_offset;
const uint8_t icon_v_offset = icon_animation_get_height(model->icon); // + vertical_offset;
const uint8_t x = canvas_width(canvas);
const uint8_t y = canvas_height(canvas);
canvas_draw_icon_animation(
canvas, x - icon_width_with_offset, y - icon_v_offset, model->icon);
// Progress bar
// Resolution: 128x64 px
float progress_value = (float)model->current_step / model->max_value;
elements_progress_bar(canvas, 8, 37, 110, progress_value > 1 ? 1 : progress_value);
snprintf(
buffer,
sizeof(buffer),
"x%d",
model->extra_repeats + subbrute_protocol_repeats_count(model->attack_type));
canvas_draw_str(canvas, 4, y - 8, buffer);
canvas_draw_str(canvas, 4, y - 1, "repeats");
elements_button_center(canvas, "Stop");
}
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include "../subbrute_custom_event.h"
#include <gui/view.h>
#include <input/input.h>
#include <gui/elements.h>
typedef void (*SubBruteAttackViewCallback)(SubBruteCustomEvent event, void* context);
typedef struct SubBruteAttackView SubBruteAttackView;
void subbrute_attack_view_set_callback(
SubBruteAttackView* instance,
SubBruteAttackViewCallback callback,
void* context);
SubBruteAttackView* subbrute_attack_view_alloc();
void subbrute_attack_view_free(SubBruteAttackView* instance);
View* subbrute_attack_view_get_view(SubBruteAttackView* instance);
void subbrute_attack_view_set_current_step(SubBruteAttackView* instance, uint64_t current_step);
void subbrute_attack_view_init_values(
SubBruteAttackView* instance,
uint8_t index,
uint64_t max_value,
uint64_t current_step,
bool is_attacking,
uint8_t extra_repeats);

View File

@@ -0,0 +1,463 @@
#include "subbrute_main_view.h"
#include "../subbrute_i.h"
#include "../subbrute_protocols.h"
#include "../helpers/gui_top_buttons.h"
#include <input/input.h>
#include <gui/elements.h>
#include <gui/icon.h>
#define STATUS_BAR_Y_SHIFT 14
#define TAG "SubBruteMainView"
#define ITEMS_ON_SCREEN 3
#define ITEMS_INTERVAL 1
#define ITEM_WIDTH 14
#define ITEM_Y 27
#define ITEM_HEIGHT 13
#define TEXT_X 6
#define TEXT_Y 37
#define TEXT_INTERVAL 3
#define TEXT_WIDTH 12
#define ITEM_FRAME_RADIUS 2
struct SubBruteMainView {
View* view;
SubBruteMainViewCallback callback;
void* context;
uint8_t index;
bool is_select_byte;
bool two_bytes;
uint64_t key_from_file;
uint8_t extra_repeats;
uint8_t window_position;
};
typedef struct {
uint8_t index;
uint8_t extra_repeats;
uint8_t window_position;
bool is_select_byte;
bool two_bytes;
uint64_t key_from_file;
} SubBruteMainViewModel;
void subbrute_main_view_set_callback(
SubBruteMainView* instance,
SubBruteMainViewCallback callback,
void* context) {
furi_assert(instance);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
}
void subbrute_main_view_center_displayed_key(
Canvas* canvas,
uint64_t key,
uint8_t index,
bool two_bytes) {
uint8_t text_x = TEXT_X;
uint8_t item_x = TEXT_X - ITEMS_INTERVAL;
canvas_set_font(canvas, FontSecondary);
for(int i = 0; i < 8; i++) {
char current_value[3] = {0};
uint8_t byte_value = (uint8_t)(key >> 8 * (7 - i)) & 0xFF;
snprintf(current_value, sizeof(current_value), "%02X", byte_value);
// For two bytes we need to select prev location
if(!two_bytes && i == index) {
canvas_set_color(canvas, ColorBlack);
canvas_draw_rbox(
canvas, item_x - 1, ITEM_Y, ITEM_WIDTH + 1, ITEM_HEIGHT, ITEM_FRAME_RADIUS);
canvas_set_color(canvas, ColorWhite);
canvas_draw_str(canvas, text_x, TEXT_Y, current_value);
} else if(two_bytes && (i == index || i == index - 1)) {
if(i == index) {
canvas_set_color(canvas, ColorBlack);
canvas_draw_rbox(
canvas,
item_x - ITEMS_INTERVAL - ITEM_WIDTH - 1,
ITEM_Y,
ITEM_WIDTH * 2 + ITEMS_INTERVAL * 2 + 1,
ITEM_HEIGHT,
ITEM_FRAME_RADIUS);
canvas_set_color(canvas, ColorWhite);
canvas_draw_str(canvas, text_x, TEXT_Y, current_value);
// Redraw prev element with white
memset(current_value, 0, sizeof(current_value));
byte_value = (uint8_t)(key >> 8 * (7 - i + 1)) & 0xFF;
snprintf(current_value, sizeof(current_value), "%02X", byte_value);
canvas_draw_str(
canvas, text_x - (TEXT_WIDTH + TEXT_INTERVAL), TEXT_Y, current_value);
} else {
canvas_set_color(canvas, ColorWhite);
canvas_draw_str(canvas, text_x, TEXT_Y, current_value);
}
} else {
canvas_set_color(canvas, ColorBlack);
canvas_draw_str(canvas, text_x, TEXT_Y, current_value);
}
text_x = text_x + TEXT_WIDTH + TEXT_INTERVAL;
item_x = item_x + ITEM_WIDTH + ITEMS_INTERVAL;
}
// Return normal color
canvas_set_color(canvas, ColorBlack);
}
void subbrute_main_view_draw(Canvas* canvas, SubBruteMainViewModel* model) {
uint16_t screen_width = canvas_width(canvas);
uint16_t screen_height = canvas_height(canvas);
if(model->is_select_byte) {
#ifdef FURI_DEBUG
//FURI_LOG_D(TAG, "key_from_file: %s", model->key_from_file);
#endif
//char msg_index[18];
//snprintf(msg_index, sizeof(msg_index), "Field index: %d", model->index);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas, 64, 17, AlignCenter, AlignTop, "Please select values to calc:");
subbrute_main_view_center_displayed_key(
canvas, model->key_from_file, model->index, model->two_bytes);
//const char* line = furi_string_get_cstr(menu_items);
//canvas_set_font(canvas, FontSecondary);
//canvas_draw_str_aligned(
// canvas, 64, 37, AlignCenter, AlignTop, furi_string_get_cstr(menu_items));
elements_button_center(canvas, "Select");
if(model->index > 0) {
elements_button_left(canvas, " ");
}
if(model->index < 7) {
elements_button_right(canvas, " ");
}
// Switch to another mode
if(model->two_bytes) {
elements_button_top_left(canvas, "One byte");
} else {
elements_button_top_left(canvas, "Two bytes");
}
} else {
// Title
canvas_set_font(canvas, FontPrimary);
canvas_draw_box(canvas, 0, 0, canvas_width(canvas), STATUS_BAR_Y_SHIFT);
canvas_invert_color(canvas);
canvas_draw_str_aligned(canvas, 64, 3, AlignCenter, AlignTop, SUBBRUTEFORCER_VER);
canvas_invert_color(canvas);
// Menu
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontSecondary);
const uint8_t item_height = 16;
#ifdef FURI_DEBUG
//FURI_LOG_D(TAG, "window_position: %d, index: %d", model->window_position, model->index);
#endif
for(uint8_t position = 0; position < SubBruteAttackTotalCount; ++position) {
uint8_t item_position = position - model->window_position;
if(item_position < ITEMS_ON_SCREEN) {
if(model->index == position) {
canvas_draw_str_aligned(
canvas,
4,
9 + (item_position * item_height) + STATUS_BAR_Y_SHIFT,
AlignLeft,
AlignCenter,
subbrute_protocol_name(position));
if(model->extra_repeats > 0) {
canvas_set_font(canvas, FontBatteryPercent);
char buffer[10];
snprintf(
buffer,
sizeof(buffer),
"x%d",
model->extra_repeats + subbrute_protocol_repeats_count(model->index));
canvas_draw_str_aligned(
canvas,
screen_width - 15,
9 + (item_position * item_height) + STATUS_BAR_Y_SHIFT,
AlignLeft,
AlignCenter,
buffer);
canvas_set_font(canvas, FontSecondary);
}
elements_frame(
canvas, 1, 1 + (item_position * item_height) + STATUS_BAR_Y_SHIFT, 124, 15);
} else {
canvas_draw_str_aligned(
canvas,
4,
9 + (item_position * item_height) + STATUS_BAR_Y_SHIFT,
AlignLeft,
AlignCenter,
subbrute_protocol_name(position));
}
}
}
elements_scrollbar_pos(
canvas,
screen_width,
STATUS_BAR_Y_SHIFT + 2,
screen_height - STATUS_BAR_Y_SHIFT,
model->index,
SubBruteAttackTotalCount);
}
}
bool subbrute_main_view_input(InputEvent* event, void* context) {
furi_assert(event);
furi_assert(context);
if(event->key == InputKeyBack && event->type == InputTypeShort) {
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "InputKey: BACK");
#endif
return false;
}
SubBruteMainView* instance = context;
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "InputKey: %d, extra_repeats: %d", event->key, instance->extra_repeats);
#endif
const uint8_t min_value = 0;
const uint8_t correct_total = SubBruteAttackTotalCount - 1;
uint8_t max_repeats = 9 - subbrute_protocol_repeats_count(instance->index);
bool updated = false;
bool consumed = false;
bool is_short = (event->type == InputTypeShort) || (event->type == InputTypeRepeat);
if(!instance->is_select_byte) {
if(event->key == InputKeyUp && is_short) {
if(instance->index == min_value) {
instance->index = correct_total;
} else {
instance->index = CLAMP(instance->index - 1, correct_total, min_value);
}
instance->extra_repeats = 0;
updated = true;
consumed = true;
} else if(event->key == InputKeyDown && is_short) {
if(instance->index == correct_total) {
instance->index = min_value;
} else {
instance->index = CLAMP(instance->index + 1, correct_total, min_value);
}
instance->extra_repeats = 0;
updated = true;
consumed = true;
} else if(event->key == InputKeyLeft && is_short) {
instance->extra_repeats = CLAMP(instance->extra_repeats - 1, max_repeats, 0);
updated = true;
consumed = true;
} else if(event->key == InputKeyRight && is_short) {
instance->extra_repeats = CLAMP(instance->extra_repeats + 1, max_repeats, 0);
updated = true;
consumed = true;
} else if(event->key == InputKeyOk && is_short) {
if(instance->index == SubBruteAttackLoadFile) {
instance->callback(SubBruteCustomEventTypeLoadFile, instance->context);
} else {
instance->callback(SubBruteCustomEventTypeMenuSelected, instance->context);
}
consumed = true;
updated = true;
}
if(updated) {
instance->window_position = instance->index;
if(instance->window_position > 0) {
instance->window_position -= 1;
}
if(SubBruteAttackTotalCount <= ITEMS_ON_SCREEN) {
instance->window_position = 0;
} else {
if(instance->window_position >= (SubBruteAttackTotalCount - ITEMS_ON_SCREEN)) {
instance->window_position = (SubBruteAttackTotalCount - ITEMS_ON_SCREEN);
}
}
}
} else if(is_short) {
if(event->key == InputKeyLeft) {
if((instance->index > 0 && !instance->two_bytes) ||
(instance->two_bytes && instance->index > 1)) {
instance->index--;
}
updated = true;
consumed = true;
} else if(event->key == InputKeyRight) {
if(instance->index < 7) {
instance->index++;
}
updated = true;
consumed = true;
} else if(event->key == InputKeyUp) {
instance->two_bytes = !instance->two_bytes;
// Because index is changing
if(instance->two_bytes && instance->index < 7) {
instance->index++;
}
// instance->callback(
// instance->two_bytes ? SubBruteCustomEventTypeChangeStepUp :
// SubBruteCustomEventTypeChangeStepDown,
// instance->context);
updated = true;
consumed = true;
} else if(event->key == InputKeyOk) {
instance->callback(SubBruteCustomEventTypeIndexSelected, instance->context);
consumed = true;
updated = true;
}
}
if(updated) {
with_view_model(
instance->view,
SubBruteMainViewModel * model,
{
model->index = instance->index;
model->window_position = instance->window_position;
model->key_from_file = instance->key_from_file;
model->is_select_byte = instance->is_select_byte;
model->two_bytes = instance->two_bytes;
model->extra_repeats = instance->extra_repeats;
},
true);
}
return consumed;
}
void subbrute_main_view_enter(void* context) {
furi_assert(context);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_main_view_enter");
#endif
}
void subbrute_main_view_exit(void* context) {
furi_assert(context);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_main_view_exit");
#endif
}
SubBruteMainView* subbrute_main_view_alloc() {
SubBruteMainView* instance = malloc(sizeof(SubBruteMainView));
instance->view = view_alloc();
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubBruteMainViewModel));
view_set_context(instance->view, instance);
view_set_draw_callback(instance->view, (ViewDrawCallback)subbrute_main_view_draw);
view_set_input_callback(instance->view, subbrute_main_view_input);
view_set_enter_callback(instance->view, subbrute_main_view_enter);
view_set_exit_callback(instance->view, subbrute_main_view_exit);
instance->index = 0;
instance->window_position = 0;
instance->key_from_file = 0;
instance->is_select_byte = false;
instance->two_bytes = false;
instance->extra_repeats = 0;
with_view_model(
instance->view,
SubBruteMainViewModel * model,
{
model->index = instance->index;
model->window_position = instance->window_position;
model->key_from_file = instance->key_from_file;
model->is_select_byte = instance->is_select_byte;
model->two_bytes = instance->two_bytes;
model->extra_repeats = instance->extra_repeats;
},
true);
return instance;
}
void subbrute_main_view_free(SubBruteMainView* instance) {
furi_assert(instance);
view_free(instance->view);
free(instance);
}
View* subbrute_main_view_get_view(SubBruteMainView* instance) {
furi_assert(instance);
return instance->view;
}
void subbrute_main_view_set_index(
SubBruteMainView* instance,
uint8_t idx,
bool is_select_byte,
bool two_bytes,
uint64_t key_from_file) {
furi_assert(instance);
furi_assert(idx < SubBruteAttackTotalCount);
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "Set index: %d, is_select_byte: %d", idx, is_select_byte);
#endif
instance->is_select_byte = is_select_byte;
instance->two_bytes = two_bytes;
instance->key_from_file = key_from_file;
instance->index = idx;
instance->window_position = idx;
if(!is_select_byte) {
if(instance->window_position > 0) {
instance->window_position -= 1;
}
if(SubBruteAttackTotalCount <= ITEMS_ON_SCREEN) {
instance->window_position = 0;
} else {
if(instance->window_position >= (SubBruteAttackTotalCount - ITEMS_ON_SCREEN)) {
instance->window_position = (SubBruteAttackTotalCount - ITEMS_ON_SCREEN);
}
}
}
with_view_model(
instance->view,
SubBruteMainViewModel * model,
{
model->index = instance->index;
model->window_position = instance->window_position;
model->key_from_file = instance->key_from_file;
model->is_select_byte = instance->is_select_byte;
model->two_bytes = instance->two_bytes;
model->extra_repeats = instance->extra_repeats;
},
true);
}
SubBruteAttacks subbrute_main_view_get_index(SubBruteMainView* instance) {
furi_assert(instance);
return instance->index;
}
uint8_t subbrute_main_view_get_extra_repeats(SubBruteMainView* instance) {
furi_assert(instance);
return instance->extra_repeats;
}
bool subbrute_main_view_get_two_bytes(SubBruteMainView* instance) {
furi_assert(instance);
return instance->two_bytes;
}

View File

@@ -0,0 +1,32 @@
#pragma once
#include "../subbrute_custom_event.h"
#include "../subbrute_protocols.h"
#include <gui/view.h>
#include <input/input.h>
#include <gui/elements.h>
typedef void (*SubBruteMainViewCallback)(SubBruteCustomEvent event, void* context);
typedef struct SubBruteMainView SubBruteMainView;
void subbrute_main_view_set_callback(
SubBruteMainView* instance,
SubBruteMainViewCallback callback,
void* context);
SubBruteMainView* subbrute_main_view_alloc();
void subbrute_main_view_free(SubBruteMainView* instance);
View* subbrute_main_view_get_view(SubBruteMainView* instance);
void subbrute_main_view_set_index(
SubBruteMainView* instance,
uint8_t idx,
bool is_select_byte,
bool two_bytes,
uint64_t file_key);
SubBruteAttacks subbrute_main_view_get_index(SubBruteMainView* instance);
uint8_t subbrute_main_view_get_extra_repeats(SubBruteMainView* instance);
bool subbrute_main_view_get_two_bytes(SubBruteMainView* instance);
void subbrute_attack_view_enter(void* context);
void subbrute_attack_view_exit(void* context);
bool subbrute_attack_view_input(InputEvent* event, void* context);
void subbrute_attack_view_draw(Canvas* canvas, void* context);