fake_worker.c 14 KB

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