From 741c784f2d14d9942b607aff093c8fb8965ffec5 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 11 Nov 2022 18:12:55 +0300 Subject: [PATCH] Introducing ibutton fuzzer --- applications/plugins/ibtn_fuzzer/LICENSE.md | 8 + .../plugins/ibtn_fuzzer/application.fam | 13 + applications/plugins/ibtn_fuzzer/ibtnfuzzer.c | 268 ++++++++++ applications/plugins/ibtn_fuzzer/ibtnfuzzer.h | 89 ++++ .../plugins/ibtn_fuzzer/ibutt_10px.png | Bin 0 -> 304 bytes .../plugins/ibtn_fuzzer/images/ibutt_10px.png | Bin 0 -> 304 bytes .../scene/ibtnfuzzer_scene_entrypoint.c | 215 ++++++++ .../scene/ibtnfuzzer_scene_entrypoint.h | 8 + .../scene/ibtnfuzzer_scene_load_custom_uids.c | 85 +++ .../scene/ibtnfuzzer_scene_load_custom_uids.h | 9 + .../scene/ibtnfuzzer_scene_load_file.c | 179 +++++++ .../scene/ibtnfuzzer_scene_load_file.h | 9 + .../scene/ibtnfuzzer_scene_run_attack.c | 490 ++++++++++++++++++ .../scene/ibtnfuzzer_scene_run_attack.h | 8 + .../scene/ibtnfuzzer_scene_select_field.c | 160 ++++++ .../scene/ibtnfuzzer_scene_select_field.h | 9 + .../ibtnfuzzer/example_uids_cyfral.txt | 8 + .../ibtnfuzzer/example_uids_ds1990.txt | 11 + .../ibtnfuzzer/example_uids_metakom.txt | 9 + 19 files changed, 1578 insertions(+) create mode 100644 applications/plugins/ibtn_fuzzer/LICENSE.md create mode 100644 applications/plugins/ibtn_fuzzer/application.fam create mode 100644 applications/plugins/ibtn_fuzzer/ibtnfuzzer.c create mode 100644 applications/plugins/ibtn_fuzzer/ibtnfuzzer.h create mode 100644 applications/plugins/ibtn_fuzzer/ibutt_10px.png create mode 100644 applications/plugins/ibtn_fuzzer/images/ibutt_10px.png create mode 100644 applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_entrypoint.c create mode 100644 applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_entrypoint.h create mode 100644 applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_load_custom_uids.c create mode 100644 applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_load_custom_uids.h create mode 100644 applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_load_file.c create mode 100644 applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_load_file.h create mode 100644 applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_run_attack.c create mode 100644 applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_run_attack.h create mode 100644 applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_select_field.c create mode 100644 applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_select_field.h create mode 100644 assets/resources/ibtnfuzzer/example_uids_cyfral.txt create mode 100644 assets/resources/ibtnfuzzer/example_uids_ds1990.txt create mode 100644 assets/resources/ibtnfuzzer/example_uids_metakom.txt diff --git a/applications/plugins/ibtn_fuzzer/LICENSE.md b/applications/plugins/ibtn_fuzzer/LICENSE.md new file mode 100644 index 000000000..ba3b84456 --- /dev/null +++ b/applications/plugins/ibtn_fuzzer/LICENSE.md @@ -0,0 +1,8 @@ +/* + * ---------------------------------------------------------------------------- + * "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. + * ---------------------------------------------------------------------------- + */ \ No newline at end of file diff --git a/applications/plugins/ibtn_fuzzer/application.fam b/applications/plugins/ibtn_fuzzer/application.fam new file mode 100644 index 000000000..b27f47ba9 --- /dev/null +++ b/applications/plugins/ibtn_fuzzer/application.fam @@ -0,0 +1,13 @@ +App( + appid="iBtn_Fuzzer", + name="iButton Fuzzer", + apptype=FlipperAppType.EXTERNAL, + entry_point="ibtnfuzzer_start", + cdefines=["APP_IBTN_FUZZ"], + requires=["gui", "storage", "dialogs", "input", "notification"], + stack_size=1 * 1024, + order=15, + fap_icon="ibutt_10px.png", + fap_category="Tools", + fap_icon_assets="images", +) diff --git a/applications/plugins/ibtn_fuzzer/ibtnfuzzer.c b/applications/plugins/ibtn_fuzzer/ibtnfuzzer.c new file mode 100644 index 000000000..f02da3b82 --- /dev/null +++ b/applications/plugins/ibtn_fuzzer/ibtnfuzzer.c @@ -0,0 +1,268 @@ +#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" + +#define IBTNFUZZER_APP_FOLDER "/ext/ibtnfuzzer" + +static void ibtnfuzzer_draw_callback(Canvas* const canvas, void* ctx) { + iBtnFuzzerState* ibtnfuzzer_state = (iBtnFuzzerState*)acquire_mutex((ValueMutex*)ctx, 100); + + if(ibtnfuzzer_state == NULL) { + return; + } + + // 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; + } + + release_mutex((ValueMutex*)ctx, ibtnfuzzer_state); +} + +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->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); + + free(ibtnfuzzer->data); + free(ibtnfuzzer->payload); + + // 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(); + ValueMutex ibtnfuzzer_state_mutex; + + // Mutex + FURI_LOG_I(TAG, "Initializing ibtnfuzzer mutex"); + if(!init_mutex(&ibtnfuzzer_state_mutex, ibtnfuzzer_state, sizeof(iBtnFuzzerState))) { + 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_mutex); + 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); + 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); + } + } + } + + // 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); + ibtnfuzzer_free(ibtnfuzzer_state); + + return 0; +} \ No newline at end of file diff --git a/applications/plugins/ibtn_fuzzer/ibtnfuzzer.h b/applications/plugins/ibtn_fuzzer/ibtnfuzzer.h new file mode 100644 index 000000000..1af5e9ff1 --- /dev/null +++ b/applications/plugins/ibtn_fuzzer/ibtnfuzzer.h @@ -0,0 +1,89 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#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 { + 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; + + DialogsApp* dialogs; + FuriString* notification_msg; + uint8_t key_index; + iButtonWorker* worker; + iButtonKey* key; + iButtonKeyType keytype; + bool workr_rund; + bool enter_rerun; + + uint8_t time_between_cards; + + // Used for custom dictionnary + Stream* uids_stream; +} iBtnFuzzerState; \ No newline at end of file diff --git a/applications/plugins/ibtn_fuzzer/ibutt_10px.png b/applications/plugins/ibtn_fuzzer/ibutt_10px.png new file mode 100644 index 0000000000000000000000000000000000000000..2fdaf123a657c00c9c84632ca3c151674e451ae1 GIT binary patch literal 304 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2xkYHHq`AGmsv7|ftIx;Y9?C1WI$O_~uBzpw; zGB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpafHrx4R1i<>&pI=m5)bW_|craZ$KesPZ!4!j_b)kjvx52z42i= z^Wk##wtdVzTiGS{99;2>!TC2M!yZeXz}?LkD}l;YOI#yLQW8s2t&)pUffR$0fsvuE zfvK*cNr<75m9c@9v4ysQft7*5`ikN&C>nC}Q!>*kp&E>VdO{3LtqcsU49p-Jly36? Qy~)7f>FVdQ&MBb@0C$~I0{{R3 literal 0 HcmV?d00001 diff --git a/applications/plugins/ibtn_fuzzer/images/ibutt_10px.png b/applications/plugins/ibtn_fuzzer/images/ibutt_10px.png new file mode 100644 index 0000000000000000000000000000000000000000..2fdaf123a657c00c9c84632ca3c151674e451ae1 GIT binary patch literal 304 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2xkYHHq`AGmsv7|ftIx;Y9?C1WI$O_~uBzpw; zGB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpafHrx4R1i<>&pI=m5)bW_|craZ$KesPZ!4!j_b)kjvx52z42i= z^Wk##wtdVzTiGS{99;2>!TC2M!yZeXz}?LkD}l;YOI#yLQW8s2t&)pUffR$0fsvuE zfvK*cNr<75m9c@9v4ysQft7*5`ikN&C>nC}Q!>*kp&E>VdO{3LtqcsU49p-Jly36? Qy~)7f>FVdQ&MBb@0C$~I0{{R3 literal 0 HcmV?d00001 diff --git a/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_entrypoint.c b/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_entrypoint.c new file mode 100644 index 000000000..a951e0c1f --- /dev/null +++ b/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_entrypoint.c @@ -0,0 +1,215 @@ +#include "ibtnfuzzer_scene_entrypoint.h" + +FuriString* main_menu_items[3]; +FuriString* main_menu_proto_items[3]; + +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(); + }*/ + + main_menu_items[0] = furi_string_alloc_set("Default Values"); + main_menu_items[1] = furi_string_alloc_set("Load File"); + main_menu_items[2] = furi_string_alloc_set("Load uids from file"); + + context->menu_proto_index = 0; + /*for(uint32_t i = 0; i < 4; i++) { + menu_proto_items[i] = furi_string_alloc(); + }*/ + + main_menu_proto_items[0] = furi_string_alloc_set("DS1990"); + main_menu_proto_items[1] = furi_string_alloc_set("Metakom"); + main_menu_proto_items[2] = furi_string_alloc_set("Cyfral"); +} + +void ibtnfuzzer_scene_entrypoint_on_exit(iBtnFuzzerState* context) { + context->enter_rerun = false; + + for(uint32_t i = 0; i < 3; i++) { + furi_string_free(main_menu_items[i]); + } + + for(uint32_t i = 0; i < 3; i++) { + furi_string_free(main_menu_proto_items[i]); + } +} + +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(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(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(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(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(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(main_menu_proto_items[context->menu_proto_index] != NULL) { + canvas_draw_str_aligned( + canvas, + 64, + 4, + AlignCenter, + AlignTop, + furi_string_get_cstr(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(main_menu_proto_items[context->menu_proto_index + 1])); + } + } +} \ No newline at end of file diff --git a/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_entrypoint.h b/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_entrypoint.h new file mode 100644 index 000000000..b77aec369 --- /dev/null +++ b/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_entrypoint.h @@ -0,0 +1,8 @@ +#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); \ No newline at end of file diff --git a/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_load_custom_uids.c b/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_load_custom_uids.c new file mode 100644 index 000000000..8f1a422b3 --- /dev/null +++ b/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_load_custom_uids.c @@ -0,0 +1,85 @@ +#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.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); +} diff --git a/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_load_custom_uids.h b/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_load_custom_uids.h new file mode 100644 index 000000000..bb51c7079 --- /dev/null +++ b/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_load_custom_uids.h @@ -0,0 +1,9 @@ +#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); \ No newline at end of file diff --git a/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_load_file.c b/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_load_file.c new file mode 100644 index 000000000..99e6db733 --- /dev/null +++ b/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_load_file.c @@ -0,0 +1,179 @@ +#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(); + 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 == 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; + } + } + } + + // 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); + } + } + + 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); + + // 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; +} \ No newline at end of file diff --git a/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_load_file.h b/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_load_file.h new file mode 100644 index 000000000..34031d08c --- /dev/null +++ b/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_load_file.h @@ -0,0 +1,9 @@ +#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); \ No newline at end of file diff --git a/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_run_attack.c b/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_run_attack.c new file mode 100644 index 000000000..55942f929 --- /dev/null +++ b/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_run_attack.c @@ -0,0 +1,490 @@ +#include "ibtnfuzzer_scene_run_attack.h" +#include + +uint8_t counter = 0; + +uint8_t id_list_ds1990[25][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, 0xFF}, // Only FF + {0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, // Only 11 + {0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22}, // Only 22 + {0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33}, // Only 33 + {0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44}, // Only 44 + {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55}, // Only 55 + {0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}, // Only 66 + {0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77}, // Only 77 + {0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88}, // Only 88 + {0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99}, // Only 99 +}; + +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[14][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}, // ?? +}; + +void ibtnfuzzer_scene_run_attack_on_enter(iBtnFuzzerState* context) { + context->time_between_cards = 10; + context->attack_step = 0; + context->key = ibutton_key_alloc(); + context->worker = ibutton_worker_alloc(); + if(context->proto == Metakom) { + context->keytype = iButtonKeyMetakom; + } else if(context->proto == Cyfral) { + context->keytype = iButtonKeyCyfral; + } else { + context->keytype = iButtonKeyDS1990; + } + 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_worker_free(context->worker); + ibutton_key_free(context->key); + 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_type(context->key, context->keytype); + ibutton_key_set_data( + context->key, context->payload, ibutton_key_get_size_by_type(context->keytype)); + 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; + } + 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 == 24) { + 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 == 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 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 > 0) { + 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; + context->attack_step = 0; + counter = 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); + notification_message(context->notify, &sequence_blink_stop); + context->current_scene = SceneEntryPoint; + break; + default: + break; + } + } + if(event.input_type == InputTypeLong) { + switch(event.key) { + case InputKeyLeft: + if(!context->is_attacking) { + if(context->time_between_cards > 0) { + 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); +} diff --git a/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_run_attack.h b/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_run_attack.h new file mode 100644 index 000000000..9e44478f7 --- /dev/null +++ b/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_run_attack.h @@ -0,0 +1,8 @@ +#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); diff --git a/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_select_field.c b/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_select_field.c new file mode 100644 index 000000000..f3217f65e --- /dev/null +++ b/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_select_field.c @@ -0,0 +1,160 @@ +#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)); +} diff --git a/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_select_field.h b/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_select_field.h new file mode 100644 index 000000000..b6c684c3b --- /dev/null +++ b/applications/plugins/ibtn_fuzzer/scene/ibtnfuzzer_scene_select_field.h @@ -0,0 +1,9 @@ +#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); \ No newline at end of file diff --git a/assets/resources/ibtnfuzzer/example_uids_cyfral.txt b/assets/resources/ibtnfuzzer/example_uids_cyfral.txt new file mode 100644 index 000000000..497d2211a --- /dev/null +++ b/assets/resources/ibtnfuzzer/example_uids_cyfral.txt @@ -0,0 +1,8 @@ +# Example file, P.S. keep empty line at the end! +0000 +F000 +FE00 +CAFE +00CA +FF00 +FFFF diff --git a/assets/resources/ibtnfuzzer/example_uids_ds1990.txt b/assets/resources/ibtnfuzzer/example_uids_ds1990.txt new file mode 100644 index 000000000..6828bb423 --- /dev/null +++ b/assets/resources/ibtnfuzzer/example_uids_ds1990.txt @@ -0,0 +1,11 @@ +# Example file, P.S. keep empty line at the end! +0000000000000000 +FE00000000000000 +CAFE000000000000 +00CAFE0000000000 +0000CAFE00000000 +000000CAFE000000 +00000000CA000000 +0000000000A00000 +00000000000123FF +FFFFFFFFFFFFFFFF diff --git a/assets/resources/ibtnfuzzer/example_uids_metakom.txt b/assets/resources/ibtnfuzzer/example_uids_metakom.txt new file mode 100644 index 000000000..911ea73b2 --- /dev/null +++ b/assets/resources/ibtnfuzzer/example_uids_metakom.txt @@ -0,0 +1,9 @@ +# Example file, P.S. keep empty line at the end! +00000000 +F0000000 +E0000000 +FE000000 +CAFE0000 +00CAFE00 +0000CA00 +FFFFFFFF