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

Merge branch 'dev' into release

This commit is contained in:
MX
2023-03-28 04:54:07 +03:00
30 changed files with 826 additions and 138 deletions

View File

@@ -1,18 +1,11 @@
### New changes
* If you have copied apps into `apps` folder - remove `apps` folder on your microSD before installing this release to avoid issues!
* Dev Builds: Add extra pack dev branch to avoid "bug" reports with `API mismatch`
* App Loader: Add option to ignore api mismatch (warning! some apps WILL not work, please update them to avoid any issues) -> (by @Willy-JL | PR #395)
* SubGHz: Add manually -> GSN protocol support
* SubGHz: Add 318 and 418 MHz back to hopping list
* SubGHz: Fix hopper stuck at 433.42 due to wide range signals -
When we using 433.92 remote flipper in hopping mode will stuck at 433.42 and may loose signal because of that, need to avoid using close freqs in hopping, only freqs with bigger difference like 310 -> 315
* Plugins: Update **TOTP (Authenticator)** [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator) -> BadBT Support
* OFW: Screen streaming improvements
* OFW: 1-Wire Overdrive Mode -> **Breaking API change, api was changed from 19.x to 20.x**
* OFW: Disable UART IRQs by default
* OFW: BadUSB: implement boot protocol
* OFW: Remove hmac_sha256 from public API -> **Breaking API change, api was changed from 18.x to 19.x**
**(this will make your manually copied plugins not work, update them in same way you installed them, or delete `apps` folder and then install firmware, if you using extra pack builds (with `e` in version) all apps in _Extra will be updated automatically)**
* SubGHz: AN-Motors AT4 + Alutech AT4N - Add Manually support
* SubGHz: Aprimatic keeloq emulation support + Add Manually
* NFC: MF Classic User Dict -> Fix deleting of the key in extra actions menu
* Plugins: Update WiFi Marauder [(by 0xchocolate)](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion)
* Plugins: Fix POCSAG pager `RIC:` text repetition and overlap (by @Willy-JL | PR #398)
* OFW: NFC: MF Classic - Additional checks before invalidating the key (Fixes issues with not using MF keys from user dict)
* OFW: Fix crash when emulating a DSGeneric key
#### [🎲 Download latest extra apps pack](https://github.com/xMasterX/all-the-plugins/archive/refs/heads/main.zip)

View File

@@ -52,9 +52,9 @@ Our Discord Community:
- Sub-GHz -> Press OK in frequency analyzer to use detected frequency in Read modes [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77)
- Sub-GHz -> Long press OK button in Sub-GHz Frequency analyzer to switch to Read menu [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/79)
- Lock device with pin(or regular lock if pin not set) by holding UP button on main screen [(by an4tur0r)](https://github.com/DarkFlippers/unleashed-firmware/pull/107)
* Sub-GHz -> Press OK in frequency analyzer to use detected frequency in Read modes
* Sub-GHz -> Long press OK button in Sub-GHz Frequency analyzer to switch to Read menu
* Sub-GHz -> External CC1101 module support
* Sub-GHz -> Short press OK in frequency analyzer to save detected frequency for usage in Read modes
* Sub-GHz -> Long press OK button in Sub-GHz Frequency analyzer to switch to Read menu and automatically use selected frequency
* Sub-GHz -> External CC1101 module support (Hardware SPI used)
* SubGHz -> **Hold right in received signal list to delete selected signal**
* SubGHz -> **Custom buttons for Keeloq / Alutech AT4N / Nice Flor S / Somfy Telis / Security+ 2.0** - now you can use arrow buttons to send signal with different button code
* SubGHz -> BFT Mitto / Somfy Telis / Nice Flor S manual creation with programming new remote into receiver (use button 0xF for BFT Mitto, 0x8 (Prog) on Somfy Telis)
@@ -84,10 +84,11 @@ Encoders/sending made by Eng1n33r & @xMasterX:
- Keeloq: Beninca
- Keeloq: Stilmatic / Schellenberg
- Keeloq: CAME Space
- Keeloq: Aprimatic (model TR and similar)
- CAME Atomo
- Nice Flor S
- 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)]
- 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)
- Security+ v1 & v2
- Star Line
@@ -189,7 +190,7 @@ Games:
## [- How to add extra Sub-GHz frequencies](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSettings.md)
## [- How to use Flipper as new remote (Nice FlorS, BFT Mitto, Somfy Telis)](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
## [- How to use Flipper as new remote (Nice FlorS, BFT Mitto, Somfy Telis, Aprimatic, AN-Motors, etc..)](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
## [- Configure Sub-GHz Remote App](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemotePlugin.md)

View File

@@ -157,8 +157,7 @@ static bool pocsag_decode_message_word(SubGhzProtocolDecoderPocsag* instance, ui
// Function called when current message got decoded, but other messages might follow
static void pocsag_message_done(SubGhzProtocolDecoderPocsag* instance) {
// append the message to the long-term storage string
furi_string_cat_printf(
instance->generic.result_ric, "\e#RIC: %" PRIu32 "\e# | ", instance->ric);
furi_string_printf(instance->generic.result_ric, "\e#RIC: %" PRIu32 "\e# | ", instance->ric);
furi_string_cat_str(instance->generic.result_ric, func_msg[instance->func]);
if(instance->func != POCSAG_FUNC_ALERT1) {
furi_string_cat(instance->done_msg, instance->msg);

View File

@@ -373,7 +373,8 @@ bool totp_scene_generate_token_handle_event(
SceneState* scene_state;
if(event->input.type == InputTypeLong) {
if(event->input.key == InputKeyDown && plugin_state->automation_method & AutomationMethodBadUsb) {
if(event->input.key == InputKeyDown &&
plugin_state->automation_method & AutomationMethodBadUsb) {
scene_state = (SceneState*)plugin_state->current_scene_state;
totp_usb_type_code_worker_notify(
scene_state->usb_type_code_worker_context, TotpUsbTypeCodeWorkerEventType);
@@ -383,7 +384,9 @@ bool totp_scene_generate_token_handle_event(
return true;
}
#ifdef TOTP_BADBT_TYPE_ENABLED
else if(event->input.key == InputKeyUp && plugin_state->automation_method & AutomationMethodBadBt) {
else if(
event->input.key == InputKeyUp &&
plugin_state->automation_method & AutomationMethodBadBt) {
scene_state = (SceneState*)plugin_state->current_scene_state;
totp_bt_type_code_worker_notify(
plugin_state->bt_type_code_worker_context, TotpBtTypeCodeWorkerEventType);

View File

@@ -4,7 +4,7 @@ App(
apptype=FlipperAppType.EXTERNAL,
entry_point="wifi_marauder_app",
requires=["gui"],
stack_size=1 * 1024,
stack_size=4 * 1024,
order=90,
fap_icon="wifi_10px.png",
fap_category="GPIO",

View File

@@ -1,3 +1,5 @@
ADD_SCENE(wifi_marauder, start, Start)
ADD_SCENE(wifi_marauder, console_output, ConsoleOutput)
ADD_SCENE(wifi_marauder, text_input, TextInput)
ADD_SCENE(wifi_marauder, settings_init, SettingsInit)
ADD_SCENE(wifi_marauder, log_viewer, LogViewer)

View File

@@ -4,6 +4,11 @@ void wifi_marauder_console_output_handle_rx_data_cb(uint8_t* buf, size_t len, vo
furi_assert(context);
WifiMarauderApp* app = context;
if(app->is_writing_log) {
app->has_saved_logs_this_session = true;
storage_file_write(app->log_file, buf, len);
}
// If text box store gets too big, then truncate it
app->text_box_store_strlen += len;
if(app->text_box_store_strlen >= WIFI_MARAUDER_TEXT_BOX_STORE_SIZE - 1) {
@@ -21,15 +26,7 @@ void wifi_marauder_console_output_handle_rx_packets_cb(uint8_t* buf, size_t len,
furi_assert(context);
WifiMarauderApp* app = context;
// If it is a sniff function, open the pcap file for recording
if(strncmp("sniff", app->selected_tx_string, strlen("sniff")) == 0 && !app->is_writing) {
app->is_writing = true;
if(!app->capture_file || !storage_file_is_open(app->capture_file)) {
wifi_marauder_create_pcap_file(app);
}
}
if(app->is_writing) {
if(app->is_writing_pcap) {
storage_file_write(app->capture_file, buf, len);
}
}
@@ -49,8 +46,7 @@ void wifi_marauder_scene_console_output_on_enter(void* context) {
furi_string_reset(app->text_box_store);
app->text_box_store_strlen = 0;
if(0 == strncmp("help", app->selected_tx_string, strlen("help"))) {
const char* help_msg = "Marauder companion " WIFI_MARAUDER_APP_VERSION
"\nby @0xchocolate\nmodified by @tcpassos\n";
const char* help_msg = "Marauder companion " WIFI_MARAUDER_APP_VERSION "\n";
furi_string_cat_str(app->text_box_store, help_msg);
app->text_box_store_strlen += strlen(help_msg);
}
@@ -62,7 +58,7 @@ void wifi_marauder_scene_console_output_on_enter(void* context) {
}
}
// Set starting text - for "View Log", this will just be what was already in the text box store
// Set starting text - for "View Log from end", this will just be what was already in the text box store
text_box_set_text(app->text_box, furi_string_get_cstr(app->text_box_store));
scene_manager_set_scene_state(app->scene_manager, WifiMarauderSceneConsoleOutput, 0);
@@ -76,8 +72,23 @@ void wifi_marauder_scene_console_output_on_enter(void* context) {
app->lp_uart,
wifi_marauder_console_output_handle_rx_packets_cb); // setup callback for packets rx thread
// Send command with newline '\n'
// Get ready to send command
if(app->is_command && app->selected_tx_string) {
// Create files *before* sending command
// (it takes time to iterate through the directory)
if(app->ok_to_save_logs) {
app->is_writing_log = true;
wifi_marauder_create_log_file(app);
}
// If it is a sniff function, open the pcap file for recording
if(app->ok_to_save_pcaps &&
strncmp("sniff", app->selected_tx_string, strlen("sniff")) == 0) {
app->is_writing_pcap = true;
wifi_marauder_create_pcap_file(app);
}
// Send command with newline '\n'
wifi_marauder_uart_tx(
(uint8_t*)(app->selected_tx_string), strlen(app->selected_tx_string));
wifi_marauder_uart_tx((uint8_t*)("\n"), 1);
@@ -111,8 +122,13 @@ void wifi_marauder_scene_console_output_on_exit(void* context) {
wifi_marauder_uart_tx((uint8_t*)("stopscan\n"), strlen("stopscan\n"));
}
app->is_writing = false;
app->is_writing_pcap = false;
if(app->capture_file && storage_file_is_open(app->capture_file)) {
storage_file_close(app->capture_file);
}
app->is_writing_log = false;
if(app->log_file && storage_file_is_open(app->log_file)) {
storage_file_close(app->log_file);
}
}

View File

@@ -0,0 +1,185 @@
#include "../wifi_marauder_app_i.h"
void wifi_marauder_scene_log_viewer_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
WifiMarauderApp* app = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(app->view_dispatcher, result);
}
}
static void _read_log_page_into_text_store(WifiMarauderApp* app) {
char temp[64 + 1];
storage_file_seek(
app->log_file, WIFI_MARAUDER_TEXT_BOX_STORE_SIZE * (app->open_log_file_page - 1), true);
furi_string_reset(app->text_box_store);
for(uint16_t i = 0; i < (WIFI_MARAUDER_TEXT_BOX_STORE_SIZE / (sizeof(temp) - 1)); i++) {
uint16_t num_bytes = storage_file_read(app->log_file, temp, sizeof(temp) - 1);
if(num_bytes == 0) {
break;
}
temp[num_bytes] = '\0';
furi_string_cat_str(app->text_box_store, temp);
}
}
void wifi_marauder_scene_log_viewer_setup_widget(WifiMarauderApp* app, bool called_from_browse) {
Widget* widget = app->widget;
bool is_open = storage_file_is_open(app->log_file);
bool should_open_log = (app->has_saved_logs_this_session || called_from_browse);
if(is_open) {
_read_log_page_into_text_store(app);
} else if(
should_open_log &&
storage_file_open(app->log_file, app->log_file_path, FSAM_READ, FSOM_OPEN_EXISTING)) {
uint64_t filesize = storage_file_size(app->log_file);
app->open_log_file_num_pages = filesize / WIFI_MARAUDER_TEXT_BOX_STORE_SIZE;
int extra_page = (filesize % WIFI_MARAUDER_TEXT_BOX_STORE_SIZE != 0) ? 1 : 0;
app->open_log_file_num_pages = (filesize / WIFI_MARAUDER_TEXT_BOX_STORE_SIZE) + extra_page;
app->open_log_file_page = 1;
_read_log_page_into_text_store(app);
} else {
app->open_log_file_page = 0;
app->open_log_file_num_pages = 0;
}
widget_reset(widget);
if(furi_string_empty(app->text_box_store)) {
char help_msg[256];
snprintf(
help_msg,
sizeof(help_msg),
"The log is empty! :(\nTry sending a command?\n\nSaving pcaps to flipper sdcard: %s\nSaving logs to flipper sdcard: %s",
app->ok_to_save_pcaps ? "ON" : "OFF",
app->ok_to_save_logs ? "ON" : "OFF");
furi_string_set_str(app->text_box_store, help_msg);
}
widget_add_text_scroll_element(
widget, 0, 0, 128, 53, furi_string_get_cstr(app->text_box_store));
if(1 < app->open_log_file_page && app->open_log_file_page < app->open_log_file_num_pages) {
// hide "Browse" text for middle pages
widget_add_button_element(
widget, GuiButtonTypeCenter, "", wifi_marauder_scene_log_viewer_widget_callback, app);
} else {
// only show "Browse" text on first and last page
widget_add_button_element(
widget,
GuiButtonTypeCenter,
"Browse",
wifi_marauder_scene_log_viewer_widget_callback,
app);
}
char pagecounter[100];
snprintf(
pagecounter,
sizeof(pagecounter),
"%d/%d",
app->open_log_file_page,
app->open_log_file_num_pages);
if(app->open_log_file_page > 1) {
if(app->open_log_file_page == app->open_log_file_num_pages) {
// only show left side page-count on last page
widget_add_button_element(
widget,
GuiButtonTypeLeft,
pagecounter,
wifi_marauder_scene_log_viewer_widget_callback,
app);
} else {
widget_add_button_element(
widget, GuiButtonTypeLeft, "", wifi_marauder_scene_log_viewer_widget_callback, app);
}
}
if(app->open_log_file_page < app->open_log_file_num_pages) {
widget_add_button_element(
widget,
GuiButtonTypeRight,
pagecounter,
wifi_marauder_scene_log_viewer_widget_callback,
app);
}
}
void wifi_marauder_scene_log_viewer_on_enter(void* context) {
WifiMarauderApp* app = context;
app->open_log_file_page = 0;
app->open_log_file_num_pages = 0;
bool saved_logs_exist = false;
if(!app->has_saved_logs_this_session && furi_string_empty(app->text_box_store)) {
// no commands sent yet this session, find last saved log
if(storage_dir_open(app->log_file, MARAUDER_APP_FOLDER_LOGS)) {
char name[70];
char lastname[70];
while(storage_dir_read(app->log_file, NULL, name, sizeof(name))) {
// keep reading directory until last file is reached
strlcpy(lastname, name, sizeof(lastname));
saved_logs_exist = true;
}
if(saved_logs_exist) {
snprintf(
app->log_file_path,
sizeof(app->log_file_path),
"%s/%s",
MARAUDER_APP_FOLDER_LOGS,
lastname);
}
}
storage_dir_close(app->log_file);
}
wifi_marauder_scene_log_viewer_setup_widget(app, saved_logs_exist);
view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewWidget);
}
bool wifi_marauder_scene_log_viewer_on_event(void* context, SceneManagerEvent event) {
WifiMarauderApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeCenter) {
// Browse
FuriString* predefined_filepath = furi_string_alloc_set_str(MARAUDER_APP_FOLDER_LOGS);
FuriString* selected_filepath = furi_string_alloc();
if(dialog_file_browser_show(
app->dialogs, selected_filepath, predefined_filepath, NULL)) {
strncpy(
app->log_file_path,
furi_string_get_cstr(selected_filepath),
sizeof(app->log_file_path));
if(storage_file_is_open(app->log_file)) {
storage_file_close(app->log_file);
}
wifi_marauder_scene_log_viewer_setup_widget(app, true);
}
furi_string_free(selected_filepath);
furi_string_free(predefined_filepath);
consumed = true;
} else if(event.event == GuiButtonTypeRight) {
// Advance page
++app->open_log_file_page;
wifi_marauder_scene_log_viewer_setup_widget(app, false);
} else if(event.event == GuiButtonTypeLeft) {
// Previous page
--app->open_log_file_page;
wifi_marauder_scene_log_viewer_setup_widget(app, false);
}
}
return consumed;
}
void wifi_marauder_scene_log_viewer_on_exit(void* context) {
WifiMarauderApp* app = context;
widget_reset(app->widget);
if(storage_file_is_open(app->log_file)) {
storage_file_close(app->log_file);
}
}

View File

@@ -0,0 +1,130 @@
#include "../wifi_marauder_app_i.h"
const char* Y = "Y";
const char* N = "N";
#define PROMPT_PCAPS 0
#define PROMPT_LOGS 1
void wifi_marauder_scene_settings_init_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
WifiMarauderApp* app = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(app->view_dispatcher, result);
}
}
void wifi_marauder_scene_settings_init_setup_widget(WifiMarauderApp* app) {
Widget* widget = app->widget;
widget_reset(widget);
widget_add_button_element(
widget, GuiButtonTypeLeft, "No", wifi_marauder_scene_settings_init_widget_callback, app);
widget_add_button_element(
widget, GuiButtonTypeRight, "Yes", wifi_marauder_scene_settings_init_widget_callback, app);
if(app->which_prompt == PROMPT_PCAPS) {
widget_add_string_element(widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "Save pcaps?");
widget_add_text_scroll_element(
widget,
0,
12,
128,
38,
"With compatible marauder\nfirmware, you can choose to\nsave captures (pcaps) to the\nflipper sd card here:\n" MARAUDER_APP_FOLDER_USER_PCAPS
"\n\nYou can change this setting in the app at any time. Would\nyou like to enable this feature now?");
} else {
widget_add_string_element(widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "Save logs?");
widget_add_text_scroll_element(
widget,
0,
12,
128,
38,
"This app supports saving text\nlogs of console output to the\nflipper sd card here:\n" MARAUDER_APP_FOLDER_USER_LOGS
"\n\nYou can change this setting in the app at any time. Would\nyou like to enable this feature now?");
}
}
void wifi_marauder_scene_settings_init_on_enter(void* context) {
WifiMarauderApp* app = context;
app->which_prompt = PROMPT_PCAPS;
wifi_marauder_scene_settings_init_setup_widget(app);
view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewWidget);
}
bool wifi_marauder_scene_settings_init_on_event(void* context, SceneManagerEvent event) {
WifiMarauderApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
// get which button press: "Yes" or "No"
if(event.event == GuiButtonTypeRight) {
// Yes
if(app->which_prompt == PROMPT_PCAPS) {
app->ok_to_save_pcaps = true;
} else {
app->ok_to_save_logs = true;
}
} else if(event.event == GuiButtonTypeLeft) {
// No
if(app->which_prompt == PROMPT_PCAPS) {
app->ok_to_save_pcaps = false;
} else {
app->ok_to_save_logs = false;
}
}
// save setting to file, load next widget or scene
if(app->which_prompt == PROMPT_PCAPS) {
if(storage_file_open(
app->save_pcap_setting_file,
SAVE_PCAP_SETTING_FILEPATH,
FSAM_WRITE,
FSOM_CREATE_ALWAYS)) {
const char* ok = app->ok_to_save_pcaps ? Y : N;
storage_file_write(app->save_pcap_setting_file, ok, sizeof(ok));
} else {
dialog_message_show_storage_error(app->dialogs, "Cannot save settings");
}
storage_file_close(app->save_pcap_setting_file);
// same scene, different-looking widget
app->which_prompt = PROMPT_LOGS;
wifi_marauder_scene_settings_init_setup_widget(app);
} else {
if(storage_file_open(
app->save_logs_setting_file,
SAVE_LOGS_SETTING_FILEPATH,
FSAM_WRITE,
FSOM_CREATE_ALWAYS)) {
const char* ok = app->ok_to_save_logs ? Y : N;
storage_file_write(app->save_logs_setting_file, ok, sizeof(ok));
} else {
dialog_message_show_storage_error(app->dialogs, "Cannot save settings");
}
storage_file_close(app->save_logs_setting_file);
// go back to start scene (main menu)
app->need_to_prompt_settings_init = false;
scene_manager_previous_scene(app->scene_manager);
}
consumed = true;
}
return consumed;
}
void wifi_marauder_scene_settings_init_on_exit(void* context) {
WifiMarauderApp* app = context;
widget_reset(app->widget);
if(storage_file_is_open(app->save_pcap_setting_file)) {
storage_file_close(app->save_pcap_setting_file);
}
if(storage_file_is_open(app->save_logs_setting_file)) {
storage_file_close(app->save_logs_setting_file);
}
}

View File

@@ -127,6 +127,13 @@ const WifiMarauderItem items[NUM_MENU_ITEMS] = {
{"Update", {"ota", "sd"}, 2, {"update -w", "update -s"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP},
{"Reboot", {""}, 1, {"reboot"}, NO_ARGS, FOCUS_CONSOLE_END, NO_TIP},
{"Help", {""}, 1, {"help"}, NO_ARGS, FOCUS_CONSOLE_START, SHOW_STOPSCAN_TIP},
{"Save to flipper sdcard", // keep as last entry or change logic in callback below
{""},
1,
{""},
NO_ARGS,
FOCUS_CONSOLE_START,
NO_TIP},
};
static void wifi_marauder_scene_start_var_list_enter_callback(void* context, uint32_t index) {
@@ -136,6 +143,13 @@ static void wifi_marauder_scene_start_var_list_enter_callback(void* context, uin
furi_assert(index < NUM_MENU_ITEMS);
const WifiMarauderItem* item = &items[index];
if(index == NUM_MENU_ITEMS - 1) {
// "Save to flipper sdcard" special case - start SettingsInit widget
view_dispatcher_send_custom_event(
app->view_dispatcher, WifiMarauderEventStartSettingsInit);
return;
}
const int selected_option_index = app->selected_option_index[index];
furi_assert(selected_option_index < item->num_options_menu);
app->selected_tx_string = item->actual_commands[selected_option_index];
@@ -147,6 +161,12 @@ static void wifi_marauder_scene_start_var_list_enter_callback(void* context, uin
item->focus_console;
app->show_stopscan_tip = item->show_stopscan_tip;
if(!app->is_command && selected_option_index == 0) {
// View Log from start
view_dispatcher_send_custom_event(app->view_dispatcher, WifiMarauderEventStartLogViewer);
return;
}
bool needs_keyboard = (item->needs_keyboard == TOGGLE_ARGS) ? (selected_option_index != 0) :
item->needs_keyboard;
if(needs_keyboard) {
@@ -193,6 +213,11 @@ void wifi_marauder_scene_start_on_enter(void* context) {
var_item_list, scene_manager_get_scene_state(app->scene_manager, WifiMarauderSceneStart));
view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewVarItemList);
// Wait, if the user hasn't initialized sdcard settings, let's prompt them once (then come back here)
if(app->need_to_prompt_settings_init) {
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneSettingsInit);
}
}
bool wifi_marauder_scene_start_on_event(void* context, SceneManagerEvent event) {
@@ -204,16 +229,28 @@ bool wifi_marauder_scene_start_on_event(void* context, SceneManagerEvent event)
if(event.event == WifiMarauderEventStartKeyboard) {
scene_manager_set_scene_state(
app->scene_manager, WifiMarauderSceneStart, app->selected_menu_index);
scene_manager_next_scene(app->scene_manager, WifiMarauderAppViewTextInput);
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneTextInput);
} else if(event.event == WifiMarauderEventStartConsole) {
scene_manager_set_scene_state(
app->scene_manager, WifiMarauderSceneStart, app->selected_menu_index);
scene_manager_next_scene(app->scene_manager, WifiMarauderAppViewConsoleOutput);
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneConsoleOutput);
} else if(event.event == WifiMarauderEventStartSettingsInit) {
scene_manager_set_scene_state(
app->scene_manager, WifiMarauderSceneStart, app->selected_menu_index);
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneSettingsInit);
} else if(event.event == WifiMarauderEventStartLogViewer) {
scene_manager_set_scene_state(
app->scene_manager, WifiMarauderSceneStart, app->selected_menu_index);
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneLogViewer);
}
consumed = true;
} else if(event.type == SceneManagerEventTypeTick) {
app->selected_menu_index = variable_item_list_get_selected_item_index(app->var_item_list);
consumed = true;
} else if(event.type == SceneManagerEventTypeBack) {
scene_manager_stop(app->scene_manager);
view_dispatcher_stop(app->view_dispatcher);
consumed = true;
}
return consumed;

View File

@@ -80,7 +80,7 @@ bool wifi_marauder_scene_text_input_on_event(void* context, SceneManagerEvent ev
if(event.event == WifiMarauderEventStartConsole) {
// Point to custom string to send
app->selected_tx_string = app->text_input_store;
scene_manager_next_scene(app->scene_manager, WifiMarauderAppViewConsoleOutput);
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneConsoleOutput);
consumed = true;
} else if(event.event == WifiMarauderEventSaveSourceMac) {
if(12 != strlen(app->text_input_store)) {
@@ -138,7 +138,7 @@ bool wifi_marauder_scene_text_input_on_event(void* context, SceneManagerEvent ev
app->special_case_input_src_addr,
app->special_case_input_dst_addr);
app->selected_tx_string = app->text_input_store;
scene_manager_next_scene(app->scene_manager, WifiMarauderAppViewConsoleOutput);
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneConsoleOutput);
}
consumed = true;
}

View File

@@ -28,6 +28,9 @@ WifiMarauderApp* wifi_marauder_app_alloc() {
app->dialogs = furi_record_open(RECORD_DIALOGS);
app->storage = furi_record_open(RECORD_STORAGE);
app->capture_file = storage_file_alloc(app->storage);
app->log_file = storage_file_alloc(app->storage);
app->save_pcap_setting_file = storage_file_alloc(app->storage);
app->save_logs_setting_file = storage_file_alloc(app->storage);
app->view_dispatcher = view_dispatcher_alloc();
app->scene_manager = scene_manager_alloc(&wifi_marauder_scene_handlers, app);
@@ -65,6 +68,17 @@ WifiMarauderApp* wifi_marauder_app_alloc() {
view_dispatcher_add_view(
app->view_dispatcher, WifiMarauderAppViewTextInput, text_input_get_view(app->text_input));
app->widget = widget_alloc();
view_dispatcher_add_view(
app->view_dispatcher, WifiMarauderAppViewWidget, widget_get_view(app->widget));
app->has_saved_logs_this_session = false;
// if user hasn't confirmed whether to save pcaps and logs to sdcard, then prompt when scene starts
app->need_to_prompt_settings_init =
(!storage_file_exists(app->storage, SAVE_PCAP_SETTING_FILEPATH) ||
!storage_file_exists(app->storage, SAVE_LOGS_SETTING_FILEPATH));
scene_manager_next_scene(app->scene_manager, WifiMarauderSceneStart);
return app;
@@ -76,6 +90,38 @@ void wifi_marauder_make_app_folder(WifiMarauderApp* app) {
if(!storage_simply_mkdir(app->storage, MARAUDER_APP_FOLDER)) {
dialog_message_show_storage_error(app->dialogs, "Cannot create\napp folder");
}
if(!storage_simply_mkdir(app->storage, MARAUDER_APP_FOLDER_PCAPS)) {
dialog_message_show_storage_error(app->dialogs, "Cannot create\npcaps folder");
}
if(!storage_simply_mkdir(app->storage, MARAUDER_APP_FOLDER_LOGS)) {
dialog_message_show_storage_error(app->dialogs, "Cannot create\npcaps folder");
}
}
void wifi_marauder_load_settings(WifiMarauderApp* app) {
if(storage_file_open(
app->save_pcap_setting_file,
SAVE_PCAP_SETTING_FILEPATH,
FSAM_READ,
FSOM_OPEN_EXISTING)) {
char ok[1];
storage_file_read(app->save_pcap_setting_file, ok, sizeof(ok));
app->ok_to_save_pcaps = ok[0] == 'Y';
}
storage_file_close(app->save_pcap_setting_file);
if(storage_file_open(
app->save_logs_setting_file,
SAVE_LOGS_SETTING_FILEPATH,
FSAM_READ,
FSOM_OPEN_EXISTING)) {
char ok[1];
storage_file_read(app->save_logs_setting_file, ok, sizeof(ok));
app->ok_to_save_logs = ok[0] == 'Y';
}
storage_file_close(app->save_logs_setting_file);
}
void wifi_marauder_app_free(WifiMarauderApp* app) {
@@ -85,10 +131,15 @@ void wifi_marauder_app_free(WifiMarauderApp* app) {
view_dispatcher_remove_view(app->view_dispatcher, WifiMarauderAppViewVarItemList);
view_dispatcher_remove_view(app->view_dispatcher, WifiMarauderAppViewConsoleOutput);
view_dispatcher_remove_view(app->view_dispatcher, WifiMarauderAppViewTextInput);
view_dispatcher_remove_view(app->view_dispatcher, WifiMarauderAppViewWidget);
widget_free(app->widget);
text_box_free(app->text_box);
furi_string_free(app->text_box_store);
text_input_free(app->text_input);
storage_file_free(app->capture_file);
storage_file_free(app->log_file);
storage_file_free(app->save_pcap_setting_file);
storage_file_free(app->save_logs_setting_file);
// View dispatcher
view_dispatcher_free(app->view_dispatcher);
@@ -118,6 +169,7 @@ int32_t wifi_marauder_app(void* p) {
WifiMarauderApp* wifi_marauder_app = wifi_marauder_app_alloc();
wifi_marauder_make_app_folder(wifi_marauder_app);
wifi_marauder_load_settings(wifi_marauder_app);
wifi_marauder_app->uart = wifi_marauder_usart_init(wifi_marauder_app);
wifi_marauder_app->lp_uart = wifi_marauder_lp_uart_init(wifi_marauder_app);

View File

@@ -4,7 +4,7 @@
extern "C" {
#endif
#define WIFI_MARAUDER_APP_VERSION "v0.3.1"
#define WIFI_MARAUDER_APP_VERSION "v0.3.3"
typedef struct WifiMarauderApp WifiMarauderApp;

View File

@@ -14,16 +14,24 @@
#include <gui/modules/text_box.h>
#include <gui/modules/text_input.h>
#include <gui/modules/variable_item_list.h>
#include <gui/modules/widget.h>
#include <storage/storage.h>
#include <dialogs/dialogs.h>
#define NUM_MENU_ITEMS (16)
#define NUM_MENU_ITEMS (17)
#define WIFI_MARAUDER_TEXT_BOX_STORE_SIZE (4096)
#define WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE (512)
#define MARAUDER_APP_FOLDER EXT_PATH("apps_data/marauder")
#define MARAUDER_APP_FOLDER_USER "apps_data/marauder"
#define MARAUDER_APP_FOLDER EXT_PATH(MARAUDER_APP_FOLDER_USER)
#define MARAUDER_APP_FOLDER_PCAPS MARAUDER_APP_FOLDER "/pcaps"
#define MARAUDER_APP_FOLDER_LOGS MARAUDER_APP_FOLDER "/logs"
#define MARAUDER_APP_FOLDER_USER_PCAPS MARAUDER_APP_FOLDER_USER "/pcaps"
#define MARAUDER_APP_FOLDER_USER_LOGS MARAUDER_APP_FOLDER_USER "/logs"
#define SAVE_PCAP_SETTING_FILEPATH MARAUDER_APP_FOLDER "/save_pcaps_here.setting"
#define SAVE_LOGS_SETTING_FILEPATH MARAUDER_APP_FOLDER "/save_logs_here.setting"
struct WifiMarauderApp {
Gui* gui;
@@ -37,9 +45,21 @@ struct WifiMarauderApp {
TextInput* text_input;
Storage* storage;
File* capture_file;
File* log_file;
char log_file_path[100];
File* save_pcap_setting_file;
File* save_logs_setting_file;
bool need_to_prompt_settings_init;
int which_prompt;
bool ok_to_save_pcaps;
bool ok_to_save_logs;
bool has_saved_logs_this_session;
DialogsApp* dialogs;
VariableItemList* var_item_list;
Widget* widget;
int open_log_file_page;
int open_log_file_num_pages;
WifiMarauderUart* uart;
WifiMarauderUart* lp_uart;
@@ -50,7 +70,8 @@ struct WifiMarauderApp {
bool is_custom_tx_string;
bool focus_console_start;
bool show_stopscan_tip;
bool is_writing;
bool is_writing_pcap;
bool is_writing_log;
// For input source and destination MAC in targeted deauth attack
int special_case_input_step;
@@ -83,4 +104,5 @@ typedef enum {
WifiMarauderAppViewVarItemList,
WifiMarauderAppViewConsoleOutput,
WifiMarauderAppViewTextInput,
WifiMarauderAppViewWidget,
} WifiMarauderAppView;

View File

@@ -5,5 +5,7 @@ typedef enum {
WifiMarauderEventStartConsole,
WifiMarauderEventStartKeyboard,
WifiMarauderEventSaveSourceMac,
WifiMarauderEventSaveDestinationMac
WifiMarauderEventSaveDestinationMac,
WifiMarauderEventStartSettingsInit,
WifiMarauderEventStartLogViewer
} WifiMarauderCustomEvent;

View File

@@ -1,7 +1,7 @@
#include "wifi_marauder_app_i.h"
#include "wifi_marauder_pcap.h"
void wifi_marauder_get_prefix_from_cmd(char* dest, const char* command) {
void wifi_marauder_get_prefix_from_sniff_cmd(char* dest, const char* command) {
int start, end, delta;
start = strlen("sniff");
end = strcspn(command, " ");
@@ -10,10 +10,17 @@ void wifi_marauder_get_prefix_from_cmd(char* dest, const char* command) {
dest[delta] = '\0';
}
void wifi_marauder_get_prefix_from_cmd(char* dest, const char* command) {
int end;
end = strcspn(command, " ");
strncpy(dest, command, end);
dest[end] = '\0';
}
void wifi_marauder_create_pcap_file(WifiMarauderApp* app) {
char prefix[10];
char capture_file_path[100];
wifi_marauder_get_prefix_from_cmd(prefix, app->selected_tx_string);
wifi_marauder_get_prefix_from_sniff_cmd(prefix, app->selected_tx_string);
int i = 0;
do {
@@ -21,7 +28,7 @@ void wifi_marauder_create_pcap_file(WifiMarauderApp* app) {
capture_file_path,
sizeof(capture_file_path),
"%s/%s_%d.pcap",
MARAUDER_APP_FOLDER,
MARAUDER_APP_FOLDER_PCAPS,
prefix,
i);
i++;
@@ -31,3 +38,27 @@ void wifi_marauder_create_pcap_file(WifiMarauderApp* app) {
dialog_message_show_storage_error(app->dialogs, "Cannot open pcap file");
}
}
void wifi_marauder_create_log_file(WifiMarauderApp* app) {
char prefix[10];
char log_file_path[100];
wifi_marauder_get_prefix_from_cmd(prefix, app->selected_tx_string);
int i = 0;
do {
snprintf(
log_file_path,
sizeof(log_file_path),
"%s/%s_%d.log",
MARAUDER_APP_FOLDER_LOGS,
prefix,
i);
i++;
} while(storage_file_exists(app->storage, log_file_path));
if(!storage_file_open(app->log_file, log_file_path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
dialog_message_show_storage_error(app->dialogs, "Cannot open log file");
} else {
strcpy(app->log_file_path, log_file_path);
}
}

View File

@@ -9,3 +9,12 @@
* @param app Application context
*/
void wifi_marauder_create_pcap_file(WifiMarauderApp* app);
/**
* Creates a log file to store text from console output.
* The file name will have a prefix according to the command being performed by the application (Eg: scanap_0.log)
*
* @param app Application context
*/
// same as wifi_marauder_create_pcap_file, but for log files (to save console text output)
void wifi_marauder_create_log_file(WifiMarauderApp* app);

View File

@@ -2,7 +2,7 @@
#include "furi_hal.h"
#define RX_BUF_SIZE (320)
#define RX_BUF_SIZE (2048)
typedef struct WifiMarauderUart WifiMarauderUart;

View File

@@ -86,9 +86,16 @@ static bool fap_loader_run_selected_app(FapLoader* loader, bool ignore_mismatch)
if(preload_res == FlipperApplicationPreloadStatusApiMismatch) {
if(!ignore_mismatch) {
DialogMessage* message = dialog_message_alloc();
dialog_message_set_header(message, "API Mismatch", 64, 0, AlignCenter, AlignTop);
dialog_message_set_header(
message, "API Mismatch", 64, 0, AlignCenter, AlignTop);
dialog_message_set_buttons(message, "Cancel", NULL, "Continue");
dialog_message_set_text(message, "This app might not\nwork correctly\nContinue anyways?", 64, 32, AlignCenter, AlignCenter);
dialog_message_set_text(
message,
"This app might not\nwork correctly\nContinue anyways?",
64,
32,
AlignCenter,
AlignCenter);
if(dialog_message_show(loader->dialogs, message) == DialogMessageButtonRight) {
retry = true;
}

View File

@@ -20,6 +20,9 @@ typedef enum {
SubmenuIndexDTMNeo433,
SubmenuIndexGibidi433,
SubmenuIndexGSN,
SubmenuIndexAprimatic,
SubmenuIndexANMotorsAT4,
SubmenuIndexAlutechAT4N,
SubmenuIndexNiceFlo12bit,
SubmenuIndexNiceFlo24bit,
SubmenuIndexNiceFlorS_433_92,

View File

@@ -98,6 +98,18 @@ void subghz_scene_set_type_on_enter(void* context) {
SubmenuIndexSomfyTelis,
subghz_scene_set_type_submenu_callback,
subghz);
submenu_add_item(
subghz->submenu,
"AN-Motors AT4 433MHz",
SubmenuIndexANMotorsAT4,
subghz_scene_set_type_submenu_callback,
subghz);
submenu_add_item(
subghz->submenu,
"Alutech AT4N 433MHz",
SubmenuIndexAlutechAT4N,
subghz_scene_set_type_submenu_callback,
subghz);
submenu_add_item(
subghz->submenu,
"KL: DoorHan 315MHz",
@@ -158,6 +170,12 @@ void subghz_scene_set_type_on_enter(void* context) {
SubmenuIndexGSN,
subghz_scene_set_type_submenu_callback,
subghz);
submenu_add_item(
subghz->submenu,
"KL: Aprimatic 433MHz",
SubmenuIndexAprimatic,
subghz_scene_set_type_submenu_callback,
subghz);
submenu_add_item(
subghz->submenu,
"KL: Elmes (PL) 433MHz",
@@ -502,6 +520,58 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
}
break;
case SubmenuIndexANMotorsAT4:
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
subghz_preset_init(subghz, "AM650", 433920000, NULL, 0);
if(subghz->txrx->transmitter) {
subghz_protocol_keeloq_create_data(
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
subghz->txrx->fff_data,
(key & 0x00FFFFFF) | 0x04000000,
0x2,
0x0021,
"AN-Motors",
subghz->txrx->preset);
flipper_format_write_string_cstr(
subghz->txrx->fff_data, "Manufacture", "AN-Motors");
generated_protocol = true;
} else {
generated_protocol = false;
}
subghz_transmitter_free(subghz->txrx->transmitter);
if(!generated_protocol) {
furi_string_set(
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
}
break;
case SubmenuIndexAprimatic:
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
subghz_preset_init(subghz, "AM650", 433920000, NULL, 0);
if(subghz->txrx->transmitter) {
subghz_protocol_keeloq_create_data(
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
subghz->txrx->fff_data,
(key & 0x000FFFFF) | 0x00600000,
0x4,
0x0003,
"Aprimatic",
subghz->txrx->preset);
flipper_format_write_string_cstr(
subghz->txrx->fff_data, "Manufacture", "Aprimatic");
generated_protocol = true;
} else {
generated_protocol = false;
}
subghz_transmitter_free(subghz->txrx->transmitter);
if(!generated_protocol) {
furi_string_set(
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
}
break;
case SubmenuIndexGibidi433:
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
@@ -717,6 +787,29 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
}
break;
case SubmenuIndexAlutechAT4N:
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
subghz->txrx->environment, SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME);
subghz_preset_init(subghz, "AM650", 433920000, NULL, 0);
if(subghz->txrx->transmitter) {
subghz_protocol_alutech_at_4n_create_data(
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
subghz->txrx->fff_data,
(key & 0x000FFFFF) | 0x00100000,
0x44,
0x0003,
subghz->txrx->preset);
generated_protocol = true;
} else {
generated_protocol = false;
}
subghz_transmitter_free(subghz->txrx->transmitter);
if(!generated_protocol) {
furi_string_set(
subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
}
break;
case SubmenuIndexSomfyTelis:
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
subghz->txrx->environment, SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME);

View File

@@ -1,58 +1,58 @@
Filetype: Flipper SubGhz Keystore File
Version: 0
Encryption: 1
IV: AB 0B A1 23 45 FE E7 06 66 73 21 67 97 12 3D 61
CA9DC3E30069ED9C257FCA6747136F617F4E390F2B8BDDFDEBEC8A398A6A0C1E
78F18401572E33117850EA83D00C2F92376E88D7CAC0BF7CBA7037BF6755F43C
909055FF43224057BCE5F965174AF46586EB7CA4CAE1B3EB8B66EA569047948A
AB9B7D338457774713147BF666A5996926B90146CB698AC2F4DE63ADE89D84BB
ED796AED9BB3185ACD94779F7CC42665D4A3B04419E4272B77DA8D94B5CF84921889CEB110AB55D7267720A7C5B290EF
88E0CECA92549C73981F95999FA8F03B1B2EB98774134752556D7D7EFA802757
C42CABAD74010E35726659C8E4AF4888282FBEA9703616B3403DA7C3DCA8A8ED
6F44BC56AC2E9883A2469C1909D171A8C58A0CFE4B506CC562EB2F08A484AE1B
65DEBEBC629FA3CE72B5028E1E385DFFEE0A9FE227FC5F6DD4368C0CB1886A7D
EA9BDC762FCBAAA11A4BE677AE344993990153C9E7A4A89F8271F49765FC72EF
8FAE9AC3033E637703626956F91791DAE4B3BEA9C82C065C91A314DDB647F8FE661750526E58C613000260675C2B520C
3D853DEC62375B3201B1C2269E31794A3C29958B191953A331D39675CCB53C002EF1491B63C49E629AF5D747CC52BD11
61A02BB85B08AA8047EAD9FB80D489AB15CBE0302C660891C4B29D2621C80DBB
5230A9651D1A0910695593E1A5F6EA6EB21990D6465E52B325CF141C9E0C9172
C9348D18DC019C3E364F7AD9CD5B6D77EE2D6486CFBDFAFE7042AB917E8FFE7C
DED385BBAC8FAB5918DBDBDC8622850048A540963AF35C3DD772926927B148C2
E1EC13990BDA8E22F2848F97069462FB46840FEA688C52EDE930CD22C4E6F445BF317A96C4A6C2DC4295B2E3E86053B9
D5453884C337587A13117F35219C7B4356E8E63EBC4C197CC1633D444D0A6AD0
72C3E291DA11AD3D195C6A1B65849B0C91B7D18762B515A5728389356C42B62C
0E9EA0D97053752977D83A019A2F0393D326407AE507F5EE6E650082DBC683F81BDD71B79BE81EEB3139815377577346
A32FF38450B3121CB01CE06AA369DC7B883CD9B1695CBADBC9609F009D6BFF7B7518D9DD690D214A1DB0D1A0C6F9FC3F
98848EFBB09D2A3EA59EE91B1B510BA3775E36B14500DE1238317AFC9872358F
E8B2785366399F84EADF07B0E299603BB885780E6ECA883508FFB7664C6473FE
1F6CEA6696B2E07FEB256506609D7E11D9F09F18B9EE43DE9BC42014ABF5213F
F2FF5045A5E90AAF92C2ECCB9FEFFBDE400A7E3E6B09CF43608896F7BC91736F
73CC30A78808BB2B3F7F398D88C79470AF86B825DE0C2FF31442D351C2826D9C
B68FD5017BA4809AD22DF64805DCE329A81C2CE3F7BE87FADFBD02211AB02321
57BC2E14A724D6E2F4B0FD9401C3E6E5117D338077958648A558E40C553C787F
882A41BC36393F06C57ED71E66D003E24B5DAE86F90D8AEDD89A2DFED6719BF1
95EDC3C3EB639AC66656B58D8F71A5B1B329002C4CCF7666C41C717A939C0979
494A32528A68F5B4DF45385CC7FB470224F25D8AC9C81AB0DBD291AA4764BB17
9A6D21675317433CE6EE860C9A2713265E1DA5E8F4024690252971EA5C2A566A
2B8379BCDDD0E6F73B1AD2D5A4D69D34D0013E98C87AD2BCE7AEED80F3BF4F69
6E5D67B8B825943F9B9979D5E1EA9348B1DD40A5DA39B20FA96B78CAD3E03747
27559A18DD6D52FFED8427376113C1A35840D64A53466071E1B769A28F161A99
A2F38E38C253947816B5E629AAC02BC77EF7B56CC95FBF291C05466C56E01E47FE92053C900C0F6F98B11D7873BB9AFC
8A7E57E1228F75F78D51C13FE79C269E43F007E55F5B87741BCADDAAA6402DF7
E088817700DBC7D778427464368D7771E3C20194CE60D08668578CAA527258B8
3E5AD04DE23578A3BBC5FB91608435EBA1FF1465EDCE3E064F60A2EED35C9015
647C9BFB61C0509D152A7B6B5C548DC558052F862314B42F4D1D8B98F6BF2412
3D659FF6999401CAB590681036C3FDABAF157C774928E0D7D76FAC08AA6CFE93
342362E28923E64DC5047E25E5A2F3FC8A6EB63554793CB8A1C99FFE632A370508CA208CA912470DB343A1636C751B9E
3B71D04AB09DFB44015F5553B4B76C9419C4D615F60184BA0B6A5687E47D66BA
14CF7621A4943DE2156AB8FDE8A9E74D26776D8362D9364387626488CB3DA5DC
2F9205BF8B310C33E38F571FFBDF6FC4BA5135457A2CF6CA9CD319F3EDF4BF6E
785EDF05A2111B8E4A126BE274C9BD8D6C0482F4A2B716FFAE93EDB8D1634F41
4B26880D1AE8EC1D285296F473EB5A805CF1C1EA47B899A6A3F8E9EFDB2CBCA3
A002B3ED0D1FCBC02298BFE7F18207CD58AB21D358F20855D067939EF50DCC08
BE82806DE526A6453C6FA309DAE0B52D67A98A194753DD4CC2C8C196A47B253F60149FAF49D0396E1F24CB1EDF1430DA
031686817FB37936FD0313B9358FD35BAF5DEB924F7A939C4B843DD095F11806
3A7B7A7AE8723C2A060FF368AB048A48737D4EEAD3C97BF98BC9E8CAE552431B
357C4A1A41F43100208863F2E607AE14CC55235D757CDE5C491BE405BB72BDB4
0C46E442B9AC3C479C18D4D94AB3E5124D4033AFD05AE00AC6881DD62F11E07F
8705CF1D9B202056CEBD98FF25CB0B6BF40175DBDC2FE86FE2A7D2AC796F818EA71A8C1312E9C7FCE6CC3D11FBBA98E4
IV: AF 0B A3 13 56 FA F7 46 76 78 25 28 34 16 3D 62
77995F096640A6CA8735DE839975FA3573145DDB995E45F58AECCD6A6F2D6FCB
A062DD58F9957EC098075344DFF69FB3B2A3C9893D4240C74BE32299F330290B
2AD2CCC4FB760D772001A903A995435260F442152BDCD5B075FBC61015BEC7E1
34AE78CF87A10211C8E6F6E2EE18C4F0BBE3B677094B7118E03AD9E89AF70E28
41943E7507D37A344F56EDF4BBDCDA75FAA10A6E97DF801ACF2A0E97E41782053CA74E31E3488EA1AFE29369E7A542C7
9FA67B118BC1FE289F38A78DA4E1FFBAEB4498404B49CBD9690B9421FC05564D
3A872E97A668C644D3827273ADDA6B1BC689A3AD09F5980EC7461E40624653BE
5E1F4D865E5F4176DBF7832992B60947812E05701E647CF36427C2EE04F97FE2
7FCF6E437D0DA231A2937C46622C4939F0045AEF5CF7FCF5D97E24B67995F0D3
D09F230FEDB9CB690B5AC7C6BCE86B0779D9C233D2823562EABE340FF06C819D
84F0A81ABB7857438BF52BE8988C1A471EFEDFE16EC11851BFC39F34EB26236F318CFAAEC9A53AD5500D48CAE21E777A
F3FDDDD5DB6038D0E2FC02750530325976ADA2600DE19BF736AF6CB7E810D7627B4F396963F0288F486182228B9AAE22
87E07B23B3B2740D93C82696C020057CC7F3864ABD6E6967656F44427C529DD1
20C35809F7F5161C21E643A606DC48A5CC85BCEB546A03023DF778C4499426E3
81CCF1CA68E2B6663DA9D12FEE241307A2E449440901793A955CB5D5915819DD
1B66D0664451153D0124364834E1543960A756351330523C3FFE83DA4EE7F0E6
7025D550A40466B472BA71F3248C37E6DE1FD59ED5C11CBB26238795DD44F4B21BD447F3CA72AED6A25B977982100A1E
99F38C3F7C89D2805FB36F931AC5D1B248A56838AC29E13B1255CAE706B68216
D138C616E4E1F6053177118C94F65C0BA6B155286CE63E0728E3F2D2BF6C6A98
276E646DBF54B341F93AB4E1C36525AF983879F7251D84BB02DD54F4A5E0FA85A3278891F7ADA9ADE2F8AAD010F6F6D4
3F3598143FE40E04FE25EADE1EC2B4CDAE339AF7730AE9DC45C97C0E44B299DBCC0E9DA6F4B0EE00F25D2FDD9E1C6BF5
20FA8F62628FEA51A584CE298F22E60FF85BFE193AF1C5DE57605FF02E90739C
B14B4896088EF58E0CE659511C93782FB5F94BC69B64E5011EBD10DF18FFB3B1
90BBE045FFEA06A77B55B0B6D0CFA8F12C4E1B35FB0111DD0C2CF1637AE8924A
04B87BC1D09E8EE3C8A91CE75169546D37868B2D87BF2D712623F84937ACE974
B8C5B04070FFB27B4686057C57F762FA3CAF2BBD3E5BEBE462C1C2FC283AE118
A40B154CEC2F5F989CA6F30703A0133217530D41F12739B25E2C1BEF54E6AC7C
4F5B9A68E8DEDB00410F5AD7FB7F7CA8F43B75F0457DA2AFAA8279A8C4AF34AB
9A7B185F6A157B1886DC6AA98B1F3D6899331D8BDDBAAC9620321E16BB4CC7E8
4A710E11F1C7A7138065801BDB4E72B07608220BBCF7455111FDD41DC0290B94
3A5B715089F926049077172755B0C48B4A4420031787D7DB113CF402C7D3D0AE
EE0B90EC27EC0F4A8DCD3C747E17594E0A27A92E05F2DE7B0457873C7154E075
0B9B201C209072676A47225BE4E43B4631B080A85F9FCFAA5683A4F9A727187A
13A15C606AA2EA40F2DCDE7F44217F02D2D9796CAC9164100B211D7A22CF333B
DF5292BBF35AB1408956D439A81EF12F53573F985489727A10FB652B7BD8B10D
50E59C9DD3A08EA8752656B753B8D9D2BFD674EB4C5F0DCAE9870E81D7F00F6AAC133FA7C7307FA197D551EE877F8CD7
E173C1798596A31F697D63E0CCDDFAB14B1B1E299DD642102A7858ECC795CF1B
92D3326A93AA6B37041F219C8035F37A057C1B69BECA7881098BED2A49C58751
27D17F007115734FA0F55F2BDF016ECE8DFA703FA6D61729456E95B78FC8AC29
4FF7306A426B7DE021D59968FAEF3453F555A9A952D81C4008D5000513799DEA
660CB0D4634EABC6CAA9E321CB08FC0C8C8F6BAE0FAF0C10C1FCCBA93B68D9B4
86D84C91BFBF0DE22088C0F5A8598A2C2807033E60BC11333E8D1A6188F043D5
F3E0E8566E12ADBA44974A3CA1D6D60456649031DCAD4365D0AE80FEDBC80AAA106A9BAB39448CD62EF916A59ECA9579
F4D6EB6D241B17CA0A9E73E93DA3B58B6B257CC0484FC92E285984A09FD4CEA9
094265CB574E0C9B8954B3130A2017492B1149C3FB9239A6B690A9C7B6635E5A
BE67B61B2F99BAA4AF94B71CB5F2386417D5F3B187899222D2671B1147BA9932
74840B34C9F27A76FCB593629C8114BCABD1B1CE96E22CC378DC9E7BEEF263FB
2511F44F0A13D94B55D7FF3297194E47D6987890F9170BCBC14A7607C5A38E01
FD0CF9314CB9B949CEFE1DA3FA05A18FBEEF751B4DC900DBAE068EE211C4492C
22ECD6934472760CF806E7C9E86885D0C0AAE501EDBF9DCB7ADC7AE53F3B73C38F2B6FB3FD0F867C5B5BFD00440CB43A
325CA78241AE4EE784CC867815403E342F77BB428EB1FE189AD569F10170CB98
BF065D29EC8E2BB411F0131DF3A06BDF07B1436A14004D0E11E1261F0E232CB8
CE015802FCE9AFD9807F855D813FD06D5446A8953057A79BC4A452BDAB8E9DD7
C6B569EB172EC4609966E2C9426BE99A86529073A57824B1752392658C4E87F08ED8675A32F44E413CD6037CA4A0DE71

View File

@@ -1,7 +1,7 @@
# to use manual settings and prevent them from being deleted on upgrade, rename *_user.example files to *_user
Filetype: Flipper SubGhz Setting File
Version: 1
# Add Standard frequencies for your region
# Add Standard frequencies included with firmware and place user frequencies after them
#Add_standard_frequencies: true
# Default Frequency: used as default for "Read" and "Read Raw"

View File

@@ -1,5 +1,55 @@
# How to use Flipper as a new SubGHz remote (not clone of original remote)
### If your system is not added here that doesn't mean flipper don't support it! Look into add manually menu, and search for your manufacturers inscturctions!
### Also many supported systems can be used only from `Read` mode, `Add Manually` is used only to make new remotes that can be binded with receiver
## AN-Motors AT4
**This instruction for older boards, if your has no** `Learn` **button but has buttons** `F`, `CL`, `+`, `-` **read instruction from Alutech AT4N**
1. Create new remote with randomly generated serial: Go to SubGHz -> Add Manually -> AN-Motors AT4 433Mhz
2. Open your new remote file
3. Open your receiver box, find button `Learn` click it one time, led will turn on.
4. Press `Send` on your flipper one time, led on receiver board will turn off.
5. Press `Send` on your flipper again, led on receiver will start flashing, wait couple seconds until led turns off.
6. Done
Watch this video to learn more (video in Russian language): https://www.youtube.com/watch?v=URVMtTELcnU
## Alutech AT4N (AN-Motors)
1. Create new remote with randomly generated serial: Go to SubGHz -> Add Manually -> Alutech AT4N 433Mhz
2. Open your new remote file
3. Open your receiver box, find button `F` press it for ~3sec, display will show `Pr`.
4. Click `F` button couple times until you see `Lr` on screen
5. Using buttons `+` / `-` select free number that has no remotes in it (if it has remote programmed on that number, it will show a red dot on the down right corner)
6. Press `Send` on your flipper one time, display on receiver board will flash and red dot will appear next to remote number.
7. Press button `F` on receiver board for ~3sec to exit programming mode
8. Done
Watch this video to learn more and see how different boards can be programmed (video in Russian language): https://www.youtube.com/watch?v=XrOVVYhFXDg
## Aprimatic TR
1. Create new remote with randomly generated serial: Go to SubGHz -> Add Manually -> KL: Aprimatic 433Mhz
2. Open your new remote file
3. Push all 4 buttons at same time on your existing remote thats already works with receiver
4. Receiver makes a continuous beep
5. Press `Send` on your flipper for ~2 seconds
6. Wait until receiver stops beeping
7. Done?
## Doorhan
1. Create new remote with randomly generated serial: Go to SubGHz -> Add Manually -> KL: Doorhan 433Mhz or 315Mhz depends on your receiver (find out by reading your existing remote)
2. Open your new remote file
3. Push `P` button for ~2 sec, led will start flashing
4. Press `Send` on your flipper for ~2 seconds
5. Led on the receiver board will flash and turn off
6. Done!
Also you can program new remote using old remote on newer boards! See first video below:
Watch this videos to learn more (videos in Russian language): https://www.youtube.com/watch?v=wZ5121HYv50 / https://www.youtube.com/watch?v=1ucrDKF3vWc
## Somfy Telis
1. Create new remote with randomly generated serial: Go to SubGHz -> Add Manually -> Somfy Telis 433Mhz

View File

@@ -119,7 +119,7 @@ bool furi_hal_subghz_check_radio(void) {
if((ver != 0) && (ver != 255)) {
FURI_LOG_D(TAG, "Radio check ok");
} else {
FURI_LOG_D(TAG, "Radio check failed");
FURI_LOG_D(TAG, "Radio check failed, revert to default");
result = false;
}
@@ -182,7 +182,7 @@ bool furi_hal_subghz_init_check(void) {
if(result) {
FURI_LOG_I(TAG, "Init OK");
} else {
FURI_LOG_E(TAG, "Failed to initialization");
FURI_LOG_E(TAG, "Selected CC1101 module init failed, revert to default");
}
return result;
}

View File

@@ -62,6 +62,7 @@ bool ds_generic_write_blank(OneWireHost* host, iButtonProtocolData* protocol_dat
}
static bool ds_generic_reset_callback(bool is_short, void* context) {
furi_assert(context);
DallasGenericProtocolData* data = context;
if(!is_short) {
onewire_slave_set_overdrive(data->state.bus, is_short);
@@ -93,7 +94,7 @@ void ds_generic_emulate(OneWireSlave* bus, iButtonProtocolData* protocol_data) {
DallasGenericProtocolData* data = protocol_data;
data->state.bus = bus;
onewire_slave_set_reset_callback(bus, ds_generic_reset_callback, NULL);
onewire_slave_set_reset_callback(bus, ds_generic_reset_callback, protocol_data);
onewire_slave_set_command_callback(bus, ds_generic_command_callback, protocol_data);
}

View File

@@ -330,17 +330,20 @@ bool mf_classic_dict_delete_index(MfClassicDict* dict, uint32_t target) {
uint32_t index = 0;
bool key_removed = false;
stream_rewind(dict->stream);
while(!key_removed) {
if(!stream_read_line(dict->stream, next_line)) break;
if(furi_string_get_char(next_line, 0) == '#') continue;
if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue;
if(index++ != target) continue;
stream_seek(dict->stream, -NFC_MF_CLASSIC_KEY_LEN, StreamOffsetFromCurrent);
if(!stream_delete(dict->stream, NFC_MF_CLASSIC_KEY_LEN)) break;
stream_seek(dict->stream, -(NFC_MF_CLASSIC_KEY_LEN + 1), StreamOffsetFromCurrent);
if(!stream_delete(dict->stream, (NFC_MF_CLASSIC_KEY_LEN + 1))) break;
dict->total_keys--;
key_removed = true;
}
stream_rewind(dict->stream);
furi_string_free(next_line);
return key_removed;
}

View File

@@ -638,7 +638,8 @@ static void nfc_worker_mf_classic_key_attack(
(uint32_t)key);
if(mf_classic_authenticate(tx_rx, block_num, key, MfClassicKeyA)) {
mf_classic_set_key_found(data, i, MfClassicKeyA, key);
FURI_LOG_D(TAG, "Key found");
FURI_LOG_D(
TAG, "Key A found: %04lx%08lx", (uint32_t)(key >> 32), (uint32_t)key);
nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context);
uint64_t found_key;
@@ -661,7 +662,8 @@ static void nfc_worker_mf_classic_key_attack(
(uint32_t)key);
if(mf_classic_authenticate(tx_rx, block_num, key, MfClassicKeyB)) {
mf_classic_set_key_found(data, i, MfClassicKeyB, key);
FURI_LOG_D(TAG, "Key found");
FURI_LOG_D(
TAG, "Key B found: %04lx%08lx", (uint32_t)(key >> 32), (uint32_t)key);
nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context);
}
}
@@ -760,9 +762,13 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) {
furi_hal_nfc_sleep();
deactivated = true;
} else {
mf_classic_set_key_not_found(data, i, MfClassicKeyA);
is_key_a_found = false;
FURI_LOG_D(TAG, "Key %dA not found in attack", i);
// If the key A is marked as found and matches the searching key, invalidate it
if(mf_classic_is_key_found(data, i, MfClassicKeyA) &&
data->block[i].value[0] == key) {
mf_classic_set_key_not_found(data, i, MfClassicKeyA);
is_key_a_found = false;
FURI_LOG_D(TAG, "Key %dA not found in attack", i);
}
}
if(!is_key_b_found) {
is_key_b_found = mf_classic_is_key_found(data, i, MfClassicKeyB);
@@ -775,9 +781,13 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) {
}
deactivated = true;
} else {
mf_classic_set_key_not_found(data, i, MfClassicKeyB);
is_key_b_found = false;
FURI_LOG_D(TAG, "Key %dB not found in attack", i);
// If the key B is marked as found and matches the searching key, invalidate it
if(mf_classic_is_key_found(data, i, MfClassicKeyB) &&
data->block[i].value[10] == key) {
mf_classic_set_key_not_found(data, i, MfClassicKeyB);
is_key_b_found = false;
FURI_LOG_D(TAG, "Key %dB not found in attack", i);
}
}
if(is_key_a_found && is_key_b_found) break;
if(nfc_worker->state != NfcWorkerStateMfClassicDictAttack) break;

View File

@@ -320,8 +320,12 @@ bool subghz_protocol_alutech_at_4n_create_data(
instance->generic.data_count_bit = 72;
bool res = subghz_protocol_alutech_at_4n_gen_data(instance, btn);
if(res) {
return SubGhzProtocolStatusOk ==
subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
if((res == SubGhzProtocolStatusOk) &&
!flipper_format_write_uint32(flipper_format, "CRC", &instance->crc, 1)) {
FURI_LOG_E(TAG, "Unable to add CRC");
res = false;
}
}
return res;
}

View File

@@ -88,7 +88,7 @@ static const char* mfname;
static uint8_t kl_type;
static uint8_t btn_temp_id;
static uint8_t btn_temp_id_original;
static bool bft_prog_mode;
static uint8_t klq_prog_mode;
static uint16_t temp_counter;
void keeloq_set_btn(uint8_t b) {
@@ -106,7 +106,7 @@ uint8_t keeloq_get_custom_btn() {
void keeloq_reset_original_btn() {
btn_temp_id_original = 0;
temp_counter = 0;
bft_prog_mode = false;
klq_prog_mode = 0;
}
void keeloq_reset_mfname() {
@@ -173,16 +173,27 @@ static bool subghz_protocol_keeloq_gen_data(
// BFT programming mode on / off conditions
if((strcmp(instance->manufacture_name, "BFT") == 0) && (btn == 0xF)) {
bft_prog_mode = true;
klq_prog_mode = 1;
}
if((strcmp(instance->manufacture_name, "BFT") == 0) && (btn != 0xF) && bft_prog_mode) {
bft_prog_mode = false;
if((strcmp(instance->manufacture_name, "BFT") == 0) && (btn != 0xF) && (klq_prog_mode == 1)) {
klq_prog_mode = 0;
}
// Aprimatic programming mode on / off conditions
if((strcmp(instance->manufacture_name, "Aprimatic") == 0) && (btn == 0xF)) {
klq_prog_mode = 2;
}
if((strcmp(instance->manufacture_name, "Aprimatic") == 0) && (btn != 0xF) &&
(klq_prog_mode == 2)) {
klq_prog_mode = 0;
}
// If we using BFT programming mode we will trasmit its seed in hop part like original remote
if(bft_prog_mode) {
if(klq_prog_mode == 1) {
hop = instance->generic.seed;
} else if(klq_prog_mode == 2) {
// If we using Aprimatic programming mode we will trasmit some strange looking hop value, why? cuz manufacturer did it this way :)
hop = 0x1A2B3C4D;
}
if(counter_up && !bft_prog_mode) {
if(counter_up && klq_prog_mode == 0) {
if(instance->generic.cnt < 0xFFFF) {
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >= 0xFFFF) {
instance->generic.cnt = 0;
@@ -193,11 +204,28 @@ static bool subghz_protocol_keeloq_gen_data(
instance->generic.cnt = 0;
}
}
if(!bft_prog_mode) {
if(klq_prog_mode == 0) {
uint32_t decrypt = (uint32_t)btn << 28 |
(instance->generic.serial & 0x3FF)
<< 16 | //ToDo in some protocols the discriminator is 0
instance->generic.cnt;
if(strcmp(instance->manufacture_name, "Aprimatic") == 0) {
// Aprimatic uses 12bit serial number + 2bit APR1 "parity" bit in front of it replacing first 2 bits of serial
// Thats in theory! We need to check if this is true for all Aprimatic remotes but we got only 3 recordings to test
// For now lets assume that this is true for all Aprimatic remotes, if not we will need to add some more code here
uint32_t apri_serial = instance->generic.serial;
uint8_t apr1 = 0;
for(uint16_t i = 1; i != 0b10000000000; i <<= 1) {
if(apri_serial & i) apr1++;
}
apri_serial &= 0b00001111111111;
if(apr1 % 2 == 0) {
apri_serial |= 0b110000000000;
}
decrypt = btn << 28 | (apri_serial & 0xFFF) << 16 | instance->generic.cnt;
}
// DTM Neo, Came_Space uses 12bit -> simple learning -- FAAC_RC,XT , Mutanco_Mutancode, Stilmatic(Schellenberg) -> 12bit normal learning
if((strcmp(instance->manufacture_name, "DTM_Neo") == 0) ||
(strcmp(instance->manufacture_name, "FAAC_RC,XT") == 0) ||
@@ -363,11 +391,14 @@ static bool
if(instance->manufacture_name == 0x0) {
instance->manufacture_name = "";
}
if(bft_prog_mode) {
if(klq_prog_mode == 1) {
instance->manufacture_name = "BFT";
} else if(klq_prog_mode == 2) {
instance->manufacture_name = "Aprimatic";
}
uint8_t klq_last_custom_btn = 0xA;
if(strcmp(instance->manufacture_name, "BFT") == 0) {
if((strcmp(instance->manufacture_name, "BFT") == 0) ||
(strcmp(instance->manufacture_name, "Aprimatic") == 0)) {
klq_last_custom_btn = 0xF;
}
@@ -649,7 +680,7 @@ void* subghz_protocol_decoder_keeloq_alloc(SubGhzEnvironment* environment) {
instance->keystore = subghz_environment_get_keystore(environment);
instance->manufacture_from_file = furi_string_alloc();
bft_prog_mode = false;
klq_prog_mode = 0;
return instance;
}
@@ -1151,7 +1182,7 @@ static void subghz_protocol_keeloq_check_remote_controller(
uint32_t key_hop = key & 0x00000000ffffffff;
// If we are in BFT programming mode we will set previous remembered counter and skip mf keys check
if(!bft_prog_mode) {
if(klq_prog_mode == 0) {
// Check key AN-Motors
if((key_hop >> 24) == ((key_hop >> 16) & 0x00ff) &&
(key_fix >> 28) == ((key_hop >> 12) & 0x0f) && (key_hop & 0xFFF) == 0x404) {
@@ -1168,10 +1199,14 @@ static void subghz_protocol_keeloq_check_remote_controller(
}
temp_counter = instance->cnt;
} else {
} else if(klq_prog_mode == 1) {
*manufacture_name = "BFT";
mfname = *manufacture_name;
instance->cnt = temp_counter;
} else if(klq_prog_mode == 2) {
*manufacture_name = "Aprimatic";
mfname = *manufacture_name;
instance->cnt = temp_counter;
}
instance->serial = key_fix & 0x0FFFFFFF;