wifit3 RX回调机制解析:WEP/WPS状态机如何绕开UI轮询实现低延迟抓包
【免费下载链接】wifit3Wifite but USB-only & cross-platform.项目地址: https://gitcode.com/GitHub_Trending/wi/wifit3
wifit3 是一款跨平台的纯 PythonWi-Fi 安全审计工具(Wifite 的 USB 专用、跨平台重写版),内置完整的 802.11 无线协议栈,支持多网卡同时抓包、WPA 握手/PMKID 捕获、WPS 恢复与 WEP 破解。它的 WEP/WPS 攻击状态机之所以能在毫秒级内响应空口事件,关键不在 UI,而在一条推式的 RX 回调链路——网卡收到帧的瞬间,事件直接"推"给等待它的状态机,完全绕开 Textual 界面的轮询节奏。本文带你从回调注册一路追到状态机消费,看懂这套低延迟设计的三层结构。
为什么不用 UI 轮询做主数据通路
很多终端工具的常见写法是:主循环里每隔 50~100ms 调一次"取包/取状态",界面刷新和逻辑推进绑在同一个节拍上。问题在于:
- 延迟被刷新周期放大:WPS 物理按钮按下后 AP 会立刻广播 M1 帧,WEP 的 ChopChop 则需要"伪造帧被 AP 接收并重播"这一瞬间的响应,轮询会把最敏感的几毫秒窗口磨平;
- 忙等浪费事件循环:轮询期间事件循环被占用,多网卡跳频、热插拔等并发任务都会被拖慢。
wifit3 的做法是把"收包"和"显示"彻底解耦:收包走 asyncio 回调(push),UI 只读共享状态(pull)。界面快慢不影响攻击路径的延迟。
第一层:网卡驱动的 RX 回调注册
每张 USB 网卡对应一个 WlanInterface,它是"纯单卡无线电"。初始化时做了一次关键的注册:
self.driver.register_rx_callback(self._on_frame_parsed)芯片驱动(chips/driver.py 定义基类)从 USB 端点收到原始字节流、解析成结构化Packet后,直接调用_on_frame_parsed,后者再依次触发挂在接口上的所有业务回调(interface.py 的_fire_rx_callbacks)。也就是说,驱动层不关心"谁在等这个帧",它只负责在帧到达的第一时间触发回调链。
第二层:WlanArray 的汇聚、去重与分发
多网卡场景下,同一帧会被多张卡听到。会话级的 WlanArray 在attach()时给每张卡挂上统一的入口回调(array.py L82):
iface.register_rx_callback(lambda pkt, i=iface: self._ingest(i, pkt))_ingest()(array.py L182-L201)在推式链路里完成三件事:
- 丢弃自己发出的帧:以发信地址(TA)比对
own_macs,避免注入帧被当成空口流量; - 跨卡去重:
StreamMerger在 0.3s 窗口内合并多卡收到的同一帧,只有"全局首见"的副本才进入共享状态; - 折叠进共享画面 + 分发等待者:先
sink.update()更新 AP/客户端/WEP 账本,紧接着sink.dispatch_rx()唤醒所有匹配的等待者。
注意这里的巧妙之处:去重副本仍会让每张卡贡献自己的 RSSI(record_signal),所以"Power"读数能选出最强天线,而不牺牲任何延迟。
第三层:WlanSink 的推送式等待 API —— next_frame
核心低延迟设施在 WlanSink。它为"下一帧匹配"提供了两个配合的方法:
next_frame(match, timeout):调用方传入一个匹配函数match(pkt),挂一个 Future 到_waiters列表然后await,不消耗任何 CPU 去轮询;dispatch_rx(pkt):每个去重后的新帧到达时,遍历等待者,命中则用loop.call_soon_threadsafe(_set_result, fut, pkt)跨线程安全地立即兑现 Future。
WlanArray再把这两个 API 原样透出(array.py L236-L240),于是所有 Campaign 状态机都拿到了同一把"事件驱动"的钥匙。对比一下同文件里还保留了wait_until()这个 50ms 步进的轮询版 API——它只用于"等待一个模糊条件稳定"(如去授权后的沉降计时 campaigns/deauth.py L87),精确帧匹配一律走 next_frame 推式等待。
WEP 状态机:IV 样本在到达瞬间入账
WEP 攻击(ARP Replay / ChopChop / Fake Auth,campaigns/wep/)对延迟最敏感。其数据通路:
_on_wepdata_frame()在sink.update()内部被同步调用,每收到一个 WEP Data 帧就立刻把 3 字节 IV 记入 WepCaptureStore(IV 位于 MAC 头后第 24 字节,见 wep/README.md);- Campaign 侧要"确认伪造帧已被 AP 接收"时,用
next_frame挂一个匹配器:广播 Data 帧、FromDS 且源地址为自己的 MAC(arp_replay.py 与 chopchop 用同一关联方式判断); - AP 重播帧被网卡听到 → 驱动回调 →
_ingest→dispatch_rx命中 → 状态机在同一事件循环周期内被唤醒,继续制造下一批 IV。
整条链路没有任何"睡 100ms 再看一眼"的环节,IV 速率因此可以顶满 AP 的重播速度——这正是 ChopChop 这类时序攻击能成立的前提。
WPS PBC:按钮按下到取出明文 PSK 的推送路径
WPS PushButton 恢复(campaigns/pbc.py)的状态机同样是"推"而非"拉":用户按下路由器 WPS 按钮后,AP 会在信标与 WSC M1 帧中翻转配置方法标志。Sink 在_on_wps_m1_frame()中解析 M1 并即时刷新 AP 的 WSC 身份;状态机侧则用next_frame精确挂住 M1 帧,命中后立刻进入注册者会话、取回明文 WPA PSK。
下面这段演示 GIF 展示的就是该路径的端到端效果——从扫描到 PBC 握手捕获一气呵成:
低延迟设计的四个关键点
| 设计点 | 位置 | 作用 |
|---|---|---|
| 回调注册制收包 | wlan/interface.py L75 | 帧到达即触发,零轮询 |
| 0.3s 窗口跨卡去重 | wlan/dedupe.py | 多卡不重复处理同一帧 |
| Future + call_soon_threadsafe | wlan/sink.py L442-L470 | 匹配帧跨线程即时唤醒等待者 |
| UI 只读共享 Sink 状态 | ui/app.py | 界面刷新节拍不影响攻击路径 |
最后一个点容易被忽略:Textual UI 的屏幕(ui/screens/)只是WlanSink的"观众"——它读access_points、packet_stats等字段做展示,从不参与"帧到达 → 状态迁移"这条关键路径。所以哪怕界面正在重绘一个大表格,WEP 的 IV 入账和 WPS 的 M1 命中都分毫不差。
延伸阅读
- 网卡接口与回调链:src/wifit3/wlan/interface.py
- 汇聚与去重:src/wifit3/wlan/array.py、src/wifit3/wlan/dedupe.py
- 共享 802.11 状态与 next_frame API:src/wifit3/wlan/sink.py
- WEP 攻击套件说明:src/wifit3/campaigns/wep/README.md
- WPS PBC 状态机:src/wifit3/campaigns/pbc.py
- 硬件支持清单:docs/SUPPORTED-HARDWARE.md
【免费下载链接】wifit3Wifite but USB-only & cross-platform.项目地址: https://gitcode.com/GitHub_Trending/wi/wifit3
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考