Rootless WiFi Lab is a lightweight distribution for running an Alpine Linux ARM64 virtual machine on Android through Termux and QEMU, without rooting Android. It provides a practical environment for authorized Wi-Fi diagnostics, wireless security research, monitor-mode experiments, and packet-injection testing with compatible USB adapters.
The project is not an Android kernel module and it does not turn every phone or every adapter into a wireless assessment platform. QEMU provides the Linux guest, Termux provides the Android-side process and USB permission bridge, and the guest kernel must contain a compatible driver and firmware. The supported and development-tested target is the Atheros AR9271 USB adapter using the ath9k_htc driver and firmware.
Authorized-use requirement: Use monitor mode, packet transmission, capture, and security tools only on networks and devices that you own or are explicitly authorized to assess. This project does not include automated credential theft, client disruption, WPS cracking, or unauthorized-access workflows.
Hardware status: The VM, launchers, persistent storage, and local QEMU paths are tested in the development environment. Actual Android OTG permission handling, AR9271 passthrough, adapter power stability, and wireless-driver behavior must still be verified on the target phone.
The project packages two independent Alpine Linux ARM64 environments in one release. The Full environment is the broader and heavier option for users who want a more complete guest and more room for additional packages. The Lite environment is a compact Wi-Fi-focused option with a smaller footprint and fewer preinstalled packages. Lite is designed to reach its console in approximately 30 seconds or less on a supported, warmed-up Android device, although the actual time depends on the phone, storage speed, QEMU load, selected profile, and USB/network setup.
Both variants use external persistent storage. A project update replaces launchers, scripts, kernels, and documentation without replacing the writable guest image. Installed Alpine packages, /root files, persistent PATH entries, backups, and exports therefore survive normal project updates.
| Capability | Full | Lite |
|---|---|---|
| Intended role | Broader, heavier general-purpose guest | Compact Wi-Fi-focused guest |
| Storage model | Independent persistent Full image | One persistent image shared by all Lite tiers |
| Kernel | Linux LTS kernel and initramfs path | safe, tiny, and lts kernel choices |
| Preinstalled scope | Larger guest lineage and broader utilities | Minimal guest with wireless diagnostics and AR9271 firmware |
| Boot target | Heavier and device-dependent | Approximately 30 seconds or less on supported devices; not a guarantee |
| Recommended use | Full Linux workspace and broader package expansion | Fast daily Wi-Fi work and adapter troubleshooting |
The primary supported adapter is the Atheros AR9271, commonly exposed by Android as USB ID 0cf3:9271. The Lite build includes the Alpine Linux linux-lts kernel path, ath9k_htc firmware package, wireless regulatory data, iw, usbutils, kmod, ethtool, and diagnostic helpers. The adapter must still be visible to Android, granted to Termux through Termux:API, and accepted by QEMU USB passthrough.
Other USB Wi-Fi adapters may work, but they are not automatically supported merely because Android can list them. A different adapter requires all of the following: a Linux ARM64 driver compatible with the exact guest kernel, the required firmware, a USB passthrough path that works on the target phone, and tools that understand the resulting wireless interface. The adapter's Android driver is irrelevant to the Linux guest; the guest needs its own Linux driver and firmware.
A user can install additional drivers manually inside the VM when the driver is available as an Alpine package or as a module and firmware set built for the exact guest kernel. The safe process is to start the VM with Internet access, install the required signed Alpine packages, load the module with modprobe, and verify it with dmesg, modinfo, lsusb, and iw dev. If the driver is not available for the guest kernel, the user must build or provide a compatible kernel/module/initramfs set; installing an arbitrary Android driver or an x86 Linux module will not work. Installing a driver also does not bypass Android USB permissions, OTG limitations, regulatory restrictions, or adapter power problems.
Example diagnostic sequence inside Lite is:
wifi-diagnose
lsusb
iw dev
modinfo ath9k_htc 2>/dev/null || true
dmesg | tail -n 80The project deliberately identifies AR9271 as the supported target rather than claiming universal support for every Realtek, MediaTek, Ralink, or Broadcom adapter.
The host is an Android device running a current ARM64-capable Termux installation with enough free storage for the selected release and persistent images. The host does not need Android root. A functional USB OTG connection is required for an external adapter, and the phone must expose that adapter to Termux.
The general installer requires pkg, bash, curl, tar, coreutils, and sha256sum. It installs the remaining host-side packages used by the VM, including the headless AArch64 QEMU package, Termux:API integration, socat, and e2fsprogs. USB use requires the Termux:API application and the matching termux-api package. The Android-side USB permission prompt is controlled by Termux:API; it cannot be simulated by the guest.
The guest needs Internet access only when downloading Alpine packages, firmware, source dependencies, or other user-selected tools. The launcher asks about Internet access during an interactive start. Offline operation is preferred when networking is not needed.
The supported new-user path is the public install.sh bootstrap installer. It downloads the latest full release, verifies the release SHA-256 file before extraction, creates the short project directory ~/awvm, and runs the bundled host installer.
Run the following commands in Termux:
pkg update -y
pkg install -y bash curl tar coreutils
curl -fL https://raw.githubusercontent.com/Mohzh344/rootless-wifi-lab/main/install.sh \
-o install.sh
bash install.shThe installer refuses to overwrite an existing project directory. It keeps writable VM data outside the project so that the project can later be replaced safely. The normal locations are:
Project checkout: $HOME/awvm
Persistent data: $XDG_DATA_HOME/awvm/
or $HOME/.local/share/awvm/
If a previous v0.3.5 or v0.3.6 installation already has persistent data under $HOME/.local/share/android-wifi-monitor-injection-rootless, the compatibility logic prefers that existing directory instead of creating duplicate images. You can select an explicit location before installation with VM_STATE_ROOT:
export VM_STATE_ROOT="$HOME/awvm-data"
bash install.shAfter installation, check the environment and start the launcher:
cd "$HOME/awvm"
bash bin/vmctl.sh doctor
bash bin/vmctl.sh info
bash bin/vm-launcher.shThe supported update path for an existing user is the updater bundled inside the current checkout:
cd "$HOME/awvm"
bash bin/awvm-update.shThe updater reads the latest GitHub Release, downloads the smaller thin update archive, verifies its SHA-256 file, runs the new host installer while the old checkout remains available for image adoption, and replaces the project only after the installer succeeds. The thin archive intentionally contains no writable Full or Lite image, so it does not re-download or replace installed guest data.
| Command | Function |
|---|---|
bash bin/awvm-update.sh |
Check, confirm, download, verify, install, and replace safely |
bash bin/awvm-update.sh --check |
Show the latest release and make no download or file changes |
bash bin/awvm-update.sh --yes |
Skip the confirmation prompt |
bash bin/awvm-update.sh --yes --keep-old |
Keep a dated copy of the previous project checkout |
If the current project is not ~/awvm, use its actual location:
cd "/path/to/current/awvm-project"
bash bin/awvm-update.shDo not delete the old project manually before the updater finishes. If a download, checksum, extraction, package installation, or replacement step fails, the updater keeps the existing checkout and persistent images available. If it is launched from inside the old checkout, it retains a temporary old-checkout slot so the parent shell does not remain in a deleted working directory; run cd "$HOME/awvm" after the update.
Most users should use install.sh. Manual installation is useful for offline staging or for selecting a specific release. Download the archive and its matching checksum from the v0.3.7 Release, verify it, extract it, and run the host installer:
sha256sum -c termux-ath9k-vm-v037-full-lite-ready.tar.gz.sha256
mkdir -p "$HOME/awvm"
tar --sparse -xzf termux-ath9k-vm-v037-full-lite-ready.tar.gz \
-C "$HOME/awvm" --strip-components=1
cd "$HOME/awvm"
bash bin/install-termux.shUse the full archive for a first installation or when no persistent image exists. Use the thin update archive only when the existing Full/Lite image is already in persistent storage:
| Release asset | Use case | Writable images included |
|---|---|---|
termux-ath9k-vm-v037-full-lite-ready.tar.gz |
New installation or first adoption | Yes |
termux-ath9k-vm-v037-update.tar.gz |
Existing installation update | No |
Matching .sha256 file |
Integrity verification | Not applicable |
The project checkout contains launchers and read-only release artifacts. The writable guest images are adopted into external persistent storage on the first Full installation. The storage library creates separate Full and Lite directories together with backups/, exports/, and an image-operation lock directory.
| Environment | Default persistent state |
|---|---|
XDG_DATA_HOME is set |
$XDG_DATA_HOME/awvm/ |
XDG_DATA_HOME is not set |
$HOME/.local/share/awvm/ |
| Existing legacy data is present | Existing $HOME/.local/share/android-wifi-monitor-injection-rootless/ is preferred for compatibility |
| Explicit override | $VM_STATE_ROOT |
A later full archive does not overwrite an image that already exists. A thin update has no writable image at all. This design preserves installed packages, /root, /home, /opt, /usr/local, managed PATH files, and the Lite image shared by the safe, tiny, and lts kernel tiers.
The storage path must remain outside a checkout that will be replaced. The installer and updater reject configurations where the persistent state is inside the project directory. Always stop QEMU before editing, backing up, resizing, exporting, or importing an image.
The recommended entry point is the unified launcher:
cd "$HOME/awvm"
bash bin/vm-launcher.shIn interactive mode it detects available Full and Lite bundles, asks which variant to run, offers a Lite kernel tier, asks whether Internet access should be granted, offers console authentication modes, and optionally requests USB permission. A dry run prints the selected plan without starting QEMU:
bash bin/vm-launcher.sh --full --dry-run --non-interactive
bash bin/vm-launcher.sh --lite --dry-run --non-interactiveTypical scripted starts are:
VM_VARIANT=full AUTH_MODE=root-console ENABLE_NET=0 \
bash bin/vm-launcher.sh --non-interactive
VM_VARIANT=lite KERNEL_TIER=safe PROFILE=wifi-only \
AUTH_MODE=root-console ENABLE_NET=0 \
bash bin/vm-launcher.sh --non-interactiveThe launcher accepts these important options:
| Option | Purpose |
|---|---|
--full |
Select the Full environment |
--lite |
Select the Lite environment |
--auth-mode MODE |
Select root-console, login, or login-empty |
--root-console |
Direct root console without a password prompt |
--login |
Normal BusyBox username/password console |
--login-empty |
Empty-root-password console for private local testing only |
--dry-run |
Print the plan without starting QEMU |
--non-interactive |
Disable prompts and require explicit choices when ambiguous |
The launcher synchronizes the Alpine clock from the Android/Termux clock at each start unless TIME_SYNC=0 is explicitly set. It asks about guest Internet access on interactive starts. ENABLE_NET=1 enables QEMU user networking and guest DHCP; ENABLE_NET=0 keeps the guest offline.
root-console is the recommended local mode. The console starts /bin/sh -l directly as root, reads /etc/profile and /etc/profile.d, and does not ask for a username or password. The -l flag means login shell; it does not invoke a password manager.
login starts a BusyBox getty username/password prompt using the guest's root password. login-empty deliberately clears the root password for private local testing and must never be combined with Internet access or an untrusted console. Authentication databases are intentionally excluded from portable migration archives.
A PATH exported interactively disappears when that shell ends. A PATH entry written through vmctl.sh path add is stored in the persistent guest at /etc/profile.d/vmctl-path.sh and is loaded by both the direct root login shell and a normal login shell.
Connect the adapter through a compatible OTG connection, then check whether Android exposes it to Termux:
termux-usb -l
bash bin/vmctl.sh usb
bash bin/vmctl.sh doctorStart the unified launcher interactively. It lists Android-visible USB devices and requests permission for the selected device. The direct passthrough path recognizes the AR9271 USB identity 0cf3:9271 when the adapter reports that identity.
After entering Alpine, verify the device and driver before using any wireless tool:
wifi-diagnose
lsusb
iw dev
iw reg getSeeing 0cf3:9271 in lsusb proves only that USB enumeration reached the guest. It does not prove that ath9k_htc loaded, that firmware was found, that a wireless interface was created, or that monitor mode and injection are available. The diagnostic output and dmesg are the correct next checks.
If the adapter disconnects repeatedly, first try a short, high-quality OTG cable and a charge-through or Y-OTG arrangement with an appropriate 5 V source. A Linux guest cannot repair an Android-side power reset, USB permission reset, cable problem, or phone-specific OTG limitation. USB power behavior is device-specific and must be tested on the target phone.
The images are intentionally not filled with every security utility. This keeps Lite small and allows users to install only what they need. Start the VM with Internet access, enter the guest as root, and run:
install-wifi-toolsThe installer first requires a guest network interface and a DHCP lease. It then uses Alpine apk with certificate verification enabled and installs the signed base set:
aircrack-ng tcpdump hostapd wireless-regdb iw usbutils
kmod ethtool wireless-tools
The script records its result in /etc/wifi-tools-install-status. It does not start capture, deauthentication, WPS, credential, or packet-transmission actions automatically. Alpine repository availability changes over time; at this release, wifite, bully, reaver, kismet, hcxdumptool, and hcxtools are recorded as optional tools rather than guaranteed repository packages. They require separate, user-directed installation or source builds and are not silently fetched by the base installer.
An explicitly requested hcx source build is available for advanced users:
BUILD_HCX=1 install-wifi-toolsThis downloads pinned source archives and compiler dependencies, builds the tools inside the guest, installs the resulting binaries, and removes build dependencies where possible. It requires a working guest network and considerably more time and storage than the base package set. The WPS-related path is intentionally opt-in and is not part of the default installation.
All normal Alpine package operations retain apk package signature verification. The installer may expose an explicitly reported TLS fallback for unusual guest certificate paths, but it does not disable apk package signatures.
bin/vmctl.sh is the single administration interface. It reduces the need to remember several separate maintenance commands and protects image-writing operations with an offline check, ext4 validation, sparse-aware copies, and an image lock.
| Command | Function | Example |
|---|---|---|
doctor |
Check host tools, release layout, storage, images, and USB readiness | bash bin/vmctl.sh doctor |
info |
Show image paths, sizes, auth entries, PATH entries, and package metadata | bash bin/vmctl.sh info --lite |
status |
Show QEMU processes and persistent image state | bash bin/vmctl.sh status |
backup |
Create a sparse-aware safety backup of a stopped image | bash bin/vmctl.sh backup --lite |
export |
Export portable user data and an apk world list | bash bin/vmctl.sh export --lite |
import |
Import portable user data into a stopped target image | bash bin/vmctl.sh import --full /path/to/export.tar.gz |
resize |
Grow a stopped ext4 image after creating a backup | bash bin/vmctl.sh resize --lite 3G |
path add |
Persist a guest PATH directory across reboot and updates | bash bin/vmctl.sh path add --lite /opt/tools/bin |
path list |
List managed persistent PATH entries | bash bin/vmctl.sh path list --lite |
usb |
Print non-destructive Android USB and host diagnostics | bash bin/vmctl.sh usb |
Operations that write an image refuse to proceed while QEMU is using that image. If a Termux process is interrupted, the lock can be recovered after the owning process is no longer running. Never force concurrent debugfs, resize2fs, e2fsck, export, import, or backup operations against the same image.
Create a safety backup before major changes:
bash bin/vmctl.sh backup --full
bash bin/vmctl.sh backup --liteBackups are local sparse-aware copies under the persistent state's backups/ directory. Export is intended for moving user data between Lite and Full or between separate installations. It does not copy the whole incompatible filesystem image:
bash bin/vmctl.sh export --lite
bash bin/vmctl.sh export --fullImport into a stopped target image:
bash bin/vmctl.sh import --full /path/to/lite-user-data-YYYYMMDDTHHMMSSZ.tar.gz
bash bin/vmctl.sh import --lite /path/to/full-user-data-YYYYMMDDTHHMMSSZ.tar.gzThe portable archive includes user-oriented paths such as /root, /home, /opt, /usr/local, /etc/profile.d, and an explicit /etc/apk/world package list. The importer writes the package list to /root/.vm-migration/apk-world and creates /root/.vm-migration/apply-packages.sh. Boot the target with Internet access when packages are needed, then run that helper as root. Packages are resolved from the target's repositories and signatures instead of being copied blindly from the old filesystem.
Authentication databases, /etc/inittab, repositories, kernels, firmware, and /lib/modules are excluded intentionally. Reconfigure console authentication with the launcher rather than copying /etc/shadow or /etc/passwd between variants. Export archives may contain private files from /root; store them securely.
Full and Lite are separate environments. Lite's kernel tiers are not monitor-mode switches and they do not reinstall packages:
| Selection | Meaning | Persistent image |
|---|---|---|
Full |
Broader and heavier Alpine guest with its own image | Full image |
Lite / safe |
Recommended compatibility-oriented custom kernel | Shared Lite image |
Lite / tiny |
Smallest AR9271-focused custom kernel | Shared Lite image |
Lite / lts |
Fallback Linux LTS kernel and initramfs path | Shared Lite image |
Switching from safe to tiny or lts changes the boot kernel only. It does not remove installed packages, firmware, /root files, or managed PATH entries.
The public user workflow intentionally has only two top-level release entry points: install.sh for a new user and bin/awvm-update.sh for an existing user. Other files are the launcher, administration interface, compatibility wrappers, guest helper, or developer/build tooling.
| Script | Role | How to run |
|---|---|---|
install.sh |
Public new-user installer; installs bootstrap packages, downloads the latest full archive, verifies SHA-256, extracts it, and runs host installation | bash install.sh from Termux |
bin/awvm-update.sh |
Existing-user updater; downloads and verifies the thin archive and replaces the checkout safely | bash bin/awvm-update.sh from the current checkout |
bin/vm-launcher.sh |
Main Full/Lite dispatcher with auth, network, clock, tier, profile, and USB choices | bash bin/vm-launcher.sh |
bin/vm-launcher-unified.sh |
Compatibility wrapper for the main dispatcher | bash bin/vm-launcher-unified.sh |
bin/vm-launcher-legacy.sh |
Preserved advanced legacy launch path | Use only when a legacy layout is required |
bin/vmctl.sh |
Unified diagnostics, backup, export/import, resize, PATH, and USB administration | bash bin/vmctl.sh doctor |
bin/vm-backup.sh |
Compatibility wrapper for vmctl.sh backup |
bash bin/vm-backup.sh --lite |
bin/vm-export.sh |
Compatibility wrapper for vmctl.sh export |
bash bin/vm-export.sh --lite |
bin/vm-import.sh |
Compatibility wrapper for vmctl.sh import |
bash bin/vm-import.sh --lite file.tar.gz |
bin/install-termux.sh |
Internal host dependency installer and persistent-image adoption step | bash bin/install-termux.sh after manual extraction |
bin/launch-vm-full-unified.sh |
Full QEMU adapter used by the dispatcher | Normally called by vm-launcher.sh |
bin/launch-vm-lite.sh |
Lite QEMU adapter used by the dispatcher | Normally called by vm-launcher.sh |
bin/qemu-lite-direct-inner.sh |
Inner Lite USB/QEMU command path | Normally called by the Lite launcher |
bin/usb-attach-lite-direct.sh |
Termux USB direct-passthrough helper | Normally called by the launcher |
src/vm-storage-lib.sh |
Shared persistent-image adoption, locks, sparse backup, and ext4 helpers | Sourced by host scripts; not normally run directly |
src/configure-console-auth.sh |
Changes a stopped image between auth modes with validation and backup | Developer/advanced maintenance |
src/patch-console-login-shell.sh |
Applies the /bin/sh -l console fix to a stopped image |
Developer/advanced maintenance |
src/guest-install-wifi-tools.sh |
Guest-side package installer copied to /usr/local/sbin/install-wifi-tools |
Inside Alpine: install-wifi-tools |
src/package-v037-unified-release.sh |
Developer packager for Full and thin v0.3.7 archives | Run only on a prepared build host |
The image builder and kernel-tier scripts under src/ are developer operations. End users do not need to run them to install or update a published release.
Rebuilding is optional. It requires a Linux build host with the project inputs, Alpine artifacts, AArch64 emulation, filesystem tools, and enough temporary storage. The canonical Full input, Lite build input, and kernel sources are selected through the packager's environment variables.
./src/download-artifacts.sh
./src/build-image.sh
./src/build-lite-image.sh
./src/package-v037-unified-release.shFor a thin update archive, set INCLUDE_IMAGES=0 and choose an update output path. The packager verifies ext4 images, applies the console-shell fixes, copies the current launchers and documentation, removes old release notes from the bundle, and writes archive-level and guest-level checksums. The historical Full v0.3.0 tag is not rewritten.
When the VM does not start, begin with a dry run and the non-destructive diagnostics:
bash bin/vm-launcher.sh --lite --dry-run --non-interactive
bash bin/vmctl.sh doctor
bash bin/vmctl.sh info --lite
bash bin/vmctl.sh statusIf Lite reports a missing image, confirm that VM_STATE_ROOT points to the directory containing lite/alpine-ath9k-v030-lite.img. If an old installation exists, check the legacy path before creating another image. If login fails, use the recommended root-console mode; normal login deliberately depends on the guest's password database and login-empty is for private local testing only.
If a Wi-Fi tool is not found after installation, verify that it was installed inside the guest rather than on the Termux host, check echo "$PATH", and use bash bin/vmctl.sh path list --lite or install-wifi-tools as appropriate. Start Lite with ENABLE_NET=1 when apk needs Internet access. A transient host network connection is not the same as a guest DHCP lease.
If lsusb sees the adapter but iw dev does not show an interface, inspect wifi-diagnose, dmesg, modinfo ath9k_htc, firmware availability, and the selected kernel tier. If Android does not list the adapter in termux-usb -l, troubleshoot the cable, OTG mode, Android permission, and power path before changing the guest.
| Path | Purpose |
|---|---|
install.sh |
General new-user bootstrap installer |
bin/awvm-update.sh |
Bundled existing-user updater |
bin/vm-launcher.sh |
Recommended Full/Lite dispatcher |
bin/vmctl.sh |
Unified administration interface |
full/guest/ |
Full release kernel and image bundle before adoption |
lite/guest/ |
Lite kernels, initramfs, and image bundle before adoption |
src/vm-storage-lib.sh |
Persistent storage and image-safety library |
src/guest-install-wifi-tools.sh |
Guest Wi-Fi package installer source |
src/package-v037-unified-release.sh |
v0.3.7 Full/thin release packager |
docs/RELEASE-v0.3.7.md |
Release migration and verification notes |
docs/LITE-v0.3.7.md |
Lite-specific release notes |
docs/UNIFIED-RELEASE.md |
Full/Lite distribution contract |
README-UNIFIED.md |
README copy embedded into unified release archives |
The public installer and updater download only the selected GitHub Release asset and its matching SHA-256 file. They verify the archive before extraction, reject absolute and traversal paths, refuse symbolic-link project targets where applicable, keep writable VM state outside the replaceable checkout, and replace an existing checkout only after the host installer succeeds.
Alpine package signatures remain enabled. The project does not automatically install or launch offensive workflows. The user remains responsible for authorization, regulatory-domain compliance, transmit-power limits, adapter firmware licensing, private export archives, and the physical safety of the Android device and USB connection.
[1] QEMU Arm virt machine documentation — virtual ARM machine model used by the launchers.
[2] Termux:API project — Android-facing APIs used for USB permission and host integration.
[3] Alpine Package Keeper documentation — signed package installation and repository behavior.
[4] Linux Wireless ath9k documentation — Linux driver family background for the AR9271 target path.
[5] Rootless WiFi Lab repository — source, release assets, issue tracker, and project history.