Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BadUSB: Mouse control #4004

Merged
merged 22 commits into from
Feb 19, 2025
Merged
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
56 changes: 56 additions & 0 deletions applications/main/bad_usb/helpers/bad_usb_hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,31 @@ bool hid_usb_kb_release(void* inst, uint16_t button) {
return furi_hal_hid_kb_release(button);
}

bool hid_usb_mouse_press(void* inst, uint8_t button) {
UNUSED(inst);
return furi_hal_hid_mouse_press(button);
}

bool hid_usb_mouse_release(void* inst, uint8_t button) {
UNUSED(inst);
return furi_hal_hid_mouse_release(button);
}

bool hid_usb_mouse_scroll(void* inst, int8_t delta) {
UNUSED(inst);
return furi_hal_hid_mouse_scroll(delta);
}

bool hid_usb_mouse_move(void* inst, int8_t dx, int8_t dy) {
UNUSED(inst);
return furi_hal_hid_mouse_move(dx, dy);
}

bool hid_usb_mouse_release_all(void* inst) {
UNUSED(inst);
return furi_hal_hid_mouse_release(0);
}

bool hid_usb_consumer_press(void* inst, uint16_t button) {
UNUSED(inst);
return furi_hal_hid_consumer_key_press(button);
Expand All @@ -51,6 +76,7 @@ bool hid_usb_release_all(void* inst) {
UNUSED(inst);
bool state = furi_hal_hid_kb_release_all();
state &= furi_hal_hid_consumer_key_release_all();
state &= hid_usb_mouse_release_all(inst);
return state;
}

Expand All @@ -67,6 +93,10 @@ static const BadUsbHidApi hid_api_usb = {

.kb_press = hid_usb_kb_press,
.kb_release = hid_usb_kb_release,
.mouse_press = hid_usb_mouse_press,
.mouse_release = hid_usb_mouse_release,
.mouse_scroll = hid_usb_mouse_scroll,
.mouse_move = hid_usb_mouse_move,
.consumer_press = hid_usb_consumer_press,
.consumer_release = hid_usb_consumer_release,
.release_all = hid_usb_release_all,
Expand Down Expand Up @@ -157,6 +187,27 @@ bool hid_ble_kb_release(void* inst, uint16_t button) {
return ble_profile_hid_kb_release(ble_hid->profile, button);
}

bool hid_ble_mouse_press(void* inst, uint8_t button) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_profile_hid_mouse_press(ble_hid->profile, button);
}
bool hid_ble_mouse_release(void* inst, uint8_t button) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_profile_hid_mouse_release(ble_hid->profile, button);
}
bool hid_ble_mouse_scroll(void* inst, int8_t delta) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_profile_hid_mouse_scroll(ble_hid->profile, delta);
}
bool hid_ble_mouse_move(void* inst, int8_t dx, int8_t dy) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_profile_hid_mouse_move(ble_hid->profile, dx, dy);
}

bool hid_ble_consumer_press(void* inst, uint16_t button) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
Expand All @@ -174,6 +225,7 @@ bool hid_ble_release_all(void* inst) {
furi_assert(ble_hid);
bool state = ble_profile_hid_kb_release_all(ble_hid->profile);
state &= ble_profile_hid_consumer_key_release_all(ble_hid->profile);
state &= ble_profile_hid_mouse_release_all(ble_hid->profile);
return state;
}

Expand All @@ -191,6 +243,10 @@ static const BadUsbHidApi hid_api_ble = {

.kb_press = hid_ble_kb_press,
.kb_release = hid_ble_kb_release,
.mouse_press = hid_ble_mouse_press,
.mouse_release = hid_ble_mouse_release,
.mouse_scroll = hid_ble_mouse_scroll,
.mouse_move = hid_ble_mouse_move,
.consumer_press = hid_ble_consumer_press,
.consumer_release = hid_ble_consumer_release,
.release_all = hid_ble_release_all,
Expand Down
4 changes: 4 additions & 0 deletions applications/main/bad_usb/helpers/bad_usb_hid.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ typedef struct {

bool (*kb_press)(void* inst, uint16_t button);
bool (*kb_release)(void* inst, uint16_t button);
bool (*mouse_press)(void* inst, uint8_t button);
bool (*mouse_release)(void* inst, uint8_t button);
bool (*mouse_scroll)(void* inst, int8_t delta);
bool (*mouse_move)(void* inst, int8_t dx, int8_t dy);
bool (*consumer_press)(void* inst, uint16_t button);
bool (*consumer_release)(void* inst, uint16_t button);
bool (*release_all)(void* inst);
Expand Down
10 changes: 9 additions & 1 deletion applications/main/bad_usb/helpers/ducky_script.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,16 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, FuriString* line) {
return cmd_result;
}

// Mouse Keys
uint16_t key = ducky_get_mouse_keycode_by_name(line_tmp);
if(key != HID_MOUSE_INVALID) {
bad_usb->hid->mouse_press(bad_usb->hid_inst, key);
bad_usb->hid->mouse_release(bad_usb->hid_inst, key);
return 0;
}

// Special keys + modifiers
uint16_t key = ducky_get_keycode(bad_usb, line_tmp, false);
key = ducky_get_keycode(bad_usb, line_tmp, false);
if(key == HID_KEYBOARD_NONE) {
return ducky_error(bad_usb, "No keycode defined for %s", line_tmp);
}
Expand Down
102 changes: 84 additions & 18 deletions applications/main/bad_usb/helpers/ducky_script_commands.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <furi_hal.h>
#include <lib/toolbox/strint.h>
#include "ducky_script.h"
#include "ducky_script_i.h"

Expand Down Expand Up @@ -124,34 +125,58 @@ static int32_t ducky_fnc_altstring(BadUsbScript* bad_usb, const char* line, int3

static int32_t ducky_fnc_hold(BadUsbScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);

line = &line[ducky_get_command_len(line) + 1];
uint16_t key = ducky_get_keycode(bad_usb, line, true);
if(key == HID_KEYBOARD_NONE) {
return ducky_error(bad_usb, "No keycode defined for %s", line);
}
bad_usb->key_hold_nb++;

if(bad_usb->key_hold_nb > (HID_KB_MAX_KEYS - 1)) {
return ducky_error(bad_usb, "Too many keys are hold");
return ducky_error(bad_usb, "Too many keys are held");
}
bad_usb->hid->kb_press(bad_usb->hid_inst, key);
return 0;

// Handle Mouse Keys here
uint16_t key = ducky_get_mouse_keycode_by_name(line);
if(key != HID_MOUSE_NONE) {
bad_usb->key_hold_nb++;
bad_usb->hid->mouse_press(bad_usb->hid_inst, key);
return 0;
}

// Handle Keyboard keys here
key = ducky_get_keycode(bad_usb, line, true);
if(key != HID_KEYBOARD_NONE) {
bad_usb->key_hold_nb++;
bad_usb->hid->kb_press(bad_usb->hid_inst, key);
return 0;
}

// keyboard and mouse were none
return ducky_error(bad_usb, "Unknown keycode for %s", line);
}

static int32_t ducky_fnc_release(BadUsbScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);

line = &line[ducky_get_command_len(line) + 1];
uint16_t key = ducky_get_keycode(bad_usb, line, true);
if(key == HID_KEYBOARD_NONE) {
return ducky_error(bad_usb, "No keycode defined for %s", line);
}

if(bad_usb->key_hold_nb == 0) {
return ducky_error(bad_usb, "No keys are hold");
return ducky_error(bad_usb, "No keys are held");
}
bad_usb->key_hold_nb--;
bad_usb->hid->kb_release(bad_usb->hid_inst, key);
return 0;

// Handle Mouse Keys here
uint16_t key = ducky_get_mouse_keycode_by_name(line);
if(key != HID_MOUSE_NONE) {
bad_usb->key_hold_nb--;
bad_usb->hid->mouse_release(bad_usb->hid_inst, key);
return 0;
}

//Handle Keyboard Keys here
key = ducky_get_keycode(bad_usb, line, true);
if(key != HID_KEYBOARD_NONE) {
bad_usb->key_hold_nb--;
bad_usb->hid->kb_release(bad_usb->hid_inst, key);
return 0;
}

// keyboard and mouse were none
return ducky_error(bad_usb, "No keycode defined for %s", line);
}

static int32_t ducky_fnc_media(BadUsbScript* bad_usb, const char* line, int32_t param) {
Expand Down Expand Up @@ -191,6 +216,43 @@ static int32_t ducky_fnc_waitforbutton(BadUsbScript* bad_usb, const char* line,
return SCRIPT_STATE_WAIT_FOR_BTN;
}

static int32_t ducky_fnc_mouse_scroll(BadUsbScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);

line = &line[strcspn(line, " ") + 1];
int32_t mouse_scroll_dist = 0;

if(strint_to_int32(line, NULL, &mouse_scroll_dist, 10) != StrintParseNoError) {
return ducky_error(bad_usb, "Invalid Number %s", line);
}

bad_usb->hid->mouse_scroll(bad_usb->hid_inst, mouse_scroll_dist);

return 0;
}

static int32_t ducky_fnc_mouse_move(BadUsbScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);

line = &line[strcspn(line, " ") + 1];
int32_t mouse_move_x = 0;
int32_t mouse_move_y = 0;

if(strint_to_int32(line, NULL, &mouse_move_x, 10) != StrintParseNoError) {
return ducky_error(bad_usb, "Invalid Number %s", line);
}

line = &line[strcspn(line, " ") + 1];

if(strint_to_int32(line, NULL, &mouse_move_y, 10) != StrintParseNoError) {
return ducky_error(bad_usb, "Invalid Number %s", line);
}

bad_usb->hid->mouse_move(bad_usb->hid_inst, mouse_move_x, mouse_move_y);

return 0;
}

static const DuckyCmd ducky_commands[] = {
{"REM", NULL, -1},
{"ID", NULL, -1},
Expand All @@ -213,6 +275,10 @@ static const DuckyCmd ducky_commands[] = {
{"WAIT_FOR_BUTTON_PRESS", ducky_fnc_waitforbutton, -1},
{"MEDIA", ducky_fnc_media, -1},
{"GLOBE", ducky_fnc_globe, -1},
{"MOUSEMOVE", ducky_fnc_mouse_move, -1},
{"MOUSE_MOVE", ducky_fnc_mouse_move, -1},
{"MOUSESCROLL", ducky_fnc_mouse_scroll, -1},
{"MOUSE_SCROLL", ducky_fnc_mouse_scroll, -1},
};

#define TAG "BadUsb"
Expand Down
5 changes: 5 additions & 0 deletions applications/main/bad_usb/helpers/ducky_script_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ extern "C" {

#define FILE_BUFFER_LEN 16

#define HID_MOUSE_INVALID 0
#define HID_MOUSE_NONE 0

struct BadUsbScript {
FuriHalUsbHidConfig hid_cfg;
const BadUsbHidApi* hid;
Expand Down Expand Up @@ -55,6 +58,8 @@ uint16_t ducky_get_keycode_by_name(const char* param);

uint16_t ducky_get_media_keycode_by_name(const char* param);

uint8_t ducky_get_mouse_keycode_by_name(const char* param);

bool ducky_get_number(const char* param, uint32_t* val);

void ducky_numlock_on(BadUsbScript* bad_usb);
Expand Down
23 changes: 23 additions & 0 deletions applications/main/bad_usb/helpers/ducky_script_keycodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,17 @@ static const DuckyKey ducky_media_keys[] = {
{"BRIGHT_DOWN", HID_CONSUMER_BRIGHTNESS_DECREMENT},
};

static const DuckyKey ducky_mouse_keys[] = {
{"LEFTCLICK", HID_MOUSE_BTN_LEFT},
{"LEFT_CLICK", HID_MOUSE_BTN_LEFT},
{"RIGHTCLICK", HID_MOUSE_BTN_RIGHT},
{"RIGHT_CLICK", HID_MOUSE_BTN_RIGHT},
{"MIDDLECLICK", HID_MOUSE_BTN_WHEEL},
{"MIDDLE_CLICK", HID_MOUSE_BTN_WHEEL},
{"WHEELCLICK", HID_MOUSE_BTN_WHEEL},
{"WHEEL_CLICK", HID_MOUSE_BTN_WHEEL},
};

uint16_t ducky_get_keycode_by_name(const char* param) {
for(size_t i = 0; i < COUNT_OF(ducky_keys); i++) {
size_t key_cmd_len = strlen(ducky_keys[i].name);
Expand All @@ -131,3 +142,15 @@ uint16_t ducky_get_media_keycode_by_name(const char* param) {

return HID_CONSUMER_UNASSIGNED;
}

uint8_t ducky_get_mouse_keycode_by_name(const char* param) {
for(size_t i = 0; i < COUNT_OF(ducky_mouse_keys); i++) {
size_t key_cmd_len = strlen(ducky_mouse_keys[i].name);
if((strncmp(param, ducky_mouse_keys[i].name, key_cmd_len) == 0) &&
(ducky_is_line_end(param[key_cmd_len]))) {
return ducky_mouse_keys[i].keycode;
}
}

return HID_MOUSE_INVALID;
}
46 changes: 46 additions & 0 deletions applications/main/bad_usb/resources/badusb/test_mouse.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
ID 1234:abcd Generic:USB Keyboard
REM Declare ourselves as a generic usb keyboard
REM You can override this to use something else
REM Check the `lsusb` command to know your own devices IDs

DEFAULT_DELAY 200
DEFAULT_STRING_DELAY 100

DELAY 1000

REM Test all mouse functions
LEFTCLICK
RIGHTCLICK
MIDDLECLICK

DELAY 1000

MOUSEMOVE -10 0
REPEAT 20
MOUSEMOVE 0 10
REPEAT 20
MOUSEMOVE 10 0
REPEAT 20
MOUSEMOVE 0 -10
REPEAT 20

DELAY 1000

MOUSESCROLL -50
MOUSESCROLL 50

DELAY 1000

REM Verify Mouse hold working
HOLD LEFTCLICK
DELAY 2000
RELEASE LEFTCLICK

DELAY 1000

REM Verify KB hold working
HOLD M
DELAY 2000
RELEASE M

ENTER
15 changes: 15 additions & 0 deletions documentation/file_formats/BadUsbScriptFormat.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,18 @@ Example:
`ID 1234:abcd Flipper Devices:Flipper Zero`

VID and PID are hex codes and are mandatory. Manufacturer and Product are text strings and are optional.

## Mouse Commands

Mouse movement and click commands. Mouse click commands support HOLD functionality.

| Command | Parameters | Notes |
| ------------- | -------------------------------| -------------------------------- |
| LEFTCLICK | None | |
| LEFT_CLICK | None | functionally same as LEFTCLICK |
| RIGHTCLICK | None | |
| RIGHT_CLICK | None | functionally same as RIGHTCLICK |
| MOUSEMOVE | x y: int move mount/direction | |
| MOUSE_MOVE | x y: int move mount/direction | functionally same as MOUSEMOVE |
| MOUSESCROLL | delta: int scroll distance | |
| MOUSE_SCROLL | delta: int scroll distance | functionally same as MOUSESCROLL |
1 change: 1 addition & 0 deletions lib/subghz/protocols/bin_raw.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ SubGhzProtocolStatus
res = SubGhzProtocolStatusErrorEncoderGetUpload;
break;
}

instance->encoder.is_running = true;

res = SubGhzProtocolStatusOk;
Expand Down
Loading