ESP8266基于NON_OS的sniffer模式开发学习
程序员文章站
2024-03-23 09:48:52
...
最近调试测试了通过成功抓取周边手机wifi广播的Probe request帧来收集手机的MAC地址。在此记录下学习过程。
一开始的思路就是将ESP8266设置为AP模式,让手机连接上ESP8266,来获取手机wifi的MAC地址。调试完后可以读出连接上ESP8266的手机的WIFI MAC地址。相关的调试过程会在之后记录下来。但是这里的话,需要手机主动连接上ESP8266的动作。在查阅了相关的资料,手机之所以能搜索到周围的wifi热点,是因为热点会向周围广播Beacon帧,手机wifi收到后就知道了有它们的存在。当手机wifi打开后,手机wifi也会向周围主动广播Probe request帧。这就是主动搜索与被动搜索的结果。那能否通过抓取手机wifi广播的Probe request帧来抓取得到手机WiFi的MAC地址呢?
在esp8266_sd_api_guide文档说明中果然有Sniffer相关接口可以帮助实现。什么是sniffer模式?一般我们在讲的Sniffer程序是把NIC(网络适配卡,一般如以太网卡)置为一种叫promiscuous杂乱模式的状态,一旦网卡设置为这种模式,它就能是Sniffer程序能接受传输在网络上的每一个信息包。
1.void wifi_promiscuous_enable(uint8 promiscuous);
功能:开启混杂模式(sniffer)
uint8 promiscuous :
0:关闭混杂模式
1:开启混杂模式
注意:
(1)仅支持在ESP8266单station模式下,开启混杂模式
(2)混杂模式下,ESP8266 station和 soft-AP接口均失效。
(3)若开启了混杂模式,请先调用wifi_station_disconnect确保没有连接
(4)混杂模式中请勿调用其他API,请先调用wifi_promiscuous_enable(0)退出snfiier。
2.void wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb);
功能:注册混杂模式下的接收数据回调函数,每收到一包数据,都会进入注册的回调函数
3.bool wifi_set_channel(uint8 channel);
功能:设置信道号,用于混杂模式
接下来,开始看代码
void ICACHE_FLASH_ATTR
user_init()
{
uart_init(115200, 115200);
os_printf("\r\n\r\nSDK version:%s\n", system_get_sdk_version());
sniffer_init();
system_init_done_cb(system_init_done);
}
在user_init()函数中,进行sniffer_init()对sniffer函数进行初始化。
void ICACHE_FLASH_ATTR
sniffer_init(void)
{
wifi_set_opmode(STATION_MODE); //sniffer只能在单sta模式下开启
os_timer_disarm(&channelchange_timer);
os_timer_setfn(&channelHop_timer, (os_timer_func_t *) channelchange, NULL);
os_timer_arm(&channelchange_timer, 3000, 1); //每隔3S钟转换wifi的扫描通道
}
//在user_init中调用,注册系统初始化完成的回调函数。
system_init_done_cb(system_init_done);
//system_init_done是系统初始化完成的回调函数
void ICACHE_FLASH_ATTR
system_init_done(void)
{
wifi_set_channel(1); //初始化为通道1
wifi_promiscuous_enable(0); //先关闭混杂模式
//注册混杂模式下的接收数据的回调函数,每收到一包数据,都会进入注册的回调函数里面。
// promisc_cb 即回调函数,在里面抓取MAC地址
wifi_set_promiscuous_rx_cb(promisc_cb);
wifi_promiscuous_enable(1); //开启混杂模式
}
static void ICACHE_FLASH_ATTR
promisc_cb(uint8_t *buf, uint16_t len)
{
if (len == 12){
/*
* len == 12
* buf的数据是结构体RxControl,该结构体的是不太可信的,它无法表示包所属的发送和接收者,
* 也无法判断该包的包头长度
* 对于AMPDU包,也无法判断子包的个数和每个子包的长度
* 该结构体中较为有用的信息有:包长,rssi和FEC_CODING
* RSSI和FEC_CODING可以用于评估是否是同一个设备所发
*/
struct RxControl *sniffer = (struct RxControl*) buf;
} else if (len == 128) {
/*
* len == 128
* buf的数据是结构体sniffer_buf2,该结构体对应的数据包是管理包,含有112字节的数据。
*sniffer_buf2.cnt为1
*sniffer_buf2.len为管理包的长度
*/
struct sniffer_buf2 *sniffer = (struct sniffer_buf2*) buf;
if(sniffer->buf[0]==64)
{
/*
* 见IEEE-802.11-2012文档上8.2.4.1.3小节的Type and Subtype fields有管理包,数据
* 包,控制包如何分类资料。
* sniffer->buf[0]==128 ---->Beacon(管理包)
* sniffer->buf[0]==64 ---->probe request(管理包)
* sniffer->buf[0]==8 ---->Data(数据包)
* sniffer->buf[0]==200 ---->QoS Null(no data)(数据包)
* sniffer->buf[0]==148 ---->Block Ack(控制包)
* sniffer->buf[0]==136 ---->QoS Data(数据包)
* sniffer->buf[0]==72 ---->NULL(数据包)
* */
//MAC帧的目的地址
printmac(sniffer->buf, 4);
//MAC帧的源地址
printmac(sniffer->buf, 10); //就可以在这里扫描到你的手机MAC地址了
os_printf("\n");
}
} else {
/*
*len == 10,
*buf的数据是结构体sniffer_buf,该结构体时比较可信的,它对应的数据包是通过CRC校验正确的
*/
struct sniffer_buf *sniffer = (struct sniffer_buf*) buf;
}
}
上一篇: 多客户端文件上传