Преглед изворни кода

little hack to marauder companion app to add camera commands

Erwin Ried пре 3 година
родитељ
комит
08d42aa2ac
16 измењених фајлова са 866 додато и 0 уклоњено
  1. 2 0
      flipper_companion_app/0xchocolate-flipperzero-firmware-with-wifi-marauder-companion- Flipper Zero firmware source code with WiFi Marauder companion.url
  2. BIN
      flipper_companion_app/ESP32CAM_Marauder.fap
  3. 12 0
      flipper_companion_app/applications/plugins/wifi_marauder_companion/application.fam
  4. 30 0
      flipper_companion_app/applications/plugins/wifi_marauder_companion/scenes/wifi_marauder_scene.c
  5. 29 0
      flipper_companion_app/applications/plugins/wifi_marauder_companion/scenes/wifi_marauder_scene.h
  6. 3 0
      flipper_companion_app/applications/plugins/wifi_marauder_companion/scenes/wifi_marauder_scene_config.h
  7. 92 0
      flipper_companion_app/applications/plugins/wifi_marauder_companion/scenes/wifi_marauder_scene_console_output.c
  8. 232 0
      flipper_companion_app/applications/plugins/wifi_marauder_companion/scenes/wifi_marauder_scene_start.c
  9. 154 0
      flipper_companion_app/applications/plugins/wifi_marauder_companion/scenes/wifi_marauder_scene_text_input.c
  10. BIN
      flipper_companion_app/applications/plugins/wifi_marauder_companion/wifi_10px.png
  11. 109 0
      flipper_companion_app/applications/plugins/wifi_marauder_companion/wifi_marauder_app.c
  12. 11 0
      flipper_companion_app/applications/plugins/wifi_marauder_companion/wifi_marauder_app.h
  13. 76 0
      flipper_companion_app/applications/plugins/wifi_marauder_companion/wifi_marauder_app_i.h
  14. 9 0
      flipper_companion_app/applications/plugins/wifi_marauder_companion/wifi_marauder_custom_event.h
  15. 93 0
      flipper_companion_app/applications/plugins/wifi_marauder_companion/wifi_marauder_uart.c
  16. 14 0
      flipper_companion_app/applications/plugins/wifi_marauder_companion/wifi_marauder_uart.h

+ 2 - 0
flipper_companion_app/0xchocolate-flipperzero-firmware-with-wifi-marauder-companion- Flipper Zero firmware source code with WiFi Marauder companion.url

@@ -0,0 +1,2 @@
+[InternetShortcut]
+URL=https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion

BIN
flipper_companion_app/ESP32CAM_Marauder.fap


+ 12 - 0
flipper_companion_app/applications/plugins/wifi_marauder_companion/application.fam

@@ -0,0 +1,12 @@
+App(
+    appid="ESP32CAM_Marauder",
+    name="[ESP32CAM] Marauder",
+    apptype=FlipperAppType.EXTERNAL,
+    entry_point="wifi_marauder_app",
+    cdefines=["APP_WIFI_MARAUDER"],
+    requires=["gui"],
+    stack_size=1 * 1024,
+    order=90,
+    fap_icon="wifi_10px.png",
+    fap_category="GPIO",
+)

+ 30 - 0
flipper_companion_app/applications/plugins/wifi_marauder_companion/scenes/wifi_marauder_scene.c

@@ -0,0 +1,30 @@
+#include "wifi_marauder_scene.h"
+
+// Generate scene on_enter handlers array
+#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
+void (*const wifi_marauder_scene_on_enter_handlers[])(void*) = {
+#include "wifi_marauder_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 wifi_marauder_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
+#include "wifi_marauder_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 wifi_marauder_scene_on_exit_handlers[])(void* context) = {
+#include "wifi_marauder_scene_config.h"
+};
+#undef ADD_SCENE
+
+// Initialize scene handlers configuration structure
+const SceneManagerHandlers wifi_marauder_scene_handlers = {
+    .on_enter_handlers = wifi_marauder_scene_on_enter_handlers,
+    .on_event_handlers = wifi_marauder_scene_on_event_handlers,
+    .on_exit_handlers = wifi_marauder_scene_on_exit_handlers,
+    .scene_num = WifiMarauderSceneNum,
+};

+ 29 - 0
flipper_companion_app/applications/plugins/wifi_marauder_companion/scenes/wifi_marauder_scene.h

@@ -0,0 +1,29 @@
+#pragma once
+
+#include <gui/scene_manager.h>
+
+// Generate scene id and total number
+#define ADD_SCENE(prefix, name, id) WifiMarauderScene##id,
+typedef enum {
+#include "wifi_marauder_scene_config.h"
+    WifiMarauderSceneNum,
+} WifiMarauderScene;
+#undef ADD_SCENE
+
+extern const SceneManagerHandlers wifi_marauder_scene_handlers;
+
+// Generate scene on_enter handlers declaration
+#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
+#include "wifi_marauder_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 "wifi_marauder_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 "wifi_marauder_scene_config.h"
+#undef ADD_SCENE

+ 3 - 0
flipper_companion_app/applications/plugins/wifi_marauder_companion/scenes/wifi_marauder_scene_config.h

@@ -0,0 +1,3 @@
+ADD_SCENE(wifi_marauder, start, Start)
+ADD_SCENE(wifi_marauder, console_output, ConsoleOutput)
+ADD_SCENE(wifi_marauder, text_input, TextInput)

+ 92 - 0
flipper_companion_app/applications/plugins/wifi_marauder_companion/scenes/wifi_marauder_scene_console_output.c

@@ -0,0 +1,92 @@
+#include "../wifi_marauder_app_i.h"
+
+void wifi_marauder_console_output_handle_rx_data_cb(uint8_t* buf, size_t len, void* context) {
+    furi_assert(context);
+    WifiMarauderApp* app = context;
+
+    // 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) {
+        furi_string_right(app->text_box_store, app->text_box_store_strlen / 2);
+        app->text_box_store_strlen = furi_string_size(app->text_box_store) + len;
+    }
+
+    // Null-terminate buf and append to text box store
+    buf[len] = '\0';
+    furi_string_cat_printf(app->text_box_store, "%s", buf);
+
+    view_dispatcher_send_custom_event(app->view_dispatcher, WifiMarauderEventRefreshConsoleOutput);
+}
+
+void wifi_marauder_scene_console_output_on_enter(void* context) {
+    WifiMarauderApp* app = context;
+
+    TextBox* text_box = app->text_box;
+    text_box_reset(app->text_box);
+    text_box_set_font(text_box, TextBoxFontText);
+    if(app->focus_console_start) {
+        text_box_set_focus(text_box, TextBoxFocusStart);
+    } else {
+        text_box_set_focus(text_box, TextBoxFocusEnd);
+    }
+    if(app->is_command) {
+        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 v0.3.0\nFor app support/feedback,\nreach out to me:\n@cococode#6011 (discord)\n0xchocolate (github)\n";
+            furi_string_cat_str(app->text_box_store, help_msg);
+            app->text_box_store_strlen += strlen(help_msg);
+        }
+
+        if(app->show_stopscan_tip) {
+            const char* help_msg = "Press BACK to send stopscan\n";
+            furi_string_cat_str(app->text_box_store, help_msg);
+            app->text_box_store_strlen += strlen(help_msg);
+        }
+    }
+
+    // Set starting text - for "View Log", 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);
+    view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewConsoleOutput);
+
+    // Register callback to receive data
+    wifi_marauder_uart_set_handle_rx_data_cb(
+        app->uart, wifi_marauder_console_output_handle_rx_data_cb); // setup callback for rx thread
+
+    // Send command with newline '\n'
+    if(app->is_command && app->selected_tx_string) {
+        wifi_marauder_uart_tx(
+            (uint8_t*)(app->selected_tx_string), strlen(app->selected_tx_string));
+        wifi_marauder_uart_tx((uint8_t*)("\n"), 1);
+    }
+}
+
+bool wifi_marauder_scene_console_output_on_event(void* context, SceneManagerEvent event) {
+    WifiMarauderApp* app = context;
+
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        text_box_set_text(app->text_box, furi_string_get_cstr(app->text_box_store));
+        consumed = true;
+    } else if(event.type == SceneManagerEventTypeTick) {
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void wifi_marauder_scene_console_output_on_exit(void* context) {
+    WifiMarauderApp* app = context;
+
+    // Unregister rx callback
+    wifi_marauder_uart_set_handle_rx_data_cb(app->uart, NULL);
+
+    // Automatically stop the scan when exiting view
+    if(app->is_command) {
+        wifi_marauder_uart_tx((uint8_t*)("stopscan\n"), strlen("stopscan\n"));
+    }
+}

+ 232 - 0
flipper_companion_app/applications/plugins/wifi_marauder_companion/scenes/wifi_marauder_scene_start.c

@@ -0,0 +1,232 @@
+//** Includes sniffbt and sniffskim for compatible ESP32-WROOM hardware.
+//wifi_marauder_app_i.h also changed **//
+#include "../wifi_marauder_app_i.h"
+
+// For each command, define whether additional arguments are needed
+// (enabling text input to fill them out), and whether the console
+// text box should focus at the start of the output or the end
+typedef enum { NO_ARGS = 0, INPUT_ARGS, TOGGLE_ARGS } InputArgs;
+
+typedef enum { FOCUS_CONSOLE_END = 0, FOCUS_CONSOLE_START, FOCUS_CONSOLE_TOGGLE } FocusConsole;
+
+#define SHOW_STOPSCAN_TIP (true)
+#define NO_TIP (false)
+
+#define MAX_OPTIONS (9)
+typedef struct {
+    const char* item_string;
+    const char* options_menu[MAX_OPTIONS];
+    int num_options_menu;
+    const char* actual_commands[MAX_OPTIONS];
+    InputArgs needs_keyboard;
+    FocusConsole focus_console;
+    bool show_stopscan_tip;
+} WifiMarauderItem;
+
+// NUM_MENU_ITEMS defined in wifi_marauder_app_i.h - if you add an entry here, increment it!
+const WifiMarauderItem items[NUM_MENU_ITEMS] = {
+    {"View Log from", {"start", "end"}, 2, {"", ""}, NO_ARGS, FOCUS_CONSOLE_TOGGLE, NO_TIP},
+    {"Scan",
+     {"ap", "station"},
+     2,
+     {"scanap", "scansta"},
+     NO_ARGS,
+     FOCUS_CONSOLE_END,
+     SHOW_STOPSCAN_TIP},
+    {"SSID",
+     {"add rand", "add name", "remove"},
+     3,
+     {"ssid -a -g", "ssid -a -n", "ssid -r"},
+     INPUT_ARGS,
+     FOCUS_CONSOLE_START,
+     NO_TIP},
+    {"List",
+     {"ap", "ssid", "station"},
+     3,
+     {"list -a", "list -s", "list -c"},
+     NO_ARGS,
+     FOCUS_CONSOLE_START,
+     NO_TIP},
+    {"Select",
+     {"ap", "ssid", "station"},
+     3,
+     {"select -a", "select -s", "select -c"},
+     INPUT_ARGS,
+     FOCUS_CONSOLE_END,
+     NO_TIP},
+    {"Clear List",
+     {"ap", "ssid", "station"},
+     3,
+     {"clearlist -a", "clearlist -s", "clearlist -c"},
+     NO_ARGS,
+     FOCUS_CONSOLE_END,
+     NO_TIP},
+    {"Attack",
+     {"deauth", "probe", "rickroll"},
+     3,
+     {"attack -t deauth", "attack -t probe", "attack -t rickroll"},
+     NO_ARGS,
+     FOCUS_CONSOLE_END,
+     SHOW_STOPSCAN_TIP},
+    {"Targeted Deauth",
+     {"station", "manual"},
+     2,
+     {"attack -t deauth -c", "attack -t deauth -s"},
+     TOGGLE_ARGS,
+     FOCUS_CONSOLE_END,
+     SHOW_STOPSCAN_TIP},
+    {"Beacon Spam",
+     {"ap list", "ssid list", "random"},
+     3,
+     {"attack -t beacon -a", "attack -t beacon -l", "attack -t beacon -r"},
+     NO_ARGS,
+     FOCUS_CONSOLE_END,
+     SHOW_STOPSCAN_TIP},
+    {"Sniff",
+     {"beacon", "deauth", "esp", "pmkid", "probe", "pwn", "raw", "bt", "skim"},
+     9,
+     {"sniffbeacon",
+      "sniffdeauth",
+      "sniffesp",
+      "sniffpmkid",
+      "sniffprobe",
+      "sniffpwn",
+      "sniffraw",
+      "sniffbt",
+      "sniffskim"},
+     NO_ARGS,
+     FOCUS_CONSOLE_END,
+     SHOW_STOPSCAN_TIP},
+    {"Sniff PMKID on channel",
+     {""},
+     1,
+     {"sniffpmkid -c"},
+     INPUT_ARGS,
+     FOCUS_CONSOLE_END,
+     SHOW_STOPSCAN_TIP},
+    {"Channel",
+     {"get", "set"},
+     2,
+     {"channel", "channel -s"},
+     TOGGLE_ARGS,
+     FOCUS_CONSOLE_END,
+     NO_TIP},
+     {"Camera",
+     {"shoot", "photo"},
+     2,
+     {"flashlight", "flashlight"},
+     NO_ARGS,
+     FOCUS_CONSOLE_END,
+     NO_TIP},
+    {"Settings",
+     {"display", "restore", "ForcePMKID", "ForceProbe", "SavePCAP", "EnableLED", "other"},
+     7,
+     {"settings",
+      "settings -r",
+      "settings -s ForcePMKID enable",
+      "settings -s ForceProbe enable",
+      "settings -s SavePCAP enable",
+      "settings -s EnableLED enable",
+      "settings -s"},
+     TOGGLE_ARGS,
+     FOCUS_CONSOLE_START,
+     NO_TIP},
+    {"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},
+};
+
+static void wifi_marauder_scene_start_var_list_enter_callback(void* context, uint32_t index) {
+    furi_assert(context);
+    WifiMarauderApp* app = context;
+
+    furi_assert(index < NUM_MENU_ITEMS);
+    const WifiMarauderItem* item = &items[index];
+
+    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];
+    app->is_command = (1 <= index);
+    app->is_custom_tx_string = false;
+    app->selected_menu_index = index;
+    app->focus_console_start = (item->focus_console == FOCUS_CONSOLE_TOGGLE) ?
+                                   (selected_option_index == 0) :
+                                   item->focus_console;
+    app->show_stopscan_tip = item->show_stopscan_tip;
+
+    bool needs_keyboard = (item->needs_keyboard == TOGGLE_ARGS) ? (selected_option_index != 0) :
+                                                                  item->needs_keyboard;
+    if(needs_keyboard) {
+        view_dispatcher_send_custom_event(app->view_dispatcher, WifiMarauderEventStartKeyboard);
+    } else {
+        view_dispatcher_send_custom_event(app->view_dispatcher, WifiMarauderEventStartConsole);
+    }
+}
+
+static void wifi_marauder_scene_start_var_list_change_callback(VariableItem* item) {
+    furi_assert(item);
+
+    WifiMarauderApp* app = variable_item_get_context(item);
+    furi_assert(app);
+
+    const WifiMarauderItem* menu_item = &items[app->selected_menu_index];
+    uint8_t item_index = variable_item_get_current_value_index(item);
+    furi_assert(item_index < menu_item->num_options_menu);
+    variable_item_set_current_value_text(item, menu_item->options_menu[item_index]);
+    app->selected_option_index[app->selected_menu_index] = item_index;
+}
+
+void wifi_marauder_scene_start_on_enter(void* context) {
+    WifiMarauderApp* app = context;
+    VariableItemList* var_item_list = app->var_item_list;
+
+    variable_item_list_set_enter_callback(
+        var_item_list, wifi_marauder_scene_start_var_list_enter_callback, app);
+
+    VariableItem* item;
+    for(int i = 0; i < NUM_MENU_ITEMS; ++i) {
+        item = variable_item_list_add(
+            var_item_list,
+            items[i].item_string,
+            items[i].num_options_menu,
+            wifi_marauder_scene_start_var_list_change_callback,
+            app);
+        variable_item_set_current_value_index(item, app->selected_option_index[i]);
+        variable_item_set_current_value_text(
+            item, items[i].options_menu[app->selected_option_index[i]]);
+    }
+
+    variable_item_list_set_selected_item(
+        var_item_list, scene_manager_get_scene_state(app->scene_manager, WifiMarauderSceneStart));
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewVarItemList);
+}
+
+bool wifi_marauder_scene_start_on_event(void* context, SceneManagerEvent event) {
+    UNUSED(context);
+    WifiMarauderApp* app = context;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        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);
+        } 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);
+        }
+        consumed = true;
+    } else if(event.type == SceneManagerEventTypeTick) {
+        app->selected_menu_index = variable_item_list_get_selected_item_index(app->var_item_list);
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void wifi_marauder_scene_start_on_exit(void* context) {
+    WifiMarauderApp* app = context;
+    variable_item_list_reset(app->var_item_list);
+}

+ 154 - 0
flipper_companion_app/applications/plugins/wifi_marauder_companion/scenes/wifi_marauder_scene_text_input.c

@@ -0,0 +1,154 @@
+#include "../wifi_marauder_app_i.h"
+
+void wifi_marauder_scene_text_input_callback(void* context) {
+    WifiMarauderApp* app = context;
+
+    switch(app->special_case_input_step) {
+    case 0: // most commands
+        view_dispatcher_send_custom_event(app->view_dispatcher, WifiMarauderEventStartConsole);
+        break;
+    case 1: // special case for deauth: save source MAC
+        view_dispatcher_send_custom_event(app->view_dispatcher, WifiMarauderEventSaveSourceMac);
+        break;
+    case 2: // special case for deauth: save destination MAC
+        view_dispatcher_send_custom_event(
+            app->view_dispatcher, WifiMarauderEventSaveDestinationMac);
+        break;
+    default:
+        break;
+    }
+}
+
+void wifi_marauder_scene_text_input_on_enter(void* context) {
+    WifiMarauderApp* app = context;
+
+    if(0 ==
+       strncmp("attack -t deauth -s", app->selected_tx_string, strlen("attack -t deauth -s"))) {
+        // Special case for manual deauth input
+        app->special_case_input_step = 1;
+        bzero(app->text_input_store, WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE);
+    } else if(false == app->is_custom_tx_string) {
+        // Most commands
+        app->special_case_input_step = 0;
+
+        // Fill text input with selected string so that user can add to it
+        size_t length = strlen(app->selected_tx_string);
+        furi_assert(length < WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE);
+        bzero(app->text_input_store, WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE);
+        strncpy(app->text_input_store, app->selected_tx_string, length);
+
+        // Add space - because flipper keyboard currently doesn't have a space
+        app->text_input_store[length] = ' ';
+        app->text_input_store[length + 1] = '\0';
+        app->is_custom_tx_string = true;
+    }
+
+    // Setup view
+    TextInput* text_input = app->text_input;
+    // Add help message to header
+    if(app->special_case_input_step == 1) {
+        text_input_set_header_text(text_input, "Enter source MAC");
+    } else if(0 == strncmp("ssid -a -g", app->selected_tx_string, strlen("ssid -a -g"))) {
+        text_input_set_header_text(text_input, "Enter # SSIDs to generate");
+    } else if(0 == strncmp("ssid -a -n", app->selected_tx_string, strlen("ssid -a -n"))) {
+        text_input_set_header_text(text_input, "Enter SSID name to add");
+    } else if(0 == strncmp("ssid -r", app->selected_tx_string, strlen("ssid -r"))) {
+        text_input_set_header_text(text_input, "Remove target from SSID list");
+    } else if(0 == strncmp("select -a", app->selected_tx_string, strlen("select -a"))) {
+        text_input_set_header_text(text_input, "Add target from AP list");
+    } else if(0 == strncmp("select -s", app->selected_tx_string, strlen("select -s"))) {
+        text_input_set_header_text(text_input, "Add target from SSID list");
+    } else {
+        text_input_set_header_text(text_input, "Add command arguments");
+    }
+    text_input_set_result_callback(
+        text_input,
+        wifi_marauder_scene_text_input_callback,
+        app,
+        app->text_input_store,
+        WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE,
+        false);
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewTextInput);
+}
+
+bool wifi_marauder_scene_text_input_on_event(void* context, SceneManagerEvent event) {
+    WifiMarauderApp* app = context;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        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);
+            consumed = true;
+        } else if(event.event == WifiMarauderEventSaveSourceMac) {
+            if(12 != strlen(app->text_input_store)) {
+                text_input_set_header_text(app->text_input, "MAC must be 12 hex chars!");
+            } else {
+                snprintf(
+                    app->special_case_input_src_addr,
+                    sizeof(app->special_case_input_src_addr),
+                    "%c%c:%c%c:%c%c:%c%c:%c%c:%c%c",
+                    app->text_input_store[0],
+                    app->text_input_store[1],
+                    app->text_input_store[2],
+                    app->text_input_store[3],
+                    app->text_input_store[4],
+                    app->text_input_store[5],
+                    app->text_input_store[6],
+                    app->text_input_store[7],
+                    app->text_input_store[8],
+                    app->text_input_store[9],
+                    app->text_input_store[10],
+                    app->text_input_store[11]);
+
+                // Advance scene to input destination MAC, clear text input
+                app->special_case_input_step = 2;
+                bzero(app->text_input_store, WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE);
+                text_input_set_header_text(app->text_input, "Enter destination MAC");
+            }
+            consumed = true;
+        } else if(event.event == WifiMarauderEventSaveDestinationMac) {
+            if(12 != strlen(app->text_input_store)) {
+                text_input_set_header_text(app->text_input, "MAC must be 12 hex chars!");
+            } else {
+                snprintf(
+                    app->special_case_input_dst_addr,
+                    sizeof(app->special_case_input_dst_addr),
+                    "%c%c:%c%c:%c%c:%c%c:%c%c:%c%c",
+                    app->text_input_store[0],
+                    app->text_input_store[1],
+                    app->text_input_store[2],
+                    app->text_input_store[3],
+                    app->text_input_store[4],
+                    app->text_input_store[5],
+                    app->text_input_store[6],
+                    app->text_input_store[7],
+                    app->text_input_store[8],
+                    app->text_input_store[9],
+                    app->text_input_store[10],
+                    app->text_input_store[11]);
+
+                // Construct command with source and destination MACs
+                snprintf(
+                    app->text_input_store,
+                    WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE,
+                    "attack -t deauth -s %18s -d %18s",
+                    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);
+            }
+            consumed = true;
+        }
+    }
+
+    return consumed;
+}
+
+void wifi_marauder_scene_text_input_on_exit(void* context) {
+    WifiMarauderApp* app = context;
+
+    text_input_reset(app->text_input);
+}

BIN
flipper_companion_app/applications/plugins/wifi_marauder_companion/wifi_10px.png


+ 109 - 0
flipper_companion_app/applications/plugins/wifi_marauder_companion/wifi_marauder_app.c

@@ -0,0 +1,109 @@
+#include "wifi_marauder_app_i.h"
+
+#include <furi.h>
+#include <furi_hal.h>
+
+static bool wifi_marauder_app_custom_event_callback(void* context, uint32_t event) {
+    furi_assert(context);
+    WifiMarauderApp* app = context;
+    return scene_manager_handle_custom_event(app->scene_manager, event);
+}
+
+static bool wifi_marauder_app_back_event_callback(void* context) {
+    furi_assert(context);
+    WifiMarauderApp* app = context;
+    return scene_manager_handle_back_event(app->scene_manager);
+}
+
+static void wifi_marauder_app_tick_event_callback(void* context) {
+    furi_assert(context);
+    WifiMarauderApp* app = context;
+    scene_manager_handle_tick_event(app->scene_manager);
+}
+
+WifiMarauderApp* wifi_marauder_app_alloc() {
+    WifiMarauderApp* app = malloc(sizeof(WifiMarauderApp));
+
+    app->gui = furi_record_open(RECORD_GUI);
+
+    app->view_dispatcher = view_dispatcher_alloc();
+    app->scene_manager = scene_manager_alloc(&wifi_marauder_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, wifi_marauder_app_custom_event_callback);
+    view_dispatcher_set_navigation_event_callback(
+        app->view_dispatcher, wifi_marauder_app_back_event_callback);
+    view_dispatcher_set_tick_event_callback(
+        app->view_dispatcher, wifi_marauder_app_tick_event_callback, 100);
+
+    view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
+
+    app->var_item_list = variable_item_list_alloc();
+    view_dispatcher_add_view(
+        app->view_dispatcher,
+        WifiMarauderAppViewVarItemList,
+        variable_item_list_get_view(app->var_item_list));
+
+    for(int i = 0; i < NUM_MENU_ITEMS; ++i) {
+        app->selected_option_index[i] = 0;
+    }
+
+    app->special_case_input_step = 0;
+
+    app->text_box = text_box_alloc();
+    view_dispatcher_add_view(
+        app->view_dispatcher, WifiMarauderAppViewConsoleOutput, text_box_get_view(app->text_box));
+    app->text_box_store = furi_string_alloc();
+    furi_string_reserve(app->text_box_store, WIFI_MARAUDER_TEXT_BOX_STORE_SIZE);
+
+    app->text_input = text_input_alloc();
+    view_dispatcher_add_view(
+        app->view_dispatcher, WifiMarauderAppViewTextInput, text_input_get_view(app->text_input));
+
+    scene_manager_next_scene(app->scene_manager, WifiMarauderSceneStart);
+
+    return app;
+}
+
+void wifi_marauder_app_free(WifiMarauderApp* app) {
+    furi_assert(app);
+
+    // Views
+    view_dispatcher_remove_view(app->view_dispatcher, WifiMarauderAppViewVarItemList);
+    view_dispatcher_remove_view(app->view_dispatcher, WifiMarauderAppViewConsoleOutput);
+    view_dispatcher_remove_view(app->view_dispatcher, WifiMarauderAppViewTextInput);
+    text_box_free(app->text_box);
+    furi_string_free(app->text_box_store);
+    text_input_free(app->text_input);
+
+    // View dispatcher
+    view_dispatcher_free(app->view_dispatcher);
+    scene_manager_free(app->scene_manager);
+
+    wifi_marauder_uart_free(app->uart);
+
+    // Close records
+    furi_record_close(RECORD_GUI);
+
+    free(app);
+}
+
+int32_t wifi_marauder_app(void* p) {
+    UNUSED(p);
+    furi_hal_power_enable_otg();
+    furi_delay_ms(300);
+
+    WifiMarauderApp* wifi_marauder_app = wifi_marauder_app_alloc();
+
+    wifi_marauder_app->uart = wifi_marauder_uart_init(wifi_marauder_app);
+
+    view_dispatcher_run(wifi_marauder_app->view_dispatcher);
+
+    wifi_marauder_app_free(wifi_marauder_app);
+
+    furi_hal_power_disable_otg();
+
+    return 0;
+}

+ 11 - 0
flipper_companion_app/applications/plugins/wifi_marauder_companion/wifi_marauder_app.h

@@ -0,0 +1,11 @@
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct WifiMarauderApp WifiMarauderApp;
+
+#ifdef __cplusplus
+}
+#endif

+ 76 - 0
flipper_companion_app/applications/plugins/wifi_marauder_companion/wifi_marauder_app_i.h

@@ -0,0 +1,76 @@
+//** Includes sniffbt and sniffskim for compatible ESP32-WROOM hardware.
+// wifi_marauder_scene_start.c also changed **//
+#pragma once
+
+#include "wifi_marauder_app.h"
+#include "scenes/wifi_marauder_scene.h"
+#include "wifi_marauder_custom_event.h"
+#include "wifi_marauder_uart.h"
+
+#include <gui/gui.h>
+#include <gui/view_dispatcher.h>
+#include <gui/scene_manager.h>
+#include <gui/modules/text_box.h>
+#include <gui/modules/text_input.h>
+#include <gui/modules/variable_item_list.h>
+
+#define NUM_MENU_ITEMS (17)
+
+#define WIFI_MARAUDER_TEXT_BOX_STORE_SIZE (4096)
+#define WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE (512)
+
+struct WifiMarauderApp {
+    Gui* gui;
+    ViewDispatcher* view_dispatcher;
+    SceneManager* scene_manager;
+
+    char text_input_store[WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE + 1];
+    FuriString* text_box_store;
+    size_t text_box_store_strlen;
+    TextBox* text_box;
+    TextInput* text_input;
+    //Widget* widget;
+
+    VariableItemList* var_item_list;
+
+    WifiMarauderUart* uart;
+    int selected_menu_index;
+    int selected_option_index[NUM_MENU_ITEMS];
+    const char* selected_tx_string;
+    bool is_command;
+    bool is_custom_tx_string;
+    bool focus_console_start;
+    bool show_stopscan_tip;
+
+    // For input source and destination MAC in targeted deauth attack
+    int special_case_input_step;
+    char special_case_input_src_addr[20];
+    char special_case_input_dst_addr[20];
+};
+
+// Supported commands:
+// https://github.com/justcallmekoko/ESP32Marauder/wiki/cli
+//   Scan
+//    -> If list is empty, then start a new scanap. (Tap any button to stop.)
+//    -> If there's a list, provide option to rescan and dump list of targets to select.
+//    -> Press BACK to go back to top-level.
+//   Attack
+//    -> Beacon
+//    -> Deauth
+//    -> Probe
+//    -> Rickroll
+//   Sniff
+//    -> Beacon
+//    -> Deauth
+//    -> ESP
+//    -> PMKID
+//    -> Pwnagotchi
+//   Channel
+//   Update
+//   Reboot
+
+typedef enum {
+    WifiMarauderAppViewVarItemList,
+    WifiMarauderAppViewConsoleOutput,
+    WifiMarauderAppViewTextInput,
+} WifiMarauderAppView;

+ 9 - 0
flipper_companion_app/applications/plugins/wifi_marauder_companion/wifi_marauder_custom_event.h

@@ -0,0 +1,9 @@
+#pragma once
+
+typedef enum {
+    WifiMarauderEventRefreshConsoleOutput = 0,
+    WifiMarauderEventStartConsole,
+    WifiMarauderEventStartKeyboard,
+    WifiMarauderEventSaveSourceMac,
+    WifiMarauderEventSaveDestinationMac
+} WifiMarauderCustomEvent;

+ 93 - 0
flipper_companion_app/applications/plugins/wifi_marauder_companion/wifi_marauder_uart.c

@@ -0,0 +1,93 @@
+#include "wifi_marauder_app_i.h"
+#include "wifi_marauder_uart.h"
+
+#define UART_CH (FuriHalUartIdUSART1)
+#define BAUDRATE (115200)
+
+struct WifiMarauderUart {
+    WifiMarauderApp* app;
+    FuriThread* rx_thread;
+    FuriStreamBuffer* rx_stream;
+    uint8_t rx_buf[RX_BUF_SIZE + 1];
+    void (*handle_rx_data_cb)(uint8_t* buf, size_t len, void* context);
+};
+
+typedef enum {
+    WorkerEvtStop = (1 << 0),
+    WorkerEvtRxDone = (1 << 1),
+} WorkerEvtFlags;
+
+void wifi_marauder_uart_set_handle_rx_data_cb(
+    WifiMarauderUart* uart,
+    void (*handle_rx_data_cb)(uint8_t* buf, size_t len, void* context)) {
+    furi_assert(uart);
+    uart->handle_rx_data_cb = handle_rx_data_cb;
+}
+
+#define WORKER_ALL_RX_EVENTS (WorkerEvtStop | WorkerEvtRxDone)
+
+void wifi_marauder_uart_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) {
+    WifiMarauderUart* uart = (WifiMarauderUart*)context;
+
+    if(ev == UartIrqEventRXNE) {
+        furi_stream_buffer_send(uart->rx_stream, &data, 1, 0);
+        furi_thread_flags_set(furi_thread_get_id(uart->rx_thread), WorkerEvtRxDone);
+    }
+}
+
+static int32_t uart_worker(void* context) {
+    WifiMarauderUart* uart = (void*)context;
+
+    while(1) {
+        uint32_t events =
+            furi_thread_flags_wait(WORKER_ALL_RX_EVENTS, FuriFlagWaitAny, FuriWaitForever);
+        furi_check((events & FuriFlagError) == 0);
+        if(events & WorkerEvtStop) break;
+        if(events & WorkerEvtRxDone) {
+            size_t len = furi_stream_buffer_receive(uart->rx_stream, uart->rx_buf, RX_BUF_SIZE, 0);
+            if(len > 0) {
+                if(uart->handle_rx_data_cb) uart->handle_rx_data_cb(uart->rx_buf, len, uart->app);
+            }
+        }
+    }
+
+    furi_stream_buffer_free(uart->rx_stream);
+
+    return 0;
+}
+
+void wifi_marauder_uart_tx(uint8_t* data, size_t len) {
+    furi_hal_uart_tx(UART_CH, data, len);
+}
+
+WifiMarauderUart* wifi_marauder_uart_init(WifiMarauderApp* app) {
+    WifiMarauderUart* uart = malloc(sizeof(WifiMarauderUart));
+
+    uart->app = app;
+    uart->rx_stream = furi_stream_buffer_alloc(RX_BUF_SIZE, 1);
+    uart->rx_thread = furi_thread_alloc();
+    furi_thread_set_name(uart->rx_thread, "WifiMarauderUartRxThread");
+    furi_thread_set_stack_size(uart->rx_thread, 1024);
+    furi_thread_set_context(uart->rx_thread, uart);
+    furi_thread_set_callback(uart->rx_thread, uart_worker);
+    furi_thread_start(uart->rx_thread);
+
+    furi_hal_console_disable();
+    furi_hal_uart_set_br(UART_CH, BAUDRATE);
+    furi_hal_uart_set_irq_cb(UART_CH, wifi_marauder_uart_on_irq_cb, uart);
+
+    return uart;
+}
+
+void wifi_marauder_uart_free(WifiMarauderUart* uart) {
+    furi_assert(uart);
+
+    furi_thread_flags_set(furi_thread_get_id(uart->rx_thread), WorkerEvtStop);
+    furi_thread_join(uart->rx_thread);
+    furi_thread_free(uart->rx_thread);
+
+    furi_hal_uart_set_irq_cb(UART_CH, NULL, NULL);
+    furi_hal_console_enable();
+
+    free(uart);
+}

+ 14 - 0
flipper_companion_app/applications/plugins/wifi_marauder_companion/wifi_marauder_uart.h

@@ -0,0 +1,14 @@
+#pragma once
+
+#include "furi_hal.h"
+
+#define RX_BUF_SIZE (320)
+
+typedef struct WifiMarauderUart WifiMarauderUart;
+
+void wifi_marauder_uart_set_handle_rx_data_cb(
+    WifiMarauderUart* uart,
+    void (*handle_rx_data_cb)(uint8_t* buf, size_t len, void* context));
+void wifi_marauder_uart_tx(uint8_t* data, size_t len);
+WifiMarauderUart* wifi_marauder_uart_init(WifiMarauderApp* app);
+void wifi_marauder_uart_free(WifiMarauderUart* uart);