注:代码仅供参考
????目前的网络协议使用的 IPV4 版本,设计时候存在漏洞,首部存在冗余或可选字段,网络设备对某些字段限制过于宽松,通过精心设计和构造,可以利用这些字段进行信息隐藏以实现隐蔽通信。这种通信不增加额外带宽,很难被网络防火墙和入侵检测系统检测到,容易逃避网络监控,实现信息隐藏的目的。传统信息隐藏的载体是静态的多媒体数据,而网络隐蔽通道的载体是动态的网络协议的首部,这种载体上的区别是两者最根本的区别;前者依赖于人的视觉或听觉不敏感性,而后者是基于网络协议在语法或语义上的冗余;前者的隐匿性主要对于人感官上的不可感知,而后者的隐匿性是对于网络监控设备而言的。多媒体数据中存在大量的信息冗余,网络协议数据包中的冗余显然要少许多;多媒体有着复杂的数据结构,任取其中的一个数据(像素、视频帧等)进行数值改写,几乎不会对它的感官效果产生影响,而网络协议的数据包中的各个首部字段都是最简单的“01”比特串,对首部字段取值的改写不但彻底改变了数据包的类型,而且有可能使得这个数据包由于畸形而被丢弃。网络协议信息隐藏(以下简称协议隐写)是一种利用数据包作为掩护载体,将秘密信息隐匿在网络协议的数据包之中的信息隐藏技术,它可以通过网络协议数据包中的保留、可选、未定义等字段和数据包的顺序、数量、到达时间、特定时间流量以及其它可被利用的特征,在网络中不同的主机之间建立隐蔽通信。
????利用协议隐写进行隐蔽通信时,发送端在协议数据包中使用嵌入算法嵌入秘密信息,得到携密数据包,可将隐蔽通信划分为 6 种模式,其中有效的方式如下图 A、B 两个。
????在传输层中,TCP和UDP都是用相同的网络层,TCP向应用层提供一种面向连接的、可靠的字节流服务,而UDP提供的是无连接的、不可靠的字节流服务。在TCP和UDP上都可以进行信息隐藏,TCP首部格式如4-5所示。
???? 实验的主要思路是在网络层实现信息发送及接收程序,由于在底层实现该程序,需要手工构造 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 发送数据包则没有这样的保证,容易造成丢包等情况,下文的原型程序仅为验证隐蔽通信的可行性,没有考虑对乱序、丢包、数据错误的处理。
// 协议
#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;
//计算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,版本号,首部长度等字节
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;
}
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;
//计算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;
}
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();
}
}
}
原文:https://www.cnblogs.com/fumengHK/p/13998796.html