fake_worker.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. #include "fake_worker.h"
  2. #include "helpers/hardware_worker.h"
  3. #include "protocol_i.h"
  4. #include <timer.h>
  5. #include <lib/toolbox/hex.h>
  6. #include <toolbox/stream/stream.h>
  7. #include <toolbox/stream/buffered_file_stream.h>
  8. #define TAG "Fuzzer worker"
  9. #define TOTAL_PROTOCOL_COUNT fuzzer_proto_get_count_of_protocols()
  10. typedef uint8_t FuzzerWorkerPayload[MAX_PAYLOAD_SIZE];
  11. struct FuzzerWorker {
  12. HardwareWorker* hw_worker;
  13. const FuzzerProtocol* protocol;
  14. HwProtocolID* suported_proto;
  15. FuzzerWorkerPayload payload;
  16. FuzzerWorkerAttackType attack_type;
  17. uint16_t index;
  18. Stream* uids_stream;
  19. uint8_t chusen_byte;
  20. bool treead_running;
  21. bool in_emu_phase;
  22. FuriTimer* timer;
  23. uint16_t timer_idle_time_ms;
  24. uint16_t timer_emu_time_ms;
  25. FuzzerWorkerUidChagedCallback tick_callback;
  26. void* tick_context;
  27. FuzzerWorkerEndCallback end_callback;
  28. void* end_context;
  29. };
  30. static bool fuzzer_worker_set_protocol(FuzzerWorker* instance, FuzzerProtocolsID protocol_index) {
  31. if(!(protocol_index < TOTAL_PROTOCOL_COUNT)) {
  32. return false;
  33. }
  34. instance->protocol = &fuzzer_proto_items[protocol_index];
  35. return hardware_worker_set_protocol_id_by_name(
  36. instance->hw_worker, fuzzer_proto_items[protocol_index].name);
  37. }
  38. static FuzzerProtocolsID
  39. fuzzer_worker_is_protocol_valid(FuzzerWorker* instance, HwProtocolID protocol_id) {
  40. for(FuzzerProtocolsID i = 0; i < TOTAL_PROTOCOL_COUNT; i++) {
  41. if(protocol_id == instance->suported_proto[i]) {
  42. return i;
  43. }
  44. }
  45. return TOTAL_PROTOCOL_COUNT;
  46. }
  47. FuzzerWorkerLoadKeyState fuzzer_worker_load_key_from_file(
  48. FuzzerWorker* instance,
  49. FuzzerProtocolsID* protocol_index,
  50. const char* filename) {
  51. furi_assert(instance);
  52. FuzzerWorkerLoadKeyState res = FuzzerWorkerLoadKeyStateUnsuportedProto;
  53. if(!hardware_worker_load_key_from_file(instance->hw_worker, filename)) {
  54. FURI_LOG_E(TAG, "Load key file: cant load file");
  55. res = FuzzerWorkerLoadKeyStateBadFile;
  56. } else {
  57. FuzzerProtocolsID loaded_id = fuzzer_worker_is_protocol_valid(
  58. instance, hardware_worker_get_protocol_id(instance->hw_worker));
  59. if(!fuzzer_worker_set_protocol(instance, loaded_id)) {
  60. FURI_LOG_E(TAG, "Load key file: Unsuported protocol");
  61. res = FuzzerWorkerLoadKeyStateUnsuportedProto;
  62. } else {
  63. if(*protocol_index != loaded_id) {
  64. res = FuzzerWorkerLoadKeyStateDifferentProto;
  65. } else {
  66. res = FuzzerWorkerLoadKeyStateOk;
  67. }
  68. *protocol_index = loaded_id;
  69. hardware_worker_get_protocol_data(
  70. instance->hw_worker, &instance->payload[0], MAX_PAYLOAD_SIZE);
  71. }
  72. }
  73. return res;
  74. }
  75. static bool fuzzer_worker_load_key(FuzzerWorker* instance, bool next) {
  76. furi_assert(instance);
  77. furi_assert(instance->protocol);
  78. bool res = false;
  79. const FuzzerProtocol* protocol = instance->protocol;
  80. switch(instance->attack_type) {
  81. case FuzzerWorkerAttackTypeDefaultDict:
  82. if(next) {
  83. if(instance->index < (protocol->dict.len - 1)) {
  84. instance->index++;
  85. } else {
  86. break;
  87. }
  88. }
  89. if(instance->index < protocol->dict.len) {
  90. memcpy(
  91. instance->payload,
  92. &protocol->dict.val[instance->index * protocol->data_size],
  93. protocol->data_size);
  94. res = true;
  95. }
  96. break;
  97. case FuzzerWorkerAttackTypeLoadFileCustomUids: {
  98. if(next) {
  99. instance->index++;
  100. }
  101. uint8_t str_len = protocol->data_size * 2 + 1;
  102. FuriString* data_str = furi_string_alloc();
  103. while(true) {
  104. furi_string_reset(data_str);
  105. if(!stream_read_line(instance->uids_stream, data_str)) {
  106. stream_rewind(instance->uids_stream);
  107. // TODO Check empty file & close stream and storage
  108. break;
  109. } else if(furi_string_get_char(data_str, 0) == '#') {
  110. // Skip comment string
  111. continue;
  112. } else if(furi_string_size(data_str) != str_len) {
  113. // Ignore strin with bad length
  114. FURI_LOG_W(TAG, "Bad string length");
  115. continue;
  116. } else {
  117. FURI_LOG_D(TAG, "Uid candidate: \"%s\"", furi_string_get_cstr(data_str));
  118. bool parse_ok = true;
  119. for(uint8_t i = 0; i < protocol->data_size; i++) {
  120. if(!hex_char_to_uint8(
  121. furi_string_get_cstr(data_str)[i * 2],
  122. furi_string_get_cstr(data_str)[i * 2 + 1],
  123. &instance->payload[i])) {
  124. parse_ok = false;
  125. break;
  126. }
  127. }
  128. res = parse_ok;
  129. }
  130. break;
  131. }
  132. }
  133. break;
  134. case FuzzerWorkerAttackTypeLoadFile:
  135. if(instance->payload[instance->index] != 0xFF) {
  136. instance->payload[instance->index]++;
  137. res = true;
  138. }
  139. break;
  140. default:
  141. break;
  142. }
  143. if(res) {
  144. hardware_worker_set_protocol_data(
  145. instance->hw_worker, &instance->payload[0], protocol->data_size);
  146. }
  147. return res;
  148. }
  149. static bool fuzzer_worker_load_previous_key(FuzzerWorker* instance) {
  150. furi_assert(instance);
  151. furi_assert(instance->protocol);
  152. bool res = false;
  153. const FuzzerProtocol* protocol = instance->protocol;
  154. switch(instance->attack_type) {
  155. case FuzzerWorkerAttackTypeDefaultDict:
  156. if(instance->index > 0) {
  157. instance->index--;
  158. memcpy(
  159. instance->payload,
  160. &protocol->dict.val[instance->index * protocol->data_size],
  161. protocol->data_size);
  162. res = true;
  163. }
  164. break;
  165. case FuzzerWorkerAttackTypeLoadFile:
  166. if(instance->payload[instance->index] != 0x00) {
  167. instance->payload[instance->index]--;
  168. res = true;
  169. }
  170. break;
  171. default:
  172. break;
  173. }
  174. if(res) {
  175. hardware_worker_set_protocol_data(
  176. instance->hw_worker, &instance->payload[0], protocol->data_size);
  177. }
  178. return res;
  179. }
  180. static void fuzzer_worker_on_tick_callback(void* context) {
  181. furi_assert(context);
  182. FuzzerWorker* instance = context;
  183. if(instance->in_emu_phase) {
  184. if(instance->treead_running) {
  185. hardware_worker_stop(instance->hw_worker);
  186. }
  187. instance->in_emu_phase = false;
  188. furi_timer_start(instance->timer, furi_ms_to_ticks(instance->timer_idle_time_ms));
  189. } else {
  190. if(!fuzzer_worker_load_key(instance, true)) {
  191. fuzzer_worker_pause(instance); // XXX
  192. if(instance->end_callback) {
  193. instance->end_callback(instance->end_context);
  194. }
  195. } else {
  196. if(instance->treead_running) {
  197. hardware_worker_emulate_start(instance->hw_worker);
  198. }
  199. instance->in_emu_phase = true;
  200. furi_timer_start(instance->timer, furi_ms_to_ticks(instance->timer_emu_time_ms));
  201. if(instance->tick_callback) {
  202. instance->tick_callback(instance->tick_context);
  203. }
  204. }
  205. }
  206. }
  207. void fuzzer_worker_get_current_key(FuzzerWorker* instance, FuzzerPayload* output_key) {
  208. furi_assert(instance);
  209. furi_assert(output_key);
  210. furi_assert(instance->protocol);
  211. output_key->data_size = instance->protocol->data_size;
  212. memcpy(output_key->data, instance->payload, instance->protocol->data_size);
  213. }
  214. bool fuzzer_worker_next_key(FuzzerWorker* instance) {
  215. furi_assert(instance);
  216. furi_assert(instance->protocol);
  217. return fuzzer_worker_load_key(instance, true);
  218. }
  219. bool fuzzer_worker_previous_key(FuzzerWorker* instance) {
  220. furi_assert(instance);
  221. furi_assert(instance->protocol);
  222. return fuzzer_worker_load_previous_key(instance);
  223. }
  224. bool fuzzer_worker_init_attack_dict(FuzzerWorker* instance, FuzzerProtocolsID protocol_index) {
  225. furi_assert(instance);
  226. bool res = false;
  227. if(!fuzzer_worker_set_protocol(instance, protocol_index)) {
  228. instance->attack_type = FuzzerWorkerAttackTypeMax;
  229. return res;
  230. }
  231. instance->attack_type = FuzzerWorkerAttackTypeDefaultDict;
  232. instance->index = 0;
  233. if(!fuzzer_worker_load_key(instance, false)) {
  234. instance->attack_type = FuzzerWorkerAttackTypeMax;
  235. } else {
  236. res = true;
  237. }
  238. return res;
  239. }
  240. bool fuzzer_worker_init_attack_file_dict(
  241. FuzzerWorker* instance,
  242. FuzzerProtocolsID protocol_index,
  243. FuriString* file_path) {
  244. furi_assert(instance);
  245. furi_assert(file_path);
  246. bool res = false;
  247. if(!fuzzer_worker_set_protocol(instance, protocol_index)) {
  248. instance->attack_type = FuzzerWorkerAttackTypeMax;
  249. return res;
  250. }
  251. Storage* storage = furi_record_open(RECORD_STORAGE);
  252. instance->uids_stream = buffered_file_stream_alloc(storage);
  253. if(!buffered_file_stream_open(
  254. instance->uids_stream, furi_string_get_cstr(file_path), FSAM_READ, FSOM_OPEN_EXISTING)) {
  255. buffered_file_stream_close(instance->uids_stream);
  256. return res;
  257. }
  258. instance->attack_type = FuzzerWorkerAttackTypeLoadFileCustomUids;
  259. instance->index = 0;
  260. if(!fuzzer_worker_load_key(instance, false)) {
  261. instance->attack_type = FuzzerWorkerAttackTypeMax;
  262. buffered_file_stream_close(instance->uids_stream);
  263. furi_record_close(RECORD_STORAGE);
  264. } else {
  265. res = true;
  266. }
  267. return res;
  268. }
  269. bool fuzzer_worker_init_attack_bf_byte(
  270. FuzzerWorker* instance,
  271. FuzzerProtocolsID protocol_index,
  272. const FuzzerPayload* new_uid,
  273. uint8_t chusen) {
  274. furi_assert(instance);
  275. bool res = false;
  276. if(!fuzzer_worker_set_protocol(instance, protocol_index)) {
  277. instance->attack_type = FuzzerWorkerAttackTypeMax;
  278. return res;
  279. }
  280. instance->attack_type = FuzzerWorkerAttackTypeLoadFile;
  281. instance->index = chusen;
  282. memcpy(instance->payload, new_uid->data, instance->protocol->data_size);
  283. hardware_worker_set_protocol_data(
  284. instance->hw_worker, &instance->payload[0], instance->protocol->data_size);
  285. return true;
  286. }
  287. FuzzerWorker* fuzzer_worker_alloc() {
  288. FuzzerWorker* instance = malloc(sizeof(FuzzerWorker));
  289. instance->hw_worker = hardware_worker_alloc();
  290. instance->suported_proto = malloc(sizeof(HwProtocolID) * TOTAL_PROTOCOL_COUNT);
  291. for(uint8_t i = 0; i < TOTAL_PROTOCOL_COUNT; i++) {
  292. if(!hardware_worker_set_protocol_id_by_name(
  293. instance->hw_worker, fuzzer_proto_items[i].name)) {
  294. // Check protocol support
  295. FURI_LOG_E(TAG, "Not supported protocol name: %s", fuzzer_proto_items[i].name);
  296. furi_crash("Not supported protocol name");
  297. } else {
  298. instance->suported_proto[i] = hardware_worker_get_protocol_id(instance->hw_worker);
  299. FURI_LOG_D(
  300. TAG,
  301. "%u: %15s Protocol_id: %lu",
  302. i + 1,
  303. fuzzer_proto_items[i].name,
  304. instance->suported_proto[i]);
  305. }
  306. }
  307. instance->attack_type = FuzzerWorkerAttackTypeMax;
  308. instance->index = 0;
  309. instance->treead_running = false;
  310. instance->in_emu_phase = false;
  311. memset(instance->payload, 0x00, sizeof(instance->payload));
  312. instance->timer_idle_time_ms = PROTOCOL_DEF_IDLE_TIME * 100;
  313. instance->timer_emu_time_ms = PROTOCOL_DEF_EMU_TIME * 100;
  314. instance->timer =
  315. furi_timer_alloc(fuzzer_worker_on_tick_callback, FuriTimerTypeOnce, instance);
  316. return instance;
  317. }
  318. void fuzzer_worker_free(FuzzerWorker* instance) {
  319. furi_assert(instance);
  320. fuzzer_worker_stop(instance);
  321. furi_timer_free(instance->timer);
  322. free(instance->suported_proto);
  323. hardware_worker_free(instance->hw_worker);
  324. free(instance);
  325. }
  326. bool fuzzer_worker_start(FuzzerWorker* instance, uint8_t idle_time, uint8_t emu_time) {
  327. furi_assert(instance);
  328. if(instance->attack_type < FuzzerWorkerAttackTypeMax) {
  329. if(idle_time == 0) {
  330. instance->timer_idle_time_ms = 10;
  331. } else {
  332. instance->timer_idle_time_ms = idle_time * 100;
  333. }
  334. if(emu_time == 0) {
  335. instance->timer_emu_time_ms = 10;
  336. } else {
  337. instance->timer_emu_time_ms = emu_time * 100;
  338. }
  339. FURI_LOG_D(
  340. TAG,
  341. "Emu_time %u ms Idle_time %u ms",
  342. instance->timer_emu_time_ms,
  343. instance->timer_idle_time_ms);
  344. if(!instance->treead_running) {
  345. hardware_worker_start_thread(instance->hw_worker);
  346. FURI_LOG_D(TAG, "Worker Starting");
  347. instance->treead_running = true;
  348. } else {
  349. FURI_LOG_D(TAG, "Worker UnPaused");
  350. }
  351. hardware_worker_emulate_start(instance->hw_worker);
  352. instance->in_emu_phase = true;
  353. furi_timer_start(instance->timer, furi_ms_to_ticks(instance->timer_emu_time_ms));
  354. return true;
  355. }
  356. return false;
  357. }
  358. void fuzzer_worker_start_emulate(FuzzerWorker* instance) {
  359. furi_assert(instance);
  360. if(!instance->treead_running) {
  361. hardware_worker_start_thread(instance->hw_worker);
  362. FURI_LOG_D(TAG, "Worker Starting");
  363. instance->treead_running = true;
  364. } else {
  365. FURI_LOG_D(TAG, "Worker UnPaused");
  366. }
  367. hardware_worker_emulate_start(instance->hw_worker);
  368. }
  369. void fuzzer_worker_pause(FuzzerWorker* instance) {
  370. furi_assert(instance);
  371. furi_timer_stop(instance->timer);
  372. if(instance->treead_running) {
  373. hardware_worker_stop(instance->hw_worker);
  374. FURI_LOG_D(TAG, "Worker Paused");
  375. }
  376. }
  377. void fuzzer_worker_stop(FuzzerWorker* instance) {
  378. furi_assert(instance);
  379. furi_timer_stop(instance->timer);
  380. if(instance->treead_running) {
  381. hardware_worker_stop_thread(instance->hw_worker);
  382. FURI_LOG_D(TAG, "Worker Stopping");
  383. instance->treead_running = false;
  384. }
  385. if(instance->attack_type == FuzzerWorkerAttackTypeLoadFileCustomUids) {
  386. buffered_file_stream_close(instance->uids_stream);
  387. furi_record_close(RECORD_STORAGE);
  388. instance->attack_type = FuzzerWorkerAttackTypeMax;
  389. }
  390. // TODO anything else
  391. }
  392. void fuzzer_worker_set_uid_chaged_callback(
  393. FuzzerWorker* instance,
  394. FuzzerWorkerUidChagedCallback callback,
  395. void* context) {
  396. furi_assert(instance);
  397. instance->tick_callback = callback;
  398. instance->tick_context = context;
  399. }
  400. void fuzzer_worker_set_end_callback(
  401. FuzzerWorker* instance,
  402. FuzzerWorkerEndCallback callback,
  403. void* context) {
  404. furi_assert(instance);
  405. instance->end_callback = callback;
  406. instance->end_context = context;
  407. }