三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

基于BW16 Wi-Fi SoC的嵌入式握手包抓取系统:从射频到Web的全栈实践

基于BW16 Wi-Fi SoC的嵌入式握手包抓取系统:从射频到Web的全栈实践

如果你是一名嵌入式开发者、网络安全爱好者,或者对无线通信协议充满好奇,那么你很可能听说过“握手包”和“Wi-Fi密码破解”。网络上充斥着各种教程,但大多停留在理论或使用特定软件工具的层面,真正将硬件、固件、协议解析和可视化界面串联起来的深度实践内容却很少。

今天这篇文章要解决的,正是这个痛点。我们将围绕一个具体的技术栈展开:如何利用一块名为 BW16 的 Wi-Fi SoC 单片机,通过定制固件,实现一个能够抓取并解析 Wi-Fi 四次握手包,并最终通过网页 UI 进行交互和管理的完整系统。

这不仅仅是另一个“破解教程”。本文的核心判断是:理解并实践从射频信号到数据包,再到应用层交互的完整链路,其价值远超于获取一个密码。它涉及射频前端、802.11 协议栈、单片机编程、网络通信和 Web 开发等多个领域的交叉,是学习嵌入式网络安全的绝佳综合项目。通过动手实现,你将深刻理解 WPA/WPA2 个人认证的“四次握手”过程为何是关键,明白抓包工具背后的原理,并掌握在资源受限的单片机上构建网络服务的能力。

对于开发者而言,这意味着:

  1. 从黑盒到白盒:不再满足于使用 Aircrack-ng 等工具,而是了解数据从空中到可分析格式的完整过程。
  2. 硬件级实践:选择 BW16 这类集成了 Wi-Fi 和 MCU 的芯片,意味着你需要处理天线匹配、功耗管理、固件烧录等真实硬件问题。
  3. 全栈思维:从底层的包过滤、解析,到上层的 TCP/HTTP 服务、JSON 数据交换和动态网页渲染,这是一个微缩的全栈应用。

接下来,我们将从核心概念讲起,逐步拆解环境搭建、固件开发、网页 UI 实现以及最终联调的完整流程。无论你是想深化对 Wi-Fi 安全的理解,还是寻找一个具有挑战性的单片机综合项目,这篇文章都将提供一条清晰的路径。

1. 这篇文章真正要解决的问题

在开始技术细节之前,我们必须明确边界和目的。本文不鼓励、不教授任何未经授权的网络入侵行为。其核心价值在于教育、研究和授权下的安全测试

我们真正要解决的技术问题是什么?在传统的 Wi-Fi 安全分析中,流程通常是:在 Linux 电脑上使用支持监听模式的网卡(如rtl8812au),运行airodump-ng抓取包含握手包的数据流,保存为pcap文件,最后用aircrack-ng配合密码字典进行离线破解。这个过程依赖于特定的硬件和操作系统,且工具链相对固定。

而本项目旨在重构并深化这一流程,将其移植到一个低功耗、可定制的嵌入式硬件平台上。具体来说,我们要解决:

  1. 硬件依赖与便携性:摆脱对特定型号 USB 网卡和 PC 的依赖,用一个火柴盒大小的设备完成抓包核心功能。
  2. 协议理解的透明化:不再将抓包工具视为黑盒,通过自己编写或修改固件,清晰了解如何设置网卡为监听模式、如何过滤管理帧和数据帧、如何识别和提取 EAPOL 帧(即四次握手包)。
  3. 数据交互的现代化:摒弃命令行文件传输,设计一个内建的 Web 服务器,提供友好的网页界面来查看抓包状态、管理目标网络列表、下载捕获到的握手包文件。
  4. 嵌入式开发的综合实践:如何在一个资源(内存、Flash、CPU)有限的单片机上,协调 Wi-Fi 射频、TCP/IP 协议栈、文件系统和 HTTP 服务器等多个复杂任务。

因此,本文的读者应该是:

  • 对 802.11 协议有基本兴趣的嵌入式工程师。
  • 希望将网络安全概念与硬件结合的学习者。
  • 寻找有挑战性的单片机综合项目的开发者。
  • 在合法合规范围内进行无线安全评估测试的专业人员。

如果你只想要一个“一键破解”的脚本,那么这篇文章可能过于硬核。但如果你想真正“知其所以然”,并构建一个属于自己的专业工具,请继续往下看。

2. 基础概念与核心原理

在动手之前,必须夯实几个关键概念。理解它们,是后续一切开发工作的基础。

2.1 什么是四次握手包?

四次握手是 WPA/WPA2-Personal(即预共享密钥模式)认证过程的核心。其目的并非传输密码,而是通过一系列信息交换,让客户端(如手机)和接入点(AP)共同推导出用于加密实际数据的临时密钥(PTK)

握手过程简述:

  1. 消息1 (AP -> Client):AP 发送一个随机数(ANonce)。
  2. 消息2 (Client -> AP):客户端收到后,结合自己的随机数(SNonce)、预共享密码(PSK)、AP的MAC地址、客户端的MAC地址等信息,计算出 PTK。然后将 SNonce 和一段消息完整性校验码(MIC)发给 AP。
  3. 消息3 (AP -> Client):AP 收到 SNonce 后,也能用同样的信息计算出 PTK。它验证客户端的 MIC,然后发送自己的 MIC 给客户端。
  4. 消息4 (Client -> AP):客户端验证 AP 的 MIC。验证通过,双方均确认对方拥有正确的 PSK,并开始使用 PTK 加密通信数据。

为什么抓取它就能破解密码?因为消息2和消息3(EAPOL帧)在空中是以明文传输的,其中包含了双方的非随机数(ANonce, SNonce)以及用于验证的 MIC。破解工具(如aircrack-ng)的工作就是:用你提供的密码字典中的每一个密码作为 PSK,结合抓包文件中已知的 AP MAC、Client MAC、ANonce、SNonce,重新计算一遍 PTK 和 MIC,然后与抓包中的 MIC 进行比对。如果匹配成功,那么你用的这个字典密码就是真实的 Wi-Fi 密码。这是一个纯粹的离线计算过程。

2.2 BW16 芯片简介

BW16 是联盛德(WinnerMicro)推出的一款高性价比 Wi-Fi SoC。它对于本项目有几个关键优势:

  • 高度集成:单芯片集成了 ARM Cortex-M4F 内核、2.4GHz Wi-Fi 射频(支持 802.11 b/g/n)、内存和 Flash,无需外接复杂的 Wi-Fi 模块。
  • 支持监听模式:这是抓包的前提。芯片的驱动和 SDK 需要提供将 Wi-Fi 射频设置为“混杂模式”或“监听模式”的接口,以接收所有信道上的所有数据帧,而不仅仅是发给自己的帧。
  • 充足的资源:通常有数百 KB 的 RAM 和数 MB 的 Flash,足以运行轻量级的 TCP/IP 协议栈(如 lwIP)和一个 Web 服务器。
  • 活跃的社区与 SDK:厂商提供基于 FreeRTOS 的 SDK,降低了开发门槛。

2.3 系统架构总览

我们的目标系统软件架构大致如下:

[Wi-Fi 射频层] (监听模式,抓取原始802.11帧) | v [驱动/协议栈层] (过滤信标帧、探测请求/响应、重点提取EAPOL帧) | v [数据管理层] (将抓到的EAPOL帧及相关信息存入文件系统,如.pcap格式) | v [网络服务层] (运行lwIP + HTTP服务器,提供RESTful API或网页服务) | v [网页UI层] (用户通过浏览器访问设备IP,进行配置、查看、下载)

3. 环境准备与前置条件

开始编码前,需要搭建完整的开发环境。

3.1 硬件准备

  • BW16 开发板:一块,确保带有天线和 USB 转串口芯片(如 CH340),用于供电和调试。
  • Micro-USB 数据线:用于供电和串口通信。
  • 电脑:Windows, Linux 或 macOS 均可。

3.2 软件工具准备

  1. 编译工具链:ARM GCC。联盛德官方 SDK 通常会提供或指定一个版本。
    # 例如,在 Linux 下安装 arm-none-eabi-gcc sudo apt-get install gcc-arm-none-eabi
  2. 代码编辑器/IDE:VSCode 或任何你喜欢的编辑器。配合 C/C++ 插件即可。
  3. 串口调试工具minicom(Linux),PuTTY(Windows),screen(macOS/Linux) 或CoolTerm
  4. 固件烧录工具:根据 BW16 的烧录方式准备,可能是通过串口的flash_download_toolesptool.py类似的工具。请查阅 BW16 的具体文档。
  5. 网络分析辅助工具(用于验证)
    • Wireshark:用于分析最终生成的.pcap文件,确认握手包是否正确。
    • aircrack-ng:用于在 PC 上测试抓取的握手包文件是否能被成功破解(使用测试密码)。

3.3 获取 SDK 与示例代码

这是最关键的一步。你需要从联盛德官方或可靠的社区仓库获取 BW16 的 SDK。

  • 通常 SDK 会包含:芯片驱动、RTOS(FreeRTOS)、网络协议栈(lwIP)、文件系统、各种外设示例。
  • 重点寻找:SDK 中是否有关于 Wi-Fi “混杂模式”或“监听模式”的示例或 API 说明。这是项目的基石。如果官方 SDK 未直接提供,可能需要深入研究驱动代码或向社区寻求帮助。

假设你获取的 SDK 目录结构类似如下:

winner_bw16_sdk/ ├── board/ ├── driver/ ├── freertos/ ├── lwip/ # 轻量级TCP/IP协议栈 ├── projects/ # 示例项目 │ └── wifi_sniffer/ # 我们希望找到或创建的项目 ├── tools/ # 编译和烧录工具 └── ...

4. 核心流程拆解

我们将开发工作分解为四个核心阶段。

4.1 阶段一:实现 Wi-Fi 监听与原始帧捕获

目标:让 BW16 的 Wi-Fi 芯片进入监听模式,并开始接收指定信道上的所有 802.11 帧。

关键步骤:

  1. 初始化 Wi-Fi 驱动:调用 SDK 中的wifi_driver_init()或类似函数。
  2. 设置监听模式:寻找类似wifi_set_mode(WIFI_MODE_SNIFFER)的 API。监听模式通常被称为 “Sniffer Mode” 或 “Monitor Mode”。
  3. 配置信道:可以固定扫描一个信道(如信道6),或实现信道跳变以捕获更多网络。API 可能为wifi_set_channel(6)
  4. 注册接收回调函数:这是核心。设置一个回调函数,当 Wi-Fi 驱动收到任何一个原始 802.11 帧时,都会调用这个函数,并将帧数据传递给我们。
    // 伪代码示例 void raw_frame_received_callback(uint8_t *data, uint32_t len, wifi_pkt_rx_info_t *info) { // data: 指向原始802.11帧数据的指针 // len: 数据长度 // info: 可能包含RSSI(信号强度)、信道等信息 // 在这里对帧进行初步过滤和处理 process_80211_frame(data, len, info); } // 在初始化时注册回调 wifi_set_raw_frame_receive_callback(raw_frame_received_callback);

4.2 阶段二:过滤与识别四次握手包

目标:从海量的原始帧中,精准地找出我们需要的 EAPOL 帧(四次握手包)。

关键步骤:

  1. 理解 802.11 帧结构:需要解析帧控制字段、地址字段等。管理帧、数据帧等类型。
  2. 识别 EAPOL 帧
    • EAPOL 帧通常被封装在 802.11 数据帧中。
    • 数据帧的“类型/子类型”需要判断。
    • 更关键的是,其 LLC/SNAP 封装后的协议 ID 应为0x888E(这是 EAPOL 的以太网类型)。
    // 简化的处理函数示例 void process_80211_frame(uint8_t *data, uint32_t len, wifi_pkt_rx_info_t *info) { // 1. 解析802.11帧头部,获取帧类型、地址等 wifi_header_t *hdr = (wifi_header_t*)data; // 2. 判断是否为数据帧,并且是“去往DS”或“来自DS”等特定子类型 if ((hdr->frame_control.type == WIFI_FRAME_DATA) && (hdr->frame_control.subtype == WIFI_DATA_SUBTYPE_DATA)) { // 3. 跳过802.11头部、可能的QoS控制字段,找到LLC/SNAP头部 uint8_t *llc = data + sizeof(wifi_header_t) + (hdr->frame_control.order ? 4 : 0); // 4. 检查LLC/SNAP头部,协议ID是否为0x888E (EAPOL) if (llc[0]==0xAA && llc[1]==0xAA && llc[2]==0x03 && llc[3]==0x00 && llc[4]==0x00 && llc[5]==0x00 && llc[6]==0x88 && llc[7]==0x8E) { // 5. 找到EAPOL帧的起始位置 uint8_t *eapol_pkt = llc + 8; // 跳过LLC/SNAP头 uint32_t eapol_len = len - (eapol_pkt - data); // 6. 解析EAPOL头部,获取密钥描述类型、密钥信息等,确认是四次握手消息(通常为消息2或3) eapol_key_frame_t *eapol_key = (eapol_key_frame_t*)eapol_pkt; if (eapol_key->key_info.key_type == 1 && // 表示是成对密钥 eapol_key->key_info.key_mic == 1) { // MIC标志位为1 // 这是一个携带MIC的EAPOL帧,极有可能是四次握手包! save_handshake_packet(data, len, info, eapol_key); } } } }
  3. 关联握手包与网络:一个完整的四次握手需要消息2和消息3。我们需要将捕获到的 EAPOL 帧与特定的 BSSID(AP的MAC地址)和客户端 MAC 地址关联起来,并标记是第几次握手。

4.3 阶段三:数据存储与文件生成

目标:将捕获到的有效握手包以及相关的网络信息(SSID、BSSID、信道等)保存起来,最好生成标准的.pcap文件格式,以便用 Wireshark 或 aircrack-ng 直接分析。

关键步骤:

  1. 实现文件系统:如果 SDK 支持 SPIFFS、LittleFS 或 FATFS,选择一个集成到项目中。用于存储抓包文件。
  2. 生成 PCAP 文件
    • PCAP 文件有固定的全局文件头和每个数据包的头。
    • 我们需要将原始的 802.11 帧(包括 radiotap 或 PPI 头部,用于存储 RSSI、信道等信息)按照 PCAP 格式写入文件。
    • 由于 BW16 驱动可能不直接提供 radiotap 头,我们可以自己构造一个简单的版本,或者直接存储为“无链路层”类型的 PCAP,但这样 Wireshark 可能无法正确识别为 802.11。更佳做法是研究驱动能否提供更多射频信息。
    // PCAP 全局文件头结构 (Magic Number, Version, etc.) typedef struct pcap_hdr_s { uint32_t magic_number; /* magic number */ uint16_t version_major; /* major version number */ uint16_t version_minor; /* minor version number */ int32_t thiszone; /* GMT to local correction */ uint32_t sigfigs; /* accuracy of timestamps */ uint32_t snaplen; /* max length of captured packets, in octets */ uint32_t network; /* data link type: 1 for Ethernet, 105 for 802.11 */ } pcap_hdr_t; // PCAP 数据包记录头结构 typedef struct pcaprec_hdr_s { uint32_t ts_sec; /* timestamp seconds */ uint32_t ts_usec; /* timestamp microseconds */ uint32_t incl_len; /* number of octets of packet saved in file */ uint32_t orig_len; /* actual length of packet */ } pcaprec_hdr_t;
  3. 设计存储逻辑:可以按 BSSID 或时间命名文件,将同一个网络的多个握手包存入同一个.pcap文件。

4.4 阶段四:构建 Web 服务器与 UI

目标:让用户可以通过浏览器方便地管理抓包任务和获取结果。

关键步骤:

  1. 初始化网络服务
    • 让 BW16 连接到一个已知的 Wi-Fi 作为上行网络(Station 模式),或者自身创建一个 AP 供手机/电脑连接。
    • 初始化 lwIP,获取 IP 地址。
  2. 集成 HTTP 服务器
    • 可以使用轻量级库,如httpd(lwIP 自带)、mongooselibesphttpd的移植版。
    • 实现几个核心 API 端点:
      • GET /:返回控制主页面(HTML)。
      • GET /api/networks:返回扫描到的 Wi-Fi 网络列表(JSON)。
      • POST /api/start_sniff:接收 JSON 参数(如目标 BSSID、信道),启动抓包任务。
      • GET /api/status:返回当前抓包状态(JSON)。
      • GET /api/captures:返回已捕获的握手包文件列表(JSON)。
      • GET /download/<filename>:下载指定的.pcap文件。
  3. 开发前端页面
    • 一个简单的单页面应用(SPA),使用 HTML、CSS 和 JavaScript。
    • 功能包括:显示设备 IP、扫描网络、选择目标、启动/停止抓包、实时显示抓包状态、列表展示已捕获的文件并提供下载链接。
    <!-- 极简示例:状态显示 --> <div id="status"> <p>设备IP: <span id="ip-addr">...</span></p> <p>抓包状态: <span id="sniff-status">Idle</span></p> <p>目标网络: <span id="target-ssid">None</span></p> </div> <button onclick="startSniffing()">开始抓包</button> <button onclick="stopSniffing()">停止抓包</button> <script> function fetchStatus() { fetch('/api/status') .then(r => r.json()) .then(data => { document.getElementById('sniff-status').textContent = data.status; document.getElementById('target-ssid').textContent = data.target_ssid; }); } setInterval(fetchStatus, 2000); </script>

5. 完整示例与代码实现

由于完整代码非常庞大,这里给出几个关键环节的代码片段,展示核心逻辑。

5.1 Wi-Fi 监听模式初始化代码片段

假设 SDK 提供了相关 API。

// 文件:main.c #include "wifi_api.h" #include "sniffer.h" // 全局抓包状态 sniffer_state_t g_sniffer_state = {0}; void wifi_sniffer_init(void) { // 1. 初始化Wi-Fi驱动 if (wifi_init() != 0) { printf("[ERROR] Wi-Fi init failed!\n"); return; } // 2. 设置Wi-Fi为监听模式 if (wifi_set_opmode(WIFI_MODE_SNIFFER) != 0) { printf("[ERROR] Set sniffer mode failed!\n"); return; } // 3. 设置监听信道(例如信道6) wifi_set_channel(6); // 4. 注册原始数据包接收回调 wifi_set_raw_frame_callback(raw_packet_handler); printf("[INFO] Wi-Fi sniffer initialized on channel 6.\n"); } // 原始数据包处理函数(在驱动中断或任务中调用) int raw_packet_handler(uint8_t *buf, uint32_t len, void *info) { // info 可能包含信号强度、噪声、信道等信息 wifi_pkt_rx_info_t *rx_info = (wifi_pkt_rx_info_t *)info; // 将数据包传递给我们的解析队列或任务 if (xQueueSend(g_packet_queue, buf, 0) == pdTRUE) { // 成功入队 } return 0; }

5.2 EAPOL 帧过滤与解析代码片段

// 文件:eapol_parser.c #include "eapol_parser.h" #include "pcap_writer.h" // 简化的802.11 MAC头部结构(不含QoS/HT控制字段) typedef struct { uint16_t frame_control; uint16_t duration_id; uint8_t addr1[6]; uint8_t addr2[6]; uint8_t addr3[6]; uint16_t seq_ctrl; } __attribute__((packed)) wifi_header_t; // 简化的EAPOL-Key帧结构(RFC 802.1X-2010) typedef struct { uint8_t version; uint8_t packet_type; // 0x03 for EAPOL-Key uint16_t packet_body_length; uint8_t descriptor_type; // 0x02 for 802.11 uint16_t key_info; uint16_t key_length; uint64_t replay_counter; uint8_t key_nonce[32]; uint8_t key_iv[16]; uint8_t key_rsc[8]; uint8_t key_id[8]; uint8_t key_mic[16]; uint16_t key_data_length; // uint8_t key_data[key_data_length]; } __attribute__((packed)) eapol_key_frame_t; void process_packet_for_handshake(uint8_t *packet, uint32_t len, wifi_pkt_rx_info_t *rx_info) { if (len < sizeof(wifi_header_t) + 8) return; // 太短,不处理 wifi_header_t *wifi_hdr = (wifi_header_t *)packet; // 检查是否为数据帧 uint8_t type = (wifi_hdr->frame_control >> 2) & 0x03; uint8_t subtype = (wifi_hdr->frame_control >> 4) & 0x0F; if (type != 0x02) return; // 不是数据帧 // 找到LLC/SNAP头部位置(跳过可能的QoS控制字段) uint8_t *llc = packet + sizeof(wifi_header_t); if ((wifi_hdr->frame_control & 0x0080) != 0) { // QoS控制字段存在 llc += 2; } // 检查LLC/SNAP: AA-AA-03-00-00-00-88-8E if (memcmp(llc, "\xaa\xaa\x03\x00\x00\x00\x88\x8e", 8) == 0) { uint8_t *eapol_start = llc + 8; uint32_t eapol_len = len - (eapol_start - packet); if (eapol_len >= sizeof(eapol_key_frame_t)) { eapol_key_frame_t *eapol_key = (eapol_key_frame_t *)eapol_start; // 检查是否为有效的EAPOL-Key帧 if (eapol_key->packet_type == 0x03 && eapol_key->descriptor_type == 0x02) { // 检查Key Info字段,判断是否为四次握手消息(MIC位为1) uint16_t key_info = eapol_key->key_info; if ((key_info & 0x0080) != 0) { // 检查MIC位 printf("[SUCCESS] Captured EAPOL handshake frame!\n"); printf(" BSSID: %02x:%02x:%02x:%02x:%02x:%02x\n", wifi_hdr->addr1[0], wifi_hdr->addr1[1], wifi_hdr->addr1[2], wifi_hdr->addr1[3], wifi_hdr->addr1[4], wifi_hdr->addr1[5]); printf(" Client: %02x:%02x:%02x:%02x:%02x:%02x\n", wifi_hdr->addr2[0], wifi_hdr->addr2[1], wifi_hdr->addr2[2], wifi_hdr->addr2[3], wifi_hdr->addr2[4], wifi_hdr->addr2[5]); // 保存到PCAP文件 save_packet_to_pcap(packet, len, rx_info); } } } } }

5.3 HTTP API 处理代码片段(基于 lwIP)

// 文件:http_server.c #include "lwip/api.h" #include "cJSON.h" // 处理 /api/status 的GET请求 void handle_api_status(struct netconn *conn) { // 构造JSON响应 cJSON *root = cJSON_CreateObject(); cJSON_AddStringToObject(root, "status", g_sniffer_state.is_running ? "running" : "stopped"); cJSON_AddStringToObject(root, "target_bssid", g_sniffer_state.target_bssid); cJSON_AddNumberToObject(root, "channel", g_sniffer_state.channel); cJSON_AddNumberToObject(root, "packets_captured", g_sniffer_state.packet_count); char *json_str = cJSON_Print(root); // 发送HTTP响应头 netconn_write(conn, "HTTP/1.1 200 OK\r\n", 17, NETCONN_COPY); netconn_write(conn, "Content-Type: application/json\r\n", 33, NETCONN_COPY); netconn_write(conn, "Connection: close\r\n", 19, NETCONN_COPY); netconn_write(conn, "\r\n", 2, NETCONN_COPY); // 发送JSON主体 netconn_write(conn, json_str, strlen(json_str), NETCONN_COPY); // 清理 cJSON_Delete(root); free(json_str); netconn_close(conn); } // 处理 /api/start_sniff 的POST请求 void handle_api_start_sniff(struct netconn *conn, char *post_data) { cJSON *root = cJSON_Parse(post_data); if (root) { cJSON *bssid = cJSON_GetObjectItem(root, "bssid"); cJSON *channel = cJSON_GetObjectItem(root, "channel"); if (cJSON_IsString(bssid) && cJSON_IsNumber(channel)) { strncpy(g_sniffer_state.target_bssid, bssid->valuestring, sizeof(g_sniffer_state.target_bssid)-1); g_sniffer_state.channel = channel->valueint; g_sniffer_state.is_running = 1; g_sniffer_state.packet_count = 0; // 实际调用函数设置Wi-Fi信道和过滤逻辑 wifi_set_channel(g_sniffer_state.channel); printf("[INFO] Sniffing started for BSSID: %s on channel %d\n", g_sniffer_state.target_bssid, g_sniffer_state.channel); // 返回成功 send_json_response(conn, "{\"success\": true}"); } else { send_json_response(conn, "{\"success\": false, \"error\": \"Invalid parameters\"}"); } cJSON_Delete(root); } netconn_close(conn); }

6. 运行结果与效果验证

完成代码编写和编译后,按照以下步骤验证系统。

6.1 编译与烧录

  1. 在 SDK 项目目录下,使用提供的 Makefile 或 CMake 进行编译。
    cd winner_bw16_sdk/projects/wifi_sniffer make clean make
  2. 如果编译成功,会生成一个.bin.elf文件。
  3. 使用烧录工具(如flash_download_tool)将固件烧录到 BW16 开发板。注意:烧录前可能需要让板子进入下载模式(通常通过按住某个按键再上电或复位)。

6.2 上电运行与连接

  1. 烧录完成后,重启开发板。
  2. 通过串口工具(如minicom -D /dev/ttyUSB0 -b 115200)查看启动日志。你应该能看到 Wi-Fi 初始化、监听模式设置成功、以及 HTTP 服务器启动并打印 IP 地址的日志。
    [INFO] System started. [INFO] Wi-Fi driver initialized. [INFO] Setting Wi-Fi to sniffer mode... OK. [INFO] HTTP server started on port 80. [INFO] Device IP: 192.168.4.1
  3. 让你的电脑或手机连接到 BW16 创建的 Wi-Fi AP(如果配置为 AP 模式),或者连接到同一个局域网(如果配置为 Station 模式)。

6.3 网页 UI 操作验证

  1. 在浏览器中输入设备的 IP 地址(如http://192.168.4.1)。
  2. 页面应加载出控制界面,显示设备状态、网络扫描列表(如果实现了扫描功能)。
  3. 在界面上选择一个目标 Wi-Fi 网络(需要知道其 BSSID 和信道),点击“开始抓包”。
  4. 观察页面状态更新为“抓包中”。同时,让一台已连接该目标 Wi-Fi 的设备执行一次重连操作(或使用aireplay-ng的 deauth 攻击触发重连,仅在你自己测试的网络中进行!),以产生四次握手。
  5. 如果抓包成功,页面应显示“已捕获握手包”的提示,并在文件列表中看到新生成的.pcap文件。

6.4 抓包文件验证

  1. 在网页文件列表中,点击下载抓取的.pcap文件。
  2. 在电脑上用Wireshark打开该文件。
    • 打开后,在过滤器中输入eapol
    • 你应该能看到捕获到的 EAPOL 帧。展开帧详情,应能看到Key MIC字段和Nonce字段。
  3. 使用aircrack-ng进行离线测试(使用一个简单的测试字典)。
    aircrack-ng -w test_wordlist.txt captured_handshake.pcap
    • 如果字典中包含正确密码,aircrack-ng会成功破解并显示密钥。
    • 这一步验证了抓取的握手包是完整且有效的。

7. 常见问题与排查思路

在开发和使用过程中,你几乎一定会遇到以下问题。这里提供排查思路。

问题现象可能原因排查方式解决方案
编译错误:找不到wifi_set_mode等函数SDK 版本不匹配或 API 名称不同;未包含正确的头文件。1. 检查 SDK 文档或头文件wifi_api.h
2. 在 SDK 示例项目中搜索类似功能的函数。
根据实际 SDK 修改函数名和参数。监听模式的 API 可能叫wifi_set_opmode(MONITOR_MODE)wifi_sniffer_enable()
烧录后设备无日志输出串口线连接错误;波特率设置不对;板子未正确启动。1. 确认开发板的 USB 转串口驱动已安装。
2. 尝试不同的波特率(如 115200, 9600)。
3. 检查电源和复位电路。
确保使用正确的串口号和波特率。参考开发板手册确认启动流程。
Wi-Fi 无法进入监听模式驱动不支持;固件版本问题;硬件天线问题。查看启动日志,是否有相关错误信息。搜索社区看该芯片型号是否支持监听模式。确认芯片型号和 SDK 的兼容性。有时需要特定的初始化序列或补丁。
能收到数据包,但全是乱码或长度异常回调函数收到的是 802.11 帧的“载荷”部分,而非完整帧;或者驱动做了处理。打印前几个字节的十六进制,与标准的 802.11 帧头(通常以0x080x00等开头)对比。深入研究驱动代码,看如何获取完整的、未加工的 MAC 层帧。可能需要修改驱动配置。
抓不到任何 EAPOL 帧信道设置错误;目标网络未发生握手;过滤逻辑有 bug。1. 先用wiresharkairodump-ng在 PC 上确认目标网络和信道。
2. 在代码中打印所有接收到的数据帧类型,确认能收到数据帧。
3. 触发客户端重连(如重启客户端 Wi-Fi)。
确保信道设置正确。简化代码,先尝试保存所有数据帧到 pcap,用 Wireshark 分析是否包含 EAPOL。调试 LLC/SNAP 头部解析逻辑。
网页无法访问HTTP 服务器未启动;IP 地址错误;防火墙阻止。1. 查看串口日志确认 HTTP 服务器启动成功并打印 IP。
2. 用ping测试设备 IP 是否可达。
3. 检查电脑是否与设备在同一子网。
确认 lwIP 初始化正确,网络任务正常运行。如果设备是 AP 模式,确保电脑连接到了它的热点。
生成 PCAP 文件 Wireshark 打不开或识别错误PCAP 文件头格式错误;链路层类型设置不对;时间戳错误。用十六进制编辑器查看文件开头,对比标准 PCAP 格式。确保写入的全局文件头和数据包记录头格式正确。链路层类型对于原始 802.11 通常是105127。考虑使用 radiotap 头。
设备运行一段时间后死机或重启内存泄漏;任务堆栈溢出;中断处理不当。1. 检查串口是否有看门狗复位或 HardFault 日志。
2. 使用 FreeRTOS 的堆栈检测功能。
3. 审查代码,确保在回调函数中不做耗时操作。
优化内存管理,避免在中断或回调中动态分配内存。增加任务堆栈大小。确保文件写入等操作在低优先级任务中执行。

8. 最佳实践与工程建议

将项目从“能跑”提升到“好用、可靠”,需要考虑以下方面。

  1. 信道跳变策略

    • 不要固定在一个信道。实现一个简单的信道跳变算法,轮流监听 1, 6, 11 等非重叠信道,以增加捕获到目标网络握手的概率。
    • 可以在网页 UI 上设置跳变间隔(如每 500ms 切换一次)。
  2. 高效的数据包处理

    • Wi-Fi 监听模式下数据流量巨大。回调函数raw_packet_handler必须非常高效,只做最必要的过滤和拷贝。
    • 将接收到的数据包指针和长度放入一个队列,由另一个独立的任务 (sniffer_task) 进行详细的解析、过滤和文件写入。避免在驱动中断上下文中进行复杂操作。
  3. 文件系统管理

    • 定期清理旧的抓包文件,避免 Flash 存储被写满。
    • 可以考虑按日期或 BSSID 建立文件夹进行分类存储。
    • 实现文件列表的缓存,网页请求时无需频繁遍历文件系统。
  4. Web UI 用户体验

    • 实现实时日志推送,可以使用 WebSocket 或 Server-Sent Events (SSE),让用户在网页上能看到抓包的实时动态(如“收到 Beacon 帧”、“捕获到 EAPOL 帧”)。
    • 添加一个简单的网络扫描功能,让 BW16 能短暂切换到 Station 模式扫描周边网络,供用户选择目标,而无需手动输入 BSSID。
  5. 功耗与性能平衡

    • 持续监听和写入 Flash 比较耗电。如果使用电池供电,需要增加休眠模式,例如只在指定时间段抓包。
    • 可以增加一个信号强度 (RSSI) 过滤阈值,只处理信号强于某个值的包,减少无效处理。
  6. 安全性提醒(至关重要)

    • 在网页 UI 的显著位置加入法律声明,明确告知用户仅可在自己拥有或获得明确授权的网络上进行测试。
    • 不要在固件中内置任何默认密码或后门。
    • 考虑为 Web 界面添加简单的 HTTP 认证,防止同一网络下的其他设备随意访问。
  7. 代码结构与可维护性

    • 将不同功能模块化:sniffer_core.c(抓包逻辑)、pcap_manager.c(文件操作)、http_server.c(网络服务)、web_ui.c(前端资源)。
    • 使用配置文件来管理参数,如默认信道、跳变列表、文件保存路径等。

9. 总结与后续学习方向

通过这个项目,我们完成了一次从射频信号到 Web 应用的完整穿越。你不仅实现了一个 Wi-Fi 握手包抓取工具,更深入理解了 802.11 协议、嵌入式网络编程和前后端交互。BW16 作为一个平台,其潜力远不止于此。

本文的核心价值总结:

  • 原理层面:揭示了 WPA2 四次握手的过程与离线破解的本质,打破了工具的黑盒。
  • 实践层面:提供了在资源受限的 MCU 上实现复杂网络功能(监听模式驱动、协议解析、文件系统、HTTP 服务器)的可行路径和代码参考。
  • 工程层面:展示了如何将一个多线程、实时性要求高的系统进行模块化设计和问题排查。

你可以继续深入的方向:

  1. 支持 WPA3:研究 WPA3-SAE 的握手过程,尝试捕获和分析其握手包。这将是更前沿的挑战。
  2. 集成破解引擎:在 BW16 上移植一个轻量级的密码字典破解引擎(如基于哈希的),实现从抓包到破解的“一体化”。但需注意性能限制和伦理法律边界。
  3. 添加更多分析功能:不仅仅是握手包,可以解析并显示网络中的设备列表(通过 Probe Request/Response)、信号强度分布、信道占用率等,做成一个简易的无线网络分析仪。
  4. 优化与封装:将整个系统设计成更通用的“固件库”,提供清晰的 API,让其他开发者可以轻松集成到自己的安防或物联网项目中。
  5. 探索其他硬件:除了 BW16,可以尝试在 ESP32、Raspberry Pi Pico W 等其他流行的 Wi-Fi MCU 上实现类似功能,对比性能与开发难度。

技术探索的乐趣在于亲手将想法变为现实,并理解其背后的每一个字节。希望这个项目能成为你深入嵌入式网络安全世界的一块坚实跳板。建议收藏本文,在实践过程中遇到问题时,再回来对照排查思路和最佳实践,定能有所收获。

← 返回列表