本文的目的是通过随机截取的一段网络数据包,然后根据协议类型来解析出这段内存。

学习本文需要掌握的基础知识:

  1. 网络协议
  2. C语言
  3. Linux操作
  4. 抓包工具的使用

其中抓包工具的安装和使用见下文:

一文包你学会网络数据抓包

视频教学链接如下:

教你如何抓取网络中的数据包!黑客必备技能

一、截取一个网络数据包

通过抓包工具,随机抓取一个tcp数据包



科莱抓包工具解析出的数据包信息如下:



数据包的内存信息:



数据信息可以直接拷贝出来:

二、用到的结构体

下面,一口君就手把手教大家如何解析出这些数据包的信息。

我们可以从Linux内核中找到协议头的定义

  • 以太头:
drivers\staging\rtl8188eu\include\if_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头
	include\uapi\linux\ip.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头

include\uapi\linux\tcp.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 <asm/byteorder.h> defines"
#endif
__be16 window;
__sum16 check;
__be16 urg_ptr;
};

因为协议头长度都是按照标准协议来定义的,

所以以太长度是14,

IP头长度是20,

tcp头长度是20,

各个协议头对应的内存空间如下:

三、解析以太头

#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 \n", MAC_ARG(ethh->h_dest));
printf("h_source:%02x:%02x:%02x:%02x:%02x:%02x \n", MAC_ARG(ethh->h_source));
printf("h_proto:%04x\n",ntohs(ethh->h_proto));

注意,数据包中的数据是网络字节序,如果要提取数据一定要注意字节序问题

ethh->h_proto 是short类型,占2个字节,所以存储到本地需要使用函数ntohs

其中:

n:network 网络字节序

h:host 主机字节序

s:short 2个字节

l:long 4个字节

ntohl() :4字节网络字节序数据转换成主机字节序

htons() :2字节主机字节序数据转换成网络字节序

ntohs() :2字节网络字节序数据转换成主机字节序

htonl() :4字节主机字节序数据转换成网络字节序

当执行下面这条语句时,

ethh = (struct ethhdr *)p;

结构体指针变量eth的成员对应关系如下:



最终打印结果如下:

四、解析ip头

解析ip头思路很简单,

就是从pkt头开始偏移过以太头长度(14字节)就可以找到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\n",IP_ARG(q)); q = (unsigned char *)&(iph->daddr);
printf("dest ip:%d.%d.%d.%d\n",IP_ARG(q));
}

最终解析结果如下:

可以看到我们正确解析出了IP地址,

结果与抓包工具分析出的数据保持了一致。

其中protocol字段表示了ip协议后面的额协议类型,常见的值如下:

数值 描述
0 保留字段,用于IPv6(跳跃点到跳跃点选项)
1 Internet控制消息 (ICMP)
2 Internet组管理 (IGMP)
3 网关到网关 (GGP)
4 1P中的IP(封装)
6 传输控制 (TCP)
7 CBT
8 外部网关协议 (EGP)
9 任何私有内部网关(Cisco在它的IGRP实现中使用) (IGP)
10 BBNRCC监视
11 网络语音协议
12 PUP
13 ARGUS
14 EMCON
15 网络诊断工具
16 混乱(Chaos)
17 用户数据报文 (UDP)
41 1Pv6
58 1Pv6的ICMP
59 1Pv6的无下一个报头
60 IPv6的信宿选项
89 OSPF IGP
92 多播传输协议
94 IP内部的IP封装协议
95 可移动网络互连控制协议
96 旗语通讯安全协议
97 IP中的以太封装
98 封装报头
100 GMTP
101 Ipsilon流量管理协议
133~254 未分配
255 保留

五、解析tcp头

查找tcp头思路很,

就是从pkt头开始偏移过以太头长度(14字节)、和IP头长度(20字节)就可以找到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 \n",ntohs(tcph->source),ntohs(tcph->dest); break;
case 0x11:
//udp break;
}

结构体与内存对应关系

打印结果如下:

六、学会用不同格式打印这块内存

在实际项目中,可能我们解析的并不是标准的TCP/IP协议数据包,

可能是我们自己的定义的协议数据包,

只要掌握了上述方法,

所有的协议分析都能够手到擒来!

有时候我们还需要打印对方发送过来的数据帧内容,

往往我们会以16进制形式将所有数据打印出来,

这样是最有利于我们分析数据内容的。

1. 按字节打印

代码如下:

	for(i=0;i<400;i++)
{
printf("%02x ",pkt[i]);
if(i%20 == 19)
{
printf("\n");
}
}

2. 按short类型分析一段内存

我们接收数据时,虽然使用一个unsigned char型数组,

但是有时候对方发送过来的数据可能是2个字节的数组,

那我们只需要用short类型的指针,指向内存的头,

然后就可以通过该指针访问到对方发送的数据,

这个时候一定要注意字节序问题,

不同场景可能不一样,所以一定要具体问题具体分析,

本例因为是网络字节序数据转换成主机字节序,

所以需要转换字节序。

//转变short型字节序
void indian_reverse(unsigned short arr[],int num)
{
int i;
unsigned short temp; for(i=0;i<num;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("\n");
}
}
………………
}

结果如下:



完整代码请关注公众号:一口Linux,回复:数据包解析

一文教你如何用C代码解析一段网络数据包?【含代码】的更多相关文章

  1. 一个C++版的网络数据包解析策略

    C++版的网络数据包解析策略(升级版) 一.数据包格式形如下图 二.代码 int ReceiveFromRemoteEndPoint() { int nPackageDataLength = ; ch ...

  2. Python 1行代码实现文本分类(实战笔记),含代码详细说明及运行结果

    Python 1行代码实现文本分类(实战笔记),含代码详细说明及运行结果 一.详细说明及代码 tc.py =============================================== ...

  3. C++版的网络数据包解析策略(升级版)

    初版:http://www.cnblogs.com/wjshan0808/p/6580638.html 说明:在实现了对应的接口后该策略可以适合绝大多数的网络数据包结构 首先,是三个接口 IProdu ...

  4. lwip:网络数据包读取和解析过程

    1. 程序的某处(poll or interrupt)在有数据可读时调用ethernetif_input,该函数依次调用以下函数: 1.1 low_level_input(),将网络数据读入内存: 1 ...

  5. MINA 网络黏包处理代码

    本文完整代码,可以浏览: https://github.com/hjj2017/xgame-code_server/blob/master/game_server/src/com/game/gameS ...

  6. lua中是 ffi 解析 【是如何处理数据包的/pkt是如何传进去的】 fsfsfs

    lua中的ffi是如何解析的呢? 拿bcc中对proto的解析说起: metatype是有大学问的: ffi.metatype(ffi.typeof('struct ip_t'), { __index ...

  7. IP报文解析及基于IP 数据包的洪水攻击

    版本(4bit) 报头长度(4bit) 优先级和服务类型(8bit) 总长度(16bit) 标识(16bit) 标志(3bit) 分段偏移(13bit) 存活期(8bit) 协议(8bit) 报头校验 ...

  8. Beam Search快速理解及代码解析

    目录 Beam Search快速理解及代码解析(上) Beam Search 贪心搜索 Beam Search Beam Search代码解析 准备初始输入 序列扩展 准备输出 总结 Beam Sea ...

  9. IM通信协议逆向分析、Wireshark自定义数据包格式解析插件编程学习

    相关学习资料 http://hi.baidu.com/hucyuansheng/item/bf2bfddefd1ee70ad68ed04d http://en.wikipedia.org/wiki/I ...

  10. 承载于以太网帧之上的数据包的解析——ARP、IPv4、IPv6

    承接上一博文而来,继续解析网络数据包,对于承载在以太网上的三种协议进行了解析,主要是分为依据RFC定义的标准先解析头部数据,然后得到有效载荷,即为协议包括的实体数据,更上层进行进一步处理. 一.ARP ...

随机推荐

  1. 【JavaScript】聊聊js中关于this的指向

    前言 最近在看回JavaScript的面试题,this 指向问题是入坑前端必须了解的知识点,现在迎来了ES6+的时代,因为箭头函数的出现,所以感觉有必要对 this 问题梳理一下,所以刚好总结一下Ja ...

  2. 解密Prompt系列33. LLM之图表理解任务-多模态篇

    上一章我们介绍了纯文本模态的表格理解任务,这一章我们聚焦多模态图表数据.先讨论下单纯使用prompt的情况下,图片和文字模态哪种表格模型理解的效果更好更好,再说下和表格相关的图表理解任务的微调方案. ...

  3. 【Redis】BigKey问题

    面试题 海量数据里查询某一固定前缀的key 生产上如何限制 keys * / flushdb / flushall 等危险命令以防止误删误用? MEMORY USAGE 命令用过吗? BigKey问题 ...

  4. windows 安装fvm 安装使用FVM,管理多版本flutter

    背景:win10 1,先用clash代理powershell命令,解决网络问题 2.使用dart 安装FVM dart pub global activate fvm 3.安装后检查系统环境变量 3. ...

  5. WPF单行TextBox自动滚动至末尾

    根据光标位置自动滚动 textBox.CaretIndex = textBox.SelectionStart; var rect = textBox.GetRectFromCharacterIndex ...

  6. 算法金 | DL 骚操作扫盲,神经网络设计与选择、参数初始化与优化、学习率调整与正则化、Loss Function、Bad Gradient

    大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」 今日 216/10000 抱个拳,送个礼 神经网络设计与选择 参数初始化与优化 学习率 ...

  7. UML类图的表示

    1.类的表示方法 2.接口的两种表示方法 3.类的继承怎么表示 空心三角形+实线 4.类实现接口 空心三角形+虚线 5.关联(association)关系 实线箭头 6.聚合(aggregation) ...

  8. 使用scikit-learn构建模型

    sklearn中还存在许多不同的机器学习模型可以直接调用,相比于自己撰写代码,直接使用sklearn的模型可以大大提高效率. sklearn中所有的模型都有四个固定且常用的方法,分别是model.fi ...

  9. 前端开发-- Webpack 代码分割和懒加载技术

    在现代前端开发中,优化应用性能是一个至关重要的任务.Webpack 作为一个强大的打包工具,为我们提供了代码分割和懒加载的功能,可以显著提升应用的加载速度和用户体验.本文将深入解析 Webpack 的 ...

  10. 【SQL】晨光咖啡馆,过滤聚合的微妙碰撞

    这天,小悦懒洋洋地步入办公楼下的咖啡馆,意外地与一位男子不期而遇.他显然因前一晚的辛勤工作而略显疲惫,却仍选择早到此地,寻找一丝宁静与放松.他叫逸尘,身姿挺拔,衣着简约而不失格调,晨光下更显英俊不凡, ...