学习NDIS一段时间了,不过还是毫无头绪,理论都能明白,可是不知道怎么下手去做,网上没有没有太详细的教程。我是比较笨,而且比较懒的。:)
所以准备暂缓NDIS网络和驱动方面的学习,等今后遇见师父了再请教之,好运~
NDIS中的网络数据都是原始的,即没有经过主机协议栈处理的网络数据,如果学习网络协议的话,我觉得研究原始数据包还是挺合适的。
Socket通信中,主机A与主机B之间通信,Socket接收到的内容都是通信的内容,没有附带主机A或主机B的信息,这点可以回想最开始学习Socket编程的时候,主机A发送“Hello,mydearfriend.”,那么主机B收到的确实是“Hello,mydearfriend.”。不像原始数据包中,还会带有以太网帧头、IP头、TCP/UDP头,然后才是通信的内容。所以呢,当我们通过NDIS获取到了原始数据包之后,应该按照现在的网络通信模型对原始数据包进行解析。
=============================================================================================
常用的以太网MAC帧格式有两种,标准:DIXEthernetV2标准(即以太网V2标准)和IEEE的802.3标准。现在使用最多的是以太网V2的MAC帧格式。该标准由5个字段组成:6字节的目的地址、6字节的源地址、2字节的类型(用来标识上一层的协议类型,例如:0x0800表示上层使用是IP数据报)、46字节至1500字节长度不等的IP数据报,以及4字节的帧检验序列(FCS)。分析每一帧可以得到此数据包的源MAC地址和目的MAC地址,并且可以得到IP数据报的完整内容。
IP数据报的第4至7位是IP首部长度,该字段可以用来准确定位上层协议的起始位置(例如:TCP的首部)。第10字节是协议字段,指出该IP数据报携带的数据使用何种协议,常用的协议字段如表1所示。第13至16字节是源IP地址,第17至20字节是目的IP地址。因此可以据此解析出该数据包的源IP地址和目的IP地址。
表1常用的IP协议和相应的字段值
协议名 |
ICMP |
IGMP |
TCP |
EGP |
IGP |
UDP |
IPv6 |
OSPF |
协议字段值 |
1 |
3 |
6 |
8 |
9 |
17 |
41 |
89 |
TCP报文段的第1至2字节是源端口号,第3至4字节是目的端口号。第13字节的前4位是数据偏移,该字段实际上指出了TCP报文段的首部长度。如果TCP承载的是HTTP协议,则可以据此定位HTTP协议的起始位置。系统处理时,如果分析是HTTP协议,则提取出HTTP的内容,以明文显示。而可以直接显示HTTP报文信息的原因是:HTTP是应用层协议,使用面向连接的TCP作为传输层协议,在向下层传递时是以明文的方式直接传递,即TCP在HTTP报文前加TCP头封装HTTP报文。因此,只要把捕获到的数据包依次剥去MAC头、IP头、TCP头,就可以显示HTTP报文的内容了。
HTTP报文分为两种:请求报文和响应报文。
对于判断是否为HTTP报文,目前还没有快速有效的方法。传统的方法依据:①传送HTTP报文前是否有TCP的三次握手;②判断数据包中是否含有诸如“GET”、“HTTP/1.1”等关键字。对于这两种方法,第①点需要一定的空间开销,要判断TCP承载的是否为HTTP报文,需要分配一定的空间存储前3个数据包的相关信息(实际并不需要存储3个数据包的全部内容,但是即便是若干比特的信息,也会增加NPF的负担),这给NPF(NetgroupPacketFilter)的运行速率和存储器带来挑战;对于第②点,由于HTTP是面向文本的,因此在报文中的每一个字段都是一些ASCII码串,因而各个字段的长度都是不确定的。请求报文中除了“GET”方法外,还有7种常用的方法,如果要一一模式匹配来确定是否是HTTP报文,显然会造成很大的时间开销。此外,响应报文含“HTTP/1.1”(或HTTP/1.0)的版本号,这个字段在请求报文中也有,具体的版本是1.1还是1.0则是不确定的。因此,综合考虑时间和空间的开销,本文采取模式匹配“HTTP”的方法来判断是否为HTTP报文。具体方法是:捕获到的数据包从TCP的尾部(HTTP的第一个字节)开始匹配“HTTP”,如果匹配成功,则认为是HTTP报文,否则就不是。这种方法存在的问题是:①如果TCP承载的是FTP或SMTP等其他应用层协议,恰好在某个部分也含有“HTTP”字样,则会误判为HTTP报文。但是由于基于HTTP协议的Web服务已经成为Internet的主流,非HTTP协议只占到小部分,因此误判的几率很小。系统测试期间,还未发现此类误判问题,用户界面显示的明文信息表明:确为HTTP协议的请求报文或响应报文。②该方法本身不存在“漏判”,因为所有的HTTP报文都含有“HTTP”字样,而抓到的数据包只要含有“HTTP”字样,就被过滤认为HTTP报文。但是,由于该方法需要一定的时间开销,可能来不及匹配后续的数据包而造成广义上的“漏判”。这个问题通过编写高效的模式匹配算法可以得到一定的改进,但是不能解决根本问题。根本问题在于匹配速度和内核的存储器容量的限制。
对于过滤用户指定的IP地址和端口号,用户输入的IP地址为char[]字符数组型,而且是用标准的Internet的“.”间隔格式来表示一个Internet地址,而捕获得到的数据包拆包后的IP地址是网络字节的,因此不可直接比较。本文的方法是:首先用inet_addr()将用户输入的IP地址转换成一个无符号长整型数(实际上是in_addr类型),然后与抓到的数据包的4字节IP地址一一比较,即可过滤出用户指定的IP地址。对于端口号亦可类似处理。
=============================================================================================
这里仅对原始数据包中HTTP的解析,如果是原始数据包中其他应用层的协议解析,也可参考此思路。
说明:这里例举原始数据包中HTTP的解析的原因是,我想做一个防火墙,不仅可以屏蔽某个网站(这里有两种方法:①屏蔽该网站的IP地址②主机发送到该网站的HTTP请求时,自己通过程序伪造一个HTTP应答在网站的主机返回HTTP应答之前返回给浏览器,毕竟和“127.0.0.1”比其他IP地址通信更快。可能第二种方法有问题。),还可以屏蔽某网站的某个页面(方法可参考屏蔽某个网站的方法②)。
【参考资料感谢作者】
基于WinPcap的数据包捕获和分析系统的设计与实现:http://www.paper.edu.cn
附:
1 #define ETHERTYPE_IP 0x0800
2 #define ETHERTYPE_ARP 0x0806
3
4 typedef struct _ETHeader // 14 bytes
5 {
6 UCHAR dhost[6]; // 目的MAC地址destination mac address
7 UCHAR shost[6]; // 源MAC地址source mac address
8 USHORT type; // 下层协议类型,如IP(ETHERTYPE_IP)、ARP(ETHERTYPE_ARP)等
9 } ETHeader, *PETHeader;
10
11 #define ARPHRD_ETHER 1
12
13 // ARP协议opcodes
14 #define ARPOP_REQUEST 1 // ARP 请求
15 #define ARPOP_REPLY 2 // ARP 响应
16
17 typedef struct _ARPHeader // 28字节的ARP头
18 {
19 USHORT hrd; // 硬件地址空间,以太网中为ARPHRD_ETHER
20 USHORT eth_type; // 以太网类型,ETHERTYPE_IP ??
21 UCHAR maclen; // MAC地址的长度,为6
22 UCHAR iplen; // IP地址的长度,为4
23 USHORT opcode; // 操作代码,ARPOP_REQUEST为请求,ARPOP_REPLY为响应
24 UCHAR smac[6]; // 源MAC地址
25 UCHAR saddr[4]; // 源IP地址
26 UCHAR dmac[6]; // 目的MAC地址
27 UCHAR daddr[4]; // 目的IP地址
28 } ARPHeader, *PARPHeader;
29
30
31 typedef union _IPADDRESS{
32 ULONG ip;
33 UCHAR a[4];
34 }IPADDRESS, *PIPADDRESS;
35
36 //Protocol
37 typedef struct _IPHeader // 20
38 {
39 UCHAR iphVerLen; // 版本号和头长度(各占4位)
40 UCHAR ipTOS; // 服务类型
41 USHORT ipLength; // 封包总长度,即整个IP报的长度
42 USHORT ipID; // 封包标识,惟一标识发送的每一个数据报
43 USHORT ipFlags; // 标志
44 UCHAR ipTTL; // 生存时间,就是TTL
45 UCHAR ipProtocol; // 协议,可能是TCP、UDP、ICMP等
46
47 #define PROTO_ICMP 1
48 #define PROTO_IGMP 2
49 #define PROTO_TCP 6
50 #define PROTO_UDP 17
51 USHORT ipChecksum; // 校验和
52 IPADDRESS srcip;
53 IPADDRESS destip;
54 } IPHeader, *PIPHeader;
55
56
57 // define the tcp flags....
58 #define TCP_FIN 0x01
59 #define TCP_SYN 0x02
60 #define TCP_RST 0x04
61 #define TCP_PSH 0x08
62 #define TCP_ACK 0x10
63 #define TCP_URG 0x20
64 #define TCP_ACE 0x40
65 #define TCP_CWR 0x80
66
67 typedef struct _TCPHeader //20 bytes
68 {
69 USHORT sourcePort; // 16位源端口号
70 USHORT destinationPort; // 16位目的端口号
71 ULONG sequenceNumber; // 32位序列号
72 ULONG acknowledgeNumber; // 32位确认号
73 UCHAR dataoffset; // 高4位表示数据偏移
74 UCHAR flags; // 6位标志位
75 //FIN - 0x01
76 //SYN - 0x02
77 //RST - 0x04
78 //PUSH- 0x08
79 //ACK- 0x10
80 //URG- 0x20
81 //ACE- 0x40
82 //CWR- 0x80
83 USHORT windows; // 16位窗口大小
84 USHORT checksum; // 16位校验和
85 USHORT urgentPointer; // 16位紧急数据偏移量
86 } TCPHeader, *PTCPHeader;
87
88 typedef struct _UDPHeader
89 {
90 USHORT sourcePort; // 源端口号
91 USHORT destinationPort;// 目的端口号
92 USHORT len; // 封包长度
93 USHORT checksum; // 校验和
94 } UDPHeader, *PUDPHeader;
95
96 /*tcp_udp校验和尾首部定义*/
97 typedef struct Psd_head{
98 IPADDRESS sadr; //源IP地址
99 IPADDRESS dadr; //目的IP地址
100 u_char mbz; //置空(0)
101 u_char proto; //协议内型
102 u_short tlen;//TCP/UDP数据包的长度(即从TCP/UDP报头算起到数据包结束的长度 单位:字节)
103 }Psd_header;
104
105 typedef struct _ICMPHeader
106 {
107 UCHAR type;
108 UCHAR code;
109 USHORT checksum;
110 USHORT id;
111 USHORT sequence;
112 ULONG timestamp;
113 } ICMPHeader, *PICMPHeader;
快捷操作:
坚其志,苦其心,劳其力,事无大小,必有所成。
@如有侵权,请作者本人尽快与我(chrayo#163.com)联系,我将及时删除侵权内容。