fake_worker.c 15 KB

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