Initial commit.

This commit is contained in:
2026-03-17 21:39:58 +01:00
commit 894dd9ea68
7 changed files with 296 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
.pio
+151
View File
@@ -0,0 +1,151 @@
# Digispark USB Rubber Ducky PoC
A proof-of-concept USB HID keystroke injection tool using a Digispark ATtiny85 development board and PlatformIO.
When plugged into a host machine the device emulates a USB keyboard and automatically types a predefined payload.
## Prerequisites
- [PlatformIO CLI](https://docs.platformio.org/en/latest/core/installation/index.html) (or the PlatformIO IDE extension for VS Code)
- A Digispark ATtiny85 board with the micronucleus bootloader
On Linux you may also need udev rules so the micronucleus uploader can access the USB device without root:
```bash
# /etc/udev/rules.d/49-micronucleus.rules
SUBSYSTEMS=="usb", ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="0753", MODE="0660", GROUP="plugdev"
```
Reload rules after creating the file:
```bash
sudo udevadm control --reload-rules && sudo udevadm trigger
```
## Project structure
```
.
├── platformio.ini # Board & framework configuration
├── src/
│ └── main.cpp # Payload source code
├── include/ # Project header files
├── lib/ # Private libraries
└── test/ # Unit tests
```
## Building
Compile the firmware:
```bash
pio run
```
PlatformIO will automatically download the required toolchain and Digistump framework on the first run.
## Uploading to the device
```bash
pio run -t upload
```
The console will print `Plug in device now...`. You then have **60 seconds** to connect the Digispark to a USB port. The micronucleus bootloader on the board will receive the firmware and reboot into the payload automatically.
> **Tip:** If the upload times out, unplug the board, run the command again and re-plug when prompted.
## Adapting the payload
All payload logic lives in the `setup()` function inside `src/main.cpp`, between the `--- payload start ---` and `--- payload end ---` comments.
### Keyboard layout
The layout is selected with a `#define` **before** the `DigiKeyboard.h` include:
```cpp
#define LAYOUT_FRENCH // AZERTY
#include <DigiKeyboard.h>
```
Available layouts (define exactly one):
| Define | Layout |
|---|---|
| `LAYOUT_US_ENGLISH` | US QWERTY (default if none specified) |
| `LAYOUT_FRENCH` | French AZERTY |
| `LAYOUT_FRENCH_BELGIAN` | Belgian AZERTY |
| `LAYOUT_FRENCH_SWISS` | Swiss French |
| `LAYOUT_CANADIAN_FRENCH` | Canadian French |
| `LAYOUT_CANADIAN_MULTILINGUAL` | Canadian Multilingual |
| `LAYOUT_GERMAN` | German QWERTZ |
| `LAYOUT_GERMAN_SWISS` | Swiss German |
| `LAYOUT_SPANISH` | Spanish |
| `LAYOUT_SPANISH_LATIN_AMERICA` | Latin American Spanish |
| `LAYOUT_ITALIAN` | Italian |
| `LAYOUT_PORTUGUESE` | Portuguese |
| `LAYOUT_PORTUGUESE_BRAZILIAN` | Brazilian Portuguese |
| `LAYOUT_DANISH` | Danish |
| `LAYOUT_FINNISH` | Finnish |
| `LAYOUT_NORWEGIAN` | Norwegian |
| `LAYOUT_SWEDISH` | Swedish |
| `LAYOUT_TURKISH` | Turkish |
| `LAYOUT_UNITED_KINGDOM` | UK |
| `LAYOUT_ICELANDIC` | Icelandic |
| `LAYOUT_IRISH` | Irish |
### Useful API
| Function | Description |
|---|---|
| `DigiKeyboard.print("text")` | Type a string |
| `DigiKeyboard.println("text")` | Type a string followed by Enter |
| `DigiKeyboard.sendKeyStroke(key)` | Send a single key press |
| `DigiKeyboard.sendKeyStroke(key, modifier)` | Send a key press with a modifier |
| `DigiKeyboard.delay(ms)` | Wait (also keeps USB alive) |
Common modifier constants: `MOD_SHIFT_LEFT`, `MOD_CONTROL_LEFT`, `MOD_ALT_LEFT`, `MOD_GUI_LEFT` (Windows/Super key).
Common key codes (USB HID usage IDs):
| Code | Key |
|---|---|
| `0x04`..`0x1D` | a..z |
| `0x1E`..`0x27` | 1..0 |
| `40` | Enter |
| `41` | Escape |
| `43` | Tab |
| `44` | Space |
The full list is in the [USB HID usage tables](https://usb.org/document-library/hid-usage-tables-15) specification (section 10, Keyboard/Keypad Page).
### Example: open a terminal on Linux and run a command
```cpp
void setup() {
DigiKeyboard.delay(2000);
// Ctrl+Alt+T opens a terminal on most Linux desktops
DigiKeyboard.sendKeyStroke(0x17, MOD_CONTROL_LEFT | MOD_ALT_LEFT); // 't'
DigiKeyboard.delay(1000);
DigiKeyboard.println("echo 'Hello from Digispark!'");
}
```
## Hardware constraints
| Resource | Total | Used by current payload |
|---|---|---|
| Flash | 6 012 bytes | ~2 860 bytes (48%) |
| RAM | 512 bytes | ~104 bytes (20%) |
The micronucleus bootloader occupies roughly 2 KB of the 8 KB total flash, leaving ~6 KB for application code. Keep payloads concise, especially long strings.
## Troubleshooting
| Problem | Solution |
|---|---|
| `Upload failed: cannot access USB device` | Add udev rules (see Prerequisites) or run with `sudo` |
| Upload times out | Unplug the board, run `pio run -t upload` again, plug in when prompted |
| Wrong characters appear on the host | Change the `LAYOUT_*` define to match the host OS keyboard layout |
| Payload runs too fast / host misses keystrokes | Increase `DigiKeyboard.delay()` values between actions |
+37
View File
@@ -0,0 +1,37 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the convention is to give header files names that end with `.h'.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
+46
View File
@@ -0,0 +1,46 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into the executable file.
The source code of each library should be placed in a separate directory
("lib/your_library_name/[Code]").
For example, see the structure of the following example libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional. for custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
Example contents of `src/main.c` using Foo and Bar:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
The PlatformIO Library Dependency Finder will find automatically dependent
libraries by scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html
+17
View File
@@ -0,0 +1,17 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:digispark-tiny]
platform = atmelavr
board = digispark-tiny
framework = arduino
; DigiKeyboard is bundled with the Digistump framework
; Upload: plug in the Digispark when prompted (uses micronucleus bootloader)
+33
View File
@@ -0,0 +1,33 @@
#include <Arduino.h>
// Select AZERTY (French) keyboard layout before including DigiKeyboard
#define LAYOUT_FRENCH
#include <DigiKeyboard.h>
// Proof of concept: types "Hello world!" on an AZERTY host.
void setup() {
// Wait for the host to recognise the USB device.
DigiKeyboard.delay(2000);
// --- payload start ---
// Open the Run dialog on Windows (Win+R)
DigiKeyboard.sendKeyStroke(0x15, MOD_GUI_LEFT); // 'r'
DigiKeyboard.delay(500);
// Launch Notepad
DigiKeyboard.print("notepad");
DigiKeyboard.sendKeyStroke(40); // Enter
DigiKeyboard.delay(1000);
// Type the message
DigiKeyboard.print("Hello world!");
// --- payload end ---
}
void loop() {
// Nothing to repeat. Keep the USB connection alive.
DigiKeyboard.delay(5000);
}
+11
View File
@@ -0,0 +1,11 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html