bad_usb_script.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  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. #include "bad_usb_script.h"
  9. #include <dolphin/dolphin.h>
  10. #define TAG "BadUSB"
  11. #define WORKER_TAG TAG "Worker"
  12. #define FILE_BUFFER_LEN 16
  13. #define SCRIPT_STATE_ERROR (-1)
  14. #define SCRIPT_STATE_END (-2)
  15. #define SCRIPT_STATE_NEXT_LINE (-3)
  16. typedef enum {
  17. WorkerEvtToggle = (1 << 0),
  18. WorkerEvtEnd = (1 << 1),
  19. WorkerEvtConnect = (1 << 2),
  20. WorkerEvtDisconnect = (1 << 3),
  21. } WorkerEvtFlags;
  22. struct BadUsbScript {
  23. FuriHalUsbHidConfig hid_cfg;
  24. BadUsbState st;
  25. string_t file_path;
  26. uint32_t defdelay;
  27. FuriThread* thread;
  28. uint8_t file_buf[FILE_BUFFER_LEN + 1];
  29. uint8_t buf_start;
  30. uint8_t buf_len;
  31. bool file_end;
  32. string_t line;
  33. string_t line_prev;
  34. uint32_t repeat_cnt;
  35. };
  36. typedef struct {
  37. char* name;
  38. uint16_t keycode;
  39. } DuckyKey;
  40. static const DuckyKey ducky_keys[] = {
  41. {"CTRL-ALT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_ALT},
  42. {"CTRL-SHIFT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT},
  43. {"ALT-SHIFT", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_SHIFT},
  44. {"ALT-GUI", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_GUI},
  45. {"CTRL", KEY_MOD_LEFT_CTRL},
  46. {"CONTROL", KEY_MOD_LEFT_CTRL},
  47. {"SHIFT", KEY_MOD_LEFT_SHIFT},
  48. {"ALT", KEY_MOD_LEFT_ALT},
  49. {"GUI", KEY_MOD_LEFT_GUI},
  50. {"WINDOWS", KEY_MOD_LEFT_GUI},
  51. {"DOWNARROW", KEY_DOWN_ARROW},
  52. {"DOWN", KEY_DOWN_ARROW},
  53. {"LEFTARROW", KEY_LEFT_ARROW},
  54. {"LEFT", KEY_LEFT_ARROW},
  55. {"RIGHTARROW", KEY_RIGHT_ARROW},
  56. {"RIGHT", KEY_RIGHT_ARROW},
  57. {"UPARROW", KEY_UP_ARROW},
  58. {"UP", KEY_UP_ARROW},
  59. {"ENTER", KEY_ENTER},
  60. {"BREAK", KEY_PAUSE},
  61. {"PAUSE", KEY_PAUSE},
  62. {"CAPSLOCK", KEY_CAPS_LOCK},
  63. {"DELETE", KEY_DELETE},
  64. {"BACKSPACE", KEY_BACKSPACE},
  65. {"END", KEY_END},
  66. {"ESC", KEY_ESC},
  67. {"ESCAPE", KEY_ESC},
  68. {"HOME", KEY_HOME},
  69. {"INSERT", KEY_INSERT},
  70. {"NUMLOCK", KEY_NUM_LOCK},
  71. {"PAGEUP", KEY_PAGE_UP},
  72. {"PAGEDOWN", KEY_PAGE_DOWN},
  73. {"PRINTSCREEN", KEY_PRINT},
  74. {"SCROLLOCK", KEY_SCROLL_LOCK},
  75. {"SPACE", KEY_SPACE},
  76. {"TAB", KEY_TAB},
  77. {"MENU", KEY_APPLICATION},
  78. {"APP", KEY_APPLICATION},
  79. {"F1", KEY_F1},
  80. {"F2", KEY_F2},
  81. {"F3", KEY_F3},
  82. {"F4", KEY_F4},
  83. {"F5", KEY_F5},
  84. {"F6", KEY_F6},
  85. {"F7", KEY_F7},
  86. {"F8", KEY_F8},
  87. {"F9", KEY_F9},
  88. {"F10", KEY_F10},
  89. {"F11", KEY_F11},
  90. {"F12", KEY_F12},
  91. };
  92. static const char ducky_cmd_comment[] = {"REM"};
  93. static const char ducky_cmd_id[] = {"ID"};
  94. static const char ducky_cmd_delay[] = {"DELAY "};
  95. static const char ducky_cmd_string[] = {"STRING "};
  96. static const char ducky_cmd_defdelay_1[] = {"DEFAULT_DELAY "};
  97. static const char ducky_cmd_defdelay_2[] = {"DEFAULTDELAY "};
  98. static const char ducky_cmd_repeat[] = {"REPEAT "};
  99. static const char ducky_cmd_altchar[] = {"ALTCHAR "};
  100. static const char ducky_cmd_altstr_1[] = {"ALTSTRING "};
  101. static const char ducky_cmd_altstr_2[] = {"ALTCODE "};
  102. static const uint8_t numpad_keys[10] = {
  103. KEYPAD_0,
  104. KEYPAD_1,
  105. KEYPAD_2,
  106. KEYPAD_3,
  107. KEYPAD_4,
  108. KEYPAD_5,
  109. KEYPAD_6,
  110. KEYPAD_7,
  111. KEYPAD_8,
  112. KEYPAD_9,
  113. };
  114. static bool ducky_get_number(const char* param, uint32_t* val) {
  115. uint32_t value = 0;
  116. if(sscanf(param, "%lu", &value) == 1) {
  117. *val = value;
  118. return true;
  119. }
  120. return false;
  121. }
  122. static uint32_t ducky_get_command_len(const char* line) {
  123. uint32_t len = strlen(line);
  124. for(uint32_t i = 0; i < len; i++) {
  125. if(line[i] == ' ') return i;
  126. }
  127. return 0;
  128. }
  129. static bool ducky_is_line_end(const char chr) {
  130. return ((chr == ' ') || (chr == '\0') || (chr == '\r') || (chr == '\n'));
  131. }
  132. static void ducky_numlock_on() {
  133. if((furi_hal_hid_get_led_state() & HID_KB_LED_NUM) == 0) {
  134. furi_hal_hid_kb_press(KEY_NUM_LOCK);
  135. furi_hal_hid_kb_release(KEY_NUM_LOCK);
  136. }
  137. }
  138. static bool ducky_numpad_press(const char num) {
  139. if((num < '0') || (num > '9')) return false;
  140. uint16_t key = numpad_keys[num - '0'];
  141. furi_hal_hid_kb_press(key);
  142. furi_hal_hid_kb_release(key);
  143. return true;
  144. }
  145. static bool ducky_altchar(const char* charcode) {
  146. uint8_t i = 0;
  147. bool state = false;
  148. FURI_LOG_I(WORKER_TAG, "char %s", charcode);
  149. furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT);
  150. while(!ducky_is_line_end(charcode[i])) {
  151. state = ducky_numpad_press(charcode[i]);
  152. if(state == false) break;
  153. i++;
  154. }
  155. furi_hal_hid_kb_release(KEY_MOD_LEFT_ALT);
  156. return state;
  157. }
  158. static bool ducky_altstring(const char* param) {
  159. uint32_t i = 0;
  160. bool state = false;
  161. while(param[i] != '\0') {
  162. if((param[i] < ' ') || (param[i] > '~')) {
  163. i++;
  164. continue; // Skip non-printable chars
  165. }
  166. char temp_str[4];
  167. snprintf(temp_str, 4, "%u", param[i]);
  168. state = ducky_altchar(temp_str);
  169. if(state == false) break;
  170. i++;
  171. }
  172. return state;
  173. }
  174. static bool ducky_string(const char* param) {
  175. uint32_t i = 0;
  176. while(param[i] != '\0') {
  177. uint16_t keycode = HID_ASCII_TO_KEY(param[i]);
  178. if(keycode != KEY_NONE) {
  179. furi_hal_hid_kb_press(keycode);
  180. furi_hal_hid_kb_release(keycode);
  181. }
  182. i++;
  183. }
  184. return true;
  185. }
  186. static uint16_t ducky_get_keycode(const char* param, bool accept_chars) {
  187. for(uint8_t i = 0; i < (sizeof(ducky_keys) / sizeof(ducky_keys[0])); i++) {
  188. uint8_t key_cmd_len = strlen(ducky_keys[i].name);
  189. if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) &&
  190. (ducky_is_line_end(param[key_cmd_len]))) {
  191. return ducky_keys[i].keycode;
  192. }
  193. }
  194. if((accept_chars) && (strlen(param) > 0)) {
  195. return (HID_ASCII_TO_KEY(param[0]) & 0xFF);
  196. }
  197. return 0;
  198. }
  199. static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) {
  200. uint32_t line_len = string_size(line);
  201. const char* line_tmp = string_get_cstr(line);
  202. bool state = false;
  203. for(uint32_t i = 0; i < line_len; i++) {
  204. if((line_tmp[i] != ' ') && (line_tmp[i] != '\t') && (line_tmp[i] != '\n')) {
  205. line_tmp = &line_tmp[i];
  206. break; // Skip spaces and tabs
  207. }
  208. if(i == line_len - 1) return SCRIPT_STATE_NEXT_LINE; // Skip empty lines
  209. }
  210. FURI_LOG_D(WORKER_TAG, "line:%s", line_tmp);
  211. // General commands
  212. if(strncmp(line_tmp, ducky_cmd_comment, strlen(ducky_cmd_comment)) == 0) {
  213. // REM - comment line
  214. return (0);
  215. } else if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) {
  216. // ID - executed in ducky_script_preload
  217. return (0);
  218. } else if(strncmp(line_tmp, ducky_cmd_delay, strlen(ducky_cmd_delay)) == 0) {
  219. // DELAY
  220. line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
  221. uint32_t delay_val = 0;
  222. state = ducky_get_number(line_tmp, &delay_val);
  223. if((state) && (delay_val > 0)) {
  224. return (int32_t)delay_val;
  225. }
  226. return SCRIPT_STATE_ERROR;
  227. } else if(
  228. (strncmp(line_tmp, ducky_cmd_defdelay_1, strlen(ducky_cmd_defdelay_1)) == 0) ||
  229. (strncmp(line_tmp, ducky_cmd_defdelay_2, strlen(ducky_cmd_defdelay_2)) == 0)) {
  230. // DEFAULT_DELAY
  231. line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
  232. state = ducky_get_number(line_tmp, &bad_usb->defdelay);
  233. return (state) ? (0) : SCRIPT_STATE_ERROR;
  234. } else if(strncmp(line_tmp, ducky_cmd_string, strlen(ducky_cmd_string)) == 0) {
  235. // STRING
  236. line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
  237. state = ducky_string(line_tmp);
  238. return (state) ? (0) : SCRIPT_STATE_ERROR;
  239. } else if(strncmp(line_tmp, ducky_cmd_altchar, strlen(ducky_cmd_altchar)) == 0) {
  240. // ALTCHAR
  241. line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
  242. ducky_numlock_on();
  243. state = ducky_altchar(line_tmp);
  244. return (state) ? (0) : SCRIPT_STATE_ERROR;
  245. } else if(
  246. (strncmp(line_tmp, ducky_cmd_altstr_1, strlen(ducky_cmd_altstr_1)) == 0) ||
  247. (strncmp(line_tmp, ducky_cmd_altstr_2, strlen(ducky_cmd_altstr_2)) == 0)) {
  248. // ALTSTRING
  249. line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
  250. ducky_numlock_on();
  251. state = ducky_altstring(line_tmp);
  252. return (state) ? (0) : SCRIPT_STATE_ERROR;
  253. } else if(strncmp(line_tmp, ducky_cmd_repeat, strlen(ducky_cmd_repeat)) == 0) {
  254. // REPEAT
  255. line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
  256. state = ducky_get_number(line_tmp, &bad_usb->repeat_cnt);
  257. return (state) ? (0) : SCRIPT_STATE_ERROR;
  258. } else {
  259. // Special keys + modifiers
  260. uint16_t key = ducky_get_keycode(line_tmp, false);
  261. if(key == KEY_NONE) return SCRIPT_STATE_ERROR;
  262. if((key & 0xFF00) != 0) {
  263. // It's a modifier key
  264. line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
  265. key |= ducky_get_keycode(line_tmp, true);
  266. }
  267. furi_hal_hid_kb_press(key);
  268. furi_hal_hid_kb_release(key);
  269. return (0);
  270. }
  271. return SCRIPT_STATE_ERROR;
  272. }
  273. static bool ducky_set_usb_id(BadUsbScript* bad_usb, const char* line) {
  274. if(sscanf(line, "%lX:%lX", &bad_usb->hid_cfg.vid, &bad_usb->hid_cfg.pid) == 2) {
  275. bad_usb->hid_cfg.manuf[0] = '\0';
  276. bad_usb->hid_cfg.product[0] = '\0';
  277. uint8_t id_len = ducky_get_command_len(line);
  278. if(!ducky_is_line_end(line[id_len + 1])) {
  279. sscanf(
  280. &line[id_len + 1],
  281. "%31[^\r\n:]:%31[^\r\n]",
  282. bad_usb->hid_cfg.manuf,
  283. bad_usb->hid_cfg.product);
  284. }
  285. FURI_LOG_D(
  286. WORKER_TAG,
  287. "set id: %04X:%04X mfr:%s product:%s",
  288. bad_usb->hid_cfg.vid,
  289. bad_usb->hid_cfg.pid,
  290. bad_usb->hid_cfg.manuf,
  291. bad_usb->hid_cfg.product);
  292. return true;
  293. }
  294. return false;
  295. }
  296. static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) {
  297. uint8_t ret = 0;
  298. uint32_t line_len = 0;
  299. string_reset(bad_usb->line);
  300. do {
  301. ret = storage_file_read(script_file, bad_usb->file_buf, FILE_BUFFER_LEN);
  302. for(uint16_t i = 0; i < ret; i++) {
  303. if(bad_usb->file_buf[i] == '\n' && line_len > 0) {
  304. bad_usb->st.line_nb++;
  305. line_len = 0;
  306. } else {
  307. if(bad_usb->st.line_nb == 0) { // Save first line
  308. string_push_back(bad_usb->line, bad_usb->file_buf[i]);
  309. }
  310. line_len++;
  311. }
  312. }
  313. if(storage_file_eof(script_file)) {
  314. if(line_len > 0) {
  315. bad_usb->st.line_nb++;
  316. break;
  317. }
  318. }
  319. } while(ret > 0);
  320. const char* line_tmp = string_get_cstr(bad_usb->line);
  321. bool id_set = false; // Looking for ID command at first line
  322. if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) {
  323. id_set = ducky_set_usb_id(bad_usb, &line_tmp[strlen(ducky_cmd_id) + 1]);
  324. }
  325. if(id_set) {
  326. furi_check(furi_hal_usb_set_config(&usb_hid, &bad_usb->hid_cfg));
  327. } else {
  328. furi_check(furi_hal_usb_set_config(&usb_hid, NULL));
  329. }
  330. storage_file_seek(script_file, 0, true);
  331. string_reset(bad_usb->line);
  332. return true;
  333. }
  334. static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_file) {
  335. int32_t delay_val = 0;
  336. if(bad_usb->repeat_cnt > 0) {
  337. bad_usb->repeat_cnt--;
  338. delay_val = ducky_parse_line(bad_usb, bad_usb->line_prev);
  339. if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
  340. return 0;
  341. } else if(delay_val < 0) { // Script error
  342. bad_usb->st.error_line = bad_usb->st.line_cur - 1;
  343. FURI_LOG_E(WORKER_TAG, "Unknown command at line %lu", bad_usb->st.line_cur - 1);
  344. return SCRIPT_STATE_ERROR;
  345. } else {
  346. return (delay_val + bad_usb->defdelay);
  347. }
  348. }
  349. string_set(bad_usb->line_prev, bad_usb->line);
  350. string_reset(bad_usb->line);
  351. while(1) {
  352. if(bad_usb->buf_len == 0) {
  353. bad_usb->buf_len = storage_file_read(script_file, bad_usb->file_buf, FILE_BUFFER_LEN);
  354. if(storage_file_eof(script_file)) {
  355. if((bad_usb->buf_len < FILE_BUFFER_LEN) && (bad_usb->file_end == false)) {
  356. bad_usb->file_buf[bad_usb->buf_len] = '\n';
  357. bad_usb->buf_len++;
  358. bad_usb->file_end = true;
  359. }
  360. }
  361. bad_usb->buf_start = 0;
  362. if(bad_usb->buf_len == 0) return SCRIPT_STATE_END;
  363. }
  364. for(uint8_t i = bad_usb->buf_start; i < (bad_usb->buf_start + bad_usb->buf_len); i++) {
  365. if(bad_usb->file_buf[i] == '\n' && string_size(bad_usb->line) > 0) {
  366. bad_usb->st.line_cur++;
  367. bad_usb->buf_len = bad_usb->buf_len + bad_usb->buf_start - (i + 1);
  368. bad_usb->buf_start = i + 1;
  369. delay_val = ducky_parse_line(bad_usb, bad_usb->line);
  370. if(delay_val < 0) {
  371. bad_usb->st.error_line = bad_usb->st.line_cur;
  372. FURI_LOG_E(WORKER_TAG, "Unknown command at line %lu", bad_usb->st.line_cur);
  373. return SCRIPT_STATE_ERROR;
  374. } else {
  375. return (delay_val + bad_usb->defdelay);
  376. }
  377. } else {
  378. string_push_back(bad_usb->line, bad_usb->file_buf[i]);
  379. }
  380. }
  381. bad_usb->buf_len = 0;
  382. if(bad_usb->file_end) return SCRIPT_STATE_END;
  383. }
  384. return 0;
  385. }
  386. static void bad_usb_hid_state_callback(bool state, void* context) {
  387. furi_assert(context);
  388. BadUsbScript* bad_usb = context;
  389. if(state == true)
  390. furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtConnect);
  391. else
  392. furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtDisconnect);
  393. }
  394. static int32_t bad_usb_worker(void* context) {
  395. BadUsbScript* bad_usb = context;
  396. BadUsbWorkerState worker_state = BadUsbStateInit;
  397. int32_t delay_val = 0;
  398. FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config();
  399. FURI_LOG_I(WORKER_TAG, "Init");
  400. File* script_file = storage_file_alloc(furi_record_open("storage"));
  401. string_init(bad_usb->line);
  402. string_init(bad_usb->line_prev);
  403. furi_hal_hid_set_state_callback(bad_usb_hid_state_callback, bad_usb);
  404. while(1) {
  405. if(worker_state == BadUsbStateInit) { // State: initialization
  406. if(storage_file_open(
  407. script_file,
  408. string_get_cstr(bad_usb->file_path),
  409. FSAM_READ,
  410. FSOM_OPEN_EXISTING)) {
  411. if((ducky_script_preload(bad_usb, script_file)) && (bad_usb->st.line_nb > 0)) {
  412. if(furi_hal_hid_is_connected()) {
  413. worker_state = BadUsbStateIdle; // Ready to run
  414. } else {
  415. worker_state = BadUsbStateNotConnected; // USB not connected
  416. }
  417. } else {
  418. worker_state = BadUsbStateScriptError; // Script preload error
  419. }
  420. } else {
  421. FURI_LOG_E(WORKER_TAG, "File open error");
  422. worker_state = BadUsbStateFileError; // File open error
  423. }
  424. bad_usb->st.state = worker_state;
  425. } else if(worker_state == BadUsbStateNotConnected) { // State: USB not connected
  426. uint32_t flags = furi_thread_flags_wait(
  427. WorkerEvtEnd | WorkerEvtConnect, osFlagsWaitAny, osWaitForever);
  428. furi_check((flags & osFlagsError) == 0);
  429. if(flags & WorkerEvtEnd) {
  430. break;
  431. } else if(flags & WorkerEvtConnect) {
  432. worker_state = BadUsbStateIdle; // Ready to run
  433. }
  434. bad_usb->st.state = worker_state;
  435. } else if(worker_state == BadUsbStateIdle) { // State: ready to start
  436. uint32_t flags = furi_thread_flags_wait(
  437. WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect,
  438. osFlagsWaitAny,
  439. osWaitForever);
  440. furi_check((flags & osFlagsError) == 0);
  441. if(flags & WorkerEvtEnd) {
  442. break;
  443. } else if(flags & WorkerEvtToggle) { // Start executing script
  444. DOLPHIN_DEED(DolphinDeedBadUsbPlayScript);
  445. delay_val = 0;
  446. bad_usb->buf_len = 0;
  447. bad_usb->st.line_cur = 0;
  448. bad_usb->defdelay = 0;
  449. bad_usb->repeat_cnt = 0;
  450. bad_usb->file_end = false;
  451. storage_file_seek(script_file, 0, true);
  452. worker_state = BadUsbStateRunning;
  453. } else if(flags & WorkerEvtDisconnect) {
  454. worker_state = BadUsbStateNotConnected; // USB disconnected
  455. }
  456. bad_usb->st.state = worker_state;
  457. } else if(worker_state == BadUsbStateRunning) { // State: running
  458. uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val);
  459. uint32_t flags = furi_thread_flags_wait(
  460. WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, osFlagsWaitAny, delay_cur);
  461. delay_val -= delay_cur;
  462. if(!(flags & osFlagsError)) {
  463. if(flags & WorkerEvtEnd) {
  464. break;
  465. } else if(flags & WorkerEvtToggle) {
  466. worker_state = BadUsbStateIdle; // Stop executing script
  467. furi_hal_hid_kb_release_all();
  468. } else if(flags & WorkerEvtDisconnect) {
  469. worker_state = BadUsbStateNotConnected; // USB disconnected
  470. furi_hal_hid_kb_release_all();
  471. }
  472. bad_usb->st.state = worker_state;
  473. continue;
  474. } else if((flags == osFlagsErrorTimeout) || (flags == osFlagsErrorResource)) {
  475. if(delay_val > 0) {
  476. bad_usb->st.delay_remain--;
  477. continue;
  478. }
  479. bad_usb->st.state = BadUsbStateRunning;
  480. delay_val = ducky_script_execute_next(bad_usb, script_file);
  481. if(delay_val == SCRIPT_STATE_ERROR) { // Script error
  482. delay_val = 0;
  483. worker_state = BadUsbStateScriptError;
  484. bad_usb->st.state = worker_state;
  485. } else if(delay_val == SCRIPT_STATE_END) { // End of script
  486. delay_val = 0;
  487. worker_state = BadUsbStateIdle;
  488. bad_usb->st.state = BadUsbStateDone;
  489. furi_hal_hid_kb_release_all();
  490. continue;
  491. } else if(delay_val > 1000) {
  492. bad_usb->st.state = BadUsbStateDelay; // Show long delays
  493. bad_usb->st.delay_remain = delay_val / 1000;
  494. }
  495. } else {
  496. furi_check((flags & osFlagsError) == 0);
  497. }
  498. } else if(
  499. (worker_state == BadUsbStateFileError) ||
  500. (worker_state == BadUsbStateScriptError)) { // State: error
  501. uint32_t flags = furi_thread_flags_wait(
  502. WorkerEvtEnd, osFlagsWaitAny, osWaitForever); // Waiting for exit command
  503. furi_check((flags & osFlagsError) == 0);
  504. if(flags & WorkerEvtEnd) {
  505. break;
  506. }
  507. }
  508. }
  509. furi_hal_hid_set_state_callback(NULL, NULL);
  510. furi_hal_usb_set_config(usb_mode_prev, NULL);
  511. storage_file_close(script_file);
  512. storage_file_free(script_file);
  513. string_clear(bad_usb->line);
  514. string_clear(bad_usb->line_prev);
  515. FURI_LOG_I(WORKER_TAG, "End");
  516. return 0;
  517. }
  518. BadUsbScript* bad_usb_script_open(string_t file_path) {
  519. furi_assert(file_path);
  520. BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript));
  521. string_init(bad_usb->file_path);
  522. string_set(bad_usb->file_path, file_path);
  523. bad_usb->st.state = BadUsbStateInit;
  524. bad_usb->thread = furi_thread_alloc();
  525. furi_thread_set_name(bad_usb->thread, "BadUsbWorker");
  526. furi_thread_set_stack_size(bad_usb->thread, 2048);
  527. furi_thread_set_context(bad_usb->thread, bad_usb);
  528. furi_thread_set_callback(bad_usb->thread, bad_usb_worker);
  529. furi_thread_start(bad_usb->thread);
  530. return bad_usb;
  531. }
  532. void bad_usb_script_close(BadUsbScript* bad_usb) {
  533. furi_assert(bad_usb);
  534. furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtEnd);
  535. furi_thread_join(bad_usb->thread);
  536. furi_thread_free(bad_usb->thread);
  537. string_clear(bad_usb->file_path);
  538. free(bad_usb);
  539. }
  540. void bad_usb_script_toggle(BadUsbScript* bad_usb) {
  541. furi_assert(bad_usb);
  542. furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtToggle);
  543. }
  544. BadUsbState* bad_usb_script_get_state(BadUsbScript* bad_usb) {
  545. furi_assert(bad_usb);
  546. return &(bad_usb->st);
  547. }