mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2024-12-01 01:27:48 +03:00
commit
7de9c957d2
@ -6,5 +6,5 @@ App(
|
||||
cdefines=["APP_FLIP_FRID"],
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
order=29,
|
||||
order=13,
|
||||
)
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "flipfrid_scene_run_attack.h"
|
||||
#include <gui/elements.h>
|
||||
|
||||
uint8_t counter = 0;
|
||||
#define TIME_BETWEEN_CARDS 5
|
||||
@ -182,7 +183,7 @@ void flipfrid_scene_run_attack_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Frame
|
||||
canvas_draw_frame(canvas, 0, 0, 128, 64);
|
||||
//canvas_draw_frame(canvas, 0, 0, 128, 64);
|
||||
|
||||
// Title
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
@ -202,11 +203,12 @@ void flipfrid_scene_run_attack_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||
canvas_draw_str_aligned(canvas, 64, 24, AlignCenter, AlignTop, uid);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
char start_stop_msg[20];
|
||||
//char start_stop_msg[20];
|
||||
if(context->is_attacking) {
|
||||
snprintf(start_stop_msg, sizeof(start_stop_msg), " Press OK to stop ");
|
||||
elements_button_center(canvas, "Stop");
|
||||
//snprintf(start_stop_msg, sizeof(start_stop_msg), " Press OK to stop ");
|
||||
} else {
|
||||
snprintf(start_stop_msg, sizeof(start_stop_msg), " Press OK to start ");
|
||||
elements_button_center(canvas, "Start");
|
||||
}
|
||||
canvas_draw_str_aligned(canvas, 64, 44, AlignCenter, AlignTop, start_stop_msg);
|
||||
//canvas_draw_str_aligned(canvas, 64, 44, AlignCenter, AlignTop, start_stop_msg);
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ void flipfrid_scene_select_field_on_draw(Canvas* canvas, FlipFridState* context)
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Frame
|
||||
canvas_draw_frame(canvas, 0, 0, 128, 64);
|
||||
//canvas_draw_frame(canvas, 0, 0, 128, 64);
|
||||
|
||||
// Title
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
|
@ -78,5 +78,6 @@ App(
|
||||
"wifi_scanner",
|
||||
"multi_converter",
|
||||
"flipfrid",
|
||||
"subbrute",
|
||||
],
|
||||
)
|
8
applications/subbrute/LICENSE.md
Normal file
8
applications/subbrute/LICENSE.md
Normal file
@ -0,0 +1,8 @@
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* @G4N4P4T1 wrote this file. As long as you retain this notice you
|
||||
* can do whatever you want with this stuff. If we meet some day, and you think
|
||||
* this stuff is worth it, you can buy me a beer in return.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
4
applications/subbrute/README.md
Normal file
4
applications/subbrute/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# FlipFrid
|
||||
|
||||
SubGhz Fuzzer
|
||||
select your base message, the field to fuzz and let's get fuzzy !
|
10
applications/subbrute/application.fam
Normal file
10
applications/subbrute/application.fam
Normal file
@ -0,0 +1,10 @@
|
||||
App(
|
||||
appid="subbrute",
|
||||
name="SubGHz Bruteforcer",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="subbrute_start",
|
||||
cdefines=["APP_SUB_BRUTE"],
|
||||
requires=["gui","dialogs"],
|
||||
stack_size=2 * 1024,
|
||||
order=11,
|
||||
)
|
198
applications/subbrute/scene/subbrute_scene_entrypoint.c
Normal file
198
applications/subbrute/scene/subbrute_scene_entrypoint.c
Normal file
@ -0,0 +1,198 @@
|
||||
#include "subbrute_scene_entrypoint.h"
|
||||
#include "../subbrute_utils.h"
|
||||
|
||||
string_t subbrute_menu_items[9];
|
||||
|
||||
void subbrute_scene_entrypoint_menu_callback(SubBruteState* context, uint32_t index) {
|
||||
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
|
||||
string_set_str(context->protocol, "RAW");
|
||||
context->repeat = 5;
|
||||
context->te = 0;
|
||||
context->attack = index;
|
||||
switch(index) {
|
||||
case SubBruteAttackLoadFile:
|
||||
context->current_scene = SceneSelectFile;
|
||||
break;
|
||||
case SubBruteAttackCAME12bit433:
|
||||
context->frequency = 433920000;
|
||||
context->bit = 12;
|
||||
string_set_str(context->protocol, "CAME");
|
||||
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
|
||||
if(!subbrute_is_frequency_allowed(context)) {
|
||||
return;
|
||||
}
|
||||
context->current_scene = SceneAttack;
|
||||
break;
|
||||
case SubBruteAttackCAME12bit868:
|
||||
context->frequency = 868350000;
|
||||
context->bit = 12;
|
||||
string_set_str(context->protocol, "CAME");
|
||||
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
|
||||
if(!subbrute_is_frequency_allowed(context)) {
|
||||
return;
|
||||
}
|
||||
context->current_scene = SceneAttack;
|
||||
break;
|
||||
case SubBruteAttackChamberlain9bit315:
|
||||
context->frequency = 315000000;
|
||||
context->bit = 9;
|
||||
string_set_str(context->protocol, "Cham_Code");
|
||||
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
|
||||
|
||||
if(!subbrute_is_frequency_allowed(context)) {
|
||||
return;
|
||||
}
|
||||
context->current_scene = SceneAttack;
|
||||
break;
|
||||
case SubBruteAttackChamberlain9bit390:
|
||||
context->frequency = 390000000;
|
||||
context->bit = 9;
|
||||
string_set_str(context->protocol, "Cham_Code");
|
||||
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
|
||||
|
||||
if(!subbrute_is_frequency_allowed(context)) {
|
||||
return;
|
||||
}
|
||||
context->current_scene = SceneAttack;
|
||||
break;
|
||||
case SubBruteAttackLinear10bit300:
|
||||
context->frequency = 300000000;
|
||||
context->bit = 10;
|
||||
string_set_str(context->protocol, "Linear");
|
||||
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
|
||||
if(!subbrute_is_frequency_allowed(context)) {
|
||||
return;
|
||||
}
|
||||
context->current_scene = SceneAttack;
|
||||
break;
|
||||
case SubBruteAttackLinear10bit310:
|
||||
context->frequency = 310000000;
|
||||
context->bit = 10;
|
||||
string_set_str(context->protocol, "Linear");
|
||||
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
|
||||
if(!subbrute_is_frequency_allowed(context)) {
|
||||
return;
|
||||
}
|
||||
context->current_scene = SceneAttack;
|
||||
break;
|
||||
case SubBruteAttackNICE12bit433:
|
||||
context->frequency = 433920000;
|
||||
context->bit = 12;
|
||||
string_set_str(context->protocol, "Nice FLO");
|
||||
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
|
||||
if(!subbrute_is_frequency_allowed(context)) {
|
||||
return;
|
||||
}
|
||||
context->current_scene = SceneAttack;
|
||||
break;
|
||||
case SubBruteAttackNICE12bit868:
|
||||
context->frequency = 868350000;
|
||||
context->bit = 12;
|
||||
string_set_str(context->protocol, "Nice FLO");
|
||||
string_set_str(context->preset, "FuriHalSubGhzPresetOok650Async");
|
||||
if(!subbrute_is_frequency_allowed(context)) {
|
||||
return;
|
||||
}
|
||||
context->current_scene = SceneAttack;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void subbrute_scene_entrypoint_on_enter(SubBruteState* context) {
|
||||
// Clear the previous payload
|
||||
context->menu_index = 0;
|
||||
for(uint32_t i = 0; i < 9; i++) {
|
||||
string_init(subbrute_menu_items[i]);
|
||||
}
|
||||
|
||||
string_set(subbrute_menu_items[0], "BF existing dump");
|
||||
string_set(subbrute_menu_items[1], "CAME 12bit 433mhz");
|
||||
string_set(subbrute_menu_items[2], "CAME 12bit 868mhz");
|
||||
string_set(subbrute_menu_items[3], "Chamberlain 9bit 315mhz");
|
||||
string_set(subbrute_menu_items[4], "Chamberlain 9bit 390mhz");
|
||||
string_set(subbrute_menu_items[5], "Linear 10bit 300mhz");
|
||||
string_set(subbrute_menu_items[6], "Linear 10bit 310mhz");
|
||||
string_set(subbrute_menu_items[7], "NICE 12bit 433mhz");
|
||||
string_set(subbrute_menu_items[8], "NICE 12bit 868mhz");
|
||||
}
|
||||
|
||||
void subbrute_scene_entrypoint_on_exit(SubBruteState* context) {
|
||||
UNUSED(context);
|
||||
for(uint32_t i = 0; i < 9; i++) {
|
||||
string_clear(subbrute_menu_items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void subbrute_scene_entrypoint_on_tick(SubBruteState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void subbrute_scene_entrypoint_on_event(SubBruteEvent event, SubBruteState* context) {
|
||||
if(event.evt_type == EventTypeKey) {
|
||||
if(event.input_type == InputTypeShort) {
|
||||
switch(event.key) {
|
||||
case InputKeyDown:
|
||||
if(context->menu_index < SubBruteAttackNICE12bit868) {
|
||||
context->menu_index++;
|
||||
}
|
||||
break;
|
||||
case InputKeyUp:
|
||||
if(context->menu_index > SubBruteAttackLoadFile) {
|
||||
context->menu_index--;
|
||||
}
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
case InputKeyRight:
|
||||
break;
|
||||
case InputKeyOk:
|
||||
subbrute_scene_entrypoint_menu_callback(context, context->menu_index);
|
||||
break;
|
||||
case InputKeyBack:
|
||||
context->is_running = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void subbrute_scene_entrypoint_on_draw(Canvas* canvas, SubBruteState* context) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Title
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 64, 6, AlignCenter, AlignTop, "SubGHz Fuzzer");
|
||||
|
||||
if(context->menu_index > SubBruteAttackLoadFile) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
24,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
string_get_cstr(subbrute_menu_items[context->menu_index - 1]));
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
36,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
string_get_cstr(subbrute_menu_items[context->menu_index]));
|
||||
|
||||
if(context->menu_index < SubBruteAttackNICE12bit868) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
48,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
string_get_cstr(subbrute_menu_items[context->menu_index + 1]));
|
||||
}
|
||||
}
|
8
applications/subbrute/scene/subbrute_scene_entrypoint.h
Normal file
8
applications/subbrute/scene/subbrute_scene_entrypoint.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#include "../subbrute.h"
|
||||
|
||||
void subbrute_scene_entrypoint_on_enter(SubBruteState* context);
|
||||
void subbrute_scene_entrypoint_on_exit(SubBruteState* context);
|
||||
void subbrute_scene_entrypoint_on_tick(SubBruteState* context);
|
||||
void subbrute_scene_entrypoint_on_event(SubBruteEvent event, SubBruteState* context);
|
||||
void subbrute_scene_entrypoint_on_draw(Canvas* canvas, SubBruteState* context);
|
212
applications/subbrute/scene/subbrute_scene_load_file.c
Normal file
212
applications/subbrute/scene/subbrute_scene_load_file.c
Normal file
@ -0,0 +1,212 @@
|
||||
#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);
|
||||
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);
|
||||
|
||||
// Input events and views are managed by file_select
|
||||
bool res = dialog_file_browser_show(
|
||||
context->dialogs, file_path, file_path, SUBGHZ_APP_EXTENSION, true, &I_sub1_10px, true);
|
||||
|
||||
if(res) {
|
||||
res = subbrute_load(context, string_get_cstr(file_path));
|
||||
}
|
||||
|
||||
string_clear(file_path);
|
||||
|
||||
return res;
|
||||
}
|
8
applications/subbrute/scene/subbrute_scene_load_file.h
Normal file
8
applications/subbrute/scene/subbrute_scene_load_file.h
Normal file
@ -0,0 +1,8 @@
|
||||
#include "../subbrute.h"
|
||||
|
||||
void subbrute_scene_load_file_on_enter(SubBruteState* context);
|
||||
void subbrute_scene_load_file_on_exit(SubBruteState* context);
|
||||
void subbrute_scene_load_file_on_tick(SubBruteState* context);
|
||||
void subbrute_scene_load_file_on_event(SubBruteEvent event, SubBruteState* context);
|
||||
void subbrute_scene_load_file_on_draw(Canvas* canvas, SubBruteState* context);
|
||||
bool subbrute_load_protocol_from_file(SubBruteState* context);
|
320
applications/subbrute/scene/subbrute_scene_run_attack.c
Normal file
320
applications/subbrute/scene/subbrute_scene_run_attack.c
Normal file
@ -0,0 +1,320 @@
|
||||
#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));
|
||||
|
||||
furi_hal_subghz_start_async_tx(subghz_transmitter_yield, context->transmitter);
|
||||
while(!(furi_hal_subghz_is_async_tx_complete())) {
|
||||
furi_delay_ms(5);
|
||||
}
|
||||
|
||||
furi_hal_subghz_stop_async_tx();
|
||||
furi_hal_subghz_idle();
|
||||
}
|
||||
|
||||
void prepare_emit(SubBruteState* context) {
|
||||
furi_hal_subghz_init();
|
||||
|
||||
context->transmitter =
|
||||
subghz_transmitter_alloc_init(context->environment, string_get_cstr(context->protocol));
|
||||
|
||||
furi_hal_subghz_reset();
|
||||
furi_hal_subghz_load_preset(str_to_preset(context->preset));
|
||||
|
||||
furi_hal_subghz_set_frequency_and_path(context->frequency);
|
||||
}
|
||||
|
||||
void clear_emit(SubBruteState* context) {
|
||||
furi_hal_subghz_stop_async_tx();
|
||||
furi_hal_subghz_sleep();
|
||||
|
||||
subghz_transmitter_free(context->transmitter);
|
||||
}
|
||||
/*
|
||||
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);
|
||||
subghz_transmitter_deserialize(context->transmitter, context->flipper_format);
|
||||
|
||||
subbrute_emit(context);
|
||||
}
|
||||
|
||||
void subbrute_send_packet(SubBruteState* context) {
|
||||
///if(string_cmp_str(context->protocol, "RAW") == 0) {
|
||||
// subbrute_send_raw_packet(context);
|
||||
//} else {
|
||||
subbrute_send_packet_parsed(context);
|
||||
//}
|
||||
string_clear(context->flipper_format_string);
|
||||
}
|
||||
|
||||
void subbrute_scene_run_attack_on_enter(SubBruteState* context) {
|
||||
if(!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->transmitter = subghz_transmitter_alloc_init(
|
||||
context->environment, string_get_cstr(context->protocol));
|
||||
prepare_emit(context);
|
||||
} else {
|
||||
toSave = false;
|
||||
}
|
||||
}
|
||||
|
||||
void subbrute_scene_run_attack_on_exit(SubBruteState* context) {
|
||||
if(!toSave) {
|
||||
clear_emit(context);
|
||||
}
|
||||
}
|
||||
|
||||
void subbrute_scene_run_attack_on_tick(SubBruteState* context) {
|
||||
if(!context->is_attacking || locked) {
|
||||
return;
|
||||
}
|
||||
if(0 != subbrute_counter) {
|
||||
locked = true;
|
||||
subbrute_send_packet(context);
|
||||
|
||||
if(context->payload == max_value) {
|
||||
context->payload = 0x00;
|
||||
subbrute_counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
} else {
|
||||
context->payload++;
|
||||
}
|
||||
locked = false;
|
||||
}
|
||||
if(subbrute_counter > SUBBRUTE_DELAY) {
|
||||
subbrute_counter = 0;
|
||||
} else {
|
||||
subbrute_counter++;
|
||||
}
|
||||
}
|
||||
|
||||
void subbrute_scene_run_attack_on_event(SubBruteEvent event, SubBruteState* context) {
|
||||
if(event.evt_type == EventTypeKey) {
|
||||
if(event.input_type == InputTypeShort) {
|
||||
switch(event.key) {
|
||||
case InputKeyDown:
|
||||
if(!context->is_attacking) {
|
||||
toSave = true;
|
||||
context->current_scene = SceneSaveName;
|
||||
}
|
||||
case InputKeyUp:
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
if(!context->is_attacking && context->payload > 0x00) {
|
||||
context->payload--;
|
||||
subbrute_send_packet(context);
|
||||
notification_message(context->notify, &sequence_blink_blue_10);
|
||||
}
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if(!context->is_attacking && context->payload < max_value) {
|
||||
context->payload++;
|
||||
subbrute_send_packet(context);
|
||||
notification_message(context->notify, &sequence_blink_blue_10);
|
||||
}
|
||||
break;
|
||||
case InputKeyOk:
|
||||
if(!context->is_attacking) {
|
||||
context->is_attacking = true;
|
||||
notification_message(context->notify, &sequence_blink_start_blue);
|
||||
} else {
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
}
|
||||
break;
|
||||
case InputKeyBack:
|
||||
locked = false;
|
||||
context->is_attacking = false;
|
||||
string_reset(context->notification_msg);
|
||||
context->payload = 0x00;
|
||||
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 (V) 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);
|
||||
}
|
8
applications/subbrute/scene/subbrute_scene_run_attack.h
Normal file
8
applications/subbrute/scene/subbrute_scene_run_attack.h
Normal file
@ -0,0 +1,8 @@
|
||||
#include "../subbrute.h"
|
||||
|
||||
void subbrute_scene_run_attack_on_enter(SubBruteState* context);
|
||||
void subbrute_scene_run_attack_on_exit(SubBruteState* context);
|
||||
void subbrute_scene_run_attack_on_tick(SubBruteState* context);
|
||||
void subbrute_scene_run_attack_on_event(SubBruteEvent event, SubBruteState* context);
|
||||
void subbrute_scene_run_attack_on_draw(Canvas* canvas, SubBruteState* context);
|
||||
void send_packet();
|
222
applications/subbrute/scene/subbrute_scene_save_name.c
Normal file
222
applications/subbrute/scene/subbrute_scene_save_name.c
Normal file
@ -0,0 +1,222 @@
|
||||
#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;
|
||||
}
|
||||
}
|
6
applications/subbrute/scene/subbrute_scene_save_name.h
Normal file
6
applications/subbrute/scene/subbrute_scene_save_name.h
Normal file
@ -0,0 +1,6 @@
|
||||
#include "../subbrute.h"
|
||||
|
||||
void subbrute_scene_save_name_on_enter(SubBruteState* context);
|
||||
void subbrute_scene_save_name_on_exit(SubBruteState* context);
|
||||
void subbrute_scene_save_name_on_event(SubBruteEvent event, SubBruteState* context);
|
||||
void subbrute_scene_save_name_on_tick(SubBruteState* context);
|
121
applications/subbrute/scene/subbrute_scene_select_field.c
Normal file
121
applications/subbrute/scene/subbrute_scene_select_field.c
Normal file
@ -0,0 +1,121 @@
|
||||
#include "subbrute_scene_select_field.h"
|
||||
|
||||
void center_displayed_key(SubBruteState* context, uint8_t index) {
|
||||
const char* key_cstr = string_get_cstr(context->key);
|
||||
uint8_t str_index = (index * 3);
|
||||
|
||||
char display_menu[17] = {
|
||||
'X', 'X', ' ', 'X', 'X', ' ', '<', 'X', 'X', '>', ' ', 'X', 'X', ' ', 'X', 'X', '\0'};
|
||||
|
||||
if(index > 1) {
|
||||
display_menu[0] = key_cstr[str_index - 6];
|
||||
display_menu[1] = key_cstr[str_index - 5];
|
||||
} else {
|
||||
display_menu[0] = ' ';
|
||||
display_menu[1] = ' ';
|
||||
}
|
||||
|
||||
if(index > 0) {
|
||||
display_menu[3] = key_cstr[str_index - 3];
|
||||
display_menu[4] = key_cstr[str_index - 2];
|
||||
} else {
|
||||
display_menu[3] = ' ';
|
||||
display_menu[4] = ' ';
|
||||
}
|
||||
|
||||
display_menu[7] = key_cstr[str_index];
|
||||
display_menu[8] = key_cstr[str_index + 1];
|
||||
|
||||
if((str_index + 4) <= (uint8_t)strlen(key_cstr)) {
|
||||
display_menu[11] = key_cstr[str_index + 3];
|
||||
display_menu[12] = key_cstr[str_index + 4];
|
||||
} else {
|
||||
display_menu[11] = ' ';
|
||||
display_menu[12] = ' ';
|
||||
}
|
||||
|
||||
if((str_index + 8) <= (uint8_t)strlen(key_cstr)) {
|
||||
display_menu[14] = key_cstr[str_index + 6];
|
||||
display_menu[15] = key_cstr[str_index + 7];
|
||||
} else {
|
||||
display_menu[14] = ' ';
|
||||
display_menu[15] = ' ';
|
||||
}
|
||||
|
||||
string_reset(context->notification_msg);
|
||||
string_set_str(context->notification_msg, display_menu);
|
||||
}
|
||||
|
||||
void subbrute_scene_select_field_on_enter(SubBruteState* context) {
|
||||
string_clear(context->notification_msg);
|
||||
}
|
||||
|
||||
void subbrute_scene_select_field_on_exit(SubBruteState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void subbrute_scene_select_field_on_tick(SubBruteState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void subbrute_scene_select_field_on_event(SubBruteEvent event, SubBruteState* context) {
|
||||
if(event.evt_type == EventTypeKey) {
|
||||
if(event.input_type == InputTypeShort) {
|
||||
//const char* key_cstr = string_get_cstr(context->key);
|
||||
|
||||
// don't look, it's ugly but I'm a python dev so...
|
||||
/*uint8_t nb_bytes = 0;
|
||||
for(uint8_t i = 0; i < strlen(key_cstr); i++) {
|
||||
if(' ' == key_cstr[i]) {
|
||||
nb_bytes++;
|
||||
}
|
||||
}*/
|
||||
|
||||
switch(event.key) {
|
||||
case InputKeyDown:
|
||||
case InputKeyUp:
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
if(context->key_index > 0) {
|
||||
context->key_index--;
|
||||
}
|
||||
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));
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
#include "../subbrute.h"
|
||||
|
||||
void subbrute_scene_select_field_on_enter(SubBruteState* context);
|
||||
void subbrute_scene_select_field_on_exit(SubBruteState* context);
|
||||
void subbrute_scene_select_field_on_tick(SubBruteState* context);
|
||||
void subbrute_scene_select_field_on_event(SubBruteEvent event, SubBruteState* context);
|
||||
void subbrute_scene_select_field_on_draw(Canvas* canvas, SubBruteState* context);
|
||||
void center_displayed_key(SubBruteState* context, uint8_t index);
|
269
applications/subbrute/subbrute.c
Normal file
269
applications/subbrute/subbrute.c
Normal file
@ -0,0 +1,269 @@
|
||||
#include "subbrute.h"
|
||||
|
||||
#include "scene/subbrute_scene_load_file.h"
|
||||
#include "scene/subbrute_scene_select_field.h"
|
||||
#include "scene/subbrute_scene_run_attack.h"
|
||||
#include "scene/subbrute_scene_entrypoint.h"
|
||||
#include "scene/subbrute_scene_save_name.h"
|
||||
|
||||
static void draw_callback(Canvas* const canvas, void* ctx) {
|
||||
SubBruteState* subbrute_state = (SubBruteState*)acquire_mutex((ValueMutex*)ctx, 100);
|
||||
|
||||
if(subbrute_state == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw correct Canvas
|
||||
switch(subbrute_state->current_scene) {
|
||||
case NoneScene:
|
||||
case SceneSelectFile:
|
||||
subbrute_scene_load_file_on_draw(canvas, subbrute_state);
|
||||
break;
|
||||
case SceneSelectField:
|
||||
subbrute_scene_select_field_on_draw(canvas, subbrute_state);
|
||||
break;
|
||||
case SceneAttack:
|
||||
subbrute_scene_run_attack_on_draw(canvas, subbrute_state);
|
||||
break;
|
||||
case SceneEntryPoint:
|
||||
subbrute_scene_entrypoint_on_draw(canvas, subbrute_state);
|
||||
break;
|
||||
case SceneSaveName:
|
||||
break;
|
||||
}
|
||||
|
||||
release_mutex((ValueMutex*)ctx, subbrute_state);
|
||||
}
|
||||
|
||||
void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
|
||||
furi_assert(event_queue);
|
||||
|
||||
SubBruteEvent event = {
|
||||
.evt_type = EventTypeKey, .key = input_event->key, .input_type = input_event->type};
|
||||
furi_message_queue_put(event_queue, &event, 100);
|
||||
}
|
||||
|
||||
static void timer_callback(FuriMessageQueue* event_queue) {
|
||||
furi_assert(event_queue);
|
||||
SubBruteEvent event = {
|
||||
.evt_type = EventTypeTick, .key = InputKeyUp, .input_type = InputTypeRelease};
|
||||
furi_message_queue_put(event_queue, &event, 100);
|
||||
}
|
||||
|
||||
SubBruteState* subbrute_alloc() {
|
||||
SubBruteState* subbrute = malloc(sizeof(SubBruteState));
|
||||
|
||||
string_init(subbrute->protocol);
|
||||
string_init(subbrute->preset);
|
||||
string_init(subbrute->file_path);
|
||||
string_init(subbrute->file_path_tmp);
|
||||
string_init_set(subbrute->notification_msg, "");
|
||||
string_init(subbrute->candidate);
|
||||
string_init(subbrute->flipper_format_string);
|
||||
|
||||
subbrute->previous_scene = NoneScene;
|
||||
subbrute->current_scene = SceneSelectFile;
|
||||
subbrute->is_running = true;
|
||||
subbrute->is_attacking = false;
|
||||
subbrute->key_index = 7;
|
||||
subbrute->notify = furi_record_open(RECORD_NOTIFICATION);
|
||||
|
||||
subbrute->view_dispatcher = view_dispatcher_alloc();
|
||||
|
||||
//Dialog
|
||||
subbrute->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
|
||||
subbrute->preset_def = malloc(sizeof(SubGhzPresetDefinition));
|
||||
|
||||
subbrute->flipper_format = flipper_format_string_alloc();
|
||||
subbrute->environment = subghz_environment_alloc();
|
||||
subbrute->receiver = subghz_receiver_alloc_init(subbrute->environment);
|
||||
subghz_receiver_set_filter(subbrute->receiver, SubGhzProtocolFlag_Decodable);
|
||||
|
||||
return subbrute;
|
||||
}
|
||||
|
||||
void subbrute_free(SubBruteState* subbrute) {
|
||||
//Dialog
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
|
||||
notification_message(subbrute->notify, &sequence_blink_stop);
|
||||
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
|
||||
view_dispatcher_free(subbrute->view_dispatcher);
|
||||
|
||||
string_clear(subbrute->preset);
|
||||
string_clear(subbrute->candidate);
|
||||
|
||||
// Path strings
|
||||
string_clear(subbrute->file_path);
|
||||
string_clear(subbrute->file_path_tmp);
|
||||
string_clear(subbrute->notification_msg);
|
||||
string_clear(subbrute->candidate);
|
||||
string_clear(subbrute->flipper_format_string);
|
||||
|
||||
flipper_format_free(subbrute->flipper_format);
|
||||
subghz_environment_free(subbrute->environment);
|
||||
subghz_receiver_free(subbrute->receiver);
|
||||
|
||||
free(subbrute->preset_def);
|
||||
|
||||
// The rest
|
||||
free(subbrute);
|
||||
}
|
||||
|
||||
// ENTRYPOINT
|
||||
int32_t subbrute_start(void* p) {
|
||||
UNUSED(p);
|
||||
// Input
|
||||
FURI_LOG_I(TAG, "Initializing input");
|
||||
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(SubBruteEvent));
|
||||
SubBruteState* subbrute_state = subbrute_alloc();
|
||||
ValueMutex subbrute_state_mutex;
|
||||
|
||||
// Mutex
|
||||
FURI_LOG_I(TAG, "Initializing flipfrid mutex");
|
||||
if(!init_mutex(&subbrute_state_mutex, subbrute_state, sizeof(SubBruteState))) {
|
||||
FURI_LOG_E(TAG, "cannot create mutex\r\n");
|
||||
furi_message_queue_free(event_queue);
|
||||
subbrute_free(subbrute_state);
|
||||
return 255;
|
||||
}
|
||||
|
||||
furi_hal_power_suppress_charge_enter();
|
||||
|
||||
// Configure view port
|
||||
FURI_LOG_I(TAG, "Initializing viewport");
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
105
applications/subbrute/subbrute.h
Normal file
105
applications/subbrute/subbrute.h
Normal file
@ -0,0 +1,105 @@
|
||||
#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,
|
||||
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;
|
||||
SubBruteScene current_scene;
|
||||
SubBruteScene previous_scene;
|
||||
NotificationApp* notify;
|
||||
Gui* gui;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
TextInput* text_input;
|
||||
Popup* popup;
|
||||
|
||||
// SubGhz Stuff
|
||||
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 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;
|
13
applications/subbrute/subbrute_utils.c
Normal file
13
applications/subbrute/subbrute_utils.c
Normal file
@ -0,0 +1,13 @@
|
||||
#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;
|
||||
}
|
4
applications/subbrute/subbrute_utils.h
Normal file
4
applications/subbrute/subbrute_utils.h
Normal file
@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#include "subbrute.h"
|
||||
|
||||
bool subbrute_is_frequency_allowed(SubBruteState* context);
|
Loading…
Reference in New Issue
Block a user