一文教你用C代碼解析一段網(wǎng)絡(luò)數(shù)據(jù)包
本文的目的是通過隨機(jī)截取的一段網(wǎng)絡(luò)數(shù)據(jù)包,然后根據(jù)協(xié)議類型來解析出這段內(nèi)存。
學(xué)習(xí)本文需要掌握的基礎(chǔ)知識:
網(wǎng)絡(luò)協(xié)議C語言Linux操作抓包工具的使用
其中抓包工具的安裝和使用見下文:
《一文包你學(xué)會網(wǎng)絡(luò)數(shù)據(jù)抓包》
視頻教學(xué)鏈接如下:
《教你如何抓取網(wǎng)絡(luò)中的數(shù)據(jù)包!黑客必備技能》
一、截取一個(gè)網(wǎng)絡(luò)數(shù)據(jù)包
通過抓包工具,隨機(jī)抓取一個(gè)tcp數(shù)據(jù)包
科萊抓包工具解析出的數(shù)據(jù)包信息如下:
數(shù)據(jù)包的內(nèi)存信息:
數(shù)據(jù)信息可以直接拷貝出來:
二、用到的結(jié)構(gòu)體
下面,一口君就手把手教大家如何解析出這些數(shù)據(jù)包的信息。
我們可以從Linux內(nèi)核中找到協(xié)議頭的定義
以太頭:driversstagingtl8188euincludeif_ether.h
struct ethhdr {
unsigned char h_dest[ETH_ALEN]; destination eth addr
unsigned char h_source[ETH_ALEN]; source ether addr
unsigned short h_proto; packet type ID field
};
IP頭 includeuapilinuxip.h
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD) //小端模式
__u8 ihl:4,
version:4;
#elif defined(__BIG_ENDIAN_BITFIELD) //大端模式
__u8 version:4,
ihl:4;
#endif
__u8 tos;
__u16 tot_len;
__u16 id;
__u16 frag_off;
__u8 ttl;
__u8 protocol;
__u16 check;
__u32 saddr;
__u32 daddr;
The options start here.
};
tcp頭
includeuapilinux cp.h
struct tcphdr {
__be16 source;
__be16 dest;
__be32 seq;
__be32 ack_seq;
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u16 res1:4,
doff:4,
fin:1,
syn:1,
rst:1,
psh:1,
ack:1,
urg:1,
ece:1,
cwr:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
__u16 doff:4,
res1:4,
cwr:1,
ece:1,
urg:1,
ack:1,
psh:1,
rst:1,
syn:1,
fin:1;
#else
#error "Adjust your
因?yàn)閰f(xié)議頭長度都是按照標(biāo)準(zhǔn)協(xié)議來定義的,
所以以太長度是14,IP頭長度是20,tcp頭長度是20,
各個(gè)協(xié)議頭對應(yīng)的內(nèi)存空間如下:
三、解析以太頭 #define MAC_ARG(p) p[0],p[1],p[2],p[3],p[4],p[5]
struct ethhdr *ethh;
unsigned char *p = pkt;
ethh = (struct ethhdr *)p;
printf("h_dest:%02x:%02x:%02x:%02x:%02x:%02x ", MAC_ARG(ethh->h_dest));
printf("h_source:%02x:%02x:%02x:%02x:%02x:%02x ", MAC_ARG(ethh->h_source));
printf("h_proto:%04x",ntohs(ethh->h_proto));
注意,數(shù)據(jù)包中的數(shù)據(jù)是網(wǎng)絡(luò)字節(jié)序,如果要提取數(shù)據(jù)一定要注意字節(jié)序問題ethh->h_proto 是short類型,占2個(gè)字節(jié),所以存儲到本地需要使用函數(shù)ntohs其中:n:network 網(wǎng)絡(luò)字節(jié)序h:host 主機(jī)字節(jié)序s:short 2個(gè)字節(jié)l:long 4個(gè)字節(jié)ntohl() :4字節(jié)網(wǎng)絡(luò)字節(jié)序數(shù)據(jù)轉(zhuǎn)換成主機(jī)字節(jié)序htons() :2字節(jié)主機(jī)字節(jié)序數(shù)據(jù)轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)序ntohs() :2字節(jié)網(wǎng)絡(luò)字節(jié)序數(shù)據(jù)轉(zhuǎn)換成主機(jī)字節(jié)序htonl() :4字節(jié)主機(jī)字節(jié)序數(shù)據(jù)轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)序
當(dāng)執(zhí)行下面這條語句時(shí),
ethh = (struct ethhdr *)p;
結(jié)構(gòu)體指針變量eth的成員對應(yīng)關(guān)系如下:
最終打印結(jié)果如下:
四、解析ip頭
解析ip頭思路很簡單,
就是從pkt頭開始偏移過以太頭長度(14字節(jié))就可以找到IP頭,
解析代碼如下:
#define IP_ARG(p) p[0],p[1],p[2],p[3]
解析IP頭
if(ntohs(ethh->h_proto) == 0x0800)
{
iph = (struct iphdr *)(p + sizeof(struct ethhdr));
q = (unsigned char *)&(iph->saddr);
printf("src ip:%d.%d.%d.%d",IP_ARG(q));
q = (unsigned char *)&(iph->daddr);
printf("dest ip:%d.%d.%d.%d",IP_ARG(q));
}
Iiph
最終解析結(jié)果如下:
可以看到我們正確解析出了IP地址,結(jié)果與抓包工具分析出的數(shù)據(jù)保持了一致。
其中protocol字段表示了ip協(xié)議后面的額協(xié)議類型,常見的值如下:
數(shù)值描述0保留字段,用于IPv6(跳躍點(diǎn)到跳躍點(diǎn)選項(xiàng))1Internet控制消息 (ICMP)2Internet組管理 (IGMP)3網(wǎng)關(guān)到網(wǎng)關(guān) (GGP)41P中的IP(封裝)6傳輸控制 (TCP)7CBT8外部網(wǎng)關(guān)協(xié)議 (EGP)9任何私有內(nèi)部網(wǎng)關(guān)(Cisco在它的IGRP實(shí)現(xiàn)中使用) (IGP)10BBNRCC監(jiān)視11網(wǎng)絡(luò)語音協(xié)議12PUP13ARGUS14EMCON15網(wǎng)絡(luò)診斷工具16混亂(Chaos)17用戶數(shù)據(jù)報(bào)文 (UDP)411Pv6581Pv6的ICMP591Pv6的無下一個(gè)報(bào)頭60IPv6的信宿選項(xiàng)89OSPF IGP92多播傳輸協(xié)議94IP內(nèi)部的IP封裝協(xié)議95可移動網(wǎng)絡(luò)互連控制協(xié)議96旗語通訊安全協(xié)議97IP中的以太封裝98封裝報(bào)頭100GMTP101Ipsilon流量管理協(xié)議133~254未分配255保留五、解析tcp頭
查找tcp頭思路很,
就是從pkt頭開始偏移過以太頭長度(14字節(jié))、和IP頭長度(20字節(jié))就可以找到tcp頭,
switch(iph->protocol)
{
case 0x1:
//icmp
break;
case 0x6:
//tcp
tcph = (struct tcphdr *)(p + sizeof(struct ethhdr) + sizeof(struct iphdr));
printf("source:%d dest:%d ",ntohs(tcph->source),ntohs(tcph->dest);
break;
case 0x11:
//udp
break;
}
結(jié)構(gòu)體與內(nèi)存對應(yīng)關(guān)系
打印結(jié)果如下:
六、學(xué)會用不同格式打印這塊內(nèi)存
在實(shí)際項(xiàng)目中,可能我們解析的并不是標(biāo)準(zhǔn)的TCP/IP協(xié)議數(shù)據(jù)包,
可能是我們自己的定義的協(xié)議數(shù)據(jù)包,
只要掌握了上述方法,
所有的協(xié)議分析都能夠手到擒來!
有時(shí)候我們還需要打印對方發(fā)送過來的數(shù)據(jù)幀內(nèi)容,
往往我們會以16進(jìn)制形式將所有數(shù)據(jù)打印出來,
這樣是最有利于我們分析數(shù)據(jù)內(nèi)容的。
1. 按字節(jié)打印
代碼如下:
for(i=0;i<400;i++)
{
printf("%02x ",pkt[i]);
if(i%20 == 19)
{
printf("");
}
}
2. 按short類型分析一段內(nèi)存
我們接收數(shù)據(jù)時(shí),雖然使用一個(gè)unsigned char型數(shù)組,
但是有時(shí)候?qū)Ψ桨l(fā)送過來的數(shù)據(jù)可能是2個(gè)字節(jié)的數(shù)組,
那我們只需要用short類型的指針,指向內(nèi)存的頭,
然后就可以通過該指針訪問到對方發(fā)送的數(shù)據(jù),
這個(gè)時(shí)候一定要注意字節(jié)序問題,
不同場景可能不一樣,所以一定要具體問題具體分析,
本例因?yàn)槭蔷W(wǎng)絡(luò)字節(jié)序數(shù)據(jù)轉(zhuǎn)換成主機(jī)字節(jié)序,
所以需要轉(zhuǎn)換字節(jié)序。
//轉(zhuǎn)變short型字節(jié)序
void indian_reverse(unsigned short arr[],int num)
{
int i;
unsigned short temp;
for(i=0;i
temp = 0;
temp = (arr[i]&0xff00)>>8;
temp |= (arr[i]&0xff)<<8;
arr[i] = temp;
}
}
main()
{
unsigned short spkt[200];
………………
memcpy(spkt,pkt,sizeof(pkt));
indian_reverse(spkt,ARRAY_SIZE(spkt));
for(i=0;i<200;i++)
{
printf("%04x ",spkt[i]);
if(i%10 == 9)
{
printf("");
}
}
………………
}
結(jié)果如下:
好了,這個(gè)例子掌握了,那么網(wǎng)絡(luò)就算入門了,快操練起來吧!
請輸入評論內(nèi)容...
請輸入評論/評論長度6~500個(gè)字
最新活動更多
-
10月31日立即下載>> 【限時(shí)免費(fèi)下載】TE暖通空調(diào)系統(tǒng)高效可靠的組件解決方案
-
即日-11.13立即報(bào)名>>> 【在線會議】多物理場仿真助跑新能源汽車
-
11月28日立即報(bào)名>>> 2024工程師系列—工業(yè)電子技術(shù)在線會議
-
12月19日立即報(bào)名>> 【線下會議】OFweek 2024(第九屆)物聯(lián)網(wǎng)產(chǎn)業(yè)大會
-
即日-12.26火熱報(bào)名中>> OFweek2024中國智造CIO在線峰會
-
即日-2025.8.1立即下載>> 《2024智能制造產(chǎn)業(yè)高端化、智能化、綠色化發(fā)展藍(lán)皮書》
推薦專題
- 1 【一周車話】沒有方向盤和踏板的車,你敢坐嗎?
- 2 特斯拉發(fā)布無人駕駛車,還未迎來“Chatgpt時(shí)刻”
- 3 特斯拉股價(jià)大跌15%:Robotaxi離落地還差一個(gè)蘿卜快跑
- 4 馬斯克給的“驚喜”夠嗎?
- 5 大模型“新星”開啟變現(xiàn)競速
- 6 海信給AI電視打樣,12大AI智能體全面升級大屏體驗(yàn)
- 7 打完“價(jià)格戰(zhàn)”,大模型還要比什么?
- 8 馬斯克致敬“國產(chǎn)蘿卜”?
- 9 神經(jīng)網(wǎng)絡(luò),誰是盈利最強(qiáng)企業(yè)?
- 10 比蘋果偉大100倍!真正改寫人類歷史的智能產(chǎn)品降臨
- 高級軟件工程師 廣東省/深圳市
- 自動化高級工程師 廣東省/深圳市
- 光器件研發(fā)工程師 福建省/福州市
- 銷售總監(jiān)(光器件) 北京市/海淀區(qū)
- 激光器高級銷售經(jīng)理 上海市/虹口區(qū)
- 光器件物理工程師 北京市/海淀區(qū)
- 激光研發(fā)工程師 北京市/昌平區(qū)
- 技術(shù)專家 廣東省/江門市
- 封裝工程師 北京市/海淀區(qū)
- 結(jié)構(gòu)工程師 廣東省/深圳市