0xhim4ri-81x/NRcap32

GitHub: 0xhim4ri-81x/NRcap32

该项目通过 ESP32 配合 Termux,让未 root 的 Android 手机以极低成本实现 Wi-Fi 监听抓包和无线安全分析。

Stars: 6 | Forks: 2

# NRcap32 NRcap32 通过 USB OTG 将无线电层工作完全卸载给 ESP32,从而彻底绕过了 Android 封闭的 Wi-Fi API。其结果是:在原厂、未 root 的 Android 手机上实现监听模式、被动数据包捕获、带有 radiotap 标注的 pcap 输出以及 EAPOL 握手包捕获。 ``` Stock Android phone ──USB OTG── ESP32-C3 SuperMini (~$3) │ │ Termux (Python) ←──────────────────→ Raw 802.11 frames No root. No ROM. Binary protocol Monitor mode ```

ESP32-C3-SuperMini connected to Android phone via OTG cable

## 为什么开发这个项目 Android 从未向用户空间应用开放过监听模式或原始数据包注入——在大多数设备上,即使拥有 root 权限也无法实现。传统的实现方式需要一部已 root 的手机、一个定制内核(例如 NetHunter)、一个受支持的外部 USB Wi-Fi 适配器,并且还要靠大量运气去匹配硬件版本。 NRcap32 完全规避了这整个问题: - **ESP32** 负责处理所有无线电层面的工作——混杂模式捕获、信道跳频、原始帧注入和 EAPOL 过滤 - **Termux** 使用 `termux-usb` + libusb 通过 USB CDC 与其通信——无需 root、无需内核模块、无需定制 ROM - **Python 桥接程序** 使用带有流量控制的紧凑型二进制帧协议,而不是串口 ASCII 通信 总硬件成本:不到 5 美元。适用于任何具有 USB-C 或 micro-USB 接口并配有 OTG 数据线的 Android 手机。 ## 功能 | | | |---|---| | **Wi-Fi 扫描** | 主动扫描,获取 SSID、BSSID、信道、RSSI 和安全类型 | | **数据包捕获** | 固定信道或信道跳频的混杂模式捕获,保存为带有 radiotap 头部的 `.pcap` 文件(兼容 Wireshark) | | **EAPOL 捕获** | 被动握手捕获,可选择按 BSSID 进行过滤 | | **解除认证 + 捕获** | 发送 deauth 帧以触发握手,同时捕获 EAPOL | | **实时流传输** | 通过命名 FIFO 将 pcap 输出通过管道传输给 termshark 进行实时分析 | | **心跳监测** | ESP32 每 5 秒发送一次运行时间和空闲堆栈信息,用于健康监测 | | **模块化固件** | 专为扩展新 CMD 而设计——计划推出 IR、NRF24 和 CC1101 模块 | ## 硬件 | 组件 | 状态 | 备注 | |-----------|:------:|-------| | **ESP32-C3 SuperMini** | ✅ 已测试 | 主要目标 —— 约 3 美元,内置原生 USB CDC | | ESP32-S3(任意开发板) | ⚠️ 未测试 | 更大的 RAM/flash,原生 USB CDC,双核 | | ESP32-S2(任意开发板) | ⚠️ 未测试 | 单核,原生 USB CDC,成本更低 | | USB OTG 数据线 / 转接器 | — | 根据你的手机选择 USB-C OTG 或 micro-USB OTG | | Android 手机 | — | 任何支持 USB host 模式的系统版本 —— 无需 root | 所有受支持的开发板均使用**原生 USB CDC** —— 无需外部 USB-UART 桥接芯片(CP2102/CH340)。它们在 Android 上显示为 `303A:xxxx` 并直接通过 USB 进行通信。 固件使用 ESP32 内置的 2.4 GHz 无线电 —— 无需外部天线。 ## 快速开始 ### 1. 安装依赖 ``` pkg update && pkg install python termux-api libusb pip install pyusb ``` 还需从 [F-Droid](https://f-droid.org) 安装 **Termux:API** 配套应用 —— *请勿*使用 Play 商店版本,该版本已过时。 ### 2. 克隆仓库 ``` git clone https://github.com/0xhim4ri-81x/nrcap32 cd nrcap32 ``` ### 3. 刷入固件 ``` cd firmware/ # 刷入 ESP32-C3 SuperMini(主要测试目标) pio run -e esp32-c3-supermini --target upload # 确认已正确启动 — 您应该会看到:ESP32_READY pio device monitor --baud 115200 ``` 如果你不想从源码构建,也可以在 [Releases](https://github.com/0xhim4ri-81x/nrcap32/releases) 页面下载预构建的二进制文件。有关 `esptool.py` 的刷入说明,请参阅 [固件部分](#firmware)。 ### 4. 连接并运行 通过 OTG 数据线将 ESP32 插入你的手机。首次运行时,Android 会弹出 USB 权限对话框 —— 点击 **OK**。该权限将持续有效,直到你拔下设备。 ``` chmod +x nrcap32 ./nrcap32 scan ``` **或者使用自动安装程序:** ``` curl -sSL https://raw.githubusercontent.com/0xhim4ri-81x/nrcap32/main/install.sh | bash ``` ## 用法 所有命令都遵循相同的模式 —— 脚本会检测 USB 设备,通过 `termux-usb` 请求权限,并使用获得的文件描述符重新调用自身。 ### 扫描附近的网络 ``` ./nrcap32 scan ``` ``` Found device: /dev/bus/usb/002/008 Requesting USB permission (tap OK)... [2026-06-19 17:38:32] === WiFi Network Scan === [2026-06-19 17:38:32] Device: 303A:1001 ESP32-S3 native USB CDC ========================================================================================== SSID BSSID CH RSSI SECURITY ------------------------------------------------------------------------------------------ HomeNetwork C8:3A:35:CA:75:48 11 -64 WPA/WPA2-PSK OfficeWifi B0:4E:26:CC:2E:F8 3 -66 WPA2-PSK 2 networks found. ``` ### 捕获数据包 ``` # 固定 channel ./nrcap32 sniff --channel 6 ./nrcap32 sniff --channel 6 -o capture.pcap # Channel 跳频(每 300ms 跳频 1–13,使用 Ctrl+C 停止) ./nrcap32 sniff --hop --interval 300 ``` ### 在 Wireshark / termshark 中打开 ``` # 传输文件并在 PC 上打开 wireshark capture.pcap # 通过手机上的 termshark 实时查看 mkfifo /tmp/live.pcap termshark -i /tmp/live.pcap & ./nrcap32 sniff --channel 6 -o /tmp/live.pcap ``` ### 捕获 EAPOL 握手包(被动) ``` ./nrcap32 sniff --channel 6 --eapol-only --bssid C8:3A:35:CA:75:48 ``` ### 解除认证 + 握手包捕获 ``` ./nrcap32 deauth \ --bssid C8:3A:35:CA:75:48 \ --channel 11 \ --count 15 \ --capture-secs 30 ``` 发送 15 个 deauth 帧以断开客户端连接,然后捕获 EAPOL 帧持续 30 秒。生成的 pcap 文件可用于 Hashcat 或 Aircrack-ng 进行离线 WPA2 密钥测试。 ## 环境 NRcap32 支持三种运行时环境,可通过 `detect_backend()` 自动检测。相同的 CLI 命令在三种环境中的工作方式完全相同。 ### 无需 root(原生 Termux) 最独特的用例。适用于任何未经修改的 Android 手机。 ``` Android USB host stack ↓ termux-usb (requests permission, grants fd) ↓ libusb_wrap_sys_device(fd) ↓ nrcap32 Python ``` ``` pkg install python termux-api libusb && pip install pyusb # 从 F-Droid 安装 Termux:API ./nrcap32 scan # permission popup appears on first run ``` ### 拥有 root(Termux + tsu/sudo) 以 uid 0 运行时,libusb 会直接打开 `/dev/bus/usb` —— 无需 `termux-usb`,无权限对话框,无引导子进程。速度更快且更简单。 ``` pkg install python libusb && pip install pyusb tsu # or: sudo ./nrcap32 scan ./nrcap32 scan ``` ### Kali NetHunter 无论在 NetHunter 终端(Kali chroot,root 环境)还是在并行运行的 Termux 会话中均可正常工作。 ``` # 在 NetHunter 终端(root)中 apt update && apt install python3 python3-pip libusb-1.0-0 pip3 install pyusb ./nrcap32 scan # 注意:如果 cdc_acm 占用了接口,nrcap32 会自动释放它 ``` ### 后端总结 | 环境 | uid | USB 访问方式 | |---|:---:|---| | 原生 Termux(无 root) | 1000 | `termux-usb` → `libusb_wrap_sys_device(fd)` | | Termux + root(tsu/sudo) | 0 | libusb → 直接访问 `/dev/bus/usb` | | NetHunter 终端 | 0 | libusb → 直接访问 `/dev/bus/usb` | | NetHunter + Termux(无 root) | 1000 | `termux-usb` → `libusb_wrap_sys_device(fd)` | 检测过程完全自动 —— 无需 `--root` 标志或手动配置。 ## 对比 | | NRcap32(无 root) | NRcap32(有 root) | NetHunter + 外部适配器 | |--|:-----------------:|:--------------:|:------------------------:| | 需要 root | ✗ | ✓ | ✓ | | 定制内核 / ROM | ✗ | ✗ | ✓ | | 硬件成本 | ~$5 | ~$5 | $150–400+ | | 支持的设备 | 所有 Android 设备 | 所有 Android 设备 | 仅限 NetHunter 支持的设备 | | 监听模式 | ✓ (ESP32) | ✓ (ESP32) | ✓ | | 数据包注入 | ✓ | ✓ | ✓ | | USB 权限对话框 | 仅首次使用 | ✗ | ✗ | | 实时 Wireshark (FIFO) | ✓ | ✓ | ✓ | | IR / RF 扩展 | 计划中 | 计划中 | ✗ | ## 固件 ### 支持的开发板 | 开发板 | `platformio.ini` 环境 | VID:PID | 状态 | |-------|---------------------|:-------:|:------:| | ESP32-C3 SuperMini | `esp32-c3-supermini` | `303A:1001` | ✅ 已测试 | | ESP32-S3 | `esp32-s3` | `303A:1001` | ⚠️ 未测试 | | ESP32-S2 | `esp32-s2` | `303A:0002` | ⚠️ 未测试 | ### 关键构建标志 ``` build_flags = -DARDUINO_USB_MODE=1 ; route Serial to native USB, not UART pins -DARDUINO_USB_CDC_ON_BOOT=1 ; enable CDC before setup() runs ← CRITICAL -DCONFIG_AUTOSTART_ARDUINO=1 ; loop() won't run without this -DCONFIG_ESP_WIFI_ENABLE_SNIFFER=1 ``` ### 使用 PlatformIO 刷入 ``` cd firmware/ # 刷入 + 打开 serial monitor pio run -e esp32-c3-supermini --target upload && pio device monitor # 确认启动 — 应打印:ESP32_READY # Heartbeat JSON 每 5s 出现一次:{"uptime":5000,"heap":250336,"type":"heartbeat"} ``` ### 刷入预构建二进制文件 预构建的 `.bin` 文件位于 [Releases](https://github.com/0xhim4ri-81x/nrcap32/releases) 页面。 ``` pip install esptool esptool.py --chip esp32c3 --port /dev/ttyUSB0 write_flash 0x0 nrcap32-c3.bin esptool.py --chip esp32s3 --port /dev/ttyUSB0 write_flash 0x0 nrcap32-s3.bin esptool.py --chip esp32s2 --port /dev/ttyUSB0 write_flash 0x0 nrcap32-s2.bin ``` 或者在 Windows 上使用 [ESP32 Flash Download Tool](https://www.espressif.com/en/support/download/other-tools)。 ## 桥接协议 NRcap32 通过 USB CDC 批量传输使用紧凑的二进制帧协议。 ``` [0xAD 0xDE][TYPE 1B][ID 1B][LENGTH 4B LE][PAYLOAD NB] ``` | 类型 | Hex | 方向 | Payload | |------|:---:|-----------|---------| | CMD | `0x01` | Termux → ESP32 | JSON `{"cmd": "...", "args": {...}}` | | RESP | `0x02` | ESP32 → Termux | JSON 响应,与对应的 CMD ID 一致 | | EVENT | `0x03` | ESP32 → Termux | JSON 异步事件(扫描结果、心跳等) | | PCAP | `0x04` | ESP32 → Termux | 原始二进制数据:radiotap header + 802.11 帧 | | ACK | `0x05` | Termux → ESP32 | JSON `{"chunk": N}` —— 流量控制 | PCAP 帧使用滑动窗口流量控制:ESP32 会在暂停前最多缓存 `SNIFF_MAX_INFLIGHT`(默认值为 4)个未确认的帧。 ### 支持的 CMD | CMD | Args | Response | |-----|------|----------| | `PING` | — | `{"ok": true, "msg": "pong"}` | | `STATUS` | — | `{"ok": true, "uptime": ms, "heap": bytes, "chip": "...", "sniffing": bool}` | | `SCAN_WIFI` | — | `{"ok": true, "count": N}` + N 个 `scan_ap` 事件 | | `START_SNIFF` | `{"mode": "fixed"\|"hop", "channel": 1-13, ...}` | `{"ok": true}` | | `STOP_SNIFF` | — | `{"ok": true, "captured": N, "sent": N, "dropped": N}` | | `DEAUTH` | `{"bssid": "...", "channel": N, "count": N, ...}` | `{"ok": true, "sent": N}` | | `DEAUTH_CAPTURE` | 同 DEAUTH | `{"ok": true, "sent": N, "sniffing": true}` | ## 项目结构 ``` nrcap32/ ├── firmware/ │ ├── platformio.ini # multi-board build config (C3/S3/S2) │ ├── src/ │ │ ├── main.cpp # Arduino entry point, CMD dispatcher │ │ ├── sniffer.cpp / .h # Promiscuous capture, radiotap builder │ │ └── override_sanity.cpp # Bypass IDF raw frame sanity check │ └── lib/ │ └── BridgeProtocol/ # Framed binary protocol (ESP32 side) ├── nrcap32 # Main CLI (chmod +x, run as ./nrcap32) ├── protocol.py # FrameParser + Protocol class ├── receiver.py # USB bulk IN background thread ├── sender.py # Thread-safe USB bulk OUT ├── usb_device.py # Device detection, fd wrapping, endpoints ├── pcap_writer.py # pcap writer, buffered + stream modes ├── data/ # Logs and captures (auto-created, gitignored) └── README.md ``` ## 设计说明 在此记录了一些不那么显而易见的实现选择,供贡献者参考: **单一无线电模式。** ESP32 在执行 `setup()` 后会永久保持 `WIFI_MODE_APSTA` 状态。模式切换需要 3 到 8 秒,并且可能会发生静默失败,因此 `SCAN_WIFI` 会直接调用 `esp_wifi_scan_start()`。`WiFi.mode()` 在整个生命周期内只会被调用一次。 **USB DATA 切换位。** 每次新的 `termux-usb` 会话都会通过一个新的文件描述符包装同一个物理设备,但端点硬件中的 USB DATA 切换位并*不会*被重置。`reset_endpoint_toggles()` 在声明接口所有权后,会在两个端点上调用 `device.clear_halt()`,将其重置为 DATA0。如果不这样做,每隔一次运行就会静默导致首个批量传输发生错误投递。 **单一端点所有者。** `ReceiverThread` 是 `device.read()` 的唯一调用者。在 Android 的 USB host 协议栈中,如果没有互斥锁,两个线程在同一个端点上并发调用 `libusb_bulk_transfer` 会导致数据损坏或使端点完全锁死。 **流量控制。** 仅当 `_inFlight < SNIFF_MAX_INFLIGHT`(默认值为 4)时,ESP32 的 `processQueue()` 才会将 PCAP 帧出队。Python 端直接从 `_read_loop` 线程发送 ACK —— 而不是在回调线程中发送 —— 以将往返延迟降至最低。 ## 故障排除 **权限对话框未出现** 确保已安装 Termux:API 配套应用(来自 F-Droid,而不是 Play 商店)。运行 `termux-usb -l` 验证它是否能检测到设备。 **`No USB devices found`** 有些数据线仅支持充电 —— 请使用支持数据传输的 OTG 数据线。运行 `termux-usb -l`(无 root 环境)或 `lsusb`(root 环境)以确认手机是否检测到了 ESP32。 **第二次运行返回 None / 超时 30 秒** 这是 USB DATA 切换位的 bug。在当前版本中已通过 `reset_endpoint_toggles()` 修复。在旧版本中,可以尝试在两次运行之间拔下/重新插入 ESP32 作为变通方案。 **`cdc_acm: device not accepting address`** 内核 CDC 驱动优先接管了该接口。运行 `rmmod cdc_acm`。在随后的运行中,NRcap32 会自动将其分离。 **捕获显示 0 个 EAPOL 帧** 客户端在捕获窗口期间没有重新关联。尝试调高 `--count` 和 `--capture-secs` 的值。有些设备会忽略广播 deauth —— 请使用 `--client ` 定向到特定设备。并确认你当前监听的信道是否正确。 **STATUS 显示堆栈降至 150 KB 以下** 在 `sniffer.h` 中减小 `SNIFF_QUEUE_DEPTH` 或 `SNIFF_MAX_INFLIGHT` 的值并重新刷入固件。低于 80 KB 时,JSON 序列化可能会发生静默失败。 ## 路线图 - [ ] AP 模式 —— 强制门户支持 - [ ] 信标广播 —— 信标垃圾信息、自定义 SSID、隐藏 SSID - [ ] WPS 支持 —— WPS Pixie Dust 攻击 - [ ] WPA3 PMKID 捕获 —— 被动捕获,无需 deauth - [ ] 蓝牙 —— BLE 扫描、广播、设备发现、BLE 垃圾信息 - [ ] HID 模拟 —— BLE BadUSB、键盘注入 - [ ] 多 ESP32 —— USB 集线器 + 多个 ESP32,实现同时多信道捕获 - [ ] 硬件扩展 —— IR、NRF24、CC1101 模块 ## 法律声明 本工具仅旨在用于授权的安全研究、针对自有基础设施的渗透测试以及教育用途。作者不对任何滥用行为负责。 发送解除认证帧会中断受影响客户端的连接。请勿在你未拥有或未获授权管理的网络上使用。在许多司法管辖区,未经授权中断网络通信属于刑事犯罪。 在对你不拥有的任何网络或设备进行测试之前,请务必获得明确的书面许可。 ## 许可证 MIT —— 见 [`LICENSE`](LICENSE)。 ## 致谢 - [Bruce 固件](https://github.com/pr3y/Bruce) —— ESP32 多功能工具固件;为本项目的无线电模式和 IR 实现提供了参考 - [esp32-deauther](https://github.com/SpacehuhnTech/esp8266_deauther) —— 原始概念灵感来源 - [Espressif IDF 团队](https://github.com/espressif/esp-idf) —— 提供了原始的 `esp_wifi_*` API,使得无需内核驱动即可实现混杂模式和帧注入 - [Termux](https://termux.dev) 及 termux-api 的贡献者 —— 让 Android 成为一个真正的 Linux 环境 - [PyUSB / libusb](https://github.com/pyusb/pyusb) —— 提供了 `libusb_wrap_sys_device`,这是实现无 root USB 访问的关键原语
标签:Android, DSL, ESP32, Python, Wi-Fi抓包, 插件系统, 无后门, 逆向工具