fake_worker.c 15 KB

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