用C/C++实现网络监听抓包 怎么用C或C++来编写一个抓包程序,或者是编写一个能够保存抓...

\u5982\u4f55\u4f7f\u7528C++\u548cMFC\u5b9e\u73b0\u7f51\u7edc\u534f\u8bae\u5206\u6790\u4e0e\u6293\u5305\u8f6f

\u4e00\u822c\u4f7f\u7528winpcap\u6765\u5b9e\u73b0C++\u548cMFC\u7f51\u7edc\u534f\u8bae\u5206\u6790\u4e0e\u6293\u5305\u8f6f\u4ef6\u7684\u5f00\u53d1\uff0c\u5177\u4f53\u53ef\u4ee5\u767e\u5ea6\u641c\u7d22\u3002

\u5148\u5f97\u4e86\u89e3\u901a\u4fe1\u534f\u8bae\uff0c\u4e2a\u5c42\u6b21\u7684

Windows2000在TCP/IP协议组件上做了很多改进,功能也有增强。比如在协议栈上的调整,增大了默认窗口大小,以及高延迟链接新算法。同时在安全性上,可应用IPSec加强安全性,比NT下有不少的改进。

Microsoft TCP/IP 组件包含“核心协议”、“服务”及两者之间的“接口”。传输驱动程序接口 (TDI) 与网络设备接口规范 (NDIS) 是公用的。 此外,还有许多用户模型应用程序的更高级接口。最常用的接口是 Windows Sockets、远程过程调用 (RPC) 和 NetBIOS。

Windows Sockets 是一个编程接口,它是在加州大学伯克利分校开发的套接字接口的基础上定义的。它包括了一组扩展件,以充分利用 Microsoft Windows 消息驱动的特点。规范的 1.1 版是在 1993 年 1 月发行的,2.2.0 版在 1996 年 5 月发行。Windows 2000 支持 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);

对于原始套接字在接收数据报的时候,要注意这么几点:
1、如果接收的数据报中协议类型和定义的原始套接字匹配,那么,接收的所有数据就拷贝到套接字中。
2、如果绑定了本地地址,那么只有接收数据IP头中对应的远端地址匹配,接收的数据就拷贝到套接字中。
3、如果定义的是外部地址,比如使用connect(),那么,只有接收数据IP头中对应的源地址匹配,接收的数据就拷贝到套接字中。

2、构造IP头和TCP头

这里,提供IP头和TCP头的结构:
// Standard TCP flags
#define URG 0x20
#define ACK 0x10
#define PSH 0x08
#define RST 0x04
#define SYN 0x02
#define FIN 0x01
typedef struct _iphdr //定义IP首部
{
unsigned char h_lenver; //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 destIP; //32位目的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; //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;

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 >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
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 7234
#define MAX_RECEIVEBYTE 255

typedef struct ip_hdr //定义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 destIP; //32位目的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; //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位紧急数据偏移量
}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 >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
return (USHORT)(~cksum);
}

void useage()
{
printf("******************************************\n");
printf("TCPPing\n");
printf("\t Written by Refdom\n");
printf("\t Email: [email protected]\n");
printf("Useage: TCPPing.exe Target_ip Target_port \n");
printf("*******************************************\n");
}

int main(int argc, char* argv[])
{
WSADATA WSAData;
SOCKET sock;
SOCKADDR_IN addr_in;
IPHEADER ipHeader;
TCPHEADER tcpHeader;
PSDHEADER psdHeader;

char szSendBuf[60]={0};
BOOL flag;
int rect,nTimeOver;

useage();

if (argc!= 3)
{ return false; }

if (WSAStartup(MAKEWORD(2,2), &WSAData)!=0)
{
printf("WSAStartup Error!\n");
return false;
}

if ((sock=WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0,WSA_FLAG_OVERLAPPED))==INVALID_SOCKET)
{
printf("Socket Setup Error!\n");
return false;
}
flag=true;
if (setsockopt(sock,IPPROTO_IP, IP_HDRINCL,(char *)&flag,sizeof(flag))==SOCKET_ERROR)
{
printf("setsockopt IP_HDRINCL error!\n");
return false;
}

nTimeOver=1000;
if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&nTimeOver, sizeof(nTimeOver))==SOCKET_ERROR)
{
printf("setsockopt SO_SNDTIMEO error!\n");
return false;
}
addr_in.sin_family=AF_INET;
addr_in.sin_port=htons(atoi(argv[2]));
addr_in.sin_addr.S_un.S_addr=inet_addr(argv[1]);

//
//
//填充IP首部
ipHeader.h_verlen=(4<<4 | sizeof(ipHeader)/sizeof(unsigned long));
// ipHeader.tos=0;
ipHeader.total_len=htons(sizeof(ipHeader)+sizeof(tcpHeader));
ipHeader.ident=1;
ipHeader.frag_and_flags=0;
ipHeader.ttl=128;
ipHeader.proto=IPPROTO_TCP;
ipHeader.checksum=0;
ipHeader.sourceIP=inet_addr("本地地址");
ipHeader.destIP=inet_addr(argv[1]);

//填充TCP首部
tcpHeader.th_dport=htons(atoi(argv[2]));
tcpHeader.th_sport=htons(SOURCE_PORT); //源端口号
tcpHeader.th_seq=htonl(0x12345678);
tcpHeader.th_ack=0;
tcpHeader.th_lenres=(sizeof(tcpHeader)/4<<4|0);
tcpHeader.th_flag=2; //修改这里来实现不同的标志位探测,2是SYN,1是FIN,16是ACK探测 等等
tcpHeader.th_win=htons(512);
tcpHeader.th_urp=0;
tcpHeader.th_sum=0;

psdHeader.saddr=ipHeader.sourceIP;
psdHeader.daddr=ipHeader.destIP;
psdHeader.mbz=0;
psdHeader.ptcl=IPPROTO_TCP;
psdHeader.tcpl=htons(sizeof(tcpHeader));

//计算校验和
memcpy(szSendBuf, &psdHeader, sizeof(psdHeader));
memcpy(szSendBuf+sizeof(psdHeader), &tcpHeader, sizeof(tcpHeader));
tcpHeader.th_sum=checksum((USHORT *)szSendBuf,sizeof(psdHeader)+sizeof(tcpHeader));

memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));
memcpy(szSendBuf+sizeof(ipHeader), &tcpHeader, sizeof(tcpHeader));
memset(szSendBuf+sizeof(ipHeader)+sizeof(tcpHeader), 0, 4);
ipHeader.checksum=checksum((USHORT *)szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader));

memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));

rect=sendto(sock, szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader),
0, (struct sockaddr*)&addr_in, sizeof(addr_in));
if (rect==SOCKET_ERROR)
{
printf("send error!:%d\n",WSAGetLastError());
return false;
}
else
printf("send ok!\n");

closesocket(sock);
WSACleanup();

return 0;
}

4、接收数据
和发送原始套接字数据相比,接收就比较麻烦了。因为在WIN我们不能用recv()来接收raw socket上的数据,这是因为,所有的IP包都是先递交给系统核心,然后再传输到用户程序,当发送一个raws socket包的时候(比如syn),核心并不知道,也没有这个数据被发送或者连接建立的记录,因此,当远端主机回应的时候,系统核心就把这些包都全部丢掉,从而到不了应用程序上。所以,就不能简单地使用接收函数来接收这些数据报。

要达到接收数据的目的,就必须采用嗅探,接收所有通过的数据包,然后进行筛选,留下符合我们需要的。可以再定义一个原始套接字,用来完成接收数据的任务,需要设置SIO_RCVALL,表示接收所有的数据。

SOCKET sniffersock;
sniffsock = WSASocket(AF_INET, SOCK_RAW, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);

DWORD lpvBuffer = 1;
DWORD lpcbBytesReturned = 0 ;
WSAIoctl(sniffersock, SIO_RCVALL, &lpvBuffer, sizeof(lpvBuffer), NULL, 0, & lpcbBytesReturned, NULL, NULL);

创建一个用于接收数据的原始套接字,我们可以用接收函数来接收数据包了。然后在使用一个过滤函数达到筛选的目的,接收我们需要的数据包。

如果在XP以上的操作系统,微软封杀了Raw Soccket,只能用wincpap之类的开发包了。

  • 涓轰粈涔堣鐢ㄥ瓧姣峜琛ㄧず鍛ㄩ暱?杩樻湁,涓轰粈涔堣鐢ㄥ瓧姣峴琛ㄧず闈㈢Н?璇风粰鎴戜竴涓...
    绛旓細C灏辨槸鑻辨枃瀛楁瘝Circumference鐨勭缉鍐欙紝S灏辨槸鑻辨枃瀛楁瘝Square鐨勭缉鍐欙紝杩欎簺瀛楁瘝澶у鏄湁杩欐牱鐨勬潵鐨勩傚杈瑰舰鐨勫懆闀跨殑闀垮害涔熺浉绛変簬鍥惧舰鎵鏈夎竟鐨勫拰锛屽渾鐨勫懆闀=蟺d=2蟺r 锛坉涓虹洿寰勶紝r涓哄崐寰勶紝蟺锛夛紝鎵囧舰鐨勫懆闀 = 2R+n蟺R梅180˚锛坣=鍦嗗績瑙掕搴︼級= 2R+kR 锛坘=寮у害锛夈傚渾锛欳=蟺d=2蟺r锛坉涓虹洿...
  • C璇█涓昏鐢ㄥ湪鍝簺鏂归潰?
    绛旓細锛1锛夊簲鐢ㄨ蒋浠躲侺inux鎿嶄綔绯荤粺涓殑搴旂敤杞欢閮芥槸浣跨敤C璇█缂栧啓鐨勶紝鍥犳杩欐牱鐨勫簲鐢ㄨ蒋浠跺畨鍏ㄦч潪甯搁珮銆傦紙2锛夊鎬ц兘瑕佹眰涓ユ牸鐨勯鍩熴備竴鑸鎬ц兘鏈変弗鏍艰姹傜殑鍦版柟閮芥槸鐢–璇█缂栧啓鐨勶紝姣斿缃戠粶绋嬪簭鐨勫簳灞傚拰缃戠粶鏈嶅姟鍣ㄧ搴曞眰銆佸湴鍥炬煡璇㈢瓑銆傦紙3锛夌郴缁熻蒋浠跺拰鍥惧舰澶勭悊銆侰璇█鍏锋湁寰堝己鐨勭粯鍥捐兘鍔涘拰鍙Щ妞嶆э紝骞朵笖鍏峰...
  • 璁$畻鏈篊璇█鏈変粈涔堢敤鍟??
    绛旓細1銆C璇█鏄珮绾ц瑷銆傚畠鎶婇珮绾ц瑷鐨勫熀鏈粨鏋勫拰璇彞涓庝綆绾ц瑷鐨勫疄鐢ㄦх粨鍚堣捣鏉ャ侰 璇█鍙互鍍忔眹缂栬瑷涓鏍峰浣嶃佸瓧鑺傚拰鍦板潃杩涜鎿嶄綔锛岃岃繖涓夎呮槸璁$畻鏈烘渶鍩烘湰鐨勫伐浣滃崟鍏冦2銆丆璇█鏄粨鏋勫紡璇█銆傜粨鏋勫紡璇█鐨勬樉钁楃壒鐐规槸浠g爜鍙婃暟鎹殑鍒嗛殧鍖栵紝鍗崇▼搴忕殑鍚勪釜閮ㄥ垎闄や簡蹇呰鐨勪俊鎭氦娴佸褰兼鐙珛銆傝繖绉嶇粨鏋勫寲鏂瑰紡...
  • c璇█鏈変粈涔堢敤
    绛旓細鈥滈」鐩┍鍔ㄥ紡鈥濇暀瀛﹀氨鏄互椤圭洰涓虹洰鐨,浠璇█鐞嗚鏁欏涓鸿繃绋,鏈缁堣兘鐢╟璇█璁捐椤圭洰,瀹炵幇椤圭洰鐨勮姹傘傗滈」鐩┍鍔ㄥ紡鈥濇暀瀛︾殑鍏抽敭鍦ㄤ簬鍩瑰吇瀛︾敓鈥滃浣曞仛浠涔堚濆拰鈥滃彲浠ュ共浠涔堚濄備竴涓」鐩氨鏄竴涓伐绋,鍦ㄢ滈」鐩┍鍔ㄥ紡鈥濇暀瀛︿腑,棣栧厛搴旇璁╁鐢熺畝鍗曚簡瑙d粈涔堟槸杞欢宸ョ▼鎬濇兂,鍏舵鍦╟璇█鐞嗚鏁欏杩囩▼涓,璁╁鐢熸噦寰楅潰鍚戝璞$殑...
  • 瀛︿範C璇█鏈変粈涔堢敤?
    绛旓細鈥濇鍠滅殑鏄紝C璇█鍔熻兘闈炲父寮哄ぇ銆佸簲鐢ㄥ箍娉涳紝涓鏃︽帉鎻′簡鍚庯紝鍐嶈嚜瀛﹀叾浠栬瑷灏辨樉寰楄交鑰屾槗涓句簡銆傚咖铏戠殑鏄紝C璇█鐘瑰鈥滃皯鏋楁鍔熲濅竴鑸崥澶х簿娣憋紝澶毦瀛︿簡銆傚叾瀹炲氨绗旇呰涓篊璇█骞堕潪鏄渄ifficult锛堝洶闅撅級鈥濈殑锛屽彧瑕佷綘鑳界悊娓呮濊矾锛屾帉鎻″畠鐨勭簿楂擄紝閭d箞鑷C璇█鏄竴浠堕潪甯稿鏄撲笖鍙堝叾涔愭棤绌风殑浜嬨備粖澶╂湰浜哄氨涓...
  • C璇█杩欎箞鍘夊,瀹冭嚜韬張鏄敤浠涔堣瑷鍐欑殑?缂栧啓杩囩▼琚О涓鸿嚜涓
    绛旓細OK锛 杩欎箞涓灞傚眰涓婃潵锛岀粓浜庡緱鍒颁簡涓涓鐢–璇█鍐欑殑缂栬瘧鍣紝 鐪熸槸澶熼夯鐑︾殑銆傚埌杩欎釜鏃跺欙紝涔嬪墠閭d釜姹囩紪鍐欑殑C璇█缂栬瘧鍣ㄥ氨鍙互鎶涘純浜嗐傚綋鐒讹紝濡傛灉鍦–璇█涔嬪墠锛屽凡缁忓嚭鐜颁簡鍒殑楂樼骇璇█锛屼緥濡侾ascal锛岄偅灏卞彲浠ョ敤Pascal鏉ュ啓涓涓狢璇█鐨勭紪璇戝櫒銆傜涓涓狿ascal鐨勭紪璇戝櫒鎹浣跨敤Fortran鍐欑殑銆傝屼綔涓虹涓涓珮绾...
  • c璇█涓殑璇█鍙互鍦╟++涓敤鍚
    绛旓細鍙互鐨勩俢++鏄悜涓嬪C璇█鍏煎鐨勩侰璇█涓墍鏈夌殑鐗规ф垨鍑芥暟杩樻湁鎿嶄綔绗﹂兘鍙湪C++涓笉缁忚繃淇敼鐩存帴浣跨敤銆備笉鍚岀殑鏄紝C++鐨勬爣鍑嗗嚱鏁板簱锛圫TL锛夊彲鑳芥彁渚涗簡鏇村ソ鐨勫疄鐜版柟寮忋傛ゼ涓诲彲浠ュぇ鑳嗗湪C++涓浣跨敤C鐨勫嚱鏁帮紝涓嶇敤鎷呭績鐨勩
  • 瀛︿範C璇█涓鑸敤浠涔堣蒋浠?
    绛旓細鏂版墜瀛︿範C璇█涓鑸敤浠涔堣蒋浠1銆丏ev-C++ Windows 鐜涓嬬殑涓涓交閲忕骇 C璇█/C++ 闆嗘垚寮鍙戠幆澧(IDE)锛岄伒瀹圙PL璁稿彲鍗忚鍒嗗彂婧愪唬鐮併傚畠闆嗗悎浜嗗姛鑳藉己澶х殑婧愮爜缂栬緫鍣ㄣ丮ingW64/TDM-GCC 缂栬瘧鍣ㄣ丟DB 璋冭瘯鍣ㄥ拰 AStyle 鏍煎紡鏁寸悊鍣ㄧ瓑浼楀鑷敱杞欢锛屾搷浣滃崄鍒嗕究鎹枫2銆丆ode::Blocks 杩欐槸涓涓紑婧愩佽法骞冲彴鐨凜/C++...
  • C璇█缂栫▼鏈夊摢浜涘ソ鐢ㄧ殑杞欢?
    绛旓細1.C璇█缂栫▼杞欢鏈夊摢浜涖侻crosoft Visual C++ 銆丮icrosoft Visual Studio銆 DEV C++銆丆ode::Blocks銆丅orland C++銆乄aTCom C++銆丅orland C++ Builder銆丟NU DJGPP C++銆丩ccwin32 C Compiler3.1銆丠igh C銆乀urb C銆乬cc銆丆-Free鍜學in-TC銆丮y Tc绛夌瓑锛岀敱浜嶤璇█姣旇緝鎴愮啛锛屾墍浠ョ紪绋嬬幆澧冨緢澶氥2.C璇█鍏ラ棬...
  • 濡備綍鐢ㄢ淐璇█鈥濆疄鐜扳滈夐」鏈夊姛鑳界殑鏂囨湰鑿滃崟鈥?
    绛旓細1銆佺洿鎺ョ敤杈撳嚭鍗冲彲瀹炵幇銆2銆佷緥绋嬶細include<stdio.h>#include <stdlib.h>void hello(){ printf("hello world\n");}int main(){ int x; while (1) { printf("---鎿嶄綔閫夐」---\n"); printf("1:杩斿洖鑿滃崟 \n"); printf("2:閫鍑虹▼搴 \n"); printf("3:鎵ц鎿嶄綔 \n"); ...
  • 扩展阅读:mac蜜桃奶茶314 ... 17173.com ... www.sony.com.cn ... c++简单源代码 ... c++入门源代码大全 ... acca免费网课 ... aoc e2243fw ... www.vivo.com ... c#入门基础知识 ...

    本站交流只代表网友个人观点,与本站立场无关
    欢迎反馈与建议,请联系电邮
    2024© 车视网