From 7481aefe9f2c386b12e9190b2635238216db37bd Mon Sep 17 00:00:00 2001 From: Sandbox <143267209+Win-Sandbox@users.noreply.github.com> Date: Thu, 2 Jul 2026 23:14:17 +0900 Subject: [PATCH] customizable name attack option "CUSTOM" for the BLESPAM App (#3239) --- .../external/blespam/ui_blespam.cpp | 70 +++++++++++++++++-- .../external/blespam/ui_blespam.hpp | 16 ++++- sdcard/BLESPAM/NAME.txt | 7 ++ 3 files changed, 87 insertions(+), 6 deletions(-) create mode 100644 sdcard/BLESPAM/NAME.txt diff --git a/firmware/application/external/blespam/ui_blespam.cpp b/firmware/application/external/blespam/ui_blespam.cpp index 93dde5ab4..cd2315f79 100644 --- a/firmware/application/external/blespam/ui_blespam.cpp +++ b/firmware/application/external/blespam/ui_blespam.cpp @@ -294,11 +294,11 @@ void BLESpamView::createWindowsPacket() { std::copy(res.begin(), res.end(), advertisementData); } -void BLESpamView::createNameSpamPacket() { - const char* names[] = {"PortaHack", "PwnBt", "iSpam", "GenericFoodVagon", "SignalSnoop", "ByteBandit", "RadioRogue", "RadioRebel", "ByteBlast"}; - - const char* name = names[rand() % 9]; //"PortaHack"; +// Builds a "Complete Local Name" HID advertisement for the given name. +// Shared by NameSpam (built-in list) and Custom (SD card list) modes. +void BLESpamView::buildNamePacket(const char* name) { uint8_t name_len = strlen(name); + if (name_len > 19) name_len = 19; // clamp so the hex string fits advertisementData[63] uint8_t size = 12 + name_len; uint8_t i = 0; @@ -327,6 +327,65 @@ void BLESpamView::createNameSpamPacket() { std::copy(res.begin(), res.end(), advertisementData); } +void BLESpamView::createNameSpamPacket() { + const char* names[] = {"PortaHack", "PwnBt", "iSpam", "GenericFoodVagon", "SignalSnoop", "ByteBandit", "RadioRogue", "RadioRebel", "ByteBlast"}; + buildNamePacket(names[rand() % 9]); +} + +// Opens /BLESPAM/NAME.txt once and keeps it open for the session. +void BLESpamView::open_custom_file() { + custom_loaded_ = true; // attempt only once + auto open_error = custom_file_.open(u"/BLESPAM/NAME.txt"); + custom_file_valid_ = !open_error; // false -> caller falls back to NameSpam +} + +// Reads the next line into custom_name_ (clamped to 19 chars), advancing the +// file position. At end of file it seeks back to the start to cycle. Returns +// false if the file holds no usable name. Only one line is ever held in RAM. +bool BLESpamView::read_next_custom_name() { + if (!custom_file_valid_) return false; + + custom_name_.clear(); + bool wrapped = false; + char c; + + while (true) { + auto read_result = custom_file_.read(&c, 1); + if (read_result.is_error()) return false; + + if (read_result.value() == 0) { + // end of file + if (!custom_name_.empty()) break; + // use the final line + if (wrapped) return false; + // no usable name in file + if (custom_file_.seek(0).is_error()) return false; + // loop back to the first line + wrapped = true; + continue; + } + + if (c == '\n' || c == '\r') { + if (!custom_name_.empty()) break; // got a complete line + continue; // skip blank lines / CRLF pairs + } + + if (custom_name_.size() < 19) // clamp; keep scanning rest of long line + custom_name_.push_back(c); + } + return true; +} + +void BLESpamView::createCustomPacket() { + if (!custom_loaded_) open_custom_file(); + + if (!read_next_custom_name()) { // no file / unreadable / empty -> fall back + createNameSpamPacket(); + return; + } + buildNamePacket(custom_name_.c_str()); +} + char BLESpamView::randomNameChar() { int randVal = rand() % 62; // 26 uppercase + 26 lowercase + 10 digits if (randVal < 26) { @@ -622,6 +681,9 @@ void BLESpamView::createPacket(ATK_TYPE attackType) { case ATK_NAMERANDOM: createNameRandomPacket(); break; + case ATK_CUSTOM: + createCustomPacket(); + break; case ATK_ALL_SAFE: createAnyPacket(true); break; diff --git a/firmware/application/external/blespam/ui_blespam.hpp b/firmware/application/external/blespam/ui_blespam.hpp index c01c0ffe3..e05090473 100644 --- a/firmware/application/external/blespam/ui_blespam.hpp +++ b/firmware/application/external/blespam/ui_blespam.hpp @@ -39,6 +39,7 @@ #include "radio_state.hpp" #include "log_file.hpp" #include "utility.hpp" +#include "file.hpp" using namespace ui; @@ -52,6 +53,7 @@ enum ATK_TYPE { ATK_SAMSUNG, ATK_NAMESPAM, ATK_NAMERANDOM, + ATK_CUSTOM, ATK_ALL_SAFE, ATK_ALL }; @@ -131,8 +133,9 @@ class BLESpamView : public View { {"Samsung", 4}, {"NameSpam", 5}, {"NameRandom", 6}, - {"All-Safe", 7}, - {"All", 8}}}; + {"NameCustom", 7}, + {"All-Safe", 8}, + {"All", 9}}}; bool is_running{false}; @@ -144,6 +147,11 @@ class BLESpamView : public View { bool randomMac{true}; bool randomDev{true}; + File custom_file_{}; // kept open while in Custom mode + std::string custom_name_{}; // holds only the current name (clamped) + bool custom_loaded_{false}; // true once an open attempt has been made + bool custom_file_valid_{false}; // true if /BLESPAM/NAME.txt opened successfully + uint8_t channel_number = 37; char mac[13] = "010203040407"; char advertisementData[63] = {"03032CFE06162CFED5A59E020AB4\0"}; @@ -156,7 +164,11 @@ class BLESpamView : public View { void createIosPacket(bool crash); void createSamsungPacket(); void createWindowsPacket(); + void buildNamePacket(const char* name); // shared name advertisement builder (NameSpam / Custom) void createNameSpamPacket(); + void createCustomPacket(); + void open_custom_file(); // open /BLESPAM/NAME.txt once (one name per line) + bool read_next_custom_name(); // read next line into custom_name_, looping at EOF void createNameRandomPacket(); void createAnyPacket(bool safe); void createPacket(ATK_TYPE attackType); diff --git a/sdcard/BLESPAM/NAME.txt b/sdcard/BLESPAM/NAME.txt new file mode 100644 index 000000000..019388a8c --- /dev/null +++ b/sdcard/BLESPAM/NAME.txt @@ -0,0 +1,7 @@ +TEST +Portapack +HackRF +1 +2 +3 +4