Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sd_files/BadUSB and BlueDucky/Ducky-br.html
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@
<div class="misc-commands-section">
<b>Comandos diversos:</b><br />
<font size="2" style="color:#bbbdba"><i><mark>REPEAT</mark> é usado para repetir o comando anterior. Ele espera o número de repetições adicionais como parâmetro.<br />
<mark>DEFINE</mark> declara uma constante (ex.: <mark>DEFINE #NOME valor</mark>) que é substituída onde quer que apareça antes da execução do payload.<br />
<mark>ALTCHAR</mark> é para exibir teclas <mark>ALT+Numpad</mark> individuais (no Windows), ou teclas <mark>ALT</mark><mark>(ALT+SHIFT)</mark> (no macOS).<br />
Clique
</i></font><font size="2" style="color:#bbbdba"><a href="https://www.alt-codes.net" target="new">AQUI</a></font><font size="2" style="color:#bbbdba"><i> para uma lista completa de códigos disponíveis para caracteres ALT.</i></font>
Expand Down
1 change: 1 addition & 0 deletions sd_files/BadUSB and BlueDucky/Ducky-en.html
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@
<div class="misc-commands-section">
<b>Misc. Commands:</b><br />
<font size="2" style="color:#bbbdba"><i><mark>REPEAT</mark> is used to repeat the previous command. It expects the number of additional repeats as parameter.<br />
<mark>DEFINE</mark> declares a constant (e.g. <mark>DEFINE #NAME value</mark>) that is substituted wherever it appears before the payload runs.<br />
<mark>ALTCHAR</mark> is to display single <mark>ALT+Numpad</mark> Keys (on Windows), or <mark>ALT</mark><mark>(ALT+SHIFT)</mark> Keys (on macOS).<br />
Click
</i></font><font size="2" style="color:#bbbdba"><a href="https://www.alt-codes.net" target="new">HERE</a></font><font size="2" style="color:#bbbdba"><i> for a complete list of available codes for ALT characters.</i></font>
Expand Down
13 changes: 13 additions & 0 deletions sd_files/BadUSB and BlueDucky/DuckyScript_DEFINE_demo.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
REM DuckyScript 3.0 DEFINE demo
REM Constants are declared with DEFINE and substituted before the payload runs.
REM Undefined names and whole tokens are left untouched (#NAME never matches #NAMES).
DEFINE #EDITOR notepad.exe
DEFINE #NAME Bruce
DEFINE #PAUSE 500

GUI r
DELAY #PAUSE
STRINGLN #EDITOR
DELAY 1000
STRINGLN Hello, my name is #NAME
STRINGLN DEFINE keeps payloads readable and easy to retarget
49 changes: 49 additions & 0 deletions src/modules/badusb_ble/ducky_typer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "esp_mac.h"
#include "modules/ble/ble_common.h"
#include <NimBLEDevice.h>
#include <map>
#if defined(USB_as_HID)
#include "tusb.h"
#endif
Expand Down Expand Up @@ -575,6 +576,49 @@ DuckyCombination *findDuckyCombination(const char *cmd) {
return nullptr;
}

// ============================================================================
// DUCKYSCRIPT 3.0 DEFINE - Constant substitution
// ============================================================================

// '#' is a token char because DEFINE names are conventionally '#'-prefixed.
static bool isDuckyDefineTokenChar(char c) { return isAlphaNumeric(c) || c == '_' || c == '#'; }

static bool parseDuckyDefine(const String &line, std::map<String, String> &defines) {
if (!line.startsWith("DEFINE ")) return false;

int nameStart = 7; // strlen("DEFINE ")
while (nameStart < (int)line.length() && line.charAt(nameStart) == ' ') nameStart++;

int nameEnd = line.indexOf(' ', nameStart);
String name = (nameEnd < 0) ? line.substring(nameStart) : line.substring(nameStart, nameEnd);
if (name.length() == 0) return true;

defines[name] = (nameEnd < 0) ? String("") : line.substring(nameEnd + 1);
return true;
}

// Replaces whole-token matches only, so a name never matches inside a larger token.
static void applyDuckyDefines(String &line, const std::map<String, String> &defines) {
for (const auto &entry : defines) {
const String &name = entry.first;
const String &value = entry.second;
int from = 0;
while (true) {
int pos = line.indexOf(name, from);
if (pos < 0) break;
int after = pos + name.length();
bool leftOk = (pos == 0) || !isDuckyDefineTokenChar(line.charAt(pos - 1));
bool rightOk = (after >= (int)line.length()) || !isDuckyDefineTokenChar(line.charAt(after));
if (leftOk && rightOk) {
line = line.substring(0, pos) + value + line.substring(after);
from = pos + value.length();
} else {
from = pos + 1;
}
}
}
}

// ============================================================================
// START KEYBOARD - Creates fresh BLE instance with new stack
// ============================================================================
Expand Down Expand Up @@ -814,6 +858,7 @@ void key_input(FS fs, const String &bad_script, HIDInterface *_hid) {
char Cmd[25];
String Argument = "";
String RepeatTmp = "";
std::map<String, String> duckyDefines;

static int nextStringDelay = -1;
static int defaultStringDelay = bruceConfig.badUSBBLEKeyDelay;
Expand Down Expand Up @@ -856,6 +901,10 @@ void key_input(FS fs, const String &bad_script, HIDInterface *_hid) {

if (lineContent.length() == 0) continue;

// DEFINE stores a constant; every other line has its constants expanded first.
if (parseDuckyDefine(lineContent, duckyDefines)) continue;
if (!duckyDefines.empty()) applyDuckyDefines(lineContent, duckyDefines);

int spaceIndex = lineContent.indexOf(' ');

if (spaceIndex > 0 && lineContent.substring(0, spaceIndex) == "REPEAT") {
Expand Down