本文将通过winsock从应用层捕捉网络层的IP数据报。
唉,原来的时候一直希望能在应用层实现网络游戏加速,发现可以捕捉网卡IP数据报后觉得可能有希望写出来。后面想了想得出结论:可以捕获没卵用,因为没法拦截(包已经发出去了,才反馈给你的,充其量自己就是个监听者),然后又搜了搜那我争取拦截呗,又发现了应用层下似乎只能通过lsp劫持实现,然后游戏呢绝壁检测你的,最终得出结论,还得上驱动【呃虚拟网卡可以吗,我不晓得,去研究一下吧】。
1.使用winsock
	//初始化套接字
	WSADATA WSAData;
	if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)
	{
		cout << endl << "WSASTartup初始化失败" << endl;
		return;
	}需要俩头文件
#include <winsock.h>
#pragma comment(lib,"ws2_32.lib")
相当于初始化加载winsock.dll,然后winsock返回给你一个WSAData告诉你本机中winsock的信息
2.创建套接字
SOCKET sock = socket(AF_INET, SOCK_RAW, IPPROTO_IP); //三个参分别为通信发生的区字段,套接字的类型,与IP协议
	if (sock == INVALID_SOCKET)
	{
		cout << endl << "创建Socket失败!" << endl;
		closesocket(sock);
		WSACleanup();
	}socket(a,b,c)
a为AF_INET 【通信发生的区字段,具体啥意思,还有啥我不知道捏,自行百度吧。】
b为SOCK_STREAM,SOCK_DGRAM,SOCK_RAW三个之一。【套接字的类型】
SOCK_STREAM(tcp)SOCK_DGRAM(UDP)SOCK_RAW(IP)
c为参数
IPPROTO_IP = 0,   /* Dummy protocol for TCP   */
 IPPROTO_ICMP = 1,   /* Internet Control Message Protocol */
 IPPROTO_IGMP = 2,   /* Internet Group Management Protocol */
 IPPROTO_IPIP = 4,   /* IPIP tunnels (older KA9Q tunnels use 94) */
 IPPROTO_TCP = 6,   /* Transmission Control Protocol */
 IPPROTO_EGP = 8,   /* Exterior Gateway Protocol   */
 IPPROTO_PUP = 12,   /* PUP protocol     */
 IPPROTO_UDP = 17,   /* User Datagram Protocol   */
 IPPROTO_IDP = 22,   /* XNS IDP protocol    */
 IPPROTO_DCCP = 33,   /* Datagram Congestion Control Protocol */
 IPPROTO_RSVP = 46,   /* RSVP protocol    */
 IPPROTO_GRE = 47,   /* Cisco GRE tunnels (rfc 1701,1702) */
IPPROTO_IPV6 = 41, /* IPv6-in-IPv4 tunnelling */
IPPROTO_ESP = 50,            /* Encapsulation Security Payload protocol */
 IPPROTO_AH = 51,             /* Authentication Header protocol       */
 IPPROTO_BEETPH = 94,        /* IP option pseudo header for BEET */
 IPPROTO_PIM    = 103,   /* Protocol Independent Multicast */
IPPROTO_COMP   = 108,                /* Compression Header protocol */
 IPPROTO_SCTP   = 132,   /* Stream Control Transport Protocol */
 IPPROTO_UDPLITE = 136, /* UDP-Lite (RFC 3828)    */
IPPROTO_RAW = 255,   /* Raw IP packets    */
 IPPROTO_MAX
对于socket(AF_INET, SOCK_RAW, IPPROTO_IP),其原型为
int socket (int domain, int type, int protocol);
1 参数protocol用来指明所要接收的协议包,如果是象IPPROTO_TCP(6)这种非0、非255的协议,当操作系统内核碰到ip头中protocol域和创建socket所使用参数protocol相同的IP包,就会交给这个raw socket来处理,因此,一般来说,要想接收什么样的数据包,就应该在参数protocol里来指定相应的协议。当内核向此raw socket交付数据包的时候,是包括整个IP头的,并且已经是重组好的IP包。
 2 如果protocol是IPPROTO_RAW(255),这时候,这个socket只能用来发送IP包,而不能接收任何的数据。发送的数据需要自己填充IP包头,并且自己计算校验和。
 3 对于protocol为0(IPPROTO_IP)的raw socket。用于接收任何的IP数据包。其中的校验和和协议分析由程序自己完成
【上面那段我抄的,差不多意思能明白点,但是这个socket函数的b和c参数不是冗余了吗,感觉是有点捏。想了想也有可能是下面这样滴】
b参数指明这个socket能盛放啥类型。c参数指明内核你要给我捕捉啥协议的。【小白理解。可能有错】
3.hostent结构体的说明

4.地址信息的表示
sockaddr_in结构体
struct sockaddr_in
{
    short sin_family;        //协议族Address family
    unsigned short sin_port;    //16位TCP/UDP端口号
    struct in_addr sin_addr;    //32位IP地址
    unsigned char sin_zero[8];  //没有实际意义,只是为了跟SOCKADDR结构在内存中对齐
};
结构体sockaddr_in的成员分析
成员sin_family:
每种协议适用的地址族均不同。比如,IPv4使用4字节地址族,IPv6使用16字节地址族,可以参考表1-2保存的sin_family地址信息
| 地址族(Adddress Family) | 含义 | 
| AF_INET | IPv4网络协议中使用的地址族 | 
| AF_INET6 | IPv6网络协议中使用的地址族 | 
| AF_LOCAL | 本地通信中采用的Unix协议的地址族 | 
AF_LOCAL只是为了说明具有多种地址族而添加的
成员sin_port:
该成员保存16位端口号,且以网络字节序保存(后续还会说明何为网络字节序)
成员sin_addr:
该成员保存32位IP地址信息,且也以网络字节序保存。为理解好该成员,应同时观察结构体in_addr。但结构体in_addr声明为uint32_t,因此只需当做32位整数即可
成员sin_zero:
无特殊含义,只是为了结构体sockaddr_in的大小与sockaddr结构体保持一致而插入的成员。必须填充为0,否则无法得到想要的结果,后续还会介绍sockaddr
【以下个人小白理解,可能有错误。】
【操作系统内部维护了一个类似socket列表的东西,socket呢就是负责你进程使用操作系统的通信资源的,一开始socket被申请出来了,但是占用的本机IP和端口都没有声明。这时候你可以调用bind来指定,指定之后,你的程序就用声明的这一块资源来做事,声明的本机IP和端口就被占用了。操作系统就不会把这个ip和端口分配给别的进程亦或者说别的socket来使用】
5.WSAIoctl
控制一个socket的模式,自行百度吧
6.所有代码,没说的东西都是没啥技术含量的。翻翻书就会的
代码在vs2019编译通过,vs2019有安全审查【可能导致编译不通过】,取消的话
【VS socket】不兼容老版本函数的问题_aaaabbbwwww的博客-CSDN博客
#include <iostream> 
#include <winsock2.h> 
#include <ws2tcpip.h> 
#include <fstream>
#include <windows.h> 
#pragma comment(lib,"ws2_32.lib") //指定连接到网络应用和internet
#define IO_RCVALL _WSAIOW(IOC_VENDOR,1)
typedef struct IP_HEAD
{
	union //定义联合
	{
		unsigned char Version;
		unsigned char HeadLen;
	};
	unsigned char ServiceType;
	unsigned short TotalLen;
	unsigned short Identifier;
	union
	{
		unsigned short Flags;
		unsigned short FragOffset;
	};
	unsigned char TimeToLive;
	unsigned char Protocol;
	unsigned short HeadChecksum;
	unsigned int SourceAddr;
	unsigned int DestinAddr;
	unsigned char Options;
}ip_head; //定义IP头部的数据结构
void main(int argc, char* argv[])
{
	using namespace std;
	ofstream outfile("C://logfile.txt", ios::out);
	/*
	if(argc!=2)
	{
	cout<<endl<<"请以下格式输入命令行:PackParse packet_sum"<<endl;
	return;
	}
	*/
	//初始化套接字
	WSADATA WSAData;
	if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)
	{
		cout << endl << "WSASTartup初始化失败" << endl;
		return;
	}
	//创建套接字
	SOCKET sock = socket(AF_INET, SOCK_RAW, IPPROTO_IP); //三个参分别为通信发生的区字段,套接字的类型,与IP协议
	if (sock == INVALID_SOCKET)
	{
		cout << endl << "创建Socket失败!" << endl;
		closesocket(sock);
		WSACleanup();
	}
	/*
	BOOL flag=TRUE;
	if(setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char *) &flag,sizeof(flag))==SOCKET_ERROR)
	{
	cout<<endl<<"setsockopt操作失败:"<<WSAGetLastError()<<endl;
	closesocket(sock);
	WSACleanup();
	}
	*/
	char hostName[128]; //获取主机名 
	if (gethostname(hostName, 128) == SOCKET_ERROR)
	{
		cout << endl << "gethostname操作失败:" << WSAGetLastError() << endl;
		closesocket(sock);
		WSACleanup();
	}
	hostent* pHostIP; //获取本地IP
	if ((pHostIP = gethostbyname(hostName)) == NULL)
	{
		cout << endl << "gethostbyname操作失败:" << WSAGetLastError() << endl;
		closesocket(sock);
		WSACleanup();
	}
	sockaddr_in host_addr; //绑定到本机套接字
	host_addr.sin_family = AF_INET;
	host_addr.sin_port = htons(9003);
	host_addr.sin_addr = *(in_addr*)pHostIP->h_addr_list[0];
	if (bind(sock, (PSOCKADDR)&host_addr, sizeof(host_addr)) == SOCKET_ERROR)
	{
		cout << endl << "bind操作失败:" << WSAGetLastError() << endl;
		closesocket(sock);
		WSACleanup();
	}
	DWORD dwBufferLen[10]; //修改本机套接字类型,以接受所有数据
	DWORD dwBufferInLen = 1;
	DWORD dwBytesReturned = 0;
	if (WSAIoctl(sock, IO_RCVALL, &dwBufferInLen, sizeof(dwBufferInLen), &dwBufferLen, sizeof(dwBufferLen), &dwBytesReturned, NULL, NULL) == SOCKET_ERROR)
	{
		cout << endl << "WSAIoctl操作失败:" << WSAGetLastError() << endl;
		closesocket(sock);
		WSACleanup();
	}
	cout << endl << "开始解析IP包:" << endl;
	char buffer[65535]; //设置缓冲区
	//int packsum=atoi("3"); //字符串转换为整形
	while(1)
	{
		if (recv(sock, buffer, 65535, 0) > 0) //四个参数分别是套接字描述符,缓冲区的地址,缓冲区大小,附加标志
		{
			dec(cout);
			ip_head ip = *(ip_head*)buffer;
			cout << "-----------------------" << endl;
			cout << "版本:" << (ip.Version >> 4) << endl; //要右移4位获取头部长度字段,第一个char的高四位bit存放version。当前是IPv4。第一个char的低四位bit存放报头长度,它指出了按32   bit   长标定的报头长度,报头的实际长度是   h_len   <<   2   。如果报头长度不是32   bit   的整数倍,则由填充域添0补充。
			cout << "头部长度:" << ((ip.HeadLen & 0x0f) * 4) << endl; //获取头部长度字段按32bit为一单位,故要乘以4
			cout << "服务类型:Priority" << (ip.ServiceType >> 5) << ", Service" << ((ip.ServiceType >> 1) & 0x0f) << endl;
			cout << "总长度:" << ntohs(ip.TotalLen) << endl;//获取总长度字段 
			cout << "标识符:" << ntohs(ip.Identifier) << endl;//获取标识字段 
			cout << "标志位:" << ((ip.Flags >> 15) & 0x01) << ",DF= " << ((ip.Flags >> 14) & 0x01) << ",Mf=" << ((ip.Flags >> 13) & 0x01) << endl; //获得标志字段
			cout << "片偏移:" << (ip.FragOffset & 0x1fff) << endl; //获取分段偏移字段
			cout << "生存周期:" << (int)ip.TimeToLive << endl; //获取生存时间字段
			cout << "协议:Protocol" << (int)ip.Protocol << endl; //获取协议字段
			cout << "头部校验和:" << hex << ntohs(ip.HeadChecksum) << hex << endl; //获取头校验和字段
			cout << "原地址:" << inet_ntoa(*(in_addr*)&ip.SourceAddr) << endl; //获取源IP地址字段
			cout << "目的IP地址:" << inet_ntoa(*(in_addr*)&ip.DestinAddr) << endl; //获取目的IP地址字段
			char str[100];
			int is = 128;
			//cout << "版本:" << itoa(is, str, 2) << endl; //要右移4位获取头部长度字段,第一个char的高四位bit存放version。当前是IPv4。第一个char的低四位bit存放报头长度,它指出了按32   bit   长标定的报头长度,报头的实际长度是   h_len   <<   2   。如果报头长度不是32   bit   的整数倍,则由填充域添0补充。
			/*cout<<"头部长度:"<<ip.HeadLen<<endl; //获取头部长度字段按32bit为一单位,故要乘以4
			cout<<"服务类型:"<<ip.ServiceType<<", Service"<<ip.ServiceType<<endl;
			cout<<"总长度:"<<ip.TotalLen<<endl;//获取总长度字段
			cout<<"标识符:"<<ip.Identifier<<endl;//获取标识字段
			cout<<"标志位:"<<ip.Flags<<endl; //获得标志字段
			cout<<"片偏移:"<<ip.FragOffset<<endl; //获取分段偏移字段
			cout<<"生存周期:"<<(int)ip.TimeToLive<<endl; //获取生存时间字段
			cout<<"协议:Protocol"<<(int)ip.Protocol<<endl; //获取协议字段
			cout<<"头部校验和:"<<ip.HeadChecksum<<endl; //获取头校验和字段
			cout<<"原地址:"<<inet_ntoa(*(in_addr *)&ip.SourceAddr)<<endl; //获取源IP地址字段
			cout<<"目的IP地址:"<<inet_ntoa(*(in_addr *)&ip.DestinAddr)<<endl; //获取目的IP地址字段
			*/
			outfile << "-----------------------" << endl;
			dec(outfile);
			outfile << "版本:" << (ip.Version >> 4) << endl;
			outfile << "头部长度:" << ((ip.HeadLen & 0x0f) * 4) << endl;
			outfile << "服务类型:Priority" << (ip.ServiceType >> 5) << ", Service" << ((ip.ServiceType >> 1) & 0x0f) << endl;
			outfile << "总长度:" << ntohs(ip.TotalLen) << endl;
			outfile << "标识符:" << ntohs(ip.Identifier) << endl;
			outfile << "标志位:" << ((ip.Flags >> 15) & 0x01) << ",DF= " << ((ip.Flags >> 14) & 0x01) << ",Mf=" << ((ip.Flags >> 13) & 0x01) << endl;
			outfile << "片偏移:" << (ip.FragOffset & 0x1fff) << endl;
			outfile << "生存周期:" << (int)ip.TimeToLive << endl;
			outfile << "协议:Protocol" << (int)ip.Protocol << endl;
			outfile << "头部校验和:" << hex << ntohs(ip.HeadChecksum) << endl;
			outfile << "原地址:" << inet_ntoa(*(in_addr*)&ip.SourceAddr) << endl;
			outfile << "目的IP地址:" << inet_ntoa(*(in_addr*)&ip.DestinAddr) << endl;
		}
	}
	closesocket(sock);
	WSACleanup();
}



![[附源码]Nodejs计算机毕业设计基于web的家教管理系统Express(程序+LW)](https://img-blog.csdnimg.cn/7297cc7ca48a406d9bd19b5fcfc6d185.png)

![[附源码]Node.js计算机毕业设计电影票网上订票系统Express](https://img-blog.csdnimg.cn/6241bce620574d6e9a91f0a6a9887d74.png)









![[附源码]Nodejs计算机毕业设计基于web的火车订票管理系统Express(程序+LW)](https://img-blog.csdnimg.cn/0a0f283ce4734e99aa72064e46a5b86a.png)



