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 1ee92bdf3..eda702cf4 100644 --- a/applications/main/bad_usb/bad_usb_app.c +++ b/applications/main/bad_usb/bad_usb_app.c @@ -35,6 +35,7 @@ static void bad_usb_load_settings(BadUsbApp* app) { 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 { @@ -44,6 +45,8 @@ static void bad_usb_load_settings(BadUsbApp* app) { 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); @@ -53,6 +56,7 @@ static void bad_usb_load_settings(BadUsbApp* app) { if(state) { furi_string_set(app->keyboard_layout, temp_str); + app->interface = interface; Storage* fs_api = furi_record_open(RECORD_STORAGE); FileInfo layout_file_info; @@ -64,6 +68,7 @@ static void bad_usb_load_settings(BadUsbApp* app) { } } else { furi_string_set(app->keyboard_layout, BAD_USB_SETTINGS_DEFAULT_LAYOUT); + app->interface = BadUsbHidInterfaceUsb; } furi_string_free(temp_str); @@ -79,6 +84,9 @@ static void bad_usb_save_settings(BadUsbApp* app) { 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); } @@ -86,6 +94,11 @@ static void bad_usb_save_settings(BadUsbApp* app) { furi_record_close(RECORD_STORAGE); } +void bad_usb_set_interface(BadUsbApp* app, BadUsbHidInterface interface) { + app->interface = interface; + bad_usb_view_set_interface(app->bad_usb_view, interface); +} + BadUsbApp* bad_usb_app_alloc(char* arg) { BadUsbApp* app = malloc(sizeof(BadUsbApp)); @@ -117,7 +130,11 @@ BadUsbApp* bad_usb_app_alloc(char* arg) { // Custom Widget app->widget = widget_alloc(); view_dispatcher_add_view( - app->view_dispatcher, BadUsbAppViewError, widget_get_view(app->widget)); + app->view_dispatcher, BadUsbAppViewWidget, widget_get_view(app->widget)); + + // Popup + app->popup = popup_alloc(); + view_dispatcher_add_view(app->view_dispatcher, BadUsbAppViewPopup, popup_get_view(app->popup)); app->var_item_list = variable_item_list_alloc(); view_dispatcher_add_view( @@ -163,9 +180,13 @@ void bad_usb_app_free(BadUsbApp* app) { bad_usb_view_free(app->bad_usb_view); // Custom Widget - view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewError); + view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWidget); widget_free(app->widget); + // Popup + view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewPopup); + popup_free(app->popup); + // Config menu view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewConfig); variable_item_list_free(app->var_item_list); diff --git a/applications/main/bad_usb/bad_usb_app_i.h b/applications/main/bad_usb/bad_usb_app_i.h index e63d0044c..b34bd5de6 100644 --- a/applications/main/bad_usb/bad_usb_app_i.h +++ b/applications/main/bad_usb/bad_usb_app_i.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "views/bad_usb_view.h" #include @@ -33,6 +34,7 @@ struct BadUsbApp { NotificationApp* notifications; DialogsApp* dialogs; Widget* widget; + Popup* popup; VariableItemList* var_item_list; BadUsbAppError error; @@ -41,11 +43,15 @@ struct BadUsbApp { BadUsb* bad_usb_view; BadUsbScript* bad_usb_script; + BadUsbHidInterface interface; FuriHalUsbInterface* usb_if_prev; }; typedef enum { - BadUsbAppViewError, + BadUsbAppViewWidget, + BadUsbAppViewPopup, BadUsbAppViewWork, BadUsbAppViewConfig, } BadUsbAppView; + +void bad_usb_set_interface(BadUsbApp* app, BadUsbHidInterface interface); diff --git a/applications/main/bad_usb/helpers/bad_usb_hid.c b/applications/main/bad_usb/helpers/bad_usb_hid.c index dcba7b5e9..5d7076314 100644 --- a/applications/main/bad_usb/helpers/bad_usb_hid.c +++ b/applications/main/bad_usb/helpers/bad_usb_hid.c @@ -1,9 +1,12 @@ #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; @@ -69,6 +72,155 @@ static const BadUsbHidApi hid_api_usb = { .release_all = hid_usb_release_all, .get_led_state = hid_usb_get_led_state, }; -const BadUsbHidApi* bad_usb_hid_get_interface() { - return &hid_api_usb; + +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); } diff --git a/applications/main/bad_usb/helpers/bad_usb_hid.h b/applications/main/bad_usb/helpers/bad_usb_hid.h index feaaacd54..71d3a58e7 100644 --- a/applications/main/bad_usb/helpers/bad_usb_hid.h +++ b/applications/main/bad_usb/helpers/bad_usb_hid.h @@ -7,6 +7,11 @@ extern "C" { #include #include +typedef enum { + BadUsbHidInterfaceUsb, + BadUsbHidInterfaceBle, +} BadUsbHidInterface; + typedef struct { void* (*init)(FuriHalUsbHidConfig* hid_cfg); void (*deinit)(void* inst); @@ -21,7 +26,7 @@ typedef struct { uint8_t (*get_led_state)(void* inst); } BadUsbHidApi; -const BadUsbHidApi* bad_usb_hid_get_interface(); +const BadUsbHidApi* bad_usb_hid_get_interface(BadUsbHidInterface interface); void bad_usb_hid_ble_remove_pairing(void); diff --git a/applications/main/bad_usb/helpers/ducky_script.c b/applications/main/bad_usb/helpers/ducky_script.c index ea2339006..8408b96ae 100644 --- a/applications/main/bad_usb/helpers/ducky_script.c +++ b/applications/main/bad_usb/helpers/ducky_script.c @@ -654,7 +654,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)); @@ -664,7 +664,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(); + 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 43969d7b6..9519623f6 100644 --- a/applications/main/bad_usb/helpers/ducky_script.h +++ b/applications/main/bad_usb/helpers/ducky_script.h @@ -34,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/resources/badusb/demo_chromeos.txt b/applications/main/bad_usb/resources/badusb/demo_chromeos.txt index c5f675fb3..7f42574ce 100644 --- a/applications/main/bad_usb/resources/badusb/demo_chromeos.txt +++ b/applications/main/bad_usb/resources/badusb/demo_chromeos.txt @@ -1,12 +1,17 @@ -REM This is BadUSB demo script for ChromeOS by kowalski7cc +REM This is BadUSB demo script for Chrome and ChromeOS by kowalski7cc +REM Exit from Overview +ESC REM Open a new tab CTRL t REM wait for some slower chromebooks DELAY 1000 +REM Make sure we have omnibox focus +CTRL l +DELAY 200 REM Open an empty editable page DEFAULT_DELAY 50 -STRING data:text/html,