. It gave me an idea to create a module that has some extended capabilities. So I set to work. And spoiler, I made it and it works fine.
Random SSID AP's are neat but the esp can do a lot more (more than I know how to do I'm sure). So I decided to add some features. Since there are 2 GPIO's and two states, I could come up with 4 variations in the actions of that script. So before building or coding anything, I decided what I wanted it to do (without knowing if it was even possible).
First things first. I'm not that good with arduino and this is my first esp8266 project. But there are a lot of examples and truthfully, I'm pretty good a copy/pasting other peoples code and getting it to work how I want. So the code probably isn't the best and definitely isn't pretty. The only coding language I know is bash, so if anything it's probably written in more of a scripting way.
Here's the kicker from the original blog post. That's cool that one esp can do all those fake esp's, but what about more. What about.....8 :). What about.....16 :). Well that's what I decided to do. The module has 8-16 available sockets when plugged in. Here's a picture real quick so you know what it looks like as I continue to talk about it.
The hardest thing to program was the Mimic Mode. This one scans for local access points to mimic. Scan, store, reproduce. But just mimicking isn't good enough. The SSID's need to be slightly different. This is because the exact same SSID's will normally jsut be grouped together. So I came up with a simple way to avoid this from happening for the host machines. Just add spaces. So here's what I did. When broadcasting any of the SSID's, every loop adds a space to teh SSID until it hits the max SSID length. So guest wifi will be guest wifi , guest wifi , guest wifi , guest wifi , etc. Easy for a computer to tell the difference but near impossible to tell for a human.
The GPIO settings. So the ESP (to start up properly) needs the gpio pins set to HIGH to start properly. Opposite from most things Arduino, OFF is HIGH and ON is LOW essentially. If the ESP starts with the GPIO pins LOW, it won't start at all and will end up in flash mode or something else. So in the VOID SETUP section, the modules wait 5 seconds after power on for the GPIO pins to be set, then reads them. One they are read, it sets the parameters for whatever mode is selected.
The relevant code about the Mode selection (the delays were for some watchdog issues that may have been unrelated...):
So by having each pin in a given on/off position, you have 4 modes it can be configured to do. Since mimic mode is the coolest mode, and the pin defaults are HIGH, that's the defaulkt mode if no switches are toggled.
Really that's pretty much it. It can broadcast a crap ton of stuff. It's hard to measure since it overloads most wifi modules I've checked. Like a built in wifi card in a netbook and an external Alfa adapter I checked. Seems that when there' sover 255 AP's available, stuff starts having problems.
Here's a quick video of it in Mimic Mode. There are 5 flashes to set the mode, and then 3 more in Mimic Mode to let all the ESP's finish their scan. The once any broadcasting in any more starts, it flashes the built in Blue LED on and off for each loop. It sends a lot out since it looks steady once started.
And the current code (it ain't pretty) in Arduino IDE. I'm sure it can be better but for a silly project, I'm calling it done:
extern "C" {
#include "user_interface.h"
}
byte channel;
int wifiCount = 0;
int fullPacket;
int switchGPIO0;
int switchGPIO2;
String wifissid;
bool promiscuousMode = false;
bool mimicMode = false;
bool scan = false;
bool randomMode = false;
int randomStart;
bool listMode = false;
char* networkList[] = {"attwifi", "HomeNetwork", "Starbucks", "guest", "ATT_8765", "Beaches", "Seagulls" };
bool staticMode = false;
String staticNet = "¯\\_(ツ)_/¯";
void setup() {
delay(1);
WiFi.mode(WIFI_STA);
// Initialize the LED_BUILTIN pin as an output
pinMode(LED_BUILTIN, OUTPUT);
// Initialize the GPIO pins as inputs
pinMode(0, INPUT);
pinMode(2, INPUT);
// Wait 5 seconds to set switches
for (int i = 0; i < 5; ++i)
{
digitalWrite(LED_BUILTIN, LOW);
delay(500);
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
}
// Check the GPIO config set up and determine the operation mode being used
switchGPIO0 = digitalRead(0);
switchGPIO2 = digitalRead(2);
delay(1);
if (switchGPIO0 == HIGH && switchGPIO2 == HIGH)
{
mimicMode = true;
scan = true;
delay(1);
}
else if (switchGPIO0 == LOW && switchGPIO2 == HIGH)
{
randomMode = true;
delay(1);
}
else if (switchGPIO0 == HIGH && switchGPIO2 == LOW)
{
listMode = true;
delay(1);
}
else //(switchGPIO0 == LOW && switchGPIO2 == LOW)
{
staticMode = true;
delay(1);
}
}
void loop() {
// Write blue LED HIGH (off)
digitalWrite(LED_BUILTIN, HIGH);
// Do an initial scan to find available network names
if (scan == true)
{
wifiCount = WiFi.scanNetworks();
// Make sure this doesn't run again now that the scan is done
scan = false;
// Wait 3 seconds for the other modules before starting
for (int i = 0; i < 3; ++i)
{
digitalWrite(LED_BUILTIN, LOW);
delay(500);
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
}
}
else if (randomMode == true)
{
wifiCount = 50;
// So after 50 loops below, pick a new random number
randomStart = random(23560);
}
else if (listMode == true)
{
wifiCount = 6;
}
else if (staticMode == true)
{
wifiCount = 1;
}
if (promiscuousMode == false)
{
promiscuousMode = true;
wifi_set_opmode(STATION_MODE);
wifi_promiscuous_enable(1);
}
delay(1);
// Start looping through SSID's
for (int i = 0; i < wifiCount; ++i)
{
// Get the SSID to use this round (increasing array value changes SSID)
if (mimicMode == true)
{
// Pick a random SSID
//int wifiCountArray = wifiCount - 1;
wifissid = WiFi.SSID(random(wifiCount));
}
else if (randomMode == true)
{
// Just start at the picked random number and add 1 each loop
int randVal = randomStart + 1;
wifissid = String(randVal);
}
else if (listMode == true)
{
wifissid = networkList[i];
}
else
{
wifissid = staticNet;
}
// Beacon Packet buffer ( this resets the variable every loop. weird things happened when it was global... )
uint8_t packet[128] = { 0x80, 0x00, 0x00, 0x00,
/*4*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/*10*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
/*16*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
/*22*/ 0xc0, 0x6c,
/*24*/ 0x83, 0x51, 0xf7, 0x8f, 0x0f, 0x00, 0x00, 0x00,
/*32*/ 0x64, 0x00,
/*34*/ 0x01, 0x04,
/* SSID */
/*36*/ 0x00, 0x01, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
/*71*/ 0x01, 0x08, 0x82, 0x84,
/*75*/ 0x8b, 0x96, 0x24, 0x30, 0x48, 0x6c, 0x03, 0x01,
/*83*/ 0x05, 0x20
};
// Get the SSID length to modify that length value in the beacon
int wifiLength = wifissid.length();
// Array spot to start printing SSID
int ssidSpot = 38;
// If the SSID is too long, cut it
if (wifiLength > 30)
{
wifiLength = 30;
}
// Start printing the SSID in to the packet array at the start spot stated above
for (int i = 0; i < wifiLength; ++i)
{
packet[ssidSpot] = wifissid[i];
++ssidSpot;
}
// BROADCAST LOOP. Start with 1 space added to SSID and continue until 30 characters long
for (int j = wifiLength; j < 30; ++j)
{
// Kill the "add a space each iteration" looping here if you want
// Add a space right after the SSID that was printed above
packet[ssidSpot] = packet[84];
// Print the now complete SSID length right before the SSID start spot in packet
packet[37] = j + 1;
// Move to the next array spot after the last space was added
++ssidSpot;
// Pick a channel to use
channel = random(1, 12);
wifi_set_channel(channel);
// Change the last array value in the "ending" part of the SSID beacon to the channel being used
packet[83] = channel;
// Just copying the left off ssid spot for the second part of the packet to start
int packetPartTwo = ssidSpot;
// Print the complete second packet portion in to the complete packet array now that the SSID is printed in
for (int m = 71; m < 84; ++m)
{
packet[packetPartTwo] = packet[m];
++packetPartTwo;
}
// Random MAC address
packet[10] = packet[16] = random(256);
packet[11] = packet[17] = random(256);
packet[12] = packet[18] = random(256);
packet[13] = packet[19] = random(256);
packet[14] = packet[20] = random(256);
packet[15] = packet[21] = random(256);
// Broadcast the Beacons!
fullPacket = packetPartTwo; // + 1;
// Write blue LED LOW (on)
digitalWrite(LED_BUILTIN, LOW);
wifi_send_pkt_freedom(packet, fullPacket, 0);
wifi_send_pkt_freedom(packet, fullPacket, 0);
wifi_send_pkt_freedom(packet, fullPacket, 0);
// Write blue LED HIGH (off)
digitalWrite(LED_BUILTIN, HIGH);
delay(10);
}
delay(10);
}
delay(10);
}