浏览代码

BadUSB ID change (#1046)

* badusb: vid/pid/strings change
* demo script update
* removed vid/pid values

Co-authored-by: あく <alleteam@gmail.com>
Nikolay Minaylov 3 年之前
父节点
当前提交
d075e00ae1

+ 0 - 5
applications/bad_usb/bad_usb_app.c

@@ -115,15 +115,10 @@ void bad_usb_app_free(BadUsbApp* app) {
 }
 
 int32_t bad_usb_app(void* p) {
-    FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config();
-    furi_hal_usb_set_config(&usb_hid);
-
     BadUsbApp* bad_usb_app = bad_usb_app_alloc((char*)p);
 
     view_dispatcher_run(bad_usb_app->view_dispatcher);
 
-    furi_hal_usb_set_config(usb_mode_prev);
     bad_usb_app_free(bad_usb_app);
-
     return 0;
 }

+ 53 - 1
applications/bad_usb/bad_usb_script.c

@@ -24,6 +24,7 @@ typedef enum {
 } WorkerEvtFlags;
 
 struct BadUsbScript {
+    FuriHalUsbHidConfig hid_cfg;
     BadUsbState st;
     string_t file_path;
     uint32_t defdelay;
@@ -101,6 +102,7 @@ static const DuckyKey ducky_keys[] = {
 };
 
 static const char ducky_cmd_comment[] = {"REM"};
+static const char ducky_cmd_id[] = {"ID"};
 static const char ducky_cmd_delay[] = {"DELAY "};
 static const char ducky_cmd_string[] = {"STRING "};
 static const char ducky_cmd_defdelay_1[] = {"DEFAULT_DELAY "};
@@ -240,12 +242,15 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) {
         if(i == line_len - 1) return SCRIPT_STATE_NEXT_LINE; // Skip empty lines
     }
 
-    FURI_LOG_I(WORKER_TAG, "line:%s", line_tmp);
+    FURI_LOG_D(WORKER_TAG, "line:%s", line_tmp);
 
     // General commands
     if(strncmp(line_tmp, ducky_cmd_comment, strlen(ducky_cmd_comment)) == 0) {
         // REM - comment line
         return (0);
+    } 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_delay, strlen(ducky_cmd_delay)) == 0) {
         // DELAY
         line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
@@ -302,10 +307,37 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) {
     return SCRIPT_STATE_ERROR;
 }
 
+static bool ducky_set_usb_id(BadUsbScript* bad_usb, const char* line) {
+    if(sscanf(line, "%lX:%lX", &bad_usb->hid_cfg.vid, &bad_usb->hid_cfg.pid) == 2) {
+        bad_usb->hid_cfg.manuf[0] = '\0';
+        bad_usb->hid_cfg.product[0] = '\0';
+
+        uint8_t id_len = ducky_get_command_len(line);
+        if(!ducky_is_line_end(line[id_len + 1])) {
+            sscanf(
+                &line[id_len + 1],
+                "%31[^\r\n:]:%31[^\r\n]",
+                bad_usb->hid_cfg.manuf,
+                bad_usb->hid_cfg.product);
+        }
+        FURI_LOG_D(
+            WORKER_TAG,
+            "set id: %04X:%04X mfr:%s product:%s",
+            bad_usb->hid_cfg.vid,
+            bad_usb->hid_cfg.pid,
+            bad_usb->hid_cfg.manuf,
+            bad_usb->hid_cfg.product);
+        return true;
+    }
+    return false;
+}
+
 static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) {
     uint8_t ret = 0;
     uint32_t line_len = 0;
 
+    string_reset(bad_usb->line);
+
     do {
         ret = storage_file_read(script_file, bad_usb->file_buf, FILE_BUFFER_LEN);
         for(uint16_t i = 0; i < ret; i++) {
@@ -313,6 +345,9 @@ static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) {
                 bad_usb->st.line_nb++;
                 line_len = 0;
             } else {
+                if(bad_usb->st.line_nb == 0) { // Save first line
+                    string_push_back(bad_usb->line, bad_usb->file_buf[i]);
+                }
                 line_len++;
             }
         }
@@ -324,7 +359,20 @@ static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) {
         }
     } while(ret > 0);
 
+    const char* line_tmp = string_get_cstr(bad_usb->line);
+    bool id_set = false; // Looking for ID command at first line
+    if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) {
+        id_set = ducky_set_usb_id(bad_usb, &line_tmp[strlen(ducky_cmd_id) + 1]);
+    }
+
+    if(id_set) {
+        furi_hal_usb_set_config(&usb_hid, &bad_usb->hid_cfg);
+    } else {
+        furi_hal_usb_set_config(&usb_hid, NULL);
+    }
+
     storage_file_seek(script_file, 0, true);
+    string_reset(bad_usb->line);
 
     return true;
 }
@@ -403,6 +451,8 @@ static int32_t bad_usb_worker(void* context) {
     BadUsbWorkerState worker_state = BadUsbStateInit;
     int32_t delay_val = 0;
 
+    FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config();
+
     FURI_LOG_I(WORKER_TAG, "Init");
     File* script_file = storage_file_alloc(furi_record_open("storage"));
     string_init(bad_usb->line);
@@ -522,6 +572,8 @@ static int32_t bad_usb_worker(void* context) {
 
     furi_hal_hid_set_state_callback(NULL, NULL);
 
+    furi_hal_usb_set_config(usb_mode_prev, NULL);
+
     storage_file_close(script_file);
     storage_file_free(script_file);
     string_clear(bad_usb->line);

+ 2 - 2
applications/debug_tools/usb_mouse.c

@@ -42,7 +42,7 @@ int32_t usb_mouse_app(void* p) {
     ViewPort* view_port = view_port_alloc();
 
     FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config();
-    furi_hal_usb_set_config(&usb_hid);
+    furi_hal_usb_set_config(&usb_hid, NULL);
 
     view_port_draw_callback_set(view_port, usb_mouse_render_callback, NULL);
     view_port_input_callback_set(view_port, usb_mouse_input_callback, event_queue);
@@ -110,7 +110,7 @@ int32_t usb_mouse_app(void* p) {
         view_port_update(view_port);
     }
 
-    furi_hal_usb_set_config(usb_mode_prev);
+    furi_hal_usb_set_config(usb_mode_prev, NULL);
 
     // remove & free all stuff created by app
     gui_remove_view_port(gui, view_port);

+ 19 - 5
applications/debug_tools/usb_test.c

@@ -10,6 +10,7 @@ typedef struct {
     Gui* gui;
     ViewDispatcher* view_dispatcher;
     Submenu* submenu;
+    FuriHalUsbHidConfig hid_cfg;
 } UsbTestApp;
 
 typedef enum {
@@ -19,12 +20,13 @@ typedef enum {
     UsbTestSubmenuIndexVcpSingle,
     UsbTestSubmenuIndexVcpDual,
     UsbTestSubmenuIndexHid,
+    UsbTestSubmenuIndexHidWithParams,
     UsbTestSubmenuIndexHidU2F,
 } SubmenuIndex;
 
 void usb_test_submenu_callback(void* context, uint32_t index) {
     furi_assert(context);
-    //UsbTestApp* app = context;
+    UsbTestApp* app = context;
     if(index == UsbTestSubmenuIndexEnable) {
         furi_hal_usb_enable();
     } else if(index == UsbTestSubmenuIndexDisable) {
@@ -32,13 +34,19 @@ void usb_test_submenu_callback(void* context, uint32_t index) {
     } else if(index == UsbTestSubmenuIndexRestart) {
         furi_hal_usb_reinit();
     } else if(index == UsbTestSubmenuIndexVcpSingle) {
-        furi_hal_usb_set_config(&usb_cdc_single);
+        furi_hal_usb_set_config(&usb_cdc_single, NULL);
     } else if(index == UsbTestSubmenuIndexVcpDual) {
-        furi_hal_usb_set_config(&usb_cdc_dual);
+        furi_hal_usb_set_config(&usb_cdc_dual, NULL);
     } else if(index == UsbTestSubmenuIndexHid) {
-        furi_hal_usb_set_config(&usb_hid);
+        furi_hal_usb_set_config(&usb_hid, NULL);
+    } else if(index == UsbTestSubmenuIndexHidWithParams) {
+        app->hid_cfg.vid = 0x1234;
+        app->hid_cfg.pid = 0xabcd;
+        strncpy(app->hid_cfg.manuf, "WEN", sizeof(app->hid_cfg.manuf));
+        strncpy(app->hid_cfg.product, "FLIP", sizeof(app->hid_cfg.product));
+        furi_hal_usb_set_config(&usb_hid, &app->hid_cfg);
     } else if(index == UsbTestSubmenuIndexHidU2F) {
-        furi_hal_usb_set_config(&usb_hid_u2f);
+        furi_hal_usb_set_config(&usb_hid_u2f, NULL);
     }
 }
 
@@ -71,6 +79,12 @@ UsbTestApp* usb_test_app_alloc() {
         app->submenu, "Dual VCP", UsbTestSubmenuIndexVcpDual, usb_test_submenu_callback, app);
     submenu_add_item(
         app->submenu, "HID KB+Mouse", UsbTestSubmenuIndexHid, usb_test_submenu_callback, app);
+    submenu_add_item(
+        app->submenu,
+        "HID KB+Mouse custom ID",
+        UsbTestSubmenuIndexHidWithParams,
+        usb_test_submenu_callback,
+        app);
     submenu_add_item(
         app->submenu, "HID U2F", UsbTestSubmenuIndexHidU2F, usb_test_submenu_callback, app);
     view_set_previous_callback(submenu_get_view(app->submenu), usb_test_exit);

+ 3 - 3
applications/gpio/usb_uart_bridge.c

@@ -84,10 +84,10 @@ static void usb_uart_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) {
 
 static void usb_uart_vcp_init(UsbUartBridge* usb_uart, uint8_t vcp_ch) {
     if(vcp_ch == 0) {
-        furi_hal_usb_set_config(&usb_cdc_single);
+        furi_hal_usb_set_config(&usb_cdc_single, NULL);
         furi_hal_vcp_disable();
     } else {
-        furi_hal_usb_set_config(&usb_cdc_dual);
+        furi_hal_usb_set_config(&usb_cdc_dual, NULL);
     }
     furi_hal_cdc_set_callbacks(vcp_ch, (CdcCallbacks*)&cdc_cb, usb_uart);
 }
@@ -247,7 +247,7 @@ static int32_t usb_uart_worker(void* context) {
 
     usb_uart_vcp_deinit(usb_uart, usb_uart->cfg.vcp_ch);
     usb_uart_serial_deinit(usb_uart, usb_uart->cfg.uart_ch);
-    furi_hal_usb_set_config(usb_mode_prev);
+    furi_hal_usb_set_config(usb_mode_prev, NULL);
     if(usb_uart->cfg.flow_pins != 0) {
         hal_gpio_init_simple(flow_pins[usb_uart->cfg.flow_pins - 1][0], GpioModeAnalog);
         hal_gpio_init_simple(flow_pins[usb_uart->cfg.flow_pins - 1][1], GpioModeAnalog);

+ 2 - 2
applications/u2f/u2f_hid.c

@@ -191,7 +191,7 @@ static int32_t u2f_hid_worker(void* context) {
     FURI_LOG_D(WORKER_TAG, "Init");
 
     FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config();
-    furi_hal_usb_set_config(&usb_hid_u2f);
+    furi_hal_usb_set_config(&usb_hid_u2f, NULL);
 
     u2f_hid->lock_timer = osTimerNew(u2f_hid_lock_timeout_callback, osTimerOnce, u2f_hid, NULL);
 
@@ -270,7 +270,7 @@ static int32_t u2f_hid_worker(void* context) {
     osTimerDelete(u2f_hid->lock_timer);
 
     furi_hal_hid_u2f_set_callback(NULL, NULL);
-    furi_hal_usb_set_config(usb_mode_prev);
+    furi_hal_usb_set_config(usb_mode_prev, NULL);
     FURI_LOG_D(WORKER_TAG, "End");
 
     return 0;

+ 4 - 0
assets/resources/badusb/demo_macos.txt

@@ -1,3 +1,7 @@
+ID 1234:5678 Apple:Keyboard
+REM You can change these values to VID/PID of original Apple keyboard
+REM to bypass Keyboard Setup Assistant
+
 REM This is BadUSB demo script for macOS
 
 REM Open terminal window

+ 4 - 2
firmware/targets/f6/furi_hal/furi_hal_usb.c

@@ -18,6 +18,7 @@ typedef struct {
     bool connected;
     FuriHalUsbInterface* if_cur;
     FuriHalUsbInterface* if_next;
+    void* if_ctx;
     FuriHalUsbStateCallback callback;
     void* cb_ctx;
 } UsbSrv;
@@ -88,8 +89,9 @@ void furi_hal_usb_init(void) {
     FURI_LOG_I(TAG, "Init OK");
 }
 
-void furi_hal_usb_set_config(FuriHalUsbInterface* new_if) {
+void furi_hal_usb_set_config(FuriHalUsbInterface* new_if, void* ctx) {
     usb.if_next = new_if;
+    usb.if_ctx = ctx;
     if(usb.thread == NULL) {
         // Service thread hasn't started yet, so just save interface mode
         return;
@@ -246,7 +248,7 @@ static int32_t furi_hal_usb_thread(void* context) {
                     usb.if_cur->deinit(&udev);
                 }
                 if(usb.if_next != NULL) {
-                    usb.if_next->init(&udev, usb.if_next);
+                    usb.if_next->init(&udev, usb.if_next, usb.if_ctx);
                     usbd_reg_event(&udev, usbd_evt_reset, reset_evt);
                     FURI_LOG_I(TAG, "USB Mode change done");
                     usb.enabled = true;

+ 2 - 2
firmware/targets/f6/furi_hal/furi_hal_usb_cdc.c

@@ -385,7 +385,7 @@ static const struct CdcConfigDescriptorDual
 static struct usb_cdc_line_coding cdc_config[IF_NUM_MAX] = {};
 static uint8_t cdc_ctrl_line_state[IF_NUM_MAX];
 
-static void cdc_init(usbd_device* dev, FuriHalUsbInterface* intf);
+static void cdc_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx);
 static void cdc_deinit(usbd_device* dev);
 static void cdc_on_wakeup(usbd_device* dev);
 static void cdc_on_suspend(usbd_device* dev);
@@ -428,7 +428,7 @@ FuriHalUsbInterface usb_cdc_dual = {
     .cfg_descr = (void*)&cdc_cfg_desc_dual,
 };
 
-static void cdc_init(usbd_device* dev, FuriHalUsbInterface* intf) {
+static void cdc_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx) {
     usb_dev = dev;
     cdc_if_cur = intf;
 

+ 61 - 24
firmware/targets/f6/furi_hal/furi_hal_usb_hid.c

@@ -21,6 +21,9 @@
 #define HID_PAGE_CONSUMER 0x0C
 #define HID_CONSUMER_CONTROL 0x01
 
+#define HID_VID_DEFAULT 0x046D
+#define HID_PID_DEFAULT 0xC529
+
 struct HidIadDescriptor {
     struct usb_iad_descriptor hid_iad;
     struct usb_interface_descriptor hid;
@@ -114,12 +117,8 @@ static const uint8_t hid_report_desc[] = {
     HID_END_COLLECTION,
 };
 
-static const struct usb_string_descriptor dev_manuf_desc = USB_STRING_DESC("Logitech");
-static const struct usb_string_descriptor dev_prod_desc = USB_STRING_DESC("USB Receiver");
-static const struct usb_string_descriptor dev_serial_desc = USB_STRING_DESC("1234567890");
-
 /* Device descriptor */
-static const struct usb_device_descriptor hid_device_desc = {
+static struct usb_device_descriptor hid_device_desc = {
     .bLength = sizeof(struct usb_device_descriptor),
     .bDescriptorType = USB_DTYPE_DEVICE,
     .bcdUSB = VERSION_BCD(2, 0, 0),
@@ -127,12 +126,12 @@ static const struct usb_device_descriptor hid_device_desc = {
     .bDeviceSubClass = USB_SUBCLASS_IAD,
     .bDeviceProtocol = USB_PROTO_IAD,
     .bMaxPacketSize0 = USB_EP0_SIZE,
-    .idVendor = 0x046d,
-    .idProduct = 0xc529,
+    .idVendor = HID_VID_DEFAULT,
+    .idProduct = HID_PID_DEFAULT,
     .bcdDevice = VERSION_BCD(1, 0, 0),
-    .iManufacturer = UsbDevManuf,
-    .iProduct = UsbDevProduct,
-    .iSerialNumber = UsbDevSerial,
+    .iManufacturer = 0,
+    .iProduct = 0,
+    .iSerialNumber = 0,
     .bNumConfigurations = 1,
 };
 
@@ -236,11 +235,26 @@ static struct HidReport {
     struct HidReportConsumer consumer;
 } __attribute__((packed)) hid_report;
 
-static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf);
+static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx);
 static void hid_deinit(usbd_device* dev);
 static void hid_on_wakeup(usbd_device* dev);
 static void hid_on_suspend(usbd_device* dev);
 
+FuriHalUsbInterface usb_hid = {
+    .init = hid_init,
+    .deinit = hid_deinit,
+    .wakeup = hid_on_wakeup,
+    .suspend = hid_on_suspend,
+
+    .dev_descr = (struct usb_device_descriptor*)&hid_device_desc,
+
+    .str_manuf_descr = NULL,
+    .str_prod_descr = NULL,
+    .str_serial_descr = NULL,
+
+    .cfg_descr = (void*)&hid_cfg_desc,
+};
+
 static bool hid_send_report(uint8_t report_id);
 static usbd_respond hid_ep_config(usbd_device* dev, uint8_t cfg);
 static usbd_respond hid_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback);
@@ -348,28 +362,48 @@ bool furi_hal_hid_consumer_key_release(uint16_t button) {
     return hid_send_report(ReportIdConsumer);
 }
 
-FuriHalUsbInterface usb_hid = {
-    .init = hid_init,
-    .deinit = hid_deinit,
-    .wakeup = hid_on_wakeup,
-    .suspend = hid_on_suspend,
-
-    .dev_descr = (struct usb_device_descriptor*)&hid_device_desc,
+static void* hid_set_string_descr(char* str) {
+    furi_assert(str);
 
-    .str_manuf_descr = (void*)&dev_manuf_desc,
-    .str_prod_descr = (void*)&dev_prod_desc,
-    .str_serial_descr = (void*)&dev_serial_desc,
+    uint8_t len = strlen(str);
+    struct usb_string_descriptor* dev_str_desc = malloc(len * 2 + 2);
+    dev_str_desc->bLength = len * 2 + 2;
+    dev_str_desc->bDescriptorType = USB_DTYPE_STRING;
+    for(uint8_t i = 0; i < len; i++) dev_str_desc->wString[i] = str[i];
 
-    .cfg_descr = (void*)&hid_cfg_desc,
-};
+    return dev_str_desc;
+}
 
-static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf) {
+static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx) {
+    FuriHalUsbHidConfig* cfg = (FuriHalUsbHidConfig*)ctx;
     if(hid_semaphore == NULL) hid_semaphore = osSemaphoreNew(1, 1, NULL);
     usb_dev = dev;
     hid_report.keyboard.report_id = ReportIdKeyboard;
     hid_report.mouse.report_id = ReportIdMouse;
     hid_report.consumer.report_id = ReportIdConsumer;
 
+    usb_hid.dev_descr->iManufacturer = 0;
+    usb_hid.dev_descr->iProduct = 0;
+    usb_hid.str_manuf_descr = NULL;
+    usb_hid.str_prod_descr = NULL;
+    usb_hid.dev_descr->idVendor = HID_VID_DEFAULT;
+    usb_hid.dev_descr->idProduct = HID_PID_DEFAULT;
+
+    if(cfg != NULL) {
+        usb_hid.dev_descr->idVendor = cfg->vid;
+        usb_hid.dev_descr->idProduct = cfg->pid;
+
+        if(cfg->manuf[0] != '\0') {
+            usb_hid.str_manuf_descr = hid_set_string_descr(cfg->manuf);
+            usb_hid.dev_descr->iManufacturer = UsbDevManuf;
+        }
+
+        if(cfg->product[0] != '\0') {
+            usb_hid.str_prod_descr = hid_set_string_descr(cfg->product);
+            usb_hid.dev_descr->iProduct = UsbDevProduct;
+        }
+    }
+
     usbd_reg_config(dev, hid_ep_config);
     usbd_reg_control(dev, hid_control);
 
@@ -379,6 +413,9 @@ static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf) {
 static void hid_deinit(usbd_device* dev) {
     usbd_reg_config(dev, NULL);
     usbd_reg_control(dev, NULL);
+
+    free(usb_hid.str_manuf_descr);
+    free(usb_hid.str_prod_descr);
 }
 
 static void hid_on_wakeup(usbd_device* dev) {

+ 2 - 2
firmware/targets/f6/furi_hal/furi_hal_usb_u2f.c

@@ -137,7 +137,7 @@ static const struct HidConfigDescriptor hid_u2f_cfg_desc = {
         },
 };
 
-static void hid_u2f_init(usbd_device* dev, FuriHalUsbInterface* intf);
+static void hid_u2f_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx);
 static void hid_u2f_deinit(usbd_device* dev);
 static void hid_u2f_on_wakeup(usbd_device* dev);
 static void hid_u2f_on_suspend(usbd_device* dev);
@@ -185,7 +185,7 @@ FuriHalUsbInterface usb_hid_u2f = {
     .cfg_descr = (void*)&hid_u2f_cfg_desc,
 };
 
-static void hid_u2f_init(usbd_device* dev, FuriHalUsbInterface* intf) {
+static void hid_u2f_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx) {
     if(hid_u2f_semaphore == NULL) hid_u2f_semaphore = osSemaphoreNew(1, 1, NULL);
     usb_dev = dev;
 

+ 1 - 1
firmware/targets/f6/furi_hal/furi_hal_vcp.c

@@ -79,7 +79,7 @@ static int32_t vcp_worker(void* context) {
     size_t missed_rx = 0;
     uint8_t last_tx_pkt_len = 0;
 
-    furi_hal_usb_set_config(&usb_cdc_single);
+    furi_hal_usb_set_config(&usb_cdc_single, NULL);
     furi_hal_cdc_set_callbacks(VCP_IF_NUM, &cdc_cb, NULL);
 
     while(1) {

+ 4 - 2
firmware/targets/f7/furi_hal/furi_hal_usb.c

@@ -18,6 +18,7 @@ typedef struct {
     bool connected;
     FuriHalUsbInterface* if_cur;
     FuriHalUsbInterface* if_next;
+    void* if_ctx;
     FuriHalUsbStateCallback callback;
     void* cb_ctx;
 } UsbSrv;
@@ -88,8 +89,9 @@ void furi_hal_usb_init(void) {
     FURI_LOG_I(TAG, "Init OK");
 }
 
-void furi_hal_usb_set_config(FuriHalUsbInterface* new_if) {
+void furi_hal_usb_set_config(FuriHalUsbInterface* new_if, void* ctx) {
     usb.if_next = new_if;
+    usb.if_ctx = ctx;
     if(usb.thread == NULL) {
         // Service thread hasn't started yet, so just save interface mode
         return;
@@ -246,7 +248,7 @@ static int32_t furi_hal_usb_thread(void* context) {
                     usb.if_cur->deinit(&udev);
                 }
                 if(usb.if_next != NULL) {
-                    usb.if_next->init(&udev, usb.if_next);
+                    usb.if_next->init(&udev, usb.if_next, usb.if_ctx);
                     usbd_reg_event(&udev, usbd_evt_reset, reset_evt);
                     FURI_LOG_I(TAG, "USB Mode change done");
                     usb.enabled = true;

+ 2 - 2
firmware/targets/f7/furi_hal/furi_hal_usb_cdc.c

@@ -385,7 +385,7 @@ static const struct CdcConfigDescriptorDual
 static struct usb_cdc_line_coding cdc_config[IF_NUM_MAX] = {};
 static uint8_t cdc_ctrl_line_state[IF_NUM_MAX];
 
-static void cdc_init(usbd_device* dev, FuriHalUsbInterface* intf);
+static void cdc_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx);
 static void cdc_deinit(usbd_device* dev);
 static void cdc_on_wakeup(usbd_device* dev);
 static void cdc_on_suspend(usbd_device* dev);
@@ -428,7 +428,7 @@ FuriHalUsbInterface usb_cdc_dual = {
     .cfg_descr = (void*)&cdc_cfg_desc_dual,
 };
 
-static void cdc_init(usbd_device* dev, FuriHalUsbInterface* intf) {
+static void cdc_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx) {
     usb_dev = dev;
     cdc_if_cur = intf;
 

+ 61 - 24
firmware/targets/f7/furi_hal/furi_hal_usb_hid.c

@@ -21,6 +21,9 @@
 #define HID_PAGE_CONSUMER 0x0C
 #define HID_CONSUMER_CONTROL 0x01
 
+#define HID_VID_DEFAULT 0x046D
+#define HID_PID_DEFAULT 0xC529
+
 struct HidIadDescriptor {
     struct usb_iad_descriptor hid_iad;
     struct usb_interface_descriptor hid;
@@ -114,12 +117,8 @@ static const uint8_t hid_report_desc[] = {
     HID_END_COLLECTION,
 };
 
-static const struct usb_string_descriptor dev_manuf_desc = USB_STRING_DESC("Logitech");
-static const struct usb_string_descriptor dev_prod_desc = USB_STRING_DESC("USB Receiver");
-static const struct usb_string_descriptor dev_serial_desc = USB_STRING_DESC("1234567890");
-
 /* Device descriptor */
-static const struct usb_device_descriptor hid_device_desc = {
+static struct usb_device_descriptor hid_device_desc = {
     .bLength = sizeof(struct usb_device_descriptor),
     .bDescriptorType = USB_DTYPE_DEVICE,
     .bcdUSB = VERSION_BCD(2, 0, 0),
@@ -127,12 +126,12 @@ static const struct usb_device_descriptor hid_device_desc = {
     .bDeviceSubClass = USB_SUBCLASS_IAD,
     .bDeviceProtocol = USB_PROTO_IAD,
     .bMaxPacketSize0 = USB_EP0_SIZE,
-    .idVendor = 0x046d,
-    .idProduct = 0xc529,
+    .idVendor = HID_VID_DEFAULT,
+    .idProduct = HID_PID_DEFAULT,
     .bcdDevice = VERSION_BCD(1, 0, 0),
-    .iManufacturer = UsbDevManuf,
-    .iProduct = UsbDevProduct,
-    .iSerialNumber = UsbDevSerial,
+    .iManufacturer = 0,
+    .iProduct = 0,
+    .iSerialNumber = 0,
     .bNumConfigurations = 1,
 };
 
@@ -236,11 +235,26 @@ static struct HidReport {
     struct HidReportConsumer consumer;
 } __attribute__((packed)) hid_report;
 
-static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf);
+static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx);
 static void hid_deinit(usbd_device* dev);
 static void hid_on_wakeup(usbd_device* dev);
 static void hid_on_suspend(usbd_device* dev);
 
+FuriHalUsbInterface usb_hid = {
+    .init = hid_init,
+    .deinit = hid_deinit,
+    .wakeup = hid_on_wakeup,
+    .suspend = hid_on_suspend,
+
+    .dev_descr = (struct usb_device_descriptor*)&hid_device_desc,
+
+    .str_manuf_descr = NULL,
+    .str_prod_descr = NULL,
+    .str_serial_descr = NULL,
+
+    .cfg_descr = (void*)&hid_cfg_desc,
+};
+
 static bool hid_send_report(uint8_t report_id);
 static usbd_respond hid_ep_config(usbd_device* dev, uint8_t cfg);
 static usbd_respond hid_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback);
@@ -348,28 +362,48 @@ bool furi_hal_hid_consumer_key_release(uint16_t button) {
     return hid_send_report(ReportIdConsumer);
 }
 
-FuriHalUsbInterface usb_hid = {
-    .init = hid_init,
-    .deinit = hid_deinit,
-    .wakeup = hid_on_wakeup,
-    .suspend = hid_on_suspend,
-
-    .dev_descr = (struct usb_device_descriptor*)&hid_device_desc,
+static void* hid_set_string_descr(char* str) {
+    furi_assert(str);
 
-    .str_manuf_descr = (void*)&dev_manuf_desc,
-    .str_prod_descr = (void*)&dev_prod_desc,
-    .str_serial_descr = (void*)&dev_serial_desc,
+    uint8_t len = strlen(str);
+    struct usb_string_descriptor* dev_str_desc = malloc(len * 2 + 2);
+    dev_str_desc->bLength = len * 2 + 2;
+    dev_str_desc->bDescriptorType = USB_DTYPE_STRING;
+    for(uint8_t i = 0; i < len; i++) dev_str_desc->wString[i] = str[i];
 
-    .cfg_descr = (void*)&hid_cfg_desc,
-};
+    return dev_str_desc;
+}
 
-static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf) {
+static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx) {
+    FuriHalUsbHidConfig* cfg = (FuriHalUsbHidConfig*)ctx;
     if(hid_semaphore == NULL) hid_semaphore = osSemaphoreNew(1, 1, NULL);
     usb_dev = dev;
     hid_report.keyboard.report_id = ReportIdKeyboard;
     hid_report.mouse.report_id = ReportIdMouse;
     hid_report.consumer.report_id = ReportIdConsumer;
 
+    usb_hid.dev_descr->iManufacturer = 0;
+    usb_hid.dev_descr->iProduct = 0;
+    usb_hid.str_manuf_descr = NULL;
+    usb_hid.str_prod_descr = NULL;
+    usb_hid.dev_descr->idVendor = HID_VID_DEFAULT;
+    usb_hid.dev_descr->idProduct = HID_PID_DEFAULT;
+
+    if(cfg != NULL) {
+        usb_hid.dev_descr->idVendor = cfg->vid;
+        usb_hid.dev_descr->idProduct = cfg->pid;
+
+        if(cfg->manuf[0] != '\0') {
+            usb_hid.str_manuf_descr = hid_set_string_descr(cfg->manuf);
+            usb_hid.dev_descr->iManufacturer = UsbDevManuf;
+        }
+
+        if(cfg->product[0] != '\0') {
+            usb_hid.str_prod_descr = hid_set_string_descr(cfg->product);
+            usb_hid.dev_descr->iProduct = UsbDevProduct;
+        }
+    }
+
     usbd_reg_config(dev, hid_ep_config);
     usbd_reg_control(dev, hid_control);
 
@@ -379,6 +413,9 @@ static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf) {
 static void hid_deinit(usbd_device* dev) {
     usbd_reg_config(dev, NULL);
     usbd_reg_control(dev, NULL);
+
+    free(usb_hid.str_manuf_descr);
+    free(usb_hid.str_prod_descr);
 }
 
 static void hid_on_wakeup(usbd_device* dev) {

+ 2 - 2
firmware/targets/f7/furi_hal/furi_hal_usb_u2f.c

@@ -137,7 +137,7 @@ static const struct HidConfigDescriptor hid_u2f_cfg_desc = {
         },
 };
 
-static void hid_u2f_init(usbd_device* dev, FuriHalUsbInterface* intf);
+static void hid_u2f_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx);
 static void hid_u2f_deinit(usbd_device* dev);
 static void hid_u2f_on_wakeup(usbd_device* dev);
 static void hid_u2f_on_suspend(usbd_device* dev);
@@ -185,7 +185,7 @@ FuriHalUsbInterface usb_hid_u2f = {
     .cfg_descr = (void*)&hid_u2f_cfg_desc,
 };
 
-static void hid_u2f_init(usbd_device* dev, FuriHalUsbInterface* intf) {
+static void hid_u2f_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx) {
     if(hid_u2f_semaphore == NULL) hid_u2f_semaphore = osSemaphoreNew(1, 1, NULL);
     usb_dev = dev;
 

+ 1 - 1
firmware/targets/f7/furi_hal/furi_hal_vcp.c

@@ -79,7 +79,7 @@ static int32_t vcp_worker(void* context) {
     size_t missed_rx = 0;
     uint8_t last_tx_pkt_len = 0;
 
-    furi_hal_usb_set_config(&usb_cdc_single);
+    furi_hal_usb_set_config(&usb_cdc_single, NULL);
     furi_hal_cdc_set_callbacks(VCP_IF_NUM, &cdc_cb, NULL);
 
     while(1) {

+ 3 - 2
firmware/targets/furi_hal_include/furi_hal_usb.h

@@ -5,7 +5,7 @@
 typedef struct FuriHalUsbInterface FuriHalUsbInterface;
 
 struct FuriHalUsbInterface {
-    void (*init)(usbd_device* dev, FuriHalUsbInterface* intf);
+    void (*init)(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx);
     void (*deinit)(usbd_device* dev);
     void (*wakeup)(usbd_device* dev);
     void (*suspend)(usbd_device* dev);
@@ -41,8 +41,9 @@ void furi_hal_usb_init();
 /** Set USB device configuration
  *
  * @param      mode new USB device mode
+ * @param      ctx context passed to device mode init function
  */
-void furi_hal_usb_set_config(FuriHalUsbInterface* new_if);
+void furi_hal_usb_set_config(FuriHalUsbInterface* new_if, void* ctx);
 
 /** Get USB device configuration
  *

+ 7 - 0
firmware/targets/furi_hal_include/furi_hal_usb_hid.h

@@ -250,6 +250,13 @@ static const uint16_t hid_asciimap[] = {
     KEY_NONE, // DEL
 };
 
+typedef struct {
+    uint32_t vid;
+    uint32_t pid;
+    char manuf[32];
+    char product[32];
+} FuriHalUsbHidConfig;
+
 typedef void (*HidStateCallback)(bool state, void* context);
 
 /** ASCII to keycode conversion macro */