首页 > 其他 > 详细

网络协议信息隐藏

时间:2020-11-18 14:39:48      阅读:63      评论:0      收藏:0      [点我收藏+]

1.实验目的

(1)掌握网络层信息隐藏的原理

(2)理解在网络层两种主要协议上进行信息隐藏的基本方法

2.实验内容

(1)利用IP/ICMP协议进行信息隐藏

(2)利用TCP协议进行信息隐藏

3.实验环境

(1)网络环境:100Mbps 交换式以太网,2 台主机,其中包括发送端(192.168.0.1/24)与接收端(192.168.0.2/24)

(2)操作系统:Windows 2003 或内核 2.4.20 以上版本的 Linux(如 Kali Linux 2.0)

(3)编程工具:Microsoft Visual C++ 6.0 以上,WinPcap 开发包(版本 3.0 以上)

4.实验原理

注:代码仅供参考

(1)基于网络层协议的信息隐藏

????目前的网络协议使用的 IPV4 版本,设计时候存在漏洞,首部存在冗余或可选字段,网络设备对某些字段限制过于宽松,通过精心设计和构造,可以利用这些字段进行信息隐藏以实现隐蔽通信。这种通信不增加额外带宽,很难被网络防火墙和入侵检测系统检测到,容易逃避网络监控,实现信息隐藏的目的。传统信息隐藏的载体是静态的多媒体数据,而网络隐蔽通道的载体是动态的网络协议的首部,这种载体上的区别是两者最根本的区别;前者依赖于人的视觉或听觉不敏感性,而后者是基于网络协议在语法或语义上的冗余;前者的隐匿性主要对于人感官上的不可感知,而后者的隐匿性是对于网络监控设备而言的。多媒体数据中存在大量的信息冗余,网络协议数据包中的冗余显然要少许多;多媒体有着复杂的数据结构,任取其中的一个数据(像素、视频帧等)进行数值改写,几乎不会对它的感官效果产生影响,而网络协议的数据包中的各个首部字段都是最简单的“01”比特串,对首部字段取值的改写不但彻底改变了数据包的类型,而且有可能使得这个数据包由于畸形而被丢弃。网络协议信息隐藏(以下简称协议隐写)是一种利用数据包作为掩护载体,将秘密信息隐匿在网络协议的数据包之中的信息隐藏技术,它可以通过网络协议数据包中的保留、可选、未定义等字段和数据包的顺序、数量、到达时间、特定时间流量以及其它可被利用的特征,在网络中不同的主机之间建立隐蔽通信。
????利用协议隐写进行隐蔽通信时,发送端在协议数据包中使用嵌入算法嵌入秘密信息,得到携密数据包,可将隐蔽通信划分为 6 种模式,其中有效的方式如下图 A、B 两个。

技术分享图片
图4-1 隐蔽通信模式示意图
????上图中的嵌入进程即为隐蔽通信的发送方,提取进程为接收方。根据网络通信的实际情况,6种模式中其实只有模式A和模式C是可行的。由于模式C需要重写操作系统的网络协议驱动,故此处采用了其中的模式A,即发送方自己产生载体(即正常协议数据包),发送方和接收方分别是数据流的始点和终点,如图4-2所示。
技术分享图片
图4-2 网络隐蔽通道的基本工作模式
????最早被用来进行协议隐写的协议是IP协议,首部如图4.1-3所示,图中灰色阴影部分可直接用于隐藏信息。
技术分享图片
图4-3 IP的首部
????ICMP(互联网控制报文协议),它通常被IP层或更高层协议用来传递差错报文,下面介绍利用ICMP的8位代码字段进行协议隐写的原理。 ????ICMP的报文格式根据前16个字节的变化而各有不同,图4.1-4是回显应答和回显请求报文的格式。
技术分享图片
图4-4 ICMMP回显请求和回显应答的报文格式
????对 ICMP 的所有首部字段进行实验,发现所有的首部字段都可随意设置,虽然 RFC 规定了 ICMP 回显请求和回显应答的报文格式,但 8 位代码字段的取值对报文的功能没有任何影响,模拟 Ping 程序在 8 位代码字段设置为任意值的情况下仍能从远端主机返回回显应答,表明此字段是协议隐写的良好载体。

(2)利用TCP协议进行信息隐藏

????在传输层中,TCP和UDP都是用相同的网络层,TCP向应用层提供一种面向连接的、可靠的字节流服务,而UDP提供的是无连接的、不可靠的字节流服务。在TCP和UDP上都可以进行信息隐藏,TCP首部格式如4-5所示。

技术分享图片
图4-5 TCP的首部
????TCP序列号是一个32位的字段,用以标识从TCP发送端向TCP接收端发送的数据字节流,它保证了传输的可靠性。正常的TCP连接建立分三步,具体原理如图4-6所示。
技术分享图片
图4-6 正常TCP的三次握手
  • 请求端发送一个SYN段指名请求端打算连接的服务器的端口以及ISN;
  • 服务器发回包含服务器ISN的SYN报文段作为应答,同时将确认号设置为请求段的ISN加1以对请求端的SYN报文段进行确认;
  • 请求端必须将确认号设置为服务器的ISN加1对服务器的SYN报文段进行确认。
    ????利用TCP数据包的32位序列号隐藏信息的方法原理如图4-7所示。
技术分享图片
图4.2-3 利用32位序列号实现协议隐写
???? 该方法只完成了图4-6中的第一步就实现了秘密信息的传输。由于事先已对此种报文做过定义,接收端将不会发送ACK信息,因此避免了接收端认为收到了SYN Flood攻击。发送端间隔1秒发送数据包是为了防止在接收端一方发生数据包乱序的现象。SEQ域的信息可以经过编码或加密,在实际实现中一般是将隐匿信息的ASCII码乘以256。该方法的可靠性较差,在理想情况下,嵌入效率为每个数据包16比特。

5.实验记录

(1)基于网络层协议的信息隐藏

1)算法描述

???? 实验的主要思路是在网络层实现信息发送及接收程序,由于在底层实现该程序,需要手工构造 IP 报文的首部字段来自定义发送数据包,因此必须使用 Raw Socket 编程。Raw Socket 允许程序绕过系统内核而直接访问底层协议,因此 IP 层的封装工作就要用手工填充数据的方法实现,而不是由操作系统自动完成。由于 Raw Socket 经常被用来编写网络扫描程序等恶意软件,微软在 Windows XP 的协议驱动 tcpip.sys 中,基于安全考虑已经对利用 Raw Socket 发送数据包进行了限制,故本文中的底层数据包发送程序在Windows 2000 下通过 VC6.0 实现。由于使用原始套接字发送数据包,数据包的某些字段还被用来隐藏信息,接收端不能用普通的 Recv( )或 Recvfrom( )来接收数据包,只能采用嗅探的方式接收发送方的数据。但网络中的数据包很多,这又会产生识别特定数据包的问题,在程序实现时,除在接收端根据源 IP 地址、目的 IP 地址、协议等字段设置规则进行过滤外,还在发送端对 IP 标志的最高位进行了置位,只有符合这些规则的数据包才会被接收。流式套接字编程对上层应用提供了可靠的服务,而使用 Raw Socket 发送数据包则没有这样的保证,容易造成丢包等情况,下文的原型程序仅为验证隐蔽通信的可行性,没有考虑对乱序、丢包、数据错误的处理。

2)数据结构

// 协议
#define PROTO_ICMP 1
typedef struct _IPHeader // 20 字节的 IP 头
{
      UCHAR iphVerLen; // 版本号和头长度(各占 4 位)
      UCHAR ipTOS; // 服务类型
      USHORT ipLength; // 数据包总长度,即整个 IP 报的长度
      USHORT ipID; // 数据包标识,唯一标识发送的每一个数据报
      USHORT ipFlags; // 标志
      UCHAR ipTTL; // 生存时间,就是 TTL
      UCHAR ipProtocol; // 协议,可能是 TCP、UDP、ICMP 等
      USHORT ipChecksum; // 校验和
      ULONG ipSource; // 源 IP 地址
      ULONG ipDestination; // 目标 IP 地址
} IPHeader, *PIPHeader;

typedef struct _ICMPHeader //定义 ICMP 报头(回显请求与回显应答)
{
      unsigned char i_type;//8 位类型
      unsigned char i_code; //8 位代码
      unsigned short i_cksum; //16 位校验和
      unsigned short i_id; //识别号(一般用进程号作为识别号)
      unsigned short i_seq; //报文序列号
      unsigned int timestamp;//时间戳
}ICMP_HEADER; 

3)算法实现

a)嵌入算法:
//计算IP包头的校验和
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 >> 16) + (cksum & 0xffff); 
	cksum += (cksum >>16); 
	return (USHORT)(~cksum); 
}

//检查输入是否合法
BOOL CIPCovertSenderDlg::CheckValidIP()
{
	BOOL bOK;
	bOK=FALSE;
	
	if (!IPCtrlToSTR(&m_SrcAddress))
		MessageBox("Please enter a valid source address!");
	else if (!IPCtrlToSTR(&m_DestAddress))
		MessageBox("Please enter a valid destination address!");
	else if (m_TypeOfService==-1)
		MessageBox("Please enter a valid type of service!");
	else if (m_FragmentationType==-1)
		MessageBox("Please enter a valid fragmentation size!");
	else
		bOK=TRUE;
	
	return bOK;
}

//将IP地址转换为字符串类型
LPSTR CIPCovertSenderDlg::IPCtrlToSTR(CIPAddressCtrl* ctrl)
{
	BYTE bOctet1;
	BYTE bOctet2;
	BYTE bOctet3;
	BYTE bOctet4;
	
	int iBlank;
	iBlank=ctrl->GetAddress(bOctet1,bOctet2,bOctet3,bOctet4);
	
	if (iBlank!=4)
		return NULL;
	else
	{
		in_addr iAddr;
		iAddr.S_un.S_un_b.s_b1=bOctet1;
		iAddr.S_un.S_un_b.s_b2=bOctet2;
		iAddr.S_un.S_un_b.s_b3=bOctet3;
		iAddr.S_un.S_un_b.s_b4=bOctet4;
		
		return inet_ntoa(iAddr);
	}
}

//发送数据包
void CIPCovertSenderDlg::OnSendIp() 
{
	UpdateData(TRUE);
	
	DWORD szDestIp;
	((CIPAddressCtrl*)GetDlgItem(IDC_DestAddress))->GetAddress(szDestIp);
	DWORD szSourceIp;
	((CIPAddressCtrl*)GetDlgItem(IDC_SrcAddress))->GetAddress(szSourceIp);
	
	char szMsg[] = "This is a test \r\n";
	int nMsgLen = strlen(szMsg);
	
	//创建原始套接字
	SOCKET sRaw = ::socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
	
	//设置IP首部包含选项
	BOOL bIncl = TRUE;
	::setsockopt(sRaw, IPPROTO_IP, IP_HDRINCL, (char *)&bIncl, sizeof(bIncl));
	
	char buff[1024] = { 0 };
	
	//开始填充IP首部
	IPHeader *pIphdr = (IPHeader *)buff;
	pIphdr->iphVerLen = (m_Version<<4 | m_HeaderSize);
	pIphdr->ipLength = m_TotalLenth;
	pIphdr->ipTTL = m_TTL;
	pIphdr->ipProtocol = m_Protocol;
	pIphdr->ipSource = htonl(szSourceIp);
	pIphdr->ipDestination = htonl(szDestIp);
	pIphdr->ipChecksum = m_CheckSum;
	pIphdr->ipTOS = m_TypeOfService;
	pIphdr->ipFlags = htons((USHORT)(m_FragmentationType<<13 | m_Offset));
	pIphdr->ipID = htons(m_Identification);
	
	//开始填充ICMP首部
	ICMP_HEADER *pIcmphdr = (ICMP_HEADER *)&buff[sizeof(IPHeader)];
	pIcmphdr->i_type = m_ICMP_Type;
	pIcmphdr->i_code = m_ICMP_Code;
	pIcmphdr->i_cksum = htons(m_ICMP_Checksum);
	pIcmphdr->i_id = htons(m_ICMP_ID);
	pIcmphdr->i_seq = htons(m_ICMP_Sequence);
	pIcmphdr->timestamp = htonl(m_ICMP_Timestamp);
	
	char *pData = &buff[sizeof(IPHeader) + sizeof(ICMP_HEADER)];
	memcpy(pData, szMsg, nMsgLen);
	
	// 设置目的地址
	SOCKADDR_IN destAddr = { 0 };
	destAddr.sin_family = AF_INET;
	destAddr.sin_port = 0;
	destAddr.sin_addr.S_un.S_addr = htonl(szDestIp);
	
	// 发送原始ICMP数据包 
	int nRet,j=0;
	CString str;
	for(int i=0; i<num_of_packet; i++,j=j+1)//+11)
	{
		pIcmphdr->i_code = filebuff[j];
		pData = &buff[sizeof(IPHeader) + sizeof(ICMP_HEADER)];
		memcpy(pData, szMsg, nMsgLen);
		nRet = ::sendto(sRaw, buff, sizeof(IPHeader) + sizeof(ICMP_HEADER) + nMsgLen, 
			0, (sockaddr*)&destAddr, sizeof(destAddr));
		if(nRet == SOCKET_ERROR)
		{
			AfxMessageBox(" sendto() failed.");
			break;
		}		
	}
	
	str.Format("%d",nRet);
	str="成功发送 "+str+" 字节!";
	AfxMessageBox(str);
	
	::closesocket(sRaw);
}

//打开文件
void CIPCovertSenderDlg::OnOpenFile() 
{
	CFileDialog m_ldFile(TRUE);
	
	// 显示打开文件对话框,并捕捉结果
	if(m_ldFile.DoModal()==IDOK)
	{
		// 捕获所选文件名
		m_sFilePathName=m_ldFile.GetPathName();
		m_sFileName=m_ldFile.GetFileName();
		// 更新对话框
		UpdateData(FALSE); 
		// 按钮可用
		GetDlgItem(ID_SEND_IP)->EnableWindow(TRUE);
	}
	UpdateData(FALSE);
	FillData();	
}

//填充读取的数据到缓存
void CIPCovertSenderDlg::FillData()
{
	FILE *fpin;
	CString str;
	int fh,ch,i,filelength;
	
	// 用户输入更新变量
	UpdateData(TRUE);
	
	if((fpin=fopen(m_sFilePathName,"rb"))==NULL)
	{
		str="打开文件 "+m_sFileName+" 失败";
		MessageBox(str);
		exit(0);
	}
	
	fh = _open( m_sFilePathName, _O_RDWR | _O_CREAT, _S_IREAD | _S_IWRITE );
	filelength=_filelength( fh );
	
	if(filelength>1024)
	{
		str="文件 "+m_sFileName+" 长度大于1024!";
		MessageBox(str);
		exit(0);
	}
	
	BeginWaitCursor();
	
	ch=fgetc(fpin);
	i=0;
    while(ch!=-1)
	{				
		filebuff[i++]=ch;
		ch=fgetc(fpin);
	}
	
	fclose(fpin);
	num_of_packet=filelength;
}

填写相应的源ip和目的ip,版本号,首部长度等字节

技术分享图片
图5-1 隐藏信息代码运行结果
技术分享图片
图5-2 新建隐藏文件
技术分享图片
图5-3 成功发送隐藏数据
b)提取算法
typedef struct _tagPROTOMAP
{
	int  ProtoNum;
	char ProtoText[MAX_PROTO_TEXT_LEN];
}PROTOMAP;

static PROTOMAP ProtoMap[MAX_PROTO_NUM]=
{
	{ IPPROTO_IP   , "IP "  },
	{ IPPROTO_ICMP , "ICMP" }, 
	{ IPPROTO_IGMP , "IGMP" },
	{ IPPROTO_GGP  , "GGP " }, 
	{ IPPROTO_TCP  , "TCP " }, 
	{ IPPROTO_PUP  , "PUP " }, 
	{ IPPROTO_UDP  , "UDP " }, 
	{ IPPROTO_IDP  , "IDP " }, 
	{ IPPROTO_ND   , "NP "  }, 
	{ IPPROTO_RAW  , "RAW " }, 
	{ IPPROTO_MAX  , "MAX " },
	{ NULL         , ""     }
};


typedef struct _iphdr //定义IP首部 
{ 
	unsigned char h_verlen; //4位首部长度,4位IP版本号 
	unsigned char tos; //8位服务类型TOS 
	unsigned short total_len; //16位总长度(字节) 
	unsigned short ident; //16位标识 
	unsigned short frag_and_flags; //3位标志位 
	unsigned char ttl; //8位生存时间 TTL 
	unsigned char proto; //8位协议 (TCP, UDP 或其他) 
	unsigned short checksum; //16位IP首部校验和 
	unsigned int sourceIP; //32位源IP地址 
	unsigned int GivenIP; //32位目的IP地址 
}IP_HEADER;
typedef struct _icmphdr //定义ICMP报头(回送与或回送响应)
{ 
	unsigned char i_type;//8位类型
	unsigned char i_code; //8位代码 
	unsigned short i_cksum; //16位校验和 
	unsigned short i_id; //识别号(一般用进程号作为识别号) 
	unsigned short i_seq; //报文序列号 
	unsigned int timestamp;//时间戳 
}ICMP_HEADER;

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 >> 16) + (cksum & 0xffff); 
	cksum += (cksum >>16); 
	return (USHORT)(~cksum); 
}
struct //定义TCP伪首部 
{ 
	unsigned long saddr; //源地址 
	unsigned long daddr; //目的地址 
	char mbz; 
	char ptcl; //协议类型 
	unsigned short tcpl; //TCP长度 
}psd_header; 

typedef struct _tcphdr //定义TCP首部 
{ 
	USHORT th_sport; //16位源端口 
	USHORT th_dport; //16位目的端口 
	unsigned int th_seq; //32位序列号 
	unsigned int th_ack; //32位确认号 
	unsigned char th_lenres;//4位首部长度/6位保留字 
	unsigned char th_flag;//6位标志位 
	USHORT th_win; //16位窗口大小 
	USHORT th_sum; //16位校验和 
	USHORT th_urp; //16位紧急数据偏移量 
}TCP_HEADER;
typedef struct _udphdr //定义UDP报头 
{
	unsigned short uh_sport;//16位源端口
	unsigned short uh_dport;//16位目的端口
	unsigned short uh_len;//16位长度
	unsigned short uh_sum;//16位校验和
}UDP_HEADER;

int DecodeIpPack(char *buf, int iBufSize);
int DecodeTcpPack(char *TcpBuf);
int DecodeUdpPack(char *UdpBuf);
int DecodeIcmpPack(char *IcmpBuf);

//将协议int转为字符串
char* CheckProtocol(int iProtocol)
{
	for(int i=0; i<MAX_PROTO_NUM; i++)
	{
		if(ProtoMap[i].ProtoNum==iProtocol)
		{
			return ProtoMap[i].ProtoText;
		}
	}
	return "";
}

void usage(char *name) 
{ 
	printf("******************************************\n"); 
	printf("Sniffer Info From Given Packets\n"); 
	printf("\t Written by yzd\n"); 
	printf("usage: %s.exe Given_ip  \n",name); 
	printf("******************************************\n"); 
} 

int main(int argc, char **argv)
{ 
	int ErrorCode; 
	int TimeOut=2000,SendSEQ=0; 
	char RecvBuf[128]; // 每个数据包是128个字节
	char GivenIP[16]; // 要嗅探的机器IP
	memset(GivenIP, 0, 4); 
	// 如果通过参数输入IP,则将这个IP赋给GivenIP,否则将DEFAULT_DEST_IP赋给GivenIP
	if(argc < 2) 
	{
		strcpy(GivenIP, DEFAULT_DEST_IP);
		usage(argv[0]);
		return FALSE;
	}
	else
		strcpy(GivenIP, argv[1]);
	// 以下是声明Socket变量和相应的数据结构
	//初始化SOCKET
	WSADATA wsaData;
	SOCKET SockRaw=(SOCKET)NULL; 
	ErrorCode = WSAStartup(MAKEWORD(2, 1), &wsaData);
	SockRaw = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
	//获取本机IP地址
	char name[MAX_HOSTNAME_LAN];
	ErrorCode = gethostname(name, MAX_HOSTNAME_LAN);
	struct hostent *pHostent;
	pHostent = (struct hostent*)malloc(sizeof(struct hostent));
	pHostent = gethostbyname(name);
	SOCKADDR_IN sa;
	sa.sin_family = AF_INET;
	sa.sin_port = htons(6000);
	memcpy(&sa.sin_addr.S_un.S_addr, pHostent->h_addr_list[0], pHostent->h_length);
	ErrorCode = bind(SockRaw, (PSOCKADDR) &sa, sizeof(sa));
	//设置SOCK_RAW为SIO_RCVALL,以便接收所有的IP包
	DWORD dwBufferLen[10];
	DWORD dwBufferInLen = 1;
	DWORD dwBytesReturned = 0;
	ErrorCode = WSAIoctl(SockRaw,SIO_RCVALL,&dwBufferInLen,sizeof(dwBufferInLen),
		&dwBufferLen,sizeof(dwBufferLen),&dwBytesReturned,NULL,NULL);
	//侦听IP报文
	while (1)
	{
		memset(RecvBuf,0,sizeof(RecvBuf));
		ErrorCode = recv(SockRaw, RecvBuf, sizeof(RecvBuf), 0);
		ErrorCode = DecodeIpPack(RecvBuf, ErrorCode);
	}
	closesocket(SockRaw);
	WSACleanup();
	
	return ErrorCode;
}
//IP包解析
int DecodeIpPack(char *buf, int iBufSize)
{
	IP_HEADER *pIpheader;
	int iProtocol, iTTL;
	char szProtocol[MAX_PROTO_TEXT_LEN];
	char szSourceIP[MAX_ADDR_LEN], szGivenIP[MAX_ADDR_LEN];
	SOCKADDR_IN saSource, saDest;
	pIpheader = (IP_HEADER*)buf;
	iProtocol = pIpheader->proto;
	strncpy(szProtocol, CheckProtocol(iProtocol), MAX_PROTO_TEXT_LEN);
	
	//获得源IP地址
	saSource.sin_addr.s_addr = pIpheader->sourceIP;
	strncpy(szSourceIP, inet_ntoa(saSource.sin_addr), MAX_ADDR_LEN);
	//获得目的IP地址
	saDest.sin_addr.s_addr = pIpheader->GivenIP;
	strncpy(szGivenIP, inet_ntoa(saDest.sin_addr), MAX_ADDR_LEN);
	iTTL = pIpheader->ttl;
	//打印
	printf("%s ", szProtocol);
	printf("%s->%s ", szSourceIP, szGivenIP);
	printf("bytes=%d TTL=%d ", iBufSize, iTTL);
	//计算IP包的首部长度
	int iIphLen = sizeof(unsigned long)*(pIpheader->h_verlen &0xf);
	//协议解析
	switch (iProtocol)
	{
	case IPPROTO_TCP:
		DecodeTcpPack(buf + iIphLen);
		break;
	case IPPROTO_UDP:
		DecodeUdpPack(buf + iIphLen);
		break;
	case IPPROTO_ICMP:
		DecodeIcmpPack(buf + iIphLen);
		break;
	default:
		break;
	}
	return true;
}
//TCP报文解析
int DecodeTcpPack(char *TcpBuf)
{
	TCP_HEADER *pTcpHeader;
	int i;
	pTcpHeader = (TCP_HEADER*)TcpBuf;
	printf("Port:%d->%d ", ntohs(pTcpHeader->th_sport), ntohs(pTcpHeader->th_dport));
	unsigned char FlagMask = 1;
	for (i = 0; i < 6; i++)
	{
		if ((pTcpHeader->th_flag) &FlagMask)
			printf("%c", ((pTcpHeader->th_flag))<<(i+2) & 0x10);
		else
			printf("-");
		FlagMask = FlagMask << 1;
	}
	printf("\n");
	return true;
} 
//UDP报文解析
int DecodeUdpPack(char *UdpBuf)
{
	UDP_HEADER *pUdpHeader;
	pUdpHeader = (UDP_HEADER*)UdpBuf;
	printf("Port:%d->%d ", ntohs(pUdpHeader->uh_sport), ntohs(pUdpHeader->uh_dport));
	printf("Len=%d\n", ntohs(pUdpHeader->uh_len));
	return true;
}
//ICMP报文解析 
int DecodeIcmpPack(char *IcmpBuf)
{
	ICMP_HEADER *pIcmpHeader;
	pIcmpHeader = (ICMP_HEADER*)IcmpBuf;
	printf("Type:%d,Code:%d ", pIcmpHeader->i_type, pIcmpHeader->i_code);
	printf("ID=%d SEQ=%d\n", pIcmpHeader->i_id, pIcmpHeader->i_seq);
	return true;
}
技术分享图片
图5-4 隐藏信息提取结果
$ensp;?$ensp;?图5-4中的Code就是文件fumeng.txt文件所对应字符的ASCII码。

(2)基于TCP协议进行信息隐藏

1)数据结构

typedef struct_TCPHeader				//20字节的TCP头
{
	USHORT sourcePort;					//16位源端口号
	USHORT destinationPort;			//16位目的端口号
	ULONG sequenceNumber;			//32位序列号
	ULONG acknowledgeNumber;		//32位确认号
	UCHAR dataoffset;					//高4位表示数据偏移
	UCHAR flags;						//6位标志位
	USHORT windows;					//16位窗口大小
	USHORT checksum;					//16位校验和
	USHORT urgentPointer;				//16位紧急数据偏移量
}TCPHeader,*PTCPHeader;
typedef struct psd_hdr					//定义TCP伪报头
{
	unsigned long saddr;				//源地址
	unsigned long daddr;				//目的地址
	char mbz;
	char ptcl;							//协议类型
	unsigned short tcpl;					//TCP长度
}PSD_HEADER;

2)算法实现

a)嵌入算法:
//计算TCP伪头校验和
void ComputeTcpPseudoHeaderChecksum(
    IPHeader    *pIphdr,
    TCPHeader *pTcphdr,
    char    *payload,
    int      payloadlen)
{
      char buff[1024];
	char *ptr = buff;
	int chksumlen = 0;
	ULONG zero = 0;
	
	// 包含源IP地址和目的IP地址
	memcpy(ptr, &pIphdr->ipSource, sizeof(pIphdr->ipSource));
	ptr += sizeof(pIphdr->ipSource);
	chksumlen += sizeof(pIphdr->ipSource);

	memcpy(ptr, &pIphdr->ipDestination, sizeof(pIphdr->ipDestination));
	ptr += sizeof(pIphdr->ipDestination);
	chksumlen += sizeof(pIphdr->ipDestination);

	// 包含8位0域
	memcpy(ptr, &zero, 1);
	ptr += 1;
	chksumlen += 1;

	// 协议
	memcpy(ptr, &pIphdr->ipProtocol, sizeof(pIphdr->ipProtocol));
	ptr += sizeof(pIphdr->ipProtocol);
	chksumlen += sizeof(pIphdr->ipProtocol);

	// TCP长度
	USHORT tcp_len = htons(sizeof(TCPHeader) + payloadlen);
	memcpy(ptr, &tcp_len, sizeof(tcp_len));
	ptr += sizeof(tcp_len);
	chksumlen += sizeof(tcp_len);

	// TCP头
	memcpy(ptr, pTcphdr, sizeof(TCPHeader));
	ptr += sizeof(TCPHeader);
	chksumlen += sizeof(TCPHeader);

	// 净荷
	memcpy(ptr, payload, payloadlen);
	ptr += payloadlen;
	chksumlen += payloadlen;

	// 补齐到下一个16位边界
	for(int i=0; i<payloadlen%2; i++)
	{
		*ptr = 0;
		ptr++;
		chksumlen++;
	}

	// 计算这个校验和,将结果填充到TCP头
	pTcphdr->checksum = checksum((USHORT*)buff, chksumlen);
}

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CIPCovertSenderDlg dialog

CIPCovertSenderDlg::CIPCovertSenderDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CIPCovertSenderDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CIPCovertSenderDlg)
	m_CheckSum = 0;
	m_FragmentationType = 0;
	m_HeaderSize = 0;
	m_Identification = 0;
	m_Offset = 0;
	m_Protocol = 0;
	m_TotalLenth = 0;
	m_TypeOfService = 0;
	m_Version = 0;
	m_TTL = 0;
	m_TCPAckNumber = 0;
	m_TCPSeqNumber = 0;
	m_TCPSrcPort = 0;
	m_TCPDestPort = 0;
	m_TCPWindow = 0;
	m_TCPUrgentPointer = 0;
	m_TCPCheckSum = 0;
	m_TCPreserved = 0;
	m_TCPHeaderSize = 0;
	m_TCPFlags = 0;
	m_sFilePathName = _T("");
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CIPCovertSenderDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CIPCovertSenderDlg)
	DDX_Control(pDX, IDC_SrcAddress, m_SrcAddress);
	DDX_Control(pDX, IDC_DestAddress, m_DestAddress);
	DDX_Text(pDX, IDC_CheckSum, m_CheckSum);
	DDV_MinMaxUInt(pDX, m_CheckSum, 0, 65535);
	DDX_Text(pDX, IDC_FragmentationType, m_FragmentationType);
	DDV_MinMaxUInt(pDX, m_FragmentationType, 0, 7);
	DDX_Text(pDX, IDC_HeaderSize, m_HeaderSize);
	//DDV_MinMaxByte(pDX, m_HeaderSize, 5, 15);
	DDX_Text(pDX, IDC_Identification, m_Identification);
	DDV_MinMaxUInt(pDX, m_Identification, 0, 65535);
	DDX_Text(pDX, IDC_Offset, m_Offset);
	DDV_MinMaxUInt(pDX, m_Offset, 0, 8191);
	DDX_Text(pDX, IDC_Protocol, m_Protocol);
	DDV_MinMaxByte(pDX, m_Protocol, 0, 255);
	DDX_Text(pDX, IDC_TotalLenth, m_TotalLenth);
	DDV_MinMaxUInt(pDX, m_TotalLenth, 0, 65535);
	DDX_Text(pDX, IDC_TypeOfService, m_TypeOfService);
	DDV_MinMaxByte(pDX, m_TypeOfService, 0, 30);
	DDX_Text(pDX, IDC_Version, m_Version);
	//DDV_MinMaxByte(pDX, m_Version, 4, 6);
	DDX_Text(pDX, IDC_TTL, m_TTL);
	DDV_MinMaxByte(pDX, m_TTL, 0, 255);
	DDX_Text(pDX, IDC_TCPAckNumber, m_TCPAckNumber);
	DDX_Text(pDX, IDC_TCPSeqNumber, m_TCPSeqNumber);
	DDX_Text(pDX, IDC_TCPSrcPort, m_TCPSrcPort);
	DDV_MinMaxUInt(pDX, m_TCPSrcPort, 0, 65535);
	DDX_Text(pDX, IDC_TCPDestPort, m_TCPDestPort);
	DDV_MinMaxUInt(pDX, m_TCPDestPort, 0, 65535);
	DDX_Text(pDX, IDC_TCPWindow, m_TCPWindow);
	DDV_MinMaxUInt(pDX, m_TCPWindow, 0, 65535);
	DDX_Text(pDX, IDC_TCPUrgentPointer, m_TCPUrgentPointer);
	DDV_MinMaxUInt(pDX, m_TCPUrgentPointer, 0, 65535);
	DDX_Text(pDX, IDC_TCPCheckSum, m_TCPCheckSum);
	DDV_MinMaxUInt(pDX, m_TCPCheckSum, 0, 65535);
	DDX_Text(pDX, IDC_TCPReserved, m_TCPreserved);
	DDV_MinMaxByte(pDX, m_TCPreserved, 0, 63);
	DDX_Text(pDX, IDC_TCPHeaderSize, m_TCPHeaderSize);
	//DDV_MinMaxByte(pDX, m_TCPHeaderSize, 5, 15);
	DDX_Text(pDX, IDC_TCPFlags, m_TCPFlags);
	DDV_MinMaxByte(pDX, m_TCPFlags, 0, 63);
	DDX_Text(pDX, IDC_EDIT_SourceFile, m_sFilePathName);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CIPCovertSenderDlg, CDialog)
	//{{AFX_MSG_MAP(CIPCovertSenderDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(ID_SEND_IP, OnSendIp)
	ON_BN_CLICKED(IDC_OpenFile, OnOpenFile)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CIPCovertSenderDlg message handlers

BOOL CIPCovertSenderDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application‘s main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CIPCovertSenderDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CIPCovertSenderDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CIPCovertSenderDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

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 >> 16) + (cksum & 0xffff); 
	cksum += (cksum >>16); 
	return (USHORT)(~cksum); 
}

BOOL CIPCovertSenderDlg::CheckValidIP()
{
	BOOL bOK;
	bOK=FALSE;

	if (!IPCtrlToSTR(&m_SrcAddress))
		MessageBox("Please enter a valid source address!");
	else if (!IPCtrlToSTR(&m_DestAddress))
		MessageBox("Please enter a valid destination address!");
	else if (m_TypeOfService==-1)
		MessageBox("Please enter a valid type of service!");
	else if (m_FragmentationType==-1)
		MessageBox("Please enter a valid fragmentation size!");
	else
		bOK=TRUE;

	return bOK;
}

LPSTR CIPCovertSenderDlg::IPCtrlToSTR(CIPAddressCtrl* ctrl)
{
	//Converts the control address to textual address
	//Convert bytes to string
	BYTE bOctet1;
	BYTE bOctet2;
	BYTE bOctet3;
	BYTE bOctet4;

	//Get the value and blank values
	int iBlank;
	iBlank=ctrl->GetAddress(bOctet1,bOctet2,bOctet3,bOctet4);

	if (iBlank!=4)
		//Not filled
		return NULL;
	else
	{
		in_addr iAddr;
		iAddr.S_un.S_un_b.s_b1=bOctet1;
		iAddr.S_un.S_un_b.s_b2=bOctet2;
		iAddr.S_un.S_un_b.s_b3=bOctet3;
		iAddr.S_un.S_un_b.s_b4=bOctet4;

		return inet_ntoa(iAddr);
	}
}

//发送数据包
void CIPCovertSenderDlg::OnSendIp() 
{
	UpdateData(TRUE);

	DWORD szDestIp;
	((CIPAddressCtrl*)GetDlgItem(IDC_DestAddress))->GetAddress(szDestIp);
	DWORD szSourceIp;
	((CIPAddressCtrl*)GetDlgItem(IDC_SrcAddress))->GetAddress(szSourceIp);

	USHORT nDestPort = 80;
	USHORT nSourcePort = 1459;
	char szMsg[] = "This is a test \r\n";
	int nMsgLen = strlen(szMsg);

	//创建原始套接字
	SOCKET sRaw = ::socket(AF_INET, SOCK_RAW, IPPROTO_RAW);

	//设置IP首部包含选项
	BOOL bIncl = TRUE;
	::setsockopt(sRaw, IPPROTO_IP, IP_HDRINCL, (char *)&bIncl, sizeof(bIncl));

	char buff[1024] = { 0 };

	//开始填充IP首部
	IPHeader *pIphdr = (IPHeader *)buff;
	pIphdr->iphVerLen = (4<<4 | (sizeof(IPHeader)/sizeof(ULONG)));

	pIphdr->ipLength = ::htons(sizeof(IPHeader) + sizeof(TCPHeader) + nMsgLen);
	pIphdr->ipTTL = 128;
	pIphdr->ipProtocol = IPPROTO_TCP;
	pIphdr->ipSource = htonl(szSourceIp);
	pIphdr->ipDestination = htonl(szDestIp);
	pIphdr->ipChecksum = checksum((USHORT*)pIphdr, sizeof(IPHeader));
	pIphdr->ipTOS = 0x00;
	pIphdr->ipFlags = htons((USHORT)(4<<13 | 0));//分片R标记置位
	pIphdr->ipID = 0;

	//TCP头
	TCPHeader *pTcphdr = (TCPHeader *)&buff[sizeof(IPHeader)];

	//填充TCP首部 
	pTcphdr->sourcePort=htons(1459);
	pTcphdr->destinationPort=htons(80);
	pTcphdr->sequenceNumber=htonl(m_TCPSeqNumber);
	pTcphdr->acknowledgeNumber=0;
	pTcphdr->dataoffset=((sizeof(IPHeader)/sizeof(ULONG))<<4 | 0>>2);
	pTcphdr->flags=(0<<6 | 34);
	pTcphdr->windows=htons(16384);
	pTcphdr->checksum=0;
	pTcphdr->urgentPointer=0;

	char *pData = &buff[sizeof(IPHeader) + sizeof(TCPHeader)];
	memcpy(pData, szMsg, nMsgLen);

	ComputeTcpPseudoHeaderChecksum(pIphdr, pTcphdr, pData, nMsgLen);

	//设置目的地址
	SOCKADDR_IN destAddr = { 0 };
	destAddr.sin_family = AF_INET;
	destAddr.sin_port = htons(nDestPort);
	destAddr.sin_addr.S_un.S_addr = htonl(szDestIp);

	//发送原始TCP数据包
	int nRet,j=0;
	CString str;
	for(int i=0; i<num_of_packet; i++,j=j+4)
	{
		pTcphdr->sourcePort = htons(1459);
		pTcphdr->destinationPort = htons(80);
		pTcphdr->sequenceNumber = htonl(filebuff[j]<<24 | filebuff[j+1]<<16 | 
			filebuff[j+2]<<8 | filebuff[j+3]);
		pTcphdr->acknowledgeNumber=0;
		pTcphdr->windows=htons(16384);
		pTcphdr->urgentPointer=0;

		pData = &buff[sizeof(IPHeader) + sizeof(TCPHeader)];
		memcpy(pData, szMsg, nMsgLen);
		nRet = ::sendto(sRaw, buff, sizeof(IPHeader) + sizeof(TCPHeader) + nMsgLen, 
			0, (sockaddr*)&destAddr, sizeof(destAddr));
		if(nRet == SOCKET_ERROR)
		{
			AfxMessageBox(" sendto() failed.");
			break;
		}
		Sleep(1000);
	}

	str.Format("%d",nRet);
	str="成功发送 "+str+" 字节!";
	AfxMessageBox(str);

	::closesocket(sRaw);
}

void CIPCovertSenderDlg::OnOpenFile() 
{
	// TODO: Add your control notification handler code here
	CFileDialog m_ldFile(TRUE);
	
	// 显示打开文件对话框,并捕捉结果
	if(m_ldFile.DoModal()==IDOK)
	{
		// 捕获所选文件名
		m_sFilePathName=m_ldFile.GetPathName();
		m_sFileName=m_ldFile.GetFileName();
		// 更新对话框
		UpdateData(FALSE); 
		// 按钮可用
		GetDlgItem(ID_SEND_IP)->EnableWindow(TRUE);
	}
	UpdateData(FALSE);
	FillData();	
}

//填充读取的数据到缓存
void CIPCovertSenderDlg::FillData()
{
	FILE *fpin;
	CString str;
	int fh,ch;
	long i,filelength=0;
		
	// 用户输入更新变量
	UpdateData(TRUE);
	
	fh = _open( m_sFilePathName, _O_RDWR | _O_CREAT, _S_IREAD | _S_IWRITE );
	filelength=_filelength( fh );

	if(filelength>65534)
	{
		str="文件 "+m_sFileName+" 长度大于65K!";
		MessageBox(str);
		exit(0);
	}
	_close( fh );

	if((fpin=fopen(m_sFilePathName,"rb"))==NULL)
	{
		str="打开文件 "+m_sFileName+" 失败";
		MessageBox(str);
		exit(0);
	}

	BeginWaitCursor();

	ch=fgetc(fpin);
	i=0;
    while(ch!=-1)
	{				
		filebuff[i++]=ch;
		ch=fgetc(fpin);
	}

	fclose(fpin);

	if(filelength%4!=0) 
		num_of_packet=filelength/4+1;
	else
		num_of_packet=filelength/4;
}
技术分享图片
图5-5 TCP信息隐藏的嵌入程序
b)提取算法
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	pcap_if_t* alldevs;
	pcap_if_t* d;
	int inum;
	int i = 0;
	pcap_t* adhandle;
	char errbuf[PCAP_ERRBUF_SIZE];
	u_int netmask;
	char packet_filter[] = "ip and tcp";
	struct bpf_program fcode;
	pcap_dumper_t *dumpfile;
	
	int nRetCode = 0;
	
	str.Empty();
	str2.Empty();
	i_dialog=0;
	
	// initialize MFC and print and error on failure
	if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
	{
		// TODO: change error code to suit your needs
		cerr << _T("Fatal Error: MFC initialization failed") << endl;
		nRetCode = 1;
	}
	else
	{
		// TODO: code your application‘s behavior here.
		
		/* 得到设备列表 */
		if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
		{
			fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);
			exit(1);
		}
		
		/* 打印列表*/
		for (d = alldevs; d; d = d->next)
		{
			printf("%d. %s", ++ i, d->name);
			if (d->description)
			{
				printf(" (%s)\n", d->description);
			}
			else
			{
				printf(" (No description available)\n");
			}
		}
		
		if (i == 0)
		{
			printf("\nNo interfaces found! Make sure Winpcap is installed.\n");
			return -1;
		}
		
		printf("Enter the interface number (1 - %d):", i);
		scanf("%d", &inum);
		
		if (inum < 1 || inum > i)
		{
			printf("\nInterface number out of range.\n");
			/* 释放设备列表 */
			pcap_freealldevs(alldevs);
			return -1;
		}
		/* 跳至选择的适配器 */
		for (d = alldevs, i = 0; i < inum - 1; d = d->next, ++ i);
		
		/* 打开适配器 */
		if ((adhandle = pcap_open(d->name,  /*设备名称 */
			65536,      /* 捕获包的最大长度 */
			PCAP_OPENFLAG_PROMISCUOUS, /* 设置为混杂模式 */
			1000,       /* 读取时延 */
			NULL,
			errbuf      /* 错误缓存 */
			)) == NULL)
		{
			fprintf(stderr, "\nUnable to open the adapter. %s is not supported by Winpcap\n");
			/* 释放设备列表 */
			pcap_freealldevs(alldevs);
			return -1;
		}
		
		/* 打开一个dump文件 */
		dumpfile = pcap_dump_open(adhandle, "message.dump");
		
		if(dumpfile==NULL)
		{
			fprintf(stderr,"\nError opening output file\n");
			return -1;
		}
		
		/* 检查链路层,目前只支持以太网协议 */
		if (pcap_datalink(adhandle) != DLT_EN10MB)
		{
			fprintf(stderr, "\nThis program works only on Ethernet networks.\n");
			/* 释放设备列表 */
			pcap_freealldevs(alldevs);
			return -1;
		}
		
		if (d->addresses != NULL)
		{
			netmask = ((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
		}
		else
		{
			netmask = 0xffffffff;
		}
		
		/* 编译过滤器 */
		if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) < 0)
		{
			fprintf(stderr, "\nUnable to compile the packet filter. Check the syntax.\n");
			/* 释放设备列表 */
			pcap_freealldevs(alldevs);
			return -1;
		}
		
		/* 设置过滤器 */
		if (pcap_setfilter(adhandle, &fcode) < 0)
		{
			fprintf(stderr, "\nError setting the filter.\n");
			/* 释放设备列表 */
			pcap_freealldevs(alldevs);
			return -1;
		}
		
		printf("\nlistening on %s ...\n", d->description);
		
		pcap_freealldevs(alldevs);
		
		/* 开始捕获 */
		pcap_loop(adhandle, 0, packet_handler, (unsigned char *)dumpfile);
		
		return 1;
	}
	
	return nRetCode;
}
/* 回调函数 */
void packet_handler(u_char* dumpfile, const struct pcap_pkthdr* header, const u_char* pkt_data){
	struct tm* ltime;
	char timestr[16];
	ip_header *ih;
	tcp_header* th;
	u_int ip_len;
	u_short sport, dport;
	u_int i_tcp_seq;
	u_int i_tcp_ack;
	u_short i_TCP_SYN,i_winsize,i_urgent;
	u_int i_temp=0;
	u_int Data;
	
	/* 转换时间戳 */
	ltime = localtime(&header->ts.tv_sec);
	strftime(timestr, sizeof(timestr), "%H:%M:%S", ltime);
	
	/* 打印间戳和包长度 */
	printf("%s.%.6d len: %d \n", timestr, header->ts.tv_usec, header->len);
	
	/* 得到IP首部的地址 */
	ih = (ip_header*)(pkt_data + 14);
	
	/* 得到tcp首部的地址 */
	ip_len = (ih->ver_ihl & 0xf) * 4;
	th = (tcp_header*)((u_char*)ih + ip_len);
	
	/* 字节序转换 */
	sport = ntohs(th->tcp_source_port);
	dport = ntohs(th->tcp_dest_port);
	
	i_winsize = ntohs(th->tcp_winsize);
	i_urgent = ntohs(th->tcp_urgent);
	
	i_TCP_SYN=ntohs((u_short)ih->identification);
	i_tcp_seq=ntohl((u_int)th->tcp_seqno);
	i_tcp_ack=ntohl((u_int)th->tcp_ackno);
	
	Data=i_tcp_seq;
	
	if(ih->flags_fo==0x80&&ih->saddr.byte1==192&&ih->saddr.byte2==168&&ih->saddr.byte3==0&&ih->saddr.byte4==1&&ih->proto==6&&th->tcp_syn==1)
	{
		printf("%d.%d.%d.%d: %d -> %d.%d.%d.%d: %d -- seq:%u\n",
			ih->saddr.byte1,
			ih->saddr.byte2,
			ih->saddr.byte3,
			ih->saddr.byte4,
			sport,
			ih->daddr.byte1,
			ih->daddr.byte2,
			ih->daddr.byte3,
			ih->daddr.byte4,
			dport,
			i_tcp_seq);
		num_packet++;
		i_dialog++;
		stream0=fopen("ISN_Data.dat","a+");
		fprintf(stream0,"%c%c%c%c%",
			(char)(Data>>24),(char)(Data>>16),
			(char)(Data>>8),(char)Data);
		str=str+(char)(Data>>24)+(char)(Data>>16)+
			(char)(Data>>8)+(char)Data;
		str_ip1.Format("%d",ih->saddr.byte1);
		str_ip2.Format("%d",ih->saddr.byte2);
		str_ip3.Format("%d",ih->saddr.byte3);
		str_ip4.Format("%d",ih->saddr.byte4);
		str2.Empty();
		str2=str2+str_ip1+‘.‘+str_ip2+‘.‘+str_ip3+‘.‘+str_ip4;
		fclose(stream0);
		stream1=fopen("TCP_SYN.txt","a+");
		fprintf(stream1,"%u    %d\n",num_packet,i_tcp_seq);
		fclose(stream1);
		
		//调节一次显示消息的数量,i_dialog表示数据包的个数,每次可显示i_dialog×32比特的消息
		if(i_dialog==20)
		{
			MessageBox(NULL,str,"收到来自"+str2+"的消息",MB_ICONINFORMATION | MB_OK);
			i_dialog=0;
			str.Empty();
			str2.Empty();
		}
	}
}
技术分享图片
图5-6 使用wireshark所抓获的TCP报文
技术分享图片??技术分享图片??技术分享图片
图5-7 抓获的3个TCP报文中所提取到的信息

网络协议信息隐藏

原文:https://www.cnblogs.com/fumengHK/p/13998796.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!