Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 53 additions & 2 deletions applications/main/bad_usb/bad_usb_app.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
#include "bad_usb_app_i.h"
#include "bad_usb_settings_filename.h"
#include <furi.h>
#include <furi_hal.h>
#include <storage/storage.h>
#include <lib/toolbox/path.h>

#define BAD_USB_SETTINGS_PATH BAD_USB_APP_BASE_FOLDER "/" BAD_USB_SETTINGS_FILE_NAME

static bool bad_usb_app_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
BadUsbApp* app = context;
Expand All @@ -22,15 +25,45 @@ static void bad_usb_app_tick_event_callback(void* context) {
scene_manager_handle_tick_event(app->scene_manager);
}

static void bad_usb_load_settings(BadUsbApp* app) {
File* settings_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
if(storage_file_open(settings_file, BAD_USB_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) {
char chr;
while((storage_file_read(settings_file, &chr, 1) == 1) &&
!storage_file_eof(settings_file) && !isspace(chr)) {
furi_string_push_back(app->keyboard_layout, chr);
}
}
storage_file_close(settings_file);
storage_file_free(settings_file);
}

static void bad_usb_save_settings(BadUsbApp* app) {
File* settings_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
if(storage_file_open(settings_file, BAD_USB_SETTINGS_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) {
storage_file_write(
settings_file,
furi_string_get_cstr(app->keyboard_layout),
furi_string_size(app->keyboard_layout));
storage_file_write(settings_file, "\n", 1);
}
storage_file_close(settings_file);
storage_file_free(settings_file);
}

BadUsbApp* bad_usb_app_alloc(char* arg) {
BadUsbApp* app = malloc(sizeof(BadUsbApp));

app->file_path = furi_string_alloc();
app->bad_usb_script = NULL;

app->file_path = furi_string_alloc();
app->keyboard_layout = furi_string_alloc();
if(arg && strlen(arg)) {
furi_string_set(app->file_path, arg);
}

bad_usb_load_settings(app);

app->gui = furi_record_open(RECORD_GUI);
app->notifications = furi_record_open(RECORD_NOTIFICATION);
app->dialogs = furi_record_open(RECORD_DIALOGS);
Expand All @@ -53,6 +86,10 @@ BadUsbApp* bad_usb_app_alloc(char* arg) {
view_dispatcher_add_view(
app->view_dispatcher, BadUsbAppViewError, widget_get_view(app->widget));

app->submenu = submenu_alloc();
view_dispatcher_add_view(
app->view_dispatcher, BadUsbAppViewConfig, submenu_get_view(app->submenu));

app->bad_usb_view = bad_usb_alloc();
view_dispatcher_add_view(
app->view_dispatcher, BadUsbAppViewWork, bad_usb_get_view(app->bad_usb_view));
Expand All @@ -64,9 +101,11 @@ BadUsbApp* bad_usb_app_alloc(char* arg) {
scene_manager_next_scene(app->scene_manager, BadUsbSceneError);
} else {
if(!furi_string_empty(app->file_path)) {
app->bad_usb_script = bad_usb_script_open(app->file_path);
bad_usb_script_set_keyboard_layout(app->bad_usb_script, app->keyboard_layout);
scene_manager_next_scene(app->scene_manager, BadUsbSceneWork);
} else {
furi_string_set(app->file_path, BAD_USB_APP_PATH_FOLDER);
furi_string_set(app->file_path, BAD_USB_APP_BASE_FOLDER);
scene_manager_next_scene(app->scene_manager, BadUsbSceneFileSelect);
}
}
Expand All @@ -77,6 +116,11 @@ BadUsbApp* bad_usb_app_alloc(char* arg) {
void bad_usb_app_free(BadUsbApp* app) {
furi_assert(app);

if(app->bad_usb_script) {
bad_usb_script_close(app->bad_usb_script);
app->bad_usb_script = NULL;
}

// Views
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork);
bad_usb_free(app->bad_usb_view);
Expand All @@ -85,6 +129,10 @@ void bad_usb_app_free(BadUsbApp* app) {
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewError);
widget_free(app->widget);

// Submenu
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewConfig);
submenu_free(app->submenu);

// View dispatcher
view_dispatcher_free(app->view_dispatcher);
scene_manager_free(app->scene_manager);
Expand All @@ -94,7 +142,10 @@ void bad_usb_app_free(BadUsbApp* app) {
furi_record_close(RECORD_NOTIFICATION);
furi_record_close(RECORD_DIALOGS);

bad_usb_save_settings(app);

furi_string_free(app->file_path);
furi_string_free(app->keyboard_layout);

free(app);
}
Expand Down
11 changes: 8 additions & 3 deletions applications/main/bad_usb/bad_usb_app_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
#include <gui/modules/widget.h>
#include "views/bad_usb_view.h"

#define BAD_USB_APP_PATH_FOLDER ANY_PATH("badusb")
#define BAD_USB_APP_EXTENSION ".txt"
#define BAD_USB_APP_BASE_FOLDER ANY_PATH("badusb")
#define BAD_USB_APP_PATH_LAYOUT_FOLDER BAD_USB_APP_BASE_FOLDER "/layouts"
#define BAD_USB_APP_SCRIPT_EXTENSION ".txt"
#define BAD_USB_APP_LAYOUT_EXTENSION ".kl"

typedef enum {
BadUsbAppErrorNoFiles,
Expand All @@ -30,14 +32,17 @@ struct BadUsbApp {
NotificationApp* notifications;
DialogsApp* dialogs;
Widget* widget;
Submenu* submenu;

BadUsbAppError error;
FuriString* file_path;
FuriString* keyboard_layout;
BadUsb* bad_usb_view;
BadUsbScript* bad_usb_script;
};

typedef enum {
BadUsbAppViewError,
BadUsbAppViewWork,
} BadUsbAppView;
BadUsbAppViewConfig,
} BadUsbAppView;
56 changes: 48 additions & 8 deletions applications/main/bad_usb/bad_usb_script.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
#define SCRIPT_STATE_END (-2)
#define SCRIPT_STATE_NEXT_LINE (-3)

#define BADUSB_ASCII_TO_KEY(script, x) \
(((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE)

typedef enum {
WorkerEvtToggle = (1 << 0),
WorkerEvtEnd = (1 << 1),
Expand All @@ -28,6 +31,7 @@ struct BadUsbScript {
BadUsbState st;
FuriString* file_path;
uint32_t defdelay;
uint16_t layout[128];
FuriThread* thread;
uint8_t file_buf[FILE_BUFFER_LEN + 1];
uint8_t buf_start;
Expand Down Expand Up @@ -115,6 +119,8 @@ static const char ducky_cmd_altchar[] = {"ALTCHAR "};
static const char ducky_cmd_altstr_1[] = {"ALTSTRING "};
static const char ducky_cmd_altstr_2[] = {"ALTCODE "};

static const char ducky_cmd_lang[] = {"DUCKY_LANG"};

static const uint8_t numpad_keys[10] = {
HID_KEYPAD_0,
HID_KEYPAD_1,
Expand Down Expand Up @@ -204,10 +210,10 @@ static bool ducky_altstring(const char* param) {
return state;
}

static bool ducky_string(const char* param) {
static bool ducky_string(BadUsbScript* bad_usb, const char* param) {
uint32_t i = 0;
while(param[i] != '\0') {
uint16_t keycode = HID_ASCII_TO_KEY(param[i]);
uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_usb, param[i]);
if(keycode != HID_KEYBOARD_NONE) {
furi_hal_hid_kb_press(keycode);
furi_hal_hid_kb_release(keycode);
Expand All @@ -217,7 +223,7 @@ static bool ducky_string(const char* param) {
return true;
}

static uint16_t ducky_get_keycode(const char* param, bool accept_chars) {
static uint16_t ducky_get_keycode(BadUsbScript* bad_usb, const char* param, bool accept_chars) {
for(size_t i = 0; i < (sizeof(ducky_keys) / sizeof(ducky_keys[0])); i++) {
size_t key_cmd_len = strlen(ducky_keys[i].name);
if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) &&
Expand All @@ -226,7 +232,7 @@ static uint16_t ducky_get_keycode(const char* param, bool accept_chars) {
}
}
if((accept_chars) && (strlen(param) > 0)) {
return (HID_ASCII_TO_KEY(param[0]) & 0xFF);
return (BADUSB_ASCII_TO_KEY(bad_usb, param[0]) & 0xFF);
}
return 0;
}
Expand All @@ -250,6 +256,9 @@ static int32_t
} else if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) {
// ID - executed in ducky_script_preload
return (0);
} else if(strncmp(line_tmp, ducky_cmd_lang, strlen(ducky_cmd_lang)) == 0) {
// DUCKY_LANG - ignore command to retain compatibility with existing scripts
return (0);
} else if(strncmp(line_tmp, ducky_cmd_delay, strlen(ducky_cmd_delay)) == 0) {
// DELAY
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
Expand All @@ -275,7 +284,7 @@ static int32_t
} else if(strncmp(line_tmp, ducky_cmd_string, strlen(ducky_cmd_string)) == 0) {
// STRING
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
state = ducky_string(line_tmp);
state = ducky_string(bad_usb, line_tmp);
if(!state && error != NULL) {
snprintf(error, error_len, "Invalid string %s", line_tmp);
}
Expand Down Expand Up @@ -311,14 +320,14 @@ static int32_t
} else if(strncmp(line_tmp, ducky_cmd_sysrq, strlen(ducky_cmd_sysrq)) == 0) {
// SYSRQ
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
uint16_t key = ducky_get_keycode(line_tmp, true);
uint16_t key = ducky_get_keycode(bad_usb, line_tmp, true);
furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN);
furi_hal_hid_kb_press(key);
furi_hal_hid_kb_release_all();
return (0);
} else {
// Special keys + modifiers
uint16_t key = ducky_get_keycode(line_tmp, false);
uint16_t key = ducky_get_keycode(bad_usb, line_tmp, false);
if(key == HID_KEYBOARD_NONE) {
if(error != NULL) {
snprintf(error, error_len, "No keycode defined for %s", line_tmp);
Expand All @@ -328,7 +337,7 @@ static int32_t
if((key & 0xFF00) != 0) {
// It's a modifier key
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
key |= ducky_get_keycode(line_tmp, true);
key |= ducky_get_keycode(bad_usb, line_tmp, true);
}
furi_hal_hid_kb_press(key);
furi_hal_hid_kb_release(key);
Expand Down Expand Up @@ -649,12 +658,19 @@ static int32_t bad_usb_worker(void* context) {
return 0;
}

static void bad_usb_script_set_default_keyboard_layout(BadUsbScript* bad_usb) {
furi_assert(bad_usb);
memset(bad_usb->layout, HID_KEYBOARD_NONE, sizeof(bad_usb->layout));
memcpy(bad_usb->layout, hid_asciimap, MIN(sizeof(hid_asciimap), sizeof(bad_usb->layout)));
}

BadUsbScript* bad_usb_script_open(FuriString* file_path) {
furi_assert(file_path);

BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript));
bad_usb->file_path = furi_string_alloc();
furi_string_set(bad_usb->file_path, file_path);
bad_usb_script_set_default_keyboard_layout(bad_usb);

bad_usb->st.state = BadUsbStateInit;
bad_usb->st.error[0] = '\0';
Expand All @@ -673,6 +689,30 @@ void bad_usb_script_close(BadUsbScript* bad_usb) {
free(bad_usb);
}

void bad_usb_script_set_keyboard_layout(BadUsbScript* bad_usb, FuriString* layout_path) {
furi_assert(bad_usb);

if((bad_usb->st.state == BadUsbStateRunning) || (bad_usb->st.state == BadUsbStateDelay)) {
// do not update keyboard layout while a script is running
return;
}

File* layout_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
if(!furi_string_empty(layout_path)) {
if(storage_file_open(
layout_file, furi_string_get_cstr(layout_path), FSAM_READ, FSOM_OPEN_EXISTING)) {
uint16_t layout[128];
if(storage_file_read(layout_file, layout, sizeof(layout)) == sizeof(layout)) {
memcpy(bad_usb->layout, layout, sizeof(layout));
}
}
storage_file_close(layout_file);
} else {
bad_usb_script_set_default_keyboard_layout(bad_usb);
}
storage_file_free(layout_file);
}

void bad_usb_script_toggle(BadUsbScript* bad_usb) {
furi_assert(bad_usb);
furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtToggle);
Expand Down
2 changes: 2 additions & 0 deletions applications/main/bad_usb/bad_usb_script.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ BadUsbScript* bad_usb_script_open(FuriString* file_path);

void bad_usb_script_close(BadUsbScript* bad_usb);

void bad_usb_script_set_keyboard_layout(BadUsbScript* bad_usb, FuriString* layout_path);

void bad_usb_script_start(BadUsbScript* bad_usb);

void bad_usb_script_stop(BadUsbScript* bad_usb);
Expand Down
3 changes: 3 additions & 0 deletions applications/main/bad_usb/bad_usb_settings_filename.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

#define BAD_USB_SETTINGS_FILE_NAME ".badusb.settings"
53 changes: 53 additions & 0 deletions applications/main/bad_usb/scenes/bad_usb_scene_config.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include "../bad_usb_app_i.h"
#include "furi_hal_power.h"
#include "furi_hal_usb.h"

enum SubmenuIndex {
SubmenuIndexKeyboardLayout,
};

void bad_usb_scene_config_submenu_callback(void* context, uint32_t index) {
BadUsbApp* bad_usb = context;
view_dispatcher_send_custom_event(bad_usb->view_dispatcher, index);
}

void bad_usb_scene_config_on_enter(void* context) {
BadUsbApp* bad_usb = context;
Submenu* submenu = bad_usb->submenu;

submenu_add_item(
submenu,
"Keyboard layout",
SubmenuIndexKeyboardLayout,
bad_usb_scene_config_submenu_callback,
bad_usb);

submenu_set_selected_item(
submenu, scene_manager_get_scene_state(bad_usb->scene_manager, BadUsbSceneConfig));

view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewConfig);
}

bool bad_usb_scene_config_on_event(void* context, SceneManagerEvent event) {
BadUsbApp* bad_usb = context;
bool consumed = false;

if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(bad_usb->scene_manager, BadUsbSceneConfig, event.event);
consumed = true;
if(event.event == SubmenuIndexKeyboardLayout) {
scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfigLayout);
} else {
furi_crash("Unknown key type");
}
}

return consumed;
}

void bad_usb_scene_config_on_exit(void* context) {
BadUsbApp* bad_usb = context;
Submenu* submenu = bad_usb->submenu;

submenu_reset(submenu);
}
2 changes: 2 additions & 0 deletions applications/main/bad_usb/scenes/bad_usb_scene_config.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
ADD_SCENE(bad_usb, file_select, FileSelect)
ADD_SCENE(bad_usb, work, Work)
ADD_SCENE(bad_usb, error, Error)
ADD_SCENE(bad_usb, config, Config)
ADD_SCENE(bad_usb, config_layout, ConfigLayout)
Loading