如何捕获网卡数据?

青化某 2014-09-30 11:41:26
请教下各位大牛,看不少资料都是说如何分析TCP/IP报头的,但就是没说最关心的用户数据怎么获取?

我目前的理解是:recv到数据后后,前把前20字节的IP头分析出来,然后第二步分析21~40的是TCP或者UDP的报头。

不知道这样理解对不对,而且第二步得到的源和目的的端口号总是好几万那么大的数,感觉不对。

剩下最关心就是真正的数据部分 只看到TCP表头里有个成员 .th_urp 是数据偏移 但总感觉不对劲 不知道怎么回事

求懂的大神给讲讲~
...全文
347 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
hzy694358 2014-10-08
  • 打赏
  • 举报
回复
引用 21 楼 hjy88168 的回复:
[quote=引用 20 楼 zzz3265 的回复:] 就是捕获不到1234的消息 注意网卡数据是倒序的, 用 htons , 其他一些数据也一样
那就是说TCP或者UDP的数据部分也是网络顺序?? [/quote] htons htonl 就是short 和 long型需要网络字节序转换
青化某 2014-10-08
  • 打赏
  • 举报
回复
引用 20 楼 zzz3265 的回复:
就是捕获不到1234的消息 注意网卡数据是倒序的, 用 htons , 其他一些数据也一样
那就是说TCP或者UDP的数据部分也是网络顺序??
Yofoo 2014-10-08
  • 打赏
  • 举报
回复
就是捕获不到1234的消息 注意网卡数据是倒序的, 用 htons , 其他一些数据也一样
青化某 2014-10-08
  • 打赏
  • 举报
回复
防火墙也关了。。 就是接受不到啊啊 啊。。 求各位神牛帮忙!
z2665 2014-10-05
  • 打赏
  • 举报
回复
为何不试试使用神奇的wincap呢。路过打酱油
青化某 2014-09-30
  • 打赏
  • 举报
回复
#include <winsock2.h> #include <windows.h> #include <Mstcpip.h> #pragma comment(lib,"Ws2_32.lib") #include <iostream> using namespace std; //IP首部 typedef struct tIPPackHead { enum PROTOCOL_TYPE{ PROTOCOL_TCP = 6, PROTOCOL_UDP = 17, PROTOCOL_ICMP = 1, PROTOCOL_IGMP = 2 }; inline unsigned HeadLen() const { //首部长度单位为4bytes。因此乘4 return (ver_hlen & 0x0F) << 2; } inline unsigned PackLen() const { return wPacketLen; } BYTE ver_hlen; //IP协议版本和IP首部长度。高4位为版本,低4位为首部的长度(单位为4bytes) BYTE byTOS; //服务类型 WORD wPacketLen; //IP包总长度。包括首部,单位为byte。[Big endian] WORD wSequence; //序号,一般每个IP包的序号递增。[Big endian] WORD wMarkFragPoi; BYTE byTTL; //生存时间 BYTE byProtocolType; //协议类型,见PROTOCOL_TYPE定义 WORD wHeadCheckSum; //IP首部校验和[Big endian] DWORD dwIPSrc; //源地址 DWORD dwIPDes; //目的地址 } IP_PK_HEAD; typedef struct _TCP_HEADER //定义TCP首部 { USHORT th_sport; //16位源端口 USHORT th_dport; //16位目的端口 UINT th_seq; //32位序列号 UINT th_ack; //32位确认号 UCHAR th_lenres; //4位首部长度/6位保留字 UCHAR th_flag; //6位标志位 USHORT th_win; //16位窗口大小 USHORT th_sum; //16位校验和 USHORT th_urp; //16位紧急数据偏移量 } TCP_HEADER; ////////////////////////////////////////////////////////////////////////// int DecodeIP(char *buf, int len) { int n = len; if( n >= sizeof(IP_PK_HEAD) ) { cout<<"sizeof(IP_PK_HEAD): "<<sizeof(IP_PK_HEAD)<<" Buffer Length is :"<<n<<endl; IP_PK_HEAD iphead; TCP_HEADER tcphead; memcpy( &iphead, buf, sizeof(iphead) ); memcpy( &tcphead,&buf[sizeof(iphead)],sizeof(tcphead)); int n = ntohs(tcphead.th_urp); cout<<"数据偏移量:"<<n<<endl; //cout<<"内容"<<&buf[40]<<endl; //cout<<"内容"<<&buf[28]<<endl; //以下三个为Big Endian字节顺序,转换成主机字节顺序 iphead.wPacketLen = ntohs( iphead.wPacketLen ); iphead.wSequence = ntohs( iphead.wSequence ); iphead.wHeadCheckSum = ntohs( iphead.wHeadCheckSum ); in_addr src,dst; src.S_un.S_addr = iphead.dwIPSrc; dst.S_un.S_addr = iphead.dwIPDes; char strsrc[20],strdst[20]; strcpy(strsrc, inet_ntoa(src) ); strcpy( strdst , inet_ntoa(dst)); tcphead.th_sport = ntohs(tcphead.th_sport); tcphead.th_dport = ntohs(tcphead.th_dport); if(tcphead.th_sport == 1234 || tcphead.th_dport == 1234) printf("#########################################################\n"); printf("IP报头信息: \nver=%d,hlen=%d,protool=%d,packet length=%d,Sequence=%d\nsrc=%s port:%u\ndst=%s port:%u\n\n\n", iphead.ver_hlen >> 4, (iphead.ver_hlen & 0x0F) << 2, iphead.byProtocolType, iphead.wPacketLen, iphead.wSequence, strsrc, tcphead.th_sport, strdst, tcphead.th_dport); } return 0; } void AutoWSACleanup() { ::WSACleanup(); } int main(int argc, char* argv[]) { //初始化winsock库,使用2.2版本 u_short wVersionRequested = 0x0202; WSADATA wsaData; if( SOCKET_ERROR == WSAStartup( wVersionRequested, &wsaData ) ) { cout << WSAGetLastError(); return 0; } atexit( AutoWSACleanup ); //创建SOCKET SOCKET h = socket( AF_INET, SOCK_RAW, IPPROTO_IP); if( h == INVALID_SOCKET ) { cout << WSAGetLastError(); return 0; } //获取本机地址 char FAR name[128]; if( -1 == gethostname(name, sizeof(name)) ) { closesocket( h ); cout << WSAGetLastError(); return 0; } struct hostent FAR * pHostent; pHostent = gethostbyname(name); //绑定本地地址到SOCKET句柄 sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr = *(in_addr*)pHostent->h_addr; //IP //addr.sin_addr.s_addr = inet_addr("192.168.211.143"); addr.sin_port = 0; //端口,IP层端口可随意填 if( SOCKET_ERROR == bind( h,(sockaddr *)&addr,sizeof(addr) ) ) { closesocket( h ); cout << WSAGetLastError(); return 0; } //设置该SOCKET为接收所有流经绑定的IP的网卡的所有数据,包括接收和发送的数据包 //该函数在mstcpip.h里面,详见MSDN帮助 u_long sioarg = 1; DWORD wt=0; if( SOCKET_ERROR == WSAIoctl( h, SIO_RCVALL , &sioarg,sizeof(sioarg),NULL,0,&wt,NULL,NULL ) ) { closesocket( h ); cout << WSAGetLastError(); return 0; } //我们只需要接收数据,因此设置为阻塞IO,使用最简单的IO模型 u_long bioarg = 0;//0 if( SOCKET_ERROR == ioctlsocket( h, FIONBIO , &bioarg ) )//FIONBIO { closesocket( h ); cout << WSAGetLastError(); return 0; } //开始接收数据 //因为前面已经设置为阻塞IO,recv在接收到数据前不会返回。 //当返回<=0时表示接收失败,退出循环 //可以在另一个线程执行此循环,主线程closesocket可以使recv失败而结束循环 char buf[102400]; int len = 0; do { len = recv( h, buf, sizeof(buf),0); if( len > 0 ) { DecodeIP( buf, len ); } }while( len > 0 ); closesocket( h ); return 0; } 求大神看看代码,为何我用一个UDP客户端绑定1234端口send数据,这个程序捕获很多,就是捕获不到1234的消息,求大神解答!
青化某 2014-09-30
  • 打赏
  • 举报
回复
引用 13 楼 shenyi0106 的回复:
网卡设置成混杂模式
设了啊 还是没有 另外我的UDP发送端的端口是1234.。但我的抓包工具中总没有端口为1234的信息~
青化某 2014-09-30
  • 打赏
  • 举报
回复
引用 13 楼 shenyi0106 的回复:
网卡设置成混杂模式
是这个吧: WSAIoctl( h, SIO_RCVALL , &sioarg,sizeof(sioarg),NULL,0,&wt,NULL,NULL )
shenyi0106 2014-09-30
  • 打赏
  • 举报
回复
网卡设置成混杂模式
青化某 2014-09-30
  • 打赏
  • 举报
回复
引用 11 楼 shenyi0106 的回复:
乱码也正常,你确认你收到的都是ASCII吗的数据吗? 不是ASCII吗的,当然是乱码
我同时写了个UDP的发送端程序,是广播形式,每次都send成功的。发送一个字符串。 但这个程序貌似也捕获不到~ ~ 不应该呀
shenyi0106 2014-09-30
  • 打赏
  • 举报
回复
乱码也正常,你确认你收到的都是ASCII吗的数据吗? 不是ASCII吗的,当然是乱码
青化某 2014-09-30
  • 打赏
  • 举报
回复
引用 9 楼 shenyi0106 的回复:
TCP是40,UDP是28呀!!
对呀对呀~可我无论是28还是40都是乱码。。。百思不得其解。。
shenyi0106 2014-09-30
  • 打赏
  • 举报
回复
TCP是40,UDP是28呀!!
青化某 2014-09-30
  • 打赏
  • 举报
回复
引用 7 楼 shenyi0106 的回复:
去掉所有的头,剩下的就是数据,这还用问???
我将recv到的buffer数据,从buff[40]开始输出都是乱码 这也需要转主机字节序么
shenyi0106 2014-09-30
  • 打赏
  • 举报
回复
去掉所有的头,剩下的就是数据,这还用问???
青化某 2014-09-30
  • 打赏
  • 举报
回复
引用 5 楼 shenyi0106 的回复:
[quote=引用 4 楼 hjy88168 的回复:] [quote=引用 3 楼 shenyi0106 的回复:] [quote=引用 2 楼 hjy88168 的回复:] [quote=引用 1 楼 shenyi0106 的回复:] 请用raw socket来接收, 你这里recv到的是的TCP负载。 话说,win7上好像不在支持raw socket了
能具体点说么[/quote] 请自行“度娘”[/quote] 我就是raw socekt实现的,我是说怎么分析接收到的这个包。。。我是XP系统。。[/quote] TCP头是20个字节,UDP头是8个字节 另外,你收到的协议是网络字节序的,需要转换成主机字节序。 比如端口,你从udphdr->src_prt里面得到的端口是网络字节序的,需要用ntohs()转成主机字节序[/quote] 多谢大神 解决了端口问题,那最关心的数据是怎么获得的呢?
shenyi0106 2014-09-30
  • 打赏
  • 举报
回复
引用 4 楼 hjy88168 的回复:
[quote=引用 3 楼 shenyi0106 的回复:] [quote=引用 2 楼 hjy88168 的回复:] [quote=引用 1 楼 shenyi0106 的回复:] 请用raw socket来接收, 你这里recv到的是的TCP负载。 话说,win7上好像不在支持raw socket了
能具体点说么[/quote] 请自行“度娘”[/quote] 我就是raw socekt实现的,我是说怎么分析接收到的这个包。。。我是XP系统。。[/quote] TCP头是20个字节,UDP头是8个字节 另外,你收到的协议是网络字节序的,需要转换成主机字节序。 比如端口,你从udphdr->src_prt里面得到的端口是网络字节序的,需要用ntohs()转成主机字节序
青化某 2014-09-30
  • 打赏
  • 举报
回复
引用 3 楼 shenyi0106 的回复:
[quote=引用 2 楼 hjy88168 的回复:] [quote=引用 1 楼 shenyi0106 的回复:] 请用raw socket来接收, 你这里recv到的是的TCP负载。 话说,win7上好像不在支持raw socket了
能具体点说么[/quote] 请自行“度娘”[/quote] 我就是raw socekt实现的,我是说怎么分析接收到的这个包。。。我是XP系统。。
shenyi0106 2014-09-30
  • 打赏
  • 举报
回复
引用 2 楼 hjy88168 的回复:
[quote=引用 1 楼 shenyi0106 的回复:] 请用raw socket来接收, 你这里recv到的是的TCP负载。 话说,win7上好像不在支持raw socket了
能具体点说么[/quote] 请自行“度娘”
青化某 2014-09-30
  • 打赏
  • 举报
回复
引用 1 楼 shenyi0106 的回复:
请用raw socket来接收, 你这里recv到的是的TCP负载。 话说,win7上好像不在支持raw socket了
能具体点说么
加载更多回复(1)
[menu_102] 70001=文件(&F) 40024=开始捕获(&S) 40025=停止捕获(&T) 40045=保存配置(&C) 40046=载入配置(&O) 40034=保存数据数据到文件 40035=载入数据数据文件 40039=导出 TCP/IP 流报告(&E) 40001=保存数据包摘要(&A) 40009=属性(&P) 40002=退出(&X) 70002=编辑(&E) 40031=复制(&C) 40007=全选(&A) 40015=全部取消选定(&D) 40032=下一项(&N) 40033=上一项(&P) 70003=查看(&V) 40005=显示网格线(&G) 40028=显示气球提示(&T) 40010=HTML 报告 - TCP/IP 流(&H) 40011=栏位设定(&N) 40012=自动调整栏的宽度(&A) 70004=选项(&O) 71001=显示模式(&M) 41101=自动(&A) 41102=ASCII(&S) 41103=16进制(&H) 71002=显示协议(&P) 41201=&TCP 41202=&UDP 41203=&ICMP 40027=显示 ASCII 码大于 127 的字符(&C) 40041=显示捕获时间(&T) 40042=将 IP 地址解析为主机名 40044=显示过滤设置 40040=高级选项(&A) 40043=捕获过滤设置 40026=选择设备(&O) 70005=帮助(&H) 40003=关于(&A) 41104=&URL 列表 [menu_104] 70001=Popup1 40010=生成 TCP/IP 流的 HTML 报告(&H) 40039=保存 TCP/IP 流报告(&E) 40001=保存数据包摘要(&A) 40011=栏位设定(&N) 40012=栏位自动宽度(&A) 40007=选择全部(&A) 40015=取消已选定(&D) 40031=复制(&C) 40032=下一项(&N) 40033=上一项(&P) 70002=Popup2 [dialog_105] caption=属性 1=确定 [dialog_108] caption=捕获选项 1007=原始套接字 (仅Windows 2000/XP) 1008=使用 WinPcap 包捕获驱动 1005=List1 1=确定 2=取消 1006=捕获方式 1009=选择网卡: 1045=选择网卡: [dialog_112] 1=确定 [dialog_113] caption=高级选项 1035=即时显示模式 - 捕获的同时列出 TCP/IP 会话 1011=每行字符数: 1013=显示时,在每 1025=显示 ASCII 字符 1026=在每行开头显示偏移量 1014=自动决定显示模式时要检查的字符数: 1032=不可显示的 ASCII 字符替换为: 1036=自动模式中, 若数据长度大于此限制则不显示16进制数据 1038=在下部面板中不显示数据长度大于此限制的项 1019=选择 1022=选择 1029=选择 1=确定 2=取消 1010=16进制显示选项 1015=个字符后插入额外的空格 1016=文字颜色 1017=源于本地主机的 TCP/IP 流的文字颜色: 1020=源于远程主机的 TCP/IP 流的文字颜色: 1030=捕获时间的文字颜色: 1031=常规显示选项 1034=捕获 1039=KB 1041=KB 1042=捕获同时显示 TCP/IP 会话内容开始的部分 1043=仅显示 TCP/IP 统计数据, 不在文件中保存捕获数据 1044=捕获时亦获取进程信息 1045=摘要模式 (每个连接之间不换行) [dialog_114] 1=确定 2=取消 3=清除 1037=输入一条或多条过滤规则, 以空格或回车分隔。以下是过滤字规则的几个例子: [dialog_1096] caption=栏位设定 1003=上移(&U) 1004=下移(&D) 1006=显示(&S) 1007=隐藏(&H) 1008=默认 1=确定 2=取消 1000=钩选要显示的内容, 用上移或下移按钮排列显示顺序 1002=栏位宽度(像素): [strings] 4=%d 个 TCP/IP 会话 5=, 选定 %d 个 6=创建本文件使用的是 7=选择保存文件的名称 8=数据包摘要 9=无法启动选定网卡上的包捕获。 10=该项所含数据长度超过 %d KB 限制。 11=可使用导出选项将此项保存到文件中。 12=此 TCP/IP 会话太大,无法在捕获同时显示。 13=停止捕获后将显示会话的完整内容。 14=正在加载... %d 15=已捕获 %d 个数据包 16=错误: 无法创建数据包文件! 17=正在捕获... 18=选择用于保存已捕获数据的文件名 19=载入存有数据数据的文件 20=确定要停止捕获并退出 SmartSniff 吗? 21=选择用于保存已捕获数据包流的文件名称 22=数据包流报告 23=当前操作含有非常大的数据包流,载入过程可能很慢,要继续吗? 24=选择要保存的配置文件名 25=选择要载入的配置文件 51=捕获过滤选项 52=显示过滤选项 101=字节 501=文本文件 502=制表符分隔的文本文件 503=空格分隔的表格化文本文件 504=HTML 文件 - 水平方式 505=HTML 文件 - 垂直方式 506=XML 文件 521=ICMP 522=TCP 523=UDP 541=文本文件 542=HTML 文件 543=原始数据文件 601=SmartSniff 数据包文件 602=tcpdump/libpcap 文件 621=SmartSniff 配置文件 1001=编号 1002=协议 1003=本地地址 1004=远程地址 1005=本地端口 1006=远程端口 1007=数据包数量 1008=包含封装信息的总数据量 1009=捕获时间 1010=不含封装信息的数据量 1011=服务名称 1012=本地主机 1013=远程主机 1014=进程号 1015=进程文件名 1051=IP 地址 1052=设备名称

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧