1
mirror of https://github.com/DarkFlippers/unleashed-firmware.git synced 2025-12-12 20:49:49 +04:00

Compare commits

...

24 Commits

Author SHA1 Message Date
MX
5e30b14d90 update changelog 2022-09-26 02:12:11 +03:00
MX
c07e3a34dd Merge pull request #75 from derskythe/subbrute-deep-refactor
SubBrute deep refactor
2022-09-26 02:08:45 +03:00
MX
be7e11e60f Merge branch 'dev' into subbrute-deep-refactor 2022-09-26 02:06:50 +03:00
MX
e96e414561 Merge branch 'fz-dev' into dev 2022-09-26 02:06:09 +03:00
derskythe
0c99cb52ec free transmitter during subbrute_worker_init_manual_transmit 2022-09-26 02:45:09 +04:00
derskythe
ad9e1ce4df set furi_hal_subghz_set_path to FuriHalSubGhzPathIsolate on each manual iteration 2022-09-26 02:42:39 +04:00
derskythe
22dc5190d1 remove furi_hal_power_suppress_charge_enter/exit from other places 2022-09-26 02:39:17 +04:00
derskythe
f2fd97d9c5 fix memory leaks 2022-09-26 02:36:38 +04:00
derskythe
08084d5763 fix first send signal equals last transferred or 0x00 2022-09-26 02:03:36 +04:00
derskythe
add1ad6949 fix manual select key on max and min values 2022-09-26 01:48:51 +04:00
DerSkythe
87654e60b8 Merge remote-tracking branch 'origin/subbrute-deep-refactor' into subbrute-deep-refactor 2022-09-26 01:10:21 +04:00
DerSkythe
6f92cd645e fixed frame width to scroll 2022-09-26 01:09:00 +04:00
DerSkythe
23f6ea2e05 refactor worker moved it to SubBruteState 2022-09-26 01:07:16 +04:00
David Coles
a6b98ccbbe Preliminary Rust support (#1781)
* Add support for R_ARM_THM_MOVW_ABS_NC/THM_MOVT_ABS

These are sometimes emitted by the Rust LLVM compiler.

Ref: https://github.com/ARM-software/abi-aa/blob/main/aaelf32/aaelf32.rst#56relocation

* Discard LLVM bitcode from extension applications

LLVM-based compilers may include uncompressed bitcode in object files
to help with link-time optimization. However this can bloat binary sizes
from KB to MB.

* Expose alligned_malloc/free functions to applications

This is required to implement a global allocator in Rust.
2022-09-26 07:06:46 +10:00
DerSkythe
ba5f590dab switched to manual transmit 2022-09-26 00:07:14 +04:00
Der Skythe
f1048733d2 Merge branch 'Eng1n33r:dev' into subbrute-deep-refactor 2022-09-25 23:16:27 +04:00
DerSkythe
ea7f68fcab fixed load existing dump 2022-09-25 23:12:31 +04:00
DerSkythe
54757428e6 fix bug with return to main menu when choice file 2022-09-25 21:31:33 +04:00
DerSkythe
6f91fa42f0 Added additional graphic decorations 2022-09-25 18:26:10 +04:00
DerSkythe
ec9ce0cad7 Working prototype, but not yet tested on a real device 2022-09-25 17:05:52 +04:00
DerSkythe
666821e9ce SubBruteMainView is ready 2022-09-25 00:46:43 +04:00
DerSkythe
b03cc8ddc3 trying to fix load failure 2022-09-24 22:30:08 +04:00
DerSkythe
c8e3d9b040 fix repeat call of view_dispatcher_alloc 2022-09-24 22:15:09 +04:00
DerSkythe
aeb02500de Deep refactor of SubBrute was made, but it doesn't start. Debug device needed 2022-09-24 21:47:21 +04:00
40 changed files with 3052 additions and 1542 deletions

View File

@@ -1,10 +1,6 @@
### New changes
* Infrared: Updated universal remote assets (by @Amec0e)
* OFW PR: SubGHz: Read RAW - datetime in default names (+ format changed) (OFW PR 1772 by Skorpionm)
* OFW: Text input overwrite max size template
* OFW: Remove unused headers
* OFW: ELF-Loader: C++ plugin support, loader overhaul.
* OFW: Core: simplify record container
* PR: SubGHz bruteforcer plugin - deep refactoring (huge thanks to @derskythe ! | PR #75)
* OFW: Preliminary Rust support
#### **DFU files no longer included in releases to avoid issues with wrong manual installation of assets - use .tgz file with qFlipper, or install automatically via web updater or use microSD update package**

View File

@@ -2,7 +2,7 @@ App(
appid="subbrute",
name="Sub-GHz Bruteforcer",
apptype=FlipperAppType.EXTERNAL,
entry_point="subbrute_start",
entry_point="subbrute_app",
cdefines=["APP_SUB_BRUTE"],
requires=["gui","dialogs"],
stack_size=2 * 1024,

View File

@@ -0,0 +1,370 @@
#include "subbrute_worker.h"
#include <subghz/environment.h>
#include <subghz/transmitter.h>
#include <flipper_format_i.h>
#define TAG "SubBruteWorker"
struct SubBruteWorker {
FuriThread* thread;
volatile bool worker_running;
volatile bool worker_manual_mode;
bool is_manual_init;
SubGhzEnvironment* environment;
SubGhzTransmitter* transmitter;
FlipperFormat* flipper_format;
uint32_t last_time_tx_data;
// Preset and frequency needed
FuriHalSubGhzPreset preset;
uint32_t frequency;
string_t protocol_name;
//SubBruteWorkerCallback callback;
//void* context;
};
/** Taken from subghz_tx_rx_worker.c */
#define SUBBRUTE_TXRX_WORKER_BUF_SIZE 2048
#define SUBBRUTE_TXRX_WORKER_MAX_TXRX_SIZE 60
#define SUBBRUTE_TXRX_WORKER_TIMEOUT_READ_WRITE_BUF 40
#define SUBBRUTE_TX_TIMEOUT 50
#define SUBBRUTE_SEND_DELAY 260
/**
* 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;
}
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "Worker start");
#endif
instance->environment = subghz_environment_alloc();
instance->transmitter = subghz_transmitter_alloc_init(
instance->environment, string_get_cstr(instance->protocol_name));
furi_hal_subghz_reset();
furi_hal_subghz_load_preset(instance->preset);
instance->frequency = furi_hal_subghz_set_frequency_and_path(instance->frequency);
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_write(&gpio_cc1101_g0, true);
// Set ready to transmit value
instance->last_time_tx_data = furi_get_tick() - SUBBRUTE_SEND_DELAY;
while(instance->worker_running) {
// Transmit
if(!furi_hal_subghz_tx()) {
FURI_LOG_E(TAG, "Cannot transmit!");
break;
}
furi_delay_ms(SUBBRUTE_TX_TIMEOUT);
}
furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate);
furi_hal_subghz_sleep();
subghz_transmitter_free(instance->transmitter);
instance->transmitter = NULL;
subghz_environment_free(instance->environment);
instance->environment = NULL;
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "Worker stop");
#endif
return 0;
}
SubBruteWorker* subbrute_worker_alloc() {
SubBruteWorker* instance = malloc(sizeof(SubBruteWorker));
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->status = SubBruteWorkerStatusIDLE;
instance->worker_running = false;
instance->worker_manual_mode = false;
instance->flipper_format = flipper_format_string_alloc();
string_init(instance->protocol_name);
return instance;
}
void subbrute_worker_free(SubBruteWorker* instance) {
furi_assert(instance);
furi_assert(!instance->worker_running);
if(instance->transmitter != NULL) {
subghz_transmitter_free(instance->transmitter);
instance->transmitter = NULL;
}
if(instance->environment != NULL) {
subghz_environment_free(instance->environment);
instance->environment = NULL;
}
furi_thread_free(instance->thread);
flipper_format_free(instance->flipper_format);
string_clear(instance->protocol_name);
free(instance);
}
bool subbrute_worker_start(
SubBruteWorker* instance,
uint32_t frequency,
FuriHalSubGhzPreset preset,
const char* protocol_name) {
furi_assert(instance);
if(instance->worker_manual_mode) {
return false;
}
instance->frequency = frequency;
instance->preset = preset;
string_clear(instance->protocol_name);
string_init_printf(instance->protocol_name, "%s", protocol_name);
bool res = false;
furi_hal_subghz_reset();
furi_hal_subghz_idle();
furi_hal_subghz_load_preset(instance->preset);
furi_hal_subghz_set_frequency_and_path(instance->frequency);
furi_hal_subghz_flush_rx();
if(furi_hal_subghz_is_tx_allowed(frequency)) {
instance->frequency = frequency;
res = true;
}
instance->worker_running = res;
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "Frequency: %d", frequency);
#endif
instance->preset = preset;
furi_thread_start(instance->thread);
return res;
}
void subbrute_worker_stop(SubBruteWorker* instance) {
furi_assert(instance);
instance->worker_running = false;
furi_thread_join(instance->thread);
furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate);
furi_hal_subghz_sleep();
}
bool subbrute_worker_is_running(SubBruteWorker* instance) {
furi_assert(instance);
return instance->worker_running;
}
bool subbrute_worker_can_transmit(SubBruteWorker* instance) {
furi_assert(instance);
return (furi_get_tick() - instance->last_time_tx_data) > SUBBRUTE_SEND_DELAY;
}
bool subbrute_worker_transmit(SubBruteWorker* instance, const char* payload) {
furi_assert(instance);
furi_assert(instance->worker_running);
if(!subbrute_worker_can_transmit(instance)) {
FURI_LOG_E(TAG, "Too early to transmit");
return false;
}
instance->last_time_tx_data = furi_get_tick();
#ifdef FURI_DEBUG
//FURI_LOG_D(TAG, "payload: %s", payload);
#endif
Stream* stream = flipper_format_get_raw_stream(instance->flipper_format);
stream_clean(stream);
stream_write_cstring(stream, payload);
subghz_transmitter_deserialize(instance->transmitter, instance->flipper_format);
return true;
}
bool subbrute_worker_init_manual_transmit(
SubBruteWorker* instance,
uint32_t frequency,
FuriHalSubGhzPreset preset,
const char* protocol_name) {
#ifdef FURI_DEBUG
FURI_LOG_D(
TAG,
"subbrute_worker_init_manual_transmit. frequency: %d, protocol: %s",
frequency,
protocol_name);
#endif
if(instance->worker_manual_mode || !subbrute_worker_can_transmit(instance)) {
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "cannot transmit");
#endif
return false;
}
if(instance->worker_running) {
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_worker_stop");
#endif
subbrute_worker_stop(instance);
}
// Not transmit at this period
instance->worker_manual_mode = true;
if(instance->is_manual_init) {
FURI_LOG_E(TAG, "Trying to setup without normally shutdown prev transmit session!");
subbrute_worker_manual_transmit_stop(instance);
}
instance->preset = preset;
instance->frequency = frequency;
string_clear(instance->protocol_name);
string_init_printf(instance->protocol_name, "%s", protocol_name);
furi_hal_subghz_reset();
furi_hal_subghz_idle();
furi_hal_subghz_load_preset(instance->preset);
furi_hal_subghz_set_frequency_and_path(instance->frequency);
furi_hal_subghz_flush_rx();
if(!furi_hal_subghz_is_tx_allowed(frequency)) {
FURI_LOG_E(TAG, "Frequency: %d invalid!", frequency);
instance->frequency = frequency;
instance->worker_manual_mode = false;
return false;
}
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "Frequency: %d", frequency);
#endif
instance->environment = subghz_environment_alloc();
instance->transmitter = subghz_transmitter_alloc_init(
instance->environment, string_get_cstr(instance->protocol_name));
furi_hal_subghz_reset();
furi_hal_subghz_load_preset(instance->preset);
instance->frequency = furi_hal_subghz_set_frequency_and_path(frequency);
furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate);
furi_hal_subghz_sleep();
subghz_transmitter_free(instance->transmitter);
instance->transmitter = NULL;
instance->worker_manual_mode = false;
instance->is_manual_init = true;
return true;
}
void subbrute_worker_manual_transmit_stop(SubBruteWorker* instance) {
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_worker_manual_transmit_stop");
#endif
if(!instance->is_manual_init) {
return;
}
furi_hal_subghz_idle();
furi_hal_subghz_sleep();
if(instance->transmitter != NULL) {
subghz_transmitter_free(instance->transmitter);
instance->transmitter = NULL;
}
subghz_environment_free(instance->environment);
instance->environment = NULL;
instance->is_manual_init = false;
}
bool subbrute_worker_manual_transmit(SubBruteWorker* instance, const char* payload) {
furi_assert(instance);
if(instance->worker_manual_mode || !subbrute_worker_can_transmit(instance)) {
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "cannot transmit");
#endif
return false;
}
if(instance->worker_running) {
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_worker_stop");
#endif
subbrute_worker_stop(instance);
}
if(!instance->is_manual_init) {
FURI_LOG_E(TAG, "Manually transmit doesn't set!");
return false;
}
instance->last_time_tx_data = furi_get_tick();
instance->worker_manual_mode = true;
Stream* stream = flipper_format_get_raw_stream(instance->flipper_format);
stream_clean(stream);
stream_write_cstring(stream, payload);
instance->transmitter = subghz_transmitter_alloc_init(
instance->environment, string_get_cstr(instance->protocol_name));
subghz_transmitter_deserialize(instance->transmitter, instance->flipper_format);
furi_hal_subghz_reset();
furi_hal_subghz_load_preset(instance->preset);
instance->frequency = 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;
stream_clean(stream);
instance->worker_manual_mode = false;
return true;
}

View File

@@ -0,0 +1,35 @@
#pragma once
#include <furi_hal_subghz.h>
typedef struct SubBruteWorker SubBruteWorker;
/**
* Same like SubGhzTxRxWorkerStatus in subghz_tx_rx_worker.h
* using just to not include that file
typedef enum {
SubBruteWorkerStatusIDLE,
SubBruteWorkerStatusTx,
// SubBruteWorkerStatusRx,
} SubBruteWorkerStatus;
//typedef void (*SubBruteWorkerCallback)(SubBruteWorkerStatus event, void* context);
*/
SubBruteWorker* subbrute_worker_alloc();
void subbrute_worker_free(SubBruteWorker* instance);
bool subbrute_worker_start(
SubBruteWorker* instance,
uint32_t frequency,
FuriHalSubGhzPreset preset,
const char* protocol_name);
void subbrute_worker_stop(SubBruteWorker* instance);
//bool subbrute_worker_write(SubBruteWorker* instance, uint8_t* data, size_t size);
bool subbrute_worker_is_running(SubBruteWorker* instance);
bool subbrute_worker_can_transmit(SubBruteWorker* instance);
bool subbrute_worker_transmit(SubBruteWorker* instance, const char* payload);
bool subbrute_worker_init_manual_transmit(SubBruteWorker* instance,
uint32_t frequency,
FuriHalSubGhzPreset preset,
const char* protocol_name);
bool subbrute_worker_manual_transmit(SubBruteWorker* instance, const char* payload);
void subbrute_worker_manual_transmit_stop(SubBruteWorker* instance);

View File

@@ -1,197 +0,0 @@
#include "subbrute_scene_entrypoint.h"
#include "../subbrute_utils.h"
string_t subbrute_menu_items[10];
void subbrute_scene_entrypoint_menu_callback(SubBruteState* context, uint32_t index) {
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
string_set_str(context->protocol, "RAW");
context->repeat = 5;
context->te = 0;
context->attack = index;
switch(index) {
case SubBruteAttackLoadFile:
context->current_scene = SceneSelectFile;
break;
case SubBruteAttackCAME12bit307:
case SubBruteAttackCAME12bit433:
case SubBruteAttackCAME12bit868:
if(index == SubBruteAttackCAME12bit307) {
context->frequency = 307800000;
} else if(index == SubBruteAttackCAME12bit433) {
context->frequency = 433920000;
} else if(index == SubBruteAttackCAME12bit868) {
context->frequency = 868350000;
}
context->bit = 12;
string_set_str(context->protocol, "CAME");
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
if(!subbrute_is_frequency_allowed(context)) {
return;
}
context->current_scene = SceneAttack;
break;
case SubBruteAttackChamberlain9bit315:
context->frequency = 315000000;
context->bit = 9;
string_set_str(context->protocol, "Cham_Code");
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
if(!subbrute_is_frequency_allowed(context)) {
return;
}
context->current_scene = SceneAttack;
break;
case SubBruteAttackChamberlain9bit390:
context->frequency = 390000000;
context->bit = 9;
string_set_str(context->protocol, "Cham_Code");
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
if(!subbrute_is_frequency_allowed(context)) {
return;
}
context->current_scene = SceneAttack;
break;
case SubBruteAttackLinear10bit300:
context->frequency = 300000000;
context->bit = 10;
string_set_str(context->protocol, "Linear");
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
if(!subbrute_is_frequency_allowed(context)) {
return;
}
context->current_scene = SceneAttack;
break;
case SubBruteAttackLinear10bit310:
context->frequency = 310000000;
context->bit = 10;
string_set_str(context->protocol, "Linear");
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
if(!subbrute_is_frequency_allowed(context)) {
return;
}
context->current_scene = SceneAttack;
break;
case SubBruteAttackNICE12bit433:
context->frequency = 433920000;
context->bit = 12;
string_set_str(context->protocol, "Nice FLO");
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
if(!subbrute_is_frequency_allowed(context)) {
return;
}
context->current_scene = SceneAttack;
break;
case SubBruteAttackNICE12bit868:
context->frequency = 868350000;
context->bit = 12;
string_set_str(context->protocol, "Nice FLO");
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
if(!subbrute_is_frequency_allowed(context)) {
return;
}
context->current_scene = SceneAttack;
break;
default:
break;
}
}
void subbrute_scene_entrypoint_on_enter(SubBruteState* context) {
// Clear the previous payload
context->menu_index = 0;
for(uint32_t i = 0; i < 10; i++) {
string_init(subbrute_menu_items[i]);
}
string_set(subbrute_menu_items[0], "BF existing dump");
string_set(subbrute_menu_items[1], "CAME 12bit 307mhz");
string_set(subbrute_menu_items[2], "CAME 12bit 433mhz");
string_set(subbrute_menu_items[3], "CAME 12bit 868mhz");
string_set(subbrute_menu_items[4], "Chamberlain 9bit 315mhz");
string_set(subbrute_menu_items[5], "Chamberlain 9bit 390mhz");
string_set(subbrute_menu_items[6], "Linear 10bit 300mhz");
string_set(subbrute_menu_items[7], "Linear 10bit 310mhz");
string_set(subbrute_menu_items[8], "NICE 12bit 433mhz");
string_set(subbrute_menu_items[9], "NICE 12bit 868mhz");
}
void subbrute_scene_entrypoint_on_exit(SubBruteState* context) {
UNUSED(context);
for(uint32_t i = 0; i < 10; i++) {
string_clear(subbrute_menu_items[i]);
}
}
void subbrute_scene_entrypoint_on_tick(SubBruteState* context) {
UNUSED(context);
}
void subbrute_scene_entrypoint_on_event(SubBruteEvent event, SubBruteState* context) {
if(event.evt_type == EventTypeKey) {
if(event.input_type == InputTypeShort) {
switch(event.key) {
case InputKeyDown:
if(context->menu_index < SubBruteAttackNICE12bit868) {
context->menu_index++;
}
break;
case InputKeyUp:
if(context->menu_index > SubBruteAttackLoadFile) {
context->menu_index--;
}
break;
case InputKeyLeft:
case InputKeyRight:
break;
case InputKeyOk:
subbrute_scene_entrypoint_menu_callback(context, context->menu_index);
break;
case InputKeyBack:
context->is_running = false;
break;
}
}
}
}
void subbrute_scene_entrypoint_on_draw(Canvas* canvas, SubBruteState* context) {
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
// Title
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 64, 6, AlignCenter, AlignTop, "Sub-GHz Bruteforcer");
if(context->menu_index > SubBruteAttackLoadFile) {
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas,
64,
24,
AlignCenter,
AlignTop,
string_get_cstr(subbrute_menu_items[context->menu_index - 1]));
}
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(
canvas,
64,
36,
AlignCenter,
AlignTop,
string_get_cstr(subbrute_menu_items[context->menu_index]));
if(context->menu_index < SubBruteAttackNICE12bit868) {
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas,
64,
48,
AlignCenter,
AlignTop,
string_get_cstr(subbrute_menu_items[context->menu_index + 1]));
}
}

View File

@@ -1,8 +0,0 @@
#pragma once
#include "../subbrute.h"
void subbrute_scene_entrypoint_on_enter(SubBruteState* context);
void subbrute_scene_entrypoint_on_exit(SubBruteState* context);
void subbrute_scene_entrypoint_on_tick(SubBruteState* context);
void subbrute_scene_entrypoint_on_event(SubBruteEvent event, SubBruteState* context);
void subbrute_scene_entrypoint_on_draw(Canvas* canvas, SubBruteState* context);

View File

@@ -1,222 +0,0 @@
#include "subbrute_scene_load_file.h"
#include "subbrute_scene_entrypoint.h"
#include "../subbrute_utils.h"
#include <lib/subghz/protocols/registry.h>
#define SUBGHZ_APP_PATH_FOLDER "/ext/subghz"
bool subbrute_load(SubBruteState* context, const char* file_path) {
bool result = false;
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
string_t temp_str;
string_init(temp_str);
uint32_t temp_data32;
do {
if(!flipper_format_file_open_existing(fff_data_file, file_path)) {
FURI_LOG_E(TAG, "Error open file %s", file_path);
string_reset(context->notification_msg);
string_set_str(context->notification_msg, "Error open file");
break;
}
if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) {
FURI_LOG_E(TAG, "Missing or incorrect header");
string_reset(context->notification_msg);
string_set_str(context->notification_msg, "Missing or incorrect header");
break;
}
// Frequency
if(flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) {
FURI_LOG_I(TAG, "Frequency: %d", temp_data32);
context->frequency = temp_data32;
if(!subbrute_is_frequency_allowed(context)) {
break;
}
} else {
FURI_LOG_E(TAG, "Missing or incorrect Frequency");
string_reset(context->notification_msg);
string_set_str(context->notification_msg, "Missing or incorrect Frequency");
break;
}
// Preset
if(!flipper_format_read_string(fff_data_file, "Preset", context->preset)) {
FURI_LOG_E(TAG, "Preset FAIL");
string_reset(context->notification_msg);
string_set_str(context->notification_msg, "Preset FAIL");
}
// Protocol
if(!flipper_format_read_string(fff_data_file, "Protocol", context->protocol)) {
FURI_LOG_E(TAG, "Missing Protocol");
string_reset(context->notification_msg);
string_set_str(context->notification_msg, "Missing Protocol");
break;
} else {
FURI_LOG_I(TAG, "Protocol: %s", string_get_cstr(context->protocol));
}
if(strcmp(string_get_cstr(context->protocol), "RAW") == 0) {
FURI_LOG_E(TAG, "RAW unsupported");
string_reset(context->notification_msg);
string_set_str(context->notification_msg, "RAW unsupported");
break;
}
const SubGhzProtocol* registry =
subghz_protocol_registry_get_by_name(string_get_cstr(context->protocol));
if(registry && registry->type == SubGhzProtocolTypeDynamic) {
FURI_LOG_D(TAG, "Protocol is dynamic - not supported");
string_reset(context->notification_msg);
string_set_str(context->notification_msg, "Dynamic protocol unsupported");
break;
}
context->decoder_result = subghz_receiver_search_decoder_base_by_name(
context->receiver, string_get_cstr(context->protocol));
if(context->decoder_result) {
FURI_LOG_I(TAG, "Found decoder");
} else {
FURI_LOG_E(TAG, "Protocol not found");
string_reset(context->notification_msg);
string_set_str(context->notification_msg, "Protocol not found");
break;
}
// Bit
if(!flipper_format_read_uint32(fff_data_file, "Bit", &temp_data32, 1)) {
FURI_LOG_E(TAG, "Missing or incorrect Bit");
string_reset(context->notification_msg);
string_set_str(context->notification_msg, "Missing or incorrect Bit");
break;
} else {
FURI_LOG_I(TAG, "Bit: %d", temp_data32);
context->bit = temp_data32;
}
// Key
if(!flipper_format_read_string(fff_data_file, "Key", temp_str)) {
FURI_LOG_E(TAG, "Missing or incorrect Key");
string_reset(context->notification_msg);
string_set_str(context->notification_msg, "Missing or incorrect Key");
break;
} else {
FURI_LOG_I(TAG, "Key: %s", string_get_cstr(temp_str));
string_set(context->key, string_get_cstr(temp_str));
}
// TE
if(!flipper_format_read_uint32(fff_data_file, "TE", &temp_data32, 1)) {
FURI_LOG_E(TAG, "Missing or incorrect TE");
//string_reset(context->notification_msg);
//string_set_str(context->notification_msg, "Missing or incorrect TE");
//break;
} else {
FURI_LOG_I(TAG, "TE: %d", temp_data32);
context->te = temp_data32;
}
// Repeat
if(flipper_format_read_uint32(fff_data_file, "Repeat", &temp_data32, 1)) {
FURI_LOG_I(TAG, "Repeat: %d", temp_data32);
context->repeat = temp_data32;
} else {
FURI_LOG_I(TAG, "Repeat: 3 (default)");
context->repeat = 3;
}
result = true;
} while(0);
string_clear(temp_str);
flipper_format_file_close(fff_data_file);
flipper_format_free(fff_data_file);
furi_record_close(RECORD_STORAGE);
if(result) {
FURI_LOG_I(TAG, "Loaded successfully");
string_reset(context->notification_msg);
string_set_str(context->notification_msg, "File looks ok.");
}
return result;
}
void subbrute_scene_load_file_on_enter(SubBruteState* context) {
if(subbrute_load_protocol_from_file(context)) {
context->current_scene = SceneSelectField;
} else {
subbrute_scene_entrypoint_on_enter(context);
context->current_scene = SceneEntryPoint;
}
}
void subbrute_scene_load_file_on_exit(SubBruteState* context) {
UNUSED(context);
}
void subbrute_scene_load_file_on_tick(SubBruteState* context) {
UNUSED(context);
}
void subbrute_scene_load_file_on_event(SubBruteEvent event, SubBruteState* context) {
UNUSED(context);
if(event.evt_type == EventTypeKey) {
if(event.input_type == InputTypeShort) {
switch(event.key) {
case InputKeyDown:
case InputKeyUp:
case InputKeyLeft:
case InputKeyRight:
case InputKeyOk:
break;
case InputKeyBack:
context->current_scene = SceneEntryPoint;
break;
}
}
}
}
void subbrute_scene_load_file_on_draw(Canvas* canvas, SubBruteState* context) {
UNUSED(context);
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
// Frame
//canvas_draw_frame(canvas, 0, 0, 128, 64);
// Title
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 64, 16, AlignCenter, AlignTop, "SubGHz Fuzzer");
canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignTop, "Error: Press back");
}
bool subbrute_load_protocol_from_file(SubBruteState* context) {
string_t file_path;
string_init(file_path);
string_set_str(file_path, SUBGHZ_APP_PATH_FOLDER);
context->environment = subghz_environment_alloc();
context->receiver = subghz_receiver_alloc_init(context->environment);
subghz_receiver_set_filter(context->receiver, SubGhzProtocolFlag_Decodable);
// Input events and views are managed by file_select
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px);
bool res = dialog_file_browser_show(context->dialogs, file_path, file_path, &browser_options);
if(res) {
res = subbrute_load(context, string_get_cstr(file_path));
}
subghz_environment_free(context->environment);
subghz_receiver_free(context->receiver);
string_clear(file_path);
return res;
}

View File

@@ -1,8 +0,0 @@
#include "../subbrute.h"
void subbrute_scene_load_file_on_enter(SubBruteState* context);
void subbrute_scene_load_file_on_exit(SubBruteState* context);
void subbrute_scene_load_file_on_tick(SubBruteState* context);
void subbrute_scene_load_file_on_event(SubBruteEvent event, SubBruteState* context);
void subbrute_scene_load_file_on_draw(Canvas* canvas, SubBruteState* context);
bool subbrute_load_protocol_from_file(SubBruteState* context);

View File

@@ -1,384 +0,0 @@
#include "subbrute_scene_run_attack.h"
#include <lib/subghz/transmitter.h>
#include <gui/elements.h>
//uint64_t subbrute_counter = 0;
uint64_t max_value;
bool locked = false;
bool toSave = false;
char subbrute_payload_byte[4];
#define SUBBRUTE_DELAY 1
FuriHalSubGhzPreset str_to_preset(string_t preset) {
if(string_cmp_str(preset, "FuriHalSubGhzPresetOok270Async") == 0) {
return FuriHalSubGhzPresetOok270Async;
}
if(string_cmp_str(preset, "FuriHalSubGhzPresetOok650Async") == 0) {
return FuriHalSubGhzPresetOok650Async;
}
if(string_cmp_str(preset, "FuriHalSubGhzPreset2FSKDev238Async") == 0) {
return FuriHalSubGhzPreset2FSKDev238Async;
}
if(string_cmp_str(preset, "FuriHalSubGhzPreset2FSKDev476Async") == 0) {
return FuriHalSubGhzPreset2FSKDev476Async;
}
if(string_cmp_str(preset, "FuriHalSubGhzPresetMSK99_97KbAsync") == 0) {
return FuriHalSubGhzPresetMSK99_97KbAsync;
}
if(string_cmp_str(preset, "FuriHalSubGhzPresetMSK99_97KbAsync") == 0) {
return FuriHalSubGhzPresetMSK99_97KbAsync;
}
return FuriHalSubGhzPresetCustom;
}
void subbrute_emit(SubBruteState* context) {
//FURI_LOG_D(TAG, string_get_cstr(context->flipper_format_string));
context->transmitter =
subghz_transmitter_alloc_init(context->environment, string_get_cstr(context->protocol));
subghz_transmitter_deserialize(context->transmitter, context->flipper_format);
furi_hal_subghz_reset();
furi_hal_subghz_load_preset(str_to_preset(context->preset));
context->frequency_cal = furi_hal_subghz_set_frequency_and_path(context->frequency);
furi_hal_subghz_start_async_tx(subghz_transmitter_yield, context->transmitter);
while(!(furi_hal_subghz_is_async_tx_complete())) {
furi_delay_ms(1);
}
furi_hal_subghz_stop_async_tx();
subghz_transmitter_stop(context->transmitter);
furi_hal_subghz_idle();
subghz_transmitter_free(context->transmitter);
}
void prepare_emit(SubBruteState* context) {
UNUSED(context);
furi_hal_subghz_init();
}
void clear_emit(SubBruteState* context) {
UNUSED(context);
//furi_hal_subghz_stop_async_tx();
//furi_hal_subghz_idle();
furi_hal_subghz_sleep();
}
/*
void subbrute_send_raw_packet(SubBruteState* context) {
string_reset(context->candidate);
// Payload to padded binary string
int* binaryNum = (int*)malloc(sizeof(int) * context->bit);
uint32_t i = 0;
for(i = 0; i < context->bit; i++) {
binaryNum[i] = 0;
}
i = 0;
uint64_t counter = context->payload;
while(counter > 0) {
binaryNum[i] = counter % 2;
counter = counter / 2;
i++;
}
// printing binary array in reverse order and build raw payload
for(uint32_t loop = 0; loop < context->repeat; loop++) {
for(int j = (int)context->bit - 1; j >= 0; j--) {
if(binaryNum[j] == 1) {
string_cat(context->candidate, context->subbrute_raw_one);
} else {
string_cat(context->candidate, context->subbrute_raw_zero);
}
}
string_cat(context->candidate, context->subbrute_raw_stop);
}
free(binaryNum);
string_init_printf(
context->flipper_format_string,
"Filetype: Flipper SubGhz RAW File\n"
"Version: 1\n"
"Frequency: %d\n"
"Preset: %s\n"
"Protocol: RAW\n"
"RAW_Data: %s",
context->frequency,
string_get_cstr(context->preset),
string_get_cstr(context->candidate));
subbrute_emit(context);
}
*/
void subbrute_send_packet_parsed(SubBruteState* context) {
if(context->attack == SubBruteAttackLoadFile) {
snprintf(subbrute_payload_byte, 4, "%02X ", (uint8_t)context->payload);
string_replace_at(context->candidate, context->str_index, 3, subbrute_payload_byte);
} else {
string_t buffer;
string_init(buffer);
string_init_printf(buffer, "%16X", context->payload);
int j = 0;
string_set_str(context->candidate, " ");
for(uint8_t i = 0; i < 16; i++) {
if(string_get_char(buffer, i) != ' ') {
string_set_char(context->candidate, i + j, string_get_char(buffer, i));
} else {
string_set_char(context->candidate, i + j, '0');
}
if(i % 2 != 0) {
j++;
}
}
string_clear(buffer);
}
if(strcmp(string_get_cstr(context->protocol), "Princeton") == 0) {
string_init_printf(
context->flipper_format_string,
"Filetype: Flipper SubGhz Key File\n"
"Version: 1\n"
"Frequency: %u\n"
"Preset: %s\n"
"Protocol: %s\n"
"Bit: %d\n"
"Key: %s\n"
"TE: %d\n",
context->frequency,
string_get_cstr(context->preset),
string_get_cstr(context->protocol),
context->bit,
string_get_cstr(context->candidate),
context->te);
} else {
string_init_printf(
context->flipper_format_string,
"Filetype: Flipper SubGhz Key File\n"
"Version: 1\n"
"Frequency: %u\n"
"Preset: %s\n"
"Protocol: %s\n"
"Bit: %d\n"
"Key: %s\n",
context->frequency,
string_get_cstr(context->preset),
string_get_cstr(context->protocol),
context->bit,
string_get_cstr(context->candidate));
}
stream_clean(context->stream);
stream_write_string(context->stream, context->flipper_format_string);
}
void subbrute_send_packet(SubBruteState* context) {
///if(string_cmp_str(context->protocol, "RAW") == 0) {
// subbrute_send_raw_packet(context);
//} else {
subbrute_send_packet_parsed(context);
subbrute_emit(context);
//}
string_clear(context->flipper_format_string);
}
void subbrute_scene_run_attack_on_exit(SubBruteState* context) {
if(!toSave) {
clear_emit(context);
furi_thread_free(context->bruthread);
flipper_format_free(context->flipper_format);
subghz_receiver_free(context->receiver);
subghz_environment_free(context->environment);
}
}
void subbrute_scene_run_attack_on_tick(SubBruteState* context) {
if(!context->is_attacking || locked) {
return;
}
//if(0 != subbrute_counter) {
locked = true;
subbrute_send_packet(context);
if(context->payload == max_value) {
//context->payload = 0x00;
//subbrute_counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
} else {
context->payload++;
}
locked = false;
//}
/*if(subbrute_counter > SUBBRUTE_DELAY) {
subbrute_counter = 0;
} else {
subbrute_counter++;
}*/
}
void subbrute_run_timer(SubBruteState* context) {
while(true) {
if(!context->is_attacking) {
context->is_thread_running = false;
break;
}
//furi_delay_ms(10);
subbrute_scene_run_attack_on_tick(context);
}
}
// entrypoint for worker
static int32_t subbrute_worker_thread(void* ctx) {
SubBruteState* app = ctx;
subbrute_run_timer(app);
return 0;
}
void start_bruthread(SubBruteState* app) {
if(!app->is_thread_running) {
furi_thread_start(app->bruthread);
app->is_thread_running = true;
}
}
void subbrute_scene_run_attack_on_enter(SubBruteState* context) {
if(!toSave) {
if(context->attack == SubBruteAttackLoadFile) {
max_value = 0xFF;
} else {
string_t max_value_s;
string_init(max_value_s);
for(uint8_t i = 0; i < context->bit; i++) {
string_cat_printf(max_value_s, "1");
}
max_value = (uint64_t)strtol(string_get_cstr(max_value_s), NULL, 2);
string_clear(max_value_s);
}
context->str_index = (context->key_index * 3);
string_init_set(context->candidate, context->key);
context->flipper_format = flipper_format_string_alloc();
context->stream = flipper_format_get_raw_stream(context->flipper_format);
context->environment = subghz_environment_alloc();
context->receiver = subghz_receiver_alloc_init(context->environment);
subghz_receiver_set_filter(context->receiver, SubGhzProtocolFlag_Decodable);
prepare_emit(context);
context->bruthread = furi_thread_alloc();
furi_thread_set_name(context->bruthread, "SubBrute Worker");
furi_thread_set_stack_size(context->bruthread, 2048);
furi_thread_set_context(context->bruthread, context);
furi_thread_set_callback(context->bruthread, subbrute_worker_thread);
} else {
toSave = false;
}
}
void subbrute_scene_run_attack_on_event(SubBruteEvent event, SubBruteState* context) {
if(event.evt_type == EventTypeKey) {
if(event.input_type == InputTypeShort) {
switch(event.key) {
case InputKeyDown:
break;
case InputKeyUp:
if(!context->is_attacking) {
subbrute_send_packet_parsed(context);
string_clear(context->flipper_format_string);
toSave = true;
context->current_scene = SceneSaveName;
}
break;
case InputKeyLeft:
if(!context->is_attacking && context->payload > 0x00) {
context->payload--;
subbrute_send_packet(context);
notification_message(context->notify, &sequence_blink_blue_10);
} else if(!context->is_attacking && context->payload == 0x00) {
context->payload = max_value;
subbrute_send_packet(context);
notification_message(context->notify, &sequence_blink_blue_10);
}
break;
case InputKeyRight:
if(!context->is_attacking && context->payload < max_value) {
context->payload++;
subbrute_send_packet(context);
notification_message(context->notify, &sequence_blink_blue_10);
} else if(!context->is_attacking && context->payload == max_value) {
context->payload = 0x00;
subbrute_send_packet(context);
notification_message(context->notify, &sequence_blink_blue_10);
}
break;
case InputKeyOk:
if(!context->is_attacking) {
if(context->payload == max_value) {
context->payload = 0x00;
//subbrute_counter = 0;
}
context->is_attacking = true;
start_bruthread(context);
notification_message(context->notify, &sequence_blink_start_blue);
} else {
context->is_attacking = false;
//context->close_thread_please = true;
if(context->is_thread_running && context->bruthread) {
furi_thread_join(context->bruthread); // wait until thread is finished
}
//context->close_thread_please = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
}
break;
case InputKeyBack:
locked = false;
//context->close_thread_please = true;
context->is_attacking = false;
if(context->is_thread_running && context->bruthread) {
furi_thread_join(context->bruthread); // wait until thread is finished
}
//context->close_thread_please = false;
string_reset(context->notification_msg);
context->payload = 0x00;
//subbrute_counter = 0;
notification_message(context->notify, &sequence_blink_stop);
if(context->attack == SubBruteAttackLoadFile) {
context->current_scene = SceneSelectField;
} else {
context->current_scene = SceneEntryPoint;
}
break;
}
}
}
}
void subbrute_scene_run_attack_on_draw(Canvas* canvas, SubBruteState* context) {
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
// Frame
//canvas_draw_frame(canvas, 0, 0, 128, 64);
// Title
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 64, 8, AlignCenter, AlignTop, "Fire in the hole!");
char msg_index[26];
snprintf(
msg_index, sizeof(msg_index), "< %04d / %04d >", (int)context->payload, (int)max_value);
canvas_draw_str_aligned(canvas, 64, 24, AlignCenter, AlignTop, msg_index);
canvas_set_font(canvas, FontSecondary);
char start_stop_msg[20];
snprintf(start_stop_msg, sizeof(start_stop_msg), " Press (^) to save ");
if(context->is_attacking) {
elements_button_center(canvas, "Stop");
} else {
elements_button_center(canvas, "Start");
}
canvas_draw_str_aligned(canvas, 64, 39, AlignCenter, AlignTop, start_stop_msg);
}

View File

@@ -1,8 +0,0 @@
#include "../subbrute.h"
void subbrute_scene_run_attack_on_enter(SubBruteState* context);
void subbrute_scene_run_attack_on_exit(SubBruteState* context);
void subbrute_scene_run_attack_on_tick(SubBruteState* context);
void subbrute_scene_run_attack_on_event(SubBruteEvent event, SubBruteState* context);
void subbrute_scene_run_attack_on_draw(Canvas* canvas, SubBruteState* context);
void send_packet();

View File

@@ -1,222 +0,0 @@
#include "../subbrute.h"
#include "m-string.h"
#include "subghz/types.h"
#include <lib/toolbox/random_name.h>
#include <gui/modules/validators.h>
#include <lib/toolbox/path.h>
#define MAX_TEXT_INPUT_LEN 22
bool backpressed = false;
bool subbrute_path_is_file(string_t path) {
return string_end_with_str_p(path, ".sub");
}
// method modified from subghz_i.c
// https://github.com/flipperdevices/flipperzero-firmware/blob/b0daa601ad5b87427a45f9089c8b403a01f72c2a/applications/subghz/subghz_i.c#L417-L456
bool subbrute_save_protocol_to_file(Stream* flipper_format_stream, const char* dev_file_name) {
furi_assert(dev_file_name);
Storage* storage = furi_record_open(RECORD_STORAGE);
bool saved = false;
string_t file_dir;
string_init(file_dir);
path_extract_dirname(dev_file_name, file_dir);
do {
if(!storage_simply_mkdir(storage, string_get_cstr(file_dir))) {
FURI_LOG_E(TAG, "(save) Cannot mkdir");
break;
}
if(!storage_simply_remove(storage, dev_file_name)) {
FURI_LOG_E(TAG, "(save) Cannot remove");
break;
}
stream_seek(flipper_format_stream, 0, StreamOffsetFromStart);
stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS);
saved = true;
FURI_LOG_D(TAG, "(save) OK Save");
} while(0);
string_clear(file_dir);
furi_record_close(RECORD_STORAGE);
return saved;
}
void custom_callback(SubBruteState* context) {
if(strcmp(context->file_name_tmp, "")) {
string_cat_printf(context->file_path, "/%s%s", context->file_name_tmp, ".sub");
if(subbrute_path_is_file(context->file_path_tmp)) {
context->current_scene = SceneAttack;
return; //false;
} else {
subbrute_save_protocol_to_file(context->stream, string_get_cstr(context->file_path));
}
string_set_str(context->file_path, EXT_PATH("subghz"));
string_reset(context->file_path_tmp);
//scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveSuccess);
context->current_scene = SceneAttack;
return; //true;
} else {
//error no file name
context->current_scene = SceneAttack;
return; //true;
}
}
void subbrute_scene_save_name_text_input_callback(void* context) {
furi_assert(context);
SubBruteState* statee = context;
custom_callback(statee);
}
void subbrute_scene_save_name_on_tick(SubBruteState* context) {
if(backpressed) {
void* validator_context = text_input_get_validator_callback_context(context->text_input);
text_input_set_validator(context->text_input, NULL, NULL);
validator_is_file_free(validator_context);
// Clear view
text_input_reset(context->text_input);
// TextInput
view_dispatcher_remove_view(context->view_dispatcher, 0);
text_input_free(context->text_input);
// Popup
view_dispatcher_remove_view(context->view_dispatcher, 1);
popup_free(context->popup);
context->current_scene = SceneAttack;
}
}
bool subbrute_back_event_callback(void* context) {
UNUSED(context);
backpressed = true;
return true;
}
void subbrute_scene_save_name_on_enter(SubBruteState* context) {
// Text Input
context->text_input = text_input_alloc();
view_dispatcher_add_view(
context->view_dispatcher, 0, text_input_get_view(context->text_input));
// Popup
context->popup = popup_alloc();
view_dispatcher_add_view(context->view_dispatcher, 1, popup_get_view(context->popup));
// Setup view
TextInput* text_input = context->text_input;
bool dev_name_empty = false;
string_t file_name;
string_t dir_name;
string_init(file_name);
string_init(dir_name);
if(!subbrute_path_is_file(context->file_path)) {
char file_name_buf[64] = {0};
set_random_name(file_name_buf, 64);
string_set_str(file_name, file_name_buf);
string_set_str(context->file_path, EXT_PATH("subghz"));
//highlighting the entire filename by default
dev_name_empty = true;
} else {
string_set(context->file_path_tmp, context->file_path);
path_extract_dirname(string_get_cstr(context->file_path), dir_name);
path_extract_filename(context->file_path, file_name, true);
string_set(context->file_path, dir_name);
}
strncpy(context->file_name_tmp, string_get_cstr(file_name), 64);
text_input_set_header_text(text_input, "Name signal");
text_input_set_result_callback(
text_input,
subbrute_scene_save_name_text_input_callback,
context,
context->file_name_tmp,
MAX_TEXT_INPUT_LEN, // buffer size
dev_name_empty);
ValidatorIsFile* validator_is_file =
validator_is_file_alloc_init(string_get_cstr(context->file_path), ".sub", "");
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
string_clear(file_name);
string_clear(dir_name);
view_dispatcher_set_navigation_event_callback(
context->view_dispatcher, subbrute_back_event_callback);
view_dispatcher_switch_to_view(context->view_dispatcher, 0);
}
void subbrute_scene_save_name_on_event(SubBruteEvent event, SubBruteState* context) {
UNUSED(context);
if(event.evt_type == EventTypeKey) {
if(event.input_type == InputTypeShort) {
switch(event.key) {
case InputKeyDown:
case InputKeyUp:
case InputKeyLeft:
case InputKeyRight:
case InputKeyOk:
break;
case InputKeyBack:
//context->current_scene = SceneAttack;
break;
}
}
}
}
void subbrute_scene_save_name_on_exit(SubBruteState* context) {
if(!backpressed) {
// Clear validator
void* validator_context = text_input_get_validator_callback_context(context->text_input);
text_input_set_validator(context->text_input, NULL, NULL);
validator_is_file_free(validator_context);
// Clear view
text_input_reset(context->text_input);
// Setup view
Popup* popup = context->popup;
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
popup_set_header(popup, "Saved!", 13, 22, AlignLeft, AlignBottom);
popup_set_timeout(popup, 1500);
popup_set_context(popup, context);
popup_set_callback(popup, NULL);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(context->view_dispatcher, 1);
furi_delay_ms(1050);
// Clear view
//Popup* popup = subghz->popup;
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_set_callback(popup, NULL);
popup_set_context(popup, NULL);
popup_set_timeout(popup, 0);
popup_disable_timeout(popup);
// TextInput
view_dispatcher_remove_view(context->view_dispatcher, 0);
text_input_free(context->text_input);
// Popup
view_dispatcher_remove_view(context->view_dispatcher, 1);
popup_free(context->popup);
} else {
backpressed = false;
}
}

View File

@@ -1,6 +0,0 @@
#include "../subbrute.h"
void subbrute_scene_save_name_on_enter(SubBruteState* context);
void subbrute_scene_save_name_on_exit(SubBruteState* context);
void subbrute_scene_save_name_on_event(SubBruteEvent event, SubBruteState* context);
void subbrute_scene_save_name_on_tick(SubBruteState* context);

View File

@@ -1,121 +0,0 @@
#include "subbrute_scene_select_field.h"
void center_displayed_key(SubBruteState* context, uint8_t index) {
const char* key_cstr = string_get_cstr(context->key);
uint8_t str_index = (index * 3);
char display_menu[17] = {
'X', 'X', ' ', 'X', 'X', ' ', '<', 'X', 'X', '>', ' ', 'X', 'X', ' ', 'X', 'X', '\0'};
if(index > 1) {
display_menu[0] = key_cstr[str_index - 6];
display_menu[1] = key_cstr[str_index - 5];
} else {
display_menu[0] = ' ';
display_menu[1] = ' ';
}
if(index > 0) {
display_menu[3] = key_cstr[str_index - 3];
display_menu[4] = key_cstr[str_index - 2];
} else {
display_menu[3] = ' ';
display_menu[4] = ' ';
}
display_menu[7] = key_cstr[str_index];
display_menu[8] = key_cstr[str_index + 1];
if((str_index + 4) <= (uint8_t)strlen(key_cstr)) {
display_menu[11] = key_cstr[str_index + 3];
display_menu[12] = key_cstr[str_index + 4];
} else {
display_menu[11] = ' ';
display_menu[12] = ' ';
}
if((str_index + 8) <= (uint8_t)strlen(key_cstr)) {
display_menu[14] = key_cstr[str_index + 6];
display_menu[15] = key_cstr[str_index + 7];
} else {
display_menu[14] = ' ';
display_menu[15] = ' ';
}
string_reset(context->notification_msg);
string_set_str(context->notification_msg, display_menu);
}
void subbrute_scene_select_field_on_enter(SubBruteState* context) {
string_clear(context->notification_msg);
}
void subbrute_scene_select_field_on_exit(SubBruteState* context) {
UNUSED(context);
}
void subbrute_scene_select_field_on_tick(SubBruteState* context) {
UNUSED(context);
}
void subbrute_scene_select_field_on_event(SubBruteEvent event, SubBruteState* context) {
if(event.evt_type == EventTypeKey) {
if(event.input_type == InputTypeShort) {
//const char* key_cstr = string_get_cstr(context->key);
// don't look, it's ugly but I'm a python dev so...
/*uint8_t nb_bytes = 0;
for(uint8_t i = 0; i < strlen(key_cstr); i++) {
if(' ' == key_cstr[i]) {
nb_bytes++;
}
}*/
switch(event.key) {
case InputKeyDown:
case InputKeyUp:
break;
case InputKeyLeft:
if(context->key_index > 0) {
context->key_index--;
}
break;
case InputKeyRight:
if(context->key_index < 7) {
context->key_index++;
}
break;
case InputKeyOk:
string_reset(context->notification_msg);
context->current_scene = SceneAttack;
break;
case InputKeyBack:
string_reset(context->notification_msg);
context->current_scene = SceneSelectFile;
break;
}
//FURI_LOG_D(TAG, "Position: %d/%d", context->key_index, nb_bytes);
}
}
}
void subbrute_scene_select_field_on_draw(Canvas* canvas, SubBruteState* context) {
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
// Frame
//canvas_draw_frame(canvas, 0, 0, 128, 64);
// Title
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 64, 10, AlignCenter, AlignTop, "use < > to select field");
char msg_index[18];
snprintf(msg_index, sizeof(msg_index), "Field index : %d", context->key_index);
canvas_draw_str_aligned(canvas, 64, 26, AlignCenter, AlignTop, msg_index);
center_displayed_key(context, context->key_index);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas, 64, 40, AlignCenter, AlignTop, string_get_cstr(context->notification_msg));
}

View File

@@ -1,8 +0,0 @@
#include "../subbrute.h"
void subbrute_scene_select_field_on_enter(SubBruteState* context);
void subbrute_scene_select_field_on_exit(SubBruteState* context);
void subbrute_scene_select_field_on_tick(SubBruteState* context);
void subbrute_scene_select_field_on_event(SubBruteEvent event, SubBruteState* context);
void subbrute_scene_select_field_on_draw(Canvas* canvas, SubBruteState* context);
void center_displayed_key(SubBruteState* context, uint8_t index);

View File

@@ -0,0 +1,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,77 @@
#include "../subbrute_i.h"
#include "../subbrute_custom_event.h"
#include <lib/subghz/protocols/registry.h>
#define TAG "SubBruteSceneLoadFile"
//void subbrute_scene_load_file_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_file_on_enter(void* context) {
furi_assert(context);
SubBruteState* instance = (SubBruteState*)context;
// Input events and views are managed by file_browser
string_t app_folder;
string_t load_path;
string_init(load_path);
string_init_set_str(app_folder, SUBBRUTE_PATH);
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, SUBBRUTE_FILE_EXT, &I_sub1_10px);
SubBruteFileResult load_result = SubBruteFileResultUnknown;
bool res =
dialog_file_browser_show(instance->dialogs, load_path, app_folder, &browser_options);
#ifdef FURI_DEBUG
FURI_LOG_D(
TAG,
"load_path: %s, app_folder: %s",
string_get_cstr(load_path),
string_get_cstr(app_folder));
#endif
if(res) {
load_result = subbrute_device_load_from_file(instance->device, load_path);
if(load_result == SubBruteFileResultOk) {
load_result = subbrute_device_attack_set(instance->device, SubBruteAttackLoadFile);
if(load_result == SubBruteFileResultOk) {
// Ready to run!
instance->device->state = SubBruteDeviceStateReady;
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);
string_t dialog_msg;
string_init(dialog_msg);
string_cat_printf(
dialog_msg, "Cannot parse\nfile: %s", subbrute_device_error_get_desc(load_result));
dialog_message_show_storage_error(instance->dialogs, string_get_cstr(dialog_msg));
string_clear(dialog_msg);
scene_manager_search_and_switch_to_previous_scene(
instance->scene_manager, SubBruteSceneStart);
}
string_clear(app_folder);
string_clear(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,61 @@
#include "../subbrute_i.h"
#include "../subbrute_custom_event.h"
#include "../views/subbrute_main_view.h"
#define TAG "SubBruteSceneStart"
void subbrute_scene_load_select_callback(SubBruteCustomEvent event, void* context) {
furi_assert(context);
SubBruteState* instance = (SubBruteState*)context;
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_scene_load_select_callback");
#endif
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->file_key);
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) {
instance->device->load_index = subbrute_main_view_get_index(instance->view_main);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "load_index: %d", instance->device->load_index);
#endif
scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack);
consumed = true;
}
} 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,83 @@
#include "../subbrute_i.h"
#include "../subbrute_custom_event.h"
#include "../views/subbrute_attack_view.h"
#include "../helpers/subbrute_worker.h"
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);
}
void subbrute_scene_run_attack_on_exit(void* context) {
furi_assert(context);
SubBruteState* instance = (SubBruteState*)context;
notification_message(instance->notifications, &sequence_blink_stop);
}
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_attack_view_init_values(
view,
(uint8_t)instance->device->attack,
instance->device->max_value,
instance->device->key_index,
true);
// Start worker if not started
subbrute_worker_init_manual_transmit(
instance->worker,
instance->device->frequency,
instance->device->preset,
string_get_cstr(instance->device->protocol_name));
}
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) {
if(event.event == SubBruteCustomEventTypeTransmitNotStarted ||
event.event == SubBruteCustomEventTypeTransmitFinished ||
event.event == SubBruteCustomEventTypeBackPressed) {
// Stop transmit
scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack);
consumed = true;
}
} else if(event.type == SceneManagerEventTypeTick) {
if(subbrute_worker_can_transmit(instance->worker)) {
// Blink
notification_message(instance->notifications, &sequence_blink_yellow_100);
if(subbrute_worker_manual_transmit(instance->worker, instance->device->payload)) {
// Make payload for new iteration or exit
if(instance->device->key_index + 1 > instance->device->max_value) {
// End of list
scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack);
} else {
instance->device->key_index++;
subbrute_attack_view_set_current_step(view, instance->device->key_index);
subbrute_device_create_packet_parsed(
instance->device, instance->device->key_index);
}
}
// Stop
notification_message(instance->notifications, &sequence_blink_stop);
}
consumed = true;
}
return consumed;
}

View File

@@ -0,0 +1,87 @@
#include <m-string.h>
#include <subghz/types.h>
#include <lib/toolbox/random_name.h>
#include <gui/modules/validators.h>
#include <lib/toolbox/path.h>
#include "../subbrute_i.h"
#include "../subbrute_custom_event.h"
#define TAG "SubBruteSceneSaveFile"
void subbrute_scene_save_name_on_enter(void* context) {
SubBruteState* instance = (SubBruteState*)context;
SubBruteDevice* device = instance->device;
// Setup view
TextInput* text_input = instance->text_input;
set_random_name(device->text_store, sizeof(device->text_store));
text_input_set_header_text(text_input, "Name of file");
text_input_set_result_callback(
text_input,
subbrute_text_input_callback,
instance,
device->text_store,
SUBBRUTE_MAX_LEN_NAME,
true);
string_set_str(device->load_path, SUBBRUTE_PATH);
ValidatorIsFile* validator_is_file =
validator_is_file_alloc_init(string_get_cstr(device->load_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->device->text_store);
#endif
bool success = false;
if(strcmp(instance->device->text_store, "")) {
string_cat_printf(
instance->device->load_path,
"/%s%s",
instance->device->text_store,
SUBBRUTE_FILE_EXT);
if(subbrute_device_save_file(
instance->device, string_get_cstr(instance->device->load_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);
string_reset(instance->device->load_path);
}

View File

@@ -0,0 +1,51 @@
#include "../subbrute_i.h"
#include "../subbrute_custom_event.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,177 @@
#include "../subbrute_i.h"
#include "../subbrute_custom_event.h"
#include "../views/subbrute_attack_view.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);
}
void subbrute_scene_setup_attack_on_enter(void* context) {
furi_assert(context);
SubBruteState* instance = (SubBruteState*)context;
SubBruteAttackView* view = instance->view_attack;
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Enter Attack: %d", instance->device->attack);
#endif
subbrute_attack_view_init_values(
view,
instance->device->attack,
instance->device->max_value,
instance->device->key_index,
false);
subbrute_worker_init_manual_transmit(
instance->worker,
instance->device->frequency,
instance->device->preset,
string_get_cstr(instance->device->protocol_name));
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_manual_transmit_stop(instance->worker);
notification_message(instance->notifications, &sequence_blink_stop);
}
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) {
subbrute_device_create_packet_parsed(instance->device, instance->device->key_index);
scene_manager_next_scene(instance->scene_manager, SubBruteSceneRunAttack);
} else if(event.event == SubBruteCustomEventTypeSaveFile) {
subbrute_worker_manual_transmit_stop(instance->worker);
subbrute_attack_view_init_values(
view,
instance->device->attack,
instance->device->max_value,
instance->device->key_index,
false);
scene_manager_next_scene(instance->scene_manager, SubBruteSceneSaveName);
} else if(event.event == SubBruteCustomEventTypeBackPressed) {
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "SubBruteCustomEventTypeBackPressed");
#endif
instance->device->key_index = 0x00;
//subbrute_attack_view_stop_worker(view);
subbrute_attack_view_init_values(
view,
instance->device->attack,
instance->device->max_value,
instance->device->key_index,
false);
scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart);
} else if(event.event == SubBruteCustomEventTypeChangeStepUp) {
// +1
if((instance->device->key_index + 1) - instance->device->max_value == 1) {
instance->device->key_index = 0x00;
} else {
uint64_t value = instance->device->key_index + 1;
if(value == instance->device->max_value) {
instance->device->key_index = value;
} else {
instance->device->key_index = value % instance->device->max_value;
}
}
subbrute_attack_view_set_current_step(view, instance->device->key_index);
} else if(event.event == SubBruteCustomEventTypeChangeStepUpMore) {
// +100
uint64_t value = instance->device->key_index + 100;
if(value == instance->device->max_value) {
instance->device->key_index += value;
} else {
instance->device->key_index = value % instance->device->max_value;
}
subbrute_attack_view_set_current_step(view, instance->device->key_index);
} else if(event.event == SubBruteCustomEventTypeChangeStepDown) {
// -1
if(instance->device->key_index - 1 == 0) {
instance->device->key_index = 0x00;
} else if(instance->device->key_index == 0) {
instance->device->key_index = instance->device->max_value;
} else {
uint64_t value = ((instance->device->key_index - 1) + instance->device->max_value);
if(value == instance->device->max_value) {
instance->device->key_index = value;
} else {
instance->device->key_index = value % instance->device->max_value;
}
}
subbrute_attack_view_set_current_step(view, instance->device->key_index);
} else if(event.event == SubBruteCustomEventTypeChangeStepDownMore) {
// -100
uint64_t value = ((instance->device->key_index - 100) + instance->device->max_value);
if(value == instance->device->max_value) {
instance->device->key_index = value;
} else {
instance->device->key_index = value % instance->device->max_value;
}
subbrute_attack_view_set_current_step(view, instance->device->key_index);
} else if(event.event == SubBruteCustomEventTypeTransmitCustom) {
if(subbrute_worker_can_transmit(instance->worker)) {
// Blink
notification_message(instance->notifications, &sequence_blink_green_100);
// if(!subbrute_attack_view_is_worker_running(view)) {
// subbrute_attack_view_start_worker(
// view,
// instance->device->frequency,
// instance->device->preset,
// string_get_cstr(instance->device->protocol_name));
// }
subbrute_device_create_packet_parsed(
instance->device, instance->device->key_index);
subbrute_worker_manual_transmit(instance->worker, instance->device->payload);
// Stop
notification_message(instance->notifications, &sequence_blink_stop);
}
}
consumed = true;
}
// if(event.type == SceneManagerEventTypeCustom) {
// switch(event.event) {
// case SubBruteCustomEventTypeMenuSelected:
// with_view_model(
// view, (SubBruteMainViewModel * model) {
// instance->menu_index = model->index;
// return false;
// });
// scene_manager_next_scene(instance->scene_manager, SubBruteSceneLoadFile);
// consumed = true;
// break;
// case SubBruteCustomEventTypeLoadFile:
// with_view_model(
// view, (SubBruteMainViewModel * model) {
// instance->menu_index = model->index;
// return false;
// });
// scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack);
// consumed = true;
// break;
// }
// }
return consumed;
}

View File

@@ -0,0 +1,66 @@
#include "../subbrute_i.h"
#include "../subbrute_custom_event.h"
#include "../views/subbrute_main_view.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, NULL);
view_dispatcher_switch_to_view(instance->view_dispatcher, instance->current_view);
}
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: %d", event.event);
#endif
if(event.event == SubBruteCustomEventTypeMenuSelected) {
SubBruteAttacks attack = subbrute_main_view_get_index(instance->view_main);
subbrute_device_attack_set(instance->device, attack);
scene_manager_next_scene(instance->scene_manager, SubBruteSceneSetupAttack);
consumed = true;
} else if(event.event == SubBruteCustomEventTypeLoadFile) {
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

@@ -1,267 +1,305 @@
#include <furi.h>
#include <furi_hal.h>
#include <input/input.h>
#include <m-string.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 <dialogs/dialogs.h>
#include "subbrute.h"
#include "subbrute_i.h"
#include "subbrute_custom_event.h"
#include "scene/subbrute_scene_load_file.h"
#include "scene/subbrute_scene_select_field.h"
#include "scene/subbrute_scene_run_attack.h"
#include "scene/subbrute_scene_entrypoint.h"
#include "scene/subbrute_scene_save_name.h"
#define TAG "SubBruteApp"
static void draw_callback(Canvas* const canvas, void* ctx) {
SubBruteState* subbrute_state = (SubBruteState*)acquire_mutex((ValueMutex*)ctx, 100);
static const char* subbrute_menu_names[] = {
[SubBruteAttackCAME12bit307] = "CAME 12bit 307mhz",
[SubBruteAttackCAME12bit433] = "CAME 12bit 433mhz",
[SubBruteAttackCAME12bit868] = "CAME 12bit 868mhz",
[SubBruteAttackChamberlain9bit315] = "Chamberlain 9bit 315mhz",
[SubBruteAttackChamberlain9bit390] = "Chamberlain 9bit 390mhz",
[SubBruteAttackLinear10bit300] = "Linear 10bit 300mhz",
[SubBruteAttackLinear10bit310] = "Linear 10bit 310mhz",
[SubBruteAttackNICE12bit433] = "NICE 12bit 433mhz",
[SubBruteAttackNICE12bit868] = "NICE 12bit 868mhz",
[SubBruteAttackLoadFile] = "BF existing dump",
[SubBruteAttackTotalCount] = "Total Count",
};
if(subbrute_state == NULL) {
return;
}
static const char* subbrute_menu_names_small[] = {
[SubBruteAttackCAME12bit307] = "CAME 307mhz",
[SubBruteAttackCAME12bit433] = "CAME 433mhz",
[SubBruteAttackCAME12bit868] = "CAME 868mhz",
[SubBruteAttackChamberlain9bit315] = "Cham 315mhz",
[SubBruteAttackChamberlain9bit390] = "Cham 390mhz",
[SubBruteAttackLinear10bit300] = "Linear 300mhz",
[SubBruteAttackLinear10bit310] = "Linear 310mhz",
[SubBruteAttackNICE12bit433] = "NICE 433mhz",
[SubBruteAttackNICE12bit868] = "NICE 868mhz",
[SubBruteAttackLoadFile] = "Existing",
[SubBruteAttackTotalCount] = "Total Count",
};
// Draw correct Canvas
switch(subbrute_state->current_scene) {
case NoneScene:
case SceneSelectFile:
subbrute_scene_load_file_on_draw(canvas, subbrute_state);
break;
case SceneSelectField:
subbrute_scene_select_field_on_draw(canvas, subbrute_state);
break;
case SceneAttack:
subbrute_scene_run_attack_on_draw(canvas, subbrute_state);
break;
case SceneEntryPoint:
subbrute_scene_entrypoint_on_draw(canvas, subbrute_state);
break;
case SceneSaveName:
break;
}
release_mutex((ValueMutex*)ctx, subbrute_state);
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);
}
void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
furi_assert(event_queue);
SubBruteEvent event = {
.evt_type = EventTypeKey, .key = input_event->key, .input_type = input_event->type};
furi_message_queue_put(event_queue, &event, 100);
static bool subbrute_back_event_callback(void* context) {
furi_assert(context);
SubBruteState* instance = context;
return scene_manager_handle_back_event(instance->scene_manager);
}
static void timer_callback(FuriMessageQueue* event_queue) {
furi_assert(event_queue);
SubBruteEvent event = {
.evt_type = EventTypeTick, .key = InputKeyUp, .input_type = InputTypeRelease};
furi_message_queue_put(event_queue, &event, 100);
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* subbrute = malloc(sizeof(SubBruteState));
SubBruteState* instance = malloc(sizeof(SubBruteState));
string_init(subbrute->protocol);
string_init(subbrute->preset);
string_init(subbrute->file_path);
string_init(subbrute->file_path_tmp);
string_init_set(subbrute->notification_msg, "");
string_init(subbrute->candidate);
string_init(subbrute->flipper_format_string);
instance->scene_manager = scene_manager_alloc(&subbrute_scene_handlers, instance);
instance->view_dispatcher = view_dispatcher_alloc();
subbrute->previous_scene = NoneScene;
subbrute->current_scene = SceneSelectFile;
subbrute->is_running = true;
subbrute->is_attacking = false;
subbrute->key_index = 7;
subbrute->notify = furi_record_open(RECORD_NOTIFICATION);
instance->gui = furi_record_open(RECORD_GUI);
subbrute->view_dispatcher = view_dispatcher_alloc();
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
subbrute->dialogs = furi_record_open(RECORD_DIALOGS);
instance->dialogs = furi_record_open(RECORD_DIALOGS);
subbrute->preset_def = malloc(sizeof(SubGhzPresetDefinition));
// Notifications
instance->notifications = furi_record_open(RECORD_NOTIFICATION);
//subbrute->flipper_format = flipper_format_string_alloc();
//subbrute->environment = subghz_environment_alloc();
// Devices
instance->device = subbrute_device_alloc();
return subbrute;
// Worker
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));
// Loading
instance->loading = loading_alloc();
//instance->flipper_format = flipper_format_string_alloc();
//instance->environment = subghz_environment_alloc();
return instance;
}
void subbrute_free(SubBruteState* subbrute) {
//Dialog
furi_record_close(RECORD_DIALOGS);
void subbrute_free(SubBruteState* instance) {
furi_assert(instance);
notification_message(subbrute->notify, &sequence_blink_stop);
// SubBruteDevice
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "free SubBruteDevice");
#endif
subbrute_device_free(instance->device);
// SubBruteWorker
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "free SubBruteDevice");
#endif
subbrute_worker_stop(instance->worker);
subbrute_worker_free(instance->worker);
// Notifications
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "free Notifications");
#endif
notification_message(instance->notifications, &sequence_blink_stop);
furi_record_close(RECORD_NOTIFICATION);
instance->notifications = NULL;
view_dispatcher_free(subbrute->view_dispatcher);
// Loading
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "free loading");
#endif
loading_free(instance->loading);
string_clear(subbrute->preset);
string_clear(subbrute->candidate);
// View Main
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "free SubBruteViewMain");
#endif
view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewMain);
subbrute_main_view_free(instance->view_main);
// Path strings
string_clear(subbrute->file_path);
string_clear(subbrute->file_path_tmp);
string_clear(subbrute->notification_msg);
string_clear(subbrute->candidate);
string_clear(subbrute->flipper_format_string);
// View Attack
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "free SubBruteViewAttack");
#endif
view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewAttack);
subbrute_attack_view_free(instance->view_attack);
//flipper_format_free(subbrute->flipper_format);
//subghz_environment_free(subbrute->environment);
//subghz_receiver_free(subbrute->receiver);
// TextInput
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "free SubBruteViewTextInput");
#endif
view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewTextInput);
text_input_free(instance->text_input);
free(subbrute->preset_def);
// Custom Widget
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "free SubBruteViewWidget");
#endif
view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewWidget);
widget_free(instance->widget);
// Popup
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "free SubBruteViewPopup");
#endif
view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewPopup);
popup_free(instance->popup);
// ViewStack
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "free SubBruteViewStack");
#endif
view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewStack);
view_stack_free(instance->view_stack);
//Dialog
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "free RECORD_DIALOGS");
#endif
furi_record_close(RECORD_DIALOGS);
instance->dialogs = NULL;
// Scene manager
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "free scene_manager");
#endif
scene_manager_free(instance->scene_manager);
// View Dispatcher
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "free view_dispatcher");
#endif
view_dispatcher_free(instance->view_dispatcher);
// GUI
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "free RECORD_GUI");
#endif
furi_record_close(RECORD_GUI);
instance->gui = NULL;
// The rest
free(subbrute);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "free instance");
#endif
free(instance);
}
void subbrute_show_loading_popup(void* context, bool show) {
TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME);
SubBruteState* instance = context;
ViewStack* view_stack = instance->view_stack;
Loading* loading = instance->loading;
if(show) {
// Raise timer priority so that animations can play
vTaskPrioritySet(timer_task, configMAX_PRIORITIES - 1);
view_stack_add_view(view_stack, loading_get_view(loading));
} else {
view_stack_remove_view(view_stack, loading_get_view(loading));
// Restore default timer priority
vTaskPrioritySet(timer_task, configTIMER_TASK_PRIORITY);
}
}
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);
}
const char* subbrute_get_menu_name(SubBruteAttacks index) {
furi_assert(index < SubBruteAttackTotalCount);
return subbrute_menu_names[index];
}
const char* subbrute_get_small_menu_name(SubBruteAttacks index) {
furi_assert(index < SubBruteAttackTotalCount);
return subbrute_menu_names_small[index];
}
// ENTRYPOINT
int32_t subbrute_start(void* p) {
int32_t subbrute_app(void* p) {
UNUSED(p);
// Input
FURI_LOG_I(TAG, "Initializing input");
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(SubBruteEvent));
SubBruteState* subbrute_state = subbrute_alloc();
ValueMutex subbrute_state_mutex;
// Mutex
FURI_LOG_I(TAG, "Initializing flipfrid mutex");
if(!init_mutex(&subbrute_state_mutex, subbrute_state, sizeof(SubBruteState))) {
FURI_LOG_E(TAG, "cannot create mutex\r\n");
furi_message_queue_free(event_queue);
subbrute_free(subbrute_state);
return 255;
}
SubBruteState* instance = subbrute_alloc();
view_dispatcher_attach_to_gui(
instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen);
scene_manager_next_scene(instance->scene_manager, SubBruteSceneStart);
furi_hal_power_suppress_charge_enter();
// Configure view port
FURI_LOG_I(TAG, "Initializing viewport");
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, draw_callback, &subbrute_state_mutex);
view_port_input_callback_set(view_port, input_callback, event_queue);
// Configure timer
FURI_LOG_I(TAG, "Initializing timer");
FuriTimer* timer = furi_timer_alloc(timer_callback, FuriTimerTypePeriodic, event_queue);
furi_timer_start(timer, furi_kernel_get_tick_frequency() / 10); // 10 times per second
// Register view port in GUI
FURI_LOG_I(TAG, "Initializing gui");
subbrute_state->gui = furi_record_open(RECORD_GUI);
gui_add_view_port(subbrute_state->gui, view_port, GuiLayerFullscreen);
view_dispatcher_attach_to_gui(
subbrute_state->view_dispatcher, subbrute_state->gui, ViewDispatcherTypeFullscreen);
subbrute_state->current_scene = SceneEntryPoint;
// Init values
SubBruteEvent event;
while(subbrute_state->is_running) {
// Get next event
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 25);
if(event_status == FuriStatusOk) {
if(event.evt_type == EventTypeKey) {
//Handle event key
FURI_LOG_D(TAG, "EVENT ###");
switch(subbrute_state->current_scene) {
case SceneSelectFile:
subbrute_scene_load_file_on_event(event, subbrute_state);
break;
case SceneSelectField:
subbrute_scene_select_field_on_event(event, subbrute_state);
break;
case SceneSaveName:
subbrute_scene_save_name_on_event(event, subbrute_state);
break;
case SceneAttack:
subbrute_scene_run_attack_on_event(event, subbrute_state);
break;
case NoneScene:
case SceneEntryPoint:
subbrute_scene_entrypoint_on_event(event, subbrute_state);
break;
}
} else if(event.evt_type == EventTypeTick) {
//Handle event tick
if(subbrute_state->current_scene != subbrute_state->previous_scene) {
// Trigger Exit Scene
switch(subbrute_state->previous_scene) {
case SceneSelectFile:
subbrute_scene_load_file_on_exit(subbrute_state);
break;
case SceneSelectField:
subbrute_scene_select_field_on_exit(subbrute_state);
break;
case SceneAttack:
subbrute_scene_run_attack_on_exit(subbrute_state);
break;
case SceneEntryPoint:
subbrute_scene_entrypoint_on_exit(subbrute_state);
break;
case SceneSaveName:
subbrute_scene_save_name_on_exit(subbrute_state);
break;
case NoneScene:
break;
}
// Trigger Entry Scene
switch(subbrute_state->current_scene) {
case NoneScene:
case SceneSelectFile:
subbrute_scene_load_file_on_enter(subbrute_state);
break;
case SceneSelectField:
subbrute_scene_select_field_on_enter(subbrute_state);
break;
case SceneAttack:
subbrute_scene_run_attack_on_enter(subbrute_state);
break;
case SceneSaveName:
subbrute_scene_save_name_on_enter(subbrute_state);
break;
case SceneEntryPoint:
subbrute_scene_entrypoint_on_enter(subbrute_state);
break;
}
subbrute_state->previous_scene = subbrute_state->current_scene;
}
// Trigger Tick Scene
switch(subbrute_state->current_scene) {
case NoneScene:
case SceneSelectFile:
subbrute_scene_load_file_on_tick(subbrute_state);
break;
case SceneSelectField:
subbrute_scene_select_field_on_tick(subbrute_state);
break;
case SceneAttack:
//subbrute_scene_run_attack_on_tick(subbrute_state);
break;
case SceneEntryPoint:
subbrute_scene_entrypoint_on_tick(subbrute_state);
break;
case SceneSaveName:
subbrute_scene_save_name_on_tick(subbrute_state);
break;
}
view_port_update(view_port);
}
}
}
// Cleanup
furi_timer_stop(timer);
furi_timer_free(timer);
view_dispatcher_run(instance->view_dispatcher);
furi_hal_power_suppress_charge_exit();
FURI_LOG_I(TAG, "Cleaning up");
gui_remove_view_port(subbrute_state->gui, view_port);
view_port_free(view_port);
furi_message_queue_free(event_queue);
furi_record_close(RECORD_GUI);
subbrute_free(subbrute_state);
subbrute_free(instance);
return 0;
}

View File

@@ -1,110 +1,3 @@
#pragma once
#include <furi.h>
#include <furi_hal.h>
#include <input/input.h>
#include <gui/gui.h>
#include "m-string.h"
#include <toolbox/stream/stream.h>
#include <lib/subghz/transmitter.h>
#include <lib/subghz/receiver.h>
#include <flipper_format/flipper_format_i.h>
#include <dialogs/dialogs.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include <gui/view_dispatcher.h>
#include <gui/modules/text_input.h>
#include <gui/modules/popup.h>
#define TAG "SUBBRUTE"
typedef enum {
NoneScene,
SceneSelectFile,
SceneSelectField,
SceneAttack,
SceneEntryPoint,
SceneSaveName
} SubBruteScene;
typedef enum {
SubBruteAttackLoadFile,
SubBruteAttackCAME12bit307,
SubBruteAttackCAME12bit433,
SubBruteAttackCAME12bit868,
SubBruteAttackChamberlain9bit315,
SubBruteAttackChamberlain9bit390,
SubBruteAttackLinear10bit300,
SubBruteAttackLinear10bit310,
SubBruteAttackNICE12bit433,
SubBruteAttackNICE12bit868,
} SubBruteAttacks;
typedef enum {
EventTypeTick,
EventTypeKey,
EventTypeCustom,
} EventType;
typedef struct {
EventType evt_type;
InputKey key;
InputType input_type;
} SubBruteEvent;
// STRUCTS
typedef struct {
// Application stuff
bool is_running;
bool is_attacking;
bool is_thread_running;
bool close_thread_please;
SubBruteScene current_scene;
SubBruteScene previous_scene;
NotificationApp* notify;
Gui* gui;
ViewDispatcher* view_dispatcher;
TextInput* text_input;
Popup* popup;
// SubGhz Stuff
FuriThread* bruthread;
FlipperFormat* flipper_format;
SubGhzEnvironment* environment;
SubGhzTransmitter* transmitter;
SubGhzReceiver* receiver;
SubGhzProtocolDecoderBase* decoder_result;
SubGhzPresetDefinition* preset_def;
string_t preset;
Stream* stream;
string_t protocol;
uint32_t frequency;
uint32_t frequency_cal;
uint32_t repeat;
uint32_t bit;
string_t key;
uint32_t te;
// Context Stuff
DialogsApp* dialogs;
char file_name_tmp[64];
string_t file_path;
string_t file_path_tmp;
string_t notification_msg;
uint8_t key_index;
uint64_t payload;
string_t candidate;
uint8_t str_index;
string_t flipper_format_string;
SubBruteAttacks attack;
//Menu stuff
uint8_t menu_index;
// RAW stuff
string_t subbrute_raw_one;
string_t subbrute_raw_zero;
string_t subbrute_raw_stop;
} SubBruteState;
typedef struct SubBruteState SubBruteState;

View File

@@ -0,0 +1,28 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
typedef enum {
// Reserve first 100 events for button types and indexes, starting from 0
SubBruteCustomEventTypeReserved = 100,
SubBruteCustomEventTypeBackPressed,
SubBruteCustomEventTypeIndexSelected,
SubBruteCustomEventTypeTransmitStarted,
SubBruteCustomEventTypeTransmitFinished,
SubBruteCustomEventTypeTransmitNotStarted,
SubBruteCustomEventTypeTransmitCustom,
SubBruteCustomEventTypeSaveFile,
SubBruteCustomEventTypeSaveSuccess,
SubBruteCustomEventTypeChangeStepUp,
SubBruteCustomEventTypeChangeStepDown,
SubBruteCustomEventTypeChangeStepUpMore,
SubBruteCustomEventTypeChangeStepDownMore,
SubBruteCustomEventTypeMenuSelected,
SubBruteCustomEventTypeTextEditDone,
SubBruteCustomEventTypePopupClosed,
SubBruteCustomEventTypeLoadFile,
} SubBruteCustomEvent;

View File

@@ -0,0 +1,643 @@
#include "subbrute_device.h"
#include "subbrute_i.h"
#include <furi.h>
#include <furi_hal.h>
#include <furi_hal_subghz.h>
#include <stdint.h>
#include <stdbool.h>
#include <lib/subghz/types.h>
#include <lib/subghz/protocols/base.h>
#include <storage/storage.h>
#include <dialogs/dialogs.h>
#include <stream/stream.h>
#include <stream/buffered_file_stream.h>
#include <lib/toolbox/path.h>
#include <lib/flipper_format/flipper_format_i.h>
#define TAG "SubBruteDevice"
/**
* List of protocols
*/
static const char* protocol_came = "CAME";
static const char* protocol_cham_code = "Cham_Code";
static const char* protocol_linear = "Linear";
static const char* protocol_nice_flo = "Nice FLO";
static const char* protocol_princeton = "Princeton";
static const char* protocol_raw = "RAW";
/**
* Values to not use less memory for packet parse operations
*/
static const char* subbrute_key_file_start =
"Filetype: Flipper SubGhz Key File\nVersion: 1\nFrequency: %u\nPreset: %s\nProtocol: %s\nBit: %d";
static const char* subbrute_key_file_key = "%s\nKey: %s\n";
static const char* subbrute_key_file_princeton_end = "%s\nKey: %s\nTE: %d\n";
// Why nobody set in as const in all codebase?
static const char* preset_ook270_async = "FuriHalSubGhzPresetOok270Async";
static const char* preset_ook650_async = "FuriHalSubGhzPresetOok650Async";
static const char* preset_2fsk_dev238_async = "FuriHalSubGhzPreset2FSKDev238Async";
static const char* preset_2fsk_dev476_async = "FuriHalSubGhzPreset2FSKDev476Async";
static const char* preset_msk99_97_kb_async = "FuriHalSubGhzPresetMSK99_97KbAsync";
static const char* preset_gfs99_97_kb_async = "FuriHalSubGhzPresetGFS99_97KbAsync";
SubBruteDevice* subbrute_device_alloc() {
SubBruteDevice* instance = malloc(sizeof(SubBruteDevice));
instance->state = SubBruteDeviceStateIDLE;
instance->key_index = 0;
string_init(instance->load_path);
string_init(instance->preset_name);
string_init(instance->protocol_name);
instance->decoder_result = NULL;
instance->receiver = NULL;
instance->environment = NULL;
subbrute_device_attack_set_default_values(instance, SubBruteAttackCAME12bit307);
return instance;
}
void subbrute_device_free(SubBruteDevice* instance) {
furi_assert(instance);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_device_free");
#endif
// I don't know how to free this
instance->decoder_result = NULL;
if(instance->receiver != NULL) {
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subghz_receiver_free");
#endif
subghz_receiver_free(instance->receiver);
instance->receiver = NULL;
}
if(instance->environment != NULL) {
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subghz_environment_free");
#endif
subghz_environment_free(instance->environment);
instance->environment = NULL;
}
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "before free");
#endif
string_clear(instance->load_path);
string_clear(instance->preset_name);
string_clear(instance->protocol_name);
free(instance);
}
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
bool result = subbrute_device_create_packet_parsed(instance, instance->key_index);
if(!result) {
FURI_LOG_E(TAG, "subbrute_device_create_packet_parsed failed!");
//subbrute_device_notification_message(instance, &sequence_error);
return false;
}
Storage* storage = furi_record_open(RECORD_STORAGE);
Stream* stream = buffered_file_stream_alloc(storage);
result = false;
do {
if(!buffered_file_stream_open(stream, dev_file_name, FSAM_READ_WRITE, FSOM_OPEN_ALWAYS)) {
buffered_file_stream_close(stream);
break;
}
stream_write_cstring(stream, instance->payload);
result = true;
} while(false);
buffered_file_stream_close(stream);
stream_free(stream);
if(!result) {
FURI_LOG_E(TAG, "stream_write_string failed!");
//subbrute_device_notification_message(instance, &sequence_error);
}
furi_record_close(RECORD_STORAGE);
return result;
}
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 = "RAW 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;
}
bool subbrute_device_create_packet_parsed(SubBruteDevice* instance, uint64_t step) {
furi_assert(instance);
//char step_payload[32];
//memset(step_payload, '0', sizeof(step_payload));
memset(instance->payload, 0, sizeof(instance->payload));
string_t candidate;
string_init(candidate);
if(instance->attack == SubBruteAttackLoadFile) {
if(step >= sizeof(instance->file_key)) {
return false;
}
char subbrute_payload_byte[4];
string_set_str(candidate, instance->file_key);
snprintf(subbrute_payload_byte, 4, "%02X ", (uint8_t)step);
string_replace_at(candidate, instance->load_index * 3, 3, subbrute_payload_byte);
//snprintf(step_payload, sizeof(step_payload), "%02X", (uint8_t)instance->file_key[step]);
} else {
//snprintf(step_payload, sizeof(step_payload), "%16X", step);
//snprintf(step_payload, sizeof(step_payload), "%016llX", step);
string_t buffer;
string_init(buffer);
string_init_printf(buffer, "%16X", step);
int j = 0;
string_set_str(candidate, " ");
for(uint8_t i = 0; i < 16; i++) {
if(string_get_char(buffer, i) != ' ') {
string_set_char(candidate, i + j, string_get_char(buffer, i));
} else {
string_set_char(candidate, i + j, '0');
}
if(i % 2 != 0) {
j++;
}
}
string_clear(buffer);
}
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "candidate: %s, step: %d", string_get_cstr(candidate), step);
#endif
if(instance->has_tail) {
snprintf(
instance->payload,
sizeof(instance->payload),
subbrute_key_file_princeton_end,
instance->file_template,
string_get_cstr(candidate),
instance->te);
} else {
snprintf(
instance->payload,
sizeof(instance->payload),
subbrute_key_file_key,
instance->file_template,
string_get_cstr(candidate));
}
#ifdef FURI_DEBUG
//FURI_LOG_D(TAG, "payload: %s", instance->payload);
#endif
string_clear(candidate);
return true;
}
SubBruteFileResult subbrute_device_attack_set(SubBruteDevice* instance, SubBruteAttacks type) {
furi_assert(instance);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_device_attack_set: %d", type);
#endif
subbrute_device_attack_set_default_values(instance, type);
switch(type) {
case SubBruteAttackLoadFile:
// In this case values must be already set
// file_result =
// subbrute_device_load_from_file(instance, string_get_cstr(instance->load_path));
// if(file_result != SubBruteFileResultOk) {
// // Failed load file so failed to set attack type
// return file_result; // RETURN
// }
break;
case SubBruteAttackCAME12bit307:
case SubBruteAttackCAME12bit433:
case SubBruteAttackCAME12bit868:
if(type == SubBruteAttackCAME12bit307) {
instance->frequency = 307800000;
} else if(type == SubBruteAttackCAME12bit433) {
instance->frequency = 433920000;
} else /* ALWAYS TRUE if(type == SubBruteAttackCAME12bit868) */ {
instance->frequency = 868350000;
}
instance->bit = 12;
string_set_str(instance->protocol_name, protocol_came);
string_set_str(instance->preset_name, preset_ook650_async);
break;
case SubBruteAttackChamberlain9bit315:
instance->frequency = 315000000;
instance->bit = 9;
string_set_str(instance->protocol_name, protocol_cham_code);
string_set_str(instance->preset_name, preset_ook650_async);
break;
case SubBruteAttackChamberlain9bit390:
instance->frequency = 390000000;
instance->bit = 9;
string_set_str(instance->protocol_name, protocol_cham_code);
string_set_str(instance->preset_name, preset_ook650_async);
break;
case SubBruteAttackLinear10bit300:
instance->frequency = 300000000;
instance->bit = 10;
string_set_str(instance->protocol_name, protocol_linear);
string_set_str(instance->preset_name, preset_ook650_async);
break;
case SubBruteAttackLinear10bit310:
instance->frequency = 310000000;
instance->bit = 10;
string_set_str(instance->protocol_name, protocol_linear);
string_set_str(instance->preset_name, preset_ook650_async);
break;
case SubBruteAttackNICE12bit433:
instance->frequency = 433920000;
instance->bit = 12;
string_set_str(instance->protocol_name, protocol_nice_flo);
string_set_str(instance->preset_name, preset_ook650_async);
break;
case SubBruteAttackNICE12bit868:
instance->frequency = 868350000;
instance->bit = 12;
string_set_str(instance->protocol_name, protocol_nice_flo);
string_set_str(instance->preset_name, preset_ook650_async);
break;
default:
FURI_LOG_E(TAG, "Unknown attack type: %d", type);
return SubBruteFileResultProtocolNotFound; // RETURN
}
if(!furi_hal_subghz_is_tx_allowed(instance->frequency)) {
FURI_LOG_E(TAG, "Frequency invalid: %d", instance->frequency);
return SubBruteFileResultMissingOrIncorrectFrequency; // RETURN
}
// For non-file types we didn't set SubGhzProtocolDecoderBase
instance->environment = subghz_environment_alloc();
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;
if(type != SubBruteAttackLoadFile) {
instance->decoder_result = subghz_receiver_search_decoder_base_by_name(
instance->receiver, string_get_cstr(instance->protocol_name));
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;
}
} else {
// And here we need to set preset enum
instance->preset = subbrute_device_convert_preset(string_get_cstr(instance->preset_name));
protocol_check_result = SubBruteFileResultOk;
}
subghz_environment_free(instance->environment);
subghz_receiver_free(instance->receiver);
instance->receiver = NULL;
instance->environment = NULL;
if(protocol_check_result != SubBruteFileResultOk) {
return SubBruteFileResultProtocolNotFound;
}
instance->has_tail =
(strcmp(string_get_cstr(instance->protocol_name), protocol_princeton) == 0);
// Calc max value
if(instance->attack == SubBruteAttackLoadFile) {
instance->max_value = 0xFF;
} else {
string_t max_value_s;
string_init(max_value_s);
for(uint8_t i = 0; i < instance->bit; i++) {
string_cat_printf(max_value_s, "1");
}
instance->max_value = (uint64_t)strtol(string_get_cstr(max_value_s), NULL, 2);
string_clear(max_value_s);
}
// Now we are ready to set file template for using in the future with snprintf
// for sending attack payload
snprintf(
instance->file_template,
sizeof(instance->file_template),
subbrute_key_file_start,
instance->frequency,
string_get_cstr(instance->preset_name),
string_get_cstr(instance->protocol_name),
instance->bit);
// strncat(instance->file_template, "\n", sizeof(instance->file_template));
// strncat(instance->file_template, subbrute_key_file_key, sizeof(instance->file_template));
// if(instance->has_tail) {
// strncat(
// instance->file_template,
// subbrute_key_file_princeton_end,
// sizeof(instance->file_template));
// }
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "tail: %d, file_template: %s", instance->has_tail, instance->file_template);
#endif
// Init payload
subbrute_device_create_packet_parsed(instance, instance->key_index);
return SubBruteFileResultOk;
}
uint8_t subbrute_device_load_from_file(SubBruteDevice* instance, string_t file_path) {
furi_assert(instance);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "subbrute_device_load_from_file: %s", string_get_cstr(file_path));
#endif
SubBruteFileResult result = SubBruteFileResultUnknown;
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
string_t temp_str;
string_init(temp_str);
uint32_t temp_data32;
instance->environment = subghz_environment_alloc();
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, string_get_cstr(file_path))) {
FURI_LOG_E(TAG, "Error open file %s", string_get_cstr(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)) {
instance->frequency = temp_data32;
if(!furi_hal_subghz_is_tx_allowed(instance->frequency)) {
result = SubBruteFileResultFrequencyNotAllowed;
break;
}
} else {
FURI_LOG_E(TAG, "Missing or incorrect Frequency");
result = SubBruteFileResultMissingOrIncorrectFrequency;
break;
}
// Preset
if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) {
FURI_LOG_E(TAG, "Preset FAIL");
result = SubBruteFileResultPresetInvalid;
} else {
string_init_set_str(instance->preset_name, string_get_cstr(temp_str));
}
// Protocol
if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) {
FURI_LOG_E(TAG, "Missing Protocol");
result = SubBruteFileResultMissingProtocol;
break;
} else {
string_init_set_str(instance->protocol_name, string_get_cstr(temp_str));
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Protocol: %s", string_get_cstr(instance->protocol_name));
#endif
}
instance->decoder_result = subghz_receiver_search_decoder_base_by_name(
instance->receiver, string_get_cstr(instance->protocol_name));
if(!instance->decoder_result ||
strcmp(string_get_cstr(instance->protocol_name), "RAW") == 0) {
FURI_LOG_E(TAG, "RAW 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
else {
FURI_LOG_D(TAG, "Decoder: %s", instance->decoder_result->protocol->name);
}
#endif
// instance->decoder_result = subghz_receiver_search_decoder_base_by_name(
// instance->receiver, string_get_cstr(instance->protocol_name));
//
// if(!instance->decoder_result) {
// FURI_LOG_E(TAG, "Protocol not found");
// result = SubBruteFileResultProtocolNotFound;
// break;
// }
// Bit
if(!flipper_format_read_uint32(fff_data_file, "Bit", &temp_data32, 1)) {
FURI_LOG_E(TAG, "Missing or incorrect Bit");
result = SubBruteFileResultMissingOrIncorrectBit;
break;
} else {
instance->bit = temp_data32;
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Bit: %d", instance->bit);
#endif
}
// Key
if(!flipper_format_read_string(fff_data_file, "Key", temp_str)) {
FURI_LOG_E(TAG, "Missing or incorrect Key");
result = SubBruteFileResultMissingOrIncorrectKey;
break;
} else {
snprintf(
instance->file_key, sizeof(instance->file_key), "%s", string_get_cstr(temp_str));
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Key: %s", instance->file_key);
#endif
}
// 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->te = temp_data32;
instance->has_tail = true;
}
// Repeat
if(flipper_format_read_uint32(fff_data_file, "Repeat", &temp_data32, 1)) {
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Repeat: %d", temp_data32);
#endif
instance->repeat = temp_data32;
} else {
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Repeat: 3 (default)");
#endif
instance->repeat = 3;
}
result = SubBruteFileResultOk;
} while(0);
string_clear(temp_str);
flipper_format_file_close(fff_data_file);
flipper_format_free(fff_data_file);
furi_record_close(RECORD_STORAGE);
subghz_environment_free(instance->environment);
subghz_receiver_free(instance->receiver);
instance->decoder_result = NULL;
instance->receiver = NULL;
instance->environment = NULL;
if(result == SubBruteFileResultOk) {
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Loaded successfully");
#endif
}
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->key_index = 0x00;
instance->load_index = 0x00;
memset(instance->file_template, 0, sizeof(instance->file_template));
memset(instance->current_key, 0, sizeof(instance->current_key));
memset(instance->text_store, 0, sizeof(instance->text_store));
memset(instance->payload, 0, sizeof(instance->payload));
if(default_attack != SubBruteAttackLoadFile) {
memset(instance->file_key, 0, sizeof(instance->file_key));
instance->max_value = (uint64_t)0x00;
string_clear(instance->protocol_name);
string_clear(instance->preset_name);
string_clear(instance->load_path);
string_init(instance->load_path);
string_init_set_str(instance->protocol_name, protocol_raw);
string_init_set_str(instance->preset_name, preset_ook650_async);
instance->preset = FuriHalSubGhzPresetOok650Async;
instance->repeat = 5;
instance->te = 0;
instance->has_tail = false;
}
#ifdef FURI_DEBUG
FURI_LOG_D(
TAG, "subbrute_device_attack_set_default_values done. has_tail: %d", instance->has_tail);
//furi_delay_ms(250);
#endif
}
FuriHalSubGhzPreset subbrute_device_convert_preset(const char* preset_name) {
string_t preset;
string_init_set_str(preset, preset_name);
FuriHalSubGhzPreset preset_value;
if(string_cmp_str(preset, preset_ook270_async) == 0) {
preset_value = FuriHalSubGhzPresetOok270Async;
} else if(string_cmp_str(preset, preset_ook650_async) == 0) {
preset_value = FuriHalSubGhzPresetOok650Async;
} else if(string_cmp_str(preset, preset_2fsk_dev238_async) == 0) {
preset_value = FuriHalSubGhzPreset2FSKDev238Async;
} else if(string_cmp_str(preset, preset_2fsk_dev476_async) == 0) {
preset_value = FuriHalSubGhzPreset2FSKDev476Async;
} else if(string_cmp_str(preset, preset_msk99_97_kb_async) == 0) {
preset_value = FuriHalSubGhzPresetMSK99_97KbAsync;
} else if(string_cmp_str(preset, preset_gfs99_97_kb_async) == 0) {
preset_value = FuriHalSubGhzPresetMSK99_97KbAsync;
} else {
preset_value = FuriHalSubGhzPresetCustom;
}
string_clear(preset);
return preset_value;
}

View File

@@ -0,0 +1,99 @@
#pragma once
#include <lib/toolbox/stream/stream.h>
#include <gui/gui.h>
#include <dialogs/dialogs.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 {
SubBruteAttackCAME12bit307,
SubBruteAttackCAME12bit433,
SubBruteAttackCAME12bit868,
SubBruteAttackChamberlain9bit315,
SubBruteAttackChamberlain9bit390,
SubBruteAttackLinear10bit300,
SubBruteAttackLinear10bit310,
SubBruteAttackNICE12bit433,
SubBruteAttackNICE12bit868,
SubBruteAttackLoadFile,
SubBruteAttackTotalCount,
} SubBruteAttacks;
typedef enum {
SubBruteFileResultUnknown,
SubBruteFileResultOk,
SubBruteFileResultErrorOpenFile,
SubBruteFileResultMissingOrIncorrectHeader,
SubBruteFileResultFrequencyNotAllowed,
SubBruteFileResultMissingOrIncorrectFrequency,
SubBruteFileResultPresetInvalid,
SubBruteFileResultMissingProtocol,
SubBruteFileResultProtocolNotSupported,
SubBruteFileResultDynamicProtocolNotValid,
SubBruteFileResultProtocolNotFound,
SubBruteFileResultMissingOrIncorrectBit,
SubBruteFileResultMissingOrIncorrectKey,
SubBruteFileResultMissingOrIncorrectTe,
} SubBruteFileResult;
typedef enum {
SubBruteDeviceStateIDLE,
SubBruteDeviceStateReady,
SubBruteDeviceStateTx,
SubBruteDeviceStateFinished,
} SubBruteDeviceState;
typedef struct {
SubBruteDeviceState state;
// Current step
uint64_t key_index;
string_t load_path;
// Index of group to bruteforce in loaded file
uint8_t load_index;
SubGhzReceiver* receiver;
SubGhzProtocolDecoderBase* decoder_result;
SubGhzEnvironment* environment;
// Attack state
SubBruteAttacks attack;
char file_template[SUBBRUTE_TEXT_STORE_SIZE];
bool has_tail;
char payload[SUBBRUTE_TEXT_STORE_SIZE * 2];
uint64_t max_value;
// Loaded info for attack type
FuriHalSubGhzPreset preset;
string_t preset_name;
string_t protocol_name;
uint32_t frequency;
uint32_t repeat;
uint32_t bit;
char current_key[SUBBRUTE_PAYLOAD_SIZE];
uint32_t te;
char file_key[SUBBRUTE_MAX_LEN_NAME];
char text_store[SUBBRUTE_PAYLOAD_SIZE];
} 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);
bool subbrute_device_create_packet_parsed(SubBruteDevice* context, uint64_t step);
SubBruteFileResult subbrute_device_attack_set(SubBruteDevice* context, SubBruteAttacks type);
uint8_t subbrute_device_load_from_file(SubBruteDevice* context, string_t file_path);
FuriHalSubGhzPreset subbrute_device_convert_preset(const char* preset);
void subbrute_device_attack_set_default_values(SubBruteDevice* context, SubBruteAttacks default_attack);

View File

@@ -0,0 +1,83 @@
#pragma once
#include <furi.h>
#include <furi_hal.h>
#include <input/input.h>
#include "lib/toolbox/path.h"
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include <m-string.h>
#include <lib/toolbox/stream/stream.h>
#include <stream_buffer.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 <dialogs/dialogs.h>
#include <lib/subghz/protocols/base.h>
#include <lib/subghz/transmitter.h>
#include <lib/subghz/receiver.h>
#include <lib/subghz/environment.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include "subbrute_device.h"
#include "helpers/subbrute_worker.h"
#include "subbrute.h"
#include "scenes/subbrute_scene.h"
#include "views/subbrute_attack_view.h"
#include "views/subbrute_main_view.h"
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;
Loading* loading;
// Views
SubBruteMainView* view_main;
SubBruteAttackView* view_attack;
SubBruteView current_view;
// Scene
SceneManager* scene_manager;
SubBruteDevice* device;
SubBruteWorker* worker;
//Menu stuff
// TODO: Do we need it?
uint8_t menu_index;
};
void subbrute_show_loading_popup(void* context, bool show);
void subbrute_text_input_callback(void* context);
void subbrute_popup_closed_callback(void* context);
const char* subbrute_get_menu_name(uint8_t index);
const char* subbrute_get_small_menu_name(uint8_t index);

View File

@@ -1,13 +0,0 @@
#include "subbrute_utils.h"
bool subbrute_is_frequency_allowed(SubBruteState* context) {
// I know you don't like it but laws are laws
// It's opensource so do whatever you want, but remember the risks :)
// (Yes, this comment is the only purpose of this function)
bool r = furi_hal_subghz_is_tx_allowed(context->frequency);
if(!r) {
FURI_LOG_E(TAG, "Frequency %d is not allowed in your region", context->frequency);
notification_message(context->notify, &sequence_single_vibro);
}
return r;
}

View File

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

View File

@@ -0,0 +1,374 @@
#include "subbrute_attack_view.h"
#include "../subbrute_i.h"
#include "assets_icons.h"
#include <input/input.h>
#include <gui/elements.h>
#include <gui/icon_i.h>
#include <gui/icon_animation_i.h>
#define TAG "SubBruteAttackView"
struct SubBruteAttackView {
View* view;
SubBruteAttackViewCallback callback;
void* context;
};
typedef struct {
SubBruteAttacks index;
uint64_t max_value;
uint64_t current_step;
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);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "InputKey: %d", event->key);
#endif
SubBruteAttackView* instance = context;
if(event->key == InputKeyBack && event->type == InputTypeShort) {
instance->callback(SubBruteCustomEventTypeBackPressed, instance->context);
with_view_model(
instance->view, (SubBruteAttackViewModel * model) {
model->is_attacking = false;
return true;
});
return true;
}
bool is_attacking = false;
with_view_model(
instance->view, (SubBruteAttackViewModel * model) {
is_attacking = model->is_attacking;
return false;
});
// if(!is_attacking) {
// instance->callback(SubBruteCustomEventTypeTransmitNotStarted, instance->context);
// } else {
// instance->callback(SubBruteCustomEventTypeTransmitStarted, instance->context);
// }
if(!is_attacking) {
if((event->type == InputTypeShort || event->type == InputTypeRepeat) &&
event->key == InputKeyOk) {
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "InputKey: %d OK", event->key);
#endif
with_view_model(
instance->view, (SubBruteAttackViewModel * model) {
model->is_attacking = true;
icon_animation_stop(model->icon);
icon_animation_start(model->icon);
return true;
});
instance->callback(SubBruteCustomEventTypeTransmitStarted, instance->context);
// } else if(event->key == InputKeyBack) {
// if(previous_scene == SubBruteSceneLoadFile) {
// instance->callback(SubBruteCustomEventTypeLoadFile, instance->context);
// } else {
// instance->callback(SubBruteCustomEventTypeBackPressed, instance->context);
// }
} else if(event->key == InputKeyUp) {
instance->callback(SubBruteCustomEventTypeSaveFile, instance->context);
} else if(event->key == InputKeyDown) {
instance->callback(SubBruteCustomEventTypeTransmitCustom, instance->context);
} else if(event->type == InputTypeShort) {
if(event->key == InputKeyLeft) {
instance->callback(SubBruteCustomEventTypeChangeStepDown, instance->context);
} else if(event->key == InputKeyRight) {
instance->callback(SubBruteCustomEventTypeChangeStepUp, instance->context);
}
// with_view_model(
// instance->view, (SubBruteAttackViewModel * model) {
// if(event->key == InputKeyLeft) {
// model->current_step =
// ((model->current_step - 1) + model->max_value) % model->max_value;
// } else if(event->key == InputKeyRight) {
// model->current_step = (model->current_step + 1) % model->max_value;
// }
// return true;
// });
// instance->callback(SubBruteCustomEventTypeChangeStep, instance->context);
} else if(event->type == InputTypeRepeat) {
if(event->key == InputKeyLeft) {
instance->callback(SubBruteCustomEventTypeChangeStepDownMore, instance->context);
} else if(event->key == InputKeyRight) {
instance->callback(SubBruteCustomEventTypeChangeStepUpMore, instance->context);
}
/*with_view_model(
instance->view, (SubBruteAttackViewModel * model) {
if(event->key == InputKeyLeft) {
model->current_step =
((model->current_step - 100) + model->max_value) % model->max_value;
} else if(event->key == InputKeyRight) {
model->current_step = (model->current_step + 100) % model->max_value;
}
return true;
});
instance->callback(SubBruteCustomEventTypeChangeStep, instance->context);*/
}
} else {
if((event->type == InputTypeShort || event->type == InputTypeRepeat) &&
(event->key == InputKeyOk || event->key == InputKeyBack)) {
with_view_model(
instance->view, (SubBruteAttackViewModel * model) {
model->is_attacking = false;
icon_animation_stop(model->icon);
icon_animation_start(model->icon);
return true;
});
instance->callback(SubBruteCustomEventTypeTransmitNotStarted, instance->context);
}
}
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);
return false;
});
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);
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);
return 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
with_view_model(
instance->view, (SubBruteAttackViewModel * model) {
model->current_step = current_step;
return true;
});
}
uint64_t subbrute_attack_view_get_current_step(SubBruteAttackView* instance) {
uint64_t current_step;
with_view_model(
instance->view, (SubBruteAttackViewModel * model) {
current_step = model->current_step;
return false;
});
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Get step: %d", current_step);
#endif
return current_step;
}
// 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) {
#ifdef FURI_DEBUG
FURI_LOG_D(
TAG, "init, index: %d, max_value: %d, current_step: %d", index, max_value, current_step);
#endif
with_view_model(
instance->view, (SubBruteAttackViewModel * model) {
model->max_value = max_value;
model->index = index;
model->current_step = current_step;
model->is_attacking = is_attacking;
if(is_attacking) {
icon_animation_start(model->icon);
} else {
icon_animation_stop(model->icon);
}
return 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);
return false;
});
}
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 = 9; //
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->width + icon_h_offset;
const uint8_t icon_v_offset = icon->height; //
const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset + 1;
const uint8_t x = 0;
const uint8_t y = 0;
canvas_draw_box(canvas, x, y, button_width, button_height);
#ifdef FURI_DEBUG
FURI_LOG_D(
TAG, "lbox, x: %d, y: %d, width: %d, height: %d", x, y, button_width, button_height);
#endif
// canvas_draw_line(canvas, x + button_width + 0, y, x + button_width + 0, y + button_height - 0); //
// canvas_draw_line(canvas, x + button_width + 1, y, x + button_width + 1, y + button_height - 1);
// canvas_draw_line(canvas, x + button_width + 2, y, x + button_width + 2, y + button_height - 2);
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 = 9;
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->width + icon_h_offset;
const uint8_t icon_v_offset = icon->height; // + vertical_offset;
const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset + 1;
const uint8_t x = canvas_width(canvas);
const uint8_t y = 0;
canvas_draw_box(canvas, x - button_width, y, button_width, button_height);
#ifdef FURI_DEBUG
FURI_LOG_D(
TAG,
"rbox, x: %d, y: %d, width: %d, height: %d",
x - button_width,
y,
button_width,
button_height);
#endif
// canvas_draw_line(canvas, x - button_width - 1, y, x + button_width - 1, y + button_height - 0);
// canvas_draw_line(canvas, x - button_width - 2, y, x + button_width - 2, y + button_height - 1);
// canvas_draw_line(canvas, x - button_width - 3, y, x + button_width - 3, y + button_height - 2);
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->width, y + icon_v_offset, icon);
canvas_invert_color(canvas);
}
void subbrute_attack_view_draw(Canvas* canvas, void* context) {
furi_assert(context);
SubBruteAttackViewModel* model = (SubBruteAttackViewModel*)context;
char buffer[26];
const char* attack_name = NULL;
attack_name = subbrute_get_menu_name(model->index);
// 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);
}
// Value
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, 17, AlignCenter, AlignTop, buffer);
canvas_set_font(canvas, FontSecondary);
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);
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 = model->icon->icon->width + icon_h_offset;
const uint8_t icon_v_offset = model->icon->icon->height; // + 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);
elements_button_center(canvas, "Stop");
}
}

View File

@@ -0,0 +1,28 @@
#pragma once
#include <gui/view.h>
#include "assets_icons.h"
#include <input/input.h>
#include <gui/elements.h>
#include <gui/icon.h>
#include <subghz/types.h>
#include "../subbrute_custom_event.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);
uint64_t subbrute_attack_view_get_current_step(SubBruteAttackView* instance);
void subbrute_attack_view_init_values(
SubBruteAttackView* instance,
uint8_t index,
uint64_t max_value,
uint64_t current_step,
bool is_attacking);

View File

@@ -0,0 +1,381 @@
#include "subbrute_main_view.h"
#include "../subbrute_i.h"
#include <input/input.h>
#include <gui/elements.h>
#include "assets_icons.h"
#include <gui/icon.h>
#define STATUS_BAR_Y_SHIFT 14
#define TAG "SubBruteMainView"
struct SubBruteMainView {
View* view;
SubBruteMainViewCallback callback;
void* context;
};
typedef struct {
uint8_t index;
uint8_t window_position;
bool is_select_byte;
const char* key_field;
} 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 center_displayed_key(string_t result, const char* key_cstr, uint8_t index) {
uint8_t str_index = (index * 3);
char display_menu[] = {
'X', 'X', ' ', 'X', 'X', ' ', '<', 'X', 'X', '>', ' ', 'X', 'X', ' ', 'X', 'X', '\0'};
if(key_cstr != NULL) {
if(index > 1) {
display_menu[0] = key_cstr[str_index - 6];
display_menu[1] = key_cstr[str_index - 5];
} else {
display_menu[0] = ' ';
display_menu[1] = ' ';
}
if(index > 0) {
display_menu[3] = key_cstr[str_index - 3];
display_menu[4] = key_cstr[str_index - 2];
} else {
display_menu[3] = ' ';
display_menu[4] = ' ';
}
display_menu[7] = key_cstr[str_index];
display_menu[8] = key_cstr[str_index + 1];
if((str_index + 4) <= (uint8_t)strlen(key_cstr)) {
display_menu[11] = key_cstr[str_index + 3];
display_menu[12] = key_cstr[str_index + 4];
} else {
display_menu[11] = ' ';
display_menu[12] = ' ';
}
if((str_index + 8) <= (uint8_t)strlen(key_cstr)) {
display_menu[14] = key_cstr[str_index + 6];
display_menu[15] = key_cstr[str_index + 7];
} else {
display_menu[14] = ' ';
display_menu[15] = ' ';
}
}
string_init_set_str(result, display_menu);
}
void subbrute_main_view_draw(Canvas* canvas, SubBruteMainViewModel* model) {
SubBruteMainViewModel* m = model;
// 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, 2, AlignCenter, AlignTop, "Sub-GHz Bruteforcer");
canvas_invert_color(canvas);
if(m->is_select_byte) {
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "key_field: %s", m->key_field);
#endif
char msg_index[18];
snprintf(msg_index, sizeof(msg_index), "Field index : %d", m->index);
canvas_draw_str_aligned(canvas, 64, 26, AlignCenter, AlignTop, msg_index);
string_t menu_items;
string_init(menu_items);
center_displayed_key(menu_items, m->key_field, m->index);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas, 64, 40, AlignCenter, AlignTop, string_get_cstr(menu_items));
elements_button_center(canvas, "Select");
elements_button_left(canvas, "<");
elements_button_right(canvas, ">");
string_reset(menu_items);
} else {
// Menu
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontSecondary);
uint8_t items_on_screen = 3;
const uint8_t item_height = 16;
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "window_position: %d, index: %d", model->window_position, m->index);
#endif
for(uint8_t position = 0; position < SubBruteAttackTotalCount; ++position) {
uint8_t item_position = position - model->window_position;
if(item_position < items_on_screen) {
const char* str = subbrute_get_menu_name(position);
if(m->index == position) {
canvas_draw_str_aligned(
canvas,
64,
9 + (item_position * item_height) + STATUS_BAR_Y_SHIFT,
AlignCenter,
AlignCenter,
str);
elements_frame(
canvas, 1, 1 + (item_position * item_height) + STATUS_BAR_Y_SHIFT, 124, 15);
} else {
canvas_draw_str_aligned(
canvas,
64,
9 + (item_position * item_height) + STATUS_BAR_Y_SHIFT,
AlignCenter,
AlignCenter,
str);
}
}
}
elements_scrollbar_pos(
canvas,
canvas_width(canvas),
STATUS_BAR_Y_SHIFT + 2,
canvas_height(canvas) - STATUS_BAR_Y_SHIFT,
m->index,
SubBruteAttackTotalCount);
}
}
bool subbrute_main_view_input(InputEvent* event, void* context) {
furi_assert(event);
furi_assert(context);
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "InputKey: %d", event->key);
#endif
if(event->key == InputKeyBack && event->type == InputTypeShort) {
return false;
}
SubBruteMainView* instance = context;
const uint8_t min_value = 0;
const uint8_t correct_total = SubBruteAttackTotalCount - 1;
uint8_t index = 0;
bool is_select_byte = false;
with_view_model(
instance->view, (SubBruteMainViewModel * model) {
is_select_byte = model->is_select_byte;
return false;
});
bool consumed = false;
if(!is_select_byte) {
if((event->type == InputTypeShort) || (event->type == InputTypeRepeat)) {
with_view_model(
instance->view, (SubBruteMainViewModel * model) {
bool ret = false;
uint8_t items_on_screen = 3;
if(event->key == InputKeyUp) {
if(model->index == min_value) {
model->index = correct_total;
} else {
model->index = CLAMP(model->index - 1, correct_total, min_value);
}
ret = true;
consumed = true;
} else if(event->key == InputKeyDown) {
if(model->index == correct_total) {
model->index = min_value;
} else {
model->index = CLAMP(model->index + 1, correct_total, min_value);
}
ret = true;
consumed = true;
}
if(ret) {
model->window_position = model->index;
if(model->window_position > 0) {
model->window_position -= 1;
}
if(SubBruteAttackTotalCount <= items_on_screen) {
model->window_position = 0;
} else {
if(model->window_position >=
(SubBruteAttackTotalCount - items_on_screen)) {
model->window_position =
(SubBruteAttackTotalCount - items_on_screen);
}
}
}
index = model->index;
return ret;
});
}
#ifdef FURI_DEBUG
with_view_model(
instance->view, (SubBruteMainViewModel * model) {
index = model->index;
return false;
});
FURI_LOG_I(TAG, "Index: %d", index);
#endif
if(event->key == InputKeyOk && event->type == InputTypeShort) {
if(index == SubBruteAttackLoadFile) {
instance->callback(SubBruteCustomEventTypeLoadFile, instance->context);
} else {
instance->callback(SubBruteCustomEventTypeMenuSelected, instance->context);
}
consumed = true;
}
} else {
if((event->type == InputTypeShort) || (event->type == InputTypeRepeat)) {
with_view_model(
instance->view, (SubBruteMainViewModel * model) {
if(event->key == InputKeyLeft) {
if(model->index > 0) {
model->index--;
}
} else if(event->key == InputKeyRight) {
if(model->index < 7) {
model->index++;
}
}
index = model->index;
return true;
});
}
#ifdef FURI_DEBUG
with_view_model(
instance->view, (SubBruteMainViewModel * model) {
index = model->index;
return false;
});
FURI_LOG_I(TAG, "Index: %d", index);
#endif
if(event->key == InputKeyOk && event->type == InputTypeShort) {
instance->callback(SubBruteCustomEventTypeIndexSelected, instance->context);
consumed = 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);
with_view_model(
instance->view, (SubBruteMainViewModel * model) {
model->index = 0;
model->window_position = 0;
model->key_field = NULL;
model->is_select_byte = false;
return 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,
const char* key_field) {
furi_assert(instance);
furi_assert(idx < SubBruteAttackTotalCount);
#ifdef FURI_DEBUG
FURI_LOG_I(TAG, "Set index: %d", idx);
#endif
with_view_model(
instance->view, (SubBruteMainViewModel * model) {
model->is_select_byte = is_select_byte;
model->key_field = key_field;
model->index = idx;
model->window_position = idx;
if(!is_select_byte) {
uint8_t items_on_screen = 3;
if(model->window_position > 0) {
model->window_position -= 1;
}
if(SubBruteAttackTotalCount <= items_on_screen) {
model->window_position = 0;
} else {
if(model->window_position >= (SubBruteAttackTotalCount - items_on_screen)) {
model->window_position = (SubBruteAttackTotalCount - items_on_screen);
}
}
}
return true;
});
}
SubBruteAttacks subbrute_main_view_get_index(SubBruteMainView* instance) {
furi_assert(instance);
uint8_t idx = 0;
with_view_model(
instance->view, (SubBruteMainViewModel * model) {
idx = model->index;
return false;
});
#ifdef FURI_DEBUG
FURI_LOG_D(TAG, "Get index: %d", idx);
#endif
return idx;
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include "../subbrute_custom_event.h"
#include <gui/view.h>
#include "assets_icons.h"
#include <input/input.h>
#include <gui/elements.h>
#include <gui/icon.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,
const char* key_field);
uint8_t subbrute_main_view_get_index(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);

View File

@@ -439,8 +439,8 @@ Function,-,acoshl,long double,long double
Function,-,acosl,long double,long double
Function,+,acquire_mutex,void*,"ValueMutex*, uint32_t"
Function,-,aligned_alloc,void*,"size_t, size_t"
Function,-,aligned_free,void,void*
Function,-,aligned_malloc,void*,"size_t, size_t"
Function,+,aligned_free,void,void*
Function,+,aligned_malloc,void*,"size_t, size_t"
Function,-,arc4random,__uint32_t,
Function,-,arc4random_buf,void,"void*, size_t"
Function,-,arc4random_uniform,__uint32_t,__uint32_t
1 entry status name type params
439 Function - acosl long double long double
440 Function + acquire_mutex void* ValueMutex*, uint32_t
441 Function - aligned_alloc void* size_t, size_t
442 Function - + aligned_free void void*
443 Function - + aligned_malloc void* size_t, size_t
444 Function - arc4random __uint32_t
445 Function - arc4random_buf void void*, size_t
446 Function - arc4random_uniform __uint32_t __uint32_t

View File

@@ -48,5 +48,7 @@ SECTIONS
{
*(.comment)
*(.comment.*)
*(.llvmbc)
*(.llvmcmd)
}
}

View File

@@ -1116,6 +1116,8 @@ typedef struct {
#define R_ARM_LDR_SBREL_11_0 35
#define R_ARM_ALU_SBREL_19_12 36
#define R_ARM_ALU_SBREL_27_20 37
#define R_ARM_THM_MOVW_ABS_NC 47 /* Direct 16 bit (Thumb32 MOVW) */
#define R_ARM_THM_MOVT_ABS 48 /* Direct high 16 bit */
#define R_ARM_GNU_VTENTRY 100
#define R_ARM_GNU_VTINHERIT 101
#define R_ARM_THM_PC11 102 /* thumb unconditional branch */

View File

@@ -255,6 +255,42 @@ static void elf_relocate_jmp_call(ELFFile* elf, Elf32_Addr relAddr, int type, El
(uint16_t)((lo & 0xc000) | (j1 << 13) | blx_bit | (j2 << 11) | imm11);
}
static void elf_relocate_mov(Elf32_Addr relAddr, int type, Elf32_Addr symAddr) {
uint16_t upper_insn = ((uint16_t*)relAddr)[0];
uint16_t lower_insn = ((uint16_t*)relAddr)[1];
/* MOV*<C> <Rd>,#<imm16>
*
* i = upper[10]
* imm4 = upper[3:0]
* imm3 = lower[14:12]
* imm8 = lower[7:0]
*
* imm16 = imm4:i:imm3:imm8
*/
uint32_t i = (upper_insn >> 10) & 1; /* upper[10] */
uint32_t imm4 = upper_insn & 0x000F; /* upper[3:0] */
uint32_t imm3 = (lower_insn >> 12) & 0x7; /* lower[14:12] */
uint32_t imm8 = lower_insn & 0x00FF; /* lower[7:0] */
int32_t addend = (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8; /* imm16 */
uint32_t addr = (symAddr + addend);
if (type == R_ARM_THM_MOVT_ABS) {
addr >>= 16; /* upper 16 bits */
} else {
addr &= 0x0000FFFF; /* lower 16 bits */
}
/* Re-encode */
((uint16_t*)relAddr)[0] = (upper_insn & 0xFBF0)
| (((addr >> 11) & 1) << 10) /* i */
| ((addr >> 12) & 0x000F); /* imm4 */
((uint16_t*)relAddr)[1] = (lower_insn & 0x8F00)
| (((addr >> 8) & 0x7) << 12) /* imm3 */
| (addr & 0x00FF); /* imm8 */
}
static bool elf_relocate_symbol(ELFFile* elf, Elf32_Addr relAddr, int type, Elf32_Addr symAddr) {
switch(type) {
case R_ARM_TARGET1:
@@ -268,6 +304,11 @@ static bool elf_relocate_symbol(ELFFile* elf, Elf32_Addr relAddr, int type, Elf3
FURI_LOG_D(
TAG, " R_ARM_THM_CALL/JMP relocated is 0x%08X", (unsigned int)*((uint32_t*)relAddr));
break;
case R_ARM_THM_MOVW_ABS_NC:
case R_ARM_THM_MOVT_ABS:
elf_relocate_mov(relAddr, type, symAddr);
FURI_LOG_D(TAG, " R_ARM_THM_MOVW_ABS_NC/MOVT_ABS relocated is 0x%08X", (unsigned int)*((uint32_t*)relAddr));
break;
default:
FURI_LOG_E(TAG, " Undefined relocation %d", type);
return false;