bad_usb.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. #include <furi.h>
  2. #include <furi-hal.h>
  3. #include <gui/gui.h>
  4. #include <input/input.h>
  5. #include <lib/toolbox/args.h>
  6. #include <furi-hal-usb-hid.h>
  7. #include <storage/storage.h>
  8. #define TAG "BadUsb"
  9. #define WORKER_TAG TAG "Worker"
  10. typedef enum {
  11. EventTypeInput,
  12. EventTypeWorkerState,
  13. } EventType;
  14. typedef enum {
  15. WorkerStateDone,
  16. WorkerStateNoFile,
  17. WorkerStateScriptError,
  18. WorkerStateDisconnected,
  19. } WorkerState;
  20. typedef enum {
  21. AppStateWait,
  22. AppStateRunning,
  23. AppStateError,
  24. AppStateExit,
  25. } AppState;
  26. typedef enum {
  27. WorkerCmdStart = (1 << 0),
  28. WorkerCmdStop = (1 << 1),
  29. } WorkerCommandFlags;
  30. // Event message from worker
  31. typedef struct {
  32. WorkerState state;
  33. uint16_t line;
  34. } BadUsbWorkerState;
  35. typedef struct {
  36. union {
  37. InputEvent input;
  38. BadUsbWorkerState worker;
  39. };
  40. EventType type;
  41. } BadUsbEvent;
  42. typedef struct {
  43. uint32_t defdelay;
  44. char msg_text[32];
  45. osThreadAttr_t thread_attr;
  46. osThreadId_t thread;
  47. osMessageQueueId_t event_queue;
  48. } BadUsbParams;
  49. typedef struct {
  50. char* name;
  51. uint16_t keycode;
  52. } DuckyKey;
  53. static const DuckyKey ducky_keys[] = {
  54. {"CTRL", KEY_MOD_LEFT_CTRL},
  55. {"CONTROL", KEY_MOD_LEFT_CTRL},
  56. {"SHIFT", KEY_MOD_LEFT_SHIFT},
  57. {"ALT", KEY_MOD_LEFT_ALT},
  58. {"GUI", KEY_MOD_LEFT_GUI},
  59. {"WINDOWS", KEY_MOD_LEFT_GUI},
  60. {"DOWNARROW", KEY_DOWN_ARROW},
  61. {"DOWN", KEY_DOWN_ARROW},
  62. {"LEFTARROW", KEY_LEFT_ARROW},
  63. {"LEFT", KEY_LEFT_ARROW},
  64. {"RIGHTARROW", KEY_RIGHT_ARROW},
  65. {"RIGHT", KEY_RIGHT_ARROW},
  66. {"UPARROW", KEY_UP_ARROW},
  67. {"UP", KEY_UP_ARROW},
  68. {"ENTER", KEY_ENTER},
  69. {"BREAK", KEY_PAUSE},
  70. {"PAUSE", KEY_PAUSE},
  71. {"CAPSLOCK", KEY_CAPS_LOCK},
  72. {"DELETE", KEY_DELETE},
  73. {"BACKSPACE", KEY_BACKSPACE},
  74. {"END", KEY_END},
  75. {"ESC", KEY_ESC},
  76. {"ESCAPE", KEY_ESC},
  77. {"HOME", KEY_HOME},
  78. {"INSERT", KEY_INSERT},
  79. {"NUMLOCK", KEY_NUM_LOCK},
  80. {"PAGEUP", KEY_PAGE_UP},
  81. {"PAGEDOWN", KEY_PAGE_DOWN},
  82. {"PRINTSCREEN", KEY_PRINT},
  83. {"SCROLLOCK", KEY_SCROLL_LOCK},
  84. {"SPACE", KEY_SPACE},
  85. {"TAB", KEY_TAB},
  86. {"MENU", KEY_APPLICATION},
  87. {"APP", KEY_APPLICATION},
  88. };
  89. static const char ducky_cmd_comment[] = {"REM"};
  90. static const char ducky_cmd_delay[] = {"DELAY"};
  91. static const char ducky_cmd_string[] = {"STRING"};
  92. static const char ducky_cmd_defdelay_1[] = {"DEFAULT_DELAY"};
  93. static const char ducky_cmd_defdelay_2[] = {"DEFAULTDELAY"};
  94. static bool ducky_get_delay_val(char* param, uint32_t* val) {
  95. uint32_t delay_val = 0;
  96. if(sscanf(param, "%lu", &delay_val) == 1) {
  97. *val = delay_val;
  98. return true;
  99. }
  100. return false;
  101. }
  102. static bool ducky_string(char* param) {
  103. uint32_t i = 0;
  104. while(param[i] != '\0') {
  105. furi_hal_hid_kb_press(HID_ASCII_TO_KEY(param[i]));
  106. furi_hal_hid_kb_release(HID_ASCII_TO_KEY(param[i]));
  107. i++;
  108. }
  109. return true;
  110. }
  111. static uint16_t ducky_get_keycode(char* param, bool accept_chars) {
  112. for(uint8_t i = 0; i < (sizeof(ducky_keys) / sizeof(ducky_keys[0])); i++) {
  113. if(strncmp(param, ducky_keys[i].name, strlen(ducky_keys[i].name)) == 0)
  114. return ducky_keys[i].keycode;
  115. }
  116. if((accept_chars) && (strlen(param) > 0)) {
  117. return (HID_ASCII_TO_KEY(param[0]) & 0xFF);
  118. }
  119. return 0;
  120. }
  121. static bool ducky_parse_line(string_t line, BadUsbParams* app) {
  122. //uint32_t line_len = string_size(line);
  123. char* line_t = (char*)string_get_cstr(line);
  124. bool state = false;
  125. // General commands
  126. if(strncmp(line_t, ducky_cmd_comment, strlen(ducky_cmd_comment)) == 0) {
  127. // REM - comment line
  128. return true;
  129. } else if(strncmp(line_t, ducky_cmd_delay, strlen(ducky_cmd_delay)) == 0) {
  130. // DELAY
  131. line_t = &line_t[args_get_first_word_length(line) + 1];
  132. uint32_t delay_val = 0;
  133. state = ducky_get_delay_val(line_t, &delay_val);
  134. if((state) && (delay_val > 0)) {
  135. // Using ThreadFlagsWait as delay function allows exiting task on WorkerCmdStop command
  136. if(osThreadFlagsWait(WorkerCmdStop, osFlagsWaitAny | osFlagsNoClear, delay_val) ==
  137. WorkerCmdStop)
  138. return true;
  139. }
  140. return state;
  141. } else if(
  142. (strncmp(line_t, ducky_cmd_defdelay_1, strlen(ducky_cmd_defdelay_1)) == 0) ||
  143. (strncmp(line_t, ducky_cmd_defdelay_2, strlen(ducky_cmd_defdelay_2)) == 0)) {
  144. // DEFAULT_DELAY
  145. line_t = &line_t[args_get_first_word_length(line) + 1];
  146. return ducky_get_delay_val(line_t, &app->defdelay);
  147. } else if(strncmp(line_t, ducky_cmd_string, strlen(ducky_cmd_string)) == 0) {
  148. // STRING
  149. if(app->defdelay > 0) {
  150. if(osThreadFlagsWait(WorkerCmdStop, osFlagsWaitAny | osFlagsNoClear, app->defdelay) ==
  151. WorkerCmdStop)
  152. return true;
  153. }
  154. line_t = &line_t[args_get_first_word_length(line) + 1];
  155. return ducky_string(line_t);
  156. } else {
  157. // Special keys + modifiers
  158. uint16_t key = ducky_get_keycode(line_t, false);
  159. if(key == KEY_NONE) return false;
  160. if((key & 0xFF00) != 0) {
  161. // It's a modifier key
  162. line_t = &line_t[args_get_first_word_length(line) + 1];
  163. key |= ducky_get_keycode(line_t, true);
  164. }
  165. if(app->defdelay > 0) {
  166. if(osThreadFlagsWait(WorkerCmdStop, osFlagsWaitAny | osFlagsNoClear, app->defdelay) ==
  167. WorkerCmdStop)
  168. return true;
  169. }
  170. furi_hal_hid_kb_press(key);
  171. furi_hal_hid_kb_release(key);
  172. return true;
  173. }
  174. return false;
  175. }
  176. static void badusb_worker(void* context) {
  177. BadUsbParams* app = context;
  178. FURI_LOG_I(WORKER_TAG, "Init");
  179. File* script_file = storage_file_alloc(furi_record_open("storage"));
  180. BadUsbEvent evt;
  181. string_t line;
  182. uint32_t line_cnt = 0;
  183. string_init(line);
  184. if(storage_file_open(script_file, "/ext/badusb.txt", FSAM_READ, FSOM_OPEN_EXISTING)) {
  185. char buffer[16];
  186. uint16_t ret;
  187. uint32_t flags =
  188. osThreadFlagsWait(WorkerCmdStart | WorkerCmdStop, osFlagsWaitAny, osWaitForever);
  189. if(flags & WorkerCmdStart) {
  190. FURI_LOG_I(WORKER_TAG, "Start");
  191. do {
  192. ret = storage_file_read(script_file, buffer, 16);
  193. for(uint16_t i = 0; i < ret; i++) {
  194. if(buffer[i] == '\n' && string_size(line) > 0) {
  195. line_cnt++;
  196. if(ducky_parse_line(line, app) == false) {
  197. ret = 0;
  198. FURI_LOG_E(WORKER_TAG, "Unknown command at line %lu", line_cnt);
  199. evt.type = EventTypeWorkerState;
  200. evt.worker.state = WorkerStateScriptError;
  201. evt.worker.line = line_cnt;
  202. osMessageQueuePut(app->event_queue, &evt, 0, osWaitForever);
  203. break;
  204. }
  205. flags = osThreadFlagsGet();
  206. if(flags == WorkerCmdStop) {
  207. ret = 0;
  208. break;
  209. }
  210. string_reset(line);
  211. } else {
  212. string_push_back(line, buffer[i]);
  213. }
  214. }
  215. } while(ret > 0);
  216. }
  217. } else {
  218. FURI_LOG_E(WORKER_TAG, "Script file open error");
  219. evt.type = EventTypeWorkerState;
  220. evt.worker.state = WorkerStateNoFile;
  221. osMessageQueuePut(app->event_queue, &evt, 0, osWaitForever);
  222. }
  223. string_reset(line);
  224. string_clear(line);
  225. furi_hal_hid_kb_release_all();
  226. storage_file_close(script_file);
  227. storage_file_free(script_file);
  228. FURI_LOG_I(WORKER_TAG, "End");
  229. evt.type = EventTypeWorkerState;
  230. evt.worker.state = WorkerStateDone;
  231. osMessageQueuePut(app->event_queue, &evt, 0, osWaitForever);
  232. furi_hal_hid_kb_release_all();
  233. osThreadExit();
  234. }
  235. static void bad_usb_render_callback(Canvas* canvas, void* ctx) {
  236. BadUsbParams* app = (BadUsbParams*)ctx;
  237. canvas_clear(canvas);
  238. canvas_set_font(canvas, FontPrimary);
  239. canvas_draw_str(canvas, 0, 10, "Bad USB test");
  240. if(strlen(app->msg_text) > 0) {
  241. canvas_set_font(canvas, FontSecondary);
  242. canvas_draw_str(canvas, 0, 62, app->msg_text);
  243. }
  244. }
  245. static void bad_usb_input_callback(InputEvent* input_event, void* ctx) {
  246. osMessageQueueId_t event_queue = ctx;
  247. BadUsbEvent event;
  248. event.type = EventTypeInput;
  249. event.input = *input_event;
  250. osMessageQueuePut(event_queue, &event, 0, osWaitForever);
  251. }
  252. int32_t bad_usb_app(void* p) {
  253. BadUsbParams* app = furi_alloc(sizeof(BadUsbParams));
  254. app->event_queue = osMessageQueueNew(8, sizeof(BadUsbEvent), NULL);
  255. furi_check(app->event_queue);
  256. ViewPort* view_port = view_port_alloc();
  257. UsbInterface* usb_mode_prev = furi_hal_usb_get_config();
  258. furi_hal_usb_set_config(&usb_hid);
  259. view_port_draw_callback_set(view_port, bad_usb_render_callback, app);
  260. view_port_input_callback_set(view_port, bad_usb_input_callback, app->event_queue);
  261. // Open GUI and register view_port
  262. Gui* gui = furi_record_open("gui");
  263. gui_add_view_port(gui, view_port, GuiLayerFullscreen);
  264. app->thread = NULL;
  265. app->thread_attr.name = "bad_usb_worker";
  266. app->thread_attr.stack_size = 2048;
  267. app->thread = osThreadNew(badusb_worker, app, &app->thread_attr);
  268. bool worker_running = true;
  269. AppState app_state = AppStateWait;
  270. snprintf(app->msg_text, sizeof(app->msg_text), "Press [OK] to start");
  271. view_port_update(view_port);
  272. BadUsbEvent event;
  273. while(1) {
  274. osStatus_t event_status = osMessageQueueGet(app->event_queue, &event, NULL, osWaitForever);
  275. if(event_status == osOK) {
  276. if(event.type == EventTypeInput) {
  277. if(event.input.type == InputTypeShort && event.input.key == InputKeyBack) {
  278. if(worker_running) {
  279. osThreadFlagsSet(app->thread, WorkerCmdStop);
  280. app_state = AppStateExit;
  281. } else
  282. break;
  283. }
  284. if(event.input.type == InputTypeShort && event.input.key == InputKeyOk) {
  285. if(worker_running) {
  286. app_state = AppStateRunning;
  287. osThreadFlagsSet(app->thread, WorkerCmdStart);
  288. snprintf(app->msg_text, sizeof(app->msg_text), "Running...");
  289. view_port_update(view_port);
  290. }
  291. }
  292. } else if(event.type == EventTypeWorkerState) {
  293. FURI_LOG_I(TAG, "ev: %d", event.worker.state);
  294. if(event.worker.state == WorkerStateDone) {
  295. worker_running = false;
  296. if(app_state == AppStateExit)
  297. break;
  298. else if(app_state == AppStateRunning) {
  299. //done
  300. app->thread = osThreadNew(badusb_worker, app, &app->thread_attr);
  301. worker_running = true;
  302. app_state = AppStateWait;
  303. snprintf(app->msg_text, sizeof(app->msg_text), "Press [OK] to start");
  304. view_port_update(view_port);
  305. }
  306. } else if(event.worker.state == WorkerStateNoFile) {
  307. app_state = AppStateError;
  308. snprintf(app->msg_text, sizeof(app->msg_text), "File not found!");
  309. view_port_update(view_port);
  310. } else if(event.worker.state == WorkerStateScriptError) {
  311. app_state = AppStateError;
  312. snprintf(
  313. app->msg_text,
  314. sizeof(app->msg_text),
  315. "Error at line %u",
  316. event.worker.line);
  317. view_port_update(view_port);
  318. }
  319. }
  320. }
  321. }
  322. furi_hal_usb_set_config(usb_mode_prev);
  323. // remove & free all stuff created by app
  324. gui_remove_view_port(gui, view_port);
  325. view_port_free(view_port);
  326. osMessageQueueDelete(app->event_queue);
  327. free(app);
  328. return 0;
  329. }