VC++编程实现网络嗅探器

2016-02-19 17:42 67 1 收藏

在这个颜值当道,屌丝闪边的时代,拼不过颜值拼内涵,只有知识丰富才能提升一个人的内在气质和修养,所谓人丑就要多学习,今天图老师给大家分享VC++编程实现网络嗅探器,希望可以对大家能有小小的帮助。

【 tulaoshi.com - 编程语言 】

[文章信息]作者:中国电波传播研究所青岛分所郎锐时间:2003-06-16出处:yesky责任编辑:方舟[文章导读]本文给出了一种在Visual C++下用原始套接字来捕捉并分析在网络上传输的数据包的简单方法 引言  从事网络安全的技术人员和相当一部分准黑客(指那些使用现成的黑客软件进行攻击而不是根据需要去自己编写代码的人)都一定不会对网络嗅探器(sniffer)感到生疏,网络嗅探器无论是在网络安全还是在黑客攻击方面均扮演了很重要的角色。通过使用网络嗅探器可以把网卡设置于混杂模式,并可实现对网络上传输的数据包的捕捉与分析。此分析结果可供网络安全分析之用,但如为黑客所利用也可以为其发动进一步的攻击提供有价值的信息。可见,嗅探器实际是一把双刃剑。虽然网络嗅探器技术被黑客利用后会对网络安全构成一定的威胁,但嗅探器本身的危害并不是很大,主要是用来为其他黑客软件提供网络情报,真正的攻击主要是由其他黑软来完成的。而在网络安全方面,网络嗅探手段可以有效地探测在网络上传输的数据包信息,通过对这些信息的分析利用是有助于网络安全维护的。权衡利弊,有必要对网络嗅探器的实现原理进行介绍。  嗅探器设计原理  嗅探器作为一种网络通讯程序,也是通过对网卡的编程来实现网络通讯的,对网卡的编程也是使用通常的套接字(socket)方式来进行。但是,通常的套接字程序只能响应与自己硬件地址相匹配的或是以广播形式发出的数据帧,对于其他形式的数据帧比如已到达网络接口但却不是发给此地址的数据帧,网络接口在验证投递地址并非自身地址之后将不引起响应,也就是说应用程序无法收取到达的数据包。而网络嗅探器的目的恰恰在于从网卡接收所有经过它的数据包,这些数据包即可以是发给它的也可以是发往别处的。显然,要达到此目的就不能再让网卡按通常的正常模式工作,而必须将其设置为混杂模式。  具体到编程实现上,这种对网卡混杂模式的设置是通过原始套接字(raw socket)来实现的,这也有别于通常经常使用的数据流套接字和数据报套接字。在创建了原始套接字后,需要通过setsockopt()函数来设置IP头操作选项,然后再通过bind()函数将原始套接字绑定到本地网卡。为了让原始套接字能接受所有的数据,还需要通过ioctlsocket()来进行设置,而且还可以指定是否亲自处理IP头。至此,实际就可以开始对网络数据包进行嗅探了,对数据包的获取仍象流式套接字或数据报套接字那样通过recv()函数来完成。但是与其他两种套接字不同的是,原始套接字此时捕捉到的数据包并不仅仅是单纯的数据信息,而是包含有 IP头、 TCP头等信息头的最原始的数据信息,这些信息保留了它在网络传输时的原貌。通过对这些在低层传输的原始信息的分析可以得到有关网络的一些信息。由于这些数据经过了网络层和传输层的打包,因此需要根据其附加的帧头对数据包进行分析。下面先给出结构.数据包的总体结构:数据包IP头TCP头(或其他信息头)数据  数据在从应用层到达传输层时,将添加TCP数据段头,或是UDP数据段头。其中UDP数据段头比较简单,由一个8字节的头和数据部分组成,具体格式如下:
  16位16位源端口目的端口UDP长度UDP校验和  而TCP数据头则比较复杂,以20个固定字节开始,在固定头后面还可以有一些长度不固定的可选项,下面给出TCP数据段头的格式组成:
  16位 16位源端口目的端口顺序号确认号TCP头长(保留)7位URGACK PSHRSTSYNFIN 窗口大小校验和 紧急指针可选项(0或更多的32位字)数据(可选项)  对于此TCP数据段头的分析在编程实现中可通过数据结构_TCP来定义:
  typedef strUCt _TCP{ Word SrcPort; // 源端口
  WORD DstPort; // 目的端口
  DWORD SeqNum; // 顺序号
  DWORD AckNum; // 确认号
  BYTE DataOff; // TCP头长
  BYTE Flags; // 标志(URG、ACK等)
  WORD Window; // 窗口大小
  WORD Chksum; // 校验和
  WORD UrgPtr; // 紧急指针
  } TCP;
  typedef TCP *LPTCP;
  typedef TCP UNALIGNED * ULPTCP;
     在网络层,还要给TCP数据包添加一个IP数据段头以组成IP数据报。IP数据头以大端点机次序传送,从左到右,版本字段的高位字节先传输(SPARC是大端点机;Pentium是小端点机)。假如是小端点机,就要在发送和接收时先行转换然后才能进行传输。IP数据段头格式如下:
  16位16位版本 IHL 服务类型总长标识 标志分段偏移生命期协议 头校验和源地址目的地址选项(0或更多)  同样,在实际编程中也需要通过一个数据结构来表示此IP数据段头,下面给出此数据结构的定义:
  typedef struct _IP{
  union{ BYTE Version; // 版本
  BYTE HdrLen; // IHL
  };
  BYTE ServiceType; // 服务类型
  WORD TotalLen; // 总长
  WORD ID; // 标识
  union{ WORD Flags; // 标志
  WORD FragOff; // 分段偏移
  };
  BYTE TimeToLive; // 生命期
  BYTE Protocol; // 协议
  WORD HdrChksum; // 头校验和
  DWORD SrcAddr; // 源地址
  DWORD DstAddr; // 目的地址
  BYTE Options; // 选项
  } IP;
  typedef IP * LPIP;
  typedef IP UNALIGNED * ULPIP;
    在明确了以上几个数据段头的组成结构后,就可以对捕捉到的数据包进行分析了。 三层交换技术交换机与路由器密码恢复交换机的选购 路由器设置专题路由故障处理手册数字化校园网解决方案 嗅探器的具体实现  根据前面的设计思路,不难写出网络嗅探器的实现代码,下面就给出一个简单的示例,该示例可以捕捉到所有经过本地网卡的数据包,并可从中分析出协议、IP源地址、IP目标地址、TCP源端口号、TCP目标端口号以及数据包长度等信息。由于前面已经将程序的设计流程讲述的比较清楚了,因此这里就不在赘述了,下面就结合注释对程序的具体是实现进行讲解,同时为程序流程的清楚起见,去掉了错误检查等保护性代码。主要代码实现清单为:// 检查 Winsock 版本号,WSAData为WSADATA结构对象
  WSAStartup(MAKEWORD(2, 2), &WSAData);
  // 创建原始套接字
  sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW));
  // 设置IP头操作选项,其中flag 设置为ture,亲自对IP头进行处理
  setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char*)&flag, sizeof(flag));
  // 获取本机名
  gethostname((char*)LocalName, sizeof(LocalName)-1);
  // 获取本地 IP 地址
  pHost = gethostbyname((char*)LocalName));
  // 填充SOCKADDR_IN结构
  addr_in.sin_addr = *(in_addr *)pHost->h_addr_list[0]; //IP
  addr_in.sin_family = AF_INET;
  addr_in.sin_port = htons(57274);
  // 把原始套接字sock 绑定到本地网卡地址上
  bind(sock, (PSOCKADDR)&addr_in, sizeof(addr_in));
  // dwValue为输入输出参数,为1时执行,0时取消
  DWORD dwValue = 1;
  // 设置 SOCK_RAW 为SIO_RCVALL,以便接收所有的IP包。其中SIO_RCVALL
  // 的定义为: #define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)
  ioctlsocket(sock, SIO_RCVALL, &dwValue);

     前面的工作基本上都是对原始套接字进行设置,在将原始套接字设置完毕,使其能按预期目的工作时,就可以通过recv()函数从网卡接收数据了,接收到的原始数据包存放在缓存RecvBuf[]中,缓冲区长度BUFFER_SIZE定义为65535。然后就可以根据前面对IP数据段头、TCP数据段头的结构描述而对捕捉的数据包进行分析:while (true)
  {
  // 接收原始数据包信息
  int ret = recv(sock, RecvBuf, BUFFER_SIZE, 0);
  if (ret 0)
  {
  // 对数据包进行分析,并输出分析结果
  ip = *(IP*)RecvBuf;
  tcp = *(TCP*)(RecvBuf + ip.HdrLen);
  TRACE("协议: %s",GetProtocolTxt(ip.Protocol));
  TRACE("IP源地址: %s",inet_ntoa(*(in_addr*)&ip.SrcAddr));
  TRACE("IP目标地址: %s",inet_ntoa(*(in_addr*)&ip.DstAddr));
  TRACE("TCP源端口号: %d",tcp.SrcPort);
  TRACE("TCP目标端口号:%d",tcp.DstPort);
  TRACE("数据包长度: %d",ntohs(ip.TotalLen));
  }
  }
  其中,在进行协议分析时,使用了GetProtocolTxt()函数,该函数负责将IP包中的协议(数字标识的)转化为文字输出,该函数实现如下:#define PROTOCOL_STRING_ICMP_TXT "ICMP"
  #define PROTOCOL_STRING_TCP_TXT "TCP"
  #define PROTOCOL_STRING_UDP_TXT "UDP"
  #define PROTOCOL_STRING_SPX_TXT "SPX"
  #define PROTOCOL_STRING_NCP_TXT "NCP"
  #define PROTOCOL_STRING_UNKNOW_TXT "UNKNOW"
  ……
  CString CSnifferDlg::GetProtocolTxt(int Protocol)
  {
  switch (Protocol){
  case IPPROTO_ICMP : //1 /* control message protocol */
  return PROTOCOL_STRING_ICMP_TXT;
  case IPPROTO_TCP : //6 /* tcp */
  return PROTOCOL_STRING_TCP_TXT;
  case IPPROTO_UDP : //17 /* user datagram protocol */
  return PROTOCOL_STRING_UDP_TXT;
  default:
  return PROTOCOL_STRING_UNKNOW_TXT;
  }
  最后,为了使程序能成功编译,需要包含头文件winsock2.h和ws2tcpip.h。在本示例中将分析结果用TRACE()宏进行输出,在调试状态下运行,得到的一个分析结果如下:协议: UDP
  IP源地址: 172.168.1.5
  IP目标地址: 172.168.1.255
  TCP源端口号: 16707
  TCP目标端口号:19522
  数据包长度: 78
  ……
  协议: TCP
  IP源地址: 172.168.1.17
  IP目标地址: 172.168.1.1
  TCP源端口号: 19714
  TCP目标端口号:10
  数据包长度: 200
  ……
  
     从分析结果可以看出,此程序完全具备了嗅探器的数据捕捉以及对数据包的分析等基本功能。  小结  本文介绍的以原始套接字方式对网络数据进行捕捉的方法实现起来比较简单,尤其是不需要编写VxD虚拟设备驱动程序就可以实现抓包,使得其编写过程变的非常简便,但由于捕捉到的数据包头不包含有帧信息,因此不能接收到与 IP 同属网络层的其它数据包, 如 ARP数据包、RARP数据包等。在前面给出的示例程序中考虑到安全因素,没有对数据包做进一步的分析,而是仅仅给出了对一般信息的分析方法。通过本文的介绍,可对原始套接字的使用方法以及TCP/IP协议结构原理等知识有一个基本的熟悉。本文所述代码在windows 2000下由Microsoft Visual C++ 6.0编译调试通过

来源:http://www.tulaoshi.com/n/20160219/1615850.html

延伸阅读
*假设调试机IP 192.168.0.182   远程机IP 192.168.0.161 *远程机为调试机分配权限,使调试机可以使用远程桌面登陆到远程机器上(这样调试起来方便)。 *调试机上安装visual studio .net 2003 共享调试机上的Visual Studio上的远程调试目录(以我的机器为例) C:Program FilesMicrosoft Visual Studio .NET 2003Common7PackagesDe...
概述 管道(Pipe)实际是用于进程间通信的一段共享内存,创建管道的进程称为管道服务器,连接到一个管道的进程为管道客户机。一个进程在向管道写入数据后,另一进程就可以从管道的另一端将其读取出来。匿名管道(Anonymous Pipes)是在父进程和子进程间单向传输数据的一种未命名的管道,只能在本地计算机中使用,而不可用于网络间的通信...
在VC++实现数据加密 作者:惠州市东晓电子有限公司 龚辉斌 下载本文示例源代码 为了保证数据的安全性与完整性,常常要对数据进行加密,在数据传输过程进行数据加密可以防止中途非法截获。我们通常称原始数据叫做源文,用约定的加密算法进行加密处理。加密算法的输入是源文与加密键,而输出的则是密文...
进入搜索功能 打开傲游云游览器,找到地址栏旁边有一个放大镜查找图标。点击进入即可开始使用资源嗅探器功能。 图片批量下载 如果要批量下载图片,点击图片; 保存路径设置 点击需要下载的图片资源,可以根据大小排序把太小的图片过滤。下方有保存到目标的路径位置,点击浏览进行修改; 开始下载 点击保...
VC++中轻松实现滑动控件 作者: 上海同济大学计算机系 小鹰 下载本文示例代码 滑动控件是Windows中最常用的控件之一。一般而言它是由一个滑动条,一个滑块和可选的刻度组成,用户可以通过移动滑块在相应的控件中显示对应的值。通常,在滑动控件附近一定有标签控件或编辑框控件,用...

经验教程

975

收藏

24
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部