Skip to content

About

No description, website, or topics provided.

Resources

Stars

6 stars

Watchers

0 watching

Forks

Repository files navigation

Bruce for CardputerZero

A Bruce-style security toolkit UI for the CardputerZero — a purple/black LVGL menu that launches Wi-Fi, Bluetooth, RF, network and SMB tooling from the device screen. Built on the M5Stack CardputerZero LVGL template.

👉 Just want to install it? See INSTALL.md for a copy-paste, step-by-step guide. The sections below are for developers.

⚠️ For authorized security testing, CTF and research only. Several menu entries (Responder, port scans, packet capture) are only legal against systems you own or have written permission to test.

How it works

Rather than reimplementing each protocol, the app shells out to the real Linux binaries already on the device (curl, nc, iw, bluetoothctl, smbclient, responder, rtl_433, …) and streams their output to the screen. That keeps the port tiny and every tool behaves exactly like its CLI.

  • Tool catalog — src/model/tool_catalog.cpp is a plain data list of categories and actions. Add a tool by editing this one file; no screen code changes needed. Each action is an argv run with execvp (no shell string built from user input → no injection surface).
  • Process runner — src/platform/process_runner.* forks/execs a tool, captures stdout+stderr on a reader thread, and delivers it to the LVGL thread via lv_async_call.
  • Screens — one reusable MenuScreen drives both the category menu and each tool list; ToolRunScreen runs a tool and shows its live log; TerminalScreen is the interactive shell behind the "Terminal" category; AboutScreen is static. ScreenManager swaps screens from the current-page subject.
  • Theme — purple/black palette in src/view/ui_const.h; light/dark toggle in the nav bar.
  • Terminal — type a command on the device keyboard, Enter runs it, output streams into a tail-following log (Up/Down recall history while typing, ESC leaves the input). A leading sudo runs the command as root: passwordless through the installed sudoers rule, otherwise the app asks for the sudo password on-device once and caches it for the terminal session. The same screen serves the user and root rows; Tool catalog stays the only place tools are defined.
  • Status bar — the title bar shows Wi-Fi strength and battery (charge state included) read from /sys, refreshed every 5 s (src/platform/device_status.*, ported from the official M5Stack template).
  • Screenshot — pressing the PrintScreen key dumps the active screen to a PNG (src/platform/screenshot_service.*, LVGL snapshot + libpng) and confirms with a toast (src/view/widgets/toast.*).

Architecture (MVVM around LVGL)

  • UI layer: BaseScreen owns the root, title bar, nav bar, and content. Widgets derive from BaseWidgets. The 5-slot NavBar is generic — each screen configures its own buttons.
  • Data model: BaseModel holds current page, theme mode, and menu selection.
  • View model: BaseViewModel exposes state as LVGL observer subjects and provides navigation actions (open menu, run tool, back, quit, toggle theme).
  • Reactive/data binding: src/reactive wraps LVGL observer subjects.
  • Platform layer: Linux input + the process runner, plus native subcommands the app re-execs itself for (--ble-spam, --wardrive, --evil-portal, …) and the --root-sh passthrough that lets the sudoers rule carry root shell rows (catalog scripts and terminal commands alike) without ever authorizing /bin/sh itself. The nav bar maps hardware/keyboard keys 4–8, plus ESC for back/quit.

Repository Layout

.
├── assets/                 # Runtime assets used by the app
│   ├── applications/       # Desktop/app launcher metadata
│   ├── audio/              # Audio resources
│   ├── fonts/              # TTF fonts loaded through FreeType
│   └── images/             # Image resources
├── screenshot/             # Simulator screenshots for supported desktop platforms
├── src/
│   ├── app/                # Application lifecycle, asset loading, screen management
│   ├── config/             # LVGL config headers for desktop and device builds
│   ├── logger/             # Project logging wrapper
│   ├── model/              # Base application data model
│   ├── platform/           # Platform input/hardware integration
│   ├── reactive/           # LVGL observer subjects and binding helpers
│   ├── view/               # Theme, UI constants, screens, and widgets
│   │   ├── screens/        # Page-level LVGL screens
│   │   └── widgets/        # Reusable LVGL widgets such as nav bar and icon button
│   ├── viewmodel/          # BaseViewModel and UI-facing actions/state subjects
│   └── main.cpp            # Program entry point
├── CMakeLists.txt          # Build graph, dependencies, options, targets
├── CMakePresets.json       # Desktop/device configure and build presets
└── README.md

Modules

  • src/app/asset_manager.*: resolves runtime assets from the optional CMake asset root, source tree assets/, and installed /usr/share/<APP_NAME>/ path.
  • src/app/screen_namager.cpp: switches LVGL screens when the current page subject changes.
  • src/config/lv_conf_desktop.h: desktop SDL simulator LVGL settings.
  • src/config/lv_conf_cm0.h: embedded Linux/CardputerZero LVGL settings.
  • src/platform/linux_input.*: Linux evdev keypad support and desktop SDL keyboard routing for nav buttons.
  • src/reactive/subjects.*: typed wrappers around LVGL subjects.
  • src/reactive/bindings.*: helper bindings for labels, theme, widget values, flags, states, and events.
  • src/view/widgets/navbar.*: bottom navigation bar and icon-button action mapping.
  • src/view/widgets/icon_button.*: transparent icon button with font/color/theme support.

Build Options

Common CMake cache options:

Option Default Description
USE_DESKTOP ON Build SDL desktop simulator when ON; build embedded Linux target when OFF.
APP_NAME bruce_cardputerzero Application name used by installed asset lookup.
APP_ASSETS_ROOT empty Optional runtime asset root. Expected layout includes fonts/, images/, etc.
APP_KEY_INPUT_DEVICE empty Optional Linux evdev device path, e.g. /dev/input/event0. Empty means auto-scan /dev/input/event*.
APP_FRAMEBUFFER_DEVICE /dev/fb0 Linux framebuffer device used by embedded builds when APP_USE_DRM=OFF.
APP_USE_DRM OFF Use LVGL's Linux DRM/KMS backend instead of fbdev for embedded builds.
APP_DRM_DEVICE /dev/dri/card0 DRM device path used when APP_USE_DRM=ON.
APP_DRM_CONNECTOR_ID -1 DRM connector id used when APP_USE_DRM=ON; -1 auto-selects.

Asset lookup order:

  1. APP_ASSETS_ROOT when provided by CMake
  2. source-tree assets/ for development
  3. /usr/share/<APP_NAME>/ for installed deployments

Desktop Builds

Desktop builds are intended for fast UI development and use SDL as the LVGL display/input backend.

Simulator Preview

macOS simulator Debian simulator Windows simulator
macOS simulator screenshot Debian simulator screenshot Windows simulator screenshot

Current dependencies info:

Dependency Version Source Notes
LVGL v9.5.0 CMakeLists.txt FetchContent Main GUI framework.
fmt 12.1.0 System package manager or vcpkg.json override Logging and formatted strings.
libpng 1.6.48 System package manager or vcpkg.json override PNG image decoding support for LVGL.
libjpeg-turbo 3.1.3 System package manager or vcpkg.json override JPEG image decoding support for LVGL.
zlib 1.3.1 System package manager or vcpkg.json override Compression dependency used by image libraries.
SDL2 2.32.54 System package manager or vcpkg.json override Desktop simulator display and input backend.
FreeType 2.13.3 System package manager or vcpkg.json override Runtime TTF font rendering.

Windows vcpkg installs use the versions above through manifest mode, with the registry baseline pinned in vcpkg-configuration.json.

Linux Desktop

Debian/Ubuntu dependencies:

sudo apt update
sudo apt install -y \
  build-essential \
  cmake \
  ninja-build \
  libpng-dev \
  libjpeg-dev \
  libfmt-dev \
  libsdl2-dev \
  libfreetype-dev \
  zlib1g-dev

Note

Minimal CMake version is 3.31.0 (in coordinate with Debian 13 trixie), for Ubuntu user you can install latest cmake via snap and run following cmake command with /snap/bin/cmake.

Configure:

cmake --preset linux-x86-64

Build:

cmake --build --preset linux-x86-64-dbg
# alternatively, you can run release build
# cmake --build --preset linux-x86-64-rel

Run:

./build/linux-x86-64/Debug/bruce_cardputerzero
# or launch release build
# ./build/linux-x86-64/Release/bruce_cardputerzero

macOS Desktop

Install the Apple command-line tools:

xcode-select --install

Install dependencies with Homebrew:

brew install \
  cmake \
  ninja \
  libpng \
  jpeg \
  fmt \
  sdl2 \
  freetype \
  dpkg \
  zlib

Configure for Apple Silicon:

cmake --preset darwin-arm64

Build:

cmake --build --preset darwin-arm64-dbg
# alternatively, you can run release build
# cmake --build --preset darwin-arm64-rel

Run:

./build/darwin-arm64/Debug/bruce_cardputerzero
# or launch release build
# ./build/darwin-arm64/Release/bruce_cardputerzero

For Intel macOS, use the darwin-x86-64 configure preset and matching build preset:

cmake --preset darwin-x86-64
cmake --build --preset darwin-x86-64-dbg
# alternatively, you can run release build
# cmake --build --preset darwin-x86-64-rel
./build/darwin-x86-64/Debug/bruce_cardputerzero
# or launch release build
# ./build/darwin-x86-64/Release/bruce_cardputerzero

Windows Desktop

Install CMake and Ninja:

winget install Kitware.CMake
winget install Ninja-build.Ninja

Install a C++ toolchain. Choose one of the following.

MSVC Build Tools:

winget install Microsoft.VisualStudio.BuildTools

In the Visual Studio installer, enable Desktop development with C++ and make sure MSVC and a Windows SDK are selected.

MinGW-w64:

winget install BrechtSanders.WinLibs.POSIX.UCRT

Alternatively, you can download from winlibs.

Install vcpkg:

git clone https://github.com/microsoft/vcpkg.git C:\vcpkg
C:\vcpkg\bootstrap-vcpkg.bat -disableMetrics

Configure environmental variables for current terminal:

$env:VCPKG_ROOT="C:\vcpkg"
$env:PATH="$env:VCPKG_ROOT;$env:PATH"

Tip

Change VCPKG_ROOT to your vcpkg installation directory if it is located elsewhere.

These environment variables are session-scoped, meaning they only apply to the current terminal session. Once the terminal is closed, the variables will be lost and need to be set again in a new session. If you want to a persist environment variable

setx VCPKG_ROOT "C:\vcpkg"

Configure and build with MSVC:

Important

These steps require launching CMake from a Developer Command Prompt or Developer PowerShell provided by Visual Studio.

This ensures that the MSVC environment (compiler, linker, and Windows SDK paths) is properly initialized.

Without this environment setup, CMake may fail to detect or correctly configure the MSVC toolchain.

cmake --preset win32-msvc
cmake --build --preset win32-msvc-dbg
.\build\msvc\Debug\bruce_cardputerzero.exe

# alternatively for release build
# cmake --build --preset win32-msvc-rel
# .\build\msvc\Release\bruce_cardputerzero.exe

Configure and build with MinGW-w64:

Important

These steps require a properly configured MinGW-w64 toolchain in your system PATH.

Please ensure the following compilers are available in the current terminal session:

  • gcc
  • g++
  • ld
  • ar

You can verify the setup by running:

gcc --version
g++ --version

If these commands are not recognized, you must add MinGW-w64 bin directory to your PATH before configuring CMake.

cmake --preset win32-mingw64
cmake --build --preset win32-mingw64-dbg
.\build\mingw64\Debug\bruce_cardputerzero.exe

# alternatively for release build
# cmake --build --preset win32-mingw64-rel
#.\build\mingw64\Release\bruce_cardputerzero.exe

Note

VCPKG will handle the dependencies during CMake configuration process automatically, this may take several minutes depend on you network connection.

CardputerZero Cross Build

This preset builds an aarch64 Linux target from a host machine with an aarch64-linux-gnu-gcc/g++ toolchain. The BSP at .cache/sdk_bsp-src is treated as a sysroot: headers, libraries, startup objects, and pkg-config metadata are resolved from that directory first. If that directory does not exist on the first configure, the toolchain downloads and extracts sdk_bsp.tar.gz automatically before CMake runs compiler checks.

Install a cross compile toolchain:

  • Debian
sudo apt install crossbuild-essential-arm64
  • MacOS
brew install aarch64-unknown-linux-gnu

Note

On Windows, it's recommended to use WSL for cross build or you can download cross compile tools and configure the PATH yourself

Configure:

cmake --preset cp0-cross

Build:

cmake --build --preset cp0-cross-dbg
# or release build
# cmake --build --preset cp0-cross-rel

Deploy the release package to your device after filling in your device user and IP:

REMOTE_USER=<user> REMOTE_HOST=<device-ip> ./deploy.sh

By default, the debian package is copied to '$HOME' folder, normally it's under '/home/<user>'.

On your device, install the copied package with apt and replace the package file name with the one you copied:

sudo apt install --no-install-recommends ./BruceCardputerZero_0.1.0_bruce1_arm64.deb

Development Guide

Navigation Keys

The bottom nav bar maps hardware/keyboard keys from left to right:

Key Nav item
4 First icon button
5 Second icon button
6 Third icon button
7 Fourth icon button
8 Fifth icon button
ESC First icon button / quit

Per-screen slot meanings: on ToolRunScreen the slots are Back / Up / Run-Stop / Down / Clear; on TerminalScreen they are Back / Up / Run-Stop / Down / Type (slot 4 focuses the command input — while typing, every key feeds the input, Enter runs the command, Up/Down recall history and ESC returns to nav mode; a leading sudo in a command runs it as root).

Adding a Screen

  1. Add a new page enum value in src/model/base_model.h.
  2. Add the page transition/state logic in BaseModel and BaseViewModel.
  3. Create a screen under src/view/screens/ deriving from BaseScreen.
  4. Extend ScreenManager to load the new screen when the page subject changes.
  5. Update NavBar icons and callbacks as needed.

Adding a Widget

  1. Derive from BaseWidgets.
  2. Implement build() and create LVGL objects under parent_.
  3. Use reactive::bind_* helpers for text, style, state, or event bindings.
  4. Keep LVGL observer lifetimes object-bound whenever possible with lv_subject_add_observer_obj or reactive::observe_obj.

Fonts and Assets

Fonts are loaded at runtime through FreeType. Place development fonts in:

assets/fonts/

Installed deployments can place fonts in:

/usr/share/<APP_NAME>/fonts/

You can also provide an asset root at configure time:

cmake --preset darwin-arm64 -DAPP_ASSETS_ROOT=/path/to/assets

Debian Package

Debian packages are produced with CPack and written to dist/. The package file name follows:

<AppName>_<Version>_m5stack1_arm64.deb

Default example:

dist/BruceCardputerZero_0.1.0_bruce1_arm64.deb

Package layout:

Path Content
/usr/bin/bruce_cardputerzero Application executable.
/usr/share/bruce_cardputerzero/ Runtime assets: fonts, images, audio.
/usr/share/APPLaunch/applications/bruce_cardputerzero.desktop APPLaunch launcher entry.
/usr/share/APPLaunch/share/images/template*.png APPLaunch launcher icons/fallbacks.
/usr/lib/systemd/system/bruce_cardputerzero.service Optional systemd service for embedded autostart.
/usr/share/doc/bruce_cardputerzero/ README and third-party asset license notes.

Build and package:

cmake --preset cp0-cross
cmake --build --preset cp0-cross-rel
cpack --preset cp0-cross-deb

Or run the full configure, release build, and package flow with one workflow preset:

cmake --workflow --preset cp0-cross-package

Note

Use Debian based Linux host with CPack generator as other OS may not resolve the dependencies correctly no full dpkg, dpkg-shlibdeps, objdump and readelf support

Contributing

If you have better framework designs on Embedded Linux or build system practice, feel free to let us know.

License

Project released under MIT license. More license information can be found in assets folder.

About

No description, website, or topics provided.

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages