This commit is contained in:
Willy-JL
2023-06-08 01:27:49 +01:00
73 changed files with 3503 additions and 3447 deletions

View File

@@ -1,8 +0,0 @@
/*
* ----------------------------------------------------------------------------
* "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.
* ----------------------------------------------------------------------------
*/

View File

@@ -1,12 +0,0 @@
App(
appid="rfid_fuzzer",
name="RFID Fuzzer",
apptype=FlipperAppType.EXTERNAL,
entry_point="flipfrid_start",
requires=["gui", "storage", "dialogs", "input", "notification"],
stack_size=2 * 1024,
order=180,
fap_icon="rfid_10px.png",
fap_category="Tools",
fap_icon_assets="images",
)

View File

@@ -1,288 +0,0 @@
#include "flipfrid.h"
#include "scene/flipfrid_scene_entrypoint.h"
#include "scene/flipfrid_scene_load_file.h"
#include "scene/flipfrid_scene_select_field.h"
#include "scene/flipfrid_scene_run_attack.h"
#include "scene/flipfrid_scene_load_custom_uids.h"
#include <dolphin/dolphin.h>
#define RFIDFUZZER_APP_FOLDER "/ext/lrfid/rfidfuzzer"
static void flipfrid_draw_callback(Canvas* const canvas, void* ctx) {
furi_assert(ctx);
FlipFridState* flipfrid_state = ctx;
furi_mutex_acquire(flipfrid_state->mutex, FuriWaitForever);
// Draw correct Canvas
switch(flipfrid_state->current_scene) {
case NoneScene:
case SceneEntryPoint:
flipfrid_scene_entrypoint_on_draw(canvas, flipfrid_state);
break;
case SceneSelectFile:
flipfrid_scene_load_file_on_draw(canvas, flipfrid_state);
break;
case SceneSelectField:
flipfrid_scene_select_field_on_draw(canvas, flipfrid_state);
break;
case SceneAttack:
flipfrid_scene_run_attack_on_draw(canvas, flipfrid_state);
break;
case SceneLoadCustomUids:
flipfrid_scene_load_custom_uids_on_draw(canvas, flipfrid_state);
break;
default:
break;
}
furi_mutex_release(flipfrid_state->mutex);
}
void flipfrid_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
furi_assert(event_queue);
FlipFridEvent event = {
.evt_type = EventTypeKey, .key = input_event->key, .input_type = input_event->type};
furi_message_queue_put(event_queue, &event, 25);
}
static void flipfrid_timer_callback(FuriMessageQueue* event_queue) {
furi_assert(event_queue);
FlipFridEvent event = {
.evt_type = EventTypeTick, .key = InputKeyUp, .input_type = InputTypeRelease};
furi_message_queue_put(event_queue, &event, 25);
}
FlipFridState* flipfrid_alloc() {
FlipFridState* flipfrid = malloc(sizeof(FlipFridState));
flipfrid->notification_msg = furi_string_alloc();
flipfrid->attack_name = furi_string_alloc();
flipfrid->proto_name = furi_string_alloc();
flipfrid->data_str = furi_string_alloc();
flipfrid->main_menu_items[0] = furi_string_alloc_set("Default Values");
flipfrid->main_menu_items[1] = furi_string_alloc_set("BF Customer ID");
flipfrid->main_menu_items[2] = furi_string_alloc_set("Load File");
flipfrid->main_menu_items[3] = furi_string_alloc_set("Load UIDs from file");
flipfrid->main_menu_proto_items[0] = furi_string_alloc_set("EM4100");
flipfrid->main_menu_proto_items[1] = furi_string_alloc_set("HIDProx");
flipfrid->main_menu_proto_items[2] = furi_string_alloc_set("PAC/Stanley");
flipfrid->main_menu_proto_items[3] = furi_string_alloc_set("H10301");
flipfrid->previous_scene = NoneScene;
flipfrid->current_scene = SceneEntryPoint;
flipfrid->is_running = true;
flipfrid->is_attacking = false;
flipfrid->key_index = 0;
flipfrid->menu_index = 0;
flipfrid->menu_proto_index = 0;
flipfrid->attack = FlipFridAttackDefaultValues;
flipfrid->notify = furi_record_open(RECORD_NOTIFICATION);
flipfrid->data[0] = 0x00;
flipfrid->data[1] = 0x00;
flipfrid->data[2] = 0x00;
flipfrid->data[3] = 0x00;
flipfrid->data[4] = 0x00;
flipfrid->data[5] = 0x00;
flipfrid->payload[0] = 0x00;
flipfrid->payload[1] = 0x00;
flipfrid->payload[2] = 0x00;
flipfrid->payload[3] = 0x00;
flipfrid->payload[4] = 0x00;
flipfrid->payload[5] = 0x00;
//Dialog
flipfrid->dialogs = furi_record_open(RECORD_DIALOGS);
return flipfrid;
}
void flipfrid_free(FlipFridState* flipfrid) {
//Dialog
furi_record_close(RECORD_DIALOGS);
notification_message(flipfrid->notify, &sequence_blink_stop);
// Strings
furi_string_free(flipfrid->notification_msg);
furi_string_free(flipfrid->attack_name);
furi_string_free(flipfrid->proto_name);
furi_string_free(flipfrid->data_str);
for(uint32_t i = 0; i < 4; i++) {
furi_string_free(flipfrid->main_menu_items[i]);
}
for(uint32_t i = 0; i < 4; i++) {
furi_string_free(flipfrid->main_menu_proto_items[i]);
}
// The rest
free(flipfrid);
}
// ENTRYPOINT
int32_t flipfrid_start(void* p) {
UNUSED(p);
// Input
FURI_LOG_I(TAG, "Initializing input");
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(FlipFridEvent));
FlipFridState* flipfrid_state = flipfrid_alloc();
DOLPHIN_DEED(DolphinDeedPluginStart);
flipfrid_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
if(!flipfrid_state->mutex) {
FURI_LOG_E(TAG, "cannot create mutex\r\n");
furi_message_queue_free(event_queue);
furi_record_close(RECORD_NOTIFICATION);
flipfrid_free(flipfrid_state);
return 255;
}
Storage* storage = furi_record_open(RECORD_STORAGE);
if(!storage_simply_mkdir(storage, RFIDFUZZER_APP_FOLDER)) {
FURI_LOG_E(TAG, "Could not create folder %s", RFIDFUZZER_APP_FOLDER);
}
furi_record_close(RECORD_STORAGE);
// Configure view port
FURI_LOG_I(TAG, "Initializing viewport");
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, flipfrid_draw_callback, flipfrid_state);
view_port_input_callback_set(view_port, flipfrid_input_callback, event_queue);
// Configure timer
FURI_LOG_I(TAG, "Initializing timer");
FuriTimer* timer =
furi_timer_alloc(flipfrid_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");
Gui* gui = (Gui*)furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
// Init values
FlipFridEvent event;
while(flipfrid_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
switch(flipfrid_state->current_scene) {
case NoneScene:
case SceneEntryPoint:
flipfrid_scene_entrypoint_on_event(event, flipfrid_state);
break;
case SceneSelectFile:
flipfrid_scene_load_file_on_event(event, flipfrid_state);
break;
case SceneSelectField:
flipfrid_scene_select_field_on_event(event, flipfrid_state);
break;
case SceneAttack:
flipfrid_scene_run_attack_on_event(event, flipfrid_state);
break;
case SceneLoadCustomUids:
flipfrid_scene_load_custom_uids_on_event(event, flipfrid_state);
break;
default:
break;
}
} else if(event.evt_type == EventTypeTick) {
//Handle event tick
if(flipfrid_state->current_scene != flipfrid_state->previous_scene) {
// Trigger Exit Scene
switch(flipfrid_state->previous_scene) {
case SceneEntryPoint:
flipfrid_scene_entrypoint_on_exit(flipfrid_state);
break;
case SceneSelectFile:
flipfrid_scene_load_file_on_exit(flipfrid_state);
break;
case SceneSelectField:
flipfrid_scene_select_field_on_exit(flipfrid_state);
break;
case SceneAttack:
flipfrid_scene_run_attack_on_exit(flipfrid_state);
break;
case SceneLoadCustomUids:
flipfrid_scene_load_custom_uids_on_exit(flipfrid_state);
break;
case NoneScene:
break;
default:
break;
}
// Trigger Entry Scene
switch(flipfrid_state->current_scene) {
case NoneScene:
case SceneEntryPoint:
flipfrid_scene_entrypoint_on_enter(flipfrid_state);
break;
case SceneSelectFile:
flipfrid_scene_load_file_on_enter(flipfrid_state);
break;
case SceneSelectField:
flipfrid_scene_select_field_on_enter(flipfrid_state);
break;
case SceneAttack:
flipfrid_scene_run_attack_on_enter(flipfrid_state);
break;
case SceneLoadCustomUids:
flipfrid_scene_load_custom_uids_on_enter(flipfrid_state);
break;
default:
break;
}
flipfrid_state->previous_scene = flipfrid_state->current_scene;
}
// Trigger Tick Scene
switch(flipfrid_state->current_scene) {
case NoneScene:
case SceneEntryPoint:
flipfrid_scene_entrypoint_on_tick(flipfrid_state);
break;
case SceneSelectFile:
flipfrid_scene_load_file_on_tick(flipfrid_state);
break;
case SceneSelectField:
flipfrid_scene_select_field_on_tick(flipfrid_state);
break;
case SceneAttack:
flipfrid_scene_run_attack_on_tick(flipfrid_state);
break;
case SceneLoadCustomUids:
flipfrid_scene_load_custom_uids_on_tick(flipfrid_state);
break;
default:
break;
}
view_port_update(view_port);
}
}
}
// Cleanup
furi_timer_stop(timer);
furi_timer_free(timer);
FURI_LOG_I(TAG, "Cleaning up");
gui_remove_view_port(gui, view_port);
view_port_free(view_port);
furi_message_queue_free(event_queue);
furi_record_close(RECORD_GUI);
furi_record_close(RECORD_NOTIFICATION);
furi_mutex_free(flipfrid_state->mutex);
flipfrid_free(flipfrid_state);
return 0;
}

View File

@@ -1,94 +0,0 @@
#pragma once
#include <furi.h>
#include <furi_hal.h>
#include <input/input.h>
#include <gui/gui.h>
#include <gui/modules/submenu.h>
#include <dialogs/dialogs.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include <toolbox/stream/stream.h>
#include <flipper_format/flipper_format_i.h>
#include <toolbox/stream/stream.h>
#include <toolbox/stream/string_stream.h>
#include <toolbox/stream/file_stream.h>
#include <toolbox/stream/buffered_file_stream.h>
#include <rfid_fuzzer_icons.h>
#include <lib/lfrfid/lfrfid_worker.h>
#include <lfrfid/protocols/lfrfid_protocols.h>
#define TAG "FlipFrid"
typedef enum {
FlipFridAttackDefaultValues,
FlipFridAttackBfCustomerId,
FlipFridAttackLoadFile,
FlipFridAttackLoadFileCustomUids,
} FlipFridAttacks;
typedef enum {
EM4100,
HIDProx,
PAC,
H10301,
} FlipFridProtos;
typedef enum {
NoneScene,
SceneEntryPoint,
SceneSelectFile,
SceneSelectField,
SceneAttack,
SceneLoadCustomUids,
} FlipFridScene;
typedef enum {
EventTypeTick,
EventTypeKey,
} EventType;
typedef struct {
EventType evt_type;
InputKey key;
InputType input_type;
} FlipFridEvent;
// STRUCTS
typedef struct {
FuriMutex* mutex;
bool is_running;
bool is_attacking;
FlipFridScene current_scene;
FlipFridScene previous_scene;
NotificationApp* notify;
u_int8_t menu_index;
u_int8_t menu_proto_index;
FuriString* data_str;
uint8_t data[6];
uint8_t payload[6];
uint8_t attack_step;
FlipFridAttacks attack;
FlipFridProtos proto;
FuriString* attack_name;
FuriString* proto_name;
FuriString* main_menu_items[4];
FuriString* main_menu_proto_items[4];
DialogsApp* dialogs;
FuriString* notification_msg;
uint8_t key_index;
LFRFIDWorker* worker;
ProtocolDict* dict;
ProtocolId protocol;
bool workr_rund;
bool attack_stop_called;
uint8_t time_between_cards;
// Used for custom dictionnary
Stream* uids_stream;
} FlipFridState;

View File

@@ -1,201 +0,0 @@
#include "flipfrid_scene_entrypoint.h"
void flipfrid_scene_entrypoint_menu_callback(
FlipFridState* context,
uint32_t index,
uint32_t proto_index) {
switch(index) {
case FlipFridAttackDefaultValues:
context->attack = FlipFridAttackDefaultValues;
context->current_scene = SceneAttack;
furi_string_set(context->attack_name, "Default Values");
break;
case FlipFridAttackBfCustomerId:
context->attack = FlipFridAttackBfCustomerId;
context->current_scene = SceneAttack;
furi_string_set(context->attack_name, "Bad Customer ID");
break;
case FlipFridAttackLoadFile:
context->attack = FlipFridAttackLoadFile;
context->current_scene = SceneSelectFile;
furi_string_set(context->attack_name, "Load File");
break;
case FlipFridAttackLoadFileCustomUids:
context->attack = FlipFridAttackLoadFileCustomUids;
context->current_scene = SceneLoadCustomUids;
furi_string_set(context->attack_name, "Load Custom UIDs");
break;
default:
break;
}
switch(proto_index) {
case EM4100:
context->proto = EM4100;
furi_string_set(context->proto_name, "EM4100");
break;
case HIDProx:
context->proto = HIDProx;
furi_string_set(context->proto_name, "HIDProx");
break;
case PAC:
context->proto = PAC;
furi_string_set(context->proto_name, "PAC/Stanley");
break;
case H10301:
context->proto = H10301;
furi_string_set(context->proto_name, "H10301");
break;
default:
break;
}
}
void flipfrid_scene_entrypoint_on_enter(FlipFridState* context) {
// Clear the previous payload
context->payload[0] = 0x00;
context->payload[1] = 0x00;
context->payload[2] = 0x00;
context->payload[3] = 0x00;
context->payload[4] = 0x00;
context->payload[5] = 0x00;
context->menu_index = 0;
/*for(uint32_t i = 0; i < 4; i++) {
menu_items[i] = furi_string_alloc();
}*/
context->menu_proto_index = 0;
/*for(uint32_t i = 0; i < 4; i++) {
menu_proto_items[i] = furi_string_alloc();
}*/
}
void flipfrid_scene_entrypoint_on_exit(FlipFridState* context) {
UNUSED(context);
}
void flipfrid_scene_entrypoint_on_tick(FlipFridState* context) {
UNUSED(context);
}
void flipfrid_scene_entrypoint_on_event(FlipFridEvent event, FlipFridState* context) {
if(event.evt_type == EventTypeKey) {
if(event.input_type == InputTypeShort) {
switch(event.key) {
case InputKeyDown:
if(context->menu_index < FlipFridAttackLoadFileCustomUids) {
context->menu_index++;
}
break;
case InputKeyUp:
if(context->menu_index > FlipFridAttackDefaultValues) {
context->menu_index--;
}
break;
case InputKeyLeft:
if(context->menu_proto_index > EM4100) {
context->menu_proto_index--;
} else if(context->menu_proto_index == EM4100) {
context->menu_proto_index = H10301;
}
break;
case InputKeyRight:
if(context->menu_proto_index < H10301) {
context->menu_proto_index++;
} else if(context->menu_proto_index == H10301) {
context->menu_proto_index = EM4100;
}
break;
case InputKeyOk:
flipfrid_scene_entrypoint_menu_callback(
context, context->menu_index, context->menu_proto_index);
break;
case InputKeyBack:
context->is_running = false;
break;
default:
break;
}
}
}
}
void flipfrid_scene_entrypoint_on_draw(Canvas* canvas, FlipFridState* context) {
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
if(context->main_menu_items != NULL) {
if(context->main_menu_items[context->menu_index] != NULL) {
if(context->menu_index > FlipFridAttackDefaultValues) {
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas,
64,
24,
AlignCenter,
AlignTop,
furi_string_get_cstr(context->main_menu_items[context->menu_index - 1]));
}
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(
canvas,
64,
36,
AlignCenter,
AlignTop,
furi_string_get_cstr(context->main_menu_items[context->menu_index]));
if(context->menu_index < FlipFridAttackLoadFileCustomUids) {
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas,
64,
48,
AlignCenter,
AlignTop,
furi_string_get_cstr(context->main_menu_items[context->menu_index + 1]));
}
if(context->menu_proto_index > EM4100) {
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas,
64,
-12,
AlignCenter,
AlignTop,
furi_string_get_cstr(
context->main_menu_proto_items[context->menu_proto_index - 1]));
}
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 27, 4, AlignCenter, AlignTop, "<");
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(
canvas,
64,
4,
AlignCenter,
AlignTop,
furi_string_get_cstr(context->main_menu_proto_items[context->menu_proto_index]));
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 101, 4, AlignCenter, AlignTop, ">");
if(context->menu_proto_index < H10301) {
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas,
64,
-12,
AlignCenter,
AlignTop,
furi_string_get_cstr(
context->main_menu_proto_items[context->menu_proto_index + 1]));
}
}
}
}

View File

@@ -1,8 +0,0 @@
#pragma once
#include "../flipfrid.h"
void flipfrid_scene_entrypoint_on_enter(FlipFridState* context);
void flipfrid_scene_entrypoint_on_exit(FlipFridState* context);
void flipfrid_scene_entrypoint_on_tick(FlipFridState* context);
void flipfrid_scene_entrypoint_on_event(FlipFridEvent event, FlipFridState* context);
void flipfrid_scene_entrypoint_on_draw(Canvas* canvas, FlipFridState* context);

View File

@@ -1,85 +0,0 @@
#include "flipfrid_scene_load_custom_uids.h"
#include "flipfrid_scene_run_attack.h"
#include "flipfrid_scene_entrypoint.h"
#define LFRFID_UIDS_EXTENSION ".txt"
#define RFIDFUZZER_APP_PATH_FOLDER "/ext/rfidfuzzer"
bool flipfrid_load_uids(FlipFridState* context, const char* file_path) {
bool result = false;
Storage* storage = furi_record_open(RECORD_STORAGE);
context->uids_stream = buffered_file_stream_alloc(storage);
result =
buffered_file_stream_open(context->uids_stream, file_path, FSAM_READ, FSOM_OPEN_EXISTING);
// Close if loading fails
if(!result) {
buffered_file_stream_close(context->uids_stream);
return false;
}
return result;
}
bool flipfrid_load_custom_uids_from_file(FlipFridState* context) {
// Input events and views are managed by file_select
FuriString* uid_path;
uid_path = furi_string_alloc();
furi_string_set(uid_path, RFIDFUZZER_APP_PATH_FOLDER);
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, LFRFID_UIDS_EXTENSION, &I_125_10px);
browser_options.base_path = RFIDFUZZER_APP_PATH_FOLDER;
browser_options.hide_ext = false;
bool res = dialog_file_browser_show(context->dialogs, uid_path, uid_path, &browser_options);
if(res) {
res = flipfrid_load_uids(context, furi_string_get_cstr(uid_path));
}
furi_string_free(uid_path);
return res;
}
void flipfrid_scene_load_custom_uids_on_enter(FlipFridState* context) {
if(flipfrid_load_custom_uids_from_file(context)) {
// Force context loading
flipfrid_scene_run_attack_on_enter(context);
context->current_scene = SceneAttack;
} else {
flipfrid_scene_entrypoint_on_enter(context);
context->current_scene = SceneEntryPoint;
}
}
void flipfrid_scene_load_custom_uids_on_exit(FlipFridState* context) {
UNUSED(context);
}
void flipfrid_scene_load_custom_uids_on_tick(FlipFridState* context) {
UNUSED(context);
}
void flipfrid_scene_load_custom_uids_on_event(FlipFridEvent event, FlipFridState* context) {
if(event.evt_type == EventTypeKey) {
if(event.input_type == InputTypeShort) {
switch(event.key) {
case InputKeyDown:
case InputKeyUp:
case InputKeyLeft:
case InputKeyRight:
case InputKeyOk:
case InputKeyBack:
context->current_scene = SceneEntryPoint;
break;
default:
break;
}
}
}
}
void flipfrid_scene_load_custom_uids_on_draw(Canvas* canvas, FlipFridState* context) {
UNUSED(context);
UNUSED(canvas);
}

View File

@@ -1,9 +0,0 @@
#pragma once
#include "../flipfrid.h"
void flipfrid_scene_load_custom_uids_on_enter(FlipFridState* context);
void flipfrid_scene_load_custom_uids_on_exit(FlipFridState* context);
void flipfrid_scene_load_custom_uids_on_tick(FlipFridState* context);
void flipfrid_scene_load_custom_uids_on_event(FlipFridEvent event, FlipFridState* context);
void flipfrid_scene_load_custom_uids_on_draw(Canvas* canvas, FlipFridState* context);
bool flipfrid_load_custom_uids_from_file(FlipFridState* context);

View File

@@ -1,193 +0,0 @@
#include "flipfrid_scene_load_file.h"
#include "flipfrid_scene_entrypoint.h"
#define LFRFID_APP_EXTENSION ".rfid"
#define LFRFID_APP_PATH_FOLDER "/ext/lfrfid"
bool flipfrid_load(FlipFridState* context, const char* file_path) {
bool result = false;
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
FuriString* temp_str;
temp_str = furi_string_alloc();
do {
if(!flipper_format_file_open_existing(fff_data_file, file_path)) {
FURI_LOG_E(TAG, "Error open file %s", file_path);
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Error open file");
break;
}
// FileType
if(!flipper_format_read_string(fff_data_file, "Filetype", temp_str)) {
FURI_LOG_E(TAG, "Missing or incorrect Filetype");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Missing or incorrect Filetypes");
break;
} else {
FURI_LOG_I(TAG, "Filetype: %s", furi_string_get_cstr(temp_str));
}
// Key type
if(!flipper_format_read_string(fff_data_file, "Key type", temp_str)) {
FURI_LOG_E(TAG, "Missing or incorrect Key type");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Missing or incorrect Key type");
break;
} else {
FURI_LOG_I(TAG, "Key type: %s", furi_string_get_cstr(temp_str));
if(context->proto == EM4100) {
if(strcmp(furi_string_get_cstr(temp_str), "EM4100") != 0) {
FURI_LOG_E(TAG, "Unsupported Key type");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Unsupported Key type");
break;
}
} else if(context->proto == PAC) {
if(strcmp(furi_string_get_cstr(temp_str), "PAC/Stanley") != 0) {
FURI_LOG_E(TAG, "Unsupported Key type");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Unsupported Key type");
break;
}
} else if(context->proto == H10301) {
if(strcmp(furi_string_get_cstr(temp_str), "H10301") != 0) {
FURI_LOG_E(TAG, "Unsupported Key type");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Unsupported Key type");
break;
}
} else {
if(strcmp(furi_string_get_cstr(temp_str), "HIDProx") != 0) {
FURI_LOG_E(TAG, "Unsupported Key type");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Unsupported Key type");
break;
}
}
}
// Data
if(!flipper_format_read_string(fff_data_file, "Data", context->data_str)) {
FURI_LOG_E(TAG, "Missing or incorrect Data");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Missing or incorrect Key");
break;
} else {
FURI_LOG_I(TAG, "Key: %s", furi_string_get_cstr(context->data_str));
if(context->proto == EM4100) {
if(furi_string_size(context->data_str) != 14) {
FURI_LOG_E(TAG, "Incorrect Key length");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Incorrect Key length");
break;
}
} else if(context->proto == PAC) {
if(furi_string_size(context->data_str) != 11) {
FURI_LOG_E(TAG, "Incorrect Key length");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Incorrect Key length");
break;
}
} else if(context->proto == H10301) {
if(furi_string_size(context->data_str) != 8) {
FURI_LOG_E(TAG, "Incorrect Key length");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Incorrect Key length");
break;
}
} else {
if(furi_string_size(context->data_str) != 17) {
FURI_LOG_E(TAG, "Incorrect Key length");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Incorrect Key length");
break;
}
}
// String to uint8_t
for(uint8_t i = 0; i < 6; i++) {
char temp_str2[3];
temp_str2[0] = furi_string_get_cstr(context->data_str)[i * 3];
temp_str2[1] = furi_string_get_cstr(context->data_str)[i * 3 + 1];
temp_str2[2] = '\0';
context->data[i] = (uint8_t)strtol(temp_str2, NULL, 16);
}
}
result = true;
} while(0);
furi_string_free(temp_str);
flipper_format_free(fff_data_file);
if(result) {
FURI_LOG_I(TAG, "Loaded successfully");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Source loaded.");
}
return result;
}
void flipfrid_scene_load_file_on_enter(FlipFridState* context) {
if(flipfrid_load_protocol_from_file(context)) {
context->current_scene = SceneSelectField;
} else {
flipfrid_scene_entrypoint_on_enter(context);
context->current_scene = SceneEntryPoint;
}
}
void flipfrid_scene_load_file_on_exit(FlipFridState* context) {
UNUSED(context);
}
void flipfrid_scene_load_file_on_tick(FlipFridState* context) {
UNUSED(context);
}
void flipfrid_scene_load_file_on_event(FlipFridEvent event, FlipFridState* context) {
if(event.evt_type == EventTypeKey) {
if(event.input_type == InputTypeShort) {
switch(event.key) {
case InputKeyDown:
case InputKeyUp:
case InputKeyLeft:
case InputKeyRight:
case InputKeyOk:
case InputKeyBack:
context->current_scene = SceneEntryPoint;
break;
default:
break;
}
}
}
}
void flipfrid_scene_load_file_on_draw(Canvas* canvas, FlipFridState* context) {
UNUSED(context);
UNUSED(canvas);
}
bool flipfrid_load_protocol_from_file(FlipFridState* context) {
FuriString* user_file_path;
user_file_path = furi_string_alloc();
furi_string_set(user_file_path, LFRFID_APP_PATH_FOLDER);
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, LFRFID_APP_EXTENSION, &I_125_10px);
browser_options.base_path = LFRFID_APP_PATH_FOLDER;
// Input events and views are managed by file_select
bool res = dialog_file_browser_show(
context->dialogs, user_file_path, user_file_path, &browser_options);
if(res) {
res = flipfrid_load(context, furi_string_get_cstr(user_file_path));
}
furi_string_free(user_file_path);
return res;
}

View File

@@ -1,9 +0,0 @@
#pragma once
#include "../flipfrid.h"
void flipfrid_scene_load_file_on_enter(FlipFridState* context);
void flipfrid_scene_load_file_on_exit(FlipFridState* context);
void flipfrid_scene_load_file_on_tick(FlipFridState* context);
void flipfrid_scene_load_file_on_event(FlipFridEvent event, FlipFridState* context);
void flipfrid_scene_load_file_on_draw(Canvas* canvas, FlipFridState* context);
bool flipfrid_load_protocol_from_file(FlipFridState* context);

View File

@@ -1,668 +0,0 @@
#include "flipfrid_scene_run_attack.h"
#include <gui/elements.h>
uint8_t counter = 0;
uint8_t id_list[17][5] = {
{0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
{0x11, 0x11, 0x11, 0x11, 0x11}, // Only 11
{0x22, 0x22, 0x22, 0x22, 0x22}, // Only 22
{0x33, 0x33, 0x33, 0x33, 0x33}, // Only 33
{0x44, 0x44, 0x44, 0x44, 0x44}, // Only 44
{0x55, 0x55, 0x55, 0x55, 0x55}, // Only 55
{0x66, 0x66, 0x66, 0x66, 0x66}, // Only 66
{0x77, 0x77, 0x77, 0x77, 0x77}, // Only 77
{0x88, 0x88, 0x88, 0x88, 0x88}, // Only 88
{0x99, 0x99, 0x99, 0x99, 0x99}, // Only 99
{0x12, 0x34, 0x56, 0x78, 0x9A}, // Incremental UID
{0x9A, 0x78, 0x56, 0x34, 0x12}, // Decremental UID
{0x04, 0xd0, 0x9b, 0x0d, 0x6a}, // From arha
{0x34, 0x00, 0x29, 0x3d, 0x9e}, // From arha
{0x04, 0xdf, 0x00, 0x00, 0x01}, // From arha
{0xCA, 0xCA, 0xCA, 0xCA, 0xCA}, // From arha
};
uint8_t id_list_hid[14][6] = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
{0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, // Only 11
{0x22, 0x22, 0x22, 0x22, 0x22, 0x22}, // Only 22
{0x33, 0x33, 0x33, 0x33, 0x33, 0x33}, // Only 33
{0x44, 0x44, 0x44, 0x44, 0x44, 0x44}, // Only 44
{0x55, 0x55, 0x55, 0x55, 0x55, 0x55}, // Only 55
{0x66, 0x66, 0x66, 0x66, 0x66, 0x66}, // Only 66
{0x77, 0x77, 0x77, 0x77, 0x77, 0x77}, // Only 77
{0x88, 0x88, 0x88, 0x88, 0x88, 0x88}, // Only 88
{0x99, 0x99, 0x99, 0x99, 0x99, 0x99}, // Only 99
{0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}, // Incremental UID
{0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12}, // Decremental UID
{0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA}, // From arha
};
uint8_t id_list_pac[17][4] = {
{0x00, 0x00, 0x00, 0x00}, // Null bytes
{0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
{0x11, 0x11, 0x11, 0x11}, // Only 11
{0x22, 0x22, 0x22, 0x22}, // Only 22
{0x33, 0x33, 0x33, 0x33}, // Only 33
{0x44, 0x44, 0x44, 0x44}, // Only 44
{0x55, 0x55, 0x55, 0x55}, // Only 55
{0x66, 0x66, 0x66, 0x66}, // Only 66
{0x77, 0x77, 0x77, 0x77}, // Only 77
{0x88, 0x88, 0x88, 0x88}, // Only 88
{0x99, 0x99, 0x99, 0x99}, // Only 99
{0x12, 0x34, 0x56, 0x78}, // Incremental UID
{0x9A, 0x78, 0x56, 0x34}, // Decremental UID
{0x04, 0xd0, 0x9b, 0x0d}, // From arha
{0x34, 0x00, 0x29, 0x3d}, // From arha
{0x04, 0xdf, 0x00, 0x00}, // From arha
{0xCA, 0xCA, 0xCA, 0xCA}, // From arha
};
uint8_t id_list_h[14][3] = {
{0x00, 0x00, 0x00}, // Null bytes
{0xFF, 0xFF, 0xFF}, // Only FF
{0x11, 0x11, 0x11}, // Only 11
{0x22, 0x22, 0x22}, // Only 22
{0x33, 0x33, 0x33}, // Only 33
{0x44, 0x44, 0x44}, // Only 44
{0x55, 0x55, 0x55}, // Only 55
{0x66, 0x66, 0x66}, // Only 66
{0x77, 0x77, 0x77}, // Only 77
{0x88, 0x88, 0x88}, // Only 88
{0x99, 0x99, 0x99}, // Only 99
{0x12, 0x34, 0x56}, // Incremental UID
{0x56, 0x34, 0x12}, // Decremental UID
{0xCA, 0xCA, 0xCA}, // From arha
};
void flipfrid_scene_run_attack_on_enter(FlipFridState* context) {
context->time_between_cards = 10;
context->attack_step = 0;
context->attack_stop_called = false;
context->dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
context->worker = lfrfid_worker_alloc(context->dict);
if(context->proto == HIDProx) {
context->protocol = protocol_dict_get_protocol_by_name(context->dict, "HIDProx");
} else if(context->proto == PAC) {
context->protocol = protocol_dict_get_protocol_by_name(context->dict, "PAC/Stanley");
} else if(context->proto == H10301) {
context->protocol = protocol_dict_get_protocol_by_name(context->dict, "H10301");
} else {
context->protocol = protocol_dict_get_protocol_by_name(context->dict, "EM4100");
}
}
void flipfrid_scene_run_attack_on_exit(FlipFridState* context) {
if(context->workr_rund) {
lfrfid_worker_stop(context->worker);
lfrfid_worker_stop_thread(context->worker);
context->workr_rund = false;
}
lfrfid_worker_free(context->worker);
protocol_dict_free(context->dict);
notification_message(context->notify, &sequence_blink_stop);
}
void flipfrid_scene_run_attack_on_tick(FlipFridState* context) {
if(context->is_attacking) {
if(1 == counter) {
protocol_dict_set_data(context->dict, context->protocol, context->payload, 6);
lfrfid_worker_free(context->worker);
context->worker = lfrfid_worker_alloc(context->dict);
lfrfid_worker_start_thread(context->worker);
lfrfid_worker_emulate_start(context->worker, context->protocol);
context->workr_rund = true;
} else if(0 == counter) {
if(context->workr_rund) {
lfrfid_worker_stop(context->worker);
lfrfid_worker_stop_thread(context->worker);
context->workr_rund = false;
furi_delay_ms(200);
}
switch(context->attack) {
case FlipFridAttackDefaultValues:
if(context->proto == EM4100) {
context->payload[0] = id_list[context->attack_step][0];
context->payload[1] = id_list[context->attack_step][1];
context->payload[2] = id_list[context->attack_step][2];
context->payload[3] = id_list[context->attack_step][3];
context->payload[4] = id_list[context->attack_step][4];
if(context->attack_step == 16) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
} else {
context->attack_step++;
}
break;
} else if(context->proto == PAC) {
context->payload[0] = id_list_pac[context->attack_step][0];
context->payload[1] = id_list_pac[context->attack_step][1];
context->payload[2] = id_list_pac[context->attack_step][2];
context->payload[3] = id_list_pac[context->attack_step][3];
if(context->attack_step == 16) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
} else {
context->attack_step++;
}
break;
} else if(context->proto == H10301) {
context->payload[0] = id_list_h[context->attack_step][0];
context->payload[1] = id_list_h[context->attack_step][1];
context->payload[2] = id_list_h[context->attack_step][2];
if(context->attack_step == 13) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
} else {
context->attack_step++;
}
break;
} else {
context->payload[0] = id_list_hid[context->attack_step][0];
context->payload[1] = id_list_hid[context->attack_step][1];
context->payload[2] = id_list_hid[context->attack_step][2];
context->payload[3] = id_list_hid[context->attack_step][3];
context->payload[4] = id_list_hid[context->attack_step][4];
context->payload[5] = id_list_hid[context->attack_step][5];
if(context->attack_step == 13) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
} else {
context->attack_step++;
}
break;
}
case FlipFridAttackBfCustomerId:
if(context->proto == EM4100) {
context->payload[0] = context->attack_step;
context->payload[1] = 0x00;
context->payload[2] = 0x00;
context->payload[3] = 0x00;
context->payload[4] = 0x00;
if(context->attack_step == 255) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
} else {
context->attack_step++;
}
break;
} else if(context->proto == PAC) {
context->payload[0] = context->attack_step;
context->payload[1] = 0x00;
context->payload[2] = 0x00;
context->payload[3] = 0x00;
if(context->attack_step == 255) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
} else {
context->attack_step++;
}
break;
} else if(context->proto == H10301) {
context->payload[0] = context->attack_step;
context->payload[1] = 0x00;
context->payload[2] = 0x00;
if(context->attack_step == 255) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
} else {
context->attack_step++;
}
break;
} else {
context->payload[0] = context->attack_step;
context->payload[1] = 0x00;
context->payload[2] = 0x00;
context->payload[3] = 0x00;
context->payload[4] = 0x00;
context->payload[5] = 0x00;
if(context->attack_step == 255) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
} else {
context->attack_step++;
}
break;
}
case FlipFridAttackLoadFile:
if(context->proto == EM4100) {
context->payload[0] = context->data[0];
context->payload[1] = context->data[1];
context->payload[2] = context->data[2];
context->payload[3] = context->data[3];
context->payload[4] = context->data[4];
context->payload[context->key_index] = context->attack_step;
if(context->attack_step == 255) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
break;
} else {
context->attack_step++;
}
break;
} else if(context->proto == PAC) {
context->payload[0] = context->data[0];
context->payload[1] = context->data[1];
context->payload[2] = context->data[2];
context->payload[3] = context->data[3];
context->payload[context->key_index] = context->attack_step;
if(context->attack_step == 255) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
break;
} else {
context->attack_step++;
}
break;
} else if(context->proto == H10301) {
context->payload[0] = context->data[0];
context->payload[1] = context->data[1];
context->payload[2] = context->data[2];
context->payload[context->key_index] = context->attack_step;
if(context->attack_step == 255) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
break;
} else {
context->attack_step++;
}
break;
} else {
context->payload[0] = context->data[0];
context->payload[1] = context->data[1];
context->payload[2] = context->data[2];
context->payload[3] = context->data[3];
context->payload[4] = context->data[4];
context->payload[5] = context->data[5];
context->payload[context->key_index] = context->attack_step;
if(context->attack_step == 255) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
break;
} else {
context->attack_step++;
}
break;
}
case FlipFridAttackLoadFileCustomUids:
if(context->proto == EM4100) {
bool end_of_list = false;
while(true) {
furi_string_reset(context->data_str);
if(!stream_read_line(context->uids_stream, context->data_str)) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
stream_rewind(context->uids_stream);
end_of_list = true;
break;
}
if(furi_string_get_char(context->data_str, 0) == '#') continue;
if(furi_string_size(context->data_str) != 11) break;
break;
}
if(end_of_list) break;
FURI_LOG_D(TAG, furi_string_get_cstr(context->data_str));
if(furi_string_size(context->data_str) != 11) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_error);
break;
}
// string is valid, parse it in context->payload
for(uint8_t i = 0; i < 5; i++) {
char temp_str[3];
temp_str[0] = furi_string_get_cstr(context->data_str)[i * 2];
temp_str[1] = furi_string_get_cstr(context->data_str)[i * 2 + 1];
temp_str[2] = '\0';
context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16);
}
break;
} else if(context->proto == PAC) {
bool end_of_list = false;
while(true) {
furi_string_reset(context->data_str);
if(!stream_read_line(context->uids_stream, context->data_str)) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
stream_rewind(context->uids_stream);
end_of_list = true;
break;
}
if(furi_string_get_char(context->data_str, 0) == '#') continue;
if(furi_string_size(context->data_str) != 9) break;
break;
}
if(end_of_list) break;
FURI_LOG_D(TAG, furi_string_get_cstr(context->data_str));
if(furi_string_size(context->data_str) != 9) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_error);
break;
}
// string is valid, parse it in context->payload
for(uint8_t i = 0; i < 4; i++) {
char temp_str[3];
temp_str[0] = furi_string_get_cstr(context->data_str)[i * 2];
temp_str[1] = furi_string_get_cstr(context->data_str)[i * 2 + 1];
temp_str[2] = '\0';
context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16);
}
break;
} else if(context->proto == H10301) {
bool end_of_list = false;
while(true) {
furi_string_reset(context->data_str);
if(!stream_read_line(context->uids_stream, context->data_str)) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
stream_rewind(context->uids_stream);
end_of_list = true;
break;
};
if(furi_string_get_char(context->data_str, 0) == '#') continue;
if(furi_string_size(context->data_str) != 7) break;
break;
}
if(end_of_list) break;
FURI_LOG_D(TAG, furi_string_get_cstr(context->data_str));
if(furi_string_size(context->data_str) != 7) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_error);
break;
};
// string is valid, parse it in context->payload
for(uint8_t i = 0; i < 3; i++) {
char temp_str[3];
temp_str[0] = furi_string_get_cstr(context->data_str)[i * 2];
temp_str[1] = furi_string_get_cstr(context->data_str)[i * 2 + 1];
temp_str[2] = '\0';
context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16);
}
break;
} else {
bool end_of_list = false;
while(true) {
furi_string_reset(context->data_str);
if(!stream_read_line(context->uids_stream, context->data_str)) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
stream_rewind(context->uids_stream);
end_of_list = true;
break;
};
if(furi_string_get_char(context->data_str, 0) == '#') continue;
if(furi_string_size(context->data_str) != 13) break;
break;
}
FURI_LOG_D(TAG, furi_string_get_cstr(context->data_str));
if(end_of_list) break;
if(furi_string_size(context->data_str) != 13) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_error);
break;
};
// string is valid, parse it in context->payload
for(uint8_t i = 0; i < 6; i++) {
char temp_str[3];
temp_str[0] = furi_string_get_cstr(context->data_str)[i * 2];
temp_str[1] = furi_string_get_cstr(context->data_str)[i * 2 + 1];
temp_str[2] = '\0';
context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16);
}
break;
default:
break;
}
}
}
if(counter > context->time_between_cards) {
counter = 0;
} else {
counter++;
}
}
}
void flipfrid_scene_run_attack_on_event(FlipFridEvent event, FlipFridState* context) {
if(event.evt_type == EventTypeKey) {
if(event.input_type == InputTypeShort) {
switch(event.key) {
case InputKeyDown:
break;
case InputKeyUp:
break;
case InputKeyLeft:
if(!context->is_attacking) {
if(context->time_between_cards > 5) {
context->time_between_cards--;
}
}
break;
case InputKeyRight:
if(!context->is_attacking) {
if(context->time_between_cards < 70) {
context->time_between_cards++;
}
}
break;
case InputKeyOk:
counter = 0;
if(!context->is_attacking) {
notification_message(context->notify, &sequence_blink_start_blue);
context->is_attacking = true;
} else {
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
}
break;
case InputKeyBack:
context->is_attacking = false;
counter = 0;
notification_message(context->notify, &sequence_blink_stop);
if(context->attack_stop_called) {
context->attack_stop_called = false;
context->attack_step = 0;
if(context->attack == FlipFridAttackLoadFileCustomUids) {
furi_string_reset(context->data_str);
stream_rewind(context->uids_stream);
buffered_file_stream_close(context->uids_stream);
}
furi_string_reset(context->notification_msg);
context->current_scene = SceneEntryPoint;
}
context->attack_stop_called = true;
break;
default:
break;
}
}
if(event.input_type == InputTypeLong) {
switch(event.key) {
case InputKeyLeft:
if(!context->is_attacking) {
if(context->time_between_cards > 0) {
if((context->time_between_cards - 10) > 5) {
context->time_between_cards -= 10;
}
}
}
break;
case InputKeyRight:
if(!context->is_attacking) {
if(context->time_between_cards < 70) {
context->time_between_cards += 10;
}
}
break;
default:
break;
}
}
}
}
void flipfrid_scene_run_attack_on_draw(Canvas* canvas, FlipFridState* 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, 2, AlignCenter, AlignTop, furi_string_get_cstr(context->attack_name));
char uid[18];
char speed[16];
if(context->proto == HIDProx) {
snprintf(
uid,
sizeof(uid),
"%02X:%02X:%02X:%02X:%02X:%02X",
context->payload[0],
context->payload[1],
context->payload[2],
context->payload[3],
context->payload[4],
context->payload[5]);
} else if(context->proto == PAC) {
snprintf(
uid,
sizeof(uid),
"%02X:%02X:%02X:%02X",
context->payload[0],
context->payload[1],
context->payload[2],
context->payload[3]);
} else if(context->proto == H10301) {
snprintf(
uid,
sizeof(uid),
"%02X:%02X:%02X",
context->payload[0],
context->payload[1],
context->payload[2]);
} else {
snprintf(
uid,
sizeof(uid),
"%02X:%02X:%02X:%02X:%02X",
context->payload[0],
context->payload[1],
context->payload[2],
context->payload[3],
context->payload[4]);
}
canvas_draw_str_aligned(canvas, 64, 38, AlignCenter, AlignTop, uid);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas, 64, 26, AlignCenter, AlignTop, furi_string_get_cstr(context->proto_name));
snprintf(speed, sizeof(speed), "Time delay: %d", context->time_between_cards);
//canvas_draw_str_aligned(canvas, 0, 22, AlignLeft, AlignTop, "Speed:");
canvas_draw_str_aligned(canvas, 64, 14, AlignCenter, AlignTop, speed);
//char start_stop_msg[20];
if(context->is_attacking) {
elements_button_center(canvas, "Stop");
//snprintf(start_stop_msg, sizeof(start_stop_msg), " Press OK to stop ");
} else {
elements_button_center(canvas, "Start");
elements_button_left(canvas, "TD -");
elements_button_right(canvas, "+ TD");
}
//canvas_draw_str_aligned(canvas, 64, 44, AlignCenter, AlignTop, start_stop_msg);
}

View File

@@ -1,8 +0,0 @@
#pragma once
#include "../flipfrid.h"
void flipfrid_scene_run_attack_on_enter(FlipFridState* context);
void flipfrid_scene_run_attack_on_exit(FlipFridState* context);
void flipfrid_scene_run_attack_on_tick(FlipFridState* context);
void flipfrid_scene_run_attack_on_event(FlipFridEvent event, FlipFridState* context);
void flipfrid_scene_run_attack_on_draw(Canvas* canvas, FlipFridState* context);

View File

@@ -1,160 +0,0 @@
#include "flipfrid_scene_select_field.h"
void flipfrid_center_displayed_key(FlipFridState* context, uint8_t index) {
char key_cstr[18];
uint8_t key_len = 18;
uint8_t str_index = (index * 3);
int data_len = sizeof(context->data) / sizeof(context->data[0]);
int key_index = 0;
if(context->proto == EM4100) {
key_len = 16;
}
if(context->proto == PAC) {
key_len = 13;
}
if(context->proto == H10301) {
key_len = 10;
}
for(uint8_t i = 0; i < data_len; i++) {
if(context->data[i] < 9) {
key_index +=
snprintf(&key_cstr[key_index], key_len - key_index, "0%X ", context->data[i]);
} else {
key_index +=
snprintf(&key_cstr[key_index], key_len - key_index, "%X ", context->data[i]);
}
}
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] = ' ';
}
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, display_menu);
}
void flipfrid_scene_select_field_on_enter(FlipFridState* context) {
furi_string_reset(context->notification_msg);
}
void flipfrid_scene_select_field_on_exit(FlipFridState* context) {
UNUSED(context);
}
void flipfrid_scene_select_field_on_tick(FlipFridState* context) {
UNUSED(context);
}
void flipfrid_scene_select_field_on_event(FlipFridEvent event, FlipFridState* context) {
if(event.evt_type == EventTypeKey) {
if(event.input_type == InputTypeShort) {
const char* key_cstr = furi_string_get_cstr(context->data_str);
int data_len = sizeof(context->data) / sizeof(context->data[0]);
// 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:
for(uint8_t i = 0; i < data_len; i++) {
if(context->key_index == i) {
context->data[i] = (context->data[i] - 1);
}
}
break;
case InputKeyUp:
for(uint8_t i = 0; i < data_len; i++) {
if(context->key_index == i) {
context->data[i] = (context->data[i] + 1);
}
}
break;
case InputKeyLeft:
if(context->key_index > 0) {
context->key_index = context->key_index - 1;
}
break;
case InputKeyRight:
if(context->key_index < nb_bytes) {
context->key_index = context->key_index + 1;
}
break;
case InputKeyOk:
furi_string_reset(context->notification_msg);
context->current_scene = SceneAttack;
break;
case InputKeyBack:
context->key_index = 0;
furi_string_reset(context->notification_msg);
context->current_scene = SceneSelectFile;
break;
default:
break;
}
FURI_LOG_D(TAG, "Position: %d/%d", context->key_index, nb_bytes);
}
}
}
void flipfrid_scene_select_field_on_draw(Canvas* canvas, FlipFridState* context) {
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
// Frame
//canvas_draw_frame(canvas, 0, 0, 128, 64);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(canvas, 12, 5, AlignLeft, AlignTop, "Left and right: select byte");
canvas_draw_str_aligned(canvas, 12, 15, AlignLeft, AlignTop, "Up and down: adjust byte");
char msg_index[18];
canvas_set_font(canvas, FontPrimary);
snprintf(msg_index, sizeof(msg_index), "Field index : %d", context->key_index);
canvas_draw_str_aligned(canvas, 64, 30, AlignCenter, AlignTop, msg_index);
flipfrid_center_displayed_key(context, context->key_index);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas, 64, 45, AlignCenter, AlignTop, furi_string_get_cstr(context->notification_msg));
}

View File

@@ -1,9 +0,0 @@
#pragma once
#include "../flipfrid.h"
void flipfrid_scene_select_field_on_enter(FlipFridState* context);
void flipfrid_scene_select_field_on_exit(FlipFridState* context);
void flipfrid_scene_select_field_on_tick(FlipFridState* context);
void flipfrid_scene_select_field_on_event(FlipFridEvent event, FlipFridState* context);
void flipfrid_scene_select_field_on_draw(Canvas* canvas, FlipFridState* context);
void center_displayed_key(FlipFridState* context, uint8_t index);

View File

@@ -1,8 +0,0 @@
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* @xMasterX and @G4N4P4T1(made original version) 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.
* ----------------------------------------------------------------------------
*/

View File

@@ -1,12 +0,0 @@
App(
appid="ibtn_fuzzer",
name="iButton Fuzzer",
apptype=FlipperAppType.EXTERNAL,
entry_point="ibtnfuzzer_start",
requires=["gui", "storage", "dialogs", "input", "notification"],
stack_size=1 * 1024,
order=15,
fap_icon="ibutt_10px.png",
fap_category="Tools",
fap_icon_assets="images",
)

View File

@@ -1,282 +0,0 @@
#include "ibtnfuzzer.h"
#include "scene/ibtnfuzzer_scene_entrypoint.h"
#include "scene/ibtnfuzzer_scene_load_file.h"
#include "scene/ibtnfuzzer_scene_select_field.h"
#include "scene/ibtnfuzzer_scene_run_attack.h"
#include "scene/ibtnfuzzer_scene_load_custom_uids.h"
#include <dolphin/dolphin.h>
#define IBTNFUZZER_APP_FOLDER "/ext/ibtnfuzzer"
static void ibtnfuzzer_draw_callback(Canvas* const canvas, void* ctx) {
furi_assert(ctx);
iBtnFuzzerState* ibtnfuzzer_state = ctx;
furi_mutex_acquire(ibtnfuzzer_state->mutex, FuriWaitForever);
// Draw correct Canvas
switch(ibtnfuzzer_state->current_scene) {
case NoneScene:
case SceneEntryPoint:
ibtnfuzzer_scene_entrypoint_on_draw(canvas, ibtnfuzzer_state);
break;
case SceneSelectFile:
ibtnfuzzer_scene_load_file_on_draw(canvas, ibtnfuzzer_state);
break;
case SceneSelectField:
ibtnfuzzer_scene_select_field_on_draw(canvas, ibtnfuzzer_state);
break;
case SceneAttack:
ibtnfuzzer_scene_run_attack_on_draw(canvas, ibtnfuzzer_state);
break;
case SceneLoadCustomUids:
ibtnfuzzer_scene_load_custom_uids_on_draw(canvas, ibtnfuzzer_state);
break;
}
furi_mutex_release(ibtnfuzzer_state->mutex);
}
void ibtnfuzzer_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
furi_assert(event_queue);
iBtnFuzzerEvent event = {
.evt_type = EventTypeKey, .key = input_event->key, .input_type = input_event->type};
furi_message_queue_put(event_queue, &event, 25);
}
static void ibtnfuzzer_timer_callback(FuriMessageQueue* event_queue) {
furi_assert(event_queue);
iBtnFuzzerEvent event = {
.evt_type = EventTypeTick, .key = InputKeyUp, .input_type = InputTypeRelease};
furi_message_queue_put(event_queue, &event, 25);
}
iBtnFuzzerState* ibtnfuzzer_alloc() {
iBtnFuzzerState* ibtnfuzzer = malloc(sizeof(iBtnFuzzerState));
ibtnfuzzer->notification_msg = furi_string_alloc();
ibtnfuzzer->attack_name = furi_string_alloc();
ibtnfuzzer->proto_name = furi_string_alloc();
ibtnfuzzer->data_str = furi_string_alloc();
ibtnfuzzer->main_menu_items[0] = furi_string_alloc_set("Default Values");
ibtnfuzzer->main_menu_items[1] = furi_string_alloc_set("Load File");
ibtnfuzzer->main_menu_items[2] = furi_string_alloc_set("Load UIDs from file");
ibtnfuzzer->main_menu_proto_items[0] = furi_string_alloc_set("DS1990");
ibtnfuzzer->main_menu_proto_items[1] = furi_string_alloc_set("Metakom");
ibtnfuzzer->main_menu_proto_items[2] = furi_string_alloc_set("Cyfral");
ibtnfuzzer->previous_scene = NoneScene;
ibtnfuzzer->current_scene = SceneEntryPoint;
ibtnfuzzer->is_running = true;
ibtnfuzzer->is_attacking = false;
ibtnfuzzer->key_index = 0;
ibtnfuzzer->menu_index = 0;
ibtnfuzzer->menu_proto_index = 0;
ibtnfuzzer->attack = iBtnFuzzerAttackDefaultValues;
ibtnfuzzer->notify = furi_record_open(RECORD_NOTIFICATION);
ibtnfuzzer->data[0] = 0x00;
ibtnfuzzer->data[1] = 0x00;
ibtnfuzzer->data[2] = 0x00;
ibtnfuzzer->data[3] = 0x00;
ibtnfuzzer->data[4] = 0x00;
ibtnfuzzer->data[5] = 0x00;
ibtnfuzzer->data[6] = 0x00;
ibtnfuzzer->data[7] = 0x00;
ibtnfuzzer->payload[0] = 0x00;
ibtnfuzzer->payload[1] = 0x00;
ibtnfuzzer->payload[2] = 0x00;
ibtnfuzzer->payload[3] = 0x00;
ibtnfuzzer->payload[4] = 0x00;
ibtnfuzzer->payload[5] = 0x00;
ibtnfuzzer->payload[6] = 0x00;
ibtnfuzzer->payload[7] = 0x00;
//Dialog
ibtnfuzzer->dialogs = furi_record_open(RECORD_DIALOGS);
return ibtnfuzzer;
}
void ibtnfuzzer_free(iBtnFuzzerState* ibtnfuzzer) {
//Dialog
furi_record_close(RECORD_DIALOGS);
notification_message(ibtnfuzzer->notify, &sequence_blink_stop);
// Strings
furi_string_free(ibtnfuzzer->notification_msg);
furi_string_free(ibtnfuzzer->attack_name);
furi_string_free(ibtnfuzzer->proto_name);
furi_string_free(ibtnfuzzer->data_str);
for(uint32_t i = 0; i < 3; i++) {
furi_string_free(ibtnfuzzer->main_menu_items[i]);
}
for(uint32_t i = 0; i < 3; i++) {
furi_string_free(ibtnfuzzer->main_menu_proto_items[i]);
}
// The rest
free(ibtnfuzzer);
}
// ENTRYPOINT
int32_t ibtnfuzzer_start(void* p) {
UNUSED(p);
// Input
FURI_LOG_I(TAG, "Initializing input");
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(iBtnFuzzerEvent));
iBtnFuzzerState* ibtnfuzzer_state = ibtnfuzzer_alloc();
DOLPHIN_DEED(DolphinDeedPluginStart);
ibtnfuzzer_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
if(!ibtnfuzzer_state->mutex) {
FURI_LOG_E(TAG, "cannot create mutex\r\n");
furi_message_queue_free(event_queue);
furi_record_close(RECORD_NOTIFICATION);
ibtnfuzzer_free(ibtnfuzzer_state);
return 255;
}
Storage* storage = furi_record_open(RECORD_STORAGE);
if(!storage_simply_mkdir(storage, IBTNFUZZER_APP_FOLDER)) {
FURI_LOG_E(TAG, "Could not create folder %s", IBTNFUZZER_APP_FOLDER);
}
furi_record_close(RECORD_STORAGE);
// Configure view port
FURI_LOG_I(TAG, "Initializing viewport");
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, ibtnfuzzer_draw_callback, ibtnfuzzer_state);
view_port_input_callback_set(view_port, ibtnfuzzer_input_callback, event_queue);
// Configure timer
FURI_LOG_I(TAG, "Initializing timer");
FuriTimer* timer =
furi_timer_alloc(ibtnfuzzer_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");
Gui* gui = (Gui*)furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
// Init values
iBtnFuzzerEvent event;
while(ibtnfuzzer_state->is_running) {
// Get next event
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 25);
//furi_mutex_acquire(ibtnfuzzer_state->mutex, FuriWaitForever);
if(event_status == FuriStatusOk) {
if(event.evt_type == EventTypeKey) {
//Handle event key
switch(ibtnfuzzer_state->current_scene) {
case NoneScene:
case SceneEntryPoint:
ibtnfuzzer_scene_entrypoint_on_event(event, ibtnfuzzer_state);
break;
case SceneSelectFile:
ibtnfuzzer_scene_load_file_on_event(event, ibtnfuzzer_state);
break;
case SceneSelectField:
ibtnfuzzer_scene_select_field_on_event(event, ibtnfuzzer_state);
break;
case SceneAttack:
ibtnfuzzer_scene_run_attack_on_event(event, ibtnfuzzer_state);
break;
case SceneLoadCustomUids:
ibtnfuzzer_scene_load_custom_uids_on_event(event, ibtnfuzzer_state);
break;
}
} else if(event.evt_type == EventTypeTick) {
//Handle event tick
if(ibtnfuzzer_state->current_scene != ibtnfuzzer_state->previous_scene) {
// Trigger Exit Scene
switch(ibtnfuzzer_state->previous_scene) {
case SceneEntryPoint:
ibtnfuzzer_scene_entrypoint_on_exit(ibtnfuzzer_state);
break;
case SceneSelectFile:
ibtnfuzzer_scene_load_file_on_exit(ibtnfuzzer_state);
break;
case SceneSelectField:
ibtnfuzzer_scene_select_field_on_exit(ibtnfuzzer_state);
break;
case SceneAttack:
ibtnfuzzer_scene_run_attack_on_exit(ibtnfuzzer_state);
break;
case SceneLoadCustomUids:
ibtnfuzzer_scene_load_custom_uids_on_exit(ibtnfuzzer_state);
break;
case NoneScene:
break;
}
// Trigger Entry Scene
switch(ibtnfuzzer_state->current_scene) {
case NoneScene:
case SceneEntryPoint:
ibtnfuzzer_scene_entrypoint_on_enter(ibtnfuzzer_state);
break;
case SceneSelectFile:
ibtnfuzzer_scene_load_file_on_enter(ibtnfuzzer_state);
break;
case SceneSelectField:
ibtnfuzzer_scene_select_field_on_enter(ibtnfuzzer_state);
break;
case SceneAttack:
ibtnfuzzer_scene_run_attack_on_enter(ibtnfuzzer_state);
break;
case SceneLoadCustomUids:
ibtnfuzzer_scene_load_custom_uids_on_enter(ibtnfuzzer_state);
break;
}
ibtnfuzzer_state->previous_scene = ibtnfuzzer_state->current_scene;
}
// Trigger Tick Scene
switch(ibtnfuzzer_state->current_scene) {
case NoneScene:
case SceneEntryPoint:
ibtnfuzzer_scene_entrypoint_on_tick(ibtnfuzzer_state);
break;
case SceneSelectFile:
ibtnfuzzer_scene_load_file_on_tick(ibtnfuzzer_state);
break;
case SceneSelectField:
ibtnfuzzer_scene_select_field_on_tick(ibtnfuzzer_state);
break;
case SceneAttack:
ibtnfuzzer_scene_run_attack_on_tick(ibtnfuzzer_state);
break;
case SceneLoadCustomUids:
ibtnfuzzer_scene_load_custom_uids_on_tick(ibtnfuzzer_state);
break;
}
view_port_update(view_port);
}
}
//furi_mutex_release(ibtnfuzzer_state->mutex);
}
// Cleanup
furi_timer_stop(timer);
furi_timer_free(timer);
FURI_LOG_I(TAG, "Cleaning up");
gui_remove_view_port(gui, view_port);
view_port_free(view_port);
furi_message_queue_free(event_queue);
furi_record_close(RECORD_GUI);
furi_record_close(RECORD_NOTIFICATION);
furi_mutex_free(ibtnfuzzer_state->mutex);
ibtnfuzzer_free(ibtnfuzzer_state);
return 0;
}

View File

@@ -1,94 +0,0 @@
#pragma once
#include <furi.h>
#include <furi_hal.h>
#include <input/input.h>
#include <gui/gui.h>
#include <gui/modules/submenu.h>
#include <dialogs/dialogs.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include <toolbox/stream/stream.h>
#include <flipper_format/flipper_format_i.h>
#include <toolbox/stream/stream.h>
#include <toolbox/stream/string_stream.h>
#include <toolbox/stream/file_stream.h>
#include <toolbox/stream/buffered_file_stream.h>
#include <ibtn_fuzzer_icons.h>
#include <lib/ibutton/ibutton_worker.h>
#include <lib/ibutton/ibutton_key.h>
#define TAG "iBtnFuzzer"
typedef enum {
iBtnFuzzerAttackDefaultValues,
iBtnFuzzerAttackLoadFile,
iBtnFuzzerAttackLoadFileCustomUids,
} iBtnFuzzerAttacks;
typedef enum {
DS1990,
Metakom,
Cyfral,
} iBtnFuzzerProtos;
typedef enum {
NoneScene,
SceneEntryPoint,
SceneSelectFile,
SceneSelectField,
SceneAttack,
SceneLoadCustomUids,
} iBtnFuzzerScene;
typedef enum {
EventTypeTick,
EventTypeKey,
} EventType;
typedef struct {
EventType evt_type;
InputKey key;
InputType input_type;
} iBtnFuzzerEvent;
// STRUCTS
typedef struct {
FuriMutex* mutex;
bool is_running;
bool is_attacking;
iBtnFuzzerScene current_scene;
iBtnFuzzerScene previous_scene;
NotificationApp* notify;
u_int8_t menu_index;
u_int8_t menu_proto_index;
FuriString* data_str;
uint8_t data[8];
uint8_t payload[8];
uint8_t attack_step;
iBtnFuzzerAttacks attack;
iBtnFuzzerProtos proto;
FuriString* attack_name;
FuriString* proto_name;
FuriString* main_menu_items[3];
FuriString* main_menu_proto_items[3];
DialogsApp* dialogs;
FuriString* notification_msg;
uint8_t key_index;
iButtonWorker* worker;
iButtonKey* key;
iButtonProtocolId keytype;
iButtonProtocols* protocols;
bool workr_rund;
bool enter_rerun;
bool attack_stop_called;
uint8_t time_between_cards;
// Used for custom dictionnary
Stream* uids_stream;
} iBtnFuzzerState;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

View File

@@ -1,201 +0,0 @@
#include "ibtnfuzzer_scene_entrypoint.h"
void ibtnfuzzer_scene_entrypoint_menu_callback(
iBtnFuzzerState* context,
uint32_t index,
uint32_t proto_index) {
switch(index) {
case iBtnFuzzerAttackDefaultValues:
context->attack = iBtnFuzzerAttackDefaultValues;
context->current_scene = SceneAttack;
furi_string_set(context->attack_name, "Default Values");
break;
case iBtnFuzzerAttackLoadFile:
context->attack = iBtnFuzzerAttackLoadFile;
context->current_scene = SceneSelectFile;
furi_string_set(context->attack_name, "Load File");
break;
case iBtnFuzzerAttackLoadFileCustomUids:
context->attack = iBtnFuzzerAttackLoadFileCustomUids;
context->current_scene = SceneLoadCustomUids;
furi_string_set(context->attack_name, "Load Custom UIDs");
break;
default:
break;
}
switch(proto_index) {
case DS1990:
context->proto = DS1990;
furi_string_set(context->proto_name, "DS1990");
break;
case Metakom:
context->proto = Metakom;
furi_string_set(context->proto_name, "Metakom");
break;
case Cyfral:
context->proto = Cyfral;
furi_string_set(context->proto_name, "Cyfral");
break;
default:
break;
}
}
void ibtnfuzzer_scene_entrypoint_on_enter(iBtnFuzzerState* context) {
// Clear the previous payload
context->payload[0] = 0x00;
context->payload[1] = 0x00;
context->payload[2] = 0x00;
context->payload[3] = 0x00;
context->payload[4] = 0x00;
context->payload[5] = 0x00;
context->payload[6] = 0x00;
context->payload[7] = 0x00;
context->menu_index = 0;
/*for(uint32_t i = 0; i < 4; i++) {
menu_items[i] = furi_string_alloc();
}*/
context->menu_proto_index = 0;
/*for(uint32_t i = 0; i < 4; i++) {
menu_proto_items[i] = furi_string_alloc();
}*/
}
void ibtnfuzzer_scene_entrypoint_on_exit(iBtnFuzzerState* context) {
context->enter_rerun = false;
}
void ibtnfuzzer_scene_entrypoint_on_tick(iBtnFuzzerState* context) {
UNUSED(context);
}
void ibtnfuzzer_scene_entrypoint_on_event(iBtnFuzzerEvent event, iBtnFuzzerState* context) {
if(event.evt_type == EventTypeKey) {
if(event.input_type == InputTypeShort) {
switch(event.key) {
case InputKeyDown:
if(context->menu_index < iBtnFuzzerAttackLoadFileCustomUids) {
context->menu_index++;
}
break;
case InputKeyUp:
if(context->menu_index > iBtnFuzzerAttackDefaultValues) {
context->menu_index--;
}
break;
case InputKeyLeft:
if(context->menu_proto_index > DS1990) {
context->menu_proto_index--;
} else if(context->menu_proto_index == DS1990) {
context->menu_proto_index = Cyfral;
}
break;
case InputKeyRight:
if(context->menu_proto_index < Cyfral) {
context->menu_proto_index++;
} else if(context->menu_proto_index == Cyfral) {
context->menu_proto_index = DS1990;
}
break;
case InputKeyOk:
ibtnfuzzer_scene_entrypoint_menu_callback(
context, context->menu_index, context->menu_proto_index);
break;
case InputKeyBack:
context->is_running = false;
break;
default:
break;
}
}
}
}
void ibtnfuzzer_scene_entrypoint_on_draw(Canvas* canvas, iBtnFuzzerState* context) {
if(!context->enter_rerun) {
ibtnfuzzer_scene_entrypoint_on_enter(context);
context->enter_rerun = true;
}
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
if(context->main_menu_items != NULL) {
if(context->main_menu_items[context->menu_index] != NULL) {
if(context->menu_index > iBtnFuzzerAttackDefaultValues) {
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas,
64,
24,
AlignCenter,
AlignTop,
furi_string_get_cstr(context->main_menu_items[context->menu_index - 1]));
}
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(
canvas,
64,
36,
AlignCenter,
AlignTop,
furi_string_get_cstr(context->main_menu_items[context->menu_index]));
if(context->menu_index < iBtnFuzzerAttackLoadFileCustomUids) {
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas,
64,
48,
AlignCenter,
AlignTop,
furi_string_get_cstr(context->main_menu_items[context->menu_index + 1]));
}
if(context->menu_proto_index > DS1990) {
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas,
64,
-12,
AlignCenter,
AlignTop,
furi_string_get_cstr(
context->main_menu_proto_items[context->menu_proto_index - 1]));
}
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 27, 4, AlignCenter, AlignTop, "<");
canvas_set_font(canvas, FontPrimary);
if(context->main_menu_proto_items[context->menu_proto_index] != NULL) {
canvas_draw_str_aligned(
canvas,
64,
4,
AlignCenter,
AlignTop,
furi_string_get_cstr(
context->main_menu_proto_items[context->menu_proto_index]));
}
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 101, 4, AlignCenter, AlignTop, ">");
if(context->menu_proto_index < Cyfral) {
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas,
64,
-12,
AlignCenter,
AlignTop,
furi_string_get_cstr(
context->main_menu_proto_items[context->menu_proto_index + 1]));
}
}
}
}

View File

@@ -1,8 +0,0 @@
#pragma once
#include "../ibtnfuzzer.h"
void ibtnfuzzer_scene_entrypoint_on_enter(iBtnFuzzerState* context);
void ibtnfuzzer_scene_entrypoint_on_exit(iBtnFuzzerState* context);
void ibtnfuzzer_scene_entrypoint_on_tick(iBtnFuzzerState* context);
void ibtnfuzzer_scene_entrypoint_on_event(iBtnFuzzerEvent event, iBtnFuzzerState* context);
void ibtnfuzzer_scene_entrypoint_on_draw(Canvas* canvas, iBtnFuzzerState* context);

View File

@@ -1,86 +0,0 @@
#include "ibtnfuzzer_scene_load_custom_uids.h"
#include "ibtnfuzzer_scene_run_attack.h"
#include "ibtnfuzzer_scene_entrypoint.h"
#define IBTNFUZZER_UIDS_EXTENSION ".txt"
#define IBTNFUZZER_APP_PATH_FOLDER "/ext/ibtnfuzzer"
bool ibtnfuzzer_load_uids(iBtnFuzzerState* context, const char* file_path) {
bool result = false;
Storage* storage = furi_record_open(RECORD_STORAGE);
context->uids_stream = buffered_file_stream_alloc(storage);
result =
buffered_file_stream_open(context->uids_stream, file_path, FSAM_READ, FSOM_OPEN_EXISTING);
// Close if loading fails
if(!result) {
buffered_file_stream_close(context->uids_stream);
return false;
}
return result;
}
bool ibtnfuzzer_load_custom_uids_from_file(iBtnFuzzerState* context) {
// Input events and views are managed by file_select
FuriString* uid_path;
uid_path = furi_string_alloc();
furi_string_set(uid_path, IBTNFUZZER_APP_PATH_FOLDER);
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(
&browser_options, IBTNFUZZER_UIDS_EXTENSION, &I_ibutt_10px);
browser_options.base_path = IBTNFUZZER_APP_PATH_FOLDER;
browser_options.hide_ext = false;
bool res = dialog_file_browser_show(context->dialogs, uid_path, uid_path, &browser_options);
if(res) {
res = ibtnfuzzer_load_uids(context, furi_string_get_cstr(uid_path));
}
furi_string_free(uid_path);
return res;
}
void ibtnfuzzer_scene_load_custom_uids_on_enter(iBtnFuzzerState* context) {
if(ibtnfuzzer_load_custom_uids_from_file(context)) {
// Force context loading
ibtnfuzzer_scene_run_attack_on_enter(context);
context->current_scene = SceneAttack;
} else {
ibtnfuzzer_scene_entrypoint_on_enter(context);
context->current_scene = SceneEntryPoint;
}
}
void ibtnfuzzer_scene_load_custom_uids_on_exit(iBtnFuzzerState* context) {
UNUSED(context);
}
void ibtnfuzzer_scene_load_custom_uids_on_tick(iBtnFuzzerState* context) {
UNUSED(context);
}
void ibtnfuzzer_scene_load_custom_uids_on_event(iBtnFuzzerEvent event, iBtnFuzzerState* context) {
if(event.evt_type == EventTypeKey) {
if(event.input_type == InputTypeShort) {
switch(event.key) {
case InputKeyDown:
case InputKeyUp:
case InputKeyLeft:
case InputKeyRight:
case InputKeyOk:
case InputKeyBack:
context->current_scene = SceneEntryPoint;
break;
default:
break;
}
}
}
}
void ibtnfuzzer_scene_load_custom_uids_on_draw(Canvas* canvas, iBtnFuzzerState* context) {
UNUSED(context);
UNUSED(canvas);
}

View File

@@ -1,9 +0,0 @@
#pragma once
#include "../ibtnfuzzer.h"
void ibtnfuzzer_scene_load_custom_uids_on_enter(iBtnFuzzerState* context);
void ibtnfuzzer_scene_load_custom_uids_on_exit(iBtnFuzzerState* context);
void ibtnfuzzer_scene_load_custom_uids_on_tick(iBtnFuzzerState* context);
void ibtnfuzzer_scene_load_custom_uids_on_event(iBtnFuzzerEvent event, iBtnFuzzerState* context);
void ibtnfuzzer_scene_load_custom_uids_on_draw(Canvas* canvas, iBtnFuzzerState* context);
bool ibtnfuzzer_load_custom_uids_from_file(iBtnFuzzerState* context);

View File

@@ -1,293 +0,0 @@
#include "ibtnfuzzer_scene_load_file.h"
#include "ibtnfuzzer_scene_entrypoint.h"
#define IBUTTON_FUZZER_APP_EXTENSION ".ibtn"
#define IBUTTON_FUZZER_APP_PATH_FOLDER "/ext/ibutton"
bool ibtnfuzzer_load(iBtnFuzzerState* context, const char* file_path) {
bool result = false;
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
FuriString* temp_str;
temp_str = furi_string_alloc();
bool key_v2 = false;
do {
if(!flipper_format_file_open_existing(fff_data_file, file_path)) {
FURI_LOG_E(TAG, "Error open file %s", file_path);
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Error open file");
break;
}
// FileType
if(!flipper_format_read_string(fff_data_file, "Filetype", temp_str)) {
FURI_LOG_E(TAG, "Missing or incorrect Filetype");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Missing or incorrect Filetypes");
break;
} else {
FURI_LOG_I(TAG, "Filetype: %s", furi_string_get_cstr(temp_str));
}
// Key type
if(!flipper_format_read_string(fff_data_file, "Key type", temp_str)) {
FURI_LOG_E(TAG, "Missing or incorrect Key type, checking for typ2..");
if(!flipper_format_rewind(fff_data_file)) {
FURI_LOG_E(TAG, "Failed to rewind file");
break;
}
if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) {
furi_string_reset(context->notification_msg);
furi_string_set(
context->notification_msg, "Missing or incorrect Protocol or Key type");
break;
}
FURI_LOG_I(TAG, "Key type V2: %s", furi_string_get_cstr(temp_str));
key_v2 = true;
if(context->proto == DS1990) {
if(strcmp(furi_string_get_cstr(temp_str), "DS1990") != 0) {
FURI_LOG_E(TAG, "Unsupported Key type");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Unsupported Key type");
break;
}
} else if(context->proto == Cyfral) {
if(strcmp(furi_string_get_cstr(temp_str), "Cyfral") != 0) {
FURI_LOG_E(TAG, "Unsupported Key type");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Unsupported Key type");
break;
}
} else {
if(strcmp(furi_string_get_cstr(temp_str), "Metakom") != 0) {
FURI_LOG_E(TAG, "Unsupported Key type");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Unsupported Key type");
break;
}
}
} else {
FURI_LOG_I(TAG, "Key type: %s", furi_string_get_cstr(temp_str));
if(context->proto == DS1990) {
if(strcmp(furi_string_get_cstr(temp_str), "Dallas") != 0) {
FURI_LOG_E(TAG, "Unsupported Key type");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Unsupported Key type");
break;
}
} else if(context->proto == Cyfral) {
if(strcmp(furi_string_get_cstr(temp_str), "Cyfral") != 0) {
FURI_LOG_E(TAG, "Unsupported Key type");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Unsupported Key type");
break;
}
} else {
if(strcmp(furi_string_get_cstr(temp_str), "Metakom") != 0) {
FURI_LOG_E(TAG, "Unsupported Key type");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Unsupported Key type");
break;
}
}
}
if(!key_v2) {
// Data
if(!flipper_format_read_string(fff_data_file, "Data", context->data_str)) {
FURI_LOG_E(TAG, "Missing or incorrect Data");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Missing or incorrect Key");
break;
} else {
FURI_LOG_I(TAG, "Key: %s", furi_string_get_cstr(context->data_str));
if(context->proto == DS1990) {
if(furi_string_size(context->data_str) != 23) {
FURI_LOG_E(TAG, "Incorrect Key length");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Incorrect Key length");
break;
}
} else if(context->proto == Cyfral) {
if(furi_string_size(context->data_str) != 5) {
FURI_LOG_E(TAG, "Incorrect Key length");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Incorrect Key length");
break;
}
} else {
if(furi_string_size(context->data_str) != 11) {
FURI_LOG_E(TAG, "Incorrect Key length");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Incorrect Key length");
break;
}
}
// String to uint8_t
for(uint8_t i = 0; i < 8; i++) {
char temp_str2[3];
temp_str2[0] = furi_string_get_cstr(context->data_str)[i * 3];
temp_str2[1] = furi_string_get_cstr(context->data_str)[i * 3 + 1];
temp_str2[2] = '\0';
context->data[i] = (uint8_t)strtol(temp_str2, NULL, 16);
}
}
} else {
// Data
if(context->proto == DS1990) {
if(!flipper_format_read_string(fff_data_file, "Rom Data", context->data_str)) {
FURI_LOG_E(TAG, "Missing or incorrect Rom Data");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Missing or incorrect Rom Data");
break;
} else {
FURI_LOG_I(TAG, "Key: %s", furi_string_get_cstr(context->data_str));
if(furi_string_size(context->data_str) != 23) {
FURI_LOG_E(TAG, "Incorrect Key length");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Incorrect Key length");
break;
}
// String to uint8_t
for(uint8_t i = 0; i < 8; i++) {
char temp_str2[3];
temp_str2[0] = furi_string_get_cstr(context->data_str)[i * 3];
temp_str2[1] = furi_string_get_cstr(context->data_str)[i * 3 + 1];
temp_str2[2] = '\0';
context->data[i] = (uint8_t)strtol(temp_str2, NULL, 16);
}
}
} else if(context->proto == Cyfral) {
if(!flipper_format_read_string(fff_data_file, "Data", context->data_str)) {
FURI_LOG_E(TAG, "Missing or incorrect Data");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Missing or incorrect Data");
break;
} else {
FURI_LOG_I(TAG, "Key: %s", furi_string_get_cstr(context->data_str));
if(furi_string_size(context->data_str) != 5) {
FURI_LOG_E(TAG, "Incorrect Key length");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Incorrect Key length");
break;
}
// String to uint8_t
for(uint8_t i = 0; i < 8; i++) {
char temp_str2[3];
temp_str2[0] = furi_string_get_cstr(context->data_str)[i * 3];
temp_str2[1] = furi_string_get_cstr(context->data_str)[i * 3 + 1];
temp_str2[2] = '\0';
context->data[i] = (uint8_t)strtol(temp_str2, NULL, 16);
}
}
} else {
if(!flipper_format_read_string(fff_data_file, "Data", context->data_str)) {
FURI_LOG_E(TAG, "Missing or incorrect Data");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Missing or incorrect Data");
break;
} else {
FURI_LOG_I(TAG, "Key: %s", furi_string_get_cstr(context->data_str));
if(furi_string_size(context->data_str) != 11) {
FURI_LOG_E(TAG, "Incorrect Key length");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Incorrect Key length");
break;
}
// String to uint8_t
for(uint8_t i = 0; i < 8; i++) {
char temp_str2[3];
temp_str2[0] = furi_string_get_cstr(context->data_str)[i * 3];
temp_str2[1] = furi_string_get_cstr(context->data_str)[i * 3 + 1];
temp_str2[2] = '\0';
context->data[i] = (uint8_t)strtol(temp_str2, NULL, 16);
}
}
}
}
result = true;
} while(0);
furi_string_free(temp_str);
flipper_format_free(fff_data_file);
if(result) {
FURI_LOG_I(TAG, "Loaded successfully");
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, "Source loaded.");
}
return result;
}
void ibtnfuzzer_scene_load_file_on_enter(iBtnFuzzerState* context) {
if(ibtnfuzzer_load_protocol_from_file(context)) {
context->current_scene = SceneSelectField;
} else {
ibtnfuzzer_scene_entrypoint_on_enter(context);
context->current_scene = SceneEntryPoint;
}
}
void ibtnfuzzer_scene_load_file_on_exit(iBtnFuzzerState* context) {
UNUSED(context);
}
void ibtnfuzzer_scene_load_file_on_tick(iBtnFuzzerState* context) {
UNUSED(context);
}
void ibtnfuzzer_scene_load_file_on_event(iBtnFuzzerEvent event, iBtnFuzzerState* context) {
if(event.evt_type == EventTypeKey) {
if(event.input_type == InputTypeShort) {
switch(event.key) {
case InputKeyDown:
case InputKeyUp:
case InputKeyLeft:
case InputKeyRight:
case InputKeyOk:
case InputKeyBack:
context->current_scene = SceneEntryPoint;
break;
default:
break;
}
}
}
}
void ibtnfuzzer_scene_load_file_on_draw(Canvas* canvas, iBtnFuzzerState* context) {
UNUSED(context);
UNUSED(canvas);
}
bool ibtnfuzzer_load_protocol_from_file(iBtnFuzzerState* context) {
FuriString* user_file_path;
user_file_path = furi_string_alloc();
furi_string_set(user_file_path, IBUTTON_FUZZER_APP_PATH_FOLDER);
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(
&browser_options, IBUTTON_FUZZER_APP_EXTENSION, &I_ibutt_10px);
browser_options.base_path = IBUTTON_FUZZER_APP_PATH_FOLDER;
// Input events and views are managed by file_select
bool res = dialog_file_browser_show(
context->dialogs, user_file_path, user_file_path, &browser_options);
if(res) {
res = ibtnfuzzer_load(context, furi_string_get_cstr(user_file_path));
}
furi_string_free(user_file_path);
return res;
}

View File

@@ -1,9 +0,0 @@
#pragma once
#include "../ibtnfuzzer.h"
void ibtnfuzzer_scene_load_file_on_enter(iBtnFuzzerState* context);
void ibtnfuzzer_scene_load_file_on_exit(iBtnFuzzerState* context);
void ibtnfuzzer_scene_load_file_on_tick(iBtnFuzzerState* context);
void ibtnfuzzer_scene_load_file_on_event(iBtnFuzzerEvent event, iBtnFuzzerState* context);
void ibtnfuzzer_scene_load_file_on_draw(Canvas* canvas, iBtnFuzzerState* context);
bool ibtnfuzzer_load_protocol_from_file(iBtnFuzzerState* context);

View File

@@ -1,501 +0,0 @@
#include "ibtnfuzzer_scene_run_attack.h"
#include <gui/elements.h>
uint8_t counter = 0;
uint8_t id_list_ds1990[18][8] = {
{0x01, 0xBE, 0x40, 0x11, 0x5A, 0x36, 0x00, 0xE1}, // код универсального ключа, для Vizit
{0x01, 0xBE, 0x40, 0x11, 0x5A, 0x56, 0x00, 0xBB}, //- проверен работает
{0x01, 0xBE, 0x40, 0x11, 0x00, 0x00, 0x00, 0x77}, //- проверен работает
{0x01, 0xBE, 0x40, 0x11, 0x0A, 0x00, 0x00, 0x1D}, //- проверен работает Визит иногда КЕЙМАНЫ
{0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2F}, //- проверен(метаком, цифрал, ВИЗИТ).
{0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x9B}, //- проверен Визит, Метакомы, КОНДОР
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x14}, //???-Открываает 98% Метаком и некоторые Цифрал
{0x01, 0x00, 0x00, 0x00, 0x00, 0x90, 0x19, 0xFF}, //???-Отлично работает на старых домофонах
{0x01, 0x6F, 0x2E, 0x88, 0x8A, 0x00, 0x00, 0x4D}, //???-Открывать что-то должен
{0x01, 0x53, 0xD4, 0xFE, 0x00, 0x00, 0x7E, 0x88}, //???-Cyfral, Metakom
{0x01, 0x53, 0xD4, 0xFE, 0x00, 0x00, 0x00, 0x6F}, //???-домофоны Визит (Vizit) - до 99%
{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3D}, //???-домофоны Cyfral CCD-20 - до 70%
{0x01, 0x00, 0xBE, 0x11, 0xAA, 0x00, 0x00, 0xFB}, //???-домофоны Кейман (KEYMAN)
{0x01, 0x76, 0xB8, 0x2E, 0x0F, 0x00, 0x00, 0x5C}, //???-домофоны Форвард
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x14}, // Only FF
{0x01, 0x78, 0x00, 0x48, 0xFD, 0xFF, 0xFF, 0xD1}, // StarNew Uni5
{0x01, 0xA9, 0xE4, 0x3C, 0x09, 0x00, 0x00, 0xE6}, // Eltis Uni
};
uint8_t id_list_metakom[17][4] = {
{0x00, 0x00, 0x00, 0x00}, // Null bytes
{0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
{0x11, 0x11, 0x11, 0x11}, // Only 11
{0x22, 0x22, 0x22, 0x22}, // Only 22
{0x33, 0x33, 0x33, 0x33}, // Only 33
{0x44, 0x44, 0x44, 0x44}, // Only 44
{0x55, 0x55, 0x55, 0x55}, // Only 55
{0x66, 0x66, 0x66, 0x66}, // Only 66
{0x77, 0x77, 0x77, 0x77}, // Only 77
{0x88, 0x88, 0x88, 0x88}, // Only 88
{0x99, 0x99, 0x99, 0x99}, // Only 99
{0x12, 0x34, 0x56, 0x78}, // Incremental UID
{0x9A, 0x78, 0x56, 0x34}, // Decremental UID
{0x04, 0xd0, 0x9b, 0x0d}, // ??
{0x34, 0x00, 0x29, 0x3d}, // ??
{0x04, 0xdf, 0x00, 0x00}, // ??
{0xCA, 0xCA, 0xCA, 0xCA}, // ??
};
uint8_t id_list_cyfral[16][2] = {
{0x00, 0x00}, // Null bytes
{0xFF, 0xFF}, // Only FF
{0x11, 0x11}, // Only 11
{0x22, 0x22}, // Only 22
{0x33, 0x33}, // Only 33
{0x44, 0x44}, // Only 44
{0x55, 0x55}, // Only 55
{0x66, 0x66}, // Only 66
{0x77, 0x77}, // Only 77
{0x88, 0x88}, // Only 88
{0x99, 0x99}, // Only 99
{0x12, 0x34}, // Incremental UID
{0x56, 0x34}, // Decremental UID
{0xCA, 0xCA}, // ??
{0x8E, 0xC9}, // Elevator code
{0x6A, 0x50}, // VERY fresh code from smartkey
};
void ibtnfuzzer_scene_run_attack_on_enter(iBtnFuzzerState* context) {
context->time_between_cards = 8;
context->attack_step = 0;
context->attack_stop_called = false;
context->protocols = ibutton_protocols_alloc();
context->key = ibutton_key_alloc(ibutton_protocols_get_max_data_size(context->protocols));
context->worker = ibutton_worker_alloc(context->protocols);
if(context->proto == Metakom) {
context->keytype = ibutton_protocols_get_id_by_name(context->protocols, "Metakom");
} else if(context->proto == Cyfral) {
context->keytype = ibutton_protocols_get_id_by_name(context->protocols, "Cyfral");
} else {
context->keytype = ibutton_protocols_get_id_by_name(context->protocols, "DS1990");
}
context->workr_rund = false;
}
void ibtnfuzzer_scene_run_attack_on_exit(iBtnFuzzerState* context) {
if(context->workr_rund) {
ibutton_worker_stop(context->worker);
ibutton_worker_stop_thread(context->worker);
context->workr_rund = false;
}
ibutton_key_free(context->key);
ibutton_worker_free(context->worker);
ibutton_protocols_free(context->protocols);
notification_message(context->notify, &sequence_blink_stop);
}
void ibtnfuzzer_scene_run_attack_on_tick(iBtnFuzzerState* context) {
if(context->is_attacking) {
if(1 == counter) {
ibutton_worker_start_thread(context->worker);
ibutton_key_set_protocol_id(context->key, context->keytype);
iButtonEditableData data;
ibutton_protocols_get_editable_data(context->protocols, context->key, &data);
data.size = sizeof(context->payload);
for(size_t i = 0; i < data.size; i++) {
data.ptr[i] = context->payload[i];
}
ibutton_worker_emulate_start(context->worker, context->key);
context->workr_rund = true;
} else if(0 == counter) {
if(context->workr_rund) {
ibutton_worker_stop(context->worker);
ibutton_worker_stop_thread(context->worker);
context->workr_rund = false;
furi_delay_ms(500);
}
switch(context->attack) {
case iBtnFuzzerAttackDefaultValues:
if(context->proto == DS1990) {
context->payload[0] = id_list_ds1990[context->attack_step][0];
context->payload[1] = id_list_ds1990[context->attack_step][1];
context->payload[2] = id_list_ds1990[context->attack_step][2];
context->payload[3] = id_list_ds1990[context->attack_step][3];
context->payload[4] = id_list_ds1990[context->attack_step][4];
context->payload[5] = id_list_ds1990[context->attack_step][5];
context->payload[6] = id_list_ds1990[context->attack_step][6];
context->payload[7] = id_list_ds1990[context->attack_step][7];
if(context->attack_step == 17) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
} else {
context->attack_step++;
}
break;
} else if(context->proto == Metakom) {
context->payload[0] = id_list_metakom[context->attack_step][0];
context->payload[1] = id_list_metakom[context->attack_step][1];
context->payload[2] = id_list_metakom[context->attack_step][2];
context->payload[3] = id_list_metakom[context->attack_step][3];
if(context->attack_step == 16) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
} else {
context->attack_step++;
}
break;
} else {
context->payload[0] = id_list_cyfral[context->attack_step][0];
context->payload[1] = id_list_cyfral[context->attack_step][1];
if(context->attack_step == 15) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
} else {
context->attack_step++;
}
break;
}
case iBtnFuzzerAttackLoadFile:
if(context->proto == DS1990) {
context->payload[0] = context->data[0];
context->payload[1] = context->data[1];
context->payload[2] = context->data[2];
context->payload[3] = context->data[3];
context->payload[4] = context->data[4];
context->payload[5] = context->data[5];
context->payload[6] = context->data[6];
context->payload[7] = context->data[7];
context->payload[context->key_index] = context->attack_step;
if(context->attack_step == 255) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
break;
} else {
context->attack_step++;
}
break;
} else if(context->proto == Cyfral) {
context->payload[0] = context->data[0];
context->payload[1] = context->data[1];
context->payload[context->key_index] = context->attack_step;
if(context->attack_step == 255) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
break;
} else {
context->attack_step++;
}
break;
} else {
context->payload[0] = context->data[0];
context->payload[1] = context->data[1];
context->payload[2] = context->data[2];
context->payload[3] = context->data[3];
context->payload[context->key_index] = context->attack_step;
if(context->attack_step == 255) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
break;
} else {
context->attack_step++;
}
break;
}
case iBtnFuzzerAttackLoadFileCustomUids:
if(context->proto == DS1990) {
bool end_of_list = false;
while(true) {
furi_string_reset(context->data_str);
if(!stream_read_line(context->uids_stream, context->data_str)) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
stream_rewind(context->uids_stream);
end_of_list = true;
break;
}
if(furi_string_get_char(context->data_str, 0) == '#') continue;
if(furi_string_size(context->data_str) != 17) break;
break;
}
if(end_of_list) break;
FURI_LOG_D(TAG, furi_string_get_cstr(context->data_str));
if(furi_string_size(context->data_str) != 17) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_error);
break;
}
// string is valid, parse it in context->payload
for(uint8_t i = 0; i < 8; i++) {
char temp_str[3];
temp_str[0] = furi_string_get_cstr(context->data_str)[i * 2];
temp_str[1] = furi_string_get_cstr(context->data_str)[i * 2 + 1];
temp_str[2] = '\0';
context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16);
}
break;
} else if(context->proto == Cyfral) {
bool end_of_list = false;
while(true) {
furi_string_reset(context->data_str);
if(!stream_read_line(context->uids_stream, context->data_str)) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
stream_rewind(context->uids_stream);
end_of_list = true;
break;
}
if(furi_string_get_char(context->data_str, 0) == '#') continue;
if(furi_string_size(context->data_str) != 5) break;
break;
}
if(end_of_list) break;
FURI_LOG_D(TAG, furi_string_get_cstr(context->data_str));
if(furi_string_size(context->data_str) != 5) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_error);
break;
}
// string is valid, parse it in context->payload
for(uint8_t i = 0; i < 2; i++) {
char temp_str[3];
temp_str[0] = furi_string_get_cstr(context->data_str)[i * 2];
temp_str[1] = furi_string_get_cstr(context->data_str)[i * 2 + 1];
temp_str[2] = '\0';
context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16);
}
break;
} else {
bool end_of_list = false;
while(true) {
furi_string_reset(context->data_str);
if(!stream_read_line(context->uids_stream, context->data_str)) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
stream_rewind(context->uids_stream);
end_of_list = true;
break;
}
if(furi_string_get_char(context->data_str, 0) == '#') continue;
if(furi_string_size(context->data_str) != 9) break;
break;
}
FURI_LOG_D(TAG, furi_string_get_cstr(context->data_str));
if(end_of_list) break;
if(furi_string_size(context->data_str) != 9) {
context->attack_step = 0;
counter = 0;
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_error);
break;
}
// string is valid, parse it in context->payload
for(uint8_t i = 0; i < 4; i++) {
char temp_str[3];
temp_str[0] = furi_string_get_cstr(context->data_str)[i * 2];
temp_str[1] = furi_string_get_cstr(context->data_str)[i * 2 + 1];
temp_str[2] = '\0';
context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16);
}
break;
}
}
}
if(counter > context->time_between_cards) {
counter = 0;
} else {
counter++;
}
}
}
void ibtnfuzzer_scene_run_attack_on_event(iBtnFuzzerEvent event, iBtnFuzzerState* context) {
if(event.evt_type == EventTypeKey) {
if(event.input_type == InputTypeShort) {
switch(event.key) {
case InputKeyDown:
break;
case InputKeyUp:
break;
case InputKeyLeft:
if(!context->is_attacking) {
if(context->time_between_cards > 4) {
context->time_between_cards--;
}
}
break;
case InputKeyRight:
if(!context->is_attacking) {
if(context->time_between_cards < 80) {
context->time_between_cards++;
}
}
break;
case InputKeyOk:
counter = 0;
if(!context->is_attacking) {
notification_message(context->notify, &sequence_blink_start_blue);
context->is_attacking = true;
} else {
context->is_attacking = false;
notification_message(context->notify, &sequence_blink_stop);
notification_message(context->notify, &sequence_single_vibro);
}
break;
case InputKeyBack:
context->is_attacking = false;
counter = 0;
notification_message(context->notify, &sequence_blink_stop);
if(context->attack_stop_called) {
context->attack_stop_called = false;
context->attack_step = 0;
if(context->attack == iBtnFuzzerAttackLoadFileCustomUids) {
furi_string_reset(context->data_str);
stream_rewind(context->uids_stream);
buffered_file_stream_close(context->uids_stream);
}
furi_string_reset(context->notification_msg);
context->current_scene = SceneEntryPoint;
}
context->attack_stop_called = true;
break;
default:
break;
}
}
if(event.input_type == InputTypeLong) {
switch(event.key) {
case InputKeyLeft:
if(!context->is_attacking) {
if(context->time_between_cards > 4) {
if((context->time_between_cards - 10) > 4) {
context->time_between_cards -= 10;
}
}
}
break;
case InputKeyRight:
if(!context->is_attacking) {
if(context->time_between_cards < 80) {
context->time_between_cards += 10;
}
}
break;
default:
break;
}
}
}
}
void ibtnfuzzer_scene_run_attack_on_draw(Canvas* canvas, iBtnFuzzerState* 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, 2, AlignCenter, AlignTop, furi_string_get_cstr(context->attack_name));
char uid[25];
char speed[16];
if(context->proto == Metakom) {
snprintf(
uid,
sizeof(uid),
"%02X:%02X:%02X:%02X",
context->payload[0],
context->payload[1],
context->payload[2],
context->payload[3]);
} else if(context->proto == Cyfral) {
snprintf(uid, sizeof(uid), "%02X:%02X", context->payload[0], context->payload[1]);
} else {
snprintf(
uid,
sizeof(uid),
"%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
context->payload[0],
context->payload[1],
context->payload[2],
context->payload[3],
context->payload[4],
context->payload[5],
context->payload[6],
context->payload[7]);
}
canvas_draw_str_aligned(canvas, 64, 38, AlignCenter, AlignTop, uid);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas, 64, 26, AlignCenter, AlignTop, furi_string_get_cstr(context->proto_name));
snprintf(speed, sizeof(speed), "Time delay: %d", context->time_between_cards);
//canvas_draw_str_aligned(canvas, 0, 22, AlignLeft, AlignTop, "Speed:");
canvas_draw_str_aligned(canvas, 64, 14, AlignCenter, AlignTop, speed);
//char start_stop_msg[20];
if(context->is_attacking) {
elements_button_center(canvas, "Stop");
//snprintf(start_stop_msg, sizeof(start_stop_msg), " Press OK to stop ");
} else {
elements_button_center(canvas, "Start");
elements_button_left(canvas, "TD -");
elements_button_right(canvas, "+ TD");
}
//canvas_draw_str_aligned(canvas, 64, 44, AlignCenter, AlignTop, start_stop_msg);
}

View File

@@ -1,8 +0,0 @@
#pragma once
#include "../ibtnfuzzer.h"
void ibtnfuzzer_scene_run_attack_on_enter(iBtnFuzzerState* context);
void ibtnfuzzer_scene_run_attack_on_exit(iBtnFuzzerState* context);
void ibtnfuzzer_scene_run_attack_on_tick(iBtnFuzzerState* context);
void ibtnfuzzer_scene_run_attack_on_event(iBtnFuzzerEvent event, iBtnFuzzerState* context);
void ibtnfuzzer_scene_run_attack_on_draw(Canvas* canvas, iBtnFuzzerState* context);

View File

@@ -1,160 +0,0 @@
#include "ibtnfuzzer_scene_select_field.h"
void ibtnfuzzer_center_displayed_key(iBtnFuzzerState* context, uint8_t index) {
char key_cstr[25];
uint8_t key_len = 25;
uint8_t str_index = (index * 3);
int data_len = sizeof(context->data) / sizeof(context->data[0]);
int key_index = 0;
if(context->proto == DS1990) {
key_len = 25;
}
if(context->proto == Metakom) {
key_len = 13;
}
if(context->proto == Cyfral) {
key_len = 7;
}
for(uint8_t i = 0; i < data_len; i++) {
if(context->data[i] < 9) {
key_index +=
snprintf(&key_cstr[key_index], key_len - key_index, "0%X ", context->data[i]);
} else {
key_index +=
snprintf(&key_cstr[key_index], key_len - key_index, "%X ", context->data[i]);
}
}
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] = ' ';
}
furi_string_reset(context->notification_msg);
furi_string_set(context->notification_msg, display_menu);
}
void ibtnfuzzer_scene_select_field_on_enter(iBtnFuzzerState* context) {
furi_string_reset(context->notification_msg);
}
void ibtnfuzzer_scene_select_field_on_exit(iBtnFuzzerState* context) {
UNUSED(context);
}
void ibtnfuzzer_scene_select_field_on_tick(iBtnFuzzerState* context) {
UNUSED(context);
}
void ibtnfuzzer_scene_select_field_on_event(iBtnFuzzerEvent event, iBtnFuzzerState* context) {
if(event.evt_type == EventTypeKey) {
if(event.input_type == InputTypeShort) {
const char* key_cstr = furi_string_get_cstr(context->data_str);
int data_len = sizeof(context->data) / sizeof(context->data[0]);
// 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:
for(uint8_t i = 0; i < data_len; i++) {
if(context->key_index == i) {
context->data[i] = (context->data[i] - 1);
}
}
break;
case InputKeyUp:
for(uint8_t i = 0; i < data_len; i++) {
if(context->key_index == i) {
context->data[i] = (context->data[i] + 1);
}
}
break;
case InputKeyLeft:
if(context->key_index > 0) {
context->key_index = context->key_index - 1;
}
break;
case InputKeyRight:
if(context->key_index < nb_bytes) {
context->key_index = context->key_index + 1;
}
break;
case InputKeyOk:
furi_string_reset(context->notification_msg);
context->current_scene = SceneAttack;
break;
case InputKeyBack:
context->key_index = 0;
furi_string_reset(context->notification_msg);
context->current_scene = SceneSelectFile;
break;
default:
break;
}
FURI_LOG_D(TAG, "Position: %d/%d", context->key_index, nb_bytes);
}
}
}
void ibtnfuzzer_scene_select_field_on_draw(Canvas* canvas, iBtnFuzzerState* context) {
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
// Frame
//canvas_draw_frame(canvas, 0, 0, 128, 64);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(canvas, 12, 5, AlignLeft, AlignTop, "Left and right: select byte");
canvas_draw_str_aligned(canvas, 12, 15, AlignLeft, AlignTop, "Up and down: adjust byte");
char msg_index[18];
canvas_set_font(canvas, FontPrimary);
snprintf(msg_index, sizeof(msg_index), "Field index : %d", context->key_index);
canvas_draw_str_aligned(canvas, 64, 30, AlignCenter, AlignTop, msg_index);
ibtnfuzzer_center_displayed_key(context, context->key_index);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas, 64, 45, AlignCenter, AlignTop, furi_string_get_cstr(context->notification_msg));
}

View File

@@ -1,9 +0,0 @@
#pragma once
#include "../ibtnfuzzer.h"
void ibtnfuzzer_scene_select_field_on_enter(iBtnFuzzerState* context);
void ibtnfuzzer_scene_select_field_on_exit(iBtnFuzzerState* context);
void ibtnfuzzer_scene_select_field_on_tick(iBtnFuzzerState* context);
void ibtnfuzzer_scene_select_field_on_event(iBtnFuzzerEvent event, iBtnFuzzerState* context);
void ibtnfuzzer_scene_select_field_on_draw(Canvas* canvas, iBtnFuzzerState* context);
void center_displayed_key(iBtnFuzzerState* context, uint8_t index);

View File

@@ -0,0 +1,49 @@
App(
appid="fuzzer_ibtn",
name="iButton Fuzzer",
apptype=FlipperAppType.EXTERNAL,
entry_point="fuzzer_start_ibtn",
requires=[
"gui",
"storage",
"dialogs",
"input",
"notification",
],
stack_size=2 * 1024,
fap_icon="icons/ibutt_10px.png",
fap_category="Tools",
fap_private_libs=[
Lib(
name="worker",
cdefines=["IBUTTON_PROTOCOL"],
),
],
fap_icon_assets="icons",
fap_icon_assets_symbol="fuzzer",
)
App(
appid="fuzzer_rfid",
name="RFID Fuzzer",
apptype=FlipperAppType.EXTERNAL,
entry_point="fuzzer_start_rfid",
requires=[
"gui",
"storage",
"dialogs",
"input",
"notification",
],
stack_size=2 * 1024,
fap_icon="icons/rfid_10px.png",
fap_category="Tools",
fap_private_libs=[
Lib(
name="worker",
cdefines=["RFID_125_PROTOCOL"],
),
],
fap_icon_assets="icons",
fap_icon_assets_symbol="fuzzer",
)

View File

@@ -0,0 +1,163 @@
#include "fuzzer_i.h"
#include "helpers/fuzzer_types.h"
#include <dolphin/dolphin.h>
static bool fuzzer_app_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
PacsFuzzerApp* app = context;
return scene_manager_handle_custom_event(app->scene_manager, event);
}
static bool fuzzer_app_back_event_callback(void* context) {
furi_assert(context);
PacsFuzzerApp* app = context;
return scene_manager_handle_back_event(app->scene_manager);
}
static void fuzzer_app_tick_event_callback(void* context) {
furi_assert(context);
PacsFuzzerApp* app = context;
scene_manager_handle_tick_event(app->scene_manager);
}
PacsFuzzerApp* fuzzer_app_alloc() {
DOLPHIN_DEED(DolphinDeedPluginStart);
PacsFuzzerApp* app = malloc(sizeof(PacsFuzzerApp));
app->fuzzer_state.menu_index = 0;
app->fuzzer_state.proto_index = 0;
app->worker = fuzzer_worker_alloc();
app->payload = fuzzer_payload_alloc();
app->file_path = furi_string_alloc();
// GUI
app->gui = furi_record_open(RECORD_GUI);
// Dialog
app->dialogs = furi_record_open(RECORD_DIALOGS);
// Open Notification record
app->notifications = furi_record_open(RECORD_NOTIFICATION);
// View Dispatcher
app->view_dispatcher = view_dispatcher_alloc();
// Popup
app->popup = popup_alloc();
view_dispatcher_add_view(app->view_dispatcher, FuzzerViewIDPopup, popup_get_view(app->popup));
// Main view
app->main_view = fuzzer_view_main_alloc();
view_dispatcher_add_view(
app->view_dispatcher, FuzzerViewIDMain, fuzzer_view_main_get_view(app->main_view));
// Attack view
app->attack_view = fuzzer_view_attack_alloc();
view_dispatcher_add_view(
app->view_dispatcher, FuzzerViewIDAttack, fuzzer_view_attack_get_view(app->attack_view));
// FieldEditor view
app->field_editor_view = fuzzer_view_field_editor_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
FuzzerViewIDFieldEditor,
fuzzer_view_field_editor_get_view(app->field_editor_view));
app->scene_manager = scene_manager_alloc(&fuzzer_scene_handlers, app);
view_dispatcher_enable_queue(app->view_dispatcher);
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
view_dispatcher_set_custom_event_callback(
app->view_dispatcher, fuzzer_app_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
app->view_dispatcher, fuzzer_app_back_event_callback);
view_dispatcher_set_tick_event_callback(
app->view_dispatcher, fuzzer_app_tick_event_callback, 100);
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
scene_manager_next_scene(app->scene_manager, FuzzerSceneMain);
return app;
}
void fuzzer_app_free(PacsFuzzerApp* app) {
furi_assert(app);
// Remote view
view_dispatcher_remove_view(app->view_dispatcher, FuzzerViewIDMain);
fuzzer_view_main_free(app->main_view);
// Attack view
view_dispatcher_remove_view(app->view_dispatcher, FuzzerViewIDAttack);
fuzzer_view_attack_free(app->attack_view);
// FieldEditor view
view_dispatcher_remove_view(app->view_dispatcher, FuzzerViewIDFieldEditor);
fuzzer_view_field_editor_free(app->field_editor_view);
// Popup
view_dispatcher_remove_view(app->view_dispatcher, FuzzerViewIDPopup);
popup_free(app->popup);
scene_manager_free(app->scene_manager);
view_dispatcher_free(app->view_dispatcher);
// Dialog
furi_record_close(RECORD_DIALOGS);
// Close records
furi_record_close(RECORD_GUI);
// Notifications
furi_record_close(RECORD_NOTIFICATION);
app->notifications = NULL;
furi_string_free(app->file_path);
fuzzer_payload_free(app->payload);
fuzzer_worker_free(app->worker);
free(app);
}
int32_t fuzzer_start_ibtn(void* p) {
UNUSED(p);
PacsFuzzerApp* fuzzer_app = fuzzer_app_alloc();
FuzzerConsts app_const = {
.custom_dict_folder = "/ext/ibtnfuzzer",
.custom_dict_extension = ".txt",
.key_extension = ".ibtn",
.path_key_folder = "/ext/ibutton",
.key_icon = &I_ibutt_10px,
};
fuzzer_app->fuzzer_const = &app_const;
view_dispatcher_run(fuzzer_app->view_dispatcher);
fuzzer_app_free(fuzzer_app);
return 0;
}
int32_t fuzzer_start_rfid(void* p) {
UNUSED(p);
PacsFuzzerApp* fuzzer_app = fuzzer_app_alloc();
FuzzerConsts app_const = {
.custom_dict_folder = "/ext/rfidfuzzer",
.custom_dict_extension = ".txt",
.key_extension = ".rfid",
.path_key_folder = "/ext/lfrfid",
.key_icon = &I_125_10px,
};
fuzzer_app->fuzzer_const = &app_const;
view_dispatcher_run(fuzzer_app->view_dispatcher);
fuzzer_app_free(fuzzer_app);
return 0;
}

View File

@@ -0,0 +1,55 @@
#pragma once
#include <furi.h>
#include <furi_hal.h>
#include <gui/gui.h>
#include <gui/view_dispatcher.h>
#include <gui/scene_manager.h>
#include <gui/modules/popup.h>
#include <dialogs/dialogs.h>
#include <notification/notification_messages.h>
#include "scenes/fuzzer_scene.h"
#include "views/main_menu.h"
#include "views/attack.h"
#include "views/field_editor.h"
#include "helpers/fuzzer_types.h"
#include "lib/worker/fake_worker.h"
#include <flipper_format/flipper_format_i.h>
#include "fuzzer_icons.h"
#define FUZZ_TIME_DELAY_MAX (80)
typedef struct {
const char* custom_dict_extension;
const char* custom_dict_folder;
const char* key_extension;
const char* path_key_folder;
const Icon* key_icon;
} FuzzerConsts;
typedef struct {
Gui* gui;
NotificationApp* notifications;
ViewDispatcher* view_dispatcher;
SceneManager* scene_manager;
Popup* popup;
DialogsApp* dialogs;
FuzzerViewMain* main_view;
FuzzerViewAttack* attack_view;
FuzzerViewFieldEditor* field_editor_view;
FuriString* file_path;
FuzzerState fuzzer_state;
FuzzerConsts* fuzzer_const;
FuzzerWorker* worker;
FuzzerPayload* payload;
} PacsFuzzerApp;

View File

@@ -0,0 +1,17 @@
#pragma once
typedef enum {
// FuzzerCustomEvent
FuzzerCustomEventViewMainBack = 100,
FuzzerCustomEventViewMainOk,
FuzzerCustomEventViewMainPopupErr,
FuzzerCustomEventViewAttackBack,
FuzzerCustomEventViewAttackOk,
// FuzzerCustomEventViewAttackTick, // now not use
FuzzerCustomEventViewAttackEnd,
FuzzerCustomEventViewFieldEditorBack,
FuzzerCustomEventViewFieldEditorOk,
} FuzzerCustomEvent;

View File

@@ -0,0 +1,30 @@
#pragma once
#include <furi.h>
typedef struct {
uint8_t menu_index;
uint8_t proto_index;
} FuzzerState;
typedef enum {
FuzzerAttackStateOff = 0,
FuzzerAttackStateIdle,
FuzzerAttackStateRunning,
FuzzerAttackStateEnd,
} FuzzerAttackState;
typedef enum {
FuzzerFieldEditorStateEditingOn = 0,
FuzzerFieldEditorStateEditingOff,
} FuzzerFieldEditorState;
typedef enum {
FuzzerViewIDPopup,
FuzzerViewIDMain,
FuzzerViewIDAttack,
FuzzerViewIDFieldEditor,
} FuzzerViewID;

View File

Before

Width:  |  Height:  |  Size: 308 B

After

Width:  |  Height:  |  Size: 308 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 304 B

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -0,0 +1,485 @@
#include "fake_worker.h"
#include "protocol_i.h"
#include <timer.h>
#include <lib/toolbox/hex.h>
#include <toolbox/stream/stream.h>
#include <toolbox/stream/buffered_file_stream.h>
#define TAG "Fuzzer worker"
#if defined(RFID_125_PROTOCOL)
#include <lib/lfrfid/lfrfid_dict_file.h>
#include <lib/lfrfid/lfrfid_worker.h>
#include <lfrfid/protocols/lfrfid_protocols.h>
#else
#include <lib/ibutton/ibutton_worker.h>
#include <lib/ibutton/ibutton_key.h>
#endif
#include <toolbox/stream/stream.h>
struct FuzzerWorker {
#if defined(RFID_125_PROTOCOL)
LFRFIDWorker* proto_worker;
ProtocolId protocol_id;
ProtocolDict* protocols_items;
#else
iButtonWorker* proto_worker;
iButtonProtocolId protocol_id; // TODO
iButtonProtocols* protocols_items;
iButtonKey* key;
#endif
const FuzzerProtocol* protocol;
FuzzerWorkerAttackType attack_type;
uint16_t timer_idle_time_ms;
uint16_t timer_emu_time_ms;
uint8_t payload[MAX_PAYLOAD_SIZE];
Stream* uids_stream;
uint16_t index;
uint8_t chusen_byte;
bool treead_running;
bool in_emu_phase;
FuriTimer* timer;
FuzzerWorkerUidChagedCallback tick_callback;
void* tick_context;
FuzzerWorkerEndCallback end_callback;
void* end_context;
};
static bool fuzzer_worker_load_key(FuzzerWorker* instance, bool next) {
furi_assert(instance);
furi_assert(instance->protocol);
bool res = false;
const FuzzerProtocol* protocol = instance->protocol;
switch(instance->attack_type) {
case FuzzerWorkerAttackTypeDefaultDict:
if(next) {
instance->index++;
}
if(instance->index < protocol->dict.len) {
memcpy(
instance->payload,
&protocol->dict.val[instance->index * protocol->data_size],
protocol->data_size);
res = true;
}
break;
case FuzzerWorkerAttackTypeLoadFileCustomUids: {
if(next) {
instance->index++;
}
uint8_t str_len = protocol->data_size * 2 + 1;
FuriString* data_str = furi_string_alloc();
while(true) {
furi_string_reset(data_str);
if(!stream_read_line(instance->uids_stream, data_str)) {
stream_rewind(instance->uids_stream);
// TODO Check empty file & close stream and storage
break;
} else if(furi_string_get_char(data_str, 0) == '#') {
// Skip comment string
continue;
} else if(furi_string_size(data_str) != str_len) {
// Ignore strin with bad length
FURI_LOG_W(TAG, "Bad string length");
continue;
} else {
FURI_LOG_D(TAG, "Uid candidate: \"%s\"", furi_string_get_cstr(data_str));
bool parse_ok = true;
for(uint8_t i = 0; i < protocol->data_size; i++) {
if(!hex_char_to_uint8(
furi_string_get_cstr(data_str)[i * 2],
furi_string_get_cstr(data_str)[i * 2 + 1],
&instance->payload[i])) {
parse_ok = false;
break;
}
}
res = parse_ok;
}
break;
}
}
break;
case FuzzerWorkerAttackTypeLoadFile:
if(instance->payload[instance->index] != 0xFF) {
instance->payload[instance->index]++;
res = true;
}
break;
default:
break;
}
#if defined(RFID_125_PROTOCOL)
protocol_dict_set_data(
instance->protocols_items, instance->protocol_id, instance->payload, MAX_PAYLOAD_SIZE);
#else
ibutton_key_set_protocol_id(instance->key, instance->protocol_id);
iButtonEditableData data;
ibutton_protocols_get_editable_data(instance->protocols_items, instance->key, &data);
// TODO check data.size logic
data.size = MAX_PAYLOAD_SIZE;
memcpy(data.ptr, instance->payload, MAX_PAYLOAD_SIZE); // data.size);
#endif
return res;
}
static void fuzzer_worker_on_tick_callback(void* context) {
furi_assert(context);
FuzzerWorker* instance = context;
if(instance->in_emu_phase) {
if(instance->treead_running) {
#if defined(RFID_125_PROTOCOL)
lfrfid_worker_stop(instance->proto_worker);
#else
ibutton_worker_stop(instance->proto_worker);
#endif
}
instance->in_emu_phase = false;
furi_timer_start(instance->timer, furi_ms_to_ticks(instance->timer_idle_time_ms));
} else {
if(!fuzzer_worker_load_key(instance, true)) {
fuzzer_worker_pause(instance); // XXX
if(instance->end_callback) {
instance->end_callback(instance->end_context);
}
} else {
if(instance->treead_running) {
#if defined(RFID_125_PROTOCOL)
lfrfid_worker_emulate_start(instance->proto_worker, instance->protocol_id);
#else
ibutton_worker_emulate_start(instance->proto_worker, instance->key);
#endif
}
instance->in_emu_phase = true;
furi_timer_start(instance->timer, furi_ms_to_ticks(instance->timer_emu_time_ms));
if(instance->tick_callback) {
instance->tick_callback(instance->tick_context);
}
}
}
}
void fuzzer_worker_get_current_key(FuzzerWorker* instance, FuzzerPayload* output_key) {
furi_assert(instance);
furi_assert(output_key);
furi_assert(instance->protocol);
output_key->data_size = instance->protocol->data_size;
memcpy(output_key->data, instance->payload, instance->protocol->data_size);
}
static void fuzzer_worker_set_protocol(FuzzerWorker* instance, FuzzerProtocolsID protocol_index) {
instance->protocol = &fuzzer_proto_items[protocol_index];
#if defined(RFID_125_PROTOCOL)
instance->protocol_id =
protocol_dict_get_protocol_by_name(instance->protocols_items, instance->protocol->name);
#else
// TODO iButtonProtocolIdInvalid check
instance->protocol_id =
ibutton_protocols_get_id_by_name(instance->protocols_items, instance->protocol->name);
#endif
}
bool fuzzer_worker_init_attack_dict(FuzzerWorker* instance, FuzzerProtocolsID protocol_index) {
furi_assert(instance);
bool res = false;
fuzzer_worker_set_protocol(instance, protocol_index);
instance->attack_type = FuzzerWorkerAttackTypeDefaultDict;
instance->index = 0;
if(!fuzzer_worker_load_key(instance, false)) {
instance->attack_type = FuzzerWorkerAttackTypeMax;
} else {
res = true;
}
return res;
}
bool fuzzer_worker_init_attack_file_dict(
FuzzerWorker* instance,
FuzzerProtocolsID protocol_index,
FuriString* file_path) {
furi_assert(instance);
furi_assert(file_path);
bool res = false;
fuzzer_worker_set_protocol(instance, protocol_index);
Storage* storage = furi_record_open(RECORD_STORAGE);
instance->uids_stream = buffered_file_stream_alloc(storage);
if(!buffered_file_stream_open(
instance->uids_stream, furi_string_get_cstr(file_path), FSAM_READ, FSOM_OPEN_EXISTING)) {
buffered_file_stream_close(instance->uids_stream);
return res;
}
instance->attack_type = FuzzerWorkerAttackTypeLoadFileCustomUids;
instance->index = 0;
if(!fuzzer_worker_load_key(instance, false)) {
instance->attack_type = FuzzerWorkerAttackTypeMax;
buffered_file_stream_close(instance->uids_stream);
furi_record_close(RECORD_STORAGE);
} else {
res = true;
}
return res;
}
bool fuzzer_worker_init_attack_bf_byte(
FuzzerWorker* instance,
FuzzerProtocolsID protocol_index,
const FuzzerPayload* new_uid,
uint8_t chusen) {
furi_assert(instance);
bool res = false;
fuzzer_worker_set_protocol(instance, protocol_index);
instance->attack_type = FuzzerWorkerAttackTypeLoadFile;
instance->index = chusen;
memcpy(instance->payload, new_uid->data, instance->protocol->data_size);
res = true;
return res;
}
// TODO make it protocol independent
bool fuzzer_worker_load_key_from_file(
FuzzerWorker* instance,
FuzzerProtocolsID protocol_index,
const char* filename) {
furi_assert(instance);
bool res = false;
fuzzer_worker_set_protocol(instance, protocol_index);
#if defined(RFID_125_PROTOCOL)
ProtocolId loaded_proto_id = lfrfid_dict_file_load(instance->protocols_items, filename);
if(loaded_proto_id == PROTOCOL_NO) {
// Err Cant load file
FURI_LOG_W(TAG, "Cant load file");
} else if(instance->protocol_id != loaded_proto_id) { // Err wrong protocol
FURI_LOG_W(TAG, "Wrong protocol");
FURI_LOG_W(
TAG,
"Selected: %s Loaded: %s",
instance->protocol->name,
protocol_dict_get_name(instance->protocols_items, loaded_proto_id));
} else {
protocol_dict_get_data(
instance->protocols_items, instance->protocol_id, instance->payload, MAX_PAYLOAD_SIZE);
res = true;
}
#else
if(!ibutton_protocols_load(instance->protocols_items, instance->key, filename)) {
// Err Cant load file
FURI_LOG_W(TAG, "Cant load file");
} else {
if(instance->protocol_id != ibutton_key_get_protocol_id(instance->key)) {
// Err wrong protocol
FURI_LOG_W(TAG, "Wrong protocol");
FURI_LOG_W(
TAG,
"Selected: %s Loaded: %s",
instance->protocol->name,
ibutton_protocols_get_name(
instance->protocols_items, ibutton_key_get_protocol_id(instance->key)));
} else {
iButtonEditableData data;
ibutton_protocols_get_editable_data(instance->protocols_items, instance->key, &data);
memcpy(instance->payload, data.ptr, data.size);
res = true;
}
}
#endif
return res;
}
FuzzerWorker* fuzzer_worker_alloc() {
FuzzerWorker* instance = malloc(sizeof(FuzzerWorker));
#if defined(RFID_125_PROTOCOL)
instance->protocols_items = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
instance->proto_worker = lfrfid_worker_alloc(instance->protocols_items);
#else
instance->protocols_items = ibutton_protocols_alloc();
instance->key =
ibutton_key_alloc(ibutton_protocols_get_max_data_size(instance->protocols_items));
instance->proto_worker = ibutton_worker_alloc(instance->protocols_items);
#endif
instance->attack_type = FuzzerWorkerAttackTypeMax;
instance->index = 0;
instance->treead_running = false;
instance->in_emu_phase = false;
memset(instance->payload, 0x00, sizeof(instance->payload));
instance->timer_idle_time_ms = PROTOCOL_DEF_IDLE_TIME * 100;
instance->timer_emu_time_ms = PROTOCOL_DEF_EMU_TIME * 100;
instance->timer =
furi_timer_alloc(fuzzer_worker_on_tick_callback, FuriTimerTypeOnce, instance);
return instance;
}
void fuzzer_worker_free(FuzzerWorker* instance) {
furi_assert(instance);
fuzzer_worker_stop(instance);
furi_timer_free(instance->timer);
#if defined(RFID_125_PROTOCOL)
lfrfid_worker_free(instance->proto_worker);
protocol_dict_free(instance->protocols_items);
#else
ibutton_worker_free(instance->proto_worker);
ibutton_key_free(instance->key);
ibutton_protocols_free(instance->protocols_items);
#endif
free(instance);
}
bool fuzzer_worker_start(FuzzerWorker* instance, uint8_t idle_time, uint8_t emu_time) {
furi_assert(instance);
if(instance->attack_type < FuzzerWorkerAttackTypeMax) {
if(idle_time == 0) {
instance->timer_idle_time_ms = 10;
} else {
instance->timer_idle_time_ms = idle_time * 100;
}
if(emu_time == 0) {
instance->timer_emu_time_ms = 10;
} else {
instance->timer_emu_time_ms = emu_time * 100;
}
FURI_LOG_D(
TAG,
"Emu_time %u ms Idle_time %u ms",
instance->timer_emu_time_ms,
instance->timer_idle_time_ms);
if(!instance->treead_running) {
#if defined(RFID_125_PROTOCOL)
lfrfid_worker_start_thread(instance->proto_worker);
#else
ibutton_worker_start_thread(instance->proto_worker);
#endif
FURI_LOG_D(TAG, "Worker Starting");
instance->treead_running = true;
} else {
FURI_LOG_D(TAG, "Worker UnPaused");
}
#if defined(RFID_125_PROTOCOL)
// lfrfid_worker_start_thread(instance->proto_worker);
lfrfid_worker_emulate_start(instance->proto_worker, instance->protocol_id);
#else
// ibutton_worker_start_thread(instance->proto_worker);
ibutton_worker_emulate_start(instance->proto_worker, instance->key);
#endif
instance->in_emu_phase = true;
furi_timer_start(instance->timer, furi_ms_to_ticks(instance->timer_emu_time_ms));
return true;
}
return false;
}
void fuzzer_worker_pause(FuzzerWorker* instance) {
furi_assert(instance);
furi_timer_stop(instance->timer);
if(instance->treead_running) {
#if defined(RFID_125_PROTOCOL)
lfrfid_worker_stop(instance->proto_worker);
#else
ibutton_worker_stop(instance->proto_worker);
#endif
FURI_LOG_D(TAG, "Worker Paused");
}
}
void fuzzer_worker_stop(FuzzerWorker* instance) {
furi_assert(instance);
furi_timer_stop(instance->timer);
if(instance->treead_running) {
#if defined(RFID_125_PROTOCOL)
lfrfid_worker_stop(instance->proto_worker);
lfrfid_worker_stop_thread(instance->proto_worker);
#else
ibutton_worker_stop(instance->proto_worker);
ibutton_worker_stop_thread(instance->proto_worker);
#endif
FURI_LOG_D(TAG, "Worker Stopping");
instance->treead_running = false;
}
if(instance->attack_type == FuzzerWorkerAttackTypeLoadFileCustomUids) {
buffered_file_stream_close(instance->uids_stream);
furi_record_close(RECORD_STORAGE);
instance->attack_type = FuzzerWorkerAttackTypeMax;
}
// TODO anything else
}
void fuzzer_worker_set_uid_chaged_callback(
FuzzerWorker* instance,
FuzzerWorkerUidChagedCallback callback,
void* context) {
furi_assert(instance);
instance->tick_callback = callback;
instance->tick_context = context;
}
void fuzzer_worker_set_end_callback(
FuzzerWorker* instance,
FuzzerWorkerEndCallback callback,
void* context) {
furi_assert(instance);
instance->end_callback = callback;
instance->end_context = context;
}

View File

@@ -0,0 +1,138 @@
#pragma once
#include <furi.h>
#include "protocol.h"
typedef enum {
FuzzerWorkerAttackTypeDefaultDict = 0,
FuzzerWorkerAttackTypeLoadFile,
FuzzerWorkerAttackTypeLoadFileCustomUids,
FuzzerWorkerAttackTypeMax,
} FuzzerWorkerAttackType;
typedef void (*FuzzerWorkerUidChagedCallback)(void* context);
typedef void (*FuzzerWorkerEndCallback)(void* context);
typedef struct FuzzerWorker FuzzerWorker;
/**
* Allocate FuzzerWorker
*
* @return FuzzerWorker* pointer to FuzzerWorker
*/
FuzzerWorker* fuzzer_worker_alloc();
/**
* Free FuzzerWorker
*
* @param instance Pointer to a FuzzerWorker
*/
void fuzzer_worker_free(FuzzerWorker* instance);
/**
* Start or continue emulation
*
* @param instance Pointer to a FuzzerWorker
* @param idle_time Delay between emulations in tenths of a second
* @param emu_time Emulation time of one UID in tenths of a second
* @return bool True if emulation has started
*/
bool fuzzer_worker_start(FuzzerWorker* instance, uint8_t idle_time, uint8_t emu_time);
/**
* Stop emulation and deinit worker
*
* @param instance Pointer to a FuzzerWorker
*/
void fuzzer_worker_stop(FuzzerWorker* instance);
/**
* Suspend emulation
*
* @param instance Pointer to a FuzzerWorker
*/
void fuzzer_worker_pause(FuzzerWorker* instance);
/**
* Init attack by default dictionary
*
* @param instance Pointer to a FuzzerWorker
* @param protocol_index index of the selected protocol
* @return bool True if initialization is successful
*/
bool fuzzer_worker_init_attack_dict(FuzzerWorker* instance, FuzzerProtocolsID protocol_index);
/**
* Init attack by custom dictionary
*
* @param instance Pointer to a FuzzerWorker
* @param protocol_index index of the selected protocol
* @param file_path file path to the dictionary
* @return bool True if initialization is successful
*/
bool fuzzer_worker_init_attack_file_dict(
FuzzerWorker* instance,
FuzzerProtocolsID protocol_index,
FuriString* file_path);
/**
* Init attack brute force one of byte
*
* @param instance Pointer to a FuzzerWorker
* @param protocol_index index of the selected protocol
* @param new_uid Pointer to a FuzzerPayload with UID for brute force
* @param chosen index of chusen byte
* @return bool True if initialization is successful
*/
bool fuzzer_worker_init_attack_bf_byte(
FuzzerWorker* instance,
FuzzerProtocolsID protocol_index,
const FuzzerPayload* new_uid,
uint8_t chusen);
/**
* Get current UID
*
* @param instance Pointer to a FuzzerWorker
* @param output_key Pointer to a FuzzerPayload
*/
void fuzzer_worker_get_current_key(FuzzerWorker* instance, FuzzerPayload* output_key);
/**
* Load UID from Flipper Format Key file
*
* @param instance Pointer to a FuzzerWorker
* @param protocol_index index of the selected protocol
* @param filename file path to the key file
* @return bool True if loading is successful
*/
bool fuzzer_worker_load_key_from_file(
FuzzerWorker* instance,
FuzzerProtocolsID protocol_index,
const char* filename);
/**
* Set callback for uid changed
*
* @param instance Pointer to a FuzzerWorker
* @param callback Callback for uid changed
* @param context Context for callback
*/
void fuzzer_worker_set_uid_chaged_callback(
FuzzerWorker* instance,
FuzzerWorkerUidChagedCallback callback,
void* context);
/**
* Set callback for end of emulation
*
* @param instance Pointer to a FuzzerWorker
* @param callback Callback for end of emulation
* @param context Context for callback
*/
void fuzzer_worker_set_end_callback(
FuzzerWorker* instance,
FuzzerWorkerEndCallback callback,
void* context);

View File

@@ -0,0 +1,291 @@
#include "protocol_i.h"
#include "furi.h"
// #######################
// ## Ibutton Protocols ##
// #######################
#define DS1990_DATA_SIZE (8)
#define Metakom_DATA_SIZE (4)
#define Cyfral_DATA_SIZE (2)
const uint8_t uid_list_ds1990[][DS1990_DATA_SIZE] = {
{0x01, 0xBE, 0x40, 0x11, 0x5A, 0x36, 0x00, 0xE1}, // код универсального ключа, для Vizit
{0x01, 0xBE, 0x40, 0x11, 0x5A, 0x56, 0x00, 0xBB}, //- проверен работает
{0x01, 0xBE, 0x40, 0x11, 0x00, 0x00, 0x00, 0x77}, //- проверен работает
{0x01, 0xBE, 0x40, 0x11, 0x0A, 0x00, 0x00, 0x1D}, //- проверен работает Визит иногда КЕЙМАНЫ
{0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2F}, //- проверен(метаком, цифрал, ВИЗИТ).
{0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x9B}, //- проверен Визит, Метакомы, КОНДОР
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x14}, //???-Открываает 98% Метаком и некоторые Цифрал
{0x01, 0x00, 0x00, 0x00, 0x00, 0x90, 0x19, 0xFF}, //???-Отлично работает на старых домофонах
{0x01, 0x6F, 0x2E, 0x88, 0x8A, 0x00, 0x00, 0x4D}, //???-Открывать что-то должен
{0x01, 0x53, 0xD4, 0xFE, 0x00, 0x00, 0x7E, 0x88}, //???-Cyfral, Metakom
{0x01, 0x53, 0xD4, 0xFE, 0x00, 0x00, 0x00, 0x6F}, //???-домофоны Визит (Vizit) - до 99%
{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3D}, //???-домофоны Cyfral CCD-20 - до 70%
{0x01, 0x00, 0xBE, 0x11, 0xAA, 0x00, 0x00, 0xFB}, //???-домофоны Кейман (KEYMAN)
{0x01, 0x76, 0xB8, 0x2E, 0x0F, 0x00, 0x00, 0x5C}, //???-домофоны Форвард
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x14}, // Only FF
{0x01, 0x78, 0x00, 0x48, 0xFD, 0xFF, 0xFF, 0xD1}, // StarNew Uni5
{0x01, 0xA9, 0xE4, 0x3C, 0x09, 0x00, 0x00, 0xE6}, // Eltis Uni
};
const uint8_t uid_list_metakom[][Metakom_DATA_SIZE] = {
{0x00, 0x00, 0x00, 0x00}, // Null bytes
{0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
{0x11, 0x11, 0x11, 0x11}, // Only 11
{0x22, 0x22, 0x22, 0x22}, // Only 22
{0x33, 0x33, 0x33, 0x33}, // Only 33
{0x44, 0x44, 0x44, 0x44}, // Only 44
{0x55, 0x55, 0x55, 0x55}, // Only 55
{0x66, 0x66, 0x66, 0x66}, // Only 66
{0x77, 0x77, 0x77, 0x77}, // Only 77
{0x88, 0x88, 0x88, 0x88}, // Only 88
{0x99, 0x99, 0x99, 0x99}, // Only 99
{0x12, 0x34, 0x56, 0x78}, // Incremental UID
{0x9A, 0x78, 0x56, 0x34}, // Decremental UID
{0x04, 0xd0, 0x9b, 0x0d}, // ??
{0x34, 0x00, 0x29, 0x3d}, // ??
{0x04, 0xdf, 0x00, 0x00}, // ??
{0xCA, 0xCA, 0xCA, 0xCA}, // ??
};
const uint8_t uid_list_cyfral[][Cyfral_DATA_SIZE] = {
{0x00, 0x00}, // Null bytes
{0xFF, 0xFF}, // Only FF
{0x11, 0x11}, // Only 11
{0x22, 0x22}, // Only 22
{0x33, 0x33}, // Only 33
{0x44, 0x44}, // Only 44
{0x55, 0x55}, // Only 55
{0x66, 0x66}, // Only 66
{0x77, 0x77}, // Only 77
{0x88, 0x88}, // Only 88
{0x99, 0x99}, // Only 99
{0x12, 0x34}, // Incremental UID
{0x56, 0x34}, // Decremental UID
{0xCA, 0xCA}, // ??
{0x8E, 0xC9}, // Elevator code
{0x6A, 0x50}, // VERY fresh code from smartkey
};
// ###########################
// ## Rfid_125khz Protocols ##
// ###########################
#define EM4100_DATA_SIZE (5)
#define HIDProx_DATA_SIZE (6)
#define PAC_DATA_SIZE (4)
#define H10301_DATA_SIZE (3)
const uint8_t uid_list_em4100[][EM4100_DATA_SIZE] = {
{0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
{0x11, 0x11, 0x11, 0x11, 0x11}, // Only 11
{0x22, 0x22, 0x22, 0x22, 0x22}, // Only 22
{0x33, 0x33, 0x33, 0x33, 0x33}, // Only 33
{0x44, 0x44, 0x44, 0x44, 0x44}, // Only 44
{0x55, 0x55, 0x55, 0x55, 0x55}, // Only 55
{0x66, 0x66, 0x66, 0x66, 0x66}, // Only 66
{0x77, 0x77, 0x77, 0x77, 0x77}, // Only 77
{0x88, 0x88, 0x88, 0x88, 0x88}, // Only 88
{0x99, 0x99, 0x99, 0x99, 0x99}, // Only 99
{0x12, 0x34, 0x56, 0x78, 0x9A}, // Incremental UID
{0x9A, 0x78, 0x56, 0x34, 0x12}, // Decremental UID
{0x04, 0xd0, 0x9b, 0x0d, 0x6a}, // From arha
{0x34, 0x00, 0x29, 0x3d, 0x9e}, // From arha
{0x04, 0xdf, 0x00, 0x00, 0x01}, // From arha
{0xCA, 0xCA, 0xCA, 0xCA, 0xCA}, // From arha
};
const uint8_t uid_list_hid[][HIDProx_DATA_SIZE] = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
{0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, // Only 11
{0x22, 0x22, 0x22, 0x22, 0x22, 0x22}, // Only 22
{0x33, 0x33, 0x33, 0x33, 0x33, 0x33}, // Only 33
{0x44, 0x44, 0x44, 0x44, 0x44, 0x44}, // Only 44
{0x55, 0x55, 0x55, 0x55, 0x55, 0x55}, // Only 55
{0x66, 0x66, 0x66, 0x66, 0x66, 0x66}, // Only 66
{0x77, 0x77, 0x77, 0x77, 0x77, 0x77}, // Only 77
{0x88, 0x88, 0x88, 0x88, 0x88, 0x88}, // Only 88
{0x99, 0x99, 0x99, 0x99, 0x99, 0x99}, // Only 99
{0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}, // Incremental UID
{0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12}, // Decremental UID
{0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA}, // From arha
};
const uint8_t uid_list_pac[][PAC_DATA_SIZE] = {
{0x00, 0x00, 0x00, 0x00}, // Null bytes
{0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
{0x11, 0x11, 0x11, 0x11}, // Only 11
{0x22, 0x22, 0x22, 0x22}, // Only 22
{0x33, 0x33, 0x33, 0x33}, // Only 33
{0x44, 0x44, 0x44, 0x44}, // Only 44
{0x55, 0x55, 0x55, 0x55}, // Only 55
{0x66, 0x66, 0x66, 0x66}, // Only 66
{0x77, 0x77, 0x77, 0x77}, // Only 77
{0x88, 0x88, 0x88, 0x88}, // Only 88
{0x99, 0x99, 0x99, 0x99}, // Only 99
{0x12, 0x34, 0x56, 0x78}, // Incremental UID
{0x9A, 0x78, 0x56, 0x34}, // Decremental UID
{0x04, 0xd0, 0x9b, 0x0d}, // From arha
{0x34, 0x00, 0x29, 0x3d}, // From arha
{0x04, 0xdf, 0x00, 0x00}, // From arha
{0xCA, 0xCA, 0xCA, 0xCA}, // From arha
};
const uint8_t uid_list_h10301[][H10301_DATA_SIZE] = {
{0x00, 0x00, 0x00}, // Null bytes
{0xFF, 0xFF, 0xFF}, // Only FF
{0x11, 0x11, 0x11}, // Only 11
{0x22, 0x22, 0x22}, // Only 22
{0x33, 0x33, 0x33}, // Only 33
{0x44, 0x44, 0x44}, // Only 44
{0x55, 0x55, 0x55}, // Only 55
{0x66, 0x66, 0x66}, // Only 66
{0x77, 0x77, 0x77}, // Only 77
{0x88, 0x88, 0x88}, // Only 88
{0x99, 0x99, 0x99}, // Only 99
{0x12, 0x34, 0x56}, // Incremental UID
{0x56, 0x34, 0x12}, // Decremental UID
{0xCA, 0xCA, 0xCA}, // From arha
};
#if defined(RFID_125_PROTOCOL)
const FuzzerProtocol fuzzer_proto_items[] = {
[EM4100] =
{
.name = "EM4100",
.data_size = EM4100_DATA_SIZE,
.dict =
{
.val = (const uint8_t*)&uid_list_em4100,
.len = COUNT_OF(uid_list_em4100),
},
},
[HIDProx] =
{
.name = "HIDProx",
.data_size = HIDProx_DATA_SIZE,
.dict =
{
.val = (const uint8_t*)&uid_list_hid,
.len = COUNT_OF(uid_list_hid),
},
},
[PAC] =
{
.name = "PAC/Stanley",
.data_size = PAC_DATA_SIZE,
.dict =
{
.val = (const uint8_t*)&uid_list_pac,
.len = COUNT_OF(uid_list_pac),
},
},
[H10301] =
{
.name = "H10301",
.data_size = H10301_DATA_SIZE,
.dict =
{
.val = (const uint8_t*)&uid_list_h10301,
.len = COUNT_OF(uid_list_h10301),
},
},
};
#else
const FuzzerProtocol fuzzer_proto_items[] = {
[DS1990] =
{
.name = "DS1990",
.data_size = DS1990_DATA_SIZE,
.dict =
{
.val = (const uint8_t*)&uid_list_ds1990,
.len = COUNT_OF(uid_list_ds1990),
},
},
[Metakom] =
{
.name = "Metakom",
.data_size = Metakom_DATA_SIZE,
.dict =
{
.val = (const uint8_t*)&uid_list_metakom,
.len = COUNT_OF(uid_list_metakom),
},
},
[Cyfral] =
{
.name = "Cyfral",
.data_size = Cyfral_DATA_SIZE,
.dict =
{
.val = (const uint8_t*)&uid_list_cyfral,
.len = COUNT_OF(uid_list_cyfral),
},
},
};
#endif
typedef struct {
const char* menu_label;
FuzzerAttackId attack_id;
} FuzzerMenuItems;
const FuzzerMenuItems fuzzer_menu_items[] = {
{"Default Values", FuzzerAttackIdDefaultValues},
#ifdef RFID_125_PROTOCOL
{"BF Customer ID", FuzzerAttackIdBFCustomerID},
#endif
{"Load File", FuzzerAttackIdLoadFile},
{"Load UIDs from file", FuzzerAttackIdLoadFileCustomUids},
};
FuzzerPayload* fuzzer_payload_alloc() {
FuzzerPayload* payload = malloc(sizeof(FuzzerPayload));
payload->data = malloc(sizeof(payload->data[0]) * MAX_PAYLOAD_SIZE);
return payload;
}
void fuzzer_payload_free(FuzzerPayload* payload) {
furi_assert(payload);
if(payload->data) {
free(payload->data);
}
free(payload);
}
const char* fuzzer_proto_get_name(FuzzerProtocolsID index) {
return fuzzer_proto_items[index].name;
}
uint8_t fuzzer_proto_get_count_of_protocols() {
return COUNT_OF(fuzzer_proto_items);
}
uint8_t fuzzer_proto_get_max_data_size() {
return MAX_PAYLOAD_SIZE;
}
uint8_t fuzzer_proto_get_def_emu_time() {
return PROTOCOL_DEF_EMU_TIME;
}
uint8_t fuzzer_proto_get_def_idle_time() {
return PROTOCOL_DEF_IDLE_TIME;
}
const char* fuzzer_proto_get_menu_label(uint8_t index) {
return fuzzer_menu_items[index].menu_label;
}
FuzzerAttackId fuzzer_proto_get_attack_id_by_index(uint8_t index) {
return fuzzer_menu_items[index].attack_id;
}
uint8_t fuzzer_proto_get_count_of_menu_items() {
return COUNT_OF(fuzzer_menu_items);
}

View File

@@ -0,0 +1,89 @@
#pragma once
#include <stdint.h>
// #define RFID_125_PROTOCOL
typedef struct FuzzerPayload FuzzerPayload;
typedef enum {
#if defined(RFID_125_PROTOCOL)
EM4100,
HIDProx,
PAC,
H10301,
#else
DS1990,
Metakom,
Cyfral,
#endif
} FuzzerProtocolsID;
typedef enum {
FuzzerAttackIdDefaultValues = 0,
FuzzerAttackIdLoadFile,
FuzzerAttackIdLoadFileCustomUids,
FuzzerAttackIdBFCustomerID,
} FuzzerAttackId;
struct FuzzerPayload {
uint8_t* data;
uint8_t data_size;
};
/**
* Allocate FuzzerPayload
*
* @return FuzzerPayload* pointer to FuzzerPayload
*/
FuzzerPayload* fuzzer_payload_alloc();
/**
* Free FuzzerPayload
*
* @param instance Pointer to a FuzzerPayload
*/
void fuzzer_payload_free(FuzzerPayload*);
/**
* Get maximum length of UID among all supported protocols
* @return Maximum length of UID
*/
uint8_t fuzzer_proto_get_max_data_size();
// TODO add description
uint8_t fuzzer_proto_get_def_emu_time();
uint8_t fuzzer_proto_get_def_idle_time();
/**
* Get protocol name based on its index
* @param index protocol index
* @return pointer to a string containing the name
*/
const char* fuzzer_proto_get_name(FuzzerProtocolsID index);
/**
* Get number of protocols
* @return number of protocols
*/
uint8_t fuzzer_proto_get_count_of_protocols();
/**
* Get menu label based on its index
* @param index menu index
* @return pointer to a string containing the menu label
*/
const char* fuzzer_proto_get_menu_label(uint8_t index);
/**
* Get FuzzerAttackId based on its index
* @param index menu index
* @return FuzzerAttackId
*/
FuzzerAttackId fuzzer_proto_get_attack_id_by_index(uint8_t index);
/**
* Get number of menu items
* @return number of menu items
*/
uint8_t fuzzer_proto_get_count_of_menu_items();

View File

@@ -0,0 +1,43 @@
#pragma once
#include "protocol.h"
#if defined(RFID_125_PROTOCOL)
#define MAX_PAYLOAD_SIZE (6)
#define PROTOCOL_DEF_IDLE_TIME (4)
#define PROTOCOL_DEF_EMU_TIME (5)
#define PROTOCOL_TIME_DELAY_MIN PROTOCOL_DEF_IDLE_TIME + PROTOCOL_DEF_EMU_TIME
#else
#define MAX_PAYLOAD_SIZE (8)
#define PROTOCOL_DEF_IDLE_TIME (2)
#define PROTOCOL_DEF_EMU_TIME (2)
#define PROTOCOL_TIME_DELAY_MIN PROTOCOL_DEF_IDLE_TIME + PROTOCOL_DEF_EMU_TIME
#endif
typedef struct ProtoDict ProtoDict;
typedef struct FuzzerProtocol FuzzerProtocol;
struct ProtoDict {
const uint8_t* val;
const uint8_t len;
};
struct FuzzerProtocol {
const char* name;
const uint8_t data_size;
const ProtoDict dict;
};
// #define MAX_PAYLOAD_SIZE 6
// #define FUZZ_TIME_DELAY_MIN (5)
// #define FUZZ_TIME_DELAY_DEFAULT (10)
// #define FUZZ_TIME_DELAY_MAX (70)
// #define MAX_PAYLOAD_SIZE 8
// #define FUZZ_TIME_DELAY_MIN (4)
// #define FUZZ_TIME_DELAY_DEFAULT (8)
// #define FUZZ_TIME_DELAY_MAX (80)
extern const FuzzerProtocol fuzzer_proto_items[];

View File

@@ -0,0 +1,30 @@
#include "fuzzer_scene.h"
// Generate scene on_enter handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
void (*const fuzzer_scene_on_enter_handlers[])(void*) = {
#include "fuzzer_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 fuzzer_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
#include "fuzzer_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 fuzzer_scene_on_exit_handlers[])(void* context) = {
#include "fuzzer_scene_config.h"
};
#undef ADD_SCENE
// Initialize scene handlers configuration structure
const SceneManagerHandlers fuzzer_scene_handlers = {
.on_enter_handlers = fuzzer_scene_on_enter_handlers,
.on_event_handlers = fuzzer_scene_on_event_handlers,
.on_exit_handlers = fuzzer_scene_on_exit_handlers,
.scene_num = FuzzerSceneNum,
};

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) FuzzerScene##id,
typedef enum {
#include "fuzzer_scene_config.h"
FuzzerSceneNum,
} FuzzerScene;
#undef ADD_SCENE
extern const SceneManagerHandlers fuzzer_scene_handlers;
// Generate scene on_enter handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
#include "fuzzer_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 "fuzzer_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 "fuzzer_scene_config.h"
#undef ADD_SCENE

View File

@@ -0,0 +1,162 @@
#include "../fuzzer_i.h"
#include "../helpers/fuzzer_custom_event.h"
const NotificationSequence sequence_one_green_50_on_blink_blue = {
&message_red_255,
&message_delay_50,
&message_red_0,
&message_blink_start_10,
&message_blink_set_color_blue,
&message_do_not_reset,
NULL,
};
static void fuzzer_scene_attack_update_uid(PacsFuzzerApp* app) {
furi_assert(app);
furi_assert(app->worker);
furi_assert(app->attack_view);
fuzzer_worker_get_current_key(app->worker, app->payload);
fuzzer_view_attack_set_uid(app->attack_view, app->payload);
}
static void fuzzer_scene_attack_set_state(PacsFuzzerApp* app, FuzzerAttackState state) {
furi_assert(app);
scene_manager_set_scene_state(app->scene_manager, FuzzerSceneAttack, state);
switch(state) {
case FuzzerAttackStateIdle:
notification_message(app->notifications, &sequence_blink_stop);
fuzzer_view_attack_pause(app->attack_view);
break;
case FuzzerAttackStateRunning:
notification_message(app->notifications, &sequence_blink_start_blue);
fuzzer_view_attack_start(app->attack_view);
break;
case FuzzerAttackStateEnd:
notification_message(app->notifications, &sequence_blink_stop);
notification_message(app->notifications, &sequence_single_vibro);
fuzzer_view_attack_end(app->attack_view);
break;
case FuzzerAttackStateOff:
notification_message(app->notifications, &sequence_blink_stop);
fuzzer_view_attack_stop(app->attack_view);
break;
}
}
void fuzzer_scene_attack_worker_tick_callback(void* context) {
furi_assert(context);
PacsFuzzerApp* app = context;
notification_message(app->notifications, &sequence_one_green_50_on_blink_blue);
fuzzer_scene_attack_update_uid(app);
// view_dispatcher_send_custom_event(app->view_dispatcher, FuzzerCustomEventViewAttackTick);
}
void fuzzer_scene_attack_worker_end_callback(void* context) {
furi_assert(context);
PacsFuzzerApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, FuzzerCustomEventViewAttackEnd);
}
void fuzzer_scene_attack_callback(FuzzerCustomEvent event, void* context) {
furi_assert(context);
PacsFuzzerApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
void fuzzer_scene_attack_on_enter(void* context) {
furi_assert(context);
PacsFuzzerApp* app = context;
fuzzer_view_attack_set_callback(app->attack_view, fuzzer_scene_attack_callback, app);
fuzzer_worker_set_uid_chaged_callback(
app->worker, fuzzer_scene_attack_worker_tick_callback, app);
fuzzer_worker_set_end_callback(app->worker, fuzzer_scene_attack_worker_end_callback, app);
fuzzer_view_attack_reset_data(
app->attack_view,
fuzzer_proto_get_menu_label(app->fuzzer_state.menu_index),
fuzzer_proto_get_name(app->fuzzer_state.proto_index));
fuzzer_scene_attack_update_uid(app);
scene_manager_set_scene_state(app->scene_manager, FuzzerSceneAttack, FuzzerAttackStateIdle);
view_dispatcher_switch_to_view(app->view_dispatcher, FuzzerViewIDAttack);
}
bool fuzzer_scene_attack_on_event(void* context, SceneManagerEvent event) {
furi_assert(context);
PacsFuzzerApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == FuzzerCustomEventViewAttackBack) {
if(scene_manager_get_scene_state(app->scene_manager, FuzzerSceneAttack) ==
FuzzerAttackStateRunning) {
// Pause if attack running
fuzzer_worker_pause(app->worker);
fuzzer_scene_attack_set_state(app, FuzzerAttackStateIdle);
} else {
// Exit
fuzzer_worker_stop(app->worker);
fuzzer_scene_attack_set_state(app, FuzzerAttackStateOff);
if(!scene_manager_previous_scene(app->scene_manager)) {
scene_manager_stop(app->scene_manager);
view_dispatcher_stop(app->view_dispatcher);
}
}
consumed = true;
} else if(event.event == FuzzerCustomEventViewAttackOk) {
if(scene_manager_get_scene_state(app->scene_manager, FuzzerSceneAttack) ==
FuzzerAttackStateIdle) {
// Start or Continue Attack
if(fuzzer_worker_start(
app->worker,
fuzzer_view_attack_get_time_delay(app->attack_view),
fuzzer_view_attack_get_emu_time(app->attack_view))) {
fuzzer_scene_attack_set_state(app, FuzzerAttackStateRunning);
} else {
// Error?
}
} else if(
scene_manager_get_scene_state(app->scene_manager, FuzzerSceneAttack) ==
FuzzerAttackStateRunning) {
// Pause if attack running
fuzzer_worker_pause(app->worker);
fuzzer_scene_attack_set_state(app, FuzzerAttackStateIdle);
}
consumed = true;
// } else if(event.event == FuzzerCustomEventViewAttackTick) {
// consumed = true;
} else if(event.event == FuzzerCustomEventViewAttackEnd) {
fuzzer_scene_attack_set_state(app, FuzzerAttackStateEnd);
consumed = true;
}
}
return consumed;
}
void fuzzer_scene_attack_on_exit(void* context) {
furi_assert(context);
PacsFuzzerApp* app = context;
// XXX the scene has no descendants, and the return will be processed in on_event
// fuzzer_worker_stop();
fuzzer_worker_set_uid_chaged_callback(app->worker, NULL, NULL);
fuzzer_worker_set_end_callback(app->worker, NULL, NULL);
}

View File

@@ -0,0 +1,3 @@
ADD_SCENE(fuzzer, main, Main)
ADD_SCENE(fuzzer, attack, Attack)
ADD_SCENE(fuzzer, field_editor, FieldEditor)

View File

@@ -0,0 +1,66 @@
#include "../fuzzer_i.h"
#include "../helpers/fuzzer_custom_event.h"
void fuzzer_scene_field_editor_callback(FuzzerCustomEvent event, void* context) {
furi_assert(context);
PacsFuzzerApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
void fuzzer_scene_field_editor_on_enter(void* context) {
furi_assert(context);
PacsFuzzerApp* app = context;
fuzzer_view_field_editor_set_callback(
app->field_editor_view, fuzzer_scene_field_editor_callback, app);
fuzzer_worker_get_current_key(app->worker, app->payload);
switch(scene_manager_get_scene_state(app->scene_manager, FuzzerSceneFieldEditor)) {
case FuzzerFieldEditorStateEditingOn:
fuzzer_view_field_editor_reset_data(app->field_editor_view, app->payload, true);
break;
case FuzzerFieldEditorStateEditingOff:
fuzzer_view_field_editor_reset_data(app->field_editor_view, app->payload, false);
break;
default:
break;
}
view_dispatcher_switch_to_view(app->view_dispatcher, FuzzerViewIDFieldEditor);
}
bool fuzzer_scene_field_editor_on_event(void* context, SceneManagerEvent event) {
furi_assert(context);
PacsFuzzerApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == FuzzerCustomEventViewFieldEditorBack) {
if(!scene_manager_previous_scene(app->scene_manager)) {
scene_manager_stop(app->scene_manager);
view_dispatcher_stop(app->view_dispatcher);
}
consumed = true;
} else if(event.event == FuzzerCustomEventViewFieldEditorOk) {
fuzzer_view_field_editor_get_uid(app->field_editor_view, app->payload);
if(fuzzer_worker_init_attack_bf_byte(
app->worker,
app->fuzzer_state.proto_index,
app->payload,
fuzzer_view_field_editor_get_index(app->field_editor_view))) {
scene_manager_next_scene(app->scene_manager, FuzzerSceneAttack);
}
}
}
return consumed;
}
void fuzzer_scene_field_editor_on_exit(void* context) {
// furi_assert(context);
// PacsFuzzerApp* app = context;
UNUSED(context);
}

View File

@@ -0,0 +1,189 @@
#include "../fuzzer_i.h"
#include "../helpers/fuzzer_custom_event.h"
#include "../lib/worker/protocol.h"
void fuzzer_scene_main_callback(FuzzerCustomEvent event, void* context) {
furi_assert(context);
PacsFuzzerApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
void fuzzer_scene_main_error_popup_callback(void* context) {
PacsFuzzerApp* app = context;
notification_message(app->notifications, &sequence_reset_rgb);
view_dispatcher_send_custom_event(app->view_dispatcher, FuzzerCustomEventViewMainPopupErr);
}
static bool fuzzer_scene_main_load_custom_dict(void* context) {
furi_assert(context);
PacsFuzzerApp* app = context;
FuzzerConsts* consts = app->fuzzer_const;
furi_string_set_str(app->file_path, consts->custom_dict_folder);
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(
&browser_options, consts->custom_dict_extension, &I_rfid_10px);
browser_options.base_path = consts->custom_dict_folder;
browser_options.hide_ext = false;
bool res =
dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options);
return res;
}
static bool fuzzer_scene_main_load_key(void* context) {
furi_assert(context);
PacsFuzzerApp* app = context;
FuzzerConsts* consts = app->fuzzer_const;
furi_string_set_str(app->file_path, consts->path_key_folder);
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(
&browser_options, consts->key_extension, consts->key_icon);
browser_options.base_path = consts->path_key_folder;
browser_options.hide_ext = true;
bool res =
dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options);
return res;
}
static void fuzzer_scene_main_show_error(void* context, const char* erre_str) {
furi_assert(context);
PacsFuzzerApp* app = context;
popup_set_header(app->popup, erre_str, 64, 20, AlignCenter, AlignTop);
notification_message(app->notifications, &sequence_set_red_255);
notification_message(app->notifications, &sequence_double_vibro);
view_dispatcher_switch_to_view(app->view_dispatcher, FuzzerViewIDPopup);
}
void fuzzer_scene_main_on_enter(void* context) {
furi_assert(context);
PacsFuzzerApp* app = context;
fuzzer_view_main_set_callback(app->main_view, fuzzer_scene_main_callback, app);
fuzzer_view_main_update_data(app->main_view, app->fuzzer_state);
// Setup view
Popup* popup = app->popup;
// popup_set_icon(popup, 72, 17, &I_DolphinCommon_56x48);
popup_set_timeout(popup, 2500);
popup_set_context(popup, app);
popup_set_callback(popup, fuzzer_scene_main_error_popup_callback);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(app->view_dispatcher, FuzzerViewIDMain);
}
bool fuzzer_scene_main_on_event(void* context, SceneManagerEvent event) {
furi_assert(context);
PacsFuzzerApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == FuzzerCustomEventViewMainBack) {
if(!scene_manager_previous_scene(app->scene_manager)) {
scene_manager_stop(app->scene_manager);
view_dispatcher_stop(app->view_dispatcher);
}
consumed = true;
} else if(event.event == FuzzerCustomEventViewMainPopupErr) {
view_dispatcher_switch_to_view(app->view_dispatcher, FuzzerViewIDMain);
consumed = true;
} else if(event.event == FuzzerCustomEventViewMainOk) {
fuzzer_view_main_get_state(app->main_view, &app->fuzzer_state);
// TODO error logic
bool loading_ok = false;
switch(fuzzer_proto_get_attack_id_by_index(app->fuzzer_state.menu_index)) {
case FuzzerAttackIdDefaultValues:
loading_ok =
fuzzer_worker_init_attack_dict(app->worker, app->fuzzer_state.proto_index);
if(!loading_ok) {
// error
fuzzer_scene_main_show_error(app, "Default dictionary\nis empty");
}
break;
case FuzzerAttackIdBFCustomerID:
// TODO
app->payload->data_size = fuzzer_proto_get_max_data_size();
memset(app->payload->data, 0x00, app->payload->data_size);
if(fuzzer_worker_init_attack_bf_byte(
app->worker, app->fuzzer_state.proto_index, app->payload, 0)) {
scene_manager_set_scene_state(
app->scene_manager,
FuzzerSceneFieldEditor,
FuzzerFieldEditorStateEditingOff);
scene_manager_next_scene(app->scene_manager, FuzzerSceneFieldEditor);
} else {
// error
}
break;
case FuzzerAttackIdLoadFile:
if(!fuzzer_scene_main_load_key(app)) {
break;
} else {
if(fuzzer_worker_load_key_from_file(
app->worker,
app->fuzzer_state.proto_index,
furi_string_get_cstr(app->file_path))) {
scene_manager_set_scene_state(
app->scene_manager,
FuzzerSceneFieldEditor,
FuzzerFieldEditorStateEditingOn);
scene_manager_next_scene(app->scene_manager, FuzzerSceneFieldEditor);
FURI_LOG_I("Scene", "Load ok");
} else {
fuzzer_scene_main_show_error(app, "Unsupported protocol\nor broken file");
FURI_LOG_W("Scene", "Load err");
}
}
break;
case FuzzerAttackIdLoadFileCustomUids:
if(!fuzzer_scene_main_load_custom_dict(app)) {
break;
} else {
loading_ok = fuzzer_worker_init_attack_file_dict(
app->worker, app->fuzzer_state.proto_index, app->file_path);
if(!loading_ok) {
fuzzer_scene_main_show_error(app, "Incorrect key format\nor length");
// error
}
}
break;
default:
fuzzer_scene_main_show_error(app, "Unsuported attack");
break;
}
if(loading_ok) {
scene_manager_next_scene(app->scene_manager, FuzzerSceneAttack);
}
consumed = true;
}
}
return consumed;
}
void fuzzer_scene_main_on_exit(void* context) {
// furi_assert(context);
// PacsFuzzerApp* app = context;
UNUSED(context);
}

View File

@@ -0,0 +1,44 @@
## Working Improvement
#### Quality of life
- [ ] Make the "Load File" independent of the current protocol
- [x] Add pause
- [ ] Switching UIDs if possible
- [x] Led and sound Notification
- [x] Led
- [x] Vibro
- [ ] Sound?
- [x] Error Notification
- [x] Custom UIDs dict loading
- [x] Key file loading
- [ ] Anything else
#### App functionality
- [x] Add `BFCustomerID` attack
- [x] Add the ability to select index
- [ ] Save key logic
## Code Improvement
- [ ] GUI
- [x] Rewrite `gui_const` logic
- [x] Icon in dialog
- [x] Description and buttons in `field_editor` view
- [ ] Protocol carousel in `main_menu`
- [x] prototype
- [x] Add the ability to edit emulation time and downtime separately
- [x] Decide on the display
- [x] UID
- [x] Simplify the storage and exchange of `uids.data` `uid.data_size` in `views`
- [x] Using `FuzzerPayload` to store the uid
- [x] `UID_MAX_SIZE`
- [x] Add pause
- [x] Fix `Custom dict` attack when ended
- [ ] Pause V2
- [ ] Save logic
- [ ] Switching UIDs if possible
- [ ] Worker
- [ ] Use `prtocol_id` instead of protocol name
- [x] this can be simplified `fuzzer_proto_items`

View File

@@ -0,0 +1,384 @@
#include "attack.h"
#include "../fuzzer_i.h"
#include <input/input.h>
#include <gui/elements.h>
#define ATTACK_SCENE_MAX_UID_LENGTH 25
#define UID_MAX_DISPLAYED_LEN (8U)
#define LIFT_RIGHT_OFFSET (3)
struct FuzzerViewAttack {
View* view;
FuzzerViewAttackCallback callback;
void* context;
};
typedef struct {
uint8_t time_delay; // 1 = 100ms
uint8_t time_delay_min; // 1 = 100ms
uint8_t emu_time; // 1 = 100ms
uint8_t emu_time_min; // 1 = 100ms
bool td_emt_cursor; // false - time_delay, true - emu_time
const char* attack_name;
const char* protocol_name;
FuzzerAttackState attack_state;
FuriString* uid_str;
} FuzzerViewAttackModel;
void fuzzer_view_attack_reset_data(
FuzzerViewAttack* view,
const char* attack_name,
const char* protocol_name) {
furi_assert(view);
with_view_model(
view->view,
FuzzerViewAttackModel * model,
{
model->attack_name = attack_name;
model->protocol_name = protocol_name;
model->attack_state = FuzzerAttackStateIdle;
furi_string_set_str(model->uid_str, "Not_set");
},
true);
}
void fuzzer_view_attack_set_uid(FuzzerViewAttack* view, const FuzzerPayload* uid) {
furi_assert(view);
furi_assert(uid->data);
with_view_model(
view->view,
FuzzerViewAttackModel * model,
{
furi_string_printf(model->uid_str, "%02X", uid->data[0]);
for(uint8_t i = 1; i < uid->data_size; i++) {
furi_string_cat_printf(model->uid_str, ":%02X", uid->data[i]);
}
},
true);
}
void fuzzer_view_attack_start(FuzzerViewAttack* view) {
furi_assert(view);
with_view_model(
view->view,
FuzzerViewAttackModel * model,
{ model->attack_state = FuzzerAttackStateRunning; },
true);
}
void fuzzer_view_attack_stop(FuzzerViewAttack* view) {
furi_assert(view);
with_view_model(
view->view,
FuzzerViewAttackModel * model,
{ model->attack_state = FuzzerAttackStateOff; },
true);
}
void fuzzer_view_attack_pause(FuzzerViewAttack* view) {
furi_assert(view);
with_view_model(
view->view,
FuzzerViewAttackModel * model,
{ model->attack_state = FuzzerAttackStateIdle; },
true);
}
void fuzzer_view_attack_end(FuzzerViewAttack* view) {
furi_assert(view);
with_view_model(
view->view,
FuzzerViewAttackModel * model,
{ model->attack_state = FuzzerAttackStateEnd; },
true);
}
void fuzzer_view_attack_set_callback(
FuzzerViewAttack* view_attack,
FuzzerViewAttackCallback callback,
void* context) {
furi_assert(view_attack);
view_attack->callback = callback;
view_attack->context = context;
}
void fuzzer_view_attack_draw(Canvas* canvas, FuzzerViewAttackModel* model) {
char temp_str[50];
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, model->attack_name);
uint16_t crt;
canvas_set_font(canvas, FontPrimary);
if(!model->td_emt_cursor) {
canvas_set_font(canvas, FontSecondary);
snprintf(temp_str, sizeof(temp_str), "Time delay:");
canvas_draw_str_aligned(canvas, LIFT_RIGHT_OFFSET, 21, AlignLeft, AlignBottom, temp_str);
crt = canvas_string_width(canvas, temp_str);
canvas_set_font(canvas, FontPrimary);
snprintf(
temp_str, sizeof(temp_str), "%d.%d", model->time_delay / 10, model->time_delay % 10);
canvas_draw_str_aligned(
canvas, crt + LIFT_RIGHT_OFFSET + 3, 21, AlignLeft, AlignBottom, temp_str);
canvas_set_font(canvas, FontSecondary);
snprintf(
temp_str, sizeof(temp_str), "EmT: %d.%d", model->emu_time / 10, model->emu_time % 10);
canvas_draw_str_aligned(
canvas, 128 - LIFT_RIGHT_OFFSET, 21, AlignRight, AlignBottom, temp_str);
} else {
canvas_set_font(canvas, FontSecondary);
snprintf(
temp_str,
sizeof(temp_str),
"TD: %d.%d",
model->time_delay / 10,
model->time_delay % 10);
canvas_draw_str_aligned(canvas, LIFT_RIGHT_OFFSET, 21, AlignLeft, AlignBottom, temp_str);
canvas_set_font(canvas, FontPrimary);
snprintf(temp_str, sizeof(temp_str), "%d.%d", model->emu_time / 10, model->emu_time % 10);
canvas_draw_str_aligned(
canvas, 128 - LIFT_RIGHT_OFFSET, 21, AlignRight, AlignBottom, temp_str);
crt = canvas_string_width(canvas, temp_str);
canvas_set_font(canvas, FontSecondary);
snprintf(temp_str, sizeof(temp_str), "Emulation time:");
canvas_draw_str_aligned(
canvas, 128 - LIFT_RIGHT_OFFSET - crt - 3, 21, AlignRight, AlignBottom, temp_str);
}
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(canvas, 64, 26, AlignCenter, AlignTop, model->protocol_name);
canvas_set_font(canvas, FontPrimary);
if(128 < canvas_string_width(canvas, furi_string_get_cstr(model->uid_str))) {
canvas_set_font(canvas, FontSecondary);
}
canvas_draw_str_aligned(
canvas, 64, 38, AlignCenter, AlignTop, furi_string_get_cstr(model->uid_str));
canvas_set_font(canvas, FontSecondary);
if(model->attack_state == FuzzerAttackStateRunning) {
elements_button_center(canvas, "Stop");
} else if(model->attack_state == FuzzerAttackStateIdle) {
if(model->td_emt_cursor) {
elements_button_center(canvas, "Start");
elements_button_left(canvas, "EmT -");
elements_button_right(canvas, "+ EmT");
} else {
elements_button_center(canvas, "Start");
elements_button_left(canvas, "TD -");
elements_button_right(canvas, "+ TD");
}
} else if(model->attack_state == FuzzerAttackStateEnd) {
// elements_button_center(canvas, "Restart"); // Reset
elements_button_left(canvas, "Exit");
}
}
bool fuzzer_view_attack_input(InputEvent* event, void* context) {
furi_assert(context);
FuzzerViewAttack* view_attack = context;
if(event->key == InputKeyBack && event->type == InputTypeShort) {
view_attack->callback(FuzzerCustomEventViewAttackBack, view_attack->context);
return true;
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
view_attack->callback(FuzzerCustomEventViewAttackOk, view_attack->context);
return true;
} else if(event->key == InputKeyLeft) {
with_view_model(
view_attack->view,
FuzzerViewAttackModel * model,
{
if(model->attack_state == FuzzerAttackStateIdle) {
if(!model->td_emt_cursor) {
// TimeDelay --
if(event->type == InputTypeShort) {
if(model->time_delay > model->time_delay_min) {
model->time_delay--;
}
} else if(event->type == InputTypeLong) {
if((model->time_delay - 10) >= model->time_delay_min) {
model->time_delay -= 10;
} else {
model->time_delay = model->time_delay_min;
}
}
} else {
// EmuTime --
if(event->type == InputTypeShort) {
if(model->emu_time > model->emu_time_min) {
model->emu_time--;
}
} else if(event->type == InputTypeLong) {
if((model->emu_time - 10) >= model->emu_time_min) {
model->emu_time -= 10;
} else {
model->emu_time = model->emu_time_min;
}
}
}
} else if(
(model->attack_state == FuzzerAttackStateEnd) &&
(event->type == InputTypeShort)) {
// Exit if Ended
view_attack->callback(FuzzerCustomEventViewAttackBack, view_attack->context);
}
},
true);
return true;
} else if(event->key == InputKeyRight) {
with_view_model(
view_attack->view,
FuzzerViewAttackModel * model,
{
if(model->attack_state == FuzzerAttackStateIdle) {
if(!model->td_emt_cursor) {
// TimeDelay ++
if(event->type == InputTypeShort) {
if(model->time_delay < FUZZ_TIME_DELAY_MAX) {
model->time_delay++;
}
} else if(event->type == InputTypeLong) {
model->time_delay += 10;
if(model->time_delay > FUZZ_TIME_DELAY_MAX) {
model->time_delay = FUZZ_TIME_DELAY_MAX;
}
}
} else {
// EmuTime ++
if(event->type == InputTypeShort) {
if(model->emu_time < FUZZ_TIME_DELAY_MAX) {
model->emu_time++;
}
} else if(event->type == InputTypeLong) {
model->emu_time += 10;
if(model->emu_time > FUZZ_TIME_DELAY_MAX) {
model->emu_time = FUZZ_TIME_DELAY_MAX;
}
}
}
} else {
// Nothing
}
},
true);
return true;
} else if(
(event->key == InputKeyUp || event->key == InputKeyDown) &&
event->type == InputTypeShort) {
with_view_model(
view_attack->view,
FuzzerViewAttackModel * model,
{ model->td_emt_cursor = !model->td_emt_cursor; },
true);
return true;
}
return true;
}
void fuzzer_view_attack_enter(void* context) {
furi_assert(context);
}
void fuzzer_view_attack_exit(void* context) {
furi_assert(context);
FuzzerViewAttack* view_attack = context;
with_view_model(
view_attack->view, FuzzerViewAttackModel * model, { model->td_emt_cursor = false; }, true);
}
FuzzerViewAttack* fuzzer_view_attack_alloc() {
if(fuzzer_proto_get_max_data_size() > UID_MAX_DISPLAYED_LEN) {
furi_crash("Maximum of displayed bytes exceeded");
}
FuzzerViewAttack* view_attack = malloc(sizeof(FuzzerViewAttack));
// View allocation and configuration
view_attack->view = view_alloc();
view_allocate_model(view_attack->view, ViewModelTypeLocking, sizeof(FuzzerViewAttackModel));
view_set_context(view_attack->view, view_attack);
view_set_draw_callback(view_attack->view, (ViewDrawCallback)fuzzer_view_attack_draw);
view_set_input_callback(view_attack->view, fuzzer_view_attack_input);
view_set_enter_callback(view_attack->view, fuzzer_view_attack_enter);
view_set_exit_callback(view_attack->view, fuzzer_view_attack_exit);
with_view_model(
view_attack->view,
FuzzerViewAttackModel * model,
{
model->time_delay = fuzzer_proto_get_def_idle_time();
model->time_delay_min = 0; // model->time_delay;
model->emu_time = fuzzer_proto_get_def_emu_time();
model->emu_time_min = 2; // model->emu_time;
model->uid_str = furi_string_alloc_set_str("Not_set");
// malloc(ATTACK_SCENE_MAX_UID_LENGTH + 1);
model->attack_state = FuzzerAttackStateOff;
model->td_emt_cursor = false;
// strcpy(model->uid_str, "Not_set");
model->attack_name = "Not_set";
model->protocol_name = "Not_set";
},
true);
return view_attack;
}
void fuzzer_view_attack_free(FuzzerViewAttack* view_attack) {
furi_assert(view_attack);
with_view_model(
view_attack->view,
FuzzerViewAttackModel * model,
{ furi_string_free(model->uid_str); },
true);
view_free(view_attack->view);
free(view_attack);
}
View* fuzzer_view_attack_get_view(FuzzerViewAttack* view_attack) {
furi_assert(view_attack);
return view_attack->view;
}
uint8_t fuzzer_view_attack_get_time_delay(FuzzerViewAttack* view) {
furi_assert(view);
uint8_t time_delay;
with_view_model(
view->view, FuzzerViewAttackModel * model, { time_delay = model->time_delay; }, false);
return time_delay;
}
uint8_t fuzzer_view_attack_get_emu_time(FuzzerViewAttack* view) {
furi_assert(view);
uint8_t emu_time;
with_view_model(
view->view, FuzzerViewAttackModel * model, { emu_time = model->emu_time; }, false);
return emu_time;
}

View File

@@ -0,0 +1,42 @@
#pragma once
#include <gui/view.h>
#include "../helpers/fuzzer_custom_event.h"
#include "../helpers/fuzzer_types.h"
#include "../lib/worker/protocol.h"
typedef struct FuzzerViewAttack FuzzerViewAttack;
typedef void (*FuzzerViewAttackCallback)(FuzzerCustomEvent event, void* context);
void fuzzer_view_attack_set_callback(
FuzzerViewAttack* view_attack,
FuzzerViewAttackCallback callback,
void* context);
FuzzerViewAttack* fuzzer_view_attack_alloc();
void fuzzer_view_attack_free(FuzzerViewAttack* view_attack);
View* fuzzer_view_attack_get_view(FuzzerViewAttack* view_attack);
void fuzzer_view_attack_reset_data(
FuzzerViewAttack* view,
const char* attack_name,
const char* protocol_name);
void fuzzer_view_attack_set_uid(FuzzerViewAttack* view, const FuzzerPayload* uid);
void fuzzer_view_attack_start(FuzzerViewAttack* view);
void fuzzer_view_attack_stop(FuzzerViewAttack* view);
void fuzzer_view_attack_pause(FuzzerViewAttack* view);
void fuzzer_view_attack_end(FuzzerViewAttack* view);
uint8_t fuzzer_view_attack_get_time_delay(FuzzerViewAttack* view);
uint8_t fuzzer_view_attack_get_emu_time(FuzzerViewAttack* view);

View File

@@ -0,0 +1,358 @@
#include "field_editor.h"
#include "../fuzzer_i.h"
#include <input/input.h>
#include <gui/elements.h>
#include <toolbox/hex.h>
#define FIELD_EDITOR_V2
#define GUI_DISPLAY_WIDTH 128
#define GUI_DISPLAY_HEIGHT 64
#define GUI_DISPLAY_HORIZONTAL_CENTER 64
#define GUI_DISPLAY_VERTICAL_CENTER 32
#define UID_STR_LENGTH 25
#ifdef FIELD_EDITOR_V2
#define EDITOR_STRING_Y 38
#else
#define EDITOR_STRING_Y 50
#endif
struct FuzzerViewFieldEditor {
View* view;
FuzzerViewFieldEditorCallback callback;
void* context;
};
typedef struct {
uint8_t* uid;
uint8_t uid_size;
FuriString* uid_str;
uint8_t index;
bool lo;
bool allow_edit;
} FuzzerViewFieldEditorModel;
void fuzzer_view_field_editor_set_callback(
FuzzerViewFieldEditor* view_edit,
FuzzerViewFieldEditorCallback callback,
void* context) {
furi_assert(view_edit);
view_edit->callback = callback;
view_edit->context = context;
}
void fuzzer_view_field_editor_reset_data(
FuzzerViewFieldEditor* view_edit,
const FuzzerPayload* new_uid,
bool allow_edit) {
furi_assert(view_edit);
furi_assert(new_uid->data);
with_view_model(
view_edit->view,
FuzzerViewFieldEditorModel * model,
{
memcpy(model->uid, new_uid->data, new_uid->data_size);
model->index = 0;
model->lo = false;
model->uid_size = new_uid->data_size;
model->allow_edit = allow_edit;
},
true);
}
void fuzzer_view_field_editor_get_uid(FuzzerViewFieldEditor* view_edit, FuzzerPayload* output_uid) {
furi_assert(view_edit);
furi_assert(output_uid);
with_view_model(
view_edit->view,
FuzzerViewFieldEditorModel * model,
{
output_uid->data_size = model->uid_size;
memcpy(output_uid->data, model->uid, model->uid_size);
},
true);
}
uint8_t fuzzer_view_field_editor_get_index(FuzzerViewFieldEditor* view_edit) {
furi_assert(view_edit);
uint8_t index;
with_view_model(
view_edit->view, FuzzerViewFieldEditorModel * model, { index = model->index; }, true);
return index;
}
void fuzzer_view_field_editor_draw(Canvas* canvas, FuzzerViewFieldEditorModel* model) {
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
#ifdef FIELD_EDITOR_V2
canvas_set_font(canvas, FontSecondary);
if(model->allow_edit) {
canvas_draw_icon(canvas, 2, 4, &I_ButtonLeft_4x7);
canvas_draw_icon(canvas, 8, 4, &I_ButtonRight_4x7);
canvas_draw_icon_ex(canvas, 62, 3, &I_Pin_arrow_up_7x9, IconRotation180);
canvas_draw_icon(canvas, 69, 3, &I_Pin_arrow_up_7x9);
canvas_draw_str(canvas, 14, 10, "select byte");
canvas_draw_str(canvas, 79, 10, "adjust byte");
} else {
canvas_draw_icon(canvas, 35, 4, &I_ButtonLeft_4x7);
canvas_draw_icon(canvas, 41, 4, &I_ButtonRight_4x7);
canvas_draw_str(canvas, 49, 10, "select byte");
}
char msg_index[18];
canvas_set_font(canvas, FontPrimary);
snprintf(msg_index, sizeof(msg_index), "Field index : %d", model->index);
canvas_draw_str_aligned(
canvas, GUI_DISPLAY_HORIZONTAL_CENTER, 24, AlignCenter, AlignBottom, msg_index);
canvas_set_font(canvas, FontSecondary);
canvas_draw_icon(canvas, 4, 52, &I_Pin_back_arrow_10x8);
canvas_draw_icon(canvas, 85, 52, &I_Ok_btn_9x9);
canvas_draw_str(canvas, 16, 60, "Back");
canvas_draw_str(canvas, 96, 60, "Attack");
#else
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas,
GUI_DISPLAY_HORIZONTAL_CENTER,
5,
AlignCenter,
AlignTop,
"Left and right: select byte");
canvas_draw_str_aligned(
canvas,
GUI_DISPLAY_HORIZONTAL_CENTER,
15,
AlignCenter,
AlignTop,
"Up and down: adjust byte");
char msg_index[18];
canvas_set_font(canvas, FontPrimary);
snprintf(msg_index, sizeof(msg_index), "Field index : %d", model->index);
canvas_draw_str_aligned(
canvas, GUI_DISPLAY_HORIZONTAL_CENTER, 28, AlignCenter, AlignTop, msg_index);
#endif
// ####### Editor #######
FuriString* temp_s = model->uid_str;
canvas_set_font(canvas, FontSecondary);
furi_string_reset(temp_s);
for(int i = -3; i != 0; i++) {
if(0 <= (model->index + i)) {
furi_string_cat_printf(temp_s, "%02X ", model->uid[model->index + i]);
}
}
canvas_draw_str_aligned(
canvas, 52, EDITOR_STRING_Y, AlignRight, AlignBottom, furi_string_get_cstr(temp_s));
furi_string_reset(temp_s);
for(int i = 1; i != 4; i++) {
if((model->index + i) < model->uid_size) {
furi_string_cat_printf(temp_s, " %02X", model->uid[model->index + i]);
}
}
canvas_draw_str_aligned(
canvas, 77, EDITOR_STRING_Y, AlignLeft, AlignBottom, furi_string_get_cstr(temp_s));
canvas_set_font(canvas, FontPrimary);
furi_string_reset(temp_s);
furi_string_cat_printf(temp_s, "<%02X>", model->uid[model->index]);
canvas_draw_str_aligned(
canvas,
GUI_DISPLAY_HORIZONTAL_CENTER,
EDITOR_STRING_Y,
AlignCenter,
AlignBottom,
furi_string_get_cstr(temp_s));
uint16_t w = canvas_string_width(canvas, furi_string_get_cstr(temp_s));
w -= 11; // '<' & '>'
w /= 2;
if(model->allow_edit) {
if(model->lo) {
canvas_draw_line(
canvas,
GUI_DISPLAY_HORIZONTAL_CENTER + 1,
EDITOR_STRING_Y + 2,
GUI_DISPLAY_HORIZONTAL_CENTER + w,
EDITOR_STRING_Y + 2);
} else {
canvas_draw_line(
canvas,
GUI_DISPLAY_HORIZONTAL_CENTER - w,
EDITOR_STRING_Y + 2,
GUI_DISPLAY_HORIZONTAL_CENTER - 1,
EDITOR_STRING_Y + 2);
}
} else {
// canvas_draw_line(
// canvas,
// GUI_DISPLAY_HORIZONTAL_CENTER - w,
// EDITOR_STRING_Y + 2,
// GUI_DISPLAY_HORIZONTAL_CENTER + w,
// EDITOR_STRING_Y + 2);
}
// ####### Editor #######
}
bool fuzzer_view_field_editor_input(InputEvent* event, void* context) {
furi_assert(context);
FuzzerViewFieldEditor* view_edit = context;
if(event->key == InputKeyBack && event->type == InputTypeShort) {
view_edit->callback(FuzzerCustomEventViewFieldEditorBack, view_edit->context);
return true;
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
view_edit->callback(FuzzerCustomEventViewFieldEditorOk, view_edit->context);
return true;
} else if(event->key == InputKeyLeft) {
with_view_model(
view_edit->view,
FuzzerViewFieldEditorModel * model,
{
if(event->type == InputTypeShort) {
if(!model->allow_edit) {
model->lo = false;
}
if(model->index > 0 || model->lo) {
if(!model->lo) {
model->index--;
}
model->lo = !model->lo;
}
} else if(event->type == InputTypeLong) {
model->index = 0;
model->lo = false;
}
},
true);
return true;
} else if(event->key == InputKeyRight) {
with_view_model(
view_edit->view,
FuzzerViewFieldEditorModel * model,
{
if(event->type == InputTypeShort) {
if(!model->allow_edit) {
model->lo = true;
}
if(model->index < (model->uid_size - 1) || !model->lo) {
if(model->lo) {
model->index++;
}
model->lo = !model->lo;
}
} else if(event->type == InputTypeLong) {
model->index = model->uid_size - 1;
model->lo = true;
}
},
true);
return true;
} else if(event->key == InputKeyUp) {
with_view_model(
view_edit->view,
FuzzerViewFieldEditorModel * model,
{
if(event->type == InputTypeShort && model->allow_edit) {
if(model->lo) {
model->uid[model->index] = (model->uid[model->index] & 0xF0) |
((model->uid[model->index] + 1) & 0x0F);
} else {
model->uid[model->index] = ((model->uid[model->index] + 0x10) & 0xF0) |
(model->uid[model->index] & 0x0F);
}
}
},
true);
return true;
} else if(event->key == InputKeyDown) {
with_view_model(
view_edit->view,
FuzzerViewFieldEditorModel * model,
{
if(event->type == InputTypeShort && model->allow_edit) {
if(model->lo) {
model->uid[model->index] = (model->uid[model->index] & 0xF0) |
((model->uid[model->index] - 1) & 0x0F);
} else {
model->uid[model->index] = ((model->uid[model->index] - 0x10) & 0xF0) |
(model->uid[model->index] & 0x0F);
}
}
},
true);
return true;
}
return true;
}
void fuzzer_view_field_editor_enter(void* context) {
furi_assert(context);
}
void fuzzer_view_field_editor_exit(void* context) {
furi_assert(context);
}
FuzzerViewFieldEditor* fuzzer_view_field_editor_alloc() {
FuzzerViewFieldEditor* view_edit = malloc(sizeof(FuzzerViewFieldEditor));
// View allocation and configuration
view_edit->view = view_alloc();
view_allocate_model(view_edit->view, ViewModelTypeLocking, sizeof(FuzzerViewFieldEditorModel));
view_set_context(view_edit->view, view_edit);
view_set_draw_callback(view_edit->view, (ViewDrawCallback)fuzzer_view_field_editor_draw);
view_set_input_callback(view_edit->view, fuzzer_view_field_editor_input);
view_set_enter_callback(view_edit->view, fuzzer_view_field_editor_enter);
view_set_exit_callback(view_edit->view, fuzzer_view_field_editor_exit);
with_view_model(
view_edit->view,
FuzzerViewFieldEditorModel * model,
{
model->uid_str = furi_string_alloc();
model->uid = malloc(fuzzer_proto_get_max_data_size());
},
true);
return view_edit;
}
void fuzzer_view_field_editor_free(FuzzerViewFieldEditor* view_edit) {
furi_assert(view_edit);
with_view_model(
view_edit->view,
FuzzerViewFieldEditorModel * model,
{
furi_string_free(model->uid_str);
free(model->uid);
},
true);
view_free(view_edit->view);
free(view_edit);
}
View* fuzzer_view_field_editor_get_view(FuzzerViewFieldEditor* view_edit) {
furi_assert(view_edit);
return view_edit->view;
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include <gui/view.h>
#include "../helpers/fuzzer_custom_event.h"
#include "../lib/worker/protocol.h"
typedef struct FuzzerViewFieldEditor FuzzerViewFieldEditor;
typedef void (*FuzzerViewFieldEditorCallback)(FuzzerCustomEvent event, void* context);
void fuzzer_view_field_editor_set_callback(
FuzzerViewFieldEditor* view_attack,
FuzzerViewFieldEditorCallback callback,
void* context);
FuzzerViewFieldEditor* fuzzer_view_field_editor_alloc();
void fuzzer_view_field_editor_free(FuzzerViewFieldEditor* view_attack);
View* fuzzer_view_field_editor_get_view(FuzzerViewFieldEditor* view_attack);
void fuzzer_view_field_editor_reset_data(
FuzzerViewFieldEditor* view_edit,
const FuzzerPayload* new_uid,
bool allow_edit);
void fuzzer_view_field_editor_get_uid(FuzzerViewFieldEditor* view_edit, FuzzerPayload* output_uid);
uint8_t fuzzer_view_field_editor_get_index(FuzzerViewFieldEditor* view_edit);

View File

@@ -0,0 +1,235 @@
#include "main_menu.h"
#include "../fuzzer_i.h"
#include <input/input.h>
#include "../lib/worker/protocol.h"
#define PROTOCOL_NAME_Y 12
// #define PROTOCOL_CAROUSEL
struct FuzzerViewMain {
View* view;
FuzzerViewMainCallback callback;
void* context;
};
typedef struct {
uint8_t proto_index;
uint8_t menu_index;
uint8_t proto_max;
uint8_t menu_max;
} FuzzerViewMainModel;
void fuzzer_view_main_update_data(FuzzerViewMain* view, FuzzerState state) {
furi_assert(view);
with_view_model(
view->view,
FuzzerViewMainModel * model,
{
model->proto_index = state.proto_index;
model->menu_index = state.menu_index;
},
true);
}
void fuzzer_view_main_get_state(FuzzerViewMain* view, FuzzerState* state) {
furi_assert(view);
with_view_model(
view->view,
FuzzerViewMainModel * model,
{
state->proto_index = model->proto_index;
state->menu_index = model->menu_index;
},
true);
}
void fuzzer_view_main_set_callback(
FuzzerViewMain* view,
FuzzerViewMainCallback callback,
void* context) {
furi_assert(view);
view->callback = callback;
view->context = context;
}
void fuzzer_view_main_draw(Canvas* canvas, FuzzerViewMainModel* model) {
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
if(model->menu_index > 0) {
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas,
64,
24,
AlignCenter,
AlignTop,
fuzzer_proto_get_menu_label(model->menu_index - 1));
}
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(
canvas, 64, 36, AlignCenter, AlignTop, fuzzer_proto_get_menu_label(model->menu_index));
if(model->menu_index < (model->menu_max - 1)) {
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas,
64,
48,
AlignCenter,
AlignTop,
fuzzer_proto_get_menu_label(model->menu_index + 1));
}
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 27, PROTOCOL_NAME_Y, AlignCenter, AlignBottom, "<");
canvas_draw_str_aligned(
canvas,
64,
PROTOCOL_NAME_Y,
AlignCenter,
AlignBottom,
fuzzer_proto_get_name(model->proto_index));
canvas_draw_str_aligned(canvas, 101, PROTOCOL_NAME_Y, AlignCenter, AlignBottom, ">");
#ifdef PROTOCOL_CAROUSEL
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas,
20,
PROTOCOL_NAME_Y,
AlignRight,
AlignBottom,
(model->proto_index > 0) ? fuzzer_proto_get_name(model->proto_index - 1) :
fuzzer_proto_get_name((model->proto_max - 1)));
canvas_draw_str_aligned(
canvas,
108,
PROTOCOL_NAME_Y,
AlignLeft,
AlignBottom,
(model->proto_index < (model->proto_max - 1)) ?
fuzzer_proto_get_name(model->proto_index + 1) :
fuzzer_proto_get_name(0));
#endif
}
bool fuzzer_view_main_input(InputEvent* event, void* context) {
furi_assert(context);
FuzzerViewMain* view = context;
if(event->key == InputKeyBack &&
(event->type == InputTypeLong || event->type == InputTypeShort)) {
view->callback(FuzzerCustomEventViewMainBack, view->context);
return true;
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
view->callback(FuzzerCustomEventViewMainOk, view->context);
return true;
} else if(event->key == InputKeyDown && event->type == InputTypeShort) {
with_view_model(
view->view,
FuzzerViewMainModel * model,
{
if(model->menu_index < (model->menu_max - 1)) {
model->menu_index++;
}
},
true);
return true;
} else if(event->key == InputKeyUp && event->type == InputTypeShort) {
with_view_model(
view->view,
FuzzerViewMainModel * model,
{
if(model->menu_index != 0) {
model->menu_index--;
}
},
true);
return true;
} else if(event->key == InputKeyLeft && event->type == InputTypeShort) {
with_view_model(
view->view,
FuzzerViewMainModel * model,
{
if(model->proto_index != 0) {
model->proto_index--;
} else {
model->proto_index = (model->proto_max - 1);
}
},
true);
return true;
} else if(event->key == InputKeyRight && event->type == InputTypeShort) {
with_view_model(
view->view,
FuzzerViewMainModel * model,
{
if(model->proto_index == (model->proto_max - 1)) {
model->proto_index = 0;
} else {
model->proto_index++;
}
},
true);
return true;
}
return true;
}
void fuzzer_view_main_enter(void* context) {
furi_assert(context);
}
void fuzzer_view_main_exit(void* context) {
furi_assert(context);
}
FuzzerViewMain* fuzzer_view_main_alloc() {
FuzzerViewMain* view = malloc(sizeof(FuzzerViewMain));
// View allocation and configuration
view->view = view_alloc();
view_allocate_model(view->view, ViewModelTypeLocking, sizeof(FuzzerViewMainModel));
view_set_context(view->view, view);
view_set_draw_callback(view->view, (ViewDrawCallback)fuzzer_view_main_draw);
view_set_input_callback(view->view, fuzzer_view_main_input);
view_set_enter_callback(view->view, fuzzer_view_main_enter);
view_set_exit_callback(view->view, fuzzer_view_main_exit);
with_view_model(
view->view,
FuzzerViewMainModel * model,
{
model->proto_index = 0;
model->proto_max = fuzzer_proto_get_count_of_protocols();
model->menu_index = 0;
model->menu_max = fuzzer_proto_get_count_of_menu_items();
},
true);
return view;
}
void fuzzer_view_main_free(FuzzerViewMain* view) {
furi_assert(view);
// with_view_model(
// view->view,
// FuzzerViewMainModel * model,
// {
// },
// true);
view_free(view->view);
free(view);
}
View* fuzzer_view_main_get_view(FuzzerViewMain* view) {
furi_assert(view);
return view->view;
}

View File

@@ -0,0 +1,23 @@
#pragma once
#include <gui/view.h>
#include "../helpers/fuzzer_custom_event.h"
#include "../helpers/fuzzer_types.h"
typedef struct FuzzerViewMain FuzzerViewMain;
typedef void (*FuzzerViewMainCallback)(FuzzerCustomEvent event, void* context);
void fuzzer_view_main_set_callback(
FuzzerViewMain* fuzzer_view_main,
FuzzerViewMainCallback callback,
void* context);
FuzzerViewMain* fuzzer_view_main_alloc();
void fuzzer_view_main_free(FuzzerViewMain* view);
View* fuzzer_view_main_get_view(FuzzerViewMain* view);
void fuzzer_view_main_update_data(FuzzerViewMain* view, FuzzerState state);
void fuzzer_view_main_get_state(FuzzerViewMain* view, FuzzerState* state);

View File

@@ -48,8 +48,9 @@ bool save_signal(ProtoViewApp* app, const char* filename) {
for(int j = 0; regs[j]; j += 2) { for(int j = 0; regs[j]; j += 2) {
furi_string_cat_printf(custom, "%02X %02X ", (int)regs[j], (int)regs[j + 1]); furi_string_cat_printf(custom, "%02X %02X ", (int)regs[j], (int)regs[j + 1]);
} }
size_t len = furi_string_size(file_content); //size_t len = furi_string_size(file_content);
furi_string_set_char(custom, len - 1, '\n'); //furi_string_set_char(custom, len - 1, '\n');
furi_string_cat(custom, "\n");
furi_string_cat(file_content, custom); furi_string_cat(file_content, custom);
furi_string_free(custom); furi_string_free(custom);
} }

View File

@@ -78,7 +78,8 @@ const Interface SPI = {
static const SensorType* sensorTypes[] = {&DHT11, &DHT12_SW, &DHT20, &DHT21, &DHT22, static const SensorType* sensorTypes[] = {&DHT11, &DHT12_SW, &DHT20, &DHT21, &DHT22,
&Dallas, &AM2320_SW, &AM2320_I2C, &HTU21x, &AHT10, &Dallas, &AM2320_SW, &AM2320_I2C, &HTU21x, &AHT10,
&SHT30, &GXHT30, &LM75, &HDC1080, &BMP180, &SHT30, &GXHT30, &LM75, &HDC1080, &BMP180,
&BMP280, &BME280, &BME680, &MAX31855, &MAX6675}; &BMP280, &BME280, &BME680, &MAX31855, &MAX6675,
&SCD30};
const SensorType* unitemp_sensors_getTypeFromInt(uint8_t index) { const SensorType* unitemp_sensors_getTypeFromInt(uint8_t index) {
if(index > SENSOR_TYPES_COUNT) return NULL; if(index > SENSOR_TYPES_COUNT) return NULL;

View File

@@ -24,6 +24,7 @@
#define UT_TEMPERATURE 0b00000001 #define UT_TEMPERATURE 0b00000001
#define UT_HUMIDITY 0b00000010 #define UT_HUMIDITY 0b00000010
#define UT_PRESSURE 0b00000100 #define UT_PRESSURE 0b00000100
#define UT_CO2 0b00001000
//Статусы опроса датчика //Статусы опроса датчика
typedef enum { typedef enum {
@@ -31,6 +32,7 @@ typedef enum {
UT_DATA_TYPE_TEMP_HUM = UT_TEMPERATURE | UT_HUMIDITY, UT_DATA_TYPE_TEMP_HUM = UT_TEMPERATURE | UT_HUMIDITY,
UT_DATA_TYPE_TEMP_PRESS = UT_TEMPERATURE | UT_PRESSURE, UT_DATA_TYPE_TEMP_PRESS = UT_TEMPERATURE | UT_PRESSURE,
UT_DATA_TYPE_TEMP_HUM_PRESS = UT_TEMPERATURE | UT_HUMIDITY | UT_PRESSURE, UT_DATA_TYPE_TEMP_HUM_PRESS = UT_TEMPERATURE | UT_HUMIDITY | UT_PRESSURE,
UT_DATA_TYPE_TEMP_HUM_CO2 = UT_TEMPERATURE | UT_HUMIDITY | UT_CO2,
} SensorDataType; } SensorDataType;
//Типы возвращаемых данных //Типы возвращаемых данных
@@ -121,6 +123,8 @@ typedef struct Sensor {
float hum; float hum;
//Атмосферное давление //Атмосферное давление
float pressure; float pressure;
// Концентрация CO2
float co2;
//Тип датчика //Тип датчика
const SensorType* type; const SensorType* type;
//Статус последнего опроса датчика //Статус последнего опроса датчика
@@ -329,4 +333,5 @@ const GPIO*
#include "./sensors/HDC1080.h" #include "./sensors/HDC1080.h"
#include "./sensors/MAX31855.h" #include "./sensors/MAX31855.h"
#include "./sensors/MAX6675.h" #include "./sensors/MAX6675.h"
#include "./sensors/SCD30.h"
#endif #endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 B

View File

@@ -0,0 +1,438 @@
/*
Unitemp - Universal temperature reader
Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n)
Contributed by divinebird (https://github.com/divinebird)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// Some information may be seen on https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library
#include "SCD30.h"
#include "../interfaces/I2CSensor.h"
//#include <3rdparty/everest/include/everest/kremlin/c_endianness.h>
inline static uint16_t load16(uint8_t* b) {
uint16_t x;
memcpy(&x, b, 2);
return x;
}
inline static uint32_t load32(uint8_t* b) {
uint32_t x;
memcpy(&x, b, 4);
return x;
}
inline static void store16(uint8_t* b, uint16_t i) {
memcpy(b, &i, 2);
}
inline static void store32(uint8_t* b, uint32_t i) {
memcpy(b, &i, 4);
}
#if BYTE_ORDER == BIG_ENDIAN
#define htobe16(x) (x)
#define htobe32(x) (x)
#define htole16(x) __builtin_bswap16(x)
#define htole32(x) __builtin_bswap32(x)
#define be16toh(x) (x)
#define be32toh(x) (x)
#define le16toh(x) __builtin_bswap16(x)
#define le32toh(x) __builtin_bswap32(x)
#elif BYTE_ORDER == LITTLE_ENDIAN
#define htobe16(x) __builtin_bswap16(x)
#define htobe32(x) __builtin_bswap32(x)
#define htole16(x) (x)
#define htole32(x) (x)
#define be16toh(x) __builtin_bswap16(x)
#define be32toh(x) __builtin_bswap32(x)
#define le16toh(x) (x)
#define le32toh(x) (x)
#else
#error "What kind of system is this?"
#endif
#define load16_le(b) (le16toh(load16(b)))
#define load32_le(b) (le32toh(load32(b)))
#define store16_le(b, i) (store16(b, htole16(i)))
#define store32_le(b, i) (store32(b, htole32(i)))
#define load16_be(b) (be16toh(load16(b)))
#define load32_be(b) (be32toh(load32(b)))
#define store16_be(b, i) (store16(b, htobe16(i)))
#define store32_be(b, i) (store32(b, htobe32(i)))
typedef union {
uint16_t array16[2];
uint8_t array8[4];
float value;
} ByteToFl;
bool unitemp_SCD30_alloc(Sensor* sensor, char* args);
bool unitemp_SCD30_init(Sensor* sensor);
bool unitemp_SCD30_deinit(Sensor* sensor);
UnitempStatus unitemp_SCD30_update(Sensor* sensor);
bool unitemp_SCD30_free(Sensor* sensor);
const SensorType SCD30 = {
.typename = "SCD30",
.interface = &I2C,
.datatype = UT_DATA_TYPE_TEMP_HUM_CO2,
.pollingInterval = 2000,
.allocator = unitemp_SCD30_alloc,
.mem_releaser = unitemp_SCD30_free,
.initializer = unitemp_SCD30_init,
.deinitializer = unitemp_SCD30_deinit,
.updater = unitemp_SCD30_update};
#define SCD30_ID 0x61
#define COMMAND_CONTINUOUS_MEASUREMENT 0x0010
#define COMMAND_SET_MEASUREMENT_INTERVAL 0x4600
#define COMMAND_GET_DATA_READY 0x0202
#define COMMAND_READ_MEASUREMENT 0x0300
#define COMMAND_AUTOMATIC_SELF_CALIBRATION 0x5306
#define COMMAND_SET_FORCED_RECALIBRATION_FACTOR 0x5204
#define COMMAND_SET_TEMPERATURE_OFFSET 0x5403
#define COMMAND_SET_ALTITUDE_COMPENSATION 0x5102
#define COMMAND_RESET 0xD304 // Soft reset
#define COMMAND_STOP_MEAS 0x0104
#define COMMAND_READ_FW_VER 0xD100
static bool dataAvailable(Sensor* sensor) __attribute__((unused));
static bool readMeasurement(Sensor* sensor) __attribute__((unused));
static void reset(Sensor* sensor) __attribute__((unused));
static bool setAutoSelfCalibration(Sensor* sensor, bool enable) __attribute__((unused));
static bool getAutoSelfCalibration(Sensor* sensor) __attribute__((unused));
static bool getFirmwareVersion(Sensor* sensor, uint16_t* val) __attribute__((unused));
static bool setForcedRecalibrationFactor(Sensor* sensor, uint16_t concentration)
__attribute__((unused));
static uint16_t getAltitudeCompensation(Sensor* sensor) __attribute__((unused));
static bool setAltitudeCompensation(Sensor* sensor, uint16_t altitude) __attribute__((unused));
static bool setAmbientPressure(Sensor* sensor, uint16_t pressure_mbar) __attribute__((unused));
static float getTemperatureOffset(Sensor* sensor) __attribute__((unused));
static bool setTemperatureOffset(Sensor* sensor, float tempOffset) __attribute__((unused));
static bool beginMeasuringWithSettings(Sensor* sensor, uint16_t pressureOffset)
__attribute__((unused));
static bool beginMeasuring(Sensor* sensor) __attribute__((unused));
static bool stopMeasurement(Sensor* sensor) __attribute__((unused));
static bool setMeasurementInterval(Sensor* sensor, uint16_t interval) __attribute__((unused));
static uint16_t getMeasurementInterval(Sensor* sensor) __attribute__((unused));
bool unitemp_SCD30_alloc(Sensor* sensor, char* args) {
UNUSED(args);
I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
i2c_sensor->minI2CAdr = SCD30_ID << 1;
i2c_sensor->maxI2CAdr = SCD30_ID << 1;
return true;
}
bool unitemp_SCD30_free(Sensor* sensor) {
//Нечего высвобождать, так как ничего не было выделено
UNUSED(sensor);
return true;
}
bool unitemp_SCD30_init(Sensor* sensor) {
if(beginMeasuring(sensor) == true) { // Start continuous measurements
setMeasurementInterval(sensor, SCD30.pollingInterval / 1000);
setAutoSelfCalibration(sensor, true);
setAmbientPressure(sensor, 0);
} else
return false;
return true;
}
bool unitemp_SCD30_deinit(Sensor* sensor) {
return stopMeasurement(sensor);
}
UnitempStatus unitemp_SCD30_update(Sensor* sensor) {
readMeasurement(sensor);
return UT_SENSORSTATUS_OK;
}
static uint8_t computeCRC8(uint8_t* message, uint8_t len) {
uint8_t crc = 0xFF; // Init with 0xFF
for(uint8_t x = 0; x < len; x++) {
crc ^= message[x]; // XOR-in the next input byte
for(uint8_t i = 0; i < 8; i++) {
if((crc & 0x80) != 0)
crc = (uint8_t)((crc << 1) ^ 0x31);
else
crc <<= 1;
}
}
return crc; // No output reflection
}
// Sends a command along with arguments and CRC
static bool sendCommandWithCRC(Sensor* sensor, uint16_t command, uint16_t arguments) {
static const uint8_t cmdSize = 5;
uint8_t bytes[cmdSize];
uint8_t* pointer = bytes;
store16_be(pointer, command);
pointer += 2;
uint8_t* argPos = pointer;
store16_be(pointer, arguments);
pointer += 2;
*pointer = computeCRC8(argPos, pointer - argPos);
I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
return unitemp_i2c_writeArray(i2c_sensor, cmdSize, bytes);
}
// Sends just a command, no arguments, no CRC
static bool sendCommand(Sensor* sensor, uint16_t command) {
static const uint8_t cmdSize = 2;
uint8_t bytes[cmdSize];
store16_be(bytes, command);
I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
return unitemp_i2c_writeArray(i2c_sensor, cmdSize, bytes);
}
static uint16_t readRegister(Sensor* sensor, uint16_t registerAddress) {
static const uint8_t regSize = 2;
if(!sendCommand(sensor, registerAddress)) return 0; // Sensor did not ACK
furi_delay_ms(3);
uint8_t bytes[regSize];
I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
if(!unitemp_i2c_readArray(i2c_sensor, regSize, bytes)) return 0;
return load16_be(bytes);
}
static bool loadWord(uint8_t* buff, uint16_t* val) {
uint16_t tmp = load16_be(buff);
uint8_t expectedCRC = computeCRC8(buff, 2);
if(buff[2] != expectedCRC) return false;
*val = tmp;
return true;
}
static bool getSettingValue(Sensor* sensor, uint16_t registerAddress, uint16_t* val) {
static const uint8_t respSize = 3;
if(!sendCommand(sensor, registerAddress)) return false; // Sensor did not ACK
furi_delay_ms(3);
uint8_t bytes[respSize];
I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
if(!unitemp_i2c_readArray(i2c_sensor, respSize, bytes)) return false;
return loadWord(bytes, val);
}
static bool loadFloat(uint8_t* buff, float* val) {
// ByteToFl tmp;
size_t cntr = 0;
uint8_t floatBuff[4];
for(size_t i = 0; i < 2; i++) {
floatBuff[cntr++] = buff[0];
floatBuff[cntr++] = buff[1];
uint8_t expectedCRC = computeCRC8(buff, 2);
if(buff[2] != expectedCRC) return false;
buff += 3;
}
uint32_t tmpVal = load32_be(floatBuff);
memcpy(val, &tmpVal, sizeof(float));
return true;
}
// Get 18 bytes from SCD30
// Updates global variables with floats
// Returns true if success
static bool readMeasurement(Sensor* sensor) {
// Verify we have data from the sensor
if(!dataAvailable(sensor)) {
return false;
}
if(!sendCommand(sensor, COMMAND_READ_MEASUREMENT)) {
FURI_LOG_E(APP_NAME, "Sensor did not ACK");
return false; // Sensor did not ACK
}
float tempCO2 = 0;
float tempHumidity = 0;
float tempTemperature = 0;
furi_delay_ms(3);
static const uint8_t respSize = 18;
uint8_t buff[respSize];
uint8_t* bytes = buff;
I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
if(!unitemp_i2c_readArray(i2c_sensor, respSize, bytes)) {
FURI_LOG_E(APP_NAME, "Error while read measures");
return false;
}
bool error = false;
if(loadFloat(bytes, &tempCO2)) {
sensor->co2 = tempCO2;
} else {
FURI_LOG_E(APP_NAME, "Error while parsing CO2");
error = true;
}
bytes += 6;
if(loadFloat(bytes, &tempTemperature)) {
sensor->temp = tempTemperature;
} else {
FURI_LOG_E(APP_NAME, "Error while parsing temp");
error = true;
}
bytes += 6;
if(loadFloat(bytes, &tempHumidity)) {
sensor->hum = tempHumidity;
} else {
FURI_LOG_E(APP_NAME, "Error while parsing humidity");
error = true;
}
return !error;
}
static void reset(Sensor* sensor) {
sendCommand(sensor, COMMAND_RESET);
}
static bool setAutoSelfCalibration(Sensor* sensor, bool enable) {
return sendCommandWithCRC(
sensor, COMMAND_AUTOMATIC_SELF_CALIBRATION, enable); // Activate continuous ASC
}
// Get the current ASC setting
static bool getAutoSelfCalibration(Sensor* sensor) {
return 1 == readRegister(sensor, COMMAND_AUTOMATIC_SELF_CALIBRATION);
}
static bool getFirmwareVersion(Sensor* sensor, uint16_t* val) {
return getSettingValue(sensor, COMMAND_READ_FW_VER, val);
}
// Set the forced recalibration factor. See 1.3.7.
// The reference CO2 concentration has to be within the range 400 ppm ≤ cref(CO2) ≤ 2000 ppm.
static bool setForcedRecalibrationFactor(Sensor* sensor, uint16_t concentration) {
if(concentration < 400 || concentration > 2000) {
return false; // Error check.
}
return sendCommandWithCRC(sensor, COMMAND_SET_FORCED_RECALIBRATION_FACTOR, concentration);
}
// Get the temperature offset. See 1.3.8.
static float getTemperatureOffset(Sensor* sensor) {
union {
int16_t signed16;
uint16_t unsigned16;
} signedUnsigned; // Avoid any ambiguity casting int16_t to uint16_t
signedUnsigned.unsigned16 = readRegister(sensor, COMMAND_SET_TEMPERATURE_OFFSET);
return ((float)signedUnsigned.signed16) / 100.0;
}
static bool setTemperatureOffset(Sensor* sensor, float tempOffset) {
// Temp offset is only positive. See: https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library/issues/27#issuecomment-971986826
//"The SCD30 offset temperature is obtained by subtracting the reference temperature from the SCD30 output temperature"
// https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/9.5_CO2/Sensirion_CO2_Sensors_SCD30_Low_Power_Mode.pdf
if(tempOffset < 0.0) return false;
uint16_t value = tempOffset * 100;
return sendCommandWithCRC(sensor, COMMAND_SET_TEMPERATURE_OFFSET, value);
}
// Get the altitude compenstation. See 1.3.9.
static uint16_t getAltitudeCompensation(Sensor* sensor) {
return readRegister(sensor, COMMAND_SET_ALTITUDE_COMPENSATION);
}
// Set the altitude compenstation. See 1.3.9.
static bool setAltitudeCompensation(Sensor* sensor, uint16_t altitude) {
return sendCommandWithCRC(sensor, COMMAND_SET_ALTITUDE_COMPENSATION, altitude);
}
// Set the pressure compenstation. This is passed during measurement startup.
// mbar can be 700 to 1200
static bool setAmbientPressure(Sensor* sensor, uint16_t pressure_mbar) {
if(pressure_mbar != 0 || pressure_mbar < 700 || pressure_mbar > 1200) {
return false;
}
return sendCommandWithCRC(sensor, COMMAND_CONTINUOUS_MEASUREMENT, pressure_mbar);
}
// Begins continuous measurements
// Continuous measurement status is saved in non-volatile memory. When the sensor
// is powered down while continuous measurement mode is active SCD30 will measure
// continuously after repowering without sending the measurement command.
// Returns true if successful
static bool beginMeasuringWithSettings(Sensor* sensor, uint16_t pressureOffset) {
return sendCommandWithCRC(sensor, COMMAND_CONTINUOUS_MEASUREMENT, pressureOffset);
}
// Overload - no pressureOffset
static bool beginMeasuring(Sensor* sensor) {
return beginMeasuringWithSettings(sensor, 0);
}
// Stop continuous measurement
static bool stopMeasurement(Sensor* sensor) {
return sendCommand(sensor, COMMAND_STOP_MEAS);
}
// Sets interval between measurements
// 2 seconds to 1800 seconds (30 minutes)
static bool setMeasurementInterval(Sensor* sensor, uint16_t interval) {
if(interval < 2 || interval > 1800) return false;
if(!sendCommandWithCRC(sensor, COMMAND_SET_MEASUREMENT_INTERVAL, interval)) return false;
uint16_t verInterval = readRegister(sensor, COMMAND_SET_MEASUREMENT_INTERVAL);
if(verInterval != interval) {
FURI_LOG_E(APP_NAME, "Measure interval wrong! Val: %02x", verInterval);
return false;
}
return true;
}
// Gets interval between measurements
// 2 seconds to 1800 seconds (30 minutes)
static uint16_t getMeasurementInterval(Sensor* sensor) {
uint16_t interval = 0;
getSettingValue(sensor, COMMAND_SET_MEASUREMENT_INTERVAL, &interval);
return interval;
}
// Returns true when data is available
static bool dataAvailable(Sensor* sensor) {
return 1 == readRegister(sensor, COMMAND_GET_DATA_READY);
}

View File

@@ -0,0 +1,59 @@
/*
Unitemp - Universal temperature reader
Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n)
Contributed by divinebird (https://github.com/divinebird)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef UNITEMP_SCD30
#define UNITEMP_SCD30
#include "../unitemp.h"
#include "../Sensors.h"
extern const SensorType SCD30;
/**
* @brief Выделение памяти и установка начальных значений датчика SCD30
* @param sensor Указатель на создаваемый датчик
* @return Истина при успехе
*/
bool unitemp_SCD30_alloc(Sensor* sensor, char* args);
/**
* @brief Инициализации датчика SCD30
* @param sensor Указатель на датчик
* @return Истина если инициализация упспешная
*/
bool unitemp_SCD30_init(Sensor* sensor);
/**
* @brief Деинициализация датчика
* @param sensor Указатель на датчик
*/
bool unitemp_SCD30_deinit(Sensor* sensor);
/**
* @brief Обновление значений из датчика
* @param sensor Указатель на датчик
* @return Статус опроса датчика
*/
UnitempStatus unitemp_SCD30_update(Sensor* sensor);
/**
* @brief Высвободить память датчика
* @param sensor Указатель на датчик
*/
bool unitemp_SCD30_free(Sensor* sensor);
#endif

View File

@@ -40,7 +40,7 @@
//Имя приложения //Имя приложения
#define APP_NAME "Unitemp" #define APP_NAME "Unitemp"
//Версия приложения //Версия приложения
#define UNITEMP_APP_VER "1.2" #define UNITEMP_APP_VER "1.3"
//Путь хранения файлов плагина //Путь хранения файлов плагина
#define APP_PATH_FOLDER "/ext/unitemp" #define APP_PATH_FOLDER "/ext/unitemp"
//Имя файла с настройками //Имя файла с настройками

View File

@@ -162,6 +162,35 @@ static void _draw_pressure(Canvas* canvas, Sensor* sensor) {
} }
} }
static void _draw_co2(Canvas* canvas, Sensor* sensor, Color color) {
const uint8_t x = 29, y = 39;
//Рисование рамки
canvas_draw_rframe(canvas, x, y, 75, 20, 3);
if(color == ColorBlack) {
canvas_draw_rbox(canvas, x, y, 75, 19, 3);
canvas_invert_color(canvas);
} else {
canvas_draw_rframe(canvas, x, y, 75, 19, 3);
}
//Рисование иконки
canvas_draw_icon(canvas, x + 3, y + 3, &I_co2_11x14);
int16_t concentration_int = sensor->co2;
// int8_t concentration_dec = (int16_t)(sensor->co2 * 10) % 10;
//Целая часть
if(concentration_int > 9999) {
snprintf(app->buff, BUFF_SIZE, "MAX ");
canvas_set_font(canvas, FontPrimary);
} else {
snprintf(app->buff, BUFF_SIZE, "%d", concentration_int);
canvas_set_font(canvas, FontBigNumbers);
}
canvas_draw_str_aligned(canvas, x + 70, y + 10, AlignRight, AlignCenter, app->buff);
}
static void _draw_singleSensor(Canvas* canvas, Sensor* sensor, const uint8_t pos[2], Color color) { static void _draw_singleSensor(Canvas* canvas, Sensor* sensor, const uint8_t pos[2], Color color) {
canvas_set_font(canvas, FontPrimary); canvas_set_font(canvas, FontPrimary);
@@ -320,6 +349,17 @@ static void _draw_carousel_values(Canvas* canvas) {
canvas, unitemp_sensor_getActive(generalview_sensor_index), hum_positions[1]); canvas, unitemp_sensor_getActive(generalview_sensor_index), hum_positions[1]);
_draw_pressure(canvas, unitemp_sensor_getActive(generalview_sensor_index)); _draw_pressure(canvas, unitemp_sensor_getActive(generalview_sensor_index));
break; break;
case UT_DATA_TYPE_TEMP_HUM_CO2:
_draw_temperature(
canvas,
unitemp_sensor_getActive(generalview_sensor_index),
temp_positions[2][0],
temp_positions[2][1],
ColorWhite);
_draw_humidity(
canvas, unitemp_sensor_getActive(generalview_sensor_index), hum_positions[1]);
_draw_co2(canvas, unitemp_sensor_getActive(generalview_sensor_index), ColorWhite);
break;
} }
} }

View File

@@ -213,7 +213,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) {
flipper_format_free(temp_fm_preset3); flipper_format_free(temp_fm_preset3);
// # HND - FM presets // # HND - FM preset
FlipperFormat* temp_fm_preset4 = flipper_format_string_alloc(); FlipperFormat* temp_fm_preset4 = flipper_format_string_alloc();
flipper_format_write_string_cstr( flipper_format_write_string_cstr(
temp_fm_preset4, temp_fm_preset4,
@@ -223,16 +223,6 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) {
subghz_setting_load_custom_preset(setting, (const char*)"HND_1", temp_fm_preset4); subghz_setting_load_custom_preset(setting, (const char*)"HND_1", temp_fm_preset4);
flipper_format_free(temp_fm_preset4); flipper_format_free(temp_fm_preset4);
FlipperFormat* temp_fm_preset5 = flipper_format_string_alloc();
flipper_format_write_string_cstr(
temp_fm_preset5,
(const char*)"Custom_preset_data",
(const char*)"02 0D 0B 06 08 32 07 04 14 00 13 02 12 07 11 36 10 E9 15 32 18 18 19 16 1D 92 1C 40 1B 03 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00");
flipper_format_rewind(temp_fm_preset5);
subghz_setting_load_custom_preset(setting, (const char*)"HND_2", temp_fm_preset5);
flipper_format_free(temp_fm_preset5);
} }
// custom presets loading - end // custom presets loading - end