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

Merge branch 'dev' into fix/subghz-notifies

This commit is contained in:
MX
2023-06-09 19:00:36 +03:00
268 changed files with 6308 additions and 5412 deletions

View File

@@ -120,6 +120,13 @@ Min level: 2
Max level: 2
Weight: 3
Name: L2_Dj_128x64
Min butthurt: 0
Max butthurt: 8
Min level: 2
Max level: 3
Weight: 4
Name: L3_Furippa3_128x64
Min butthurt: 0
Max butthurt: 6

View File

@@ -1,8 +1,8 @@
diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c
index f91a73f32..b559a79ad 100644
index 2f947fe..03c4c76 100644
--- a/applications/services/notification/notification_app.c
+++ b/applications/services/notification/notification_app.c
@@ -6,6 +6,7 @@
@@ -9,6 +9,7 @@
#include "notification.h"
#include "notification_messages.h"
#include "notification_app.h"
@@ -10,7 +10,7 @@ index f91a73f32..b559a79ad 100644
#define TAG "NotificationSrv"
@@ -564,6 +565,7 @@ int32_t notification_srv(void* p) {
@@ -579,6 +580,7 @@ int32_t notification_srv(void* p) {
break;
case SaveSettingsMessage:
notification_save_settings(app);
@@ -19,7 +19,7 @@ index f91a73f32..b559a79ad 100644
}
diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c
index f5d7a82ca..930c0bd1f 100644
index 565d4f1..bae9299 100644
--- a/applications/settings/notification_settings/notification_settings_app.c
+++ b/applications/settings/notification_settings/notification_settings_app.c
@@ -3,6 +3,7 @@
@@ -30,15 +30,7 @@ index f5d7a82ca..930c0bd1f 100644
#define MAX_NOTIFICATION_SETTINGS 4
@@ -73,7 +74,6 @@ const bool vibro_value[VIBRO_COUNT] = {false, true};
static void backlight_changed(VariableItem* item) {
NotificationAppSettings* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
-
variable_item_set_current_value_text(item, backlight_text[index]);
app->notification->settings.display_brightness = backlight_value[index];
notification_message(app->notification, &sequence_display_backlight_on);
@@ -125,6 +125,14 @@ static void vibro_changed(VariableItem* item) {
@@ -162,6 +163,14 @@ static void vibro_changed(VariableItem* item) {
notification_message(app->notification, &sequence_single_vibro);
}
@@ -53,8 +45,8 @@ index f5d7a82ca..930c0bd1f 100644
static uint32_t notification_app_settings_exit(void* context) {
UNUSED(context);
return VIEW_NONE;
@@ -143,7 +151,13 @@ static NotificationAppSettings* alloc_settings() {
uint8_t value_index;
@@ -187,7 +196,13 @@ static NotificationAppSettings* alloc_settings() {
variable_item_set_current_value_text(item, contrast_text[value_index]);
item = variable_item_list_add(
- app->variable_item_list, "LCD Backlight", BACKLIGHT_COUNT, backlight_changed, app);
@@ -68,17 +60,9 @@ index f5d7a82ca..930c0bd1f 100644
value_index = value_index_float(
app->notification->settings.display_brightness, backlight_value, BACKLIGHT_COUNT);
variable_item_set_current_value_index(item, value_index);
@@ -215,6 +229,7 @@ int32_t notification_settings_app(void* p) {
NotificationAppSettings* app = alloc_settings();
view_dispatcher_run(app->view_dispatcher);
notification_message_save_settings(app->notification);
+
free_settings(app);
return 0;
}
diff --git a/applications/settings/notification_settings/rgb_backlight.c b/applications/settings/notification_settings/rgb_backlight.c
new file mode 100644
index 000000000..269b544ae
index 0000000..269b544
--- /dev/null
+++ b/applications/settings/notification_settings/rgb_backlight.c
@@ -0,0 +1,171 @@
@@ -255,7 +239,7 @@ index 000000000..269b544ae
+}
diff --git a/applications/settings/notification_settings/rgb_backlight.h b/applications/settings/notification_settings/rgb_backlight.h
new file mode 100644
index 000000000..b63d223e6
index 0000000..b63d223
--- /dev/null
+++ b/applications/settings/notification_settings/rgb_backlight.h
@@ -0,0 +1,79 @@
@@ -340,7 +324,7 @@ index 000000000..b63d223e6
+const char* rgb_backlight_get_color_text(uint8_t index);
\ No newline at end of file
diff --git a/firmware/targets/f7/furi_hal/furi_hal_light.c b/firmware/targets/f7/furi_hal/furi_hal_light.c
index 83e1603b7..cad5b86cb 100644
index 83e1603..cad5b86 100644
--- a/firmware/targets/f7/furi_hal/furi_hal_light.c
+++ b/firmware/targets/f7/furi_hal/furi_hal_light.c
@@ -3,6 +3,7 @@
@@ -389,7 +373,7 @@ index 83e1603b7..cad5b86cb 100644
void furi_hal_light_blink_start(Light light, uint8_t brightness, uint16_t on_time, uint16_t period) {
diff --git a/lib/drivers/SK6805.c b/lib/drivers/SK6805.c
new file mode 100644
index 000000000..572e1df97
index 0000000..572e1df
--- /dev/null
+++ b/lib/drivers/SK6805.c
@@ -0,0 +1,101 @@
@@ -496,7 +480,7 @@ index 000000000..572e1df97
+}
diff --git a/lib/drivers/SK6805.h b/lib/drivers/SK6805.h
new file mode 100644
index 000000000..7c58956fa
index 0000000..7c58956
--- /dev/null
+++ b/lib/drivers/SK6805.h
@@ -0,0 +1,51 @@
@@ -552,5 +536,3 @@ index 000000000..7c58956fa
+
+#endif /* SK6805_H_ */
\ No newline at end of file
\ No newline at end of file

View File

@@ -96,7 +96,7 @@ Encoders or sending made by @Eng1n33r(first implementation in Q2 2022) & @xMaste
- CAME Atomo -> Update! check out new [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
- Nice Flor S -> How to create new remote - [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
- FAAC SLH (Spa) [External seed calculation required (For info contact me in Discord: Nano#8998)]
- Keeloq: BFT Mitto [External seed calculation required (For info contact me in Discord: Nano#8998)] -> Update! check out new [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
- Keeloq: BFT Mitto -> Update! check out new [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
- Star Line
- Security+ v1 & v2 (encoders was made in OFW)
@@ -134,7 +134,8 @@ You can support us by using links or addresses below:
### Community apps included:
- **RFID Fuzzer** [(by Ganapati & @xMasterX)](https://github.com/DarkFlippers/unleashed-firmware/pull/54) & New protocols by @mvanzanten
- **RFID Fuzzer** [(by @gid9798)](https://github.com/DarkFlippers/unleashed-firmware/pull/507) (original by Ganapati & xMasterX)
- **iButton Fuzzer** [(by @gid9798)](https://github.com/DarkFlippers/unleashed-firmware/pull/507) (original by xMasterX)
- **Sub-GHz bruteforcer** [(by @derskythe & xMasterX)](https://github.com/derskythe/flipperzero-subbrute) [(original by Ganapati & xMasterX)](https://github.com/DarkFlippers/unleashed-firmware/pull/57)
- **Sub-GHz playlist** [(by darmiel)](https://github.com/DarkFlippers/unleashed-firmware/pull/62)
- ESP8266 Deauther plugin [(by SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-Wifi-ESP8266-Deauther-Module)
@@ -157,7 +158,6 @@ You can support us by using links or addresses below:
- Morse Code [(by wh00hw)](https://github.com/wh00hw/MorseCodeFAP)
- **Unitemp - Temperature sensors reader** (DHT11/22, DS18B20, BMP280, HTU21x and more) [(by quen0n)](https://github.com/quen0n/unitemp-flipperzero)
- BH1750 - Lightmeter [(by oleksiikutuzov)](https://github.com/oleksiikutuzov/flipperzero-lightmeter)
- **iButton Fuzzer** [(by xMasterX)](https://github.com/xMasterX/ibutton-fuzzer)
- HEX Viewer [(by QtRoS)](https://github.com/QtRoS/flipper-zero-hex-viewer)
- POCSAG Pager [(by xMasterX & Shmuma)](https://github.com/xMasterX/flipper-pager)
- Text Viewer [(by kowalski7cc & kyhwana)](https://github.com/kowalski7cc/flipper-zero-text-viewer/tree/refactor-text-app)

View File

@@ -171,7 +171,7 @@ distenv.Depends(firmware_env["FW_RESOURCES"], external_apps_artifacts.resources_
fap_deploy = distenv.PhonyTarget(
"fap_deploy",
"${PYTHON3} ${ROOT_DIR}/scripts/storage.py send ${SOURCE} /ext/apps",
"${PYTHON3} ${FBT_SCRIPT_DIR}/storage.py -p ${FLIP_PORT} send ${SOURCE} /ext/apps",
source=Dir("#/assets/resources/apps"),
)
@@ -323,7 +323,9 @@ distenv.PhonyTarget(
)
# Start Flipper CLI via PySerial's miniterm
distenv.PhonyTarget("cli", "${PYTHON3} ${FBT_SCRIPT_DIR}/serial_cli.py")
distenv.PhonyTarget(
"cli", "${PYTHON3} ${FBT_SCRIPT_DIR}/serial_cli.py -p ${FLIP_PORT}"
)
# Find blackmagic probe

View File

@@ -399,7 +399,7 @@ int32_t arkanoid_game_app(void* p) {
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
// Call dolphin deed on game start
DOLPHIN_DEED(DolphinDeedPluginGameStart);
dolphin_deed(DolphinDeedPluginGameStart);
GameEvent event;
for(bool processing = true; processing;) {

View File

@@ -276,7 +276,7 @@ void dealer_tick(GameState* game_state) {
if(dealer_score >= DEALER_MAX) {
if(dealer_score > 21 || dealer_score < player_score) {
DOLPHIN_DEED(DolphinDeedPluginGameWin);
dolphin_deed(DolphinDeedPluginGameWin);
enqueue(
&(game_state->queue_state),
game_state,
@@ -571,7 +571,7 @@ int32_t blackjack_app(void* p) {
AppEvent event;
// Call dolphin deed on game start
DOLPHIN_DEED(DolphinDeedPluginGameStart);
dolphin_deed(DolphinDeedPluginGameStart);
for(bool processing = true; processing;) {
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);

View File

@@ -383,7 +383,7 @@ int32_t bomberduck_app(void* p) {
return 255;
}
DOLPHIN_DEED(DolphinDeedPluginGameStart);
dolphin_deed(DolphinDeedPluginGameStart);
// Создаем новый view port
ViewPort* view_port = view_port_alloc();
// Создаем callback отрисовки, без контекста
@@ -458,7 +458,7 @@ int32_t bomberduck_app(void* p) {
world.running = 0;
world.level += 1;
if(world.level % 5 == 0) {
DOLPHIN_DEED(DolphinDeedPluginGameWin);
dolphin_deed(DolphinDeedPluginGameWin);
}
}
for(int i = 0; i < world.bombs_count; i++) {

View File

@@ -991,7 +991,7 @@ int32_t doom_app() {
music_player_worker_start(plugin_state->music_instance->worker);
#endif
// Call dolphin deed on game start
DOLPHIN_DEED(DolphinDeedPluginGameStart);
dolphin_deed(DolphinDeedPluginGameStart);
for(bool processing = true; processing;) {
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);

View File

@@ -309,7 +309,7 @@ int32_t flappy_game_app(void* p) {
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
// Call dolphin deed on game start
DOLPHIN_DEED(DolphinDeedPluginGameStart);
dolphin_deed(DolphinDeedPluginGameStart);
GameEvent event;
for(bool processing = true; processing;) {

View File

@@ -1,8 +0,0 @@
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* @G4N4P4T1 wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return.
* ----------------------------------------------------------------------------
*/

View File

@@ -1,36 +0,0 @@
# Flipfrid
Basic LFRFID Fuzzer.
## Why
Flipfrid is a simple Rfid fuzzer using lfrfid protocols (125khz).
Objective is to provide a simple to use fuzzer to test readers by emulating various cards.
- EM4100 cards use a 1 byte customer id and 4 bytes card id.
- HIDProx cards use a 2 byte customer id and 3 byte card id.
## How
1) Select the Protocol with the left and right arrows
2) Select the Mode with the up and down arrows
3) Set TD (Time delay) between ID switch if you need, or left it as is
4) Click Start
### Info
There are 4 Protocols:
- EM4100
- HIDProx
- PAC/Stanley
- H10301
There are 4 modes:
- Default Values: Try factory/default keys and emulate one after the other.
- BF customer id: An iteration from 0X00 to 0XFF on the first byte.
- Load Dump file: Load an existing dump (.rfid) generated by Flipperzero, select an index and bruteforce from 0X00 to 0XFF;
- Uids list: Iterate over an input text file (one uid per line) and emulate one after the other.
TODO :
- Add second byte test to `BF customer id`

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -464,7 +464,7 @@ int32_t game15_app() {
FPS, (SandboxRenderCallback)render_callback, (SandboxEventHandler)game_event_handler);
// Call dolphin deed on game start
DOLPHIN_DEED(DolphinDeedPluginGameStart);
dolphin_deed(DolphinDeedPluginGameStart);
sandbox_loop();
sandbox_free();

View File

@@ -401,7 +401,7 @@ int32_t game_2048_app() {
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
// Call dolphin deed on game start
DOLPHIN_DEED(DolphinDeedPluginGameStart);
dolphin_deed(DolphinDeedPluginGameStart);
bool is_finished = false;
while(!is_finished) {

View File

@@ -535,7 +535,7 @@ int32_t heap_defence_app(void* p) {
game->animation = AnimationPause;
// Call dolphin deed on game start
DOLPHIN_DEED(DolphinDeedPluginGameStart);
dolphin_deed(DolphinDeedPluginGameStart);
GameEvent event = {0};
while(event.input.key != InputKeyBack) {

View File

@@ -414,7 +414,7 @@ int32_t hid_usb_app(void* p) {
bt_hid_connection_status_changed_callback(BtStatusConnected, app);
DOLPHIN_DEED(DolphinDeedPluginStart);
dolphin_deed(DolphinDeedPluginStart);
view_dispatcher_run(app->view_dispatcher);
@@ -454,7 +454,7 @@ int32_t hid_ble_app(void* p) {
furi_hal_bt_start_advertising();
bt_set_status_changed_callback(app->bt, bt_hid_connection_status_changed_callback, app);
DOLPHIN_DEED(DolphinDeedPluginStart);
dolphin_deed(DolphinDeedPluginStart);
view_dispatcher_run(app->view_dispatcher);

View File

@@ -1,8 +0,0 @@
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* @xMasterX and @G4N4P4T1(made original version) wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return.
* ----------------------------------------------------------------------------
*/

View File

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

View File

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

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1112,7 +1112,7 @@ void mfkey32(ProgramState* program_state) {
}
if(keyarray_size > 0) {
// TODO: Should we use DolphinDeedNfcMfcAdd?
DOLPHIN_DEED(DolphinDeedNfcMfcAdd);
dolphin_deed(DolphinDeedNfcMfcAdd);
}
napi_mf_classic_nonce_array_free(nonce_arr);
napi_mf_classic_dict_free(user_dict);

View File

@@ -240,7 +240,7 @@ static bool game_won(Minesweeper* minesweeper_state) {
dialog_message_set_buttons(message, NULL, "Play again", NULL);
// Call dolphin deed when we win the game
DOLPHIN_DEED(DolphinDeedPluginGameWin);
dolphin_deed(DolphinDeedPluginGameWin);
DialogMessageButton choice = dialog_message_show(minesweeper_state->dialogs, message);
dialog_message_free(message);
@@ -397,7 +397,7 @@ int32_t minesweeper_app(void* p) {
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
// Call dolphin deed on game start
DOLPHIN_DEED(DolphinDeedPluginGameStart);
dolphin_deed(DolphinDeedPluginGameStart);
PluginEvent event;
for(bool processing = true; processing;) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

Before

Width:  |  Height:  |  Size: 308 B

After

Width:  |  Height:  |  Size: 308 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 304 B

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,29 @@
#pragma once
#include <gui/scene_manager.h>
// Generate scene id and total number
#define ADD_SCENE(prefix, name, id) FuzzerScene##id,
typedef enum {
#include "fuzzer_scene_config.h"
FuzzerSceneNum,
} FuzzerScene;
#undef ADD_SCENE
extern const SceneManagerHandlers fuzzer_scene_handlers;
// Generate scene on_enter handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
#include "fuzzer_scene_config.h"
#undef ADD_SCENE
// Generate scene on_event handlers declaration
#define ADD_SCENE(prefix, name, id) \
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
#include "fuzzer_scene_config.h"
#undef ADD_SCENE
// Generate scene on_exit handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
#include "fuzzer_scene_config.h"
#undef ADD_SCENE

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -19,7 +19,7 @@ void picopass_scene_device_info_on_enter(void* context) {
FuriString* wiegand_str = furi_string_alloc();
FuriString* sio_str = furi_string_alloc();
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
dolphin_deed(DolphinDeedNfcReadSuccess);
// Setup view
PicopassBlock* AA1 = picopass->dev->dev_data.AA1;

View File

@@ -10,7 +10,7 @@ void picopass_read_card_worker_callback(PicopassWorkerEvent event, void* context
void picopass_scene_read_card_on_enter(void* context) {
Picopass* picopass = context;
DOLPHIN_DEED(DolphinDeedNfcRead);
dolphin_deed(DolphinDeedNfcRead);
// Setup view
Popup* popup = picopass->popup;

View File

@@ -21,7 +21,7 @@ void picopass_scene_read_card_success_on_enter(void* context) {
FuriString* wiegand_str = furi_string_alloc();
FuriString* sio_str = furi_string_alloc();
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
dolphin_deed(DolphinDeedNfcReadSuccess);
// Send notification
notification_message(picopass->notifications, &sequence_success);

View File

@@ -19,7 +19,7 @@ void picopass_scene_read_factory_success_on_enter(void* context) {
FuriString* title = furi_string_alloc_set("Factory Default");
FuriString* subtitle = furi_string_alloc_set("");
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
dolphin_deed(DolphinDeedNfcReadSuccess);
// Send notification
notification_message(picopass->notifications, &sequence_success);

View File

@@ -8,7 +8,7 @@ void picopass_scene_save_success_popup_callback(void* context) {
void picopass_scene_save_success_on_enter(void* context) {
Picopass* picopass = context;
DOLPHIN_DEED(DolphinDeedNfcSave);
dolphin_deed(DolphinDeedNfcSave);
// Setup view
Popup* popup = picopass->popup;

View File

@@ -9,7 +9,7 @@ void picopass_write_card_worker_callback(PicopassWorkerEvent event, void* contex
void picopass_scene_write_card_on_enter(void* context) {
Picopass* picopass = context;
DOLPHIN_DEED(DolphinDeedNfcSave);
dolphin_deed(DolphinDeedNfcSave);
// Setup view
Popup* popup = picopass->popup;

View File

@@ -18,7 +18,7 @@ void picopass_scene_write_card_success_on_enter(void* context) {
Widget* widget = picopass->widget;
FuriString* str = furi_string_alloc_set("Write Success!");
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
dolphin_deed(DolphinDeedNfcReadSuccess);
// Send notification
notification_message(picopass->notifications, &sequence_success);

View File

@@ -9,7 +9,7 @@ void picopass_write_key_worker_callback(PicopassWorkerEvent event, void* context
void picopass_scene_write_key_on_enter(void* context) {
Picopass* picopass = context;
DOLPHIN_DEED(DolphinDeedNfcSave);
dolphin_deed(DolphinDeedNfcSave);
// Setup view
Popup* popup = picopass->popup;

View File

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

View File

@@ -344,7 +344,7 @@ int32_t snake_game_app(void* p) {
notification_message_block(notification, &sequence_display_backlight_enforce_on);
DOLPHIN_DEED(DolphinDeedPluginGameStart);
dolphin_deed(DolphinDeedPluginGameStart);
SnakeEvent event;
for(bool processing = true; processing;) {

View File

@@ -276,7 +276,7 @@ void tick(GameState* game_state, NotificationApp* notification) {
if(game_state->state == GameStatePlay) {
if(game_state->top_cards[0].character == 11 && game_state->top_cards[1].character == 11 &&
game_state->top_cards[2].character == 11 && game_state->top_cards[3].character == 11) {
DOLPHIN_DEED(DolphinDeedPluginGameWin);
dolphin_deed(DolphinDeedPluginGameWin);
game_state->state = GameStateAnimate;
return;
}
@@ -492,7 +492,7 @@ int32_t solitaire_app(void* p) {
AppEvent event;
// Call Dolphin deed on game start
DOLPHIN_DEED(DolphinDeedPluginGameStart);
dolphin_deed(DolphinDeedPluginGameStart);
for(bool processing = true; processing;) {
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 150);

View File

@@ -3130,7 +3130,7 @@ int32_t swd_probe_app_main(void* p) {
DBGS("swd_execute_script");
swd_execute_script(app, ANY_PATH("swd_scripts/startup.swd"));
DOLPHIN_DEED(DolphinDeedPluginGameStart);
dolphin_deed(DolphinDeedPluginGameStart);
DBGS("processing");
for(bool processing = true; processing;) {

View File

@@ -389,7 +389,7 @@ int32_t tetris_game_app() {
uint8_t downRepeatCounter = 0;
// Call dolphin deed on game start
DOLPHIN_DEED(DolphinDeedPluginGameStart);
dolphin_deed(DolphinDeedPluginGameStart);
for(bool processing = true; processing;) {
// This 10U implicitly sets the game loop speed. downRepeatCounter relies on this value

View File

@@ -333,7 +333,7 @@ int32_t tictactoe_game_app(void* p) {
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
// Call dolphin deed on game start
DOLPHIN_DEED(DolphinDeedPluginGameStart);
dolphin_deed(DolphinDeedPluginGameStart);
GameEvent event;
for(bool processing = true; processing;) {

View File

@@ -173,7 +173,7 @@ int32_t totp_app() {
}
// Affecting dolphin level
DOLPHIN_DEED(DolphinDeedPluginStart);
dolphin_deed(DolphinDeedPluginStart);
// Set system callbacks
ViewPort* view_port = view_port_alloc();

View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 B

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,365 @@
#include "oregon3.h"
#include <lib/subghz/blocks/const.h>
#include <lib/subghz/blocks/decoder.h>
#include <lib/subghz/blocks/encoder.h>
#include <lib/subghz/blocks/math.h>
#include "ws_generic.h"
#include <lib/toolbox/manchester_decoder.h>
#include <lib/flipper_format/flipper_format_i.h>
#define TAG "WSProtocolOregon3"
static const SubGhzBlockConst ws_oregon3_const = {
.te_long = 1100,
.te_short = 500,
.te_delta = 300,
.min_count_bit_for_found = 32,
};
#define OREGON3_PREAMBLE_BITS 28
#define OREGON3_PREAMBLE_MASK 0b1111111111111111111111111111
// 24 ones + 0101 (inverted A)
#define OREGON3_PREAMBLE 0b1111111111111111111111110101
// Fixed part contains:
// - Sensor type: 16 bits
// - Channel: 4 bits
// - ID (changes when batteries are changed): 8 bits
// - Battery status: 4 bits
#define OREGON3_FIXED_PART_BITS (16 + 4 + 8 + 4)
#define OREGON3_SENSOR_ID(d) (((d) >> 16) & 0xFFFF)
#define OREGON3_CHECKSUM_BITS 8
// bit indicating the low battery
#define OREGON3_FLAG_BAT_LOW 0x4
/// Documentation for Oregon Scientific protocols can be found here:
/// https://www.osengr.org/Articles/OS-RF-Protocols-IV.pdf
// Sensors ID
#define ID_THGR221 0xf824
struct WSProtocolDecoderOregon3 {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
WSBlockGeneric generic;
ManchesterState manchester_state;
bool prev_bit;
uint8_t var_bits;
uint64_t var_data;
};
typedef struct WSProtocolDecoderOregon3 WSProtocolDecoderOregon3;
typedef enum {
Oregon3DecoderStepReset = 0,
Oregon3DecoderStepFoundPreamble,
Oregon3DecoderStepVarData,
} Oregon3DecoderStep;
void* ws_protocol_decoder_oregon3_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
WSProtocolDecoderOregon3* instance = malloc(sizeof(WSProtocolDecoderOregon3));
instance->base.protocol = &ws_protocol_oregon3;
instance->generic.protocol_name = instance->base.protocol->name;
instance->generic.humidity = WS_NO_HUMIDITY;
instance->generic.temp = WS_NO_TEMPERATURE;
instance->generic.btn = WS_NO_BTN;
instance->generic.channel = WS_NO_CHANNEL;
instance->generic.battery_low = WS_NO_BATT;
instance->generic.id = WS_NO_ID;
instance->prev_bit = false;
return instance;
}
void ws_protocol_decoder_oregon3_free(void* context) {
furi_assert(context);
WSProtocolDecoderOregon3* instance = context;
free(instance);
}
void ws_protocol_decoder_oregon3_reset(void* context) {
furi_assert(context);
WSProtocolDecoderOregon3* instance = context;
instance->decoder.parser_step = Oregon3DecoderStepReset;
instance->decoder.decode_data = 0UL;
instance->decoder.decode_count_bit = 0;
manchester_advance(
instance->manchester_state, ManchesterEventReset, &instance->manchester_state, NULL);
instance->prev_bit = false;
instance->var_data = 0;
instance->var_bits = 0;
}
static ManchesterEvent level_and_duration_to_event(bool level, uint32_t duration) {
bool is_long = false;
if(DURATION_DIFF(duration, ws_oregon3_const.te_long) < ws_oregon3_const.te_delta) {
is_long = true;
} else if(DURATION_DIFF(duration, ws_oregon3_const.te_short) < ws_oregon3_const.te_delta) {
is_long = false;
} else {
return ManchesterEventReset;
}
if(level)
return is_long ? ManchesterEventLongHigh : ManchesterEventShortHigh;
else
return is_long ? ManchesterEventLongLow : ManchesterEventShortLow;
}
// From sensor id code return amount of bits in variable section
// https://temofeev.ru/info/articles/o-dekodirovanii-protokola-pogodnykh-datchikov-oregon-scientific
static uint8_t oregon3_sensor_id_var_bits(uint16_t sensor_id) {
switch(sensor_id) {
case ID_THGR221:
default:
// nibbles: temp + hum + '0'
return (4 + 2 + 1) * 4;
}
}
static void ws_oregon3_decode_const_data(WSBlockGeneric* ws_block) {
ws_block->id = OREGON3_SENSOR_ID(ws_block->data);
ws_block->channel = (ws_block->data >> 12) & 0xF;
ws_block->battery_low = (ws_block->data & OREGON3_FLAG_BAT_LOW) ? 1 : 0;
}
static uint16_t ws_oregon3_bcd_decode_short(uint32_t data) {
return (data & 0xF) * 10 + ((data >> 4) & 0xF);
}
static float ws_oregon3_decode_temp(uint32_t data) {
int32_t temp_val;
temp_val = ws_oregon3_bcd_decode_short(data >> 4);
temp_val *= 10;
temp_val += (data >> 12) & 0xF;
if(data & 0xF) temp_val = -temp_val;
return (float)temp_val / 10.0;
}
static void ws_oregon3_decode_var_data(WSBlockGeneric* ws_b, uint16_t sensor_id, uint32_t data) {
switch(sensor_id) {
case ID_THGR221:
default:
ws_b->humidity = ws_oregon3_bcd_decode_short(data >> 4);
ws_b->temp = ws_oregon3_decode_temp(data >> 12);
break;
}
}
void ws_protocol_decoder_oregon3_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
WSProtocolDecoderOregon3* instance = context;
// Oregon v3.0 protocol is inverted
ManchesterEvent event = level_and_duration_to_event(!level, duration);
// low-level bit sequence decoding
if(event == ManchesterEventReset) {
instance->decoder.parser_step = Oregon3DecoderStepReset;
instance->prev_bit = false;
instance->decoder.decode_data = 0UL;
instance->decoder.decode_count_bit = 0;
}
if(manchester_advance(
instance->manchester_state, event, &instance->manchester_state, &instance->prev_bit)) {
subghz_protocol_blocks_add_bit(&instance->decoder, instance->prev_bit);
}
switch(instance->decoder.parser_step) {
case Oregon3DecoderStepReset:
// waiting for fixed oregon3 preamble
if(instance->decoder.decode_count_bit >= OREGON3_PREAMBLE_BITS &&
((instance->decoder.decode_data & OREGON3_PREAMBLE_MASK) == OREGON3_PREAMBLE)) {
instance->decoder.parser_step = Oregon3DecoderStepFoundPreamble;
instance->decoder.decode_count_bit = 0;
instance->decoder.decode_data = 0UL;
}
break;
case Oregon3DecoderStepFoundPreamble:
// waiting for fixed oregon3 data
if(instance->decoder.decode_count_bit == OREGON3_FIXED_PART_BITS) {
instance->generic.data = instance->decoder.decode_data;
instance->generic.data_count_bit = instance->decoder.decode_count_bit;
instance->decoder.decode_data = 0UL;
instance->decoder.decode_count_bit = 0;
// reverse nibbles in decoded data as oregon v3.0 is LSB first
instance->generic.data = (instance->generic.data & 0x55555555) << 1 |
(instance->generic.data & 0xAAAAAAAA) >> 1;
instance->generic.data = (instance->generic.data & 0x33333333) << 2 |
(instance->generic.data & 0xCCCCCCCC) >> 2;
ws_oregon3_decode_const_data(&instance->generic);
instance->var_bits =
oregon3_sensor_id_var_bits(OREGON3_SENSOR_ID(instance->generic.data));
if(!instance->var_bits) {
// sensor is not supported, stop decoding, but showing the decoded fixed part
instance->decoder.parser_step = Oregon3DecoderStepReset;
if(instance->base.callback)
instance->base.callback(&instance->base, instance->base.context);
} else {
instance->decoder.parser_step = Oregon3DecoderStepVarData;
}
}
break;
case Oregon3DecoderStepVarData:
// waiting for variable (sensor-specific data)
if(instance->decoder.decode_count_bit == instance->var_bits + OREGON3_CHECKSUM_BITS) {
instance->var_data = instance->decoder.decode_data & 0xFFFFFFFFFFFFFFFF;
// reverse nibbles in var data
instance->var_data = (instance->var_data & 0x5555555555555555) << 1 |
(instance->var_data & 0xAAAAAAAAAAAAAAAA) >> 1;
instance->var_data = (instance->var_data & 0x3333333333333333) << 2 |
(instance->var_data & 0xCCCCCCCCCCCCCCCC) >> 2;
ws_oregon3_decode_var_data(
&instance->generic,
OREGON3_SENSOR_ID(instance->generic.data),
instance->var_data >> OREGON3_CHECKSUM_BITS);
instance->decoder.parser_step = Oregon3DecoderStepReset;
if(instance->base.callback)
instance->base.callback(&instance->base, instance->base.context);
}
break;
}
}
uint8_t ws_protocol_decoder_oregon3_get_hash_data(void* context) {
furi_assert(context);
WSProtocolDecoderOregon3* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
SubGhzProtocolStatus ws_protocol_decoder_oregon3_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) {
furi_assert(context);
WSProtocolDecoderOregon3* instance = context;
SubGhzProtocolStatus ret = SubGhzProtocolStatusError;
ret = ws_block_generic_serialize(&instance->generic, flipper_format, preset);
if(ret != SubGhzProtocolStatusOk) return ret;
uint32_t temp = instance->var_bits;
if(!flipper_format_write_uint32(flipper_format, "VarBits", &temp, 1)) {
FURI_LOG_E(TAG, "Error adding VarBits");
return SubGhzProtocolStatusErrorParserOthers;
}
if(!flipper_format_write_hex(
flipper_format,
"VarData",
(const uint8_t*)&instance->var_data,
sizeof(instance->var_data))) {
FURI_LOG_E(TAG, "Error adding VarData");
return SubGhzProtocolStatusErrorParserOthers;
}
return ret;
}
SubGhzProtocolStatus
ws_protocol_decoder_oregon3_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
WSProtocolDecoderOregon3* instance = context;
uint32_t temp_data;
SubGhzProtocolStatus ret = SubGhzProtocolStatusError;
do {
ret = ws_block_generic_deserialize(&instance->generic, flipper_format);
if(ret != SubGhzProtocolStatusOk) {
break;
}
if(!flipper_format_read_uint32(flipper_format, "VarBits", &temp_data, 1)) {
FURI_LOG_E(TAG, "Missing VarLen");
ret = SubGhzProtocolStatusErrorParserOthers;
break;
}
instance->var_bits = (uint8_t)temp_data;
if(!flipper_format_read_hex(
flipper_format,
"VarData",
(uint8_t*)&instance->var_data,
sizeof(instance->var_data))) { //-V1051
FURI_LOG_E(TAG, "Missing VarData");
ret = SubGhzProtocolStatusErrorParserOthers;
break;
}
if(instance->generic.data_count_bit != ws_oregon3_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key: %d", instance->generic.data_count_bit);
ret = SubGhzProtocolStatusErrorValueBitCount;
break;
}
} while(false);
return ret;
}
static void oregon3_append_check_sum(uint32_t fix_data, uint64_t var_data, FuriString* output) {
uint8_t sum = fix_data & 0xF;
uint8_t ref_sum = var_data & 0xFF;
var_data >>= 4;
for(uint8_t i = 1; i < 8; i++) {
fix_data >>= 4;
var_data >>= 4;
sum += (fix_data & 0xF) + (var_data & 0xF);
}
// swap calculated sum nibbles
sum = (((sum >> 4) & 0xF) | (sum << 4)) & 0xFF;
if(sum == ref_sum)
furi_string_cat_printf(output, "Sum ok: 0x%hhX", ref_sum);
else
furi_string_cat_printf(output, "Sum err: 0x%hhX vs 0x%hhX", ref_sum, sum);
}
void ws_protocol_decoder_oregon3_get_string(void* context, FuriString* output) {
furi_assert(context);
WSProtocolDecoderOregon3* instance = context;
furi_string_cat_printf(
output,
"%s\r\n"
"ID: 0x%04lX, ch: %d, bat: %d, rc: 0x%02lX\r\n",
instance->generic.protocol_name,
instance->generic.id,
instance->generic.channel,
instance->generic.battery_low,
(uint32_t)(instance->generic.data >> 4) & 0xFF);
if(instance->var_bits > 0) {
furi_string_cat_printf(
output,
"Temp:%d.%d C Hum:%d%%",
(int16_t)instance->generic.temp,
abs(
((int16_t)(instance->generic.temp * 10) -
(((int16_t)instance->generic.temp) * 10))),
instance->generic.humidity);
oregon3_append_check_sum((uint32_t)instance->generic.data, instance->var_data, output);
}
}
const SubGhzProtocolDecoder ws_protocol_oregon3_decoder = {
.alloc = ws_protocol_decoder_oregon3_alloc,
.free = ws_protocol_decoder_oregon3_free,
.feed = ws_protocol_decoder_oregon3_feed,
.reset = ws_protocol_decoder_oregon3_reset,
.get_hash_data = ws_protocol_decoder_oregon3_get_hash_data,
.serialize = ws_protocol_decoder_oregon3_serialize,
.deserialize = ws_protocol_decoder_oregon3_deserialize,
.get_string = ws_protocol_decoder_oregon3_get_string,
};
const SubGhzProtocol ws_protocol_oregon3 = {
.name = WS_PROTOCOL_OREGON3_NAME,
.type = SubGhzProtocolWeatherStation,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
.decoder = &ws_protocol_oregon3_decoder,
};

Some files were not shown because too many files have changed in this diff Show More