Linux系統(tǒng)無線網(wǎng)絡(luò)抓包程序(分析手機(jī)WIFI MAC地址)

前面講述了使用tcpdump和wireshark抓WIFI包左腔,但這只是使用工具的層面擒贸,再深一層則是自己寫代碼實(shí)現(xiàn)這個(gè)功能。本文在前面文章《Linux系統(tǒng)有線網(wǎng)絡(luò)抓包程序》的基礎(chǔ)上添加實(shí)現(xiàn)無線網(wǎng)絡(luò)的抓包功能紊遵。

首先要介紹ieee802.11的幀格式沐悦,只有知道幀格式才能正確解析對(duì)應(yīng)字段,拿到我們感興趣的信息崔兴。其次介紹Linux raw socket編程抓包彰导。最后解析ieee802.11數(shù)據(jù)包,從而獲取到MAC地址敲茄。實(shí)際上位谋,從數(shù)據(jù)包中可以得到很多信息,這些信息就是后續(xù)需要繼續(xù)進(jìn)行的事了堰燎。

一掏父、ieee802.11幀格式

ieee802.11幀格式如下圖所示:

上圖來自ieee802.11標(biāo)準(zhǔn)文檔《802.11-2012.pdf》的8.2.3小節(jié)。它比802.3以太幀不同秆剪。幀類型有很三大類:數(shù)據(jù)幀赊淑、管理幀、控制幀仅讽。每種類型幀又分很多種“子幀”陶缺。在手機(jī)WIFI開啟掃描熱點(diǎn)、連接熱點(diǎn)何什、過程主要涉及管理幀组哩。手機(jī)或PC在開啟WIFI時(shí),會(huì)向周邊發(fā)出probe request幀(子幀類型為4)处渣,熱點(diǎn)會(huì)回應(yīng)probe response幀(子幀類型為5),其中probe request幀頭部包含了手機(jī)MAC號(hào)信息蛛砰。抓到此包罐栈,就能解析出手機(jī)MAC號(hào)了。不同的幀的Frame Body不同泥畅,但這不是本文關(guān)注的重點(diǎn)荠诬。關(guān)于幀類型,具體參考ieee802.11標(biāo)準(zhǔn)文檔8.2.4.1.3 (Type and Subtype fields)小節(jié)位仁。

二柑贞、C實(shí)現(xiàn)socket抓包

Linux系統(tǒng)抓包使用SOCK_RAW方式,類型為ETH_P_ALL(表示抓取所有類型的幀聂抢,不管是IP幀還是ARP幀)钧嘶。下面給出代碼重要函數(shù)代碼片段。為減小文章篇幅琳疏,保留主要代碼函數(shù)有决,至于完整代碼闸拿,請(qǐng)參閱文章后面的附錄。

1书幕、設(shè)置混雜模式

抓包工具都會(huì)開啟混雜模式(promisc)新荤,下面是代碼:

// 混雜模式

bool set_promisc_mode(const char* eth, bool promisc)

{

int org_errno = 0;

int fd;

struct ifreq ifreq;

if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)

return false;

memset(&ifreq, 0, sizeof(ifreq));

strncpy(ifreq.ifr_name, eth, IF_NAMESIZE - 1);

ioctl(fd, SIOCGIFFLAGS, &ifreq);

// check if eth is up

if (!(ifreq.ifr_flags & IFF_UP))

{

printf("%s is not up yet.\n", eth);

return false;

}

if (promisc)

ifreq.ifr_flags |= IFF_PROMISC;

else

ifreq.ifr_flags &= ~IFF_PROMISC;

ioctl(fd, SIOCSIFFLAGS, &ifreq);

if (close(fd))

return false;

return true;

}

2、初始化socket

初始化socket包括創(chuàng)建RAW socket台汇,綁定指定網(wǎng)卡苛骨。

int init_socket(const char* eth)

{

int ret = 0;

int fd = -1;

// 混雜模式

if (!set_promisc_mode(eth, true))

{

//printf("set %s to promisc mode failed.\n", eth);

return -1;

}

// 注意與下面綁定時(shí)協(xié)議一致

fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

// 綁定網(wǎng)卡

struct ifreq req;

strcpy(req.ifr_name, eth);

ioctl(fd, SIOCGIFINDEX, &req);

struct sockaddr_ll addr;

addr.sll_family = PF_PACKET;

addr.sll_ifindex = req.ifr_ifindex;

addr.sll_protocol = htons(ETH_P_ALL);

ret = bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_ll));

return fd;

}

3、獲取網(wǎng)卡信息

int get_hwinfo(int fd, char* eth, unsigned char* mac)

{

struct ifreq ifr;

memset(&ifr, 0, sizeof(ifr));

strncpy(ifr.ifr_name, eth, IFNAMSIZ - 1);

ifr.ifr_name[IFNAMSIZ - 1] = '\0';

if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0)

{

printf("Could not get arptype\n");

return -1;

}

printf("ARPTYPE %d\n", ifr.ifr_hwaddr.sa_family);

memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);

return ifr.ifr_hwaddr.sa_family;

}

注意苟呐,函數(shù)返回的sa_family十分重要痒芝,它是判斷抓取的幀類型的依據(jù)。跟蹤SIOCGIFHWADDR調(diào)用過程掠抬,發(fā)現(xiàn)內(nèi)核驅(qū)動(dòng)將dev->dev_addr賦值給ifr->ifr_hwaddr.sa_data吼野,而dev->type賦值給ifr->ifr_hwaddr.sa_family。

4两波、接收數(shù)據(jù)

一般網(wǎng)絡(luò)接收數(shù)據(jù)都會(huì)使用select模型瞳步,使用recv即可收到內(nèi)核傳遞的數(shù)據(jù)。

int receive_packet(int socket)

{

int ret = 0;

struct timeval tv;

static fd_set read_fds;

tv.tv_sec = 0;

tv.tv_usec = 100;

FD_ZERO(&read_fds);

FD_SET(socket, &read_fds);

ret = select(socket+1, &read_fds, NULL, NULL, &tv);

if (ret == -1 && errno == EINTR) /* interrupted */

return -1;

if (ret == 0)

return -1;

else if (ret < 0)

return -1;

if (FD_ISSET(socket, &read_fds))

{

memset(buffer, '\0', BUFFER_SIZE);

ret = recv(socket, buffer, BUFFER_SIZE, MSG_DONTWAIT);

if (ret <= 0)

return -1;

//printf("--recv len: %d\n", ret);

if (debug_level)

{

dump(buffer, ret);

printf("====================\n");

}

if (arphrd == 1)

parse_packet(buffer, ret); // ieee802.3包

else if (arphrd == 802 || arphrd == 803) // ieee802.11包

parse_packet_wlan(buffer, ret);

}

return 0;

}

函數(shù)最后根據(jù)arphrd類型調(diào)用不同的解析函數(shù)腰奋。這樣就能在同一個(gè)程序中把有線網(wǎng)絡(luò)单起、無線網(wǎng)絡(luò)抓包合二為一了。但本文只針對(duì)無線網(wǎng)絡(luò)包解析劣坊,即函數(shù)parse_packet_wlan嘀倒。

三、解析

下圖是筆者手機(jī)發(fā)的probe request幀截圖(使用tcpdump抓包局冰,再用wireshark查看)测蘑。

其中第一部分是radiotap頭部,第二部分是probe request頭部康二,第三部分是probe request的frame body碳胳。本文只關(guān)心第二部分的MAC地址。其它跳過忽略沫勿。

1挨约、radiotap頭部

radiotap包含大量有用信息,比如SSI信號(hào)強(qiáng)度产雹。但我們暫時(shí)不需要诫惭,直接跳過。它的結(jié)構(gòu)體定義如下:

// radiotap頭部

// radiotap官網(wǎng):http://www.radiotap.org/

struct ieee80211_radiotap_header {

uint8_t? ? ? ? it_version;? ? /* set to 0 */

uint8_t? ? ? ? it_pad;

uint16_t? ? ? it_len;? ? ? ? /* entire length */

uint32_t? ? ? it_present;? ? /* fields present */

} __attribute__((__packed__));

其中的it_len成員表示整個(gè)radiotap頭部的大小蔓挖。因此在代碼中直接使用it_len作偏移量計(jì)算出ieee802.11頭部地址夕土。

2、ieee802.11頭部

ieee802.11頭部結(jié)構(gòu)體如下:

// 802.11幀頭

struct wlan_frame {

uint16_t fc;

uint16_t duration;

uint8_t addr1[6];

uint8_t addr2[6];

uint8_t addr3[6];

uint16_t seq;

union {

uint16_t qos;

uint8_t addr4[6];

struct {

uint16_t qos;

uint32_t ht;

} __attribute__ ((packed)) ht;

struct {

uint8_t addr4[6];

uint16_t qos;

uint32_t ht;

} __attribute__ ((packed)) addr4_qos_ht;

} u;

} __attribute__ ((packed));

從前面的圖示知道时甚,addr1為接收方(Receiver)MAC地址隘弊,addr2為發(fā)送者(Transmitter)MAC地址哈踱,addr3為BSSID。不同類型的幀梨熙,Receiver和Transmitter不同开镣,對(duì)于probe request類型幀來說,Transmitter地址即為所需要的MAC號(hào)——因?yàn)閜robe都是廣播咽扇,目標(biāo)地址都是ff邪财。

下面是解析ieee802.11的函數(shù)代碼:

int parse_packet_wlan(const char* buffer, int len)

{

int hdrlen = 0;

uint16_t fc = 0;

uint8_t* ra = NULL;

uint8_t* ta = NULL;

uint8_t* bssid = NULL;

struct ieee80211_radiotap_header* radiotap_header = NULL;

struct wlan_frame* wh = NULL;

if (buffer == NULL)

{

return -1;

}

radiotap_header = (struct ieee80211_radiotap_header*)buffer;

// it_len表示整個(gè)radiotap信息,包括頭部质欲,因此直接跳過到ieee80211頭部

int radiotap_len = radiotap_header->it_len;

wh = (struct wlan_frame*)(buffer+radiotap_len);

fc = le16toh(wh->fc); // 傳輸格式為little endian树埠,要轉(zhuǎn)換成host格式

int wlan_type = (fc & 0xfc);

int type = (fc & 0xc)>>2;

int stype = (fc & 0xf0)>>4;

//printf("fc:0x%x wlan_type 0x%x - type 0x%x - stype 0x%x \n", fc, wlan_type, type, stype);

// 數(shù)據(jù)幀

if (type == 0x02)

{

}

// 控制幀

else if (type == 0x01)

{

}

// 管理幀

else if (type == 0x0)

{

if (stype == 0x04) // probe幀

{

ra = wh->addr1;

ta = wh->addr2;

bssid = wh->addr3;

if (ta)

printf("SRC MAC: [" MACFMT "] --> ", MAC2ADDR(ta));

if (ra)

printf("DST MAC: [" MACFMT "]", MAC2ADDR(ra));

if (bssid)

printf(" BSSID MAC: [" MACFMT "]", MAC2ADDR(bssid));

printf("\n");

}

}

else

{

printf("unknown frame.\n");

return -1;

}

return 0;

}

看上去十分簡(jiǎn)單,因?yàn)槲覀冎恍枰渲幸环N幀的MAC地址信息嘶伟,其它一概忽視怎憋。

下圖是掃描probe得到的MAC地址,并且根據(jù)OUI查出MAC所屬組織名稱(代碼需修改):

修改后的版本演示結(jié)果如下(代碼需修改):

PS:本文所述代碼工程將會(huì)不斷完善九昧,并擇機(jī)上傳至github绊袋。

附代碼:

李遲 2016.11.01 夜

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市铸鹰,隨后出現(xiàn)的幾起案子癌别,更是在濱河造成了極大的恐慌,老刑警劉巖蹋笼,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件展姐,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡剖毯,警方通過查閱死者的電腦和手機(jī)圾笨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來逊谋,“玉大人墅拭,你說我怎么就攤上這事』凉罚” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵舒憾,是天一觀的道長镀钓。 經(jīng)常有香客問我,道長镀迂,這世上最難降的妖魔是什么丁溅? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮探遵,結(jié)果婚禮上窟赏,老公的妹妹穿的比我還像新娘妓柜。我一直安慰自己,他們只是感情好涯穷,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布棍掐。 她就那樣靜靜地躺著,像睡著了一般拷况。 火紅的嫁衣襯著肌膚如雪作煌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天赚瘦,我揣著相機(jī)與錄音粟誓,去河邊找鬼。 笑死起意,一個(gè)胖子當(dāng)著我的面吹牛鹰服,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播揽咕,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼悲酷,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了心褐?” 一聲冷哼從身側(cè)響起舔涎,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎逗爹,沒想到半個(gè)月后亡嫌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掘而,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年挟冠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片袍睡。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡知染,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出斑胜,到底是詐尸還是另有隱情控淡,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布止潘,位于F島的核電站掺炭,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏凭戴。R本人自食惡果不足惜涧狮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧者冤,春花似錦肤视、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至拜银,卻和暖如春殊鞭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背尼桶。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工操灿, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人泵督。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓趾盐,卻偏偏與公主長得像,于是被迫代替她去往敵國和親小腊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子救鲤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容