TCP/IP 网络嗅探器开发实例
创始人
2024-03-16 09:16:28
0

主要内容

实例使用环境

知识储备

IP数据报格式

IP头结构体定义

TCP头格式

TCP头结构体定义

实例的调用演示

 实例的完整代码

initsock.h

protoinfo.h文件 

 Sniffer.cpp文件

实例总结

基于原始套接字的网络封包嗅探的工作过程

Sniffer节点调用分析

在Visual Studio2019 的调用事项

问题一:程序的打开问题

问题二:解决编译器的C4996代码问题


主要内容

1,了解利用原始套接字进行通信程序的编写,编译和执行。

2,利用原始套接字编程将网卡设置为混杂模式,对局域网(自组网/机房网络/宿舍网络或其他)上传输的数据包进行捕获与分析;

3,能分析出捕获的IP数据包的生存时间、协议、头部校验和、源IP地址以及目标IP地址等内容。并将上述解析结果规范显示出来。

实例使用环境

操作系统:  Microsoft Windows 11

编程环境:  Visual Studio 2019


知识储备

IP数据报格式

IP数据报格式

IP头结构体定义

IP头结构体
typedef struct _IPHeader         // 20字节的IP头
{UCHAR     iphVerLen;         // 4位首部长度+4位IP版本号           UCHAR     ipTOS;             // 8位服务类型                       USHORT    ipLength;          // 16位封包总长度,即整个IP报的长度  USHORT    ipID;              // 16位封包标识,惟一标识发送的每一个数据报 USHORT    ipFlags;           // 3位标志位+13报片偏移 UCHAR     ipTTL;             // 8位生存时间,就是TTL              UCHAR     ipProtocol;        // 8位协议,TCP、UDP、ICMP等         USHORT    ipChecksum;        // 16位IP首部校验和              ULONG     ipSource;          // 32位源IP地址                 ULONG     ipDestination;     // 32位目标IP地址                    
} IPHeader, * PIPHeader;

 

TCP头格式

TCP包头格式

TCP头结构体定义

typedef struct _TCPHeader       // 20字节的TCP头
{USHORT sourcePort;          // 16位源端口号    USHORT destinationPort;     // 16位目的端口号 ULONG sequenceNumber;       // 32位序列号     ULONG acknowledgeNumber;    // 32位确认号    UCHAR   dataoffset;         // 高4位表示数据偏移,低6位保留字 UCHAR   flags;              // 6位标志位       USHORT windows;             // 16位窗口大小    USHORT checksum;            // 16位校验和      USHORT urgentPointer;       // 16位紧急数据偏移量   
} TCPHeader, * PTCPHeader;

 


实例的调用演示

程序成功绑定了本机的IP地址(注意不能是任意)

程序尝试嗅探主机中的IP数据封包,并成功解析出源IP地址以及目标IP地址,协议及对应端口等内容。


 实例的完整代码

initsock.h

#include 
#pragma comment(lib, "WS2_32")	// 链接到WS2_32.libclass CInitSock
{
public:CInitSock(BYTE minorVer = 2, BYTE majorVer = 2){// 初始化WS2_32.dllWSADATA wsaData;WORD sockVersion = MAKEWORD(minorVer, majorVer);if (::WSAStartup(sockVersion, &wsaData) != 0){exit(0);}}~CInitSock(){::WSACleanup();}
};

protoinfo.h文件 

// protoinfo.h文件/*定义协议格式
定义协议中使用的宏*/
#ifndef __PROTOINFO_H__
#define __PROTOINFO_H__#define ETHERTYPE_IP    0x0800
#define ETHERTYPE_ARP   0x0806typedef struct _ETHeader         // 14字节的以太头
{UCHAR	dhost[6];			// 目的MAC地址destination mac addressUCHAR	shost[6];			// 源MAC地址source mac addressUSHORT	type;				// 下层协议类型,如IP(ETHERTYPE_IP)、ARP(ETHERTYPE_ARP)等
} ETHeader, * PETHeader;#define ARPHRD_ETHER 	1// ARP协议opcodes
#define	ARPOP_REQUEST	1		// ARP 请求	
#define	ARPOP_REPLY		2		// ARP 响应typedef struct _ARPHeader		// 28字节的ARP头
{USHORT	hrd;				//	硬件地址空间,以太网中为ARPHRD_ETHERUSHORT	eth_type;			//  以太网类型,ETHERTYPE_IP ??UCHAR	maclen;				//	MAC地址的长度,为6UCHAR	iplen;				//	IP地址的长度,为4USHORT	opcode;				//	操作代码,ARPOP_REQUEST为请求,ARPOP_REPLY为响应UCHAR	smac[6];			//	源MAC地址UCHAR	saddr[4];			//	源IP地址UCHAR	dmac[6];			//	目的MAC地址UCHAR	daddr[4];			//	目的IP地址
} ARPHeader, * PARPHeader;// 协议
#define PROTO_ICMP    1
#define PROTO_IGMP    2
#define PROTO_TCP     6
#define PROTO_UDP     17typedef struct _IPHeader		// 20字节的IP头
{UCHAR     iphVerLen;      // 版本号和头长度(各占4位)UCHAR     ipTOS;          // 服务类型 USHORT    ipLength;       // 封包总长度,即整个IP报的长度USHORT    ipID;			  // 封包标识,惟一标识发送的每一个数据报USHORT    ipFlags;	      // 标志UCHAR     ipTTL;	      // 生存时间,就是TTLUCHAR     ipProtocol;     // 协议,可能是TCP、UDP、ICMP等USHORT    ipChecksum;     // 校验和ULONG     ipSource;       // 源IP地址ULONG     ipDestination;  // 目标IP地址
} IPHeader, * PIPHeader;// 定义TCP标志
#define   TCP_FIN   0x01
#define   TCP_SYN   0x02
#define   TCP_RST   0x04
#define   TCP_PSH   0x08
#define   TCP_ACK   0x10
#define   TCP_URG   0x20
#define   TCP_ACE   0x40
#define   TCP_CWR   0x80typedef struct _TCPHeader		// 20字节的TCP头
{USHORT	sourcePort;			// 16位源端口号USHORT	destinationPort;	// 16位目的端口号ULONG	sequenceNumber;		// 32位序列号ULONG	acknowledgeNumber;	// 32位确认号UCHAR	dataoffset;			// 高4位表示数据偏移UCHAR	flags;				// 6位标志位//FIN - 0x01//SYN - 0x02//RST - 0x04 //PUSH- 0x08//ACK- 0x10//URG- 0x20//ACE- 0x40//CWR- 0x80USHORT	windows;			// 16位窗口大小USHORT	checksum;			// 16位校验和USHORT	urgentPointer;		// 16位紧急数据偏移量 
} TCPHeader, * PTCPHeader;typedef struct _UDPHeader
{USHORT			sourcePort;		// 源端口号		USHORT			destinationPort;// 目的端口号		USHORT			len;			// 封包长度USHORT			checksum;		// 校验和
} UDPHeader, * PUDPHeader;#endif // __PROTOINFO_H__

 Sniffer.cpp文件

// Sniffer.cpp文件
#pragma warning(disable:4996)
#include "initsock.h"
#include "protoinfo.h" #include 
#include #pragma comment(lib, "Advapi32.lib")CInitSock theSock;void DecodeTCPPacket(char* pData)
{TCPHeader* pTCPHdr = (TCPHeader*)pData;printf(" Port: %d -> %d \n", ntohs(pTCPHdr->sourcePort), ntohs(pTCPHdr->destinationPort));// 下面还可以根据目的端口号进一步解析应用层协议switch (::ntohs(pTCPHdr->destinationPort)){case 21:break;case 80:case 8080:break;}
}void DecodeIPPacket(char* pData)
{IPHeader* pIPHdr = (IPHeader*)pData;in_addr source, dest;char szSourceIp[32], szDestIp[32];printf("\n\n-------------------------------\n");// 从IP头中取出源IP地址和目的IP地址source.S_un.S_addr = pIPHdr->ipSource;dest.S_un.S_addr = pIPHdr->ipDestination;strcpy(szSourceIp, ::inet_ntoa(source));strcpy(szDestIp, ::inet_ntoa(dest));printf("	%s -> %s \n", szSourceIp, szDestIp);// IP头长度int nHeaderLen = (pIPHdr->iphVerLen & 0xf) * sizeof(ULONG);switch (pIPHdr->ipProtocol){case IPPROTO_TCP: // TCP协议DecodeTCPPacket(pData + nHeaderLen);break;case IPPROTO_UDP:break;case IPPROTO_ICMP:break;}
}void main()
{// 创建原始套节字SOCKET sRaw = socket(AF_INET, SOCK_RAW, IPPROTO_IP);// 获取本地IP地址char szHostName[56];SOCKADDR_IN addr_in;struct  hostent* pHost;gethostname(szHostName, 56);if ((pHost = gethostbyname((char*)szHostName)) == NULL)return;// 在调用ioctl之前,套节字必须绑定addr_in.sin_family = AF_INET;addr_in.sin_port = htons(0);memcpy(&addr_in.sin_addr.S_un.S_addr, pHost->h_addr_list[0], pHost->h_length);printf(" Binding to interface : %s \n", ::inet_ntoa(addr_in.sin_addr));if (bind(sRaw, (PSOCKADDR)&addr_in, sizeof(addr_in)) == SOCKET_ERROR)return;// 设置SIO_RCVALL控制代码,以便接收所有的IP包	DWORD dwValue = 1;if (ioctlsocket(sRaw, SIO_RCVALL, &dwValue) != 0)return;// 开始接收封包char buff[1024];int nRet;while (TRUE){nRet = recv(sRaw, buff, 1024, 0);if (nRet > 0){DecodeIPPacket(buff);}}closesocket(sRaw);
}

实例总结

基于原始套接字的网络封包嗅探的工作过程

使用原始套接字写嗅探器的流程:

1 使用socket创建基于IP协议的原始套接字。

2 获取本地IP地址。

3 将原始套接字绑定到本地IP地址上。

4 使用ioctlsocket函数设置套接字选项SIO_RCVALL,即接受所有数据。

5 无尽调用recv函数。

Sniffer节点调用分析

    通常的套接字程序只能响应与自己MAC地址相匹配的或是以广播形式发出的数据帧,对于其他形式的数据帧网络接口采取的动作是直接丢弃。为了使网卡接收所有经过它的封包,要将其设置为混杂模式。

    程序运行之后,首先要创建原始套接字,将它绑定到一个明确的本地地址(不能为ADDR_ANY),然后设置SIO_RCVALL控制代码,最后进入无限循环,不断调用recv函数接收经过本地网卡的IP封包。

    程序接收到IP封包之后,调用自定义函数DecodeIPPaccket进行解包。这个函数萃取出封包中的协议头,向用户打印出协议信息,本次实验Sniffer程序仅解析了封包中的IP头和TCP头

在Visual Studio2019 的调用事项

问题一:程序的打开问题

由于网络嗅探器程序需要较高的使用权限,所以要以编译器要以管理员的身份打开使用。

问题二:解决编译器的C4996代码问题

由于代码样例的使用规则与现行的编译器的代码定义规则(安全性过高)存在不兼容的问题,在尝试过许多方法后,尝试解决思路如下:

如果都没很好的解决问题,最后只能输入#pragma warning(disable:4996)强制忽略掉C4996所带来的警告程序恢复了正常运行。

相关内容

热门资讯

汽车油箱结构是什么(汽车油箱结... 本篇文章极速百科给大家谈谈汽车油箱结构是什么,以及汽车油箱结构原理图解对应的知识点,希望对各位有所帮...
美国2年期国债收益率上涨15个... 原标题:美国2年期国债收益率上涨15个基点 美国2年期国债收益率上涨15个基...
嵌入式 ADC使用手册完整版 ... 嵌入式 ADC使用手册完整版 (188977万字)💜&#...
重大消息战皇大厅开挂是真的吗... 您好:战皇大厅这款游戏可以开挂,确实是有挂的,需要了解加客服微信【8435338】很多玩家在这款游戏...
盘点十款牵手跑胡子为什么一直... 您好:牵手跑胡子这款游戏可以开挂,确实是有挂的,需要了解加客服微信【8435338】很多玩家在这款游...
senator香烟多少一盒(s... 今天给各位分享senator香烟多少一盒的知识,其中也会对sevebstars香烟进行解释,如果能碰...
终于懂了新荣耀斗牛真的有挂吗... 您好:新荣耀斗牛这款游戏可以开挂,确实是有挂的,需要了解加客服微信8435338】很多玩家在这款游戏...
盘点十款明星麻将到底有没有挂... 您好:明星麻将这款游戏可以开挂,确实是有挂的,需要了解加客服微信【5848499】很多玩家在这款游戏...
总结文章“新道游棋牌有透视挂吗... 您好:新道游棋牌这款游戏可以开挂,确实是有挂的,需要了解加客服微信【7682267】很多玩家在这款游...
终于懂了手机麻将到底有没有挂... 您好:手机麻将这款游戏可以开挂,确实是有挂的,需要了解加客服微信【8435338】很多玩家在这款游戏...