Releases: tworjaga/ESP32Gotchi
v1.1.0 - Architecture Overhaul & Bug Fix Release
v1.1.0 — Architecture Overhaul & Bug Fix Release
This release addresses eight bugs found during a full firmware audit — two of which could cause device lock-up or silent data loss under normal use. No new features. Flash it, move one wire, and it works correctly.
⚠️ Hardware Change Required
Move the button wire from IO0 to IO4.
GPIO0 is the ESP32 boot-mode strapping pin. If it reads LOW when the chip samples strapping pins after a reset (~50 ms post-boot), the ROM enters serial Download Mode instead of starting your firmware — the screen stays black and the device appears bricked until power-cycled. The long-press restart triggers on release, so most users never hit this, but the failure mode is real and reproducible. GPIO4 has no strapping function. One wire. That's it.
Memory Architecture Redesign
The two most consequential bugs were both memory layout problems.
hs_slot_t embedded raw[4][1600] inline. Each handshake slot was 6 430 bytes. With 32 slots, g_hs[] alone consumed 205 KB — nearly the entire user DRAM budget after the Wi-Fi stack. Slots now store four pool-block indices instead. Raw frame bytes live in a dedicated static pool and are released after the PCAP is written. Slot metadata is now ~40 bytes.
The write queue allocated 51 440 bytes and copied frame data three times per capture. write_item_t was a full value-copy of hs_slot_t. The queue now carries a single uint8_t slot index (8 bytes total queue storage). task_write reads g_hs[] directly.
promisc_cb called malloc() on every captured frame. In a busy RF environment this means thousands of variable-size allocations per second. After hours of operation the heap fragments until allocations silently fail and the sniffer goes blind. All packet storage is now handled by two static pools of 32 × 1 600 B blocks, allocated once at boot. Runtime heap allocations: zero.
Bug Fixes
Task priority inversion — task_hop was priority 3, below task_proc at 5. In a dense RF environment the packet queue never drains, task_proc monopolises Core 0, and the channel hopper freezes on a single channel. task_hop is now priority 6 (highest on Core 0). task_write raised from 2 to 4.
Unnecessary mutex on the hot path — g_ap_mutex was acquired on every beacon and data frame to protect a write-write race that cannot occur (task_proc is the only writer of g_aps[]). Removed.
O(N) AP scan — linear memcmp over up to 100 entries, called thousands of times per second. Replaced with a 256-bucket open-addressing hash table. AP lookup is now O(1) average.
EAPOL slot-exhaustion DoS — 32 spoofed EAPOL frames with random source MACs exhaust all tracking slots instantly, blinding the device for 30 seconds, repeating indefinitely. New slot creation is now rate-limited to one per 100 ms. MAX_HS_SLOTS reduced to 16, HS_EXPIRE_MS halved to 15 s.
What Changed at a Glance
| v1.0.0 | v1.1.0 | |
|---|---|---|
| Button pin | GPIO0 |
GPIO4 |
task_hop priority |
3 | 6 |
task_write priority |
2 | 4 |
| Runtime heap allocations | per-packet | 0 |
hs_slot_t size |
6 430 B | ~40 B |
| Write queue allocation | 51 440 B | 8 B |
| AP lookup | O(N) | O(1) |
| HS slot timeout | 30 s | 15 s |
| Max HS slots | 32 | 16 |
Full source and wiring instructions in the README. Compiled and tested on ESP32-WROOM-32 @ 240 MHz, arduino-esp32 2.0.x.
First release v1.0.0
v1.0.0 — Initial Release
First public release of ESP32Gotchi.
Firmware features:
- Passive WPA/WPA2 4-way handshake capture via ESP32 promiscuous mode
- IEEE 802.11-2020 compliant EAPOL parser (messages 1-4)
- Standard libpcap output, opens directly in Wireshark
- Channel hopping across 1-11 (2.4 GHz), 200 ms dwell
- FreeRTOS: 4 tasks, dual-core, dedicated SD write task
- SSD1306 OLED status display
- LED feedback state machine
- SD retry, space check, watchdog
Hardware: ESP32 DevKit V1 + SSD1306 OLED + MicroSD SPI module. ~10 EUR total.
For authorised security research only.