mirror of
https://github.com/cecio/USBvalve.git
synced 2026-04-23 01:01:23 +00:00
1.0.0
This commit is contained in:
290
src/main.c
Normal file
290
src/main.c
Normal file
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* USBvalve - Pure Pico SDK Implementation
|
||||
*
|
||||
* USB security tool: acts as USB Mass Storage Device (Core 0) while
|
||||
* simultaneously running USB Host via PIO USB (Core 1) to detect
|
||||
* BadUSB/HID attacks.
|
||||
*
|
||||
* Copyright (c) Cesare Pizzi
|
||||
* MIT License
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/multicore.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/watchdog.h"
|
||||
#include "hardware/clocks.h"
|
||||
#include "tusb.h"
|
||||
#include "usb_config.h"
|
||||
#include "usb_device.h"
|
||||
#include "usb_host.h"
|
||||
#include "display.h"
|
||||
#include "serial_output.h"
|
||||
|
||||
#ifdef USE_BOOTSEL
|
||||
#include "pico/bootrom.h"
|
||||
#include "hardware/structs/ioqspi.h"
|
||||
#include "hardware/structs/sio.h"
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Shared state (cross-core, volatile. ARM word writes are atomic)
|
||||
//--------------------------------------------------------------------
|
||||
volatile bool flag_readme = false;
|
||||
volatile bool flag_autorun = false;
|
||||
volatile bool flag_written = false;
|
||||
volatile bool flag_deleted = false;
|
||||
volatile bool flag_written_reported = false;
|
||||
volatile bool flag_deleted_reported = false;
|
||||
volatile bool flag_hid_sent = false;
|
||||
volatile bool flag_hid_reported = false;
|
||||
volatile bool flag_hid_mounted = false;
|
||||
volatile bool flag_msc_mounted = false;
|
||||
volatile bool flag_cdc_mounted = false;
|
||||
volatile uint32_t hid_event_num = 0;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Software reset via watchdog
|
||||
//--------------------------------------------------------------------
|
||||
static void swreset(void) {
|
||||
watchdog_enable(1500, 1);
|
||||
while (1) {
|
||||
tight_loop_contents();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_BOOTSEL
|
||||
//--------------------------------------------------------------------
|
||||
// BOOTSEL button check (multi-core safe)
|
||||
//
|
||||
// WARNING: Reading BOOTSEL temporarily disconnects flash (QSPI CS
|
||||
// override), which crashes any core executing from flash. This
|
||||
// disrupts PIO USB on Core 1 and causes unreliable Low Speed device
|
||||
// detection. Only enable this on boards without an external button.
|
||||
//
|
||||
// Core 1 must call multicore_lockout_victim_init() at startup.
|
||||
//--------------------------------------------------------------------
|
||||
static bool __no_inline_not_in_flash_func(bootsel_pressed_raw)(void) {
|
||||
const uint CS_PIN_INDEX = 1;
|
||||
|
||||
hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl,
|
||||
GPIO_OVERRIDE_LOW << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
|
||||
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
|
||||
|
||||
for (volatile int i = 0; i < 1000; i++);
|
||||
|
||||
bool pressed = !(sio_hw->gpio_hi_in & (1u << CS_PIN_INDEX));
|
||||
|
||||
hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl,
|
||||
GPIO_OVERRIDE_NORMAL << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
|
||||
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
|
||||
|
||||
return pressed;
|
||||
}
|
||||
|
||||
static bool bootsel_pressed(void) {
|
||||
multicore_lockout_start_blocking();
|
||||
uint32_t flags = save_and_disable_interrupts();
|
||||
bool pressed = bootsel_pressed_raw();
|
||||
restore_interrupts(flags);
|
||||
multicore_lockout_end_blocking();
|
||||
return pressed;
|
||||
}
|
||||
#endif // USE_BOOTSEL
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Main (Core 0)
|
||||
//--------------------------------------------------------------------
|
||||
int main(void) {
|
||||
// Sysclock must be a multiple of 12MHz for PIO USB.
|
||||
#if defined(PICO_RP2350)
|
||||
set_sys_clock_khz(144000, true);
|
||||
#else
|
||||
set_sys_clock_khz(240000, true);
|
||||
#endif
|
||||
sleep_ms(10);
|
||||
|
||||
// Launch Core 1 for USB host BEFORE device init.
|
||||
// Core 1 handles PIO USB host. Must start first so PIO IRQs
|
||||
// are registered on Core 1.
|
||||
multicore_reset_core1();
|
||||
multicore_launch_core1(core1_entry);
|
||||
|
||||
// Init device stack on native USB (rhport 0)
|
||||
tud_init(0);
|
||||
|
||||
// Run ramdisk self-test
|
||||
bool selftest_ok = usb_device_selftest();
|
||||
|
||||
// Initialize display
|
||||
display_init();
|
||||
cls();
|
||||
|
||||
if (selftest_ok) {
|
||||
printout("\n[+] Selftest: OK");
|
||||
} else {
|
||||
printout("\n[!] Selftest: KO");
|
||||
printout("\n[!] Stopping...");
|
||||
while (1) {
|
||||
sleep_ms(1000);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PIWATCH
|
||||
// Set up LED pin (PIWATCH uses GPIO 25 for backlight)
|
||||
gpio_init(LED_PIN);
|
||||
gpio_set_dir(LED_PIN, GPIO_OUT);
|
||||
gpio_put(LED_PIN, 1); // LED on = OK
|
||||
|
||||
// Set up external reset button (active-low with pull-up)
|
||||
gpio_init(BUTTON_PIN);
|
||||
gpio_set_dir(BUTTON_PIN, GPIO_IN);
|
||||
gpio_pull_up(BUTTON_PIN);
|
||||
#endif
|
||||
|
||||
// Core 0 main loop
|
||||
while (true) {
|
||||
// Process TinyUSB device tasks (required for CDC serial + MSC)
|
||||
tud_task();
|
||||
|
||||
// Flush CDC writes from Core 1 callbacks
|
||||
tud_cdc_write_flush();
|
||||
|
||||
// Check flags and report events
|
||||
if (flag_readme) {
|
||||
printout("\n[!] README (R)");
|
||||
flag_readme = false;
|
||||
#ifndef PIWATCH
|
||||
gpio_put(LED_PIN, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (flag_autorun) {
|
||||
printout("\n[+] AUTORUN (R)");
|
||||
flag_autorun = false;
|
||||
}
|
||||
|
||||
if (flag_deleted && !flag_deleted_reported) {
|
||||
printout("\n[!] DELETING");
|
||||
flag_deleted = false;
|
||||
flag_deleted_reported = true;
|
||||
#ifndef PIWATCH
|
||||
gpio_put(LED_PIN, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (flag_written && !flag_written_reported) {
|
||||
printout("\n[!] WRITING");
|
||||
flag_written = false;
|
||||
flag_written_reported = true;
|
||||
#ifndef PIWATCH
|
||||
gpio_put(LED_PIN, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (flag_hid_mounted) {
|
||||
printout("\n[!!] HID Device");
|
||||
flag_hid_mounted = false;
|
||||
#ifndef PIWATCH
|
||||
gpio_put(LED_PIN, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (flag_msc_mounted) {
|
||||
printout("\n[++] Mass Device");
|
||||
flag_msc_mounted = false;
|
||||
}
|
||||
|
||||
if (flag_cdc_mounted) {
|
||||
printout("\n[++] CDC Device");
|
||||
flag_cdc_mounted = false;
|
||||
}
|
||||
|
||||
if (flag_hid_sent && !flag_hid_reported) {
|
||||
printout("\n[!!] HID Sending data");
|
||||
flag_hid_sent = false;
|
||||
flag_hid_reported = true;
|
||||
#ifndef PIWATCH
|
||||
gpio_put(LED_PIN, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef PIWATCH
|
||||
// External button on GPIO 0 (active-low, debounced)
|
||||
if (!gpio_get(BUTTON_PIN)) {
|
||||
sleep_ms(50); // debounce
|
||||
if (!gpio_get(BUTTON_PIN)) {
|
||||
uint32_t press_start = to_ms_since_boot(get_absolute_time());
|
||||
while (!gpio_get(BUTTON_PIN)) {
|
||||
sleep_ms(10);
|
||||
}
|
||||
uint32_t press_duration = to_ms_since_boot(get_absolute_time()) - press_start;
|
||||
|
||||
if (press_duration > 2000) {
|
||||
// Long press: show HID event count
|
||||
char outstr[32];
|
||||
snprintf(outstr, sizeof(outstr), "\n[+] HID Evt# %u", (unsigned)hid_event_num);
|
||||
printout(outstr);
|
||||
} else {
|
||||
// Short press: reset
|
||||
printout("\n[+] RESETTING");
|
||||
swreset();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // !PIWATCH
|
||||
|
||||
// CDC serial commands
|
||||
// 'r'/'R' = reset, 'h'/'H' = HID event count
|
||||
if (tud_cdc_available()) {
|
||||
char buf[64];
|
||||
uint32_t count = tud_cdc_read(buf, sizeof(buf));
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
switch (buf[i]) {
|
||||
case 'r': case 'R':
|
||||
printout("\n[+] RESETTING");
|
||||
swreset();
|
||||
break;
|
||||
case 'h': case 'H': {
|
||||
char outstr[32];
|
||||
snprintf(outstr, sizeof(outstr), "\n[+] HID Evt# %u", (unsigned)hid_event_num);
|
||||
printout(outstr);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_BOOTSEL
|
||||
// BOOTSEL polling (disabled by default, disrupts Low Speed USB).
|
||||
// Only enable via -DUSE_BOOTSEL for boards without external button.
|
||||
static uint32_t last_bootsel_check = 0;
|
||||
uint32_t now = to_ms_since_boot(get_absolute_time());
|
||||
if (now - last_bootsel_check > 1500) {
|
||||
last_bootsel_check = now;
|
||||
if (bootsel_pressed()) {
|
||||
uint32_t press_start = to_ms_since_boot(get_absolute_time());
|
||||
while (bootsel_pressed()) {
|
||||
sleep_ms(10);
|
||||
}
|
||||
uint32_t press_duration = to_ms_since_boot(get_absolute_time()) - press_start;
|
||||
|
||||
if (press_duration > 2000) {
|
||||
char outstr[32];
|
||||
snprintf(outstr, sizeof(outstr), "\n[+] HID Evt# %u", (unsigned)hid_event_num);
|
||||
printout(outstr);
|
||||
} else {
|
||||
printout("\n[+] RESETTING");
|
||||
swreset();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // USE_BOOTSEL
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user