Add mifare fuzzer

This commit is contained in:
Willy-JL
2023-06-01 03:34:45 +01:00
parent 15c3eb1f32
commit 2044cb5127
16 changed files with 1326 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
App(
appid="mifare_fuzzer",
name="Mifare Fuzzer",
apptype=FlipperAppType.EXTERNAL,
entry_point="mifare_fuzzer_app",
requires=[
"storage",
"gui",
],
stack_size=4 * 1024,
order=30,
fap_icon="images/mifare_fuzzer_10px.png",
fap_category="NFC",
fap_icon_assets="images",
)
Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B

+157
View File
@@ -0,0 +1,157 @@
#include "mifare_fuzzer_i.h"
/// @brief mifare_fuzzer_custom_event_callback()
/// @param context
/// @param event
/// @return
static bool mifare_fuzzer_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
MifareFuzzerApp* app = context;
return scene_manager_handle_custom_event(app->scene_manager, event);
}
/// @brief mifare_fuzzer_back_event_callback()
/// @param context
/// @return
static bool mifare_fuzzer_back_event_callback(void* context) {
furi_assert(context);
MifareFuzzerApp* app = context;
return scene_manager_handle_back_event(app->scene_manager);
}
/// @brief mifare_fuzzer_tick_event_callback()
/// @param context
static void mifare_fuzzer_tick_event_callback(void* context) {
furi_assert(context);
MifareFuzzerApp* app = context;
scene_manager_handle_tick_event(app->scene_manager);
}
/// @brief mifare_fuzzer_alloc()
/// @return
MifareFuzzerApp* mifare_fuzzer_alloc() {
MifareFuzzerApp* app = malloc(sizeof(MifareFuzzerApp));
app->view_dispatcher = view_dispatcher_alloc();
app->scene_manager = scene_manager_alloc(&mifare_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, mifare_fuzzer_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
app->view_dispatcher, mifare_fuzzer_back_event_callback);
// 1000 ticks are about 1 sec
view_dispatcher_set_tick_event_callback(
app->view_dispatcher, mifare_fuzzer_tick_event_callback, MIFARE_FUZZER_TICK_PERIOD);
// Open GUI record
app->gui = furi_record_open(RECORD_GUI);
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
// view: select card type
app->submenu_card = submenu_alloc();
view_dispatcher_add_view(
app->view_dispatcher, MifareFuzzerViewSelectCard, submenu_get_view(app->submenu_card));
// view: select attack type
app->submenu_attack = submenu_alloc();
view_dispatcher_add_view(
app->view_dispatcher, MifareFuzzerViewSelectAttack, submenu_get_view(app->submenu_attack));
// view: emulator
app->emulator_view = mifare_fuzzer_emulator_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
MifareFuzzerViewEmulator,
mifare_fuzzer_emulator_get_view(app->emulator_view));
// worker
app->worker = mifare_fuzzer_worker_alloc();
// storage
app->storage = furi_record_open(RECORD_STORAGE);
if(!storage_simply_mkdir(app->storage, MIFARE_FUZZER_APP_FOLDER)) {
FURI_LOG_E(TAG, "Could not create folder: %s", MIFARE_FUZZER_APP_FOLDER);
}
// dialog
app->dialogs = furi_record_open(RECORD_DIALOGS);
// furi strings
app->uid_str = furi_string_alloc();
app->file_path = furi_string_alloc();
app->app_folder = furi_string_alloc_set(MIFARE_FUZZER_APP_FOLDER);
return app;
}
/// @brief mifare_fuzzer_free()
/// @param app
void mifare_fuzzer_free(MifareFuzzerApp* app) {
furi_assert(app);
// Views
//FURI_LOG_D(TAG, "mifare_fuzzer_free() :: Views");
view_dispatcher_remove_view(app->view_dispatcher, MifareFuzzerViewSelectCard);
view_dispatcher_remove_view(app->view_dispatcher, MifareFuzzerViewSelectAttack);
// Submenus
//FURI_LOG_D(TAG, "mifare_fuzzer_free() :: Submenus");
submenu_free(app->submenu_card);
submenu_free(app->submenu_attack);
// View Dispatcher
//FURI_LOG_D(TAG, "mifare_fuzzer_free() :: View Dispatcher");
view_dispatcher_free(app->view_dispatcher);
// Scene Manager
//FURI_LOG_D(TAG, "mifare_fuzzer_free() :: Scene Manager");
scene_manager_free(app->scene_manager);
// GUI
//FURI_LOG_D(TAG, "mifare_fuzzer_free() :: GUI");
furi_record_close(RECORD_GUI);
app->gui = NULL;
// Worker
//FURI_LOG_D(TAG, "mifare_fuzzer_free() :: Worker");
mifare_fuzzer_worker_free(app->worker);
// storage
furi_record_close(RECORD_STORAGE);
app->storage = NULL;
// dialog
furi_record_close(RECORD_DIALOGS);
app->dialogs = NULL;
// furi strings
furi_string_free(app->uid_str);
furi_string_free(app->file_path);
furi_string_free(app->app_folder);
// App
//FURI_LOG_D(TAG, "mifare_fuzzer_free() :: App");
free(app);
}
/// @brief mifare_fuzzer_app (ENTRYPOINT)
/// @param p
/// @return
int32_t mifare_fuzzer_app(void* p) {
UNUSED(p);
//FURI_LOG_D(TAG, "mifare_fuzzer_app()");
MifareFuzzerApp* app = mifare_fuzzer_alloc();
// init some defaults
scene_manager_set_scene_state(app->scene_manager, MifareFuzzerSceneStart, 0);
scene_manager_set_scene_state(app->scene_manager, MifareFuzzerSceneAttack, 0);
// open scene
scene_manager_next_scene(app->scene_manager, MifareFuzzerSceneStart);
view_dispatcher_run(app->view_dispatcher);
// free
mifare_fuzzer_free(app);
return 0;
}
+3
View File
@@ -0,0 +1,3 @@
#pragma once
typedef struct MifareFuzzerApp MifareFuzzerApp;
@@ -0,0 +1,14 @@
#pragma once
typedef enum MifareFuzzerEvent {
MifareFuzzerEventClassic1k = 1,
MifareFuzzerEventClassic4k,
MifareFuzzerEventUltralight,
MifareFuzzerEventTestValueAttack,
MifareFuzzerEventRandomValuesAttack,
MifareFuzzerEventLoadUIDsFromFileAttack,
MifareFuzzerEventStartAttack,
MifareFuzzerEventStopAttack,
MifareFuzzerEventIncrementTicks,
MifareFuzzerEventDecrementTicks,
} MifareFuzzerEvent;
+76
View File
@@ -0,0 +1,76 @@
#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/submenu.h>
#include <dialogs/dialogs.h>
#include <input/input.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 "mifare_fuzzer.h"
#include "scenes/mifare_fuzzer_scene.h"
#include "views/mifare_fuzzer_emulator.h"
#include "mifare_fuzzer_worker.h"
#define TAG "MifareFuzzerApp"
#define MIFARE_FUZZER_APP_FOLDER EXT_PATH("mifare_fuzzer")
#define MIFARE_FUZZER_FILE_EXT ".txt"
#define MIFARE_FUZZER_TICK_PERIOD 200
#define MIFARE_FUZZER_DEFAULT_TICKS_BETWEEN_CARDS 10
#define MIFARE_FUZZER_MIN_TICKS_BETWEEN_CARDS 5
#define MIFARE_FUZZER_MAX_TICKS_BETWEEN_CARDS 50
typedef enum MifareFuzzerSceneState {
MifareFuzzerSceneStateClassic1k,
MifareFuzzerSceneStateClassic4k,
MifareFuzzerSceneStateUltralight,
} MifareFuzzerSceneState;
typedef enum {
MifareFuzzerViewSelectCard,
MifareFuzzerViewSelectAttack,
MifareFuzzerViewEmulator,
} MifareFuzzerView;
struct MifareFuzzerApp {
Gui* gui;
ViewDispatcher* view_dispatcher;
SceneManager* scene_manager;
DialogsApp* dialogs;
Storage* storage;
// Common Views
Submenu* submenu_card;
Submenu* submenu_attack;
MifareFuzzerEmulator* emulator_view;
MifareFuzzerWorker* worker;
MifareCard card;
MifareFuzzerAttack attack;
FuriHalNfcDevData nfc_dev_data;
FuriString* app_folder;
FuriString* file_path;
FuriString* uid_str;
Stream* uids_stream;
};
@@ -0,0 +1,88 @@
#include "mifare_fuzzer_worker.h"
/// @brief mifare_fuzzer_worker_alloc()
/// @return
MifareFuzzerWorker* mifare_fuzzer_worker_alloc() {
MifareFuzzerWorker* mifare_fuzzer_worker = malloc(sizeof(MifareFuzzerWorker));
// Worker thread attributes
mifare_fuzzer_worker->thread = furi_thread_alloc_ex(
"MifareFuzzerWorker", 8192, mifare_fuzzer_worker_task, mifare_fuzzer_worker);
mifare_fuzzer_worker->state = MifareFuzzerWorkerStateStop;
return mifare_fuzzer_worker;
}
/// @brief mifare_fuzzer_worker_free()
/// @param mifare_fuzzer_worker
void mifare_fuzzer_worker_free(MifareFuzzerWorker* mifare_fuzzer_worker) {
furi_assert(mifare_fuzzer_worker);
furi_thread_free(mifare_fuzzer_worker->thread);
free(mifare_fuzzer_worker);
}
/// @brief mifare_fuzzer_worker_stop()
/// @param mifare_fuzzer_worker
void mifare_fuzzer_worker_stop(MifareFuzzerWorker* mifare_fuzzer_worker) {
furi_assert(mifare_fuzzer_worker);
if(mifare_fuzzer_worker->state != MifareFuzzerWorkerStateStop) {
mifare_fuzzer_worker->state = MifareFuzzerWorkerStateStop;
furi_thread_join(mifare_fuzzer_worker->thread);
}
}
/// @brief mifare_fuzzer_worker_start()
/// @param mifare_fuzzer_worker
void mifare_fuzzer_worker_start(MifareFuzzerWorker* mifare_fuzzer_worker) {
furi_assert(mifare_fuzzer_worker);
mifare_fuzzer_worker->state = MifareFuzzerWorkerStateEmulate;
furi_thread_start(mifare_fuzzer_worker->thread);
}
/// @brief mifare_fuzzer_worker_task()
/// @param context
/// @return
int32_t mifare_fuzzer_worker_task(void* context) {
MifareFuzzerWorker* mifare_fuzzer_worker = context;
if(mifare_fuzzer_worker->state == MifareFuzzerWorkerStateEmulate) {
FuriHalNfcDevData params = mifare_fuzzer_worker->nfc_dev_data;
furi_hal_nfc_exit_sleep();
while(mifare_fuzzer_worker->state == MifareFuzzerWorkerStateEmulate) {
furi_hal_nfc_listen(
params.uid, params.uid_len, params.a_data.atqa, params.a_data.sak, false, 500);
furi_delay_ms(50);
}
furi_hal_nfc_sleep();
}
mifare_fuzzer_worker->state = MifareFuzzerWorkerStateStop;
return 0;
}
/// @brief mifare_fuzzer_worker_is_emulating()
/// @param mifare_fuzzer_worker
/// @return
bool mifare_fuzzer_worker_is_emulating(MifareFuzzerWorker* mifare_fuzzer_worker) {
if(mifare_fuzzer_worker->state == MifareFuzzerWorkerStateEmulate) {
return true;
}
return false;
}
/// @brief mifare_fuzzer_worker_set_nfc_dev_data()
/// @param mifare_fuzzer_worker
/// @param nfc_dev_data
void mifare_fuzzer_worker_set_nfc_dev_data(
MifareFuzzerWorker* mifare_fuzzer_worker,
FuriHalNfcDevData nfc_dev_data) {
mifare_fuzzer_worker->nfc_dev_data = nfc_dev_data;
}
/// @brief mifare_fuzzer_worker_get_nfc_dev_data()
/// @param mifare_fuzzer_worker
/// @return
FuriHalNfcDevData mifare_fuzzer_worker_get_nfc_dev_data(MifareFuzzerWorker* mifare_fuzzer_worker) {
return mifare_fuzzer_worker->nfc_dev_data;
}
@@ -0,0 +1,31 @@
#pragma once
#include <furi.h>
#include <furi_hal.h>
typedef enum MifareFuzzerWorkerState {
MifareFuzzerWorkerStateEmulate,
MifareFuzzerWorkerStateStop,
} MifareFuzzerWorkerState;
#define UID_LEN 7
#define ATQA_LEN 2
typedef struct MifareFuzzerWorker {
FuriThread* thread;
MifareFuzzerWorkerState state;
FuriHalNfcDevData nfc_dev_data;
} MifareFuzzerWorker;
// worker
MifareFuzzerWorker* mifare_fuzzer_worker_alloc();
void mifare_fuzzer_worker_free(MifareFuzzerWorker* mifare_fuzzer_worker);
void mifare_fuzzer_worker_stop(MifareFuzzerWorker* mifare_fuzzer_worker);
void mifare_fuzzer_worker_start(MifareFuzzerWorker* mifare_fuzzer_worker);
// task
int32_t mifare_fuzzer_worker_task(void* context);
//
bool mifare_fuzzer_worker_is_emulating(MifareFuzzerWorker* mifare_fuzzer_worker);
void mifare_fuzzer_worker_set_nfc_dev_data(
MifareFuzzerWorker* mifare_fuzzer_worker,
FuriHalNfcDevData nfc_dev_data);
FuriHalNfcDevData mifare_fuzzer_worker_get_nfc_dev_data(MifareFuzzerWorker* mifare_fuzzer_worker);
@@ -0,0 +1,30 @@
#include "mifare_fuzzer_scene.h"
// Generate scene on_enter handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
void (*const mifare_fuzzer_on_enter_handlers[])(void*) = {
#include "mifare_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 mifare_fuzzer_on_event_handlers[])(void* context, SceneManagerEvent event) = {
#include "mifare_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 mifare_fuzzer_on_exit_handlers[])(void* context) = {
#include "mifare_fuzzer_scene_config.h"
};
#undef ADD_SCENE
// Initialize scene handlers configuration structure
const SceneManagerHandlers mifare_fuzzer_scene_handlers = {
.on_enter_handlers = mifare_fuzzer_on_enter_handlers,
.on_event_handlers = mifare_fuzzer_on_event_handlers,
.on_exit_handlers = mifare_fuzzer_on_exit_handlers,
.scene_num = MifareFuzzerSceneNum,
};
@@ -0,0 +1,29 @@
#pragma once
#include <gui/scene_manager.h>
// Generate scene id and total number
#define ADD_SCENE(prefix, name, id) MifareFuzzerScene##id,
typedef enum {
#include "mifare_fuzzer_scene_config.h"
MifareFuzzerSceneNum,
} MifareFuzzerScene;
#undef ADD_SCENE
extern const SceneManagerHandlers mifare_fuzzer_scene_handlers;
// Generate scene on_enter handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
#include "mifare_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 "mifare_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 "mifare_fuzzer_scene_config.h"
#undef ADD_SCENE
@@ -0,0 +1,143 @@
#include "../mifare_fuzzer_i.h"
#include "../mifare_fuzzer_custom_events.h"
enum SubmenuIndex {
SubmenuIndexTestValue,
SubmenuIndexRandomValuesAttack,
SubmenuIndexLoadUIDsFromFile,
};
/// @brief mifare_fuzzer_scene_attack_submenu_callback()
/// @param context
/// @param index
void mifare_fuzzer_scene_attack_submenu_callback(void* context, uint32_t index) {
//FURI_LOG_D(TAG, "mifare_fuzzer_scene_attack_submenu_callback() :: index = %ld", index);
MifareFuzzerApp* app = context;
uint8_t custom_event = 255;
switch(index) {
case SubmenuIndexTestValue:
custom_event = MifareFuzzerEventTestValueAttack;
break;
case SubmenuIndexRandomValuesAttack:
custom_event = MifareFuzzerEventRandomValuesAttack;
break;
case SubmenuIndexLoadUIDsFromFile:
custom_event = MifareFuzzerEventLoadUIDsFromFileAttack;
break;
default:
return;
}
//FURI_LOG_D(TAG, "mifare_fuzzer_scene_attack_submenu_callback() :: custom_event = %d", custom_event);
view_dispatcher_send_custom_event(app->view_dispatcher, custom_event);
}
/// @brief mifare_fuzzer_scene_attack_on_enter()
/// @param context
void mifare_fuzzer_scene_attack_on_enter(void* context) {
//FURI_LOG_D(TAG, "mifare_fuzzer_scene_attack_on_enter()");
MifareFuzzerApp* app = context;
Submenu* submenu_attack = app->submenu_attack;
submenu_set_header(submenu_attack, "Mifare Fuzzer (attack)");
submenu_add_item(
submenu_attack,
"Test Values",
SubmenuIndexTestValue,
mifare_fuzzer_scene_attack_submenu_callback,
app);
submenu_add_item(
submenu_attack,
"Random Values",
SubmenuIndexRandomValuesAttack,
mifare_fuzzer_scene_attack_submenu_callback,
app);
submenu_add_item(
submenu_attack,
"Load UIDs from file",
SubmenuIndexLoadUIDsFromFile,
mifare_fuzzer_scene_attack_submenu_callback,
app);
// set selected menu
submenu_set_selected_item(
submenu_attack,
scene_manager_get_scene_state(app->scene_manager, MifareFuzzerSceneAttack));
view_dispatcher_switch_to_view(app->view_dispatcher, MifareFuzzerViewSelectAttack);
}
/// @brief mifare_fuzzer_scene_attack_on_event()
/// @param context
/// @param event
/// @return
bool mifare_fuzzer_scene_attack_on_event(void* context, SceneManagerEvent event) {
//FURI_LOG_D(TAG, "mifare_fuzzer_scene_attack_on_event()");
MifareFuzzerApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
//FURI_LOG_D(TAG, "mifare_fuzzer_scene_attack_on_event() :: event.event = %ld", event.event);
if(event.event == MifareFuzzerEventTestValueAttack) {
// save selected item
scene_manager_set_scene_state(
app->scene_manager, MifareFuzzerSceneAttack, SubmenuIndexTestValue);
// set emulator attack
app->attack = MifareFuzzerAttackTestValues;
mifare_fuzzer_emulator_set_attack(app->emulator_view, app->attack);
// open next scene
scene_manager_next_scene(app->scene_manager, MifareFuzzerSceneEmulator);
consumed = true;
} else if(event.event == MifareFuzzerEventRandomValuesAttack) {
// save selected item
scene_manager_set_scene_state(
app->scene_manager, MifareFuzzerSceneAttack, SubmenuIndexRandomValuesAttack);
// set emulator attack
app->attack = MifareFuzzerAttackRandomValues;
mifare_fuzzer_emulator_set_attack(app->emulator_view, app->attack);
// open next scene
scene_manager_next_scene(app->scene_manager, MifareFuzzerSceneEmulator);
consumed = true;
} else if(event.event == MifareFuzzerEventLoadUIDsFromFileAttack) {
// save selected item
scene_manager_set_scene_state(
app->scene_manager, MifareFuzzerSceneAttack, SubmenuIndexLoadUIDsFromFile);
// set emulator attack
app->attack = MifareFuzzerAttackLoadUidsFromFile;
mifare_fuzzer_emulator_set_attack(app->emulator_view, app->attack);
// open dialog file
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, MIFARE_FUZZER_FILE_EXT, NULL);
browser_options.hide_ext = false;
bool res = dialog_file_browser_show(
app->dialogs, app->file_path, app->app_folder, &browser_options);
if(res) {
app->uids_stream = buffered_file_stream_alloc(app->storage);
res = buffered_file_stream_open(
app->uids_stream,
furi_string_get_cstr(app->file_path),
FSAM_READ,
FSOM_OPEN_EXISTING);
if(res) {
// open next scene
scene_manager_next_scene(app->scene_manager, MifareFuzzerSceneEmulator);
} else {
buffered_file_stream_close(app->uids_stream);
}
}
consumed = true;
}
} else if(event.type == SceneManagerEventTypeTick) {
//FURI_LOG_D(TAG, "mifare_fuzzer_scene_attack_on_event() :: SceneManagerEventTypeTick");
//consumed = true;
}
return consumed;
}
/// @brief mifare_fuzzer_scene_attack_on_exit()
/// @param context
void mifare_fuzzer_scene_attack_on_exit(void* context) {
//FURI_LOG_D(TAG, "mifare_fuzzer_scene_attack_on_exit()");
MifareFuzzerApp* app = context;
submenu_reset(app->submenu_attack);
}
@@ -0,0 +1,3 @@
ADD_SCENE(mifare_fuzzer, start, Start)
ADD_SCENE(mifare_fuzzer, attack, Attack)
ADD_SCENE(mifare_fuzzer, emulator, Emulator)
@@ -0,0 +1,242 @@
#include "../mifare_fuzzer_i.h"
uint8_t tick_counter = 0;
uint8_t attack_step = 0;
uint8_t id_uid_test[9][7] = {
{0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17},
{0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28},
{0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39},
{0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a},
{0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b},
{0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c},
{0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d},
{0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e},
{0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f},
};
/// @brief mifare_fuzzer_scene_emulator_callback()
/// @param event
/// @param context
static void mifare_fuzzer_scene_emulator_callback(MifareFuzzerEvent event, void* context) {
//FURI_LOG_D(TAG, "mifare_fuzzer_scene_emulator_callback()");
furi_assert(context);
MifareFuzzerApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
/// @brief mifare_fuzzer_scene_emulator_on_enter()
/// @param context
void mifare_fuzzer_scene_emulator_on_enter(void* context) {
//FURI_LOG_D(TAG, "mifare_fuzzer_scene_emulator_on_enter()");
MifareFuzzerApp* app = context;
MifareFuzzerEmulator* emulator = app->emulator_view;
// init callback
mifare_fuzzer_emulator_set_callback(emulator, mifare_fuzzer_scene_emulator_callback, app);
// init ticks
tick_counter = 0;
mifare_fuzzer_emulator_set_tick_num(app->emulator_view, tick_counter);
emulator->ticks_between_cards = MIFARE_FUZZER_DEFAULT_TICKS_BETWEEN_CARDS;
mifare_fuzzer_emulator_set_ticks_between_cards(
app->emulator_view, emulator->ticks_between_cards);
// init default card data
FuriHalNfcDevData nfc_dev_data;
nfc_dev_data.a_data.atqa[0] = 0x00;
nfc_dev_data.a_data.atqa[1] = 0x00;
nfc_dev_data.a_data.sak = 0x00;
if(app->card == MifareCardUltralight) {
nfc_dev_data.uid_len = 0x07;
} else {
nfc_dev_data.uid_len = 0x04;
}
for(uint32_t i = 0; i < nfc_dev_data.uid_len; i++) {
nfc_dev_data.uid[i] = 0x00;
}
mifare_fuzzer_emulator_set_nfc_dev_data(app->emulator_view, nfc_dev_data);
// init other vars
attack_step = 0;
// switch to view
view_dispatcher_switch_to_view(app->view_dispatcher, MifareFuzzerViewEmulator);
}
/// @brief mifare_fuzzer_scene_emulator_on_event()
/// @param context
/// @param event
/// @return
bool mifare_fuzzer_scene_emulator_on_event(void* context, SceneManagerEvent event) {
//FURI_LOG_D(TAG, "mifare_fuzzer_scene_emulator_on_event()");
FuriHalNfcDevData nfc_dev_data;
MifareFuzzerApp* app = context;
MifareFuzzerEmulator* emulator = app->emulator_view;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == MifareFuzzerEventStartAttack) {
//FURI_LOG_D(TAG, "mifare_fuzzer_scene_emulator_on_event() :: MifareFuzzerEventStartAttack");
// Stop worker
mifare_fuzzer_worker_stop(app->worker);
// Set card type
// TODO: Move somewhere else, I do not like this to be there
if(app->card == MifareCardClassic1k) {
nfc_dev_data.a_data.atqa[0] = 0x04;
nfc_dev_data.a_data.atqa[1] = 0x00;
nfc_dev_data.a_data.sak = 0x08;
nfc_dev_data.uid_len = 0x04;
} else if(app->card == MifareCardClassic4k) {
nfc_dev_data.a_data.atqa[0] = 0x02;
nfc_dev_data.a_data.atqa[1] = 0x00;
nfc_dev_data.a_data.sak = 0x18;
nfc_dev_data.uid_len = 0x04;
} else if(app->card == MifareCardUltralight) {
nfc_dev_data.a_data.atqa[0] = 0x44;
nfc_dev_data.a_data.atqa[1] = 0x00;
nfc_dev_data.a_data.sak = 0x00;
nfc_dev_data.uid_len = 0x07;
}
// Set UIDs
if(app->attack == MifareFuzzerAttackTestValues) {
// Load test UIDs
for(uint8_t i = 0; i < nfc_dev_data.uid_len; i++) {
nfc_dev_data.uid[i] = id_uid_test[attack_step][i];
}
// Next UIDs on next loop
if(attack_step >= 8) {
attack_step = 0;
} else {
attack_step++;
}
} else if(app->attack == MifareFuzzerAttackRandomValues) {
if(app->card == MifareCardUltralight) {
// First byte of a 7 byte UID is the manufacturer-code
// https://github.com/Proxmark/proxmark3/blob/master/client/taginfo.c
// https://stackoverflow.com/questions/37837730/mifare-cards-distinguish-between-4-byte-and-7-byte-uids
// https://stackoverflow.com/questions/31233652/how-to-detect-manufacturer-from-nfc-tag-using-android
// TODO: Manufacture-code must be selectable from a list
// use a fixed manufacture-code for now: 0x04 = NXP Semiconductors Germany
nfc_dev_data.uid[0] = 0x04;
for(uint8_t i = 1; i < nfc_dev_data.uid_len; i++) {
nfc_dev_data.uid[i] = (furi_hal_random_get() & 0xFF);
}
} else {
for(uint8_t i = 0; i < nfc_dev_data.uid_len; i++) {
nfc_dev_data.uid[i] = (furi_hal_random_get() & 0xFF);
}
}
} else if(app->attack == MifareFuzzerAttackLoadUidsFromFile) {
//bool end_of_list = false;
// read stream
while(true) {
furi_string_reset(app->uid_str);
if(!stream_read_line(app->uids_stream, app->uid_str)) {
// restart from beginning on empty line
stream_rewind(app->uids_stream);
continue;
//end_of_list = true;
}
// Skip comments
if(furi_string_get_char(app->uid_str, 0) == '#') continue;
// Skip lines with invalid length
if((furi_string_size(app->uid_str) != 9) &&
(furi_string_size(app->uid_str) != 15))
continue;
break;
}
// TODO: stop on end of list?
//if(end_of_list) break;
// parse string to UID
// TODO: a better validation on input?
for(uint8_t i = 0; i < nfc_dev_data.uid_len; i++) {
if(i <= ((furi_string_size(app->uid_str) - 1) / 2)) {
char temp_str[3];
temp_str[0] = furi_string_get_cstr(app->uid_str)[i * 2];
temp_str[1] = furi_string_get_cstr(app->uid_str)[i * 2 + 1];
temp_str[2] = '\0';
nfc_dev_data.uid[i] = (uint8_t)strtol(temp_str, NULL, 16);
} else {
nfc_dev_data.uid[i] = 0x00;
}
}
}
mifare_fuzzer_worker_set_nfc_dev_data(app->worker, nfc_dev_data);
mifare_fuzzer_emulator_set_nfc_dev_data(app->emulator_view, nfc_dev_data);
// Reset tick_counter
tick_counter = 0;
mifare_fuzzer_emulator_set_tick_num(app->emulator_view, tick_counter);
// Start worker
mifare_fuzzer_worker_start(app->worker);
} else if(event.event == MifareFuzzerEventStopAttack) {
//FURI_LOG_D(TAG, "mifare_fuzzer_scene_emulator_on_event() :: MifareFuzzerEventStopAttack");
// Stop worker
mifare_fuzzer_worker_stop(app->worker);
} else if(event.event == MifareFuzzerEventIncrementTicks) {
if(!emulator->is_attacking) {
if(emulator->ticks_between_cards < MIFARE_FUZZER_MAX_TICKS_BETWEEN_CARDS) {
emulator->ticks_between_cards++;
mifare_fuzzer_emulator_set_ticks_between_cards(
app->emulator_view, emulator->ticks_between_cards);
};
};
} else if(event.event == MifareFuzzerEventDecrementTicks) {
if(!emulator->is_attacking) {
if(emulator->ticks_between_cards > MIFARE_FUZZER_MIN_TICKS_BETWEEN_CARDS) {
emulator->ticks_between_cards--;
mifare_fuzzer_emulator_set_ticks_between_cards(
app->emulator_view, emulator->ticks_between_cards);
};
};
}
consumed = true;
} else if(event.type == SceneManagerEventTypeTick) {
//FURI_LOG_D(TAG, "mifare_fuzzer_scene_emulator_on_event() :: SceneManagerEventTypeTick");
// Used to check tick length (not perfect but enough)
//FuriHalRtcDateTime curr_dt;
//furi_hal_rtc_get_datetime(&curr_dt);
//FURI_LOG_D(TAG, "Time is: %.2d:%.2d:%.2d", curr_dt.hour, curr_dt.minute, curr_dt.second);
// If emulator is attacking
if(emulator->is_attacking) {
// increment tick_counter
tick_counter++;
mifare_fuzzer_emulator_set_tick_num(app->emulator_view, tick_counter);
//FURI_LOG_D(TAG, "tick_counter is: %.2d", tick_counter);
if(tick_counter >= emulator->ticks_between_cards) {
// Queue event for changing UID
view_dispatcher_send_custom_event(
app->view_dispatcher, MifareFuzzerEventStartAttack);
}
}
consumed = true;
}
return consumed;
}
/// @brief mifare_fuzzer_scene_emulator_on_exit()
/// @param context
void mifare_fuzzer_scene_emulator_on_exit(void* context) {
//FURI_LOG_D(TAG, "mifare_fuzzer_scene_emulator_on_exit()");
MifareFuzzerApp* app = context;
mifare_fuzzer_worker_stop(app->worker);
if(app->attack == MifareFuzzerAttackLoadUidsFromFile) {
furi_string_reset(app->uid_str);
stream_rewind(app->uids_stream);
buffered_file_stream_close(app->uids_stream);
}
}
@@ -0,0 +1,124 @@
#include "../mifare_fuzzer_i.h"
#include "../mifare_fuzzer_custom_events.h"
enum SubmenuIndex {
SubmenuIndexClassic1k,
SubmenuIndexClassic4k,
SubmenuIndexUltralight,
};
/// @brief mifare_fuzzer_scene_start_submenu_callback()
/// @param context
/// @param index
void mifare_fuzzer_scene_start_submenu_callback(void* context, uint32_t index) {
//FURI_LOG_D(TAG, "mifare_fuzzer_scene_start_submenu_callback() :: index = %ld", index);
MifareFuzzerApp* app = context;
uint8_t custom_event = 255;
switch(index) {
case SubmenuIndexClassic1k:
custom_event = MifareFuzzerEventClassic1k;
break;
case SubmenuIndexClassic4k:
custom_event = MifareFuzzerEventClassic4k;
break;
case SubmenuIndexUltralight:
custom_event = MifareFuzzerEventUltralight;
break;
default:
return;
}
//FURI_LOG_D(TAG, "mifare_fuzzer_scene_start_submenu_callback() :: custom_event = %d", custom_event);
view_dispatcher_send_custom_event(app->view_dispatcher, custom_event);
}
/// @brief mifare_fuzzer_scene_start_on_enter()
/// @param context
void mifare_fuzzer_scene_start_on_enter(void* context) {
//FURI_LOG_D(TAG, "mifare_fuzzer_scene_start_on_enter()");
MifareFuzzerApp* app = context;
Submenu* submenu_card = app->submenu_card;
submenu_set_header(submenu_card, "Mifare Fuzzer (card)");
submenu_add_item(
submenu_card,
"Classic 1k",
SubmenuIndexClassic1k,
mifare_fuzzer_scene_start_submenu_callback,
app);
submenu_add_item(
submenu_card,
"Classic 4k",
SubmenuIndexClassic4k,
mifare_fuzzer_scene_start_submenu_callback,
app);
submenu_add_item(
submenu_card,
"Ultralight",
SubmenuIndexUltralight,
mifare_fuzzer_scene_start_submenu_callback,
app);
// set selected menu
submenu_set_selected_item(
submenu_card, scene_manager_get_scene_state(app->scene_manager, MifareFuzzerSceneStart));
view_dispatcher_switch_to_view(app->view_dispatcher, MifareFuzzerViewSelectCard);
}
/// @brief mifare_fuzzer_scene_start_on_event()
/// @param context
/// @param event
/// @return
bool mifare_fuzzer_scene_start_on_event(void* context, SceneManagerEvent event) {
//FURI_LOG_D(TAG, "mifare_fuzzer_scene_start_on_event()");
MifareFuzzerApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
//FURI_LOG_D(TAG, "mifare_fuzzer_scene_start_on_event() :: event.event = %ld", event.event);
if(event.event == MifareFuzzerEventClassic1k) {
// save selected item
scene_manager_set_scene_state(
app->scene_manager, MifareFuzzerSceneStart, SubmenuIndexClassic1k);
// set emulator card
app->card = MifareCardClassic1k;
mifare_fuzzer_emulator_set_card(app->emulator_view, app->card);
// open next scene
scene_manager_next_scene(app->scene_manager, MifareFuzzerSceneAttack);
consumed = true;
} else if(event.event == MifareFuzzerEventClassic4k) {
// save selected item
scene_manager_set_scene_state(
app->scene_manager, MifareFuzzerSceneStart, SubmenuIndexClassic4k);
// set emulator card
app->card = MifareCardClassic4k;
mifare_fuzzer_emulator_set_card(app->emulator_view, app->card);
// open next scene
scene_manager_next_scene(app->scene_manager, MifareFuzzerSceneAttack);
consumed = true;
} else if(event.event == MifareFuzzerEventUltralight) {
// save selected item
scene_manager_set_scene_state(
app->scene_manager, MifareFuzzerSceneStart, SubmenuIndexUltralight);
// set emulator card
app->card = MifareCardUltralight;
mifare_fuzzer_emulator_set_card(app->emulator_view, app->card);
// open next scene
scene_manager_next_scene(app->scene_manager, MifareFuzzerSceneAttack);
consumed = true;
}
} else if(event.type == SceneManagerEventTypeTick) {
//FURI_LOG_D(TAG, "mifare_fuzzer_scene_start_on_event() :: SceneManagerEventTypeTick");
//consumed = true;
}
return consumed;
}
/// @brief mifare_fuzzer_scene_start_on_exit()
/// @param context
void mifare_fuzzer_scene_start_on_exit(void* context) {
//FURI_LOG_D(TAG, "mifare_fuzzer_scene_start_on_exit()");
MifareFuzzerApp* app = context;
submenu_reset(app->submenu_card);
}
@@ -0,0 +1,301 @@
#include "mifare_fuzzer_emulator.h"
#define TAG "MifareFuzzerApp_emulator_view"
// Screen is 128 × 64 pixels
/// @brief mifare_fuzzer_emulator_set_callback
/// @param mifare_fuzzer_emulator
/// @param callback
/// @param context
void mifare_fuzzer_emulator_set_callback(
MifareFuzzerEmulator* mifare_fuzzer_emulator,
MifareFuzzerEmulatorCallback callback,
void* context) {
furi_assert(mifare_fuzzer_emulator);
furi_assert(callback);
mifare_fuzzer_emulator->callback = callback;
mifare_fuzzer_emulator->context = context;
}
/// @brief mifare_fuzzer_emulator_draw_callback
/// @param canvas
/// @param _model
static void mifare_fuzzer_emulator_draw_callback(Canvas* canvas, void* _model) {
MifareFuzzerEmulatorModel* model = _model;
FuriString* furi_string = furi_string_alloc();
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
// Primary font
canvas_set_font(canvas, FontPrimary);
// Title
canvas_draw_str(canvas, 4, 11, model->title);
// Emulated UID
uint8_t cpos;
char uid[25];
char uid_char[3];
cpos = 0;
for(uint8_t i = 0; i < model->nfc_dev_data.uid_len; i++) {
if(i > 0) {
uid[cpos] = ':';
cpos++;
}
snprintf(uid_char, sizeof(uid_char), "%02X", model->nfc_dev_data.uid[i]);
uid[cpos] = uid_char[0];
cpos++;
uid[cpos] = uid_char[1];
cpos++;
}
uid[cpos] = 0x00;
canvas_draw_str_aligned(canvas, 128 / 2, 43, AlignCenter, AlignCenter, uid);
// Secondary font
canvas_set_font(canvas, FontSecondary);
// Card
canvas_draw_str(canvas, 4, 22, "c:");
canvas_draw_str(canvas, 15, 22, model->mifare_card_dsc);
// Timing
furi_string_printf(furi_string, "%d", model->ticks_between_cards);
canvas_draw_str(canvas, 90, 22, "t:");
canvas_draw_str(canvas, 100, 22, furi_string_get_cstr(furi_string));
// Attack
canvas_draw_str(canvas, 4, 33, "a:");
canvas_draw_str(canvas, 15, 33, model->attack_dsc);
if(!model->is_attacking) {
elements_button_left(canvas, "t-1");
elements_button_center(canvas, "Start");
elements_button_right(canvas, "t+1");
} else {
canvas_draw_line(canvas, 1, 49, (128 * model->tick_num / model->ticks_between_cards), 49);
elements_button_center(canvas, "Stop");
}
// Free temp string
furi_string_free(furi_string);
}
/// @brief mifare_fuzzer_emulator_input_callback
/// @param event
/// @param context
/// @return
static bool mifare_fuzzer_emulator_input_callback(InputEvent* event, void* context) {
//FURI_LOG_D(TAG, "mifare_fuzzer_emulator_input_callback()");
furi_assert(context);
MifareFuzzerEmulator* mifare_fuzzer_emulator = context;
bool consumed = false;
if(event->type == InputTypeShort) {
if(event->key == InputKeyRight) {
if(!mifare_fuzzer_emulator->is_attacking) {
mifare_fuzzer_emulator->callback(
MifareFuzzerEventIncrementTicks, mifare_fuzzer_emulator->context);
};
consumed = true;
} else if(event->key == InputKeyLeft) {
if(!mifare_fuzzer_emulator->is_attacking) {
mifare_fuzzer_emulator->callback(
MifareFuzzerEventDecrementTicks, mifare_fuzzer_emulator->context);
};
consumed = true;
} else if(event->key == InputKeyUp) {
consumed = true;
} else if(event->key == InputKeyDown) {
consumed = true;
} else if(event->key == InputKeyOk) {
// Toggle attack
if(mifare_fuzzer_emulator->is_attacking) {
mifare_fuzzer_emulator->is_attacking = false;
mifare_fuzzer_emulator->callback(
MifareFuzzerEventStopAttack, mifare_fuzzer_emulator->context);
} else {
mifare_fuzzer_emulator->is_attacking = true;
mifare_fuzzer_emulator->callback(
MifareFuzzerEventStartAttack, mifare_fuzzer_emulator->context);
}
with_view_model(
mifare_fuzzer_emulator->view,
MifareFuzzerEmulatorModel * model,
{ model->is_attacking = mifare_fuzzer_emulator->is_attacking; },
true);
consumed = true;
}
}
return consumed;
}
/// @brief mifare_fuzzer_emulator_enter_callback
/// @param context
static void mifare_fuzzer_emulator_enter_callback(void* context) {
//FURI_LOG_D(TAG, "mifare_fuzzer_emulator_enter_callback()");
furi_assert(context);
MifareFuzzerEmulator* mifare_fuzzer_emulator = context;
//UNUSED(mifare_fuzzer_emulator);
mifare_fuzzer_emulator->is_attacking = false;
with_view_model(
mifare_fuzzer_emulator->view,
MifareFuzzerEmulatorModel * model,
{ model->is_attacking = false; },
true);
}
/// @brief mifare_fuzzer_emulator_alloc
/// @return
MifareFuzzerEmulator* mifare_fuzzer_emulator_alloc() {
MifareFuzzerEmulator* mifare_fuzzer_emulator = malloc(sizeof(MifareFuzzerEmulator));
mifare_fuzzer_emulator->view = view_alloc();
view_set_context(mifare_fuzzer_emulator->view, mifare_fuzzer_emulator);
view_allocate_model(
mifare_fuzzer_emulator->view, ViewModelTypeLocking, sizeof(MifareFuzzerEmulatorModel));
view_set_draw_callback(mifare_fuzzer_emulator->view, mifare_fuzzer_emulator_draw_callback);
view_set_input_callback(mifare_fuzzer_emulator->view, mifare_fuzzer_emulator_input_callback);
view_set_enter_callback(mifare_fuzzer_emulator->view, mifare_fuzzer_emulator_enter_callback);
with_view_model(
mifare_fuzzer_emulator->view,
MifareFuzzerEmulatorModel * model,
{ model->title = "Mifare Fuzzer (emulator)"; },
true);
return mifare_fuzzer_emulator;
}
/// @brief mifare_fuzzer_emulator_free
/// @param context
void mifare_fuzzer_emulator_free(MifareFuzzerEmulator* context) {
//FURI_LOG_D(TAG, "mifare_fuzzer_emulator_free()");
furi_assert(context);
MifareFuzzerEmulator* mifare_fuzzer_emulator = context;
/*
with_view_model(
mifare_fuzzer_emulator->view,
MifareFuzzerEmulatorModel* model,
{
UNUSED(model);
},
true
);
*/
view_free(mifare_fuzzer_emulator->view);
free(mifare_fuzzer_emulator);
}
/// @brief mifare_fuzzer_emulator_get_view
/// @param mifare_fuzzer_emulator
/// @return
View* mifare_fuzzer_emulator_get_view(MifareFuzzerEmulator* mifare_fuzzer_emulator) {
furi_assert(mifare_fuzzer_emulator);
return mifare_fuzzer_emulator->view;
}
/// @brief Set card type
/// @param mifare_fuzzer_emulator
/// @param mifare_card
void mifare_fuzzer_emulator_set_card(
MifareFuzzerEmulator* mifare_fuzzer_emulator,
MifareCard mifare_card) {
furi_assert(mifare_fuzzer_emulator);
furi_assert(mifare_card);
with_view_model(
mifare_fuzzer_emulator->view,
MifareFuzzerEmulatorModel * model,
{
model->mifare_card = mifare_card;
switch(mifare_card) {
case MifareCardClassic1k:
model->mifare_card_dsc = "Classic 1k";
break;
case MifareCardClassic4k:
model->mifare_card_dsc = "Classic 4k";
break;
case MifareCardUltralight:
model->mifare_card_dsc = "Ultralight";
break;
}
},
true);
}
/// @brief Set attack type
/// @param mifare_fuzzer_emulator
/// @param mifare_attack
void mifare_fuzzer_emulator_set_attack(
MifareFuzzerEmulator* mifare_fuzzer_emulator,
MifareFuzzerAttack mifare_attack) {
furi_assert(mifare_fuzzer_emulator);
furi_assert(mifare_attack);
with_view_model(
mifare_fuzzer_emulator->view,
MifareFuzzerEmulatorModel * model,
{
model->attack = mifare_attack;
switch(mifare_attack) {
case MifareFuzzerAttackTestValues:
model->attack_dsc = "Test values";
break;
case MifareFuzzerAttackRandomValues:
model->attack_dsc = "Random values";
break;
case MifareFuzzerAttackLoadUidsFromFile:
model->attack_dsc = "Load Uids From File";
break;
}
},
true);
}
/// @brief mifare_fuzzer_emulator_set_nfc_dev_data
/// @param mifare_fuzzer_emulator
/// @param nfc_dev_data
void mifare_fuzzer_emulator_set_nfc_dev_data(
MifareFuzzerEmulator* mifare_fuzzer_emulator,
FuriHalNfcDevData nfc_dev_data) {
furi_assert(mifare_fuzzer_emulator);
with_view_model(
mifare_fuzzer_emulator->view,
MifareFuzzerEmulatorModel * model,
{ model->nfc_dev_data = nfc_dev_data; },
true);
}
/// @brief mifare_fuzzer_emulator_set_ticks_between_cards
/// @param mifare_fuzzer_emulator
/// @param ticks
void mifare_fuzzer_emulator_set_ticks_between_cards(
MifareFuzzerEmulator* mifare_fuzzer_emulator,
uint8_t ticks) {
furi_assert(mifare_fuzzer_emulator);
with_view_model(
mifare_fuzzer_emulator->view,
MifareFuzzerEmulatorModel * model,
{ model->ticks_between_cards = ticks; },
true);
}
/// @brief mifare_fuzzer_emulator_set_tick_num
/// @param mifare_fuzzer_emulator
/// @param tick_num
void mifare_fuzzer_emulator_set_tick_num(
MifareFuzzerEmulator* mifare_fuzzer_emulator,
uint8_t tick_num) {
furi_assert(mifare_fuzzer_emulator);
with_view_model(
mifare_fuzzer_emulator->view,
MifareFuzzerEmulatorModel * model,
{ model->tick_num = tick_num; },
true);
}
@@ -0,0 +1,70 @@
#pragma once
#include "../mifare_fuzzer_custom_events.h"
#include <furi.h>
#include <furi_hal.h>
#include <gui/view.h>
#include <gui/elements.h>
typedef void (*MifareFuzzerEmulatorCallback)(MifareFuzzerEvent event, void* context);
typedef enum MifareCard {
MifareCardClassic1k = 1,
MifareCardClassic4k,
MifareCardUltralight,
} MifareCard;
typedef enum MifareFuzzerAttack {
MifareFuzzerAttackTestValues = 1,
MifareFuzzerAttackRandomValues,
MifareFuzzerAttackLoadUidsFromFile,
} MifareFuzzerAttack;
typedef struct MifareFuzzerEmulator {
View* view;
MifareFuzzerEmulatorCallback callback;
void* context;
bool is_attacking;
uint8_t ticks_between_cards;
} MifareFuzzerEmulator;
typedef struct MifareFuzzerEmulatorModel {
const char* title;
MifareCard mifare_card;
const char* mifare_card_dsc;
MifareFuzzerAttack attack;
const char* attack_dsc;
FuriHalNfcDevData nfc_dev_data;
bool is_attacking;
uint8_t tick_num;
uint8_t ticks_between_cards;
} MifareFuzzerEmulatorModel;
MifareFuzzerEmulator* mifare_fuzzer_emulator_alloc();
void mifare_fuzzer_emulator_free(MifareFuzzerEmulator* context);
View* mifare_fuzzer_emulator_get_view(MifareFuzzerEmulator* context);
void mifare_fuzzer_emulator_set_card(
MifareFuzzerEmulator* mifare_fuzzer_emulator,
MifareCard mifare_card);
void mifare_fuzzer_emulator_set_attack(
MifareFuzzerEmulator* mifare_fuzzer_emulator,
MifareFuzzerAttack mifare_attack);
void mifare_fuzzer_emulator_set_callback(
MifareFuzzerEmulator* mifare_fuzzer_emulator,
MifareFuzzerEmulatorCallback callback,
void* context);
void mifare_fuzzer_emulator_set_nfc_dev_data(
MifareFuzzerEmulator* mifare_fuzzer_emulator,
FuriHalNfcDevData nfc_dev_data);
void mifare_fuzzer_emulator_set_ticks_between_cards(
MifareFuzzerEmulator* mifare_fuzzer_emulator,
uint8_t ticks);
void mifare_fuzzer_emulator_set_tick_num(
MifareFuzzerEmulator* mifare_fuzzer_emulator,
uint8_t tick_num);