diff --git a/SConstruct b/SConstruct index 83ee626f1..e75907c87 100644 --- a/SConstruct +++ b/SConstruct @@ -42,6 +42,7 @@ distenv = coreenv.Clone( "openocd", "blackmagic", "jflash", + "doxygen", ], ENV=os.environ, UPDATE_BUNDLE_DIR="dist/${DIST_DIR}/f${TARGET_HW}-update-${DIST_SUFFIX}", @@ -417,3 +418,18 @@ distenv.PhonyTarget( "env", "@echo $( ${FBT_SCRIPT_DIR.abspath}/toolchain/fbtenv.sh $)", ) + +doxy_build = distenv.DoxyBuild( + "documentation/doxygen/build/html/index.html", + "documentation/doxygen/Doxyfile-awesome.cfg", + doxy_env_variables={ + "DOXY_SRC_ROOT": Dir(".").abspath, + "DOXY_BUILD_DIR": Dir("documentation/doxygen/build").abspath, + "DOXY_CONFIG_DIR": "documentation/doxygen", + }, +) +distenv.Alias("doxygen", doxy_build) +distenv.AlwaysBuild(doxy_build) + +# Open generated documentation in browser +distenv.PhonyTarget("doxy", open_browser_action, source=doxy_build) diff --git a/applications/debug/subghz_test/scenes/subghz_test_scene_show_only_rx.c b/applications/debug/subghz_test/scenes/subghz_test_scene_show_only_rx.c index 3d5a54355..d8eade41d 100644 --- a/applications/debug/subghz_test/scenes/subghz_test_scene_show_only_rx.c +++ b/applications/debug/subghz_test/scenes/subghz_test_scene_show_only_rx.c @@ -12,7 +12,7 @@ void subghz_test_scene_show_only_rx_on_enter(void* context) { // Setup view Popup* popup = app->popup; - const char* header_text = "Transmission is blocked"; + const char* header_text = "Transmission is Blocked"; const char* message_text = "Transmission on\nthis frequency is\nrestricted in\nyour region"; if(!furi_hal_region_is_provisioned()) { header_text = "Firmware update needed"; diff --git a/applications/main/bad_usb/application.fam b/applications/main/bad_usb/application.fam index 9844e248d..8d3909fcc 100644 --- a/applications/main/bad_usb/application.fam +++ b/applications/main/bad_usb/application.fam @@ -7,7 +7,7 @@ App( icon="A_BadUsb_14", order=70, resources="resources", - fap_libs=["assets"], + fap_libs=["assets", "ble_profile"], fap_icon="icon.png", fap_category="USB", ) diff --git a/applications/main/bad_usb/bad_usb_app.c b/applications/main/bad_usb/bad_usb_app.c index ea97c4487..0cf7f1924 100644 --- a/applications/main/bad_usb/bad_usb_app.c +++ b/applications/main/bad_usb/bad_usb_app.c @@ -1,11 +1,14 @@ #include "bad_usb_app_i.h" -#include "bad_usb_settings_filename.h" #include #include #include #include +#include -#define BAD_USB_SETTINGS_PATH BAD_USB_APP_BASE_FOLDER "/" BAD_USB_SETTINGS_FILE_NAME +#define BAD_USB_SETTINGS_PATH BAD_USB_APP_BASE_FOLDER "/.badusb.settings" +#define BAD_USB_SETTINGS_FILE_TYPE "Flipper BadUSB Settings File" +#define BAD_USB_SETTINGS_VERSION 1 +#define BAD_USB_SETTINGS_DEFAULT_LAYOUT BAD_USB_APP_PATH_LAYOUT_FOLDER "/en-US.kl" static bool bad_usb_app_custom_event_callback(void* context, uint32_t event) { furi_assert(context); @@ -26,46 +29,69 @@ static void bad_usb_app_tick_event_callback(void* context) { } 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); - } - } else { - furi_string_reset(app->keyboard_layout); - } - storage_file_close(settings_file); - storage_file_free(settings_file); + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* fff = flipper_format_file_alloc(storage); + bool state = false; + + FuriString* temp_str = furi_string_alloc(); + uint32_t version = 0; + uint32_t interface = 0; + + if(flipper_format_file_open_existing(fff, BAD_USB_SETTINGS_PATH)) { + do { + if(!flipper_format_read_header(fff, temp_str, &version)) break; + if((strcmp(furi_string_get_cstr(temp_str), BAD_USB_SETTINGS_FILE_TYPE) != 0) || + (version != BAD_USB_SETTINGS_VERSION)) + break; + + if(!flipper_format_read_string(fff, "layout", temp_str)) break; + if(!flipper_format_read_uint32(fff, "interface", &interface, 1)) break; + if(interface > BadUsbHidInterfaceBle) break; + + state = true; + } while(0); + } + flipper_format_free(fff); + furi_record_close(RECORD_STORAGE); + + if(state) { + furi_string_set(app->keyboard_layout, temp_str); + app->interface = interface; - if(!furi_string_empty(app->keyboard_layout)) { Storage* fs_api = furi_record_open(RECORD_STORAGE); FileInfo layout_file_info; FS_Error file_check_err = storage_common_stat( fs_api, furi_string_get_cstr(app->keyboard_layout), &layout_file_info); furi_record_close(RECORD_STORAGE); - if(file_check_err != FSE_OK) { - furi_string_reset(app->keyboard_layout); - return; - } - if(layout_file_info.size != 256) { - furi_string_reset(app->keyboard_layout); + if((file_check_err != FSE_OK) || (layout_file_info.size != 256)) { + furi_string_set(app->keyboard_layout, BAD_USB_SETTINGS_DEFAULT_LAYOUT); } + } else { + furi_string_set(app->keyboard_layout, BAD_USB_SETTINGS_DEFAULT_LAYOUT); + app->interface = BadUsbHidInterfaceUsb; } + + furi_string_free(temp_str); } 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* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* fff = flipper_format_file_alloc(storage); + + if(flipper_format_file_open_always(fff, BAD_USB_SETTINGS_PATH)) { + do { + if(!flipper_format_write_header_cstr( + fff, BAD_USB_SETTINGS_FILE_TYPE, BAD_USB_SETTINGS_VERSION)) + break; + if(!flipper_format_write_string(fff, "layout", app->keyboard_layout)) break; + uint32_t interface_id = app->interface; + if(!flipper_format_write_uint32(fff, "interface", (const uint32_t*)&interface_id, 1)) + break; + } while(0); } - storage_file_close(settings_file); - storage_file_free(settings_file); + + flipper_format_free(fff); + furi_record_close(RECORD_STORAGE); } BadUsbApp* bad_usb_app_alloc(char* arg) { @@ -103,13 +129,15 @@ BadUsbApp* bad_usb_app_alloc(char* arg) { view_dispatcher_add_view( app->view_dispatcher, BadUsbAppViewError, widget_get_view(app->widget)); - app->submenu = submenu_alloc(); + app->var_item_list = variable_item_list_alloc(); view_dispatcher_add_view( - app->view_dispatcher, BadUsbAppViewConfig, submenu_get_view(app->submenu)); + app->view_dispatcher, + BadUsbAppViewConfig, + variable_item_list_get_view(app->var_item_list)); - app->bad_usb_view = bad_usb_alloc(); + app->bad_usb_view = bad_usb_view_alloc(); view_dispatcher_add_view( - app->view_dispatcher, BadUsbAppViewWork, bad_usb_get_view(app->bad_usb_view)); + app->view_dispatcher, BadUsbAppViewWork, bad_usb_view_get_view(app->bad_usb_view)); view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); @@ -122,8 +150,6 @@ BadUsbApp* bad_usb_app_alloc(char* arg) { furi_check(furi_hal_usb_set_config(NULL, NULL)); 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_BASE_FOLDER); @@ -144,15 +170,15 @@ void bad_usb_app_free(BadUsbApp* app) { // Views view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork); - bad_usb_free(app->bad_usb_view); + bad_usb_view_free(app->bad_usb_view); // Custom Widget view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewError); widget_free(app->widget); - // Submenu + // Config menu view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewConfig); - submenu_free(app->submenu); + variable_item_list_free(app->var_item_list); // View dispatcher view_dispatcher_free(app->view_dispatcher); diff --git a/applications/main/bad_usb/bad_usb_app_i.h b/applications/main/bad_usb/bad_usb_app_i.h index cf1c02ebc..c12f9ac75 100644 --- a/applications/main/bad_usb/bad_usb_app_i.h +++ b/applications/main/bad_usb/bad_usb_app_i.h @@ -3,12 +3,12 @@ #include "bad_usb_app.h" #include "scenes/bad_usb_scene.h" #include "helpers/ducky_script.h" +#include "helpers/bad_usb_hid.h" #include #include #include #include -#include #include #include #include @@ -33,7 +33,7 @@ struct BadUsbApp { NotificationApp* notifications; DialogsApp* dialogs; Widget* widget; - Submenu* submenu; + VariableItemList* var_item_list; BadUsbAppError error; FuriString* file_path; @@ -41,6 +41,7 @@ struct BadUsbApp { BadUsb* bad_usb_view; BadUsbScript* bad_usb_script; + BadUsbHidInterface interface; FuriHalUsbInterface* usb_if_prev; }; diff --git a/applications/main/bad_usb/bad_usb_settings_filename.h b/applications/main/bad_usb/bad_usb_settings_filename.h deleted file mode 100644 index 12ba8f31c..000000000 --- a/applications/main/bad_usb/bad_usb_settings_filename.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#define BAD_USB_SETTINGS_FILE_NAME ".badusb.settings" diff --git a/applications/main/bad_usb/helpers/bad_usb_hid.c b/applications/main/bad_usb/helpers/bad_usb_hid.c new file mode 100644 index 000000000..289e3ae8c --- /dev/null +++ b/applications/main/bad_usb/helpers/bad_usb_hid.c @@ -0,0 +1,226 @@ +#include "bad_usb_hid.h" +#include +#include +#include + +#define TAG "BadUSB HID" + +#define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys" + +void* hid_usb_init(FuriHalUsbHidConfig* hid_cfg) { + furi_check(furi_hal_usb_set_config(&usb_hid, hid_cfg)); + return NULL; +} + +void hid_usb_deinit(void* inst) { + UNUSED(inst); + furi_check(furi_hal_usb_set_config(NULL, NULL)); +} + +void hid_usb_set_state_callback(void* inst, HidStateCallback cb, void* context) { + UNUSED(inst); + furi_hal_hid_set_state_callback(cb, context); +} + +bool hid_usb_is_connected(void* inst) { + UNUSED(inst); + return furi_hal_hid_is_connected(); +} + +bool hid_usb_kb_press(void* inst, uint16_t button) { + UNUSED(inst); + return furi_hal_hid_kb_press(button); +} + +bool hid_usb_kb_release(void* inst, uint16_t button) { + UNUSED(inst); + return furi_hal_hid_kb_release(button); +} + +bool hid_usb_consumer_press(void* inst, uint16_t button) { + UNUSED(inst); + return furi_hal_hid_consumer_key_press(button); +} + +bool hid_usb_consumer_release(void* inst, uint16_t button) { + UNUSED(inst); + return furi_hal_hid_consumer_key_release(button); +} + +bool hid_usb_release_all(void* inst) { + UNUSED(inst); + bool state = furi_hal_hid_kb_release_all(); + state &= furi_hal_hid_consumer_key_release_all(); + return state; +} + +uint8_t hid_usb_get_led_state(void* inst) { + UNUSED(inst); + return furi_hal_hid_get_led_state(); +} + +static const BadUsbHidApi hid_api_usb = { + .init = hid_usb_init, + .deinit = hid_usb_deinit, + .set_state_callback = hid_usb_set_state_callback, + .is_connected = hid_usb_is_connected, + + .kb_press = hid_usb_kb_press, + .kb_release = hid_usb_kb_release, + .consumer_press = hid_usb_consumer_press, + .consumer_release = hid_usb_consumer_release, + .release_all = hid_usb_release_all, + .get_led_state = hid_usb_get_led_state, +}; + +typedef struct { + Bt* bt; + FuriHalBleProfileBase* profile; + HidStateCallback state_callback; + void* callback_context; + bool is_connected; +} BleHidInstance; + +static const BleProfileHidParams ble_hid_params = { + .device_name_prefix = "BadUSB", + .mac_xor = 0x0002, +}; + +static void hid_ble_connection_status_callback(BtStatus status, void* context) { + furi_assert(context); + BleHidInstance* ble_hid = context; + ble_hid->is_connected = (status == BtStatusConnected); + if(ble_hid->state_callback) { + ble_hid->state_callback(ble_hid->is_connected, ble_hid->callback_context); + } +} + +void* hid_ble_init(FuriHalUsbHidConfig* hid_cfg) { + UNUSED(hid_cfg); + BleHidInstance* ble_hid = malloc(sizeof(BleHidInstance)); + ble_hid->bt = furi_record_open(RECORD_BT); + bt_disconnect(ble_hid->bt); + + // Wait 2nd core to update nvm storage + furi_delay_ms(200); + + bt_keys_storage_set_storage_path(ble_hid->bt, APP_DATA_PATH(HID_BT_KEYS_STORAGE_NAME)); + + ble_hid->profile = bt_profile_start(ble_hid->bt, ble_profile_hid, (void*)&ble_hid_params); + furi_check(ble_hid->profile); + + furi_hal_bt_start_advertising(); + + bt_set_status_changed_callback(ble_hid->bt, hid_ble_connection_status_callback, ble_hid); + + return ble_hid; +} + +void hid_ble_deinit(void* inst) { + BleHidInstance* ble_hid = inst; + furi_assert(ble_hid); + + bt_set_status_changed_callback(ble_hid->bt, NULL, NULL); + bt_disconnect(ble_hid->bt); + + // Wait 2nd core to update nvm storage + furi_delay_ms(200); + bt_keys_storage_set_default_path(ble_hid->bt); + + furi_check(bt_profile_restore_default(ble_hid->bt)); + furi_record_close(RECORD_BT); + free(ble_hid); +} + +void hid_ble_set_state_callback(void* inst, HidStateCallback cb, void* context) { + BleHidInstance* ble_hid = inst; + furi_assert(ble_hid); + ble_hid->state_callback = cb; + ble_hid->callback_context = context; +} + +bool hid_ble_is_connected(void* inst) { + BleHidInstance* ble_hid = inst; + furi_assert(ble_hid); + return ble_hid->is_connected; +} + +bool hid_ble_kb_press(void* inst, uint16_t button) { + BleHidInstance* ble_hid = inst; + furi_assert(ble_hid); + return ble_profile_hid_kb_press(ble_hid->profile, button); +} + +bool hid_ble_kb_release(void* inst, uint16_t button) { + BleHidInstance* ble_hid = inst; + furi_assert(ble_hid); + return ble_profile_hid_kb_release(ble_hid->profile, button); +} + +bool hid_ble_consumer_press(void* inst, uint16_t button) { + BleHidInstance* ble_hid = inst; + furi_assert(ble_hid); + return ble_profile_hid_consumer_key_press(ble_hid->profile, button); +} + +bool hid_ble_consumer_release(void* inst, uint16_t button) { + BleHidInstance* ble_hid = inst; + furi_assert(ble_hid); + return ble_profile_hid_consumer_key_release(ble_hid->profile, button); +} + +bool hid_ble_release_all(void* inst) { + BleHidInstance* ble_hid = inst; + furi_assert(ble_hid); + bool state = ble_profile_hid_kb_release_all(ble_hid->profile); + state &= ble_profile_hid_consumer_key_release_all(ble_hid->profile); + return state; +} + +uint8_t hid_ble_get_led_state(void* inst) { + UNUSED(inst); + FURI_LOG_W(TAG, "hid_ble_get_led_state not implemented"); + return 0; +} + +static const BadUsbHidApi hid_api_ble = { + .init = hid_ble_init, + .deinit = hid_ble_deinit, + .set_state_callback = hid_ble_set_state_callback, + .is_connected = hid_ble_is_connected, + + .kb_press = hid_ble_kb_press, + .kb_release = hid_ble_kb_release, + .consumer_press = hid_ble_consumer_press, + .consumer_release = hid_ble_consumer_release, + .release_all = hid_ble_release_all, + .get_led_state = hid_ble_get_led_state, +}; + +const BadUsbHidApi* bad_usb_hid_get_interface(BadUsbHidInterface interface) { + if(interface == BadUsbHidInterfaceUsb) { + return &hid_api_usb; + } else { + return &hid_api_ble; + } +} + +void bad_usb_hid_ble_remove_pairing(void) { + Bt* bt = furi_record_open(RECORD_BT); + bt_disconnect(bt); + + // Wait 2nd core to update nvm storage + furi_delay_ms(200); + + furi_hal_bt_stop_advertising(); + + bt_keys_storage_set_storage_path(bt, APP_DATA_PATH(HID_BT_KEYS_STORAGE_NAME)); + bt_forget_bonded_devices(bt); + + // Wait 2nd core to update nvm storage + furi_delay_ms(200); + bt_keys_storage_set_default_path(bt); + + furi_check(bt_profile_restore_default(bt)); + furi_record_close(RECORD_BT); +} \ No newline at end of file diff --git a/applications/main/bad_usb/helpers/bad_usb_hid.h b/applications/main/bad_usb/helpers/bad_usb_hid.h new file mode 100644 index 000000000..71d3a58e7 --- /dev/null +++ b/applications/main/bad_usb/helpers/bad_usb_hid.h @@ -0,0 +1,35 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef enum { + BadUsbHidInterfaceUsb, + BadUsbHidInterfaceBle, +} BadUsbHidInterface; + +typedef struct { + void* (*init)(FuriHalUsbHidConfig* hid_cfg); + void (*deinit)(void* inst); + void (*set_state_callback)(void* inst, HidStateCallback cb, void* context); + bool (*is_connected)(void* inst); + + bool (*kb_press)(void* inst, uint16_t button); + bool (*kb_release)(void* inst, uint16_t button); + bool (*consumer_press)(void* inst, uint16_t button); + bool (*consumer_release)(void* inst, uint16_t button); + bool (*release_all)(void* inst); + uint8_t (*get_led_state)(void* inst); +} BadUsbHidApi; + +const BadUsbHidApi* bad_usb_hid_get_interface(BadUsbHidInterface interface); + +void bad_usb_hid_ble_remove_pairing(void); + +#ifdef __cplusplus +} +#endif diff --git a/applications/main/bad_usb/helpers/ducky_script.c b/applications/main/bad_usb/helpers/ducky_script.c index d2d7dae51..e1bd44169 100644 --- a/applications/main/bad_usb/helpers/ducky_script.c +++ b/applications/main/bad_usb/helpers/ducky_script.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include "ducky_script.h" #include "ducky_script_i.h" @@ -71,39 +70,40 @@ bool ducky_get_number(const char* param, uint32_t* val) { return false; } -void ducky_numlock_on(void) { - if((furi_hal_hid_get_led_state() & HID_KB_LED_NUM) == 0) { - furi_hal_hid_kb_press(HID_KEYBOARD_LOCK_NUM_LOCK); - furi_hal_hid_kb_release(HID_KEYBOARD_LOCK_NUM_LOCK); +void ducky_numlock_on(BadUsbScript* bad_usb) { + if((bad_usb->hid->get_led_state(bad_usb->hid_inst) & HID_KB_LED_NUM) == 0) { + bad_usb->hid->kb_press(bad_usb->hid_inst, HID_KEYBOARD_LOCK_NUM_LOCK); + bad_usb->hid->kb_release(bad_usb->hid_inst, HID_KEYBOARD_LOCK_NUM_LOCK); } } -bool ducky_numpad_press(const char num) { + +bool ducky_numpad_press(BadUsbScript* bad_usb, const char num) { if((num < '0') || (num > '9')) return false; uint16_t key = numpad_keys[num - '0']; - furi_hal_hid_kb_press(key); - furi_hal_hid_kb_release(key); + bad_usb->hid->kb_press(bad_usb->hid_inst, key); + bad_usb->hid->kb_release(bad_usb->hid_inst, key); return true; } -bool ducky_altchar(const char* charcode) { +bool ducky_altchar(BadUsbScript* bad_usb, const char* charcode) { uint8_t i = 0; bool state = false; - furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT); + bad_usb->hid->kb_press(bad_usb->hid_inst, KEY_MOD_LEFT_ALT); while(!ducky_is_line_end(charcode[i])) { - state = ducky_numpad_press(charcode[i]); + state = ducky_numpad_press(bad_usb, charcode[i]); if(state == false) break; i++; } - furi_hal_hid_kb_release(KEY_MOD_LEFT_ALT); + bad_usb->hid->kb_release(bad_usb->hid_inst, KEY_MOD_LEFT_ALT); return state; } -bool ducky_altstring(const char* param) { +bool ducky_altstring(BadUsbScript* bad_usb, const char* param) { uint32_t i = 0; bool state = false; @@ -116,7 +116,7 @@ bool ducky_altstring(const char* param) { char temp_str[4]; snprintf(temp_str, 4, "%u", param[i]); - state = ducky_altchar(temp_str); + state = ducky_altchar(bad_usb, temp_str); if(state == false) break; i++; } @@ -140,12 +140,12 @@ bool ducky_string(BadUsbScript* bad_usb, const char* param) { if(param[i] != '\n') { 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); + bad_usb->hid->kb_press(bad_usb->hid_inst, keycode); + bad_usb->hid->kb_release(bad_usb->hid_inst, keycode); } } else { - furi_hal_hid_kb_press(HID_KEYBOARD_RETURN); - furi_hal_hid_kb_release(HID_KEYBOARD_RETURN); + bad_usb->hid->kb_press(bad_usb->hid_inst, HID_KEYBOARD_RETURN); + bad_usb->hid->kb_release(bad_usb->hid_inst, HID_KEYBOARD_RETURN); } i++; } @@ -163,12 +163,12 @@ static bool ducky_string_next(BadUsbScript* bad_usb) { if(print_char != '\n') { uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_usb, print_char); if(keycode != HID_KEYBOARD_NONE) { - furi_hal_hid_kb_press(keycode); - furi_hal_hid_kb_release(keycode); + bad_usb->hid->kb_press(bad_usb->hid_inst, keycode); + bad_usb->hid->kb_release(bad_usb->hid_inst, keycode); } } else { - furi_hal_hid_kb_press(HID_KEYBOARD_RETURN); - furi_hal_hid_kb_release(HID_KEYBOARD_RETURN); + bad_usb->hid->kb_press(bad_usb->hid_inst, HID_KEYBOARD_RETURN); + bad_usb->hid->kb_release(bad_usb->hid_inst, HID_KEYBOARD_RETURN); } bad_usb->string_print_pos++; @@ -205,8 +205,8 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, FuriString* line) { key |= ducky_get_keycode(bad_usb, line_tmp + offset, true); } } - furi_hal_hid_kb_press(key); - furi_hal_hid_kb_release(key); + bad_usb->hid->kb_press(bad_usb->hid_inst, key); + bad_usb->hid->kb_release(bad_usb->hid_inst, key); return 0; } @@ -235,6 +235,17 @@ static bool ducky_set_usb_id(BadUsbScript* bad_usb, const char* line) { return false; } +static void bad_usb_hid_state_callback(bool state, void* context) { + furi_assert(context); + BadUsbScript* bad_usb = context; + + if(state == true) { + furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtConnect); + } else { + furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtDisconnect); + } +} + static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) { uint8_t ret = 0; uint32_t line_len = 0; @@ -269,10 +280,11 @@ static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) { } if(id_set) { - furi_check(furi_hal_usb_set_config(&usb_hid, &bad_usb->hid_cfg)); + bad_usb->hid_inst = bad_usb->hid->init(&bad_usb->hid_cfg); } else { - furi_check(furi_hal_usb_set_config(&usb_hid, NULL)); + bad_usb->hid_inst = bad_usb->hid->init(NULL); } + bad_usb->hid->set_state_callback(bad_usb->hid_inst, bad_usb_hid_state_callback, bad_usb); storage_file_seek(script_file, 0, true); furi_string_reset(bad_usb->line); @@ -349,17 +361,6 @@ static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_fil return 0; } -static void bad_usb_hid_state_callback(bool state, void* context) { - furi_assert(context); - BadUsbScript* bad_usb = context; - - if(state == true) { - furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtConnect); - } else { - furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtDisconnect); - } -} - static uint32_t bad_usb_flags_get(uint32_t flags_mask, uint32_t timeout) { uint32_t flags = furi_thread_flags_get(); furi_check((flags & FuriFlagError) == 0); @@ -386,8 +387,6 @@ static int32_t bad_usb_worker(void* context) { bad_usb->line_prev = furi_string_alloc(); bad_usb->string_print = furi_string_alloc(); - furi_hal_hid_set_state_callback(bad_usb_hid_state_callback, bad_usb); - while(1) { if(worker_state == BadUsbStateInit) { // State: initialization if(storage_file_open( @@ -396,7 +395,7 @@ static int32_t bad_usb_worker(void* context) { FSAM_READ, FSOM_OPEN_EXISTING)) { if((ducky_script_preload(bad_usb, script_file)) && (bad_usb->st.line_nb > 0)) { - if(furi_hal_hid_is_connected()) { + if(bad_usb->hid->is_connected(bad_usb->hid_inst)) { worker_state = BadUsbStateIdle; // Ready to run } else { worker_state = BadUsbStateNotConnected; // USB not connected @@ -412,7 +411,8 @@ static int32_t bad_usb_worker(void* context) { } else if(worker_state == BadUsbStateNotConnected) { // State: USB not connected uint32_t flags = bad_usb_flags_get( - WorkerEvtEnd | WorkerEvtConnect | WorkerEvtStartStop, FuriWaitForever); + WorkerEvtEnd | WorkerEvtConnect | WorkerEvtDisconnect | WorkerEvtStartStop, + FuriWaitForever); if(flags & WorkerEvtEnd) { break; @@ -494,10 +494,10 @@ static int32_t bad_usb_worker(void* context) { break; } else if(flags & WorkerEvtStartStop) { worker_state = BadUsbStateIdle; // Stop executing script - furi_hal_hid_kb_release_all(); + bad_usb->hid->release_all(bad_usb->hid_inst); } else if(flags & WorkerEvtDisconnect) { worker_state = BadUsbStateNotConnected; // USB disconnected - furi_hal_hid_kb_release_all(); + bad_usb->hid->release_all(bad_usb->hid_inst); } else if(flags & WorkerEvtPauseResume) { pause_state = BadUsbStateRunning; worker_state = BadUsbStatePaused; // Pause @@ -517,12 +517,12 @@ static int32_t bad_usb_worker(void* context) { delay_val = 0; worker_state = BadUsbStateScriptError; bad_usb->st.state = worker_state; - furi_hal_hid_kb_release_all(); + bad_usb->hid->release_all(bad_usb->hid_inst); } else if(delay_val == SCRIPT_STATE_END) { // End of script delay_val = 0; worker_state = BadUsbStateIdle; bad_usb->st.state = BadUsbStateDone; - furi_hal_hid_kb_release_all(); + bad_usb->hid->release_all(bad_usb->hid_inst); continue; } else if(delay_val == SCRIPT_STATE_STRING_START) { // Start printing string with delays delay_val = bad_usb->defdelay; @@ -550,7 +550,7 @@ static int32_t bad_usb_worker(void* context) { worker_state = BadUsbStateRunning; } else if(flags & WorkerEvtDisconnect) { worker_state = BadUsbStateNotConnected; // USB disconnected - furi_hal_hid_kb_release_all(); + bad_usb->hid->release_all(bad_usb->hid_inst); } bad_usb->st.state = worker_state; continue; @@ -565,11 +565,11 @@ static int32_t bad_usb_worker(void* context) { } else if(flags & WorkerEvtStartStop) { worker_state = BadUsbStateIdle; // Stop executing script bad_usb->st.state = worker_state; - furi_hal_hid_kb_release_all(); + bad_usb->hid->release_all(bad_usb->hid_inst); } else if(flags & WorkerEvtDisconnect) { worker_state = BadUsbStateNotConnected; // USB disconnected bad_usb->st.state = worker_state; - furi_hal_hid_kb_release_all(); + bad_usb->hid->release_all(bad_usb->hid_inst); } else if(flags & WorkerEvtPauseResume) { if(pause_state == BadUsbStateRunning) { if(delay_val > 0) { @@ -599,10 +599,10 @@ static int32_t bad_usb_worker(void* context) { break; } else if(flags & WorkerEvtStartStop) { worker_state = BadUsbStateIdle; // Stop executing script - furi_hal_hid_kb_release_all(); + bad_usb->hid->release_all(bad_usb->hid_inst); } else if(flags & WorkerEvtDisconnect) { worker_state = BadUsbStateNotConnected; // USB disconnected - furi_hal_hid_kb_release_all(); + bad_usb->hid->release_all(bad_usb->hid_inst); } else if(flags & WorkerEvtPauseResume) { pause_state = BadUsbStateStringDelay; worker_state = BadUsbStatePaused; // Pause @@ -632,7 +632,8 @@ static int32_t bad_usb_worker(void* context) { } } - furi_hal_hid_set_state_callback(NULL, NULL); + bad_usb->hid->set_state_callback(bad_usb->hid_inst, NULL, NULL); + bad_usb->hid->deinit(bad_usb->hid_inst); storage_file_close(script_file); storage_file_free(script_file); @@ -651,7 +652,7 @@ static void bad_usb_script_set_default_keyboard_layout(BadUsbScript* bad_usb) { memcpy(bad_usb->layout, hid_asciimap, MIN(sizeof(hid_asciimap), sizeof(bad_usb->layout))); } -BadUsbScript* bad_usb_script_open(FuriString* file_path) { +BadUsbScript* bad_usb_script_open(FuriString* file_path, BadUsbHidInterface interface) { furi_assert(file_path); BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript)); @@ -661,6 +662,7 @@ BadUsbScript* bad_usb_script_open(FuriString* file_path) { bad_usb->st.state = BadUsbStateInit; bad_usb->st.error[0] = '\0'; + bad_usb->hid = bad_usb_hid_get_interface(interface); bad_usb->thread = furi_thread_alloc_ex("BadUsbWorker", 2048, bad_usb_worker, bad_usb); furi_thread_start(bad_usb->thread); diff --git a/applications/main/bad_usb/helpers/ducky_script.h b/applications/main/bad_usb/helpers/ducky_script.h index dca61ed4e..9519623f6 100644 --- a/applications/main/bad_usb/helpers/ducky_script.h +++ b/applications/main/bad_usb/helpers/ducky_script.h @@ -6,6 +6,7 @@ extern "C" { #include #include +#include "bad_usb_hid.h" typedef enum { BadUsbStateInit, @@ -33,7 +34,7 @@ typedef struct { typedef struct BadUsbScript BadUsbScript; -BadUsbScript* bad_usb_script_open(FuriString* file_path); +BadUsbScript* bad_usb_script_open(FuriString* file_path, BadUsbHidInterface interface); void bad_usb_script_close(BadUsbScript* bad_usb); diff --git a/applications/main/bad_usb/helpers/ducky_script_commands.c b/applications/main/bad_usb/helpers/ducky_script_commands.c index fdf963b40..7f9a48fb2 100644 --- a/applications/main/bad_usb/helpers/ducky_script_commands.c +++ b/applications/main/bad_usb/helpers/ducky_script_commands.c @@ -1,5 +1,4 @@ #include -#include #include "ducky_script.h" #include "ducky_script_i.h" @@ -93,9 +92,9 @@ static int32_t ducky_fnc_sysrq(BadUsbScript* bad_usb, const char* line, int32_t line = &line[ducky_get_command_len(line) + 1]; uint16_t key = ducky_get_keycode(bad_usb, line, 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(); + bad_usb->hid->kb_press(bad_usb->hid_inst, KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN); + bad_usb->hid->kb_press(bad_usb->hid_inst, key); + bad_usb->hid->release_all(bad_usb->hid_inst); return 0; } @@ -103,8 +102,8 @@ static int32_t ducky_fnc_altchar(BadUsbScript* bad_usb, const char* line, int32_ UNUSED(param); line = &line[ducky_get_command_len(line) + 1]; - ducky_numlock_on(); - bool state = ducky_altchar(line); + ducky_numlock_on(bad_usb); + bool state = ducky_altchar(bad_usb, line); if(!state) { return ducky_error(bad_usb, "Invalid altchar %s", line); } @@ -115,8 +114,8 @@ static int32_t ducky_fnc_altstring(BadUsbScript* bad_usb, const char* line, int3 UNUSED(param); line = &line[ducky_get_command_len(line) + 1]; - ducky_numlock_on(); - bool state = ducky_altstring(line); + ducky_numlock_on(bad_usb); + bool state = ducky_altstring(bad_usb, line); if(!state) { return ducky_error(bad_usb, "Invalid altstring %s", line); } @@ -135,7 +134,7 @@ static int32_t ducky_fnc_hold(BadUsbScript* bad_usb, const char* line, int32_t p if(bad_usb->key_hold_nb > (HID_KB_MAX_KEYS - 1)) { return ducky_error(bad_usb, "Too many keys are hold"); } - furi_hal_hid_kb_press(key); + bad_usb->hid->kb_press(bad_usb->hid_inst, key); return 0; } @@ -151,7 +150,36 @@ static int32_t ducky_fnc_release(BadUsbScript* bad_usb, const char* line, int32_ return ducky_error(bad_usb, "No keys are hold"); } bad_usb->key_hold_nb--; - furi_hal_hid_kb_release(key); + bad_usb->hid->kb_release(bad_usb->hid_inst, key); + return 0; +} + +static int32_t ducky_fnc_media(BadUsbScript* bad_usb, const char* line, int32_t param) { + UNUSED(param); + + line = &line[ducky_get_command_len(line) + 1]; + uint16_t key = ducky_get_media_keycode_by_name(line); + if(key == HID_CONSUMER_UNASSIGNED) { + return ducky_error(bad_usb, "No keycode defined for %s", line); + } + bad_usb->hid->consumer_press(bad_usb->hid_inst, key); + bad_usb->hid->consumer_release(bad_usb->hid_inst, key); + return 0; +} + +static int32_t ducky_fnc_globe(BadUsbScript* bad_usb, const char* line, int32_t param) { + UNUSED(param); + + line = &line[ducky_get_command_len(line) + 1]; + uint16_t key = ducky_get_keycode(bad_usb, line, true); + if(key == HID_KEYBOARD_NONE) { + return ducky_error(bad_usb, "No keycode defined for %s", line); + } + + bad_usb->hid->consumer_press(bad_usb->hid_inst, HID_CONSUMER_FN_GLOBE); + bad_usb->hid->kb_press(bad_usb->hid_inst, key); + bad_usb->hid->kb_release(bad_usb->hid_inst, key); + bad_usb->hid->consumer_release(bad_usb->hid_inst, HID_CONSUMER_FN_GLOBE); return 0; } @@ -183,6 +211,8 @@ static const DuckyCmd ducky_commands[] = { {"HOLD", ducky_fnc_hold, -1}, {"RELEASE", ducky_fnc_release, -1}, {"WAIT_FOR_BUTTON_PRESS", ducky_fnc_waitforbutton, -1}, + {"MEDIA", ducky_fnc_media, -1}, + {"GLOBE", ducky_fnc_globe, -1}, }; #define TAG "BadUsb" diff --git a/applications/main/bad_usb/helpers/ducky_script_i.h b/applications/main/bad_usb/helpers/ducky_script_i.h index 9c1025b00..bbafdccb6 100644 --- a/applications/main/bad_usb/helpers/ducky_script_i.h +++ b/applications/main/bad_usb/helpers/ducky_script_i.h @@ -7,6 +7,7 @@ extern "C" { #include #include #include "ducky_script.h" +#include "bad_usb_hid.h" #define SCRIPT_STATE_ERROR (-1) #define SCRIPT_STATE_END (-2) @@ -19,6 +20,8 @@ extern "C" { struct BadUsbScript { FuriHalUsbHidConfig hid_cfg; + const BadUsbHidApi* hid; + void* hid_inst; FuriThread* thread; BadUsbState st; @@ -50,15 +53,17 @@ bool ducky_is_line_end(const char chr); uint16_t ducky_get_keycode_by_name(const char* param); +uint16_t ducky_get_media_keycode_by_name(const char* param); + bool ducky_get_number(const char* param, uint32_t* val); -void ducky_numlock_on(void); +void ducky_numlock_on(BadUsbScript* bad_usb); -bool ducky_numpad_press(const char num); +bool ducky_numpad_press(BadUsbScript* bad_usb, const char num); -bool ducky_altchar(const char* charcode); +bool ducky_altchar(BadUsbScript* bad_usb, const char* charcode); -bool ducky_altstring(const char* param); +bool ducky_altstring(BadUsbScript* bad_usb, const char* param); bool ducky_string(BadUsbScript* bad_usb, const char* param); diff --git a/applications/main/bad_usb/helpers/ducky_script_keycodes.c b/applications/main/bad_usb/helpers/ducky_script_keycodes.c index 56b5144d4..290618c13 100644 --- a/applications/main/bad_usb/helpers/ducky_script_keycodes.c +++ b/applications/main/bad_usb/helpers/ducky_script_keycodes.c @@ -1,5 +1,4 @@ #include -#include #include "ducky_script_i.h" typedef struct { @@ -78,6 +77,37 @@ static const DuckyKey ducky_keys[] = { {"F24", HID_KEYBOARD_F24}, }; +static const DuckyKey ducky_media_keys[] = { + {"POWER", HID_CONSUMER_POWER}, + {"REBOOT", HID_CONSUMER_RESET}, + {"SLEEP", HID_CONSUMER_SLEEP}, + {"LOGOFF", HID_CONSUMER_AL_LOGOFF}, + + {"EXIT", HID_CONSUMER_AC_EXIT}, + {"HOME", HID_CONSUMER_AC_HOME}, + {"BACK", HID_CONSUMER_AC_BACK}, + {"FORWARD", HID_CONSUMER_AC_FORWARD}, + {"REFRESH", HID_CONSUMER_AC_REFRESH}, + + {"SNAPSHOT", HID_CONSUMER_SNAPSHOT}, + + {"PLAY", HID_CONSUMER_PLAY}, + {"PAUSE", HID_CONSUMER_PAUSE}, + {"PLAY_PAUSE", HID_CONSUMER_PLAY_PAUSE}, + {"NEXT_TRACK", HID_CONSUMER_SCAN_NEXT_TRACK}, + {"PREV_TRACK", HID_CONSUMER_SCAN_PREVIOUS_TRACK}, + {"STOP", HID_CONSUMER_STOP}, + {"EJECT", HID_CONSUMER_EJECT}, + + {"MUTE", HID_CONSUMER_MUTE}, + {"VOLUME_UP", HID_CONSUMER_VOLUME_INCREMENT}, + {"VOLUME_DOWN", HID_CONSUMER_VOLUME_DECREMENT}, + + {"FN", HID_CONSUMER_FN_GLOBE}, + {"BRIGHT_UP", HID_CONSUMER_BRIGHTNESS_INCREMENT}, + {"BRIGHT_DOWN", HID_CONSUMER_BRIGHTNESS_DECREMENT}, +}; + uint16_t ducky_get_keycode_by_name(const char* param) { for(size_t i = 0; i < COUNT_OF(ducky_keys); i++) { size_t key_cmd_len = strlen(ducky_keys[i].name); @@ -89,3 +119,15 @@ uint16_t ducky_get_keycode_by_name(const char* param) { return HID_KEYBOARD_NONE; } + +uint16_t ducky_get_media_keycode_by_name(const char* param) { + for(size_t i = 0; i < COUNT_OF(ducky_media_keys); i++) { + size_t key_cmd_len = strlen(ducky_media_keys[i].name); + if((strncmp(param, ducky_media_keys[i].name, key_cmd_len) == 0) && + (ducky_is_line_end(param[key_cmd_len]))) { + return ducky_media_keys[i].keycode; + } + } + + return HID_CONSUMER_UNASSIGNED; +} diff --git a/applications/main/bad_usb/resources/badusb/demo_chromeos.txt b/applications/main/bad_usb/resources/badusb/demo_chromeos.txt new file mode 100644 index 000000000..c5f675fb3 --- /dev/null +++ b/applications/main/bad_usb/resources/badusb/demo_chromeos.txt @@ -0,0 +1,80 @@ +REM This is BadUSB demo script for ChromeOS by kowalski7cc + +REM Open a new tab +CTRL t +REM wait for some slower chromebooks +DELAY 1000 +REM Open an empty editable page +DEFAULT_DELAY 50 +STRING data:text/html,