From d4fa97039f71fe073a3ee5af85b81bdee662de57 Mon Sep 17 00:00:00 2001 From: W0rthlessS0ul Date: Mon, 16 Jun 2025 19:01:49 +0300 Subject: [PATCH] Added WiFi jammer --- jammer.c | 263 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 191 insertions(+), 72 deletions(-) diff --git a/jammer.c b/jammer.c index 12a1be5..b525c9e 100644 --- a/jammer.c +++ b/jammer.c @@ -20,13 +20,13 @@ #define TAG "jammer" -#define MARGIN_LEFT 5 -#define MARGIN_TOP 5 -#define MARGIN_BOT 5 +#define MARGIN_LEFT 5 +#define MARGIN_TOP 5 +#define MARGIN_BOT 5 #define MARGIN_RIGHT 5 -#define KEY_WIDTH 5 -#define KEY_HEIGHT 10 -#define KEY_PADDING 2 +#define KEY_WIDTH 5 +#define KEY_HEIGHT 10 +#define KEY_PADDING 2 typedef struct { FuriMutex* mutex; @@ -34,7 +34,8 @@ typedef struct { bool is_nrf24_connected; bool close_thread_please; bool select_file_on_next_render; - uint8_t jam_type; // 0:narrow, 1:wide, 2:all, 3:custom + uint8_t wifi_channel; + uint8_t jam_type; // 0:narrow, 1:wide, 2:all, 3:WiFi, 4:custom FuriThread* jam_thread; } PluginState; @@ -50,51 +51,52 @@ typedef struct { // various types of hopping I empirically found uint8_t hopping_channels_2[128]; -uint8_t hopping_channels_1[] = {32,34, 46,48, 50, 52, 0, 1, 2, 4, 6, 8, 22, 24, 26, 28, 30, 74, 76, 78, 80, 82, 84,86 }; +uint8_t hopping_channels_1[] = {32, 34, 46, 48, 50, 52, 0, 1, 2, 4, 6, 8, + 22, 24, 26, 28, 30, 74, 76, 78, 80, 82, 84, 86}; uint8_t hopping_channels_0[] = {2, 26, 80}; -uint8_t hopping_channels_len[] = {3, 24, 42, 0}; +uint8_t hopping_channels_3[] = {12, 17, 22, 27, 32, 37, 42, 47, 52, 57, 62, 67, 72}; +uint8_t hopping_channels_len[] = {3, 24, 42, 12, 0}; - -int parse_custom_list(char *input, uint8_t **out_arr) { +int parse_custom_list(char* input, uint8_t** out_arr) { // Make a copy of the input string, because strtok modifies it - char *temp = strdup(input); - if (!temp) { + char* temp = strdup(input); + if(!temp) { *out_arr = NULL; return 0; } // First pass: count how many integers we have (commas + 1) int count = 0; - for (int i = 0; temp[i] != '\0'; i++) { - if (temp[i] == ',') { + for(int i = 0; temp[i] != '\0'; i++) { + if(temp[i] == ',') { count++; } } - count++; // one more than number of commas + count++; // one more than number of commas // Allocate the array - *out_arr = (uint8_t *)malloc(count * sizeof(uint8_t)); - if (!(*out_arr)) { + *out_arr = (uint8_t*)malloc(count * sizeof(uint8_t)); + if(!(*out_arr)) { free(temp); return 0; // allocation failed } // Second pass: tokenize and parse int index = 0; - char *token = strtok(temp, ","); - while (token != NULL) { - (*out_arr)[index++] = (uint8_t) atoi(token); + char* token = strtok(temp, ","); + while(token != NULL) { + (*out_arr)[index++] = (uint8_t)atoi(token); token = strtok(NULL, ","); } free(temp); - return count; // number of integers parsed + return count; // number of integers parsed } -char *jam_types[] = {"narrow", "wide", "full", "custom"}; -uint8_t *hopping_channels; +char* jam_types[] = {"narrow", "wide", "full", "WiFi", "custom"}; +uint8_t* hopping_channels; int hopping_channels_custom_len = 0; -uint8_t *hopping_channels_custom_arr = NULL; +uint8_t* hopping_channels_custom_arr = NULL; static void render_callback(Canvas* const canvas, void* ctx) { furi_assert(ctx); @@ -107,27 +109,35 @@ static void render_callback(Canvas* const canvas, void* ctx) { canvas_set_font(canvas, FontSecondary); char tmp[128]; - snprintf(tmp, 128, "^ type:%s", jam_types[plugin_state->jam_type]); + if(plugin_state->jam_type == 3) + snprintf( + tmp, + 128, + "^ type:%s > channel:%d", + jam_types[plugin_state->jam_type], + plugin_state->wifi_channel + 1); + else + snprintf(tmp, 128, "^ type:%s", jam_types[plugin_state->jam_type]); canvas_draw_str_aligned(canvas, 10, 3, AlignLeft, AlignTop, tmp); - if(!plugin_state->is_thread_running && plugin_state->jam_type <= 3) { + if(!plugin_state->is_thread_running && plugin_state->jam_type <= 4) { canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned(canvas, 10, 20, AlignLeft, AlignBottom, "Press Ok button to start"); - - if (plugin_state->jam_type == 3) { - canvas_draw_str(canvas, 80, 30, "select file >"); + canvas_draw_str_aligned( + canvas, 10, 20, AlignLeft, AlignBottom, "Press Ok button to start"); + + if(plugin_state->jam_type == 4) { + canvas_draw_str(canvas, 80, 30, "select file >"); } - + if(!plugin_state->is_nrf24_connected) { canvas_draw_str_aligned( canvas, 10, 30, AlignLeft, AlignBottom, "Connect NRF24 to GPIO!"); } - } else if(plugin_state->is_thread_running && plugin_state->jam_type <= 3) { + } else if(plugin_state->is_thread_running && plugin_state->jam_type <= 4) { canvas_set_font(canvas, FontSecondary); canvas_draw_str_aligned(canvas, 3, 30, AlignLeft, AlignBottom, "Causing mayhem..."); canvas_draw_str_aligned(canvas, 3, 40, AlignLeft, AlignBottom, "Please wait!"); - canvas_draw_str_aligned( - canvas, 3, 50, AlignLeft, AlignBottom, "Press back to exit."); + canvas_draw_str_aligned(canvas, 3, 50, AlignLeft, AlignBottom, "Press back to exit."); } else { canvas_draw_str_aligned(canvas, 3, 10, AlignLeft, AlignBottom, "Unknown Error"); canvas_draw_str_aligned(canvas, 3, 20, AlignLeft, AlignBottom, "press back"); @@ -135,9 +145,9 @@ static void render_callback(Canvas* const canvas, void* ctx) { } uint8_t limit = hopping_channels_len[plugin_state->jam_type]; canvas_draw_frame(canvas, 0, 52, 128, 13); - if (limit > 0) { + if(limit > 0) { for(int i = 0; i < limit; i++) { - canvas_draw_line(canvas, hopping_channels[i]+1, 53, hopping_channels[i]+1, 64); + canvas_draw_line(canvas, hopping_channels[i] + 1, 53, hopping_channels[i] + 1, 64); } } //furi_mutex_release(plugin_state->mutex); @@ -158,24 +168,71 @@ static void jammer_state_init(PluginState* const plugin_state) { static int32_t mj_worker_thread(void* ctx) { PluginState* plugin_state = ctx; plugin_state->is_thread_running = true; + +#define size 32 + uint8_t tx[size + 1] = {0}; + FURI_LOG_D(TAG, "Starting optimized carrier jamming"); - + + if(plugin_state->jam_type == 3) { + char tmp[128]; + + nrf24_set_idle(nrf24_HANDLE); + + uint8_t mac[] = {0xDE, 0xAD}; // DEAD BEEF FEED + + uint8_t ping_packet[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, + 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, + 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF}; + + nrf24_configure(nrf24_HANDLE, 2, mac, mac, 2, 1, true, true); + + uint8_t setup; + nrf24_read_reg(nrf24_HANDLE, REG_RF_SETUP, &setup, 1); + setup = (setup & 0xF8) | 7; + nrf24_write_reg(nrf24_HANDLE, REG_RF_SETUP, setup); + + uint8_t conf; + nrf24_read_reg(nrf24_HANDLE, REG_CONFIG, &conf, 1); + snprintf(tmp, sizeof(tmp), "NRF24 SETUP REGISTER: %d", setup); + FURI_LOG_D(TAG, tmp); + snprintf(tmp, sizeof(tmp), "NRF24 CONFIG REGISTER: %d", conf); + FURI_LOG_D(TAG, tmp); + + tx[0] = W_TX_PAYLOAD_NOACK; + memcpy(&tx[1], ping_packet, size); + +#define nrf24_TIMEOUT 500 + nrf24_spi_trx(nrf24_HANDLE, tx, 0, size + 1, nrf24_TIMEOUT); + nrf24_set_tx_mode(nrf24_HANDLE); + } + NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); notification_message(notification, &sequence_blink_red_100); - nrf24_startConstCarrier(nrf24_HANDLE, 3, hopping_channels[0]); - + if(plugin_state->jam_type != 3) nrf24_startConstCarrier(nrf24_HANDLE, 3, hopping_channels[0]); + uint8_t current_channel = 0; uint8_t limit = hopping_channels_len[plugin_state->jam_type]; - + while(!plugin_state->close_thread_please) { for(int ch = 0; ch < limit && !plugin_state->close_thread_please; ch++) { current_channel = hopping_channels[ch]; - nrf24_write_reg(nrf24_HANDLE, REG_RF_CH, current_channel); + if(plugin_state->jam_type == 3) { + for(int wifi_ch = hopping_channels_3[plugin_state->wifi_channel]; + wifi_ch < hopping_channels_3[plugin_state->wifi_channel + 6] && + !plugin_state->close_thread_please; + wifi_ch++) { + nrf24_write_reg(nrf24_HANDLE, REG_RF_CH, wifi_ch); + nrf24_spi_trx(nrf24_HANDLE, tx, 0, 3, nrf24_TIMEOUT); + } + } else + nrf24_write_reg(nrf24_HANDLE, REG_RF_CH, current_channel); } } - - nrf24_stopConstCarrier(nrf24_HANDLE); + + if(plugin_state->jam_type != 3) nrf24_stopConstCarrier(nrf24_HANDLE); + furi_record_close(RECORD_NOTIFICATION); plugin_state->is_thread_running = false; return 0; @@ -189,6 +246,7 @@ int32_t jammer_app(void* p) { PluginState* plugin_state = malloc(sizeof(PluginState)); jammer_state_init(plugin_state); plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); + plugin_state->wifi_channel = 0; if(!plugin_state->mutex) { FURI_LOG_E("jammer", "cannot create mutex\r\n"); furi_message_queue_free(event_queue); @@ -216,7 +274,8 @@ int32_t jammer_app(void* p) { nrf24_init(); FURI_LOG_D(TAG, "nrf24 init done!"); PluginEvent event; - for(int i = 0; i < 128; i++) hopping_channels_2[i] = i*2; + for(int i = 0; i < 128; i++) + hopping_channels_2[i] = i * 2; hopping_channels = hopping_channels_0; plugin_state->is_nrf24_connected = true; if(!nrf24_check_connected(nrf24_HANDLE)) { @@ -225,7 +284,6 @@ int32_t jammer_app(void* p) { for(bool processing = true; processing;) { FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - if(event_status == FuriStatusOk) { // press events if(event.type == EventTypeKey) { @@ -234,24 +292,60 @@ int32_t jammer_app(void* p) { switch(event.input.key) { case InputKeyUp: - if(!plugin_state -> is_thread_running) { - plugin_state->jam_type = (plugin_state->jam_type + 1) % 4; - + if(!plugin_state->is_thread_running) { + plugin_state->jam_type = (plugin_state->jam_type + 1) % 5; + switch(plugin_state->jam_type) { - case 0: hopping_channels = hopping_channels_0; break; - case 1: hopping_channels = hopping_channels_1; break; - case 2: hopping_channels = hopping_channels_2; break; - case 3: hopping_channels = hopping_channels_custom_arr; - default: break; + case 0: + hopping_channels = hopping_channels_0; + break; + case 1: + hopping_channels = hopping_channels_1; + break; + case 2: + hopping_channels = hopping_channels_2; + break; + case 3: + hopping_channels = hopping_channels_3; + break; + case 4: + hopping_channels = hopping_channels_custom_arr; + default: + break; } view_port_update(view_port); } break; case InputKeyDown: + if(!plugin_state->is_thread_running) { + plugin_state->jam_type = + (plugin_state->jam_type == 0) ? 4 : (plugin_state->jam_type - 1); + + switch(plugin_state->jam_type) { + case 0: + hopping_channels = hopping_channels_0; + break; + case 1: + hopping_channels = hopping_channels_1; + break; + case 2: + hopping_channels = hopping_channels_2; + break; + case 3: + hopping_channels = hopping_channels_3; + break; + case 4: + hopping_channels = hopping_channels_custom_arr; + default: + break; + } + + view_port_update(view_port); + } break; case InputKeyRight: - if(plugin_state->jam_type == 3) { + if(plugin_state->jam_type == 4 && !plugin_state->is_thread_running) { DialogsApp* dialogs = furi_record_open("dialogs"); Storage* storage = furi_record_open(RECORD_STORAGE); plugin_state->select_file_on_next_render = true; @@ -261,15 +355,24 @@ int32_t jammer_app(void* p) { path = furi_string_alloc(); furi_string_set(path, "/ext/"); DialogsFileBrowserOptions browser_options; - dialog_file_browser_set_basic_options(&browser_options, ".txt", &I_badusb_10px); + dialog_file_browser_set_basic_options( + &browser_options, ".txt", &I_badusb_10px); browser_options.hide_ext = false; browser_options.base_path = "/ext/"; furi_delay_ms(1000); - bool ret = dialog_file_browser_show(dialogs, path, path, &browser_options); + bool ret = + dialog_file_browser_show(dialogs, path, path, &browser_options); furi_record_close("dialogs"); if(ret) { - if(!file_stream_open(file_stream, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { - FURI_LOG_D(TAG, "Cannot open file \"%s\"", furi_string_get_cstr(path)); + if(!file_stream_open( + file_stream, + furi_string_get_cstr(path), + FSAM_READ, + FSOM_OPEN_EXISTING)) { + FURI_LOG_D( + TAG, + "Cannot open file \"%s\"", + furi_string_get_cstr(path)); } else { size_t file_size = 0; size_t bytes_read = 0; @@ -281,11 +384,18 @@ int32_t jammer_app(void* p) { bytes_read = stream_read(file_stream, file_buf, file_size); if(bytes_read == file_size) { FURI_LOG_I(TAG, "read file"); - hopping_channels_custom_len = parse_custom_list((char *)file_buf, &hopping_channels_custom_arr); + hopping_channels_custom_len = parse_custom_list( + (char*)file_buf, &hopping_channels_custom_arr); - FURI_LOG_D(TAG, "Length: %d\n", hopping_channels_custom_len); // e.g. 6 - for (int i = 0; i < hopping_channels_custom_len; i++) { - FURI_LOG_D(TAG, "%d ", hopping_channels_custom_arr[i]); // 1 2 3 4 1 2 + FURI_LOG_D( + TAG, + "Length: %d\n", + hopping_channels_custom_len); // e.g. 6 + for(int i = 0; i < hopping_channels_custom_len; i++) { + FURI_LOG_D( + TAG, + "%d ", + hopping_channels_custom_arr[i]); // 1 2 3 4 1 2 } hopping_channels_len[3] = hopping_channels_custom_len; hopping_channels = hopping_channels_custom_arr; @@ -298,15 +408,25 @@ int32_t jammer_app(void* p) { } } furi_string_free(path); - + + view_port_update(view_port); + } else if(plugin_state->jam_type == 3 && !plugin_state->is_thread_running) { + plugin_state->wifi_channel = (plugin_state->wifi_channel + 1) % 13; view_port_update(view_port); } break; case InputKeyLeft: + if(plugin_state->jam_type == 3 && !plugin_state->is_thread_running) { + plugin_state->wifi_channel = (plugin_state->wifi_channel == 0) ? + 12 : + (plugin_state->wifi_channel - 1); + view_port_update(view_port); + } break; case InputKeyOk: if(!plugin_state->is_thread_running) { - if(!nrf24_check_connected(nrf24_HANDLE)) { + if(!nrf24_check_connected(nrf24_HANDLE) || + !plugin_state->is_nrf24_connected) { plugin_state->is_nrf24_connected = false; notification_message(notification, &sequence_error); } else { @@ -314,30 +434,29 @@ int32_t jammer_app(void* p) { } view_port_update(view_port); } - + break; case InputKeyBack: FURI_LOG_D(TAG, "terminating thread..."); if(!plugin_state->is_thread_running) processing = false; plugin_state->close_thread_please = true; - + if(plugin_state->is_thread_running && plugin_state->jam_thread) { plugin_state->is_thread_running = false; - furi_thread_join(plugin_state->jam_thread); // wait until thread is finished + furi_thread_join( + plugin_state->jam_thread); // wait until thread is finished view_port_update(view_port); } plugin_state->close_thread_please = false; - + break; default: break; } - - //view_port_update(view_port); + //view_port_update(view_port); } - } }