ESP8266基于NON_OS的sniffer模式开发

最近调试测试了通过成功抓取周边手机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;
    }
}

猜你喜欢

转载自blog.csdn.net/Strange_Gu/article/details/85692845
今日推荐