[FL-3134] BadUSB: Script interpreter refactoring (#2485)
* Script command and character tables * Non-blocking stringdelay, docs update * altchar/altstring fix * Layout select UI fix * Remove debug print Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									445a1aa7b0
								
							
						
					
					
						commit
						0444a80f19
					
				| @ -2,7 +2,7 @@ | |||||||
| 
 | 
 | ||||||
| #include "bad_usb_app.h" | #include "bad_usb_app.h" | ||||||
| #include "scenes/bad_usb_scene.h" | #include "scenes/bad_usb_scene.h" | ||||||
| #include "bad_usb_script.h" | #include "helpers/ducky_script.h" | ||||||
| 
 | 
 | ||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
| #include <assets_icons.h> | #include <assets_icons.h> | ||||||
|  | |||||||
| @ -5,17 +5,13 @@ | |||||||
| #include <lib/toolbox/args.h> | #include <lib/toolbox/args.h> | ||||||
| #include <furi_hal_usb_hid.h> | #include <furi_hal_usb_hid.h> | ||||||
| #include <storage/storage.h> | #include <storage/storage.h> | ||||||
| #include "bad_usb_script.h" | #include "ducky_script.h" | ||||||
| #include "mnemonic.h" | #include "ducky_script_i.h" | ||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| #define TAG "BadUSB" | #define TAG "BadUSB" | ||||||
| #define WORKER_TAG TAG "Worker" | #define WORKER_TAG TAG "Worker" | ||||||
| 
 | 
 | ||||||
| #define SCRIPT_STATE_ERROR (-1) |  | ||||||
| #define SCRIPT_STATE_END (-2) |  | ||||||
| #define SCRIPT_STATE_NEXT_LINE (-3) |  | ||||||
| 
 |  | ||||||
| #define BADUSB_ASCII_TO_KEY(script, x) \ | #define BADUSB_ASCII_TO_KEY(script, x) \ | ||||||
|     (((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE) |     (((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE) | ||||||
| 
 | 
 | ||||||
| @ -26,87 +22,20 @@ typedef enum { | |||||||
|     WorkerEvtDisconnect = (1 << 3), |     WorkerEvtDisconnect = (1 << 3), | ||||||
| } WorkerEvtFlags; | } WorkerEvtFlags; | ||||||
| 
 | 
 | ||||||
| typedef struct { |  | ||||||
|     char* name; |  | ||||||
|     uint16_t keycode; |  | ||||||
| } DuckyKey; |  | ||||||
| 
 |  | ||||||
| static const DuckyKey ducky_keys[] = { |  | ||||||
|     {"CTRL-ALT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_ALT}, |  | ||||||
|     {"CTRL-SHIFT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT}, |  | ||||||
|     {"ALT-SHIFT", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_SHIFT}, |  | ||||||
|     {"ALT-GUI", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_GUI}, |  | ||||||
|     {"GUI-SHIFT", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT}, |  | ||||||
|     {"GUI-CTRL", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_CTRL}, |  | ||||||
| 
 |  | ||||||
|     {"CTRL", KEY_MOD_LEFT_CTRL}, |  | ||||||
|     {"CONTROL", KEY_MOD_LEFT_CTRL}, |  | ||||||
|     {"SHIFT", KEY_MOD_LEFT_SHIFT}, |  | ||||||
|     {"ALT", KEY_MOD_LEFT_ALT}, |  | ||||||
|     {"GUI", KEY_MOD_LEFT_GUI}, |  | ||||||
|     {"WINDOWS", KEY_MOD_LEFT_GUI}, |  | ||||||
| 
 |  | ||||||
|     {"DOWNARROW", HID_KEYBOARD_DOWN_ARROW}, |  | ||||||
|     {"DOWN", HID_KEYBOARD_DOWN_ARROW}, |  | ||||||
|     {"LEFTARROW", HID_KEYBOARD_LEFT_ARROW}, |  | ||||||
|     {"LEFT", HID_KEYBOARD_LEFT_ARROW}, |  | ||||||
|     {"RIGHTARROW", HID_KEYBOARD_RIGHT_ARROW}, |  | ||||||
|     {"RIGHT", HID_KEYBOARD_RIGHT_ARROW}, |  | ||||||
|     {"UPARROW", HID_KEYBOARD_UP_ARROW}, |  | ||||||
|     {"UP", HID_KEYBOARD_UP_ARROW}, |  | ||||||
| 
 |  | ||||||
|     {"ENTER", HID_KEYBOARD_RETURN}, |  | ||||||
|     {"BREAK", HID_KEYBOARD_PAUSE}, |  | ||||||
|     {"PAUSE", HID_KEYBOARD_PAUSE}, |  | ||||||
|     {"CAPSLOCK", HID_KEYBOARD_CAPS_LOCK}, |  | ||||||
|     {"DELETE", HID_KEYBOARD_DELETE_FORWARD}, |  | ||||||
|     {"BACKSPACE", HID_KEYBOARD_DELETE}, |  | ||||||
|     {"END", HID_KEYBOARD_END}, |  | ||||||
|     {"ESC", HID_KEYBOARD_ESCAPE}, |  | ||||||
|     {"ESCAPE", HID_KEYBOARD_ESCAPE}, |  | ||||||
|     {"HOME", HID_KEYBOARD_HOME}, |  | ||||||
|     {"INSERT", HID_KEYBOARD_INSERT}, |  | ||||||
|     {"NUMLOCK", HID_KEYPAD_NUMLOCK}, |  | ||||||
|     {"PAGEUP", HID_KEYBOARD_PAGE_UP}, |  | ||||||
|     {"PAGEDOWN", HID_KEYBOARD_PAGE_DOWN}, |  | ||||||
|     {"PRINTSCREEN", HID_KEYBOARD_PRINT_SCREEN}, |  | ||||||
|     {"SCROLLLOCK", HID_KEYBOARD_SCROLL_LOCK}, |  | ||||||
|     {"SPACE", HID_KEYBOARD_SPACEBAR}, |  | ||||||
|     {"TAB", HID_KEYBOARD_TAB}, |  | ||||||
|     {"MENU", HID_KEYBOARD_APPLICATION}, |  | ||||||
|     {"APP", HID_KEYBOARD_APPLICATION}, |  | ||||||
| 
 |  | ||||||
|     {"F1", HID_KEYBOARD_F1}, |  | ||||||
|     {"F2", HID_KEYBOARD_F2}, |  | ||||||
|     {"F3", HID_KEYBOARD_F3}, |  | ||||||
|     {"F4", HID_KEYBOARD_F4}, |  | ||||||
|     {"F5", HID_KEYBOARD_F5}, |  | ||||||
|     {"F6", HID_KEYBOARD_F6}, |  | ||||||
|     {"F7", HID_KEYBOARD_F7}, |  | ||||||
|     {"F8", HID_KEYBOARD_F8}, |  | ||||||
|     {"F9", HID_KEYBOARD_F9}, |  | ||||||
|     {"F10", HID_KEYBOARD_F10}, |  | ||||||
|     {"F11", HID_KEYBOARD_F11}, |  | ||||||
|     {"F12", HID_KEYBOARD_F12}, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static const char ducky_cmd_comment[] = {"REM"}; |  | ||||||
| static const char ducky_cmd_id[] = {"ID"}; | 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_stringln[] = {"STRINGLN "}; |  | ||||||
| static const char ducky_cmd_defdelay_1[] = {"DEFAULT_DELAY "}; |  | ||||||
| static const char ducky_cmd_defdelay_2[] = {"DEFAULTDELAY "}; |  | ||||||
| static const char ducky_cmd_stringdelay_1[] = {"STRINGDELAY "}; |  | ||||||
| static const char ducky_cmd_stringdelay_2[] = {"STRING_DELAY "}; |  | ||||||
| static const char ducky_cmd_repeat[] = {"REPEAT "}; |  | ||||||
| static const char ducky_cmd_sysrq[] = {"SYSRQ "}; |  | ||||||
| static const char ducky_cmd_hold[] = {"HOLD "}; |  | ||||||
| static const char ducky_cmd_release[] = {"RELEASE "}; |  | ||||||
| 
 | 
 | ||||||
| static const char ducky_cmd_altchar[] = {"ALTCHAR "}; | static const uint8_t numpad_keys[10] = { | ||||||
| static const char ducky_cmd_altstr_1[] = {"ALTSTRING "}; |     HID_KEYPAD_0, | ||||||
| static const char ducky_cmd_altstr_2[] = {"ALTCODE "}; |     HID_KEYPAD_1, | ||||||
|  |     HID_KEYPAD_2, | ||||||
|  |     HID_KEYPAD_3, | ||||||
|  |     HID_KEYPAD_4, | ||||||
|  |     HID_KEYPAD_5, | ||||||
|  |     HID_KEYPAD_6, | ||||||
|  |     HID_KEYPAD_7, | ||||||
|  |     HID_KEYPAD_8, | ||||||
|  |     HID_KEYPAD_9, | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| uint32_t ducky_get_command_len(const char* line) { | uint32_t ducky_get_command_len(const char* line) { | ||||||
|     uint32_t len = strlen(line); |     uint32_t len = strlen(line); | ||||||
| @ -121,76 +50,150 @@ bool ducky_is_line_end(const char chr) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint16_t ducky_get_keycode(BadUsbScript* bad_usb, const char* param, bool accept_chars) { | 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++) { |     uint16_t keycode = ducky_get_keycode_by_name(param); | ||||||
|         size_t key_cmd_len = strlen(ducky_keys[i].name); |     if(keycode != HID_KEYBOARD_NONE) { | ||||||
|         if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) && |         return keycode; | ||||||
|            (ducky_is_line_end(param[key_cmd_len]))) { |  | ||||||
|             return ducky_keys[i].keycode; |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     if((accept_chars) && (strlen(param) > 0)) { |     if((accept_chars) && (strlen(param) > 0)) { | ||||||
|         return (BADUSB_ASCII_TO_KEY(bad_usb, param[0]) & 0xFF); |         return (BADUSB_ASCII_TO_KEY(bad_usb, param[0]) & 0xFF); | ||||||
|     } |     } | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int32_t | bool ducky_get_number(const char* param, uint32_t* val) { | ||||||
|     ducky_parse_line(BadUsbScript* bad_usb, FuriString* line, char* error, size_t error_len) { |     uint32_t value = 0; | ||||||
|  |     if(sscanf(param, "%lu", &value) == 1) { | ||||||
|  |         *val = value; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ducky_numlock_on() { | ||||||
|  |     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); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | bool ducky_numpad_press(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); | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ducky_altchar(const char* charcode) { | ||||||
|  |     uint8_t i = 0; | ||||||
|  |     bool state = false; | ||||||
|  | 
 | ||||||
|  |     furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT); | ||||||
|  | 
 | ||||||
|  |     while(!ducky_is_line_end(charcode[i])) { | ||||||
|  |         state = ducky_numpad_press(charcode[i]); | ||||||
|  |         if(state == false) break; | ||||||
|  |         i++; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     furi_hal_hid_kb_release(KEY_MOD_LEFT_ALT); | ||||||
|  |     return state; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ducky_altstring(const char* param) { | ||||||
|  |     uint32_t i = 0; | ||||||
|  |     bool state = false; | ||||||
|  | 
 | ||||||
|  |     while(param[i] != '\0') { | ||||||
|  |         if((param[i] < ' ') || (param[i] > '~')) { | ||||||
|  |             i++; | ||||||
|  |             continue; // Skip non-printable chars
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         char temp_str[4]; | ||||||
|  |         snprintf(temp_str, 4, "%u", param[i]); | ||||||
|  | 
 | ||||||
|  |         state = ducky_altchar(temp_str); | ||||||
|  |         if(state == false) break; | ||||||
|  |         i++; | ||||||
|  |     } | ||||||
|  |     return state; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int32_t ducky_error(BadUsbScript* bad_usb, const char* text, ...) { | ||||||
|  |     va_list args; | ||||||
|  |     va_start(args, text); | ||||||
|  | 
 | ||||||
|  |     vsnprintf(bad_usb->st.error, sizeof(bad_usb->st.error), text, args); | ||||||
|  | 
 | ||||||
|  |     va_end(args); | ||||||
|  |     return SCRIPT_STATE_ERROR; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ducky_string(BadUsbScript* bad_usb, const char* param) { | ||||||
|  |     uint32_t i = 0; | ||||||
|  | 
 | ||||||
|  |     while(param[i] != '\0') { | ||||||
|  |         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); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             furi_hal_hid_kb_press(HID_KEYBOARD_RETURN); | ||||||
|  |             furi_hal_hid_kb_release(HID_KEYBOARD_RETURN); | ||||||
|  |         } | ||||||
|  |         i++; | ||||||
|  |     } | ||||||
|  |     bad_usb->stringdelay = 0; | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool ducky_string_next(BadUsbScript* bad_usb) { | ||||||
|  |     if(bad_usb->string_print_pos >= furi_string_size(bad_usb->string_print)) { | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     char print_char = furi_string_get_char(bad_usb->string_print, bad_usb->string_print_pos); | ||||||
|  | 
 | ||||||
|  |     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); | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         furi_hal_hid_kb_press(HID_KEYBOARD_RETURN); | ||||||
|  |         furi_hal_hid_kb_release(HID_KEYBOARD_RETURN); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bad_usb->string_print_pos++; | ||||||
|  | 
 | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int32_t ducky_parse_line(BadUsbScript* bad_usb, FuriString* line) { | ||||||
|     uint32_t line_len = furi_string_size(line); |     uint32_t line_len = furi_string_size(line); | ||||||
|     const char* line_tmp = furi_string_get_cstr(line); |     const char* line_tmp = furi_string_get_cstr(line); | ||||||
|     const char* ducky_cmd_table[] = { |  | ||||||
|         ducky_cmd_comment, |  | ||||||
|         ducky_cmd_id, |  | ||||||
|         ducky_cmd_delay, |  | ||||||
|         ducky_cmd_string, |  | ||||||
|         ducky_cmd_defdelay_1, |  | ||||||
|         ducky_cmd_defdelay_2, |  | ||||||
|         ducky_cmd_stringdelay_1, |  | ||||||
|         ducky_cmd_stringdelay_2, |  | ||||||
|         ducky_cmd_repeat, |  | ||||||
|         ducky_cmd_sysrq, |  | ||||||
|         ducky_cmd_altchar, |  | ||||||
|         ducky_cmd_altstr_1, |  | ||||||
|         ducky_cmd_altstr_2, |  | ||||||
|         ducky_cmd_stringln, |  | ||||||
|         ducky_cmd_hold, |  | ||||||
|         ducky_cmd_release, |  | ||||||
|         NULL}; |  | ||||||
|     int32_t (*fnc_ptr[])(BadUsbScript*, FuriString*, const char*, char*, size_t) = { |  | ||||||
|         &ducky_fnc_noop, |  | ||||||
|         &ducky_fnc_noop, |  | ||||||
|         &ducky_fnc_delay, |  | ||||||
|         &ducky_fnc_string, |  | ||||||
|         &ducky_fnc_defdelay, |  | ||||||
|         &ducky_fnc_defdelay, |  | ||||||
|         &ducky_fnc_strdelay, |  | ||||||
|         &ducky_fnc_strdelay, |  | ||||||
|         &ducky_fnc_repeat, |  | ||||||
|         &ducky_fnc_sysrq, |  | ||||||
|         &ducky_fnc_altchar, |  | ||||||
|         &ducky_fnc_altstring, |  | ||||||
|         &ducky_fnc_altstring, |  | ||||||
|         &ducky_fnc_stringln, |  | ||||||
|         &ducky_fnc_hold, |  | ||||||
|         &ducky_fnc_release, |  | ||||||
|         NULL}; |  | ||||||
| 
 | 
 | ||||||
|     if(line_len == 0) { |     if(line_len == 0) { | ||||||
|         return SCRIPT_STATE_NEXT_LINE; // Skip empty lines
 |         return SCRIPT_STATE_NEXT_LINE; // Skip empty lines
 | ||||||
|     } |     } | ||||||
|     FURI_LOG_D(WORKER_TAG, "line:%s", line_tmp); |     FURI_LOG_D(WORKER_TAG, "line:%s", line_tmp); | ||||||
|  | 
 | ||||||
|     // Ducky Lang Functions
 |     // Ducky Lang Functions
 | ||||||
|     for(size_t i = 0; ducky_cmd_table[i]; i++) { |     int32_t cmd_result = ducky_execute_cmd(bad_usb, line_tmp); | ||||||
|         if(strncmp(line_tmp, ducky_cmd_table[i], strlen(ducky_cmd_table[i])) == 0) |     if(cmd_result != SCRIPT_STATE_CMD_UNKNOWN) { | ||||||
|             return ((fnc_ptr[i])(bad_usb, line, line_tmp, error, error_len)); |         return cmd_result; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     // Special keys + modifiers
 |     // Special keys + modifiers
 | ||||||
|     uint16_t key = ducky_get_keycode(bad_usb, line_tmp, false); |     uint16_t key = ducky_get_keycode(bad_usb, line_tmp, false); | ||||||
|     if(key == HID_KEYBOARD_NONE) { |     if(key == HID_KEYBOARD_NONE) { | ||||||
|         if(error != NULL) { |         return ducky_error(bad_usb, "No keycode defined for %s", line_tmp); | ||||||
|             snprintf(error, error_len, "No keycode defined for %s", line_tmp); |  | ||||||
|         } |  | ||||||
|         return SCRIPT_STATE_ERROR; |  | ||||||
|     } |     } | ||||||
|     if((key & 0xFF00) != 0) { |     if((key & 0xFF00) != 0) { | ||||||
|         // It's a modifier key
 |         // It's a modifier key
 | ||||||
| @ -199,7 +202,7 @@ static int32_t | |||||||
|     } |     } | ||||||
|     furi_hal_hid_kb_press(key); |     furi_hal_hid_kb_press(key); | ||||||
|     furi_hal_hid_kb_release(key); |     furi_hal_hid_kb_release(key); | ||||||
|     return (0); |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool ducky_set_usb_id(BadUsbScript* bad_usb, const char* line) { | static bool ducky_set_usb_id(BadUsbScript* bad_usb, const char* line) { | ||||||
| @ -277,8 +280,7 @@ static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_fil | |||||||
| 
 | 
 | ||||||
|     if(bad_usb->repeat_cnt > 0) { |     if(bad_usb->repeat_cnt > 0) { | ||||||
|         bad_usb->repeat_cnt--; |         bad_usb->repeat_cnt--; | ||||||
|         delay_val = ducky_parse_line( |         delay_val = ducky_parse_line(bad_usb, bad_usb->line_prev); | ||||||
|             bad_usb, bad_usb->line_prev, bad_usb->st.error, sizeof(bad_usb->st.error)); |  | ||||||
|         if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
 |         if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
 | ||||||
|             return 0; |             return 0; | ||||||
|         } else if(delay_val < 0) { // Script error
 |         } else if(delay_val < 0) { // Script error
 | ||||||
| @ -313,10 +315,11 @@ static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_fil | |||||||
|                 bad_usb->buf_len = bad_usb->buf_len + bad_usb->buf_start - (i + 1); |                 bad_usb->buf_len = bad_usb->buf_len + bad_usb->buf_start - (i + 1); | ||||||
|                 bad_usb->buf_start = i + 1; |                 bad_usb->buf_start = i + 1; | ||||||
|                 furi_string_trim(bad_usb->line); |                 furi_string_trim(bad_usb->line); | ||||||
|                 delay_val = ducky_parse_line( |                 delay_val = ducky_parse_line(bad_usb, bad_usb->line); | ||||||
|                     bad_usb, bad_usb->line, bad_usb->st.error, sizeof(bad_usb->st.error)); |  | ||||||
|                 if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
 |                 if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
 | ||||||
|                     return 0; |                     return 0; | ||||||
|  |                 } else if(delay_val == SCRIPT_STATE_STRING_START) { // Print string with delays
 | ||||||
|  |                     return delay_val; | ||||||
|                 } else if(delay_val < 0) { |                 } else if(delay_val < 0) { | ||||||
|                     bad_usb->st.error_line = bad_usb->st.line_cur; |                     bad_usb->st.error_line = bad_usb->st.line_cur; | ||||||
|                     FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_usb->st.line_cur); |                     FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_usb->st.line_cur); | ||||||
| @ -339,10 +342,11 @@ static void bad_usb_hid_state_callback(bool state, void* context) { | |||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     BadUsbScript* bad_usb = context; |     BadUsbScript* bad_usb = context; | ||||||
| 
 | 
 | ||||||
|     if(state == true) |     if(state == true) { | ||||||
|         furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtConnect); |         furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtConnect); | ||||||
|     else |     } else { | ||||||
|         furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtDisconnect); |         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) { | static uint32_t bad_usb_flags_get(uint32_t flags_mask, uint32_t timeout) { | ||||||
| @ -368,6 +372,7 @@ static int32_t bad_usb_worker(void* context) { | |||||||
|     File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); |     File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); | ||||||
|     bad_usb->line = furi_string_alloc(); |     bad_usb->line = furi_string_alloc(); | ||||||
|     bad_usb->line_prev = furi_string_alloc(); |     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); |     furi_hal_hid_set_state_callback(bad_usb_hid_state_callback, bad_usb); | ||||||
| 
 | 
 | ||||||
| @ -420,6 +425,7 @@ static int32_t bad_usb_worker(void* context) { | |||||||
|                 bad_usb->defdelay = 0; |                 bad_usb->defdelay = 0; | ||||||
|                 bad_usb->stringdelay = 0; |                 bad_usb->stringdelay = 0; | ||||||
|                 bad_usb->repeat_cnt = 0; |                 bad_usb->repeat_cnt = 0; | ||||||
|  |                 bad_usb->key_hold_nb = 0; | ||||||
|                 bad_usb->file_end = false; |                 bad_usb->file_end = false; | ||||||
|                 storage_file_seek(script_file, 0, true); |                 storage_file_seek(script_file, 0, true); | ||||||
|                 worker_state = BadUsbStateRunning; |                 worker_state = BadUsbStateRunning; | ||||||
| @ -492,12 +498,17 @@ static int32_t bad_usb_worker(void* context) { | |||||||
|                     delay_val = 0; |                     delay_val = 0; | ||||||
|                     worker_state = BadUsbStateScriptError; |                     worker_state = BadUsbStateScriptError; | ||||||
|                     bad_usb->st.state = worker_state; |                     bad_usb->st.state = worker_state; | ||||||
|  |                     furi_hal_hid_kb_release_all(); | ||||||
|                 } else if(delay_val == SCRIPT_STATE_END) { // End of script
 |                 } else if(delay_val == SCRIPT_STATE_END) { // End of script
 | ||||||
|                     delay_val = 0; |                     delay_val = 0; | ||||||
|                     worker_state = BadUsbStateIdle; |                     worker_state = BadUsbStateIdle; | ||||||
|                     bad_usb->st.state = BadUsbStateDone; |                     bad_usb->st.state = BadUsbStateDone; | ||||||
|                     furi_hal_hid_kb_release_all(); |                     furi_hal_hid_kb_release_all(); | ||||||
|                     continue; |                     continue; | ||||||
|  |                 } else if(delay_val == SCRIPT_STATE_STRING_START) { // Start printing string with delays
 | ||||||
|  |                     delay_val = bad_usb->defdelay; | ||||||
|  |                     bad_usb->string_print_pos = 0; | ||||||
|  |                     worker_state = BadUsbStateStringDelay; | ||||||
|                 } else if(delay_val > 1000) { |                 } else if(delay_val > 1000) { | ||||||
|                     bad_usb->st.state = BadUsbStateDelay; // Show long delays
 |                     bad_usb->st.state = BadUsbStateDelay; // Show long delays
 | ||||||
|                     bad_usb->st.delay_remain = delay_val / 1000; |                     bad_usb->st.delay_remain = delay_val / 1000; | ||||||
| @ -505,7 +516,35 @@ static int32_t bad_usb_worker(void* context) { | |||||||
|             } else { |             } else { | ||||||
|                 furi_check((flags & FuriFlagError) == 0); |                 furi_check((flags & FuriFlagError) == 0); | ||||||
|             } |             } | ||||||
|  |         } else if(worker_state == BadUsbStateStringDelay) { // State: print string with delays
 | ||||||
|  |             uint32_t flags = furi_thread_flags_wait( | ||||||
|  |                 WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, | ||||||
|  |                 FuriFlagWaitAny, | ||||||
|  |                 bad_usb->stringdelay); | ||||||
| 
 | 
 | ||||||
|  |             if(!(flags & FuriFlagError)) { | ||||||
|  |                 if(flags & WorkerEvtEnd) { | ||||||
|  |                     break; | ||||||
|  |                 } else if(flags & WorkerEvtToggle) { | ||||||
|  |                     worker_state = BadUsbStateIdle; // Stop executing script
 | ||||||
|  |                     furi_hal_hid_kb_release_all(); | ||||||
|  |                 } else if(flags & WorkerEvtDisconnect) { | ||||||
|  |                     worker_state = BadUsbStateNotConnected; // USB disconnected
 | ||||||
|  |                     furi_hal_hid_kb_release_all(); | ||||||
|  |                 } | ||||||
|  |                 bad_usb->st.state = worker_state; | ||||||
|  |                 continue; | ||||||
|  |             } else if( | ||||||
|  |                 (flags == (unsigned)FuriFlagErrorTimeout) || | ||||||
|  |                 (flags == (unsigned)FuriFlagErrorResource)) { | ||||||
|  |                 bool string_end = ducky_string_next(bad_usb); | ||||||
|  |                 if(string_end) { | ||||||
|  |                     bad_usb->stringdelay = 0; | ||||||
|  |                     worker_state = BadUsbStateRunning; | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 furi_check((flags & FuriFlagError) == 0); | ||||||
|  |             } | ||||||
|         } else if( |         } else if( | ||||||
|             (worker_state == BadUsbStateFileError) || |             (worker_state == BadUsbStateFileError) || | ||||||
|             (worker_state == BadUsbStateScriptError)) { // State: error
 |             (worker_state == BadUsbStateScriptError)) { // State: error
 | ||||||
| @ -524,6 +563,7 @@ static int32_t bad_usb_worker(void* context) { | |||||||
|     storage_file_free(script_file); |     storage_file_free(script_file); | ||||||
|     furi_string_free(bad_usb->line); |     furi_string_free(bad_usb->line); | ||||||
|     furi_string_free(bad_usb->line_prev); |     furi_string_free(bad_usb->line_prev); | ||||||
|  |     furi_string_free(bad_usb->string_print); | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_I(WORKER_TAG, "End"); |     FURI_LOG_I(WORKER_TAG, "End"); | ||||||
| 
 | 
 | ||||||
| @ -7,8 +7,6 @@ extern "C" { | |||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <furi_hal.h> | #include <furi_hal.h> | ||||||
| 
 | 
 | ||||||
| #define FILE_BUFFER_LEN 16 |  | ||||||
| 
 |  | ||||||
| typedef enum { | typedef enum { | ||||||
|     BadUsbStateInit, |     BadUsbStateInit, | ||||||
|     BadUsbStateNotConnected, |     BadUsbStateNotConnected, | ||||||
| @ -16,6 +14,7 @@ typedef enum { | |||||||
|     BadUsbStateWillRun, |     BadUsbStateWillRun, | ||||||
|     BadUsbStateRunning, |     BadUsbStateRunning, | ||||||
|     BadUsbStateDelay, |     BadUsbStateDelay, | ||||||
|  |     BadUsbStateStringDelay, | ||||||
|     BadUsbStateDone, |     BadUsbStateDone, | ||||||
|     BadUsbStateScriptError, |     BadUsbStateScriptError, | ||||||
|     BadUsbStateFileError, |     BadUsbStateFileError, | ||||||
| @ -30,23 +29,7 @@ typedef struct { | |||||||
|     char error[64]; |     char error[64]; | ||||||
| } BadUsbState; | } BadUsbState; | ||||||
| 
 | 
 | ||||||
| typedef struct BadUsbScript { | typedef struct BadUsbScript BadUsbScript; | ||||||
|     FuriHalUsbHidConfig hid_cfg; |  | ||||||
|     BadUsbState st; |  | ||||||
|     FuriString* file_path; |  | ||||||
|     uint32_t defdelay; |  | ||||||
|     uint16_t layout[128]; |  | ||||||
|     uint32_t stringdelay; |  | ||||||
|     FuriThread* thread; |  | ||||||
|     uint8_t file_buf[FILE_BUFFER_LEN + 1]; |  | ||||||
|     uint8_t buf_start; |  | ||||||
|     uint8_t buf_len; |  | ||||||
|     bool file_end; |  | ||||||
|     FuriString* line; |  | ||||||
| 
 |  | ||||||
|     FuriString* line_prev; |  | ||||||
|     uint32_t repeat_cnt; |  | ||||||
| } BadUsbScript; |  | ||||||
| 
 | 
 | ||||||
| BadUsbScript* bad_usb_script_open(FuriString* file_path); | BadUsbScript* bad_usb_script_open(FuriString* file_path); | ||||||
| 
 | 
 | ||||||
| @ -62,12 +45,6 @@ void bad_usb_script_toggle(BadUsbScript* bad_usb); | |||||||
| 
 | 
 | ||||||
| BadUsbState* bad_usb_script_get_state(BadUsbScript* bad_usb); | BadUsbState* bad_usb_script_get_state(BadUsbScript* bad_usb); | ||||||
| 
 | 
 | ||||||
| uint16_t ducky_get_keycode(BadUsbScript* bad_usb, const char* param, bool accept_chars); |  | ||||||
| 
 |  | ||||||
| uint32_t ducky_get_command_len(const char* line); |  | ||||||
| 
 |  | ||||||
| bool ducky_is_line_end(const char chr); |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
							
								
								
									
										177
									
								
								applications/main/bad_usb/helpers/ducky_script_commands.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								applications/main/bad_usb/helpers/ducky_script_commands.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,177 @@ | |||||||
|  | #include <furi_hal.h> | ||||||
|  | #include <furi_hal_usb_hid.h> | ||||||
|  | #include "ducky_script.h" | ||||||
|  | #include "ducky_script_i.h" | ||||||
|  | 
 | ||||||
|  | typedef int32_t (*DuckyCmdCallback)(BadUsbScript* bad_usb, const char* line, int32_t param); | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     char* name; | ||||||
|  |     DuckyCmdCallback callback; | ||||||
|  |     int32_t param; | ||||||
|  | } DuckyCmd; | ||||||
|  | 
 | ||||||
|  | static int32_t ducky_fnc_delay(BadUsbScript* bad_usb, const char* line, int32_t param) { | ||||||
|  |     UNUSED(param); | ||||||
|  | 
 | ||||||
|  |     line = &line[ducky_get_command_len(line) + 1]; | ||||||
|  |     uint32_t delay_val = 0; | ||||||
|  |     bool state = ducky_get_number(line, &delay_val); | ||||||
|  |     if((state) && (delay_val > 0)) { | ||||||
|  |         return (int32_t)delay_val; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ducky_error(bad_usb, "Invalid number %s", line); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int32_t ducky_fnc_defdelay(BadUsbScript* bad_usb, const char* line, int32_t param) { | ||||||
|  |     UNUSED(param); | ||||||
|  | 
 | ||||||
|  |     line = &line[ducky_get_command_len(line) + 1]; | ||||||
|  |     bool state = ducky_get_number(line, &bad_usb->defdelay); | ||||||
|  |     if(!state) { | ||||||
|  |         return ducky_error(bad_usb, "Invalid number %s", line); | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int32_t ducky_fnc_strdelay(BadUsbScript* bad_usb, const char* line, int32_t param) { | ||||||
|  |     UNUSED(param); | ||||||
|  | 
 | ||||||
|  |     line = &line[ducky_get_command_len(line) + 1]; | ||||||
|  |     bool state = ducky_get_number(line, &bad_usb->stringdelay); | ||||||
|  |     if(!state) { | ||||||
|  |         return ducky_error(bad_usb, "Invalid number %s", line); | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int32_t ducky_fnc_string(BadUsbScript* bad_usb, const char* line, int32_t param) { | ||||||
|  |     line = &line[ducky_get_command_len(line) + 1]; | ||||||
|  |     furi_string_set_str(bad_usb->string_print, line); | ||||||
|  |     if(param == 1) { | ||||||
|  |         furi_string_cat(bad_usb->string_print, "\n"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(bad_usb->stringdelay == 0) { // stringdelay not set - run command immidiately
 | ||||||
|  |         bool state = ducky_string(bad_usb, furi_string_get_cstr(bad_usb->string_print)); | ||||||
|  |         if(!state) { | ||||||
|  |             return ducky_error(bad_usb, "Invalid string %s", line); | ||||||
|  |         } | ||||||
|  |     } else { // stringdelay is set - run command in thread to keep handling external events
 | ||||||
|  |         return SCRIPT_STATE_STRING_START; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int32_t ducky_fnc_repeat(BadUsbScript* bad_usb, const char* line, int32_t param) { | ||||||
|  |     UNUSED(param); | ||||||
|  | 
 | ||||||
|  |     line = &line[ducky_get_command_len(line) + 1]; | ||||||
|  |     bool state = ducky_get_number(line, &bad_usb->repeat_cnt); | ||||||
|  |     if((!state) || (bad_usb->repeat_cnt == 0)) { | ||||||
|  |         return ducky_error(bad_usb, "Invalid number %s", line); | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int32_t ducky_fnc_sysrq(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); | ||||||
|  |     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; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int32_t ducky_fnc_altchar(BadUsbScript* bad_usb, const char* line, int32_t param) { | ||||||
|  |     UNUSED(param); | ||||||
|  | 
 | ||||||
|  |     line = &line[ducky_get_command_len(line) + 1]; | ||||||
|  |     ducky_numlock_on(); | ||||||
|  |     bool state = ducky_altchar(line); | ||||||
|  |     if(!state) { | ||||||
|  |         return ducky_error(bad_usb, "Invalid altchar %s", line); | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int32_t ducky_fnc_altstring(BadUsbScript* bad_usb, const char* line, int32_t param) { | ||||||
|  |     UNUSED(param); | ||||||
|  | 
 | ||||||
|  |     line = &line[ducky_get_command_len(line) + 1]; | ||||||
|  |     ducky_numlock_on(); | ||||||
|  |     bool state = ducky_altstring(line); | ||||||
|  |     if(!state) { | ||||||
|  |         return ducky_error(bad_usb, "Invalid altstring %s", line); | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int32_t ducky_fnc_hold(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->key_hold_nb++; | ||||||
|  |     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); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int32_t ducky_fnc_release(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); | ||||||
|  |     } | ||||||
|  |     if(bad_usb->key_hold_nb == 0) { | ||||||
|  |         return ducky_error(bad_usb, "No keys are hold"); | ||||||
|  |     } | ||||||
|  |     bad_usb->key_hold_nb--; | ||||||
|  |     furi_hal_hid_kb_release(key); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static const DuckyCmd ducky_commands[] = { | ||||||
|  |     {"REM ", NULL, -1}, | ||||||
|  |     {"ID ", NULL, -1}, | ||||||
|  |     {"DELAY ", ducky_fnc_delay, -1}, | ||||||
|  |     {"STRING ", ducky_fnc_string, 0}, | ||||||
|  |     {"STRINGLN ", ducky_fnc_string, 1}, | ||||||
|  |     {"DEFAULT_DELAY ", ducky_fnc_defdelay, -1}, | ||||||
|  |     {"DEFAULTDELAY ", ducky_fnc_defdelay, -1}, | ||||||
|  |     {"STRINGDELAY ", ducky_fnc_strdelay, -1}, | ||||||
|  |     {"STRING_DELAY ", ducky_fnc_strdelay, -1}, | ||||||
|  |     {"REPEAT ", ducky_fnc_repeat, -1}, | ||||||
|  |     {"SYSRQ ", ducky_fnc_sysrq, -1}, | ||||||
|  |     {"ALTCHAR ", ducky_fnc_altchar, -1}, | ||||||
|  |     {"ALTSTRING ", ducky_fnc_altstring, -1}, | ||||||
|  |     {"ALTCODE ", ducky_fnc_altstring, -1}, | ||||||
|  |     {"HOLD ", ducky_fnc_hold, -1}, | ||||||
|  |     {"RELEASE ", ducky_fnc_release, -1}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | int32_t ducky_execute_cmd(BadUsbScript* bad_usb, const char* line) { | ||||||
|  |     for(size_t i = 0; i < COUNT_OF(ducky_commands); i++) { | ||||||
|  |         if(strncmp(line, ducky_commands[i].name, strlen(ducky_commands[i].name)) == 0) { | ||||||
|  |             if(ducky_commands[i].callback == NULL) { | ||||||
|  |                 return 0; | ||||||
|  |             } else { | ||||||
|  |                 return ((ducky_commands[i].callback)(bad_usb, line, ducky_commands[i].param)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return SCRIPT_STATE_CMD_UNKNOWN; | ||||||
|  | } | ||||||
							
								
								
									
										69
									
								
								applications/main/bad_usb/helpers/ducky_script_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								applications/main/bad_usb/helpers/ducky_script_i.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #include <furi.h> | ||||||
|  | #include <furi_hal.h> | ||||||
|  | #include "ducky_script.h" | ||||||
|  | 
 | ||||||
|  | #define SCRIPT_STATE_ERROR (-1) | ||||||
|  | #define SCRIPT_STATE_END (-2) | ||||||
|  | #define SCRIPT_STATE_NEXT_LINE (-3) | ||||||
|  | #define SCRIPT_STATE_CMD_UNKNOWN (-4) | ||||||
|  | #define SCRIPT_STATE_STRING_START (-5) | ||||||
|  | 
 | ||||||
|  | #define FILE_BUFFER_LEN 16 | ||||||
|  | 
 | ||||||
|  | struct BadUsbScript { | ||||||
|  |     FuriHalUsbHidConfig hid_cfg; | ||||||
|  |     FuriThread* thread; | ||||||
|  |     BadUsbState st; | ||||||
|  | 
 | ||||||
|  |     FuriString* file_path; | ||||||
|  |     uint8_t file_buf[FILE_BUFFER_LEN + 1]; | ||||||
|  |     uint8_t buf_start; | ||||||
|  |     uint8_t buf_len; | ||||||
|  |     bool file_end; | ||||||
|  | 
 | ||||||
|  |     uint32_t defdelay; | ||||||
|  |     uint32_t stringdelay; | ||||||
|  |     uint16_t layout[128]; | ||||||
|  | 
 | ||||||
|  |     FuriString* line; | ||||||
|  |     FuriString* line_prev; | ||||||
|  |     uint32_t repeat_cnt; | ||||||
|  |     uint8_t key_hold_nb; | ||||||
|  | 
 | ||||||
|  |     FuriString* string_print; | ||||||
|  |     size_t string_print_pos; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | uint16_t ducky_get_keycode(BadUsbScript* bad_usb, const char* param, bool accept_chars); | ||||||
|  | 
 | ||||||
|  | uint32_t ducky_get_command_len(const char* line); | ||||||
|  | 
 | ||||||
|  | bool ducky_is_line_end(const char chr); | ||||||
|  | 
 | ||||||
|  | uint16_t ducky_get_keycode_by_name(const char* param); | ||||||
|  | 
 | ||||||
|  | bool ducky_get_number(const char* param, uint32_t* val); | ||||||
|  | 
 | ||||||
|  | void ducky_numlock_on(void); | ||||||
|  | 
 | ||||||
|  | bool ducky_numpad_press(const char num); | ||||||
|  | 
 | ||||||
|  | bool ducky_altchar(const char* charcode); | ||||||
|  | 
 | ||||||
|  | bool ducky_altstring(const char* param); | ||||||
|  | 
 | ||||||
|  | bool ducky_string(BadUsbScript* bad_usb, const char* param); | ||||||
|  | 
 | ||||||
|  | int32_t ducky_execute_cmd(BadUsbScript* bad_usb, const char* line); | ||||||
|  | 
 | ||||||
|  | int32_t ducky_error(BadUsbScript* bad_usb, const char* text, ...); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
							
								
								
									
										79
									
								
								applications/main/bad_usb/helpers/ducky_script_keycodes.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								applications/main/bad_usb/helpers/ducky_script_keycodes.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,79 @@ | |||||||
|  | #include <furi_hal.h> | ||||||
|  | #include <furi_hal_usb_hid.h> | ||||||
|  | #include "ducky_script_i.h" | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     char* name; | ||||||
|  |     uint16_t keycode; | ||||||
|  | } DuckyKey; | ||||||
|  | 
 | ||||||
|  | static const DuckyKey ducky_keys[] = { | ||||||
|  |     {"CTRL-ALT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_ALT}, | ||||||
|  |     {"CTRL-SHIFT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT}, | ||||||
|  |     {"ALT-SHIFT", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_SHIFT}, | ||||||
|  |     {"ALT-GUI", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_GUI}, | ||||||
|  |     {"GUI-SHIFT", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT}, | ||||||
|  |     {"GUI-CTRL", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_CTRL}, | ||||||
|  | 
 | ||||||
|  |     {"CTRL", KEY_MOD_LEFT_CTRL}, | ||||||
|  |     {"CONTROL", KEY_MOD_LEFT_CTRL}, | ||||||
|  |     {"SHIFT", KEY_MOD_LEFT_SHIFT}, | ||||||
|  |     {"ALT", KEY_MOD_LEFT_ALT}, | ||||||
|  |     {"GUI", KEY_MOD_LEFT_GUI}, | ||||||
|  |     {"WINDOWS", KEY_MOD_LEFT_GUI}, | ||||||
|  | 
 | ||||||
|  |     {"DOWNARROW", HID_KEYBOARD_DOWN_ARROW}, | ||||||
|  |     {"DOWN", HID_KEYBOARD_DOWN_ARROW}, | ||||||
|  |     {"LEFTARROW", HID_KEYBOARD_LEFT_ARROW}, | ||||||
|  |     {"LEFT", HID_KEYBOARD_LEFT_ARROW}, | ||||||
|  |     {"RIGHTARROW", HID_KEYBOARD_RIGHT_ARROW}, | ||||||
|  |     {"RIGHT", HID_KEYBOARD_RIGHT_ARROW}, | ||||||
|  |     {"UPARROW", HID_KEYBOARD_UP_ARROW}, | ||||||
|  |     {"UP", HID_KEYBOARD_UP_ARROW}, | ||||||
|  | 
 | ||||||
|  |     {"ENTER", HID_KEYBOARD_RETURN}, | ||||||
|  |     {"BREAK", HID_KEYBOARD_PAUSE}, | ||||||
|  |     {"PAUSE", HID_KEYBOARD_PAUSE}, | ||||||
|  |     {"CAPSLOCK", HID_KEYBOARD_CAPS_LOCK}, | ||||||
|  |     {"DELETE", HID_KEYBOARD_DELETE_FORWARD}, | ||||||
|  |     {"BACKSPACE", HID_KEYBOARD_DELETE}, | ||||||
|  |     {"END", HID_KEYBOARD_END}, | ||||||
|  |     {"ESC", HID_KEYBOARD_ESCAPE}, | ||||||
|  |     {"ESCAPE", HID_KEYBOARD_ESCAPE}, | ||||||
|  |     {"HOME", HID_KEYBOARD_HOME}, | ||||||
|  |     {"INSERT", HID_KEYBOARD_INSERT}, | ||||||
|  |     {"NUMLOCK", HID_KEYPAD_NUMLOCK}, | ||||||
|  |     {"PAGEUP", HID_KEYBOARD_PAGE_UP}, | ||||||
|  |     {"PAGEDOWN", HID_KEYBOARD_PAGE_DOWN}, | ||||||
|  |     {"PRINTSCREEN", HID_KEYBOARD_PRINT_SCREEN}, | ||||||
|  |     {"SCROLLLOCK", HID_KEYBOARD_SCROLL_LOCK}, | ||||||
|  |     {"SPACE", HID_KEYBOARD_SPACEBAR}, | ||||||
|  |     {"TAB", HID_KEYBOARD_TAB}, | ||||||
|  |     {"MENU", HID_KEYBOARD_APPLICATION}, | ||||||
|  |     {"APP", HID_KEYBOARD_APPLICATION}, | ||||||
|  | 
 | ||||||
|  |     {"F1", HID_KEYBOARD_F1}, | ||||||
|  |     {"F2", HID_KEYBOARD_F2}, | ||||||
|  |     {"F3", HID_KEYBOARD_F3}, | ||||||
|  |     {"F4", HID_KEYBOARD_F4}, | ||||||
|  |     {"F5", HID_KEYBOARD_F5}, | ||||||
|  |     {"F6", HID_KEYBOARD_F6}, | ||||||
|  |     {"F7", HID_KEYBOARD_F7}, | ||||||
|  |     {"F8", HID_KEYBOARD_F8}, | ||||||
|  |     {"F9", HID_KEYBOARD_F9}, | ||||||
|  |     {"F10", HID_KEYBOARD_F10}, | ||||||
|  |     {"F11", HID_KEYBOARD_F11}, | ||||||
|  |     {"F12", HID_KEYBOARD_F12}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 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); | ||||||
|  |         if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) && | ||||||
|  |            (ducky_is_line_end(param[key_cmd_len]))) { | ||||||
|  |             return ducky_keys[i].keycode; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return HID_KEYBOARD_NONE; | ||||||
|  | } | ||||||
| @ -1,327 +0,0 @@ | |||||||
| #include <furi_hal.h> |  | ||||||
| #include <furi_hal_usb_hid.h> |  | ||||||
| #include "mnemonic.h" |  | ||||||
| 
 |  | ||||||
| #define TAG "BadUSB" |  | ||||||
| #define WORKER_TAG TAG "Worker" |  | ||||||
| 
 |  | ||||||
| #define FILE_BUFFER_LEN 16 |  | ||||||
| #define SCRIPT_STATE_ERROR (-1) |  | ||||||
| #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) |  | ||||||
| 
 |  | ||||||
| static const uint8_t numpad_keys[10] = { |  | ||||||
|     HID_KEYPAD_0, |  | ||||||
|     HID_KEYPAD_1, |  | ||||||
|     HID_KEYPAD_2, |  | ||||||
|     HID_KEYPAD_3, |  | ||||||
|     HID_KEYPAD_4, |  | ||||||
|     HID_KEYPAD_5, |  | ||||||
|     HID_KEYPAD_6, |  | ||||||
|     HID_KEYPAD_7, |  | ||||||
|     HID_KEYPAD_8, |  | ||||||
|     HID_KEYPAD_9, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static bool ducky_get_number(const char* param, uint32_t* val) { |  | ||||||
|     uint32_t value = 0; |  | ||||||
|     if(sscanf(param, "%lu", &value) == 1) { |  | ||||||
|         *val = value; |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
|     return false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void ducky_numlock_on() { |  | ||||||
|     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); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| static bool ducky_numpad_press(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); |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static bool ducky_altchar(const char* charcode) { |  | ||||||
|     uint8_t i = 0; |  | ||||||
|     bool state = false; |  | ||||||
| 
 |  | ||||||
|     FURI_LOG_I(WORKER_TAG, "char %s", charcode); |  | ||||||
| 
 |  | ||||||
|     furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT); |  | ||||||
| 
 |  | ||||||
|     while(!ducky_is_line_end(charcode[i])) { |  | ||||||
|         state = ducky_numpad_press(charcode[i]); |  | ||||||
|         if(state == false) break; |  | ||||||
|         i++; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     furi_hal_hid_kb_release(KEY_MOD_LEFT_ALT); |  | ||||||
|     return state; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static bool ducky_altstring(const char* param) { |  | ||||||
|     uint32_t i = 0; |  | ||||||
|     bool state = false; |  | ||||||
| 
 |  | ||||||
|     while(param[i] != '\0') { |  | ||||||
|         if((param[i] < ' ') || (param[i] > '~')) { |  | ||||||
|             i++; |  | ||||||
|             continue; // Skip non-printable chars
 |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         char temp_str[4]; |  | ||||||
|         snprintf(temp_str, 4, "%u", param[i]); |  | ||||||
| 
 |  | ||||||
|         state = ducky_altchar(temp_str); |  | ||||||
|         if(state == false) break; |  | ||||||
|         i++; |  | ||||||
|     } |  | ||||||
|     return state; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static bool ducky_string(BadUsbScript* bad_usb, const char* param) { |  | ||||||
|     uint32_t i = 0; |  | ||||||
| 
 |  | ||||||
|     while(param[i] != '\0') { |  | ||||||
|         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); |  | ||||||
|             if(bad_usb->stringdelay > 0) { |  | ||||||
|                 furi_delay_ms(bad_usb->stringdelay); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         i++; |  | ||||||
|     } |  | ||||||
|     bad_usb->stringdelay = 0; |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int32_t ducky_fnc_noop( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len) { |  | ||||||
|     (void)bad_usb; |  | ||||||
|     (void)line; |  | ||||||
|     (void)line_tmp; |  | ||||||
|     (void)error; |  | ||||||
|     (void)error_len; |  | ||||||
|     return (0); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int32_t ducky_fnc_delay( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len) { |  | ||||||
|     bool state = false; |  | ||||||
|     (void)bad_usb; |  | ||||||
|     (void)line; |  | ||||||
| 
 |  | ||||||
|     line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; |  | ||||||
|     uint32_t delay_val = 0; |  | ||||||
|     state = ducky_get_number(line_tmp, &delay_val); |  | ||||||
|     if((state) && (delay_val > 0)) { |  | ||||||
|         return (int32_t)delay_val; |  | ||||||
|     } |  | ||||||
|     if(error != NULL) { |  | ||||||
|         snprintf(error, error_len, "Invalid number %s", line_tmp); |  | ||||||
|     } |  | ||||||
|     return SCRIPT_STATE_ERROR; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int32_t ducky_fnc_defdelay( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len) { |  | ||||||
|     bool state = false; |  | ||||||
|     (void)line; |  | ||||||
| 
 |  | ||||||
|     line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; |  | ||||||
|     state = ducky_get_number(line_tmp, &bad_usb->defdelay); |  | ||||||
|     if(!state && error != NULL) { |  | ||||||
|         snprintf(error, error_len, "Invalid number %s", line_tmp); |  | ||||||
|     } |  | ||||||
|     return (state) ? (0) : SCRIPT_STATE_ERROR; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int32_t ducky_fnc_strdelay( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len) { |  | ||||||
|     bool state = false; |  | ||||||
|     (void)line; |  | ||||||
| 
 |  | ||||||
|     line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; |  | ||||||
|     state = ducky_get_number(line_tmp, &bad_usb->stringdelay); |  | ||||||
|     if((state) && (bad_usb->stringdelay > 0)) { |  | ||||||
|         return state; |  | ||||||
|     } |  | ||||||
|     if(error != NULL) { |  | ||||||
|         snprintf(error, error_len, "Invalid number %s", line_tmp); |  | ||||||
|     } |  | ||||||
|     return SCRIPT_STATE_ERROR; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int32_t ducky_fnc_string( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len) { |  | ||||||
|     bool state = false; |  | ||||||
|     (void)line; |  | ||||||
| 
 |  | ||||||
|     line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; |  | ||||||
|     state = ducky_string(bad_usb, line_tmp); |  | ||||||
|     if(!state && error != NULL) { |  | ||||||
|         snprintf(error, error_len, "Invalid string %s", line_tmp); |  | ||||||
|     } |  | ||||||
|     return (state) ? (0) : SCRIPT_STATE_ERROR; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int32_t ducky_fnc_repeat( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len) { |  | ||||||
|     bool state = false; |  | ||||||
|     (void)line; |  | ||||||
| 
 |  | ||||||
|     line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; |  | ||||||
|     state = ducky_get_number(line_tmp, &bad_usb->repeat_cnt); |  | ||||||
|     if(!state && error != NULL) { |  | ||||||
|         snprintf(error, error_len, "Invalid number %s", line_tmp); |  | ||||||
|     } |  | ||||||
|     return (state) ? (0) : SCRIPT_STATE_ERROR; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int32_t ducky_fnc_sysrq( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len) { |  | ||||||
|     (void)error; |  | ||||||
|     (void)error_len; |  | ||||||
|     (void)line; |  | ||||||
|     line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; |  | ||||||
|     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); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int32_t ducky_fnc_altchar( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len) { |  | ||||||
|     bool state = false; |  | ||||||
|     (void)bad_usb; |  | ||||||
|     (void)line; |  | ||||||
| 
 |  | ||||||
|     line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; |  | ||||||
|     ducky_numlock_on(); |  | ||||||
|     state = ducky_altchar(line_tmp); |  | ||||||
|     if(!state && error != NULL) { |  | ||||||
|         snprintf(error, error_len, "Invalid altchar %s", line_tmp); |  | ||||||
|     } |  | ||||||
|     return (state) ? (0) : SCRIPT_STATE_ERROR; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int32_t ducky_fnc_altstring( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len) { |  | ||||||
|     bool state = false; |  | ||||||
|     (void)bad_usb; |  | ||||||
|     (void)line; |  | ||||||
| 
 |  | ||||||
|     line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; |  | ||||||
|     ducky_numlock_on(); |  | ||||||
|     state = ducky_altstring(line_tmp); |  | ||||||
|     if(!state && error != NULL) { |  | ||||||
|         snprintf(error, error_len, "Invalid altstring %s", line_tmp); |  | ||||||
|     } |  | ||||||
|     return (state) ? (0) : SCRIPT_STATE_ERROR; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int32_t ducky_fnc_stringln( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len) { |  | ||||||
|     bool state = false; |  | ||||||
|     (void)line; |  | ||||||
| 
 |  | ||||||
|     line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; |  | ||||||
|     state = ducky_string(bad_usb, line_tmp); |  | ||||||
|     if(!state && error != NULL) { |  | ||||||
|         snprintf(error, error_len, "Invalid string %s", line_tmp); |  | ||||||
|     } |  | ||||||
|     furi_hal_hid_kb_press(HID_KEYBOARD_RETURN); |  | ||||||
|     furi_hal_hid_kb_release(HID_KEYBOARD_RETURN); |  | ||||||
|     return (state) ? (0) : SCRIPT_STATE_ERROR; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int32_t ducky_fnc_hold( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len) { |  | ||||||
|     (void)line; |  | ||||||
|     line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; |  | ||||||
|     uint16_t key = ducky_get_keycode(bad_usb, line_tmp, true); |  | ||||||
|     if(key == HID_KEYBOARD_NONE) { |  | ||||||
|         if(error != NULL) { |  | ||||||
|             snprintf(error, error_len, "No keycode defined for %s", line_tmp); |  | ||||||
|         } |  | ||||||
|         return SCRIPT_STATE_ERROR; |  | ||||||
|     } |  | ||||||
|     furi_hal_hid_kb_press(key); |  | ||||||
|     return (0); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int32_t ducky_fnc_release( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len) { |  | ||||||
|     (void)line; |  | ||||||
|     line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; |  | ||||||
|     uint16_t key = ducky_get_keycode(bad_usb, line_tmp, true); |  | ||||||
|     if(key == HID_KEYBOARD_NONE) { |  | ||||||
|         if(error != NULL) { |  | ||||||
|             snprintf(error, error_len, "No keycode defined for %s", line_tmp); |  | ||||||
|         } |  | ||||||
|         return SCRIPT_STATE_ERROR; |  | ||||||
|     } |  | ||||||
|     furi_hal_hid_kb_release(key); |  | ||||||
|     return (0); |  | ||||||
| } |  | ||||||
| @ -1,96 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus |  | ||||||
| extern "C" { |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #include "bad_usb_script.h" |  | ||||||
| 
 |  | ||||||
| // A no opperation function
 |  | ||||||
| int32_t ducky_fnc_noop( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len); |  | ||||||
| // DELAY
 |  | ||||||
| int32_t ducky_fnc_delay( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len); |  | ||||||
| // DEFAULTDELAY
 |  | ||||||
| int32_t ducky_fnc_defdelay( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len); |  | ||||||
| // STRINGDELAY
 |  | ||||||
| int32_t ducky_fnc_strdelay( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len); |  | ||||||
| // STRING
 |  | ||||||
| int32_t ducky_fnc_string( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len); |  | ||||||
| // STRINGLN
 |  | ||||||
| int32_t ducky_fnc_stringln( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len); |  | ||||||
| // REPEAT
 |  | ||||||
| int32_t ducky_fnc_repeat( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len); |  | ||||||
| // SYSRQ
 |  | ||||||
| int32_t ducky_fnc_sysrq( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len); |  | ||||||
| // ALTCHAR
 |  | ||||||
| int32_t ducky_fnc_altchar( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len); |  | ||||||
| // ALTSTRING
 |  | ||||||
| int32_t ducky_fnc_altstring( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len); |  | ||||||
| // HOLD
 |  | ||||||
| int32_t ducky_fnc_hold( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len); |  | ||||||
| // RELEASE
 |  | ||||||
| int32_t ducky_fnc_release( |  | ||||||
|     BadUsbScript* bad_usb, |  | ||||||
|     FuriString* line, |  | ||||||
|     const char* line_tmp, |  | ||||||
|     char* error, |  | ||||||
|     size_t error_len); |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
| @ -17,7 +17,7 @@ void bad_usb_scene_config_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         submenu, |         submenu, | ||||||
|         "Keyboard Layout", |         "Keyboard Layout (global)", | ||||||
|         SubmenuIndexKeyboardLayout, |         SubmenuIndexKeyboardLayout, | ||||||
|         bad_usb_scene_config_submenu_callback, |         bad_usb_scene_config_submenu_callback, | ||||||
|         bad_usb); |         bad_usb); | ||||||
|  | |||||||
| @ -33,8 +33,10 @@ void bad_usb_scene_config_layout_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     if(bad_usb_layout_select(bad_usb)) { |     if(bad_usb_layout_select(bad_usb)) { | ||||||
|         bad_usb_script_set_keyboard_layout(bad_usb->bad_usb_script, bad_usb->keyboard_layout); |         bad_usb_script_set_keyboard_layout(bad_usb->bad_usb_script, bad_usb->keyboard_layout); | ||||||
|     } |         scene_manager_search_and_switch_to_previous_scene(bad_usb->scene_manager, BadUsbSceneWork); | ||||||
|  |     } else { | ||||||
|         scene_manager_previous_scene(bad_usb->scene_manager); |         scene_manager_previous_scene(bad_usb->scene_manager); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool bad_usb_scene_config_layout_on_event(void* context, SceneManagerEvent event) { | bool bad_usb_scene_config_layout_on_event(void* context, SceneManagerEvent event) { | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| #include "../bad_usb_script.h" | #include "../helpers/ducky_script.h" | ||||||
| #include "../bad_usb_app_i.h" | #include "../bad_usb_app_i.h" | ||||||
| #include "../views/bad_usb_view.h" | #include "../views/bad_usb_view.h" | ||||||
| #include <furi_hal.h> | #include <furi_hal.h> | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| #include "bad_usb_view.h" | #include "bad_usb_view.h" | ||||||
| #include "../bad_usb_script.h" | #include "../helpers/ducky_script.h" | ||||||
| #include <toolbox/path.h> | #include <toolbox/path.h> | ||||||
| #include <gui/elements.h> | #include <gui/elements.h> | ||||||
| #include <assets_icons.h> | #include <assets_icons.h> | ||||||
| @ -79,7 +79,12 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { | |||||||
|         canvas_draw_str_aligned( |         canvas_draw_str_aligned( | ||||||
|             canvas, 127, 46, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); |             canvas, 127, 46, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); | ||||||
|         furi_string_reset(disp_str); |         furi_string_reset(disp_str); | ||||||
|         canvas_draw_str_aligned(canvas, 127, 56, AlignRight, AlignBottom, model->state.error); | 
 | ||||||
|  |         furi_string_set_str(disp_str, model->state.error); | ||||||
|  |         elements_string_fit_width(canvas, disp_str, canvas_width(canvas)); | ||||||
|  |         canvas_draw_str_aligned( | ||||||
|  |             canvas, 127, 56, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); | ||||||
|  |         furi_string_reset(disp_str); | ||||||
|     } else if(model->state.state == BadUsbStateIdle) { |     } else if(model->state.state == BadUsbStateIdle) { | ||||||
|         canvas_draw_icon(canvas, 4, 26, &I_Smile_18x18); |         canvas_draw_icon(canvas, 4, 26, &I_Smile_18x18); | ||||||
|         canvas_set_font(canvas, FontBigNumbers); |         canvas_set_font(canvas, FontBigNumbers); | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <gui/view.h> | #include <gui/view.h> | ||||||
| #include "../bad_usb_script.h" | #include "../helpers/ducky_script.h" | ||||||
| 
 | 
 | ||||||
| typedef struct BadUsb BadUsb; | typedef struct BadUsb BadUsb; | ||||||
| typedef void (*BadUsbButtonCallback)(InputKey key, void* context); | typedef void (*BadUsbButtonCallback)(InputKey key, void* context); | ||||||
|  | |||||||
| @ -98,7 +98,7 @@ static void submenu_view_draw_callback(Canvas* canvas, void* _model) { | |||||||
| 
 | 
 | ||||||
|             FuriString* disp_str; |             FuriString* disp_str; | ||||||
|             disp_str = furi_string_alloc_set(SubmenuItemArray_cref(it)->label); |             disp_str = furi_string_alloc_set(SubmenuItemArray_cref(it)->label); | ||||||
|             elements_string_fit_width(canvas, disp_str, item_width - 20); |             elements_string_fit_width(canvas, disp_str, item_width - (6 * 2)); | ||||||
| 
 | 
 | ||||||
|             canvas_draw_str( |             canvas_draw_str( | ||||||
|                 canvas, |                 canvas, | ||||||
|  | |||||||
| @ -11,18 +11,18 @@ BadUsb app can execute only text scrips from `.txt` files, no compilation is req | |||||||
| ## Comment line | ## Comment line | ||||||
| 
 | 
 | ||||||
| Just a single comment line. The interpreter will ignore all text after the REM command. | Just a single comment line. The interpreter will ignore all text after the REM command. | ||||||
| |Command|Parameters|Notes| | | Command | Parameters   | Notes | | ||||||
| |-|-|-| | | ------- | ------------ | ----- | | ||||||
| |REM|Comment text|| | | REM     | Comment text |       | | ||||||
| 
 | 
 | ||||||
| ## Delay | ## Delay | ||||||
| 
 | 
 | ||||||
| Pause script execution by a defined time. | Pause script execution by a defined time. | ||||||
| |Command|Parameters|Notes| | | Command       | Parameters        | Notes                               | | ||||||
| |-|-|-| | | ------------- | ----------------- | ----------------------------------- | | ||||||
| |DELAY|Delay value in ms|Single delay| | | DELAY         | Delay value in ms | Single delay                        | | ||||||
| |DEFAULT_DELAY|Delay value in ms|Add delay before every next command| | | DEFAULT_DELAY | Delay value in ms | Add delay before every next command | | ||||||
| |DEFAULTDELAY|Delay value in ms|Same as DEFAULT_DELAY| | | DEFAULTDELAY  | Delay value in ms | Same as DEFAULT_DELAY               | | ||||||
| 
 | 
 | ||||||
| ## Special keys | ## Special keys | ||||||
| 
 | 
 | ||||||
| @ -56,32 +56,42 @@ Pause script execution by a defined time. | |||||||
| ## Modifier keys | ## Modifier keys | ||||||
| 
 | 
 | ||||||
| Can be combined with a special key command or a single character. | Can be combined with a special key command or a single character. | ||||||
| |Command|Notes| | | Command        | Notes      | | ||||||
| |-|-| | | -------------- | ---------- | | ||||||
| |CONTROL / CTRL|| | | CONTROL / CTRL |            | | ||||||
| |SHIFT|| | | SHIFT          |            | | ||||||
| |ALT|| | | ALT            |            | | ||||||
| |WINDOWS / GUI|| | | WINDOWS / GUI  |            | | ||||||
| |CTRL-ALT|CTRL+ALT| | | CTRL-ALT       | CTRL+ALT   | | ||||||
| |CTRL-SHIFT|CTRL+SHIFT| | | CTRL-SHIFT     | CTRL+SHIFT | | ||||||
| |ALT-SHIFT|ALT+SHIFT| | | ALT-SHIFT      | ALT+SHIFT  | | ||||||
| |ALT-GUI|ALT+WIN| | | ALT-GUI        | ALT+WIN    | | ||||||
| |GUI-SHIFT|WIN+SHIFT| | | GUI-SHIFT      | WIN+SHIFT  | | ||||||
| |GUI-CTRL|WIN+CTRL| | | GUI-CTRL       | WIN+CTRL   | | ||||||
|  | 
 | ||||||
|  | ## Key hold and release | ||||||
|  | 
 | ||||||
|  | Up to 5 keys can be hold simultaneously. | ||||||
|  | | Command | Parameters                      | Notes                                     | | ||||||
|  | | ------- | ------------------------------- | ----------------------------------------- | | ||||||
|  | | HOLD    | Special key or single character | Press and hold key untill RELEASE command | | ||||||
|  | | RELEASE | Special key or single character | Release key                               | | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| ## String | ## String | ||||||
| 
 | 
 | ||||||
| | Command  | Parameters  | Notes                                      | | | Command  | Parameters  | Notes                                      | | ||||||
| | -------  | ----------- | -----------------                          | | | -------  | ----------- | -----------------                          | | ||||||
| | STRING   | Text string | Print text string                          | | | STRING   | Text string | Print text string                          | | ||||||
|  | | STRINGLN | Text string | Print text string and press enter after it | | ||||||
| 
 | 
 | ||||||
| ## String delay | ## String delay | ||||||
| 
 | 
 | ||||||
| Delay between keypresses. | Delay between keypresses. | ||||||
| |Command|Parameters|Notes| | | Command      | Parameters        | Notes                                         | | ||||||
| |-|-|-| | | ------------ | ----------------- | --------------------------------------------- | | ||||||
| |STRING_DELAY|Delay value in ms|Applied once to next appearing string| | | STRING_DELAY | Delay value in ms | Applied once to next appearing STRING command | | ||||||
| |STRINGDELAY|Delay value in ms|Same as STRING_DELAY| | | STRINGDELAY  | Delay value in ms | Same as STRING_DELAY                          | | ||||||
| 
 | 
 | ||||||
| ## Repeat | ## Repeat | ||||||
| 
 | 
 | ||||||
| @ -91,19 +101,19 @@ Delay between keypresses. | |||||||
| 
 | 
 | ||||||
| ## ALT+Numpad input | ## ALT+Numpad input | ||||||
| 
 | 
 | ||||||
| On Windows and some Linux systems, you can print characters by pressing `ALT` key and entering its code on Numpad. | On Windows and some Linux systems, you can print characters by holding `ALT` key and entering its code on Numpad. | ||||||
| |Command|Parameters|Notes| | | Command   | Parameters     | Notes                                                           | | ||||||
| |-|-|-| | | --------- | -------------- | --------------------------------------------------------------- | | ||||||
| |ALTCHAR|Character code|Print single character| | | ALTCHAR   | Character code | Print single character                                          | | ||||||
| |ALTSTRING|Text string|Print text string using ALT+Numpad method| | | ALTSTRING | Text string    | Print text string using ALT+Numpad method                       | | ||||||
| |ALTCODE|Text string|Same as ALTSTRING, presents in some Duckyscript implementations| | | ALTCODE   | Text string    | Same as ALTSTRING, presents in some Duckyscript implementations | | ||||||
| 
 | 
 | ||||||
| ## SysRq | ## SysRq | ||||||
| 
 | 
 | ||||||
| Send [SysRq command](https://en.wikipedia.org/wiki/Magic_SysRq_key) | Send [SysRq command](https://en.wikipedia.org/wiki/Magic_SysRq_key) | ||||||
| |Command|Parameters|Notes| | | Command | Parameters       | Notes | | ||||||
| |-|-|-| | | ------- | ---------------- | ----- | | ||||||
| |SYSRQ|Single character|| | | SYSRQ   | Single character |       | | ||||||
| 
 | 
 | ||||||
| ## USB device ID | ## USB device ID | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -11,9 +11,6 @@ | |||||||
| #define HID_EP_OUT 0x01 | #define HID_EP_OUT 0x01 | ||||||
| #define HID_EP_SZ 0x10 | #define HID_EP_SZ 0x10 | ||||||
| 
 | 
 | ||||||
| #define HID_KB_MAX_KEYS 6 |  | ||||||
| #define HID_CONSUMER_MAX_KEYS 2 |  | ||||||
| 
 |  | ||||||
| #define HID_INTERVAL 2 | #define HID_INTERVAL 2 | ||||||
| 
 | 
 | ||||||
| #define HID_VID_DEFAULT 0x046D | #define HID_VID_DEFAULT 0x046D | ||||||
|  | |||||||
| @ -9,6 +9,11 @@ | |||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | /** Max number of simultaneously pressed keys (keyboard) */ | ||||||
|  | #define HID_KB_MAX_KEYS 6 | ||||||
|  | /** Max number of simultaneously pressed keys (consumer control) */ | ||||||
|  | #define HID_CONSUMER_MAX_KEYS 2 | ||||||
|  | 
 | ||||||
| #define HID_KEYBOARD_NONE 0x00 | #define HID_KEYBOARD_NONE 0x00 | ||||||
| 
 | 
 | ||||||
| /** HID keyboard modifier keys */ | /** HID keyboard modifier keys */ | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Nikolay Minaylov
						Nikolay Minaylov