1.怎样用C语言实现网络抓包?
2.[源码和文档分享]基于Libpcap实现的局域网嗅探抓包发包解析工具
怎样用C语言实现网络抓包?
第一法则:站在巨人肩膀上 && 不要重复造轮子。对于这种复杂的过程,第一选择是使用现成的,节约时间,提升效率。
Wireshark(前称Ethereal)是并发编程源码分析一个网络封包分析软件。网络封包分析软件的功能是撷取网络封包,并尽可能显示出最为详细的网络封包资料。Wireshark使用WinPCAP作为接口,直接与网卡进行数据报文交换。
网络封包分析软件的功能可想像成 "电工技师使用电表来量测电流、电压、电阻" 的如何修改linux源码工作 - 只是将场景移植到网络上,并将电线替换成网络线。在过去,网络封包分析软件是非常昂贵,或是专门属于营利用的软件。Ethereal的出现改变了这一切。在GNUGPL通用许可证的保障范围底下,使用者可以以免费的代价取得软件与其源代码,并拥有针对其源代码修改及客制化的权利。Ethereal是目前全世界最广泛的网络封包分析软件之一。
第二法则:学习 && 提升。
如果是单纯的学习知识,可以直接尝试写一些具有部分功能的月亮是光源码程序,过程会有点艰难,但非常有意义。学习网络编程,需要了解 开放系统互连参考模型的的七层每一层的意义以及现实当中实现的四层的网络协议。然后就可以知道抓包的包位于模型当中的传输层协议,包括UDP和TCP的协议。进一步要学习每种协议的格式,表头,数据包等等。一句话,冰冻三尺非一日之寒。
Windows下的信用评级程序源码抓包及简单的编程。
Windows在TCP/IP协议组件上做了很多改进,功能也有增强。比如在协议栈上的调整,增大了默认窗口大小,以及高延迟链接新算法。同时在安全性上,可应用IPSec加强安全性,比NT下有不少的改进。
Microsoft TCP/IP 组件包含“核心协议”、“服务”及两者之间的“接口”。传输驱动程序接口 (TDI) 与网络设备接口规范 (NDIS) 是公用的。 此外,微信 网页源码还有许多用户模型应用程序的更高级接口。最常用的接口是 Windows Sockets、远程过程调用 (RPC) 和 NetBIOS。
Windows Sockets 是一个编程接口,它是在加州大学伯克利分校开发的套接字接口的基础上定义的。它包括了一组扩展件,以充分利用 Microsoft Windows 消息驱动的特点。规范的 1.1 版是在 年 1 月发行的,2.2.0 版在 年 5 月发行。Windows 支持 Winsock 2.2 版。在Winsock2中,支持多个传输协议的原始套接字,重叠I/O模型、服务质量控制等。
这里介绍Windows Sockets的一些关于原始套接字(Raw Socket)的编程。同Winsock1相比,最明显的就是支持了Raw Socket套接字类型,通过原始套接字,我们可以更加自如地控制Windows下的多种协议,而且能够对网络底层的传输机制进行控制。
1、创建一个原始套接字,并设置IP头选项。
SOCKET sock;
sock = socket(AF_INET,SOCK_RAW,IPPROTO_IP);
或者:
s = WSASoccket(AF_INET,SOCK_RAW,IPPROTO_IP,NULL,0,WSA_FLAG_OVERLAPPED);
这里,我们设置了SOCK_RAW标志,表示我们声明的是一个原始套接字类型。创建原始套接字后,IP头就会包含在接收的数据中,如果我们设定 IP_HDRINCL 选项,那么,就需要自己来构造IP头。注意,如果设置IP_HDRINCL 选项,那么必须具有 administrator权限,要不就必须修改注册表:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Afd\Parameter\
修改键:DisableRawSecurity(类型为DWORD),把值修改为 1。如果没有,就添加。
BOOL blnFlag=TRUE;
setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&blnFlag, sizeof(blnFlag);
对于原始套接字在接收数据报的时候,要注意这么几点:
a、如果接收的数据报中协议类型和定义的原始套接字匹配,那么,接收的所有数据就拷贝到套接字中。
b、如果绑定了本地地址,那么只有接收数据IP头中对应的远端地址匹配,接收的数据就拷贝到套接字中。
c、如果定义的是外部地址,比如使用connect(),那么,只有接收数据IP头中对应的源地址匹配,接收的数据就拷贝到套接字中。
2、构造IP头和TCP头
这里,提供IP头和TCP头的结构:
// Standard TCP flags
#define URG 0x
#define ACK 0x
#define PSH 0x
#define RST 0x
#define SYN 0x
#define FIN 0x
typedef struct _iphdr //定义IP首部
{
unsigned char h_lenver; //4位首部长度+4位IP版本号
unsigned char tos; //8位服务类型TOS
unsigned short total_len; //位总长度(字节)
unsigned short ident; //位标识
unsigned short frag_and_flags; //3位标志位
unsigned char ttl; //8位生存时间 TTL
unsigned char proto; //8位协议 (TCP, UDP 或其他)
unsigned short checksum; //位IP首部校验和
unsigned int sourceIP; //位源IP地址
unsigned int destIP; //位目的IP地址
}IP_HEADER;
typedef struct psd_hdr //定义TCP伪首部
{
unsigned long saddr; //源地址
unsigned long daddr; //目的地址
char mbz;
char ptcl; //协议类型
unsigned short tcpl; //TCP长度
}PSD_HEADER;
typedef struct _tcphdr //定义TCP首部
{
USHORT th_sport; //位源端口
USHORT th_dport; //位目的端口
unsigned int th_seq; //位序列号
unsigned int th_ack; //位确认号
unsigned char th_lenres; //4位首部长度/6位保留字
unsigned char th_flag; //6位标志位
USHORT th_win; //位窗口大小
USHORT th_sum; //位校验和
USHORT th_urp; //位紧急数据偏移量
}TCP_HEADER;
TCP伪首部并不是真正存在的,只是用于计算检验和。校验和函数:
USHORT checksum(USHORT *buffer, int size)
{
unsigned long cksum=0;
while (size > 1)
{
cksum += *buffer++;
size -= sizeof(USHORT);
}
if (size)
{
cksum += *(UCHAR*)buffer;
}
cksum = (cksum >> ) + (cksum & 0xffff);
cksum += (cksum >>);
return (USHORT)(~cksum);
}
当需要自己填充IP头部和TCP头部的时候,就同时需要自己计算他们的检验和。
3、发送原始套接字数据报
填充这些头部稍微麻烦点,发送就相对简单多了。只需要使用sendto()就OK。
sendto(sock, (char*)&tcpHeader, sizeof(tcpHeader), 0, (sockaddr*)&addr_in,sizeof(addr_in));
下面是一个示例程序,可以作为SYN扫描的一部分。
#include <stdio.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#define SOURCE_PORT
#define MAX_RECEIVEBYTE
typedef struct ip_hdr //定义IP首部
{
unsigned char h_verlen; //4位首部长度,4位IP版本号
unsigned char tos; //8位服务类型TOS
unsigned short total_len; //位总长度(字节)
unsigned short ident; //位标识
unsigned short frag_and_flags; //3位标志位
unsigned char ttl; //8位生存时间 TTL
unsigned char proto; //8位协议 (TCP, UDP 或其他)
unsigned short checksum; //位IP首部校验和
unsigned int sourceIP; //位源IP地址
unsigned int destIP; //位目的IP地址
}IPHEADER;
typedef struct tsd_hdr //定义TCP伪首部
{
unsigned long saddr; //源地址
unsigned long daddr; //目的地址
char mbz;
char ptcl; //协议类型
unsigned short tcpl; //TCP长度
}PSDHEADER;
typedef struct tcp_hdr //定义TCP首部
{
USHORT th_sport; //位源端口
USHORT th_dport; //位目的端口
unsigned int th_seq; //位序列号
unsigned int th_ack; //位确认号
unsigned char th_lenres; //4位首部长度/6位保留字
unsigned char th_flag; //6位标志位
USHORT th_win; //位窗口大小
USHORT th_sum; //位校验和
USHORT th_urp; //位紧急数据偏移量
}TCPHEADER;
//CheckSum:计算校验和的子函数
USHORT checksum(USHORT *buffer, int size)
{
unsigned long cksum=0;
while(size >1)
{
cksum+=*buffer++;
size -=sizeof(USHORT);
}
if(size )
{
cksum += *(UCHAR*)buffer;
}
cksum = (cksum >> ) + (cksum & 0xffff);
cksum += (cksum >>);
return (USHORT)(~cksum);
}
void useage()
{
printf("